最新SpringBoot2.0X整合SpringData JPA实战完整篇

先来张效果图吧
在这里插入图片描述

一、pom.xml 导入依赖包

<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
  </dependency>

 <!--jpa依赖-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

  <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
  </dependency>

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

  <!--devtools热部署-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
      <scope>true</scope>
  </dependency>

  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
          <exclusion>
              <groupId>org.junit.vintage</groupId>
              <artifactId>junit-vintage-engine</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
</dependencies>

二、application.yml 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_itboot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
     ddl-auto: update
    show-sql: true
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML
    encoding: UTF-8
    servlet:
      content-type: text/html
    cache: false
  resources:
    chain:
      strategy:
        content:
          enabled: false
          paths: /**
  mvc:
    static-path-pattern: /static/**
server:
  port: 8081

三、User 实体类

@Entity                     //告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "user")       //@Table指定和哪个表对应,如果省略该注解默认表名就是user
public class User {

    @Id      //这是一个主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)   //自增主键
    @Column(name = "id", unique = true, length = 11)      //unique = true 是指这个字段的值在这张表里不能重复,所有记录值都要唯一,就像主键那样;
    private Integer id;

    @Column(nullable=false,name = "name")  //省略默认列名就是属性名、nullable=false是这个字段在保存时必需有值,不能还是null值就调用save去保存入库;
    private String name;

    @Column(nullable=true,name = "sex")   //nullable默认可以为空,如果改为false,参数没有值的时候就save会报错
    private Integer sex;

    private String position;

    ...此处省略get、set方法
    
    //无参数的构造器
    public User() {
    }

    //添加信息:有参数的构造器
    public User(String name){
        this.name = name;
    }

    //更新信息:有参数的构造器
    public User(Integer id,String name){
        this.id = id;
        this.name = name;
    }
}

四、控制器、实现层核心接口编写

包结构如下:
在这里插入图片描述
UserDao.java

//继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法
public interface UserDao extends JpaRepository<User,Integer> {}

五、测试代码接口

UserController.java

   @Autowired
    private UserDao userDao;

    /***
     * 根据id查询用户信息
     * @param id
     * @return
     */
    @GetMapping(value = "getById/{id}")
    @ResponseBody
    public User getUser(@PathVariable("id") Integer id){
        Optional<User> user = userDao.findById(id);  //根据ID查询
        return user.ofNullable(user).map(user1->user.get()).orElse(null);
    }

    /***
     * 查询所有用户List集合
     * @return
     */
    @GetMapping(value = "list")
    @ResponseBody
    public List<User> findAll(){
        return userDao.findAll();
    }

    /**
     * 添加用户信息
     * @return
     */
    @PostMapping(value = "save")
    @ResponseBody
    public Map<String,Object> saveUser(){
        Map<String,Object> map = new HashMap<>();
        User user = userDao.save(new User("DT开发者002"));
        if (!StringUtils.isEmpty(user)){
            map.put("code",2000);
            map.put("message","添加成功");
            map.put("data",user);
        }else {
            map.put("code",20001);
            map.put("message","添加失败");
        }
        return map;
    }

    /***
     * 根据id修改用户信息
     * @return
     */
    @PostMapping(value = "update/{id}")
    @ResponseBody
    public Map<String,Object> updateUserById(@PathVariable Integer id){
        Map<String,Object> map = new HashMap<>();
        //1、根据id查询用户信息
        Optional<User> user = userDao.findById(id);
        if(user.isPresent()){
            //2、调用接口进行更新
            User update = userDao.save(new User(user.get().getId(), "DT开发者0022"));
            //3、判断是否成功
            if(!StringUtils.isEmpty(update)){
                map.put("code",2000);
                map.put("message","修改成功");
                map.put("data",user);
            }else {
                map.put("code",2001);
                map.put("message","事务回滚");
                map.put("data",user);
            }
            System.out.println("ID==="+user.get().getId());
        }else {
            map.put("code",2001);
            map.put("message","修改失败");
            map.put("data",user);
        }
        return map;
    }

    /**
     *根据主键id删除用户信息
     * @return
     */
    @DeleteMapping(value = "remove/{id}")
    @ResponseBody
    public Map<String,Object> removeUserById(@PathVariable Integer id){
        Map<String,Object> map = new HashMap<>();
        userDao.deleteById(id);
        map.put("code",2000);
        map.put("message","删除成功");
        map.put("data",id);
        return map;
    }

