乐趣区

CKEditor-5-SpringBoot实战三SpringData-JPA数据持久化

在本系列的文章中,我将介绍如何在 Spring Boot Application 中使用 CKEditor 编辑器。介绍的内容包括基本环境的搭建,文件上传,SpringData JPA 数据持久化,CKEditor5 的安装,CKEditor 图片上传,CKEditor 插入视频,获取 / 设置 CKEditor 内容等。

项目源码

本系列文章的项目源码同步更新至码云 和 Github,你可以任选其一下载源码到本地。项目地址如下:

  1. 码云:https://gitee.com/ramostear/CKEditor5-SpringBoot
  2. Github:https://github.com/ramostear/CKEditor5-SpringBoot

你也可以通过 Git 命令行工具下载项目源码,命令如下(二者任选其一):

git clone https://gitee.com/ramostear/CKEditor5-SpringBoot.git
git clone https://github.com/ramostear/CKEditor5-SpringBoot.git

接上篇内容,本篇的主要内容是引入 MySQL 数据库驱动依赖和 SpringData JPA 依赖,然后创建内容实体,并完成数据持久层(DAO)和业务逻辑层(Service)相关代码的设计和实现。

引入依赖

前面的内容中我们分析过,需要将 CKEditor5 编辑的内容存储到数据库中(图片数据存储到磁盘)。本项目使用 MySQL 数据库来存储数据。数据的持久化过程选用 SpringData JPA 进行实现,除此之外,我们借用 Alibaba Druid 来管理数据库连接池。

在项目根目录下找到并打开 pom.xml 文件,然后向文件中添加如下的依赖:

SpringData JPA

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

MySQL Driver

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    <scope>runtime</scope>
</dependency>

Alibaba Druid

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.14</version>
</dependency>

项目配置

依赖包加载完成,我们需要对项目中的 JPA 和数据源进行配置。配置的内容包括数据库的类型,数据库方言,数据源类型,数据库驱动以及连接数据库所需要的用户名,密码和连接地址。详细配置如下图:

在“src/main/resources”目录下找到_application.properties_ 文件,并将该文件更名为_application.yml_ 并添加下列配置信息:

spring:
  jpa:
    database: mysql
    show-sql: true
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL5Dialect
    properties:
      hibernate.format_sql: true
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/db_ckeditor_springboot?useUnicode=true&useSSL=false&characterEncoding=utf8

如上图所示:

①:指定数据库类型为 MySQL 数据库

②:在启动项目时,如果数据库表和对应的实体之间的映射不一致,则更新数据库表,并保留原有数据

③:配置数据库方言为 org.hibernate.dialect.MySQL5Dialect

④:配置数据源类型为 Alibaba Druid Datasource

⑤:配置数据库驱动

⑥:数据账户名

⑦:账户密码

⑧:数据库的连接地址

创建数据库

在上一步中,我们配置的数据库连接地址为:jdbc : mysql://localhost:3306/db_ckeditor_springboot?useUnicode=true&useSSL=false&characterEncoding=utf8。因此,我们需要创建一个名为 db_ckeditor_springboot 的数据库。你可以使用 Navicat 或 SQLyog 这一类的可视化软件来创建数据库,也可以使用 MySQL 命令行窗口来创建。这里我们使用命令行的方式来创建 db_ckeditor_springboot 数据库,命令如下:

CREATE DATABASE `db_ckeditor_springboot` `CHARACTER SET utf5 COLLATE utf8_bin`;
USE `db_ckeditor_springboot`;

提示:

在配置环节,我们配置了 spring.jpa.hibernate.ddl-auto=update。因此,我们不需要再手动创建数据库表,当项目中存在对应的实体类时,SpringData JPA 为自动生成表。

spring.jpa.hibernate.ddl-auto 有四个可选配置项:

  • create:每次加载 hibernate 时都会删除上一次的生成的表,然后根据你的 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。[删除 - 创建 - 操作]
  • create-drop:每次加载 hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。[删除 - 创建 - 操作 - 再删除]
  • update:最常用的属性,第一次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。[没表 - 创建 - 操作 | 有表 - 更新没有的属性列 - 操作]
  • validate:每次加载 hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。[启动验证表结构,验证不成功,项目启动失败]

创建实体

com.ramostear.ckeditor 包下创建 model 包用来存放实体类,为了减少编码工作量,这里我们需要引入 Lombok 依赖包。在 pom.xml 文件中添加如下依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

接下来,我们创建一个用于存储 CKEditor 编辑器内容的实体类 Content, 为了简化操作,该类只设计三个属性,具体如下:

属性名

类型

数据库类型

id

Integer

int 自增, 不允许为空

text

String

text, 默认值为””

createTime

Date

Date, 默认值为 CURRENT_TIMESTAMP

Content.java 类详细信息如下:

①:@Table 为实体类指定数据库表。

②:@GeneratedValue 注解存在的意义主要就是为一个实体生成一个唯一标识的主键、@GeneratedValue 提供了主键的生成策略。

③:@Lob 指定持久属性或字段应作为大对象持久保存到数据库支持的大对象类型。

④:@PrePersist 在持久化之前自动填充实体属性。

以下是 Content.java 的源代码:

package com.ramostear.ckeditor.model;

import lombok.Data;
import org.hibernate.annotations.Type;

import javax.persistence.*;
import java.util.Date;

@Data
@Entity
@Table(name = "content")
public class Content {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Lob
    @Type(type = "text")
    @Column(name = "text")
    private String text;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "create_time",columnDefinition = "timestamp default CURRENT_TIMESTAMP")
    private Date createTime;

    @PrePersist
    public void prePersist(){
        this.id = null;
        this.createTime = new Date();
        if(text == null || text.trim().equals("")){text = "";}
    }
}

