web day21 web过滤器Filter,应用案例统计IP,解决全站乱码,粗粒度权限控制,页面静态化

时间:2022-07-04 18:28:12

web day21 web过滤器Filter,应用案例统计IP,解决全站乱码,粗粒度权限控制,页面静态化



JavaWeb三大组件

 
1. 都需要在web.xml中进行配置

Servlet

Listener(2个感知监听器不需要配置)

Filter

 
过滤器

  它会在一组资源(jsp、servlet、.css、.html等等)的前面执行!

  它可以让请求得到目标资源,也可以不让请求达到!

  * 过滤器有拦截请求的能力!

 

登录:

允许它访问AServlet、BServlet、CServlet

 web day21 web过滤器Filter,应用案例统计IP,解决全站乱码,粗粒度权限控制,页面静态化

-------------------------------

 

过滤器如何编写

 

1. 写一个类实现Filter接口

2. 在web.xml中进行配置

 

Filter接口

 

void init(FilterConfig)

  * 创建之后,马上执行;Filter会在服务器启动时就创建!

void destory()

  * 销毁之前执行!在服务器关闭时销毁

voiddoFilter(ServletRequest,ServletResponse,FilterChain)

  * 每次过滤时都会执行

 

Filter是单例的!


web.xml部署

<filter>

 <filter-name>xxx</filter-name>

 <filter-class>cn.itcast.web.filter.AFitler</fitler-class>

</filter>

<fitler-mapping>

 <filter-name>xxx</filter-name>

 <url-pattern>/*</url-pattern>

<!--除了url-pattern servlet也可以 -->

</filter-mapping>

 

-------------------------------

 

FilterConfig-->与ServletConfig相似

  * 获取初始化参数:getInitParameter()

  * 获取过滤器名称:getFilterName()

  * 获取appliction:getServletContext()

 
FilterChain

  *doFilter(ServletRequest, ServletResponse):放行!

  放行,就相当于调用了目标Servlet的service()方法!

 

-------------------------------

 

-------------------------------

 

多过滤器

 

FilterChain#doFilter()方法:

  执行目标资源,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器!

 

 

-------------------------------

 
过滤器的四种拦截方式

 

 <dispatcher>REQUEST</dispatcher>默认的!

 <dispatcher>FORWARD</dispatcher>

 <dispatcher>INCLUDE</dispatcher>

 <dispatcher>ERROR</dispatcher>

 

在<filter-mapping>中进行配置!

 

 

-------------------------------

 

多个过滤器的执行顺序

 

<filter-mapping>的配置顺序决定了过滤器的执行顺序!

 

 

 Filter应用案例

 1.分IP统计网站访问次数

代码

lintener

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) {
}
}
filter

/**
* 从application中获取Map
* 从request中得到当前客户端的IP
* 进行统计工作,结果保存到Map中
* @author cxf
*
*/
public class AFilter implements Filter {
private FilterConfig config;
public void destroy() {
}

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
/*
* 1. 得到application中的map
* 2. 从request中获取当前客户端的ip地址
* 3. 查看map中是否存在这个ip对应访问次数,如果存在,把次数+1再保存回去
* 4. 如果不存在这个ip,那么说明是第一次访问本站,设置访问次数为1
*/
/*
* 1. 得到appliction
*/
ServletContext app = config.getServletContext();
Map<String,Integer> map = (Map<String, Integer>) app.getAttribute("map");
/*
* 2. 获取客户端的ip地址
*/
String ip = request.getRemoteAddr();
/*
* 3. 进行判断
*/
if(map.containsKey(ip)) {//这个ip在map中存在,说明不是第一次访问
int cnt = map.get(ip);
map.put(ip, cnt+1);
} else {//这个ip在map中不存在,说明是第一次访问
map.put(ip, 1);
}
app.setAttribute("map", map);//把map再放回到app中

chain.doFilter(request, response);//肯定放行
}

/**
* 在服务器启动时就会执行本方法,而且本方法只执行一次!
*/
public void init(FilterConfig fConfig) throws ServletException {
this.config = fConfig;
}
}



