Spring 源码解析七:异常处理与视图解析

x33g5p2x  于2022-02-11 发布在 Spring  
字(21.2k)|赞(0)|评价(0)|浏览(543)

接着上一篇,讲一下剩下的几个策略

另外,View.render 视图渲染也在这里讲一下

1. ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver
的主要功能是解析处理器调用产生的异常

继承关系如下

  1. - AbstractHandlerExceptionResolver
  2. - AbstractHandlerMethodExceptionResolver
  3. - ExceptionHandlerExceptionResolver

1.1. AbstractHandlerExceptionResolver

AbstractHandlerExceptionResolver
的主要功能是可以设置异常处理器

  1. public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
  2. // 设置自定义处理器
  3. public void setMappedHandlers(Set<?> mappedHandlers) {
  4. this.mappedHandlers = mappedHandlers;
  5. }
  6. // 设置自定义处理器类
  7. public void setMappedHandlerClasses(Class<?>... mappedHandlerClasses) {
  8. this.mappedHandlerClasses = mappedHandlerClasses;
  9. }
  10. // 解析异常
  11. public ModelAndView resolveException(
  12. HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
  13. // 检查是否可应用处理器
  14. if (shouldApplyTo(request, handler)) {
  15. // 解析异常,调用处理器处理
  16. ModelAndView result = doResolveException(request, response, handler, ex);
  17. // ... 代码省略
  18. return result;
  19. }
  20. else {
  21. return null;
  22. }
  23. }
  24. }
  1. public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
  2. // 检查是否可应用处理器
  3. protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
  4. if (handler != null) {
  5. // 如果包含在mappedHandlers中,可以处理
  6. if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
  7. return true;
  8. }
  9. // 如果包含在mappedHandlerClasses中,可以处理
  10. if (this.mappedHandlerClasses != null) {
  11. for (Class<?> handlerClass : this.mappedHandlerClasses) {
  12. if (handlerClass.isInstance(handler)) {
  13. return true;
  14. }
  15. }
  16. }
  17. }
  18. // 如果没有mappedHandlers与mappedHandlerClasses,默认可以使用
  19. return !hasHandlerMappings();
  20. }
  21. // 解析异常,调用处理器处理,子类实现
  22. protected abstract ModelAndView doResolveException(
  23. HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
  24. }

1.2. AbstractHandlerMethodExceptionResolver

AbstractHandlerMethodExceptionResolver
的主要功能是可以通过异常类型来处理

  1. public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
  2. // 检查是否可应用处理器
  3. @Override
  4. protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
  5. if (handler == null) {
  6. return super.shouldApplyTo(request, null);
  7. }
  8. // 如果是,获取HandlerMethod内部的handler,继续判断
  9. else if (handler instanceof HandlerMethod) {
  10. HandlerMethod handlerMethod = (HandlerMethod) handler;
  11. handler = handlerMethod.getBean();
  12. return super.shouldApplyTo(request, handler);
  13. }
  14. // 如果有全局的异常处理器或自定义异常处理器,继续判断
  15. else if (hasGlobalExceptionHandlers() && hasHandlerMappings()) {
  16. return super.shouldApplyTo(request, handler);
  17. }
  18. // 否则就不能处理了
  19. else {
  20. return false;
  21. }
  22. }
  23. // 解析异常,调用处理器处理
  24. @Override
  25. protected final ModelAndView doResolveException(
  26. HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
  27. // 只能是HandlerMethod才能用于处理异常
  28. HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null);
  29. // 实际处理
  30. return doResolveHandlerMethodException(request, response, handlerMethod, ex);
  31. }
  32. // 实际处理,由子类实现
  33. protected abstract ModelAndView doResolveHandlerMethodException(
  34. HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);
  35. }

1.3. ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver
的主要功能是可以通过注解@ExceptionHandler来处理异常

