您的位置:首页 > 其它

26、过滤器

2016-06-11 16:31 281 查看

过滤器

项目开发中,经常会涉及到重复代码的实现!

注册 ---- 提交Servlet 【1. 设置编码格式】 ----转到JSP
修改 ---- 提交Servlet 【1. 设置编码格式】 --- 转到JSP


其他:

如判断用户是否登陆,只有登陆才能有操作权限!
涉及到重复判断: 获取session,取出session数据,判断是否为空,为空说明没有登陆,不能操作
只有登陆后,才能操作!


如何解决:

抽取重复代码,封装

每个用到重复代码的地方,手动的调用!

过滤器,设计执行流程:

用户访问服务器

过滤器: 对Servlet请求进行拦截

先进入过滤器, 过滤器处理

过滤器处理完后, 在放行, 此时,请求到达Servlet/JSP

Servlet处理

Servlet处理完后,再回到过滤器, 最后在由tomcat服务器相应用户;

(过滤器就像回家的门!)

基本知识

过滤器:
* 概述:
* Filter的作用:起到过滤的作用.
* Filter执行的时机:
* 在执行对应的Servlet之前.(过滤Request对象中的内容)
* 在执行对应的Servlet之后.(过滤Respons对象中的内容)
* 发展:
* Filter最早在Servlet 2.3版本提供.
* Filter在Servlet 2.5版本完善.
* 如何使用Filter:
* Filter是JavaEE提供的一个接口.(自定义Filter需要实现该接口,并重写所有方法)
* Filter提供的方法:
* init()
* doFilter()
* destroy()
* 实现步骤:
* 创建Java类,实现Filter接口,并且重写所有方法.
* 在web.xml文件中进行配置.
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>app.java.filter.MyFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* Filter的生命周期:
* 出生:Hello World
* init()方法
* 活着:Love World
* doFilter()方法
* 死去:GoodBye World
* destroy()方法
* 过滤器链:
* 问题:
* 如何定义过滤器被执行的先后顺序?
* Filter的doFilter()方法具有一个参数FilterChain,通过调用chain.doFilter()方法可以放行.
* 在过滤器链中,执行chain.doFilter()方法,是否还是放行的作用?
* 如果是,应该被放行到哪里去了?(单个Filter时,直接被放行到对应的Web资源[Servlet、JSP])
* 解决以上问题:
* chain.doFilter()方法依旧是放行方法.
* 如果执行的不是过滤器链中最后一个过滤器的话,执行chain.doFilter()方法,会被放行到下一个过滤器里.
* 如果执行的是过滤器链中最后一个过滤器的话,chain.doFilter()方法,才会被放行到对应Web资源中.
* 过滤器链中的过滤器执行的先后顺序由web.xml文件中的<filter-mapping>标签定义的先后顺序决定.
* 实际开发的意义:
* 单个Filter完成单个任务.
* FilterConfig
* 读取web.xml文件中的初始化参数.
* 在web.xml文件中是如何配置的:
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>app.java.filter.MyFilter2</filter-class>
<init-param>
<param-name>mingjiao</param-name>
<param-value>zhangwuji</param-value>
</init-param>
</filter>
* FilterConfig的用法与ServletConfig一致.
* 在web.xml文件中配置全局初始化参数<context-param>,通过ServletContext对象读取.
* Filter的映射配置:<url-pattern>
* 完全匹配:/xxxx
* 目录匹配:/aaaa/
* 扩展名匹配:*.do
* 优先级别:完全匹配 -> 目录匹配 -> 扩展名匹配

* 如果当前Filter拦截对应Servlet的话:
* 还可以使用<servlet-name>标签

* Filter拦截Servlet默认情况是拦截直接请求.
* 在web.xml文件中配置<filter-mapping>标签中具有<dispatcher>
* <dispatcher>标签在同一个Filter的配置中,可以配置多个.
* <dispatcher>标签的值:
* REQUEST:是默认值,表示一次请求.
* FORWARD:表示请求转发到.
* INCLUDE:表示包含(例如JSP包含另一个JSP等)
* ERROR:表示JSP的<%@ page errorPage=""%>

* Filter的案例:
* 全站乱码案例:
* 利用Servlet的doGet()和doPost()方法中,可以解决中文乱码:
* doGet()
String value = request.getParameter("");
value = new String(value.getBytes("ISO8859-1"),"utf-8");

