SpringBoot整合MongoDB JPA使用

一、整合MongoDB

SpringDataMongoDB是 SpringData家族成员之一,MongoDB的持久层框架,底层封装了 mongodb-driver。mongodb-driver 是 MongoDB官方推出的 Java连接 MongoDB的驱动包,相当于JDBC驱动。

SpringBoot整合 MongoDB,引入 SpringDataMongoDB依赖。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

1、配置MongoDB信息

在 application.yml文件中,添加 MongoDB连接信息。

spring:data:mongodb:# 超级管理员是必须指定?后面的固定写法uri: mongodb://用户名:密码@127.0.0.1:27017/ws_sb_local?authSource=admin&authMechanism=SCRAM-SHA-1# 普通用户不能指定?后面的固定写法# uri: mongodb://luna1:密码@127.0.0.1:27017/ws_sb_local

然后启动项目就可以使用 MongoTemplate或者 MongoDB JPA框架(SpringDataMongoDB)。

2、JPA查询规范

使用 JPA查询时,我们要遵循一定的规范。

示例如下:

在这里插入图片描述

3、JPA注解

JPA常用注解如下:

@Id
用于字段级别,标记这个字段是一个主键,默认生成的名称是“_id”。

@Document
用于类,以表示这个类需要映射到数据库,您也可以指定映射到数据库的集合名称。

@Field
用于字段,并描述字段的名称,因为它将在MongoDB BSON文档中表示,允许名称与该类的字段名不同。

@CreatedDate
用途: 该注解用于标记一个字段,表示这个字段将自动保存文档首次创建时的日期和时间。
行为: 当一个新的文档被插入到MongoDB集合中时,标记了@CreatedDate的字段会被自动填充为当前的日期和时间。
数据类型: 通常该字段应为java.util.Date、java.time.LocalDateTime或java.time.Instant等日期时间类型。

@LastModifiedDate
用途: 这个注解用于标记一个字段,以记录文档最后一次被修改的日期和时间。
行为: 每当文档被更新时,这个字段会自动更新为当前的日期和时间。
数据类型: 类似于@CreatedDate,它也支持java.util.Date、java.time.LocalDateTime或java.time.Instant等类型。

@Indexed
用于字段,表示该字段需要如何创建索引。

@CompoundIndex
用于类,以声明复合索引。

@GeoSpatialIndexed
用于字段,进行地理位置索引 。

@DBRef
用于字段,以表示它将使用com.mongodb.DBRef进行存储。

@TextIndexed
用于字段,标记该字段要包含在文本索引中。

@Language
用于字段,以设置文本索引的语言覆盖属性。

@Transient
默认情况下,所有私有字段都映射到文档,此注解将会去除此字段的映射

@PersistenceConstructor
标记一个给定的构造函数,即使是一个protected修饰的,在从数据库实例化对象时使用。构造函数参数通过名称映射到检索的DBObject中的键值。

@Value
这个注解是 Spring框架的一部分。在映射框架内,它可以应用于构造函数参数。这允许您使用Spring表达式语言语句来转换在数据库中检索的键值,然后再用它来构造一个域对象。为了引用给定文档的属性,必须使用以下表达式:@Value(“#root.myProperty”),root要指向给定文档的根。

@Version
用于字段锁定,保存操作时检查修改。初始值是0,每次更新时自动触发。

二、MongoDB JPA使用

这里直接上代码。

1、DO类

/*** 设备Gps信息*/
@Data
@Document("device_gps")
public class DeviceGpsDO implements Serializable {private static final long serialVersionUID = -9179758476973350170L;/*** 主键*/@Idprivate String id;/*** 创建时间*/@CreatedDate@Field("create_time")private LocalDateTime createTime;/*** 修改时间*/@LastModifiedDate@Field("update_time")private LocalDateTime updateTime;/*** 设备名称*/@Field("device_name")@Indexedprivate String deviceName;/*** 设备编号*/@Field("device_no")private String deviceNo;/*** 设备识别VIN码*/@Field("vin_no")private String vinNo;/*** 预警状态*/@Field("warn_status")private Integer warnStatus;/*** 速度(千米/小时)*/@Field("speed")private Float speed;/*** 海拔高度*/@Field("altitude")private Double altitude;/*** 卫星定位时间*/@Field("satellite_time")private Date satelliteTime;/*** 地理位置,用于LBS搜索*/@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)private GeoJsonPoint location;/*** 经度*/@Field("longitude")private Double longitude;/*** 纬度*/@Field("latitude")private Double latitude;}

2、Dao类

/*** 设备Gps信息* 继承 MongoRepository,指定实体和主键的类型作为泛型*/
public interface DeviceGpsDao extends MongoRepository<DeviceGpsDO, String> {/*** JPA语法查询根据速度大于等于和预警状态查询** @param speed      速度* @param warnStatus 预警状态* @return*/List<DeviceGpsDO> findBySpeedGreaterThanEqualAndWarnStatusEquals(Float speed, Integer warnStatus);/*** @Query注解查询根据速度大于等于和预警状态查询** @param speed      速度* @param warnStatus 预警状态* @return*/@Query("{ speed: {$gte : ?0}, warn_status: ?1  }")List<DeviceGpsDO> getBySpeedAndWarnStatus(Float speed, Integer warnStatus);}

3、Service类

(1)接口

public interface DeviceGpsService {/*** 分页查询** @param pageQueryRequest* @return*/BasePageResult pageQuery(DeviceGpsPageQueryRequest pageQueryRequest);/*** 新增** @param deviceGpsDO*/BaseOperateResult insert(DeviceGpsDO deviceGpsDO);/*** 新增或者修改** @param deviceGpsDO*/BaseOperateResult insertOrUpdate(DeviceGpsDO deviceGpsDO);/*** 根据 id删除** @param id*/BaseOperateResult deleteById(String id);/*** 根据 id查询** @param id* @return*/DeviceGpsDO findById(String id);/*** 查询所有** @return*/List<DeviceGpsDO> findAll();/*** JPA语法查询根据速度大于等于和预警状态查询** @param speed      速度* @param warnStatus 预警状态* @return*/List<DeviceGpsDO> findBySpeedGreaterThanEqualAndWarnStatusEquals(Float speed, Integer warnStatus);/*** @Query注解查询根据速度大于等于和预警状态查询** @param speed      速度* @param warnStatus 预警状态* @return*/List<DeviceGpsDO> getBySpeedAndWarnStatus(Float speed, Integer warnStatus);}