1.3.1. ExceptionHandlerExceptionResolver.afterPropertiesSet

  1. public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
  2. implements ApplicationContextAware, InitializingBean {
  3. // 当属性都注入后,由上下文环境调用此方法初始化
  4. @Override
  5. public void afterPropertiesSet() {
  6. // 初始化`@ControllerAdvice`注解标注的组件
  7. initExceptionHandlerAdviceCache();
  8. if (this.argumentResolvers == null) {
  9. // 获取默认的参数解析器
  10. List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
  11. this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
  12. }
  13. if (this.returnValueHandlers == null) {
  14. // 获取默认的响应值处理器
  15. List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
  16. this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
  17. }
  18. }
  19. // 初始化`@ControllerAdvice`注解标注的组件
  20. private void initExceptionHandlerAdviceCache() {
  21. // ... 代码省略
  22. // 获取有`@ControllerAdvice`注解的bean
  23. List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
  24. // 进行遍历
  25. for (ControllerAdviceBean adviceBean : adviceBeans) {
  26. Class<?> beanType = adviceBean.getBeanType();
  27. if (beanType == null) {
  28. // 没有类型,报错
  29. }
  30. // @ExceptionHandler注解解析器
  31. ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
  32. // 有异常处理方法
  33. if (resolver.hasExceptionMappings()) {
  34. // 加入全局异常处理器缓存容器
  35. this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
  36. }
  37. // 是ResponseBodyAdvice的子类
  38. if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
  39. // 加入容器
  40. this.responseBodyAdvice.add(adviceBean);
  41. }
  42. }
  43. // ... 代码省略
  44. }
  45. }
  1. public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
  2. implements ApplicationContextAware, InitializingBean {
  3. // 获取默认的参数解析器
  4. protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
  5. List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
  6. // @SessionAttribute 解析
  7. resolvers.add(new SessionAttributeMethodArgumentResolver());
  8. // @RequestAttribute 解析
  9. resolvers.add(new RequestAttributeMethodArgumentResolver());
  10. // 从原生 ServletRequest 对象的输入流中解析请求头、请求体等
  11. resolvers.add(new ServletRequestMethodArgumentResolver());
  12. // 把处理器最终的数据写入到原生 ServletResponse 对象的输出流中,包括响应头、响应体等
  13. resolvers.add(new ServletResponseMethodArgumentResolver());
  14. // 重定向处理
  15. resolvers.add(new RedirectAttributesMethodArgumentResolver());
  16. // Model 处理
  17. resolvers.add(new ModelMethodProcessor());
  18. // ... 代码省略
  19. }
  20. // 获取默认的响应值处理器
  21. protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
  22. List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
  23. // ModelAndView 处理
  24. handlers.add(new ModelAndViewMethodReturnValueHandler());
  25. // Model 处理
  26. handlers.add(new ModelMethodProcessor());
  27. // View 处理
  28. handlers.add(new ViewMethodReturnValueHandler());
  29. // HttpEntity 处理
  30. handlers.add(new HttpEntityMethodProcessor(
  31. getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
  32. // 数据绑定解析
  33. handlers.add(new ServletModelAttributeMethodProcessor(false));
  34. // @RequestBody @ResponseBody 解析
  35. handlers.add(new RequestResponseBodyMethodProcessor(
  36. getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
  37. // 视图名字处理
  38. handlers.add(new ViewNameMethodReturnValueHandler());
  39. // Map 处理
  40. handlers.add(new MapMethodProcessor());
  41. // ... 代码省略
  42. return handlers;
  43. }
  44. }

1.3.2. ExceptionHandlerExceptionResolver.doResolveHandlerMethodException

  1. public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
  2. implements ApplicationContextAware, InitializingBean {
  3. // 实际处理异常
  4. @Override
  5. protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
  6. HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
  7. // 获取异常处理的方法对象
  8. ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
  9. // 如果没有,返回null
  10. if (exceptionHandlerMethod == null) {
  11. return null;
  12. }
  13. if (this.argumentResolvers != null) {
  14. // 注入参数解析器argumentResolvers
  15. exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  16. }
  17. if (this.returnValueHandlers != null) {
  18. // 注入响应处理returnValueHandlers
  19. exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  20. }
  21. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  22. // 响应容器
  23. ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  24. ArrayList<Throwable> exceptions = new ArrayList<>();
  25. try {
  26. // 遍历内部的异常
  27. Throwable exToExpose = exception;
  28. while (exToExpose != null) {
  29. exceptions.add(exToExpose);
  30. Throwable cause = exToExpose.getCause();
  31. exToExpose = (cause != exToExpose ? cause : null);
  32. }
  33. Object[] arguments = new Object[exceptions.size() + 1];
  34. exceptions.toArray(arguments);
  35. arguments[arguments.length - 1] = handlerMethod;
  36. // 调用处理器,获取处理结果,应用响应处理returnValueHandlers
  37. exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
  38. }
  39. catch (Throwable invocationEx) {
  40. // ... 代码省略
  41. }
  42. // 如果是已经处理过了,返回空ModelAndView
  43. if (mavContainer.isRequestHandled()) {
  44. return new ModelAndView();
  45. }
  46. else {
  47. // 获取模型对象
  48. ModelMap model = mavContainer.getModel();
  49. // 生成ModelAndView
  50. ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
  51. // ... 代码省略
  52. // 处理重定向
  53. if (model instanceof RedirectAttributes) {
  54. // ... 代码省略
  55. }
  56. return mav;
  57. }
  58. }
  59. // 获取异常处理的方法对象
  60. protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
  61. @Nullable HandlerMethod handlerMethod, Exception exception) {
  62. Class<?> handlerType = null;
  63. if (handlerMethod != null) {
  64. // 获取bean类型
  65. handlerType = handlerMethod.getBeanType();
  66. // 获取缓存的处理器
  67. ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
  68. // 如果没有,就生成,并缓存
  69. if (resolver == null) {
  70. resolver = new ExceptionHandlerMethodResolver(handlerType);
  71. this.exceptionHandlerCache.put(handlerType, resolver);
  72. }
  73. // 解析处理exception的方法
  74. Method method = resolver.resolveMethod(exception);
  75. // 有了就返回一个封装对象
  76. if (method != null) {
  77. return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
  78. }
  79. // ... 代码省略
  80. }
  81. // 没有自定义的,就使用全局的异常处理器
  82. for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
  83. ControllerAdviceBean advice = entry.getKey();
  84. if (advice.isApplicableToBeanType(handlerType)) {
  85. ExceptionHandlerMethodResolver resolver = entry.getValue();
  86. // 解析处理exception的方法
  87. Method method = resolver.resolveMethod(exception);
  88. // 有了就返回一个封装对象
  89. if (method != null) {
  90. return new ServletInvocableHandlerMethod(advice.resolveBean(), method);
  91. }
  92. }
  93. }
  94. return null;
  95. }
  96. }

