//mongoDB ,创建一个自动增长的ID public abstract class AbstractIdEntity{ @Id Long _id; @Transient protected Datastore ds; public AbstractIdEntity(){ } public void setDs(Datastore ds) { this.ds = ds; } @PrePersist void prePersist(){ if (_id == null) { String collName = ds.getCollection(getClass()).getName(); Query<StoredSeqence> q = ds.find(StoredSeqence.class, "_id", collName); UpdateOperations<StoredSeqence> uOps = ds.createUpdateOperations(StoredSeqence.class).inc("value"); StoredSeqence newId = ds.findAndModify(q, uOps); if (newId == null) { newId = new StoredSeqence(collName); ds.save(newId); } _id = newId.value; } } public Long geId() { return _id; } } @Entity(value="book_score_mongo", noClassnameStored=true) public class BookScoreMongo extends AbstractIdEntity { /**书的ID*/ private Long bookId; /**书的类型(1为原创,2为藏书)*/ private Integer bookType; /**用户的userId*/ private Integer userId; /**评分的分数*/ private Long score; public Long getBookId() { return bookId; } public void setBookId(Long bookId) { this.bookId = bookId; } public Integer getBookType() { return bookType; } public void setBookType(Integer bookType) { this.bookType = bookType; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public Long getScore() { return score; } public void setScore(Long score) { this.score = score; } } public interface IDAO { /** * 查询mongo数据库集合中的所有记录数 * * @param clazz 通过cls配置的MongoCollect注解找到集合名 * @return 返回集合的所有记录数 */ public <T> long count(Class<T> clazz); public <T> long count(Class<T> clazz, Map<String, Object> conditions); /** * 保存对象,返回主键值 * * @param entity 需要保存的对象 * @return 主键值 */ <T> Object saveRtnKey(T entity); <T> void delete(Class<T> clazz, Map<String, Object> conditions); /** * 根据主键值,将指定的字段更新为相应的值 * * @param clazz * @param id 主键id * @param updateFieldsMap updateFieldsMap中的key为字段名,value为字段值 * @return 返回更新的行数 */ <T, V> int update(Class<T> clazz, V id, Map<String, Object> updateFieldsMap); /** * 根据主键值,查询数据库,查询结果转换为指定类的实例对象,没有结果,返回null。 * * @param clazz 查询结果转换为该类 * @param id 主键值,作为查询条件 * @return 返回指定类cls的实例对象 */ <T,V> T queryForObjectById(Class<T> clazz, V id); /** * 查询所有记录,查询结果转换为指定类的实例对象列表,没有结果,返回空的List对象。 * * @param cls 查询结果转换为该类 * @return 返回指定类的实例对象列表 */ <T> List<T> queryForList(Class<T> clazz); /** * 查询所有记录,并根据字段进行排序,查询结果转换为指定类的实例对象列表,没有结果,返回空的List对象。 * 排序字段示例: * ("age") * ("-age") age字段降序排序 * ("age,date") * ("age,-date") age字段升序,date字段降序排序 * * @param cls 查询结果转换为该类 * @param orderFields 排序字段列表 * @return 返回指定类的实例对象列表 */ <T> List<T> queryForListWithOrder(Class<T> clazz, String orderFields); /** * 查询所有符合条件的记录,查询结果转换为指定类的实例对象列表,没有结果,返回空的List对象。 * 属性名必须是"属性名 操作符"("age >") * 属性中,可以使用的有效操作符 ["=", "==","!=", "<>", ">", "<", ">=", "<=", "in", "nin", "all", "size", "exists"] * 例如: * * ("yearsOfOperation >", 5) * ("rooms.maxBeds >=", 2) * ("rooms.bathrooms exists", 1) * ("stars in", new Long[]{3,4}) //3 and 4 stars (midrange?)} * ("age >=", age) * ("age =", age) * ("age", age)如果不写操作符,默认为=号 * ("age !=", age) * ("age in", ageList) * ("customers.loyaltyYears in", yearsList) * * @param clazz 查询结果转换为该类 * @param property * @param value * @return 返回指定类的实例对象列表 */ <T, V> List<T> queryForListByConExpr(Class<T> clazz, String property, V value); /** * 查询所有符合条件的记录,查询结果转换为指定类的实例对象列表,没有结果,返回空的List对象, * 多个查询条件之间的关系是与关系 * * @param cls 查询结果转换为该类 * @param conditions key为property,可参考queryForListByConExpr方法说明 * @return 返回指定类的实例对象列表 */ <T> List<T> queryForListByConExprMap(Class<T> cls, Map<String, Object> conditions); <T> List<T> queryForListByConExprMapWithOrder(Class<T> cls, Map<String, Object> conditions, String orderFields); <T> List<T> queryForListByConExprMapWithOrderLimit(Class<T> clazz, Map<String, Object> conditions, String orderFields, int rtnNum); <T> List<T> queryForListByConExprMapWithOrderSkipLimit(Class<T> cls, Map<String, Object> conditions,String orderFields, int skipNum, int rtnNum); } public class MongoServiceDAO implements IDAO{ public static final String MONGO_ID_KEY="_id"; private Datastore ds; private static MongoServiceDAO instance = new MongoServiceDAO(); static{ init(); } private MongoServiceDAO(){} public static MongoServiceDAO getInstance(){ return instance; } private static void init(){ InputStream in=null; try { in = MongoServiceDAO.class.getClassLoader().getResourceAsStream("mongodb.properties"); Properties prop = new Properties(); prop.load(in); String host = prop.getProperty("host").trim(); int port = Integer.valueOf(prop.getProperty("port").trim()); String dbName = prop.getProperty("dbName").trim(); String userName = prop.getProperty("userName").trim(); String password = prop.getProperty("password").trim(); Morphia morphia = new Morphia(); Mongo mongo = new Mongo(host, port); instance.ds = morphia.createDatastore(mongo,dbName); if (isMongoSecure(userName, password)){ boolean bauth = instance.ds.getDB().authenticate(userName, password.toCharArray()); if (!bauth) { throw new Exception("auth fail."); } } } catch(Exception e){ SysLogger.error(e.getMessage()); throw new RuntimeException(e.getMessage()); }finally{ if (in!=null){ try { in.close(); } catch (IOException e) { SysLogger.error(e.getMessage()); } } } } private static boolean isMongoSecure(String mongoUsername, String mongoPassword) { if (mongoUsername == null || "".equals(mongoUsername) || mongoPassword == null || "".equals(mongoPassword)) return false; return true; } @Override public <T> long count(Class<T> clazz){ return this.ds.getCount(clazz); } @Override public <T> long count(Class<T> clazz, Map<String, Object> conditions){ if (conditions==null) return this.count(clazz); Set<Entry<String, Object>> set = conditions.entrySet(); Query<T> q = this.ds.createQuery(clazz); //加入过滤条件 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } return this.ds.getCount(q); } @Override public <T> Object saveRtnKey(T entity) { if (AbstractIdEntity.class.isAssignableFrom(entity.getClass())){ ((AbstractIdEntity)entity).setDs(this.ds); } Key<T> key = this.ds.save(entity); return key.getId(); } @Override public <T> void delete(Class<T> clazz, Map<String, Object> conditions){ Query<T> q = this.ds.createQuery(clazz); if (conditions != null){ Set<Entry<String, Object>> set = conditions.entrySet(); //加入过滤条件 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } } this.ds.delete(q); } @Override public <T, V> int update(Class<T> clazz, V id, Map<String, Object> updateFieldsMap){ Query<T> q = this.ds.find(clazz, "_id =", id); UpdateOperations<T> ops = this.ds.createUpdateOperations(clazz); for (Map.Entry<String, Object> entry : updateFieldsMap.entrySet()){ ops.set(entry.getKey(), entry.getValue()); } UpdateResults<T> updateResult = this.ds.update(q, ops); return updateResult.getUpdatedCount(); } @Override public <T, V> T queryForObjectById(Class<T> clazz, V id) { return this.ds.get(clazz, id); } @Override public <T> List<T> queryForList(Class<T> clazz) { List<T> rtnList = new ArrayList<T>(); Query<T> q = this.ds.find(clazz); Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T> List<T> queryForListWithOrder(Class<T> clazz, String orderFields) { List<T> rtnList = new ArrayList<T>(); Query<T> q = this.ds.find(clazz); //排序 q.order(orderFields); //返回结果 Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T, V> List<T> queryForListByConExpr(Class<T> clazz, String property, V value) { List<T> rtnList = new ArrayList<T>(); Query<T> q = this.ds.find(clazz, property, value); Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T> List<T> queryForListByConExprMap(Class<T> clazz, Map<String, Object> conditions) { List<T> rtnList = new ArrayList<T>(); Set<Entry<String, Object>> set = conditions.entrySet(); Query<T> q = this.ds.createQuery(clazz); //过滤 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } //返回结果 Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T> List<T> queryForListByConExprMapWithOrder(Class<T> clazz, Map<String, Object> conditions, String orderFields) { List<T> rtnList = new ArrayList<T>(); Set<Entry<String, Object>> set = conditions.entrySet(); Query<T> q = this.ds.createQuery(clazz); //过滤 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } //排序 q.order(orderFields); //返回结果 Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T> List<T> queryForListByConExprMapWithOrderLimit(Class<T> clazz, Map<String, Object> conditions, String orderFields, int rtnNum) { List<T> rtnList = new ArrayList<T>(); Set<Entry<String, Object>> set = conditions.entrySet(); Query<T> q = this.ds.createQuery(clazz); //过滤 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } //排序 q.order(orderFields); //取查询结果顶部rtnNum条记录 q.limit(rtnNum); //返回结果 Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } @Override public <T> List<T> queryForListByConExprMapWithOrderSkipLimit(Class<T> clazz, Map<String, Object> conditions,String orderFields, int skipNum, int rtnNum) { List<T> rtnList = new ArrayList<T>(); Set<Entry<String, Object>> set = conditions.entrySet(); Query<T> q = this.ds.createQuery(clazz); //过滤 for(Entry<String,Object> entry : set){ q.filter(entry.getKey(), entry.getValue()); } //排序 q.order(orderFields); //查询结果指针偏移数 q.offset(skipNum); //取查询结果指针位置后的rtnNum记录 q.limit(rtnNum); //返回结果 Iterator<T> itor = q.fetch().iterator(); while (itor.hasNext()){ rtnList.add(itor.next()); } return rtnList; } /** * 对传入的key通过分割符/进行层次分解, * 例如key为a/b/c/d,分解之后的层次为a, a/b, a/b/c, a/b/c/d四层, * 对每层中的给定的所有字段值加1 * 例如:addFieldsValueFromLeafkey2Rootkey("a/b/c","field1","field2") * 将执行: * _id field1 field2 * ------------------------------------------ * a/b/c field1.value+1 field2.value+1 * a/b field1.value+1 field2.value+1 * a field1.value+1 field2.value+1 * * @param leafkey 叶层次的key值 * @param fieldNames 需要字段值加1的字段 */ public void incFieldsValueFromLeafkey2Rootkey(Class clazz,String leafkey, String...fieldNames){ this.addFieldsValueFromLeafkey2Rootkey(clazz, leafkey, 1, fieldNames); } public void addFieldsValueFromLeafkey2Rootkey(Class clazz, String leafkey, int value, String...fieldNames){ DBCollection coll = this.ds.getCollection(clazz); for (String fieldName:fieldNames){ recurseAddVisitCount(coll, leafkey, value, fieldName); } } public void incFieldsValue(Class clazz, Object primaryKeyValue, String...fieldNames){ this.addFieldsValue(clazz, primaryKeyValue, 1, fieldNames); } public void addFieldsValue(Class clazz, Object primaryKeyValue, int value, String...fieldNames){ DBCollection coll = this.ds.getCollection(clazz); for (String fieldName:fieldNames){ addFieldValue(coll, primaryKeyValue, value, fieldName); } } private void addFieldValue(DBCollection coll, Object primaryKeyValue, int value, String fieldName){ if (primaryKeyValue==null) return; BasicDBObject conditionDBObject = new BasicDBObject(); conditionDBObject.put(MONGO_ID_KEY, primaryKeyValue); BasicDBObject valDBObject = new BasicDBObject(); valDBObject.put(fieldName, value); BasicDBObject updateDBObject = new BasicDBObject(); updateDBObject.put("$inc", valDBObject); coll.update(conditionDBObject, updateDBObject, true, false); } private static final String KEY_SEPERATOR = "/"; //db.c.update({_id:10},{$inc:{count:value}}) private void recurseAddVisitCount(DBCollection coll, String key, int value, String fieldName){ if (key==null || key.trim().equals("")) return; if(key.startsWith(KEY_SEPERATOR) || key.endsWith(KEY_SEPERATOR)) throw new RuntimeException("key can't start or end with "+KEY_SEPERATOR+",because it is key seperator."); BasicDBObject conditionDBObject = new BasicDBObject(); conditionDBObject.put(MONGO_ID_KEY, key); BasicDBObject valDBObject = new BasicDBObject(); valDBObject.put(fieldName, value); BasicDBObject updateDBObject = new BasicDBObject(); updateDBObject.put("$inc", valDBObject); coll.update(conditionDBObject, updateDBObject, true, false); int pos = key.lastIndexOf(KEY_SEPERATOR); if (pos>0){ String newKey = key.substring(0,pos); recurseAddVisitCount(coll, newKey, value, fieldName); } } } //业务层具体实现增,删,改,查, /** * 评分 */ @Service public class BookScoreMongoManager{ @Autowired private OriginalBookManager originalBookManager; @Autowired private PaperBookManager paperBookManager; /** * 插入评分mongo表 * @param bookScoreMongo * @return */ public Long insertBookScoreMongo(BookScoreMongo bookScoreMongo){ return (Long)MongoServiceDAO.getInstance().saveRtnKey(bookScoreMongo); } /** * 通过ID获取评分mongo数据 * @param id * @return */ public BookScoreMongo getBookScoreMongoById(Long id){ return MongoServiceDAO.getInstance().queryForObjectById(BookScoreMongo.class, id); } /** * 修改个人对书的评分分数 * @param bookScoreMongo * @param score */ private void updateBookScoreMongoById(BookScoreMongo bookScoreMongo ,Long score){ if(score!=null && score>0 ){ Map<String, Object> updateFieldsMap = new HashMap<String, Object>(); updateFieldsMap.put("score", score); MongoServiceDAO.getInstance().update(BookScoreMongo.class,bookScoreMongo.geId(),updateFieldsMap); } } /** * 通过书籍ID,书籍类型和用户ID取评分mongo * @param bookid * @param userid * @param booktype * @return */ public BookScoreMongo getScoreById(Long bookId,Integer userid,Integer booktype){ Map<String,Object> maps = new HashMap<String,Object>(); maps.put("bookId",bookId); maps.put("userId",userid); maps.put("bookType",booktype); List<BookScoreMongo> list = MongoServiceDAO.getInstance().queryForListByConExprMapWithOrderLimit(BookScoreMongo.class,maps,"",1); if(list != null && list.size() > 0){ return list.get(0); }else{ return null; } } public BookScoreMongo getScoreByBookidUserId(Long bookid,Integer userid,Integer booktype){ Map<String, Object> conditions = new HashMap<String, Object>(); conditions.put("bookId", bookid); conditions.put("userId", userid); conditions.put("bookType", booktype); List<BookScoreMongo> list = MongoServiceDAO.getInstance().queryForListByConExprMapWithOrderLimit(BookScoreMongo.class,conditions,"",1); if(list != null && list.size() >0){ return list.get(0); }else{ return null; } } public void updateByBookUserId(Long bookId,Integer userid,Long score,Integer booktype){ if(score != null && score > 0){ } } /** * 插入或者修改个人评分分数 * @param bookid * @param userid * @param score * @param booktype(1为原创,2为藏书) */ public void updateByBookidUserId(Long bookid,Integer userid,Long score,Integer booktype){ if(score != null && score >0){ BookScoreMongo bookScoreMongo = getScoreByBookidUserId(bookid,userid,booktype); if(bookScoreMongo != null){ if(score != bookScoreMongo.getScore()){ updateBookScoreMongoById(bookScoreMongo,score); //修改总分数 if(booktype.equals(1)){ originalBookManager.changScore(bookid,score,bookScoreMongo.getScore()); }else if(booktype.equals(2)){ paperBookManager.changScore(bookid,score,bookScoreMongo.getScore()); } } }else{ bookScoreMongo = new BookScoreMongo(); bookScoreMongo.setBookId(bookid); bookScoreMongo.setUserId(userid); bookScoreMongo.setScore(score); bookScoreMongo.setBookType(booktype); insertBookScoreMongo(bookScoreMongo); //修改总分数和评分总人数 if(booktype.equals(1)){ originalBookManager.addScoreSun(bookid,score); }else if(booktype.equals(2)){ paperBookManager.addScoreSun(bookid,score); } } } } } @SuppressWarnings("serial") public class BookScoreAction extends ActionSupport{ /**书籍ID*/ private int bookId; /**分数*/ private int score; /**类型 (如1是原创,2是藏书)*/ private int type; private int userId; /** * ids */ private String ids; @Autowired private BookScoreMongoManager bookScoreMongoManager; @Autowired private PaperBookManager paperBookManager; @Autowired private OriginalBookManager originalBookManager; public String getIds() { return ids; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public void setIds(String ids) { this.ids = ids; } protected final ObjectMapper mapper = new ObjectMapper(); /** * 对书进行评分Action */ public void insertScore() throws Exception{ if(userId != 0){ BookUserUtil.scored(userId,bookId,type,score); }else{ BookUserUtil.scored(RequestContext.getCurrUser().getId().intValue(),bookId,type,score); } Map<String, Object> scoreMap = new HashMap<String, Object>(); bookScoreMongoManager.updateByBookidUserId((long) bookId, RequestContext.getCurrUser().getId().intValue(), (long) score, type); BookScoreMongo bookScoreMongo = bookScoreMongoManager.getScoreByBookidUserId((long)bookId, RequestContext.getCurrUser().getId().intValue(), type); scoreMap.put("bookScoreMongo", bookScoreMongo); // 藏书 if (type == 2) { PaperBookMongo paperBookMongo = paperBookManager .getMongoBookById((long) bookId); scoreMap.put("paperBookMongo", paperBookMongo); } else if (type == 1) { OriginalBookMongo originalBookMongo = originalBookManager .getMongoBookById((long) bookId); scoreMap.put("originalBookMongo", originalBookMongo); } String result =mapper.writeValueAsString(scoreMap); Struts2Utils.renderJson(result); } /** * 根据登入userId获取用户对 原创/藏书的评分 */ public void getScoreByUser(){ Struts2Utils.renderJson(bookScoreMongoManager.getScoreByBookidUserId((long)bookId,RequestContext.getCurrUser().getId().intValue(),type)); } /** * 根据传入userId获取用户对 原创/藏书的评分 */ public void getScoreByOtherUser(){ Struts2Utils.renderJson(bookScoreMongoManager.getScoreByBookidUserId((long)bookId,userId,type)); } /** * 批量获取评分统计 */ // public void getStatisticList(){ // // List<Integer> params=null; // // if (ids != null && !"".equals(ids)) { // params = new ArrayList<Integer>(); // String[] idArr = ids.split(","); // for (int i = 0; i < idArr.length; i++) { // params.add(Integer.parseInt(idArr[i])); // } // } // //evaluationManager.get // Struts2Utils.renderJson(scoreManager.getScoreStatisticals(params, type)); // } public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } }