从0开始写一个SpringBoot程序【Part1】

1 前置环境

  • JAVA “1.8.0_181”

  • Maven “3.8.4”

  • SpringBoot “2.5.5”【2022】

  • IDEA 2021.3.2

创建基础项目说明

Spring官方提供快速构建工具:Spring Initializr:https://start.spring.io/

也可以使用IDEA直接创建项目,效果同Spring Initializr一致

项目结构分析:

通过上面步骤完成了基础项目的创建。就会自动生成以下文件

  1. 程序的主启动类(使用@SpringBootApplicationXXXApplication.java

    其中自动配置的核心文件是META-INF/spring.factories(源码里有说),文件位置在External Libraries/Maven:org.springframework.boot:spring-boot-autoconfigure:版本号包下。

  2. 一个 application.properties 配置文件

  3. 一个测试类

  4. 一个pom.xml的Maven配置文件

POM(Project Object Model,项目对象模型),是Maven项目中的文件,使用XML语法。

该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。

web接口与相关依赖

web启动器(被封装到pom.xml文件中的spring-boot-starter-web依赖中),SpringBoot web项目的启动场景。

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

新建controller软件包,编写第一个测试接口

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello world!!";
    }
}

可选:更改启动时显示的字符图案

如何更改启动时显示的字符拼成的字母:SpringBoot呢?

  • 到项目下的 resources 目录下新建一个banner.txt即可。

    图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!

至此SpringBoot项目环境搭建成功


2 项目结构

  • DAO(Data Access objects)数据存取对象:是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。这是一种JavaWeb设计模式,提供了一种将数据访问代码从业务逻辑中分离出来的方法,从而提高了代码的可维护性和可测试性。

  • POJO(Plain Ordinary Java Object)简单的Java对象,这个软件包存放实体类,具备setter/getter方法。

  • Service层,应用程序的核心层,位于业务逻辑层和数据访问层之间,负责业务逻辑和数据。主要任务包括:

    • 处理业务逻辑,如数据校验、处理和相关算法等。
    • 调用数据访问(DAO)层
    • 事务管理,确保业务操作的原子性和一致性。
    • 接口封装,向上层(如控制器或其他Service层)提供接口。

    在Java中,Service层通常以接口和实现类的形式实现。接口定义了Service层的方法,实现类实现了这些方法并处理具体的业务逻辑。

    通过将业务逻辑与数据访问分离,Service层提供了更好的代码复用性和可维护性。它使得底层的数据访问层可以独立变化,而不会影响上层的业务逻辑。

3 整合Swagger

前后端分离项目使用Swagger,可以自动生成在线文档,还支持Web界面在线接口测试

  • 依赖添加

    <!-- swagger-bootstrap-ui  localhost:port/doc.html -->
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>swagger-bootstrap-ui</artifactId>
                <version>1.9.6</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>
    
  • 配置类,启用Swagger2

    controller包同级,创建SwaggerConfig.java,固定写法如下

    package com.moon.config;
    ...
    
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        @Bean
        public Docket api(){
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("com.moon"))
                    .paths(PathSelectors.any())
                    .build();
        }
    
        private ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("Haha_Video Api doc")
                    .description("Api interface")
                    .version("1.0")
                    .contact(new Contact("moonjay","this is a link","131xxxxxxx@qq.com"))
                    .build();
        }
    }
    
  • @ApiModel注解使用,以User.java为例

  • 启动项目,访问http://127.0.0.1:8888/doc.html,无法看到Swagger Models,解决办法:

    • 只要在接口中,返回值中存在实体类,就会被扫描到swagger中。因此可以改写前文的HelloController

      @RestController
      public class HelloController {
          @RequestMapping("/hello")
          public String hello(){ return "hello world!!"; }
      
          @PostMapping("/user_API")
          public User user(){ return new User(); }
      }
      
    • 使用@RequestBody注解

          @ApiOperation(value = "添加用户", notes = "添加新用户")
          @PostMapping("/add")
          public Map addUser(@RequestBody Account account){
              return userService.createUser(account);
          }
      

4 整合JPA生成User表