2. ResponseStatusExceptionResolver

ResponseStatusExceptionResolver
的主要功能是支持@ResponseStatus注解映射状态码

  1. public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {
  2. // 解析异常,调用处理器处理
  3. @Override
  4. protected ModelAndView doResolveException(
  5. HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
  6. try {
  7. // 如果ResponseStatusException,把ResponseStatusException内部的responseHeaders设置到响应中
  8. // 并设置响应码和响应原因
  9. if (ex instanceof ResponseStatusException) {
  10. return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);
  11. }
  12. // 不然,查看异常类的`@ResponseStatus`注解,如果有,设置响应码和响应原因
  13. ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
  14. if (status != null) {
  15. return resolveResponseStatus(status, request, response, handler, ex);
  16. }
  17. // 如果有内部异常,循环遍历处理
  18. if (ex.getCause() instanceof Exception) {
  19. return doResolveException(request, response, handler, (Exception) ex.getCause());
  20. }
  21. }
  22. catch (Exception resolveEx) {
  23. // ... 代码省略
  24. }
  25. return null;
  26. }
  27. }

3. DefaultHandlerExceptionResolver

DefaultHandlerExceptionResolver
的主要功能是把标准 SpringMVC 异常映射状态码

  1. public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
  2. // 解析异常,调用处理器处理
  3. @Override
  4. protected ModelAndView doResolveException(
  5. HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
  6. try {
  7. // 405
  8. if (ex instanceof HttpRequestMethodNotSupportedException) {
  9. return handleHttpRequestMethodNotSupported(
  10. (HttpRequestMethodNotSupportedException) ex, request, response, handler);
  11. }
  12. // 415
  13. else if (ex instanceof HttpMediaTypeNotSupportedException) {
  14. return handleHttpMediaTypeNotSupported(
  15. (HttpMediaTypeNotSupportedException) ex, request, response, handler);
  16. }
  17. // 406
  18. else if (ex instanceof HttpMediaTypeNotAcceptableException) {
  19. return handleHttpMediaTypeNotAcceptable(
  20. (HttpMediaTypeNotAcceptableException) ex, request, response, handler);
  21. }
  22. // 500
  23. else if (ex instanceof MissingPathVariableException) {
  24. return handleMissingPathVariable(
  25. (MissingPathVariableException) ex, request, response, handler);
  26. }
  27. // 400
  28. else if (ex instanceof MissingServletRequestParameterException) {
  29. return handleMissingServletRequestParameter(
  30. (MissingServletRequestParameterException) ex, request, response, handler);
  31. }
  32. // 400
  33. else if (ex instanceof ServletRequestBindingException) {
  34. return handleServletRequestBindingException(
  35. (ServletRequestBindingException) ex, request, response, handler);
  36. }
  37. // 500
  38. else if (ex instanceof ConversionNotSupportedException) {
  39. return handleConversionNotSupported(
  40. (ConversionNotSupportedException) ex, request, response, handler);
  41. }
  42. // 400
  43. else if (ex instanceof TypeMismatchException) {
  44. return handleTypeMismatch(
  45. (TypeMismatchException) ex, request, response, handler);
  46. }
  47. // 400
  48. else if (ex instanceof HttpMessageNotReadableException) {
  49. return handleHttpMessageNotReadable(
  50. (HttpMessageNotReadableException) ex, request, response, handler);
  51. }
  52. // 500
  53. else if (ex instanceof HttpMessageNotWritableException) {
  54. return handleHttpMessageNotWritable(
  55. (HttpMessageNotWritableException) ex, request, response, handler);
  56. }
  57. // 400
  58. else if (ex instanceof MethodArgumentNotValidException) {
  59. return handleMethodArgumentNotValidException(
  60. (MethodArgumentNotValidException) ex, request, response, handler);
  61. }
  62. // 400
  63. else if (ex instanceof MissingServletRequestPartException) {
  64. return handleMissingServletRequestPartException(
  65. (MissingServletRequestPartException) ex, request, response, handler);
  66. }
  67. // 400
  68. else if (ex instanceof BindException) {
  69. return handleBindException((BindException) ex, request, response, handler);
  70. }
  71. // 404
  72. else if (ex instanceof NoHandlerFoundException) {
  73. return handleNoHandlerFoundException(
  74. (NoHandlerFoundException) ex, request, response, handler);
  75. }
  76. // 503
  77. else if (ex instanceof AsyncRequestTimeoutException) {
  78. return handleAsyncRequestTimeoutException(
  79. (AsyncRequestTimeoutException) ex, request, response, handler);
  80. }
  81. }
  82. catch (Exception handlerEx) {
  83. // ... 代码省略
  84. }
  85. return null;
  86. }
  87. }

