框架--SpringMVC
第 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 插件,配置如下:
<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
中配置如下:
<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 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://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
绑定请求路径:
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:获取单个/多个简单参数
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):
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注解自动生成)
}
控制器方法:
// 请求路径: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):
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 类:
public class Student {private int id;private String name;private String sex;private Address address; // 关联Address对象// getter/setter/toString
}
控制器方法与请求路径:
// 请求路径: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(如多选框数据)
// 请求路径: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):
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
}
控制器方法与请求路径:
// 请求路径: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):
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;
}
控制器方法与请求路径:
// 请求路径: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),无需手动创建:
// 请求路径: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 为转换后类型):
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> {@Overridepublic 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 中注册转换器:
<!-- 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"/>
控制器方法测试:
// 请求路径: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 中配置解决:
<!-- 编码过滤器(必须放在所有过滤器最上方) -->
<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 中添加如下配置:
<!-- 视图解析器:解析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 会默认跳转到 "前缀 + 方法请求路径 + 后缀" 的视图:
// 请求路径: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:
前缀实现请求转发或重定向:
@RequestMapping("/c2/hello1")
public String helloMVC1() {return "helloMVC"; // 逻辑视图名
}
forward:/c2/hello2
:服务器内部转发,地址栏不变。redirect:/c2/hello2
:客户端重定向,地址栏变化。
返回值为 ModelAndView(带数据跳转)
ModelAndView
对象允许同时设置视图和数据,数据默认存入 request
域:
@RequestMapping("/c2/hello2")
public ModelAndView useMAV() {ModelAndView mav = new ModelAndView();mav.addObject("username", "百战程序员"); // 数据存入request域mav.setViewName("baizhan"); // 视图名return mav;
}
JSP 中通过 EL 表达式获取数据:
<h1>你好!${requestScope.username}</h1>
需确保 web.xml
使用 Servlet 3.1 以支持 EL 表达式。
向不同作用域传递数据
向 request 域传递数据
- HttpServletRequest:直接操作
request
对象。 - Model/ModelMap/Map:框架自动注入参数,数据存入
request
域。
@RequestMapping("/c2/hello4")
public String setRequest(Model model) {model.addAttribute("username", "尚学堂");return "baizhan";
}
向 session 域传递数据
通过 HttpSession
对象设置数据:
@RequestMapping("/c2/hello6")
public String setSession(HttpSession session) {session.setAttribute("address", "北京");return "baizhan";
}
向 context 域传递数据
需通过 HttpSession
获取 ServletContext
:
@RequestMapping("/c2/hello7")
public String setContext(HttpSession session) {ServletContext context = session.getServletContext();context.setAttribute("age", 10);return "baizhan";
}
请求转发与重定向
方式 | 特点 | 适用场景 |
---|---|---|
请求转发(forward) | 服务器内部跳转,地址栏不变,共享 request 域数据。 | 同一模块内跳转(如提交表单后显示结果)。 |
重定向(redirect) | 客户端重新发起请求,地址栏变化,不共享 request 域数据,可跳转外部路径。 | 跨模块跳转(如登录后跳首页)。 |
原生实现方式:
@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
结合使用定义请求路径。
@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"}
)。
@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
)。
@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
)。
@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 域,位于类上方。
@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:前置方法
@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 中获取数据
@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风格控制器
@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) { // 占位符与参数名一致,省略valueSystem.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
的配置,使代码更简洁。
示例:简化后的控制器
@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)@PostMappingpublic 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中配置过滤器
<!-- 支持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
。 示例表单(用于删除学生):
<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自动封装简单参数,提升开发效率。 如果您有具体问题(如代码调试或扩展案例),请提供更多细节,我将进一步协助!
<%@ 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):
<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>
定义结果实体类(封装响应数据):
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):
@Controller
@RequestMapping("/c8")
public class MyController8 {// 新增学生,返回JSON结果@PostMapping("/addStudent")@ResponseBody // 将Result对象转为JSONpublic Result addStudent(String name, String sex) {System.out.println("新增学生:" + name + ",性别:" + sex);// 返回JSON:{"flag":true,"message":"添加学生成功!"}return new Result(true, "添加学生成功!");}
}
前端发送 Ajax 请求(JSP 示例):
<%@ 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)。
@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 请求:
<%@ 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", // 声明请求体为JSONdata: 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 参数):
@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 处理。
- 优点:简单快捷,无需指定具体路径。
- 示例配置:
<!-- 放行静态资源(JS、CSS、图片等) --> <mvc:default-servlet-handler/>
- 此方案等同于选项 A 的“配置静态资源筛查器”(术语“筛查器”可能为笔误,实际应为“检查器”或“处理器”)。
- 在 SpringMVC 配置文件(如
方案 2:配置静态资源映射器(对应选项 B)
- 在
springmvc.xml
中使用<mvc:resources/>
标签,为特定路径映射静态资源目录。 - 作用:精确控制静态资源的访问路径和存储位置。
- 优点:性能高效,可直接从指定目录加载资源。
- 示例配置:
<!-- 配置静态资源映射:/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 容器。
- 示例配置:
<!-- 让默认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>
- 在