Servlet中组件一共有三种:Servlet、过滤器、监听器
组件 | 作用 | 实现接口 |
---|---|---|
Servlet | 是一个运行在服务器端的Java小程序,用来接收请求并做出响应 | javax.servlet.Servlet |
过滤器 | 用于拦截用户的请求和响应,并且修改请求中的数据,对数据进行处理。 | javax.servlet.Filter |
监听器 | 监听Web程序在运行过程中对作用域操作的事件,并且对事件进行处理 多个不同的接口 | javax.servlet.XxxListener |
过滤器是服务器与客户端请求与响应的中间层组件,在实际项目开发中过滤器主要用于对浏览器的请求进行过滤处理,将过滤后的请求再转给下一个资源。与其他的WEB应用程序组件不同的是,过滤器是采用了“链”的方式进行处理的。
与Servlet的执行不同,Servlet是有访问的地址。不是由用户主动调用,而是自动执行,是通过匹配用户的访问地址去进行过滤。
开发过滤器的步骤:
/**
* a) 编写一个类,实现javax.servlet.Filter接口
* @author NewBoy
*
*/
public class HelloFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 执行过滤任务
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("请求经过过滤器");
//放行,让请求继续到达web资源(Servlet),调用chain中的方法
chain.doFilter(request, response);
System.out.println("响应回来经过过滤器");
}
@Override
public void destroy() {
}
}
Servlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("我是HelloServlet,Web资源");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
<filter>
<filter-name>hellofilter-name>
<filter-class>com.filter.HelloFilterfilter-class>
filter>
<filter-mapping>
<filter-name>hellofilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
生命周期的方法:
Filter接口中的方法
- void init(FilterConfig filterConfig)
- 在初始化过滤器的时候**执行1次**
- void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- 参数:请求,响应,过滤链
- 请求和响应这两个接口是HttpServletRequest和HttpServletResponse的父接口
- 执行过滤的功能,**每次请求都会执行这个方法**
- public void destroy()
- 在服务器关闭的时候销毁,执行1次
在Servlet中url-pattern是访问的地址
在Filter中url-pattern是要过滤的地址
问:浏览器访问目标资源的路径,如果目标地址不存在,过滤器会不会运行?
如果Web资源不存在,只要匹配过滤的地址,同样会执行过滤器。
匹配方式 | 匹配哪些资源 | 示例 |
---|---|---|
完全匹配 | 必须与访问地址精确匹配 | /demo1 、/aaa/bbb |
目录匹配 | 匹配某一个目录下所有的Web资源 | /aaa/* 、/* 匹配所有的资源 |
扩展名匹配 | *.扩展名 匹配某一类扩展名 | *.do 、*.action |
同时出现会在web项目加载的时候就失败,导致当前项目所有的web资源都无法访问。
<filter>
<filter-name>lifefilter-name>
<filter-class>com.filter.Demo1LifeCycleFilterfilter-class>
filter>
<filter-mapping>
<filter-name>lifefilter-name>
<url-pattern>/demo1url-pattern>
<url-pattern>/demo2url-pattern>
filter-mapping>
<filter>
<filter-name>lifefilter-name>
<filter-class>com.filter.Demo1LifeCycleFilterfilter-class>
filter>
<filter-mapping>
<filter-name>lifefilter-name>
<url-pattern>/demo1url-pattern>
filter-mapping>
<filter-mapping>
<filter-name>lifefilter-name>
<url-pattern>/demo2url-pattern>
filter-mapping>
<filter>
<filter-name>lifefilter-name>
<filter-class>com.filter.Demo1LifeCycleFilterfilter-class>
filter>
<filter-mapping>
<filter-name>lifefilter-name>
<servlet-name>HelloServletservlet-name>
filter-mapping>
过滤器的拦截方式一共有4种,
REQUEST、FORWARD、INCLUDE、ERROR
默认是请求的方式:只有直接来源于浏览器的请求,才经过过滤器。
<jsp:forward page="/demo1">jsp:forward> 发现没有经过过滤器,但servlet还是访问了。
<filter>
<filter-name>lifefilter-name>
<filter-class>com.filter.Demo1LifeCycleFilterfilter-class>
filter>
<filter-mapping>
<filter-name>lifefilter-name>
<url-pattern>/demo1url-pattern>
<dispatcher>FORWARDdispatcher>
filter-mapping>
<filter>
<filter-name>lifefilter-name>
<filter-class>com.filter.Demo1LifeCycleFilterfilter-class>
filter>
<filter-mapping>
<filter-name>lifefilter-name>
<url-pattern>/demo1url-pattern>
<dispatcher>FORWARDdispatcher>
<dispatcher>REQUESTdispatcher>
filter-mapping>
过滤类型 | 作用 |
---|---|
REQUEST | 直接来源于浏览器的访问地址,(包含重定向) |
FORWARD | 转发的时候经过过滤器 |
INCLUDE | 页面包络另一个页面访问时也经过过滤器 |
ERROR | 页面错误时经过过滤器 |
<filter>
<filter-name>Demo2ConfigFilterfilter-name>
<filter-class>com.filter.Demo2ConfigFilterfilter-class>
<init-param>
<param-name>charsetparam-name>
<param-value>GBKparam-value>
init-param>
<init-param>
<param-name>countryparam-name>
<param-value>Chinaparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>Demo2ConfigFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
方法名 | 功能 |
---|---|
String getInitParameter(String name) | 通过初始参数名得到参数值 |
Enumeration getInitParameterNames() | 得到所有的初始参数名字,返回枚举类 |
ServletContext getServletContext() | 得到上下文对象 |
- 在过滤器初始化init方法中把上面的配置参数输出
//得到初始的配置参数
String charset = filterConfig.getInitParameter("charset");
String country = filterConfig.getInitParameter("country");
System.out.println(charset);
System.out.println(country);
//得到所有的配置参数名
Enumeration names = filterConfig.getInitParameterNames();
//遍历
while (names.hasMoreElements()) {
//得到其中的一个名字
String name = names.nextElement();
System.out.println("名字:" + name + ", 值:" + filterConfig.getInitParameter(name));
}
//过滤的编码参数,通过filterConfig得到
@Override
public void init(FilterConfig config) throws ServletException {
charset = config.getInitParameter("charset");
System.out.println(charset);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//设置汉字的编码, charset相当于utf-8
request.setCharacterEncoding(charset);
//放行
chain.doFilter(request, response);
}
过滤器配置
<filter>
<filter-name>EncodingFilterfilter-name>
<filter-class>com.filter.EncodingFilterfilter-class>
<init-param>
<param-name>charsetparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>EncodingFilterfilter-name>
<url-pattern>/loginurl-pattern>
<url-pattern>/registerurl-pattern>
filter-mapping>
一次请求可以同时经过多个过滤器,每个过滤器会将请求传递给下一个过滤器,如果下一个没有过滤器了,则传递给Web资源,这多个过滤器就组成了一个过滤器链。请求的时候经过每一个过滤器,响应的时候以相反顺序再回到每一个过滤器。
过滤器的顺序是根据配置文件中配置的顺序
Filter接口中的方法 | 参数的作用 |
---|---|
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | **ServletRequest**:代表请求对象是HttpServletRequest接口的父接口,如果要使用HttpServletRequest对象,**需要对类型进行强转**。**ServletResponse**: 代表响应对象是HttpServletResponse的父接口,如果要使用HttpServletResponse对象,**需要对类型进行强转**。**FilterChain**:代表过滤链对象用于请求的放行。 |
FilterChain接口中的方法 参数的作用
放行
doFilter(ServletRequest request, ServletResponse response) ServletRequest:代表请求对象,是HttpServletRequest接口的父接口,如果要使用HttpServletRequest对象,需要对类型进行强转。
ServletResponse: 代表响应对象,是HttpServletResponse的父接口,如果要使用HttpServletResponse对象,需要对类型进行强转。
将上一个请求传递给下一个过滤器或Web资源
第一个过滤器
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//处理请求
System.out.println("请求经过了第1个过滤器");
//放行
chain.doFilter(request, response);
//处理响应
System.out.println("响应经过了第1个过滤器");
}
第二个过滤器
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//处理请求
System.out.println("请求经过了第2个过滤器");
//放行
chain.doFilter(request, response);
//处理响应
System.out.println("响应经过了第2个过滤器");
}
*配置参数的顺序!!*
<filter>
<filter-name>OneFilterfilter-name>
<filter-class>com.filter.OneFilterfilter-class>
filter>
<filter-mapping>
<filter-name>OneFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>TwoFilterfilter-name>
<filter-class>com.filter.TwoFilterfilter-class>
filter>
<filter-mapping>
<filter-name>TwoFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
实现步骤:
1. 在WebRoot下创建页面 login.jsp上使用${msg},显示信息。
1. 创建LoginServlet, 判断用户名密码是否正确,如果正确,则在会话域中保存用户信息。登录成功跳转到list.jsp,登录失败则在域中写入登录失败的信息,并且跳转到login.jsp。
使用过滤器解决:创建LoginAuthorityFilter
创建成员变量HashSet,用于保存所有不经过过滤器的页面
在init方法中添加登录页面和登录的Servlet到HashSet中
public class LoginAuthorityFilter implements Filter {
//创建成员变量HashSet,用于保存所有不经过过滤器的页面
private HashSet paths = new HashSet();
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//得到子接口
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//得到会话域
HttpSession session = request.getSession();
//在doFilter过滤的方法中获取当前访问的路径,判断当前路径是否在集合中
String path = request.getServletPath();
System.out.println(path);
if (paths.contains(path)) {
//如果在集合中则放行并返回
chain.doFilter(request, response);
return;
}
//否则判断会话域中是否有指定的用户信息
String user = (String) session.getAttribute("user");
if (user != null) {
//如果有则放行,并返回
chain.doFilter(request, response);
return;
}
System.out.println("拦截到非法的用户:" + request.getRemoteAddr());
//最后重定向到登录页面
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
@Override
public void init(FilterConfig config) throws ServletException {
// 在init方法中添加登录页面和登录的Servlet到HashSet中
paths.add("/login.jsp");
paths.add("/login");
}
}
HttpSession session = request.getSession();
//得到用户名和密码
String name = request.getParameter("user");
String pwd = request.getParameter("pwd");
//判断是否登录成功
if ("newboy".equals(name) && "123".equals(pwd)) {
//如果登录成功,将用户的信息保存到会话域中
session.setAttribute("user", name);
//跳转到list.jsp
response.sendRedirect(request.getContextPath() + "/list.jsp");
}
//如果登录失败,写错误信息到请求域,跳转到login.jsp显示出来
else {
request.setAttribute("msg", "用户名或密码不正确");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}