1.listener定义
监听器,它是一个接口
2.作用
监听web中中的域对象 ServletContext ServletRequest HttpSession
3.监听内容
1. 监听三个对象的创建和销毁
ServletContextListener创建:服务器启动的时候,会为每一个项目都创建一个servletContext
销毁:服务器关闭的时候,或者项目被移除的时候
以后用来加载配置文件(项目启动的时候要做的事情可以在这里做)public class MyServletContextLis implements ServletContextListener{ @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("ServletContext销毁"); } @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("ServletContext创建了"); } } 同时修改配置文件 <listener> <listener-class>com.javaweb.listener_servletcontext.MyServletContextLis</listener-class> </listener>
ServletRequestListener创建:请求来的时候
销毁:响应生成的时候
HttpSessionListener
创建:
java中第一次调用request.getSession的时候
jsp访问的时候创建
销毁:
三种情况:
session超时
手动销毁session
服务器非正常关闭
2. 监听三个对象属性的变化(添加 替换 删除)
ServletContextAttributeListener先在jsp中添加属性 <% application.setAttribute("username", "tom"); %> 然后再实现ServletContextAttributeListener接口,重写他的三个方法这里只写了一个 public void attributeAdded(ServletContextAttributeEvent scab) { System.out.println("添加了一个属性名称为"+scab.getName()); }
ServletRequestAttributeListener
HttpSessionAttributeListener
3. 监听session中javabean的状态 ★ ★ ★ ★
注意:这两个接口需要javabean实现.是让javabean感知到自己的状态
1.HttpSessionActivationListener(钝化和活化)钝化:javabean从session中序列化到磁盘上(关闭服务器可以写到磁盘上)
String 类型的对象可以序列化到磁盘山,因为它实现了序列化接口
而javabean没有实现,所以要想它也可以的话就得实现序列化接口。
活化:javabean从磁盘上加载到了session中(重启后可重写加载)用法:
先构造一个javabean★★★
package com.javaweb.domain; import java.io.Serializable; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; public class Person2 implements HttpSessionActivationListener,Serializable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person2() { } public Person2(int id, String name) { this.id = id; this.name = name; } @Override //钝化 public void sessionWillPassivate(HttpSessionEvent se) { System.out.println("person对象 写入磁盘 钝化"); } @Override //活化 public void sessionDidActivate(HttpSessionEvent se) { System.out.println("person对象 活化了~~~"); } }
第二步:jsp页面中添加属性
<body> 将person和person2对象添加到session中 <% /* session.setAttribute("p", new Person(1,"tom")); */ session.setAttribute("p2", new Person2(2,"jack")); %> </body>
第三部:jsp中getbean
${p2.name }
为了更方便的减轻服务器压力★★★
可以通过配置文件修改javabean什么时候钝化
修改一个项目
只需要在项目下/meta-info创建一个context.xml
内容如下:
<Context>
<!--
maxIdleSwap :1分钟 如果session不使用就会序列化到硬盘.
directory :itheima 序列化到硬盘的文件存放的位置.
-->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="itheima"/>
</Manager>
</Context>
2.HttpSessionBindingListener(绑定和解绑,是否把对象放到了session中)检测java是否添加到session或者从session中移除
用法:写一个javabean然后去实现这个接口 其次重写里面的方法即可
————————————————————————————————
1.Filter
过滤器,也是一个接口,用来过滤请求和响应
2.作用:
- 自动登录.
- 统一编码.
- 过滤关键字
3.使用filter步骤:
1.编写一个类
a.实现filter接口
b.重写方法
2.编写配置文件
a.注册filter
b.绑定路径
3.测试
代码实现:
step1:新建一个class实现Filter
public class HelloFilter implements Filter {
@Override★
public void destroy() {
}
@Override★
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("filter收到了請求");
//放行★★★只有放行才可以去执行servlet
chain.doFilter(request, response);
}
@Override★
public void init(FilterConfig filterConfig) throws ServletException {
}
step2:编写配置文件url是/demo1
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>com.javaweb.filter.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloFilter</filter-name>
<url-pattern>/demo1</url-pattern>★★★
</filter-mapping>
step3:新建一个servlet demo1servlet(url=/demo1)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1 servlet执行了");
}
分析:★★
filter是浏览器和服务器之间的一座桥梁,只有放行才可以去执行服务器中寻找servlet
4.Filter接口的方法:
init(FilterConfig config):初始化操作
doFilter(ServletRequest request, ServletResponse response, FilterChain chain):处理业务逻辑
destroy() :销毁操作
5.filter的生命周期:
filter在服务器启动的时候 服务器创建filter 调用init方法 实现初始化操作
请求来的时候,创建一个线程 根据路径调用dofilter 执行业务逻辑
当filter被移除的时候或者服务器正常关闭的时候 调用destory方法 执行销毁操作.filter是单实例多线程(只创建一次)
6.FilterChain:过滤链
通过chain的dofilter方法,可以将请求放行到下一个过滤器,直到最后一个过滤器放行才可以访问到servlet|jsp
doFilter()放行方法
7.★url-pattern配置
1.完全匹配 必须以"/" 开始 例如: /a/b
2.目录匹配 必须以"/" 开始 以"*"结束 例如:/a/b/*
3. 后缀名匹配 以"*."开始 以字符结束 例如 : *.jsp *.do *.action
例如:
afilter 路径 /*
bFilter 路径 /demo4★一个资源有可能被多个过滤器匹配成功,多个过滤器的执行顺序是按照 web.xml 中 filter-mapping的顺序执行的
数据响应回来时刚好相反
8.案例实现-自动登录:
步骤分析:
step1:
新建一个登录页面 表单
step2:
表单提交 loginservlet
接受用户名和密码
调用service完成登录操作,返回值User
判断user是否为空
若不为空,(说明存在该用户)将user放入session中
判断是否勾选了自动登录
若勾选了:
需要将用户名和密码(从session)写回浏览器(cookie)
step3:
下次访问网站的时候
过滤器拦截任意请求
判断有无指定的cookie
有cookie,获取用户名和密码
调用service完成登录操作,返回user
当user不为空的时候将user放入session中.
问题解析:
当我们换用name登录的时候发现登录不了
自动登录只需要登录一次:当session中没有用户的时候
访问有些资源是不需要自动登录的(和登录还有注册相关的资源)
修改filter的逻辑:
首先判断session中是否有user
若没有 并且访问的路径不是和登录注册相关的时候
才去获取指定的cookie
代码实现
step1:login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="${pageContext.request.contextPath }/login">★★
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username" ></td>
</tr>
<tr>
<td>密码</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td colspan="1"><input type="checkbox" name="saveName" value="ok">记住用户名</td>
<td colspan="1"><input type="checkbox" name="autoLogin" value="ok">自动登录</td>★★★
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>
<script type="text/javascript">
onload=function(){
var s="${cookie.savename.value }";★★cookie写入中文
s=decodeURI(s);
//alert(s);
//将解码后的用户名付给username的文本框
document.getElementsByName("username")[0].value=s;
}
</script>
</body>
</html>
step2:login.servlet
package com.javaweb.servlet;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.javaweb.Constant.Constant;
import com.javaweb.domain.User;
import com.javaweb.service.UserService;
/**
* 登录
*/
public class LoginServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0.设置编码
request.setCharacterEncoding("utf-8");
//1.获取用户名和密码
String username=request.getParameter("username");
String password=request.getParameter("password");
//2.调用service'
User user=null;
try {
user = new UserService().login(username,password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//3.判断user是否为空★★★
if(user==null){
request.setAttribute("msg", "用户名和密码不匹配");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}else{
//若不为空 跳转到success.jsp
request.getSession().setAttribute("user", user);★★★
//判断是否勾选了自动登录 若勾选了需要将用户名和密码放入cookie中, 写回浏览器★
if(Constant.IS_AUTO_LOGIN.equals(request.getParameter("autoLogin")))
{
Cookie c=new Cookie("autologin", username+"-"+password);
c.setMaxAge(3600);
c.setPath(request.getContextPath()+"/");
response.addCookie(c);
}
//判断是否勾选了记住用户名 若勾选了需要将用户名放入cookie中 写回浏览器
if(Constant.IS_SAVA_NAME.equals(request.getParameter("saveName"))){
//创建cookie
Cookie c=new Cookie("savename", URLEncoder.encode(username, "utf-8"));
c.setMaxAge(3600);
c.setPath(request.getContextPath()+"/");
response.addCookie(c);
}
//页面重定向★★★
response.sendRedirect(request.getContextPath()+"/success.jsp");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
step3:success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
${user.username}:Welcome back★★
</body>
</html>
step4:service层
package com.javaweb.service;
import java.sql.SQLException;
import com.javaweb.dao.Userdao;
import com.javaweb.domain.User;
public class UserService {
public User login(String username, String password) throws SQLException {
return new Userdao().getUserByUserNameAndPwd(username,password);
}
}
step5:dao层
package com.javaweb.dao;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.javaweb.domain.User;
import com.javaweb.utils.DataSourceUtils;
public class Userdao {
public User getUserByUserNameAndPwd(String username, String password) throws SQLException {
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
String sql="select * from user where username = ? and password = ? limit 1";★
return qr.query(sql, new BeanHandler<>(User.class), username,password);
}
}
step6:constant
package com.javaweb.Constant;
public interface Constant {
String IS_AUTO_LOGIN="ok";★
String IS_SAVA_NAME="ok";
}
step7:domain
package com.javaweb.domain;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
step7:完成自动登录
package com.javaweb.filter;
import java.io.IOException;
import java.sql.SQLException;
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.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.javaweb.domain.User;
import com.javaweb.service.UserService;
import com.javaweb.utils.CookUtils;
public class AutoLoginFilter implements Filter{
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//1.强转★★★
HttpServletRequest request =(HttpServletRequest) req;
HttpServletResponse response =(HttpServletResponse) resp;
//2.完成自动登录★★★
//2.1 判断session中有无登录登录用户 没有的话继续自动登录★★
User user=(User) request.getSession().getAttribute("user");
if(user==null){
//没有用户 需要自动登录★★
//2.2 判断访问的资源是否和登录注册相关,若相关则不需要自动登录★★★★★★★
String path = request.getRequestURI();// /day1601/xxx自动登录只用一次即可
if(!path.contains("/login")){//不然会造成直接从cookie中取值
//2.3获取指定的cookie★★★
Cookie c = CookUtils.getCookieByName("autologin", request.getCookies());
//判断cookie是否为空
//若不为空 获取值(username和passowrd) 调用serivce完成登录 判断user是否为空 不为空 放入session
if(c!=null){
String username=c.getValue().split("-")[0];
String password=c.getValue().split("-")[1];
//调用serivce完成登录
//user=null;
try {
user = new UserService().login(username, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(user!=null){
//将user放入session中★★★
request.getSession().setAttribute("user", user);
}
}
}
}
//3.放行
chain.doFilter(request, response);★★
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
9.Filter相关总结:
1.filterConfig:(了解)
过滤器的配置对象
作用:
获取全局管理者getservletcontext
获取当前filter的名称
获取当前filter的初始化参数
2. filter-mapping的子标签(理解)
servlet-name:匹配哪个servlet★★ 值写的是serlvet标签中servlet-name的值★★★
建议:不要在一个filter中重复的匹配servlet
例如: serlvet的url-pattern为 /a/b/hello serlvetname:HelloServlet
如果filter中的url-pattern /*
最好不要在写 servlet-name:HelloServlet
dispatcher:
匹配哪种请求★★
默认的是REQUEST,一旦显式的写出来哪种请求,默认就不起作用了
理解
REQUEST:从浏览器发送过来的请求(默认) 理解
FORWARD:转发过来的请求 理解
了解
ERROR:因服务器错误而发送过来的请求
INCLUDE:包含过来的请求url-pattern匹配的是那个路径
注意:先执行的是filter再是servlet★★★
所以这边假如是request请求的话会执行filter再执行servlet
如果是forward的话则不会执行filter,servlet就直接执行了
9.案例实现统一编码:
需求:
以前我们开发的时候若有参数,第一步都是设置编码,才不会出现乱码,通过过滤器设置,到servlet或者jsp上的时候已经没有乱码问题
技术分析:
filter 配置路径/* 过滤器的第一个位置
在filter中重写getParameter(加强)
步骤分析:
我们只需要在filter中 对request进行加强(例如:只对request.getParameter()进行加强)
方法加强:
1.继承(获取构造器)
2.装饰者模式(静态代理)
3.动态代理
装饰者书写步骤:
1.要求装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要加强方法进行加强
4.对不需要加强的方法调用原来的方法即可
加强request.getParameter(String key)
首先请求的方式不同,处理的方式也不同
获取请求的方法
若是get请求
new String(value.getBytes("iso8859-1"),"utf-8");
若是post请求
只需要设置一句话
request.setCharacterEncoding("utf-8");
最后将包装过的request对象(MyRequest)传递给servlet即可
代码实现如下:
新建一个form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/day1001/Login" method="post">//★★★
用户名:<input name="username"><br>
密码:<input name="password"><br>
<input type="submit">
</form>
</body>
</html>
step2:新建一个LoginServlet url设置为Login
package com.javaweb.encoding;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取用户名和密码★★★
String username = request.getParameter("username");
String password = request.getParameter("password");
//2.打印在控制台
System.out.println(username+"::"+password);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
step3:在步骤2的同一个包下新建一个Filter,同时在web.xml中配置filter
package com.javaweb.encoding;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
public class EncodingFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//1.强转★★★
HttpServletRequest request=(HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) resp;
//2.放行 将包装过的request传递★★★
chain.doFilter(new MyRequest(request), response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
class MyRequest extends HttpServletRequestWrapper{//★★★查询的不用记,知道就行,包裹的意思
private HttpServletRequest request;
public MyRequest(HttpServletRequest request) {//★★★
super(request);
this.request=request;
}
@Override
public String getParameter(String name) {//★★★
//获取请求方式
String m = request.getMethod();
if("get".equalsIgnoreCase(m)){//★★★
//get请求
String value = request.getParameter(name);
try {
return new String(value.getBytes("iso8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
}
}else if("post".equalsIgnoreCase(m)){//★★★
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
}
return request.getParameter(name);
}
return super.getParameter(name);//★★★
}
}
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>com.javaweb.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>//★★★拦截所有
</filter-mapping>
9.2补充:
关于获取参数的方法
String getParameter(String name);// arr[0]
String[] getParameterValues(String name);// map.get(name)
Map<String,String[]> getParameterMap();
统一编码实现Map方式理解即可
package cn.itcast.web.filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
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.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
/**
* 统一编码
* @author Administrator
*
*/
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//1.强转
HttpServletRequest request=(HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) resp;
//2.放行
chain.doFilter(new MyRequest(request), response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
class MyRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
private boolean flag=true;
public MyRequest(HttpServletRequest request) {
super(request);
this.request=request;
}
@Override
public String getParameter(String name) {
if(name==null || name.trim().length()==0){
return null;
}
String[] values = getParameterValues(name);
if(values==null || values.length==0){
return null;
}
return values[0];
}
@Override
/**
* hobby=[eat,drink]
*/
public String[] getParameterValues(String name) {
if(name==null || name.trim().length()==0){
return null;
}
Map<String, String[]> map = getParameterMap();
if(map==null || map.size()==0){
return null;
}
return map.get(name);
}
@Override
/**
* map{ username=[tom],password=[123],hobby=[eat,drink]}
*/
public Map<String,String[]> getParameterMap() {
/**
* 首先判断请求方式
* 若为post request.setchar...(utf-8)
* 若为get 将map中的值遍历编码就可以了
*/
String method = request.getMethod();
if("post".equalsIgnoreCase(method)){
try {
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if("get".equalsIgnoreCase(method)){
Map<String,String[]> map = request.getParameterMap();
if(flag){
for (String key:map.keySet()) {
String[] arr = map.get(key);
//继续遍历数组
for(int i=0;i<arr.length;i++){
//编码
try {
arr[i]=new String(arr[i].getBytes("iso8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
flag=false;
}
//需要遍历map 修改value的每一个数据的编码
return map;
}
return super.getParameterMap();
}
}
10.小总结:
1.强转
HttpServletRequest request=(HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) resp;
2.自己设置404页面的方法 (Filter下的子标签)
<error-page>
<error-code>404</error-code>
<location>404.jsp </location>
</error-page>
3.cookie写入中文
在自动登录案例中的login.jsp中和login.servlet中体现
4.用到的工具类
cookUtils
DataSourceUtils
5.自动登录和统一编码的逻辑过程要清楚,filter的用法
判断用户是否为空(从数据库中查询所得结果包含用户名和密码),调用的servlet实现
空:跳转原来页面
不空:放入session域中
判断是够勾选自动登录
是:放入cookie中,下次访问浏览器会直接从cookie中拿值
点击提交
success.jsp中
自动登录实现filter
1.强转
2.判断session中有没有登录的用户,没有说明可以继续自动登录
同时判断懒是够和注册相关,通过获取路径来判断,登录过的是day10/xxx
如果路径含有/login说明有人登录,取反if(!path.contains("/login"))
如果是注册是不需要自动登录的或者已经有用户存在了,用户师兄session中取值的所以session空
3.自动登录:
①获取cookie
②分割cookie中的(key,value)中的value得到用户名和密码
③调用service完成自动登录
6.过滤器拦截所有的请求
url设置为/*
7.filter的配置方法