文章目录
SpringMVC
Spring MVC是Spring框架的一部分,主要用于构建Web应用程序。它遵循了模型-视图-控制器(MVC)的设计模式。在Spring MVC中,模型代表数据和业务逻辑,视图是用于呈现数据的界面,而控制器处理用户的请求并调用后端服务。
使用Spring MVC的步骤大致如下:
- 设置DispatcherServlet:这是Spring MVC的核心,用于拦截请求并分发给相应的处理器。
- 创建控制器:控制器接受用户输入,并调用模型以处理数据。
- 定义请求映射:控制器中的方法可以通过注解来映射具体的请求路径。
- 创建视图:可以是JSP、HTML或其他模板,用于展示数据。
- 配置Spring的配置文件或使用注解来指定组件、视图解析器等。
1. 快速入门
1)导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
2)在web.xml中配置servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
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>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- springmvc 的配置文件和以前 spring 的配置文件类似 -->
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<!-- 在 web 项目启动时,就加载这个 servlet 实例 1 表示加载的顺序号-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 为了支持 rest 风格的 url 这里的 url-patther 需要写成 / -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3)创建applicationContext-mvc.xml,配置视图解析器
<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.lhs.controller"/>
<!-- 配置 SpringMVC 的视图解析器, 比如我们的 controller return 的是 ok
那么这个页面就是 /WEB-INF/pages/ok.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
4)创建登录界面web/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h3>登录页面</h3>
<form action="login">
u:<input name="username" type="text"> <br/>
p:<input name="password" type="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
5)在创建返回界面web-info/pages/login_ok.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h1>恭喜 登录成功!</h1>
</body>
</html>
6)创建userService,当接收到表单提交的数据后返回login_ok.jsp
@Controller
public class UserServlet {
@RequestMapping("/login")
public String login(){
System.out.println("login...");
return "login_ok";
}
}
7)配置并启动tomcat访问登录界面完成测试
2. 执行流程
3. @RequestMapping
@RequestMapping
注解可以修饰方法,还可以修饰类 当同时修饰类和方法时,请求的 url 就是: /类请求值/方法请求值
@RequestMapping
还可以指定请求的方式(post/get/put/delete…),默认的请求方式为Get和Post使用
@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
可替代@RequestMapping
,相当于指定了请求方式
@Controller
@RequestMapping("/user")
public class UserServlet {
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(){
System.out.println("login...");
return "login_ok";
}
}
@RequestMapping 支持 Ant 风格资源地址:
?
:匹配文件名中的一个字符*
:匹配文件名中的任意字符**
: 匹配多层路径
示例:
/user/*/createUser
: 匹配 /user/aaa/createUser、/user/bbb/createUser 等 URL/user/**/createUser
: 匹配 /user/createUser、/user/aaa/bbb/createUser 等 URL/user/createUser??
: 匹配 /user/createUseraa、/user/createUserbb 等 URL
4. 映射请求数据
4.1 获取参数值
我们可以通过
@RequestParam
注解来接收请求参数值
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(@RequestParam(value = "username",required = false) String name){
System.out.println(name);
return "login_ok";
}
}
说明:
- @RequestParam : 表示说明一个接受到的参数
- value=“username” : 接收的参数名是 username
- required=false : 表示该参数可以有,也可以没有,如果 required=true,表示必须传递该参数
4.2 获取请求头
我们可以通过
@RequestHeader
注解来接收请求头
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(@RequestParam(value = "username",required = true) String name,
@RequestHeader("Host") String host){
System.out.println(name);
System.out.println(host);
return "login_ok";
}
}
4.3 获取javabean形式的数据
我们可以使用一个javabean来接收请求参数
示例:
1)创建Pet.java
public class Pet {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
2)创建Master.java
public class Master {
private Integer id;
private String name;
private Pet pet;
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public Master() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Master{" +"id=" + id +
", name='" + name + '\'' +
", pet=" + pet +
'}';
}
}
3)创建表单界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加主人和宠物</title>
</head>
<body>
<h3>添加主人和宠物</h3>
<form action="login" method="post">
主人号:<input type="text" name="id"><br>
主人名:<input type="text" name="name"><br>
宠物号:<input type="text" name="pet.id"><br>
宠物名:<input type="text" name="pet.name"><br>
<input type="submit" value="添加主人和宠物">
</form>
</body>
</html>
4)创建Servlet接收请求数据
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(Master master){
System.out.println(master);
return "login_ok";
}
}
5)测试
输出:Master{id=1, name=‘lhs’, pet=Pet{id=2, name=‘xh’}}
4.4 获取servlet api
我们在MVC框架中也能获取到原生的Servlet Api
1)导入依赖
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>servlet-api</artifactId>
<version>6.0.53</version>
</dependency>
2)获取HttpServletRequest
和HttpServletResponse
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response){
System.out.println(request.getParameter("username"));
System.out.println(request.getParameter("password"));
return "login_ok";
}
}
还可以通过这种方式获取到HttpSession
:
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request.getParameter("username"));
System.out.println(request.getParameter("password"));
System.out.println(session);
return "login_ok";
}
}
5. 模型数据
5.1 将数据放入request域
在控制器中通过javabean接收到的数据会传递到视图层,我们也可以手动在request域中添加数据给视图层
方式一:通过HttpServletRequest放入request 域
@RequestMapping(value = "/show")
public String show(Master master,HttpServletRequest request){
request.setAttribute("address","tj");
return "show_info";
}
方式二:通过请求的方法参数 Map<String,Object> 放入 request 域
@RequestMapping(value = "/show")
public String show(Map<String, Object> map, Master master){
map.put("address","bj");
return "show_info";
}
方式三:通过返回 ModelAndView 对象实现将数据放入到request域中
@RequestMapping(value = "/show")
public ModelAndView show(Map<String, Object> map, Master master){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("address","sh");
modelAndView.addObject("master",master);
modelAndView.setViewName("show_info");
return modelAndView;
}
视图层通过el表达式显示数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>vote_ok </title>
</head>
<body>
<h1>获取的的数据显示页面</h1>
<hr>
取出 request 域的数据
<br>
address: ${address }<br>
主人名字= ${requestScope.master.name }
主人信息= ${requestScope.master }
宠物名字= ${requestScope.master.pet.name }
</body>
</html>
5.2 将数据放入session域
通过HttpSession将数据放入session域:
@RequestMapping(value = "/show")
public String show(Master master,HttpSession session){
session.setAttribute("address","fj");
session.setAttribute("master",master);
return "show_info";
}
在视图层通过el表达式取出:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>vote_ok </title>
</head>
<body>
<h1>获取的的数据显示页面</h1>
<hr>
取出 session 域的数据
<br>
address: ${sessionScope.address }<br>
主人名字= ${sessionScope.master.name }
主人信息= ${sessionScope.master }
宠物名字= ${sessionScope.master.pet.name }
</body>
</html>
5.3 @ModelAttribute
在某个方法上,增加了@ModelAttribute 注解后,在调用该 Handler 的任何一个方法时,都会先调用这个方法。
@Controller
public class UserServlet {
@RequestMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response){
return "login_ok";
}
@RequestMapping(value = "/show")
public String show(Master master,HttpSession session){
session.setAttribute("address","fj");
session.setAttribute("master",master);
return "show_info";
}
@ModelAttribute
public void prepareMode(){
System.out.println("前置方法被调用");
}
}
说明:在调用login()
和show()
方法前都会先调用prepareMode()
应用场景:在修改用户信息前,在前置方法中从数据库查出这个用户,在修改方法(目标方法)中,可以使用前置方法从数据库查询的用户,如果表单中对用户的某个属性修改了,则以新的数据为准,如果没有修改,则以数据库的信息为准,比如,用户的某个属性不能修改,就保持原来的值。
6. 视图和视图解析器
在默认情况下,我们都是返回默认的视图,然后这个返回的视图交由 SpringMVC 的
InternalResourceViewResolver 视图处理器来处理的
applicationContext-mvc.xml:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
6.1 自定义视图实例
1)在applicationContext-mvc.xml中配置自定义视图解析器
</bean>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" >
<property name="order" value="0"></property>
</bean>
说明:
- BeanNameViewResolver 这个就是可以解析自定义视图的解析器
- name=“order” :表示给这个解析器设置优先级, 默认优先级很低值 Integer.MAX_VALUE
- 一般来说明,我们自己的视图解析优先级高,Order 值越小,优先级越高
2)创建视图类继承AbstractView
@Component(value = "myView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html");
response.getWriter().write("<html><body>这是myView</body></html>");
}
}
3)调用
@RequestMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response){
return "myView";
}
7. 数据格式化
在我们提交数据时,基本数据类型可以和字符串之间自动完成转换
示例:将表单请求的字符串数据转化成java数据类型
1)创建Matster.java用来接收数据
public class Master {
private Integer id;
private String name;
private Pet pet;
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public Master() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Master{" +"id=" + id +
", name='" + name + '\'' +
", pet=" + pet +
'}';
}
}
2)创建入口界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>add</title>
</head>
<body>
<a href="show">添加master</a>
</body>
</html>
3)跳转到添加界面
@RequestMapping(value = "/show")
public String show(Master master){
return "show_info";
}
4)在添加界面中使用spring提供的form标签封装数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>vote_ok </title>
</head>
<body>
<form:form action="save" method="POST" modelAttribute="master">
id: <form:input path="id"/> <br><br>
姓名~: <form:input path="name"/> <br><br>
宠物id: <form:input path="pet.id"/> <br><br>
宠物名称: <form:input path="pet.name"/> <br><br>
<input type="submit" value="添加"/>
</form:form>
</body>
</html>
5)接收传递来的数据,跳转到成功界面
@RequestMapping(value = "/save")
public String save(Master master){
System.out.println(master);
return "success";
}
6)success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>添加成功</h1>
</body>
</html>
若要完成字符串与特殊数据类型的转换可以使用相应注解,在传递数据时也需要按相应格式传递,否则无法接收
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;
@NumberFormat(pattern="###,###.##")
private float salary;
8. 数据验证
对输入的数据(比如表单数据),可以进行必要的验证,并给出相应的提示信息。
对于验证表单数据,springMVC 提供了很多实用的注解,这些注解由 JSR 303 验证框架提供
JSR 303 提供的基本验证注解有:
Hibernate Validator 是 JSR 303 实现的一个扩展,扩展注解有如下:
示例:
1)导入依赖
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.6.Final</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
2)配置validator
<mvc:annotation-driven validator="validator"/>
3)给需要验证的字段添加注解
public class Master {
@Range(min = 1,max = 100)
@NotNull
private Integer id;
@NotEmpty
private String name;
@Email
private String eamil;
private Date birthday;
@NotNull
private float salary;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
public String getEamil() {
return eamil;
}
public void setEamil(String eamil) {
this.eamil = eamil;
}
public Master(Integer id, String name, String eamil, Date birthday, float salary, Pet pet) {
this.id = id;
this.name = name;
this.eamil = eamil;
this.birthday = birthday;
this.salary = salary;
}
public Master() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Master{" +
"id=" + id +
", name='" + name + '\'' +
", eamil='" + eamil + '\'' +
", birthday=" + birthday +
", salary=" + salary +
'}';
}
}
4)在handler中用@Valid
注解对数据进行验证,并用Errors和map接收验证信息
@RequestMapping(value = "/save")
public String save(@Valid Master master, Errors errors, Map<String, Object> map){
System.out.println(master);
System.out.println(errors);
System.out.println(map);
if(errors.hasErrors()){
return "show_info";
}
return "success";
}
8.1 自定义错误信息
1)配置xml
<!-- 配置国际化文件名字
如果你这样配的话,表示 messageSource 回到 src/i18nXXX.properties 去读取错误信息
-->
<bean id="messageSource" class=
"org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
2)在resources目录下创建i18n.properties文件
NotEmpty.master.name=\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
typeMismatch.master.id=\u5e74\u9f84\u8981\u6c42\u5728\u0031\u002d\u0031\u0035\
u0030\u4e4b\u95f4
8.2 取消数据绑定
在默认情况下,表单提交的数据都会和 pojo 类型的 javabean 属性绑定,如果程序员在开发中,希望取消某个属性的绑定,也就是说,不希望接收到某个表单对应的属性的值,则可以通过 @InitBinder 注解取消绑定。
在handler中添加方法:
//取消绑定 master 的 name 表单提交的值给 monster.name 属性
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("name");
}
9. 中文乱码处理
我们可以使用过滤器来解决中文乱码问题。
自定义中文乱码过滤器:
public class MyCharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 设置字符编码
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
在web.xml文件中配置过滤器:
<filter>
<filter-name>myCharacterFilter</filter-name>
<filter-class>com.lhs.filter.MyCharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myCharacterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
10. 处理 json 数据
在前后端分离的项目中,我们一般需要将数据以json格式返回,这时我们可以使用
@ResponseBody
注解表示返回Json数据。同理,在接收Json数据时我们也需要在参数前添加
@RquestBody
注解。我们可以将
@ResponseBody
注解写在类上,使其对所有方法生效。可以用
@RestController
注解来替代@ResponseBody
+@Controller
两个注解
返回Json数据示例:
1)创建jsp界面,发出请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>json 提交</title>
<!-- 引入 jquery -->
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<!-- 编写 jquery 代码和请求 -->
<script type="text/javascript">
$(function () {
//绑定超链接点击事件
$("#getJson").click(function () {
//href 是一个完整的请求地址
var href = this.href;
alert(href);
var args = {"time": new Date()};//防止缓存
//发出一个 jquery 的 post 请求,请求返回 json
$.post(href, args, function (data) {
alert(" name= " + data.name + " address= " + data.address);
//1. data 是 json 对象
//2. JSON.stringify(data) 是将 json 对象转成字符串
alert("返回数据 json=" + data)
alert("返回数据 json=" + JSON.stringify(data))
}, "json");
//防止重复提交
return false;
})
})
</script>
</head>
<body>
<h1>请求一个 json 数据</h1>
<a href="getJson" id="getJson">点击获取 json 数据</a>
</body>
</html>
2)返回json数据
@RequestMapping("getJson")
@ResponseBody // 表示返回的数据为Json格式
public Master getJson(){
Master master = new Master(1,"lxg","123@qq.com",11.1f);
return master;
}
接收Json数据示例:
1 )修改jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<!-- 编写 jquery 代码和请求 -->
<script>
$(function (){
//绑定超链接点击事件
$("#getJson").click(function () {
//href 是一个完整的请求地址
var href = this.href;
alert(href);
var args = {"time": new Date()};//防止缓存
//发出一个 jquery 的 post 请求,请求返回 json
$.post(href, args, function (data) {
alert(" name= " + data.name + " address= " + data.address);
//1. data 是 json 对象
//2. JSON.stringify(data) 是将 json 对象转成字符串
alert("返回数据 json=" + data)
alert("返回数据 json=" + JSON.stringify(data))
}, "json");
//防止重复提交
return false;
})
$("button[name='butt1']").click(function () {
var userName = $("#userName").val()
var age = $("#age").val()
$.ajax({
url: "/springmvc/save2",
data: JSON.stringify({"username": userName, "age": age}),
type: "POST",
success:
function (data) {
alert("返回的信息=" + JSON.stringify(data));
},
contentType: "application/json;charset=utf-8"
});
})
})
</script>
</head>
<body>
<h1>请求一个 json 数据</h1>
<a href="getJson" id="getJson">点击获取 json 数据</a>
<h1>发出一个 json 数据</h1>
u:<input id="userName" type="text"><br/>
a:<input id="age" type="text"><br/>
<button name="butt1">添加用户</button>
</body>
</html>
2)接收json数据
@RequestMapping("save2")
@ResponseBody
public User save2(@RequestBody User user){
System.out.println(user);
return user;
}
11. HttpMessageConverter<T>
SpringMVC 处理 JSON-底层实现是依靠 HttpMessageConverter来进行转换的
当控制器处理方法使用到 @RequestBody/@ResponseBody 或 HttpEntity/ResponseEntity 时,Spring 首先根据请求头或响应头的 Accept 属性选择匹配 的 HttpMessageConverter,进而根据参数类型或泛型类型的过滤得 到匹配 的HttpMessageConverter, 若找不到可用的 HttpMessageConverter 将报错
12. 文件上传
Spring MVC 为文件上传提供了直接的支持 , 这种支持是通过即插即用的 MultipartResolver 实现的 。
示例:
1)导入依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
2)Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
3)创建jsp界面,上传图片
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<h1>文件上传的演示</h1>
<form action="fileUpload" method="post" enctype="multipart/form-data">
文件介绍:<input type="text" name="introduce"><br>
选择文件:<input type="file" name="file"><br>
<input type="submit" value="上传文件">
</form>
</body>
</html>
4)handler中接收上传的图片
@RequestMapping(value="/fileUpload")
public String fileUpload(@RequestParam(value="file") MultipartFile file, HttpServletRequest request)
throws Exception {
String originalFilename = file.getOriginalFilename();
System.out.println("上传文件名= " + originalFilename);
String filepath = "E:\\javaProject\\SpringMVCDemo\\web\\images\\" + originalFilename;
File saveToFile = new File(filepath);
file.transferTo(saveToFile);
return "success";
}
13. 自定义拦截器
Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能
自定义的拦截器必须实现 HandlerInterceptor 接口
自定义拦截器的三个方法:
- preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request 进行处理。
- postHandle():这个方法在目标方法处理完请求后执行
- afterCompletion():这个方法在完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
自定义拦截器执行流程说明:
- 如果 preHandle 方法 返回 false,则不再执行目标方法,可以在此指定返回页面
- postHandle 在目标方法被执行后执行,可以在方法中访问到目标方法返回的ModelAndView 对象
- 若 preHandle 返回 true,则 afterCompletion 方法在渲染视图之后被执行
- 若 preHandle 返回 false,则 afterCompletion 方法不会被调用
- 在配置拦截器时,可以指定该拦截器对哪些请求生效,哪些请求不生效
示例:
1)创建拦截器
@Component
public class MyInterceptor01 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
// System.out.println("preHandle.....");
// String mess = "炸弹";
// if(mess.equals("炸弹")){
// //返回到一个警告页面
// arg0.getRequestDispatcher("/WEB-INF/pages/warning.jsp").forward(arg0, arg1);
// return false;
// }else{
// return true;
// }
System.out.println("===MyInterceptor01 preHandle()===");
return true;
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("===MyInterceptor01 postHandle()===");
}
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println("===MyInterceptor01 afterCompletion()===");
}
}
2)在spring的配置文件中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置匹配规则-->
<mvc:mapping path="/h*"/>
<!-- 配置需要排除的路径-->
<mvc:exclude-mapping path="/hello"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
</mvc:interceptors>
14. 异常处理
Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
我们可以自定义异常处理方式,若未设置,当服务器发生异常时,默认的异常处理机制会返回一个状态码为500的界面。
14.1 局部异常
//局部异常就是直接在这个 Handler 中编写即可
@ExceptionHandler({ArithmeticException.class,NullPointerException.class})
public String localException(Exception ex, HttpServletRequest request){
System.out.println("异常信息是~" + ex.getMessage());
//将异常的信息带到下一个页面
request.setAttribute("reason", ex.getMessage());
return "exception_mes";
14.2 全局异常
ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 类的@ExceptionHandler 注解方法,这样就相当于一个全局异常处理器。
@ControllerAdvice
public class MyGlobalException {
//全局异常就不管是哪个 Handler 抛出的异常,都可以捕获
@ExceptionHandler({ClassCastException.class, NumberFormatException.class})
public String localException(Exception ex, HttpServletRequest request) {
System.out.println("全局异常信息是= " + ex.getMessage());
request.setAttribute("reason", ex.getMessage());
//将异常的信息带到下一个页面.
return "exception_mes";
}
}
14.3 SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
示例:对数组越界异常进行统一处理
//统一的异常
@RequestMapping(value="/testException03")
public String test03(){
int[] arr = new int[]{3,9,10,190};
System.out.println(arr[90]);
return "success";
}
添加统一异常处理的配置:
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop>
<!-- 对未知异常进行处理 -->
<!-- <prop key="java.lang.Exception">otherEx</prop> -->
</props>
</property>
</bean>
创建/WEB-INF/pages/arrEx.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>数组越界了</title>
</head>
<body>
<h1>数组越界了~</h1>
</body>
</html>