response.setContentType("text/html;charset=utf-8");
* doPost()
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
* 以上问题:
* 实际开发时,Web应用程序的逻辑比较复杂(多个Servlet).
* 上述的解决方案,仅能解决当前Servlet的中文乱码问题.
* 如果使用上述方案,解决中文乱码问题:代码重复性太多.


过滤器案例:

接口:

|-- interface  Filter               过滤器核心接口
Void  init(filterConfig);    初始化方法,在服务器启动时候执行
Void  doFilter(request,response,filterChain);   过滤器拦截的业务处理方法
Void destroy();             销毁过滤器实例时候调用

|-- interface  FilterConfig   获取初始化参数信息
String  getInitParameter(java.lang.String name)
Enumeration getInitParameterNames()

|-- interface  FilterChain     过滤器链参数;一个个过滤器形成一个执行链;
void doFilter(ServletRequest request, ServletResponse response);
//执行下一个过滤器或放行


public class HelloFilter implements Filter{

// 创建实例
public HelloFilter(){
System.out.println("1. 创建过滤器实例");
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2. 执行过滤器初始化方法");

// 获取过滤器在web.xml中配置的初始化参数
String encoding = filterConfig.getInitParameter("encoding");
System.out.println(encoding);

// 获取过滤器在web.xml中配置的初始化参数 的名称
Enumeration<String> enums =  filterConfig.getInitParameterNames();
while (enums.hasMoreElements()){
// 获取所有参数名称:encoding、path
String name = enums.nextElement();
// 获取名称对应的值
String value = filterConfig.getInitParameter(name);
System.out.println(name + "\t" + value);
}
}

// 过滤器业务处理方法: 在请求到达servlet之前先进入此方法处理公用的业务逻辑操作
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("3. 执行过滤器业务处理方法");
// 放行 (去到Servlet)
// 如果有下一个过滤器,进入下一个过滤器,否则就执行访问servlet
chain.doFilter(request, response);

System.out.println("5. Servlet处理完成,又回到过滤器");
}

@Override
public void destroy() {
System.out.println("6. 销毁过滤器实例");
}
}


public class HelloFilter2 implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("第二个过滤器");
// 放心
chain.doFilter(request, response);
System.out.println("第二个过滤器执行结束");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub

}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}


xml配置:

<!-- 过滤器配置
<filter>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>path</param-name>
<param-value>c:/...</param-value>
</init-param>

<filter-name>hello_filter</filter-name>
<filter-class>cn.itcast.a_filter_hello.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hello_filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->

<!-- 配置第二个过滤器 -->
<!-- 演示: 拦截指定的请求 -->
<filter>
<filter-name>hello_filter2</filter-name>
<filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>hello_filter2</filter-name>
<!-- 1. 拦截所有
<url-pattern>/*</url-pattern>
-->

<!-- 2. 拦截指定的jsp
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
-->
<!-- 拦截所有的jsp
<url-pattern>*.jsp</url-pattern>
-->
<!-- 3. 根据servlet的内部名称拦截
<servlet-name>IndexServlet</servlet-name>
-->
<!-- 拦截指定的servlet
<url-pattern>/index</url-pattern>
-->

<!-- 4. 指定拦截指定的类型 -->
<url-pattern>/*</url-pattern>
<!-- 拦截直接访问的请求或者重定向的资源 -->
<dispatcher>REQUEST</dispatcher>
<!--<dispatcher>FORWARD</dispatcher>-->
</filter-mapping>


编码处理过滤器

public class EncodingFilter implements Filter {

// 过滤器业务处理方法:处理的公用的业务逻辑操作
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 转型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 一、处理公用业务
request.setCharacterEncoding("UTF-8");                  // POST提交有效
response.setContentType("text/html;charset=UTF-8");
/*
* 出现GET中文乱码,是因为在request.getParameter方法内部没有进行提交方式判断并处理。
* String name = request.getParameter("userName");
*
* 解决:对指定接口的某一个方法进行功能扩展,可以使用代理!
*      对request对象(目标对象),创建代理对象!
*/
HttpServletRequest proxy =  (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(),        // 指定当前使用的累加载器
new Class[]{HttpServletRequest.class},      // 对目标对象实现的接口类型
new InvocationHandler() {                   // 事件处理器
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 定义方法返回值
Object returnValue = null;
// 获取方法名
String methodName = method.getName();
// 判断:对getParameter方法进行GET提交中文处理
if ("getParameter".equals(methodName)) {

// 获取请求数据值【 <input type="text" name="userName">】
String value = request.getParameter(args[0].toString());    // 调用目标对象的方法

// 获取提交方式
String methodSubmit = request.getMethod(); // 直接调用目标对象的方法

// 判断如果是GET提交,需要对数据进行处理  (POST提交已经处理过了)
if ("GET".equals(methodSubmit)) {
if (value != null && !"".equals(value.trim())){
// 处理GET中文
value = new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}
return value;
}
else {
// 执行request对象的其他方法
returnValue = method.invoke(request, args);
}

return returnValue;
}
});