自定义CRUD、UserController.java

/**
     * 自定义:根据用户名查询用户信息
     * @param name
     * @return
     */
    @GetMapping(value = "findCustomByName")
    @ResponseBody
    public User findCustomByName(@PathParam("name") String name){
        return userService.findCustomByName(name);
    }

    /**
     * 自定义:根据用户名查询用户信息 (模糊查询)
     * @param name
     * @return
     */
    @GetMapping(value = "findVagueByName")
    @ResponseBody
    public List<User> findVagueByName(@PathParam("name") String name){
        return userService.findVagueByName(name);
    }

    /**
     * 自定义:根据用户名id更新用户信息
     * @param user
     * @return
     */
    @PostMapping(value = "updateCustomByById")
    @ResponseBody
    public Map<String,Object> updateCustomByById(User user){
        return userService.updateCustomByById(user);
    }


    /**
     * 自定义:根据用户名id删除用户信息
     * @param id
     * @return
     */
    @DeleteMapping(value = "removeCustomByById/{id}")
    @ResponseBody
    public Map<String,Object> removeCustomByById(@PathVariable Integer id){
        return userService.removeCustomByById(id);
    }

UserServiceImpl .java

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;
    
    /**
     * 自定义:根据用户名查询用户信息
     * @param name
     * @return
     */
    @Override
    public User findCustomByName(String name) {
        if(StringUtils.isNotBlank(name)){
            return userDao.findCustomByName(name);
        }else {
            return null;
        }
    }

    /**
     * 自定义:根据用户名查询用户信息 (模糊查询)
     * @param name
     * @return
     */
    @Override
    public List<User> findVagueByName(String name) {
        if(StringUtils.isNotBlank(name)){
            return userDao.findVagueByName(name);
        }else {
            return null;
        }
    }

    /**
     * 自定义:根据用户名id更新用户信息
     * @param user
     * @return
     */
    @Override
    @Transactional  //必须加@Transactional,来代表这是一个事务级别的操作。jpa要求,'没有事务支持,不能执行更新和删除操作'
    public Map<String, Object> updateCustomByById(User user) {
        Map<String,Object> map = new HashMap<>();
        if(user !=null){
            //注意:1、返回值只有int和void 2、入参绝对不能定义成 User对象,JPA不支持,只有查询可以使用SPEL表达式
            int user1 = userDao.updateCustomByById(user.getId(),user.getName());
            if(user1 > 0){
                map.put("code","2000");
                map.put("message","修改成功");
                map.put("data",user1);
            }else {
                map.put("code","2001");
                map.put("message","修改失败");
            }
        }else {
            map.put("code","2001");
            map.put("message","参数不能为空");
        }
        return map;
    }

    /**
     * 自定义:根据用户名id删除用户信息
     * @param id
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> removeCustomByById(Integer id) {
        Map<String,Object> map = new HashMap<>();
        int count = userDao.removeCustomByById(id);
        if(count > 0){
            map.put("code","2000");
            map.put("message","删除成功");
            map.put("data",id);
        }else {
            map.put("code","2001");
            map.put("message","删除失败");
        }
        return map;
    }
}

UserDao.java

public interface UserDao extends JpaRepository<User,Integer> {

    /**
     * 自定义:根据用户名查询用户信息
     * @param name
     * @return
     */
    @Query(value = "select id,name from user where name = :name",nativeQuery = true)
    User findCustomByName(@Param("name") String name);

    /**
     * 自定义:根据用户名查询用户信息 (模糊查询)
     * @param name
     * @return
     */
    //@Query(value = "select id,name from user where name like %:name%",nativeQuery = true) //第一种写法
    @Query(value = "select t.id,t.name from user t where t.name like %?1%",nativeQuery = true)  //第二种写法 1表示占位符,从第一个参数开始
    List<User> findVagueByName(String name);

    /**
     * 自定义:根据用户名id更新用户信息
     * @param id
     * @param name
     * @return
     */
    @Modifying
    @Query(value = "update user set name = :name where id = :id",nativeQuery = true)
    int updateCustomByById(Integer id,String name);  //入参绝对不能定义成 User对象,JPA不支持,只有查询可以使用SPEL表达式

    /**
     * 自定义:根据用户名id删除用户信息
     * 执行完modifying query, EntityManager可能会包含过时的数据,因为EntityManager不会自动清除实体。
     * 只有添加clearAutomatically属性,EntityManager才会自动清除实体对象。
     * @param id
     * @return
     */
    @Modifying(clearAutomatically = true)
    @Query(value = "delete from user where id = :id",nativeQuery = true)
    int removeCustomByById(Integer id);
}

