JavaWeb之过滤器
Posted WWWYC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb之过滤器相关的知识,希望对你有一定的参考价值。
时间:
Talk is cheap Show me the code
JavaWeb三大组件:
Servlet、Listener、Filter
都需要在web.xml中进行配置,Listener中的两个感知监听器不需要配置。
——过滤器概述
过滤器是JavaWeb的三大组件之一,它与Servlet很相似,不过过滤器是用来拦截请求的,而不是处理请求的。
当用户请求某个Servlet或其他资源(JSP、css、html)时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继续执行用户请求的资源,如果Filter“不放行”,那么就不会执行用户请求的资源。
其实可以这么理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定,可以理解为,Filter来决定是否调用Servlet,当执行完成Servlet的代码后,还会执行FilterChain中doFilter()方法后面的代码。
——编写一个过滤器
Filter是单例的。
1、编写一个类,并且实现Filter接口
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 编写过滤器
* 1、写一个类,并且实现Filter接口
* 2、在web.xml中进行相关配置
*
* @author 31067
*
*/
public class AFilter implements Filter {
/**
* 在销毁之前执行,用来对非内存资源进行释放
*/
@Override
public void destroy() {
System.out.println("销毁");
}
/**
* 每次过滤时都会执行
*/
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
System.out.println("拦截");
chain.doFilter(request, response);
System.out.println("放行了");
}
/**
* 在Filter创建后马上调用,用来做初始化操作
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("出生");
}
}
2、在web.xml文件中进行配置
<filter>
<filter-name>xxx</filter-name>
<filter-class>com.wyc.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>xxx</filter-name>
<url-pattern>/*</url-pattern> //通常会使用通配符进行url-pattern的配置 /web/*
</filter-mapping>
——Filter的生命周期
1、Filter接口生命周期方法:
* void init(FilterConfig config)
在服务器启动时会创建Filter的实例对象,并且每个类型的Filter只会创建一个实例对象,也就是说Filter是单例的。
在创建完Filter实例后,会马上调用init()方法完成初始化操作,这个方法只会被执行一次。
* void destory()
服务器会在创建Filter对象之后,把Filter放到内存中一直使用,通常不会销毁它,一般会在服务器关闭时销毁Filter对象。
在销毁Filter对象之前,服务器会调用Filter对象的destory()方法。
* void doFilter(ServletRequest , ServletResponse , FilterChain)
这个方法会在用户每次访问“目标资源<url-pattern>/index.jsp</url-pattern>”时执行。
如果需要“放行”,那么需要调用FilterChain对象的doFilter(ServletRequest, ServletResponse)方法,如果不调用该方法,则无法请求目标资源。
2、生命周期方法中的参数
FilterConfig:
* 获取初始化参数:getInitParameter();
* 获取所有初始化参数的名称:Enumeration getInitParameterNames()。
* 获取过滤器名称:getFilterName();
* 获取application:getServletContext();(获取当前上下文对象)
FilterChain:
* doFilter(ServletRequest, ServletResponse)
执行“放行”功能,使请求可以访问到资源。
相当于调用了请求Servlet的Service方法。
如果当前过滤器是最后一个过滤器,那么调用chain.doFilter()方法表示执行目标资源,如果不是最后一个过滤器,那么chain.doFilter()表示执行下一个过滤器的doFilter()方法。
面试:Filter接口的doFilter()方法和FilterChain的doFilter()方法有什么区别?
——过滤器的四种拦截方式
拦截方式:
* 请求:DISPATCHER
* 转发:FORWARD
* 包含:INCLUDE
* 错误:ERROR
如果不写,则默认<dispatcher>REQUEST</dispatcher>,如果只写一种,则默认拦截方式就不存在了。
拦截方式需要在<filter-mapping>中进行配置:
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher> // 默认拦截方式
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
——过滤器的执行顺序
<filter-mapping>中的配置执行顺序决定了过滤器的执行顺序。
先配置先执行。
XML配置如下:
<web-app>
<filter>
<filter-name>AFilter</filter-name>
<filter-class>com.wyc.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>BFilter</filter-name>
<filter-class>com.wyc.web.filter.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
执行效果如下:(与栈相似,当chain的doFilter()方法执行完毕后,还会继续执行剩余代码)
AFilter...start
BFilter...start
index.jsp
BFilter...end
AFilter...end
——Filter的应用场景
1、执行目标资源之前做预处理工作,例如设置编码,这种操作通常都会放行,只是在目标资源执行之前做一些准备工作。
几乎在所有的Servlet中都需要写:request.setCharacterEncoding();,这就可以把代码放到过滤器中。
2、通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否被禁用。
3、在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理。
也称为回程拦截。
——Filter设置目标资源
在web.xml文件中部署Filter时,可以通过“*”来执行目标资源:
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/*</url-pattern> // 表示过滤所有资源
</filter-mapping>
这一特性与Servlet完全相同,通过这一特性,可以在用户访问敏感资源时,执行过滤器,例如:<url-pattern>/admin/*</url-pattern>,可以把所有管理员才能访问的资源放到/admin路径下,这时就可以通过过滤器来校验用户身份了。
还可以为<filter-mapping>指定目标资源为某个Servlet,例如:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.wyc.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.wyc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilger</filter-name>
<servlet-name>MyServlet</servlet-name> // 访问指定的Servlet
</filter-mapping>
当用户访问:localhost:8080/FilterDemo/MyServlet时,会执行名称为MyServlet的Servlet,这时会执行绑定的过滤器。
<filter-mapping>中可以写以下四种标签:
<filter-name>
<url-pattern>
<dispatcher>
<servlet-name>
——Filter小结
1、Filter接口的三个方法:
* void init(FilterConfig config)
在Tomcat启动时被调用。
* void destory()
在Tomcat关闭时被调用。
* void doFilter(ServletRequest, ServletResponse, FilterChain)
每次请求时都会调用该方法。
2、FilterConfig类
与ServletConfig相似,用来获取Filter的初始化参数。
* ServletContext getServletContext()
获取Servlet上下文对象。
* String getFilterName()
获取Filter的配置名称。
* String getInitParameter(String name)
获取Filter的初始化参数,与<init-param>元素对应。
* Enumeration getInitParameterNames()
获取所有初始化参数的名称。
3、FilterChain类
* void doFilter(ServletRequest, ServletResponse)
“放行”方法,表示执行下一个过滤器,或者执行目标资源。可以在调用FilterChain的doFilter()方法前后添加语句。在FilterChain的doFilter()方法之前的语句会在目标资源执行前执行,在FilterChain的doFilter()方法之后的语句会在目标资源执行后执行。
4、四中拦截方式:
REQUEST:拦截直接请求方式
FORWARD:拦截请求转发方式
INCLUDE:拦截请求包含方式
ERROR:拦截错误转发方式
默认是REQUEST。
——分IP统计网站的访问次数
说明:网站统计每个IP地址访问本网站的次数。
分析:
因为一个网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,所以使用过滤器最为方便。
因为需要分IP进行统计,所以可以在过滤器中创建一个Map,使用IP作为key,访问次数为value。当有用户访问时,获取请求的IP,如果IP在Map中存在,说明以前访问过,那么在访问次数上+1即可,如果IP在Map中不存在,那么设置value为1。
整个网站只需要一个Map即可。
Map什么时候创建,将Map保存到那里?
> Map需要在Filter中使用,也要在页面中使用,所以保存到ServletContext中(application)
> 可以放到ServletContextListener监听器中,在服务器启动时完成创建,并保存到ServletContext中。
代码:
监听器:
public class IPListener implements ServletContextListener {
/**
* 在服务器启动时创建Map,保存到ServletContext中
*/
public void contextInitialized(ServletContextEvent sce) {
// 创建Map
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
// 得到ServletContext
ServletContext sc = sce.getServletContext();
// 将map保存到ServletContext中
sc.setAttribute("ipMaps", map);
}
public void contextDestroyed(ServletContextEvent arg0) {
}
}
过滤器:
/**
* 从ServletContext中获取Map对象
* 从request中得到请求客户端的IP
* 进行统计工作,将结果保存到Map中
*
* @author 31067
*
*/
public class IPFilter implements Filter {
private FilterConfig config;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
/*
* 1、得到ServletContext中的Map
* 2、从request中获取当前客户端的IP地址
* 3、查看Map中是否存在这个IP对应的访问次数,如果存在,把次数+1再保存
* 4、如果IP不存在,那么说明是第一次访问,设置访问次数为1
*/
// 1、得到ServletContext
ServletContext app = this.config.getServletContext();
// 得到Map
Map<String, Integer> map = (Map<String, Integer>) app.getAttribute("ipMaps");
/*
* 2、获取客户端的IP地址
*/
String ip = request.getRemoteAddr();
/*
* 3、进行判断
*/
if (map.get(ip) == null) {
map.put(ip, 1);
} else {
int count = map.get(ip);
map.put(ip, count + 1);
}
chain.doFilter(request, response);
}
/**
* 在服务器启动时就会执行本方法,而且本方法只执行一次
*/
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
}
——粗粒度权限控制
拦截是否登录、拦截用户名、权限拦截。
基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。
说明:
给出三个页面:index.jsp user.jsp admin.jsp
* index.jsp:任何用户都可以访问,没有限制。
* user.jsp:只有登录用户才能访问。
* admin.jsp:只有管理员才能访问。
代码:
Servlet:
public class LoginServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
/*
* 1、获取用户名
* 2、判断用户名中是否包含wyc
* > 如果包含,就是管理员
* > 如果不包含,就是普通会员
* 3、要把登录的用户名称保存到Session域中
* 4、转发到index.jsp
*/
String username = null;
String n = request.getParameter("username");
// 判断用户名是否为空并且是否为空字符串
if(n != null && !n.trim().isEmpty()){
username = n;
}
// 如果用户名不为null,则进行判断,避免空指针异常
if(username != null && username.contains("wyc")){
request.getSession().setAttribute("admin", username);
} else {
request.getSession().setAttribute("username", username);
}
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
}
过滤器:
UserFilter:过滤/user/*路径下的请求。
public class UserFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
/*
* 1、得到Session
* 2、判断session域中是否存在admin,如果存在,则放行
* 3、判断session域中是否存在username,如果存在,则放行
* 4、如果都不存在,进行拦截操作,并将页面转发到index.jsp
*/
HttpServletRequest req = (HttpServletRequest)request;
String name = (String)req.getSession().getAttribute("admin");
if(name != null) {
chain.doFilter(request, response);
return;
}
name = (String)req.getSession().getAttribute("username");
if(name != null) {
chain.doFilter(request, response);
return;
} else {
request.setAttribute("msg", "请先登录");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
AdminFilter:过滤/admin/*路径下的请求。
public class AdminFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
/*
* 1、得到session
* 2、判断session域中是否存在admin,如果存在,则放行
*/
HttpServletRequest req = (HttpServletRequest)request;
String name = (String)req.getSession().getAttribute("admin");
if(name != null) {
chain.doFilter(request, response);
return;
} else {
request.setAttribute("msg", "管理员,请先登录");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
——解决全站字符乱码问题(POST和GET中文编码问题)
POST请求:
> request.setCharacterEncoding("utf-8");
GET请求:
> String username = request.getParameter("username");
> username = new String(username.getBytes("iso-8859-1"), "utf-8");
过滤器:
Encodingfilter:
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 处理POST请求编码
request.setCharacterEncoding("utf-8");
/*
* 处理GET请求的编码问题
*/
/*
* 将原请求对象转换为自己的HttpServletRequest对象
* 1、写一个request的装饰类
* 2、增强getParameter()方法
* 3、在“放行”时使用自己的request对象
*/
/*
* 判断请求方式
* 不同的请求方式应该使用不同的编码处理方式
*/
HttpServletRequest req = (HttpServletRequest)request;
if(req.getMethod().equals("GET")){
EncodingRequest er = new EncodingRequest(req);
/*
* 将实现了HttpServletRequest接口的对象传入
*/
chain.doFilter(er, response);
} else if(req.getMethod().equals("POST")) {
chain.doFilter(request, response);
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
HttpServletRequest装饰类:
可以将此类保存为工具类,只需要在web.xml中进行配置即可使用。
/**
* 装饰request
*
* @author 31067
*
*/
public class EncodingRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
public EncodingRequest(HttpServletRequest request) {
/*
* 父类实现了“一切拜托你”
*/
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
/*
* 处理编码问题
*/
try {
value = new String(value.getBytes("iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return value;
}
}
——页面静态化
说明:
你到“当当”搜索最多的是什么分类呢?没错,就是Java分类。当你去搜索Java分类时,“当当”会不会去查询数据库呢?当然会了,不查询数据库怎么获取Java分类下的图书呢?其实每天都会有很多人去搜索“Java分类”的图书,每次都需要访问数据库,这会有性能上的缺失,如果是访问静态页面(HTML)那么就会快得多了,静态页面本身就比动态页面快很多倍,而且动态页面总是要去查询数据库,这会更加的降低速度。
页面静态化是把动态页面生成的HTML保存到服务器的文件上,然后当有相同请求时,不再去执行动态页面,而是直接给用户响应上次已经生成的静态页面,而且静态页面还有助于搜索引擎找到你。
步骤:
1、写一个小项目,图书管理系统
页面:
* jsp:index.jsp
链接页面,有四个超链接。
> 查询所有
> 查看SE分类
> 查看EE分类
> 查看框架分类
* show.jsp
显示查询结果。
Servlet:
BookServlet
> findAll()
查看所有图书
> findByCategory(int category)
按分类查询
BookService:
略
BookDao:
> List<Book> findAll()
> List<Book> findByCategory(int category)
domain:
Book类
SQL脚本:
create database bookdb;
create table book (
id char(32) primary key,
name varchar(100),
price numeric(10, 2),
category int
);
insert into book values (‘b1‘, ‘JavaSE_1‘, 10, 1);
insert into book values (‘b2‘, ‘JavaSE_2‘, 15, 1);
insert into book values (‘b3‘, ‘JavaSE_3‘, 20, 1);
insert into book values (‘b4‘, ‘JavaSE_4‘, 25, 1);
insert into book values (‘b5‘, ‘JavaEE_1‘, 30, 2);
insert into book values (‘b6‘, ‘JavaEE_2‘, 35, 2);
insert into book values (‘b7‘, ‘JavaEE_3‘, 40, 2);
insert into book values (‘b8‘, ‘Java_frameword_1‘, 45, 3);
insert into book values (‘b9‘, ‘Java_frameword_2‘, 50, 3);
select * from book;
===============================================================================
com.wyc.book.dao.BookDao
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import com.wyc.book.domain.Book;
import com.wyc.jdbc.TxQueryRunner;
public class BookDao {
private QueryRunner qr = new TxQueryRunner();
public List<Book> findAll() {
String sql = "select * from book";
try {
return qr.query(sql, new BeanListHandler<Book>(Book.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public List<Book> findByCategory(int category) {
String sql = "select * from book where category = ?";
Object[] params = { category };
try {
return qr.query(sql, new BeanListHandler<Book>(Book.class), params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
===============================================================================
com.wyc.book.domain.Book
public class Book {
private String id;
private String name;
private double price;
private int category;
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + ", categroy=" + category + "]";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCategory() {
return category;
}
public void setCategory(int category) {
this.category = category;
}
}
===============================================================================
com.wyc.book.service.BookService
import java.util.List;
import com.wyc.book.dao.BookDao;
import com.wyc.book.domain.Book;
public class BookService {
private BookDao bookDao = new BookDao();
public List<Book> findAll(){
return bookDao.findAll();
}
public List<Book> findByCategory(int category){
return bookDao.findByCategory(category);
}
}
===============================================================================
com.wyc.book.web.servlet.BookServlet
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wyc.book.service.BookService;
import com.wyc.servlet.BaseServlet;
public class BookServlet extends BaseServlet {
private BookService bookService = new BookService();
public String findAll(HttpServletRequest request, HttpServletResponse response) {
request.setAttribute("bookList", bookService.findAll());
return "f:show.jsp";
}
public String findByCategory(HttpServletRequest request, HttpServletResponse response) {
String value = request.getParameter("category");
int category = Integer.parseInt(value);
request.setAttribute("bookList", bookService.findByCategory(category));
return "f:show.jsp";
}
}
===============================================================================
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置 -->
<default-config>
<!-- 连接四大参数配置 -->
<property name="jdbcUrl">jdbc:
mysql://localhost:3306/bookdb</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">Admin123</property>
<!-- 连接池参数配置 -->
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<prpperty name="minPoolSize">2</prpperty>
<property name="maxPoolSize">10</property>
</default-config>
</c3p0-config>
===============================================================================
index.jsp
<body>
<h1>链接页面</h1>
<a href="<c:url value=‘/BookServlet?method=findAll‘ />">查询所有</a>
<a href="<c:url value=‘/BookServlet?method=findByCategory&category=1‘ />">查询SE</a>
<a href="<c:url value=‘/BookServlet?method=findByCategory&category=2‘ />">查询EE</a>
<a href="<c:url value=‘/BookServlet?method=findByCategory&category=3‘ />">查询Framework</a>
</body>
===============================================================================
show.jsp
<body>
<h1 align="center">图书列表</h1>
<table border="1" align="center" width="50%">
<tr>
<th>书名</th>
<th>单价</th>
<th>分类</th>
</tr>
<c:forEach items="${requestScope.bookList }" var="book">
<tr>
<td>${book.name }</td>
<td>${book.price }</td>
<c:if test="${book.category eq 1 }">
<td><font color="green">JavaSE</font></td>
</c:if>
<c:if test="${book.category eq 2 }">
<td><font color="red">JavaEE</font></td>
</c:if>
<c:if test="${book.category eq 3 }">
<td><font color="blue">JavaFramework</font></td>
</c:if>
</tr>
</c:forEach>
</table>
</body>
===============================================================================
2、页面静态化
首次访问时去数据库获取数据,然后把数据保存到HTML页面中。
第二次访问时,就不再去访问数据库了,而是直接显示HTML。
给出一个过滤器,把Servlet请求的资源所做的输出,保存到HTML中,然后再重定向到HTML页面,当第二次访问时,这个HTML已经存在,那么直接重定向即可,不需要再次访问Servlet了。
com.wyc.book.web.filter.StaticFilter
import java.io.File;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class StaticFilter implements Filter {
private FilterConfig config;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
/*
* 1、第一次访问时,要查找请求对应的HTML页面是否存在,如果存在,则重定向到指定页面
* 2、如果HTML不存在,则放行,把Servlet访问数据库后输出给客户端的数据保存到一个HTML页面中,再重定向到HTML页面
*/
/*
* 一、获取Category参数,来判断请求的页面
* category有四种可能:
* > null -->null.html
* > 1 --> 1.html
* > 2 --> 2.html
* > 3 --> 3.html
* HTML页面保存的路径,在htmls目录下
*
* 判断对应的HTML文件是否存在,如果存在,直接重定向
*/
String category = request.getParameter("category");
// 得到对应的文件名称
String htmlPage = category + ".html";
// 得到文件的存放目录,获取的是真实目录
String htmlPath = config.getServletContext().getRealPath("/htmls");
// 创建文件
File destFile = new File(htmlPath, htmlPage);
// 如果文件存在,则重定向到该文件
if(destFile.exists()) {
// 重定向,重定向要使用完整的绝对路径
resp.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage);
return;
}
/*
* 二、如果HTML文件不存在,需要生成HTML页面并保存
* 1、放行,show.jsp页面会做出输出操作,可以将输出的内容输出到指定的HTML页面,而不是输出到客户端
* 2、调包response,让它的getWriter()与一个HTML文件绑定,而不是客户端,那么show.jsp的输出操作就输出到了指定的HTML文件中了
*/
// 传递文件的绝对路径
StaticResponse sr = new StaticResponse(resp, destFile.getAbsolutePath());
/*
* 放行,即生成了HTML文件
*
* 在放行(输出)之前,需要解决乱码问题:
* 因为所有的数据都是通过show.jsp页面进行输出的,所以可以在show.jsp页面中添加如下meta标签
* <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
*/
chain.doFilter(request, sr);
// 此时HTML文件已经存在了,可以重定向到指定页面了
sr.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage);
}
public void init(FilterConfig fConfig) throws ServletException {
this.config = fConfig;
}
}
===============================================================================
com.wyc.book.web.filter.StaticResponse
HttpServletResponse装饰类
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class StaticResponse extends HttpServletResponseWrapper {
private PrintWriter pw;
/*
* String path:指向HTML文件的路径
*/
public StaticResponse(HttpServletResponse response, String path) {
super(response);
try {
// 创建一个HTML文件并创建一个与HTML文件路径绑定在一起的流对象
this.pw = new PrintWriter(path, "utf-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public PrintWriter getWriter(){
// 返回一个与HTML绑定在一起的printWriter对象
// JSP会使用它进行输出,这样数据都会输出到指定的HTML文件中了
return pw;
}
}
以上是关于JavaWeb之过滤器的主要内容,如果未能解决你的问题,请参考以下文章
javaWeb--之--过滤器(filter)篇
JavaWeb 之 Filter:过滤器
JavaWeb详解(第三篇)之Servlet基础简介-过滤器Filter&Listener监听器
JavaWeb之Filter&Listener
javaweb之session过期验证
java_day30_javaWeb三大组件之过滤器Filter