前言:MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。支持的数据结构非常松散,是类似 json 的 bjson 格式,因此可以存储比较复杂的数据类型。其语法对面向对象语言比较友好,及其适用于java编程。

适用场景:

1,大量且无强关系型数据。--比如日志,缓存等

2,高频读写操作又对事务强制性要求较低。--比如实验性数据,测试数据等

3,轻查询重显示数据。比如可介于redis和mysql之间的做视图应用

环境:

springboot版本:2.2.5.RELEASE

mongodb版本:4.4.0  安装传送门

一、 配置

spring Boot 对mongodb进行了封装,配置很简单。

pom文件中引入jar:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

bootstrap.yml(application.properties)中引入配置

spring:
  data:
    mongodb:
      uri: mongodb://name:pwd@localhost:27017/dataname

//多个 IP 集群可以采用以下配置:
//spring.data.mongodb.uri=mongodb://user:pwd@ip1:port1,ip2:port2/database

二、spring boot中应用

2.1 数据实体(po)--比如日志统计类

@Document(collection = "tk_log")
public class TkLogMg {
	@Id
	private String id;
	private String logType;
	private String logName;
	private JSONObject tjJson;
	private Date beginTime;
	private Date endTime;

	@Transient
	private String diffTime;

//getter、setter省略
}

常用注释说明:

@Document

标注在实体类上,标明由mongodb来维护该表。

@Id

主键,不可重复,自带索引,需要自己生成并维护不重复的约束。

@Indexed

索引,加索引后以该字段为条件检索将大大提高速度。 

@Field

定义存储字段名。可以不加,不加的话默认以参数名为列名。

@Transient

被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。

@DBRef

设置对象的关联。类似于关系型数据库的外键

2.2 创建dao层--MongoRepository包含了丰富的数据操作

public interface TkLogMgDao extends MongoRepository<TkLogMg, String>{

	Page<TkLogMg> findByLogType(String logType,Pageable pageable);
	
	List<TkLogMg> findByBeginTimeLessThan(Date beginTime);
}

MongoRepository有以下常用方法:

count()统计总数
count(Example< S > example)条件统计总数
delete(T entities)通过对象信息删除某条数据
deleteById(ID id)通过id删除某条数据
deleteALL(Iterable<? extends T> entities)批量删除某条数据
deleteAll() 清空表中所有的数据
existsById(ID id) 判断数据是否存在
exists(Example< T > example) 判断某特定数据是否存在
findAll() 获取表中所有的数据
findAll(Sort sort) 获取表中所有的数据,按照某特定字段排序
findAll(Pageable pageAble) 获取表中所有的数据,分页查询
findAll(Example< T > example) 条件查询
findAll(Iterable ids) 条件查询
findAll(Example< T > example,Pageable pageable) 条件分页查询
findAll(Example< T > example,Sort sort) 条件查询排序
findOneById(ID id) 通过id查询一条数据
findOne(Example example) 通过条件查询一条数据

也支持mongodb源生语句---不建议使用,可读性差,如果数据的curd达到一定的复杂度,客观上已经不建议使用此技术。

GreaterThan(大于) 
findByAgeGreaterThan(int age) 
{"age" : {"$gt" : age}}
LessThan(小于) 
findByAgeLessThan(int age) 
{"age" : {"$lt" : age}}
Between(在...之间) 
findByAgeBetween(int from, int to) 
{"age" : {"$gt" : from, "$lt" : to}}
IsNotNull, NotNull(是否非空) 
findByFirstnameNotNull() 
{"age" : {"$ne" : null}}
IsNull, Null(是否为空) 
findByFirstnameNull() 
{"age" : null}
Like(模糊查询) 
findByFirstnameLike(String name) 
{"age" : age} ( age as regex)
(No keyword) findByFirstname(String name) 
{"age" : name}
Not(不包含) 
findByFirstnameNot(String name) 
{"age" : {"$ne" : name}}
Near(查询地理位置相近的) 
findByLocationNear(Point point) 
{"location" : {"$near" : [x,y]}}
Within(在地理位置范围内的) 
findByLocationWithin(Circle circle) 
{"location" : {"$within" : {"$center" : [ [x, y], distance]}}}
Within(在地理位置范围内的) 
findByLocationWithin(Box box) 
{"location" : {"$within" : {"$box" : [ [x1, y1], x2, y2]}}}

附上更多方法:

mono 支持spring.net springboot mongodb_mono 支持spring.net

