介绍

  • 开发中JPA用的较多,所以对它做了一定的封装
    • 定义了常用的实体类
    • 自定义了数据库操作的方法
    • 自定义了简单的动态查询工具
    • 定义了实体的快速转换方法
  • 我只验证了MySQL数据库

    引入依赖

    ```xml
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test cn.jdevelops caches-jpa-server 2.0.4

mysql mysql-connector-java

  1. <a name="B7oCq"></a>
  2. # 前置操作
  3. <a name="J8crA"></a>
  4. ## ✨主要就是配置数据库的连接,这是常规操作
  5. > **如果要自定建库 ,请参考** [自动建库](https://www.yuque.com/tanning/yg9ipo/os495n?view=doc_embed)
  6. ```yaml
  7. server.port=1238
  8. spring.jpa.show-sql=true
  9. spring.jpa.hibernate.ddl-auto=update
  10. spring.datasource.password=root
  11. spring.datasource.username=root
  12. spring.datasource.url=jdbc:mysql://192.168.0.3:3306/hjpa?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
  13. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

数据初始化(测试项目)

  1. INSERT INTO `hjpa`.`sys_user`(`id`, `create_time`, `create_user_name`, `update_time`, `update_user_name`, `address`, `login_name`, `login_pwd`, `name`, `phone`, `user_icon`, `user_no`) VALUES (1, '2021-11-17 11:08:38', 'admin', '2021-12-03 14:02:22', 'admin', '重庆s', 'admin', '123', '超级管理员', '15888888888', NULL, 'admin');
  2. INSERT INTO `hjpa`.`sys_user`(`id`, `create_time`, `create_user_name`, `update_time`, `update_user_name`, `address`, `login_name`, `login_pwd`, `name`, `phone`, `user_icon`, `user_no`) VALUES (2, '2021-12-03 13:48:14', 'admin', '2021-12-03 13:50:01', 'admin', '', 'user', '123', '用户1', '231', NULL, '1466645430750781440');
  3. INSERT INTO `hjpa`.`sys_user`(`id`, `create_time`, `create_user_name`, `update_time`, `update_user_name`, `address`, `login_name`, `login_pwd`, `name`, `phone`, `user_icon`, `user_no`) VALUES (3, '2021-12-03 14:05:23', 'admin', '2021-12-03 14:05:43', 'admin', '', 'user02', '123', '用户2', '12321', NULL, '1466649744075108352');
  4. INSERT INTO `hjpa`.`sys_user`(`id`, `create_time`, `create_user_name`, `update_time`, `update_user_name`, `address`, `login_name`, `login_pwd`, `name`, `phone`, `user_icon`, `user_no`) VALUES (4, '2021-12-10 15:02:39', 'admin', '2021-12-10 15:02:39', 'admin', '', 'SH-01', '123', '111', '', NULL, '1469200870634397696');
  5. INSERT INTO `hjpa`.`sys_user`(`id`, `create_time`, `create_user_name`, `update_time`, `update_user_name`, `address`, `login_name`, `login_pwd`, `name`, `phone`, `user_icon`, `user_no`) VALUES (5, '2021-12-10 15:02:49', 'admin', '2021-12-10 15:03:00', 'admin', '222', 'LR-01', '1231', '111', '1312', NULL, '1469200914007695360');

全局异常处理

全局异常捕获

基础配置

实体继承JpaAuditFields可选

