方式一
/**
* 自定义异常处理器,处理请求产生的异常。在这里即可封装返回的json数据。
* 但是没有自适应效果,即浏览器端访问和其他客户端访问均返回json数据。
**/
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
// 请求抛出自定义的UserNotExistException异常,在这里声明专门捕获该异常
@ExceptionHandler(UserNotExistException.class)
public Map<String,Object> handleException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
return map;
}
}
通过上述自定义异常处理器的方式,无法实现自适应的效果。因此,不能通过直接拦截异常处理的方式来定制返回的json数据。
因此,我们需要进行优化,可以通过转发到/error
,进而被BasicErrorController
处理的方式,来进行自适应响应的效果处理。
方式二
/**
* 自定义异常处理器,不再直接返回json数据,而是重定向到 /error,进而被BasicErrorController处理,
* 再通过自定义的ErrorAttributes来处理json。
**/
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
/**
* 传入我们自己的错误状态码,并且保证该状态码有对应的错误页面和解析流程,
* 否则就不会进入定制错误页面的解析流程
**/
request.setAttribute("javax.servlet.error.status_code", 504);
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
// 重定向到/error
return "forward:/error";
}
}
接下来就需要将我们的定制数据携带出去。出现错误以后,会来到/error
请求,会被BasicErrorController
处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法)。
思路:
1、完全来编写一个ErrorController
的实现类或者是编写AbstractErrorController
的子类,放在容器中。
2、页面上能获取的数据或者是json返回的数据都是通过errorAttributes.getErrorAttributes()
得到。
容器中DefaultErrorAttributes.getErrorAttributes()
用于数据处理。
// 给容器中加入自定义的ErrorAttributes,通过定制ErrorAttributes改变需要返回的内容
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company","atguigu");
return map;
}
}
最终的效果:响应是自适应的,浏览器访问返回定制的错误页面,其他客户端访问返回定制的json数据。