项目调整持久层框架有mybatis转到jpa,用户和角色多对多小demo。
依赖pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.dxylearn.study</groupId>
<artifactId>myjpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>myjpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.配置文件 application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.password=123456
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/dbgirl
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
3.启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyjpaApplication {
public static void main(String[] args) {
SpringApplication.run(MyjpaApplication.class, args);
}
}
4.实体类
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "sys_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
@Column(name = "user_id")
private String userId;
@Column(name = "user_name")
private String userName;
@Column(name = "age")
private Integer age;
/*
* 配置用户到角色的多对多关系
* 配置多对多的映射关系
* 1.声明表关系
* @ManyToMany(targetEntity = Role.class) //多对多
* targetEntity:代表对方的实体类字节码
* 2.配置中间表(包含两个外键)
* @JoinTable
* name:中间表的名称
* joinColumns:配置当前对象在中间表的外键
* @JoinColumn的数组
* name:外键名
* referencedColumnName:参照的主表的主键名
* inverseJoinColumns:配置对方对象在中间表的外键
* */
//这里防止死循环无限输出
@JsonIgnoreProperties(value = { "users" })
//这边维护约束关系,多的发起放方
@ManyToMany(targetEntity = Role.class,cascade = CascadeType.PERSIST)
@JoinTable(name = "sys_user_role",
//joinColumns,当前对象在中间中的外键
joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
//inverseJoinColumns,对方对象在中间表的外键
inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} ,
//不生成外键
foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT),
inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private List<Role> roles;
}
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "sys_role")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
@Id
@Column(name = "role_id")
private String roleId;
@Column(name = "role_name")
private String roleName;
/*
*配置多对多
* */
@JsonIgnoreProperties(value = { "roles" })
//这边放弃维护约束关系,多的接受方
@ManyToMany(mappedBy = "roles",fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
private List<User> users;
}
dao:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
//这里不实例化,作为父级接口
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaSpecificationExecutor<T>,JpaRepository<T, ID> {
}
import com.dxylearn.study.domain.Role;
public interface RoleDao extends BaseRepository<Role, String> {
}
public interface UserDao extends BaseRepository<User, String> {
}
service:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public interface BaseService<T , ID extends Serializable> {
/**
* 新增或更新
*/
T save(T t);
/**
* 新增或更新
* 注意数量不要太大,特别是数据迁移时不要使用该方法
*/
Iterable<T> save(Iterable<T> entities);
/**
* 根据ID删除
*/
@Transactional(rollbackFor = Exception.class)
@Modifying
void del(String id);
@Transactional(rollbackFor = Exception.class)
@Modifying
void deleteInBatch(List<T> objList);
/**
* 根据实体删除
*/
//void del(T t);
/**
* 根据ID查找对象
*/
T findById(String id);
/**
* 获取所有列表
* @return
*/
List<T> findAll();
/**
* 统计所有条数
* @return
*/
Integer countAll();
/**
* 分页排序获取数据
* 禁止使用该接口进行count操作
* Pageable pageable = new PageRequest(0, 10, new Sort(Sort.Direction.DESC,"id"));
* @param pageable
* @return
*/
Page<T> findAll(Pageable pageable);
/**
* 多条件查询
* 注:多个条件间是and关系 & 参数是属性对应的类型 使用时注意避免结果集过大
* @param params {"username:like":"test"} 键的格式为字段名:过滤方式,过滤方式见{@code QueryTypeEnum}
* @return
*/
List<T> list(Map<String, Object> params);
/**
* 分页多条件查询
* 注:多个条件间是and关系 & 参数是属性对应的类型
* @param params {"username:like":"test"} 键的格式为字段名:过滤方式,过滤方式见{@code QueryTypeEnum}
* @param pageable 分页信息 new PageRequest(page, size,new Sort(Direction.DESC, "updateTime"))
* @return
*/
Page<T> list(Map<String, Object> params, Pageable pageable);
}
import com.dxylearn.study.dao.BaseRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public abstract class BaseServiceImpl<T ,ID extends Serializable> implements BaseService<T, ID> {
public abstract BaseRepository<T, String> getRepository();
@Override
public T save(T t) {
return getRepository().saveAndFlush(t);
}
@Override
public Iterable<T> save(Iterable<T> entities) {
for (T t : entities) {
}
return getRepository().saveAll(entities);
}
@Override
public void del(String id) {
T t = findById(id);
if (t == null) {
return;
}
getRepository().delete(t);
}
@Override
public void deleteInBatch(List<T> objList) {
getRepository().deleteInBatch(objList);
}
@Override
public T findById(String id) {
T t = getRepository().findById(id).orElse(null);
return t;
}
@Override
public List<T> findAll() {
return getRepository().findAll();
}
@Override
public Integer countAll() {
return getRepository().findAll().size();
}
@Override
public Page<T> findAll(Pageable pageable) {
return getRepository().findAll(pageable);
}
@Override
public List<T> list(final Map<String, Object> params) {
Specification<T> spec = new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
Object value = entry.getValue();
if (value == null ) {
continue;
}
String key = entry.getKey();
String[] arr = key.split(":");
Predicate predicate = getPredicate(arr, value, root, cb);
list.add(predicate);
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}
};
List<T> list = getRepository().findAll(spec);
return list;
}
@Override
public Page<T> list(final Map<String, Object> params, Pageable pageable) {
Specification<T> spec = new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
Object value = entry.getValue();
if (value == null) {
continue;
}
String key = entry.getKey();
String[] arr = key.split(":");
Predicate predicate = getPredicate(arr, value, root, cb);
list.add(predicate);
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}
};
Page<T> page = getRepository().findAll(spec, pageable);
return page;
}
private Predicate getPredicate(String[] arr, Object value,
Root<T> root, CriteriaBuilder cb) {
if (arr.length == 1) {
return cb.equal(root.get(arr[0]).as(value.getClass()), value);
}
if (QueryTypeEnum.like.name().equals(arr[1])) {
return cb.like(root.get(arr[0]).as(String.class), String.format("%%%s%%", value));
}
if (QueryTypeEnum.ne.name().equals(arr[1])) {
return cb.notEqual(root.get(arr[0]).as(value.getClass()), value);
}
if (QueryTypeEnum.in.name().equals(arr[1])) {
List<String> datas = new ArrayList<>();
if(value instanceof List){
datas =(List<String>) value;
}
return root.get(arr[0]).in(datas);
}
if (QueryTypeEnum.notin.name().equals(arr[1])) {
List<String> datas = new ArrayList<>();
if(value instanceof List){
datas =(List<String>) value;
}
return root.get(arr[0]).in(datas).not();
}
if (QueryTypeEnum.lt.name().equals(arr[1])) {
return getLessThanPredicate(arr, value, root, cb);
}
if (QueryTypeEnum.lte.name().equals(arr[1])) {
return getLessThanOrEqualToPredicate(arr, value, root, cb);
}
if (QueryTypeEnum.gt.name().equals(arr[1])) {
return getGreaterThanPredicate(arr, value, root, cb);
}
throw new UnsupportedOperationException(String.format("不支持的查询类型[%s]", arr[1]));
}
private Predicate getLessThanPredicate(String[] arr, Object value,
Root<T> root, CriteriaBuilder cb) {
if (Integer.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Integer.class), (int) value);
}
if (Long.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Long.class), (long) value);
}
if (Double.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Double.class), (double) value);
}
if (Float.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Float.class), (float) value);
}
if (Timestamp.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Timestamp.class), (Timestamp) value);
}
if (Date.class == value.getClass()) {
return cb.lessThan(root.get(arr[0]).as(Date.class), (Date) value);
}
return cb.lessThan(root.get(arr[0]).as(String.class), String.valueOf(value));
}
private Predicate getLessThanOrEqualToPredicate(String[] arr,
Object value, Root<T> root, CriteriaBuilder cb) {
if (Integer.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Integer.class), (int) value);
}
if (Long.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Long.class), (long) value);
}
if (Double.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Double.class), (double) value);
}
if (Float.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Float.class), (float) value);
}
if (Timestamp.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Timestamp.class), (Timestamp) value);
}
if (Date.class == value.getClass()) {
return cb.lessThanOrEqualTo(root.get(arr[0]).as(Date.class), (Date) value);
}
return cb.lessThanOrEqualTo(root.get(arr[0]).as(String.class), String.valueOf(value));
}
private Predicate getGreaterThanPredicate(String[] arr,
Object value, Root<T> root, CriteriaBuilder cb) {
if (Integer.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Integer.class), (int) value);
}
if (Long.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Long.class), (long) value);
}
if (Double.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Double.class), (double) value);
}
if (Float.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Float.class), (float) value);
}
if (Timestamp.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Timestamp.class), (Timestamp) value);
}
if (Date.class == value.getClass()) {
return cb.greaterThan(root.get(arr[0]).as(Date.class), (Date) value);
}
return cb.greaterThan(root.get(arr[0]).as(String.class), String.valueOf(value));
}
private Predicate getGreaterThanOrEqualToPredicate(String[] arr, Object value,
Root<T> root, CriteriaBuilder cb) {
if (Integer.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Integer.class), (int) value);
}
if (Long.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Long.class), (long) value);
}
if (Double.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Double.class), (double) value);
}
if (Float.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Float.class), (float) value);
}
if (Timestamp.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Timestamp.class), (Timestamp) value);
}
if (Date.class == value.getClass()) {
return cb.greaterThanOrEqualTo(root.get(arr[0]).as(Date.class), (Date) value);
}
return cb.lessThanOrEqualTo(root.get(arr[0]).as(String.class), String.valueOf(value));
}
public List<T> listByIds(final Map<String, Object> params) {
Specification<T> specification =(root, query, cb) -> {
List<Predicate> list = new ArrayList<Predicate>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
Object value = entry.getValue();
if (value == null) {
continue;
}
String key = entry.getKey();
if ("id".equals(key)) {
// 指定in需要的字段
Object o = params.get("id");
if(o instanceof List){
List<String> datas =(List<String>)o;
//设置值
Predicate validDnaPredicate = root.get("id").in(datas).not();
list.add(validDnaPredicate);
}
}else {
String[] arr = key.split(":");
Predicate predicate = getPredicate(arr, value, root, cb);
list.add(predicate);
}
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
};
List<T> list = getRepository().findAll(specification);
return list;
}
public enum QueryTypeEnum {
like,
equal,
ne,
lt,
lte,
gt,
gte,
in,
notin
}
}
public interface RoleService {
/**
*
* @param role
* @return
*/
Role save(Role role);
}
@Service
public class RoleServiceImpl extends BaseServiceImpl<Role, String> implements RoleService {
@Autowired
private RoleDao roleDao;
@Override
public BaseRepository<Role, String> getRepository() {
return roleDao;
}
@Override
public Role save(Role role) {
role.setRoleId(role.getRoleId()!=null ? role.getRoleId() : UUID.randomUUID().toString());
roleDao.save(role);
return role;
}
}
public interface UserService {
User save(User user);
List<User> findAll();
void deleteId(String id);
}
@Service
public class UserServiceImpl extends BaseServiceImpl<User, String> implements UserService {
@Autowired
private UserDao userDao;
@Override
public BaseRepository<User, String> getRepository() {
return userDao;
}
@Override
public User save(User user) {
user.setUserId(user.getUserId()!=null ? user.getUserId() : UUID.randomUUID().toString());
userDao.save(user);
return user;
}
@Override
public void deleteId(String id) {
userDao.deleteById(id);
}
}
Controller:
RestController
public class TestController {
@Resource
UserService userServer;
@GetMapping("/test")
public String getList(@RequestBody User user){
System.out.println(user);
userServer.save(user);
return "ok";
}
@DeleteMapping("/{id}")
public String deleteId(@PathVariable String id){
System.out.println(id);
userServer.deleteId(id);
return "ok";
}
@GetMapping("/query")
public List<User> getList(){
System.out.println("");
return userServer.findAll();
}
}
效果: