springMVC02-视图解析器、RESTful设计风格,静态资源访问配置

一、SpringMVC 的视图

在 SpringMVC 中,视图的作用渲染数据,将模型 Model (将控制器(Controller))中的数据展示给用户。

在 Java 代码中,视图由接口 org.springframework.web.servlet.View 表示

SpringMVC 视图的种类很多,默认转发视图InternalResourceView重定向视图RedirectView

当工程引入 Jstl 的依赖,转发视图会自动转换为 JstlView;

若使用的视图技术为 Thymeleaf,在 SpringMVC 的配置文件中配置了 Thymeleaf 的视图解析器,由此视图解析器解析之后所得到的是 ThymeleafView。

1-1、视图解析流程(基本原理)

当你在控制器中 return "success",SpringMVC 会做以下几步:

  1. "success" 当作视图名(ViewName)

  2. 使用 视图解析器(ViewResolver) 解析这个视图名

  3. 返回一个实现了 View 接口的视图对象(如 InternalResourceView, JstlView, ThymeleafView

  4. 调用 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 路径对比

功能传统风格 URLRESTful 风格 URL
查询用户/user/get?id=1GET /user/1
添加用户/user/addPOST /user
修改用户/user/update?id=1PUT /user/1
删除用户/user/delete?id=1DELETE /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/图片可能无法加载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88169.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go中使用Google Authenticator

现在为了安全Google二次验证使用越来越平凡了&#xff0c;所以我们自己做的一些产品中&#xff0c;也会用到Google Authenticator。 介绍 Google Authenticator采用的算法是TOTP&#xff08;Time-Based One-Time Password基于时间的一次性密码&#xff09;&#xff0c;其核心内…

ReactNative【实战系列教程】我的小红书 4 -- 首页(含顶栏tab切换,横向滚动频道,频道编辑弹窗,瀑布流布局列表等)

最终效果 顶栏 modules/index/components/topBar.tsx import icon_daily from "/assets/images/icon_daily.png"; import MaterialIcons from "expo/vector-icons/MaterialIcons"; import { useCallback, useState } from "react"; import { Im…

告别Root风险:四步构建安全高效的服务器管理体系

当整个开发团队都使用root账号操作服务器&#xff0c;且重要数据无备份时&#xff0c;系统如同行走在悬崖边缘。本文将分享一套经过验证的四步解决方案&#xff0c;帮助团队快速提升主机安全性。 为什么必须告别Root账号&#xff1f; 直接使用root账号的风险&#xff1a; &am…

【IM项目笔记】1、WebSocket协议和服务端推送Web方案

这里写自定义目录标题 1、HTTP和WebSocket协议2、WebSocket3、Http VS WebSocket4、WebSocket - 建立连接5、服务端推送Web方案(1) 短轮询(2) 长轮询(3) WebSocket长连接1、HTTP和WebSocket协议 📕 HTTP请求的特点:通信只能由客户端发起。所以,早期很多网站为了实现推送技…

【深度学习新浪潮】什么是上下文长度?

大型语言模型(LLM)的上下文长度是指模型在处理当前输入时能够有效利用的历史文本长度,通常以token(如单词、子词或标点)为单位衡量。例如,GPT-4支持128K token的上下文,而Llama 4 Scout甚至达到了10M token的惊人规模。这一指标直接影响模型在长文档理解、多轮对话等复杂…

Modbus TCP转Profibus网关轻松让流量计与DCS通讯

Modbus TCP转Profibus网关轻松让流量计与DCS通讯工业自动化系统中&#xff0c;协议差异常成为设备互联的“语言障碍”。例如&#xff0c;当流量计采用Modbus TCP协议&#xff0c;而DCS系统仅支持Profibus DP时&#xff0c;如何实现无缝通信&#xff1f;本文将结合技术原理与真实…

云时代下的IT资产管理自动化实践

前言伴随着企业数字化转型进程的加快&#xff0c;IT资产规模日益庞大且复杂。传统的手工IT资产登记、跟踪与管理方式&#xff0c;效率低下且容易出错&#xff0c;已经无法满足现代企业对于敏捷化、可视化和自动化运维的需求。云计算、容器化、微服务架构的普及又进一步加快了资…

Windows主机远程桌面连接Ubuntu24.04主机

最近刚刚换了台新电脑&#xff0c;想着空出老电脑直接装一个Ubuntu系统给新电脑远程连接过去进行开发&#xff0c;就可以完美避开双系统老是要重启切换的问题。仔细一查发现Ubuntu24.04自带了RDP远程工具&#xff0c;大喜&#xff01;于是探究了一番。 本篇文章将介绍本人探究…

Android WebView 性能优化指南

Android WebView 性能优化指南 WebView优化需要从多个维度综合考虑&#xff1a;优化维度关键措施预期收益初始化延迟加载、实例复用降低内存峰值渲染硬件加速、合理布局提升流畅度20%内存独立进程、泄漏防护减少OOM风险网络缓存策略、资源拦截节省流量30%安全漏洞修复、接口限制…

Linux下SPHinXsys源码编译安装及使用

目录 软件介绍 基本依赖 一、源码下载 二、安装依赖库 1、BLAS 2、LAPACK 3、oneTBB 4、googletest 5、Boost 6、Simbody 7、pybind11 8、Eigen3 三、解压缩 四、编译安装 软件介绍 SPHinXsys是胡湘渝博士团队采用C/C开发的一个开源无网格、多分辨率、多物理场、…

Linux中的静态库和动态库

首先 我们要明白什么是库? 库&#xff08;Library&#xff09;是一组预编译的代码&#xff0c;提供特定的功能&#xff0c;可以被多个程序共享调用&#xff0c;避免重复编写代码。在链接步骤中&#xff0c;链接器将从库文件取得所需的代码&#xff0c;复制到生成的可执行文件中…

Vue3-组件化-Vue核心思想之一

一.组件及组件化1.组件化的作用由于之前的代码全写在一个App.vue这个文件里面&#xff0c;会到导致一个文件代码过于多而且不易复用&#xff0c;所以有组件化的思想。2.组件的使用①创建创建一个.vue文件&#xff0c;使用setup的简写方式会自动导出.vue文件②导入import 组件对…

OS学习笔记

《几个基本知识点》 一、2的幂 1024210 51229 25628 12827 6426 3225 1624 823 422 221 K210 G220 M230 T240 P250 E260 Z270 Y280 R290 Q2100 二、常用的ASCII码 ‘1’0x31 ‘A’0x41 ‘a’0x61 空格0x20 换行0x0A 回车0x0D 三、存储器层次中的典型速度 CPU/寄存器&#xff1a…

嵌入式学习笔记-MCU阶段-DAY01

恭喜大家完成了C语言的学习&#xff0c;现在咱们来到咱们的硬件MCU阶段&#xff0c;咱们这里的工程用的是keil&#xff0c;环境搭建不再赘述&#xff0c;希望大家在这一阶段仍然学的愉快 1.资料部分 用的最多的就是STM32f103的手册&#xff0c;搭配STM32F103ZET6的开发板 2.概…

three案例 Three.js波纹效果演示

波纹效果&#xff0c;在智慧城市可视化开发中经常用到&#xff0c;这里分享一个比较好玩的案例 以下是详细的步骤&#xff1a; 初始化部分&#xff1a;设置 Three.js 环境&#xff0c;包括场景、相机、渲染器和控制器 几何体和纹理&#xff1a;创建平面几何体并加载波纹纹理 着…

Flutter-详解布局

上一章我们详细的学习了 Flutter 中的Widget&#xff0c;这一章我们将要学习 Flutter 的布局&#xff0c; 在上一章我们了解到了&#xff1a;Everything is a widget&#xff0c;在 Flutter 中几乎所有的对象都是一个 Widget &#xff0c;当然也包括布局&#xff0c;Flutter 的…

EPLAN 电气制图:建立自己的部件库,添加部件-加SQL Server安装教程(三)上

在智能电气设计领域&#xff0c;EPLAN 作为主流的设计软件&#xff0c;其部件库的完善程度直接影响项目设计的效率与质量。本文将从实际操作出发&#xff0c;详细讲解如何在 EPLAN 中建立专属部件库并添加部件&#xff0c;为电气设计奠定坚实基础。一、部件库&#xff1a;电气设…

静态路由进阶实战全解

一、项目背景二、项目拓扑图三、设备命名与IP地址规划设备名接口编号IP地址规划R1GE0/0192.168.1.1/24GE0/1172.16.1.1/24R2GE0/0192.168.1.2/24GE0/1192.168.2.2/24R3GE0/0192.168.2.3/24GE0/1192.168.3.3/24GE0/2192.168.4.3/24R4GE0/0192.168.3.4/24GE0/1192.168.4.4/24GE0/…

stm32hal模块驱动(3)ssd1305 oled驱动

SD1305 OLED 驱动芯片详细介绍SSD1305 是 Solomon Systech 公司生产的一款 OLED 显示控制器/驱动器&#xff0c;专为 128x64 或 128x32 点阵的 OLED 显示屏设计。下面我将从多个方面详细介绍这款驱动芯片。一、SSD1305 基本特性显示分辨率&#xff1a;最大支持 128 segments 6…

安全为先:如何在 Python 中安全处理数据库连接与敏感信息

安全为先:如何在 Python 中安全处理数据库连接与敏感信息 引言:Python 与安全的数据库交互 自 1991 年诞生以来,Python 凭借其简洁优雅的语法和强大的生态系统,成为 Web 开发、数据科学、人工智能和数据库交互的首选语言。作为“胶水语言”,Python 不仅让开发者能够快速…