如果不使用基础字段,一定要继承 SerializableVO,因为有些功能用到了里面的内置方法

  1. package cn.tannn.hjpa.entity;
  2. import lombok.Data;
  3. import lombok.EqualsAndHashCode;
  4. import org.hibernate.annotations.DynamicInsert;
  5. import org.hibernate.annotations.DynamicUpdate;
  6. import javax.persistence.Column;
  7. import javax.persistence.Entity;
  8. import javax.persistence.Index;
  9. import javax.persistence.Table;
  10. /**
  11. * 用户表
  12. * @author : tn
  13. * @date : 2021-9-10
  14. */
  15. @Entity
  16. @Table(name = "sys_user",
  17. indexes = {
  18. @Index(name = "user_no_index", columnList = "userNo", unique = true),
  19. })
  20. @org.hibernate.annotations.Table(appliesTo = "sys_user", comment = "用户表")
  21. @Data
  22. @EqualsAndHashCode(callSuper = true)
  23. @DynamicUpdate
  24. @DynamicInsert
  25. public class User extends JpaAuditFields<User> {
  26. @Id
  27. @GeneratedValue(strategy = GenerationType.IDENTITY)
  28. @Column(columnDefinition="int(11) COMMENT '主键,自动生成'")
  29. private Integer id;
  30. /**
  31. * 用户编号
  32. */
  33. @Column(columnDefinition = " varchar(50) not null comment ' 用户编号' ")
  34. private String userNo;
  35. /**
  36. * 姓名
  37. */
  38. @Column(columnDefinition = " varchar(100) not null comment ' 姓名' ")
  39. private String name;
  40. /**
  41. * 地址
  42. */
  43. @Column(columnDefinition = " varchar(100) comment ' 地址' ")
  44. private String address;
  45. /**
  46. * 登录名称
  47. */
  48. @Column(columnDefinition = " varchar(100) not null comment '登录名称' ")
  49. private String loginName;
  50. /**
  51. * 登录密码
  52. */
  53. @Column(columnDefinition = " varchar(100) not null comment '登录密码' ")
  54. private String loginPwd;
  55. /**
  56. * 手机号/联系电话
  57. */
  58. @Column(columnDefinition = " varchar(15) comment ' 手机号/联系电话 ' ")
  59. private String phone;
  60. /**
  61. * 用户头像
  62. */
  63. @Column(columnDefinition = " varchar(60) comment ' 用户头像' ")
  64. private String userIcon;
  65. }

Repository继承JpaBasicsDao

如果实体不使用基础字段,一定要继承 SerializableVO,因为有些功能用到了里面的内置方法

  1. package cn.tannn.hjpa.dao;
  2. import cn.jdevelops.jpa.server.dao.JpaBasicsDao;
  3. import cn.tannn.hjpa.entity.User;
  4. /**
  5. * 用户表
  6. *
  7. * @author tan
  8. * @date 2021-09-10 1StudentDao1:08
  9. */
  10. public interface UserDao extends JpaBasicsDao<User, Integer> {
  11. }

Service 继承 J2Service

有个JService 也可以用,但是后期可能会被删除

  1. package cn.tannn.hjpa.service;
  2. import cn.jdevelops.jpa.server.service.J2Service;
  3. import cn.tannn.hjpa.entity.User;
  4. /**
  5. * 用户表
  6. *
  7. * @author lxw
  8. * @className 用户表
  9. * @date 2021-09-10 11:24
  10. */
  11. public interface UserService extends J2Service<User> {
  12. }

ServiceImpl 继承 J2ServiceImpl

service 使用的是 J2Service则 实现就必须继承 J2ServiceImpl

  1. package cn.tannn.hjpa.service.impl;
  2. import cn.jdevelops.jpa.server.service.impl.J2ServiceImpl;
  3. import cn.tannn.hjpa.dao.UserDao;
  4. import cn.tannn.hjpa.entity.User;
  5. import cn.tannn.hjpa.service.UserService;
  6. import lombok.AllArgsConstructor;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.stereotype.Service;
  9. /**
  10. * 用户表
  11. *
  12. * @author lxw
  13. * @className * 用户表
  14. * @date 2021-09-10 11:41
  15. */
  16. @Slf4j
  17. @Service
  18. public class UserServiceImpl extends J2ServiceImpl<UserDao, User, Integer> implements UserService {
  19. }

使用演示

自带的方法基本都一看都懂,我这儿演示下动态查询个 service中 直接使用 Repository

  • 细节情况本文档的下层文档

JPAUtilExpandCriteria 查询

  1. @Autowired
  2. private UserService userService;
  3. @PostMapping("dyFind")
  4. public ResultVO<List<UserVO>> dyFind(UserFindDTO user){
  5. User to = user.to(User.class);
  6. JPAUtilExpandCriteria<User> selectBean = CommUtils.getSelectBean(to);
  7. List<User> all = userService.getJpaBasicsDao().findAll(selectBean);
  8. return ResultVO.successForData(User.to(all, UserVO.class));
  9. }

