在前面的文章中, 表示了视图解析的原理和异常解析器的解析原理。
这篇通过如何自定义视图和自定义异常处理和自定义异常处理的原理进行说明。
这里说明一下, 自定义的视图和自定义的异常都是会代替容器默认的组件的, 异常还好说, 就是不符合就抛, 视图的话需要注意一下优先级, 可以在自定义的视图解析器上加上@Order
注解。
MeiNvView.java
public class MeiNvView implements View {
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
StringBuilder sb = new StringBuilder();
sb.append(model.get("info")).append(request.getParameter("name"));
response.getWriter().write(sb.toString());
}
}
MeiNvViewResolver.java
@Order
@Component
public class MeiNvViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (viewName.startsWith("meinv:")){
return new MeiNvView();
}
return null;
}
}
HelloController.java
@GetMapping("/meinv")
public String meinv(String name, Model model){
model.addAttribute("info", "001");
return "meinv:" + name;
}
这里原理就是添加一个视图和视图解析器, 然后放入容器中, 最后访问相应的路径就可以。
原理解释请看之前的文章
GgktException
: 自定义异常类
@Data
@AllArgsConstructor
@NoArgsConstructor
// 自定义异常
public class GgktException extends RuntimeException {
private Integer code;
private String msg;
}
GlobalExceptionHandler
: 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
// 全局异常
@ExceptionHandler(Exception.class)
// @ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.fail().message("执行了全局异常处理");
}
// 特定异常
@ExceptionHandler(ArithmeticException.class)
// @ResponseBody
public Result error(ArithmeticException e){
e.printStackTrace();
return Result.fail().message("执行了特定异常处理");
}
// 自定义异常
@ExceptionHandler(GgktException.class)
// @ResponseBody
public Result error(GgktException e){
e.printStackTrace();
return Result.fail().message(e.getMsg()).code(e.getCode());
}
}
Result
: 对于上述的异常处理的返回处理
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result(){}
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = new Result<T>();
if (body != null) {
result.setData(body);
}
result.setCode(code);
result.setMessage(message);
return result;
}
public static<T> Result<T> ok(){
return Result.ok(null);
}
/**
* 操作成功
* @param data baseCategory1List
* @param
* @return
*/
public static<T> Result<T> ok(T data){
return build(data,20000,"成功");
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
/**
* 操作失败
* @param data
* @param
* @return
*/
public static<T> Result<T> fail(T data){
return build(data, 20001,"失败");
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
}
这里通过一个自定义的异常加入到全局的异常处理中, 上面加了@ExceptionHandler
的注解
由上一篇可知, 异常解析器解析的过程中, 有3步, 第一步如果注解有@ExceptionHandler
的话优先考虑这个方案。
在此做一个解释。
因为ExceptionHandlerExceptionResolver
实现了 InitializingBean
这个接口, 所以实现了afterPropertiesSet
方法
ExceptionHandler
的一些信息@ControllerAdvice
的 ControllerAdviceBean
@ExceptionHandler
的注解的方法.
找到所以含有@ControllerAdvice
的类
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
}
public static final MethodFilter EXCEPTION_HANDLER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
这里是找到@ExceptionHandler
的类, 并缓存起来
AbstractHandlerMethodExceptionResolver.doResolveException()
-> ExceptionHandlerExceptionResolver.doResolveHandlerMethodException()
ExceptionHandlerExceptionResolver.doResolveHandlerMethodException()
这个方法遍历了所以的@ControllerAdvice
, 看哪个类可以解析异常