Spring框架:SpringMVC具体解释
SpringMVC的工作流程。最先接触到请求的是DispatcherServlet,它会将请求依据配置文件转发到控制器,控制器返回视图名称和一个Model表示处理结果。DispatcherServlet再将处理结果发送给视图模板引擎,由它进行页面的渲染。下图是整个过程。
基本配置
声明servlet。首先要在web.xml中声明Spring的Servlet,代码例如以下:
<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/<url-pattern> </servlet-mapping>
重要提示:这里的url-pattern不能用/*,会导致全部的请求都返回404错误。由于我们自己编写的控制器仅仅会返回一个视图名称,而解析视图名称的时候还会再次通过servlet获取资源。假设使用/*。那么全部的资源都由Spring框架来处理,可是Spring控制器中没有不论什么jsp文件,假设设置成/,那么对于xxx.jsp文件就会优先通过Tomcat自带的Servlet返回静态资源。
静态资源。让Spring框架处理全部的静态资源,须要例如以下的声明。下面是spring-servlet.xml文件,文件名servlet-name有关。
<beans xmlns="..."> <mvc:resources mapping="/res/**" location="/res/"/> </beans>
注解声明。为了开启注解方式的配置,须要在spring-servlet.xml中声明:
<mvc:annotation-driven/> <context:component-scan base-package="com.example"/>
控制器
控制器的编写很灵活。以下看几个样例。
// 最简单的样例,仅仅要学会这个就能解决大部分问题了 @Controller public class TestController { // 映射请求URL,返回一个model和视图名称 @RequestMapping("/test1") public String test1(Model model) { return "hello"; } } // RequestMapping使用方法 @Controller @RequestMapping("/myapp") public class MyAppController { // 通过/myapp訪问 @RequestMapping(method=RequestMethod.GET) public Map<String, String> get() { } // 通过/myapp/xxx訪问 @RequestMapping(value="/{name}", method=RequestMethod.GET) public Map<String, String> getForName(@PathVariable("name") String name) { } @RequestMapping(method=RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { } } // URL中包括多个变量 @Controller @RequestMapping("/people/{peopleId}") public class TestController { @RequestMapping("/order/{orderId}" public void getOrder(@PathVariable("peopleId") int peopleId, @PathVariable("orderId") String orderId, Model model) { } } // URL正则匹配 @Controller @RequestMapping("/people/{peopleId:[0-9]+}") public class TestController { } // 匹配请求中的參数 @Controller public class Test { @RequestMapping(value="/test", params="name=alice") public void test() { } // 没有name參数的请求 @RequestMapping(value="/test" params="!name") { } } // 匹配Http请求报头 @Controller public class Test() { @RequestMapping(value="/test", headers="Accept-Encoding=UTF-8") public void test() { } // Header中存在Cookie @RequestMapping(value="/test", headers="Cookie") public void test() { } } // 接受json请求 @Controller public class TestController { @RequestMapping(value="/test" method=RequestMethod.POST, consumes="application/json") public void test(@RequestBody People people, Model model) { } } // 返回json结果 @Controller public class TestController { @RequestMapping(value="/test", method=RequestMethod.GET, produces="application/json") public @ResponseBody People getPeople() { } } // Cookie @RequestMapping("/test") public void test(@CookieValue("Hello") String hello) { } // Http头 @RequestMapping("/test") public void test(@RequestHeader("Accept-Encoding") String encoding) { } // 文件上传 @RequestMapping("/test/") public void test(@RequestParam(value="image", required=false)MultipartFile image) { } // 參数验证 @Controller public class TestController { @Size(min=3, max=20, message="xxx") @Pattern(regexp="^[a-zA-Z][a-zA-Z0-9]*") private String username; } // 错误处理 @Controller public class TestController { @RequestMapping("/test") public String test() { } @ExceptionHandler(IOException.class) public ResponseEntity(String) error() { } }
视图
当控制器返回一个视图名称之后。须要通过ViewResolver解析视图。ViewResolver有多种类型:InternalResourceViewResolver、TilesViewResolver、FreemarkerViewResolver、VelocityViewResolver等等。
配置视图引擎。在xxxx-servlet.xml中增加下面代码就可以。
<!--简单的JSP模板引擎--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!--JSTL模板引擎--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!--Tiles模板引擎--> <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> <property name="definitions"> <list> <value>/WEB-INF/views/**/views.xml</value> </list> </property> </bean>
假设使用的是InternalResourceViewResolver,那么不须要额外的配置。仅仅要返回文件名称就能够了。比方以下的代码会渲染/WEB-INF/views/test.jsp
public String test(){ return "test"; }
假设须要跳转,仅仅要返回redirect:就可以,以下请看样例。
public String test() { return "redirect:/hello/test/xxx"; }
拦截器
拦截器须要在xxx-servlet.xml中声明。代码例如以下:
<mvc:interceptors> <!--简单拦截器--> <bean class="com.example.LoginInterceptor/> <!--限定拦截URL--> <mvc:interceptor> <mvc:mapping path="/admin/*"/> <bean class="com.example.AdminInterceptor/> </mvc:interceptor> </mvc:interceptors>
RESTful集成
REST是一种URL规范。全部的API都不包括QueryString。
REST注重资源。而传统的API注重行为。
REST通过HTTP Method的不同来做出不同的行为。请看以下几个REST API的样例。返回的结果能够是XML或者JSON。
http://test.com/user/alice http://test.com/question/1232/answer/321
Spring MVC因为它的映射机制比較良好,因此实现REST API并不困难。以下请看一个样例。
@Controller public class TestController { @RequestMapping("/user/{id}", method=RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public String updateUser(@PathVariable("id") long id, @Valid User user) { } @RequestMapping("/user/{id}", method=RequestMethod.DELETE) @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteUser(@PathVariable("id") long id) { { } @RequestMapping("/user/{id}", method=RequestMethod.GET) public @ResponseBody User getUser(@PathVariable("id") long id) { } @RequestMapping("/user", method=RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public @ResponseBody User createUser(@Valid User user, BindingResult result, HttpServletResponse response) throws BindException { long userId = service.createUser(user); // 返回资源位置 response.setHeader("Location", "/user/" + userId); return user; } }
资源的表述。资源的表述有多种方式,html/xml/json,html适合给人类看。而xml/json适合用于系统之间的通信。
定义资源表述能够通过ContentNegotiatingViewResolver。
须要在Spring配置中增加例如以下代码。
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaType"> <map> <entry key="json" value="application/json"/> <entry key="xml" value="text/xml"/> <entry key="htm" value="text/html"/> </map> </property> <property name="defaultContentType" value="text/html"/> </bean>
Spring通过多种途径确定该返回哪种格式:URL扩展名,queryString參数,HTTP Header中的Accept字段。