JPA(Java Persistence API),Java持久层API,描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中

  • 引入依赖

    		<dependency>
                <!--    -->
                <!--    描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中-->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
    		<!-- mysql connector -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
                <scope>runtime</scope>
            </dependency>
    
  • Navicat创建数据库

    字符集

    常用的UTF-8(Unicode Transformation Format-8)和UTF-8MB4(UTF-8 Multibyte 4-byte)字符编码方案,用于表示 Unicode 字符集中的字符。它们之间的主要区别在于编码范围

    • UTF-8:UTF-8 是一种变长编码方式,可以用一个至四个字节来表示不同范围内的字符。大部分常用的字符可以使用一个字节表示,但某些罕见的字符需要使用多个字节进行编码。UTF-8 编码最多可以表示 Unicode 字符集中的 1,112,064 个字符。
    • UTF-8MB4:UTF-8MB4 是对 UTF-8 的扩展,它支持更广泛的字符集范围。UTF-8MB4 使用一到四个字节来表示不同范围内的字符,与 UTF-8 相比,它多了一些额外的字符表示范围。UTF-8MB4 可以表示 Unicode 字符集中的所有字符,包括一些罕见的、辅助平面的以及 Emoji 表情等。

    一般情况下,当我们处理文字内容时,如数据库存储、网页显示等,建议使用 UTF-8 编码,因为 UTF-8 能够满足绝大多数的需求,而且它占用的空间相对较小。UTF-8MB4 则适用于需要支持更广泛字符集范围的场景,如存储包含 Emoji 表情的文本内容。

    排序规则

    • utf8_bin
      • 特性: 在 utf8_bin 排序规则中,字符串是通过二进制数据进行编译和存储的。
      • 大小写区分: 是。在这种排序规则下,a 和 A 被视为不同的字符。
      • 适用场景: 需要严格区分大小写或者需要存储二进制内容时。例如,密码字段字段需要确切地区分大小写。
    • utf8_general_ci
      • 特性: utf8_general_ci 是一种不区分大小写的排序规则。它在比较字符串时,不会区分字符的大小写。
      • 大小写区分: 否。在这种排序规则下,a 和 A 被视为相同的字符。
      • 适用场景: 适用于那些不需要区分大小写的场景,如用户登录时的用户名或邮箱地址,可以确保即使用户在输入时改变了字母的大小写,仍然能够被正确地识别。
    • utf8mb4_unicode_ci / utf8mb4_general_ci
      • 描述: 这些排序规则用于 UTF8MB4 字符集。ci 表示不区分大小写(case-insensitive)
      • 区别: utf8mb4_unicode_ci 基于标准的 Unicode 来排序,而 utf8mb4_general_ci 是一种性能更优的简化排序算法。
      • 适用场景: 当需要确保在多种语言环境下的文本比较和排序的准确性时,utf8mb4_unicode_ci 是更好的选择。如果性能是主要考虑因素,且可以接受稍微粗糙的排序,则可以选择 utf8mb4_general_ci。
    • utf8_general_cs
      • cs 表示区分大小写(case-sensitive)
    • utf8_unicode_ci
      • 特性: utf8_unicode_ci 在校对时的准确度更高,但速度稍慢。
      • 中英文处理: 对中文和英文来说,与 utf8_general_ci 没有实质性的差别。
      • 选择建议: 如果对准确性有较高要求,可以考虑使用 utf8_unicode_ci。
    • binary
      • 描述: 这是一种区分大小写的排序规则,按照字节值进行比较。
      • 适用场景: 当需要严格区分大小写和特殊字符,或者对数据进行精确的字节级比较时,适合选择 binary 排序规则。

  • resources目录下新建配置文件application.yml

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JavaEE架构中取代CMP,完成数据持久化的重任。

    spring:
      datasource:
        username: root
        password: pwd...
        url: jdbc:mysql://localhost:3306/haha_video?useSSL=false
        driver-class-name: com.mysql.jdbc.Driver
      jpa:
        properties:
          hibernate:
            hbm2ddl:
              auto: update
            dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        show-sql: true
        open-in-view: false   # avoid warn info
    
  • User.java

    @Entity标识实体类,在这个类中被注解标注的字段,都会被映射到数据库中

    @Table实体类与数据表的映射,通过name确定表名(默认类名为表名)

    @ApiModel(value = "用户实体类", description = "用户信息描述")
    @Entity
    @Table(name = "t_users")
    public class User {
        /** 主键设置为id id自增长*/
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(length = 64)
        @ApiModelProperty(hidden = true,name = "id",value = "用户id(唯一)")
        private Integer id;
        @Column(name = "username", length = 20, nullable = false)
        private String name;
        @Column(name = "password", length = 64, nullable = false)
        private String pwd;
        @Column(name = "face_image")
        private String faceImage;
        @Column(length = 20, nullable = false)
        private String nickname;
        @Column(name = "fans_counts", length = 11)
        private Integer fansCounts;
        @Column(name = "follow_counts", length = 11)
        private Integer followCounts;
        @Column(name = "receive_like_counts", length = 11)
        private Integer receiveLikes;
    
        /** Setter & Getter */
    }
    
  • 启动项目,发现数据库已经自动生成table:“t_user”