4. DefaultRequestToViewNameTranslator

DefaultRequestToViewNameTranslator
的主要功能是把 URI 映射视图名字

  1. public class DefaultRequestToViewNameTranslator implements RequestToViewNameTranslator {
  2. // 根据请求获取视图名字
  3. @Override
  4. public String getViewName(HttpServletRequest request) {
  5. // 获取URI的path部分
  6. String path = ServletRequestPathUtils.getCachedPathValue(request);
  7. // 加上前缀与后缀
  8. return (this.prefix + transformPath(path) + this.suffix);
  9. }
  10. // 转换path
  11. protected String transformPath(String lookupPath) {
  12. String path = lookupPath;
  13. // 去掉开头的/
  14. if (this.stripLeadingSlash && path.startsWith(SLASH)) {
  15. path = path.substring(1);
  16. }
  17. // 去掉结尾的/
  18. if (this.stripTrailingSlash && path.endsWith(SLASH)) {
  19. path = path.substring(0, path.length() - 1);
  20. }
  21. // 去掉扩展名
  22. if (this.stripExtension) {
  23. path = StringUtils.stripFilenameExtension(path);
  24. }
  25. // 确保分隔符为/
  26. if (!SLASH.equals(this.separator)) {
  27. path = StringUtils.replace(path, SLASH, this.separator);
  28. }
  29. return path;
  30. }
  31. }

5. InternalResourceViewResolver

InternalResourceViewResolver
的主要功能是把视图名字解析成视图对象

继承关系如下

  1. - AbstractCachingViewResolver
  2. - UrlBasedViewResolver
  3. - InternalResourceViewResolver

5.1. AbstractCachingViewResolver

