Spring Boot使用MongoDB

虛擬機安裝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的時候,不需額外設置,會自動生成一個以下圖的主鍵:分佈式

Spring Boot使用MongoDB

這是一個名爲」_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 })
相關文章
相關標籤/搜索