SpringMVC-day01
SpringMVC,底层是把Servlet、Filter、Listener 再次封装
课程内容
- SpringMVC介绍
- 请求与响应
- RESTful风格请求交互
- SSM整合(注解版)
- 拦截器
学习目标
- 掌握基于SpringMVC获取请求参数与响应json数据操作
- 熟练应用基于REST风格的请求路径设置与参数传递
- 能够根据实际业务建立前后端开发通信协议并进行实现
- 基于SSM整合技术开发任意业务模块功能
01_SpringMVC基本概念
目标
- 了解SpringMVC框架在三层架构存在的意义
路径
- 三层架构
- MVC模型
- 请求响应模型演化过程
- SpringMVC概述
三层架构
表现层:WEB层,用来和客户端(浏览器)进行数据交互的。表现层一般会采用MVC的设计模型
业务层:处理公司具体的业务逻辑的
持久层:用来操作数据库的
MVC架构
MVC(Model View Controller):
- Model(模型):负责封装应用的状态,并实现应用的功能。通常分为:数据模型、业务逻辑模型
- View(视图):页面视图,用于展示数据 (因为开发中前后端分离了,这块内容后端技术人员接触少了)
- Controller(控制器):处理用户交互的调度器,用于根据用户需求处理程序逻辑
请求响应模型演化过程
web阶段:
同步场景下的SpringMVC:
异步场景下的SpringMVC:
SpringMVC概述
SpringMVC是一种基于Java实现的MVC模型的轻量级Web框架
-
底层基于Spring (IOC和AOP)
-
封装了web三大组件(Servlet,Filter,Listener)
SpringMVC的优点:
- 使用简单,开发便捷(相比于Servlet)
- 灵活性强
02_SpringMVC入门
目标
- 能够搭建SpringMVC程序并接收请求
路径
- SpringMVC开发步骤
- SpringMVC入门代码
SpringMVC开发步骤
使用SpringMVC开发的步骤:
- 导入坐标(SpringMVC依赖、Servlet依赖)
- 创建SpringMVC控制器类(等同于Servlet)
- 初始化SpringMVC环境 【没有web.xml文件、没有@WebServlet注解了】
- 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC请求拦截的路径
SpringMVC入门代码
案例工程目录:
代码示例:
- 导入坐标(SpringMVC依赖、Servlet依赖)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_day01-quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- 依赖管理 -->
<dependencies>
<!-- Servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- SpringMVC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
</project>
- 创建SpringMVC控制器类(等同于Servlet)
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//定义表现层控制器bean
@Controller
public class UserController {
@RequestMapping("/save") //让请求的路径[/save]映射到目标方法上
@ResponseBody //设置当前操作返回结果为字符串
public String save(){
System.out.println("保存用户...");
return "success";
}
}
- 初始化SpringMVC环境
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//springmvc配置类,本质上还是一个spring配置类
@Configuration
@ComponentScan("com.itheima.controller") //指定要扫描的包
public class SpringmvcConfig {
}
- 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC请求拦截的路径
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
//web容器配置类
//AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
@Override
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//加载指定配置类
ctx.register(SpringmvcConfig.class);
return ctx;
}
//设置由springmvc控制器处理的请求映射路径
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring配置类
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
测试:将项目部署到tomcat,使用浏览器测试请求
@Controller注解
- 作用:设置SpringMVC的核心控制器bean
@Controller //指定UserController类为表现层的控制器bean
public class UserController {
}
@RequestMapping注解
- 作用:让请求的路径映射到控制器类中的方法上
@Controller
public class UserController {
@RequestMapping("/save") //让请求的路径[/save]映射到目标方法上
public String save(){
return "success";
}
}
@ResponseBody注解
- 作用:设置当前控制器方法响应体内容为当前返回值(无需解析)
@Controller
public class UserController {
@RequestMapping("/save")
@ResponseBody //设置当前操作返回结果为字符串
public String save(){
return "success";
}
}
03_使用SPI机制创建Servlet
目标
- 了解Servlet中的SPI机制
路径
- SPI介绍
- ServletContainerInitializer
SPI介绍
SPI全称:Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。
Java SPI 基于 “接口编程+策略模式+配置文件(约定)”组合实现的动态加载机制。
Java的SPI机制就是将一些类信息写在约定的文件中,然后由特定的类加载器加载解析文件获取资源。
-
约定的配置文件
配置文件必须存放在:META-INF/services目录下
-
特定的类加载器
java.util.ServiceLoader类 (类加载器) ServiceLoader.load(Class cls) //示例:ServiceLoader.load(接口.class) 在ServiceLoader.load的时候,根据传入的接口类,遍历META-INF/services目录下的以该接口命名的文件中的所有类,并实例化返回
ServletContainerInitializer
ServletContainerInitializer是Servlet3.0新增的一个接口,主要用于在web容器(Tomcat)启动阶段通过编程风格注册Filter、Servlet、Listener,以取代通过web.xml配置注册。这样就利于开发内聚的web应用框架。
- 简单来讲:就是不需要在web项目工程中使用web.xml文件了
约定文件:
- 要求:
- 必须存放在META-INF/services目录下
- 使用接口的全限定名作为配置文件名
#javax.servlet.ServletContainerInitializer接口的实现类
com.itheima.config.MyServletContainerInitializer
实现类:
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println("start..........................");
MyServlet myServlet = new MyServlet();
ctx.addServlet("myServlet", myServlet).addMapping("/myServlet");
}
}
Servlet类:
public class MyServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello SPI");
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
运行原理:
-
ServletContainerInitializer接口的实现类通过Java SPI声明自己是ServletContainerInitializer的provider
-
web容器启动阶段依据java spi获取到所有ServletContainerInitializer的实现类,然后执行其onStartup方法
-
在onStartup中通过编码方式将组件Servlet加载到ServletContext
小结
- 由于Servlet3.0提供了SPI机制,所以web工程可以不用xml和注解配置
04_入门案例的执行过程分析
目标
- 能够说出SpringMVC执行过程
路径
- 简易版SpringMVC执行过程分析
- 详解版SpringMVC执行过程分析
所谓的Tomcat就是一个:ServerSocket程序(在学习Java运行ServerSocket程序是通过main方法执行)
Web工程和Java工程的区别:
- 打包方式: java工程是jar包,web工程是war包
- 运行方式:java工程是直接通过main方法运行,web工程的main方法是在web容器中
- web工程必须要部署在web容器(如:Tomcat)上才能运行
简易版SpringMVC执行过程分析
SpringMVC加载机制:
- Tomcat => ServletContainerInitConfig => SpringmvcConfig => UserController
- Tomcat: web容器
- ServletContainerInitConfig: web容器配置类(SPI机制)
- SpringmvcConfig: SpringMVC配置类
- UserController:表现层的控制器类(等同于Servlet)
- 执行顺序:
- Tomcat根据SPI机制加载ServletContainerInitConfig类
- ServletContainerInitConfig类中方法执行
- SpringmvcConfig类加载(由ServletContainerInitConfig类中方法运行时加载)
- UserController类被SpringmvcConfig类扫描到并加载
详解版SpringMVC执行过程分析
SpringMVC加载机制:Tomcat => ServletContainerInitConfig => SpringmvcConfig => UserController
- Tomcat
- tomcat的main方法执行时,根据SPI机制加载ServletContainerInitConfig类
- spring-web.jar下有META-INF/services/javax.servlet.ServletContainerInitializer文件
- 此文件中配置实现类 org.springframework.web.SpringServletContainerInitializer
- SpringServletContainerInitializer类会被Tomcat所加载(SPI机制),此类上的有个注解配置,指定要加载的类型
- @HandlesTypes({WebApplicationInitializer.class})
- WebApplicationInitializer接口的所有实现类都会被加载
- 入门案例中的ServletContainerInitConfig类就是WebApplicationInitializer接口的实现类
- tomcat的main方法执行时,根据SPI机制加载ServletContainerInitConfig类
- ServletContainerInitConfig(web容器配置类)
- createServletApplicationContext方法运行,加载springmvc配置类
- getServletMappings方法运行,给DispatcherServlet类设置访问路径为
/
(表示拦截所有)
- SpringmvcConfig(SpringMVC配置类)
- @ComponentScan("com.itheima.controller")
- springmvc底层开始扫描:com.itheima.controller包
- @ComponentScan("com.itheima.controller")
- UserController(控制器)[等同于Servlet]
- @Controller : 表示此bean会添加到springmvc的ioc容器
- @RequestMapping("/save") : 设置访问路径和目标方法的映射
- @ResponseBody : 方法的的返回值将会通过响应体返回给前端
05_SpringMVC的请求过程
目标
- 了解SpringMVC架构的请求过程
路径
- SpringMVC的请求过程
SpringMVC的请求过程
请求:
- 浏览器(前端)
- 发送请求:
http://localhost:8080/save
- 发送请求:
- 服务器(后端)
- Tomcat接收到请求
- 请求交给DispatcherServlet处理
- DispatcherServlet设置的请求路径为:
/
(所有请求)
- DispatcherServlet设置的请求路径为:
- DispatherServlet找到
/save
对应的控制器方法:UserController类中的save()方法 - 执行UserController类中的save()方法,并把save()方法执行后的结果,通过响应体返回给前端
06_RequestMapping注解
目标
- 能够使用RequestMapping注解建立请求路径和目标方法的映射
路径
- RequestMapping注解介绍
- RequestMapping注解书写位置
- RequestMapping注解常用属性
RequestMapping注解介绍
RequestMapping注解,用于建立请求路径与目标方法的对应关系
RequestMapping注解书写位置
@RequestMapping书写位置:
-
类上
窄化路径。访问类中的方法时,必须加上类上定义的请求路径
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/save") @ResponseBody public String save(){ return "save success"; } }
请求:http://localhost:8080/user/save
-
方法
建立请求资源路径与方法的直接对应关系
@Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(){ return "save success"; } }
请求:http://localhost:8080/save
RequestMapping注解常用属性
常用属性:
- value 或 path:指定访问路径
- method:限定请求方式(restful风格)
- 不写,默认什么请求方式都可以
- 指定了请求方式后,如果不匹配就会响应405状态码
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(path = "/save",method = RequestMethod.GET)
@ResponseBody
public String save(){
return "save success";
}
@RequestMapping(value = "/save",method = RequestMethod.POST)
@ResponseBody
public String saveUser(){
return "save success";
}
}
GET请求方式:( 类似Servlet中的doGet方法 )
http://localhost:8080/user/save
POST请求方式:( 类似Servlet中的doPost方法 )
http://localhost:8080/user/save
07_练习:搭建SpringMVC环境
SpringMVC开发步骤:
- 导入坐标(SpringMVC依赖、Servlet依赖)
- 创建SpringMVC控制器类(等同于Servlet)
- 创建SpringMVC配置类(初始化SpringMVC环境)
- 创建Web容器配置类
- 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC请求拦截的路径
代码示例:
- SpringMVC控制器类
@Controller
@RequestMapping("/role")
public class RoleController {
@RequestMapping(value = "/save", method = RequestMethod.GET)
@ResponseBody
public String save(){
System.out.println("RoleController save...");
return "save success";
}
@RequestMapping(path = "/delete", method = RequestMethod.POST)
@ResponseBody
public String delete(){
System.out.println("RoleController delete...");
return "delete success";
}
}
- SpringMVC配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringmvcConfig {
}
- Web容器配置类
- 使用AbstractDispatcherServletInitializer的子类简化SpringMVC的容器配置类
- 子类:AbstractAnnotationConfigDispatcherServletInitializer
- 使用AbstractDispatcherServletInitializer的子类简化SpringMVC的容器配置类
//web容器配置类
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//加载SpringMVC配置
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringmvcConfig.class};
}
//设置由springmvc控制器处理的请求映射路径
@Override
protected String[] getServletMappings() {
return new String[]{"/"};//SpringMVC控制器处理所有的请求
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
}
08_SpringMVC的请求处理
目标
- 了解SpringMVC的请求处理方式
路径
- SpringMVC的请求处理介绍
SpringMVC的请求处理介绍
SpringMVC主要应用在三层架构中的表现层(web层)。作用就是:
-
接收请求
-
业务处理(交给业务层)
-
响应数据
SpringMVC的请求处理可以分为两大类:
-
同步请求(前后端不分离)
-
请求参数通常以url格式为主
GET :http://localhost:8080/save?username=itheima&password=123 POST :http//localhost:8080/save 请求体:username=itheima&password=123
-
特点:同步请求的响应内容会刷新整个网页
-
响应:跳转页面
-
-
异步请求
- 请求参数通常有:url格式、json格式
- 特点:请求的响应内容只会让页页局部刷新
- 响应:字符串数据、json格式数据
SpringMvc对请求和响应进行了封装:
-
控制器类中的方法可以接收请求参数
-
请求携带以下类型的数据时SpringMVC会自动接收,并在解析之后传递给方法进行使用
- 基本数据类型、String
- pojo类型
- 数组类型
- 集合类型
-
使用方式:直接在方法上定义形参
@RequestMapping(value = "/login") @ResponseBody public String login(String username,String password){ return "login success"; }
- 注意:方法上的形参名称必须要和请求参数名称保持一致
URL格式的GET请求: http://localhost:8080/login?username=itheima&password=123
09_SpringMVC的url格式请求参数
目标
- 能够使用SpringMVC接收前端发送的url格式请求参数
路径
- 获取url格式的请求参数
获取url格式的请求参数
url格式的请求参数类型:
- 基本数据类型、String
- Pojo类型
- 数组类型
- 集合类型
代码示例:
- 控制器类
@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 "commonParam";
}
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "pojoParam";
}
//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
return "pojoContainPojoParam";
}
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "arrayParam";
}
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "listParam";
}
}
- Pojo类
public class Address {
private String province;//省份
private String city;//城市
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
public class User {
private String name;
private Integer age;
public Address address;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
使用postman工具,测试请求参数:
-
基本数据类型、String
@RequestMapping("/commonParam") @ResponseBody public String commonParam(String name ,int age){ System.out.println("普通参数传递 name ==> "+name); System.out.println("普通参数传递 age ==> "+age); return "commonParam"; }
- GET请求:url地址传参,请求参数名与方法形参变量名相同(定义形参即可接收参数)
- POST请求:form表单参数名与方法的形参变量名相同(定义形参即可接收参数)
-
Pojo类型
- 请求参数名与方法形参对象属性名相同(定义POJO类型形参即可接收参数)
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递 @RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "pojoParam"; }
- 嵌套POJO参数:请求参数名与形参对象属性名相同(按照对象层次结构关系即可接收嵌套POJO属性参数)
//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递 @RequestMapping("/pojoContainPojoParam") @ResponseBody public String pojoContainPojoParam(User user){ System.out.println("pojo嵌套pojo参数传递 user ==> "+user); return "pojoContainPojoParam"; }
-
数组类型
- 请求参数名与方法形参数组名相同且请求参数为多个(定义数组类型形参即可接收参数)
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中 @RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[] likes){ System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes)); return "arrayParam"; }
-
集合类型
- 请求参数名与形参集合对象名相同且请求参数为多个,使用@RequestParam绑定参数关系
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据 @RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List<String> likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "listParam"; }
小结
在前端发送请求参数时,只要保证请求参数名字和目标方法中接收数据的参数名一致,就可以实现:
- 请求参数映射到目标方法对应参数列表中
请求参数类型:
- 基础类型:8种基本类型、包装类、String
- 请求参数名字 和 方法中参数名 一致
- pojo类型:实体封装类
- 请求参数名字 和 实体类中属性名 一致
- 特殊:嵌套pojo
- 请求参数名格式: 对象名.成员变量名
- 数组类型:
- 请求参数名字 和 数组名 一致(请求参数名字相同,值有多个)
- 集合类型:
- 请求参数名字 和 集合对象名 一致(请求参数名字相同,值有多个)
- 要想要把请求参数映射到集合对象中,要使用:@RequestParam
10_SpringMVC的json格式请求参数
目标
- 能够使用SpringMVC接收前端发送的json格式请求参数
路径
- Json知识介绍
- SpringMVC接收json请求参数的步骤
- 获取json格式的请求参数
Json知识介绍
json格式数据:
- 对象 :
- 数组 :[ ]
json格式请求参数常见类型:
-
json对象
User {"name":"zs","age" : 18}
-
json数组
String[] ["a","b","c"]
-
json数组(POJO)
List<User> [{"name":"zs","age" : 18},{"name":"ls","age":19}]
Java中的json转换工具:
- FastJson
- JackSon (SpringMVC底层使用)
SpringMVC接收json请求参数的步骤
开发步骤:
-
导入坐标
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
-
开启json数据自动转换
//开启json数据类型自动转换 @EnableWebMvc
-
接收json数据:使用@RequestBody注解把json数据映射到方法形参上
public String pojoParamForJson(@RequestBody User user)
获取json格式的请求参数
代码示例:
- SpringMVC配置类
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc //@EnableWebMvc注解整合了多个功能,此处仅使用json数据进行自动类型转换
public class SpringmvcConfig {
}
- SpringMVC控制器类
@Controller
public class UserController {
//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 "pojoParamForJson";
}
//集合参数: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 "listParamForJson";
}
//集合参数: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 "listPojoParamForJson";
}
}
使用postman工具,测试请求参数:
-
POJO参数:json数据与形参对象属性名相同 (定义POJO类型形参即可接收参数)
@RequestMapping("/pojoParamForJson") @ResponseBody public String pojoParamForJson(@RequestBody User user){ System.out.println("pojo(json)参数传递 user ==> "+user); return "pojoParamForJson"; }
-
POJO集合参数:json数组数据与集合泛型属性名相同 (定义List类型形参即可接收参数)
@RequestMapping("/listPojoParamForJson") @ResponseBody public String listPojoParamForJson(@RequestBody List<User> list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "listPojoParamForJson"; }
关键API总结
- url格式请求参数
- @RequestParam (接收集合类型的参数)
- json格式请求参数
- @EnableWebMvc //开启webmvc功能(功能之一: 自动实现json和pojo转换)
- @RequestBody //在参数前面添加,用于接收json格式参数映射到pojo上
11_SpringMVC请求参数的特殊情况
目标
- 能够处理请求中存在的特殊情况:中文乱码、参数名不一致、日期格式
路径
- 请求参数名称不一致
- 编码过滤器
- 日期处理
请求参数名称不一致
当请求的参数名和目标方法中的形参名不一致时:控制器中的方法就不能接收请求数据
GET请求:http://localhost:8080/commonParam?name=itheima&age=20
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String username ,int userage){
System.out.println("普通参数传递 name ==> "+username);
System.out.println("普通参数传递 age ==> "+userage);
return "commonParam";
}
解决方案:
- 修改名称,保证请求参数名与方法形参名一致
- 使用@RequestParam注解,建立请求参数名与形参名称之间的关系
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(@RequestParam("name") String username ,
@RequestParam("age") int userage){
System.out.println("普通参数传递 name ==> "+username);
System.out.println("普通参数传递 age ==> "+userage);
return "commonParam";
}
@RequestParam注解属性:
-
value
- 指定前端的属性名映射到某个参数上
-
required
- 用于指定此参数是否必传。取值:true/false (默认值 : true)
-
defaultValue
- 如果前端此参数值没有设置,这里参数会指定一个默认值。
编码过滤器
在之前学习Servlet时,有遇到请求中携带了中文数据,处理方案:
GET请求: Tomcat8版本开始已解决
POST请求: response.setCharacterEncoding("UTF-8")
而在SpringMVC中已经提供好了编码过滤器,我们直接使用即可。
在ServletContainersInitConfig配置类中进行配置即可
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//POST请求乱码处理
@Override
protected Filter[] getServletFilters() {
//spring封装的过滤器, 拦截所有的请求,如果是post请求,就将编码修改为指定编码
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
日期处理
日期类型数据基于系统不同格式也不尽相同
- 2088-08-18
- 2088/08/18
- 08/18/2088
接收形参时,根据不同的日期格式设置不同的接收方式
//@DateTimeFormat注解设置日期类型数据格式,默认格式:yyyy/MM/dd
@RequestMapping("/dateParam")
@ResponseBody
public String dateParam(Date date1, //使用默认格式:yyyy/MM/dd
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date2,
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3){
System.out.println("参数传递 date ==> "+date1);
System.out.println("参数传递 date(yyyy-MM-dd) ==> "+date2);
System.out.println("参数传递 date(yyyy/MM/dd HH:mm:ss) ==> "+date3);
return "dateParam";
}
http://localhost:8080/dateParam?date1=2088/08/18&date2=2088-08-18&date3=2088/08/18 12:18:28
需要注意的是:使用@DateTimeFormat时,要配置@EnableWebMvc
12_SpringMVC的响应处理
目标
- 能够使用SpringMVC给前端响应数据
路径
- SpringMVC的响应
- SpringMVC给前端响应数据
SpringMVC的响应
SpringMVC对响应的封装可以分为两类:
- 响应页面
- 响应数据
- 字符串数据
- json数据
SpringMVC响应数据时使用@ResponseBody注解:
- 设置当前方法返回值作为响应体
@RequestMapping("/toText")
@ResponseBody //设置当前控制器返回值作为响应体
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}
/*
只要配置好对应的环境 (导入jackson, 开启@EnableWebMvc)
SpringMVC会自动将JavaBean返回值转成json格式字符串
*/
@RequestMapping("/toJsonPOJO")
@ResponseBody //自动把对象类型,转换为json字符串(导入jackson, 开启@EnableWebMvc)
public User toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User("itheima",20);
return user;//返回值是对象类型(把对象转换为json格式字符串)
}
SpringMVC给前端响应数据
代码示例:
- 控制器类
@Controller
public class UserController {
//响应文本数据
//返回值为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("itheima",20);
return user;//把User对象转换为json格式字符串,再响应给前端
}
//响应POJO集合对象
//返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList(){
System.out.println("返回json集合数据");
User user1 = new User();
user1.setName("传智播客");
user1.setAge(15);
User user2 = new User();
user2.setName("黑马程序员");
user2.setAge(12);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
return userList; //把集合对象转换为json格式字符串
}
//响应页面/跳转页面
//返回值为String类型,设置返回值为页面名称,即可实现页面跳转
@RequestMapping("/toJumpPage") ////////今天课程内容,无法实现页面跳转
public String toJumpPage(){
System.out.println("跳转页面");
return "index.jsp";
}
}
使用postman测试:响应处理
-
响应文本数据:String
-
响应Pojo对象:User
-
响应集合对象:List
小结
- 在Controller中,给前端响应,可以使用:@ResponseBody
- 把当前方法的返回值,作为响应体,响应给前端
- 响应的数据是:json格式
- 把Java对象类型,转换为json字符串
- 步骤:
- 导入坐标:Jackson
- 开启json和对象的自动转换: @EnableWebMvc
- @ResponseBody: 会自动把Java对象,转换为json字符串
- 步骤:
- 把Java对象类型,转换为json字符串
13_SpringMVC的RESTful风格
目标
- 了解SpringMVC框架在三层架构存在的意义
路径
- RESTful介绍
- RESTful行为约定方式
- RESTful开发入门
- 使用组合注解优化RESTful开发
RESTful介绍
REST( Representational State Transfer) 翻译后意思是:表现层的状态转化
- 一种网络资源的访问风格,定义了网络资源的访问方式
RESTful是按照REST风格访问网络资源。
传统风格访问路径:
http://localhost:80/user/get?id=1
http://localhost/user/delete?id=1
REST风格访问路径:
http://localhost/user/1
可以具有多个含义:
既可以是查询,也可以是删除,也可以是修改,也可以是添加(别人根本就不知道开发者在干嘛)
优点:
- 隐藏资源的访问行为,通过地址无法得知做的是何种操作(提高安全性)
- 简化书写
RESTful行为约定方式
RESTful使用url定位资源,用HTTP请求方式(GET,POST,PUT,DELETE)描述操作
GET(查询) : http://localhost/user //GET请求方式
POST(保存) : http://localhost/user //POST请求方式
PUT(更新) : http://localhost/user //PUT请求方式
DELETE(删除): http://localhost/user //DELETE请求方式
注意:上述行为是约定方式,约定不是硬性规范,可以打破,所以称REST风格,而不是REST规范
RESTful开发入门
代码示例:
- Pojo类
public class User {
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 控制器类
@Controller
public class RestfulController {
//添加用户
@RequestMapping(value = "/rest",method = RequestMethod.POST)
@ResponseBody
public String add(@RequestBody User user){
System.out.println("add: " + user);
return "add success";
}
//修改用户
@RequestMapping(value = "/rest",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("update: "+ user);
return "update success";
}
//删除所有用户
@RequestMapping(value = "/rest",method = RequestMethod.DELETE)
@ResponseBody
public String deleteAll(){
System.out.println("deleteAll");
return "delete all success";
}
//查询所有用户
@RequestMapping(value = "/rest",method = RequestMethod.GET)
@ResponseBody
public List<User> findAll(){
System.out.println("findAll");
User user1 = new User(1,"传智播客",16);
User user2 = new User(2,"黑马程序员",13);
List<User> userList = new ArrayList<User>();
Collections.addAll(userList,user1,user2);
return userList;
}
//根据用户id删除用户
@RequestMapping(value = "/rest/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String deleteById(@PathVariable Integer id){
System.out.println("deleteById : " + id);
return "delete success";
}
//根据用户id查询用户
@RequestMapping(value = "/rest/{id}",method = RequestMethod.GET)
@ResponseBody
public User findById(@PathVariable Integer id){
System.out.println("findById : " + id);
User user = new User(1,"itheima",16);
return user;
}
//分页查询用户
@RequestMapping(value = "/rest/{page}/{pageSize}",method = RequestMethod.GET)
@ResponseBody
public List<User> findByPage(@PathVariable Integer page,
@PathVariable Integer pageSize){
System.out.println("findByPage : " + page + "," + pageSize);
User user1 = new User(1,"传智播客",16);
User user2 = new User(2,"黑马程序员",13);
List<User> userList = new ArrayList<User>();
Collections.addAll(userList,user1,user2);
return userList;
}
}
使用postman测试:RESTful风格请求
-
添加用户
-
查询所有用户
-
根据用户id删除用户
-
分页查询用户
使用组合注解优化RESTful开发
在SpringMVC中提供了一些组合注解,来简化代码的书写:
- @RestController
- 效果: @Controller + @ResponseBody
- @GetMapping("/rest")
- 效果: @RequestMapping(value = "/rest" , method = RequestMethod.GET)
代码示例:
- 控制器类
//@Controller
@RestController // @RestController = @Controller + @ResponseBody
@RequestMapping("/rest")
public class RestfulController {
//添加用户
//@RequestMapping(value = "/rest",method = RequestMethod.POST)
//@ResponseBody
@PostMapping()
public String add(@RequestBody User user){
System.out.println("add: " + user);
return "add success";
}
//修改用户
//@RequestMapping(value = "/rest",method = RequestMethod.PUT)
//@ResponseBody
@PutMapping
public String update(@RequestBody User user){
System.out.println("update: "+ user);
return "update success";
}
//删除所有用户
//@RequestMapping(value = "/rest",method = RequestMethod.DELETE)
//@ResponseBody
@DeleteMapping
public String deleteAll(){
System.out.println("deleteAll");
return "delete all success";
}
//查询所有用户
//@RequestMapping(value = "/rest",method = RequestMethod.GET)
//@ResponseBody
@GetMapping
public List<User> findAll(){
System.out.println("findAll");
User user1 = new User(1,"传智播客",16);
User user2 = new User(2,"黑马程序员",13);
List<User> userList = new ArrayList<User>();
Collections.addAll(userList,user1,user2);
return userList;
}
//根据用户id删除用户
//@RequestMapping(value = "/rest/{id}",method = RequestMethod.DELETE)
//@ResponseBody
@DeleteMapping("/{id}")
public String deleteById(@PathVariable Integer id){
System.out.println("deleteById : " + id);
return "delete success";
}
//根据用户id查询用户
//@RequestMapping(value = "/rest/{id}",method = RequestMethod.GET)
//@ResponseBody
@GetMapping("/{id}")
public User findById(@PathVariable Integer id){
System.out.println("findById : " + id);
User user = new User(1,"itheima",16);
return user;
}
//分页查询用户
//@RequestMapping(value = "/rest/{page}/{pageSize}",method = RequestMethod.GET)
//@ResponseBody
@GetMapping("/{page}/{pageSize}")
public List<User> findByPage(@PathVariable Integer page,
@PathVariable Integer pageSize){
System.out.println("findByPage : " + page + "," + pageSize);
User user1 = new User(1,"传智播客",16);
User user2 = new User(2,"黑马程序员",13);
List<User> userList = new ArrayList<User>();
Collections.addAll(userList,user1,user2);
return userList;
}
}
14_案例:基于RESTful页面数据交互
导入素材中的代码: springmvc_07_rest-case
- 前端:vue+elementui
- 后端:springmvc