AbstractCachingViewResolver
的主要功能是把视图名字解析成视图对象

  1. public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {
  2. // 把视图名字解析成视图对象
  3. @Override
  4. public View resolveViewName(String viewName, Locale locale) throws Exception {
  5. // 如果不使用缓存,则每次都加载一次视图文件
  6. if (!isCache()) {
  7. return createView(viewName, locale);
  8. }
  9. else {
  10. // 获取缓存键
  11. Object cacheKey = getCacheKey(viewName, locale);
  12. // 获取缓存
  13. View view = this.viewAccessCache.get(cacheKey);
  14. if (view == null) {
  15. synchronized (this.viewCreationCache) {
  16. view = this.viewCreationCache.get(cacheKey);
  17. if (view == null) {
  18. // 缓存中不存在,加载创建视图对象,并加入缓存
  19. view = createView(viewName, locale);
  20. // ... 代码省略
  21. if (view != null) {
  22. this.viewAccessCache.put(cacheKey, view);
  23. this.viewCreationCache.put(cacheKey, view);
  24. }
  25. }
  26. }
  27. }
  28. return (view != UNRESOLVED_VIEW ? view : null);
  29. }
  30. }
  31. protected View createView(String viewName, Locale locale) throws Exception {
  32. return loadView(viewName, locale);
  33. }
  34. // 加载视图,子类实现
  35. protected abstract View loadView(String viewName, Locale locale) throws Exception;
  36. }

5.2. UrlBasedViewResolver

UrlBasedViewResolver
的主要功能是支持把直接视图名字映射为 url

  1. public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
  2. @Override
  3. protected View createView(String viewName, Locale locale) throws Exception {
  4. // ... 代码省略
  5. // 以"redirect:"开头的重定向,可以跳到其他视图
  6. if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
  7. String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
  8. RedirectView view = new RedirectView(redirectUrl,
  9. isRedirectContextRelative(), isRedirectHttp10Compatible());
  10. // ... 代码省略
  11. return view;
  12. }
  13. // 以"forward:"开头的重定向,可以转发到其他视图
  14. if (viewName.startsWith(FORWARD_URL_PREFIX)) {
  15. String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
  16. InternalResourceView view = new InternalResourceView(forwardUrl);
  17. return view;
  18. }
  19. // 其他保持父类行为
  20. return super.createView(viewName, locale);
  21. }
  22. }
  1. public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
  2. // 加载视图
  3. @Override
  4. protected View loadView(String viewName, Locale locale) throws Exception {
  5. // 构建视图
  6. AbstractUrlBasedView view = buildView(viewName);
  7. // ... 代码省略
  8. return view;
  9. }
  10. // 构建视图
  11. protected AbstractUrlBasedView buildView(String viewName) throws Exception {
  12. // 初始化视图类
  13. AbstractUrlBasedView view = instantiateView();
  14. // 设置路径
  15. view.setUrl(getPrefix() + viewName + getSuffix());
  16. // 设置解析数据
  17. view.setAttributesMap(getAttributesMap());
  18. // ... 代码省略
  19. return view;
  20. }
  21. }

5.3. InternalResourceViewResolver

InternalResourceViewResolver
的主要功能是支持 InternalResourceView 和 JstlView

  1. public class InternalResourceViewResolver extends UrlBasedViewResolver {
  2. @Override
  3. protected AbstractUrlBasedView instantiateView() {
  4. return (getViewClass() == InternalResourceView.class ? new InternalResourceView() :
  5. (getViewClass() == JstlView.class ? new JstlView() : super.instantiateView()));
  6. }
  7. }

6. 视图渲染

6.1. View

View
是所有扩展视图组件的基础接口,主要就是 render 方法

  1. public interface View {
  2. void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
  3. throws Exception;
  4. }

6.2. AbstractView

