springboot data jpa 多对多 小demo

  项目调整持久层框架有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();
    }
}

效果:

 

猜你喜欢

转载自blog.csdn.net/u012440725/article/details/128250619