SpringBoot
8 SpringBoot异常处理和单元测试
8.1 异常处理
8.1.1 自定义错误页面
SpringBoot默认处理异常机制:SpringBoot默认已经提供了一套处理异常的机制。一旦 程序中出现异常,SpringBoot会向/error的url发送请求。在SpringBoot中提供了一个名为BasicErrorController来处理/error请求,然后跳转到默认显示异常页面来显示异常信息。
我们可以在src/main/resources/templates 目录下创建error.html页面。注意:页面名称必须叫error。这时出现异常直接跳转到我们创建的error页面。
缺点:所有的异常都将会跳转到这个页面,不能根据异常的不同而跳到不同的页面。
8.1.2 @ExceptionHandler注解(分别处理不同的异常)
空指针异常:方法必须返回ModelAndView
/**
* ExceptionHandler:处理哪些个异常,这个注解会给方法注入Exception对象
* 缺点:需要和相应的请求处理方法在同一个controller中
* @param e
* @return
*/
@ExceptionHandler(value = {java.lang.NullPointerException.class})
public ModelAndView getNullPointerException(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("msgError",e.toString());//异常信息
mv.setViewName("error1");//跳转到异常页面
return mv;
}
error1.html中显示异常信息
<span th:text="${msgError}"></span>
缺点:需要和相应的请求处理方法在同一个controller中;别的controller中想要相应的异常处理,就需要重新写一遍方法,代码冗余。
8.1.3 @ControllerAdvice和@ExceptionHandler(进行全局异常处理)
为了解决上面缺点,将异常进行封装,可使所有的controller都可以使用。所以需要创建一个全局异常类。
[注意]:必须要在类上添加@ControllerAdvice注解,在这类中就可以添加相应的异常处理方法进行异常的处理。
/**
* 全局异常处理必须加上ControllerAdvice注解
*/
@ControllerAdvice
public class GlobalException {
//处理空指针异常
@ExceptionHandler(value = {java.lang.NullPointerException.class})
public ModelAndView getNullPointerException(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("msgError",e.toString());
mv.setViewName("error2");
return mv;
}
//处理数学运算异常
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public ModelAndView getArithmeticException(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("msgError",e.toString());
mv.setViewName("error3");
return mv;
}
}
缺点:全局异常类中的方法会有很多,相对比较复杂。
8.1.4 SimpleMappingExceptionResolver对象
为了解决上面的缺点,使用SimpleMappingExceptionResolver对象,只需要一个方法就可以处理不同的异常。需要创建一个配置类,并注入一个SimpleMappingExceptionResolver的bean。
/**
* 创建一个配置类,并注入一个SimpleMappingExceptionResolver的bean
*/
@Configuration
public class GlogalException2 {
/**
* 这个方法的返回值必须是SimpleMappingExceptionResolver对象
* 缺点:只能进行页面跳转,而不能返回错误信息
* @return
*/
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
//这个有两个参数:第一个参数:异常类型,全类名;第二个参数:视图的名称
properties.put("java.lang.NullPointerException","error4");
properties.put("java.lang.ArithmeticException","error5");
resolver.setExceptionMappings(properties);
return resolver;
}
}
缺点:只能进行页面跳转,而不能返回错误信息。
8.1.5 自定义HandlerExceptionResolver对象
为了解决8.1.4缺点,该方法实现HandlerExceptionResolver接口,并且重写resolveException这个方法。
/**
* 通过Configuration注解进行开发.必须实现HandlerExceptionResolver接口,并且重写resolveException这个方法.
* 在这个方法中判断发生的是哪一个异常,针对不同的异常跳转到不同的视图,并且进行异常信息的跳转
*/
@Configuration
public class GlobalException3 implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object handler, Exception e) {
ModelAndView mv = new ModelAndView();
if(e instanceof NullPointerException){
mv.setViewName("error6");
}else if(e instanceof ArithmeticException){
mv.setViewName("error7");
}
mv.addObject("Err",e.toString());
return mv;
}
}
8.2 单元测试(SpringBoot2.x使用的是Junit5)
1、在pom文件添加测试启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!--junit-vintage-engine支持junit3和junit4的运行平台-->
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
//@SpringBootTest
@SpringBootTest(classes = SpringBootExceptionAndJunitApplication.class)
public class Junit5Test {
@Autowired
private UserServiceImpl userService;
@Test
public void test(){
this.userService.insInfo();
}
}
9 SpringBoot服务端数据校验
9.1 对实体对象的校验
9.1.1创建实体类=>创建controller=>页面
public class User {
private int id;
private String name;
private String sex;
}
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/addUser")
public String addUser(User user){
return "ok";
}
}
<form th:action="@{/user/addUser}" method="post">
姓名:<input type="text" name="name"><br>
性别:<input type="text" name="sex"><br>
<input type="submit" value="Submit">
</form>
9.1.2对实体对象做数据校验
步骤:
(1)修改实体类,添加校验规则
/**
* @NotNull:是基本类型的对象类型进行非空判断
* @NotBlank:对字符串类型进行非空校验
* @NotEmpty:对集合类型进行非空校验
*/
public class User {
@NotNull
private int id;
@NotBlank
private String name;
@NotBlank
private String sex;
}
(2)修改controller
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 进行相应的数据校验
* Validated:校验的对象
* BindingResult:如果校验不成功将会返回这个值
*/
@RequestMapping("/addUser")
public String addUser(@Validated User user, BindingResult result){
//判断都否合法
if(result.hasErrors()){
//保存错误信息
List<ObjectError> list = result.getAllErrors();
for (ObjectError err:list){
FieldError error = (FieldError) err;
//校验不合法的名称
String fieldName = error.getField();
//校验不合法的信息
String fieldMsg = error.getDefaultMessage();
System.out.println(fieldName+":"+fieldMsg);
}
return "addUser";
}
return "ok";
}
}
(3)在页面获取提示信息
<form th:action="@{/user/addUser}" method="post">
姓名:<input type="text" name="name"><font color="red"><span th:errors="${user.name}"/></font><br>
性别:<input type="text" name="sex"><font color="red"><span th:errors="${user.sex}"/></font><br>
<input type="submit" value="Submit">
</form>
9.1.3 自定义错误提示信息
1、在注解中定义提示信息
@NotNull(message = “xxxxxxxx”)
缺点:硬编码,修改不方便。
2、在配置文件中定义提示信息
[注意]:配置文件名必须是ValidationMessages.properties
name.notNull=name不能为空--
sex.notNull=sex不能为空--
@NotBlank(message = "{name.notNull}")
9.1.4 解决页面跳转异常
直接访问页面会出现异常,所以可以在页面跳转的方法中注入一个User(进行校验的实体类)对象,SpringMVC会将该对象放到Model中传递。
@Controller
public class PageController {
@RequestMapping("/{page}")
/**
* 注入一个User对象,由于springMVC会将该对象放到Model中传递
*/
public String showPage(@PathVariable String page, User user){
//System.out.println(page);
return page;
}
}
9.2 对controller中其他参数的校验
步骤:
1、对参数指定校验规则
2、controller上添加@Validated
@Controller
@RequestMapping("/user")
@Validated
public class UserController {
/**
* 其他参数校验:1、对参数指定校验规则 2、Controller上加@Validated
* @param name
* @return
*/
@RequestMapping("/findUser")
public String findUser(@NotBlank(message = "name不能为空") String name){
System.out.println(name);
return "ok";
}
}
此时请求会报错:ConstraintViolationException!!!所以这里就需要使用全局异常处理对该异常进行处理,并返回一个异常页面。
@Configuration
public class GlobalException implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object handler, Exception e) {
ModelAndView mv = new ModelAndView();
if (e instanceof ConstraintViolationException){
mv.setViewName("findUser");
}
mv.addObject("Err",e.getMessage().split(":")[1]);
return mv;
}
}
10 SpringBoot热部署
在之前的学习中,我们发现只要是修改项目,就必须重新启动项目。
热部署:在修改原有代码之后不需要重新启动就可以直接呈现。
步骤:
1、修改pom文件:添加devtool依赖
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
2、配置Idea:
(1)设置自动编译;
(2)设置Regidtry。(Ctrl+shift+Alt+/)