回顾
1. request作用
开发人员可以通过request对象,获取http协议请求消息
2. request获取Http请求信息
请求行
1.请求方式:getMethod()
2.虚拟路径:getContextPath()
请求头
getHeader(String name); -- 不区分大小写
referer:防盗链
user-agent:浏览器兼容性
请求参数(体)
String getParameter(String name);
String[] getParameterValues(String name);
Map getParameterMap(); 结合BeanUtils实现参数快速封装...
3. 请求转发
服务器内部资源的一种跳转方式
4. 域对象(共享数据)
何时创建?
用户发送请求
何时销毁?
服务器做出响应
作用范围?
一次请求,多次转发
5. 案例:用户登录
接收请求参数
请求转发
域对象
ServletContext&Response
今日目标
1. ServletContext:应用上下文对象
2. response【重点】
3. 综合案例
一 ServletContext
1.1 概述
- web容器(tomcat)在启动时,它会为每个web项目承建一个对应的ServletContext对象
- 它代表:当前web项目
主要作用
- 域对象(共享数据)
- 获取资源在服务器的真实地址
- 获取全局的配置参数
- 获取文件MIME类型
获取ServletContext对象
1. 通过request对象获得
ServletContext sc = request.getServletContext();
2. 继承HttpServlet后,可以直接调用
ServletContext sc = getServletContext();
1.2 域对象(共享数据)
- 在当前项目范围内,共享数据(多个servlet都可以获取)
1. 存储数据
void setAttribute(String name,Object value)
2. 获取数据
Object getAttribute(String name)
3. 删除数据
void removeAttribute(String name)
@WebServlet("/OneServlet")
public class OneServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 向servletContext域存数据....
ServletContext sc1 = request.getServletContext();
ServletContext sc2 = getServletContext();
sc1.setAttribute("user", "jack");
System.out.println("OneServlet存了数据。。。");
}
}
@WebServlet("/TwoServlet")
public class TwoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从servletContext域获取数据
String user = (String) request.getServletContext().getAttribute("user");
System.out.println("TwoServlet获取数据:"+user);
}
}
生命周期
1. 何时创建?
项目加载时,创建
2. 何时销毁?
项目卸载时,销毁
3. 作用范围?
与项目共存亡(多个servlet都可以操作它)
1.3 获取资源在服务器的真实地址
- 可以实现web项目的移植性...动态获取文件真实路径
* API
String getRealPath(String path);
@WebServlet("/RealpathServlet")
public class RealpathServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取car.jpg 文件真实路径
String carPath = request.getServletContext().getRealPath("/img/car.jpg");
System.out.println(carPath);
// 获取web.xml 文件真实路径
String webPath = request.getServletContext().getRealPath("/WEB-INF/web.xml");
System.out.println(webPath);
}
}
1.4 获取全局的配置参数
- 读取web.xml配置文件中<context-param>标签信息,实现参数和代码的解耦(多个servlet都可以获取)
<?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_3_1.xsd"
version="3.1">
<!--全局配置参数:所有的servlet都可以读取...-->
<context-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</context-param>
</web-app>
@WebServlet("/ContextPathServlet")
public class ContextPathServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取全局参数
String value = request.getServletContext().getInitParameter("encode");
System.out.println("全局配置参数:"+value);
}
}
1.5 获取文件MIME类型
- 在互联网通信过程中定义的一种文件数据类型
- 格式:
大类型/小类型
例如:text/html image/jpeg
<a href="/day10_servletContext/MimeServlet?filename=luola.avi">获取文件的mime类型</a><br>
@WebServlet("/MimeServlet")
public class MimeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取指定文件的mime类型
// 获取请求参数
String filename = request.getParameter("filename");
// 获取文件的mime类型
String mimeType = request.getServletContext().getMimeType(filename);
response.getWriter().write(filename + "---" + mimeType);
}
}
1.6 案例:统计网站的访问次数
需求
一般个人博客的首页,都会显示你是第几位访问此网站...
@WebServlet(value = "/CountServlet", loadOnStartup = 4) // 服务器启动时,创建此servlet对象
public class CountServlet extends HttpServlet {
@Override
public void init() throws ServletException {
getServletContext().setAttribute("count", 0);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置response响应编码
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("<h1>itcast博客网站</h1>");
// 用户每次访问,从域中取出,加1,再存进去
ServletContext servletContext = request.getServletContext();
// 从域中取出
Integer count = (Integer) servletContext.getAttribute("count");
// 加1
count++;
// 再存进去
servletContext.setAttribute("count", count);
response.getWriter().write("<div>你是,第" + count + "位访问此网站...</div>");
}
}
二 Response【重点】
2.1 概述
- response对象表示web服务器给浏览器返回的响应信息
- 作用:开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息
Response体系结构
ServletResponse 接口
|
HttpServletResponse 接口
|
org.apache.catalina.connector.ResponseFacade 实现类(由tomcat提供的)
2.2 设置Http响应消息
响应行
* 格式
协议/版本号 状态码
* 例如
HTTP/1.1 200
* API
1. 设置状态码
void setStatus(int sc)
响应头
* 格式
响应头名称:响应头的值
* 例如
Location:http://www.itcast.cn
* API
1. 设置指定头名称和对应的值
void setHeader(String name, String value)
响应体【重点】
* API(输出流对象)
1. 字符输出流
PrintWriter getWriter()
2. 字节输出流
ServletOutputStream getOutputStream()
注意:在同一个servlet中,二种类型的输出流不能同时存在,互斥
2.3 响应重定向
需求
用户访问AServlet后,服务器告诉浏览器重定向到BServlet
步骤分析
* 方式一
// 1.设置状态码
response.setStatus(302);
// 2.设置响应头 Location
response.setHeader("Location","重定向网络地址");
* 方式二
// 1.response这哥们封装专门处理重定向的方法
response.sendRedirect("重定向网络地址");
重定向特点
1. 地址栏会发生改变
2. 重定向是二次请求
3. 重定向是客户端(浏览器)行为,可以跳转到服务器外部资源...
4. 不能使用request域共享数据
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("AServlet执行了....");
/* // 1.设置状态码
response.setStatus(302);
// 2.设置响应头 Location
response.setHeader("Location","/day10_response/BServlet");*/
// 1.response这哥们封装专门处理重定向的方法
response.sendRedirect("http://www.itcast.cn");
}
}
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("BServlet执行了....");
}
}
转发与重定向的区别
1. 哪个对象
转发(request对象的方法)
request.getRequestDispatcher("/bServlet").forward(request,response);
重定向(response对象的方法)
response.sendRedirect("/day10_response/bServlet");
2. 几次请求
转发
地址栏: 没有改变
浏览器: 发了一次请求
服务器: 只有一对请求和响应对象
发生的位置: 服务器
重定向
地址栏: 发生了改变
浏览器: 发了两次请求
服务器: 有两对请求和响应对象
发生的位置: 浏览器
3. 小结
写法
转发("/servlet资源路径") 服务器内部行为
重定向 ("/虚拟路径(项目名)/servlet资源路径") 浏览器外部行为
使用场景(重点掌握)
如果需要传递数据(request域),使用转发
如果不需要传递数据(request域),使用重定向
2.4 响应定时刷新
需求
在当前页面停留3秒钟之后,跳转到传智播客首页
步骤分析
1. 通过response设置响应头 Refresh
response.setHeader("Refresh","间隔时间(秒);跳转页面");
@WebServlet("/RefreshServlet")
public class RefreshServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 通过response设置响应头 Refresh
response.setHeader("Refresh", "3;http://www.itcast.cn");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("操作成功,3秒后跳转到传智首页...");
}
}
2.5 响应中文【重中之重】
需求
向页面输出中文数据没有乱码
步骤分析
1. 通过response获取字符输出流
PrintWriter pw = response.getWriter();
2. 通过字符输出输出文本
pw.write("中文....");
解决中文乱码
1. 指定服务器响应编码方式
response.setCharacterEncoding("GBK");
2. 统一浏览器和服务器编码
response.setContentType("text/html;charset=utf-8");
@WebServlet("/EncodeServlet")
public class EncodeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 指定服务器响应编码方式
// response.setCharacterEncoding("UTF-8");
// 统一浏览器和服务器编码
response.setContentType("text/html;charset=utf-8");
// 1. 通过response获取字符输出流
PrintWriter pw = response.getWriter();
// 2. 通过字符输出输出文本
pw.write("中文....");
}
}
三 综合案例【作业】
3.1 点击切换验证码
需求
在页面展示登录验证码,点击此验证码可以更换新的验证码
作用:防止表单的恶意提交
本质上:就是一张随机图片
如何通过java代码制作一个验证码
在今天的资料中,准备了验证码制作Servlet工具类
/*
跟我一起了解一下验证码的制作代码....
*/
@WebServlet("/CheckcodeServlet")
public class CheckcodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建画布
int width = 120;
int height = 40;
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获得画笔
Graphics g = bufferedImage.getGraphics();
// 填充背景颜色
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 绘制边框
g.setColor(Color.red);
g.drawRect(0, 0, width - 1, height - 1);
// 生成随机字符
// 准备数据
String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
// 准备随机对象
Random r = new Random();
// 声明一个变量 保存验证码
String code = "";
// 书写4个随机字符
for (int i = 0; i < 4; i++) {
// 设置字体
g.setFont(new Font("宋体", Font.BOLD, 28));
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
String str = data.charAt(r.nextInt(data.length())) + "";
g.drawString(str, 10 + i * 28, 30);
// 将新的字符 保存到验证码中
code = code + str;
}
// 绘制干扰线
for (int i = 0; i < 6; i++) {
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
}
// 将验证码 打印到控制台
System.out.println(code);
// 将验证码放到session中
request.getSession().setAttribute("code_session", code);
// 将画布显示在浏览器中
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
<img src="/day10_response/CheckcodeServlet" alt="servlet随机验证码" id="img1"> <br>
<script>
// 给图片绑定一个点击事件
document.getElementById('img1').onclick=function () {
// 重置src路径,重写发送请求
this.src='/day10_response/CheckcodeServlet?'+new Date().getTime(); // 后面加一个毫秒值的时间戳,欺骗浏览器
}
</script>
3.2 文件下载
需求
用户点击页面的链接,浏览器开始下载文件。
3.2.1 使用链接下载文件
① 将资料中的下载素材复制到web项目中
② 编写下载页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>donload.html</title>
</head>
<body>
<h3>文件下载</h3>
<h5>超链接下载</h5>
<a href="/day10_response/download/demo.docx">word文档</a><br>
<a href="/day10_response/download/car.jpg">图片下载</a><br>
<a href="/day10_response/download/test.zip">压缩包下载</a><br>
<h5>servlet下载</h5>
</body>
</html>
③ 缺点
- 浏览器可识别的媒体类型,是直接打开而不是下载...
- 不能判断用户是否登录(vip),进行限制
3.2.2 使用Servlet下载文件【推荐....】
- 二个响应头二个字节流
1. 被下载文件的字节输入流
FileInputStream
2. response字节输出流
ServletOutputStream
3. 告知客户端下载文件的MIME类型(最新的浏览器此步骤可以省略....)
Content-Type:MIME类型
4. 告知浏览器以附件的方式保存
Content-Disposition:attachment;filename=文件名
attachment 附件
filename=文件名
需求分析
① download.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>donload.html</title>
</head>
<body>
<h3>文件下载</h3>
<h5>超链接下载</h5>
<a href="/day10_response/download/demo.docx">word文档</a><br>
<a href="/day10_response/download/car.jpg">图片下载</a><br>
<a href="/day10_response/download/test.zip">压缩包下载</a><br>
<h5>servlet下载</h5>
<a href="/day10_response/DownLoadServlet?filename=demo.docx">word文档</a><br>
<a href="/day10_response/DownLoadServlet?filename=girl.jpg">靓女</a><br>
<a href="/day10_response/DownLoadServlet?filename=禽兽.jpg">禽兽</a><br>
</body>
</html>
② DownLoadServlet
@WebServlet("/DownLoadServlet")
public class DownLoadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取请求文件名
String filename = request.getParameter("filename");
// 2.获取文件真实路径,封装到字节输入流
ServletContext servletContext = request.getServletContext();
String realPath = servletContext.getRealPath("/download/" + filename);
FileInputStream in = new FileInputStream(realPath);
// 3.告诉浏览器mime类型
String mimeType = servletContext.getMimeType(filename);
response.setContentType(mimeType);
// 4.告诉浏览器以附件方式保存
// 解决中文乱码和浏览器兼容性
String userAgent = request.getHeader("user-agent");
// 调用工具类处理
filename = DownLoadUtils.getName(userAgent, filename);
response.setHeader("content-disposition", "attachment;filename=" + filename);
// 5.获取字节输出流
ServletOutputStream out = response.getOutputStream();
// 6.io流的拷贝
byte[] b = new byte[4096];// 4kb
int len = -1;
while((len = in.read(b))!=-1){
out.write(b, 0, len);
}
// 7.释放资源
out.close(); // out流对象,可以交给tomcat关闭
in.close();
}
}
③ 中文乱码
* 如果该下载文件名是中文的话,会出现乱码...
谷歌和绝大多数的浏览器是通过 url编码
URLEncode() 编码
URLDecode() 解码
火狐浏览器 base64编码
* 我们就需要考虑浏览器兼容性问题....
今天帅哥提供了判断浏览器不同编码的工具类直接使用即可....
④ hutool工具包.....
- 这哥们封装了se阶段的很多基础操作.....
老师已经帮助大家下载了....
老师下午总结
疑惑点
-
找资源文件的方式
-
如果我们查找web目录下的资源,我们使用ServletContext去查找。
package com.itheima.response; 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.FileInputStream; import java.io.IOException; import java.io.InputStream; @WebServlet("/demo1") public class Demo1Servlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 找到目标文件(如果是web目录下的资源,我们都使用ServletContext去查找) // getRealPath("/") 获取资源的绝对路径 //getResourceAsStream("/路径") 返回资源的输入流 InputStream inputStream = request.getServletContext().getResourceAsStream("/img/5.jpg"); //2. 获取response的输出流 ServletOutputStream outputStream = response.getOutputStream(); //3. 边读取目标文件的数据,边输出 byte[] buf = new byte[1024]; int length = 0 ; while((length = inputStream.read(buf))!=-1){ outputStream.write(buf,0,length); } inputStream.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
-
- **如果我们查找是src下面的内容,我们使用类路径去查找。**
```java
package com.itheima.response;
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;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Properties;
@WebServlet("/demo2")
public class Demo2Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//如果需要读取src下面的内容,我们使用类路径
//注意:如果需要使用类路径,一定要使用Class对象的getResourceAsStream的方法。
//类路径: 查找类路径
InputStream inputStream = Demo2Servlet.class.getResourceAsStream("/db.properties");//这个/则代表了classes目录
//加载到ProPerties中
Properties properties = new Properties();
properties.load(inputStream);
//输出到浏览器
PrintWriter out = response.getWriter();
out.write("用户名:"+ properties.getProperty("username")+"<br/>");
out.write("密码:"+ properties.getProperty("password"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
```
-
请求转发与请求重定向的区别
回顾请求转发原理图
package com.itheima.forward; 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; //往request域中存储数据 @WebServlet("/demo3") public class Demo3Servlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //往request域中存储数据 request.setAttribute("name","gouwa"); //请求转发到Demo4 request.getRequestDispatcher("/demo4").forward(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } } package com.itheima.forward; 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; //从request域中获取数据 @WebServlet("/demo4") public class Demo4Servlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //解决向浏览器输出中文乱码问题 response.setContentType("text/html;charset=utf-8"); //从request域中取出数据 String name = (String) request.getAttribute("name"); //向浏览器输出 response.getWriter().write("从request域中获取到的数据:"+ name); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
请求重定向原理图
请求转发与请求重定向的区别:
-
请求转发的时候浏览器地址栏不变化的,请求重定向浏览器地址栏是变化的。
-
请求转发浏览器发出一次请求,请求重定向浏览器发出了两次请求。
"/"在进行资源跳转的时候,
- 如果是给服务器去使用那么“/”代表了 http://localhost:8080/项目根路径
- 如果/是给浏览器去使用的时候,那么“/”代表了 http://localhost:8080/
今日重点
-
ServletContext对象
-
ServletContext作为域对象
- setAttribute()
- getAttribute()
- removeAttribute()
-
ServletContext获取当前模块的web目录下的资源(非常重要)
- getRealPath
- getResourceAsStream()
-
-
Response对象
- 向浏览器输出
- getOutputSteam() 获取输出字节流
- getWrite() 获取输出字符流
- 向浏览器输出中文数据并且解决乱码问题
- response.setcontentType("text/html';charset=utf-8")
- 请求重定向
- response.sendRedirect()
- 文件下载请求头
-
response.setHeader(“content-disposition”,"attachement;filename=文件名")
servletContext&response.png
-
网友评论