5 User的数据库操作

数据库操作业务代码

基本流程为:DAO包创建接口,继承JpaRepository<T, ID>Service包创建接口,最后在Service/Impl包中实现接口。

1)DAO包,创建UserDao接口

@Transactional
public interface UserDao extends JpaRepository<User,Integer> {
    @Query(value = "select * from t_users u where u.username = ?1 and u.password = ?2", nativeQuery = true)
    User findUserByNameAndPwd(String name,String pwd);
}
  • @Transactional

    • 作用于类,表示所有该类的public方法都配置相同的事务属性信息。
    • 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
    • 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP使用CGLib动态代理,将会导致@Transactional注解失效
  • JpaRepository接口

    继承自PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>

    • QueryByExampleExecutor<T>:查询的一些批量操作

    • PagingAndSortingRepository<T, ID>继承自CrudRepository<T, ID>

      CrudRepository<T, ID> :包含常用的CRUD操作:

          <S extends T> S save(S entity);
          <S extends T> Iterable<S> saveAll(Iterable<S> entities);
          Optional<T> findById(ID id);
          boolean existsById(ID id);
          Iterable<T> findAll();
          Iterable<T> findAllById(Iterable<ID> ids);
          long count();
          void deleteById(ID id);
          void delete(T entity);
          void deleteAllById(Iterable<? extends ID> ids);
          void deleteAll(Iterable<? extends T> entities);
          void deleteAll();
      

使用@Query注解修饰查询方法,可以让查询方法使用自定义的JPQL或SQL执行查询,该注解可以指定如下常用属性:

  • name:指定使用哪个命名查询。命名查询的本质就是为JPQL或SQL语句起个名字,因此指定使用哪个命名查询也就是指定了JPQL或SQL语句。
  • nativeQuery:指定是否为SQL查询,如果该属性为true,表明是原生SQL查询,否则就是JPQL查询。
  • value:指定自定义的JPQL或SQL语句。

定义findUserByNameAndPwd(String name,String pwd);的意义在于后面根据用户名密码匹配用户进行登录校验,然而JpaRepository接口中没有根据namepwd查询的接口,这就需要我们自行定义。

2)Service包,创建UserService接口

public interface UserService {
    void insertUser(User user);

    List<User> findAll();

    User findUser(String name,String pwd);
}

3)Service/impl包,创建UserServiceImpl

使用@Service注解标识一个类为服务层组件。

  • 服务层(Service Layer): 应用程序的一个层次结构,位于控制层(Controller Layer)和数据访问层(Data Access Layer)之间。服务层的主要责任是处理业务逻辑、协调数据访问和其他服务,并为控制器层提供数据。
  • 依赖注入:@Service 注解告诉 Spring 框架将这个类实例化为一个 Bean,并将其纳入 Spring IoC 容器中。
  • AOP 支持: 通过 @Service 注解,Spring 可以将切面(Aspect)应用于服务层组件,以实现例如事务管理、日志记录等方面的功能。
  • 基于组件扫描的自动装配: 在 Spring 应用程序中,通常使用组件扫描(Component Scanning)来自动发现标记有 @Service 注解的类,并将它们自动注册为 Spring Bean,从而简化了配置。
  • 提高代码可读性和可维护性: 使用 @Service 注解可以使代码更具有可读性,因为它清晰地标识了哪些类属于服务层,从而提高了代码的可维护性。

注解@Autowired自动装配UserDao接口。

