Filter过滤器
Filter过滤器
一、Filter介绍
- Filter(过滤器)是一种用于对数据流进行处理的软件组件。
- Filter 的作用是从输入流中获取数据,对其进行处理后再将其写入输出流中。
- Filter 组件通常用于数据校验、数据转换、数据压缩等方面,以及对网络通信进行处理。
- 在 Web 开发中,Filter 是 Servlet 标准中的一种组件,用于在 Servlet 执行之前或之后对请求和响应进行处理。可以通过 Filter 实现各种功能,如请求参数过滤、字符编码转换、请求重定向、登录验证等。
- 使用 Filter 组件可以提高 Web 应用的易用性、安全性和可扩展性。
二、Filter应用场景
(1)Filter(过滤器)是Java Servlet API中一种可以在请求和响应的处理过程中,干预或修改请求和响应的内容的组件。它主要用来过滤HTTP请求和响应,对前端的输入进行过滤,保护系统安全,提高应用的性能等。
(2)Filter应用的场景包括:
- 参数校验:用户输入的参数可能包含恶意字符或参数格式错误,通过使用Filter可以拦截并进行参数校验,以保证应用安全。
- 多语言选择:通过获取请求头的语言参数,Filter可以根据用户的语言选择相应的语言。
- 登录拦截:通过Filter对所有请求进行拦截,检查用户是否登录,若未登录则跳转至登录页面。
- 编码转换:对于不同的请求和响应,可能需要采用不同的编码方式,Filter可以将请求和响应进行编码转换。
- 访问控制:通过Filter实现拦截指定路径的请求,实现权限访问控制。
以上是Filter应用的常见场景,它可以通过Java Servlet API提供的Filter接口进行实现。同时,Filter的执行顺序可以通过在web.xml中配置Filter的顺序来决定。
三、Filter拦截器流程图
四、编写Filter过滤器
1. 写一个类实现Filter接口
Filter接口包含三个生命周期方法:void init(FilterConfig)、void doFilter(ServletRequest, ServletResponse, FilterChain)和void destroy()
-
void init(FilterConfig) -- 创建Servlet对象之后马上执行,Filter会在服务器启动时就创建
public void init(FilterConfig filterConfig) throws ServletException {}
-
void doFilter(ServletRequest, ServletResponse, FilterChain) -- 每次过滤都会执行
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {}
-
void destroy() -- 销毁之前执行,在服务器关闭时销毁
public void destroy() {}
-
Filter也是跟Servlet一样是单例的
2. 在web.xml中配置Fliter过滤器
Filter过滤器在web.xml中配置与Servlet差不多,只不过需要注意的是
<web-app ...>
<filter>
<filter-name>xxx</filter-name>
<filter-class>cn.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>xxx</filter-name>
<url-pattern>/AServlet</url-pattern>
</filter-mapping>
</web-app>
3. 实现Fliter过滤器案例
- 创建一个AServlet类和一个AFilter类
- 在web.xml中配置Fliter
- 将项目放到Tomcat,启动服务器
AServlet.java
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("AServlet....");
}
}
AFilter.java
public class AFilter implements Filter {
/**
* 创建之后马上执行,用作初始化
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("创建拦截器!!!");
}
/**
* 每次过滤时都执行
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("正在拦截!!!");
filterChain.doFilter(servletRequest,servletResponse); // 放行!
System.out.println("你又回来了?");
}
/**
* 销毁之前执行,用来对非内存资源进行释放
*/
@Override
public void destroy() {
System.out.println("拦截器已销毁!!!");
}
}
web.xml中配置
<?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>AServlet</servlet-name>
<servlet-class>cn.web.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>AFilter</filter-name>
<filter-class>cn.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/AServlet</url-pattern>
</filter-mapping>
</web-app>
五、FilterConfig接口
1. FilterConfig接口介绍
FilterConfig 是 Servlet API 提供的一个用于获取 Filter 程序在 web.xml 文件中的配置信息的接口,该接口封装了 Filter 程序在 web.xml 中的所有注册信息,并且提供了一系列获取这些配置信息的方法。
方法 | 功能 |
---|---|
String getInitParameter(String name) | getInitParameter(String name) 方法用于返回在 web.xml 文件中为 Filter 所设置的某个名称的初始化参数值,如果指定名称的初始化参数不存在,则返回 null |
String getFilterName() | getFilterName() 方法用于返回在 web.xml 文件中为 Filter 所设置的名称,也就是返回 <filter-name> 元素的设置值 |
ServletContext getServletContext() | getServletContext()方法用于返回 FilterConfig 对象中所包装的 ServletContext 对象的引用 |
Enumeration getInitParameterNames() | getInitParameterNames() 方法用于返回一个 Enumeration 集合对象,该集合对象包含在 web.xml 文件中为当前 Filter 设置的所有初始化参数的名称 |
六、FilterChain(过滤器链)
1. FilterChain介绍
在 Web 应用中,可以部署多个 Filter,若这些 Filter 都拦截同一目标资源,则它们就组成了一个 Filter 链(也称过滤器链)。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到传递给目标资源。
2. FilterChain 接口
javax.servlet 包中提供了一个 FilterChain 接口,该接口由容器实现。容器将其实例对象作为参数传入 Filter 对象的 doFilter() 方法中。Filter 对象可以使用 FilterChain 对象调用链中下一个 Filter 的 doFilter() 方法,若该 Filter 是链中最后一个过滤器,则调用目标资源的 service() 方法。
总结作用:让 Filter 链上的当前过滤器放行,使请求进入下一个 Filter。
方法 | 功能 |
---|---|
void doFilter(ServletRequest, ServletResponse) | 使用该方法可以调用过滤器链中的下一个 Filter 的 doFilter() 方法,若该 Filter 是链中最后一个过滤器,则调用目标资源的 service() 方法。 |
3. Filter 链的拦截过程
当浏览器访问 Web 服务器中的资源时,需要经过两个过滤器 Filter1 和 Filter2。首先 Filter1 会对这个请求进行拦截,在 Filter1 中理完请求后,通过调用 Filter1 的 doFilter() 方法将请求传递给 Filter2,Filter2 处理用户请求后同样调用 doFilter() 方法,最终将请求发送给目标资源。当 Web 服务器对这个请求做出响应时,也会被过滤器拦截,但这个拦截顺序与之前相反,最终将响应结果发送给客户端浏览器。
注:过滤器链中的任何一个 Filter 没有调用 FilterChain.doFilter() 方法,请求都不会到达目标资源。
总结:执行目标资源,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器!
4. Filter 链中拦截器的执行顺序
通过 web.xml 配置的 Filter 过滤器,执行顺序由 <filter-mapping>
标签的配置顺序决定。**<filter-mapping>
靠前,则 Filter 先执行,靠后则后执行。通过修改 <filter-mapping>
的顺序便可以修改 Filter 的执行顺序。
注:通过 @WebFilter 注解配置的 Filter 过滤器,无法进行排序。
5.演示多个Filter拦截器执行顺序
- 创建两个Servlet类和两个Filter类
- 在web.xml中配置Servlet和Filter
- 加载到Tomcat,启动服务器
实现AServlet和BServlet类文件
AServlet.java
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("AServlet已开始...");
}
}
BServlet.java
public class BServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("BServlet已开始...");
}
}
实现AFilter和BFilter接口文件
AFilter.java
public class AFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("创建A拦截器!!!");
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("AFilter已开始...");
filterChain.doFilter(servletRequest,servletResponse); // 放行!
System.out.println("AFilter已结束...");
}
public void destroy() {
System.out.println("A拦截器已销毁!!!");
}
}
BFilter.java
public class BFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("创建B拦截器!!!");
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("BFilter已开始...");
filterChain.doFilter(servletRequest,servletResponse); // 放行!
System.out.println("BFilter已结束...");
}
public void destroy() {
System.out.println("B拦截器已销毁!!!");
}
}
在web.xml中配置Servlet和Filter
<?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>AServlet</servlet-name>
<servlet-class>cn.web.servlet.AServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>cn.web.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>/BServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>AFilter</filter-name>
<filter-class>cn.web.filter.AFilter</filter-class>
</filter>
<filter>
<filter-name>BFilter</filter-name>
<filter-class>cn.web.filter.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/BServlet</url-pattern>
</filter-mapping>
</web-app>
因为主要拦截的是BServlet,访问http://localhost:8080/Filter/BServlet后的执行结果
创建B拦截器!!!
创建A拦截器!!!
AFilter已开始...
AFilter已结束...
AFilter已开始...
BFilter已开始...
BServlet已开始...
BFilter已结束...
AFilter已结束...
B拦截器已销毁!!!
A拦截器已销毁!!!
七、Filter的四种拦截方式
1. 四种拦截方式
都必须在<filter-mapping>
标签下进行四种拦截配置。
- 拦截请求(REQUEST)--
<dispatcher>REQUEST</dispatcher>
- 拦截转发(FORWARD)--
<dispatcher>FORWARD</dispatcher>
- 拦截包含(INCLUDE)--
<dispatcher>INCLUDE</dispatcher>
- 拦截错误(ERROR)--
<dispatcher>ERROR</dispatcher>
默认拦截方式为REQUEST,没有配置的话拦截方式就是REQUEST
2.演示
现在配置一个FORWARD转发拦截方式并通过访问BServlet转发至AServlet
AServlet.java
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("AServlet已开始...");
}
}
BServlet.java
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* getRequestDispatcher()是请求转发
* forward(req,resp)是转发(容器中控制权转向),在客户端浏览器地址栏中不会显示出转向后的地址。
*/
req.getRequestDispatcher("/AServlet").forward(req,resp);
}
}
web.xml
<?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"
id="WebApp_ID" version="4.0">
<display-name>day0412_1</display-name>
<filter>
<filter-name>AFilter</filter-name> <!-- 自定义名称 -->
<filter-class>cn.web.filter.AFilter</filter-class> <!-- Filter类所在路径 -->
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name> <!-- 自定义名称匹配 -->
<url-pattern>/*</url-pattern> <!-- 拦截的资源路径 -->
</filter-mapping>
<filter>
<filter-name>BFilter</filter-name> <!-- 自定义名称 -->
<filter-class>cn.web.filter.BFilter</filter-class> <!-- Filter类所在路径 -->
</filter>
<filter-mapping>
<filter-name>BFilter</filter-name> <!-- 自定义名称匹配 -->
<url-pattern>/AServlet</url-pattern> <!-- 拦截的资源路径 -->
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
</web-app>
启动服务器,浏览器访问BServlet:http://localhost:8080/Filter/BServlet
查看控制台输出结果:
结论分析:
首先是AFilter拦截成功,因为AFilter拦截方式为默认的REQUEST请求,而访问BServlet正是这种方式;然后是AFilter放行,放行后执行BServlet,执行BServlet时会执行BServlet中的转发操作,那么这个时候就会被BFilter拦截,因为BFilter的拦截方式是FORWARD转发,随后BFilter会进行放行,然后执行AServlet。
可以发现执行顺序就是先执行的后结束。
八、设置目标资源方式
必须在web.xml文件下的<filter-mapping>
标签下进行设置
<filter-mapping>
标签包含以下元素:
<filter-name>
-- 拦截器名字<url-pattern>
-- 拦截的资源路径<dispatcher>
-- 拦截方式<servlet-name>
-- 它与某个Servlet的配置名称相同
九、Filter小结
1. Filter的三个方法
- void init(Eilterconfig):在Tomcat启动时被调用;
- void destroy():在Tomcat关闭时被调用;
- void doFiter(ServletRequest, ServletResponse, FilterChain):每次有请求时都调用该方法;
2. FilterConfig接口
与ServletConfig相似,用来获取Filter的初始化参数
- ServletContext getServletContext():获取ServletContext的方法;
- String getFilterName():获取Filter的配置名称;
- String getlnitParameter(String name):获取 Filter的初始化配置,与
元素对应; - Enumeration getlnitParameterMame():获取所有初始化参数的名称。
3. FilterChain接口
-
void doFilter( ServletRequest,ServletResponse):放行!
-
表示执行下一个过滤器,或者执行目标资源。
-
可以在调用FilterChain的doFilter()方法的前后添加语句,在FilterChain的 doEilter()方法之前的语句会在目标资源执行之前执行,在FilterChain的 doFilter()方法之后的语句会在目标资源执行之后执行。
4. 四种拦截方法
四条拦截方式:REQUEST、FORWARD、INCLUDE、ERROR,默认是REQUEST方式。
- REQUEST:拦截直接请求方式;
- FORWARD:拦截请求转发方式;
- INCLUDE:拦截请求包含方式;
- ERROR:拦截错误转发方式。
十、过滤器应用案例
案例1:分IP统计访问次数
-
说明
- 网站统计每个IP地址访问本网站的次数。
-
分析
- 用什么来统计网站的访问次数?
因为网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,也就是说统计工作在任何的资源被访问之前都要执行,所以使用过滤器比较方便。而且我们的这个过滤器不需要任何的拦截操作,只需要统计次数就可以了。 - 用什么来存储网站中每个IP的访问次数?
我们需要用什么来装载统计数据呢?答案是Map<String,Integer>,我们可以在过滤器中创建一个Map,key就是IP地址,value就是对应IP地址访问的次数。
当有用户访问时,就获取请求的IP地址:如果这个IP在map中存在,就说明以前访问过,就在访问次数上+1;如果IP在map中不存在,就设置访问次数为1。 - Map怎么创建?存放在哪里?
这个Map什么时候创建呢,我们可以使用监听器,也就是使用ServletContextListener,在服务器启动的时候完成创建,并且存放到ServletContext中。
- 用什么来统计网站的访问次数?
-
代码步骤
-
创建访问页面
- 新建两个jsp,供访问使用。
- 新建两个jsp,供访问使用。
-
创建监听器
-
创建一个监听器,让其在服务器启动的时候创建一个Map,并且保存到ServletContext中。
public class AListener implements ServletContextListener { /** * 在服务器启动时创建Map,保存到ServletContext */ public void contextInitialized(ServletContextEvent sce) { // 创建 Map Map<String, Integer> map = new LinkedHashMap<String,Integer>(); // 得到ServletContext对象 ServletContext application = sce.getServletContext(); // 把 map 保存到 application对象中 application.setAttribute("map",map); } public void contextDestroyed(ServletContextEvent sce) {} }
-
-
创建过滤器
-
/** * 从application中获取Map * 从request中得到当前客户端的 IP * 进行统计工作,结果保存到Map中 */ public class AFilter implements Filter { private FilterConfig config = null; // 在服务器启动时就会执行本方法,而且本方法只会执行一次! public void init(FilterConfig config) throws ServletException { // 保存config this.config = config; } public void destroy() {} public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { /** * 1.得到application中的map * 2.从request中获取当前客户端的IP地址 * 3.查看map中是否存在这个ip对应访问次数,如果存在,把次数+1再保存回去 * 4.如果不存在这个ip,那么说明第一次访问本站,设置访问次数为1 */ // 得到application ServletContext app = config.getServletContext(); // 得到application中的map Map<String, Integer> map = (Map<String, Integer>) app.getAttribute("map"); // 从request中获取当前客户端的IP地址 String ip = servletRequest.getRemoteAddr(); // 判断map中是否存在该IP地址 if (map.containsKey(ip)){ // ip在map中存在,说明不是第一次访问 int cnt = map.get(ip); map.put(ip, cnt+1); }else { // ip在map中不存在,说明是第一次访问 map.put(ip, 1); } // 把map再保存回application中 app.setAttribute("map", map); filterChain.doFilter(servletRequest,servletResponse); // 肯定放行 } }
-
-
web.xml的有关配置
<filter> <filter-name>AFilter</filter-name> <filter-class>cn.web.filter.AFilter</filter-class> </filter> <filter-mapping> <filter-name>AFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>cn.web.listener.AListener</listener-class> </listener>
-
创建一个显示页面
-
创建一个show.jsp,用来显示我们的统计数据。
<body> <h1 align="center">显示结果</h1> <table align="center" width="60%" border="1"> <tr> <th>IP地址</th> <th>访问次数</th> </tr> <c:forEach items="${applicationScope.map }" var="entry"> <tr> <td>${entry.key }</td> <td>${entry.value }</td> </tr> </c:forEach> </table> </body>
-
-
运行方式
- 启动Tomcat服务器,然后访问 http://localhost:8080/DemoProject/show.jsp
-
案例2:粗粒度权限管理
1、粗粒度权限控制(拦截是否登录、拦截用户名admin权限)
RBAC→基于角色的权限控制
- tb_user
- tb_role
- tb_userrole
- tb_menu(增、删、改、查)->属于细粒度权限控制
- tb_rolemenu
2、说明
我们给出三个页面: index.jsp、 userjsp、 admin.jsp
- index.jsp:谁都可以访问,没有限制;
- user.jsp:只有登录用户才能访问;
- admin.jsp:只有管理员才能访问。
3、分析
- 首先需要一个登录页面(login.jsp)用于传递登录的用户名和密码。
- 然后创建一个Servlet,当用户登录成功后,进行判断权限级别,并把用户名保存到session域中。
- 最后创建拦截器,两种过滤方式:UserFilter、AdminFilter。
JSP的编写
创建四个JSP文件,分别为:welcom.jsp
、login.jsp
,users
文件夹下的user.jsp
和admin
文件夹下的admin.jsp
。
welcom.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>游客界面</h1>
当前用户:<%=session.getAttribute("username")%><br/>
<a href="<c:url value="/welcome.jsp"/>">游客入口</a><br>
<a href="<c:url value="/users/users.jsp"/>">用户入口</a><br>
<a href="<c:url value="/admin/admin.jsp"/>">管理员入口</a><br>
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>登录</h1>
<font color="red"> ${msg} </font><br/>
当前用户:<%=session.getAttribute("username")%><br/>
<form action="<c:url value="/Login"/>" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"/></td>
</tr>
</table>
</form>
</body>
</html>
user.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>用户界面</h1>
当前用户:<%=session.getAttribute("username")%><br/>
<a href="<c:url value="/welcome.jsp"/>">游客入口</a><br>
<a href="<c:url value="/users/users.jsp"/>">用户入口</a><br>
<a href="<c:url value="/admin/admin.jsp"/>">管理员入口</a><br>
</body>
</html>
admin.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>管理员界面</h1>
<%
String name= (String) session.getAttribute("admin");
session.setAttribute("username",name);
%>
当前用户:<%=session.getAttribute("username")%><br/>
<a href="<c:url value="/welcome.jsp"/>">游客入口</a><br>
<a href="<c:url value="/users/users.jsp"/>">用户入口</a><br>
<a href="<c:url value="/admin/admin.jsp"/>">管理员入口</a><br>
</body>
</html>
编一个User对象
User.class
package cn.web.user;
public class User {
private String username;
private String password;
private int grade;
public User(String username, String password, int grade) {
this.username = username;
this.password = password;
this.grade = grade;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "web.user.User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Servlet的编写
创建servlet文件夹存放LoginServlet.class用于处理请求。
LoginServlet.class
@WebServlet(name = "LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); //处理中文问题
/*1.获取用户名,获取密码
* 2.判断用户名中和密码是否为“”,
* 3.如果不为空,且包含特定字符,就是管理员
* 4.如果不包含,就是普通用户
* 5.否则就是游客
* 6.把登录的用户名称保存到session中
* 7.转发到welcome.jsp*/
String name=request.getParameter("username");
String password=request.getParameter("password");
if (name!="" && password!=""){
if (name.contains("chen") && password.equals("123456")){
request.getSession().setAttribute("admin",name);
//name是login.jsp中提交的值,一个键值对:username:chen
//setAttribute,创建一个新的session域对象,名称为andmin,值为name的值
}else {
request.getSession().setAttribute("username",name);
}
}else {
request.getSession().setAttribute("tourist",name);
}
request.getRequestDispatcher("/UserDemo/welcom.jsp").forward(request,response);
System.out.println("已经转发");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
在web.xml配置LoginServlet路径
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>cn.web.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>
此时Servlet与JSP完成,可以访问三个页面畅通无阻。而为了实现我们的粗粒度权限管理,我们还需要编写两个过滤器,以达到权限管理的目的。
Filter的编写
创建filter文件夹存放UserFilter.class和AdminFilter用于过滤,以达到权限管理的目的。
UserFilter.class
public class UserFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
/*1.得到session
* 2.判断session域中是否存在admin,如果存在放行
* 3.判断session域中是否存在username,如果存在放行
* 4.否则打回login.jsp*/
HttpServletRequest request= (HttpServletRequest) req; //强转,用它才能使用getSession()方法
String name = (String) request.getSession().getAttribute("admin");
if (name!=null){
/*获取admin,如果不为空,就是管理员*/
chain.doFilter(req, resp);
return;
}
name=(String)request.getSession().getAttribute("username"); //获取用户
if (name!=null){
chain.doFilter(req,resp);
}else {
request.setAttribute("msg","游客请登录"); //保存错误信息到request域中,再转发
request.getRequestDispatcher("/login.jsp").forward(req,resp);
System.out.println("UserFilter拦截");
}
}
public void init(FilterConfig config) throws ServletException {
}
}
AdminFilter.class
public class AdminFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request= (HttpServletRequest) req;
String name= (String) request.getSession().getAttribute("admin");
if (name!=null){
/*获取admin,如果不为空,就是管理员*/
chain.doFilter(req, resp);
return;
}else {
request.setAttribute("msg","没有管理员权限"); //保存错误信息到request域中,再转发
request.getRequestDispatcher("/login.jsp").forward(req,resp);
System.out.println("AdminFilter拦截");
}
}
public void init(FilterConfig config) throws ServletException {
}
}
在web.xml中进行UserFilter、AdminFilter的配置
<filter>
<filter-name>UserFilter</filter-name>
<filter-class>cn.web.filter.UserFilter</filter-class>
</filter>
<filter>
<filter-name>AdminFilter</filter-name>
<filter-class>cn.web.filter.AdminFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UserFilter</filter-name>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AdminFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
分析与总结
流程分析
- login.jsp提交信息到LoginServlet;
- LoginServlet判断提交信息中是否包含指定数据,如果包含管理员数据则在session域中创建名为admin的数据,并将提交信息中的username的值作为新值传递给admin;若满足用户判读条件,则仿照上面的创建一个名为username的键值对。最后将其转发到welcom.jsp;
- welcom.jsp中定义三个超链接,指向welcom.jsp和user文件夹下的user.jsp以及admin文件夹下的admin.jsp
- 在welcom.jsp中,UserFilter和AdminFilter的作用就显示出来了。
- UserFilter和AdminFilter通过session域中是否存在username和admin的数据,判断是否放行。
其中的知识点有JavaWeb三大组件的Servlet、Filter和Session域。
本文作者:粤先生
本文链接:https://www.cnblogs.com/magicYue/p/18174184
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!