(6)Spring Boot web开发 --- 错误处理页面
处理时间(Date)类型
Spring Boot 进行参数绑定使用的是 SpringMvc ,涉及 Date 类型的参数绑定的时候,默认是时间格式是 yyyy/MM/dd ,我们可以自定义格式,只需要配置文件里面配置下:
# 日期格式
spring.mvc.date-format=yyyy.MM.dd
thymeleaf 页面拼接字符串
表达式之间直接使用 + 拼接,比如 :@{/emp/} + ${emp.id} ;
映射路径占位符
在映射路径中可以使用占位符的 @GetMapping(/emp/{id}) ;这样参数传入 id 就会被放到
使用 put、delete 方法
表单 仅支持两种方法提交,POST ,GET ;
如果想要使用其他方法,则需要进行一番操作;
-
SpringMvc配置HiddenHttpMethodFilter(Spring Boot已经自动配置好了,美滋滋); -
页面创建一个表单
-
创建一个
input项,type为hidden,·name属性值必须为_method,然后value属性的值,就写我们想要使用的方法:<input type="hidden" name="_method" value="put">
错误处理机制
-
Spring Boot默认返回一个白板页面; -
自定义错误响应
-
定制错误的页面
-
有模板引擎
将错误页面放在 类路径 的
templates/error文件夹下面,命名为 状态码.html ,这样发生错误的时候,就会去寻找状态码对应的页面;当然这样很傻,那么多状态码,需要写很多页面,因此,还可以直接创建
4xx.html、5xx.html,这样发生404,402,403这些4xx的错误的时候,由于没有对应的页面,就会退而其次,匹配4xx.html页面,5xx也是同样的道理 ;如果
4xx.html、404.html同时存在,这时候发生404错误,会匹配上404.html,精确优先 ;在页面中还可以获取一些信息:
timestamp(时间戳)、status(状态码)、error(错误提示)、exception(异常对象),message(异常消息),errors(JSR303数据校验的错误信息) -
没有模板引擎
没有模板引擎,就去静态资源文件夹下面,寻找对应的
4xx.html ,5xx.html; -
以上两种情况都没有
那就莫得选择了,只能使用
Spring Boot的默认错误提示页面 ;
-
-
定制错误
JSON自定义异常处理器,使用
@ControllerAdvice标注类,然后在方法上,使用@ExceptionHandler标注要处理什么异常,然后只要发生了对应的异常,该方法就会得到调用,方法参数可以写一些我们自己想要获得的对象;@ControllerAdvice public class MyExceptionController { @ResponseBody @ExceptionHandler({UserNotExistException.class}) public Map<String,Object> handlerUserNotExist(Exception e){ Map<String,Object> map = new HashMap<>(); map.put("code","Test Exception"); map.put("message",e.getMessage()); return map ; } }方法的返回值,就会被送到页面,但是这样有个缺点,丢失自适应效果(本来浏览器和终端方法,
Spring Boot会显示不同的效果的,浏览器显示 白板错误页面,终端显示JSON串 ),无论是浏览器还是终端,都显示JSON串;进行改动下,转发到
/error炸,就可以自适应了:@ExceptionHandler({UserNotExistException.class}) public String handlerUserNotExistAdaptive(Exception e){ Map<String,Object> map = new HashMap<>(); map.put("code","Test Exception"); map.put("message",e.getMessage()); // 转发到 /error return "forward:/error" ; }但是 又有新问题了:发生异常以后,状态码,就会变成
4xx ,5xx,然后被我上面的方法捕捉到以后,来了一个转发,异常被吞咽了,异常链断掉了,状态码已经变了,变为正常的200,因为转发又没发生异常;虽然转发到
/error,但是状态码已经变了,此时去/error下面,没有对应的页面了,就只能找默认的页面了;因此,我们在转发之前,设置下状态码:
request.setAttribute("javax.servlet.error.status_code",400);,键不是瞎写的,是必须是这个:@ExceptionHandler({UserNotExistException.class}) public String handlerUserNotExistAdaptive(Exception e, HttpServletRequest request){ request.setAttribute("javax.servlet.error.status_code",400); Map<String,Object> map = new HashMap<>(); map.put("code","Test Exception"); map.put("message",e.getMessage()); // 转发到 /error return "forward:/error" ; }现在还有最后一个问题,我们在转发的时候,带过去的数据,页面其实拿不到的,现在要解决这个问题:
页面上能用的数据,或者
JSON返回能用的数据,其实都是在ErrorAttributes.class类里面的,通过getErrorAttibutes获取的,因此,我们只需要获取到getErrorAttibutes方法的返回值,然后再返回值里面添加上我们自己的数据即可 ;@Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace); errorAttributes.put("message","Test"); return errorAttributes; } }
-
如果我们在别的地方也有数据想要带到页面,需要向下面这样做:
-
首先在转发之前,将我们的数据放到域里面;
@ExceptionHandler({UserNotExistException.class}) public String handlerUserNotExistAdaptive(Exception e, HttpServletRequest request){ request.setAttribute("javax.servlet.error.status_code",400); Map<String, Object> myErrorAttributesMap = new HashMap<>(); myErrorAttributesMap.put("message","sasasa"); myErrorAttributesMap.put("code","Test Exception"); request.setAttribute("errorAttributesMap",myErrorAttributesMap); // 转发到 /error return "forward:/error" ; } -
然后在
getErrorAttibutes方法,从域里面取出来,然后添加到getErrorAttibutes方法的返回值中;
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
// 数字代表域,0 是 request , 1 是 session ,
Map<String, Object> errorAttributesMap = (Map<String, Object>) webRequest.getAttribute("errorAttributesMap", 0);
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
errorAttributes.put("message","Test");
errorAttributes.put("error",errorAttributesMap);
return errorAttributes;
}

浙公网安备 33010602011771号