Appearance
ServletContext
ServletContext
ServletContext是什么
java
Servlet用于与Web容器(Tomcat)通信的一组方法、每个Web应用都有一个上下文,有且只有一个
ServletContext的获取方式
GenericServlet.getServletContext()
texthis为GenericServlet的派生类
request.getServletContext()
javathis.getServletContext(); getServletContext();// 推荐使用方式 request.getServletContext();
ServletContext的作用
获得Web应用资源下的文件路径【重点】
相关API
String getRealPath(String path)
获取真实路径
如果 path 当中的文件,不存在的话,还是会返回
InputStream getResourceAsStream(String path)
从资源当中获取一个输入流
如果 path 当中的文件,不存在的话,返回值是 null
案例
- 利用 getRealPath 及 getResourceAsStream,改进文件下载 Servlet
实现
- index.html
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Servlet Download</h2>
<a href="download_sample?filename=file.txt">file.txt</a><br>
<a href="download_sample?filename=file.zip">file.zip</a><br>
<a href="download_sample?filename=搞笑.gif">搞笑.gif</a><br>
</body>
</html>
- DownloadServlet.java
java
package com.futureweaver.web;
import org.apache.commons.io.IOUtils;
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_sample")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取前端发过来的文件名参数
String filename = request.getParameter("filename");
// 告诉浏览器下载文件的文件名
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
// 获取字节输出流
OutputStream out = response.getOutputStream();
// 获取文件的输入流对象
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/" + filename);
System.out.println("Download:");
System.out.println(this.getServletContext().getRealPath("/WEB-INF/" + filename));
System.out.println();
// 利用IOUtils进行读取、写入
IOUtils.copy(in, out);
// 关闭流对象
in.close();
out.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
下载中文文件错误解决
java
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中文", "utf-8") + ".gif");
小结
String getRealPath(String path)
获取文件的绝对路径
获取真实路径
坑:只是单纯的字符串拼接,不做"文件是否存在"的检查
InputStream getResourceAsStream(String path)
获取资源作为流(输入流)
坑: 如果文件路径不正确的话,返回的是null
获得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">
<!-- 设置参数 -->
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>pwd</param-value>
</context-param>
</web-app>
相关API
String getInitParameter(String name)
Enumeration<String> getInitParameterNames()
实现
java
package com.futureweaver.web;
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 = "InitParamServlet")
public class InitParamServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 读取参数
ServletContext servletContext = this.getServletContext();
System.out.println("username: " + servletContext.getInitParameter("username"));
System.out.println("password: " + servletContext.getInitParameter("password"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
小结
设置全局初始化参数
在web.xml,
<context-param>
<param-name>
<param-value>
获取全局初始化参数
String(value) getInitParameter(String name)
【扩展】Servlet获取初始化参数
参数设置
- web.xml
xml
<servlet>
<servlet-name>InitParamServlet</servlet-name>
<servlet-class>com.futureweaver.web.InitParamServlet</servlet-class>
<!-- Servlet初始化参数配置 -->
<init-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</init-param>
<init-param>
<param-name>age</param-name>
<param-value>13</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>InitParamServlet</servlet-name>
<url-pattern>/init_param</url-pattern>
</servlet-mapping>
相关API
String getInitParameter(String name)
Enumeration<String> getInitParameterNames()
实现
- InitParamServlet
java
package com.futureweaver.web;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
// 初始化参数相关的Servlet
public class InitParamServlet implements Servlet {
private ServletConfig config = null;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
config = servletConfig;
String name = servletConfig.getInitParameter("name");
String age = servletConfig.getInitParameter("age");
System.out.println(name);
System.out.println(age);
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("InitParamServlet被调用了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
- InitParamServlet
java
// 初始化参数相关的Servlet
public class InitParamServlet implements HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = getInitParameter("name");
String age = getInitParameter("age");
System.out.println(name);
System.out.println(age);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
【重点】ServletContext是一个域对象
作用范围
Servlet
- 第一次被访问时,由Tomcat创建
- 项目卸载时,由Tomcat销毁
- 创建1次,线程不安全
请求域
- 服务器接收到浏览器的请求时,由Tomcat创建
- 响应结束时,由Tomcat销毁
上下文域
- 项目加载时,由Tomcat创建
- 项目卸载时,由Tomcat销毁
作用范围
- 请求域 一个用户的一次请求
- 上下文域 所有用户的所有请求
相关API
- setAttribute(String key, Object obj)
- Object getAttribute(String key)
- removeAttribute(String key)
案例
- 统计某 Servlet 的访问次数
实现
java
package com.futureweaver.web;
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("/count_sample")
public class CountServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 统计这个Servlet的访问次数
// 把"访问次数"输出到浏览器
// 字符输出流当中有中文,设置编码
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
// 先获取上下文域对象
ServletContext context = getServletContext();
// 规定:"访问次数"的域 对象的名字:accessCount
// 规定:"accessCount"是整型
// 1. 如果第1次访问的,根本就没存,所以需要做判断
Integer accessCount = (Integer) context.getAttribute("accessCount");
if (accessCount == null) {
// 因为一次还要再加1,所以先给一个0
// 因为一会再加1之后,还需要设置回去,也就是调用setAttribute,所以,一起设置
accessCount = 0;
}
// 2. 每一次访问,"访问次数"取出来,加1,再存回去
accessCount ++;
// 3. 要统计的,把"访问次数"找个地方存
// 把这个数据存放的地方,定为服务器内部
// 选择域对象进行存储
// 在请求域和上下文域当中,做出选择
// 请求域:因为请求域使用的是request对象,request对象在每一次受浏览器访问时,都会创建一份新的
// 所以放到请求域当中,永远都是1
// 上下文域:在项目启动时创建,在项目卸载时销毁,有且只有1个
// 既然有且只有1个的话,那么这个数据,就可以放到上下文域当中
context.setAttribute("accessCount", accessCount);
out.write("<h1>此Servlet被访问了" + accessCount + "次</h1>");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
ServletContext与Request域的对比
ServletContext
上下文域
HttpServletRequest
请求域
上下文域,在 Web 应用被 Web 容器加载的时候被创建,在 Web 程序被卸载的时候被销毁。在 Web 应用程序内部有效
请求域 | 上下文域 | |
---|---|---|
创建 | 服务器接收到浏览器的请求时 | 服务器加载时 |
销毁 | 响应结束时 | 服务器卸载时 |
作用范围 | 一个用户的一次请求 | 所有用户的所有请求 |
小结
ServletContext 的获取方式
javagetServletContext(); request.getServletContext();
ServletContext 的作用
获得 Web 应用资源下的文件路径
javaString path = context.getRealPath("download.gif"); InputStream in = new FileInputStream(path); InputStream input = context.getResourceAsStream("download.gif");
获得 Web 应用的全局初始化参数【了解】
设置
xml<context-param> <param-name>name</param-name> <param-value>zhangsan</param-value> </context-param>
获取
context.getInitParameter("name");
ServletContext 是一个域对象【重点】
- setAttribute()
- getAttribute()
- removeAttribute()
ServletContext 的生命周期
作用范围
所有用户的所有请求
案例
需求
在浏览器上展示一张随机生成的验证码图片
技术铺垫
相关类
- java.awt.image.BufferedImage
指定宽、高和图片的类型,创建一个缓存图片对象,用于生成图片
- java.awt.Graphics
画笔对象,用于绘制图形
- setColor(Color c)
设置画笔的颜色
- fillRect(int x, int y, int width, int height)
填充一个矩形区域,指定起始的坐标点,宽度和高度
- setFont(Font font)
设置字符的字体
- drawString(String str, int x, int y)
画一个字符串
- drawLine(int x1, int y1, int x2, int y2)
指定起点和终点画一条线
- java.awt.Color
表示一个颜色类
- java.awt.Font
表示一种字体类
- Font(String name, int style, int size)
- name
字体。
Font.DIALOG
- style
样式: 粗体、斜体。
Font.BOLD
+Font.ITALIC
- size
字号。19
- javax.imageio.ImageIO
用于将缓存的图片输出到浏览器
代码
java
package com.futureweaver.web;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
// 生成验证码图片
@WebServlet("/check_code")
public class CheckCodeServlet extends HttpServlet {
private Random random = new Random();
private Color randomColor() {
// 随机0-255,random.nextInt(256)
int r = random.nextInt(256);
int g = random.nextInt(256);
int b = random.nextInt(256);
return new Color(r, g, b);
}
private BufferedImage generateImg() {
int width = 100;
int height = 30;
// 创建画布
// 参数1: 画布宽度
// 参数2: 画布高度
// 参数3: 画布的配色方案
BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取画笔
Graphics graphics = out.getGraphics();
// 将画笔的颜色设置为白色
graphics.setColor(Color.WHITE);
// 用白色的画笔,刷满整个画布
graphics.fillRect(0, 0, width, height);
// 写随机4位字符
String allstr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
for (int idx = 0; idx < 4; ++idx) {
// 算出一个随机的字符
int randomStrBegin = random.nextInt(allstr.length());
String randomStr = allstr.substring(randomStrBegin, randomStrBegin + 1);
// 设置随机字符的颜色
graphics.setColor(randomColor());
// 设置字体、样式、字号
graphics.setFont(new Font(Font.DIALOG, Font.BOLD + Font.ITALIC, 19));
// 将随机算出的字符,利用画笔画到画布上
// 字号18/19
// 每一个字符的跨度都是20
// 字符的位置是: 10 + idx * 20
graphics.drawString(randomStr, 10 + idx * 20, 20);
}
// TODO: 画8条干扰线
// 干扰线的起始与结束,都应该是随机生成的
graphics.setColor(randomColor());
graphics.drawLine(0, 0, 100, 20);
return out;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletOutputStream out = response.getOutputStream();
// 生成验证码到out
ImageIO.write(generateImg(), "jpg", out);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
学习目标总结
- 能够使用 ServletContext 域对象