===================================================================================
SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行 预处理 和 后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用。
过滤器(filter):
- servlet 规范中的一部分,任何 java web 工程都可以使用;
- 在
<url-pattern>
中配置了/*
之后,可以对所有要访问的资源进行拦截;
拦截器(interceptor):
- 拦截器属于 SpringMVC 框架的,只有使用了 SpringMVC 框架的工程才能使用;
- 拦截器只会拦截访问的控制器方法, 如果访问的是 jsp/html/css/image/js 是不会进行拦截的;
自定义拦截器
想要自定义拦截器,必须实现 HandlerInterceptor
接口。
- 配置 web.xml 和 springmvc-servlet.xml 文件
- 编写一个拦截器:
package com.yusael.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// 在请求处理的方法之前执行
// 如果返回 true 执行下一个拦截器(放行)
// 如果返回 false 就不执行下一个拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("---------处理前---------");
return true;
}
// 在请求处理方法执行之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---------处理后---------");
}
// 在 dispatcherServlet 处理后执行, 做清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("---------清理---------");
}
}
- 在 SpringMVC 的配置文件中配置拦截器:
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.yusael.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- 编写一个 Controller,接收请求:
package com.yusael.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 测试拦截器的控制器
@RestController
public class InterceptorController {
@RequestMapping("/interceptor")
public String testFunction() {
System.out.println("控制器中的方法执行了!");
return "hello";
}
}
- 前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
- 启动 Tomcat 进行测试。
如果自定义拦截器中 preHandle
返回 false
,表示不放行,被拦截了,不继续执行了。
如果自定义拦截器中 preHandle
返回 true
,表示放行,继续执行后面的代码。
验证用户是否登录 (认证用户)
==================================================================================
思路:
- 有一个登陆页面,需要写一个 Controller 访问页面。
- 登陆页面有一个提交表单的动作,需要在 Controller 中处理;
判断用户名密码是否正确:如果正确,向 session 中写入用户信息,返回登陆成功。 - 拦截用户请求,判断用户是否登陆。
如果用户已经登陆,放行;
如果用户未登陆,跳转到登陆页面;
没有拦截器
如果没有拦截器,也就是上面思路中的 1 和 2 步,用户未登录也可以进入主页。
- 编写一个登陆页面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
</head>
<h1>登录页面</h1>
<hr>
<body>
<form action="${pageContext.request.contextPath}/user/login">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="pwd"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
- 编写一个 Controller 处理请求
package com.yusael.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class UserController {
// 跳转到登录界面
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
// 跳转到成功页面
@RequestMapping("/toSuccess")
public String toSucess() {
return "success";
}
// 登录提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String password) {
// 向 session 记录用户身份信息
System.out.println("接收前端 ===> " + username);
session.setAttribute("user", username);
return "success";
}
// 登录过期
@RequestMapping("/logout")
public String logout(HttpSession httpSession) {
// session 过期
httpSession.invalidate();
return "login";
}
}
- 编写一个登陆成功的页面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>登录成功页面</h1>
<hr>
${user}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>
- 编写主页 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h1>首页</h1>
<hr>
<%--登录--%>
<a href="${pageContext.request.contextPath}/user/toLogin">登录</a>
<a href="${pageContext.request.contextPath}/user/toSuccess">成功页面</a>
</body>
</html>
测试:
点击 登录,会请求跳转到 登陆页面 login.jsp;
点击 成功页面,会请求跳转到 成功页面 success.jsp
这里就出现问题了,只要在 地址栏发出请求,可以直接 越过登录,进入登录成功的界面,这个肯定是有问题的。那要如何解决这个问题呢? —— 通过 拦截器。
配置拦截器
- 编写用户登录拦截器 LoginInterceptor.java
package com.yusael.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是登录页面则放行
System.out.println(request.getRequestURI());
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已经登录也放行
if (session.getAttribute("user") != null) {
return true;
}
// 如果用户没有登录则跳转到登录界面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
- 在 Springmvc 的配置文件中注册拦截器:
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.yusael.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
测试:
由于配置了 拦截器,直接登录 成功页面,虽然会请求跳转到 success.jsp 页面,但是由于不满足拦截器进行了判断,不满足放行的条件则会跳转到 登录界面。只有满足拦截器放行的条件才会跳转到 成功页面。
文件的上传
========================================================================
文件上传是项目开发中最常见的功能之一 ,SpringMVC 可以很好的支持文件上传,但是 SpringMVC 上下文中默认没有装配 MultipartResolver
,因此默认情况下其不能处理文件上传工作。如果想使用Spring 的文件上传功能,则需要在上下文中配置 MultipartResolver
。
对前端表单的要求:为了能上传文件,必须将表单的 method
设置为 POST
,并将 enctype
设置为multipart/form-data
。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
表单中的 enctype
(编码方式)属性的说明:
application/x-www=form-urlencoded
:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。multipart/form-data
:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。text/plain
:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
一旦设置了 enctype
为 multipart/form-data
,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的 HTTP 响应。
在2003年,Apache Software Foundation 发布了开源的 Commons FileUpload 组件,其很快成为Servlet/JSP 程序员上传文件的最佳选择。
Servlet3.0 规范已经提供方法来处理文件上传,但这种上传需要在 Servlet 中完成;而Spring MVC则提供了更简单的封装;
Spring MVC 为文件上传提供了直接的支持,这种支持是用即插即用的 MultipartResolver
实现的。
Spring MVC 使用 Apache Commons FileUpload 技术实现了一个 MultipartResolver
实现类:
CommonsMultipartResolver
。因此,SpringMVC 的文件上传还需要依赖 Apache Commons FileUpload 的组件。
文件输出流进行文件上传
- 引入 commons-fileupload 的依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
### 最后分享一波,Java核心架构进阶知识点
面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Java核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、Spring相关、分布式、微服务、RPC、网络、设计模式、MQ、Redis、MySQL、设计模式、负载均衡、算法、数据结构、kafka、ZK、集群等。而这些也全被整理浓缩到了一份pdf——《Java核心架构进阶知识点整理》,全部都是精华中的精华,本着共赢的心态,好东西自然也是要分享的
![image]()
![image]()
![image]()
\
<version>1.3.3</version>
</dependency>
#