目录
在实际开发过程中,我们需要对某一些访问资源进行筛选 过滤,当这个请求满足特定的情况,才能让这个请求访问目标资源,如果不满足条件,就不能访问目标资源. 例如:对于管理员的访问功能,我们应该在请求之前判断一下是否是管理员权限,如果当前用户是管理员权限的时候可以访问,反之则不可以.
Filter
Filter是java中预先定义的接口,可以根据需求过滤不同的内容,具体的过滤内容需要自己定义一个实现类,然后实现接口中的过滤方法. 当客户端浏览器发出一个请求的时候,这个请求在访问真正的目标资源之前,进行一个条件的过滤,然后在请求目标资源,这个过程就可以通过过滤器来完成.
当我们访问的某一个资源的时候,如果访问的路径存在的话,filter会进行一个放行操作,正常执行后面的servlet代码,如果此时访问的路径不存在,那么filter就不会进行放行操作,此时控制台会输出filter的内容.
案例代码:
操作步骤:
- 编写一个类,实现javax.servlet.Filter接口
- 重写filter的方法,有事注dofilter的方法
- 在web.xml中配置filter(作用)
- 告诉servlet容器我是一个filter
- 告诉filter容器访问其他资源的时候会执行过滤操作.
web.xml代码:
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>com.james.filter.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloFilter</filter-name>
<!--表示当前filter所拦截的路径设置-->
<url-pattern>/demo2</url-pattern>
</filter-mapping>
HelloFilter(Filter)代码:
public class HelloFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* filter执行过滤 主要编写代码的方法 等效 Servlet中的service方法
* 代码的逻辑 一行一行执行的
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("入门过滤器执行 A");
//不放行就相当于 当前请求就结束了 直接响应回去
//放行 进入原来的链接路径 相当 于调用方法 DemoServlet.doGet(request,response)
//filterChain.doFilter(servletRequest , servletResponse) ;//放行代码
System.out.println("入门过滤器执行 B");
}
@Override
public void destroy() {
}
}
servlet代码:
public class DemoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo被访问了");
response.getWriter().print("demo");
}
}
执行流程:
生命周期:
void init(FilterConfig config):初始化方法,在项目启动的时候就会执行,只执行一次
void doFilter(request,response,FilterChain chain):执行过滤方法,当请求匹配上的时候就会执行
void destroy():销毁,在项目被移除的时候或者服务器关闭的时候就会执行,只执行一次
Servlet:默认第一次被访问初始化 每一次执行Servlet执行service方法 服务器停止 执行destroy方法
Filter是一个单实例的线程不安全的对象(不要给成员变量)
服务器启动的时候,服务器创建filter对象,且调用filter的init方法,实现初始化操作.
当请求来的时候,若filter能匹配到此路径,服务器就会从线程池中获取一个线程,在线程中调用filter的doFilter方法,当doFilter方法执行了放行操作的时候才会到达下一个地方
当线程正常关闭的时候,服务器会调用filter的destroy的方法实现销毁操作
注意:一个路径只能有一个servlet执行,但是一个路径可以有多个filter执行,且filter中不存在路径优先级问题
解决全栈乱码:
每一个servlet的第一步操作都是处理和响应编码,而浏览器在发出一任何请求的时候,我们可以通过过滤器同一进行中文乱码的处理.
在Tomcat8.5处理了get请求的中文乱码,但是post没有进行处理,对于post请求我们之前的操作是通过request.setCharacterEncoding("utf-8");并且每一个servlet都要写一句这种代码,非常麻烦,通过过滤器我们便可以只写一次而对多个servlet有效.
代码步骤:
- 编写一个过滤器
- 配置过滤器的路径为 /*
- 编写过滤器的请求逻辑
package com.james.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "EncodingFilter" , urlPatterns = "/*")
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//全站编码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//放行
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
Listener
在我们java程序中,我们需要监事某些事情的执行,一旦被监视的对象发生相应的改变,我们需要采取相应的操作.
JavaWeb中又三大域对象:
ServletRequest HTTPSession ServletContext
今天就ServletContextLister来做一下小总结:
监听器一共有8个:
- 监听域对象的创建和销毁
- ServletRequestListener
- HttpSessionListener
- ServletContextListener
- 监听域对象对的属性操作
- ServletRequestAttributeListener
- HttpSessionAttributeListener
- ServletContextAttributeListener
- 监听特殊的JavaBean在session中的特殊处理
- HttpSessionBingdingListener
- HttpSessionActivationListener
监听器的主要概念:
事件源:发生事件的对象
事件:发生了什么事情
监听器:一个接口,需要我们自己实现.
案例代码:
统计在线人数实例步骤分析:
1. 编写一个监听器,实现HttpSessionListener
2. 在session创建后的操作
- 获取servletContext对象
- 获取在线的人数
- 若人数为null,则设置人数为1
- 若人数不为null,设置人数+1\
3. 在session销毁后的操作
- 获取servletContext对象
- 获取在线人数
- 将人数--,放入servletContext域中
4 . 创建一个servlet进行测试.
listener
package com.james.web.listener;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 登录成功 或者 退出登录 其实操作的是 session的创建和销毁
* 监听session的创建和销毁即可
*/
@WebListener
public class MyHttpSessionListener implements HttpSessionListener {
/**
* 数量+1
* httpSessionEvent 事件对象
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
HttpSession session = httpSessionEvent.getSession();
System.out.println(session.getId()+",第一次被创建,放入servletContext中");
//获得全局的域对象
ServletContext sc = session.getServletContext();
//先获得原来的登录数量
Integer count = (Integer)sc.getAttribute("count");
//以前一定登录过
if(count != null && count !=0 ){ // 先判断非空 再判断值
count++;
}else{
count=1; //以前没有登录过
}
sc.setAttribute("count" , count);
}
/**
* 数量-1
*/
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
//获得session
HttpSession session = httpSessionEvent.getSession();
System.out.println(session.getId() +" : 即将销毁 , 退出登录");
//获得servletContext
ServletContext servletContext = session.getServletContext();
Integer count = (Integer)servletContext.getAttribute("count");
//表示当前一定有人正在登录状态
if(count != null && count >0 ){
count -- ;
}else{
count= 0 ;
}
servletContext.setAttribute("count" , count);
}
}
login
package com.james.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "LoginServlet" , urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("登陆成功:" +request.getSession().getId());
}
}
logout
package com.james.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "LoginOutServlet" , urlPatterns = "/loginOut")
public class LoginOutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("退出了session:" + request.getSession().getId());
//销毁session
request.getSession().invalidate();
}
}
showCount:
package com.james.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "ShowLogin" , urlPatterns = "/showLogin")
public class ShowLogin extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("当前人数为:" + getServletContext().getAttribute("count"));
}
}
页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/login">点我登录服务器-不需要做登录案例</a><br/>
<a href="${pageContext.request.contextPath}/loginOut">点我退出登录</a><br/>
<a href="${pageContext.request.contextPath}/showLogin">点我查看登录成功服务器人数</a>
当前登录人数为: ${count}<br/>
<%--jsp的底层有九大内置对象 默认自己调用request.getSession();--%>
</body>
</html>
通过session的创建(request.getsession())销毁(request.getSession().invalidate();)来调用监视器中的方法从而实现session个数的改变.最终能够在页面上进行显示.