当前位置:Gxlcms > 数据库问题 > spring-boot-jap-layui-mysql 完整的jpa多对一

spring-boot-jap-layui-mysql 完整的jpa多对一

时间:2021-07-01 10:21:17 帮助过:9人阅读

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> <groupId>com.xfyuao</groupId> <artifactId>spring-boot-jpa-layui-2</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-jpa-layui-2</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.2.6.RELEASE</spring-boot.version> </properties> <dependencies> <!-- jpa依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- springmvc依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- mysql依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>true</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <!-- springboot版本 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>

2.application.properties

#应用项目名称
#server.context-path=/mydemo
#应用端口
#server.port=8080

# 数据源配置,IDEA当中需主动配置时区为GMT+8
spring.datasource.url=jdbc:mysql://localhost:3306/ace?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

##Spring Data JPA 配置,指明用的数据库,数据库方言,因为要生成sql语句
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
##运行时输出 jpa 执行的 sql 语句
spring.jpa.show-sql=true
## spring-boot-starter-data-jpa 自动映射创建表动作 配置: 有表更新,无表创建,按名称判断不会更新类型
spring.jpa.hibernate.ddl-auto=update

#修改 tomcat 的 URIEncoding 为 UTF-8
server.tomcat.uri-encoding=UTF-8
#集中解决各种编码问题
#banner.charset=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8

#jackson 对日期时间格式化设置
#springmvc(也就是controller层)返回前端页面时遵守的日期格式,把Date转化为String
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#jackson 对日期时间格式化设置:时区设置
spring.jackson.time-zone=GMT+8

3.启动类

package com.xfyuao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories("com.xfyuao.dao")
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

4.实体类、一:Dept

package com.xfyuao.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
@Entity//基于该类建表
@Table(name = "t_dept")//表名
@Data//主要要getter、setter、toString
@AllArgsConstructor//全参构造器
@NoArgsConstructor//无参构造器
public class Dept implements Serializable {
    @Id//标注主键列
    @GeneratedValue(strategy = GenerationType.IDENTITY)//mysql支持主键自增
    @Column(columnDefinition="int unsigned NOT NULL comment ‘备注:部门编号,主键自动增长‘")
    private Integer deptNo;
    @Column(columnDefinition="varchar(20) NOT NULL comment ‘备注:部门名称‘")
    private String dname;
    @Column(columnDefinition="text comment ‘备注:办公地点‘")
    private String loc;
}
package com.xfyuao.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name = "t_emp")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(columnDefinition = "int unsigned NOT NULL comment ‘备注:员工编号,主键自动增长‘")
    private Integer empNo;
    @Column(columnDefinition = "char(34) NOT NULL comment ‘备注:后台生成的卡号‘")
    private String empCardNo;
    @Column(columnDefinition = "varchar(20) NOT NULL comment ‘备注:员工姓名‘")
    private String ename;
    @Column(columnDefinition = "datetime NOT NULL comment ‘备注:入职日期‘")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")//springmvc接收日期字符串时按该格式转化成日期
    private Date hiredate;
    @Column(columnDefinition = "char(1) NOT NULL comment ‘备注:员工状态,0表示正常在职‘")
    private Integer state;
    @Column(columnDefinition = "text comment ‘备注:备注‘")
    private String remake;
    // 不要级联增删改
    @ManyToOne(targetEntity = Dept.class, cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
    //会自动在emp表新建非空列dept_no,作为外键,但不会创建外键约束
    @JoinColumn(name = "deptNo", referencedColumnName = "deptNo")
    private Dept dept;

}

5.接口

package com.xfyuao.dao;

import com.xfyuao.domain.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;

/**
 * 部门的dao接口,一个方法对于一条sql语句
 * 继承JpaRepository接口获取基本的crud方法
 * 继承JpaSpecificationExecutor获取实现动态sql查询的方法
 * */
public interface DeptDao extends JpaRepository<Dept, Integer>, JpaSpecificationExecutor<Dept> {
   
    /**
     * 这个方法完全不用写,就使用save方法返回实体类即可
     * 原因:继承的修改方法,在修改时如果没有某一列的值会把该列修改为null,
     * 所以想修改部分列、但不修改的列未传值,就需要使用自定义修改语句:JPQL或原生SQL
     * 方式:原生SQL
     * @return Modifying queries can only use void or int/Integer as return type!
     * */
    @Query(value = "update t_dept set dname=?1,loc=?2  where dept_no=?3 ", nativeQuery = true)
    @Modifying
    @Transactional
    public Integer updateDept(String dame,String loc,Integer deptNo);
    
}

 