(2)实现类

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceGpsServiceImpl implements DeviceGpsService {private final DeviceGpsDao deviceGpsDao;@Overridepublic BasePageResult pageQuery(DeviceGpsPageQueryRequest pageQueryRequest) {BasePageResult pageResult = new BasePageResult();String deviceName = pageQueryRequest.getDeviceName();Integer warnStatus = pageQueryRequest.getWarnStatus();// 创建查询条件的实例DeviceGpsDO queryDO = new DeviceGpsDO();if (StringUtils.isNoneBlank(deviceName)) {queryDO.setDeviceName(deviceName);}if (warnStatus != null) {queryDO.setWarnStatus(warnStatus);}// 设置ExampleMatcher来定义匹配规则ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreCase() // 忽略大小写.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING); // 包含// 使用条件对象和匹配器创建Example实例Example<DeviceGpsDO> example = Example.of(queryDO, matcher);// 构造分页对象, 从 0 开始int currentPage = pageQueryRequest.getCurrentPage().intValue();int pageSize = pageQueryRequest.getPageSize().intValue();PageRequest pageRequest = PageRequest.of(currentPage - 1, pageSize);// 分页查询/*** Example 这种方式更适合于属性匹配(如字符串的模糊匹配)。对于比较运算(如大于、小于等),使用Spring Data MongoDB提供的Criteria和Query对象来构建更复杂的查询条件。*/Page<DeviceGpsDO> doPage = deviceGpsDao.findAll(example, pageRequest);log.info("doPage.getNumber() = {}", doPage.getNumber());log.info("doPage.getNumberOfElements() = {}", doPage.getNumberOfElements());log.info("doPage.getSize() = {}", doPage.getSize());log.info("doPage.getTotalElements() = {}", doPage.getTotalElements());log.info("doPage.getTotalPages() = {}", doPage.getTotalPages());pageResult.setPaginator(new Paginator(doPage.getNumber() + 1, doPage.getSize(), doPage.getTotalElements(), doPage.getTotalPages()));pageResult.setPageList(doPage.getContent());pageResult.setSuccess(true);return pageResult;}@Overridepublic BaseOperateResult insert(DeviceGpsDO deviceGpsDO) {BaseOperateResult operateResult = new BaseOperateResult();// 新增Double longitude = deviceGpsDO.getLongitude();Double latitude = deviceGpsDO.getLatitude();if (longitude != null || latitude != null) {// 经纬度 GeoJsonPointdeviceGpsDO.setLocation(new GeoJsonPoint(longitude, latitude));}deviceGpsDao.insert(deviceGpsDO);operateResult.setSuccess(Boolean.TRUE);return operateResult;}@Overridepublic BaseOperateResult insertOrUpdate(DeviceGpsDO deviceGpsDO) {BaseOperateResult operateResult = new BaseOperateResult();// 新增或者修改Double longitude = deviceGpsDO.getLongitude();Double latitude = deviceGpsDO.getLatitude();if (longitude != null || latitude != null) {// 经纬度 GeoJsonPointdeviceGpsDO.setLocation(new GeoJsonPoint(longitude, latitude));}// MongoDB会清除字段为 null的字段。deviceGpsDao.save(deviceGpsDO);operateResult.setSuccess(Boolean.TRUE);return operateResult;}@Overridepublic BaseOperateResult deleteById(String id) {BaseOperateResult operateResult = new BaseOperateResult();deviceGpsDao.deleteById(id);operateResult.setSuccess(Boolean.TRUE);return operateResult;}@Overridepublic DeviceGpsDO findById(String id) {return deviceGpsDao.findById(id).get();}@Overridepublic List<DeviceGpsDO> findAll() {return deviceGpsDao.findAll();}@Overridepublic List<DeviceGpsDO> findBySpeedGreaterThanEqualAndWarnStatusEquals(Float speed, Integer warnStatus) {List<DeviceGpsDO> list = deviceGpsDao.findBySpeedGreaterThanEqualAndWarnStatusEquals(speed, warnStatus);return list;}@Overridepublic List<DeviceGpsDO> getBySpeedAndWarnStatus(Float speed, Integer warnStatus) {List<DeviceGpsDO> list = deviceGpsDao.getBySpeedAndWarnStatus(speed, warnStatus);return list;}}

然后,单元测试调用ok。

4、MongoDB的UTC时差问题

SpringDataMongoDB框架会自动处理 MongoDB的UTC时差问题。我们正常在服务端代码中保存和查询操作即可。但是,对于 Controller接口返回是不一样的,与使用 LocalDateTime和 Date类型有关。

MongoDB数据库记录:
在这里插入图片描述

Controller接口返回DO数据:

在这里插入图片描述

结论:

  • 如果使用 Date类型,接口返回存在 8小时时差,请使用 @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")注解并且必须指定时区解决。
  • 如果使用 LocalDateTime,接口返回不存在时差问题,序列化时也可以使用 @JsonFormat注解。
  • 推荐使用 LocalDateTime

在这里插入图片描述

5、“_class” 字段问题

SpringBoot整合mongodb时,发现添加文档会自动添加一个_class的字段。

在这里插入图片描述

有或者没有_class列,对于我们使用 MongoDB进行任何操作及序列化实体类都没有任何影响。

所以,我们可以使用下面方法,禁用 “_class” 字段。

新建 MongoDB配置类。

//@EnableMongoAuditing   // 开启审计功能
@Configuration
public class MongoDBConfig implements InitializingBean {@Resourceprivate MappingMongoConverter mappingMongoConverter;@Overridepublic void afterPropertiesSet() {// 禁用 "_class" 字段mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));}}

6、开启审计功能

使用 @EnableMongoAuditing注解开启审计功能。

我们在启动类或者 上面配置类上添加它之后,@CreatedDate和 @LastModifiedDate注解就会生效了。

注意:@CreatedDate:id为空时生效。

三、@Query注解使用

在 Dao类中,我们可以通过使用 @Query 注解手写查询语句。

1、简单参数传参

我们需要使用 ?数字占位符 表达式来取出参数中指定位置的值,占位符从 0开始。

    @Query("{ speed: {$gte : ?0}, warn_status: ?1  }")List<DeviceGpsDO> getBySpeedAndWarnStatus(Float speed, Integer warnStatus);

2、对象参数传参

我们需要使用 SpEL 表达式,格式:?#{[]}

括号中使用 [下标] 来取出指定位置的参数,比如:?#{[0]} 则取出第一个参数。之后直接取出参数中的指定属性即可,比如如 ?#{[1].age} 就是取出第二个参数的age属性。

    @Query("{ speed: {$gte : ?#{[0].speed}}, warn_status: ?#{[0].warnStatus} }")List<DeviceGpsDO> getBySpeedAndWarnStatus2(DeviceGpsDO deviceGpsDO);

3、投影查询

如果我们只想获取指定的字段,可以使用 @Query注解的 fields 来进行投影查询。

    @Query(value= "{ speed: {$gte : ?#{[0].speed}}, warn_status: ?#{[0].warnStatus} }",fields = "{ speed:1, warn_status:1 }")List<DeviceGpsDO> getBySpeedAndWarnStatus3(DeviceGpsDO deviceGpsDO);

测试:

    @Overridepublic List<DeviceGpsDO> getBySpeedAndWarnStatus(Float speed, Integer warnStatus) {List<DeviceGpsDO> list = deviceGpsDao.getBySpeedAndWarnStatus(speed, warnStatus);DeviceGpsDO deviceGpsDO = new DeviceGpsDO();deviceGpsDO.setSpeed(0.0F);deviceGpsDO.setWarnStatus(0);List<DeviceGpsDO> list2 = deviceGpsDao.getBySpeedAndWarnStatus2(deviceGpsDO);List<DeviceGpsDO> list3 = deviceGpsDao.getBySpeedAndWarnStatus3(deviceGpsDO);log.info("list = {} ", list);log.info("list2 = {} ", list2);log.info("list3 = {} ", list3);return list;}

在这里插入图片描述

总结:

  • 对于保存、修改、删除等操作,JPA语法使用非常友好,推荐使用
  • 对于动态条件查询,JPA语法与@Query注解处理不够友好,不推荐使用。
  • 对于动态条件查询,推荐使用 Criteria对象构建动态参数,然后使用 mongoTemplate查询。
  • 项目中,通常会 JPA语法与 mongoTemplate两者结合使用。

– 求知若饥,虚心若愚。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/34229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Mac】XnViewMP for Mac(图片浏览查看器)及同类型软件介绍

软件介绍 XnViewMP 是一款多功能、跨平台的图像查看和管理软件&#xff0c;适用于 macOS、Windows 和 Linux 系统。它是经典 XnView 软件的增强版本&#xff0c;更加现代化且功能更强大。XnViewMP 支持数百种图像格式&#xff0c;并提供多种图像处理工具&#xff0c;使其成为摄…

【摄像头标定】使用kalibr进行双目摄像头标定(ros1、ros2)

使用kalibr进行双目摄像头标定 前言标定板标定①板端准备和录制②上位机准备和标定 前言 本文不是纯用ros1进行标定&#xff0c;需要ros1和ros2通信。给使用ros2进行开发&#xff0c;但又想用kalibr标定双目摄像头的小伙伴一个教程。本文双目摄像头的数据发布使用ros2&#xf…

收银系统源码-千呼新零售2.0【线上营销】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看&a…

Js逆向爬虫基础篇

这里写自定义目录标题 逆向技巧断点一 、请求入口定位1. 关键字搜索2. 请求堆栈3. hook4. JSON.stringify 二、响应入口定位&#xff1a;1. 关键字搜索2. hook3. JSON.parse 逆向技巧 断点 普通断点 条件断点 日志断点 XHR断点 一 、请求入口定位 1. 关键字搜索 key关…

办公软件的答案?ONLYOFFICE 桌面应用编辑器会是最好用的 Office 软件?ONLYOFFICE 桌面编辑器使用初体验

文章目录 &#x1f4cb;前言&#x1f3af;什么是 ONLYOFFICE&#x1f3af; 主要功能介绍及 8.1 新功能体验&#x1f3af; 在线体验&#x1f4dd;最后 &#x1f4cb;前言 提到办公软件&#xff0c;大家最常用的可能就是微软的 Microsoft Office 和国产的 WPS Office。这两款软件…

jenkins环境搭建--关于jenkins在Ubuntu下的安装篇(一)

在ubuntu下使用命令进行下载安装包&#xff1a; 关于jenkins的安装有多种&#xff0c;可以借助docker容器进行安装&#xff0c;也可以通过传统方法手动一步步的进行安装&#xff0c;以下介绍手动一步步的安装方法&#xff0c;后续我们将解释关于jenkins的相关配置以及实战使用…

欧盟指控苹果应用商店规则非法压制竞争,面临巨额罚款风险

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Excel 宏录制与VBA编程 —— 14、使用VBA处理Excel事件

简介 若希望特定事件处理程序在触发特定事件时运行&#xff0c;可以为 Application 对象编写事件处理程序。 Application 对象的事件处理程序是全局的&#xff0c;这意味着只要 Microsoft Excel 处于打开状态&#xff0c;事件处理程序将在发生相应的事件时运行&#xff0c;而不…

计算机网络 交换机的基本配置

一、理论知识 1.三种模式&#xff1a; ①用户模式&#xff1a;当登录路由器后&#xff0c;系统自动进入用户EXEC命令模式。 例如&#xff1a; Router> 在用户模式状态下&#xff0c;用户只能查看路由器的连接状态和基本信息&#xff0c;访问其他网络和主机&#xff0c…

数据库管理与数据库语句

数据库用户管理及高级sql语句 数据库管理 数据库用户管理 mysql权限表 在mysql中mysql库中的user表是最重要的权限表&#xff0c;记录允许连接到服务器的账号信息以及全局权限&#xff0c; 在mysql库中db和host表也是重要的权限表 db表中存储了用户对某个数据库的操作权限&…

DataGrip 2024 mac/win版:让数据库管理更简单

JetBrains DataGrip 2024 是一款专为数据库开发者设计的集成开发环境(IDE)&#xff0c;它凭借其卓越的性能和丰富的功能&#xff0c;为数据库管理提供了前所未有的便利。 DataGrip 2024 mac/win版获取 DataGrip 2024 支持几乎所有主流的关系型数据库管理系统&#xff0c;如 My…

浅谈目标检测之YOLO(You Only Look Once)v1

简介&#xff1a;本文章要介绍的YOLOv1算法&#xff0c;它与之前的目标检测算法如R-CNN等不同&#xff0c;R-NN等目标检测算法是一种两阶段&#xff08;two-stage&#xff09;算法&#xff0c;步骤为先在图片上生成候选框&#xff0c;然后利用分类器对这些候选框进行逐一的判断…

记录一下MATLAB优化器出现的问题和解决

今天MATLAB优化器出了点问题。我想了想&#xff0c;决定解决一下&#xff0c;不然后面项目没有办法进行下去。 我忘了截图了。 具体来说&#xff0c;是出现了下面的问题。 Gurobi: Cplex: 在上次为了强化学习调整了Pytoch环境以后&#xff08;不知道是不是这个原因&#…

仓库管理系统09--修改用户密码

1、添加窗体 2、窗体布局控件 UI设计这块还是传统的表格布局&#xff0c;采用5行2列 3、创建viewmodel 4、前台UI绑定viewmodel 这里要注意属性绑定和命令绑定及命令绑定时传递的参数 <Window x:Class"West.StoreMgr.Windows.EditPasswordWindow"xmlns"http…

制造业工厂的管理到底有多难

一、引言 随着全球经济的不断发展&#xff0c;制造业作为实体经济的核心&#xff0c;对国家的经济增长起着至关重要的作用。然而&#xff0c;制造业工厂的管理却是一项复杂而艰巨的任务。本文将深入探讨制造业工厂管理所面临的挑战&#xff0c;并提出相应的应对策略。 二、制造…

TCP: 传输控制协议

TCP: 传输控制协议 TCP的服务TCP 的首部小结 本系列文章旨在巩固网络编程理论知识&#xff0c;后续将结合实际开展深入理解的文章。 TCP的服务 T C P和U D P都使用相同的网络层&#xff08;I P&#xff09;&#xff0c;T C P却向应用层提供与U D P完全不同的服务。 T C P提供一…

【已解决】Python报错:AttributeError: module ‘json‘ has no attribute ‘loads‘

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《AI实战中的各种bug…

图片如何去水印,分享4个小妙招,手把手教会你!

作为一个经常逛社区网站下载表情包、头像的人&#xff0c;遇到的一个大难题就是图片有水印。如何才能快速去除水印&#xff1f;询问了一圈身边朋友&#xff0c;搜集了各种资料&#xff0c;小编整理了4个超好用的方法。 如果大家和小编一样&#xff0c;能坐着就不站着&#xff0…

一次DC1靶机的渗透测试

确定目标IP&#xff1a; nmap -sP 192.168.11.1/24 发现目标机器 扫描开放的端口&#xff1a; nmap -T4 -A -v 192.168.11.145 发现开放了一个80端口&#xff0c;并且给出了是Drupal的管理系统 浏览器访问这个服务&#xff1a; 因为这是一个Drupal的管理系统&#xff0c;那么…

利用第三方服务对目标进行被动信息收集防止被发现(web安全白帽子)

利用第三方服务对目标进行被动信息收集防止被发现&#xff08;web安全白帽子&#xff09; 1 被动信息收集1.1 信息收集内容1.2 信息用途 2 信息收集-DNS2.1 DNS信息收集NSLOOKUP2.1.1 ping2.1.2 nslookup 2.2 DNS信息收集-DIG&#xff08;此命令查到的结果更复杂些&#xff0c;…