前言

刚刚接触到了mongodb数据库,对于mongodb的操作以前没有了解,这里也是接触到了Spring提供的Spring Data Jpa工程,使用Spring Data Jpa来对mongodb进行一些增删改查,因为了解的不多,这里记录了一些简单的增删改查。

1、JPA

先了解什么是JPA?
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队。
重点:JPA是一套规范,不是一套产品。

2、Spring Data Jpa是什么

Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展,使用它可以提高我们的开发效率。基本上所有CRUD都可以依赖于它来实现。

3、Spring Data Jpa的使用

 

(1)yml配置


需要配置连接到mongodb的信息,如下:

spring:
  ## mongodb连接配置
  data:
    mongodb:
      uri: mongodb://user40642330:xxxxxxx@dds-bp12ailpzf1ijx8u-pub.mongodb.rds.aliyuncs.com:3717
      database: test_ycz  

我用的是阿里云的mongodb产品。

(2)pojo


因为我的model是单独分一个工程出去的,所有pojo都在这个工程中定义,所以在pojo所在的工程需要先添加依赖,为什么要加依赖?因为要使用它的注解。

		<!-- data-mongodb依赖 -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
			<version>3.1.1</version>
		</dependency>

然后pojo实体类如下:

@Document(collection = "music_detail")
public class MusicDetail {
    
    @Id
    @Getter
    @Setter
    private String musicId;//音乐ID
    
    @Getter
    @Setter
    private String musicName;//音乐名称
    
    @Getter
    @Setter
    private String musicType;//音乐类型
    
    @Getter
    @Setter
    private String author;//音乐表演者
    
    @Getter
    @Setter
    private String album;//所属专辑
    
    @Getter
    @Setter
    private Date addTime;//添加时间

}

@Id和@Document是它提供的注解。

因为后期我要使用参数来查询,所以这里封装了一个查询对象,所有的查询参数都封装在这个对象中,如下:

/*
 * 此类型用来接收查询参数
 */
@Data
public class QueryRequest {
    
    //音乐名称
    private String musicName;
    
    //音乐类型
    private String musicType;
    
    //专辑
    private String album;
    
    //作者
    private String author;

}

(3)api

 

@Api(value = "音乐信息管理",description = "提供音乐的增删改查",tags = {"音乐信息管理"})
public interface MusicControllerApi {
    
    @ApiOperation("音乐信息添加")
    ResponseResult addMusic(MusicDetail musicDetail);
    
    @ApiOperation("音乐信息修改")
    ResponseResult editMusic(String musicId,MusicDetail musicDetail);
    
    @ApiOperation("音乐信息删除")
    ResponseResult delMusic(String musicId);
    
    @ApiOperation("按指定条件查询并且分页")
    QueryResponseResult<MusicDetail> getMusic(int page,int size,QueryRequest queryRequest);

}

这里简单的定义了4个接口,测试增删改查,api我是单独分了一个api工程出去的。

(4)dao

 

package com.ycz.swagger.dao;

import org.springframework.data.mongodb.repository.MongoRepository;

import com.ycz.domain.music.MusicDetail;

public interface MusicDetailRepository extends MongoRepository<MusicDetail, String>{
    
    //通过作者和歌名查询
    MusicDetail findByMusicNameAndAuthor(String musicName,String author);

}

直接定义一个接口来继承MongoRepository就行了,第一个参数是collection对应的实体类,第二个参数是主键类型,这里我定义了一个简单接口,来做添加前的简单判断。

(5)Service

 

@Service
public class MusicDetailService {
    
    @Autowired
    MusicDetailRepository musicDetailRepository;