package com.xfyuao.dao;

import com.xfyuao.domain.Dept;
import com.xfyuao.domain.Emp;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

public interface EmpDao extends JpaRepository<Emp, Integer>, JpaSpecificationExecutor<Emp> {
    /**
     * 根据外键id查询,使用的是关键字抽象方法,也可以使用原生sql实现;
     * @param dept 只需要部门编号即可
     * @return 该部门下的学生
     * */
    /*关键字抽象方法:findBy/readBy/getBy开头,加上属性名,
     * 表示根据该属性查询,参数对应该属性,有多个条件使用关键字拼接
     */
    public List<Emp> findByDept(Dept dept);
}

6.dto

package com.xfyuao.dto;

import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import com.xfyuao.domain.Emp;
import lombok.Data;

/**
 * 数据传输类,有额外的查询条件在该类中定义
 * 如:日期区间的多的一个日期
 * */
@Data
public class EmpDto extends Emp {
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date hiredate2;//结束日期
    
    //page分页的一种实现方式,另一种是每次接数据直接用PageUtil类接,参见DeptController的selectPageDept方法
    private Integer page=1 ;// 页码
    private Integer limit=10;// 每页条数
    
    @Override
    public String toString() {
        return super.toString() + " EmpDto [hiredate2=" + hiredate2 + ", page=" + page + ", limit=" + limit + "]";
    }
    
}

7.service

package com.xfyuao.service;

import com.xfyuao.domain.Dept;
import com.xfyuao.util.PageUtil;
import java.util.List;
import org.springframework.data.domain.Page;
/** * 部门的业务层,一个方法对应页面一个按钮功能 * 复杂业务逻辑要在本接口的实现类实现 * */ public interface DeptService { /** * 新增部门 * * @param dept 页面传递的要新增的部门信息 * @return 返回带id的部门对象 */ public Dept insert(Dept dept); /** * 删除部门 * * @param deptNo 要删除的部门的编号 * @return 返回状态码,1表示成功 */ public Integer delete(Integer deptNo); /** * 修改部门 * * @param dept 页面传递的要修改的部门信息 * @return 返回修改后的部门对象 */ public Integer update(Dept dept); /** * 动态条件分页查 * * @param deptDto 查询条件,包含分页 * @return 查询到的Page对象 */ public Page<Dept> selectByDynamicSQLPage(Dept dept, PageUtil pageUtil); /** * 查所有 * 员工的条件查、新增和修改员工、不能重复添加,都需要查所有 * @return 查询到的部门结果集 */ public List<Dept> selectAll(); }
package com.xfyuao.service;

import com.xfyuao.domain.Emp;
import com.xfyuao.domain.Emp;
import com.xfyuao.dto.EmpDto;
import com.xfyuao.dto.EmpDto;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface EmpService {
    /**
     * 新增员工
     * 
     * @param emp 页面传递的要新增的员工信息
     * @return 返回带id的员工对象
     */
    public Emp insert(Emp emp);

    /**
     * 删除员工
     * 
     * @param empNo 要删除的员工的id
     * @return 返回状态码
     */
    public Integer delete(Integer empNo);

    /**
     * 修改员工
     * 
     * @param emp 页面传递的要修改的员工信息
     * @return 返回修改后的员工对象
     */
    public Emp update(Emp emp);

    /**
     * 动态条件分页查
     * 
     * @param empDto 查询条件,包含分页
     * @return 查询到的Page对象
     */
    public Page<Emp> selectByDynamicSQLPage(EmpDto empDto);

    /**
     * 根据外键查询
     * 
     * @param deptNo 要查询的部门
     * @return 该部门下的员工
     */
    public List<Emp> selectByDeptNo(Integer deptNo);

}

8.impl

package com.xfyuao.service.impl;

import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.xfyuao.dao.DeptDao;
import com.xfyuao.domain.Dept;
import com.xfyuao.service.DeptService;
import com.xfyuao.util.PageUtil;

