目录
Java Web三大组件:Servlet 、过滤器Filter和监听器Listener
过滤器
过滤器的作用:向被访问的资源加一层外壳:
1.请求到达资源前的“请求的预处理器”;
2.响应离开资源后的“响应的后处理器”
注意:响应处理的过滤器更像是一种加工机器,真正的响应由Servlet产生
Web服务器资源共有5种访问方式,分别是:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST
Filter是在资源外面加一层外壳,应该提前准备资源,由于:不存在的资源也是一个资源,所以先从请求访问一个不存在的资源,快速上手Filter
小露身手:创建过滤器ABCFilter
创建Web项目fal
在Java Resource的src处右键创建Filter
package填filter
class name 填ABCFilter
注意:请留意一下ABCFilter的Filter Mapping,保持默认值
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
//@WebFilter("/ABCFilter")
@WebFilter(filterName = "ABCFilter",urlPatterns = {"/ABCFilter","*.do","/test/*"})
public class ABCFilter implements Filter {
public ABCFilter() {
System.out.println("执行ABCFilter的构造方法");
}
public void destroy() {
System.out.println("执行ABCFilter的destroy方法");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("执行ABCFilter的doFilter之前的代码");
chain.doFilter(request, response);
System.out.println("执行ABCFilter的doFilter之后的代码");
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("执行ABCFilter的init()方法");
}
}
需要注意的是:如果删除了chain那语句,那么符合filter的网址都会空白
chain的语句时将该 经过 该过滤器的request和response响应对象传至目的资源,此时浏览器显示空白页面(Content-Lenght=0)
Web服务器根据请求类型和请求的URL是否与urlPartterns匹配,判断是否触发过过滤器的doFilter()方法
过滤器的主要用途顾名思义,原本多个Servlet程序相近的代码(敏感词等)现在都可以集中在Filter里面进行
小露身手:过滤器链的使用
复制ABCFilter,另一份取名为BCDFilter
创建web.xml:右键项目名,找到javaEE tool然后点击Genertate Deployment Descriptor Stub
@WebFilter的注解复制粘贴的时候多注意修改下
结论:某个请求URL匹配了多个Filter按照<filter-mapping>在web.xml配置文件中出现的先后顺序,过滤器按照“从外到内的顺序”组装成一条过滤器链,
通过注解@WebFilter不能配置过滤器链的先后顺序,web.xml配置文件没有<filter-mapping>的话,则会按照过滤器类名在ASCII表出现的先后顺序配置!(名字的限制)
过滤器综合应用1:URL级别的权限访问控制
权限访问控制是资源安全保护的一种重要手段
中心思想:划分角色,不同的角色访问不同的资源,为受保护的资源文件分配url路径
如果受保护资源是JSP程序,同一种角色的受保护JSP程序,放在一个文件夹下,例如任何浏览器用户都可以登陆访问login.jsp
如果是Servlet程序,urlPattern相同或者兼容
小露身手:使用过滤器实现URL级别的权限访问控制
步骤:WebContent下创建admin文件夹,该文件夹创建admin.jsp,输入如下代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>这是管理员隐私界面</h3>
同理user
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h3>这是注册用户隐私界面</h3>
WebContent目录下创建登录表单程序login.jsp并输入下列代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String contextPath = request.getContextPath();
if(session.getAttribute("msg")!=null){
String msg = (String)session.getAttribute("msg");
out.println(msg + "<br/>");
session.removeAttribute("msg");
}
%>
<form action="<%=contextPath%>/LoginServlet" method="post">
用户名:<input type="text" name="userName" /><br/>
密码<input type="password" name="password" /><br/>
<input type="submit" value="登录" />
</form>
然后是经典的创建controller然后LoginServlet
代码如下
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
//处理登录表单提交的用户数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
response.setContentType("Text/html;charset=UTF-8");
if("admin".equals(userName) && "admin".equals(password)) {
request.getSession().setAttribute("role", "admin");
response.getWriter().append("admin登录成功");
}else if("user".equals(userName) && "user".equals(password)) {
request.getSession().setAttribute("role", "user");
response.getWriter().append("user登录成功");
}else {
request.getSession().setAttribute("role", null);
response.getWriter().append("登录失败");
}
}
}
Filter包添加如下代码,文件名自己看得到
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter(urlPatterns= {"/user/*","/admin/*"})
public class PermissionFilter implements Filter {
public PermissionFilter() {
// TODO Auto-generated constructor stub
}
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
//request应该是主要获取数据,response内装入返回的数据
HttpSession session = httpServletRequest.getSession();
Object o = session.getAttribute("role");
String contextPath = httpServletRequest.getContextPath();
if(o == null) {
session.setAttribute("msg", "受资源保护,请先登录");
httpServletResponse.sendRedirect(contextPath+"/login.jsp");
return;
}
String role = (String)o;
String requestURI = httpServletRequest.getRequestURI();
if(requestURI.contains("/admin") && !"admin".equals(role)){
session.setAttribute("msg", "admin的受保护资源,请先登录!");
httpServletResponse.sendRedirect(contextPath+"/login.jsp");
return;
}
if(requestURI.contains("/user") && !"user".equals(role)){
session.setAttribute("msg", "user的受保护资源,请先登录!");
httpServletResponse.sendRedirect(contextPath+"/login.jsp");
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
过滤器的综合应用2:过滤器进行表单验证
B/S架构方法,表单验证分两个级别:JavaScript级别的表单验证,Web应用程序级别的表单验证。其中JavaScript级别的表单验证属于第一道防线,Web应用程序属于第二道防线
默认情况下浏览器的JavaScript功能是开启的,但用户可以手动关闭,所以JavaScript功能被禁用,表单验证将会失效
通常情况下,为了实现Web应用级别的表单验证,表单验证代码需要编写在Servlet程序中。结果就是导致,Servlet既要包含业务逻辑代码,又要包含表单验证代码,不利于代码日常维护的工作。
因此,过滤器作用诞生了
小露身手:使用过滤器进行表单验证
filter包中创建登录表单验证过滤器 LoginValidatorFilter.java
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter("/LoginServlet")
public class LoginValidatorFilter implements Filter {
public LoginValidatorFilter() {
// TODO Auto-generated constructor stub
}
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
HttpSession session = req.getSession();
String userName = req.getParameter("userName");
String password = req.getParameter("password");
String msg="";
if(userName != null) {
if(userName.trim().length() > 20 || userName.trim().length() < 4 ) {
msg = msg+"用户名长度4~20位<br/>";
}
}
if(password != null) {
if(password.trim().length() > 20 || password.trim().length() < 4 ) {
msg = msg+"密码长度4~20位<br/>";
}
}
if("".equals(msg)) {
chain.doFilter(req, res);
}
else {
session.setAttribute("msg", msg);
res.sendRedirect(req.getHeader("referer"));
//技巧,上行代码用于获取本次HTTP请求来自哪个URL。代码res.sendRedirect(req.getHeader("referer"))将请求按原路径返回
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
监听器
javaWeb监听器比较多,自行查找,由于写者学过相关监听器知识,所以文字内容较少
监听器分为状态监听器和属性监听器
小露身手:演示 Java Web状态监听器和属性监听器
Java resource的src,右键创建listener 包,class name填写ABCListener
选择监听器的话,除了session migration、object binding 和 async events
package listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class ABCListener implements ServletContextListener, ServletContextAttributeListener, HttpSessionListener, HttpSessionAttributeListener, HttpSessionIdListener, ServletRequestListener, ServletRequestAttributeListener {
public ABCListener() {
System.out.println("构造方法");
}
public void sessionCreated(HttpSessionEvent se) {
System.out.println(se.getSession().getId()+"的Session被创建");
}
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext的属性" + scae.getName() + "被解除绑定");
}
public void sessionIdChanged(HttpSessionEvent arg0, String arg1) {
System.out.println(arg0.getSession().getId()+"的SessionID被修改成" + arg1);
}
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("向request请求对象绑定名是" + srae.getName() + ",值是" + srae.getValue() + "的属性");
}
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("Session属性" + se.getName() + "的值被改变 ,原来的值是:" + se.getValue());
}
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext 全局对象被Web服务器初始化了");
}
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("向ServletContext对象绑定名是,"+scae.getName()+",值是"+scae.getValue());
}
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("来自" + sre.getServletRequest().getRemoteAddr() + "的request请求对象被删除了");
}
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("request请求对象的" + srae.getName() + "属性被解除绑定了");
}
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("来自" + sre.getServletRequest().getRemoteAddr() + "的request请求对象被创建了");
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println(se.getSession().getId()+"的Session被删除");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext 全局对象被Web服务器销毁了");
}
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("request 的属性"+srae.getName()+"的值改变了,原来的值是:"+srae.getValue());
}
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("向Session绑定了属性名是" + se.getName() + "的属性");
}
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("session的属性 " + se.getName() + "被解绑了");
}
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext 的属性"+scae.getName()+"的值改变了,原来的值是:"+scae.getValue());
}
}
package controller;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
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 javax.servlet.http.HttpSession;
@WebServlet("/TestServlet")
public class ABCListenerServlet extends HttpServlet {
public ABCListenerServlet() {
System.out.println("执行TestServlet的构造方法!");
}
public void init(ServletConfig config) throws ServletException {
System.out.println("执行TestServlet的init方法!");
}
public void destroy() {
System.out.println("执行TestServlet的destroy方法!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc= request.getServletContext();
sc.setAttribute("scName", "scValue1");//绑定属性
sc.setAttribute("scName", "scValue2");//修改属性
sc.removeAttribute("scName");//删除属性
request.setAttribute("requestName", "requestValue1");
request.setAttribute("requestName", "requestValue2");
request.removeAttribute("requestName");
HttpSession session = request.getSession();
session.setMaxInactiveInterval(5);//要使当前会话时间维持5秒
session.setAttribute("sessionName", "sessionValue1");
session.setAttribute("sessionName", "sessionValue2");
session.removeAttribute("sessionName");
request.changeSessionId();
session.invalidate();
}
}
注意:一定要在Servers里面 关闭!
结论:简而言之,Web服务器的内存对象,按照产生时间的顺序排序,监听器对象>ServletContext对象>request请求对象>Servlet对象(“>”表示早于)
小露身手:利用HttpSessionListener统计在线人数
在listener包下创建OnlineListener
Next按钮后选择HttpSessionListener
Finish按钮,将生产的HttpSessionListener.java修改成如下代码
package listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class OnlineListener implements HttpSessionListener {
public OnlineListener() {
}
public void sessionCreated(HttpSessionEvent se) {
Object o = se.getSession().getServletContext().getAttribute("OnLineNum");
if(o==null) {
se.getSession().getServletContext().setAttribute("onLineNum", 1);
}else {
int onLineNum = (int)o;
se.getSession().getServletContext().setAttribute("onLineNum", onLineNum+1);
}
}
public void sessionDestroyed(HttpSessionEvent se) {
//将在线人数存入ServletConText全局变量中
int onLineNum = (int)se.getSession().getServletContext().getAttribute("onLineNum");
se.getSession().getServletContext().setAttribute("onLineNum", onLineNum-1);
}
}
创建index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
在线人数是:<%=request.getSession().getServletContext().getAttribute("onLineNum") %>