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

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

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

另外,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 许可证

相关文章