一.本次笔记小目标
重点了解过滤器的实现
了解过滤器链
了解监听器的配置
掌握 Servlet3.0 常用注解的使用
二.过滤器
1.前期介绍
Filter 即为过滤,用于在 Servlet 之外对 Request 或者 Response 进行修改。它主要用于对用户请求进行预处理,也可以对 HttpServletResponse 进行后处理。使用 Filter 的完整流程: Filter 对用户请求进行预处理,接着将请求交给 Servlet进行处理并生成响应,最后 Filter 再 对服务器响应进行后处理。在一个 web 应用中,可以开发编写多个 Filter,这些 Filter 组合 起来称之为一个 Filter 链。
单个过滤器
过滤器链
若是一个过滤器链:先配置先执行(请求时的执行顺序);响应时: 以相反的顺序执行。
2. 实现
我们可以通过实现一个叫做 javax.servlet.Fileter 的接口来实现一个过滤器,其中定义了 三个方法, init(), doFilter(), destroy()分别在相应的时机执行。后期观察生命周期。 Filter 的实现只需要两步:
Step1: 编写 java 类实现 Filter 接口,并实现其 doFilter 方法。
Step2: 在 web.xml 文件中对编写的 filter 类进行注册,并设置它所能拦截的资源。
package com.shsxt.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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* filter过滤器
* 1、在请求到达资源之前,拦截request请求
* 2、在响应到达客户端之前,拦截response响应
* 3、当访问资源时,如果设置了过滤器的路径,过滤器中需要放行,否则请求无法到达资源
* 4、如果有多个过滤器(过滤器链):
* 顺序:请求的顺序是配置文件中的先后顺序,响应的顺序反过来即可。
* 过滤器链中,第一个过滤器如果没有放行,则无法到达下一个过滤器,资源也无法访问
* 原理:会拦截到请求的过滤器:第一个过滤器如果放行,会进入下一个过滤器,如果下一个过滤器不存在,则进入指定资源
* 5、chain.doFilter(request, response);方法之前处理请求相关的信息,方法之后处理响应相关的信息
* @author Lisa Li
*
*/
public class Filter01 implements Filter {
/**
* 初始化,服务器启动时加载,只会加载一次
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter01 出生了。。。");
}
/***
* 过滤处理方法
*/
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("Filter01 正在处理...");
// 基于HTTP
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 设置请求的编码
request.setCharacterEncoding("UTF-8");
// 响应编码
response.setContentType("text/html;charset=UTF-8");
// 放行
chain.doFilter(request, response);
// 响应
System.out.println("Filter01 处理完毕...");
}
/**
* 销毁,服务关闭时销毁
*/
@Override
public void destroy() {
System.out.println("Filter01 die...");
}
}
Filter 接口中有一个 doFilter 方法,当开发人员编写好 Filter,并配置对哪个 web 资源进行拦截后, Web 服务器每次在调用 web 资源的 service 方法之前,都会先调用一下 filter 的 doFilter 方法。
web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象是 filter 接口中最重要的一个对象,它提供了一个 doFilter 方法,开发人员可以根据需求决定 是否调用此方法,调用该方法,则 web 服务器就会调用 web 资源的 service 方法,即 web 资源就会被访问,否则 web 资源不会被访问。(本质是放行,调用 doFilter 方法后,即请求可以到达资源)
<filter>
<filter-name>filter02</filter-name>
<filter-class>com.shsxt.filter.Filter02</filter-class>
</filter>
<filter-mapping>
<filter-name>filter02</filter-name>
<url-pattern>/*</url-pattern><!-- 拦截所有资源 -->
</filter-mapping>
url-pattern 的配置:
①配置具体路径/index.html/TestServlet.do
②带有通配符的配置*.do /* /user/* *.html *.jsp
3. 过滤器执行的顺序
通过观察 web.xml 中的配置和各个 filter 的执行顺序,找出 filter 执行先后的依据。根据之前观察 Servlet 生命周期的的方式,观察一下过滤器的生命周期。resqust与response相反.
三.监听器
1.自我介绍
web 监听器是一种 Servlet 中的特殊的类,它们能帮助开发者监听 web 中的特定事件, 比如 ServletContext,HttpSession,ServletRequest 的创建和销毁;变量的创建、销毁和修改等。 可以在某些动作前后增加处理,实现监控。例如可以用来统计在线人数等。
2. 实现
监听器有三类 8 种: ⑴监听生命周期:实现接口ServletRequestListenerHttpSessionListener 、ServletContextListener⑵监听值的变化:实现接口ServletRequestAttributeListener、 HttpSessionAttributeListener、ServletContextAttributeListener ⑶针对 session 中的对象:监听 session 中的java 对象(javaBean) 是 javaBean 直接实现监听器 的接口。
Step1:创建一个监听器,需要实现某种接口,根据需求选取HttpSessionListener
Step2:在 web.xml 中配置该监听器
package com.shsxt.listener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class Listener01 implements HttpSessionListener,HttpSessionAttributeListener {
/**
* 添加域对象
*/
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("Session添加域对象");
}
/**
* 移除域对象
*/
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("Session移除域对象");
}
/**
* 替换域对象
*/
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("Session替换域对象");
}
/**
* session对象被创建
*/
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session对象被创建");
}
/**
* session对象被销毁
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session对象被销毁");
}
}
3.在线人数统计及弹幕实现
a.监听器的实现
package com.shsxt.listener;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class OnlineListener02 implements HttpSessionListener, HttpSessionAttributeListener{
private ServletContext servletContext = null;
private List<String> onlineList = new ArrayList<>();
@Override
public void sessionCreated(HttpSessionEvent se) {
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
}
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
// 获取session作用域中的用户名
if ("username".equals(se.getName())) {
String uname = (String) se.getSession().getAttribute(se.getName());
onlineList.add(uname);
servletContext = se.getSession().getServletContext();
servletContext.setAttribute("onlineList", onlineList);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
// TODO Auto-generated method stub
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
// TODO Auto-generated method stub
}
}
b.Servlet的实现
package com.shsxt.web;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class OnlineServlet02 extends HttpServlet {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 创建session对象
HttpSession session = request.getSession();
// 得到用户名
String uname = request.getParameter("uname");
if (uname != null && !"".equals(uname.trim())) {
// 将用户名存到作用域中
session.setAttribute("username", uname);
}
List<String> onlineList = (List<String>) request.getServletContext().getAttribute("onlineList");
if (onlineList != null && onlineList.size() > 0) {
response.getWriter().write("<h1>当前登录用户: " + uname +"</h1>");
response.getWriter().write("<h2>用户列表 </h2>");
String serverName=request.getRemoteHost();//获取远程计算机的名字
String remoteIp=request.getRemoteAddr();//获取客户端的ip
System.err.println( remoteIp + " : " + uname );
for (String string : onlineList) {
response.getWriter().write("<h3>"+ serverName + " " + remoteIp + ":" + string + "</h3>");
}
}
}
/**
* 获取Ip地址
*/
protected String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public void test (HttpServletRequest request) {
Locale languageType=request.getLocale();//获取用户语言
String localIp=request.getLocalAddr();//获取本地ip
int localPort=request.getLocalPort();//获取本地的端口
String localName=request.getLocalName();//获取本地计算机的名字
String remoteIp=request.getRemoteAddr();//获取客户端的ip
int remotePort=request.getRemotePort();//获取客户端的端口号
String serverName=request.getRemoteHost();//获取远程计算机的名字
System.out.println("语言类型->" + languageType);
System.out.println(localName + ": " + serverName);
System.out.println(localIp + ":" + localPort + " " + remoteIp + ":" + remotePort);
}
}
四.Servlet3.0 注解
1. @WebServlet
开发 servlet 项目,使用@WebServlet 将一个继承于javax.servlet.http.HttpServlet 的类定义为 Servlet 组件。在 Servlet3.0 中 , 可以使用@WebServlet 注解将一个继承于 javax.servlet.http.HttpServlet 的类标注为可以处理用户请求的 Servlet。
a.用注解配置 Servlet
b.配置多个 urlPatterns 来指定多个访问路径
c.常用这种形式:@WebServlet("/s01")
package com.shsxt.servlet;
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("/s01")
//@WebServlet(value = "/s01")
//@WebServlet(value = {"/s01","/s02"})
//@WebServlet(urlPatterns = "/s01")
//@WebServlet(urlPatterns = {"/s01","/s02"})
//@WebServlet(urlPatterns = "/s01",loadOnStartup = 1,name="Servlet01")
public class Servlet01 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet01...");
}
}
2. @WebFilter
@WebFilter 用来配置过滤器
使用注解时:过滤器链按照类名的字母排序(大部分情况)
package com.shsxt.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;
/**
* Servlet Filter implementation class Filter01
*/
//@WebFilter(urlPatterns = "/*")
@WebFilter("/*")
public class Filter01 implements Filter {
/**
* Default constructor.
*/
public Filter01() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
3. @WebListener
Servlet3.0 提供@WebListener 注解将一个实现了特定监听器接口的类定义为监听器。将 实现了 ServletContextListener 接口的 MyServletContextListener标注为监听器。
package com.shsxt.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* Application Lifecycle Listener implementation class Listener
*
*/
@WebListener
public class Listener01 implements HttpSessionListener {
/**
* Default constructor.
*/
public Listener01() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpSessionListener#sessionCreated(HttpSessionEvent)
*/
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generated method stub
}
/**
* @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
*/
public void sessionDestroyed(HttpSessionEvent se) {
// TODO Auto-generated method stub
}
}
4. @MultipartConfig
使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。
上传的前台页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<!--
如果是文件上传表单
1、必须设置enctype="multipart/form-data",设置MIME编码
2、请求方式为POST
3、文件域需要设置name属性值
-->
<form action="upload" method="post" enctype="multipart/form-data">
用戶名:<input type="text" name="uname" />
文件名:<input type="file" name="myfile" />
<input type="submit" />
</form>
</body>
</html>
上传的后台页面:
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
* servlet3.0上传文件
*/
@WebServlet("/upload")
/*
* 使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。
Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作
*/
//@MultipartConfig
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 得到参数
String uname = request.getParameter("uname");
System.out.println(uname);
// 得到上传对象
Part part = request.getPart("myfile"); // getPart(name):前台表单的文件域的name属性值
// 得到服务器的服务器的真实路径
String realPath = getServletContext().getRealPath("/");
// 得到上传的文件名
String fileName = part.getSubmittedFileName();
// 上传文件到指定位置
part.write(realPath + fileName);
}
}