// 二、放行 (执行下一个过滤器或者servlet)
chain.doFilter(proxy, response);        // 传入代理对象
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}
@Override
public void destroy() {

}
}


数据过滤器

/**
* 无效数据过滤
* @author Jie.Yuan
*
*/
public class DateFilter implements Filter {

// 初始化无效数据
private List<String> dirtyData;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 模拟几个数据
dirtyData = new ArrayList<String>();
dirtyData.add("NND");
dirtyData.add("炸使馆");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {

// 转型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

// 一、处理公用业务
request.setCharacterEncoding("UTF-8");                  // POST提交有效
response.setContentType("text/html;charset=UTF-8");

HttpServletRequest proxy =  (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(),        // 指定当前使用的累加载器
new Class[]{HttpServletRequest.class},      // 对目标对象实现的接口类型
new InvocationHandler() {                   // 事件处理器
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 定义方法返回值
Object returnValue = null;
// 获取方法名
String methodName = method.getName();
// 判断:对getParameter方法进行GET提交中文处理
if ("getParameter".equals(methodName)) {

// 获取请求数据值【 <input type="text" name="userName">】
String value = request.getParameter(args[0].toString());    // 调用目标对象的方法

// 获取提交方式
String methodSubmit = request.getMethod(); // 直接调用目标对象的方法

// 判断如果是GET提交,需要对数据进行处理  (POST提交已经处理过了)
if ("GET".equals(methodSubmit)) {
if (value != null && !"".equals(value.trim())){
// 处理GET中文
value = new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}

// 中文数据已经处理完: 下面进行无效数据过滤
//【如何value中出现dirtyData中数据,用****替换】
for (String data : dirtyData) {
// 判断当前输入数据(value), 是否包含无效数据
if (value.contains(data)){
value = value.replace(data, "*****");
}
}
// 处理完编码、无效数据后的正确数据
return value;
}
else {
// 执行request对象的其他方法
returnValue = method.invoke(request, args);
}

return returnValue;
}
});

// 二、放行 (执行下一个过滤器或者servlet)
chain.doFilter(proxy, response);        // 传入代理对象
}
@Override
public void destroy() {

}
}


拦截过滤器

/**
* 登陆验证过滤器
*
*  http://localhost:8080/emp_sys/login.jsp   可以直接访问 http://localhost:8080/emp_sys/login      可以直接访问 http://localhost:8080/emp_sys/index   不能直接访问 http://localhost:8080/emp_sys/list.jsp   不能直接访问

* @author Jie.Yuan
*
*/
public class LoginFilter implements Filter {

private String uri;

/**
* 分析:
*
1. 先指定放行的资源,哪些资源不需要拦截:
login.jsp   +    /login  (request对象可以获取)
2. 获取session,从session中获取登陆用户
3. 判断是否为空:
为空, 说明没有登陆, 跳转到登陆
不为空, 已经登陆,放行!
*/
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {

//0. 转换
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

//1. 获取请求资源,截取
String uri = request.getRequestURI();   // /emp_sys/login.jsp
// 截取 【login.jsp或login】
String requestPath = uri.substring(uri.lastIndexOf("/") + 1, uri.length());

//2. 判断: 先放行一些资源:/login.jsp、/login
if ("login".equals(requestPath) || "login.jsp".equals(requestPath)) {
// 放行
chain.doFilter(request, response);
}
else {
//3. 对其他资源进行拦截
//3.1 先获取Session、获取session中的登陆用户(loginInfo)
HttpSession session = request.getSession(false);
// 判断
if (session != null) {

Object obj = session.getAttribute("loginInfo");

//3.2如果获取的内容不为空,说明已经登陆,放行
if (obj != null) {
// 放行
chain.doFilter(request, response);
} else {
//3.3如果获取的内容为空,说明没有登陆; 跳转到登陆
uri = "/login.jsp";
}

} else {
// 肯定没有登陆
uri = "/login.jsp";
}
request.getRequestDispatcher(uri).forward(request, response);
}
}

public void init(FilterConfig filterConfig) throws ServletException {
}

public void destroy() {
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: