Servlet
学习目标
Cookie对象
Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的,如常见的记住密码就是通过Cookie实现的
有一个专门操作Cookie的类 javax.servlet.http.Cookie
Cookie 的格式:键值对用“=”连接,多个键值对间通过“;”隔开
1 Cookie的创建和发送
创建Cookie对象
new Cookie("key","value")
发送Cookie对象
response.addCookie(Cookie对象);
例:
// 创建Cookie对象 Cookie cookie = new Cookie("uname","zhangsan"); // 发送Cookie对象 response.addCookie(cookie);
进入浏览器后按F12可查看
2 Cookie的获取
在服务器端只提供了一个 getCookies()
的方法用来获取客户端回传的所有 cookie 组成的一个数组,如果需要获取单个 cookie 则需要通过遍历
getName()获取 Cookie 的名称
getValue()获取 Cookie 的值
// 获取Cookie数组
Cookie[] cookies = request.getCookies();
// 判断数组是否为空
if (cookies != null && cookies.length > 0) {
// 遍历Cookie数组
for (Cookie cookie : cookies){
//获取 Cookie 的名称
System.out.println(cookie.getName());
//获取 Cookie 的值
System.out.println(cookie.getValue());
}
}
3 Cookei设置到期时间
到期时间用来指定该 cookie 何时失效,默认为当前浏览器关闭即失效
以手动设定 cookie 的有效时间(通过到期时间计算),通过 **setMaxAge(int time);
**方法设定 cookie 的最大有效时间,以秒为单位
到期时间的取值:
取值 | 结果 |
---|---|
负整数 | 不存储该cookie |
正整数 | 储存该cookie的秒数 |
零 | 删除该cookie |
// 创建Cookie对象
Cookie cookie = new Cookie("uname","zhangsan");
// 设置Cookie 3天后失效
cookie.setMaxAge(3 * 24 * 60 * 60);
// 发送Cookie对象
response.addCookie(cookie);
4 Cookie路径
cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie
Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些cookie
当访问的路径包含了cookie的路径时,则该请求将带上该cookie;
如果访问路径不包含cookie路径,则该请求不会携带该cookie
5 Cookie注意问题
1、Cookie只保存在当前浏览器中,不能跨浏览器
2、服务器端发送重复的Cookie那么会覆盖原有的Cookie
3、不同的浏览器储存的Cookie数量不同且有上限
4、Cookie存中文问题
Cookie 中是不能出现中文,如果有中文则通过
URLEncoder.encode()
来进行编码,获取时通过URLDecoder.decode()
来进行解码
// 设置中文储存数据
String name = "姓名";
String value = "张三";
// 通过 URLEncoder.encode()来进行编码
name = URLEncoder.encode(name);
value = URLEncoder.encode(value);
// 创建Cookie对象
Cookie cookie = new Cookie(name,value);
// 发送Cookie对象
response.addCookie(cookie);
// 获取时通过 URLDecoder.decode()来进行解码
URLDecoder.decode(cookie.getName());
URLDecoder.decode(cookie.getValue());
HttpSession对象
HttpSession对象是 javax.servlet.http.HttpSession
的实例,该接口并不像 HttpServletRequest 或HttpServletResponse 还存在一个父接口,该接口只是一个纯粹的接口。这因为 session 本身就属于HTTP 协议的范畴
session 无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置的 session,因为每一个 session 只保存在当前的浏览器当中,并在相关的页面取得
Session 的作用就是为了标识一次会话,或者说确认一个用户,并且在一次会话期间共享数据
通过**request.getSessions()
方法来获取当前会话的session对象**
// 如果session对象存在,则获取;如果session对象不存在,则创建
HttpSession session = request.getSession();
1 标识符 JSESSIONID
Session 既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是sessionId
每当一次请求到达服务器,如果开启了会话(访问了 session),服务器第一步会查看是否从客户端回传一个名为 JSESSIONID 的 cookie,
如果没有则认为这是一次新的会话,会创建 一个新的 session 对象,并用唯一的 sessionId 为此次会话做一个标志。
如果有 JESSIONID 这个cookie回传,服务器则会根据 JSESSIONID 这个值去查看是否含有id为JSESSION值的session 对象,
如果没有则认为是一个新的会话,重新创建一个新的 session 对象,并标志此次会话;
如果找到了相应的 session 对象,则认为是之前标志过的一次会话,返回该 session 对象,数据达到共享
这里提到一个叫做 JSESSIONID 的 cookie,这是一个比较特殊的 cookie
当用户请求服务器时,如果访问了 session,则服务器会创建一个名为 JSESSIONID,值为获取到的 session的 sessionId 的 cookie 对象,并添加到 response 对象中,响应给客户端,有效时间为关闭浏览器
所以 Session 的底层依赖 Cookie 来实现
2 session域对象
Session表示一次会话,在一次会话中数据是共享的,此时session作为域对象存在
通过 setAttribute(name,value)
方法向域对象中添加数据
通过 getAttribute(name)
方法从域对象获取数据
通过 removeeAttribute(name)
方法从域对象中移除数据
// 获取session对象
HttpSession session = request.getSession();
// 设置session域对象
session.setAttribute("uname","admin");
// 获取指定名称的session域对象
String uname = (String) request.getAttribute("uname");
// 移除指定名称的session域对象
session.removeAttribute("uname");
数据存储在 session 域对象中,当 session 对象不存在了,或者是两个不同的 session 对象时,数据就不能共享了
3 session对象的销毁
1 默认时间到期
当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,Tomcat 中 session 默认的存活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时
可以在 Tomcat 中的 conf 目录下的 web.xml 文件中进行修改默认到期时间
<!-- session 默认的最大不活动时间。单位:分钟。 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2 自己设定到期时间
通过 session.setMaxInactiveInterval(int)
来设定 session 的最大不活动时间,单位为秒
//获取session对象
HttpSession session = requestgetSession();
//设置session的最大不活动时间
session.setMaxInactiveInterval(30); //30秒
通过 getMaxInactiveInterval()
方法来查看当前 Session 对象的最大不活动时间
//获取session的最大不活动时间
int time = session.getMaxInactiveInterval();
3 立刻失效
以通过 session.invalidate()
方法让 session 立刻失效
//销毁session对象
session.invalidate();
ServletContext对象
每一个 web 应用都有且仅有一个ServletContext 对象,又称 Application 对象
在 WEB 容器启动的时候,会为每一个 WEB 应用程序创建一个对应的 ServletContext 对象
作用:
1、作为域对象用来共享数据
2、保存了当前应用程序相关信息
1 常用方法
获取 ServletContext 对象(四种方式)
1、通过 request 对象获取
ServletContext servletContext = request.getServletContext();
2、通过 session 对象获取
ServletContext servletContext = request.getSession().getServletContext();
3、通过 ServletConfig() 方法来获取
ServletContext servletContext = getServletConfig.getServletContext();
4、直接通过ServletContext 获取
ServletContext ServletContext = getServletContext();
获取项目存放的真实路径
String realPath = request.getServletContext().getRealPath("/");
获取当前服务器的版本信息
String serverInfo = request.getServletContext().getServerInfo();
2 ServletContext 域对象
通过向 ServletContext 中存取数据,可以使得整个应用程序共享某些数据。
当然不建议存放过多数据,因为 ServletContext 中的数据一旦存储进去没有手动移除将会一直保存
1、设置域对象
servletContext.setAttribute("name","zhangsan");
2、获取域对象
String name = (String) servletContext.getAttribute("name");
3、移除域对象
servletContext.removeAttribute("name");
3 生命周期
创建:服务器启动的时候,服务器为每个WEB应用创建一个属于该web项目的对象ServletContext类
销毁:服务器关闭或者项目从服务器中移除的时候
有效:在整个服务器上被保留
文件上传和下载
使用 servlet 可以实现文件的上传和下载
文件上传
文件上传涉及到前台页面的编写和后台服务器端代码的编写,前台发送文件,后台接收并保存文件,这才是一个完整的文件上传
1 前台页面
页面里需要存在表单
表单的请求方式必须为post ----> method="post"
表单的类型必须为文件上传表单 ----> enctype="multipart/form-data"
<form action="upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="uname">
文件:<input type="file" name="myFile">
<input type="submit" value="提交">
</form>
2 后台实现
使用注解 @MultipartConfig
将一个 Servlet 标识为支持文件上传
Servlet 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作
package com.xxxx.servlet;
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;
import java.io.IOException;
@WebServlet("/upload")
@MultipartConfig //表单上传文件必须添加的注解@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求的编码格式
request.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
//获取表单用户名的值
String name = req.getParameter("name");
//获取表单中文件的name值
Part part = req.getPart("myFile");
//获取上传的文件名
String fileName = part.getSubmittedFileName();
//根据ServletContext获取文件的路径
String filePath = req.getServletContext().getContextPath();
//将路径上传到指定位置
part.write(filePath+fileName);
}
}
文件下载
将服务器上的资源下载(拷贝)到本地
有两种方式:
1、通过超链接本身的特性:download
2、通过代码下载
1 超连接下载
默认下载
<!-- 当超链接遇到浏览器不识别的资源时,会自动下载,如压缩包 -->
<a href="test.zip">超链接下载</a>
指定 download 下载
<!-- 当超链接遇到浏览器识别的资源时,默认不会下载。通过download属性可进行下载 -->
<a href="test.txt" download>超链接下载</a>
注意:
download 属性可以不写任何信息,会自动使用默认文件名
如果设置了download属性的值,则使用设置的值做为文件名
当用户打开浏览器点击链接的时候就会直接下载文件
2 后台实现下载
前台页面设置下载路径
<a href="download?filename=test.txt">下载文件</a>
后台代码实现
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取文件路径
String filePath = req.getServletContext().getContextPath();
//获取文件名
String fileName = req.getParameter("name");
//通过路径和文件名获得对象
File file = new File(filePath+fileName);
//判断文件是否存在且不为文件夹,是则读写文件内容,否则不读取数据
if(file.exists() || file.isFile()){
//设置响应类型
resp.setContentType("application/x-msdownload");
//设置响应头信息
resp.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//输入流
InputStream is = new FileInputStream(file);
//输出流
ServletOutputStream os = resp.getOutputStream();
//定义数组
byte[] b = new byte[1024];
int len = -1;
//循环读取数据
while((len = is.read(b)) != -1){
os.write(b,0,len);
}
//释放资源
os.flush();
os.close();
is.close();
}else{
System.out.println("文件下载失败!!!请重试");
}
}
}
过滤器Filter
Servlet过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改
对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器端之间的请求与响应信息,对其修改或过滤
过滤器原理:
作用如下:
- 在客户访问后台资源之前拦截客户请求
- 在资源被送到客户端之前加以控制
- Servlet过滤器负责过滤的Web组件可以是Servlet、JSP或HTML文件
在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链
过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet
过滤器链原理:
Filter接口
过滤器实现 javax.servlet.Filter
接口,注解为**@WebFilter**,必须按顺序执行并重写3个方法
1、init(FilterConfig filterConfig)
初始化配置参数
2、doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
在客户端请求及服务器端回复时自动调用
ServletRequest和ServletResponse必须先转换成HttpServletRequest 和HttpServletResponse 才能使用
HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response;
3、destroy()
销毁过滤器
Filter生命周期(饿汉单例) :
创建 初始化 服务 销毁
应用
- 字符集处理
- 用户访问权限判断
- 积分下载资源
- 水印处理
- “和谐词语”修改替换
- 缓存处理
- 自动登录案例
字符集处理实例:
package com.xxxx.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class CharsetFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init......");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//转型
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//设置编码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//放行
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
System.out.println("destroy......");
}
}
注意:
@WebFilter("/*") 表示为所有java类都可以进行过滤,
需要指定某些时可以直接加后缀,如@WebFilter(".do") @WebFilter(".action")
监听器Listener
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行
监听原理
1、存在事件源
2、提供监听器
3、为事件源注册监听器
4、操作事件源,产生事件对象,将事件对象传递给监听器,并且执行监听器相应监听方法
JAVAweb 提供了八大监听器,给Web应用增加事件处理机制,以便更好地监视和控制Web应用的状态变化,从而在后台调用相应处理程序,其主要控制application session request对象的发生的特定事件
JAVAweb八大监听器
监听事件都要实现监听接口
监听对象 | 实现监听接口 | 监听事件 |
---|---|---|
ServletRequest | ServletRequestListener | ServletRequestEvent |
ServletRequestAttributeListener | ServletRequestAttributeEvent | |
HttpSession | HttpSessionListener | HttpSessionEvent |
HttpSessionActivationListener | ||
HttpSessionAttributeListener | HttpSessionBindingEvent | |
HttpSessionBindingListener | ||
ServletContext | ServletContextListener | ServletContextEvent |
ServletContextAttributeListener | ServletContextAttributeEvent |
生命周期及作用
ServletRequest
创建:启动服务器时创建
销毁:关闭服务器或者从服务器移除项目
作用:利用ServletContextListener
监听器在创建ServletContext
域对象时完成一些想要初始化的工作或者执行自定义任务调度
HttpSession
创建:访问服务器任何资源都会发送请求(ServletRequest)出现,访问.html和.jsp和.servlet都会创建请求
销毁:服务器已经对该次请求做出了响应
作用:每一个会话只能访问当前会话作用域,在线多人登录
ServletContext
创建:只要调用了getSession()方法就会创建,一次会话只会创建一次
销毁:1.超时(默认为30分钟) 2.非正常关闭,销毁 3.正常关闭服务器(序列化)
作用:每位用户登录网站时都会创建一个HTTPSession
对象,利用这个统计在线人数
简单实现监听 ServletContext
只要服务器开启就执行 contextInitialized() 方法
服务器销毁就执行 contextDestroyed() 方法
HttpSession和ServletContext同理
package com.xxxx.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ServletListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContextListener创建。。。");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContextListener销毁。。。");
}
}