2.粗粒度权限控制

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,如果存在,放行
* 3. 判断session域中是否存在username,如果存在,放行,否则打回到login.jsp,并告诉它不要瞎留达
*/
HttpServletRequest req = (HttpServletRequest) request;
String name = (String)req.getSession().getAttribute("admin");
if(name != null) {
chain.doFilter(request, response);
} else {
req.setAttribute("msg", "您可能是个啥,但肯定不是管理员!");
req.getRequestDispatcher("/login.jsp").forward(request, response);
}
}

public void init(FilterConfig fConfig) throws ServletException {

}
}



------------------
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,如果存在,放行,否则打回到login.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);
} else {
req.setAttribute("msg", "您啥都不是,不要瞎溜达!");
req.getRequestDispatcher("/login.jsp").forward(request, response);
}
}

public void init(FilterConfig fConfig) throws ServletException {

}
}




3.解决post/get中文编码问题

原理:利用装饰模式及HttpServletRequestWrapper包装类


filter

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");

HttpServletRequest req = (HttpServletRequest) request;

/*
* 处理GET请求的编码问题
*/
//String username = request.getParameter("username");
//username = new String(username.getBytes("ISO-8859-1"), "UTF-8");

/*
* 调包request
* 1. 写一个request的装饰类
* 2. 在放行时,使用我们自己的request
*/
if(req.getMethod().equals("GET")) {
EncodingRequest er = new EncodingRequest(req);
chain.doFilter(er, response);
} else if(req.getMethod().equals("POST")) {
chain.doFilter(request, response);
}
}

public void init(FilterConfig fConfig) throws ServletException {

}
}

装饰包装类

/**
* 装饰reqeust
* @author cxf
*
*/
public class EncodingRequest extends HttpServletRequestWrapper {
private HttpServletRequest req;

public EncodingRequest(HttpServletRequest request) {
super(request);
this.req = request;
}

public String getParameter(String name) {
String value = req.getParameter(name);

// 处理编码问题
try {
value = new String(value.getBytes("iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}

return value;
}
}



4.页面静态化


1. 第一步

写一个简单的单表查询(略)

 

2. 第二步:什么是页面静态化!

  首次访问去数据库获取数据,然后把数据保存到一个html页面中(服务器)

  二次访问,就不再去数据库获取了,而是直接显示html

 

----------------------------------------------------------


1. 目标!

  给出一个过滤器,把servlet请求的资源所做输出保存到html中,重定向到html页面。

  二次访问时,这个html已经存在,那么直接重定向,不用再去访问servlet!

web day21 web过滤器Filter,应用案例统计IP,解决全站乱码,粗粒度权限控制,页面静态化



代码

filter

public class StaticFilter implements Filter {
private FilterConfig config;
public void destroy() {}
public void init(FilterConfig fConfig) throws ServletException {
this.config = fConfig;
}

public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
/*
* 1. 第一次访问时,查找请求对应的html页面是否存在,如果存在重定向到html
* 2. 如果不存在,放行!把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()) {//如果文件存在
// 重定向到这个文件
res.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage);
return;
}

/*
* 二、如果html文件不存在,我们要生成html
* 1. 放行,show.jsp会做出很多的输出,我们要让它别再输出给客户端,而是输出到我们指定的一个html文件中
* 完成:
* * 调包response,让它的getWriter()与一个html文件绑定,那么show.jsp的输出就到了html文件中
*/
StaticResponse sr = new StaticResponse(res, destFile.getAbsolutePath());
chain.doFilter(request, sr);//放行,即生成了html文件

// 这时页面已经存在,重定向到html文件
res.sendRedirect(req.getContextPath() + "/htmls/" + htmlPage);
}
}


包装响应类

public class StaticResponse extends HttpServletResponseWrapper {
private PrintWriter pw;

/**
* String path:html文件路径!
* @param response
* @param path
* @throws UnsupportedEncodingException
* @throws FileNotFoundException
*/
public StaticResponse(HttpServletResponse response, String path)
throws FileNotFoundException, UnsupportedEncodingException {
super(response);

// 创建一个与html文件路径在一起的流对象
pw = new PrintWriter(path, "utf-8");
}

public PrintWriter getWriter() {
// 返回一个与html绑定在一起的printWriter对象
// jsp会使用它进行输出,这样数据都输出到html文件了。
return pw;
}
}