先来张效果图吧
一、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地址 、如果有问题可随时提问,觉得不错,欢迎点赞评论。