• 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
    • 测试结果

    在这里插入图片描述


  • 相关阅读:
    分享从零开始学习网络设备配置--任务4.1 IPv6地址的基本配置
    Java--Spring之IoC控制反转;基于XML配置文件的DI
    Java 获取 URL 中的域名
    做题杂记222
    【Python 千题 —— 基础篇】输出列表方差
    Oracle 19c Active Data Guard (ADG)新特性
    2022.11.9 英语背诵
    pgsql 报错 later table “drop column” is not supported now
    前端发送请求,显示超时取消
    Google Earth Engine(GEE)——
  • 原文地址:https://blog.csdn.net/m0_53157173/article/details/126137179