虛擬機安裝MongoDB請參看《CentOS7安裝MongoDB4》正則表達式
我使用的IDE是STS4,你們按照本身的習慣選擇便可。spring
關鍵是pom.xml要加入:mongodb
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
在application.properties中加入:數據庫
spring.data.mongodb.uri=mongodb://用戶名:密碼@IP:PORT/數據庫
實體類服務器
@Document(collection = "test_goods") publicclass GoodsEntity implements Serializable { privatestaticfinallongserialVersionUID = -805486477824888750L; @Id private String id; private String goodsName; privatelongcategoryId; privateintgoodsStatus; private String labels; //省略get、set方法 }
其餘都不解釋了,一看就懂,這裏要注意id這個字段。app
如上配置,加上註解@Id的狀況下,咱們新建一條Document的時候,不需額外設置,會自動生成一個以下圖的主鍵:分佈式
這是一個名爲」_id」的ObjectId類型的主鍵,12個字節的BSON類型字符串。ide
4字節是UNIX時間戳,3字節表示MongoDB服務器,2字節是生成ID的進程,3字節是隨機數。spring-boot
這麼作的好處是對分佈式友好。而且,由於id中包含時間戳,自然的就帶上了建立時間。咱們能夠經過測試
ObjectId id = new ObjectId(entity.getId()); System.out.println(id.getDate());
獲取建立時間。
固然了,若是咱們使用MongoDB是對傳統DB的一個補充,在系統中仍是但願將DB中的ID存入MongoDB的話,那就去除id字段的註解,處理的時候對ID字段作好設置便可。
Dao
@Component publicclass GoodsDao { @Autowired private MongoTemplate mongoTemplate; /** * 新建 * * @param entity * @return */ public GoodsEntity add(GoodsEntity entity) { returnmongoTemplate.save(entity); } /** * 根據ID修改 * * @param entity * @return */ public UpdateResult upd(GoodsEntity entity) { Query query = new Query(Criteria.where("id").is(entity.getId())); Update update = new Update().set("goodsName", entity.getGoodsName()).set("categoryId", entity.getCategoryId()) .set("goodsStatus", entity.getGoodsStatus()).set("labels", entity.getLabels()); returnmongoTemplate.updateFirst(query, update, GoodsEntity.class); } /** * 根據ID刪除 * * @param id * @return */ public DeleteResult delById(longid) { Query query = new Query(Criteria.where("id").is(id)); returnmongoTemplate.remove(query, GoodsEntity.class); } /** * 根據主鍵獲取詳情 * * @param id * @return */ public GoodsEntity getById(longid) { Query query = new Query(Criteria.where("id").is(id)); GoodsEntity entity = mongoTemplate.findOne(query, GoodsEntity.class); returnentity; } /** * 列出全部記錄 * * @return */ public List<GoodsEntity> listAll() { List<GoodsEntity> entities = mongoTemplate.find(new Query(), GoodsEntity.class); returnentities; } /** * 根據某字段使用正則表達式模糊查詢,且分頁、ID倒序 * * @param label * @param pageNumber * @param pageSize * @return */ public List<GoodsEntity> queryPageByLabel(String label, intpageNumber, intpageSize) { // 徹底匹配 // Pattern pattern = Pattern.compile("^" + label + "$", // Pattern.CASE_INSENSITIVE); // 右匹配 // Pattern pattern = Pattern.compile("^.*\"+label+\"$", // Pattern.CASE_INSENSITIVE); // 左匹配 // Pattern pattern = Pattern.compile("^\"+label+\".*$", // Pattern.CASE_INSENSITIVE); // 模糊匹配 Pattern pattern = Pattern.compile("^.*" + MongoDBUtils.escapeExprSpecialWord(label) + ".*$", Pattern.CASE_INSENSITIVE); Query query = new Query(Criteria.where("labels").regex(pattern)); // ID倒序 query.with(new Sort(Sort.Direction.DESC, "id")); // 分頁 PageRequest pageableRequest = PageRequest.of(pageNumber, pageSize); query.with(pageableRequest); returnmongoTemplate.find(query, GoodsEntity.class); } /** * 多查詢條件,分頁,ID倒序 * * @param entity * @param pageNumber * @param pageSize * @return */ public List<GoodsEntity> queryPage(GoodsEntity entity, intpageNumber, intpageSize) { Criteria criteria = new Criteria(); if (!StringUtils.isEmpty(entity.getGoodsName())) { Pattern pattern = Pattern.compile("^.*" + entity.getGoodsName() + ".*$", Pattern.CASE_INSENSITIVE); criteria.and("goodsName").regex(pattern); } if (!StringUtils.isEmpty(entity.getLabels())) { Pattern pattern = Pattern.compile("^.*" + entity.getLabels() + ".*$", Pattern.CASE_INSENSITIVE); criteria.and("labels").regex(pattern); } if (entity.getCategoryId() > 0) { criteria.and("categoryId").is(entity.getCategoryId()); } if (entity.getGoodsStatus() > 0) { criteria.and("goodsStatus").is(entity.getGoodsStatus()); } Query query = new Query(criteria); // 分頁&ID倒序 PageRequest pageableRequest = PageRequest.of(pageNumber, pageSize, Sort.Direction.DESC, "id"); query.with(pageableRequest); returnmongoTemplate.find(query, GoodsEntity.class); } }
我的感受基本覆蓋了大部分需求,再也不對代碼詳細解釋了。
主要是注意一下,我此次沒有使用ObjectId,而是用DB的ID,因此這裏的Entity的ID是long。
測試
@RunWith(SpringRunner.class) @SpringBootTest publicclass GoodsDaoTest { @Autowired private GoodsDao goodsDao; @Test publicvoid add() { GoodsEntity entity = new GoodsEntity(); entity.setId(3); // 若是使用ObjectId,就不須要額外處理ID字段了。 entity.setCategoryId(5); entity.setGoodsName("測試商品E"); entity.setGoodsStatus(1); entity.setLabels("a,b,c,*,d"); GoodsEntity newEntity = goodsDao.add(entity); JsonFormaterUtil.printFromObj(newEntity); } @Test publicvoid upd() { GoodsEntity entity = goodsDao.getById(1); entity.setLabels("a,b,c,d"); JsonFormaterUtil.printFromObj(goodsDao.upd(entity)); } @Test publicvoid del() { JsonFormaterUtil.printFromObj(goodsDao.delById(3)); } @Test publicvoid getById() { JsonFormaterUtil.printFromObj(goodsDao.getById(1)); } @Test publicvoid listAll() { JsonFormaterUtil.printFromObj(goodsDao.listAll()); } @Test publicvoid queryByLabel() { JsonFormaterUtil.printFromObj(goodsDao.queryPageByLabel("*", 0, 2)); } @Test publicvoid queryPage() { GoodsEntity entity = new GoodsEntity(); // entity.setCategoryId(5); entity.setGoodsName("測試商品"); // entity.setGoodsStatus(1); // entity.setLabels("a,b,c"); JsonFormaterUtil.printFromObj(goodsDao.queryPage(entity, 0, 10)); } }
沒什麼好說的。
日誌配置
由於我我的喜愛在控制檯打印出對DB操做的語句,因此對log配置進行了修改。
Spring Boot使用的是logback,在resources目錄下建立logback.xml文件,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定義日誌文件的存儲絕對路徑--> <property name="LOG_HOME" value="d:/" /> <!-- 控制檯輸出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} : %n%msg%n </pattern> </encoder> </appender> <!-- 按照天天生成日誌文件 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日誌文件輸出的文件名 --> <FileNamePattern>${LOG_HOME}/mongodbdemo.log.%d{yyyy-MM-dd}.log </FileNamePattern> <!--日誌文件保留天數 --> <MaxHistory>30</MaxHistory> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} : %msg%n </pattern> </encoder> <!--日誌文件最大的大小 --> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>10MB</MaxFileSize> </triggeringPolicy> </appender> <!-- 日誌輸出級別 --> <root level="ERROR"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> <!-- MongoDB日誌輸出 --> <logger name="org.springframework.data.mongodb.core.MongoTemplate" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT" /> </logger> </configuration>
關鍵點是配置MongoDB日誌輸出,其中name是輸出日誌的類,level設置成debug,纔會將執行的語句輸出出來,相似:
find using query: { "goodsName" : { "$regex" : "^.*測試商品.*$", "$options" : "i" } } fields: Document{{}} for class: class org.leo.mongodb.demo.entity.GoodsEntity in collection: test_goods
而加上additivity="false"是由於若是不加,上面的日誌會在控制檯上打印兩次。
其餘
經過正則表達式查詢的時候,會趕上一些特殊字符(*,?等),須要轉義一下,代碼以下:
publicclass MongoDBUtils { privatestaticfinal String[] fbsArr = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" }; /** * regex對輸入特殊字符轉義 * * @param keyword * @return */ publicstatic String escapeExprSpecialWord(String keyword) { if (!StringUtils.isEmpty(keyword)) { for (String key : fbsArr) { if (keyword.contains(key)) { keyword = keyword.replace(key, "\\" + key); } } } returnkeyword; } }
索引:
db.getCollection("test_goods").createIndex({ "categoryId": 1 }, { "name": "idx_goods_categoryid" })
爲categoryId建立索引,其中{ "categoryId": 1 }的1,表明按升序建立,-1表明降序。
建立複合索引,以下:
db.getCollection("test_goods").createIndex({ "categoryId": 1, "goodsStatus": -1 })
設置惟一索引,以下:
db.getCollection("test_goods").createIndex({ "categoryId": 1}, { "unique": true })