该文章基于《Spring+MyBatis企业应用实战》进行总结,旨在积累巩固
DispatcherServlet
该类主要用于调度控制,所有的请求驱动都围绕着这个DispatcherServlet来分派请求,可以将DispatcherServlet理解为特殊的控制器,该类的配置一般在web.xml文件中,常见配置信息如下:
<!--web.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name><!--Servlet名称--></servlet-name>
<servlet-class>
<!--一般为org.springframework.web.servlet.DispatcherServlet-->
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!--包含springmvc-config.xml的配置路径,以web路径为根节点-->
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name><!--Servlet名称--></servlet-name>
<url-pattern>
<!--你想要监听的路径,如果该值为'/',那么将会监听所有请求-->
</url-pattern>
</servlet-mapping>
</web-app>
Dispatcher会查找配置路径下对应的配置文件,然后基于ServletContext实例初始化WebApplicationContext,具体的源码分析可以查看我之前的博客SpringMVC源码分析。
Controller(控制器)
非注解方式
Controller本身应该是需要实现org.springframework.web.servlet.mvc.Controller接口的ModelAndView handleRequest(HttpServletRequest,HttpServletResponse)方法,我们在谈到DispatcherServlet时也谈到了contextConfigLocation属性用于指定搜索servlet名称-config.xml文件,故Controller的配置就应该位于此xml文件中,以达到模块化开发的目的,
一下为常见的配置文件格式:
<!--servlet名称-config.xml-->
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans">
<bean name= "需要处理的请求的映射,例如'/test'"
class="Controller接口的实现类的位置"/>
</beans>
其中Spring会自动初始化三个其他的bean,包括BeanNameUrlHandlerMapping用于将bean的名称映射到请求,SimpleControllerHandlerAdapter用于完成对Controller类的handleRequest方法的调用,可以从名字看出这个类的设计是适配器,InternalResourceViewResolver来解析适配器。注意如果Spring版本在4.0之前,那么需要显式地声明这几个bean。
如果出现无法加载lib中jar包的情况,将lib放在/web/WEB-INF/目录之下
注解方式
通过@Controller代替实现Controller接口,通过@RequestMapping代替通过beanname指定请求路径,通过注解方式配置的Controller的[servlet]-config文件与通过实现接口的配置文件有不同:下面是典型的xml配置文件:
<!--[servlet]-config.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<context:component-scan base-package="controller"/>
</beans>
最主要的就是这一项配置了,与通过非注释方法配置的Controller相对应的是,这种情况下Spring会自动加载三个bean——RequestMappingHandlerMapping(查找对应的映射)、RequestMappingHandlerAdapter(用来完成对@RequestMapping标注方法的调用)、与注释方法相同的InternalResourceViewResolver(解析视图)
InternalResourceViewResolver
该类可以通过指定它的prefix和suffix属性,返回指定路径下的页面
例如:
<!--[servletname]-config.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<context:component-scan base-package="controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/view/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
所有controller返回的ModelAndView的视图名称都会加上/WEB-INF/view/前缀和.jsp后缀
@RequestMapping
用于映射请求的URL,可以为类级别或者方法级别,常见属性有value、method、params(用于处理包含指定参数的请求)、headers(用于处理包含指定Referer的请求),该注解注解的方法参数类型不唯一、返回类型也不唯一,参数类型很多在此不赘述,下面主要谈一下返回类型中最重要的几个返回参数的类型:
(1)Model:通过返回String指定返回的view,对参数操作需要通过调用asMap方法
(2)ModelMap:通过返回String指定返回的view,可以直接通过addAttribute添加参数
(3)ModelAndView:通过setViewName指定返回的View,通过addObject添加参数
(4)@ModelAttribute
(5)@SessionAttributes
参数绑定注解
处理request body部分的注解:@RequestParam,@RequestBody
处理request uri部分的注解:@PathVariable
处理request header部分的注解:@RequestHeader,@CookieValue
处理attribute类型的注解:@SessionAttributes,@ModelAttribute
处理response类型的注解:@ResponseBody
一下按照顺序进行总结:
@RequestParam
用于将请求参数映射到方法参数中,主要用于名称的转化
@RequestBody
可以用于将JSON格式的输入转化为指定的domain,故为参数层面注解
@PathVariable
@PathVariable通过与@RequestMapping进行配合,可以将请求中的URL参数绑定到方法参数中,如下所示:
@RequestMapping(value="/path/{param}")
public void pathVariableTest(@PathVaraiable String param)
@RequestHeader
实际作用同@PathVariable相同,但是这里映射的是映射头的值,而不是URL的动态参数
@CookieValue
用于将Cookie中的值映射到参数中,可以设置default属性
@SessionAttributes
只能用于类声明,而不能用在方法,用于有选择的指定Model中哪些属性:1.需要将ModelXXX中转存到HttpSession对象中,2.通过names指定,或者通过types属性指定(不能通过父类指定)
@ModelAttribute
该注解可以用于①方法,②参数,@ModelAttribute修饰的方法会先于@RequestMapping的方法调用 / 或者Controller方法,用于前置的参数处理,注释的方法的参数名称默认和传入的参数名称对应,否则可以通过@RequestParam进行注解,如果被注释的方法返回具体值,可以通过指定key直接将该返回值作为value加入Model中,需要注意,如果@ModelAttribute与@RequestMapping同时注释一个方法,那么该方法实际只会调用一次,通过代码解释:
@ModelAttribute("mapkey")
@RequestMapping("/index")
public String handleRequest() throws Exception {
System.out.println("invoke");
return "mapvalue";
}
当有/index的请求时上面的代码只会被调用一次,并且会返回至@RequestMapping的属性值指定的页面中,而Model属性中会添加“mapkey” → “mapvalue”,私以为这是SpringMVC设计时的错误,因为在这种状态下,本来应该被执行两次的方法实际上只被执行了一次。当注释在参数上时与之前谈到的放入不同,参数上的@ModelAttribute实际是从Model模型中取出值,或者由请求参数构造实例
@ModelAttribute获得的值实际上是放在ModelMap中
@ResponseBody
用于将输出的参数转化为JSON,故为方法层面注解
处理不同ContentType分为一下几种情况:
ContentType | @RequestBody | @ModelAttribute | @RequestParam |
---|---|---|---|
application/x-www-form-urlencoded | √ | √ | √ |
multipart/form-data | × | ? | ? |
application/json、application/xml | √ | × | × |
信息转换
HttpMessageConverter<T>
HttpMessageConverter<T>是Spring3.0之后新增的接口,负责将请求信息转化为一个对象、或者将对象转化为相应信息,由HandlerAdapter的实现类RequestMappingHandlerAdapter进行使用:
可以看到其中默认加载了几个实例,其他的实例需要通过显示添加才行。
转换JSON数据的HttpMessageConverter→MappingJackson2HttpMessageConverter
<mvc:annotation-driven/>
在[servletname]-config.xml进行注册,用于自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter,在这里记录一件非常操蛋的事情,就是不要重复的注册RequestMappingHandlerXXX与<mvc:annotation-driven/>,这样会引起错误,如果不想使用默认的转换器,需要在配置文件中重写,代码如下所示:
<mvc:annotation-driven>
<!-- 设置不使用默认的消息转换器 -->
<mvc:message-converters register-defaults="false">
<!-- 配置Spring的转换器 -->
<bean class="XXX"/>
<!-- 配置fastjson中实现HttpMessageConverter接口的转换器 -->
<bean id="fastJsonHttpMessageConverter"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 加入支持的媒体类型:返回contentType -->
<property name="supportedMediaTypes">
<list>
<!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler/>
在[servletname]-config.xml进行注册,用于使用默认的servlet响应静态文件,一般用于js文件引用的问题,最好不要将js、css文件放入WEB-INF目录中。
@InitBinder
该注解用于判断输入是否正确,并且是方法层面的注解,可以和自带标签库中的errors标签进行配合
@InitBinder//在@Controller类中定义
public void initBinder(DataBinder binder){
binder.setValidator(new XXXValidator());
}
public class XXXValidator implements Validator{
public boolean supports(Class<?> clazz){
return XXX.class.equals(clazz);
}
public void validate(Object object, Errors errors){
ValidationUtils.rejectIfEmpty(errors,"属性名",null,"错误信息");
}
}