mono 支持spring.net springboot mongodb_mono 支持spring.net_02

 2.3 service中使用--主要注意除了对MongoRepository的操作外,某些场景亦可使用MongoTemplate。

@Service
public class TkLogMgService {
    
    //1,无事务约束
    //2,save包含插入和修改,无id为插入,有id为覆盖修改
    public void save(TkLogMg mg) {
		tkLogMgDao.save(mg);
	}

    //查询单个
    public TkLogMg getById(String id) {
		Optional<TkLogMg> optional = tkLogMgDao.findById(id);
		if (optional.isPresent()) {
			return optional.get();
		} else {
			return null;
		}
	}
    
    //使用MongoRepository分页查询
    public Page<TkLogMg> page(Integer currPage, Integer pageSize, TkLogMg queryMg) {
		Sort sort = Sort.by(Sort.Direction.DESC, "num");
		PageRequest pageRequest = PageRequest.of(currPage - 1, pageSize, sort);
		TkLogMg mrMg = new TkLogMg();
		BeanUtils.copyProperties(queryMg, mrMg);
		ExampleMatcher matcher = ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) // 改变默认字符串匹配方式:模糊查询
				.withIgnoreCase(true) // 改变默认大小写忽略方式:忽略大小写
				.withMatcher("lot", ExampleMatcher.GenericPropertyMatchers.contains()) // 采用“包含匹配”的方式查询
				.withMatcher("num", ExampleMatcher.GenericPropertyMatchers.contains());
		Example<TkLogMg> example = Example.of(mrMg, matcher);
		Page<TkLogMg> all = matchRecomMgDao.findAll(example, pageRequest);
		return all;
	}

    //使用mongoTemplate查询列表
    public List<TkLogMg> loadLoseRecom(Date begin, String lot) {
		Query query = new Query();
		query.addCriteria(Criteria.where("bgTime").lt(begin).and("lot").is(lot));
		return mongoTemplate.find(query, TkLogMg.class);
	}

    @Autowired
	private TkLogMgDao tkLogMgDao;
    @Autowired
	private MongoTemplate mongoTemplate;
}

注意:mongodb整体上对查询的支持并不好,此处只距离说明MongoRepository和mongoTemplate的使用,更多的应用,单独写一篇。

三、数据输出处理

3.1 在action层的操作跟正常的数据操作无疑,这里不过多赘述。

3.2 主要说下关于分页操作的情况。

action中:

@Autowired
	private TkLogMgService tkLogMgService;
	
	@GetMapping("/showPage.html")
	public String recordPage(Integer curPage, String ln, String sid, ModelMap model) {
		curPage = curPage == null ? 1 : curPage;
		int pageSize = 15;
		TkLogMg queryMg = new TkLogMg();
		Page<TkLogMg > recordMgPage = tkLogMgService .page(curPage, pageSize, queryMg);
		PageQuery<TkLogMg> recordPage = new PageQuery<TkLogMg>(recordMgPage.getNumber(), "",
				recordMgPage.getTotalElements(), pageSize);
		model.addAttribute("recordPage", recordPage);
		return "/front/log/showPage";
	}

主要是对page对象的转化,由org.springframework.data.domain.Page转为org.beetl.sql.core.engine.PageQuery(此类为beetle中的分页类,亦可自定义分页类),目的是为了使前台分页得到统一。

自定义分页类如下:

import java.io.Serializable;
import java.util.List;

public class PageBo<T> implements Serializable{
	private static final long serialVersionUID = -3948389268046368059L;
	
	protected List<T> list;        //分页结果List
	protected int pageNumber;        //页数
	protected int totalPage;        //总页数
	protected int pageSize=15; 
	protected long totalRow;
	public  PageBo(){
		
	}
	public  PageBo(List<T> list,Integer pageNumber,int totalPage,long totalRow){
		this.list=list;
		this.pageNumber=pageNumber;
		this.totalPage=totalPage;
		this.totalRow=totalRow;
	}
	public List<T> getList() {
		return list;
	}
	public void setList(List<T> list) {
		this.list = list;
	}
	public int getPageNumber() {
		return pageNumber;
	}
	public void setPageNumber(int pageNumber) {
		this.pageNumber = pageNumber;
	}
	public int getTotalPage() {
		return totalPage;
	}
	public long getTotalRow() {
		return totalRow;
	}
	public int getPageSize() {
		return pageSize;
	}
	
}

3.3 页面中的使用和常规使用一样即可。