实战:五

4.16

实现数据字典

后端接口部分

/**
 * 为了实现数据字典,这个方法用来查找对应父id的子id
 *
 * @param id
 * @return
 */
@ApiOperation("根据数据id查询子数据列表")
@GetMapping("findChildData/{id}")
public Result findChildData(@PathVariable Long id) {
    List<Dict> childData = dictService.findChildData(id);
    return Result.ok(childData);
}
//service层部分。用于判断该数据是否还有子节点,是否还需要继续下沿。
/**
 * 根据传进的id,查询parent_id为此id的所有数据。
 * @param id
 * @return
 */
@Override
public List<Dict> findChildData(Long id) {
    QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();
    dictQueryWrapper.eq("parent_id",id);
    List<Dict> dicts = baseMapper.selectList(dictQueryWrapper);
    //list集合中每个数据判断是否还有子节点
    for (Dict dict : dicts) {
        //根据当前字段的id判断他有没有子节点。
        // 没有->false;有->true
        dict.setHasChildren(isHasChildren(dict.getId()));
    }
    return dicts;
}

/**
 * 用来判断数据是否有子节点。
 * @param id
 * @return
 * /
private boolean isHasChildren(Long id){
    QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();
    dictQueryWrapper.eq("parent_id",id);
    Integer integer = baseMapper.selectCount(dictQueryWrapper);
    return integer>0;
}

前端部分

首先定义router

{
    path: '/cmn',
    component: Layout,
    redirect: '/cmn/list',
    name: '数据管理',
    meta: { title: '数据管理', icon: 'example' },
    alwaysShow:true,//如果只有一个子模块也会单独列出。flase时不会。
    children: [
      {
        path: 'list',
        name: '数据字典',
        component: () => import('@/views/dict/list'),
        meta: { title: '数据字典', icon: 'table' }
      },
    ]
  },

api/index定义接口信息

import request from '@/utils/request'
export default {
  //数据列表方法
  dictList(id){
    return request({
      url:`/admin/cmn/dict/findChildData/${id}`,
      method:"get",
    })
  }
}

页面渲染

基于Element-ui完成的页面渲染。

<div>
    <el-table
      :data="list"
      style="width: 100%"
      row-key="id"
      border
      lazy
      :load="getChildrens"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column label="名称" width="230" align="left">
        <template slot-scope="scope">
          <span>{{ scope.row.name }}</span>
        </template>
      </el-table-column>

      <el-table-column label="编码" width="220">
        <template slot-scope="{ row }">
          {{ row.dictCode }}
        </template>
      </el-table-column>
      <el-table-column label="值" width="230" align="left">
        <template slot-scope="scope">
          <span>{{ scope.row.value }}</span>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" align="center">
        <template slot-scope="scope">
          <span>{{ scope.row.createTime }}</span>
        </template>
      </el-table-column>
    </el-table>
  </div>
methods: {
    getDictList: function (id) {
        dict.dictList(id).then((response) => {
            this.list = response.data;
        });
    },
        getChildrens:function(tree, treeNode, resolve) {
            dict.dictList(tree.id).then((response) => {
                resolve(response.data);
            });
        },
},
    //生命周期 - 创建完成(可以访问当前this实例)
    created() {
        this.getDictList(1);
    },

EasyExcel

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。

  • 引入依赖

    <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.1.1</version>
    </dependency>
    
  • 需要一个实体类

    @Data
    //不能存在有参构造方法,不会读取时会报错。
    public class UserData {
        @ExcelProperty(value = "用户编号",index = 0)
        private int uid;
        @ExcelProperty(value = "用户名称",index = 1)
        private String uname;
    }
    
  • 写操作逻辑

    public static void main(String[] args) {
        //设置文件地址和文件名
        String filename="G:\\excel\\01.xlsx";
        //构建一个数据的list集合
        ArrayList<UserData> userData = new ArrayList<UserData>();
        for (int i = 0; i < 10; i++) {
            UserData userData1 = new UserData(i, "hello" + i);
            userData.add(userData1);
        }
        //需要指定地址,数据类型,表别名,数据。
        EasyExcel.write(filename,UserData.class).sheet("用户信息")
            .doWrite(userData);
    }
    
  • 读操作逻辑

    需要一个监督类

    public class ExcelListen extends AnalysisEventListener<UserData> {
        /**
         * 一行一行读取内容
         */
        @Override
        public void invoke(UserData userData, AnalysisContext analysisContext) {
            System.out.println(userData);
        }
    
        public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
    
            System.out.println("表头信息:"+headMap);
        }
    
        /**
         * 读取后执行的方法
         * @param analysisContext
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    
        }
    }
    

    读取的逻辑

    public class TestRead {
        public static void main(String[] args) {
            //设置读取文件的位置。
            String filename = "G:\\excel\\01.xlsx";
            //调用方法,参数:文件地址、文件类型、监听器。
            EasyExcel.read(filename,UserData.class, new ExcelListen()).sheet().doRead();
        }
    }
    

上传和下载文件

下载

@Override
public void export(HttpServletResponse response) {
    //设置下载的信息
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
    String fileName = "dict";
    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    //查询数据库
    List<Dict> dictList = baseMapper.selectList(null);
    ArrayList<DictEeVo> arrayList = new ArrayList();
    //将dict的id复制给dicteevo
    for (Dict dict : dictList) {
        DictEeVo dictEeVo = new DictEeVo();
        BeanUtils.copyProperties(dict,dictEeVo);
        arrayList.add(dictEeVo);
    }

    //Excel写
    try {
        EasyExcel.write(response.getOutputStream(), DictEeVo.class)
            .sheet("dict")
            .doWrite(arrayList);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

上传

//controller
/**
 * 用于向服务器端提交内容
 */
