文章目录
SpringMVC学习笔记(一)- 请求与响应
SpringMVC环境搭建及工作原理描述
-
使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标
<!-- 导入坐标springmvc 与 servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency>
-
创建SpringMVC控制器类(与Servlet功能等效)
/** * 1.定义Controller * 2.使用@Controller 定义 bean */ @Controller public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(){ System.out.println("user save ..."); return "{'module':'springmvc'}"; } }
-
初始化SpringMVC(同Spring环境),设定SpringMVC加载对应的bean
//创建springmvc的配置文件,加载controller对应的bean @Configuration @ComponentScan("com.itheima.controller") public class SpringMvcConfig { }
-
初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求(注意要在pom.xml文件导入tomcat坐标,同时添加tomcat的插件)
//定义一个servlet容器启动的配置类,在里面加载spring的配置 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { //加载springMVC容器配置 protected WebApplicationContext createServletApplicationContext() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } //设置哪些请求归属SpringMVC处理 protected String[] getServletMappings() { return new String[]{"/"}; } //加载spring容器配置 protected WebApplicationContext createRootApplicationContext() { return null; } }
启动服务器初始化过程
- 服务器启动,执行ServletContainersInitConfig类,初始化web容器;
- 执行createServletApplicationContext方法,创建了WebApplicationContext对象
- 加载SpringMvcConfig
- 执行
@ComponentScan
加载对应的bean - 加载UserController,每个
@RequestMapping
的名称对应一个具体的方法 - 执行getServletMappings方法,定义所有的请求都通过SpringMVC
单次请求过程
- 发送请求localhost/save
- web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
- 解析请求路径/save
- 由/save匹配执行对应的方法save()
- 执行save()
- 检测到有
@ResponseBody
直接将save()方法的返回值作为响应请求体返回给请求方;
Bean加载控制
问题引入:因为功能不同,如何避免Spring错误的加载到SpringMVC的bean
解决方案:
-
类注解方式:
//创建springmvc的配置文件,加载controller对应的bean /** * excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes) * includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes) */ @Configuration @ComponentScan(value="com.itheima.controller", excludeFilters=@ComponentScan.Filter( type=FilterType.ANNOTATION, classes=Controller.class ) ) public class SpringConfig { }
-
bean的加载格式
//定义一个servlet容器启动的配置类,在里面加载spring的配置 public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { //加载springMVC容器配置 protected WebApplicationContext createServletApplicationContext() { //初始化WebApplicationContext对象 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //加载指定配置类 ctx.register(SpringMvcConfig.class); return ctx; } //加载spring容器配置 protected WebApplicationContext createRootApplicationContext() { //初始化WebApplicationContext对象 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //加载指定配置类 ctx.register(SpringConfig.class); return ctx; } //设置哪些请求归属SpringMVC处理 protected String[] getServletMappings() { return new String[]{"/"}; } }
-
简化开发
public class ServletContainersInitConfig extends AbstractAnnotationDispatcherServletInitializer { protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }
请求与响应
请求映射路径
- 团队多人开发,由于每个人设置不同的请求路径会出现冲突路径,提出设置模块名作为请求路径前缀
- 解决方案:设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀
@RequestMapping("/book") @Controller public class BookController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("book save ..."); return "{'module':'save'}"; } }
参数传递类型
普通参数
GET请求
- 在对应Controller类中的函数添加参数
@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(String name,String age){ System.out.println("username:"+name+", age:"+age); return "{'module':'springmvc'}"; } }
- 普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数
POST请求
-
普通参数:form表单post请求形参,表单参数与形参变量名相同,定义形参即可接收参数
-
在对应Controller类中的函数添加参数
@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(String name,String age){ System.out.println("username:"+name+", age:"+age); return "{'module':'springmvc'}"; } }
-
【注意】:Post请求中文乱码处理方法
在ServletContainersInitConfig类中,复写getServletFilters函数。为web容器添加过滤器并指定字符集,Spring-web包中提供了专用的字符过滤器@Override protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("utf-8"); return new Filter[]{filter}; }
普通参数请求参数名与形参数名不同的情况,我们通常可以用@RequestParam
解决
@Controller
@RequestMapping("/user")
public class UserController {
//设置当前操作的访问路径
@RequestMapping("/save")
//设置当前操作的返回类型
@ResponseBody
public String save(@RequestParam("name") String username, String age){
System.out.println("username:"+username+", age:"+age);
return "{'module':'springmvc'}";
}
}
POJO类型参数
- 请求参数名与形参属性名相同,定义POJO类型形参即可接收参数
- 在对应Controller中的函数添加pojo参数
@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(User user){ System.out.println("pojo参数传递" + user); return "{'module':'springmvc'}"; } }
- POST MAN 接口测试
嵌套POJO类型参数
- 嵌套POJO参数:POJO对象中包含POJO对象
public class User { private String name; private int age; private Address address;//嵌套的对象 public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", address=" + address + '}'; } }
- POST MAN 接口测试
数组类型参数
- 请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(String[] hobbies){ System.out.println("数组参数传递" + Arrays.toString(hobbies)); return "{'module':'springmvc'}"; } }
- POST MAN 接口测试
集合类型参数
- 请求参数名与形参集合对象名相同且请求参数为多个,
@RequestParam
绑定参数关系@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(@RequestParam List<String> hobbies){ System.out.println("集合参数传递" + hobbies); return "{'module':'springmvc'}"; } }
- POST MAN 接口测试
响应json数据(开发常见的方式)
-
在pom.xml文件中导入处理json格式的依赖坐标
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency>
-
在核心配置中添加注解
@EnableWebMvc
,开启自动转换json数据的支持//创建springmvc的配置文件,加载controller对应的bean @Configuration @ComponentScan("com.itheima.controller") @EnableWebMvc public class SpringMvcConfig { }
-
在POST MAN接口测试中选择如下选项(确定传递的数据为JSON格式)
-
在Controller对应的函数的形参中添加
@ReuestBody
注解 -
传递json数组:
@Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(@RequestBody List<String> hobbies){ System.out.println("json格式数组参数传递" + hobbies); return "{'module':'springmvc'}"; } }
-
传递json对象
/** * { * "name":"xukun cai", * "age":22 * } */ @Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(@RequestBody User user){ System.out.println("json对象格式参数传递" + user); return "{'module':'springmvc'}"; } }
-
传递json对象数组
/** * [ * { * "name":"xukun cai", * "age":22 * }, * { * "name":"fengjie", * "age":50 * } * ] */ @Controller @RequestMapping("/user") public class UserController { //设置当前操作的访问路径 @RequestMapping("/save") //设置当前操作的返回类型 @ResponseBody public String save(@RequestBody User[] user){ System.out.println("json格式对象数组参数传递" + Arrays.toString(user)); return "{'module':'springmvc'}"; } }
日期类型参数传递
- 日期类型数据基于系统不同格式也不近相同,如:
- 2000-12-31
- 2000/12/31
- 12/31/2000
- 接收型参时,根据不同的日期格式设置不同的接收方式,使用
@DateTimeFormate
注解@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/update") @ResponseBody public String update(Date date1, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2, @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3){ System.out.println("参数传递 date1 ==>" + date1); System.out.println("参数传递 date2(yyyy-MM-dd) ==>" + date2); System.out.println("参数传递 date3(yyyy/MM/dd HH:mm:ss) ==>" + date3); return "{'module':'update'}"; } }
响应
响应JSON数据(对象转JSON)
-
【注意】:一定要导入jackson-core这个依赖坐标,否则是无法实现对象转JSON格式
-
响应JSON数据(对象转JSON)
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/add") @ResponseBody public User add(){ User user = new User(); user.setName("赵云"); user.setAge(30); return user; } }
-
响应JSON数据(对象转JSON数组)
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/insert") @ResponseBody public List<User> insert(){ User user1 = new User(); User user2 = new User(); user1.setName("马云"); user1.setAge(58); user2.setName("马化腾"); user2.setAge(51); List<User> user = new ArrayList<User>(); user.add(user1); user.add(user2); return user; } }
-
实验结果分析:通常需要在Controller类对应的函数中添加
@ResponseBody
注解,其作用是设置当前控制器返回值作为响应体