@Service("UserService")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public void insertUser(User user) { userDao.save(user); }

    @Override
    public List<User> findAll() { return userDao.findAll(); }

    @Override
    public User findUser(String name,String pwd) { return userDao.findUserByNameAndPwd(name,pwd); }
}

SpringBoot单元测试

上一节已经编写了User实体类并与MySQL数据库连接,创建了haha_video数据库与t_users数据表。

接下来,在/test/java/...目录下的HahaVideoApplicationTests.java编写单元测试方法进行CRUD测试。

@SpringBootTest
class HahaVideoApplicationTests {

    @Autowired
    private UserService userService;

    @Test
    void testUserInsert(){
        User user = new User();
        user.setFaceImage("");
        user.setName("moonjay");
        user.setNickname("moonjay");
        user.setPwd("123456");

        try {
            userService.insertUser(user);
        }catch (Exception e){
            e.printStackTrace();
        }finally { System.out.println("user insert func completed!"); }
    }

}
  • @SpringBootTest

    Spring Boot Test支持的测试种类,大致可以分为如下三类:

    • 单元测试:一般面向方法,编写一般业务代码时,测试成本较大。涉及到的注解有@Test
    • 切片测试:一般面向难于测试的边界功能,介于单元测试和功能测试之间。涉及到的注解有@RunWith@WebMvcTest等。
    • 功能测试:一般面向某个完整的业务功能,同时也可以使用切面测试中的mock能力,推荐使用。涉及到的注解有@RunWith@SpringBootTest等。(通过这两者启动spring容器)
    		<!-- 初始化SpringBoot项目时已存在 -->
    		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    

    一旦依赖了spring-boot-starter-test,下面这些类库将被一同依赖进去:

    • JUnit:java测试事实上的标准,默认依赖版本是4.12(JUnit5和JUnit4差别比较大,集成方式有不同)。
    • Spring Test & Spring Boot Test:Spring的测试支持。
    • AssertJ:提供了流式的断言方式。
    • Hamcrest:提供了丰富的matcher。
    • Mockito:mock框架,可以按类型创建mock对象,可以根据方法参数指定特定的响应,也支持对于mock调用过程的断言。
    • JSONassert:为JSON提供了断言功能。
    • JsonPath:为JSON提供了XPATH功能。
  • 注意:使用@Test的测试方法不要由参数,否则会出现以下错误:

    org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter
    

运行上面编写的测试方法,控制台输出SQL语句,表示成功向数据表添加一条数据:

使用Navicat也可以看到数据被加入:


热部署、SkipTest

 	<properties>
        <!-- 编译打包时关掉单元测试 -->
        <skipTests>true</skipTests>
    </properties>
		<!-- springboot热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

application.yml中设置热部署排除的文件