提示:

@Data 是 @Getter,@Setter,@RequiredArgsConstructor,@ToString 和 @EqualsAndHashCode 的组合注解(快捷方式),用于生成 getter(),setter(),toString()等方法。

创建持久化类

SpringData JPA 是 spring 在 ORM 框架和 JPA 规范的基础上封装的一套 JPA 应用框架,可以使开发者使用极简的代码实现对数据库的访问和操作。它提供了包括增删改查等在内的基本功能,且易于扩展。因此,创建持久化类最快的方式是继承 SpringData JPA 提供的基础类。我们将继承 SpringData JPA 的 JpaRepository 类来实现内容数据的增删改查功能。下面是 ContentRepository.java 类的代码明细:

package com.ramostear.ckeditor.repository;

import com.ramostear.ckeditor.model.Content;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ContentRepository extends JpaRepository<Content,Integer> {}

提示:

该类放置在“com.ramostear.ckeditor.repository”包下,在一开始的时候,我们只需要继承 JpaRepository 接口即可。

创建业务逻辑类

首先,我们仅提供一个包含增、删、改、查四个功能的业务逻辑接口 (ContentService.java),并在其实现类(ContentServiceImpl.java) 中实现接口中定义的方法。

ContentService.java

package com.ramostear.ckeditor.service;

import com.ramostear.ckeditor.model.Content;
import java.util.List;

public interface ContentService {

    /**
     * 保存内容
     * @param content
     * @return
     */
    Content save(Content content);

    /**
     * 修改内容
     * @param content
     * @return
     */
    boolean update(Content content);

    /**
     * 根据 ID 删除内容
     * @param id
     * @return
     */
    boolean delete(Integer id);

    /**
     * 根据 ID 查询内容
     * @param id
     * @return
     */
    Content findById(Integer id);

    /**
     * 获取所有的内容
     * @return
     */
    List<Content> findAll();}

ContentServiceImpl.java

package com.ramostear.ckeditor.service.impl;

import com.ramostear.ckeditor.model.Content;
import com.ramostear.ckeditor.repository.ContentRepository;
import com.ramostear.ckeditor.service.ContentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service(value = "contentService")
@Transactional(readOnly = true)
public class ContentServiceImpl implements ContentService {

    private final ContentRepository contentRepository;

    @Autowired
    ContentServiceImpl(ContentRepository contentRepository){this.contentRepository = contentRepository;}


    @Override
    @Transactional
    public Content save(Content content) {return contentRepository.save(content);
    }

    @Override
    @Transactional
    public boolean update(Content content) {Content target = this.findById(content.getId());
        if(target != null){BeanUtils.copyProperties(content,target,"id","createTime");
            contentRepository.saveAndFlush(target);
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public boolean delete(Integer id) {Optional<Content> check = contentRepository.findById(id);
        if(check.isPresent()){contentRepository.deleteById(id);
            return true;
        }
        return false;
    }

    @Override
    public Content findById(Integer id) {return contentRepository.findById(id).orElse(null);
    }

    @Override
    public List<Content> findAll() {return contentRepository.findAll(Sort.by(Sort.Direction.DESC,"createTime"));
    }
}

提示:

所有的业务接口都放置在“com.ramostear.ckeditor.service”包下,所有的业务接口实现类都放置在“com.ramostear.ckeditor.service.impl”包下。

其中,@Service 注解表面当前类是一个被 Spring 容器所管理的 Bean,Bean 的名称为“contentService”;@Transactional 是声明式事务管理编程中使用的注解, 该注解放置在接口实现类或方法上;另外,在 ContentServiceImpl.java 类中,使用基于构造方法的方式将 ContentRepository.java 的实例化对象注入其中。特别地,当类中只有一个构造方法时,@Autowired 注解可以省略不写。

启动应用

完成以上编码工作后,我们将启动应用程序,检查应用程序是否与 MySQL 数据库连接成功并创建名为“content”的数据表。启动应用后,当 IDEA 控制台输出如下的信息,则表明我们的应用已经和 MySQL 建立连接,并成功在 db_ckeditor_springboot 数据库创建了 content 表。

为了进一步验证是否创建了 content 表,我们可以打开 MySQL 命令行工具,并输入如下命令进行检查:

>mysql use db_ckeditor_springboot;
>mysql show tables;
>mysql show columns from content;

若查询结果如下,则证明 content 表已经创建:

另外,我们还可以通过 Druid 来查看应用的数据库连接信息,要实现该功能,只需向 application.yml 配置文件中添加如下的配置项即可:

spring:
  datasource:
    druid:
      stat-view-servlet:
        enabled: true

然后重启应用,应用启动成功后,在浏览器中输入:http://localhost:8080/druid/index.html 便可查看应用的数据库连接情况,如下图:

本章小结

本章详细介绍了依赖包的引入,项目的配置,实体类,持久化类和业务类的实现过程,并通过 SpringData JPA 实现了自动创建数据表,最后介绍了通过命令行工具和 Druid Monitor 两种方式查看数据库信息。你可以访问下面的地址,下载该项目的所有源代码:

  1. 码云:https://gitee.com/ramostear/CKEditor5-SpringBoot
  2. Github:https://github.com/ramostear/CKEditor5-SpringBoot

在下一章节中,我将着重介绍如何在 SpringBoot 中实现文件上传功能,以及如何映射上传文件路径等技术要点。

未经作者允许,请勿擅自转载

退出移动版