以前只听过非关系型数据库(nosql),最近公司的新项目要用到,才知道Mongodb。用的框架是spring mvc,这个比较熟没问题。但是mongodb可是第一次听说啊,没人教,只能自己边学边做。下面是自己的一点学习小心得,希望更多像我一样的入门新手看了能有点感受。
一:mongodb的实体类建立:
例如:
@Document(collection="SYS_USER") //指定表名,第一次自动创建
public class User {
public User(){
this.id = ObjectId.get();
}
@Id
private ObjectId id;
private String firstName;
private String lastName;
private String username;
private String password;
@DBRef //引用式关系,数据库中存储的是role的id
@CascadeSave //级联保存
private Role role;
public ObjectId getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
如果是内嵌式:就是@Embedded。若有些字段不需要存储进数据库表中,则使用@Tranisent
二:dao层
这个是网上copy的,没办法新手啊,只能引用下前辈的东西了。重要的是要懂其中的意思
public class MongoDbBaseDao<T> {
/**
* 日志对象
*/
protected Logger log = LoggerFactory.getLogger(getClass());
@Autowired
MongoOperations mongoOperation;
/**
* 实体类类型(由构造方法自动赋值)
*/
private Class<?> entityClass;
/**
* 构造方法,根据实例类自动获取实体类类型
*/
public MongoDbBaseDao() {
entityClass = Reflections.getClassGenricType(getClass());
}
/**
* 保存一个对象
* @param t
*/
public void save(T t){
log.info("[Mongo Dao ]save:" + t);
this.mongoOperation.save(t);
}
/**
* 根据Id从Collection中查询对象
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public T queryById(String id) {
Query query = new Query();
Criteria criteria = Criteria.where("_id").is(id);
query.addCriteria(criteria);
log.info("[Mongo Dao ]queryById:" + query);
return (T)this.mongoOperation.findOne(query, this.entityClass);
}
/**
* 根据条件查询集合
* @param query 查询条件
* @return
*/
@SuppressWarnings("unchecked")
public List<T> queryList(Query query){
log.info("[Mongo Dao ]queryList:" + query);
return (List<T>) this.mongoOperation.find(query, this.entityClass);
}
/**
* 通过条件查询单个实体
* @param query 查询条件
* @return
*/
@SuppressWarnings("unchecked")
public T queryOne(Query query){
log.info("[Mongo Dao ]queryOne:" + query);
return (T)this.mongoOperation.findOne(query, this.entityClass);
}
/**
* 根据条件查询库中符合记录的总数,为分页查询服务
* @param query
* @return
*/
public Long count(Query query){
log.info("[Mongo Dao ]queryPageCount:" + query);
return this.mongoOperation.count(query, this.entityClass);
}
/**
* 分页
* @param page
* @param query
* @return
*/
@SuppressWarnings("unchecked")
public Page<T> findPage(Page<T> page,Query query){
// get count
if (!page.isDisabled() && !page.isNotCount()){
page.setCount(count(query));
if (page.getCount() < 1) {
return page;
}
}
// set page
if (!page.isDisabled()){
query.skip(page.getFirstResult());
query.limit(page.getMaxResults());
}
// order by
if (StringUtils.isNotBlank(page.getOrderBy())){
for (String order : StringUtils.split(page.getOrderBy(), ",")){
String[] o = StringUtils.split(order, " ");
if (o.length==1){
query.with(new Sort(Sort.Direction.DESC, o[0]));
}else if (o.length==2){
if ("DESC".equals(o[1].toUpperCase())){
query.with(new Sort(Sort.Direction.DESC, o[0]));
}else{
query.with(new Sort(Sort.Direction.ASC, o[0]));
}
}
}
}
List<T> list = (List<T>) this.mongoOperation.find(query, this.entityClass);
page.setList(list);
return page;
}
/**
* 根据Id删除用户
* @param id
*/
public void deleteById(String id) {
Criteria criteria = Criteria.where("_id").in(id);
if (null != criteria) {
Query query = new Query(criteria);
log.info("[Mongo Dao ]deleteById:" + query);
if (null != query && this.queryOne(query) != null) {
this.delete(query);
}
}
}
public void delete(T t) {
log.info("[Mongo Dao ]delete:" + t);
this.mongoOperation.remove(t);
}
public void delete(Query query) {
log.info("[Mongo Dao ]delete query:" + query);
this.mongoOperation.remove(query);
}
/**
* 更新满足条件的第一个记录
* @param query
* @param update
*/
public void updateFirst(Query query, Update update) {
log.info("[Mongo Dao ]updateFirst:query(" + query + "),update(" + update + ")");
this.mongoOperation.updateFirst(query, update, this.entityClass);
}
/**
* 更新满足条件的所有记录
* @param query
* @param update
*/
public void updateMulti(Query query, Update update){
log.info("[Mongo Dao ]updateMulti:query(" + query + "),update(" + update + ")");
this.mongoOperation.updateMulti(query, update, this.entityClass);
}
/**
* 查找更新,如果没有找到符合的记录,则将更新的记录插入库中
* @param query
* @param update
*/
public void updateInser(Query query, Update update){
log.info("[Mongo Dao ]updateInser:query(" + query + "),update(" + update + ")");
this.mongoOperation.upsert(query, update, this.entityClass);
}
/**
* delete
* @param <T>
* @param entityids
* @return
*/
public int delete(String... entityids) {
this.mongoOperation.remove(Query.query(Criteria.where("_id").in(Arrays.asList(entityids))), this.entityClass);
return entityids.length;
}
public int update( String[] fields, Object[] fieldValues, String id) {
WriteResult result = this.mongoOperation.updateFirst(new Query(where("_id").is(id)), setFieldValue(fields, fieldValues), this.entityClass);
CommandResult commandResult = result.getLastError();
if(commandResult.ok()){
return 1;
}
throw new RuntimeException(commandResult.getErrorMessage());
}
public static Update setFieldValue( String[] fields, Object[] fieldValues){
Update update = new Update();
for (int i = 0; i < fieldValues.length; i++) {
update.set(fields[i], fieldValues[i]);
}
return update;
}
/**
* 更新
* @param id
* @param values
*/
public void update(String id, Map<String, Object> values) {
Query query = Query.query(Criteria.where("_id").is(id));
Update update = new Update();
MongoGenericDaoUtil.bindUpdateFieldValue(update, values);
this.mongoOperation.updateFirst(query, update, entityClass);
}
/**
* 根据ID查询
* @param id
* @param fields
* @return
*/
@SuppressWarnings("unchecked")
public T get(String id, Set<String> fields) {
Query query = Query.query(Criteria.where("_id").is(id));
MongoGenericDaoUtil.bindFields(query, fields);
return (T) this.mongoOperation.findOne(query, entityClass);
}
}
三:service层:
写一个实现类userRepository实现上面的dao,service中引用实现类userRepository。
书写实现功能要用到的方法即可。
例如:
/**
* id查询
* @return
*/
public User findById(String id){
return userRepository.queryById(id);
}
/**
* 首页查询所有
* @return
*/
public List<User> findAllList(){
Query query = new Query();
return userRepository.queryList(query);
}
重点的是条件查询:
所有的查询条件都汇聚到query对象中:
1——如果是实体User中的基本属性:
query.addCriteria(Criteria.where("name").regex(user,getName(),"i"));
2——如果是实体中的引用对象(role或者role的list集合):
query.addCriteria(Criteria.where("role.$id").regex(uid,"i"));//DBRef查询,只能通过引用对象的ID查询,其它字段则无效。注意$符号
3——如果是实体中的内嵌对象(适用于单个实体和list集合):
query.addCriteria(Criteria.where("role.name").regex(role.getName(),"i"));//直接对象变量名.对象属性即可
分页查询:
例如:
public Page<Module> findPage(Page<Module> page,Module module){
Query query = new Query();
query.addCriteria(Criteria.where("delFlag").is("0"));
//时间查询
if(module.getOdate1()!=null&&module.getOdate2()!=null){
query.addCriteria(Criteria.where("onlinedate").gte(module.getOdate1()).lte(module.getOdate2()));//日期区间
}
if(module.getMdate1()!=null&&module.getMdate2()!=null){
query.addCriteria(Criteria.where("maintenancedate").gte(module.getMdate1()).lte(module.getMdate2()));//与该交维日期
}
page.setOrderBy("modulecode");//排序
return moduleRepository.findPage(page, query);
}
其中的Page对象:
package com.aspire.ops.common.persistence;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import com.aspire.ops.common.config.Global;
import com.aspire.ops.common.utils.CookieUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* 分页类
* @author ThinkGem
* @version 2013-7-2
* @param <T>
*/
public class Page<T> {
private int pageNo = 1; // 当前页码
private int pageSize = Integer.valueOf(Global.getConfig("page.pageSize")); // 页面大小,设置为“-1”表示不进行分页(分页无效)
private long count;// 总记录数,设置为“-1”表示不查询总数
private int first;// 首页索引
private int last;// 尾页索引
private int prev;// 上一页索引
private int next;// 下一页索引
private boolean firstPage;//是否是第一页
private boolean lastPage;//是否是最后一页
private int length = 8;// 显示页面长度
private int slider = 1;// 前后显示页面长度
private List<T> list = new ArrayList<T>();
private String orderBy = ""; // 标准查询有效, 实例: updatedate desc, name asc
private String funcName = "page"; // 设置点击页码调用的js函数名称,默认为page,在一页有多个分页对象时使用。
private String message = ""; // 设置提示消息,显示在“共n条”之后
public Page() {
this.pageSize = -1;
}
/**
* 构造方法
* @param request 传递 repage 参数,来记住页码
* @param response 用于设置 Cookie,记住页码
*/
public Page(HttpServletRequest request, HttpServletResponse response){
this(request, response, -2);
}
/**
* 构造方法
* @param request 传递 repage 参数,来记住页码
* @param response 用于设置 Cookie,记住页码
* @param defaultPageSize 默认分页大小,如果传递 -1 则为不分页,返回所有数据
*/
public Page(HttpServletRequest request, HttpServletResponse response, int defaultPageSize){
// 设置页码参数(传递repage参数,来记住页码)
String no = request.getParameter("pageNo");
if (StringUtils.isNumeric(no)){
CookieUtils.setCookie(response, "pageNo", no);
this.setPageNo(Integer.parseInt(no));
}else if (request.getParameter("repage")!=null){
no = CookieUtils.getCookie(request, "pageNo");
if (StringUtils.isNumeric(no)){
this.setPageNo(Integer.parseInt(no));
}
}
// 设置页面大小参数(传递repage参数,来记住页码大小)
String size = request.getParameter("pageSize");
if (StringUtils.isNumeric(size)){
CookieUtils.setCookie(response, "pageSize", size);
this.setPageSize(Integer.parseInt(size));
}else if (request.getParameter("repage")!=null){
no = CookieUtils.getCookie(request, "pageSize");
if (StringUtils.isNumeric(size)){
this.setPageSize(Integer.parseInt(size));
}
}else if (defaultPageSize != -2){
this.pageSize = defaultPageSize;
}
// 设置排序参数
String orderBy = request.getParameter("orderBy");
if (StringUtils.isNotBlank(orderBy)){
this.setOrderBy(orderBy);
}
}
/**
* 构造方法
* @param pageNo 当前页码
* @param pageSize 分页大小
*/
public Page(int pageNo, int pageSize) {
this(pageNo, pageSize, 0);
}
/**
* 构造方法
* @param pageNo 当前页码
* @param pageSize 分页大小
* @param count 数据条数
*/
public Page(int pageNo, int pageSize, long count) {
this(pageNo, pageSize, count, new ArrayList<T>());
}
/**
* 构造方法
* @param pageNo 当前页码
* @param pageSize 分页大小
* @param count 数据条数
* @param list 本页数据对象列表
*/
public Page(int pageNo, int pageSize, long count, List<T> list) {
this.setCount(count);
this.setPageNo(pageNo);
this.pageSize = pageSize;
this.setList(list);
}
/**
* 初始化参数
*/
public void initialize(){
//1
this.first = 1;
this.last = (int)(count / (this.pageSize < 1 ? 20 : this.pageSize) + first - 1);
if (this.count % this.pageSize != 0 || this.last == 0) {
this.last++;
}
if (this.last < this.first) {
this.last = this.first;
}
if (this.pageNo <= 1) {
this.pageNo = this.first;
this.firstPage=true;
}
if (this.pageNo >= this.last) {
this.pageNo = this.last;
this.lastPage=true;
}
if (this.pageNo < this.last - 1) {
this.next = this.pageNo + 1;
} else {
this.next = this.last;
}
if (this.pageNo > 1) {
this.prev = this.pageNo - 1;
} else {
this.prev = this.first;
}
//2
if (this.pageNo < this.first) {// 如果当前页小于首页
this.pageNo = this.first;
}
if (this.pageNo > this.last) {// 如果当前页大于尾页
this.pageNo = this.last;
}
}
/**
* 默认输出当前分页标签
* <div class="page">${page}</div>
*/
@Override
public String toString() {
initialize();
StringBuilder sb = new StringBuilder();
if (pageNo == first) {// 如果是首页
sb.append("<li class=\"disabled\"><a href=\"javascript:\">« 上一页</a></li>\n");
} else {
sb.append("<li><a href=\"javascript:\" οnclick=\""+funcName+"("+prev+","+pageSize+");\">« 上一页</a></li>\n");
}
int begin = pageNo - (length / 2);
if (begin < first) {
begin = first;
}
int end = begin + length - 1;
if (end >= last) {
end = last;
begin = end - length + 1;
if (begin < first) {
begin = first;
}
}
if (begin > first) {
int i = 0;
for (i = first; i < first + slider && i < begin; i++) {
sb.append("<li><a href=\"javascript:\" οnclick=\""+funcName+"("+i+","+pageSize+");\">"
+ (i + 1 - first) + "</a></li>\n");
}
if (i < begin) {
sb.append("<li class=\"disabled\"><a href=\"javascript:\">...</a></li>\n");
}
}
for (int i = begin; i <= end; i++) {
if (i == pageNo) {
sb.append("<li class=\"active\"><a href=\"javascript:\">" + (i + 1 - first)
+ "</a></li>\n");
} else {
sb.append("<li><a href=\"javascript:\" οnclick=\""+funcName+"("+i+","+pageSize+");\">"
+ (i + 1 - first) + "</a></li>\n");
}
}
if (last - end > slider) {
sb.append("<li class=\"disabled\"><a href=\"javascript:\">...</a></li>\n");
end = last - slider;
}
for (int i = end + 1; i <= last; i++) {
sb.append("<li><a href=\"javascript:\" οnclick=\""+funcName+"("+i+","+pageSize+");\">"
+ (i + 1 - first) + "</a></li>\n");
}
if (pageNo == last) {
sb.append("<li class=\"disabled\"><a href=\"javascript:\">下一页 »</a></li>\n");
} else {
sb.append("<li><a href=\"javascript:\" οnclick=\""+funcName+"("+next+","+pageSize+");\">"
+ "下一页 »</a></li>\n");
}
sb.append("<li class=\"disabled controls\"><a href=\"javascript:\">当前 ");
sb.append("<input type=\"text\" value=\""+pageNo+"\" οnkeypress=\"var e=window.event||this;var c=e.keyCode||e.which;if(c==13)");
sb.append(funcName+"(this.value,"+pageSize+");\" οnclick=\"this.select();\"/> / ");
sb.append("<input type=\"text\" value=\""+pageSize+"\" οnkeypress=\"var e=window.event||this;var c=e.keyCode||e.which;if(c==13)");
sb.append(funcName+"("+pageNo+",this.value);\" οnclick=\"this.select();\"/> 条,");
sb.append("共 " + count + " 条"+(message!=null?message:"")+"</a><li>\n");
sb.insert(0,"<ul>\n").append("</ul>\n");
sb.append("<div style=\"clear:both;\"></div>");
// sb.insert(0,"<div class=\"page\">\n").append("</div>\n");
return sb.toString();
}
/**
* 获取分页HTML代码
* @return
*/
public String getHtml(){
return toString();
}
// public static void main(String[] args) {
// Page<String> p = new Page<String>(3, 3);
// System.out.println(p);
// System.out.println("首页:"+p.getFirst());
// System.out.println("尾页:"+p.getLast());
// System.out.println("上页:"+p.getPrev());
// System.out.println("下页:"+p.getNext());
// }
/**
* 获取设置总数
* @return
*/
public long getCount() {
return count;
}
/**
* 设置数据总数
* @param count
*/
public void setCount(long count) {
this.count = count;
if (pageSize >= count){
pageNo = 1;
}
}
/**
* 获取当前页码
* @return
*/
public int getPageNo() {
return pageNo;
}
/**
* 设置当前页码
* @param pageNo
*/
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
/**
* 获取页面大小
* @return
*/
public int getPageSize() {
return pageSize;
}
/**
* 设置页面大小(最大500)
* @param pageSize
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize <= 0 ? 10 : pageSize;// > 500 ? 500 : pageSize;
}
/**
* 首页索引
* @return
*/
@JsonIgnore
public int getFirst() {
return first;
}
/**
* 尾页索引
* @return
*/
@JsonIgnore
public int getLast() {
return last;
}
/**
* 获取页面总数
* @return getLast();
*/
@JsonIgnore
public int getTotalPage() {
return getLast();
}
/**
* 是否为第一页
* @return
*/
@JsonIgnore
public boolean isFirstPage() {
return firstPage;
}
/**
* 是否为最后一页
* @return
*/
@JsonIgnore
public boolean isLastPage() {
return lastPage;
}
/**
* 上一页索引值
* @return
*/
@JsonIgnore
public int getPrev() {
if (isFirstPage()) {
return pageNo;
} else {
return pageNo - 1;
}
}
/**
* 下一页索引值
* @return
*/
@JsonIgnore
public int getNext() {
if (isLastPage()) {
return pageNo;
} else {
return pageNo + 1;
}
}
/**
* 获取本页数据对象列表
* @return List<T>
*/
public List<T> getList() {
return list;
}
/**
* 设置本页数据对象列表
* @param list
*/
public Page<T> setList(List<T> list) {
this.list = list;
return this;
}
/**
* 获取查询排序字符串
* @return
*/
@JsonIgnore
public String getOrderBy() {
return orderBy;
}
/**
* 设置查询排序,标准查询有效, 实例: updatedate desc, name asc
*/
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
/**
* 获取点击页码调用的js函数名称
* function ${page.funcName}(pageNo){location="${ctx}/list-${category.id}${urlSuffix}?pageNo="+i;}
* @return
*/
@JsonIgnore
public String getFuncName() {
return funcName;
}
/**
* 设置点击页码调用的js函数名称,默认为page,在一页有多个分页对象时使用。
* @param funcName 默认为page
*/
public void setFuncName(String funcName) {
this.funcName = funcName;
}
/**
* 设置提示消息,显示在“共n条”之后
* @param message
*/
public void setMessage(String message) {
this.message = message;
}
/**
* 分页是否有效
* @return this.pageSize==-1
*/
@JsonIgnore
public boolean isDisabled() {
return this.pageSize==-1;
}
/**
* 是否进行总数统计
* @return this.count==-1
*/
@JsonIgnore
public boolean isNotCount() {
return this.count==-1;
}
/**
* 获取 Hibernate FirstResult
*/
public int getFirstResult(){
int firstResult = (getPageNo() - 1) * getPageSize();
if (firstResult >= getCount()) {
firstResult = 0;
}
return firstResult;
}
public int getLastResult(){
int lastResult = getFirstResult()+getMaxResults();
if(lastResult>getCount()) {
lastResult =(int) getCount();
}
return lastResult;
}
/**
* 获取 Hibernate MaxResults
*/
public int getMaxResults(){
return getPageSize();
}
}
四:controller层:
例如:
@RequestMapping
public String listModule(Module module,HttpServletRequest request,HttpServletResponse response,Model model){
Page<Module> page = moduleService.findPage(new Page<Module>(request, response), module);
model.addAttribute("page", page);
model.addAttribute("modulequery", module);
return "mongodb/module/moduleQueryList";
}