@ApiOperation("上传数据字典")
@PostMapping("importData")
public Result importData(MultipartFile file) {//通过MultipartFile来接收文件
    dictService.importData(file);
    return Result.ok();
}
//service
/**
 * 将上传的excel写入数据库
 * @param file
 */
@Override
public void importData(MultipartFile file) {
    try {
        //使用EasyExcel的read方法一行一行的读
        EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet().doRead();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//监听器
public class DictListener extends AnalysisEventListener<DictEeVo> {

    private DictMapper dictMapper;

    public DictListener(DictMapper dictMapper) {
        this.dictMapper = dictMapper;
    }

    @Override
    public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
        //将DictEeVo转换为Dict对象
        Dict dict = new Dict();
        BeanUtils.copyProperties(dictEeVo,dict);
        //调用数据库方法
        dictMapper.insert(dict);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

前端

<div class="el-toolbar">
    <div class="el-toolbar-body" style="justify-content: flex-start">
        <el-button type="text" @click="exportData"
                   ><i class="fa fa-plus" /> 导出</el-button
            >
        <el-button type="text" @click="importData"
                   ><i class="fa fa-plus" /> 导入</el-button
            >
    </div>

    <el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px">
        <el-form label-position="right" label-width="170px">
            <el-form-item label="文件">
                <el-upload
                           :multiple="false"
                           :on-success="onUploadSuccess"
                           :action="'http://localhost:8202/admin/cmn/dict/importData'"
                           class="upload-demo"
                           >
                    <el-button size="small" type="primary">点击上传</el-button>
                    <div slot="tip" class="el-upload__tip">
                        只能上传exls文件,且不超过500kb
                    </div>
                </el-upload>
            </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
            <el-button @click="dialogImportVisible = false"> 取消 </el-button>
        </div>
    </el-dialog>
    //上传文件(导入数据)的方法
    importData: function () {
        this.dialogImportVisible=true;
    },
    //上传成功的方法
    onUploadSuccess:function(){
        //关闭弹框
        this.dialogImportVisible=false;
        //刷新页面
        this.getDictList(1);
    }

为数据字典添加缓存

Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)

  • 导入依赖

    <!-- redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <!-- spring2.X集成redis所需common-pool2-->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.6.0</version>
    </dependency>
    
  • 编写配置类

    @Configuration
    @EnableCaching
    public class RedisConfig {
        /**
         * 自定义key规则
         *
         * @return
         */
        @Bean
        public KeyGenerator keyGenerator() {
            return (target, method, params) -> {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            };
        }
    
        /**
         * 设置RedisTemplate规则
         *
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            //序列号key value
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        /**
         * 设置CacheManager缓存规则
         *
         * @param factory
         * @return
         */
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory factory) {
            RedisSerializer<String> redisSerializer = new StringRedisSerializer();
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            // 配置序列化(解决乱码的问题),过期时间600秒
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
    
            RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
            return cacheManager;
        }
    
    
    }
    
    
    • 使用Spring Cache的注解完成缓存

      注解名 描述 参数
      @Cacheable 根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。 value:缓存名,必填,它指定了你的缓存存放在哪块命名空间。cacheNames:与 value 差不多,二选一即可。key:可选属性,可以使用 SpEL 标签自定义缓存的key 。
      @CachePut 使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。 value:缓存名,必填,它指定了你的缓存存放在哪块命名空间。cacheNames:与 value 差不多,二选一即可。key:可选属性,可以使用 SpEL 标签自定义缓存的key 。
      @CacheEvict 使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上 value:缓存名,必填,它指定了你的缓存存放在哪块命名空间。cacheNames:与 value 差不多,二选一即可。key:可选属性,可以使用 SpEL 标签自定义缓存的key。allEntries:是否清空所有缓存,默认为 false。如果指定为true,则方法调用后将立即清空所有的缓存。 beforeInvocation:是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存。
    • 修改service层方法

      @Override
      @Cacheable(value = "dict",keyGenerator = "keyGenerator")//添加上此注解。
      public List<Dict> findChildData(Long id) {
          QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();
          dictQueryWrapper.eq("parent_id", id);
          List<Dict> dicts = baseMapper.selectList(dictQueryWrapper);
          //list集合中每个数据判断是否还有子节点
          for (Dict dict : dicts) {
              //根据当前字段的id判断他有没有子节点。
              // 没有->false;有->true
              dict.setHasChildren(isHasChildren(dict.getId()));
          }
          return dicts;
      }
      

    MongDb

    NoSQL(NoSQL = Not Only SQL),意即反SQL运动,指的是非关系型的数据库,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于目前铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。

    为什幺使用NoSQL :

    • 对数据库高并发读写。
    • 对海量数据的高效率存储和访问。
    • 对数据库的高可扩展性和高可用性。

    弱点:

    • 数据库事务一致性需求
    • 数据库的写实时性和读实时性需求
    • 对复杂的SQL查询,特别是多表关联查询的需求

    什么是MongoDB

    MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

    在高负载的情况下,添加更多的节点,可以保证服务器性能。

    MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

    MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

    安装MongDB

    • 拉取镜像

      docker pull mongo:latest
      
    • 创建并启动容器

      docker run -d --restart=always -p 27017:27017 --name mymongo -v /data/db:/data/db -d mongo
      

      p67


4.17

查漏补缺:MongoDB

传统的关系型数据库(如MySQL),在数据操作的“三高”需求以及应对Web2.0的网站需求面前,显得力不从心。

解释:“三高”需求:

  • High performance - 对数据库高并发读写的需求。

  • Huge Storage - 对海量数据的高效率存储和访问的需求。

  • High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求。

而MongoDB可应对“三高”需求。

具体的应用场景如:

1)社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。

