关于后端:Spring-源码解析七异常处理与视图解析

48次阅读

共计 21018 个字符,预计需要花费 53 分钟才能阅读完成。

Spring 源码解析七:异样解决与视图解析

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

  • 把 ExceptionHandlerExceptionResolver
    、ResponseStatusExceptionResolver
    、DefaultHandlerExceptionResolver
    作为默认的处理器异样解析器
  • 把 DefaultRequestToViewNameTranslator
    作为默认的视图查找处理器
  • 把 InternalResourceViewResolver
    作为默认的视图解析器

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

1. ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver
的次要性能是解析处理器调用产生的异样

继承关系如下

- AbstractHandlerExceptionResolver
  - AbstractHandlerMethodExceptionResolver
    - ExceptionHandlerExceptionResolver

1.1. AbstractHandlerExceptionResolver

AbstractHandlerExceptionResolver
的次要性能是能够设置异样处理器

public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
    // 设置自定义处理器
    public void setMappedHandlers(Set<?> mappedHandlers) {this.mappedHandlers = mappedHandlers;}
    // 设置自定义处理器类
    public void setMappedHandlerClasses(Class<?>... mappedHandlerClasses) {this.mappedHandlerClasses = mappedHandlerClasses;}

    // 解析异样
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
        // 查看是否可利用处理器
        if (shouldApplyTo(request, handler)) {
            // 解析异样,调用处理器解决
            ModelAndView result = doResolveException(request, response, handler, ex);

            // ... 代码省略

            return result;
        }
        else {return null;}
    }
}
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
    // 查看是否可利用处理器
    protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {if (handler != null) {
            // 如果蕴含在 mappedHandlers 中,能够解决
            if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {return true;}
            // 如果蕴含在 mappedHandlerClasses 中,能够解决
            if (this.mappedHandlerClasses != null) {for (Class<?> handlerClass : this.mappedHandlerClasses) {if (handlerClass.isInstance(handler)) {return true;}
                }
            }
        }
        // 如果没有 mappedHandlers 与 mappedHandlerClasses,默认能够应用
        return !hasHandlerMappings();}

    // 解析异样,调用处理器解决,子类实现
    protected abstract ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

1.2. AbstractHandlerMethodExceptionResolver

AbstractHandlerMethodExceptionResolver
的次要性能是能够通过异样类型来解决

public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
    // 查看是否可利用处理器
    @Override
    protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {if (handler == null) {return super.shouldApplyTo(request, null);
        }
        // 如果是,获取 HandlerMethod 外部的 handler,持续判断
        else if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;
            handler = handlerMethod.getBean();
            return super.shouldApplyTo(request, handler);
        }
        // 如果有全局的异样处理器或自定义异样处理器,持续判断
        else if (hasGlobalExceptionHandlers() && hasHandlerMappings()) {return super.shouldApplyTo(request, handler);
        }
        // 否则就不能解决了
        else {return false;}
    }

    // 解析异样,调用处理器解决
    @Override
    protected final ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
        // 只能是 HandlerMethod 能力用于解决异样
        HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null);
        // 理论解决
        return doResolveHandlerMethodException(request, response, handlerMethod, ex);
    }

    // 理论解决,由子类实现
    protected abstract ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);

}

1.3. ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver
的次要性能是能够通过注解 @ExceptionHandler 来解决异样

