在实际开发中,最为常见的是基于数据库的CRUD封装等,比如SpringBoot集成MySQL数据库,常用的方式有JPA和MyBatis; 本文是SpringBoot第23讲,主要介绍基于JPA方式的基础封装思路。
需要对MySQL,JPA以及接口封装有了解。
MySQL第一讲:MySQL索引规范
MySQL第六讲:MySQL语法基础(库表操作/子查询/事务/权限管理)
MySQL第三讲:数据库基础面试题汇总(mysql调优/底层B+ tree机制/sql执行计划详解/索引优化详解/sql语句优化)
本例主要简单示例下基于JPA DAO/Service层封装, 并且注意下如下例子MySQL是5.7版本,8.x版本相关例子也在示例源码中。
创建MySQL的schema test_db, 导入SQL 文件如下
DROP TABLE IF EXISTS `tb_role`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`role_key` varchar(255) NOT NULL,
`description` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_role`
--
LOCK TABLES `tb_role` WRITE;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
INSERT INTO `tb_role` VALUES (1,'admin','admin','admin','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_user`
--
DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`email` varchar(45) DEFAULT NULL,
`phone_number` int(11) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_user`
--
LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (1,'qiwenjie','123456','[email protected]',1212121213,'afsdfsaf','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_user_role`
--
DROP TABLE IF EXISTS `tb_user_role`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_user_role`
--
LOCK TABLES `tb_user_role` WRITE;
/*!40000 ALTER TABLE `tb_user_role` DISABLE KEYS */;
INSERT INTO `tb_user_role` VALUES (1,1);
/*!40000 ALTER TABLE `tb_user_role` ENABLE KEYS */;
UNLOCK TABLES;
引入maven依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>com.github.wenhaogroupId>
<artifactId>jpa-specartifactId>
<version>3.1.0version>
dependency>
增加yml配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_user?useSSL=false&autoReconnect=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: qwj930828
initial-size: 20
max-idle: 60
max-wait: 10000
min-idle: 10
max-active: 200
jpa:
generate-ddl: false
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
format_sql: true
use-new-id-generator-mappings: false
USER/ROLE
BaseEntity
package springboot.mysql8.jpa.entity;
import java.io.Serializable;
/**
* @author qiwenjie
*/
public interface BaseEntity extends Serializable {
}
User
package springboot.mysql8.jpa.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Set;
/**
* @author qiwenjie
*/
@Getter
@Setter
@ToString
@Entity
@Table(name = "tb_user")
public class User implements BaseEntity {
/**
* user id.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
/**
* username.
*/
private String userName;
/**
* user pwd.
*/
private String password;
/**
* email.
*/
private String email;
/**
* phoneNumber.
*/
private long phoneNumber;
/**
* description.
*/
private String description;
/**
* create date time.
*/
private LocalDateTime createTime;
/**
* update date time.
*/
private LocalDateTime updateTime;
/**
* join to role table.
*/
@ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
@JoinTable(name = "tb_user_role", joinColumns = {
@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")})
private Set<Role> roles;
}
Role
package springboot.mysql8.jpa.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* @author qiwenjie
*/
@Getter
@Setter
@ToString
@Entity
@Table(name = "tb_role")
public class Role implements BaseEntity {
/**
* role id.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
/**
* role name.
*/
private String name;
/**
* role key.
*/
private String roleKey;
/**
* description.
*/
private String description;
/**
* create date time.
*/
private LocalDateTime createTime;
/**
* update date time.
*/
private LocalDateTime updateTime;
}
BaseDao
package springboot.mysql8.jpa.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import springboot.mysql8.jpa.entity.BaseEntity;
import java.io.Serializable;
/**
* @author qiwenjie
*/
@NoRepositoryBean
public interface IBaseDao<T extends BaseEntity, I extends Serializable>
extends JpaRepository<T, I>, JpaSpecificationExecutor<T> {
}
UserDao
package springboot.mysql8.jpa.dao;
import org.springframework.stereotype.Repository;
import springboot.mysql8.jpa.entity.User;
/**
* @author qiwenjie
*/
@Repository
public interface IUserDao extends IBaseDao<User, Long> {
}
RoleDao
package springboot.mysql8.jpa.dao;
import org.springframework.stereotype.Repository;
import springboot.mysql8.jpa.entity.Role;
/**
* @author qiwenjie
*/
@Repository
public interface IRoleDao extends IBaseDao<Role, Long> {
}
封装BaseService
package springboot.mysql8.jpa.service;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
/**
* @author qiwenjie
*/
public interface IBaseService<T, I extends Serializable> {
/**
* @param id id
* @return T
*/
T find(I id);
/**
* @return List
*/
List<T> findAll();
/**
* @param ids ids
* @return List
*/
List<T> findList(I[] ids);
/**
* @param ids ids
* @return List
*/
List<T> findList(Iterable<I> ids);
/**
* @param pageable pageable
* @return Page
*/
Page<T> findAll(Pageable pageable);
/**
* @param spec spec
* @param pageable pageable
* @return Page
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);
/**
* @param spec spec
* @return T
*/
T findOne(Specification<T> spec);
/**
* count.
*
* @return long
*/
long count();
/**
* count.
*
* @param spec spec
* @return long
*/
long count(Specification<T> spec);
/**
* exists.
*
* @param id id
* @return boolean
*/
boolean exists(I id);
/**
* save.
*
* @param entity entity
*/
void save(T entity);
/**
* save.
*
* @param entities entities
*/
void save(List<T> entities);
/**
* update.
*
* @param entity entity
* @return T
*/
T update(T entity);
/**
* delete.
*
* @param id id
*/
void delete(I id);
/**
* delete by ids.
*
* @param ids ids
*/
void deleteByIds(List<I> ids);
/**
* delete.
*
* @param entities entities
*/
void delete(T[] entities);
/**
* delete.
*
* @param entities entities
*/
void delete(Iterable<T> entities);
/**
* delete.
*
* @param entity entity
*/
void delete(T entity);
/**
* delete all.
*/
void deleteAll();
/**
* find list.
*
* @param spec spec
* @return list
*/
List<T> findList(Specification<T> spec);
/**
* find list.
*
* @param spec spec
* @param sort sort
* @return List
*/
List<T> findList(Specification<T> spec, Sort sort);
/**
* flush.
*/
void flush();
}
BaseService实现类
package springboot.mysql8.jpa.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import springboot.mysql8.jpa.dao.IBaseDao;
import springboot.mysql8.jpa.entity.BaseEntity;
import springboot.mysql8.jpa.service.IBaseService;
import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
* @author qiwenjie
*/
@Slf4j
@Transactional
public abstract class BaseDoServiceImpl<T extends BaseEntity, I extends Serializable> implements IBaseService<T, I> {
/**
* @return IBaseDao
*/
public abstract IBaseDao<T, I> getBaseDao();
/**
* findById.
*
* @param id id
* @return T
*/
@Override
public T find(I id) {
return getBaseDao().findById(id).orElse(null);
}
/**
* @return List
*/
@Override
public List<T> findAll() {
return getBaseDao().findAll();
}
/**
* @param ids ids
* @return List
*/
@Override
public List<T> findList(I[] ids) {
List<I> idList = Arrays.asList(ids);
return getBaseDao().findAllById(idList);
}
/**
* find list.
*
* @param spec spec
* @return list
*/
@Override
public List<T> findList(Specification<T> spec) {
return getBaseDao().findAll(spec);
}
/**
* find list.
*
* @param spec spec
* @param sort sort
* @return List
*/
@Override
public List<T> findList(Specification<T> spec, Sort sort) {
return getBaseDao().findAll(spec, sort);
}
/**
* find one.
*
* @param spec spec
* @return T
*/
@Override
public T findOne(Specification<T> spec) {
return getBaseDao().findOne(spec).orElse(null);
}
/**
* @param pageable pageable
* @return Page
*/
@Override
public Page<T> findAll(Pageable pageable) {
return getBaseDao().findAll(pageable);
}
/**
* count.
*
* @return long
*/
@Override
public long count() {
return getBaseDao().count();
}
/**
* count.
*
* @param spec spec
* @return long
*/
@Override
public long count(Specification<T> spec) {
return getBaseDao().count(spec);
}
/**
* exists.
*
* @param id id
* @return boolean
*/
@Override
public boolean exists(I id) {
return getBaseDao().findById(id).isPresent();
}
/**
* save.
*
* @param entity entity
*/
@Override
public void save(T entity) {
getBaseDao().save(entity);
}
/**
* save.
*
* @param entities entities
*/
@Override
public void save(List<T> entities) {
getBaseDao().saveAll(entities);
}
/**
* update.
*
* @param entity entity
* @return T
*/
@Override
public T update(T entity) {
return getBaseDao().saveAndFlush(entity);
}
/**
* delete.
*
* @param id id
*/
@Override
public void delete(I id) {
getBaseDao().deleteById(id);
}
/**
* delete by ids.
*
* @param ids ids
*/
@Override
public void deleteByIds(List<I> ids) {
getBaseDao().deleteAllById(ids);
}
/**
* delete all.
*/
@Override
public void deleteAll() {
getBaseDao().deleteAllInBatch();
}
/**
* delete.
*
* @param entities entities
*/
@Override
public void delete(T[] entities) {
List<T> tList = Arrays.asList(entities);
getBaseDao().deleteAll(tList);
}
/**
* delete.
*
* @param entities entities
*/
@Override
public void delete(Iterable<T> entities) {
getBaseDao().deleteAll(entities);
}
/**
* delete.
*
* @param entity entity
*/
@Override
public void delete(T entity) {
getBaseDao().delete(entity);
}
/**
* @param ids ids
* @return List
*/
@Override
public List<T> findList(Iterable<I> ids) {
return getBaseDao().findAllById(ids);
}
/**
* @param spec spec
* @param pageable pageable
* @return Page
*/
@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
return getBaseDao().findAll(spec, pageable);
}
/**
* flush.
*/
@Override
public void flush() {
getBaseDao().flush();
}
}
UserService接口定义
package springboot.mysql8.jpa.service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import springboot.mysql8.jpa.entity.User;
import springboot.mysql8.jpa.entity.query.UserQueryBean;
/**
* @author qiwenjie
*/
public interface IUserService extends IBaseService<User, Long> {
/**
* find by page.
*
* @param userQueryBean query
* @param pageRequest pageRequest
* @return page
*/
Page<User> findPage(UserQueryBean userQueryBean, PageRequest pageRequest);
}
UserService实现类
import com.github.wenhao.jpa.Specifications;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import springboot.mysql8.jpa.dao.IBaseDao;
import springboot.mysql8.jpa.dao.IUserDao;
import springboot.mysql8.jpa.entity.User;
import springboot.mysql8.jpa.entity.query.UserQueryBean;
import springboot.mysql8.jpa.service.IUserService;
@Service
public class UserDoServiceImpl extends BaseDoServiceImpl<User, Long> implements IUserService {
/**
* userDao.
*/
private final IUserDao userDao;
/**
* init.
*
* @param userDao2 user dao
*/
public UserDoServiceImpl(final IUserDao userDao2) {
this.userDao = userDao2;
}
/**
* @return base dao
*/
@Override
public IBaseDao<User, Long> getBaseDao() {
return this.userDao;
}
/**
* find by page.
*
* @param queryBean query
* @param pageRequest pageRequest
* @return page
*/
@Override
public Page<User> findPage(UserQueryBean queryBean, PageRequest pageRequest) {
Specification<User> specification = Specifications.<User>and()
.like(StringUtils.isNotEmpty(queryBean.getName()), "user_name", queryBean.getName())
.like(StringUtils.isNotEmpty(queryBean.getDescription()), "description",
queryBean.getDescription())
.build();
return this.getBaseDao().findAll(specification, pageRequest);
}
}
RoleService接口定义
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import springboot.mysql8.jpa.entity.Role;
import springboot.mysql8.jpa.entity.query.RoleQueryBean;
public interface IRoleService extends IBaseService<Role, Long> {
/**
* find page by query.
*
* @param roleQueryBean query
* @param pageRequest pageRequest
* @return page
*/
Page<Role> findPage(RoleQueryBean roleQueryBean, PageRequest pageRequest);
}
RoleService实现类
import com.github.wenhao.jpa.Specifications;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import springboot.mysql8.jpa.dao.IBaseDao;
import springboot.mysql8.jpa.dao.IRoleDao;
import springboot.mysql8.jpa.entity.Role;
import springboot.mysql8.jpa.entity.query.RoleQueryBean;
import springboot.mysql8.jpa.service.IRoleService;
@Service
public class RoleDoServiceImpl extends BaseDoServiceImpl<Role, Long> implements IRoleService {
/**
* roleDao.
*/
private final IRoleDao roleDao;
/**
* init.
*
* @param roleDao2 role dao
*/
public RoleDoServiceImpl(final IRoleDao roleDao2) {
this.roleDao = roleDao2;
}
/**
* @return base dao
*/
@Override
public IBaseDao<Role, Long> getBaseDao() {
return this.roleDao;
}
/**
* find page by query.
*
* @param roleQueryBean query
* @param pageRequest pageRequest
* @return page
*/
@Override
public Page<Role> findPage(RoleQueryBean roleQueryBean, PageRequest pageRequest) {
Specification<Role> specification = Specifications.<Role>and()
.like(StringUtils.isNotEmpty(roleQueryBean.getName()), "name",
roleQueryBean.getName())
.like(StringUtils.isNotEmpty(roleQueryBean.getDescription()), "description",
roleQueryBean.getDescription())
.build();
return this.roleDao.findAll(specification, pageRequest);
}
}
UserController
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;
import springboot.mysql8.jpa.entity.User;
import springboot.mysql8.jpa.entity.query.UserQueryBean;
import springboot.mysql8.jpa.entity.response.ResponseResult;
import springboot.mysql8.jpa.service.IUserService;
import java.time.LocalDateTime;
/**
* @author qiwenjie
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
/**
* @param user user param
* @return user
*/
@ApiOperation("Add/Edit User")
@PostMapping("add")
public ResponseResult<User> add(User user) {
if (user.getId()==null || !userService.exists(user.getId())) {
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
} else {
user.setUpdateTime(LocalDateTime.now());
userService.update(user);
}
return ResponseResult.success(userService.find(user.getId()));
}
/**
* @return user list
*/
@ApiOperation("Query User One")
@GetMapping("edit/{userId}")
public ResponseResult<User> edit(@PathVariable("userId") Long userId) {
return ResponseResult.success(userService.find(userId));
}
/**
* @return user list
*/
@ApiOperation("Query User Page")
@GetMapping("list")
public ResponseResult<Page<User>> list(@RequestParam int pageSize, @RequestParam int pageNumber) {
return ResponseResult.success(userService.findPage(UserQueryBean.builder().build(), PageRequest.of(pageNumber, pageSize)));
}
}
查询分页列表
todo