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一致
项目结构分析:
通过上面步骤完成了基础项目的创建。就会自动生成以下文件
-
程序的主启动类(使用
@SpringBootApplication
)XXXApplication.java
其中自动配置的核心文件是
META-INF/spring.factories
(源码里有说),文件位置在External Libraries/Maven:org.springframework.boot:spring-boot-autoconfigure:版本号
包下。 -
一个
application.properties
配置文件 -
一个测试类
-
一个
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接口中没有根据name和pwd查询的接口,这就需要我们自行定义。
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…