SpringMVC
SpringMVC简介
SpringMVC是一种基于Java实现MVC模型的轻量级Web框架。
优点:
使用简单,开发便捷(相比于Servlet)
灵活性强
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.tomcat.maven</groupId> 5 <artifactId>tomcat7-maven-plugin</artifactId> 6 <version>2.1</version> 7 <configuration> 8 <port>80</port> 9 <path>/</path> 10 </configuration> 11 </plugin> 12 </plugins> 13 </build>
【第二步】在pom.xml导入坐标(SpringMVC+Servlet)
1 <dependencies> 2 <dependency> 3 <groupId>javax.servlet</groupId> 4 <artifactId>javax.servlet-api</artifactId> 5 <version>3.1.0</version> 6 <scope>provided</scope> 7 </dependency> 8 <dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-webmvc</artifactId> 11 <version>5.2.10.RELEASE</version> 12 </dependency> 13 </dependencies>
1 //定义表现层控制器bean 2 @Controller 3 public class UserController { 4 //设置映射路径为/save,即外部访问路径 5 @RequestMapping("/save") 6 //设置当前操作返回结果为指定json数据(本质上是一个字符串信息) 7 @ResponseBody 8 public String save(){ 9 System.out.println("user save ..."); 10 return "{'info':'springmvc'}"; 11 } 12 }
@RequestMapping注解:
位置:SpringMVC控制器方法定义上方。
作用:设置当前控制器方法请求访问路径。
注:对于SpringMVC而言,Controller方法返回值默认表示要跳转的页面,没有对应的页面就会报错。如果不想跳转页面而是响应数据,那么就需要在方法上使用@ResponseBody注解。
@ResponseBody注解:
位置:SpringMVC控制器方法定义上方。
作用:设置当前控制器返回值作为响应体
【第四步】编写SpringMVC配置类,加载处理请求的Bean。
1 //springmvc配置类,本质上还是一个spring配置类 2 @Configuration 3 @ComponentScan("com.test.controller") 4 public class SpringMvcConfig { 5 }
【第五步】加载SpringMVC配置,并设置SpringMVC请求拦截的路径
1 //web容器配置类 2 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { 3 //加载springmvc配置类,产生springmvc容器(本质还是spring容器) 4 protected WebApplicationContext createServletApplicationContext() { 5 //初始化WebApplicationContext对象 6 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); 7 //加载指定配置类 8 ctx.register(SpringMvcConfig.class); 9 return ctx; 10 } 11 12 //设置由springmvc控制器处理的请求映射路径 13 protected String[] getServletMappings() { 14 return new String[]{"/"}; 15 } 16 17 //加载spring配置类 18 protected WebApplicationContext createRootApplicationContext() { 19 return null; 20 } 21 }
AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类。
AbstractDispatcherServletInitializer提供三个接口方法供用户实现:
createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围。
getServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理。
createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式同createServletApplicationContext()。
1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器
2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象
3. 加载SpringMvcConfig配置类
4. 执行@ComponentScan加载对应的bean
5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法
6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC
单次请求过程
1. 发送请求localhost/save
2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
3. 解析请求路径/save
4. 由/save匹配执行对应的方法save()
5. 执行save()
6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方
SpringMVC相关bean:表现层bean
Spring控制的bean:
业务bean(Service)
功能bean(DataSource等)
SpringMVC相关bean加载控制:
SpringMVC加载的bean对应的包均在com.test.controller包内
Spring相关bean加载控制:
方式一:Spring加载的bean设定扫描范围为com.test,排除掉controller包内的bean
1 @Configuration 2 @ComponentScan(value = "com.test", 3 excludeFilters = @ComponentScan.Filter( 4 type = FilterType.ANNOTATION, //ANNOTATION:按注解过滤 5 classes = Controller.class //需要过滤的注解类型 6 ) 7 ) 8 public class SpringConfig { 9 }
属性:
excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)。
includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes)。
需要过滤的注解类型:
方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等(开发主要用)
1 @Configuration 2 @ComponentScan({"com.test.service","com.test.dao"}) 3 public class SpringConfig { 4 }
方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中
1 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { 2 protected WebApplicationContext createServletApplicationContext() { 3 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); 4 ctx.register(SpringMvcConfig.class); 5 return ctx; 6 } 7 protected WebApplicationContext createRootApplicationContext() { 8 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); 9 ctx.register(SpringConfig.class); 10 return ctx; 11 } 12 protected String[] getServletMappings() { 13 return new String[]{"/"}; 14 } 15 }
简化格式:
1 public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{ 2 protected Class<?>[] getServletConfigClasses() { 3 return new Class[]{SpringMvcConfig.class} 4 }; 5 protected String[] getServletMappings() { 6 return new String[]{"/"}; 7 } 8 protected Class<?>[] getRootConfigClasses() { 9 return new Class[]{SpringConfig.class}; 10 } 11 }
名称:@RequestMapping
类型:方法注解 类注解
位置:SpringMVC控制器方法定义上方
作用:设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀
范例:
1 @Controller 2 //类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径 3 @RequestMapping("/user") 4 public class UserController { 5 //请求路径映射 6 @RequestMapping("/save") //此时save方法的访问路径是:/user/save 7 @ResponseBody 8 public String save(){ 9 System.out.println("user save ..."); 10 return "{'module':'user save'}"; 11 } 12 }
1 //普通参数:请求参数与形参名称对应即可完成参数传递 2 @RequestMapping("/commonParam") 3 @ResponseBody 4 public String commonParam(String name ,int age){ 5 System.out.println("普通参数传递 name ==> "+name); 6 System.out.println("普通参数传递 age ==> "+age); 7 return "{'module':'common param'}"; 8 }
get请求中文乱码处理
注:tomcat 8.5版本之后GET请求就不再出现中文乱码问题。
tomcat 8.5版本之前乱码解决:在pom.xml添加tomcat7插件处配置UTF-8字符集,解决GET请求中文乱码问题。
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.tomcat.maven</groupId> 5 <artifactId>tomcat7-maven-plugin</artifactId> 6 <version>2.1</version> 7 <configuration> 8 <port>80</port><!--tomcat端口号--> 9 <path>/</path> <!--虚拟目录--> 10 <uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集--> 11 </configuration> 12 </plugin> 13 </plugins> 14 </build>
POST请求传递普通参数
普通参数:form表单post请求传参,表单参数名与形参变量名相同,定义形参即可接收参数
1 //普通参数:请求参数与形参名称对应即可完成参数传递 2 @RequestMapping("/commonParam") 3 @ResponseBody 4 public String commonParam(String name ,int age){ 5 System.out.println("普通参数传递 name ==> "+name); 6 System.out.println("普通参数传递 age ==> "+age); 7 return "{'module':'common param'}"; 8 }
为web容器添加过滤器并指定字符集,Spring-web包中提供了专用的字符过滤器
1 public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { 2 protected Class<?>[] getRootConfigClasses() { 3 return new Class[0]; 4 } 5 protected Class<?>[] getServletConfigClasses() { 6 return new Class[]{SpringMvcConfig.class}; 7 } 8 protected String[] getServletMappings() { 9 return new String[]{"/"}; 10 } 11 12 //乱码处理 13 @Override 14 protected Filter[] getServletFilters() { 15 CharacterEncodingFilter filter = new CharacterEncodingFilter(); 16 filter.setEncoding("UTF-8"); 17 return new Filter[]{filter}; 18 } 19 }
1 //普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系 2 @RequestMapping("/commonParamDifferentName") 3 @ResponseBody 4 public String commonParamDifferentName(@RequestParam("name") String userName , int age){ 5 System.out.println("普通参数传递 userName ==> "+userName); 6 System.out.println("普通参数传递 age ==> "+age); 7 return "{'module':'common param different name'}"; 8 }
名称:@RequestParam
类型:形参注解
位置:SpringMVC控制器方法形参定义前面
作用:绑定请求参数与处理器方法形参间的关系
参数:
required:是否为必传参数
defaultValue:参数默认值
1 public class User { 2 private String name; 3 private int age; 4 ... 5 }
1 //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递 2 @RequestMapping("/pojoParam") 3 @ResponseBody 4 public String pojoParam(User user){ 5 System.out.println("pojo参数传递 user ==> "+user); 6 return "{'module':'pojo param'}"; 7 }
注:请求参数key的名称要和POJO中属性的名称一致,否则无法封装。
1 public class User { 2 private String name; 3 private int age; 4 private Address address; 5 ... 6 } 7 public class Address { 8 private String province; 9 private String city;10 }
嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
1 //嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递 2 @RequestMapping("/pojoContainPojoParam") 3 @ResponseBody 4 public String pojoContainPojoParam(User user){ 5 System.out.println("pojo嵌套pojo参数传递 user ==> "+user); 6 return "{'module':'pojo contain pojo param'}"; 7 }
注:请求参数key的名称要和POJO中属性的名称一致,否则无法封装。
数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型即可接收参数
1 //数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中 2 @RequestMapping("/arrayParam") 3 @ResponseBody 4 public String arrayParam(String[] likes){ 5 System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes)); 6 return "{'module':'array param'}"; 7 }
1 //集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据 2 @RequestMapping("/listParam") 3 @ResponseBody 4 public String listParam(@RequestParam List<String> likes){ 5 System.out.println("集合参数传递 likes ==> "+ likes); 6 return "{'module':'list param'}"; 7 }
json普通数组(["","","",...])
json对象({key:value,key:value,...})
json对象数组([{key:value,...},{key:value,...}])
传递json普通数组
1.添加json数据转换相关坐标
1 <dependency> 2 <groupId>com.fasterxml.jackson.core</groupId> 3 <artifactId>jackson-databind</artifactId> 4 <version>2.9.0</version> 5 </dependency>
2.设置发送json数据(请求body中添加json数据)
3.开启自动转换json数据的支持
1 @Configuration 2 @ComponentScan("com.test.controller") 3 //开启json数据类型自动转换 4 @EnableWebMvc 5 public class SpringMvcConfig { 6 }
注:@EnableWebMvc注解功能强大,该注解整合了多个功能,此处仅使用其中一部分功能,即json数据进行自动类型转换。
4.在Controller中编写方法接收json参数
1 //集合参数:json格式 2 //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc 3 //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据 4 @RequestMapping("/listParamForJson") 5 @ResponseBody 6 public String listParamForJson(@RequestBody List<String> likes){ 7 System.out.println("list common(json)参数传递 list ==> "+likes); 8 return "{'module':'list common for json param'}"; 9 }
1 //POJO参数:json格式 2 //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc 3 //2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应 4 @RequestMapping("/pojoParamForJson") 5 @ResponseBody 6 public String pojoParamForJson(@RequestBody User user){ 7 System.out.println("pojo(json)参数传递 user ==> "+user); 8 return "{'module':'pojo for json param'}"; 9 }
1 //集合参数:json格式 2 //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc 3 //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应 4 @RequestMapping("/listPojoParamForJson") 5 @ResponseBody 6 public String listPojoParamForJson(@RequestBody List<User> list){ 7 System.out.println("list pojo(json)参数传递 list ==> "+list); 8 return "{'module':'list pojo for json param'}"; 9 }
@RequestBody与@RequestParam区别
区别:
@RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
@RequestBody用于接收json数据【application/json】
应用:
后期开发中,发送json格式数据为主,@RequestBody应用较广
如果发送非json格式数据,选用@RequestParam接收请求参数
名称:@DateTimeFormat
类型:形参注解
位置:SpringMVC控制器方法形参前面
作用:设定日期时间型数据格式
属性:pattern:日期时间格式字符串
1 //使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd 2 @RequestMapping("/dataParam") 3 @ResponseBody 4 public String dataParam(Date date, 5 @DateTimeFormat(pattern="yyyy-MM-dd") Date date1, 6 @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){ 7 System.out.println("参数传递 date ==> "+date); 8 System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1); 9 System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2); 10 return "{'module':'data param'}"; 11 }
1 public interface Converter<S, T> { 2 @Nullable 3 T convert(S var1); 4 }
请求参数年龄数据(String→Integer)
json数据转对象(json → POJO)
日期格式转换(String → Date)
注:传递日期类型参数必须在配置类上使用@EnableWebMvc注解。其功能之一:根据类型匹配对应的类型转换器。
响应
1 @Controller 2 public class UserController { 3 //响应页面/跳转页面 4 //返回值为String类型,设置返回值为页面名称,即可实现页面跳转 5 @RequestMapping("/toJumpPage") 6 public String toJumpPage(){ 7 System.out.println("跳转页面"); 8 return "page.jsp"; 9 } 10 }
page.jsp:
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>Title</title> 5 </head> 6 <body> 7 <h2>Hello Spring MVC!</h2> 8 </body> 9 </html>
1 //响应文本数据 2 //返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解 3 @RequestMapping("/toText") 4 @ResponseBody 5 public String toText(){ 6 System.out.println("返回纯文本数据"); 7 return "response text"; 8 }
1 //响应POJO对象 2 //返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解 3 @RequestMapping("/toJsonPOJO") 4 @ResponseBody 5 public User toJsonPOJO(){ 6 System.out.println("返回json对象数据"); 7 User user = new User(); 8 user.setName("itcast"); 9 user.setAge(15); 10 return user; 11 }
对象集合转json数组
1 //响应POJO集合对象 2 //返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解 3 @RequestMapping("/toJsonList") 4 @ResponseBody 5 public List<User> toJsonList(){ 6 System.out.println("返回json集合数据"); 7 User user1 = new User(); 8 user1.setName("张三"); 9 user1.setAge(15); 10 11 User user2 = new User(); 12 user2.setName("李四"); 13 user2.setAge(12); 14 15 List<User> userList = new ArrayList<User>(); 16 userList.add(user1); 17 userList.add(user2); 18 19 return userList; 20 }
注:需要添加jackson-databind依赖以及在SpringMvcConfig配置类上添加@EnableWebMvc注解
工作原理
类型转换器:HttpMessageConverter接口
1 public interface HttpMessageConverter<T> { 2 boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); 3 boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); 4 List<MediaType> getSupportedMediaTypes(); 5 T read(Class<? extends T> clazz, HttpInputMessage inputMessage) 6 throws IOException, HttpMessageNotReadableException; 7 void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) 8 throws IOException, HttpMessageNotWritableException; 9 }
最终实现类:MappingJackson2HttpMessageConverter,依赖jackson-databind坐标。需要添加jackson-databind依赖才能实现转换。
REST(Representational State Transfer),表现形式状态转换。
传统风格资源描述形式:
http://localhost/user/getById?id=1
http://localhost/user/saveUser
REST风格描述形式:
http://localhost/user/1
http://localhost/user
优点:
隐藏资源的访问行为,无法通过地址得知对资源是何种操作。
书写简化。
RESTful介绍
按照REST风格访问资源时使用行为动作区分对资源进行了何种操作。
http://localhost/users 查询全部用户信息 GET(查询)
http://localhost/users/1 查询指定用户信息 GET(查询)
http://localhost/users 添加用户信息 POST(新增/保存)
http://localhost/users 修改用户信息 PUT(修改/更新)
http://localhost/users/1 删除用户信息 DELETE(删除)
根据REST风格对资源进行访问称为RESTful。
注:
上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范。
描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts……
1 @Controller 2 public class UserController { 3 4 //设置当前请求方法为POST,表示REST风格中的添加操作 5 @RequestMapping(value = "/users",method = RequestMethod.POST) 6 @ResponseBody 7 public String save(){ 8 System.out.println("user save..."); 9 return "{'module':'user save'}"; 10 } 11 12 //设置当前请求方法为DELETE,表示REST风格中的删除操作 13 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 14 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) 15 @ResponseBody 16 public String delete(@PathVariable Integer id){ 17 System.out.println("user delete..." + id); 18 return "{'module':'user delete'}"; 19 } 20 21 //设置当前请求方法为PUT,表示REST风格中的修改操作 22 @RequestMapping(value = "/users",method = RequestMethod.PUT) 23 @ResponseBody 24 public String update(@RequestBody User user){ 25 System.out.println("user update..."+user); 26 return "{'module':'user update'}"; 27 } 28 29 //设置当前请求方法为GET,表示REST风格中的查询操作 30 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 31 @RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET) 32 @ResponseBody 33 public String getById(@PathVariable Integer id){ 34 System.out.println("user getById..."+id); 35 return "{'module':'user getById'}"; 36 } 37 38 //设置当前请求方法为GET,表示REST风格中的查询操作 39 @RequestMapping(value = "/users",method = RequestMethod.GET) 40 @ResponseBody 41 public String getAll(){ 42 System.out.println("user getAll..."); 43 return "{'module':'user getAll'}"; 44 } 45 }
@RequestMapping
类型:方法注解
位置:SpringMVC控制器方法定义上方
作用:设置当前控制器方法请求访问路径
属性:
value(默认):请求访问路径
method:http请求动作,标准动作(GET/POST/PUT/DELETE)
@PathVariable
类型:形参注解
位置:SpringMVC控制器方法形参定义前面
作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应。
区别:
@RequestParam用于接收url地址传参或表单传参。
@RequestBody用于接收json数据。
@PathVariable用于接收路径参数,使用{参数名称}描述路径参数。
应用:
后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广。
如果发送非json格式数据,选用@RequestParam接收请求参数。
采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值。
问题1:每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高。
问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。
问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。
解决问题1:在Controller类上使用@RequestMapping定义共同的访问路径。
1 @Controller 2 @RequestMapping("/books") 3 public class BookController { 4 5 @RequestMapping(method = RequestMethod.POST) 6 public String save(@RequestBody Book book){ 7 System.out.println("book save..." + book); 8 return "{'module':'book save'}"; 9 } 10 @RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE) 11 public String delete(@PathVariable Integer id){ 12 System.out.println("book delete..." + id); 13 return "{'module':'book delete'}"; 14 } 15 @RequestMapping(method = RequestMethod.PUT) 16 public String update(@RequestBody Book book){ 17 System.out.println("book update..."+book); 18 return "{'module':'book update'}"; 19 } 20 @RequestMapping(value = "/{id}" ,method = RequestMethod.GET) 21 public String getById(@PathVariable Integer id){ 22 System.out.println("book getById..."+id); 23 return "{'module':'book getById'}"; 24 } 25 26 @RequestMapping(method = RequestMethod.GET) 27 public String getAll(){ 28 System.out.println("book getAll..."); 29 return "{'module':'book getAll'}"; 30 } 31 }
解决问题2:使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替@RequestMapping(method=RequestMethod.XXX)
名称:@GetMapping @PostMapping @PutMapping @DeleteMapping
类型:方法注解
位置:基于SpringMVC的RESTful开发控制器方法定义上方
作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求
属性:value(默认):请求访问路径
1 @Controller 2 @RequestMapping("/books") 3 public class BookController { 4 5 // @RequestMapping( method = RequestMethod.POST) 6 @PostMapping//使用@PostMapping简化Post请求方法对应的映射配置 7 public String save(@RequestBody Book book){ 8 System.out.println("book save..." + book); 9 return "{'module':'book save'}"; 10 } 11 12 // @RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE) 13 @DeleteMapping("/{id}") //使用@DeleteMapping简化DELETE请求方法对应的映射配置 14 public String delete(@PathVariable Integer id){ 15 System.out.println("book delete..." + id); 16 return "{'module':'book delete'}"; 17 } 18 19 // @RequestMapping(method = RequestMethod.PUT) 20 @PutMapping //使用@PutMapping简化Put请求方法对应的映射配置 21 public String update(@RequestBody Book book){ 22 System.out.println("book update..."+book); 23 return "{'module':'book update'}"; 24 } 25 26 // @RequestMapping(value = "/{id}" ,method = RequestMethod.GET) 27 @GetMapping("/{id}") //使用@GetMapping简化GET请求方法对应的映射配置 28 public String getById(@PathVariable Integer id){ 29 System.out.println("book getById..."+id); 30 return "{'module':'book getById'}"; 31 } 32 33 // @RequestMapping(method = RequestMethod.GET) 34 @GetMapping //使用@GetMapping简化GET请求方法对应的映射配置 35 public String getAll(){ 36 System.out.println("book getAll..."); 37 return "{'module':'book getAll'}"; 38 } 39 }
解决问题3:在Controller类上使用@RestController注解,等同于@Controller与@ResponseBody两个注解组合功能
名称:@RestController
类型:类注解
位置:基于SpringMVC的RESTful开发控制器类定义上方
作用:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能
1 @RestController //使用@RestController注解替换@Controller与@ResponseBody注解,简化书写 2 @RequestMapping("/books") 3 public class BookController { 4 ...//方法省略 5 }
使用WebMvcConfigurationSupport添加资源过滤:
1 @Configuration 2 public class SpringMvcSupport extends WebMvcConfigurationSupport { 3 //设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载 4 @Override 5 protected void addResourceHandlers(ResourceHandlerRegistry registry) { 6 //当访问/pages/????时候,从/pages目录下查找内容 7 registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); 8 registry.addResourceHandler("/js/**").addResourceLocations("/js/"); 9 registry.addResourceHandler("/css/**").addResourceLocations("/css/"); 10 } 11 }
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。
作用:
1.在指定的方法调用前后执行预先设定的代码。
2.阻止原始方法的执行。
归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术。
拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强。
1 @Component //注意当前类必须受Spring容器控制 2 //定义拦截器类,实现HandlerInterceptor接口 3 public class ProjectInterceptor implements HandlerInterceptor { 4 @Override 5 //原始方法调用前执行的内容 6 //返回值类型可以拦截控制的执行,true放行,false终止 7 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 8 System.out.println("preHandle..."+contentType); 9 return true; 10 } 11 12 @Override 13 //原始方法调用后执行的内容 14 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 15 System.out.println("postHandle..."); 16 } 17 18 @Override 19 //原始方法调用完成后执行的内容 20 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 21 System.out.println("afterCompletion..."); 22 } 23 }
定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置);添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个:
1 @Configuration 2 public class SpringMvcSupport extends WebMvcConfigurationSupport { 3 @Autowired 4 private ProjectInterceptor projectInterceptor; 5 6 @Override 7 protected void addInterceptors(InterceptorRegistry registry) { 8 //配置拦截器 9 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); 10 } 11 }
另:可使用标准接口WebMvcConfigurer简化开发(缺点:该方法侵入式较强,直接与Spring强绑定)
1 @Configuration 2 @ComponentScan({"com.test.controller"}) 3 @EnableWebMvc 4 //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性 5 public class SpringMvcConfig implements WebMvcConfigurer { 6 @Autowired 7 private ProjectInterceptor projectInterceptor; 8 9 @Override 10 public void addInterceptors(InterceptorRegistry registry) { 11 //配置多拦截器 12 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); 13 } 14 }
1 //原始方法调用前执行的内容 2 //返回值类型可以拦截控制的执行,true放行,false终止 3 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 4 System.out.println("preHandle..."+contentType); 5 return true; 6 }
参数:
request:请求对象
response:响应对象
handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
返回值:返回值为false,被拦截的处理器将不执行
1 //原始方法调用后执行的内容 2 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 3 System.out.println("postHandle..."); 4 }
参数:modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整。
注意:如果处理器方法出现异常了,该方法不会执行。
1 //原始方法调用完成后执行的内容 2 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 3 System.out.println("afterCompletion..."); 4 }
参数:ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理。
1 @Configuration 2 @ComponentScan({"com.test.controller"}) 3 @EnableWebMvc 4 //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性 5 public class SpringMvcConfig implements WebMvcConfigurer { 6 @Autowired 7 private ProjectInterceptor projectInterceptor; 8 @Autowired 9 private ProjectInterceptor2 projectInterceptor2; 10 11 @Override 12 public void addInterceptors(InterceptorRegistry registry) { 13 //配置多拦截器 14 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); 15 registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*"); 16 } 17 }
当配置多个拦截器时,形成拦截器链。
拦截器链的运行顺序参照拦截器添加顺序为准。
当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行。
当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作。