@Service // spring的ioc的体现,当前类交给spring管理(创建对象)并标注为service层
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptDao deptDao;

    @Override
    public Dept insert(Dept dept) {
        return deptDao.save(dept);
    }

    @Override
    public Integer delete(Integer deptNo) {
        try {
            deptDao.deleteById(deptNo);
            return 1;// 不报错就返回1,模仿数据库成功则受影响的行是1
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("删除失败!");
        }
        return 0;
    }

    @Override
    public Integer update(Dept dept) {
        return deptDao.updateDept(dept.getDname(), dept.getLoc(), dept.getDeptNo());
    }

    @Override
    public Page<Dept> selectByDynamicSQLPage(Dept dept, PageUtil pageUtil) {
        // 根据主键倒叙
        Sort sort = Sort.by(Sort.Direction.DESC, "deptNo");
        // 传入分页条件:页码和条数
        Pageable pageable = PageRequest.of(pageUtil.getPage() - 1, pageUtil.getLimit(), sort);
        // 动态SQL语句
        Specification<Dept> spec = this.myWhere(dept);
        return deptDao.findAll(spec, pageable);
    }

    @Override
    public List<Dept> selectAll() {
        return deptDao.findAll();
    }

    private Specification<Dept> myWhere(Dept dept) {
        Specification<Dept> spec = new Specification<Dept>() {

            @Override
            public Predicate toPredicate(Root<Dept> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.conjunction();// 动态 SQL 表达式
                List<Expression<Boolean>> exList = predicate.getExpressions();
                // 如果传来的条件中包含dname,就对dname模糊查
                if (dept.getDname() != null && !"".equals(dept.getDname())) {
                    exList.add(cb.like(root.<String>get("deptName"), "%" + dept.getDname() + "%"));
                }
                return predicate;
            }
        };
        return spec;
    }

}
package com.xfyuao.service.impl;

import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.xfyuao.dao.EmpDao;
import com.xfyuao.domain.Dept;
import com.xfyuao.domain.Emp;
import com.xfyuao.dto.EmpDto;
import com.xfyuao.service.EmpService;

@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpDao empDao;

    @Override
    public Emp insert(Emp emp) {
        return empDao.save(emp);
    }

    @Override
    public Integer delete(Integer empNo) {
        try {
            empDao.deleteById(empNo);
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("删除失败!");
        }
        return 0;
    }

    @Override
    public Emp update(Emp emp) {
        return empDao.save(emp);
    }

    @Override
    public Page<Emp> selectByDynamicSQLPage(EmpDto empDto) {
        Sort sort = Sort.by(Sort.Direction.ASC, "empNo");
        Pageable pageable = PageRequest.of(empDto.getPage() - 1, empDto.getLimit(), sort);
        Specification<Emp> spec = this.myWhere(empDto);
        return empDao.findAll(spec, pageable);
    }

    private Specification<Emp> myWhere(EmpDto empDto) {
        Specification<Emp> spec = new Specification<Emp>() {

            @Override
            public Predicate toPredicate(Root<Emp> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.conjunction();// 动态 SQL 表达式
                List<Expression<Boolean>> exList = predicate.getExpressions();

                if (empDto.getEname() != null && !"".equals(empDto.getEname())) {
                    exList.add(cb.like(root.<String>get("ename"), "%" + empDto.getEname() + "%"));
                }
                if (empDto.getEmpCardNo() != null && !"".equals(empDto.getEmpCardNo())) {
                    exList.add(cb.like(root.<String>get("empCardNo"), "%" + empDto.getEmpCardNo() + "%"));
                }
                //大于开始日期
                if (empDto.getHiredate() != null) {
                    exList.add(cb.greaterThanOrEqualTo(root.<Date>get("hiredate"), empDto.getHiredate()));
                }
                //小于结束日期
                if (empDto.getHiredate2() != null) {
                    exList.add(cb.lessThanOrEqualTo(root.<Date>get("hiredate"), empDto.getHiredate2()));
                }
                // 根据外键列查询
                if (empDto.getDept() != null && empDto.getDept().getDeptNo() != null) {
                    // 等值使用equal(x,y)
                    exList.add(cb.equal(root.<Integer>get("dept"), empDto.getDept().getDeptNo()));
                }
                return predicate;
            }
        };
        return spec;
    }

    @Override
    public List<Emp> selectByDeptNo(Integer deptNo) {
        return empDao.findByDept(new Dept(deptNo, null, null));
    }

}

9.controller

package com.xfyuao.web;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xfyuao.domain.Dept;
import com.xfyuao.domain.Emp;
import com.xfyuao.service.DeptService;
import com.xfyuao.service.EmpService;
import com.xfyuao.util.PageUtil;
import com.xfyuao.util.Result;

/**
 * 控制层
 */
@RestController // 每个方法都返回json数据,不走视图解析器
public class DeptController {

    @Autowired // spring的DI,依赖注入,这个是自动注入,自动去spring容器找同名或同类型的对象给该属性赋值
    private DeptService deptService;
    @Autowired
    private EmpService empService;