2)游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。

3)物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将

订单所有的变更读取出来。

4)物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。

5)视频直播,使用 MongoDB 存储用户信息、点赞互动信息等。

这些应用场景中,数据操作方面的共同特点是:

(1)数据量大

(2)写入操作频繁(读写都很频繁)

(3)价值较低的数据,对事务性要求不高

对于这样的数据,我们更适合使用MongoDB来实现数据的存储。

什么时候选择MongoDB

  • 在架构选型上,除了上述的三个特点外,如果你还犹豫是否要选择它?可以考虑以下的一些问题:

  • 应用不需要事务及复杂 join 支持

  • 新应用,需求会变,数据模型无法确定,想快速迭代开发

  • 应用需要2000-3000以上的读写QPS(更高也可以)

  • 应用需要TB甚至 PB 级别数据存储

  • 应用发展迅速,需要能快速水平扩展

  • 应用要求存储的数据不丢失

  • 应用需要99.999%高可用

  • 应用需要大量的地理位置查询、文本查询

如果上述有1个符合,可以考虑 MongoDB,2个及以上的符合,选择 MongoDB 绝不会后悔。


MongoDB简介

MongoDB是一个开源、高性能、无模式的文档型数据库,当初的设计就是用于简化开发和方便扩展,是NoSQL数据库产品中的一种。是最像关系型数据库(MySQL)的非关系型数据库。

它支持的数据结构非常松散,是一种类似于 JSON 的 格式叫BSON,所以它既可以存储比较复杂的数据类型,又相当的灵活。

MongoDB中的记录是一个文档,它是一个由字段和值对(fifield:value)组成的数据结构。MongoDB文档类似于JSON对象,即一个文档认为就是一个对象。字段的数据类型是字符型,它的值除了使用基本的一些类型外,还可以包括其他文档、普通数组和文档数组。

image-20220417205804568

image-20220417205841262


MongoDB的特点

(1)高性能

MongoDB提供高性能的数据持久性。特别是,

对嵌入式数据模型的支持减少了数据库系统上的I/O活动。

索引支持更快的查询,并且可以包含来自嵌入式文档和数组的键。(文本索引解决搜索的需求、TTL索引解决历史数据自动过期的需求、地

理位置索引可用于构建各种 O2O 应用)

mmapv1、wiredtiger、mongorocks(rocksdb)、in-memory 等多引擎支持满足各种场景需求。

Gridfs解决文件存储的需求。

(2)高可用性:

MongoDB的复制工具称为副本集(replica set),它可提供自动故障转移和数据冗余。

(3)高扩展性:

MongoDB提供了水平可扩展性作为其核心功能的一部分。

分片将数据分布在一组集群的机器上。(海量数据存储,服务能力水平扩展)

从3.4开始,MongoDB支持基于片键创建数据区域。在一个平衡的集群中,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些

片。

(4)丰富的查询支持:

MongoDB支持丰富的查询语言,支持读和写操作(CRUD),比如数据聚合、文本搜索和地理空间查询等。

(5)其他特点:如无模式(动态模式)、灵活的文档模型


MongoDB安装

#拉取镜像 
docker pull mongo:latest
#创建和启动容器 
docker run -d --restart=always -p 27017:27017 --name mymongo -v /data/db:/data/db -d mongo
#进入容器 
docker exec -it mymongo /bin/bash
#使用MongoDB客户端进行操作 
mongo 


MongoDB基本命令

#Help查看命令提示 
db.help()
#切换/创建数据库
use test#如果数据库不存在,则创建数据库,否则切换到指定数据库
#查询所有数据库 
show dbs;
#删除当前使用数据库 
db.dropDatabase();
#查看当前使用的数据库 
db.getName();
#显示当前db状态 
db.stats();
#当前db版本 
db.version();
#查看当前db的链接机器地址 
db.getMongo〇;

文档

文档是一组键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

下表列出了 RDBMS 与 MongoDB 对应的术语:

RDBMS MongoDB
数据库 数据库
表格 集合
文档
字段
表联合 嵌入文档
主键 主键 (MongoDB 提供了 key 为 _id )

文档的一些操作

#创建一个集合(table)
db.createCollection( "collName");
#得到指定名称的集合(table )
db.getCollection("user");

