一、SpringMVC 的视图
在 SpringMVC 中,视图的作用渲染数据,将模型 Model (将控制器(Controller))中的数据展示给用户。
在 Java 代码中,视图由接口 org.springframework.web.servlet.View
表示
SpringMVC 视图的种类很多,默认有转发视图InternalResourceView
和重定向视图RedirectView
。
当工程引入 Jstl 的依赖,转发视图会自动转换为 JstlView;
若使用的视图技术为 Thymeleaf,在 SpringMVC 的配置文件中配置了 Thymeleaf 的视图解析器,由此视图解析器解析之后所得到的是 ThymeleafView。
1-1、视图解析流程(基本原理)
当你在控制器中 return "success"
,SpringMVC 会做以下几步:
把
"success"
当作视图名(ViewName)使用 视图解析器(ViewResolver) 解析这个视图名
返回一个实现了 View 接口的视图对象(如
InternalResourceView
,JstlView
,ThymeleafView
)调用
view.render(...)
渲染模型数据(model)+ 转发或重定向
1-2、SpringMVC 支持的视图类型
类型 | 说明 | 关键类或说明 |
---|---|---|
转发视图 | 默认是 InternalResourceView ,通过 RequestDispatcher.forward() 转发 | 不改变地址栏,可共享 request 域 |
重定向视图 | RedirectView ,使用 response.sendRedirect() | 地址栏改变,不能共享 request 域 |
JSTL 视图 | 加了 JSTL 依赖后,转发视图会自动变成 JstlView | 支持 <c:forEach> 等标签 |
Thymeleaf 视图 | 配置了 Thymeleaf 解析器后使用 ThymeleafView | 支持 Thymeleaf 模板语法 |
其他 | VelocityView、FreeMarkerView 等 | 可扩展视图技术 |
1-3、Thymeleaf
若是视图是由Thymeleaf解析器解析之后得到的,获取到的视图就是ThymeleafView,但是不是左右的情况,获取的都是ThymeleafView。
当控制方法中返回的视图名称以“forword:”为前缀的时候,创建的是InternalResourceView
当控制方法中返回的视图名称以“redirect:”为前缀的时候,创建的是RedirectView
只有视图名称没有任何前缀的时候,创建的才是ThymeleafView。
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被 SpringMVC 配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转。
1-4、转发视图
1、浏览器发送一次请求,浏览器中的URL不会变!能获取到请求域中的数据!
2、web-inf下的资源不能通过浏览器获取到,但是可以通过服务器转发获取到!
3、不能跨域
SpringMVC 中默认的转发视图是 InternalResourceView
SpringMVC 中创建转发视图的情况:
当控制器方法中所设置的视图名称以 "forward:" 为前缀时,创建 InternalResourceView 视图,此时的视图名称不会被 SpringMVC 配置文件中所配置的视图解析器解析,而是会将前缀 "forward:" 去掉,剩余部分作为最终路径通过转发的方式实现跳转。
例如 "forward:/", "forward:/employee"
用的比较少,因为Thymeleaf视图解析器,默认就是转发视图!
1-5、重定向视图
1、浏览器发送两次请求,浏览器中的URL会变!不能获取到请求域中的数据!
2、可以跨域!
SpringMVC 中默认的重定向视图是 RedirectView。
当控制器方法中所设置的视图名称以 "redirect:" 为前缀时,创建 RedirectView 视图,此时的视图名称不会被 SpringMVC 配置文件中所配置的视图解析器解析,而是会将前缀 "redirect:" 去掉,剩余部分作为最终路径通过重定向的方式实现跳转。
例如 "redirect:/", "redirect:/employee"
1-6、视图控制器:view-controller
没有其他控制方法的处理,只需要通过请求映射,返回一个视图名称的时候。
此时控制中的所有的请求映射将全部失效!
<mvc:view-controller>
是 Spring XML 配置中的简洁写法,专门用于静态页面跳转,适合“无业务逻辑”的场景,现在依然常用,尤其在配置登录页、首页等时非常实用。
在 Spring Boot 中,不再使用 XML 配置 <mvc:view-controller>
,而是使用 Java 配置(基于代码的方式)来实现相同功能。
目标:实现“请求路径直接跳转到某个页面”,不写 Controller 方法
比如我们希望:
访问
/login
→ 显示login.html
访问
/
→ 显示index.html
1、Spring Boot Java 配置方式(推荐写法)
你只需创建一个配置类,实现 WebMvcConfigurer
接口,重写 addViewControllers()
方法:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MyMvcConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/login").setViewName("login");registry.addViewController("/").setViewName("index");}
}
2、视图位置说明(默认)
Spring Boot 默认使用的是 Thymeleaf,默认的视图位置是:
src/main/resources/templates/
所以你要在这里放:
src/main/resources/templates/login.html
src/main/resources/templates/index.html
(如果你用的是 JSP,需要特殊配置)
3、等价于 Spring XML 中的写法:
<mvc:view-controller path="/login" view-name="login"/>
总结一句话:
在 Spring Boot 中,你可以通过实现
WebMvcConfigurer
接口的 Java 配置类,用addViewControllers()
实现和 XML 中<mvc:view-controller>
一样的功能 —— 页面跳转,无需写 Controller,简单又优雅。
二、RESTful设计风格
2-1、什么是 RESTful?
RESTful 是一种 Web 设计风格,不是技术,是一种“使用 URL + HTTP 方法 表达资源操作”的设计规范,常用于 Web API 接口开发。
2-2、RESTful 的核心特点
要素 | 示例 | 含义 |
---|---|---|
URL 表示资源 | /user/1 | 表示用户 ID 为 1 的用户 |
HTTP 方法表示动作 | GET、POST、PUT、DELETE | 分别对应:查、增、改、删 |
【注意】:
请求参数以/xxxx的方式拼接在URL中!
2-3、传统 VS RESTful 路径对比
功能 | 传统风格 URL | RESTful 风格 URL |
---|---|---|
查询用户 | /user/get?id=1 | GET /user/1 |
添加用户 | /user/add | POST /user |
修改用户 | /user/update?id=1 | PUT /user/1 |
删除用户 | /user/delete?id=1 | DELETE /user/1 |
2-4、Spring MVC 实现 RESTful:案例说明
我们现在用一个简单的 Spring MVC 项目说明 RESTful 怎么落地实现。
1. RESTful Controller 示例(路径 + 方法)
package com.example.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping("/user")
public class UserController {// 查询用户(GET /user/admin)@GetMapping("/{username}")public String getUser(@PathVariable("username") String username) {System.out.println("查询用户:" + username);return "success";}// 添加用户(POST /user)@PostMappingpublic String addUser(User user) {System.out.println("添加用户: " + user);return "success";}// 修改用户(PUT /user/wsbazinga/123)@PutMappingpublic String updateUser(@RequestParam("username") String username,@RequestParam("password") String password) {System.out.println("更新用户: username = " + username + ", password = " + password);return "success";}// 删除用户(DELETE /user/wsbazinga)@DeleteMapping("/{username}")public String deleteUser(@PathVariable("username") String username) {System.out.println("删除用户:" + username);return "success";}
}
2-5、前端如何测试不同的 HTTP 方法?
1、post和get请求:
<!-- get请求 --><a th:href="@{/user/admin}">查询id = 1的用户</a><br><!-- post请求 --><form th:action="@{/user}" method="post">username: <input type="text" name="username">password: <input type="text" name="password">role: <input type="text" name="role"><input type="submit" value="add"></form>
2、put请求
浏览器默认只能发 GET 和 POST 请求。对于 PUT 和 DELETE,有几种方法:
方法1:使用 Postman测试
curl -X PUT http://localhost:8080/user/1
curl -X DELETE http://localhost:8080/user/1
方法2:表单中使用 Spring 的隐藏字段 + 过滤器支持
示例:put请求
<form th:action="@{/user}" method="post"><!-- 对用户没有意义 --><input type="hidden" name="_method" value="put" />username: <input type="text" name="username">password: <input type="text" name="password">role: <input type="text" name="role"><input type="submit" value="update"></form>
【注意】:
type="hidden":用户页面不可见
name = "_method" value="put"才能让post请求变成put请求!
并在 web.xml
中配置过滤器:
<!-- 支持RESTful方式提交PUT/DELETE -->
<filter><filter-name>hiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping><filter-name>hiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
3、delete请求
通过<a>超链接,点击之后,调用form表单的delete方法,走filter执行。
<div id="delete"><h2>form delete request</h2><a th:href="@{/user/wsbainga123}" @click="deleteUser">delete user</a><form id="deleteForm" method="post"><!-- 对用户没有意义 --><input type="hidden" name="_method" value="delete" /></form></div><!-- 引入 Vue --><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>new Vue({el: '#delete',methods:{deleteUser: function (event) {// 获取form表单var deleteForm = document.getElementById("deleteForm");// 添加form表单的action属性,若是没有,默认提交到当前页面// form表单的action属性 = 点击事件<a>的href的值deleteForm.action = event.target.href;// 提交表单deleteForm.submit();// 取消超链接的默认行为(跳转页面)event.preventDefault();}}});</script>
2-6、总结一句话:
RESTful 是一种使用“URL 表示资源 + HTTP 方法表示动作”的设计风格。Spring MVC 通过
@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
注解完美支持 RESTful,非常适合写清晰简洁的接口。
2-7、web.xml中多个过滤器
此时web.xml文件中有两个过滤器,对顺序有要求!
<!-- 处理编码的过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!-- 请求设置编码 --><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><!-- 响应设置编码 --><init-param><param-name>forceResponseEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 支持RESTful方式提交PUT/DELETE --><filter><filter-name>hiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping><filter-name>hiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
一定要是处理编码的过滤器在前!否则,中卫乱码,因为 hiddenHttpMethodFilter 中会先获取参数_method,导致处理编码的过滤器失效!
springmvc项目的web.xml文件内容,基本上就是:一个servlet+两个过滤器
三、default-servlet-handler配置
在 Spring MVC 中,default-servlet-handler
是一个非常关键但经常被忽略的配置,它的作用是:让静态资源(如图片、CSS、JS 等)能够被正常访问。
3-1、为什么需要 default-servlet-handler
?
Spring MVC 的核心思想是:把所有请求都交给前端控制器 DispatcherServlet
统一处理。
比如你在 web.xml
中通常是这样配置的:
<servlet-mapping><servlet-name>springDispatcher</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
这意味着:所有请求(包括静态资源)都会被 SpringMVC 接管!
⚠️ 问题:
SpringMVC 的 DispatcherServlet
默认只处理动态请求(Controller 处理的),对像 /css/style.css
、/js/app.js
这样的静态资源它是不会处理的,所以最终就 404 了。
3-2、<mvc:default-servlet-handler>
的作用
该配置的作用是:
告诉 SpringMVC:你不处理静态资源,请把它们交回给默认的 Servlet(即 Tomcat 的 DefaultServlet)去处理。
处理顺序:
1、先交给dispatherServlet处理;
2、找不到,交给defaultServlet处理;
3、找不到,返回404!
示例配置:在springMVC.xml文件中配置
<mvc:default-servlet-handler />
配合使用 DispatcherServlet
的 /
映射时效果最好:
<servlet-mapping><servlet-name>springDispatcher</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
【注意】:
![]()
这两个注解要一起使用,要是只配置了
default-servlet-handler,所有的请求将交给default-servlet-handler处理!包括动态请求!
3-3、补充:Spring Boot 中怎么处理静态资源?
Spring Boot 不需要配置 <mvc:default-servlet-handler>
,它默认自动处理静态资源,资源路径为:
src/main/resources/static/
src/main/resources/public/
src/main/resources/resources/
3-4、WEB-INF下的静态资源
即使你配置了 <mvc:default-servlet-handler/>
,如果静态资源(如 .html
、.css
、图片等)放在 WEB-INF
文件夹下,浏览器依然无法直接访问!
Web 容器(如 Tomcat)会自动阻止用户直接访问 WEB-INF
及其子目录的任何资源,这是 Java Web 的安全机制。
正确放静态资源的位置:
你应该把 HTML、CSS、JS、图片 等资源放在这些位置:
放置路径 | 是否能被访问 | 说明 |
---|---|---|
/webapp/static/ | ✅ 可以访问 | 推荐:SpringMVC 中常用 |
/webapp/public/ | ✅ 可以访问 | Tomcat 支持的默认静态目录 |
/webapp/css/ 、/js/ | ✅ 可以访问 | 可以自由命名 |
/WEB-INF/ | ❌ 不能访问 | SpringMVC 和浏览器都无法直接访问 |
示例项目结构(推荐):
src
└── main└── webapp├── index.html ✅ 可访问:http://localhost:8080/项目名/index.html├── css/│ └── style.css ✅ 可访问:http://localhost:8080/项目名/css/style.css├── js/└── WEB-INF/└── views/└── page.jsp ✅ 只能通过控制器转发访问,不能直接访问
那 WEB-INF
的作用是什么?
用来存放 JSP 文件(如视图页面)
保证用户不能通过 URL 直接访问它们
必须通过控制器转发才能访问,如:
3-5、总结:
在 Spring MVC 中,
<mvc:default-servlet-handler />
是用于将 静态资源请求交还给 Web 容器(如 Tomcat)默认处理的关键配置,如果你使用了/
映射 DispatcherServlet,就必须加它,否则 CSS/JS/图片可能无法加载。