美文网首页我爱编程
[spring]applicationContext.xml-m

[spring]applicationContext.xml-m

作者: 骑着乌龟去看海 | 来源:发表于2018-03-31 08:25 被阅读80次

    紧接着上文,我们来学习mvc标签。

    Spring版本:4.3.14。

    6.mvc 命名空间

      mvc命名空间内的标签是用于Spring MVC的配置,一般情况下Spring的配置文件和Spring-MVC的配置文件都是分开配置的,Spring MVC的配置文件默认情况下是 dispatcher-servlet.xml,所以mvc的配置通常都是在该配置文件中。下面我们来学习下每个标签的用处。

      首先,记得先引入命名空间,并且先搭建好Spring MVC环境,这些都很简单,这里就不多说了。

    6.1 <mvc:annotation-driven>标签

    mvc:annotation-driven标签是一种简写的形式,用于为Spring MVC分发请求到Controller上,不过该标签支持的功能很多,比如@InitBinder数据绑定,@NumberFormatannotation数据格式化,@DateTimeFormat日期格式化,数据校验,@RequestBody @ResponseBody的json支持等;下面来看一下该标签中各个属性的配置。

    6.1.1 ignore-default-model-on-redirect元素

    顾名思义,用于请求重定向时是否忽略model的参数,布尔值,true和false,默认是false,但文档中建议应该设置为true:

    The default setting is false but new applications should consider setting it to true.

    有的时候,我们重定向的时候需要传参数,我们通过Model添加参数,通过ModelAttribute来获取URL的参数,但有些时候在重定向的时候,我们不想把参数带过去,比如说我们重定向的地址是:http://localhost:8080/hello/test.html?users=user1&users=user2&users=user3&users=user4...,这时候我们可以通过配置该属性为true,来忽略URL后面这一堆参数。
    具体使用可参考:https://stackoverflow.com/questions/13247239/spring-mvc-controller-redirect-without-parameters-being-added-to-my-url%3C/b%3E

    6.1.2 enable-matrix-variables元素

    一般情况下,我们URL中很少会出现name-value这种类似于键值对的形式,而Spring MVC却提供了对这种形式的支持,在Spring MVC中,它们被称为matrix-variables。而如果要在Spring中使用该功能,需要先配置enable-matrix-variables属性,该属性是布尔类型,有true和false,默认情况下是false,也就是不开启的状态。

    matrix variables的形式如:/cars;color=red,green;year=2012,其中各个变量之间使用分号分隔,每个变量如果多个值,使用逗号分割;简单看下官网的几个例子:

    // GET /pets/42;q=11;r=22
    @GetMapping("/pets/{petId}")
    public void findPet(@PathVariable String petId, @MatrixVariable int q) {
    
        // petId == 42
        // q == 11
    }
    

    这里简单说下,GetMapping是Spring4.3之后的一个组合注解。我们在URL中配置相应的name-value组合之后,可以通过注解@MatrixVariable来获取该组合的值。如果要查看更多有关matrix-variables相关,可参考官网文件:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-matrix-variables

    6.1.3 conversion-service元素

    在我们通过浏览器向我们的服务器提交数据的时候,也就是在字段绑定期间,用于类型转换的ConversionService的bean的名称,默认情况下的实现是FormattingConversionService,如果我们需要自定义转换类型的时候可以通过配置该bean指向我们自定义的转换器来实现。

    自定义转换器:

    public class DateConverter implements Converter<String, Date> {
        @Override
        public Date convert(String dateString) {
            try {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    引入我们的转换器,当然我们开可以配置多个转换器:

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="expend.DateConverter"/>
            </set>
        </property>
    </bean>
    

    其实Spring已经给我们提供了许多种类型转换器,位于org.springframework.core.convert.support目录下,在以上转换器都不满足的情况下,我们可以自定义我们的类型转换器;并且使用的时候可以结合@InitBinder注解来一并学习使用。

    6.1.4 message-codes-resolver元素

    一般情况下,在浏览器传递参数到服务器的时候,我们都需要进行数据绑定,并且进行参数验证,如果绑定失败或者验证失败,对应的错误码会保存到Spring的错误对象中,而我们可以通过MessageCodesResolver来对错误code构建相应的message信息。默认情况下,Spring将使用DefaultMessageCodesResolver对象进行解析,当然如果有需要,我们也可以自定义我们的解析器。

    6.1.5 validator元素

      上面我们也已经说过,对于从浏览器端传递过来的参数,前端的JS可以涵盖大部分的校验职责,但为了避免用户绕过浏览器,使用HTTP工具向后台直接发送一些非正常的数据,我们后台的校验也是必须的。
      而在这一点上,Java中的JSR303/JSR-349定义了相应的规范,而Bean Validation则是该规范的具体实现。Bean Validation是一个通过配置注解来验证参数的框架,它包含两部分Bean Validation API和Hibernate Validator:

    • Bean Validation API是Java定义的一个验证参数的规范。
    • Hibernate Validator是Bean Validation API的一个实现。

    而我们如果在Spring中使用该框架的话,只需要简单配置即可:

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">  
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>  
        <!-- 如果不加默认,则到使用classpath下的 ValidationMessages.properties -->  
        <property name="validationMessageSource" ref="messageSource"/>  
    </bean>  
    
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
        <property name="basenames">  
            <list>  
                <!-- 在web环境中一定要定位到classpath 否则默认到当前web应用下找  -->  
                <value>classpath:messages</value>  
                <value>classpath:org/hibernate/validator/ValidationMessages</value>  
            </list>  
        </property>  
        <property name="useCodeAsDefaultMessage" value="false"/>  
        <property name="defaultEncoding" value="UTF-8"/>  
        <property name="cacheSeconds" value="60"/>  
    </bean>  
    

    其中消息文件 ValidationMessages.properties 定义了我们配置的一些信息:

    user.id.null=用户编号不能为空  
    user.name.null=用户名不能为空  
    user.name.length.illegal=用户名长度必须在5到20之间  
    user.name.illegal=用户名必须是字母  
    user.password.null=密码不能为空  
    

    以上参考自:http://jinnianshilongnian.iteye.com/blog/1990081

    6.1.6 content-negotiation-manager元素

      该元素中文一般翻译为内容协商,意思是同一资源可以多种展示方式,比如说当输入后缀是html的时候,返回html页面,当输入json后缀的时候,返回j'son格式的数据,当然是在同一个方法里,其实就是根据请求规则决定返回什么样的内容类型。
      比如说类似于这种:@RequestMapping(value={"/user/{id}","/user/{id}.json"}),也就是说当输入user/1的时候返回对应的试图,当输入user/1.json的时候,返回json格式的数据,这种就是所谓的内容协商了,而Spring中content-negotiation-manager该元素就是用于实现这个功能的,当然不单单是json,还有其他方式,比如XML等等。
    在RESTful该特性的实现方式大概有以下三种:

    • 1.使用http request header: Accept
    GET /user/123 HTTP/1.1
    Accept: application/xml                 //将返回xml格式数据
    
    GET /user/123 HTTP/1.1
    Accept: application/json               //将返回json格式数据
    
      1. 使用扩展名
    /user/123.xml  将返回xml格式数据
    /user/123.json 将返回json格式数据
    /user/123.html 将返回html格式数据
    
      1. 使用参数
    /user/123?format=xml          //将返回xml数据
    /user/123?format=json          //将返回json数据
    

    而Spring则是支持以上三种方式的,ContentNegotiatingViewResolver是根据客户提交的MimeType(如 text/html,application/xml)来跟服务端的一组viewResover的MimeType相比较,如果符合,即返回viewResover的数据。
    而 /user/123.xml, ContentNegotiatingViewResolver会首先将 .xml 根据mediaTypes属性将其转换成 application/xml,然后完成前面所说的比较。

    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <!-- 设置为true以忽略对Accept Header的支持-->
        <property name="ignoreAcceptHeader" value="true"/>
        <!-- 在没有扩展名时即: "/user/1" 时的默认展现形式 -->
        <property name="defaultContentType" value="text/html"/>
        <property name="mediaTypes">
            <value>
                json=application/json
                xml=application/xml
            </value>
        </property>
    </bean>
    
    <!-- 配置ContentNegotiatingViewResolver -->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
            </list>
        </property>
    </bean>
    

    如果想更多的了解内容协商相关的问题,可参考:
    Spring MVC Content Negotiation
    https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/
    官网文档-mvc-config-content-negotiation

    6.1.7 mvc:argument-resolvers子标签

    该标签用于自定义参数解析器,比如说我们通过@RequestBody来解析json格式的参数,通过@RequestParam来解析表单相关的参数,如果Spring自带的参数解析器满足不了我们的需要,我们可以自定义解析器,实现HandlerMethodArgumentResolver接口,然后配合注解来完成自定义解析参数的功能。

    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="..."/>
        </mvc:argument-resolvers>
    </mvc:annotation-driven>
    
    6.1.8 mvc:return-value-handlers子标签

    该标签表示允许我们对特定的返回类型做处理,看一个例子就明白了:、

    @RequestMapping("/testReturnHandlers")
    public User testHandlerReturnMethod(){
        User u  = new User();
        u.setUserName("test");
        return u;
    }
    

      由于上面testReturnHandlers接口返回的是一个pojo类型,正常情况下Spring MVC无法解析,最后会由DefaultRequestToViewNameTranslator解析处一个缺省的view name,转到 testReturnHandlers.jsp,如果没有的话就会报错。这时候我们就可以通过该标签引入我们自定义的 HandlerMethodReturnValueHandler的实现来完成数据的处理。

    这时候我们先自定义我们的返回Handler处理器:

    public class UserHandlers implements HandlerMethodReturnValueHandler {
        Logger logger = LoggerFactory.getLogger(this.getClass());
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
            Class<?> type = returnType.getParameterType();
            if(User.class.equals(type))
            {
                return true;
            }
            return false;
        }
    
        @Override
        public void handleReturnValue(Object returnValue,
                MethodParameter returnType, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest) throws Exception {
            logger.info("handler  for return type users ");
            mavContainer.setViewName("helloworld");
        }
    }
    

    然后进行相关配置:

    <mvc:annotation-driven>
        <mvc:return-value-handlers>
            <bean class="UserHandlers"/>
        </mvc:return-value-handlers>
    </mvc:annotation-driven>
    

    最终我们再访问testReturnHandlers的时候,Spring就会通过我们自定义的UserHandlers来处理返回类型是User的返回值;

    6.1.9 mvc:path-matching子标签

    该标签用于控制Spring MVC请求URL的路径匹配,比如说,我们的某个方法配置如下:

    @RequestMapping("/world")
    public String hello() {
        return "hello";
    }
    

    默认情况下,Spring MVC会自动匹配所有.*的请求,就上面这个例子而言,我们请求/world/wold.html/world.do都会匹配成功,然后执行相应的操作。如果我们不想按照Spring的这种默认的匹配规则来的话,就可以通过配置该标签来完成我们所需的操作。下面来简单看下该标签下的几个参数:

    1. suffix-pattern元素:布尔类型,true和false,该元素表示URL匹配的时候是否使用默认的后缀模式匹配全部(.*),默认是true,如果我们配置为false的话,那么就上面例子来说,我们再使用/world.*类似的就匹配不到了。
    2. trailing-slash元素:布尔类型,true和false,该属性表示匹配的时候是否不考虑斜杠/,默认是true,也就是不考虑斜杠的存在,那么映射到/users的方法也就可以匹配/users/
    3. registered-suffixes-only元素:布尔类型,true和false,具体作用不明,官网解释:
        Whether to use suffix pattern match for registered file extensions only when matching patterns to requests.If enabled, a controller method mapped to "/users" also matches to "/users.json" assuming ".json" is a file extension registered with the provided ContentNegotiationManager. This can be useful for allowing only specific URL extensions to be used as well as in cases where a "." in the URL path can lead to ambiguous interpretation of path variable content, (e.g. given "/users/{user}" and incoming URLs such as "/users/john.j.joe" and "/users/john.j.joe.json").
        If enabled, this attribute also enables suffix-pattern. The default value is false.
    1. path-matcher元素:我们自定义的地址匹配PathMatcher的实现,如果我们不配置,默认的实现是AntPathMatcher
    2. path-helper元素:我们自定义的用于解析路径匹配的UrlPathHelper的实现,默认的是UrlPathHelper。
    <mvc:annotation-driven>
        <mvc:path-matching
            suffix-pattern="true"
            trailing-slash="false"
            registered-suffixes-only="true"
            path-helper="pathHelper"
            path-matcher="pathMatcher"/>
    </mvc:annotation-driven>
    
    <bean id="pathHelper" class="org.example.app.MyPathHelper"/>
    <bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
    
    6.1.10 mvc:message-converters子标签

      该标签表示配置Spring的消息转换器。我们都使用过@RequestBody和@ResponseBody这两个注解,当使用RequestBody注解,对请求的数据进行对象映射时,Spring会根据Request对象header部分的content-Type类型,选择合适的HttpMessageConverter来读取数据;而ResponseBody,则是在进行响应时,同样选择合适的HttpMessageConverter来进行转换,返回对应格式的数据。

      假如我们通过RequestBody注解定义一个对象,来接收前台传入的json参数时,有的时候可能会由于属性的不匹配出现400错误,这时候,我们就可以自定义HttpMessageConverter来完成我们的参数匹配。具体的实例可参考:SpringMVC自定义配置消息转换器踩坑总结

    该标签有一个参数:register-defaults,表示除了我们自定义的之外,是否还使用默认的HttpMessageConverter来处理。布尔类型,默认是true,大多数情况下这个值都是true类型。

    <mvc:message-converters register-defaults="true">
        <!-- 字符串返回时的编码问题 -->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json;charset=UTF-8</value>
                    <value>text/html;charset=UTF-8</value>
                </list>
            </property>
            <property name="objectMapper"><ref bean="objectMapper"/> </property>
        </bean>
    </mvc:message-converters>
    
    6.1.11 mvc:async-support子标签

      Spring MVC异步请求的配置选项。一般情况下,在同步请求中,浏览器发起请求,服务器开启一个线程响应,响应完成返回一个值给浏览器,而异步的话返回的一般是Callable对象或者DeferredResult对象,然后后端会通过一个回调线程来处理调用的结果,处理完成后再返回。这里请求线程与后台处理是两个线程,并且Callable对象和DeferredResult对象略有些不同,感兴趣的可以自行搜索一下。

    • default-timeout属性,默认超时时间,单位毫秒,如果不配置,则使用底层实现的默认超时时间,比如Servlet3中Tomcat上的10秒;
    • task-executor属性,线程池配置,默认是使用SimpleAsyncTaskExecutor线程池来执行Callable的代码,不过该线程池不重用任何线程,或者说它每次调用都启动一个新线程,性能不是太高,我们可以使用自定义线程池来实现。
      实现可参考:Spring MVC 异步处理请求,提高程序性能

    下面看下该标签下的两个子标签:

    1. mvc:callable-interceptors,异步操作的拦截器处理,我们可以自定义拦截器来处理异步操作过程中的一些问题,拦截的响应对象是Callable,比如说超时了咋滴整等;
      The ordered set of interceptors that intercept the lifecycle of concurrently executed requests, which start after a controller returns a java.util.concurrent.Callable.
    2. mvc:deferred-result-interceptors,和上面这个标签类似,不过该标签拦截的是DeferredResult对象;
      The ordered set of interceptors that intercept the lifecycle of concurrently executed requests, which start after a controller returns a DeferredResult.
    6.2 mvc:interceptors标签

    Spring MVC中的拦截器的配置,拦截日志,登陆,权限等操作,我们直接来看一下该标签下各元素的使用。

    • path-matcher元素:表示我们可以自定义拦截器路径的匹配规则,默认采用的匹配规则是AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
    6.2.1 mvc:interceptor子标签

    mvc:interceptors 标签下有三种子标签,也就是有两种类型的配置,其中bean和ref表示拦截所有的请求,而mvc:interceptor则是一种更细粒度的配置,可以自定义拦截的路径和要排除的路径。当有多个拦截器的时候,执行的顺序将按照它们配置的顺序来执行。

    • mvc:mapping,表示要拦截的路径,其中属性path为具体要拦截的路径,ref或bean表示具体实现的拦截器;
    • mvc:exclude-mapping,表示要排除掉不需要拦截的路径;
    6.3 mvc:default-servlet-handler标签

      Spring MVC用于处理静态资源的一种方式。为了实现优雅的Rest风格的的方式,我们配置DispatcherServlet的请求路径是一般都是配置为/,这种情况下Spring MVC将会捕获Web容器所有的请求,包括静态资源的请求,然后分发到具体的controller去处理,如果找不到则会出现异常。这种情况下,对于静态资源请求的处理,则显得尤为重要了,而Spring MVC自从3.0之后就提供了两种比较优雅的方式:

    1. 一种是配置mvc:default-servlet-handler,配置之后,Spring MVC上下文中会定义一个DefaultServletHttpRequestHandler,请求进入DispatcherServlet之后,会被分发到各个HandlerMapping进行处理,如果该请求最后处理不了,会交给默认的DefaultServletHttpRequestHandler来进行处理;
    2. 一般Web应用服务器默认的Servlet名称是"default",假如我们的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定;
    <mvc:default-servlet-handler default-servlet-name="_ah_default"/>
    

    而DefaultServletHttpRequestHandler中各个服务器对应的servlet名称如下:

    /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish */
    private static final String COMMON_DEFAULT_SERVLET_NAME = "default";
    
    /** Default Servlet name used by Google App Engine */
    private static final String GAE_DEFAULT_SERVLET_NAME = "_ah_default";
    
    /** Default Servlet name used by Resin */
    private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file";
    
    /** Default Servlet name used by WebLogic */
    private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet";
    
    /** Default Servlet name used by WebSphere */
    private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet";
    
    6.4 mvc:resources标签

    而另一种处理静态资源的方式就是mvc:resources标签了。mvc:default-servlet-handler标签将静态资源的处理最终是由Spring MVC交给了Web服务器进行处理,而mvc:resources则是由Spring MVC自己处理,并且还可以配置一些简单的优化方式。

    <mvc:resources mapping="/javascript/" location="/WEB-INF/js/" order="1" cache-period="31536000"/>
    
    1. location元素:首先,<mvc:resources/> 允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中,通过location属性指定静态资源的位置,当然支持通配符的方式;
    2. cache-period元素:我们可以通过配置该属性指定静态资源在浏览器端的缓存时间,单位是秒,默认是没有缓存。在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,直接从缓存中取值,提高程序性能;
    3. mapping元素:映射地址,比如当我们要引用/WEB-INF/js/文件夹下的文件时,可以直接引用/javascript/**.js,这样就会去我们的WEB-INF/js/里面去找。也就是说,配置了mapping之后,Spring会做一层映射,然后去映射所对应的location下查找静态资源,因为location的位置不是固定的;
    4. order元素:如果配置了多个mvc:resources,那么可以通过order元素指定过滤查找时的优先级,order值越小优先级越高,默认的order值是:Integer.MAX_VALUE - 1

    以上静态资源的问题都是基于我们web.xml中配置的url-pattern是拦截全部/的情况。而如果我们的配置是*.do等相关格式的话,就不会有以上相关的问题了。

    6.5 mvc:view-controller标签

      对于WEB-INF目录下的页面,我们知道,由于安全性的问题我们无法直接通过URL访问到,一般都是通过在控制器中使用转发的方式来进行访问。而有一些时候我们如果单纯的只是想访问该目录下的页面,并没有一些逻辑操作的时候,可以通过配置该标签将要访问的URL与相应的视图进行映射,不用再通过控制器就可以解析为对应的视图。

     <mvc:view-controller path="/test" view-name="hello/hello"/>
    
    1. path参数,是要访问的URL,比如localhost:8080/test
    2. view-name参数,要映射的文件的路径,比如某一个jsp的文件路径是WEB-INF/hello/hello.jsp,那对应的view-name则就是hello/hello,不过不要忘记配置视图解析器。另外,view-name的另外一种方式是重定向的方式:<... view-name="redirect:/admin/index">,有兴趣的可以尝试一下。

    总结

    到这里,Spring MVC命名空间下的主要标签都学习完了。MVC下的标签针对的是Http请求过程中的各种配置,了解了这些配置,可以让我们在写Web相关的接口的时候更加游刃有余。

    本文主要参考资料:官网资料及StackOverFlow网站

    相关文章

      网友评论

        本文标题:[spring]applicationContext.xml-m

        本文链接:https://www.haomeiwen.com/subject/yszwcftx.html