• SpringBoot使用JPA实现增删查改


    运行环境

    • SpringBoot2.3.0
    • JDK1.8
    • IDEA2020.1.2
    • MySQL5.7

    依赖及应用程序配置

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <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>
    <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>
    
    1. 升级到SpringBoot2.2,spring-boot-starter-test默认使用JUnit 5作为单元测试框架 ,写单元测试时注解@RunWith(Spring.class)升级为@ExtendWith(SpringExtension.class)
    2. 升级到SpringBoot2.3,hibernate-validator从spring-boot-starter-web移除,需要单独引入
    3. 升级到SpringBoot2.3,MySQL驱动由com.mysql.jdbc.Driver变更为com.mysql.cj.jdbc.Driver;同时,数据源url需要添加serverTimezone=UTC&useSSL=false参数
    4. 升级到SpringBoot2.x,默认不自动注入HiddenHttpMethodFilter ,需要设置spring.mvc.hiddenmethod.filter.enabled=true开启PUT、DELETE方法支持

    应用程序配置如下:

    spring.application.name=springbootjpa
    management.endpoints.jmx.exposure.include=*
    management.endpoints.web.exposure.include=*
    management.endpoint.health.show-details=always
    # 应用服务 WEB 访问端口
    server.port=8080
    # Actuator Web 访问端口
    management.server.port=8081
    
    # mysql setting
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springbootjpa?serverTimezone=UTC&useSSL=false
    spring.datasource.username=username
    spring.datasource.password=password
    
    # JPA setting
    spring.jpa.properties.hibernate.hbm2ddl.auto=update
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
    spring.jpa.show-sql=true
    
    # thymeleaf setting
    spring.thymeleaf.cache=false
    
    # delete、put方法支持
    spring.mvc.hiddenmethod.filter.enabled=true
    

    定义实体

    使用@Entity标记实体类

    import lombok.Data;
    
    import javax.persistence.*;
    import javax.validation.constraints.NotEmpty;
    import java.io.Serializable;
    
    @Entity
    @Data
    public class Article extends BaseEntity implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false, unique = true)
        @NotEmpty(message = "标题不能为空")
        private String title;
    
        @Column(nullable = false)
        private String body;
    }
    

    为了自动添加创建日期、修改日期、创建人及修改人,我们把创建、修改信息放到父类中由实体类继承,并开启SpringBoot的自动审计功能,将创建/修改信息自动注入

    1、定义实体类的父类,@CreatedDate、@LastModifiedDate、@CreatedBy、@LastModifiedBy标注相应字段

    import org.hibernate.annotations.Columns;
    import org.springframework.data.annotation.CreatedBy;
    import org.springframework.data.annotation.CreatedDate;
    import org.springframework.data.annotation.LastModifiedBy;
    import org.springframework.data.annotation.LastModifiedDate;
    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    
    import javax.persistence.Column;
    import javax.persistence.EntityListeners;
    import javax.persistence.MappedSuperclass;
    
    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public class BaseEntity {
        @CreatedDate
        private Long createTime;
    
        @LastModifiedDate
        private Long updateTime;
        
        @Column(name = "create_by")
        @CreatedBy
        private String createBy;
    
        @Column(name = "lastmodified_by")
        @LastModifiedBy
        private String lastmodifiedBy;
        
        public Long getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Long createTime) {
            this.createTime = createTime;
        }
    
        public Long getUpdateTime() {
            return updateTime;
        }
    
        public void setUpdateTime(Long updateTime) {
            this.updateTime = updateTime;
        }
        
        public String getCreateBy() {
            return createBy;
        }
    
        public void setCreateBy(String createBy) {
            this.createBy = createBy;
        }
    
        public String getLastmodifiedBy() {
            return lastmodifiedBy;
        }
    
        public void setLastmodifiedBy(String lastmodifiedBy) {
            this.lastmodifiedBy = lastmodifiedBy;
        }
    }
    

    @MappedSuperclass注解:

    • 作用于实体类的父类上,父类不生成对应的数据库表
    • 标注@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口
    • 每个子类(实体类)对应一张数据库表,数据库表包含子类属性和父类属性
    • 标注@MappedSuperclass的类可以直接标注@EntityListeners实体监听器

    @EntityListeners(AuditingEntityListener.class)注解:

    • 作用范围仅在标注@MappedSuperclass类的所有继承类中,并且实体监听器可以被其子类继承或重载
    • 开启JPA的审计功能,需要在SpringBoot的入口类标注@EnableJpaAuditing

    创建日期、修改日期有默认方法注入值,但创建人和修改人注入则需要手动实现AuditorAware接口:

    @Configuration
    public class BaseEntityAuditor implements AuditorAware<String> {
        @Override
        public Optional<String> getCurrentAuditor() {
            return "";
        }
    }
    

    DAO层实现

    JPA支持通过约定方法名进行数据库查询、修改:

    import org.springframework.data.jpa.repository.JpaRepository;
    import springbootjpa.entity.Article;
    
    public interface ArticleRepository extends JpaRepository<Article, Long> {
        Article findById(long id);
    }
    

    通过约定方法名查询,只需实现JpaRepository接口声明查询方法而不需要具体实现

    此外,可以在方法上标注@Query实现JPQL或原生SQL查询

    JpaRepository<T, ID>,T表示要操作的实体对象,ID表示主键。该接口继承了分页排序接口PadingAndSortRepository,通过构建Pageable实现分页查询:

    @Autowired
    private ArticleRepository articleRepository;
    
    @RequestMapping("")
    public ModelAndView articlelist(@RequestParam(value = "start", defaultValue = "0") Integer start, @RequestParam(value = "limit", defaultValue = "5") Integer limit) {
            start = start < 0 ? 0 : start;
            Sort sort = Sort.by(Sort.Direction.DESC, "id");
            Pageable pageable = PageRequest.of(start, limit, sort);
            Page<Article> page = articleRepository.findAll(pageable);
            ModelAndView modelAndView = new ModelAndView("article/list");
            modelAndView.addObject("page", page);
            return modelAndView;
    }
    

    如果根据某一字段排序,可以用Sort.by方法构建Sort对象;如果根据多个字段排序,首先构建Sort.Order数组List<Sort.Order>,然后再传入Sort.by方法构建Sort对象。

    PageRequest.of方法生成Pageable对象

    Contrller控制器

    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.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.servlet.ModelAndView;
    import springbootjpa.entity.Article;
    import springbootjpa.repository.ArticleRepository;
    
    @Controller
    @RequestMapping("/article")
    public class ArticleController {
        @Autowired
        private ArticleRepository articleRepository;
    
        @RequestMapping("")
        public ModelAndView articlelist(@RequestParam(value = "start", defaultValue = "0") Integer start,
                                        @RequestParam(value = "limit", defaultValue = "5") Integer limit) {
            start = start < 0 ? 0 : start;
            Sort sort = Sort.by(Sort.Direction.DESC, "id");
            Pageable pageable = PageRequest.of(start, limit, sort);
            Page<Article> page = articleRepository.findAll(pageable);
            ModelAndView modelAndView = new ModelAndView("article/list");
            modelAndView.addObject("page", page);
            return modelAndView;
        }
    
        @RequestMapping("/add")
        public String addArticle() {
            return "article/add";
        }
    
        @PostMapping("")
        public String saveArticle(Article article) {
            articleRepository.save(article);
            return "redirect:/article";
        }
    
        @GetMapping("/{id}")
        public ModelAndView getArticle(@PathVariable("id") Integer id) {
            Article article = articleRepository.findById(id);
            ModelAndView modelAndView = new ModelAndView("article/show");
            modelAndView.addObject("article", article);
            return modelAndView;
        }
    
        @DeleteMapping("/{id}")
        public String deleteArticle(@PathVariable("id") long id) {
            System.out.println("put 方法");
            articleRepository.deleteById(id);
            return "redirect:/article";
        }
    
        @GetMapping("edit/{id}")
        public ModelAndView editArticle(@PathVariable("id") Integer id) {
            Article article = articleRepository.findById(id);
            ModelAndView modelAndView = new ModelAndView("article/edit");
            modelAndView.addObject("article", article);
            return modelAndView;
        }
    
        @PutMapping("/{id}")
        public String editArticleSave(Article article, long id) {
            System.out.println("put 方法");
            article.setId(id);
            articleRepository.save(article);
            return "redirect:/article";
        }
    }
    
    

    因为<form>表单只能发送GETPOST请求,spring3引入一个监听器HiddenHttpMethodFilter 来将POST请求转换为PUTPOST请求。

    SpringBoot2.x开始默认不自动注入HiddenHttpMethodFilter ,需要设置spring.mvc.hiddenmethod.filter.enabled=true开启PUT、DELETE方法支持

    配置完后,前端页面需要在表单中加入隐藏域,表明实际请求方法:

    <!-- DELETE 请求 -->
    <form id="deletePost" method="POST" action="">
        <input type="hidden" name="_method" value="delete">
    </form>
    
    
    <!-- PUT 请求 -->
    <form id="putPost" method="POST" action="">
        <input type="hidden" name="_method" value="put">
    </form>
    

    其他

    th:valueth:field区别:

    • th:value解析成html,表现为:value="${th:value}"
    • th:field解析成html,表现为:name="${th:name}" value="${th:value}"
  • 相关阅读:
    php 闭包 function use用法
    php序列号和反序列化
    [转]php composer使用
    hex编码,用途是什么,为什么需要hex编码呢?
    美术资源优化/LOD
    ASTC纹理压缩格式详解
    Elastic Stack之 Elasticsearch 6.7.1版本单机版安装、集群版安装
    使用datax将mysql数据同步到ES 附elasticsearchwriter插件
    Java1.8之Lambda表达式
    Java1.8之Lambda表达式、流Stream学习
  • 原文地址:https://www.cnblogs.com/weixia-blog/p/13618603.html
Copyright © 2020-2023  润新知