    /**
     * http://localhost:8080/insertDept 新增,id自增
     * 
     * @param dep
     * @return 0代表成功
     */
    @RequestMapping("/insertDept")
    public Object insertDept(Dept dept) {
        // 简单的业务逻辑可以放在controller层实现
        /* 新增前先判断是否已存在
         * 1.查询所有记录,然后判断名称是否存在,
         * 2.数据行和列较少,考虑没必要单独查名称
         * 3.员工模块的条件查也会用到全查所有部门
         * */
        List<Dept> list = deptService.selectAll();
        for (Dept d : list) {
            if (d.getDname().equals(dept.getDname())) {
                return new Result(1, "添加失败,该名称已存在!");
            }
        }
        Dept de = deptService.insert(dept);
        if (de != null) {
            return new Result(0, "添加成功!");
        }
        return new Result(2, "添加失败!");
    }

    /**
     * http://localhost:8080/deleteDept 根据id删除
     * 
     * @param depId
     * @return 0代表成功
     */
    @RequestMapping("/deleteDept")
    public Object deleteDept(Integer deptNo) {
        // 删除前先判断该部门下是否有数据(员工)
        List<Emp> list = empService.selectByDeptNo(deptNo);
        if (!list.isEmpty()) {
            return new Result(1, "该部门下有数据,删除失败!");
        }
        Integer i = deptService.delete(deptNo);
        if (i == 1) {
            return new Result(0, "删除成功!");
        }
        return new Result(1, "删除失败!");
    }

    /**
     * http://localhost:8080/updateDept 修改
     * 
     * @param dept
     * @return 0代表成功
     */
    @RequestMapping("/updateDept")
    public Object updateDept(Dept dept) {
        List<Dept> list = deptService.selectAll();
        for (Dept d : list) {
            // if (d.getDname().equals(dept.getDname())) {
            // 如果只判断名字,没修改直接提交时会报错,因为原名字是存在的
            // 所以还要判断id,如果传入的名字、id和某一条数据的完全一样,表示是同一条
            if (d.getDname().equals(dept.getDname()) && !d.getDeptNo().equals(dept.getDeptNo())) {
                return new Result(1, "修改失败,该名称已存在!");
            }
        }
        Integer i = deptService.update(dept);
        if (i == 1) {
            return new Result(0, "修改成功!");
        }
        return new Result(1, "修改失败!");
    }

    /**
     * http://localhost:8080/selectPageDept 动态条件分页查
     * 
     * @param dept 查询条件 pageUtil 分页数据
     * @return layui数据表格要的数据格式
     */
    @RequestMapping("/selectPageDept")
    public Object selectPageDept(Dept dept, PageUtil pageUtil) {
        Page<Dept> page = deptService.selectByDynamicSQLPage(dept, pageUtil);
        /*layui要的正确数据:            该页数据                总条数
         *     成功时:{"code":0, "msg":"", data:[{},{}...], count:100}
         *     code不为0则为失败,需要在msg中放入失败原因
         */
        return new Result(0, "", page.getContent(), page.getTotalElements());
    }

    /**
     * http://localhost:8080/selectAllDept 查全部
     * 
     * @return 全部部门
     */
    @RequestMapping("/selectAllDept")
    public Object selectAllDept() {
        return deptService.selectAll();
    }
}
package com.xfyuao.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.xfyuao.domain.Emp;
import com.xfyuao.dto.EmpDto;
import com.xfyuao.service.EmpService;
import com.xfyuao.util.CardUtil;
import com.xfyuao.util.Result;

@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * http://localhost:8080/insertEmp 新增,id自增
     * 
     * @param emp
     * @return 0代表成功
     */
    @RequestMapping("/insertEmp")
    public Object insertEmp(Emp emp) {
        System.out.println("接收到的要新增的emp:"+emp);
        //调用工具类获取一个员工卡号
        emp.setEmpCardNo(CardUtil.getEmpCard());
        Emp e = empService.insert(emp);
        if (e != null) {
            return new Result(0, "添加成功!");
        }
        return new Result(2, "添加失败!");
    }

    /**
     * http://localhost:8080/deleteEmp 根据id删除
     * 
     * @param empNo
     * @return 0代表成功
     */
    @RequestMapping("/deleteEmp")
    public Object deleteEmp(Integer empNo) {
        Integer i = empService.delete(empNo);
        if (i == 1) {
            return new Result(0, "删除成功!");
        }
        return new Result(1, "删除失败!");
    }

    /**
     * http://localhost:8080/updateEmp 修改
     * 
     * @param emp
     * @return 0代表成功
     */
    @RequestMapping("/updateEmp"
                        
                    

人气教程排行