java web过滤器_Java Web之过滤器(Filter)

过滤器(Filter)

过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理

通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理

大概流程图如下

7162208e71353c8e6eb21d2a5669f601.png

应用场景

自动登录

统一设置编码格式

访问权限控制

敏感字符过滤等

创建Filter##

在Servlet中我们一般都会对request和response中的字符集编码进行配置,如果Servlet过多字符集编码发生变化时修改起码会很麻烦,这些通用的字符集编码配置等工作我们可以放到Filter中来实现。

下面我们来创建一个处理字符集编码的Filter。

右键包名—>new ---->Filter

e376a9c226996312caee503ecef2c2cf.png

输入过滤器名称,跟创建Servlet一样,这里我们直接使用**@WebFilter**注解,不再去web,xml中进行配置了。

7924de81af2323a1a01ac628e68d66c2.png

创建完成后默认代码,可以看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。

package filter;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter(filterName = "CharsetFilter")

public class CharsetFilter implements Filter {

public void destroy() {

/*销毁时调用*/

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

/*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/

chain.doFilter(req, resp);//交给下一个过滤器或servlet处理

}

public void init(FilterConfig config) throws ServletException {

/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

配置Filter

可配置的属性有这些

1532708c8b36b43123806124a2b8824f.png

常用配置项

urlPatterns

配置要拦截的资源

以指定资源匹配。例如"/index.jsp"

以目录匹配。例如"/servlet/*"

以后缀名匹配,例如"*.jsp"

通配符,拦截所有web资源。"/*"

**initParams **

配置初始化参数,跟Servlet配置一样

例如

initParams = {

@WebInitParam(name = "key",value = "value")

}

1

2

3

dispatcherTypes **

配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST**

例如

dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR}

1

其中DispatcherType是个枚举类型,有下面几个值

FORWARD,//转发的

INCLUDE,//包含在页面的

REQUEST,//请求的

ASYNC,//异步的

ERROR;//出错的

1

2

3

4

5

下面我们来对CharsetFilter 代码进行一下修改

package filter;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import javax.servlet.annotation.WebInitParam;

import java.io.IOException;

@WebFilter(filterName = "CharsetFilter",

urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/

initParams = {

@WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/

})

public class CharsetFilter implements Filter {

private String filterName;

private String charset;

public void destroy() {

/*销毁时调用*/

System.out.println(filterName + "销毁");

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

/*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/

System.out.println(filterName + "doFilter()");

req.setCharacterEncoding(charset);

resp.setCharacterEncoding(charset);

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/

filterName = config.getFilterName();

charset = config.getInitParameter("charset");

System.out.println("过滤器名称:" + filterName);

System.out.println("字符集编码:" + charset);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

这样一个简单的字符集编码处理的过滤器就完成了

我们看看执行打印的结果

cb4222c617b8a6aba659e29199dabce8.png

需要注意的是

过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.

当Filter被移除或服务器正常关闭时,会执行destroy方法

多个Filter的执行顺序

在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。

如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下

在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行

使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行

如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

我们写个小例子看一下

新建3个Filter,加上之前的CharsetFilter一共四个

ae62af092b79a48a53864abb04fddac7.png

其中CharsetFilter和ABFilter是通过注解声明的

CharsetFilter注解配置

@WebFilter(filterName = "CharsetFilter",

urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/

initParams = {

@WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/

})

1

2

3

4

5

6

ABFilter

@WebFilter(filterName = "ABFilter",urlPatterns = "/*")

1

AFilter和BFilter是在web.xml配置的。

执行顺序跟的顺序无关

的顺序才决定执行顺序

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

AFilter

filter.AFilter

BFilter

filter.BFilter

BFilter

/filter.jsp

AFilter

/filter.jsp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

每个Filter添加了打印语句,如下

以ABFilter为例

package filter;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter(filterName = "ABFilter",urlPatterns = "/*")

public class ABFilter implements Filter {

private String filterName;

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

System.out.println(filterName + " doFilter()");

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

filterName= config.getFilterName();

System.out.println("过滤器名称:" + filterName +" init");

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

下面我们来访问filter.jsp看看打印结果

ad3fe05f417c4f4fa1b4be395b62eba3.gif

可以看到,执行结果符合预期。

BFilter和AFilter是在web.xml中声明的,且BFilter的在前,故BFilter在AFilter之前执行。

ABFilter和CharsetFilter是通过注解声明的,故他俩在BFilter和AFilter之后执行,但是ABFilter的名称以A开头,故在CharsetFilter之前执行

83c61ed11426fdb0b3b368558fd20eb7.png

访问权限控制小例子##

下面我们写一个访问控制权限控制的小例子。

我们在浏览一些网站经常有这个情况,没有登录时是不允许我们访其主页的,只有登录过后才能访问。

下面我们就用Filter简单实现一下。

需求分析

登录时将登录的账号密码保存到cookie中,下次访问时携带账号和密码,过滤器中进行校验

用户没有登录直接访问主页时,要跳转到登录页面

登录过滤器不对登录页面进行过滤

我们先来看一下项目结构

7f7020e2f16594995cc36074560f66aa.png

这里主要看一下LoginFilter的代码

我们在LoginFilter中对非登录页面的其他jsp都会进行过滤,判断cookie中是否携带了account和pwd。

如果有这两个数据表示之前登录过,那么对数据进行校验,正确的话就进行下一个操作。

否则的话,跳转到登录界面

package filter;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebFilter(filterName = "LoginFilter", urlPatterns = "*.jsp", dispatcherTypes = {})

public class LoginFilter implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

System.out.println("LoginFilter doFilter");

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) resp;

String url = request.getRequestURI();

System.out.println("请求的url:" + url);

/*登录页面不需要过滤*/

int idx = url.lastIndexOf("/");

String endWith = url.substring(idx + 1);

if (!endWith.equals("login.jsp")) {

/*不是登录页面 进行拦截处理*/

System.out.println("不是登录页面,进行拦截处理");

if (!isLogin(request)) {

System.out.println("没有登录过或者账号密码错误,跳转到登录界面");

response.sendRedirect("login.jsp");

} else {

System.out.println("已经登录,进行下一步");

chain.doFilter(req, resp);

}

} else {

System.out.println("是登录页面,不进行拦截处理");

chain.doFilter(req, resp);

}

}

private boolean isLogin(HttpServletRequest request) {

Cookie[] cookies = request.getCookies();

String account = "";

String pwd = "";

if (cookies != null && cookies.length > 0) {

for (Cookie cookie : cookies) {

if (cookie.getName().equals("account")) {

account = cookie.getValue();

} else if (cookie.getName().equals("pwd")) {

pwd = cookie.getValue();

}

}

}

if (account.equals("") || pwd.equals("")) {

return false;

} else if (account.equals("yzq") && pwd.equals("123")) {

return true;

}

return false;

}

public void init(FilterConfig config) throws ServletException {

System.out.println("LoginFilter init");

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

执行效果

4e9815a34e7062e307d636aa010602da.gif

可以看到,我们在没有登录的情况下直接去访问index.jsp页面时会自动跳转到登录页面,在登录成功后,再次直接访问index页面则可以访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值