1.3.1. ExceptionHandlerExceptionResolver.afterPropertiesSet

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
        implements ApplicationContextAware, InitializingBean {
    // 当属性都注入后,由上下文环境调用此办法初始化
    @Override
    public void afterPropertiesSet() {
        // 初始化 `@ControllerAdvice` 注解标注的组件
        initExceptionHandlerAdviceCache();

        if (this.argumentResolvers == null) {
            // 获取默认的参数解析器
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            // 获取默认的响应值处理器
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }

    // 初始化 `@ControllerAdvice` 注解标注的组件
    private void initExceptionHandlerAdviceCache() {
        // ... 代码省略

        // 获取有 `@ControllerAdvice` 注解的 bean
        List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
        // 进行遍历
        for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();
            if (beanType == null) {// 没有类型,报错}
            // @ExceptionHandler 注解解析器
            ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
            // 有异样解决办法
            if (resolver.hasExceptionMappings()) {
                // 退出全局异样处理器缓存容器
                this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
            }
            // 是 ResponseBodyAdvice 的子类
            if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
                // 退出容器
                this.responseBodyAdvice.add(adviceBean);
            }
        }

        // ... 代码省略
    }
}
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
        implements ApplicationContextAware, InitializingBean {
    // 获取默认的参数解析器
    protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

        // @SessionAttribute 解析
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        // @RequestAttribute 解析
        resolvers.add(new RequestAttributeMethodArgumentResolver());

        // 从原生 ServletRequest 对象的输出流中解析申请头、申请体等
        resolvers.add(new ServletRequestMethodArgumentResolver());
        // 把处理器最终的数据写入到原生 ServletResponse 对象的输入流中,包含响应头、响应体等
        resolvers.add(new ServletResponseMethodArgumentResolver());
        // 重定向解决
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        // Model 解决
        resolvers.add(new ModelMethodProcessor());

        // ... 代码省略
    }

    // 获取默认的响应值处理器
    protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

        // ModelAndView 解决
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        // Model 解决
        handlers.add(new ModelMethodProcessor());
        // View 解决
        handlers.add(new ViewMethodReturnValueHandler());
        // HttpEntity 解决
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

        // 数据绑定解析
        handlers.add(new ServletModelAttributeMethodProcessor(false));
        // @RequestBody @ResponseBody 解析
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

        // 视图名字解决
        handlers.add(new ViewNameMethodReturnValueHandler());
        // Map 解决
        handlers.add(new MapMethodProcessor());

        // ... 代码省略

        return handlers;
    }
}

1.3.2. ExceptionHandlerExceptionResolver.doResolveHandlerMethodException

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
        implements ApplicationContextAware, InitializingBean {
    // 理论解决异样
    @Override
    protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
            HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
        // 获取异样解决的办法对象
        ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
        // 如果没有,返回 null
        if (exceptionHandlerMethod == null) {return null;}

        if (this.argumentResolvers != null) {
            // 注入参数解析器 argumentResolvers
            exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
            // 注入响应解决 returnValueHandlers
            exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        // 响应容器
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();

        ArrayList<Throwable> exceptions = new ArrayList<>();
        try {
            // 遍历外部的异样
            Throwable exToExpose = exception;
            while (exToExpose != null) {exceptions.add(exToExpose);
                Throwable cause = exToExpose.getCause();
                exToExpose = (cause != exToExpose ? cause : null);
            }
            Object[] arguments = new Object[exceptions.size() + 1];
            exceptions.toArray(arguments);
            arguments[arguments.length - 1] = handlerMethod;

            // 调用处理器,获取处理结果,利用响应解决 returnValueHandlers
            exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
        }
        catch (Throwable invocationEx) {// ... 代码省略}

        // 如果是曾经解决过了,返回空 ModelAndView
        if (mavContainer.isRequestHandled()) {return new ModelAndView();
        }
        else {
            // 获取模型对象
            ModelMap model = mavContainer.getModel();
            // 生成 ModelAndView
            ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());

            // ... 代码省略

            // 解决重定向
            if (model instanceof RedirectAttributes) {// ... 代码省略}
            return mav;
        }
    }

    // 获取异样解决的办法对象
    protected ServletInvocableHandlerMethod getExceptionHandlerMethod(@Nullable HandlerMethod handlerMethod, Exception exception) {

        Class<?> handlerType = null;

        if (handlerMethod != null) {
            // 获取 bean 类型
            handlerType = handlerMethod.getBeanType();
            // 获取缓存的处理器
            ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
            // 如果没有,就生成,并缓存
            if (resolver == null) {resolver = new ExceptionHandlerMethodResolver(handlerType);
                this.exceptionHandlerCache.put(handlerType, resolver);
            }
            // 解析解决 exception 的办法
            Method method = resolver.resolveMethod(exception);
            // 有了就返回一个封装对象
            if (method != null) {return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
            }

            // ... 代码省略
        }

        // 没有自定义的,就应用全局的异样处理器
        for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {ControllerAdviceBean advice = entry.getKey();
            if (advice.isApplicableToBeanType(handlerType)) {ExceptionHandlerMethodResolver resolver = entry.getValue();
                // 解析解决 exception 的办法
                Method method = resolver.resolveMethod(exception);
                // 有了就返回一个封装对象
                if (method != null) {return new ServletInvocableHandlerMethod(advice.resolveBean(), method);
                }
            }
        }

        return null;
    }
}

2. ResponseStatusExceptionResolver

ResponseStatusExceptionResolver
的次要性能是反对 @ResponseStatus 注解映射状态码

public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {
    // 解析异样,调用处理器解决
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

        try {
            // 如果 ResponseStatusException,把 ResponseStatusException 外部的 responseHeaders 设置到响应中
            // 并设置响应码和响应起因
            if (ex instanceof ResponseStatusException) {return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);
            }

            // 不然,查看异样类的 `@ResponseStatus` 注解,如果有,设置响应码和响应起因
            ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
            if (status != null) {return resolveResponseStatus(status, request, response, handler, ex);
            }

            // 如果有外部异样,循环遍历解决
            if (ex.getCause() instanceof Exception) {return doResolveException(request, response, handler, (Exception) ex.getCause());
            }
        }
        catch (Exception resolveEx) {// ... 代码省略}
        return null;
    }
}

3. DefaultHandlerExceptionResolver

DefaultHandlerExceptionResolver
的次要性能是把规范 SpringMVC 异样映射状态码

public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
    // 解析异样,调用处理器解决
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
        try {
            // 405
            if (ex instanceof HttpRequestMethodNotSupportedException) {
                return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request, response, handler);
            }
            // 415
            else if (ex instanceof HttpMediaTypeNotSupportedException) {
                return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response, handler);
            }
            // 406
            else if (ex instanceof HttpMediaTypeNotAcceptableException) {
                return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response, handler);
            }
            // 500
            else if (ex instanceof MissingPathVariableException) {
                return handleMissingPathVariable((MissingPathVariableException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof MissingServletRequestParameterException) {
                return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof ServletRequestBindingException) {
                return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response, handler);
            }
            // 500
            else if (ex instanceof ConversionNotSupportedException) {
                return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof TypeMismatchException) {
                return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof HttpMessageNotReadableException) {
                return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
            }
            // 500
            else if (ex instanceof HttpMessageNotWritableException) {
                return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof MethodArgumentNotValidException) {
                return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof MissingServletRequestPartException) {
                return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request, response, handler);
            }
            // 400
            else if (ex instanceof BindException) {return handleBindException((BindException) ex, request, response, handler);
            }
            // 404
            else if (ex instanceof NoHandlerFoundException) {
                return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
            }
            // 503
            else if (ex instanceof AsyncRequestTimeoutException) {
                return handleAsyncRequestTimeoutException((AsyncRequestTimeoutException) ex, request, response, handler);
            }
        }
        catch (Exception handlerEx) {// ... 代码省略}
        return null;
    }
}

4. DefaultRequestToViewNameTranslator

DefaultRequestToViewNameTranslator
的次要性能是把 URI 映射视图名字

public class DefaultRequestToViewNameTranslator implements RequestToViewNameTranslator {
    // 依据申请获取视图名字
    @Override
    public String getViewName(HttpServletRequest request) {
        // 获取 URI 的 path 局部
        String path = ServletRequestPathUtils.getCachedPathValue(request);
        // 加上前缀与后缀
        return (this.prefix + transformPath(path) + this.suffix);
    }

    // 转换 path
    protected String transformPath(String lookupPath) {
        String path = lookupPath;
        // 去掉结尾的 /
        if (this.stripLeadingSlash && path.startsWith(SLASH)) {path = path.substring(1);
        }
        // 去掉结尾的 /
        if (this.stripTrailingSlash && path.endsWith(SLASH)) {path = path.substring(0, path.length() - 1);
        }
        // 去掉扩展名
        if (this.stripExtension) {path = StringUtils.stripFilenameExtension(path);
        }
        // 确保分隔符为 /
        if (!SLASH.equals(this.separator)) {path = StringUtils.replace(path, SLASH, this.separator);
        }
        return path;
    }
}

5. InternalResourceViewResolver

InternalResourceViewResolver
的次要性能是把视图名字解析成视图对象

继承关系如下

- AbstractCachingViewResolver
  - UrlBasedViewResolver
    - InternalResourceViewResolver

5.1. AbstractCachingViewResolver

AbstractCachingViewResolver
的次要性能是把视图名字解析成视图对象

public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {
    // 把视图名字解析成视图对象
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        // 如果不应用缓存,则每次都加载一次视图文件
        if (!isCache()) {return createView(viewName, locale);
        }
        else {
            // 获取缓存键
            Object cacheKey = getCacheKey(viewName, locale);
            // 获取缓存
            View view = this.viewAccessCache.get(cacheKey);
            if (view == null) {synchronized (this.viewCreationCache) {view = this.viewCreationCache.get(cacheKey);
                    if (view == null) {
                        // 缓存中不存在,加载创立视图对象,并退出缓存
                        view = createView(viewName, locale);

                        // ... 代码省略

                        if (view != null) {this.viewAccessCache.put(cacheKey, view);
                            this.viewCreationCache.put(cacheKey, view);
                        }
                    }
                }
            }
            return (view != UNRESOLVED_VIEW ? view : null);
        }
    }

    protected View createView(String viewName, Locale locale) throws Exception {return loadView(viewName, locale);
    }

    // 加载视图,子类实现
    protected abstract View loadView(String viewName, Locale locale) throws Exception;
}

5.2. UrlBasedViewResolver

UrlBasedViewResolver
的次要性能是反对把间接视图名字映射为 url

public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
    @Override
    protected View createView(String viewName, Locale locale) throws Exception {
        // ... 代码省略

        // 以 "redirect:" 结尾的重定向,能够跳到其余视图
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            RedirectView view = new RedirectView(redirectUrl,
                    isRedirectContextRelative(), isRedirectHttp10Compatible());

            // ... 代码省略

            return view;
        }

        // 以 "forward:" 结尾的重定向,能够转发到其余视图
        if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
            InternalResourceView view = new InternalResourceView(forwardUrl);
            return view;
        }

        // 其余放弃父类行为
        return super.createView(viewName, locale);
    }
}
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
    // 加载视图
    @Override
    protected View loadView(String viewName, Locale locale) throws Exception {
        // 构建视图
        AbstractUrlBasedView view = buildView(viewName);

        // ... 代码省略

        return view;
    }

    // 构建视图
    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        // 初始化视图类
        AbstractUrlBasedView view = instantiateView();
        // 设置门路
        view.setUrl(getPrefix() + viewName + getSuffix());
        // 设置解析数据
        view.setAttributesMap(getAttributesMap());

        // ... 代码省略

        return view;
    }
}

5.3. InternalResourceViewResolver

InternalResourceViewResolver
的次要性能是反对 InternalResourceView 和 JstlView

public class InternalResourceViewResolver extends UrlBasedViewResolver {
    @Override
    protected AbstractUrlBasedView instantiateView() {return (getViewClass() == InternalResourceView.class ? new InternalResourceView() :
                (getViewClass() == JstlView.class ? new JstlView() : super.instantiateView()));
    }
}

6. 视图渲染

6.1. View

View
是所有扩大视图组件的根底接口,次要就是 render 办法

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

6.2. AbstractView

AbstractView
的次要性能是反对 Spring 对视图组件以 bean 模式来治理

public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware {
    // 渲染视图
    @Override
    public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        // 合并其余数据到模型中
        Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
        // 渲染合并的模型数据
        renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    }

    // 合并其余数据到模型中
    protected Map<String, Object> createMergedOutputModel(@Nullable Map<String, ?> model,
            HttpServletRequest request, HttpServletResponse response) {
        // 门路变量
        Map<String, Object> pathVars = (this.exposePathVariables ?
                (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);

        // 注入的动态属性
        int size = this.staticAttributes.size();
        size += (model != null ? model.size() : 0);
        size += (pathVars != null ? pathVars.size() : 0);

        // 合并门路变量与动态属性到模型中
        Map<String, Object> mergedModel = CollectionUtils.newLinkedHashMap(size);
        mergedModel.putAll(this.staticAttributes);
        if (pathVars != null) {mergedModel.putAll(pathVars);
        }
        if (model != null) {mergedModel.putAll(model);
        }

        // ... 代码省略

        return mergedModel;
    }

    // 渲染合并的模型数据,子类实现
    protected abstract void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

6.3. AbstractUrlBasedView

AbstractUrlBasedView
的次要性能是要求有一个 url 数据,其余没有什么性能

6.4. AbstractTemplateView

AbstractTemplateView
的次要性能是实现模板渲染,纯接口数据(不须要模板渲染的),间接继承 AbstractView 就能够了

public abstract class AbstractTemplateView extends AbstractUrlBasedView {
    // 渲染合并的模型数据
    @Override
    protected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        // ... 代码省略,载入申请属性、session 属性、spring 宏属性到模型数据中

        // 渲染合并的模型数据到模板
        renderMergedTemplateModel(model, request, response);
    }

    // 渲染合并的模型数据到模板,子类实现
    protected abstract void renderMergedTemplateModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

6.5. FreeMarkerView

FreeMarkerView
的次要性能是用 FreeMarker 渲染视图

public class FreeMarkerView extends AbstractTemplateView {
    // 渲染合并的模型数据到模板
    @Override
    protected void renderMergedTemplateModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {doRender(model, request, response);
    }

    protected void doRender(Map<String, Object> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        // ... 代码省略

        // 构建 FreeMarker 模板对象
        SimpleHash fmModel = buildTemplateModel(model, request, response);

        // ... 代码省略

        // 获取模板文件,渲染模板到 response
        processTemplate(getTemplate(locale), fmModel, response);
    }

    // 渲染模板到 response
    protected void processTemplate(Template template, SimpleHash model, HttpServletResponse response)
            throws IOException, TemplateException {
        // 输出模板渲染后果到 response writer
        template.process(model, response.getWriter());
    }
}

6.6. MappingJackson2JsonView

MappingJackson2JsonView
的次要性能是用 jackson 来序列化输入接口数据,间接继承 AbstractView

public class MappingJackson2JsonView extends AbstractView {
    // 渲染合并的模型数据
    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        // 字节数组输入流
        ByteArrayOutputStream temporaryStream = null;
        // 输入流
        OutputStream stream;

        // 须要更新 'Content-Length' 头
        if (this.updateContentLength) {
            // 创立一个新的长期输入流
            temporaryStream = createTemporaryOutputStream();
            stream = temporaryStream;
        }
        else {
            // 不然应用 response 的输入流
            stream = response.getOutputStream();}

        // 把一些不须要的对象过滤掉,包装成可序列化的对象
        Object value = filterAndWrapModel(model, request);
        // 把后果写入输入流中
        writeContent(stream, value);

        if (temporaryStream != null) {
            // 如果有新的长期输入流,把这个新的流写入到 response 对象中
            writeToResponse(response, temporaryStream);
        }
    }

    // 把后果写入输入流中
    protected void writeContent(OutputStream stream, Object object) throws IOException {
        // 生成一个 JsonGenerator
        try (JsonGenerator generator = this.objectMapper.getFactory().createGenerator(stream, this.encoding)) {
            // ... 代码省略

            Object value = object;
            Class<?> serializationView = null;
            FilterProvider filters = null;

            // 获取序列化视图和过滤器
            if (value instanceof MappingJacksonValue) {MappingJacksonValue container = (MappingJacksonValue) value;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();}

            // 给 writer 退出序列化视图
            ObjectWriter objectWriter = (serializationView != null ?
                    this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
            // 给 writer 退出过滤器,如字段过滤
            if (filters != null) {objectWriter = objectWriter.with(filters);
            }
            objectWriter.writeValue(generator, value);

            // ... 代码省略

            // 刷新数据
            generator.flush();}
    }
}

后续

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

作者:深予之 (@senntyou)

版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)

正文完
 0