springmvc框架是一个基于请求驱动的web框架,使用了前端控制器模式来设计。根据请求映射规则分发给相应的页面控制器进行处理。
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
在web.xml文件中配置DispatcherServlet。DispatcherServlet是一个标准的Java web servlet。它是继承自Servlet基类的。
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
在上面的配置中,我们还指定了DispatcherServlet配置文件的位置信息。为/WEB-INF/spring/appServlet/servlet-context.xml。在这个xml文件中,可以配置springmvc怎么将请求映射到controller,springmvc使用什么视图引擎等重要信息。
在这个xml文件中,我们需配置如下的几个bean。
bean type | 说明 |
HandlerMapping | 将一个http请求映射到一个handler chain。包含一个handler和一系列interceptor。 |
HandlerAdapter | 帮助DispatcherServlet将一个handler映射到请求中,而不管实际调用的是那个handler。使用了适配器模式。 |
HandlerExceptionResolver | 异常相关的 |
ViewResolver | 使用的是什么视图引擎 |
LocalResolver和LocaleContextResolver | |
ThemeResolver | |
MultipartResolver | 处理multi-part请求。上传文件相关的 |
FlashMapManager | 存储和读取FlashMap。用来传递attributes从一个请求到另一个请求。经常用在redirect中。 |
DispatcherServlet的默认配置
# Default implementation classes for DispatcherServlet's strategy interfaces. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver, org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager |
DispatcherServlet 初始化参数
参数 | 说明 |
contextClass | 实现了接口WebApplicationContext的类。默认使用xmlWebApplicationContext |
contextConfigLocation | 初始化context的xml文件位置 |
namespace |
实现Controllers
consumable media type
使用consumable media type可以限定,只有当请求的Content-Type header满足指定的media type时,使用该action。例如:
@Controller @RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json") public void addPet(@RequestBody Pet pet, Model model) { // implementation omitted } |
producible media type
当请求的Accept Type header满足我们指定的media type是,才使用该action
@Controller @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json") @ResponseBody public Pet getPet(@PathVariable String petId, Model model) { // implementation omitted } |
matrix Variables
matrix Variables是一个http的url规范,用的比较少。实际情况下应该不会使用。更多详情见:http://www.w3.org/DesignIssues/MatrixURIs.html。
// GET /pets/42;q=11;r=22 @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET) public void findPet(@PathVariable String petId, @MatrixVariable int q) { // petId == 42 // q == 11 } |
// GET /owners/42;q=11/pets/21;q=22 @RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET) public void findPet( @MatrixVariable(value="q", pathVar="ownerId") int q1, @MatrixVariable(value="q", pathVar="petId") int q2) { // q1 == 11 // q2 == 22 } |
Request Parameters and header values
我们可以指定url中是否包含,参数中的某个参数=??。请求的header中是否包含某个值来匹配方法。"myParam"
, "!myParam"
, or "myParam=myValue"
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } } |
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets", method = RequestMethod.GET, headers="myHeader=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } } |
小提示:尽管我们可以使用headers=“content-type=text/×”来匹配如text/plain或text/html,但是还是推荐使用consumes and produces。因为这2个注解是专门为了解决这种情况的。
request body
request body注解可以将http请求的body映射到方法的参数中
@RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException { writer.write(body); } |
responsebody
将方法的结果直接写进http response中
@RequestMapping(value = "/something", method = RequestMethod.PUT) @ResponseBody public String helloWorld() { return "Hello World"; } |
比如在一些ajax请求中,或一些给第三方的接口中,我们希望返回的只是纯文本,json或xml格式的数据,这时候就要用到response注解了。
RestController
如果我们设计了一个rest风格的controller,这个controller方法中返回的都是纯文本,json或xml数据,而不是html页面。那么我们可以在这个contrller的所有方法中都添加一个responseBody注解,但这是比较麻烦和笨重的方法。使用restController注解就可以了。
httpEntity
httpEntity和requestBody,ResponseBode类似,httpEntity注解可以将一个http请求,http相应的header和body都绑定到方法的一个参数中去。
@RequestMapping("/something") public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException { String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader")); byte[] requestBody = requestEntity.getBody(); // do something with request header and body HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("MyResponseHeader", "MyValue"); return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED); } |
modelAttribute
ModelAttribute可以用在方法或方法的参数中。
用在方法中:标识该方法的目的是添加一个或多个model属性。有modelAyyribute注解的方法不能直接映射到请求。相反,有modelAttribute注解的方法会在该Controller的所有RequestMapping方法之前被调用。
// Add one attribute // The return value of the method is added to the model under the name "account" // You can customize the name via @ModelAttribute("myAccount") @ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); } // Add multiple attributes @ModelAttribute public void populateModel(@RequestParam String number, Model model) { model.addAttribute(accountManager.findAccount(number)); // add more ... } |
modelAttribute使用在一个方法的参数中,用于参数绑定。并将该参数暴露成model的一个参数。
sessionAttributes
用于绑定命令对象到session中。用于在多次请求中保持数据,比如:多步骤表单的提交。
sessionAttribute用于类中。表示该类中的方法,
@Controller @RequestMapping("/editPet.do") @SessionAttributes("pet") public class EditPetForm { // ... } |
表示将模型数据中的名字为user的对象存储到session中。