目录
多个servlet共享方案
ServletContext接口和Cookie
HttpSession接口
HttpSession接口来自于Servlet规范下一个接口,存在于Tomcat中servlet-api.jar,其实现类由Http服务器提供;
如果两个Servlet来自同一个网站,并且为同一个浏览器、用户提供服务。此时借助于HttpSession对象进行数据共享;
开发人员将HttpSession接口修饰对象称为会话作用域对象;
HttpSessino 与 Cookie 区别:
存储位置:
Cookie:放在客户端计算机(浏览器内存/硬盘)
HttpSession:存放在服务端计算机内存
数据类型:
Cookie对象存储共享数据类型只能时String
HttpSession对象可以存储任意类型的共享数据Object
数据数量:
一个Cookie只能存储一个共享数据
HttpSession使用Map集合存储共享数据,可以存储任意数量共享数据
参照物:
Cookie相当于客户端在服务端【会员卡】
HttpSession相当于客户端在服务端【私人保险柜】
实现步骤:
看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购物首页</title>
</head>
<body>
<table border="2px">
<tr>
<td>商品名称</td>
<td>商品单价</td>
<td>评价</td>
<td>放入购物车</td>
</tr>
<tr>
<td>笔记本</td>
<td>6000</td>
<td>好</td>
<td><a href="/myWeb/one?goodsName=笔记本">放入购物车</a></td>
</tr>
<tr>
<td>电视</td>
<td>800</td>
<td>好</td>
<td><a href="/myWeb/one?goodsName=电视">放入购物车</a></td>
</tr>
<tr>
<td>苹果</td>
<td>5.5</td>
<td>变质</td>
<td><a href="/myWeb/one?goodsName=苹果">放入购物车</a></td>
</tr>
</table>
<a href="/two">查看我的购物车</a>
</body>
</html>
package com;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String goodsName;
//请求头获取商品名称
goodsName = request.getParameter("goodsName");
System.out.println(goodsName);
//调用请求对象,向Tomcat索要当前用户在服务端的储物柜
HttpSession session = request.getSession();
//将用户选购的商品添加到当前用户私人储物柜
Integer goodsNum = (Integer)session.getAttribute(goodsName);
if(goodsName == null){
/*没有这个商品*/
session.setAttribute(goodsName,1);
}else{
session.setAttribute(goodsName,goodsNum + 1);
}
}
}
package com;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Enumeration;
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//调用请求对象,向Tomcat索要当前对象在服务端私人储物柜
HttpSession session = request.getSession();
//将session中的所有key读取出来,存放一个枚举对象
Enumeration goodsNames = session.getAttributeNames();
while (goodsNames.hasMoreElements()){
String goodsName = (String)goodsNames.nextElement();
int goodsNum = (int)session.getAttribute(goodsName);
System.out.println("商品名称:" + goodsName + "商品数量:" + goodsNum);
}
}
}
结果:
代码有bug,容我改改!!!
HttpSession的销毁
用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中;
在浏览器关闭时,意味着用户与他的HttpSession关联被切断;
由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的HttpSesssion销毁;
为了解决这个问题,Tomcat为每个HttpSession对象设置了空闲时间,这个空闲时间默认为30min,如果档期那HttpSession对象空闲时间达到30分钟,此时Tomcat认为用户已经放弃了自己的HttpSession,此时Tomcat就会销毁掉这个HttpSession;
设定空闲时间
设定5s
<session-config>
<session-timeout>5</session-timeout>
</session-config>
也可以这样设置
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60*3);//以秒为单位
3分钟挂壁
HttpServletRequest接口实现数据共享
同一个网站中,如果两个Servlet之间通过请求转发方式进行调用,彼此之间共享同一个请求协议包。二一个请求协议包只对应一个请求对象,因此servlet之间共享同一个请求对象,此时可以利用这个请求对象在两个Servlet之间实现数据共享 ;
在请求对象实现Servlet之间数据共享功能时,开发人员将请求对象称为请求作用域;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//将数据添加到请求作用域,作为共享数据
request.setAttribute("key1","http");
//代替浏览器,向Tomcat索要TwoServlet完成剩余任务
request.getRequestDispatcher("/one").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//从OneServlet中得到共享数据
String result = request.getAttribute("key1").toString();
System.out.println(result);
}
servlet监听器接口
一组来自Servlet规范下接口,共有8个接口。在Tomcat存在servlet-api.jar包
监听器接口需要由开发人员亲自实现,Http服务器提供jar包没有对应的实现类;
监听器接口用于监控作用域对象生命周期变化时刻以及作用域对象共享数据变化时刻;
作用域对象:服务端内存中可以子某些条件下为两个Servlet之间提供数据共享方案的对象,被称为作用域对象
servlet规范下作用域对象:
servletContext:全局作用域对象;
HttpSession:会话作用域对象;
HttpServletRequest:请求作用域对象;
监听器接口实现类开发规范:三步:
1、根据监听的实际情况,选择对应监听器接口进行实现
2、重写监听器接口声明监听事件处理方法
3、在web.xml文件将监听器接口实现类注册到Http服务器
ServletContextListener接口:
作用:通过这个接口合法的检测 全局作用域对象被初始化时刻以及被销毁时刻
监听事件处理方法:
public void contextInitlized() : 在全局作用域对象被Http服务器初始化被调用;
public void contextDestory() : 在全局作用域对象被Http服务器销毁时触发调用;
OneListener.java
监听类要放在一个listener的文件夹当中
package com.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class OneListener implements ServletContextListener
{
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("创建时");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("销毁时");
}
}
在web.xml中声明
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.listener.OneListener</listener-class>
</listener>
</web-app>
结果:
ServletContextAttributeListener接口:
作用:通过这个接口合法的检测全局作用域对象共享数据变化时刻
监听事件处理方法:
public void contextAdd() : 在全局作用域对象添加共享数据
public void context replace() : 在全局作用域对象更新对象更新共享数据
public void contextRemove() : 在全局在于对象删除共享数据
package com.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
public class OneListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("新增共享数据");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("删除共享数据");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("更新共享数据");
}
}
package com.controller;
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 java.io.IOException;
@WebServlet(name = "OneServlet")
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext application = request.getServletContext();
application.setAttribute("key1","学习java");
application.setAttribute("key1","学习C++");
application.removeAttribute("key1");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.listener.OneListener</listener-class>
</listener>
<servlet>
<servlet-name>OneServlet</servlet-name>
<servlet-class>com.controller.OneServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OneServlet</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
</web-app>
结果:
HttpSessionListener
看个例子
Servlet处理,创建sesion
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" session="false" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="/myweb/login?name=liang&age=11">click this</a>
</body>
</html>
注意这个session=false属性,它表示在jsp中禁用session,因此第一次创建在servlet中了(应该?)
然后是HttpsessionListener
package Listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class sessionListen implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
ServletContext application = session.getServletContext();
System.out.println("用户创建成功");
session.setMaxInactiveInterval(1);//设置一分钟后中止
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("用户退出系统");
}
}
不要忘了在web.xml中配置listener
<listener>
<listener-class>Listener.sessionListen</listener-class>
</listener>
结果:
Filter接口 过滤器
来自于Servlet规范下接口,在Tomcat中存在于servler-api.jar包
Filter接口实现类由开发人员负责提供,Http服务器不负责提供
Filter接口在Http服务器调用资源文件之前,对Http服务器进行拦截
作用:拦截Http服务器,帮助Http服务器检测当前请求合法性,对当前请求进行增强操作。
开发步骤:
1、创建一个java类实现Filter接口
2、重写Filter接口中doFilter方法
3、web.xml将过滤器接口实现类注册到Http服务器
例子
package com.filter;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
public class OneFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String age = (String)servletRequest.getParameter("age");
System.out.println(age);
if(Integer.parseInt(age) < 18){
//拒绝本次请求
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter out = servletResponse.getWriter();
out.println("<div>未成年人不得访问</div>");
}else{
filterChain.doFilter(servletRequest,servletResponse);//放行
}
}
@Override
public void destroy() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>OneFilter</filter-name>
<filter-class>com.filter.OneFilter</filter-class>
</filter>
<!--通知Tomcat在调用何种资源文件的时候,需要被当前拦截器拦截-->
<filter-mapping>
<filter-name>OneFilter</filter-name>
<!--在调用mm.jpg时拦截器启动-->
<url-pattern>/mm.jpg</url-pattern>
</filter-mapping>
</web-app>
结果:
age属性<18,拦截不显示图片
用过滤器对浏览器进行增强
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<form action="/myWeb/one" method="post">
参数:<input type="text" name="userName">
<input type="submit" value="post方式访问oneServlet">
</form>
<form action="/myWeb/two" method="post">
参数:<input type="text" name="userName">
<input type="submit" value="post方式访问twoServlet">
</form>
</center>
</body>
</html>
先写一个htm,用来给用户传一个userName的参
然后用两个Servlet来获取这个userName
package com.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//直接从请求体中读取请求参数
String userName = (String)request.getParameter("userName");
System.out.println("oneServlet从请求体得到的:" + userName);
}
}
package com.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//直接从请求体中读取请求参数
String userName = (String)request.getParameter("userName");
System.out.println("twoServlet从请求体得到的:" + userName);
}
}
如果没有设置utf-8,那么获得的中文字符在控制台打印出来是???,如果在每个Servlet都设置一次,则比较麻烦,因此,可以在过滤器中统一进行设置
OneFilter.java
package com.filter;
import javax.servlet.*;
import java.io.IOException;
public class OneFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
结果
拦截地址格式
如上例子,有
在当前网站中调用任意文件都经过过滤器
<filter-mapping>
<filter-name>OneFilter</filter-name>
<url-pattern>/*</url-pattern><!-- /*代表通知Tomcat调用所有资源文件之前,调用OneFilter -->
</filter-mapping>
在某个文件夹下的所有文件
<url-pattern>/img/*</url-pattern>
要求Tomcat在调用某种类型文件之前,需要拦截
<url-pattern>*.jpg</url-pattern>
防止用户恶意登录/访问
例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<div style="text-align: center">
<form action="/myWeb/loginServlet" method="get">
名字:<input type="text" name="user"/>
<input type="submit" value="点击按钮查看mm图片"/>
</form>
</div>
</body>
</html>
一个处理登录的Servlet
package com.controller;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我被访问了");
Object user = request.getParameter("user");
/*由于这是举例子,在此之前没有session,因此当用户登录进来时先创建一个*/
if(user != null){
HttpSession session = request.getSession();
}
HttpSession session = request.getSession(false);
if(session == null){
System.out.println("你是非法用户!");
}else{
System.out.println("你是合法的!");
response.sendRedirect("/myWeb/this.html");
}
}
}
一个负责拦截的Filter
package com.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.http.HttpRequest;
public class OneFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpSession session = request.getSession(false);
if(session == null){
System.out.println("你是非法的");
return;
}else{
System.out.println("欢迎欢迎!!!");
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
被访问的this.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是一个被保护的html
</body>
</html>
结果:
正常访问this.html
经过servlet,跳到了this.html
再来个非法访问
直接输入localhost:……this.html访问,页面不显示
控制台输出:
url跟踪
encodeURL只对本应用进行重写并附加会话id在url之后,对空字符串的url则处理成当前应用的上下文根目录然后附加会话id
encodeRedirctURL可以跨域实现重写,但不附加会话id;如果对本应用有效url进行重写则在url后附加会话id
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="UrlServlet" method="post">
账号:<input type="text" name="user"/><br>
密码:<input type="text" name="password"/><br>
<input type="submit" >
</form>
</body>
</html>
Servlet
package com.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class UrlServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("user",request.getParameter("user"));
String sessId = session.getId();
System.out.println("当前会话的id:" + sessId);
String newUrl = "welcome.jsp";
String rewriteUrl = response.encodeURL(newUrl);
System.out.println("被重写后的url:" + rewriteUrl);
request.getRequestDispatcher(rewriteUrl).forward(request,response);
}
}
welcome.jsp
<body>
欢迎光临<br>
当前用户名称:${sessionScope.user}
</body>
结果:
(注意看网址)
获取url名称:
/*获取当前应用程序url全名称*/
String http = request.getScheme();
String ip = request.getServerName();
int port = request.getServerPort();
String path = request.getServletPath();
String contextFullPath = http + "://" + ip +":"+ port + path + "/";
结语
2021.9.29结束,没什么感想,还要搞很多东西