1. 能够说出过滤器的生命周期
2. 能够写出过滤器的映射路径
3. 能够说出过滤器的四种过滤类型
4. 能够利用FilterConfig获取过滤器的配置参数
5. 能够说出什么是过滤器链
6. 能够说出过滤器链的执行顺序
Java Web的三大组件( 1)都需要交给web服务器运行 2)在web.xml文件中配置 )
1. Servlet: javax.servlet.Servlet 通过HTTP协议接收客户端的请求,并且做出响应的一个Java应用程序。
2. Filter过滤器:javax.servlet.Filter 是一个接口,过滤请求,实现请求的拦截或者放行,并且添加新的功能。
3. Listener 监听器: javax.servlet.XxxListener,用来监听Web容器中各种域的事件
1、场景1: 用户表单提交参数,使用POST方法提交,编写Servlet,接收参数: request.getParameter() /getParameterValues() 如果在客户端提交汉字而不做任何处理,就出现中文乱码的问题。
解决编码问题: request.setCharacterEncoding("utf-8");
Ø 问题:如果在项目中的每一个Servlet都加上request.setCharacterEncoding("utf-8");
代码重复,而且后期维护也不方便。能不能把这部分公共代码抽取处理,放在一个地方执行?
2、场景2: 登录 -> 输入信息 -> 登录成功 -> 看到用户主页(欢迎xxx回来。。。)
用于验证用户是否登录成功代码:
HttpSession session = request.getSession()
Object obj = session.getAttribute("loginInfo");
if(obj==null){
//没有登录标记,代表没有登录
}else{
///已经登录了,继续访问此功能
}
如果用户不登录,直接访问用户主页,跳转到登录页面
在其他需要登录才能访问的页面中,同样也需要加上验证用户是否登录成功代码。
Ø 问题: 能不能把这部分公共验证用户是否登录成功代码抽取处理,在一个地方执行?
3. 结论:
以上两种场景出现的问题,可以使用过滤器(Filter)解决!
1. 作用:
通过Filter技术,对Web服务器管理的所有Web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,并且添加功能,从而实现一些“共同”的功能。
2. 例如:
1) 实现URL级别的权限访问控制
2) 过滤敏感词汇
3) 自动登录
4) 压缩响应信息等一些功能。
特点:过滤器不是用户主动调用的,而是根据规则自己执行
1. 编写一个java类,实现Filter接口,并实现其中的所有方法
2. 在web.xml文件中配置Filter
3. 把Filter部署到tomcat服务器运行
4. 示例:
创建一个过滤器HelloFilter,在运行HelloServlet前和后分别输出一句话,在HelloServlet中也输出一句话,观察控制台的运行效果。
1) 过滤器类:
public class HelloFilter implements Filter { ... @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("1.请求的时候运行一次过滤器"); chain.doFilter(request, response); System.out.println("3.响应的时候运行一次过滤器"); } ... }
|
2) web.xml中的配置
|
3) HelloServlet类:
public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("2.执行了目标资源:HelloServlet被执行"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
4) 运行结果:
1.请求的时候运行一次过滤器
2.运行了Web资源
3.响应的时候运行一次过滤器
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个Web资源进行拦截后,Web服务器每次在调用Web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
1) 调用目标资源之前,执行一段代码,request执行过滤任务。
2) 是否调用目标资源(即是否让用户访问Web资源)。
Web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则Web服务器就会调用Web资源的service方法,即Web资源就会被访问,否则Web资源不会被访问。
3) 调用目标资源之后,执行一段代码,response执行过滤任务。
1. 过滤器加载的时机:
过滤器在Web服务器启动的时候就加载了,因为要拦截Web资源,所以必须在所有Web资源启动之前就加载过滤器。
2. 生命周期的方法:
1). init方法:
在创建完过滤器对象之后被调用。只执行一次
注:过滤器在Web服务器中也是单例模式
2). doFilter方法:
执行过滤任务方法。执行多次。
3). destroy方法:
Web服务器停止或者Web应用重新加载,销毁过滤器对象。
3. 示例:生命周期的过程
/** * 第一个过滤器程序 * @author NewBoy */ public class HelloFilter implements Filter{ /** * 1)构造方法 */ public HelloFilter(){ System.out.println("1)Filter生命周期-构造方法"); }
/** * 2)init初始化方法 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("2)Filter生命周期-init方法"); } /** * 3)过滤器执行过滤任务的方法 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("1.request->执行过滤任务"); /** * 放行 */ chain.doFilter(request, response); System.out.println("3.response->执行完过滤任务"); } /** * 4)销毁方法 */ public void destroy() { System.out.println("4)Filter生命周期-destory方法"); } }
|
1. Filter与Servlet中
1) Servlet中的url-pattern: 访问地址
2) 过滤器中的url-pattern: 过滤的地址
注:浏览器访问目标资源的路径,就算是目标地址不存在,过滤器依然会正常运行。
2. url-pattern过滤匹配:
问:在Servlet中URL地址有哪些写法?
Ø /* 匹配所有的地址
Ø *.后缀名 如:*.action
1) 精确过滤
/index.jsp
2) 模糊过滤
/* 过滤所有的资源,包含jsp,servlet,图片
*.jpg 过滤所有的图片
/manager/* 过滤某个文件夹下所有的资源
3. 有关匹配的要点:
1) url-pattern要么以斜杠开头,要么以*.扩展名结尾 例如: /* 或*.do
2) 不能同时出现这两种方式。例如 /*.do 是非法的
3) 如果存在多个需要被过滤的资源,可以在一个filter-mapping中写多个url-pattern去匹配。或者一个filter对应多个filter-mapping
如:
或:
|
4) 如果是动态资源servlet,可以使用servlet的访问URL,也可以使用Servlet名称
如:
1. 什么是过滤类型:声明哪种类型的请求才可以被拦截(过滤)
在Servlet2.4中一共有4种过滤类型:
REQUEST、FORWARD、INCLUDE、ERROR
2. 默认:当过滤器的访问地址精确匹配时,默认来自于直接访问的请求才可以被拦截
这个配置与不配置是一样的效果。
3. 来自于转发的请求才可以被拦截
1). 在index.jsp转发到HelloServlet
2). 过滤器的配置
4. 来自于包含的请求才可以被拦截
1). 页面上使用包含动作,包含HelloServlet
2). 过滤器的配置
5. 来自于错误的请求才可以被拦截
1). 在index.jsp中产生一个异常,如:100/0
<% int num = 100 / 0; %>
2). 在web.xml中配置,错误页面为/HelloServlet
3). 过滤器的配置
6. 以上的过滤类型可以同时写多个
类似于ServletConfig:得到Servlet中的一些配置信息
如:得到一个参数名为name的配置参数:
getInitParameter("name")
1. 什么是FilterConfig对象:
过滤器配置对象,用于加载过滤器的参数配置
2. 在web.xml文件中配置
|
3. 在过滤器器中使用
public void init(FilterConfig filterConfig) throws ServletException { System.out.println("2)Filter生命周期-init方法"); /** * 通过FilterConfig对象得到参数配置信息 */ //得到一个参数 System.out.println(filterConfig.getInitParameter("AAA"));
Enumeration //遍历所有参数 while(enums.hasMoreElements()){ String paramName = enums.nextElement(); String paramValue = filterConfig.getInitParameter(paramName); System.out.println(paramName+"="+paramValue); } } |
编写过滤器,过滤所有Servlet中使用POST方法提交的汉字的编码。
1. 需求:
1) 有2个Servlet,一个是LoginServlet登录,一个是RegisterServlet注册
2) 有2个JSP页面,1个是login.jsp,有表单,登录名。1个register.jsp,有表单,登录名。都使用POST提交 用户名使用汉字提交
3) 使用过滤器,对所有的Servlet的POST方法进行过滤。
4) 过滤的编码参数,通过filterConfig得到
2. login.jsp
用户登录
|
3. LoginServlet
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.print("登录成功,欢迎您:" + request.getParameter("name")); out.close(); }
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
} |
4. register.jsp
用户注册
|
5. RegisterServlet.java
public class RegisterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.print(request.getParameter("user") + ",注册成功!"); out.close(); }
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
6. 过滤器
/** * 编码过滤器 * @author NewBoy */ public class EncodeFilter implements Filter {
@Override public void destroy() { }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //设置编码 request.setCharacterEncoding(charset); //放行 chain.doFilter(request, response); }
String charset = null; //定义成员变量
//得到编码的参数 @Override public void init(FilterConfig filterConfig) throws ServletException { charset = filterConfig.getInitParameter("charset"); }
}
|
7. web.xml
< url-pattern>/register
|
在一个Web程序中,如果存在多个过滤器过滤同一个Web资源,这些过滤器按前后顺序就组成了一个过滤器链。
1. Filter接口中的方法:
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
1) 参数一: 请求对象ServletRequest父接口,使用的时候,传入的是HttpServletRequest
2) 参数二: 响应对象,使用的时候,传入的是HttpServletResponse对象
3) 参数三: 过滤器链对象,把请求传递给下一个过滤器
2. FilterChain接口中的方法:
doFilter(ServletRequest request, ServletResponse response):
如果在过滤器中调用这个方法,则会把请求放行。把请求传递给下一个过滤器。
3. 示例:创建两个过滤器,每个过滤器的请求和响应各输出一句话,观察过滤器的执行过程。
/** * 第一个过滤器 */ public class FirstFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { } /** * 执行过滤任务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("1.执行FirstFilter的过滤任务"); /** * 放行,执行下一个过滤器 */ chain.doFilter(request, response); System.out.println("5.执行完毕FirstFilter"); } }
/** * 第二个过滤器 */ public class SecondFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { } /** * 执行过滤任务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("2.执行SecondFilter的过滤任务"); /** * 放行。执行下一个过滤器。没有下一个过滤器,则执行目标资源 */ chain.doFilter(request, response); System.out.println("4.执行完毕SecondFilter"); } }
/** Web资源:Servlet */ public class SecondServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("3.执行SecondServlet目标资源"); response.setContentType("text/html;charset=utf-8"); response.getWriter().print("6.输出内容到浏览器"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
● 疑问:多个过滤器是按什么样的顺序执行的?
按在web.xml中filter和filter-mapping配置的先后顺序来决定,哪个配置在前面,先运行哪个
/** * 第一个过滤器 */ public class FirstFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { } /** * 执行过滤任务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("1.执行FirstFilter的过滤任务"); /** * 放行,执行下一个过滤器 */ chain.doFilter(request, response); System.out.println("5.执行完毕FirstFilter"); } }
/** * 第二个过滤器 */ public class SecondFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { } /** * 执行过滤任务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("2.执行SecondFilter的过滤任务"); /** * 放行。执行下一个过滤器。没有下一个过滤器,则执行目标资源 */ chain.doFilter(request, response); System.out.println("4.执行完毕SecondFilter"); } }
/** Web资源:Servlet */ public class SecondServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("3.执行SecondServlet目标资源"); response.setContentType("text/html;charset=utf-8"); response.getWriter().print("6.输出内容到浏览器"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
1. 概念:
Decorator Pattern。装饰者模式是在不改变原类文件,使用继承的情况下,动态地扩展一个类的功能。
它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
2. 装饰者模式的使用场景:
在开发过程中,如果发现某个类的某个(某些)方法不满足需求(不够用),那么可以使用装饰者模式对该类进行装饰,
增强这个类的方法。
装饰者模式的作用:专门对类的方法进行增强!
3. 装饰者模式中的各个角色:
1) 抽象角色:给出一个抽象接口,以规范准备接收附加功能的对象(即具体角色)。
Star HttpServletRequest
2) 具体角色:定义一个将要接收附加功能的类。
BabyStrong HttpServletRequestWrapper
3) 装饰角色:持有一个具体角色的实例,继承于抽象角色或具体角色,给具体角色添加附加功能的类。
Decorator1, Decorator2 MyRequestWrapper
4. 开发步骤:
1)编写一个装饰类,需要继承被装饰类 (被装饰类不能是final)
2)在装饰类中声明一个被装饰类型的成员变量
3)在装饰类的构造方法中,接收传入的被装饰类实例
4)在装饰类中重写需要增强的方法
5 示例:
1) 明星有唱歌的行为,这是抽象角色
2) 春哥是实现类,实现了唱歌的行为,这是具体角色
3) 装饰类继承于春哥类,并且持有了Star的成员对象,Star对象通过构造方法传入SpringBrother。
4) 对现有的唱歌行为进行装饰,增加新的功能。
5) 多个装饰角色可以以不同的顺序调用,产生的装饰效果不同。
/** * 抽象角色:明星的行为 */ public interface Star { /** * 唱歌的行为 */ void song(); }
/** *具体角色: 春哥,有唱歌的行为 */ public class SpringBrother implements Star { @Override public void song() { System.out.println("春哥:想唱就唱,要唱得漂亮"); } }
/** * 装饰角色1 * @author NewBoy */ public class StarDecorator1 extends SpringBrother { //持有一个具体对象的实例,注意这里是Star接口,不是SpringBrother类 Star sb; public StarDecorator1(Star sb) { this.sb = sb; } @Override public void song() { //对现有的功能增强 System.out.println("乐队准备,音乐响起~~"); sb.song(); } }
/** * 装饰角色2 * @author NewBoy */ public class StarDecorator2 extends SpringBrother { //持有一个具体对象的实例 Star sb; public StarDecorator2(Star sb) { this.sb = sb; } @Override public void song() { System.out.println("隆重出场,主持人报幕!"); sb.song(); } }
//操作类 public class Test { public static void main(String[] args) { //没有装饰的情况 SpringBrother s1 = new SpringBrother(); s1.song(); System.out.println("============="); //装饰1 Star d1 = new StarDecorator1(s1); d1.song(); System.out.println("============="); //在装饰1的基础上再装饰2 Star d2 = new StarDecorator2(d1); d2.song(); } }
|
1) 装饰者模式:关注于在一个对象上对方法的增强,并且可以多个装饰器组合使用,一般使用继承的方式实现。
2) 代理模式:关注于对对象的访问控制,对被代理的对象进行控制、改写其原有的功能。
在RegisterServlet中解决乱码的问题。要求既要能解决POST方法,又要能解决GET方法。
public class RegisterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); // 解决POST方法 request.setCharacterEncoding("utf-8"); //得到用户名参数 String name = request.getParameter("name"); //解决GET方法,注意tomcat8.0,默认是utf-8,无需这样解码 if ("GET".equals(request.getMethod())) { name = new String(name.getBytes("iso-8859-1"),"utf-8"); } out.print(request.getMethod() + ",用户名是:" + name); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
1. 分析思路:
1) POST方法很容易实现,GET方法因为需要得到每一项的参数进行编码,而且一开始并不知道有哪些参数。
2) 在过滤器中使用装饰者模式的方式来实现
3) 要继承的代理类是哪一个呢?查API文档可知,HttpServletRequest接口的实现类是HttpServletRequestWrapper
4) 重写request.getParameter()方法,对这个方法进行装饰,在方法中实现编码的功能。
5) 在Servlet中只需调用request.getParameter()即可。
2. 实现步骤:
1) 写一个类MyRequestWrapper继承于HttpServletRequestWrapper
2) 在类中声明一个成员变量HttpServletRequest
3) 通过构造方法转入HttpServletRequest的对象
4) 重写request.getParameter()方法,对汉字进行编码。
①. 调用原来request.getParameter() 得到未编码前的值
②. 判断如果是GET方法,而且值不为null,则进行编码
③. 返回增强以后的内容
5) 在过滤器中首先给POST方法编码
6) 创建装饰类对象
7) 在过滤器链中放行,注意:这里的过滤器放行的是装饰类的对象,而不应该是原来的request对象。
8) 在后面的Servlet中都不需要再写关于编码的代码,只需接收即可。
因为doGet方法中注入的HttpServletRequest的实现类是自己的装饰类。
3. 代码:
● HttpServlet的装饰类:
//1.继承于HttpServletRequestWrapper class MyRequestWrapper extends HttpServletRequestWrapper {
//2.在类中声明一个成员变量HttpServletRequest private HttpServletRequest request; //3.通过构造方法转入HttpServletRequest的对象 public MyRequestWraper(HttpServletRequest request) { super(request); this.request = request; }
//4.重写request.getParameter()方法,对汉字进行编码。 @Override public String getParameter(String name) { //①. 得到参数值 String value = request.getParameter(name); //②. 判断如果是GET方法,则进行编码 if ("GET".equals(request.getMethod()) && value!=null) { try { value = new String(value.getBytes("iso-8859-1"),"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } //③. 返回增强以后的内容 return value; } }
|
● 汉字编码的过滤器类
public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //给POST进行编码 request.setCharacterEncoding("utf-8"); //给GET编码,先创建装饰者类 MyRequestWraper req = new MyRequestWraper((HttpServletRequest) request); //在过滤器链中放行,注意:这里的过滤器放行的是装饰类的对象,而不应该是原来的request对象。 chain.doFilter(req, response); } @Override public void destroy() { } }
|
● 过滤器的配置
|
● 注册的Servlet类
public class RegisterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); //在后面的Servlet中都不需要再写关于编码的代码,只需接收即可。 String name = request.getParameter("name"); out.append(request.getMethod() + ",用户名是:" + name); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
使用装饰者模式重写String[] request.getParameterValues()方法,实现过滤多个值的参数。
1. 需求:
1) 注册表单上有一个复选框,爱好这一栏。爱好:游泳、旅游、上网、下棋。
复选框的名字叫hobby
2) 使用装饰者模式重写request.getParameterValues()方法,解决汉字乱码的问题
2. 步骤:
1) 修改上面的装饰类,重写方法:request.getParameterValues()
2) 调用原有request.getParameterValues()的方法,得到字符串数组
3) 判断是否是GET方法,而且value不为空。则使用循环,将数组中的每一个参数进行编码。
3) 在Servlet中得到爱好的值,并输出。
3. 代码:
● 装饰类中重写新的方法
@Override public String[] getParameterValues(String name) { //1.调用原来的request的同名方法,得到值 String [] values = request.getParameterValues(name); //2. 判断数组是否为空,而且是GET方法 if (values!=null && "GET".equals(request.getMethod())) { for (int i = 0; i < values.length; i++) { //3.对每个值进行编码 try { values[i] = new String(values[i].getBytes("iso-8859-1"),"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } return values; } |
● 注册Servlet类的代码:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); //在后面的Servlet中都不需要再写关于编码的代码,只需接收即可。 String name = request.getParameter("name"); //得到爱好 String[] hobbies = request.getParameterValues("hobby"); out.print(request.getMethod() + ",用户名是:" + name + " out.print("您的爱好是:" + Arrays.toString(hobbies)); out.close(); } |
add.jsp 添加数据,需要登录才可访问
update.jsp 修改数据,需要登录才可访问
list.jsp 查询数据,不用登录
login.jsp 登录页面
使用过滤器进行权限的控制,实现正确的访问。
1. 在WebRoot下创建4个页面
login.jsp上使用${msg},显示信息。
2. 创建LoginServlet
判断用户名密码是否正确,如果正确,则在会话中保存用户信息。登录成功跳转到list.jsp,登录失败则在域中写入登录失败的信息,并且跳转到login.jsp。
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //汉字的编码 request.setCharacterEncoding("utf-8"); String name = request.getParameter("name"); String password = request.getParameter("password"); if ("admin".equals(name) && "123".equals(password)) { //如果登录成功,则把用户信息放入会话中 request.getSession().setAttribute("name", name); //转到查询页面 response.sendRedirect(request.getContextPath() + "/list.jsp"); } else { request.setAttribute("msg", "登录失败"); //转到登录页面 request.getRequestDispatcher("/login.jsp").forward(request, response); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
现在的状态是:所有的页面都可以直接访问,无论有没有登录。
按之前的做法是在每个页面判断会话中是否有用户信息,这种做法太繁琐。
3. 使用过滤器解决:创建LoginAuthorityFilter
1) 得到HttpServletRequest、HttpSession对象
2) 如果会话中没有用户信息,则转到登录页面,并return。
3) 否则继续访问后续的Web资源
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //得到request,session对象 HttpServletRequest req = (HttpServletRequest) request; HttpSession session = req.getSession(); //判断会话中是否有已经登录的用户信息 String name = (String) session.getAttribute("name"); if (name==null) { //表示会话中没有登录信息 req.setAttribute("msg", "你没有登录,无权访问此页面"); request.getRequestDispatcher("/login.jsp").forward(req, resp); //加上return,让后面的代码不再运行 return; } //如果已经登录了,则可以正常访问 chain.doFilter(req, resp);}
|
4. 配置web.xml中的过滤器
● 问:url-pattern怎么写?
1) 方式一:写多个add.jsp
如果页面太多,写起来很繁琐
2) 方式二:写*.jsp
会把login.jsp和list.jsp也过滤掉,导致死循环
这些方式都存在一定的问题
● 解决方案:
一般按不同的用户权限创建不同的文件夹,则把需要过滤的页面放在指定的文件夹下。
这里把add.jsp和modify.jsp放入manager文件夹下。
写成:
● 注意:不要把LoginServlet的访问路径也加入过滤器了,不然会导致永远都登录不成功。
需求:改造联系人管理的项目,一个模块中所有的功能使用一个Servlet来实现。即一个Servlet实现增删改查的功能。
1. 每个功能使用一个Servlet来实现,一个功能模块,增删改查就会出现4个Servlet,随着项目的开发,功能模块越来越多。项目中的Servlet也会越来越多,项目越大Servlet的数量就会越大,对项目的管理和维护不利。
2. 每个Servlet在运行的时候,都会加载进内存,而且是常驻内存,一直到服务器关闭都不会释放。所以少创建一个Servlet,系统占用内存会更少。
1. 创建一个Servlet,名为ContactServlet,这个Servlet的访问地址是:/contact
2. 核心:给每种访问操作添加一个参数,用来区分不同的操作。
添加联系人,则使用:/contact?action=addContact做为参数
更新联系人,则使用:/contact?action=updateContact做为参数
查询联系人,则使用:/contact?action=listContact做为参数
删除联系人,则使用:/contact?action=deleteContact做为参数
查询指定联系人,则使用:/contact?action=queryContact做为参数
3. 在ContactServlet中写五个方法:
五个方法都直接从原来相应的servlet中复制过来即可
如addContact从AddContactServlet的doGet方法中复制过来。并且把doGet方法改名为addContact(),
其它不变。
/*
* 添加联系人
*/
public void addContact(HttpServletRequest request, HttpServletResponse response)
/*
* 显示所有的联系人
*/
public void listContact(HttpServletRequest request, HttpServletResponse response)
/*
* 更新联系人
*/
public void updateContact(HttpServletRequest request, HttpServletResponse response)
/*
* 删除联系人
*/
public void deleteContact(HttpServletRequest request, HttpServletResponse response)
/*
* 查询指定的联系人
*/
public void queryContact(HttpServletRequest request, HttpServletResponse response)
4. 在ContactServlet中接收action的值,通过接收不同的值来调用不同的方法
● 注意:编码要放在所有汉字得到之前
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //注意:编码要放在所有汉字得到之前 request.setCharacterEncoding("utf-8"); //1.得到用户提交的action参数 String action = request.getParameter("action"); //2.通过不同的参数调用不同的方法 if ("listContact".equals(action)) { listContact(request, response); //查询所有联系人 } else if ("addContact".equals(action)) { addContact(request, response); //添加联系人 } else if ("updateContact".equals(action)) { updateContact(request, response); //修改所有联系人 } else if ("queryContact".equals(action)) { queryContact(request, response); //查询一个所有联系人 } else if ("deleteContact".equals(action)) { deleteContact(request, response); //删除指定联系人 } }
|
5. 在web.xml中配置的变化:
1) 删除其它的Servlet的配置,只保留ContactServlet的配置
2) 注意:欢迎文件列表这样写不起作用
可以创建一个index.jsp,在index.jsp上进行页面的转发。
6. JSP上所有相应的访问地址都要修改
1) 添加add.jsp的表单