ITPub博客

首页 > 应用开发 > Java > 深入Spring:自定义ViewResolver

深入Spring:自定义ViewResolver

Java 作者:爆seed 时间:2016-06-08 09:34:06 0 删除 编辑

这里在介绍一下ViewResolver的使用,并介绍一下HandlerMethodReturnValueHandler和ViewResolver的关系。

ViewResolver和HandlerMethodReturnValueHandler

自定义ResponseBody这篇文章介绍过ResponseBody的编码规则,ViewResolver和ResponseBody是明显互斥的。 这两个不同类型的返回值就是通过不同的HandlerMethodReturnValueHandler来是实现的。 先看RequestResponseBodyMethodProcessor,这里设置了setRequestHandled为true,然后通过HttpMessageConverters编码对应的model。

 public void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
        mavContainer.setRequestHandled(true); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, webRequest);
    } 

再看ViewNameMethodReturnValueHandler,这里没有设置setRequestHandled,而是取出CharSequence类型的返回值,并赋值viewName。

 public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue instanceof CharSequence) { String viewName = returnValue.toString();
            mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) {
                mavContainer.setRedirectModelScenario(true);
            }
        } else if (returnValue != null){ // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
        }
    } 

再看RequestMappingHandlerAdapter中使用方法,假如mavContainer.isRequestHandled是true直接返回null,后面就不会调用ViewResolver了。假如是false,会取出mavContainer.getViewName,返回ModelAndView,后面会根据ViewName进行模板的映射。

 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
        modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) {
            return null;
        } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) {
            mav.setView((View) mavContainer.getView());
        } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
        return mav;
    } 

自定义ViewResolver

相比ExceptionHandler,自定义ViewResolver就比较简单了,只要注入一个ViewResolver的实现类就可以了。 不过为了介绍ViewResolver的原理,这里自定义了一个HandlerMethodReturnValueHandler来取代ViewNameMethodReturnValueHandler; 完整的代码还是在Github上了。

  1. 定义Controller。ViewName自定义类来包装viewName。
     @Controller public static class ControllerClass { @RequestMapping public ViewName index(ModelMap modelMap) {
             modelMap.put("message", "hello world");
             ViewName viewName = new ViewName();
             viewName.setName("index"); return viewName;
         } @RequestMapping("html") public ViewName htmlIndex(ModelMap modelMap) {
             modelMap.put("message", "hello world");
             ViewName viewName = new ViewName();
             viewName.setName("html"); return viewName;
         }
     } public static class ViewName { private String name; public String getName() { return name;
         } public void setName(String name) { this.name = name;
         }
     } 
  2. 注入自定义的ViewResolvers和HandlerMethodReturnValueHandler
     @Configuration public static class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport { public void configureViewResolvers(ViewResolverRegistry registry) { MyViewResolver myViewResolver = new MyViewResolver();
             registry.viewResolver(myViewResolver);
         }
         public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
             returnValueHandlers.add(new MyHandlerMethodReturnValueHandler());
         }
     } 
  3. 自定义HandlerMethodReturnValueHandler,指定只支持ViewName这个类,处理时,取出来ViewName的name,设置到ModelAndViewContainer中。
     public static class MyHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { public boolean supportsReturnType(MethodParameter returnType) { return returnType.getParameterType().isAssignableFrom(ViewName.class);
         } public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
             ViewName viewName = (ViewName) returnValue;
             mavContainer.setViewName(viewName.getName());
         }
     } 
  4. 自定义ViewResolver,定义了MyView和MyHtmlView一个处理index返回纯文字,另一个处理html返回html格式。
     public static class MyViewResolver implements ViewResolver { private View htmlView = new MyHtmlView(); private View view = new MyView(); public View resolveViewName(String viewName, Locale locale) throws Exception { if (viewName.equals("index")) { return view;
             } else if (viewName.equals("html")) { return htmlView;
             } return null;
         }
     } public static class MyView implements View { public String getContentType() { return "text/html";
         } public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
             StringBuilder stringBuilder = new StringBuilder(); for (Map.Entry<String, ?> entry : model.entrySet()) {
                 stringBuilder.append(entry.getKey()).append(":").append(entry.getValue());
             }
             response.getWriter().write(stringBuilder.toString());
         }
     } public static class MyHtmlView implements View { public String getContentType() { return "text/html";
         } public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { String head = "<html><head><title>Hello World</title></head><body><ul>"; String tail = "</ul></body></html>";
             StringBuilder sb = new StringBuilder();
             sb.append(head); for (Map.Entry<String, ?> entry : model.entrySet()) {
                 sb.append("<li>").append(entry.getKey()).append(":").append(entry.getValue()).append("
  5. "); } sb.append(tail); response.getWriter().write(sb.toString()); } }
  6. 程序入口,北京java培训基本都会讲到这些,这里同时请求了/和/html分别用到了MyView和MyHtmlView。
     @Configuration public class CustomizeViewResolverTest { public static void main(String[] args) throws ServletException, IOException {
             MockServletContext mockServletContext = new MockServletContext();
             MockServletConfig mockServletConfig = new MockServletConfig(mockServletContext);
             AnnotationConfigWebApplicationContext annotationConfigWebApplicationContext = new AnnotationConfigWebApplicationContext();
             annotationConfigWebApplicationContext.setServletConfig(mockServletConfig);
             annotationConfigWebApplicationContext.register(CustomizeViewResolverTest.class);
             DispatcherServlet dispatcherServlet = new DispatcherServlet(annotationConfigWebApplicationContext);
             dispatcherServlet.init(mockServletConfig);
             MockHttpServletResponse response = new MockHttpServletResponse();
             MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
             dispatcherServlet.service(request, response);
             System.out.println(new String(response.getContentAsByteArray()));
             MockHttpServletResponse htmlResponse = new MockHttpServletResponse();
             MockHttpServletRequest htmlRequest = new MockHttpServletRequest("GET", "/html");
             dispatcherServlet.service(htmlRequest, htmlResponse);
             System.out.println(new String(htmlResponse.getContentAsByteArray()));
         }
     } 

运行程序就会发现,一个输出了文章,另一个输出了html格式的文字。

结语

ViewResolver和ResponseBody都是用来处理HttpResponseBody的内容的,只不过处理的方式不同。 ResponseBody的编码方式是一样的,一般是处理JSON的编码。ViewResolver还可以一根据ViewName来路由到不用的View,每个View都可以自己的编码规则。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29917475/viewspace-2117238/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: java自学的故事
下一篇: java中的线程
请登录后发表评论 登录
全部评论

注册时间:2014-09-26

  • 博文量
    28
  • 访问量
    34439