详细的描述了SpringMVC中的请求与响应

SpringMVC概述

SpringMVC是一种基于Java实现MVC模型的轻量级web框架

优点

  • 使用简单,开发便捷(相比于Servlet)
  • 灵活性强

样例

样例代码

  1. 使用SpringMVC技术需要先导入SpringMIVC坐标与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>
  1. 创建SpringMvc控制器类(等同于servlet功能)
// 2.定义Controller
// 2.1 使用Controller定义Bean
@Controller
public class UserController {
// 2.2 设置当前操作的访问路径
@RequestMapping("/save")
// 2.3 设置当前操作的返回值类型
@ResponseBody
public String save(){
System.out.println("user save...");
return "{'moudle' : 'springmvc'}";
}
}
  1. 初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean
// 3.创建springmvc的配置文件,加载controller对应的Bean
@Configuration
@ComponentScan("com.wang.controller")
public class SpringMvcConfig {
}
  1. 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求
// 4.定义一个Servlet容器启动的配置类,在里面加载spring的配置
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {

//加载springmvc容器配置
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}

//设置哪些请求归属springmvc处理
protected String[] getServletMappings() {
return new String[]{"/"};
}

//加载spring容器配置
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}

上述案例中用到的注解说明:

  • @Controller

类注解,放置于SpringMVC控制器定义上方,作用为设定SpringMVC的核心控制器Bean

  • @RequestMapping

方法注解,放置于SpringMVC控制器方法上方,作用为设定当前控制器方法的请求访问路径

  • @ResponseBody

方法注解,放置于SpringMVC控制器方法上方,作用为设置当前控制器方法的响应内容为当前返回值,无需解析

  • @ComponentScan

属性1:excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)

属性2:includeFilters:加载指定的bean,需要指定类别(type)与具体项(classes)

SpringMVC入门程序开发总结(1+N)

  • 一次性工作
    • 创建工程,设置服务器,加载工程
    • 导入坐标
    • 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径
    • SpringMvc核心配置类(设置配置类,扫描controller包,加载Controller控制器bean)
  • 多次工作
    • 定义处理请求的控制器类
    • 定义处理请求的控制器方法,并配置映射路径(@RequestMapping)与返回json数据(@ResponseBody)

工作流程

启动服务器初始化过程

  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()方法的返回值作为响应求体返回给请求方

问题

因为功能不同,如何避免Spring错误的加载到SpringMVC的bean?

加载Spring控制的bean的时候排除掉SpringMVC控制的bean

SpringMIVC相关bean(表现层bean)

Spring控制的bean

  • 业务bean (Service)
  • 功能bean (DataSource等)

SpringMVC相关bean加载控制

  • SpringMVC加载的bean对应的包均在com.xxx.controller包内

Spring相关bean加载控制

  • 方式一:Spring加载的bean设定扫描范围为com.xxx,排除掉controller包内的bean
  • 方式二: Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中

方式一如下:

@ComponentScan(value = "com.wang",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
))

方式二如下:

@ComponentScan({"com.wang.service", "com.wang.dao"})

注意:简化开发代码如下:

public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

请求

设置请求的映射路径

团队多人开发,每人设置不同的请求路径,冲突问题如何解决?

设置模块名作为请求路径前缀

@RequestMapping(“/xxx”)

当写在类上方时,即为统计设置请求路径的前缀,类方法中的@RequestMapping会自动加上前缀

PostMan发送get请求和post请求

get请求

普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数

post请求

普通参数:form表单post请求传参,表单参数名与形参变量名相同,定义形参即可接收参数

post请求中文乱码问题:

为web容器添加过滤器并指定字符集,Spring-web包中提供了专用的字符过滤器

//乱码处理
@override
protected Filter[] getServletFilters(){
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[](filter);
}

参数种类

若传入的属性名与实体类中的属性名一致,则会自动放入实体类中

样例代码:

//请求参数
@Controller
public class UserController {

//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通参数传递 name ==> "+name);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param'}";
}

//普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(@RequestParam("name") String userName , int age){
System.out.println("普通参数传递 userName ==> "+userName);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param different name'}";
}

//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}

//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
return "{'module':'pojo contain pojo param'}";
}

//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}

//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}


//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}

//POJO参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("pojo(json)参数传递 user ==> "+user);
return "{'module':'pojo for json param'}";
}

//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("list pojo(json)参数传递 list ==> "+list);
return "{'module':'list pojo for json param'}";
}

//日期参数
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
System.out.println("参数传递 date ==> "+date);
System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
return "{'module':'data param'}";
}
}

总结

普通的形参

若形参与请求参数名称相同,则会自动绑定

@RequestParam

可以绑定请求参数与处理器方法形参之间的关系

参数:required:是否为必传参数 defaultValue:参数默认值

Pojo参数

请求参数名与形参对象属性名相同,定义PO30类型形参即可接收参数

嵌套的Pojo参数

请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJo属性参数

数组参数

请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数

集合保存普通参数

请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系

json 数据参数

四个步骤:

  1. pom.xml中添加json坐标
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
  1. 主配置类中加入注解

@EnableWebMvc

开启由json对象装换位对象的功能

  1. postman中传入参数
  2. 在参数前面加上@RequestBody
  • json数组
["game","music","hobby"]
  • json对象(Pojo)
{
"name":"wang",
"age":15,
"address":{
"province":"beijing",
"city":"beijing"
}
}
  • json数组(Pojo)
[
{"name":"wang","age":9},
{"name":"nine","age":99}
]

@RequestBody与@RequestParam区别

  • 区别

    • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】

    • @RequestBody用于接收json数据【application/json】

  • 应用

    • 后期开发中,发送json格式数据为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@Requestparam接收请求参数

日期格式参数

@DateTimeFormat(patter=“yyyy-MM-dd”)

指定日期的格式

类型转换器

  • Convert接口
public interface Converter<S, T> {
@Nullable
T convert(S var1);
}

响应

  • 响应页面
  • 响应数据
    • 文本数据
    • json数据

样例代码:

@Controller
public class UserController {

//响应页面/跳转页面
//返回值为String类型,设置返回值为页面名称,即可实现页面跳转
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}

//响应文本数据
//返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解
@RequestMapping("/toText")
@ResponseBody
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}

//响应POJO对象
//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}

//响应POJO集合对象
//返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList(){
System.out.println("返回json集合数据");
User user1 = new User();
user1.setName("Tom");
user1.setAge(15);

User user2 = new User();
user2.setName("Jerry");
user2.setAge(12);

List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);

return userList;
}
}

@ResponseBody

方法注解,SpringMVC控制器方法定义上方,设置当前控制器方法响应内容为当前返回值,无需解析

内部是由类型转换器 HttpMessageConverter 接口发挥作用