MongoDB的CRUD操作

  • INSERT

    > db.User.save({name:'zhangsan',age:21,sex:true})
    > db.User.find()
    {"_id": Objectld("4f69e680c9106ee2ec95da66"), "name": "zhangsan", "age": 21,
    "sex": true}
    
    

    _id组合

    Objectld是、id”的默认类型。Objectld使用12字节的存储空间,每个字节二位十六进制数字, 是一个24位的字符串

    ![img](file:///C:/Users/Boerk/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)

  • Query

    # select * from User where name = 'zhangsan' sql
    > db.User.find({name:"zhangsan"}) #MongoDB
    
    # select name, age from User where age = 21
    > db.User.find({age:21}, {'name':1, 'age':1})
    
    #在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。
    # select * from User order by age
    > db.User.find().sort({age:1})
    
    #SUCE
    #在 MongoDB 中使用 limit()方法来读取指定数量的数据,skip()方法来跳过指定数量的数据
    # select * from User skip 2 limit 3
    > db.User.find().skip(0).limit(3)
    
    # select * from User where age in (21, 26, 32)
    > db.User.find({age:{$in:[21,26,32]}})
    
    # select count(*) from User where age >20
    > db.User.find({age:{$gt:20}}).count()
    
    # select * from User where age = 21 or age = 28
    > db.User.find({$or:[{age:21}, {age:28}]})
    
  • Update

    # update Userset age = 100, sex = 0 where name = 'user1'
    > db.User.update({name:"zhangsan"}, {$set:{age:100, sex:0}})
    
    

    Update()有几个参数需要注意。

    db.collection.update(criteria, objNew, upsert, mult)

    criteria:需要更新的条件表达式

    objNew:更新表达式

    upsert:如FI标记录不存在,是否插入新文档。

    multi:是否更新多个文档。

  • Remove

    #移除对应id的行
    > db.User.remove(id)
    #移除所有
    > db.User.remove({})
    
    
    
    

Springboot整合MongoDB

spring-data-mongodb提供了MongoTemplate与MongoRepository两种方式访问mongodb,MongoRepository操作简单,MongoTemplate操作灵活,我们在项目中可以灵活适用这两种方式操作mongodb,MongoRepository的缺点是不够灵活,MongoTemplate正好可以弥补不足。

  • 引入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    
  • 配置MongoDB的地址

    spring.data.mongodb.uri=mongodb://ip:27017/test
    
  • 创建对应的实体类

    @Data
    @Document("User")
    public class User {
        @Id
        private String id;
        private String name;
        private Integer age;
        private String email;
        private String createDate;
    }
    
  • 添加

    /**
     * 这是对MongoDB进行新增的方法
     */
    @Test
    public void add(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        user.setEmail("110120119");
        User user1 = mongoTemplate.insert(user);
        System.out.println(user1);
    }
    
  • 查询

    /**
     * 这是对MongoDB进行查找的方法
     */
    @Test
    public void query() {
        List<User> all = mongoTemplate.findAll(User.class);
        System.err.println(all);
    }
    
    /**
     * 这是根据id对MongoDb的精细查询的方法
     */
    @Test
    public void queryById(){
        User user = mongoTemplate.findById("625c1bbaa2f93370884eafeb", User.class);
        System.out.println(user);
    }
    
    //条件查询
    /**
     * 这是根据条件查询的方法
     */
    @Test
    public void queryUserList() {
        //name=zhangsan &age=18
        Query query = new Query(Criteria
                                .where("name").is("zhangsan") //name is zhangsan
                                .and("age").is(18)            //age is 18
                               );
        mongoTemplate.find(query, User.class);
    }
    
    //模糊查询
    /**
     * 模糊查询
     */
    @Test
    public void queryUserLike(){
        //名字中包含zhang
        String name = "zhang";
        //正则表达式的匹配规则
        String regex = String.format("%s%s%s", "^.*", name, ".*$");
        Pattern pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        //匹配正则
        Query query = new Query(Criteria.where("name").regex(pattern));
        List<User> users = mongoTemplate.find(query, User.class);
        System.err.println(users);
    }
    
    //分页查询
    /**
     * 分页查询
     */
    @Test
    public void queryUserLikePage(){
        //分页信息
        int pageNum=1;
        int pageSize=3;
        //名字中包含zhang
        String name = "zhang";
        //正则表达式的匹配规则
        String regex = String.format("%s%s%s", "^.*", name, ".*$");
        Pattern pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        //匹配正则
        Query query = new Query(Criteria.where("name").regex(pattern));
        //分页查询
        List<User> users = mongoTemplate.find(query.skip((pageNum-1)*pageSize).limit(pageSize), User.class);
        System.out.println(users);
    }
    
  • Upsert

    /**
     * 修改
     */
    @Test
    public void update(){
        //1.首先查询
        User user = mongoTemplate.findById("625c1bbaa2f93370884eafeb", User.class);
        user.setName("lisi");
        //改哪个?查出来!
        //根据id查找要改的信息
        Query query = new Query(Criteria.where("id").is(user.getId()));
        //怎么改?写出来!
        Update update = new Update();
        update.set("name",user.getName());
        UpdateResult upsert = mongoTemplate.upsert(query, update, User.class);
        long matchedCount = upsert.getMatchedCount();
        System.out.println("修改数量:"+matchedCount);
    }
    
  • Remove

    /**
     * 删除
     */
    @Test
    public void delete(){
        Query query = new Query(Criteria.where("id").is("625c1bbaa2f93370884eafeb"));
        mongoTemplate.remove(query,User.class);
    }
    
posted @ 2022-04-17 23:50  Boerk  阅读(43)  评论(0编辑  收藏  举报