MVC架构模式#
约 2664 个字 156 行代码 预计阅读时间 58 分钟
不使用MVC模式存在的问题#
- 不使用MVC模式,Servlet需要负责
数据接收
、核心业务逻辑处理
、数据库连接和增删改查操作
、页面展示
等功能。职责过重。 - 代码的
复用性差
,相同的业务操作或数据库操作,需要在不同Servlet中编写重复代码,不方便维护。 - 代码
耦合度高
,导致代码很难扩展。 - 操作数据库的代码和处理业务逻辑的代码混杂在一起,很容易出错,无法专注于业务逻辑的编写。
MVC模式概述#
M(Model、模型)
:用于处理业务V(View、视图)
:负责页面展示C(Controller、控制器)
:控制器是MVC架构的核心,
DAO(Data Access Object、数据访问对象)
属于JavaEE的设计模式之一。只负责数据库的增删改查,没有任何业务逻辑在里面
三层架构#
表示层
:Controller控制器+View视图业务逻辑层
:Service服务持久化层
:DAO数据访问对象
Spring MVC概述#
Spring Web MVC
是基于 Servlet API 构建的原始 Web 框架,从 Spring 框架诞生之初就已包含其中。其正式名称Spring Web MVC
源自其源码模块名称:spring-webmvc
,但更常被称为Spring MVC
。
与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个名为Spring WebFlux
的响应式堆栈Web框架,其名称也基于其源模块 spring-webflux
。
Spring MVC
是实现MVC架构模式
的Web框架。底层使用Servlet
实现。
Spring MVC能干什么
- 入口控制:通过
DispatcherServlet
作为入口控制器负责接收请求和分发请求。 - 自动将表单请求参数封装为JavaBean对象
- 统一使用IOC容器管理对象
- 统一请求处理:提供拦截器、统一异常处理等机制
- 视图解析:轻松切换JSP、Freemarker、Velocity等视图模板
- 对Controller进行单元测试时
入口控制
:Servlet开发中,每个Servlet都需要在web.xml中进行配置,Spring MVC通过DispatcherServlet
作为入口控制器负责统一接收请求和分发请求。- Spring MVC会自动将表单数据封装为JavaBean对象,而不需要手动通过request对象获取表单数据。
- Spring MVC通过IOC容器管理对象,不需要手动创建对象。
- Spring MVC提供拦截器、异常处理器等统一处理请求机制。不需要手动编写过滤器。
视图解析器
:Spring MVC提供了JSP、Freemarker、Velocity等视图解析器。
Spring MVC入门案例#
创建maven工程,将工程改为war包,引入依赖:
<?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.luguosong</groupId>
<artifactId>springmvc-hello</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--Spring MVC依赖中包含了Spring的相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.8</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<!--provided表示该依赖只在编译和测试时有效-->
<!--打war包时不会包含,由Tomcat提供-->
<scope>provided</scope>
</dependency>
<!--日志-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.3</version>
</dependency>
<!--thymeleaf与spring6整合-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Warning
注意,需要将maven工程改为war包:<packaging>war</packaging>
创建webapp/WEB-INF/web.xml
目录和文件。
在web.xml
中配置前端控制器(DispatcherServlet):
Note
相比于Servlet开发,Spring MVC会配置一个全局统一的DispatcherServlet
来管理所有请求。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--优化:让DispatcherServlet在启动时就加载,而不是首次访问时加载,提高首次访问速度-->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--url-pattern配置/表示处理除jsp外的所有请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在Spring MVC配置文件配置包扫描视图解析器:
其中常见的视图解析器有以下几种:
- JSP的视图解析器:InternalResourceViewResolver
- FreeMarker的视图解析器:FreeMarkerViewResolver
- Velocity的视图解析器:VelocityViewResolver
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.luguosong.controller"/>
<!--配置视图解析器-->
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="order" value="1"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring6.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
编写视图:
编写Controller:
package com.luguosong.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
public class HelloController {
//请求映射
@RequestMapping("/hello-mvc")
public String hello() {
//返回逻辑视图名称
return "hello";
}
}
Note
逻辑视图名称
会根spring mvc配置文件中的prefix
和suffix
属性进行拼接。找到具体的视图位置(物理视图名称)。
启动Tomcat,通过以下地址可以访问视图:
Spring MVC执行流程#
自定义Spring MVC配置文件名称#
默认情况下,Spring MVC会根据web.xml中<servlet-name>标签
的值去寻找Spring MVC配置文件。
比如<servlet-name>
的值为springmvc
,那么就会去寻找/WEB-INF/springmvc-servlet.xml
配置文件。
当然,也可以手动指定Spring MVC配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定配置文件位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
@RequestMapping注解#
@RequestMapping注解的使用#
您可以使用@RequestMapping
注解将请求映射到控制器方法。
@RequestMapping
可以作用于类
或者方法
。
value属性#
value属性
与path属性
功能相同,都是用于映射请求路径。
@Controller
public class HelloController {
//请求映射
@RequestMapping("/hello1-1")
public String hello() {
//返回逻辑视图名称
return "hello";
}
//多个映射可以指向同一个方法
@RequestMapping({"/hello2-1", "/hello2-2"})
public String hello() {
//返回逻辑视图名称
return "hello";
}
}
value属性Ant风格#
value属性也支持Ant风格
的通配符:
?
:匹配任意单个字符*
:匹配任意多个字符**
:匹配任意多个字符(包括目录,即/
)
Warning
如果使用**
,左右两边只能是/
。
@Controller
public class HelloController {
//?表示任意单个字符,比如 hello1 或 helloa 都会访问到该方法
@RequestMapping("/hello?")
public String hello() {
//返回逻辑视图名称
return "hello";
}
}
value属性占位符#
使用占位符
,可以实现Restful风格
的参数传递
方法中通过@PathVariable
获取参数
@Controller
public class HelloController {
@RequestMapping("/login/{username}/{password}")
public String login(@PathVariable String username,
@PathVariable String password) {
//用户登录
//...
return "ok";
}
}
method属性#
method属性
用于限制请求方法,method
属性的值可以是GET
、POST
、PUT
、DELETE
等。
@Controller
public class HelloController {
//只会接收Get类型的请求
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
//返回逻辑视图名称
return "hello";
}
}
衍生Mapping#
除了@RequestMapping
注解,还可以使用@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
、@PatchMapping
等注解。表示具体method方法的请求。
params属性#
params属性
对请求参数进行限制
@Controller
public class HelloController {
//表示请求参数中必须存在username和password,且username必须为张三
@PostMapping(value = "/hello", params = {"username=张三", "password"})
public String hello() {
//返回逻辑视图名称
return "ok";
}
}
headers属性#
headers属性
对请求头进行限制
@Controller
public class HelloController {
//表示请求头中必须存在token
@PostMapping(value = "/hello", headers = {"token"})
public String hello() {
//返回逻辑视图名称
return "ok";
}
}
获取请求参数#
形参获取表单请求参数#
package com.luguosong.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/form")
public class FormController {
@GetMapping("/formView")
public String formView() {
return "get-parameters/form";
}
/*
* 模拟Servlet接收参数
* */
@PostMapping("/servlet")
public String servletPost(HttpServletRequest request) {
request.setAttribute("username", request.getParameter("username"));
return "get-parameters/form";
}
/*
* @RequestParam注解value值为请求参数名
* required属性表示参数是否必须,默认为true
* defaultValue属性为默认值
* */
@PostMapping("/springMvc")
public String springMvc(
@RequestParam(
value = "username",
required = false,
defaultValue = "张三") String username,
HttpServletRequest request) {
request.setAttribute("username", username);
return "get-parameters/form";
}
/*
* 如果请求参数的形参名和方法参数名一样,则@RequestParam注解可以省略
* */
@PostMapping("/springMvc2")
public String springMvc2(
String username,
HttpServletRequest request) {
request.setAttribute("username", username);
return "get-parameters/form";
}
}
如果是Spring6+,想要省略@RequestParam注解,需要在pom.xml中配置-parameters
标记
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
JavaBean获取表单请求参数#
package com.luguosong.controller;
import com.luguosong.pojo.User;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/formPojo")
public class FormPojoController {
@PostMapping("/springMvc")
public String springMvcPojo(
User user,
HttpServletRequest request) {
request.setAttribute("username", user.getUsername());
return "get-parameters/form";
}
}
package com.luguosong.pojo;
/**
* @author luguosong
*/
public class User {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
}
Get请求中文乱码问题#
Tomcat8以及之前版本,解决Get请求中文乱码,在Tomcat服务器CATALINA_HOME/conf/server.xml
中配置:
Tomcat8之后版本,请求行默认采用UTF-8编码,无需解决中文乱码问题。
Post请求中文乱码问题#
Tomcat9以及之前的版本,需要解决Post请求中文乱码问题。
在Servlet编程
中,可以使用request.setCharacterEncoding("UTF-8");
解决乱码问题。
但在Spring MVC中,无法在Controller中使用以上方法解决中文乱码。
解决方案一:编写Servlet过滤器
,过滤器会在DispatcherServlet之前执行。因此在过滤器中设置 request.setCharacterEncoding("UTF-8");
可以解决乱码问题。
解决方案二:Spring MVC为我们提供了类似的过滤器类CharacterEncodingFilter,无需我们重新手写过滤器类。只需要在web.xml
中配置该过滤器并设置encoding属性
即可。
Tomcat10请求体默认采用UTF-8编码,无需解决中文乱码问题。
获取请求头信息#
根据请求头名称获取请求头信息#
package com.luguosong.controller.header_info;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/header-info")
public class HeaderInfoController {
@PostMapping("/springMvc")
public String springMvc(@RequestHeader(value = "content-type", required = false) String contentType) {
System.out.println(contentType);
return "header-info/form";
}
}
获取Cookie信息#
package com.luguosong.controller.header_info;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/cookie")
public class CookieController {
/*
* ❗cookie需要在父路径相同的情况才能保存下来
* 因此通过该地址访问视图
* */
@GetMapping("/view")
public String view() {
return "header-info/form";
}
@RequestMapping("/springMvc")
public String springMvc(@CookieValue("username") String username) {
System.out.println(username);
return "header-info/form";
}
}
域对象操作#
request域#
package com.luguosong.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/request-scope")
public class RequestScopeController {
/**
* 模拟Servlet存储Request域
*/
@RequestMapping("/servlet")
public String servletTest(HttpServletRequest request) {
request.setAttribute("requestScope", "通过HttpServletRequest设置请求域");
return "request-scope";
}
/*
* Model对象存储request域
* */
@RequestMapping("/model")
public String modelTest(Model model) {
model.addAttribute("requestScope", "通过Model对象设置请求域");
return "request-scope";
}
/*
* Map集合存储request域
* */
@RequestMapping("/map")
public String mapTest(Map<String, Object> map) {
map.put("requestScope", "通过Map对象设置请求域");
return "request-scope";
}
/*
* ModelMap对象存储request域
* */
@RequestMapping("/modelMap")
public String modelMapTest(ModelMap modelMap) {
modelMap.addAttribute("requestScope", "通过ModelMap对象设置请求域");
return "request-scope";
}
/*
* ⭐ModelAndView对象存储request域
* */
@RequestMapping("/modelAndView")
public ModelAndView modelAndViewTest() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("requestScope", "通过ModelAndView对象设置请求域");
modelAndView.setViewName("request-scope");
return modelAndView;
}
}
不管是Model对象
、Map集合
还是ModelMap对象
,实际创建的的都是BindingAwareModelMap对象
。
Spring MVC为了更好的体现MVC架构模式,还提供了ModelAndView类
,这个类封装了Model和View。也就是说这个类封装业务处理之后的数据,体支持跳转指定视图。通过ModelAndView也可以设置请求域。
session域#
package com.luguosong.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/session-scope")
@SessionAttributes({"sessionScope"})
public class SessionScopeController {
/*
* 通过Servlet方式设置session
* */
@RequestMapping("/servlet")
public String servletTest(HttpServletRequest request) {
request.getSession().setAttribute("sessionScope", "通过Servlet原生方式设置session域");
System.out.println(request.getSession().getAttribute("sessionScope"));
return "session-scope";
}
/*
* 通过@SessionAttributes注解设置session
* */
@RequestMapping("/modelAndView")
public ModelAndView modelAndViewTest() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("sessionScope", "通过@SessionAttributes注解方式设置session域");
modelAndView.setViewName("session-scope");
return modelAndView;
}
}
一般情况下modelAndView.addObject
是设置request域的,但通过@SessionAttributes({"xxx"})
注解可以指定特定字段为session域。
application域#
package com.luguosong.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
@RequestMapping("/application-scope")
public class ApplicationScopeController {
@RequestMapping("/servlet")
public String servletTst(HttpServletRequest request) {
request.getServletContext().setAttribute("applicationScope", "通过Servlet方式设置application域");
return "application-scope";
}
}
一般直接采用Servlet原始方式设置application域。
视图(View)#
常见的视图#
InternalResourceView
:内部资源视图,Spring MVC框架内置,专门为JSP模板语法准备RedirectView
:重定向视图,Spring MVC框架内置,用来完成重定向效果ThymeLeafView
:Thymeleaf 是一种现代化的服务器端 Java 模板引擎,适用于网页和独立环境。Thymeleaf 的主要目标是为您的开发流程带来优雅的自然模板——这些 HTML 可以在浏览器中正确显示,同时也能作为静态原型使用,从而增强开发团队的协作。它提供了 Spring Framework 的模块、与您喜爱的工具的多种集成,并允许您插入自己的功能,因此 Thymeleaf 非常适合现代 HTML5 JVM 的网页开发——尽管它的功能远不止于此。FreeMarkerView
:Apache FreeMarker™ 是一个模板引擎:它是一个 Java 库,用于根据模板和变化的数据生成文本输出(如 HTML 网页、电子邮件、配置文件、源代码等)。模板使用 FreeMarker 模板语言(FTL)编写,这是一种简单的专用语言(不像 PHP 那样是完整的编程语言)。通常,会使用通用编程语言(如 Java)来准备数据(执行数据库查询、进行业务计算)。然后,Apache FreeMarker 使用模板展示这些准备好的数据。在模板中,你专注于如何展示数据,而在模板之外,你专注于展示哪些数据。VelocityView
:VelocityView 包含所有的 GenericTools,并增加了在 Web 应用程序(Java EE 项目)视图层中使用 Velocity 的基础设施和专用工具。这包括用于处理 Velocity 模板请求的 VelocityViewServlet 或 VelocityLayoutServlet,以及用于在 JSP 中嵌入 Velocity 的 VelocityViewTag。PDFView
:第三方,用于生成pdf文件视图ExcelView
:第三方,用于生成excel文件视图
配置JSP视图解析器#
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.luguosong.controller"/>
<!--配置JSP视图解析器-->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
配置Thymeleaf视图解析器#
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.luguosong.controller"/>
<!--配置视图解析器-->
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="order" value="1"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring6.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
视图控制器#
如何仅仅是进行视图转发,无需编写Controller类,可以通过spring mvc配置文件mvc:view-controller
标签进行配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.luguosong.controller"/>
<!--配置JSP视图解析器-->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--在Spring MVC配置文件中配置视图控制器-->
<mvc:view-controller path="/test" view-name="test"/>
<!--<mvc:view-controller/>会让Spring MVC项目中的注解失效,需要重新开启-->
<!--开启注解驱动-->
<mvc:annotation-driven/>
</beans>
转发和重定向#
package com.luguosong.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author luguosong
*/
@Controller
public class TestController {
/*
* 转发
* */
@RequestMapping("forward")
public String forwardTest() {
return "forward:/test";
}
/*
* 重定向
* */
@RequestMapping("redirect")
public String redirectTest() {
return "redirect:/test";
}
@RequestMapping("/test")
public String test() {
return "test";
}
}
静态资源访问#
由于DispatcherServlet的url-pattern
配置的是/
,访问静态资源会经过DispatcherServlet
。DispatcherServlet
没有静态资源处理。
方式一:开启默认Servlet#
Tomcat目录conf/web.xml
中存在名为default
的servlet
其url-pattern
与DispatcherServlet
一样也是/
,因此默认servlet
访问被DispatcherServlet
覆盖。
Spring MVC仍然允许静态资源请求由Tomcat的默认Servlet
处理。它配置了一个DefaultServletHttpRequestHandler
,URL映射为/**
,并且相对于其他URL映射具有最低优先级
。
以下示例展示了如何通过默认设置启用该功能:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
以下示例展示了如何在Spring MVC配置文件 XML 中实现相同的配置:
方式二:配置静态资源处理#
在下一个示例中,对于以 /resources 开头的请求,将使用相对路径来查找和提供相对于 Web 应用程序根目录下的 /public 或类路径下的 /static 的静态资源。这些资源的过期时间设置为一年,以确保最大限度地利用浏览器缓存并减少浏览器发出的 HTTP 请求。Last-Modified 信息通过 Resource#lastModified 推断,以支持带有 "Last-Modified" 头的 HTTP 条件请求。
以下列表展示了如何使用 Java 配置来实现:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
}
}
以下示例展示了如何在 XML 中实现相同的配置:XML
<beans>
<mvc:resources mapping="/resources/**"
location="/public, classpath:/static/"
cache-period="31556926"/>
<mvc:annotation-driven/>
</beans>
RESTFul#
概述#
RESTFul是web服务接口的一种设计风格
。提供了一套约束,可以让web服务接口更加简介、易于理解。
- 查询:使用GET方法请求
- 添加:使用POST方法请求
- 更新:使用PUT方法请求
- 删除:使用DELETE方法请求
请求参数从/springmvc/getUserById?id=1
风格转为/springmvc/user/1
风格,变得更加简洁。
示例#
模拟通过表单发送get
、post
、put
、delete
请求。
Warning
理论上表单只能发送get请求
和post请求
。
但是可以借助HiddenHttpMethodFilter过滤器
,将post
方法转为put
、delete
或patch
方法。