• Spring MVC更多家族成员----Handler与HandlerAdaptor---07



    问题的起源

    最初为了降低理解的难度,我们说,HandlerMapping将会通过HandlerExecutionchain返回一个Controller用于具体Web请求的处理。

    public interface HandlerMapping {
         ...  
    	@Nullable
    	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    现在我们要进一步澄清事实:HandlerExecutionchain中所返回的用于处理Web请求的处理对象,可以不只是Controller一种类型。
    在这里插入图片描述

    在Spring MVC中,任何可以用于Web请求处理的处理对象统称为Handler。Controller是Handler的一种特殊类型。

    HandlerMapping通过HandlerExecutionChain所返回的是一个Object类型的Handler对象,而并没限定说只能是Controller类型。

    所以,一般意义上讲,任何类型的Handler都可以在Spring MVC中使用,比如Struts的Action和WebWork的Action等,只要它们是用于处理Web请求的处理对象就行。

    不过,对于DispatcherServlet来说,这就有点儿问题了,它如何来判断我们到底使用的是什么类型的Handler,又如何决定调用Handler对象的哪个方法来处理Web请求呢?

    显然,在DispatcherServlet直接硬编码if-else来枚举每一种可能的Handler类型是不具任何扩展性的。

    为了能够以统一的方式调用各种类型的Handler,DispatcherServlet将不同Handler的调用职责转交给了一个称为HandlerAdaptor的角色。

    public interface HandlerAdapter {
    	boolean supports(Object handler);
    	
    	@Nullable
    	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    	
    	@Deprecated
    	long getLastModified(HttpServletRequest request, Object handler);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实际上,人如其名。哦,不对!是“接口”如其名。HandlerAdaptor将作为一个适配器,屏蔽不同Handler类型给DispatcherServlet)所造成的“困扰”(所谓Adaptor Pattern应该也就是为了这种类似的目的吧)

    HandlerAdapter得以成为DispatcherServlet和不同Handler的“中间人”,要归功于它的两个主要方法,即supports(…)和handle(…)。

    至于getLastModified(…)方法,它的主要目的只是为返回给客户端的Last-Modified这个HTTP头提供相应的时间值。如果我们不想支持该功能,直接返间-1即可。

    DispatcherServlet从HandlerMapping获得一个Handler之后,将询问HandlerAdaptor的supports(…)方法,以便了解当前HandlerAdaptor是否支持HandlerMapping刚刚返回的Handler类型的调用。

                    ....
    				mappedHandler = getHandler(processedRequest);
    				if (mappedHandler == null) {
    					noHandlerFound(processedRequest, response);
    					return;
    				}
                    ....
    				//寻找上面返回的handler对应的HandlerAdapter 
    				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果supports(…)返回true,DispatcherServlet则调用HandlerAdaptor的Handle方法,同时将刚才的Handler作为参数传入。

    	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    		if (this.handlerAdapters != null) {
    			for (HandlerAdapter adapter : this.handlerAdapters) {
    				if (adapter.supports(handler)) {
    					return adapter;
    				}
    			}
    		}
    		throw new ServletException("No adapter for handler [" + handler +
    				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    方法执行后将返回ModelAndview,之后的工作就由ViewResolver接手了。

    				// Determine handler adapter for the current request.
    				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    				// Process last-modified header, if supported by the handler.
    				String method = request.getMethod();
    				boolean isGet = HttpMethod.GET.matches(method);
    				if (isGet || HttpMethod.HEAD.matches(method)) {
    					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    						return;
    					}
    				}
    
    				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    					return;
    				}
    
    				//通过HandlerAdapter的handle方法返回一个ModelAndView
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    现在,DispatcherServlet只需要面对HandlerAdaptor提供的统一接口,而不需要面对纷繁复杂的Handler类型。支持新的Handler类型,意味着只需要为DispatcherServlet提供新的HandlerAdaptor实现即可。

    DispatcherServlet借助多个HandlerAdaptor,调用当前HandlerMapping所返回的Handler:来处理Web请求的逻
    辑。


    无论我们想在Spring MVC中使用什么类型的Handler,只要同时为DispatcherServlet:提供对应该Handler的HandlerAdaptor实现就成,DispatcherServlet无须任何变动。

    我想,HandlerAdaptor存在的原因我们已经搞清楚了,但还有一些问题不明,比如:

    • 如果Controller只是一种特殊类型的Handler,那么Spring MVC是否还提供了其他可用的Handler类型呢?如果要提供我们自己的Handler类型又需要考虑哪些事情呢?
    • 如何实现一个具体的HandlerAdaptor? Spring MVC有提供现成的实现吗?
    • 如果想使用自定义的Handler,并且提供了对应的HandlerAdaptor实现,要通过什么方式告知DispatcherServlet来使用它们?

    我想只有解开以上问题的答案才能帮助我们更深刻地理解Handler与HandlerAdaptor之间的关系。


    深入了解Handler

    到目前为止,我们使用最多的Handler就是Controller。不过,如果Controller不合我们的口味的话,我们也可以使用Spring MVC提供的其他类型的Handler,甚至于自定义Handler类型。

    自定义Handler

    可以说,自定义Handler对于Handler类型来说并没任何限制,任何我们喜欢的形式都可以。如果不喜欢Controller,那么可以定义自己的MyHandler,甚至不需要强制Handler实现任何接口,仅是一个简单的POJO对象,只要能有办法知道该类就是用于Web请求处理的Handler类就行,比如用注解标注一下,然后通过反射机制就能获知哪些对象是用于Web请求处理的Handler,如下所示:

    @Handler
    public class AnyType{}
    
    • 1
    • 2

    虽说对Handler自身没有任何限制,但是要让我们的Handler登上“历史舞台”发挥它的作用,却需要有能够给予帮助的“左膀右臂”,为我们的Handler提供必要的HandlerMapping和HandlerAdaptor,这才是真正让Handler自身没有任何限制的原因所在。

    HandlerMapping负责查找相应的Handler以处理Web请求。

    要想使用Handler,首先需要提供一个能够识别该Handler的HandlerMapping实现。比如,无论是BeanNameUrlHandlerMapping还是SimpleUrlHandlerMapping,它们都可以获取并返回Controller类型的Handler.。

    如果可以通过BeanNameUrlHandlerMapping或者SimpleUrlHandlerMapping告知DispatcherServlet我们的Handler存在的话,那还好。

    否则,我们就不得不提供一个能够识别我们自己Handler类型的HandlerMapping。

    Spring2.5就提供了特定的DefaultAnnotationHandlerMapping,处理新提供的基于注解的Handler的查找。

    现在HandlerMapping返回了我们自定义的Handler,但DispatcherServlet本身显然是不管我们的Handlerl到底是何方人物的。为了让我们的Handler得以被DispatcherServlet所“青睐”,我们不得不提供一个HandlerAdaptor。实际上,并非只有我们的自定义Handler要“受此礼遇”,所有SpringMVC框架内的Handler都提供有相对应的HandlerAdaptor实现,如下所述。

    • Controller 将 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter作为其HandlerAdaptor。
    • Spring2.5新添加的基于注解的Handler由org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter作为其HandlerAdaptor。

    这是一个“传统”,我们也得遵守。不过话又说回来了,保持框架设计的统一性确实非常重要。说了这么多,你对HandlerAdaptor可能还是没有一个感性的认识。别急,马上为你奉上。


    近看HandlerAdaptor的奥秘

    在这里插入图片描述

    实际上,为具体的Handler类型提供一个HandlerAdaptor实现类非常简单。

    主要工作只是调用这个HandlerAdaptor“认识”的Handler的Web请求处理方法,然后将处理结果转换为DispatcherServlet统一使用的ModelAndview就行。

    我们不妨就以Controllerl的HandlerAdaptor为例,来看一下HandlerAdaptor实现到底长什么样子。

    public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    
    	@Override
    	public boolean supports(Object handler) {
    		return (handler instanceof Controller);
    	}
    
    	@Override
    	@Nullable
    	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		return ((Controller) handler).handleRequest(request, response);
    	}
    
    	@Override
    	@SuppressWarnings("deprecation")
    	public long getLastModified(HttpServletRequest request, Object handler) {
    		if (handler instanceof LastModified) {
    			return ((LastModified) handler).getLastModified(request);
    		}
    		return -1L;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    SimpleControllerHandlerAdapter是Controller对应的HandlerAdaptor实现。

    supports方法决定了它只认识Controller一个人,所以,在handle方法中,直接将object类型的Handler强制转型为Controller,然后调用其handleRequest即可。因为Controller的handleRequest方法可以返回已经组装好的ModelAndview,所以,就直接返回了。


    告知Handler与HandlerAdaptor的存在

    我们已经有了要添加到Spring MVC框架的新的Handler类型,也给出了针对该Handler类型的
    HandlerAdaptor实现类,现在是让DispatcherServlet接纳它们的时候了!

    首先,如果现有的HandlerMapping不足以“感知”到我们的Handler类型的话,那么我们需要提供一个能够“感知”我们Handler的HandlerMapping实现类,并将其注册到DispatcherServlet的WebApplicationContext中。如果现有的HandlerMapping实现可以“感知”到我们的Handler,那么将可以省去实现自定义HandlerMapping的工作,但依然需要将使用的HandlerMapping添加到DispatcherServlet的WebApplicationContext中,除非我们使用默认的BeanNameUrlHandlerMapping。

    大部分情况下,只要我们提供的Handler在容器中的引用,能够明确指定给BeanNameUrlHandlerMapping.或者SimpleUrlHandlerMapping等现有HandlerMapping实现类,都不需要自定义HandlerMapping实现。

    当然,在稍后详细介绍Spring2.5新添加的基于注解的Handler实现的时候,我们将看到第一个为特定Handler提供的HandlerMapping实现。

    其次,有了可以返回我们自定义的Handler的HandlerMapping之后,我们要为DispatcherServlet
    提供能够调用该类型Handlerf的HandlerAdaptor实现。

    这同样是通过将HandlerAdaptor实现类添加到WebApplicationContext完成的。

    可以向DispatcherServlet的WebApplicationContext中添加多个HandlerAdaptor。

    DispatcherServlet将根据类型自动检测容器内可用的HandlerAdaptor实例。如果无法找到可用的HandlerAdaptor,DispatcherServlet将启用后备的几个默认使用的HandlerAdaptor实现。

    	private void initHandlerAdapters(ApplicationContext context) {
    		this.handlerAdapters = null;
            //默认会去搜索容器内所有类型为HandlerAdapter的Bean 
    		if (this.detectAllHandlerAdapters) {
    			Map<String, HandlerAdapter> matchingBeans =
    					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
    			//如果用户往容器中放入了相关HandlerAdapter实现Bean		
    			if (!matchingBeans.isEmpty()) {
    				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
    				//排序---order接口
    				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
    			}
    		}
    		else {
    			try {
    			   //如果我们将detectAllHandlerAdapters设置为false,那么默认只会去容器中
    			   //寻找beanName为handlerAdapter的Bean
    				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
    				this.handlerAdapters = Collections.singletonList(ha);
    			}
    			catch (NoSuchBeanDefinitionException ex) {
    				// Ignore, we'll add a default HandlerAdapter later.
    			}
    		}
    
    		//如果没找到,那么采用默认的策略
    		if (this.handlerAdapters == null) {
    			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
    						"': using default strategies from DispatcherServlet.properties");
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    加载默认策略:

    	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    	//第一次进来时,首先初始化
    		if (defaultStrategies == null) {
    			try {
    			//加载DispatcherServlet类路径下的DispatcherServlet.properties文件
    				ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
    				//加载该文件
    				defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    			}
    			catch (IOException ex) {
    				throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    			}
    		}
            //key就是要寻找的默认类路径---这里对应上面为handlerAdapter的全类名
    		String key = strategyInterface.getName();
    		//去配置文件中定位默认组件---如果存在多个,使用逗号分割
    		String value = defaultStrategies.getProperty(key);
    		if (value != null) {
    		//如果默认配置存在的话,按照逗号分割,拿到所有默认实现类的每一个全类名
    			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
    			List<T> strategies = new ArrayList<>(classNames.length);
    			for (String className : classNames) {
    				try {
    					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
    					//实例化后,放入容器中
    					Object strategy = createDefaultStrategy(context, clazz);
    					strategies.add((T) strategy);
    				}
    				catch (ClassNotFoundException ex) {
    					throw new BeanInitializationException(
    							"Could not find DispatcherServlet's default strategy class [" + className +
    							"] for interface [" + key + "]", ex);
    				}
    				catch (LinkageError err) {
    					throw new BeanInitializationException(
    							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
    							className + "] for interface [" + key + "]", err);
    				}
    			}
    			return strategies;
    		}
    		else {
    			return Collections.emptyList();
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    当某个组件在进行初始化时,如果用户没有自定义的话,那么就采用配置文件中提供的默认值,如果默认组件存在多个,就使用","分割。
    在这里插入图片描述


    也就是说,如果使用的Handler是现有Handler类型,那么无须在DispatcherServlet的WebApplicationContext中做任何配置,默认的HandlerAdaptor已经足够了。

    不过,如果需要添加这些HandlerAdaptor类型之外的HandlerAdaptor实现,并且我们依然希望同时使用这些默认HandlerAdaptor所支持的Handler的话,那就需要在添加我们的自定义HandlerAdaptor的基础上,同时添
    加以上几种默认的HandlerAdaptor实现。


    案例

    假设Spring没有提供注解版本的Controller,现在需要我们自己来进行实现,你会怎么做呢?

    思路如下:

    • 自定义一个AnnoHandlerMapping扫描容器内所有标注了@Controller注解的Bean,然后将每个Controller能够处理的请求路径和自身做好映射
    • 请求来临时,通过AnnoHandlerMapping中保存的映射关系,判断哪一个Controller来处理当前请求
    • 当请求交给Controller之后,Controller内部再进行解析,判断具体应该交给哪个方法进行处理
    • Controller内部方法处理完毕后,将返回的值包装为ModelAndView返回

    默认返回值通通作为JSON处理

    • AnnoHandlerMapping封装映射关系
    public class AnnoHandlerMapping extends AbstractHandlerMapping implements InitializingBean {
       //封装扫描到的所有标注了@Controller注解的handler
        private static List<ControllerHolder> controllerHolders;
    
    
        @Override
        public void afterPropertiesSet() throws Exception {
            ApplicationContext app = getApplicationContext();
            if (app != null) {
                //扫描+解析
                Set<Map.Entry<String, Object>> handlers = app.getBeansWithAnnotation(Controller.class).entrySet();
                controllerHolders=new ArrayList<>();
                for (Map.Entry<String, Object> handler : handlers) {
                    controllerHolders.add(ControllerHolder.parserController(handler.getValue()));
                }
            }
        }
    
       
        @Override
        protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
            String reqURI = request.getRequestURI();
            for (ControllerHolder controllerHolder : controllerHolders) {
                Method method = controllerHolder.getMappings().get(reqURI);
                if(method==null){
                    continue;
                }
                //设置当前正在执行的方法和方法实参列表值
                controllerHolder.setCurMethod(method);
                controllerHolder.setParamsVal(request);
                //返回ControllerHolder 
                return controllerHolder;
            }
            return null;
        }
    
    
        @Data
        public static class ControllerHolder{
           //封装目标对象
            private Object controller;
          //处理当前请求的方法
            private Method curMethod;
         //方法实参    
            private Object[] paramsVal;
        //当前目标handler对象中请求路径和方法的映射关系 
            private Map<String,Method> mappings;
        //方法和当前方法中参数信息封装     
            private Map<Method,List<MethodParam>> methodParams;
         //用于类型转换
             private TypeConverter typeConverter=new SimpleTypeConverter();
    
            public ControllerHolder(Object controller, Map<String, Method> mappings, Map<Method,List<MethodParam>> methodParams) {
                this.controller = controller;
                this.mappings = mappings;
                this.methodParams=methodParams;
            }
           
           //解析controller对象   
            public static ControllerHolder parserController(Object controller){
                Method[] methods = controller.getClass().getMethods();
                Map<String,Method> mappings=new HashMap<>();
                Map<Method,List<MethodParam>> methodParams=new HashMap<>();
                //解析controller对象中所有方法
                for (Method method : methods) {
                    //获取方法上标注的@RequestMapping注解
                    RequestMapping req = method.getAnnotation(RequestMapping.class);
                    //没有标注该注解的方法不会被作为处理请求的方法
                    if(req==null){
                        continue;
                    }
                    //当前方法和对应请求的映射
                    mappings.put(req.value()[0],method);
                    //当前方法和对应方法参数信息的封装
                    methodParams.put(method,parseMethodParam(method));
                }
                return new ControllerHolder(controller,mappings,methodParams);
            }
    
            private static List<MethodParam> parseMethodParam(Method method) {
                List<MethodParam> paramNames=new ArrayList<>();
                 //方法参数挨个解析--MethodParam封装方法参数名和对应的方法参数类型
                for (Parameter parameter : method.getParameters()) {
                    RequestParam annotation = parameter.getAnnotation(RequestParam.class);
                    Assert.notNull(annotation,"方法参数上必须要标注@RequestParam注解");
                    paramNames.add(new MethodParam(annotation.value(), parameter.getType()));
                }
                return paramNames;
            }
    
            public void setParamsVal(HttpServletRequest request) {
                this.paramsVal=getParamValue(methodParams.get(curMethod),request);
            }
    
            private Object[] getParamValue(List<MethodParam> methodParams, HttpServletRequest request) {
             //从request的请求参数集合中取出当参数值,然后根据参数类型判断是否需要进行类型转换
                Object[] paramVals = new Object[methodParams.size()];
                for (int i = 0; i < methodParams.size(); i++) {
                    MethodParam methodParam = methodParams.get(i);                     paramVals[i]=typeConverter.convertIfNecessary(request.getParameter(methodParams.get(i).paramName),methodParam.paramClass);
                }
                return paramVals;
            }
        }
    
        @Data
        @AllArgsConstructor
        public static class MethodParam{
            private String paramName;
            private Class<?> paramClass;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • AnnoHandlerAdaptor适配器
    public class AnnoHandlerAdaptor implements HandlerAdapter {
        @Override
        public boolean supports(Object handler) {
            return handler.getClass().isAssignableFrom(AnnoHandlerMapping.ControllerHolder.class);
        }
    
        @Override
        public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            AnnoHandlerMapping.ControllerHolder controllerHolder = (AnnoHandlerMapping.ControllerHolder) handler;
            //触发方法的调用,将返回值进行封装
            Object res = controllerHolder.getCurMethod().invoke(controllerHolder.getController(), controllerHolder.getParamsVal());
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject(res);
            //例如我们自定义的JsonView将返回结果输出为JSON后返回
            modelAndView.setView(new JsonView());
            return modelAndView;
        }
    
        @Override
        public long getLastModified(HttpServletRequest request, Object handler) {
            return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 自定义的JsonView
    @Slf4j
    public class JsonView extends AbstractView {
        private ObjectMapper objectMapper = new ObjectMapper();
        private JsonEncoding encoding=JsonEncoding.UTF8;
    
        public JsonView() {
            setContentType("application/json");
        }
    
        @Override
        protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                writeContent(outputStream,model,null);
                writeToResponse(response,outputStream);
        }
    
    
        protected void writeContent(OutputStream stream, Object value, String jsonPrefix) throws IOException {
            JsonGenerator generator = this.objectMapper.getJsonFactory().createJsonGenerator(stream, this.encoding);
    
            if (this.objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
                generator.useDefaultPrettyPrinter();
            }
    
            if (jsonPrefix != null) {
                generator.writeRaw(jsonPrefix);
            }
    
            this.objectMapper.writeValue(generator, value);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • DispathcerServlet对应的配置文件
         <bean id="handlerMapping" class="com.example.AnnoHandlerMapping"/>
         <bean id="handlerAdaptor" class="com.example.AnnoHandlerAdaptor"/>
         <bean id="helloController" class="com.example.HelloController"/>
    
    • 1
    • 2
    • 3
    • 测试Controller
    @Controller
    public class HelloController {
        @RequestMapping("/hello")
        public Stu sayHello(@RequestParam("name") String name, @RequestParam("age") Integer age){
            return new Stu(name,age);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 测试结果

    在这里插入图片描述


  • 相关阅读:
    大数据运维实战第一课 大话 Hadoop 生态圈
    python案例5:数值转换--初级
    【Java SE】this引用注意事项
    EFCore之执行原生SQL语句
    图文详解线性回归与局部加权线性回归+房价预测实例
    nginx反向代理负载均衡实战
    leetcode 热题 100_环形链表
    Servlet规范之预览
    「中秋来袭」没想到,用OpenCV竟能画出这么漂亮的月饼「附源码」
    uniapp iconfont-引用阿里巴巴矢量图标库
  • 原文地址:https://blog.csdn.net/m0_53157173/article/details/126137179