    //添加音乐信息
    public ResponseResult addMusic(MusicDetail musicDetail) {
        // 先查询
        MusicDetail music = musicDetailRepository.
                findByMusicNameAndAuthor(musicDetail.getMusicName(), musicDetail.getAuthor());
        if(music!=null) {
            return new ResponseResult(CommonCode.FAIL);
        }
        musicDetail.setAddTime(new Date());
        musicDetailRepository.save(musicDetail);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    //修改音乐信息
    public ResponseResult editMusic(String musicId, MusicDetail musicDetail) {
        //先查询
        Optional<MusicDetail> optional = musicDetailRepository.findById(musicId);
        if(!optional.isPresent()) {
            return new ResponseResult(CommonCode.FAIL);
        }
        //执行修改保存
        MusicDetail music = optional.get();
        music.setMusicName(musicDetail.getMusicName());
        music.setMusicType(musicDetail.getMusicType());
        music.setAuthor(musicDetail.getAuthor());
        music.setAlbum(musicDetail.getAlbum());
        musicDetailRepository.save(music);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    //执行删除
    public ResponseResult delMusic(String musicId) {
        // 先查询
        Optional<MusicDetail> optional = musicDetailRepository.findById(musicId);
        if(!optional.isPresent()) {
            return new ResponseResult(CommonCode.FAIL);
        }
        //删除
        musicDetailRepository.deleteById(musicId);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    //按条件查询,并且分页
    public QueryResponseResult<MusicDetail> getMusic(int page, int size, QueryRequest queryRequest) {
        // 判断查询条件非空
        if(queryRequest==null) {
            queryRequest = new QueryRequest();
        }
        //创建条件值对象
        MusicDetail music = new MusicDetail();
        //按照作者、音乐名称、专辑名模糊查询
        //定义条件匹配器
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().
                withMatcher("author", GenericPropertyMatchers.contains()).
                withMatcher("musicName", GenericPropertyMatchers.contains()).
                withMatcher("album", GenericPropertyMatchers.contains());
        //在条件匹配器中我没有设置musicType这个参数
        //没有设置的话它默认是按精确匹配
        //判断各参数是否为空
        if(StringUtils.isNotEmpty(queryRequest.getMusicType())) {
            music.setMusicType(queryRequest.getMusicType());
        }
        if(StringUtils.isNotEmpty(queryRequest.getMusicName())) {
            music.setMusicName(queryRequest.getMusicName());
        }
        if(StringUtils.isNotEmpty(queryRequest.getAlbum())) {
            music.setAlbum(queryRequest.getAlbum());
        }
        if(StringUtils.isNotEmpty(queryRequest.getAuthor())) {
            music.setAuthor(queryRequest.getAuthor());
        }
        //基于值对象和匹配器定义条件对象
        Example<MusicDetail> example = Example.of(music, exampleMatcher);
        if(page<=0) {
            page = 1;
        }
        //page=0代表第1页,所以这里要从0开始
        page = page - 1;
        if(size<=5) {
            size = 5;
        }
        //分页
        Pageable pageable = PageRequest.of(page, size);
        //获取分页对象
        Page<MusicDetail> all = musicDetailRepository.findAll(example, pageable);
        //获取总的记录条数
        long total = all.getTotalElements();
        //获取查询列表
        List<MusicDetail> list = all.getContent();
        //封装对象
        QueryResult<MusicDetail> queryResult = new QueryResult<MusicDetail>();
        queryResult.setTotal(total);
        queryResult.setList(list);
        return new QueryResponseResult<>(CommonCode.SUCCESS, queryResult);
    }

}

(6)Controller

 

@RestController
@RequestMapping("/music")
public class MusicController implements MusicControllerApi{
    
    @Autowired
    MusicDetailService musicDetailService;

    @Override
    @PostMapping("/addMusic")
    public ResponseResult addMusic(@RequestBody MusicDetail musicDetail) {
        return musicDetailService.addMusic(musicDetail);
    }

    @Override
    @PutMapping("/editMusic/{musicId}")
    public ResponseResult editMusic(@PathVariable("musicId") String musicId, 
            @RequestBody MusicDetail musicDetail) {
        return musicDetailService.editMusic(musicId,musicDetail);
    }

    @Override
    @DeleteMapping("/delMusic/{musicId}")
    public ResponseResult delMusic(@PathVariable("musicId") String musicId) {
        return musicDetailService.delMusic(musicId);
    }

    @Override
    @GetMapping("/getMusic/list/{page}/{size}")
    public QueryResponseResult<MusicDetail> getMusic(
            @PathVariable("page") int page, @PathVariable("size") int size, 
            QueryRequest queryRequest) {
        return musicDetailService.getMusic(page,size,queryRequest);
    }

}

这个控制器统一返回json数据,实现了api工程中新定义的接口,接口在这里暴露出来。

(7)测试


使用swagger进行测试,
浏览器进入:http://localhost:10000/swagger-ui.html
在这里插入图片描述

先来测添加:


在这里插入图片描述
返回结果:
在这里插入图片描述

 

测试修改:


在这里插入图片描述
返回结果:

在这里插入图片描述

 

 

测试删除:


在这里插入图片描述
返回结果:
在这里插入图片描述
测试查询:
在这里插入图片描述
这里先不设其他参数,只设置分页的page和size,结果太长,截不了图,用代码贴出:

{
  "success": true,
  "code": 10000,
  "message": "操作成功!",
  "queryResult": {
    "list": [
      {
        "musicId": "5fe47e2100739f6474c19422",
        "musicName": "晚晴润雨",
        "musicType": "pure",
        "author": "陈致逸",
        "album": "天涯明月刀",
        "addTime": "2020-12-24T11:40:16.948+00:00"
      },
      {
        "musicId": "5fe47e8300739f6474c19423",
        "musicName": "云水逸",
        "musicType": "pure",
        "author": "张晓红",
        "album": "古筝爱好者",
        "addTime": "2020-12-24T11:41:55.952+00:00"
      },
      {
        "musicId": "5fe47ed600739f6474c19424",
        "musicName": "雪满山中",
        "musicType": "pure",
        "author": "忘乡",
        "album": "雪满山中",
        "addTime": "2020-12-24T11:43:18.411+00:00"
      },
      {
        "musicId": "5fe47f0a00739f6474c19425",
        "musicName": "峨眉金顶",
        "musicType": "pure",
        "author": "卢小旭",
        "album": "蜀山OL原乐声",
        "addTime": "2020-12-24T11:44:10.881+00:00"
      },
      {
        "musicId": "5fe47f3800739f6474c19426",
        "musicName": "鸿迹",
        "musicType": "pure",
        "author": "变奏的梦想",
        "album": "鸿迹",
        "addTime": "2020-12-24T11:44:56.743+00:00"
      },
      {
        "musicId": "5fe47f5400739f6474c19427",
        "musicName": "比翼鸟",
        "musicType": "pure",
        "author": "麦振鸿",
        "album": "武侠音乐之喜气洋洋",
        "addTime": "2020-12-24T11:45:24.505+00:00"
      },
      {
        "musicId": "5fe47f8600739f6474c19428",
        "musicName": "御史秦风云",
        "musicType": "pure",
        "author": "霹雳布袋戏",
        "album": "霹雳布袋戏",
        "addTime": "2020-12-24T11:46:14.611+00:00"
      },
      {
        "musicId": "5fe4808c00739f6474c19429",
        "musicName": "轻风",
        "musicType": "pure",
        "author": "四季春色",
        "album": "春夏之交,轻旋淡律",
        "addTime": "2020-12-24T11:50:36.700+00:00"
      },
      {
        "musicId": "5fe480dc00739f6474c1942a",
        "musicName": "潇湘子",
        "musicType": "pure",
        "author": "霹雳布袋戏",
        "album": "霹雳英雄",
        "addTime": "2020-12-24T11:51:56.745+00:00"
      },
      {
        "musicId": "5fe4812000739f6474c1942b",
        "musicName": "该不该难过",
        "musicType": "sing",
        "author": "魏枫",
        "album": "该不该难过",
        "addTime": "2020-12-24T11:53:04.673+00:00"
      }
    ],
    "total": 17
  }
}

可以看到,查询的一共17条记录,我数据库中也只有17条记录,但是返回的是第1页,因为设置了分页参数。

 

按专辑名模糊查询:


在这里插入图片描述
返回结果:

{
  "success": true,
  "code": 10000,
  "message": "操作成功!",
  "queryResult": {
    "list": [
      {
        "musicId": "5fe47f8600739f6474c19428",
        "musicName": "御史秦风云",
        "musicType": "pure",
        "author": "霹雳布袋戏",
        "album": "霹雳布袋戏",
        "addTime": "2020-12-24T11:46:14.611+00:00"
      },
      {
        "musicId": "5fe480dc00739f6474c1942a",
        "musicName": "潇湘子",
        "musicType": "pure",
        "author": "霹雳布袋戏",
        "album": "霹雳英雄",
        "addTime": "2020-12-24T11:51:56.745+00:00"
      }
    ],
    "total": 2
  }
}

查到2条记录,专辑霹雳布袋戏、霹雳英雄这2条记录。

 

按类型查询,查找所有类型为sing,并且歌名中带有爱,并且歌手姓杨的:


在这里插入图片描述
返回结果:

{
  "success": true,
  "code": 10000,
  "message": "操作成功!",
  "queryResult": {
    "list": [
      {
        "musicId": "5fe4823500739f6474c1942d",
        "musicName": "爱笑的女孩",
        "musicType": "sing",
        "author": "杨陆",
        "album": "爱笑的女孩",
        "addTime": "2020-12-24T11:57:41.780+00:00"
      }
    ],
    "total": 1
  }
}

结果正确,和数据库中记录是匹配的。

 

4、总结


使用Spring Data Mongodb可以非常快速简便的对mongodb中的collection进行CRUD,大大提高了我们的开发效率,目前刚用,只是有一个简单的了解,相信它并不只有这么点功能,以后继续了解深入。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