AbstractView
的主要功能是支持 Spring 对视图组件以 bean 形式来管理

  1. public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware {
  2. // 渲染视图
  3. @Override
  4. public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
  5. HttpServletResponse response) throws Exception {
  6. // 合并其他数据到模型中
  7. Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
  8. // 渲染合并的模型数据
  9. renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
  10. }
  11. // 合并其他数据到模型中
  12. protected Map<String, Object> createMergedOutputModel(@Nullable Map<String, ?> model,
  13. HttpServletRequest request, HttpServletResponse response) {
  14. // 路径变量
  15. Map<String, Object> pathVars = (this.exposePathVariables ?
  16. (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);
  17. // 注入的静态属性
  18. int size = this.staticAttributes.size();
  19. size += (model != null ? model.size() : 0);
  20. size += (pathVars != null ? pathVars.size() : 0);
  21. // 合并路径变量与静态属性到模型中
  22. Map<String, Object> mergedModel = CollectionUtils.newLinkedHashMap(size);
  23. mergedModel.putAll(this.staticAttributes);
  24. if (pathVars != null) {
  25. mergedModel.putAll(pathVars);
  26. }
  27. if (model != null) {
  28. mergedModel.putAll(model);
  29. }
  30. // ... 代码省略
  31. return mergedModel;
  32. }
  33. // 渲染合并的模型数据,子类实现
  34. protected abstract void renderMergedOutputModel(
  35. Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
  36. }

6.3. AbstractUrlBasedView

AbstractUrlBasedView
的主要功能是要求有一个 url 数据,其他没有什么功能

6.4. AbstractTemplateView

AbstractTemplateView
的主要功能是实现模板渲染,纯接口数据(不需要模板渲染的),直接继承 AbstractView 就可以了

  1. public abstract class AbstractTemplateView extends AbstractUrlBasedView {
  2. // 渲染合并的模型数据
  3. @Override
  4. protected final void renderMergedOutputModel(
  5. Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
  6. // ... 代码省略,载入请求属性、session属性、spring宏属性到模型数据中
  7. // 渲染合并的模型数据到模板
  8. renderMergedTemplateModel(model, request, response);
  9. }
  10. // 渲染合并的模型数据到模板,子类实现
  11. protected abstract void renderMergedTemplateModel(
  12. Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
  13. }

6.5. FreeMarkerView

FreeMarkerView
的主要功能是用 FreeMarker 渲染视图

  1. public class FreeMarkerView extends AbstractTemplateView {
  2. // 渲染合并的模型数据到模板
  3. @Override
  4. protected void renderMergedTemplateModel(
  5. Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
  6. doRender(model, request, response);
  7. }
  8. protected void doRender(Map<String, Object> model, HttpServletRequest request,
  9. HttpServletResponse response) throws Exception {
  10. // ... 代码省略
  11. // 构建FreeMarker模板对象
  12. SimpleHash fmModel = buildTemplateModel(model, request, response);
  13. // ... 代码省略
  14. // 获取模板文件,渲染模板到response
  15. processTemplate(getTemplate(locale), fmModel, response);
  16. }
  17. // 渲染模板到response
  18. protected void processTemplate(Template template, SimpleHash model, HttpServletResponse response)
  19. throws IOException, TemplateException {
  20. // 输入模板渲染结果到response writer
  21. template.process(model, response.getWriter());
  22. }
  23. }

6.6. MappingJackson2JsonView

MappingJackson2JsonView
的主要功能是用 jackson 来序列化输出接口数据,直接继承 AbstractView

  1. public class MappingJackson2JsonView extends AbstractView {
  2. // 渲染合并的模型数据
  3. @Override
  4. protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
  5. HttpServletResponse response) throws Exception {
  6. // 字节数组输出流
  7. ByteArrayOutputStream temporaryStream = null;
  8. // 输出流
  9. OutputStream stream;
  10. // 需要更新'Content-Length'头
  11. if (this.updateContentLength) {
  12. // 创建一个新的临时输出流
  13. temporaryStream = createTemporaryOutputStream();
  14. stream = temporaryStream;
  15. }
  16. else {
  17. // 不然使用response的输出流
  18. stream = response.getOutputStream();
  19. }
  20. // 把一些不需要的对象过滤掉,包装成可序列化的对象
  21. Object value = filterAndWrapModel(model, request);
  22. // 把结果写入输出流中
  23. writeContent(stream, value);
  24. if (temporaryStream != null) {
  25. // 如果有新的临时输出流,把这个新的流写入到response对象中
  26. writeToResponse(response, temporaryStream);
  27. }
  28. }
  29. // 把结果写入输出流中
  30. protected void writeContent(OutputStream stream, Object object) throws IOException {
  31. // 生成一个JsonGenerator
  32. try (JsonGenerator generator = this.objectMapper.getFactory().createGenerator(stream, this.encoding)) {
  33. // ... 代码省略
  34. Object value = object;
  35. Class<?> serializationView = null;
  36. FilterProvider filters = null;
  37. // 获取序列化视图和过滤器
  38. if (value instanceof MappingJacksonValue) {
  39. MappingJacksonValue container = (MappingJacksonValue) value;
  40. value = container.getValue();
  41. serializationView = container.getSerializationView();
  42. filters = container.getFilters();
  43. }
  44. // 给writer加入序列化视图
  45. ObjectWriter objectWriter = (serializationView != null ?
  46. this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
  47. // 给writer加入过滤器,如字段过滤
  48. if (filters != null) {
  49. objectWriter = objectWriter.with(filters);
  50. }
  51. objectWriter.writeValue(generator, value);
  52. // ... 代码省略
  53. // 刷新数据
  54. generator.flush();
  55. }
  56. }
  57. }

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证

相关文章