spring:
  devtools:
    restart:
      exclude: static/**, application.yml
      # enabled: true  # 设置为false关闭

6 Video实体与数据库操作

同上面两个小节的流程一样

  • 创建实体类

    这里使用了Lombok@Getter@Setter注解

            <!-- lombok - setter & getter -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.30</version>
                <scope>provided</scope>
            </dependency>
    
    @ApiModel(value = "视频实体类", description = "视频信息描述")
    @Entity
    @Table(name = "t_videos")
    @Setter
    @Getter
    public class Video {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
        @Column(name = "user_id")
        private Integer userId;
        @Column(name = "audio_id")
        private Integer audioId;
        @Column(name = "video_desc", length = 128)
        private String videoDesc;
        @Column(name = "video_path", nullable = false)
        private String videoPath;
        @Column(name = "video_seconds", precision = 6, scale = 2)
        /** precision和scale属性只在BigDecimal类型中有效*/
        private Float videoSeconds;
        @Column(name = "video_width")
        private Integer videoWidth;
        @Column(name = "video_height")
        private Integer videoHeight;
        @Column(name = "cover_path", nullable = false)
        private String coverPath;
        @Column(name = "like_counts")
        private Long likeCounts;
        private Integer status;
        @ApiModelProperty(value = "创建时间(datetime)")
        @Column(name = "create_time", nullable = false)
        private String crateTime;
        // 直接将java.util.Date存入数据库是不行的,后文会进行相关处理
    }
    
  • VideoDao接口、VideoService接口以及VideoServiceImpl实现类

    @Transactional
    public interface VideoDao extends JpaRepository<Video,Integer> {
        @Modifying
        @Query(value = "update t_videos v set v.videoPath = ?1, v.coverPath = ?2, v.videoDesc = ?3 where v.id = ?4", nativeQuery = true)
        void updateById(String videoPath, String coverPath, String videoDesc, Integer id);
    
        @Query(value = "select * from t_videos v where v.user_id = ?1", nativeQuery = true)
        List<Video> findAllByUserId(Integer user_id);
    }
    
    public interface VideoService {
        List<Video> findAll();
        void addVideo(Video video);
        void deleteVideo(Integer id);
        void updateVideo(String videoPath,String coverPath,String videoDesc,Integer id);
        List<Video> findAllById(Integer id);
    }
    
    @Service("VideoService")
    public class VideoServiceImpl implements VideoService {
        @Autowired
        private VideoDao videoDao;
    
        @Override
        public List<Video> findAll() { return videoDao.findAll(); }
    
        @Override
        public void addVideo(Video video) { videoDao.save(video); }
    
        @Override
        public void deleteVideo(Integer id) {
            Video video = videoDao.getById(id);
            videoDao.delete(video);
        }
    
        @Override
        public void updateVideo(String videoPath, String coverPath, String videoDesc, Integer id) {
            videoDao.updateById(videoPath,coverPath,videoDesc,id);
        }
    
        @Override
        public List<Video> findAllById(Integer id) { return videoDao.findAllByUserId(id); }
    }
    
  • CRUD单元测试

    日期添加:Date类获取当前日期 - SimpleDateFormat类进行格式转换 - 得到String格式的日期字符串

        @Test
        void testVideoInsert(){
            Video video = new Video();
            video.setVideoDesc("1st video");video.setAudioId(1);
            // 视频的长、宽默认为100
            // 点赞数默认为0,状态码默认为0
            video.setUserId(1);
            // 视频的默认创建时间为当前的日期
            Date dt = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String currentTime = sdf.format(dt);
            video.setCrateTime(currentTime);
            // 文件的path
            video.setVideoPath("/videos/funny01.mp4");
            video.setCoverPath("/videos/funny1.jpg");
            try {
                videoService.addVideo(video);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                System.out.println("video insert func completed!");
            }
        }
    

7 Bgm实体与数据库操作

  • 实体类

    @ApiModel(value = "BGM实体类", description = "bgm信息描述")
    @Entity
    @Table(name = "t_bgms")
    @Setter
    @Getter
    public class Bgm {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(length = 64)
        private Integer id;
        @Column(nullable = false)
        private String author;
        @Column(name = "music_name", nullable = false)
        private String musicName;
        @Column(nullable = false)
        private String path;
    }
    
  • BgmDao接口、BgmService接口以及BgmServiceImpl实现类

    @Transactional
    public interface BgmDao extends JpaRepository<Bgm, Integer> {
        @Modifying
        @Query("update bgm b SET b.path = ?1,b.musicName=?2,b.author=?3 where b.id =?4 ")
        void updateBgmAddress(String address,String musicName, String author,Integer bgmId);
    }
    
    public interface BgmService {
        List<Bgm> findAll();
        void addBgm(Bgm bgm);
        Bgm getById(Integer id);
        void delBgm(Integer id);
        void updateBgm(String address,String musicName,String author, Integer id);
    }
    
    @Service("BgmService")
    public class BgmDaoImpl implements BgmService {
        @Autowired
        private BgmDao bgmDao;
        @Override
        public List<Bgm> findAll() { return bgmDao.findAll(); }
    
        @Override
        public void addBgm(Bgm bgm) { bgmDao.save(bgm); }
    
        @Override
        public Bgm getById(Integer id) { return bgmDao.getById(id); }
    
        @Override
        public void delBgm(Integer id) {
            Bgm bgm = bgmDao.getById(id);
            bgmDao.delete(bgm);
        }
    
        @Override
        public void updateBgm(String address, String musicName, String author, Integer id) {
            bgmDao.updateBgmAddress(address, musicName, author, id);
        }
    }
    
  • CRUD单元测试

git提交静态资源文件问题