六、JPA + BootStrap 无条件查询分页

UserController.java

/**
 * 分页(无条件查询)
 * @param modelMap
 * @param pageNumber
 * @param pageSize
 * @return
 */
@GetMapping(value = "listUsers")
public String listUsers(ModelMap modelMap,
                            @RequestParam(value = "pageNumber",defaultValue = "0") Integer pageNumber,
                            @RequestParam(value = "pageSize",defaultValue = "5") Integer pageSize){
    //设置分页
    Pageable pageable = PageRequest.of(pageNumber,pageSize, Sort.Direction.DESC, "id");
    //进行查询
    Page<User> userPage = userDao.findAll(pageable);
    modelMap.addAttribute("data",userPage);
    return "index";
}

index.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="page">
<head>
    <meta charset="UTF-8">
    <title>分页</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" >

    <style>
        .active{
            background: #49af4f !important;
            color: #fff !important;
        }
    </style>
</head>
<body style="padding: 50px;">
<div class="panel panel-success">
    <div class="panel-heading">
        <h2 class="panel-title" style="text-align: center;font-weight: bold;">无条件查询 | 分页</h2>
    </div>
    <div class="panel-body">

        <!--bootstrap表格-->
        <table class="table table-hover">
            <thead>
            <tr>
                <th>ID</th>
                <th>用户</th>
                <th>性别</th>
                <th>职位</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="user : ${data}">
                <td th:text="${user.id}"></td>
                <td th:text="${user.name}"></td>
                <td th:text="${user.sex == 1 ? '女':'男'}"></td>
                <td th:text="${user.position}">2</td>
            </tr>
            </tbody>
        </table>

        <!--bootstrap自定义分页-->
        <ul class="pager">
            <li th:if="${data.hasPrevious()}">
                <a th:href="@{/user/listUsers(pageNumber=0)}">首页</a>
            </li>
            <li th:if="${data.hasPrevious()}">
                <a th:href="@{/user/listUsers(pageNumber=${data.number}-1)}">上一页</a>
            </li>

            <!--总页数大于等于0并且小于等于5-->
            <div th:if="${(data.totalPages le 5) and (data.totalPages gt 0)}" th:remove="tag">
                <!--根据一个数字在页面循环生成固定的标签-->
                <div th:each="pg : ${#numbers.sequence(0, data.totalPages - 1)}" th:remove="tag">
                    <!--如果循环的数等于当前页-->
                    <span th:if="${pg eq data.getNumber()}" th:remove="tag">
                        <li><span class="active" th:text="${pg+1}"></span></li>
                    </span>
                    <!--如果循环的数不等于当前页-->
                    <span th:unless="${pg eq data.getNumber()}" th:remove="tag">
                        <li><a th:href="@{/user/listUsers(pageNumber=${pg})}" th:text="${pg+1}"></a></li>
                    </span>
                </div>
            </div>

            <!-- 总页数大于5时、中间留五个分页条 -->
            <div th:if="${data.totalPages gt 5}" th:remove="tag">
                <li th:if="${data.getNumber()-2 ge 0}"><a th:href="@{/user/listUsers(pageNumber=${data.getNumber()}-2)}" th:text="${data.getNumber()-1}"></a></li>
                <li th:if="${data.getNumber()-1 ge 0}"><a th:href="@{/user/listUsers(pageNumber=${data.getNumber()}-1)}" th:text="${data.getNumber()}"></a></li>
                <li><span class="active" th:text="${data.getNumber()+1}"></span></li>
                <li th:if="${data.getNumber()+1 lt data.totalPages}"><a th:href="@{/user/listUsers(pageNumber=${data.getNumber()}+1)}" th:text="${data.getNumber()+2}"></a></li>
                <li th:if="${data.getNumber()+2 lt data.totalPages}"><a th:href="@{/user/listUsers(pageNumber=${data.getNumber()}+2)}" th:text="${data.getNumber()+3}"></a></li>
            </div>

            <li  th:if="${data.hasNext()}">
                <a th:href="@{/user/listUsers(pageNumber=${data.getNumber()}+1)}">下一页</a>
            </li>
            <li><a th:href="@{/user/listUsers(pageNumber=${data.totalPages}-1)}">尾页</a></li>
            <li><span th:utext="'共'+${data.totalPages}+'页 / 总'+${data.totalElements}+'条'"></span></li>
        </ul>
    </div>
</div>

</body>
</html>

效果:
在这里插入图片描述

七、JPA + BootStrap 带条件查询分页

UserController.java

/**
 * 分页(带条件查询)
 * @param modelMap
 * @param pageNumber
 * @param pageSize
 * @param userQuery
 * @return
 */
@GetMapping(value = "listUserQuery")
public String listUserQuery(ModelMap modelMap,
                                @RequestParam(value = "pageNumber",defaultValue = "0") Integer pageNumber,
                                @RequestParam(value = "pageSize",defaultValue = "5") Integer pageSize,
                                UserQuery userQuery){
    //设置分页
    Pageable pageable = PageRequest.of(pageNumber,pageSize,Sort.Direction.ASC, "id");
    //进行查询
    Page<User> userPage = userService.findUserQuery(pageable,userQuery);
    modelMap.addAttribute("data",userPage);
    modelMap.addAttribute("name",userQuery.getName());
    modelMap.addAttribute("sex",userQuery.getSex());
    modelMap.addAttribute("position",userQuery.getPosition());
    return "home";
}

UserQuery.java

//数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输
public class UserQuery {

    private String name;

    private Integer sex;

    private String position;
    
    ...此处省略get、set
}

UserServiceImpl.java

/**
 * 分页(带条件查询)
 * @param pageable
 * @param userQuery
 * @return
 */
@Override
public Page<User> findUserQuery(Pageable pageable, UserQuery userQuery) {
    Page<User> userPage = userDao.findAll(new Specification<User>(){
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
            List<Predicate> list = new ArrayList<>();
            if (StringUtils.isNotBlank(userQuery.getName())){
                list.add(criteriaBuilder.equal(root.get("name").as(String.class), userQuery.getName()));
            }
            if(userQuery.getSex() != null){
                list.add(criteriaBuilder.equal(root.get("sex").as(Integer.class), userQuery.getSex()));
            }
            if (StringUtils.isNotBlank(userQuery.getPosition())){
                list.add(criteriaBuilder.equal(root.get("position").as(String.class), userQuery.getPosition()));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        }
    },pageable);
    return userPage;
}

效果1
在这里插入图片描述
效果2
在这里插入图片描述

八、demo地址、可下载

完整代码已同步至Github,可下载 Github地址 、如果有问题可随时提问,觉得不错,欢迎点赞评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小严

你的鼓励是我创作的源泉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值