Spring Boot使用MongoDB

虚拟机安装MongoDB请参看《CentOS7安装MongoDB4》

我使用的IDE是STS4,大家按照自己的习惯选择即可。

关键是pom.xml要加入:


<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这个字段。

如上配置,加上注解@Id的情况下,我们新建一条Document的时候,不需额外设置,会自动生成一个如下图的主键:

Spring Boot使用MongoDB

这是一个名为”_id”的ObjectId类型的主键,12个字节的BSON类型字符串。

4字节是UNIX时间戳,3字节表示MongoDB服务器,2字节是生成ID的进程,3字节是随机数。

这么做的好处是对分布式友好。并且,因为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 })

猜你喜欢

转载自blog.51cto.com/15067227/2603603