简单使用

调用接口:Post : http://127.0.0.1:8080/dyFind
curl —location —request POST ‘http://127.0.0.1:8080/dyFind‘ —header ‘Content-Type: application/json’ —data-raw ‘{}’

不存参数

查询所有 Hibernate: select user0_.id as id1_0_, user0_.create_time as create_t2_0_, user0_.create_user_name as create_u3_0_, user0_.update_time as update_t4_0_, user0_.update_user_name as update_u5_0_, user0_.address as address6_0_, user0_.login_name as login_na7_0_, user0_.login_pwd as login_pw8_0_, user0_.name as name9_0_, user0_.phone as phone10_0_, user0_.user_icon as user_ic11_0_, user0_.user_no as user_no12_0_ from sys_user user0_ where 1=1

image.png

选择传入

默认 and and 相连 Hibernate: select user0_.id as id1_0_, user0_.create_time as create_t2_0_, user0_.create_user_name as create_u3_0_, user0_.update_time as update_t4_0_, user0_.update_user_name as update_u5_0_, user0_.address as address6_0_, user0_.login_name as login_na7_0_, user0_.login_pwd as login_pw8_0_, user0_.name as name9_0_, user0_.phone as phone10_0_, user0_.user_icon as user_ic11_0_, user0_.user_no as user_no12_0_ from sys_user user0_ where user0_.address=? and user0_.phone=?

image.png

高阶使用

设置条件的 连接符运算符

  1. 在实体中加入 @JpaSelectOperator_(_operator = SQLOperator._EQ_,ignoreNull = true, connect = SQLConnect._AND)_
    1. 详情请看注解注释’
    2. image.png
  2. 传参测试
    1. {
    2. "name": "超",
    3. "userNo": "146664"
    4. }
    1. SELECT
    2. user0_.id AS id1_0_,
    3. user0_.create_time AS create_t2_0_,
    4. user0_.create_user_name AS create_u3_0_,
    5. user0_.update_time AS update_t4_0_,
    6. user0_.update_user_name AS update_u5_0_,
    7. user0_.address AS address6_0_,
    8. user0_.login_name AS login_na7_0_,
    9. user0_.login_pwd AS login_pw8_0_,
    10. user0_.NAME AS name9_0_,
    11. user0_.phone AS phone10_0_,
    12. user0_.user_icon AS user_ic11_0_,
    13. user0_.user_no AS user_no12_0_
    14. FROM
    15. sys_user user0_
    16. WHERE
    17. user0_.address =?
    18. AND user0_.phone =? Hibernate : SELECT
    19. user0_.id AS id1_0_,
    20. user0_.create_time AS create_t2_0_,
    21. user0_.create_user_name AS create_u3_0_,
    22. user0_.update_time AS update_t4_0_,
    23. user0_.update_user_name AS update_u5_0_,
    24. user0_.address AS address6_0_,
    25. user0_.login_name AS login_na7_0_,
    26. user0_.login_pwd AS login_pw8_0_,
    27. user0_.NAME AS name9_0_,
    28. user0_.phone AS phone10_0_,
    29. user0_.user_icon AS user_ic11_0_,
    30. user0_.user_no AS user_no12_0_
    31. FROM
    32. sys_user user0_
    33. WHERE
    34. user0_.user_no LIKE ?
    35. OR user0_.NAME LIKE ?
    image.png

SpecificationUtil 查询

只写了个简单的测试用例,具体使用,等项目中用到了再来补充

HjpaApplicationTests(示例项目中测试类)

  1. package cn.tannn.hjpa;
  2. import cn.jdevelops.jap.core.util.JPAUtilExpandCriteria;
  3. import cn.jdevelops.jap.core.util.SpecificationUtil;
  4. import cn.jdevelops.jap.core.util.criteria.Restrictions;
  5. import cn.tannn.hjpa.entity.User;
  6. import cn.tannn.hjpa.service.UserService;
  7. import org.junit.jupiter.api.Test;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.boot.test.context.SpringBootTest;
  10. import org.springframework.data.jpa.domain.Specification;
  11. import org.springframework.transaction.annotation.Transactional;
  12. @SpringBootTest
  13. @Transactional(rollbackFor = Exception.class)
  14. class HjpaApplicationTests {
  15. @Autowired
  16. private UserService userService;
  17. @Test
  18. void testSpecificationUtil() {
  19. /**
  20. *
  21. WHERE
  22. ( address LIKE '%重庆%' )
  23. AND (
  24. NAME = '用户'
  25. OR login_pwd = '123'
  26. OR phone = '123'
  27. OR user_no = '123')
  28. */
  29. // address().and(
  30. // name().or(loginPwd()).or(phone()).or(userNo())
  31. // )
  32. SpecificationUtil<User> instance = SpecificationUtil.getInstance();
  33. Specification<User> and = instance.like("address", "重庆", true)
  34. .and(instance.eq("name", "用户", true)
  35. .or(instance.eq("loginPwd", "123", true))
  36. .or(instance.eq("phone", "123", true))
  37. .or(instance.eq("userNo", "123", true))
  38. );
  39. userService.getJpaBasicsDao().findAll(and).forEach(System.out::println);
  40. }
  41. @Test
  42. void testAndOr1() {
  43. /**
  44. * WHERE
  45. * ( address LIKE '重庆' )
  46. * AND (
  47. * NAME LIKE '%用户%'
  48. * OR login_pwd LIKE '123'
  49. * OR phone LIKE '123'
  50. * OR phone LIKE '123'
  51. * )
  52. */
  53. userService.getJpaBasicsDao().findAll(
  54. address().and(name().or(loginPwd()).or(phone()).or(userNo()) )
  55. ).forEach(System.out::println);
  56. }
  57. @Test
  58. void testAndOr2() {
  59. userService.getJpaBasicsDao().findAll(
  60. address().and(
  61. loginPwd().or(phone()).or(name())
  62. ).or(
  63. loginPwd().and(
  64. phone().or(name())
  65. )
  66. )
  67. ).forEach(System.out::println);
  68. }
  69. @Test
  70. void test3() {
  71. Specification<User> test = (root, criteriaQuery, criteriaBuilder) -> criteriaQuery.getRestriction();;
  72. userService.getJpaBasicsDao().findAll(test).forEach(System.out::println);
  73. }
  74. public static Specification<User> name() {
  75. return (root, query, builder) -> builder.like(root.get("name"), "%用户%");
  76. }
  77. public static Specification<User> loginPwd() {
  78. return (root, query, builder) -> builder.like(root.get("loginPwd"), "123");
  79. }
  80. public static Specification<User> address() {
  81. return (root, query, builder) -> builder.like(root.get("address"), "重庆");
  82. }
  83. public static Specification<User> phone() {
  84. return (root, query, builder) -> builder.like(root.get("phone"), "123");
  85. }
  86. public static Specification<User> userNo() {
  87. return (root, query, builder) -> builder.like(root.get("phone"), "123");
  88. }
  89. }

其他

SerializableVO

实体互转方法to JpaExample to = jpaExampleVo.to(JpaExample.class);

  • to(list, Bvo.Class) List转List
  • to(b, Bvo.Class) B转Bvo
  • to(Page, Bvo.Class) JPA的Page转 Page
  • ·········

    JpaAuditFields

    1. /**
    2. * 表示该字段为创建时间字段,在这个实体被insert的时候,会自动为其赋值
    3. */
    4. @ApiModelProperty(value = "创建时间",hidden=true)
    5. private LocalDateTime createTime;
    6. /**
    7. * 表示该字段为创建人,在这个实体被insert的时候,会自动为其赋值
    8. */
    9. @ApiModelProperty(value = "创建人",hidden=true)
    10. private String createUserName;
    11. /**
    12. * 表示该字段为修改时间字段,在这个实体被update的时候,会自动为其赋值
    13. */
    14. @ApiModelProperty(value = "修改时间",hidden=true)
    15. private LocalDateTime updateTime;
    16. /**
    17. * 表示该字段为修改人,在这个实体被update的时候,会自动为其赋值
    18. */
    19. @ApiModelProperty(value = "修改人",hidden=true)
    20. private String updateUserName;

    JPA的预处理使用的MySQL版本选择测试

    示例项目地址

    https://github.com/en-o/Jdevelops-Example/tree/main/HJPA