本项目使用的静态资源包括音频、视频以及CSS/JS文件,数量较多,容量较大(占35MB)。使用git push命令推送到远程仓库出现问题:“fatal: The remote end hung up unexpectedly ”

  • 解决方案1:修改git的配置文件(成功解决

    在末尾加上:

    [http]  
    postBuffer = 524288000
    

    再重新推送即可。

    或者通过下面的方式设置缓存

    $ git config http.postBuffer 524288000
    $ git config --global http.postBuffer 524288000
    $ git config --global https.postBuffer 1048576000
    
  • 解决方案2:配置git的最低速度和最低速度时间(此问题可能由网络原因引起)

    git config --global http.lowSpeedLimit 0
    git config --global http.lowSpeedTime 999999  # 秒
    

    --global配置对当前用户生效,如果需要对所有用户生效,则用--system

8 Comment、Report实体与数据库操作

  • 实体类

    @ApiModel(value = "Comment实体类", description = "video comment")
    @Entity
    @Table(name = "t_comments")
    @Setter
    @Getter
    public class Comment {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
        @Column(name = "from_user_id",nullable = false)
        private Integer fromUserId;
        @Column(name = "video_id",nullable = false)
        private Integer videoId;
        @Column(nullable = false)
        private String comment;
        @Column(name = "create_time", nullable = false)
        private String createTime;
    }
    
    @ApiModel(value = "Report实体类", description = "用户对某个视频的反馈")
    @Entity
    @Table(name = "t_reports")
    @Setter
    @Getter
    public class Report {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(length = 64)
        private Integer id;
        @Column(name = "dealt_user_id", length = 64, nullable = false)
        private Integer userId;
        @Column(name = "dealt_video_id", length = 64, nullable = false)
        private Integer videoId;
        @Column(length = 128, nullable = false)
        private String title;
        private String content;
        @Column(length = 64, nullable = false)
        private Integer uId;
        @Column(name = "create_time", nullable = false)
        private String createTime;
    }
    
  • CommentDao&ReportDao接口、CommentService&ReportService接口以及CommentServiceImpl&ReportServiceImpl实现类

    @Transactional
    public interface CommentDao extends JpaRepository<Comment,Integer> {
        @Modifying
        @Query(value = "update t_comments c set c.comment = ?1 where c.id = ?2", nativeQuery = true)
        void updateComment(String comment,Integer id);
    }
    
    @Transactional
    public interface ReportDao extends JpaRepository<Report,Integer> {
        @Modifying
        @Query(value = "update t_reports r set r.content = ?1,r.title = ?2 where r.id=?3", nativeQuery = true)
        void updateReport(String content,String title,Integer id);
    }
    

    public interface CommentService {
        List<Comment> findAll();
        void addComment(Comment comments);
        void deleteComment(Integer id);
        void updateComment(String comment,Integer id);
        Comment getById(Integer id);
    }
    
    public interface ReportService {
        List<Report> findAll();
    
        void addReport(Report userReport);
    
        void deleteReport(Integer id);
    
        void updateReport(String content,String title,Integer id);
    
        Report getById(Integer id);
    }
    

    @Service("CommentService")
    public class CommentServiceImpl implements CommentService {
        @Autowired
        private CommentDao commentDao;
    
        @Override
        public List<Comment> findAll() { return commentDao.findAll(); }
    
        @Override
        public void addComment(Comment comments) { commentDao.save(comments); }
    
        @Override
        public void deleteComment(Integer id) {
            Comment comment = commentDao.getById(id);
            commentDao.delete(comment);
        }
    
        @Override
        public void updateComment(String comment, Integer id) { commentDao.updateComment(comment, id); }
    
        @Override
        public Comment getById(Integer id) { return commentDao.getById(id); }
    }
    
    @Service("ReportService")
    public class ReportServiceImpl implements ReportService {
        @Autowired
        private ReportDao reportDao;
    
        @Override
        public List<Report> findAll() { return reportDao.findAll(); }
    
        @Override
        public void addReport(Report userReport) { reportDao.save(userReport); }
    
        @Override
        public void deleteReport(Integer id) {
            Report userReport = reportDao.getById(id);
            reportDao.delete(userReport);
        }
    
        @Override
        public void updateReport(String content, String title, Integer id) {
            reportDao.updateReport(content, title, id);
        }
    
        @Override
        public Report getById(Integer id) { return reportDao.getById(id); }
    }
    
  • CRUD单元测试

TO BE CONTONUED…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值