一、Spring MVC 的简介
- Spring MVC 是 Spring 提供的 MVC 框架
- Spring MVC 是 Spring Framework 的一部分,负责表示层
二、Spring MVC 的架构图
三、Spring MVC 的入门案例
1. 入门案例一
1.1 在 pom.xml 中导入相关依赖
<!-- 导入 spring-webmvc 会自动导入 spring 的相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- 入门案例一使用了,所以要导入 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<scope>provided</scope>
</dependency>
1.2 在 web.xml 中配置控制器并加载 Spring 的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>
dispatcherServlet
</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<!-- 加载 Spring 的配置文件 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--dispatcherServlet 的 url 为 "/",千万注意 -->
<!-- 不能配置为 /*,否则 Spring MVC 给出的结果视图是 JSP 的话,因为是转发,会出现循环,出现又进入 springmvc 的情况 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
1.3 在 application.xml 中配置映射器和处理器
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启 Spring 的注解扫描 -->
<context:component-scan base-package="com.chenlianyuan"/>
<!-- 映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean name="/hello" class="com.cskaoyan.controller.HelloController"/>
</beans>
1.4 创建 controller 类用于演示
package com.cskaoyan.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller {public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest,javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {ModelAndView modelAndView = new ModelAndView();
String value = "SpringMvc";
modelAndView.setViewName("hello.jsp");
modelAndView.addObject("value",value);
return modelAndView;
}
}
1.5 创建 JSP 页面用于演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
Hello ${value}
</body>
</html>
1.6 结果
2. 入门案例二
2.1 在 pom.xml 中导入相关依赖
同入门案例一
2.2 在 web.xml 中配置控制器并加载 Spring 的配置文件
同入门案例一
2.3 开启 Spring MVC 的注解扫描(及注册驱动)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 需要一个 mvc 的标签 -->
<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:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--Spring 的注解开关 -->
<context:component-scan base-package="com.cskaoyan"/>
<!--Spring MVC 的注解开关(注册驱动)-->
<!-- 加了这句话以后会自动配置最新版的注解的处理器映射器和处理器适配器 -->
<mvc:annotation-driven/>
</beans>
2.4 创建 controller 类用于演示
package com.cskaoyan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {@RequestMapping("hello")
public ModelAndView hello1(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("hello.jsp");
modelAndView.addObject("value","Hello Spring MVC");
return modelAndView;
}
}
2.5 创建 JSP 页面用于演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
Hello ${value}
</body>
</html>
2.6 结果
三、Spring MVC 的用法
1. URL 路径映射
1.1 一个 URL 映射到一个方法上
// 代码节选
@Controller
public class MyController{
//URL 和方法建立联系
@RequestMapping(value = "hello")
public ModelAndView hello(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/hello.jsp");
modelAndView.addObject("value","Spring MVC");
return modelAndView;
}
//URL 和方法建立联系
@RequestMapping(value = "goodbye")
public ModelAndView hello1(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/goodbye.jsp");
modelAndView.addObject("value","Spring MVC");
return modelAndView;
}
}
1.2 多个 URL 映射到一个方法上(一一列举)
// 代码节选
@Controller
public class MyController{
// 多个 URL 和方法建立联系
@RequestMapping(value = {"login1","login2","login3"})
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("value","Please sign in");
return modelAndView;
}
}
1.3 多个 URL 映射到一个方法上(使用通配符)
// 代码节选
@Controller
public class MyController{
// 多个 URL 和方法建立联系
@RequestMapping(value = {"login*"})
public ModelAndView hello(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("value","Please sign in");
return modelAndView;
}
}
2. 请求方法限定(错误码 405)
2.1 方式一
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 限定了请求方法
@RequestMapping(value = "register",method = RequestMethod.POST)
public ModelAndView register(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/user.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
2.2 方式二
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 注解上已限定了请求方法
@PostMapping("login")
//@GetMapping("login")
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
// 代码节选
//@PostMapping 注解内部
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = {RequestMethod.POST}
)
public @interface PostMapping {...// 省略}
3. 参数的限定(错误码 400)
3.1 限定必须有某个参数
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 要求必须要有 "username" 和 "password" 两个参数
@RequestMapping(value = "login",method = RequestMethod.POST,params ={"username","password"})
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
3.2 限定参数的值
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 要求 "username" 参数的值不能为 "XiDaDa"
@RequestMapping(value = "login",method = RequestMethod.POST,params ={"username!=XiDaDa","password"})
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
4. Content-type 的限定(错误码 415)
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 限定了 Content-type 类型
@RequestMapping(value = "login",method = RequestMethod.POST,params ={"username!=XiDaDa","password"},consumes = "text/html")
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
5. Accept 限定(错误码 406)
// 代码节选
@Controller
@RequestMapping("user")
public class UserController{
// 限定了 Accept 类型
@RequestMapping(value = "login",method = RequestMethod.POST,params ={"username!=XiDaDa","password"},produces = "text/html")
public ModelAndView login(){ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
modelAndView.addObject("method","register");
return modelAndView;
}
}
五、Spring MVC 的 Controller 方法的返回值
1. 返回 ModelAndView
// 节选部分代码
@Controller
@RequestMapping(value = "hello")
public class MyController {@RequestMapping(value = "modelAndView")
public ModelAndView showUser() throws Exception{User user = new User();
user.setAge(1);
user.setName("ChenLianYuan");
user.setPhoneNumber("123456789");
// 新建一个 ModelAndView 类
ModelAndView modelAndView = new ModelAndView();
//Model 处理:通过 modelandView 的 addObject 方法
modelAndView.addObject("user",user);
//View 的处理:通过 modelandView 的 setViewName 方法
modelAndView.setViewName("user");
return modelAndView;
}
}
<!--user.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
Hello ${user}
</body>
</html>
2. 返回 void
// 节选部分代码
@Controller
public class MyController {@RequestMapping(value = "void")
public void showUser(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception{User user = new User();
user.setAge(1);
user.setName("ChenLianYuan");
user.setPhoneNumber("123456789");
// 通过 Request 和 Response 去实现 Model 和 view 的处理
httpServletRequest.setAttribute("user",user);
httpServletRequest.getRequestDispatcher("/WEB-INF/user.jsp").forward(httpServletRequest,httpServletResponse);
return;
}
}
<!--user.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
Hello ${user}
</body>
</html>
3. 返回字符串
3.1 物理视图名
// 节选部分代码
@Controller
public class MyController {@RequestMapping(value = "unhappy")
// 使用的是 org.springframework.ui.Model
public String unHappy(Model model){model.addAttribute("method","unHappy");
// 物理视图
return "/WEB-INF/view/Hellp.jsp";
}
}
3.2 逻辑视图名
@Controller
public class MyController {@RequestMapping(value = "unhappy")
// 使用的是 org.springframework.ui.Model
public String unHappy(Model model){model.addAttribute("method","unHappy");
return "Hello";
}
}
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
3.3 重定向
// 重定向的是 URL,而不是页面
@Controller
public class MyController {
// 重定向到了这个方法
@RequestMapping(value = "hello2")
public String hello2(){return "/WEB-INF/view/hello1.jsp";}
@RequestMapping(value = "hello3")
public String hello3(){
return "forward:hello2";
// 重定向到了 hello2(),而不是 hello2.jsp
// 最终结果是访问到了 hello1.jsp
}
}
3.4 转发
4. 返回 JSON(演示)
4.1 导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
4.2 演示返回 JSON 数据
4.2.1 使用 @ResponseBody
@Controller
public class HelloController {@RequestMapping("hello")
//JSON 的注解。使返回值是 JSON 格式
@ResponseBody
public User hello(){User user = new User();
user.setUsername("ChenLianYuan");
user.setPassword("123456");
user.setId(1);
Hobby hobby = new Hobby();
hobby.setName("rap");
user.setHobby(hobby);
return user;
}
}
4.2.2 使用 @RestController
// 此注解是 @Controller 和 @ResponseBody 的结合
// 使用此注解相当于在当前类下的所有 @RequestMapping 的方法上都加了 @ResponseBody 注解
@RestController
public class HelloController {@RequestMapping("hello")
public User hello(){User user = new User();
user.setUsername("ChenLianYuan");
user.setPassword("123456");
user.setId(1);
Hobby hobby = new Hobby();
hobby.setName("rap");
user.setHobby(hobby);
return user;
}
}
4.3 额外演示下接收 JSON 数据(使用 Postman)
@RestController
public class GoodbyeController {@RequestMapping("goodbye")
public User Goodbye(@RequestBody User user){return user;}
}
六、Spring MVC 的请求参数的封装
1. 通过 Request 封装(以后不再使用这个)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<form action="/submitRequest" method="post">
<imput type="text" name="username"/><br/>
<imput type="text" name="password"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
@Controller
public class GoodbyeController {@RequestMapping("submitRequest")
public ModelAndView getParameterByRequest(HttpServletRequest request){String username = request.getParameter("username");
String password = request.getParameter("password");
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/view/show.jsp");
User user = new User(username,password);
modelAndView.addObject("user",user);
return modelAndView;
}
}
2. 自动封装(需要注意乱码问题和日期转换问题)
2.1 基本类型
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 基本类型参数的封装 </title>
</head>
<body>
<form action="/submitBaseParameter" method="post">
<imput type="text" name="username"/><br/>
<imput type="text" name="password"/><br/>
<imput type="text" name="age"/><br/>
<imput type="text" name="married"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
// 我们将 age 和 married 转换成 int 和 boolean 类型的值
// 通过 Spring MVC 默认提供的类型转换器
@Controller
public class MyController {
// 要求请求方法的形参的参数名要和 input 标签的 name 对应
@RequestMapping("submitBaseParameter")
public String getBaseParameter(String username,String password,int age,boolean married,Model model){User user = new User(username,password,age,married);
model.addAttribute("user",user);
return "show";
}
}
2.2 单级 JavaBean
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Java Bean 类型参数的封装 </title>
</head>
<body>
<form action="/submitJavaBeanParameter" method="post">
<imput type="text" name="username"/><br/>
<imput type="text" name="password"/><br/>
<imput type="text" name="age"/><br/>
<imput type="text" name="married"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
@Controller
public class MyController {
//Java Bean 写在请求方法的形参中
// 要求 Java Bean 的成员变量名和 input 标签中的 name 一致
@RequestMapping("submitJavaBeanParameter")
public String getBaseParameter(User user,Model model){User user = new User(username,password,age,married);
model.addAttribute("user",user);
return "show";
}
}
2.3 多级 JavaBean
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 多级 Java Bean 类型参数的封装 </title>
</head>
<body>
<form action="/submitMultiJavaBeanParameter" method="post">
<imput type="text" name="user.username"/><br/>
<imput type="text" name="user.password"/><br/>
<imput type="text" name="user.age"/><br/>
<imput type="text" name="user.married"/><br/>
<imput type="text" name="description"/><br/>
<imput type="text" name="count"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
public class SuperBean {
private User user;
private String descirption;
private int count;
...// 省略
}
// 多级 Java Bean 的成员变量名,要和 input 标签的头一级目录对应
2.4 日期(需要转换器)
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="myconverter" class="com.chenlianyuan.converter.StringToDateConverter"/>
<bean id="conversionService"
class="org.Springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myconverter"/>
</set>
</property>
</bean>
package com.chenlianyuan.converter;
public class StringToDateConverter implements Converter<String,Date> {
@Override
public Date convert(String s) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd");
try {Date parse = simpleDateFormat.parse(s);
return parse;
} catch(ParseException e) {e.printStackTrace();
}
return null;
}
}
2.5 数组(基本类型)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 数组类型 (基本类型) 参数的封装 </title>
</head>
<body>
<form action="/submitArray" method="post">
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
// 使用同一个 name,并且 input 标签中的 name 与形参的参数名对应
@Controller
public class MyController {@RequestMapping("submitArray")
public String getArray(String[] array){System.out.println(Arrays.toString(array));
return "show";
}
}
2.6 数组(JavaBean)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 数组类型 (JavaBean) 参数的封装 </title>
</head>
<body>
<form action="/submitArrayInJavaBean" method="post">
<imput type="text" name="name"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="text" name="array"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
public class ArrayBean {String[] array;
String name;
...// 省略
}
@Controller
public class MyController {@RequestMapping("submitArrayInJavaBean")
public String getArray(ArrayBean arrayBean){String[] array = arrayBean.getArray();
System.out.println(Arrays.toString(array));
return "show";
}
}
2.7 集合(用 List 演示)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title> 多级 Java Bean 类型参数的封装 </title>
</head>
<body>
<form action="/submitListBean" method="post">
<imput type="text" name="user.username"/><br/>
<imput type="text" name="user.password"/><br/>
<imput type="text" name="user.age"/><br/>
<imput type="text" name="user.married"/><br/>
<imput type="text" name="abc"/><br/>
<!--User 要和成员变量名对应 -->
<imput type="text" name="users[0].name"/><br/>
<imput type="text" name="users[0].password"/><br/>
<imput type="text" name="users[0].age"/><br/>
<imput type="text" name="users[0].married"/><br/>
<imput type="text" name="users[1].name"/><br/>
<imput type="text" name="users[1].password"/><br/>
<imput type="text" name="users[1].age"/><br/>
<imput type="text" name="users[1].married"/><br/>
<imput type="submit"/>
</form>
</body>
</html>
public class ListBean {
User user;
int abc;
ArrayList<User> users;
...// 省略
}
@Controller
public class MyController {@RequestMapping("submitListBean")
public String getListBean(ListBean listBean,Model model){
...
return "show";
}
}
七、Spring MVC 的文件上传(演示)
1. 导入依赖(pom.xml)
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2. 配置表单(FileUpload.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>FileUpload</title>
</head>
<body>
<h1> 文件上传 </h1>
<%--form 表单提交默认是 application/x-www-form-urlencoded--%>
<%-- 而上传文件把文件用二进制的方式传输,默认的格式已经满足不了需求,就需要使用 multipart/form-data 格式来发送接收 --%>
<form action="fileupload" enctype="multipart/form-data" method="post">
<input type="file" name="myfile"/><br/>
<input type="submit">
</form>
</body>
</html>
3. 配置上传成功页面(success.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
上传成功
</body>
</html>
4. 配置文件上传的处理器(application.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 需要一个 mvc 的标签 -->
<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:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--Spring 的注解开关 -->
<!--<context:component-scan base-package="com.chenlianyuan"/>-->
<!--Spring MVC 的注解开关 -->
<mvc:annotation-driven/>
<!--id 一定要等于 multipartResolver-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 可以限制上传的文件的大小 -->
<!-- 设置上传的文件的最大尺寸为 5MB-->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
</beans>
5. 创建 controller 类用于演示
package com.chenlianyuan.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
public class MyController {@RequestMapping(value = "fileupload")
// 参数名要和 input 标签中的 name 一致
public String fileupload(MultipartFile myfile) throws IOException{
// 创建一个文件夹用来接收文件
File directory = new File("D://FileUpload");
if (!directory.exists()){directory.mkdir();
}
String name = myfile.getName();
File file = new File(directory,name);
// 接收文件的核心代码
myfile.transferTo(file);
return "/success.jsp";
}
}
6. 注册 controller 类(application.xml)
<!-- 在 3. 所在的 application.xml 中注册 -->
八、Spring MVC 的静态资源处理
1. 方式一:通过默认的 servlet 进行放行
<!-- 在 web.xml 中加上 -->
<!-- 要配置多个,每种文件配置一个 -->
<!-- 要写在 DispatcherServlet 的前面,让 defaultServlet 先拦截请求,这样请求就不会进入 Spring 了 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
2. 方式二:web 服务器默认的资源处理器
<!-- 在 application.xml 中加上 -->
<!--web 服务器默认的资源处理器 -->
在 springMVC-servlet.xml(spring 的配置文件)中配置 <mvc:default-servlet-handler /> 后,会在 Spring MVC 上下文中定义一个 org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入 DispatcherServlet 的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理。一般 Web 应用服务器默认的 Servlet 名称是 "default",因此 DefaultServletHttpRequestHandler 可以找到它。如果你所有的 Web 应用服务器的默认 Servlet 名称不是 "default",则需要通过 default-servlet-name 属性显示指定:<mvc:default-servlet-handler default-servlet-name="所使用的 Web 服务器默认使用的 Servlet 名称" />
<mvc:default-servlet-handler/>
3. 方式三:Spring MVC 的资源处理器
<mvc:default-servlet-handler /> 将静态资源的处理经由 Spring MVC 框架交回 Web 应用服务器处理。而 <mvc:resources /> 更进一步,由 Spring MVC 框架自己处理静态资源,并添加一些有用的附加值功能。
首先,<mvc:resources /> 允许静态资源放在任何地方,如 WEB-INF 目录下、类路径下等,你甚至可以将 JavaScript 等静态文件打到 JAR 包中。通过 location 属性指定静态资源的位置,由于 location 属性是 Resources 类型,因此可以使用诸如 ”classpath:” 等的资源前缀指定资源位置。传统 Web 容器的静态资源只能放在 Web 容器的根路径下,<mvc:resources /> 完全打破了这个限制。
其次,<mvc:resources /> 依据当前著名的 Page Speed、YSlow 等浏览器优化原则对静态资源提供优化。你可以通过 cacheSeconds 属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的 Expires 和 Cache-Control 值。
在接收到静态资源的获取请求时,会检查请求头的 Last-Modified 值,如果静态资源没有发生变化,则直接返回 303 相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
在 springMVC-servlet 中添加如下配置:
<mvc:resources
location=”/,classpath:/META-INF/publicResources/” mapping=”/resources/**”/>
以上配置将 Web 根路径 ”/” 及类路径下 /META-INF/publicResources/ 的目录映射为 /resources 路径。假设 Web 根路径下拥有 images、js 这两个资源目录, 在 images 下面有 bg.gif 图片,在 js 下面有 test.js 文件,则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
假设 WebRoot 还拥有 images/bg1.gif 及 js/test1.js,则也可以在网页中通过 /resources/images/bg1.gif 及 /resources/js/test1.js 进行引用。
<!-- 在 application.xml 中加上 -->
<!--mapping:访问路径或映射路径 -->
<!--location:真实路径,要以 / 结尾 -->
<mvc:resources mapping="/abc/**" location="/WEB-INF/jpg/"/>
九、解决中文乱码
<!-- 在 web.xml 中注册 -->
<filter>
<filter-name>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<!-- 注意这里 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
十、Rest 风格
1. URL 的一部分作为形参
<!-- 如 CSDN 上的某一篇文章 -->
https://blog.csdn.net/weixin_39786569/article/details/91797233
<!-- 网址最后的 "91797233" 是文章的 ID-->
// 如某段 Rest 风格的代码
@Controller
public class MyController {
// 使用 @PathVariable 注解完成 Restful 风格
@RequestMapping("queryUser/id/{myid}/{name}")
public String queryUserById(@PathVariable("myid") int id,@PathVariable("name") String name,Model model){userService.queryUserById(id);
model.addAttribute("id",id);
return "/show.jsp";
}
}
2. @RequestParam(请求参数的限定)
@Controller
public class MyController {@RequestMapping("queryUsernameAndPassword")
public String queryUsernameAndPassword(@RequestParam("username") String username,String password,Model model){userService.queryUserById(id);
model.addAttribute("id",id);
return "/show.jsp";
}
}
3. @RequestHeader
@Controller
public class MyController {@RequestMapping("queryUsernameAndPassword")
public String queryUsernameAndPassword(@RequestParam("username") String username,String password,@RequestHeader("Accept-Language")String acceptLanguage,Model model){userService.queryUserById(id);
model.addAttribute("id",id);
return "/show.jsp";
}
}
十一、Spring MVC 的异常处理(案例)
1. 思路
-
系统中异常包括两类:
- 编译时异常(通过捕获异常从而获取异常信息)
- 运行时异常(通过规范代码开发、测试通过手段减少运行时异常的发生)
- 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 Spring MVC 的前端控制器交由异常处理器进行异常处理。