简单的junit使用小案例
1.导入测试对应的starter
2.测试类使用@SpringBootTest修饰
3.使用自动装配的形式添加要测试的对象
服务类
package com.yanyu.service;
public interface BookService {
public void save();
}
package com.yanyu.service;
import org.springframework.stereotype.Service;
@Service
public class BookServiceImpl implements BookService {
@Override
public void save() {
System.out.println("book service is running ...");
}
}
测试类
package com.yanyu;
import com.yanyu.service.BookService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SpringTest2ApplicationTests {
//1.注入你要测试的对象
//2.执行要测试的对象对应的方法
@Autowired
private BookService bookDao;
@Test
void testSave(){
bookDao.save();
}
@Test
void contextLoads() {
System.out.println("test...");
}
}
名称:@SpringBootTest
类型:测试类注解
位置:测试类定义上方
作用:设置JUnit加载的SpringBoot启动类,它的作用类似于@RunWith(SpringRunner.class)
和@SpringBootTest
。
范例:@SpringBootTest(classes = Springboot05JUnitApplication.class) class Springboot07JUnitApplicationTests { }
相关属性
◆classes:设置SpringBoot.启动类
核心配置:数据库连接相关信息(连什么、连谁、什么权限)
映射配置:SQL映射(XML/注解)?
①整合MyBatis需要在创建模块/工程的时候在SQL中勾选:
②设置数据源参数
#2.配置相关信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springboot
username: root
password: root
?③创建实体类
package com.yanyu.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
④创建dao(定义数据层接口与映射配置)
数据库SQL映射需要添加@Mapper被容器识别到
package com.yanyu.dao;
import com.yanyu.domain.Book;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface BookDao {
@Select("select * from book where id=#{id}")
public Book getById(Integer id);
}
@Mapper
注解是MyBatis框架中的一个注解,用于标记接口为映射器接口。映射器接口主要用于定义SQL语句和实体类之间的映射关系。
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`description` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
?⑤测试
package com.yanyu;
import com.yanyu.dao.BookDao;
import com.yanyu.domain.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringTest3ApplicationTests {
@Autowired
private BookDao bookDao;
@Test
public void testBookDao(){
Book book = bookDao.getById(1);
System.out.println(book);
}
}
①自行导入Druid的坐标
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
②配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://122.9.47.93:3306/
username:
password:
type: com.alibaba.druid.pool.DruidDataSource
测试:
同上
手动添加配置
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://122.9.47.93:3306/
username:
password:
package com.yanyu.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`description` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into book(type,name,description) values
('计算机理论','Spring实战 第五版','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into book(type,name,description) values
('计算机理论','Spring实战 核心原理','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into book(type,name,description) values
('计算机理论','Spring实战 设计模式','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into book(type,name,description) values
('计算机理论','Spring实战 入门到开发','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into book(type,name,description) values
('计算机理论','Java核心技术卷','Spring入门经典教程,深入理解Spring原理技术内幕');
package com.yanyu.service;
import com.yanyu.domain.Book;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* BookService接口,提供对书籍的增删改查操作。
*/
@Transactional
public interface BookService {
/**
* 保存书籍信息
* @param book 要保存的书籍对象
* @return 保存成功返回true,否则返回false
*/
public boolean save(Book book);
/**
* 修改书籍信息
* @param book 要修改的书籍对象
* @return 修改成功返回true,否则返回false
*/
public boolean update(Book book);
/**
* 根据ID删除书籍信息
* @param id 要删除的书籍ID
* @return 删除成功返回true,否则返回false
*/
public boolean delete(Integer id);
/**
* 根据ID查询书籍信息
* @param id 要查询的书籍ID
* @return 查询到的书籍对象,如果没有找到则返回null
*/
public Book getById(Integer id);
/**
* 查询所有书籍信息
* @return 包含所有书籍对象的列表,如果没有书籍则返回空列表
*/
public List<Book> getAll();
}
@Transactional
注解?
@Transactional
注解是Spring框架中的一个注解,用于声明一个方法需要进行事务管理。当在一个类中使用了@Transactional
注解的方法发生异常时,Spring会自动回滚事务,保证数据的一致性。
package com.yanyu.dao;
import com.yanyu.domain.Book;
import org.apache.ibatis.annotations.*;
import java.util.List;
// TODO 添加@Mapper
@Mapper
public interface BookDao {
@Insert("insert into book (type,name,description) values(#{type},#{name},#{description})")
public int save(Book book);
@Update("update book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
public int update(Book book);
@Delete("delete from book where id = #{id}")
public int delete(Integer id);
@Select("select * from book where id = #{id}")
public Book getById(Integer id);
@Select("select * from book")
public List<Book> getAll();
}
package com.yanyu.service.impl;
import com.yanyu.controller.Code;
import com.yanyu.dao.BookDao;
import com.yanyu.domain.Book;
import com.yanyu.exception.BusinessException;
import com.yanyu.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public boolean save(Book book) {
return bookDao.save(book) > 0;
}
public boolean update(Book book) {
return bookDao.update(book) > 0;
}
public boolean delete(Integer id) {
return bookDao.delete(id) > 0;
}
public Book getById(Integer id) {
if(id == 1){
throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
}
return bookDao.getById(id);
}
public List<Book> getAll() {
return bookDao.getAll();
}
}
package com.yanyu.service;
import com.yanyu.domain.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
void testSave() {
Book book = new Book(null, "游戏", "全职高手", "人生有梦,各自精彩");
bookService.save(book);
}
@Test
public void testUpdate() {
Book book = new Book(1, "小说", "红楼梦", "世事如梦,人生如戏");
bookService.update(book);
}
@Test
public void testDelete() {
bookService.delete(1);
}
@Test
public void testGetById() {
Book book = bookService.getById(2);
System.out.println(book);
}
@Test
public void testGetAll() {
List<Book> all = bookService.getAll();
System.out.println(all);
}
}
表现层数据封装
package com.yanyu.controller;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 结果类,用于封装返回给前端的数据
*/
@Data
@NoArgsConstructor
public class Result {
private Object data; // 数据对象
private Integer code; // 状态码
private String msg; // 消息提示
/**
* 带参数的构造方法
* @param code 状态码
* @param data 数据对象
*/
public Result(Integer code, Object data) {
this.data = data;
this.code = code;
}
/**
* 带参数和消息提示的构造方法
* @param code 状态码
* @param data 数据对象
* @param msg 消息提示
*/
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
}
package com.yanyu.controller;
// 定义一个名为Code的类
public class Code {
// 定义一些常量,表示不同的状态码
public static final Integer SAVE_OK = 20011; // 保存成功的状态码
public static final Integer DELETE_OK = 20021; // 删除成功的状态码
public static final Integer UPDATE_OK = 20031; // 更新成功的状态码
public static final Integer GET_OK = 20041; // 获取成功的状态码
public static final Integer SAVE_ERR = 20010; // 保存失败的状态码
public static final Integer DELETE_ERR = 20020; // 删除失败的状态码
public static final Integer UPDATE_ERR = 20030; // 更新失败的状态码
public static final Integer GET_ERR = 20040; // 获取失败的状态码
public static final Integer SYSTEM_ERR = 50001; // 系统错误的状态码
public static final Integer SYSTEM_TIMEOUT_ERR = 50002; // 系统超时的错误状态码
public static final Integer SYSTEM_UNKNOW_ERR = 59999; // 未知系统错误的状态码
public static final Integer BUSINESS_ERR = 60002; // 业务错误的状态码
}
业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 大家常见的就是提示用户名已存在或密码格式不正确等
系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
- 系统繁忙,请稍后再试
- 系统正在维护升级,请稍后再试
- 系统出问题,请联系系统管理员等
- 发送特定消息给运维人员,提醒维护
- 可以发送短信、邮箱或者是公司内部通信软件
- 记录日志
- 发消息和记录日志对用户来说是不可见的,属于后台程序
其他异常(Exception)
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给编程人员,提醒维护(纳入预期范围内)
- 一般是程序没有考虑全,比如未做非空校验等
- 记录日志
package com.yanyu.exception;
import lombok.Getter;
import lombok.Setter;
/**
* BusinessException类,继承自RuntimeException
*/
@Getter
@Setter
public class BusinessException extends RuntimeException {
private Integer code;
/**
* 构造方法1:接收错误码和错误信息
* @param code 错误码
* @param message 错误信息
*/
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
/**
* 构造方法2:接收错误码、错误信息和异常原因
* @param code 错误码
* @param message 错误信息
* @param cause 异常原因
*/
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
package com.yanyu.exception;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SystemException extends RuntimeException{
private Integer code;
public SystemException(Integer code, String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
package com.yanyu.controller;
import com.yanyu.exception.BusinessException;
import com.yanyu.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice // 使用@RestControllerAdvice注解,表示这是一个全局异常处理类
public class ProjectExceptionAdvice {
// 处理SystemException异常
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
// 记录日志
// 发送消息给运维
// 发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
// 处理BusinessException异常
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
// 处理其他异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
// 记录日志
// 发送消息给运维
// 发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
@RestControllerAdvice
注解?
@RestControllerAdvice
注解是Spring框架中的一个注解,用于创建一个全局的异常处理类。这个类可以处理所有的控制器抛出的异常,而不需要为每个控制器单独定义一个异常处理器。
@RestControllerAdvice
注解相当于以下几个注解的组合:
@ControllerAdvice
注解:用于定义一个全局的异常处理类。@ExceptionHandler
注解:用于指定处理方法,可以处理控制器抛出的异常。@ResponseBody
注解:用于将方法返回值转换为JSON格式响应体。@ResponseStatus
注解:用于设置HTTP状态码。
@ExceptionHandler
注解用于指定处理方法,可以处理控制器抛出的异常。它通常与@ControllerAdvice
注解一起使用,以定义全局的异常处理类。
????????@ControllerAdvice是一个注解,用于定义一个全局的异常处理器。它可以用于捕获控制器中抛出的异常,并统一处理这些异常。@ControllerAdvice注解可以用于类级别或方法级别。
????????在类级别上使用@ControllerAdvice注解,可以让它成为一个全局的异常处理器,可以处理所有控制器中抛出的异常。在方法级别上使用@ControllerAdvice注解,可以将它应用于特定的控制器方法,只处理该方法抛出的异常。
????????@ControllerAdvice注解可以定义一个或多个@ExceptionHandler方法,用于处理特定类型的异常。@ExceptionHandler方法可以接收一个异常对象作为参数,并返回一个包含错误信息的ModelAndView对象或一个响应对象。
前后端分离结构设计中页面归属前端服务器
单体工程中页面放置在resources目录下的static目录中(建议执行clean)
?