
第 1 章 SpringMVC 基础
1.1 MVC 模型
**MVC 全称 Model View Controller,是一种设计创建 Web 应用程序的模式。**这三个单词分别代表 Web 应用程序的三个部分:
-
Model(模型) :指数据模型,用于存储数据以及处理用户请求的业务逻辑。在 Web 应用中,JavaBean 对象、业务模型等都属于 Model。
举例 :电商网站中,Product
类(存储商品 ID、名称、价格)和ProductService
类(处理商品查询、新增逻辑)都属于 Model。 -
View(视图) :用于展示模型中的数据,一般为 JSP 或 HTML 文件。
举例 :电商网站的商品详情页(productDetail.jsp
),通过 JSP 标签展示Product
对象的名称、价格等数据。 -
Controller(控制器) :是应用程序中处理用户交互的部分,接收视图提出的请求,将数据交给模型处理,并将处理后的结果交给视图显示。
举例 :电商网站的ProductController
,接收用户 "查询商品详情" 的请求(如/product/1
),调用ProductService
查询 ID 为 1 的商品,再将商品数据传递给productDetail.jsp
展示。
MVC 交互流程:浏览器发起请求(如点击 "查看商品")→ Controller 接收请求 → 调用 Model 处理业务(查询商品数据)→ Model 返回处理结果(商品信息)→ Controller 将结果传递给 View → View 渲染数据并展示给用户。
1.2 SpringMVC 简介
SpringMVC 是一个基于 MVC 模式 的轻量级 Web 框架,是 Spring 框架 的一个模块,可与 Spring 直接整合使用(无需额外配置复杂依赖)。它的核心优势是替代 Servlet 技术,通过一套注解(如@Controller
、@RequestMapping
),让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。
举例:
传统 Servlet 需要继承HttpServlet
并重写doGet/doPost
方法,而 SpringMVC 中只需在类上加@Controller
,方法上加@RequestMapping("/hello")
,即可处理/hello
路径的请求,代码更简洁。
SpringMVC 的核心特性:
- 注解驱动:通过注解快速绑定请求路径与控制器方法。
- 自动参数封装 :无需手动调用
request.getParameter()
,可直接将请求参数封装为 Java 对象。 - 灵活的视图支持:支持 JSP、Thymeleaf、Freemarker 等多种视图技术。
- 与 Spring 生态无缝整合:可直接使用 Spring 的 IOC 容器、事务管理等功能。
第 2 章 SpringMVC 入门案例
本节通过 Maven 创建 Web 项目,实现一个简单的 SpringMVC 请求处理(访问指定路径打印日志),步骤如下:
2.1 创建 Maven Web 项目
用 IDEA 创建 Maven 项目,选择 "maven-archetype-webapp" 骨架,补齐包结构(src/main/java
、src/main/resources
)。
引入核心依赖(Spring 核心、SpringWeb、SpringMVC、Servlet、JSP)和 Tomcat 插件,配置如下:
XML
<dependencies>
<!-- Spring核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- SpringMVC模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope> <!-- 服务器已提供,打包时不包含 -->
</dependency>
<!-- JSP -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Tomcat插件(用于启动项目) -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port> <!-- 项目启动端口 -->
<path>/</path> <!-- 项目上下文路径(根路径) -->
<uriEncoding>UTF-8</uriEncoding> <!-- 解决URL中文乱码 -->
</configuration>
</plugin>
</plugins>
</build>
2.2 配置前端控制器(web.xml)
SpringMVC 的核心是DispatcherServlet
(前端控制器) ,它是所有请求的入口,负责协调其他组件。在web.xml
中配置如下:
XML
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
<display-name>SpringMVC-Demo</display-name>
<!-- SpringMVC前端控制器(本质是Servlet) -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置SpringMVC核心配置文件路径 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 容器启动时加载(优先级1,确保启动顺序) -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 映射所有请求到前端控制器 -->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> <!-- 匹配所有请求(除JSP外) -->
</servlet-mapping>
</web-app>
2.3 编写 SpringMVC 核心配置文件(springmvc.xml)
该文件用于配置组件扫描、注解支持等,与 Spring 配置文件语法一致:
XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 扫描控制器所在包(如com.itbaizhan.controller) -->
<context:component-scan base-package="com.itbaizhan"/>
<!-- 2. 开启SpringMVC注解支持(如@RequestMapping、@Controller) -->
<mvc:annotation-driven/>
</beans>
2.4 编写控制器(Controller)
通过@Controller
注解标记一个 Java 类为控制器,通过@RequestMapping
绑定请求路径:
java
package com.itbaizhan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 标记为控制器,交给Spring管理
public class MyController1 {
// 绑定请求路径:访问http://localhost:8080/c1/hello1会触发该方法
@RequestMapping("/c1/hello1")
public void helloMVC() {
System.out.println("Hello SpringMVC!"); // 控制台打印日志
}
}
2.5 启动项目并测试
- 执行 Maven 命令
tomcat7:run
启动项目; - 浏览器访问
http://localhost:8080/c1/hello1
; - 查看 IDEA 控制台,会输出
Hello SpringMVC!
,说明请求处理成功。
第 3 章 SpringMVC 执行流程与核心组件
3.1 执行流程(附详细拆解)
SpringMVC 的执行流程是前端控制器(DispatcherServlet)协调其他组件完成请求处理的过程,具体步骤如下(结合 "访问 /c1/hello1" 案例):
- 浏览器发送 HTTP 请求 :用户访问
http://localhost:8080/c1/hello1
,请求被 DispatcherServlet 接收; - DispatcherServlet 找 HandlerMapping :HandlerMapping (处理器映射器)根据请求路径
/c1/hello1
,找到对应的控制器方法(MyController1 的helloMVC
方法),返回 "方法执行链"; - DispatcherServlet 找 HandlerAdapter :HandlerAdapter(处理器适配器)根据方法类型(无返回值、参数为空),找到能执行该方法的适配器;
- 执行控制器方法 :适配器调用 MyController1 的
helloMVC
方法,执行业务逻辑(打印日志); - 返回处理结果 :控制器方法无返回值,默认返回 "路径名 + 后缀" 的视图(如
/c1/hello1.jsp
,若不存在会报 404,后续章节会讲视图解析器); - 视图渲染与响应 :若存在视图,ViewResolver (视图解析器)解析视图路径,View (视图)渲染数据后,通过 DispatcherServlet 返回 HTTP 响应给浏览器。
流程示意图 :
浏览器 → DispatcherServlet(前端控制器)→ HandlerMapping(找方法)→ HandlerAdapter(执行方法)→ Controller(业务逻辑)→ ModelAndView(结果)→ ViewResolver(解析视图)→ View(渲染)→ 浏览器
3.2 核心组件说明
组件名称 | 作用 |
---|---|
DispatcherServlet | 前端控制器 ,接收所有请求,协调 HandlerMapping、HandlerAdapter 等组件,是 SpringMVC 的 "入口"。 |
HandlerMapping | 处理器映射器 ,根据请求路径匹配对应的控制器方法(如 /c1/hello1 匹配 helloMVC 方法)。 |
HandlerAdapter | 处理器适配器,根据控制器方法的参数、返回值类型,选择合适的方式执行方法(适配不同方法签名)。 |
ViewResolver | 视图解析器 ,将逻辑视图名(如 "hello")解析为实际视图路径(如 /WEB-INF/jsp/hello.jsp )。 |
View | 视图,负责渲染模型数据(如 JSP 通过 EL 表达式展示 Model 中的数据)。 |
以下是复现的完整内容,严格保留原始结构和格式,仅按规范调整标题层级和重点标注:
第 4 章 SpringMVC 参数获取
SpringMVC 支持多种参数获取方式,无需手动调用request.getParameter()
,比 Servlet 更简洁。
4.1 封装为简单数据类型
直接在控制器方法参数中声明与请求参数名一致的变量,SpringMVC 会自动封装。
示例 1:获取单个/多个简单参数
java
package com.itbaizhan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ParamController {
// 请求路径:http://localhost:8080/c1/param1?username=张三&age=20
@RequestMapping("/c1/param1")
public void simpleParam(String username, int age) {
System.out.println("用户名:" + username); // 输出"张三"
System.out.println("年龄:" + age); // 输出"20"
}
}
规则 :请求参数名(如username
)必须与方法参数名(String username
)一致,支持 String
、int
、double
等简单类型。
4.2 封装为对象类型
若请求参数较多(如用户注册:姓名、年龄、性别),可直接封装为 Java 对象(如Student
),SpringMVC 会根据 "请求参数名 = 对象属性名" 自动赋值。
示例 2:封装单个对象
定义实体类(Student):
java
package com.itbaizhan.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Student {
private int id;
private String name;
private String sex;
// 省略getter/setter/toString(可通过Lombok注解自动生成)
}
控制器方法:
java
// 请求路径:http://localhost:8080/c1/param2?id=1&name=张三&sex=男
@RequestMapping("/c1/param2")
public void objParam(Student student) {
System.out.println(student); // 输出"Student(id=1, name=张三, sex=男)"
}
示例 3:封装关联对象(如 Student 包含 Address)
定义关联对象(Address):
java
package com.itbaizhan.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Address {
private String info; // 地址详情(如"北京市海淀区")
private String postcode;// 邮编(如"100086")
}
修改 Student 类:
java
public class Student {
private int id;
private String name;
private String sex;
private Address address; // 关联Address对象
// getter/setter/toString
}
控制器方法与请求路径:
java
// 请求路径:http://localhost:8080/c1/param3?id=1&name=张三&sex=男&address.info=北京市海淀区&address.postcode=100086
@RequestMapping("/c1/param3")
public void objParam2(Student student) {
System.out.println(student);
// 输出"Student(id=1, name=张三, sex=男, address=Address(info=北京市海淀区, postcode=100086))"
}
4.3 封装为集合类型
SpringMVC 支持将参数封装为List
或Map
,但需注意:简单类型 List 需加@RequestParam
,对象类型集合需封装到含集合属性的对象中。
示例 4:封装简单类型 List(如多选框数据)
java
// 请求路径:http://localhost:8080/c1/param4?users=张三&users=李四(多个users参数)
@RequestMapping("/c1/param4")
// 简单类型List必须加@RequestParam,否则SpringMVC无法识别
public void listParam(@RequestParam List<String> users) {
System.out.println(users); // 输出"[张三, 李四]"
}
// 也支持数组类型(无需@RequestParam)
@RequestMapping("/c1/param5")
public void listParam2(String[] users) {
System.out.println(users[0]); // 输出"张三"
System.out.println(users[1]); // 输出"李四"
}
示例 5:封装对象类型 List(如批量新增学生)
定义含 List 属性的对象(StudentList):
java
package com.itbaizhan.model;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class StudentList {
private List<Student> students; // 存储多个Student对象的List
}
控制器方法与请求路径:
java
// 请求路径:http://localhost:8080/c1/param6?students[0].id=1&students[0].name=张三&students[1].id=2&students[1].name=李四
@RequestMapping("/c1/param6")
public void listParam3(StudentList studentList) {
System.out.println(studentList.getStudents());
// 输出"[Student(id=1, name=张三), Student(id=2, name=李四)]"
}
示例 6:封装 Map 集合
定义含 Map 属性的对象(StudentMap):
java
package com.itbaizhan.model;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter
@Setter
public class StudentMap {
// Map的key为自定义标识(如"student1"),value为Student对象
private Map<String, Student> studentMap;
}
控制器方法与请求路径:
java
// 请求路径:http://localhost:8080/c1/param7?studentMap['student1'].id=1&studentMap['student1'].name=张三&studentMap['student2'].id=2&studentMap['student2'].name=李四
@RequestMapping("/c1/param7")
public void mapParam(StudentMap studentMap) {
System.out.println(studentMap.getStudentMap());
// 输出"{student1=Student(id=1, name=张三), student2=Student(id=2, name=李四)}"
}
SpringMVC 支持直接在方法参数中声明 Servlet 原生对象(如HttpServletRequest
、HttpServletResponse
、HttpSession
),无需手动创建
4.4 使用 Servlet 原生对象获取参数
SpringMVC 支持直接在方法参数中声明 Servlet 原生对象(如 HttpServletRequest、HttpServletResponse、HttpSession),无需手动创建:
java
// 请求路径:http://localhost:8080/c1/param8?name=张三
@RequestMapping("/c1/param8")
public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
// 1. 用HttpServletRequest获取请求参数
String name = request.getParameter("name");
System.out.println("姓名:" + name); // 输出"张三"
// 2. 用HttpServletResponse设置响应编码
response.setCharacterEncoding("UTF-8");
// 3. 用HttpSession存储数据
session.setAttribute("username", name);
System.out.println("SessionID:" + session.getId()); // 输出Session唯一标识
}
注意:SpringMVC 提供了更简洁的参数获取方式(如对象封装),建议优先使用 SpringMVC 方式,避免与 Servlet 容器紧耦合。
4.5 自定义参数类型转换器
SpringMVC 默认支持 "字符串转简单类型"(如 String→int),但对特殊类型(如 Date)无法自动转换(因日期格式多样,如 2025-01-01、2025/01/01),需自定义转换器。
示例:自定义 Date 类型转换器
定义转换器类,实现 Converter<S, T> 接口(S 为转换前类型,T 为转换后类型):
java
package com.itbaizhan.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
// 实现String→Date的转换
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) { // source:请求中的日期字符串(如"2025-01-01")
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 定义日期格式
try {
return sdf.parse(source); // 转换为Date对象
} catch (ParseException e) {
e.printStackTrace();
return null; // 转换失败返回null
}
}
}
在 springmvc.xml 中注册转换器:
java
<!-- 1. 配置转换器工厂 -->
<bean id="converterFactory" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 注册自定义Date转换器 -->
<bean class="com.itbaizhan.converter.DateConverter"/>
</set>
</property>
</bean>
<!-- 2. 让SpringMVC使用自定义转换器 -->
<mvc:annotation-driven conversion-service="converterFactory"/>
控制器方法测试:
java
// 请求路径:http://localhost:8080/c1/param9?birthday=2025-01-01
@RequestMapping("/c1/param9")
public void dateParam(Date birthday) {
System.out.println("生日:" + birthday); // 输出"生日:Wed Jan 01 00:00:00 CST 2025"
}
4.6 解决中文乱码(编码过滤器)
Tomcat 8+ 可自动处理 GET 请求的中文乱码,但 POST 请求仍会乱码。SpringMVC 提供了 CharacterEncodingFilter 过滤器,可在 web.xml 中配置解决:
java
<!-- 编码过滤器(必须放在所有过滤器最上方) -->
<filter>
<filter-name>encFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置编码格式为UTF-8 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<!-- 映射所有请求 -->
<filter-mapping>
<filter-name>encFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第 5 章 SpringMVC 处理响应
SpringMVC 的响应包括 "视图跳转" 和 "数据传递",核心是通过视图解析器和模型(Model)实现。
5.1 配置视图解析器(ViewResolver)
SpringMVC 默认的视图解析器是 InternalResourceViewResolver,用于解析 JSP 视图。通过配置 "前缀" 和 "后缀",可简化视图路径编写。
示例:配置 JSP 视图解析器
在 springmvc.xml 中添加如下配置:
XML
<!-- 视图解析器:解析JSP视图 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/> <!-- 视图前缀(JSP文件所在目录) -->
<property name="suffix" value=".jsp"/> <!-- 视图后缀(文件扩展名) -->
</bean>
规则:控制器返回的逻辑视图名(如 "hello")会被解析为 "前缀 + 逻辑视图名 + 后缀",即 /WEB-INF/jsp/hello.jsp。
5.2 控制器方法的返回值类型
控制器方法的返回值决定了视图跳转的方式,支持 void、String、ModelAndView 三种类型。
5.2.1 返回值为 void(默认跳转)
返回 void 时,SpringMVC 会默认跳转到 "前缀 + 方法请求路径 + 后缀" 的视图:
java
// 请求路径:http://localhost:8080/helloMVC
@RequestMapping("/helloMVC")
public void helloMVC() {
System.out.println("Hello SpringMVC!");
}
跳转逻辑:结合视图解析器配置(prefix=/WEB-INF/jsp/,suffix=.jsp),会跳转到 /WEB-INF/jsp/helloMVC.jsp。
返回 String 时,SpringMVC 会跳转到 "前缀 + 返回值 + 后缀" 的视图,灵活性更高:
返回值为 String(指定视图)
在 SpringMVC 中,控制器方法返回 String
类型时,框架会根据视图解析器的配置跳转到对应的视图页面。默认逻辑视图名会拼接前缀和后缀,例如返回 "helloMVC"
会解析为 /WEB-INF/jsp/helloMVC.jsp
。
特殊用法是通过 forward:
或 redirect:
前缀实现请求转发或重定向:
java
@RequestMapping("/c2/hello1")
public String helloMVC1() {
return "helloMVC"; // 逻辑视图名
}
forward:/c2/hello2
:服务器内部转发,地址栏不变。redirect:/c2/hello2
:客户端重定向,地址栏变化。
返回值为 ModelAndView(带数据跳转)
ModelAndView
对象允许同时设置视图和数据,数据默认存入 request
域:
java
@RequestMapping("/c2/hello2")
public ModelAndView useMAV() {
ModelAndView mav = new ModelAndView();
mav.addObject("username", "百战程序员"); // 数据存入request域
mav.setViewName("baizhan"); // 视图名
return mav;
}
JSP 中通过 EL 表达式获取数据:
html
<h1>你好!${requestScope.username}</h1>
需确保 web.xml
使用 Servlet 3.1 以支持 EL 表达式。
向不同作用域传递数据
向 request 域传递数据
- HttpServletRequest :直接操作
request
对象。 - Model/ModelMap/Map :框架自动注入参数,数据存入
request
域。
java
@RequestMapping("/c2/hello4")
public String setRequest(Model model) {
model.addAttribute("username", "尚学堂");
return "baizhan";
}
向 session 域传递数据
通过 HttpSession
对象设置数据:
java
@RequestMapping("/c2/hello6")
public String setSession(HttpSession session) {
session.setAttribute("address", "北京");
return "baizhan";
}
向 context 域传递数据
需通过 HttpSession
获取 ServletContext
:
java
@RequestMapping("/c2/hello7")
public String setContext(HttpSession session) {
ServletContext context = session.getServletContext();
context.setAttribute("age", 10);
return "baizhan";
}
请求转发与重定向
方式 | 特点 | 适用场景 |
---|---|---|
请求转发(forward) | 服务器内部跳转,地址栏不变,共享 request 域数据。 |
同一模块内跳转(如提交表单后显示结果)。 |
重定向(redirect) | 客户端重新发起请求,地址栏变化,不共享 request 域数据,可跳转外部路径。 |
跨模块跳转(如登录后跳首页)。 |
原生实现方式:
java
@RequestMapping("/c2/hello8")
public void myForward1(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 请求转发
request.getRequestDispatcher("/c2/hello9").forward(request, response);
// 或重定向
response.sendRedirect("/c2/hello9");
}
第 6 章 SpringMVC 常用注解
6.1 @Controller:标记控制器
在 SpringMVC 中,使用 @Controller
标注控制器类,将其交给 Spring 容器管理。该注解通常位于类上方,并可与 @RequestMapping
结合使用定义请求路径。
java
@Controller // 标记为控制器
@RequestMapping("/c3") // 类级别的请求路径(父路径)
public class MyController3 {
// 方法级别的请求路径:完整路径为/c3/annotation1
@RequestMapping("/annotation1")
public String annotation1() {
return "baizhan";
}
}
6.2 @RequestMapping:绑定请求路径
@RequestMapping
为控制器类或方法绑定请求路径,支持指定请求方式、参数、请求头等。可作用于类上方(父路径)或方法上方(子路径)。
核心属性
value/path
:请求路径(如/annotation1
)。method
:指定请求方式(如RequestMethod.GET
、RequestMethod.POST
)。params
:规定必须携带的请求参数(如params = {"age"}
)。headers
:规定必须包含的请求头(如headers = {"User-Agent"}
)。
java
@Controller
@RequestMapping("/c3") // 父路径:/c3
public class MyController3 {
@RequestMapping(
path = "/annotation1",
method = {RequestMethod.GET, RequestMethod.POST},
params = {"age"},
headers = {"User-Agent"}
)
public String annotation1(String username) {
System.out.println(username);
return "baizhan";
}
}
6.3 @RequestParam:获取请求参数
@RequestParam
手动指定请求参数名与方法参数名的映射,支持设置默认值和是否必传。位于方法参数前。
核心属性
name/value
:请求参数名(如name = "username"
)。defaultValue
:参数默认值。required
:是否必传(默认true
)。
java
@RequestMapping("/annotation2")
public String annotation2(
@RequestParam(name = "username", defaultValue = "sxt", required = false) String name
) {
System.out.println(name); // 若未传参数,输出"sxt";若传参数,输出"张三"
return "baizhan";
}
6.4 @RequestHeader 与 @CookieValue:获取请求头与 Cookie
6.4.1 @RequestHeader:获取请求头数据
用于获取 HTTP 请求头中的数据(如 User-Agent
、Content-Type
)。
6.4.2 @CookieValue:获取 Cookie 数据
用于获取浏览器 Cookie 中的数据(如 JSESSIONID
)。
java
@RequestMapping("/annotation3")
public String annotation3(
@RequestHeader("User-Agent") String userAgent,
@CookieValue("JSESSIONID") String jSessionId
) {
System.out.println("浏览器标识:" + userAgent);
System.out.println("SessionID:" + jSessionId);
return "baizhan";
}
6.5 @SessionAttributes:将 Model 数据存入 Session
@SessionAttributes
将 Model 中的指定 key 的数据自动存入 Session 域,位于类上方。
java
@Controller
@RequestMapping("/c4")
@SessionAttributes("name") // 将Model中key为name的数据存入Session
public class MyController4 {
@RequestMapping("/t1")
public String t1(Model model) {
model.addAttribute("name", "北京尚学堂"); // Model→Request+Session
return "baizhan";
}
@RequestMapping("/t2")
public String t2(HttpSession session) {
String name = (String) session.getAttribute("name");
System.out.println(name); // 输出"北京尚学堂"
return "baizhan";
}
}
6.6 @ModelAttribute:前置方法与数据绑定
@ModelAttribute
有两种用法:
- 标记前置方法:该方法会在控制器其他方法执行前自动执行。
- 从 Model 中获取数据:解决参数不从请求中获取,而从 Model 中获取的场景。
示例 1:前置方法
java
@Controller
@RequestMapping("/c5")
public class MyController5 {
@ModelAttribute
public void before() {
System.out.println("前置方法执行"); // 先输出
}
@RequestMapping("/t1")
public String t1() {
System.out.println("t1方法执行"); // 后输出
return "baizhan";
}
}
示例 2:从 Model 中获取数据
java
@Controller
@RequestMapping("/c6")
public class MyController6 {
@ModelAttribute
public void before(Model model) {
model.addAttribute("name", "尚学堂");
}
@RequestMapping("/t1")
public String t1(@ModelAttribute("name") String name) {
System.out.println(name); // 输出"尚学堂"
return "baizhan";
}
}
第7章 SpringMVC RESTful风格支持
RESTful是一种URL设计范式,将数据视为"资源",通过URL路径标识资源(如学生),并通过HTTP请求方式(GET、POST、PUT、DELETE)区分操作类型。这种设计使API更简洁、语义化,易于扩展和维护。
7.1 RESTful风格简介
RESTful的核心规则:
- URL仅标识资源 :不包含操作名称(如
findById
或delete
),而是通过路径表示资源本身(如/student/30
表示ID=30的学生)。 - 请求方式区分操作 :
- GET:查询资源(如获取学生信息)。
- POST:新增资源(如添加新学生)。
- PUT:修改资源(如更新学生数据)。
- DELETE:删除资源(如移除学生)。
- 优势:结构清晰、符合HTTP协议语义、减少URL冗余、支持跨平台调用。
传统URL与RESTful URL对比:
操作 | 传统URL示例 | RESTful URL示例 | 请求方式 |
---|---|---|---|
查询学生(ID=30) | http://localhost:8080/student/findById?id=30 |
http://localhost:8080/student/30 |
GET |
删除学生(ID=30) | http://localhost:8080/student/deleteById?id=30 |
http://localhost:8080/student/30 |
DELETE |
新增学生 | http://localhost:8080/student/add |
http://localhost:8080/student |
POST |
修改学生(ID=30) | http://localhost:8080/student/updateById?id=30 |
http://localhost:8080/student/30 |
PUT |
7.2 用Postman发送RESTful请求
浏览器默认仅支持GET和POST请求,DELETE和PUT请求需借助工具(如Postman)发送。步骤如下:
- 下载并打开Postman:从官网安装Postman应用。
- 创建请求集合:例如,新建名为"SpringMVC-RESTful"的集合。
- 配置请求 :
- 选择请求方式(GET、POST、DELETE或PUT)。
- 输入URL(如
http://localhost:8080/student/30
)。 - 如需传递参数(如新增学生时),在"Body"标签中选择:
form-data
:用于表单数据(键值对)。x-www-form-urlencoded
:用于URL编码参数。
- 添加参数(如
name=张三&age=20
)。
- 发送请求:点击"Send"按钮,查看响应结果(状态码、响应体等)。
7.3 @PathVariable:获取URL路径参数
在RESTful风格中,URL路径包含占位符(如/student/{id}
),@PathVariable
注解用于从路径中提取这些参数值。它位于方法参数前,核心属性为value
(指定占位符名称;若参数名与占位符一致,可省略)。
示例:RESTful风格控制器
java
@Controller
@RequestMapping("/student") // 父路径:/student
public class StudentController {
// 1. 查询学生(GET /student/30)
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String findStudentById(@PathVariable("id") int id) {
System.out.println("查询ID为" + id + "的学生");
return "baizhan";
}
// 2. 删除学生(DELETE /student/30)
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public String deleteStudent(@PathVariable int id) { // 占位符与参数名一致,省略value
System.out.println("删除ID为" + id + "的学生");
return "baizhan";
}
// 3. 新增学生(POST /student)
@RequestMapping(method = RequestMethod.POST)
public String addStudent(Student student) {
System.out.println("新增学生:" + student);
return "baizhan";
}
// 4. 修改学生(PUT /student/30)
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public String updateStudent(@PathVariable int id, Student student) {
System.out.println("修改ID为" + id + "的学生:" + student);
return "baizhan";
}
}
关键点:
@PathVariable
将URL中的{id}
绑定到方法参数id
。- 方法需指定
method
属性以匹配HTTP请求方式。
7.4 简化请求方式注解
SpringMVC提供了专用注解(@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
),简化@RequestMapping
的配置,使代码更简洁。
示例:简化后的控制器
java
@Controller
@RequestMapping("/student")
public class StudentController {
// 等价于@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@GetMapping("/{id}")
public String findStudentById(@PathVariable int id) {
System.out.println("查询ID为" + id + "的学生");
return "baizhan";
}
// 等价于@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public String deleteStudent(@PathVariable int id) {
System.out.println("删除ID为" + id + "的学生");
return "baizhan";
}
// 等价于@RequestMapping(method = RequestMethod.POST)
@PostMapping
public String addStudent(Student student) {
System.out.println("新增学生:" + student);
return "baizhan";
}
// 等价于@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@PutMapping("/{id}")
public String updateStudent(@PathVariable int id, Student student) {
System.out.println("修改ID为" + id + "的学生:" + student);
return "baizhan";
}
}
优势:减少冗余代码,提高可读性。
7.5 HiddenHttpMethodFilter:支持浏览器发送DELETE/PUT请求
浏览器表单仅支持GET和POST请求。SpringMVC的HiddenHttpMethodFilter
过滤器允许将POST请求"伪装"为DELETE或PUT请求。实现步骤如下:
步骤1:在web.xml中配置过滤器
XML
<!-- 支持DELETE/PUT请求的过滤器 -->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
步骤2:编写表单(伪装请求) 表单需满足:
- 提交方式为
method="post"
。 - 添加隐藏域
_method
,值为DELETE
或PUT
。 示例表单(用于删除学生):
XML
<form action="/student/30" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除学生">
</form>
原理 :过滤器读取_method
参数,将POST请求转换为指定HTTP方式。
总结
- RESTful核心 :通过URL路径标识资源,HTTP方式定义操作,使用
@PathVariable
获取路径参数。 - 工具支持 :Postman用于发送全类型请求;
HiddenHttpMethodFilter
扩展浏览器能力。 - 简化开发 :利用
@GetMapping
等注解减少配置。 - 参数获取:SpringMVC自动封装简单参数,提升开发效率。 如果您有具体问题(如代码调试或扩展案例),请提供更多细节,我将进一步协助!
XML
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>RESTful表单</title>
</head>
<body>
<!-- 1. 伪装DELETE请求(删除ID=1的学生) -->
<form action="/student/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除学生">
</form>
<!-- 2. 伪装PUT请求(修改ID=1的学生) -->
<form action="/student/1" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="text" name="name" value="张三">
<input type="submit" value="修改学生">
</form>
</body>
</html>
第 8 章 SpringMVC JSON 数据交互
SpringMVC 支持 JSON 格式的数据交互(如前后端分离架构),核心注解为 @ResponseBody 和 @RequestBody。
8.1 @ResponseBody:返回 JSON 数据
作用 :将控制器方法的返回值(如 Java 对象)转换为 JSON 格式,直接写入 HTTP 响应体,不经过视图解析器(无需跳转视图)。
位置:方法上方或方法返回值前。
示例 1:返回 JSON 格式结果
引入 Jackson 依赖(SpringMVC 默认使用 Jackson 转换 JSON):
XML
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
定义结果实体类(封装响应数据):
java
package com.itbaizhan.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Result {
private boolean flag; // 请求是否成功(true=成功,false=失败)
private String message; // 提示信息
// 构造方法
public Result(boolean flag, String message) {
this.flag = flag;
this.message = message;
}
}
控制器方法(返回 JSON):
java
@Controller
@RequestMapping("/c8")
public class MyController8 {
// 新增学生,返回JSON结果
@PostMapping("/addStudent")
@ResponseBody // 将Result对象转为JSON
public Result addStudent(String name, String sex) {
System.out.println("新增学生:" + name + ",性别:" + sex);
// 返回JSON:{"flag":true,"message":"添加学生成功!"}
return new Result(true, "添加学生成功!");
}
}
前端发送 Ajax 请求(JSP 示例):
XML
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Ajax请求</title>
<!-- 引入jQuery -->
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
// 获取表单数据
var name = $("#name").val();
var sex = $("#sex").val();
// 发送Ajax请求
$.get("/c8/addStudent", {"name": name, "sex": sex}, function (data) {
console.log(data); // 打印JSON结果:{flag: true, message: "添加学生成功!"}
});
});
});
</script>
</head>
<body>
姓名:<input id="name"/><br/>
性别:<input id="sex"/><br/>
<input type="button" value="提交" id="btn"/>
</body>
</html>
8.2 @RestController:简化 JSON 返回
作用 :组合 @Controller 和 @ResponseBody ,标记在类上方,表示该类所有方法的返回值都会自动转为 JSON(无需每个方法加 @ResponseBody)。
java
@RestController // 等价于@Controller + @ResponseBody
@RequestMapping("/c8")
public class MyController8 {
// 无需加@ResponseBody,返回值自动转为JSON
@PostMapping("/addStudent")
public Result addStudent(String name, String sex) {
System.out.println("新增学生:" + name + ",性别:" + sex);
return new Result(true, "添加学生成功!");
}
}
8.3 @RequestBody:接收 JSON 格式参数
作用 :将 HTTP 请求体中的 JSON 格式参数转换为 Java 对象(如 Student
)。
位置:方法参数前。
示例 2:接收 JSON 参数并返回 JSON 结果
前端发送 JSON 格式的 Ajax 请求:
XML
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Ajax请求(JSON参数)</title>
<script src="/js/jquery-2.1.1.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
// 1. 构造JSON数据
var param = JSON.stringify({
"name": $("#name").val(),
"sex": $("#sex").val()
});
// 2. 发送Ajax请求(Content-Type为application/json)
$.ajax({
url: "/c8/addStudent2",
type: "post",
contentType: "application/json", // 声明请求体为JSON
data: param,
success: function (data) {
console.log(data); // 打印JSON响应
}
});
});
});
</script>
</head>
<body>
姓名:<input id="name"/><br/>
性别:<input id="sex"/><br/>
<input type="button" value="提交" id="btn"/>
</body>
</html>
控制器方法(接收 JSON 参数):
java
@RestController
@RequestMapping("/c8")
public class MyController8 {
// 用@RequestBody将JSON参数转为Student对象
@PostMapping("/addStudent2")
public Result addStudent2(@RequestBody Student student) {
System.out.println("新增学生:" + student); // 输出Student对象
return new Result(true, "添加学生成功!");
}
}
8.4 放行静态资源
SpringMVC 提供了多种方式配置静态资源映射,确保前端资源能被正确加载。每种方法都适用于不同场景,且在实际项目中可灵活选择或组合使用。
-
方案 1:配置默认资源检查器(对应选项 A)
-
在 SpringMVC 配置文件(如
springmvc.xml
)中添加<mvc:default-servlet-handler/>
。 -
作用:让 SpringMVC 将静态资源请求委托给 Web 服务器(如 Tomcat)的默认 Servlet 处理。
-
优点:简单快捷,无需指定具体路径。
-
示例配置:
XML<!-- 放行静态资源(JS、CSS、图片等) --> <mvc:default-servlet-handler/>
-
此方案等同于选项 A 的"配置静态资源筛查器"(术语"筛查器"可能为笔误,实际应为"检查器"或"处理器")。
-
-
方案 2:配置静态资源映射器(对应选项 B)
-
在
springmvc.xml
中使用<mvc:resources/>
标签,为特定路径映射静态资源目录。 -
作用:精确控制静态资源的访问路径和存储位置。
-
优点:性能高效,可直接从指定目录加载资源。
-
示例配置:
XML<!-- 配置静态资源映射:/js/**路径映射到/webapp/js/目录 --> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/img/**" location="/img/"/>
-
此方案直接对应选项 B 的"配置静态资源映射器"。
-
-
方案 3:配置默认 Servlet 处理静态资源(对应选项 C)
-
在
web.xml
中配置 Web 服务器(如 Tomcat)的默认 Servlet,指定其处理特定文件类型的请求。 -
作用:绕过 SpringMVC,让服务器直接处理静态资源。
-
优点:兼容性强,适用于所有 Servlet 容器。
-
示例配置:
XML<!-- 让默认Servlet处理JS、CSS、图片 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping>
-