Response&ServletContext
一 Response【重点】
1.1 概述
-
response对象表示web服务器给浏览器返回的响应信息
-
作用:开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息
注意: tomcat在响应会有一些默认的设置, 开发人员在servlet中的设置会覆盖tomcat的设置
ServletResponse 接口 (理论上兼容大部分协议)
|
HttpServletResponse 接口 (专门指的是http协议的响应)
|
org.apache.catalina.connector.ResponseFacade 实现类(由tomcat提供的)
HTTP响应报文
1.2 设置Http响应行
* 格式
协议/版本号 状态码(status code)
* 例如
HTTP/1.1 200
* API
1. 设置状态码
void setStatus(int sc)
2. 常见响应状态码:
200:请求和响应都OK(顺利)
302:重定向
304:浏览器从缓存中加载数据
404:请求的路径错误或请求的资源不存在(自己开发的时候,路径有问题)
405: 在HttpServlet的子类中, doGet或doPost方法没有重写
500:服务器内部异常
3. 注意事项:上述常见的响应状态码,通常是由tomcat服务器自动响应给浏览器。我们一般是不需要手动设置的;
浏览器缓存(304)**
1.3 设置Http响应头
* 格式
响应头名称:响应头的值
* 例如
Content-Length : 5 (指的是响应体内容长度5个字符)
* API
1. 设置指定头名称和对应的值
void setHeader(String name, String value)
2. value值可以由多个参数组成,不同参数之间使用分号隔开:
response.setHeader(key,"value1;value2");
3. 常用响应头:
refresh:定时刷新;
content-type:设置响应数据的数据类型和编码格式;
location:配合302响应状态码完成重定向;
content-disposition:通知浏览器以附件的形式解析响应的数据;
1.4 设置Http响应体
响应体中包含 响应数据的正文
响应是服务器给浏览器发送数据: 输出流
* API(输出流对象)
1. 字符输出流 : 用于向浏览器输出字符数据(文本)
PrintWriter getWriter()
2. 字节输出流 : 用于向浏览器输出二进制数据(比如文件下载)
ServletOutputStream getOutputStream()
注意:在同一个servlet中,二种类型的输出流不能同时存在,互斥
/*
* 响应体中包含 响应数据的正文
响应是服务器给浏览器发送数据: 输出流
* API(输出流对象)
1. 字符输出流 : 用于向浏览器输出字符数据(文本)
PrintWriter getWriter()
2. 字节输出流 : 用于向浏览器输出二进制数据(比如文件下载)
ServletOutputStream getOutputStream()
注意:在同一个servlet中,二种类型的输出流不能同时存在,互斥
* */
@WebServlet("/ResponseServlet01")
public class ResponseServlet01 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. 打印字符流: 响应体出现网页上的(字符流的底层也是字节流)
// PrintWriter writer = response.getWriter();
// writer.print("hello world");
// response.getWriter().print("hello world"); //链式编程
//2. 字节输出流 (输出文件的数据)
ServletOutputStream os = response.getOutputStream();
String str = "hello world2";
byte[] bytes = str.getBytes();
os.write(bytes);
}
}
二. 响应头的功能【重点】
2.1 响应定时刷新(refresh)
需求
在当前页面停留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);
}
/*
# 响应: 服务器发送给浏览器的数据!!!
* API
1. 设置指定头名称和对应的值
void setHeader(String name, String value)
2. value值可以由多个参数组成,不同参数之间使用分号隔开:
response.setHeader(key,"value1;value2");
3. 常用响应头:
refresh:定时刷新;
response.setHeader("refresh","time;url"); -> time秒之后跳转到url
*
* */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应头 refresh -> 定时刷新页面
// 服务器通过这个响应头 告诉浏览器 : 你5秒之后,自己访问百度
response.setHeader("refresh","5;http://www.baidu.com");
response.setContentType("text/html;charset=utf-8");//防止中文乱码(待会)
response.getWriter().print("支付成功,等待5秒跳转到订单页面"); // 响应体: 出现在网页上
}
2.2 响应体中文乱码(content-type)
需求
向页面输出中文数据没有乱码
原因分析
1. 通过response获取字符输出流
PrintWriter pw = response.getWriter();
2. 通过字符输出输出中文字符
pw.write("中文....");
3. 浏览器访问,网页出现中文乱码
4. 原因: tomcat默认使用ISO-8859-1编码, 然后也让浏览器用ISO-8859-1解码
而ISO-8859-1不支持中文,所以出现乱码
5. 解决 : 统一浏览器和服务器编码(utf-8)
response.setContentType("text/html;charset=utf-8");
解决中文乱码
统一浏览器和服务器编码
response.setCharacterEncoding("utf-8"); // 简要写法
response.setHeader("content-type","text/html;charset=utf-8"); //完整写法
response.setContentType("text/html;charset=utf-8"); //推荐!!!!`
@WebServlet("/ContentTypeServlet")
public class ContentTypeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
/*
* 1. 问题: 响应体中文乱码
* 2. 原因: tomcat默认使用ISO-8859-1编码(欧码, 拉丁文, 不支持中文)
* 服务端编码 : iso
* 浏览器解码 : iso
*
* 3. 分析(响应头: 内容类型 )
* Content-Type: text/html;charset=ISO-8859-1
* value1;value2
*
* value2的意思是: 服务器跟浏览器约定 编解码使用字符集 ISO
* (chrome现在是无法查看网页使用的编码,淘汰了, IE可以)
*
* 4. 解决
* 1. response.setHeader("content-type","text/html;charset=utf-8");
* 服务器跟浏览器约定 编解码使用字符集 utf-8 (支持中文)
*
* 2. response.setContentType("text/html;charset=utf-8"); -> 掌握
*
* 3. response.setCharacterEncoding("utf-8"); -> 知道即可
*
* 5. 补充: value1解释(mime 类型)
* windows的文件类型(后缀名): txt html json jsp exe zip
* 网络传输的文件类型(MIME): text/plain text/html application/json
* MIME格式: 大类型/小类型
*
* 作用: 服务器告知浏览器, 响应体数据以何种类型的语法去解析
* */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//响应体正文
// response.getWriter().print("hello world");
//如果这一行,不写, 是看不到这个响应头 , 是因为如果servlet中不设置这个头,tomcat默认设置是看不到的
// Content-Type: text/html;charset=ISO-8859-1
response.setHeader("content-type","text/html");
//解决
// response.setHeader("content-type","text/html;charset=utf-8");
//简易 (掌握!!!)
response.setContentType("text/plain;charset=utf-8");
//修改content-type头中的charset的值, 这个不推荐
// response.setCharacterEncoding("utf-8");
response.getWriter().print("<h1>你好,世界</h1>");
}
}
2.3 响应重定向(location+302)
需求
用户访问AServlet后,服务器告诉浏览器重定向到BServlet
步骤分析
* 方式一
// 1.设置状态码
response.setStatus(302);
// 2.设置响应头 Location
response.setHeader("Location","重定向网络地址");
* 方式二
// 1.response这哥们封装专门处理重定向的方法 (掌握)
response.sendRedirect("重定向网络地址");
重定向特点
1. 发起两次请求
2. 地址栏的url被修改了(指向最后访问的地址)
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("我说: loser,我没有经验,让他找赵老师");
//重定向(302 + location)
//表示重定向
// response.setStatus(302);
//重定向的地址
// response.setHeader("location","/day10-response/BServlet");
// response.setHeader("location","http://www.baidu.com");
//简化api (302+location)
response.sendRedirect("/day10-response/BServlet");
}
}
@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("赵老师说: 我很有经验,首先得这样,然后再这样...");
//避免响应体中文乱码
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("恋爱大法");
}
转发与重定向的区别
1. 哪个对象
转发(request对象的方法)
request.getRequestDispatcher("/bServlet").forward(request,response);
地址栏: 没有改变 -> AServlet
浏览器: 发了一次请求(可以通过request域对象共享数据)
服务器: 只有一对请求和响应对象 (Aservlet Bservlet的请求和响应和A传给他的)
发生的位置: 服务器内部,无法访问服务器外部资源
重定向(response对象的方法)
response.sendRedirect("/day10_response/bServlet");
地址栏: 发生了改变 -> BServlet
浏览器: 发了两次请求(不可以通过request域对象共享数据)
服务器: 有两对请求和响应对象
发生的位置: 浏览器行为, 可以访问服务器外部资源
2. 几次请求
转发 : 1次
重定向: 起码2次
3. 小结
写法
转发("/servlet资源路径") 服务器内部行为
重定向 ("/虚拟路径(项目名)/servlet资源路径") 浏览器外部行为
使用场景(重点掌握)
如果需要传递数据(request域),使用请求转发
如果不需要传递数据(request域),使用重定向
三 ServletContext
3.1 概述
- web容器(tomcat)在启动时,它会为每个web项目承建一个对应的ServletContext对象(唯一)
- 它代表:当前web项目
主要作用
-
域对象(共享数据)
javaweb四大域对象: 有作用范围,并可在作用范围中共享数据的对象(有点像Map) 1. 域对象方法api对一样 : setAttribute(name,value) value = getAttribute(name) removeAttribute(name) 2. 作用范围不一样 pageContext < request < session < ServletContext 3. 获取域对象规律: 小域对象可以获取大域对象
-
获取一些应用全局的数据
1). 获取全局的配置参数
2).获取项目中资源的真实路径
3).获取资源的MIME类型
获取ServletContext对象
1. 通过request对象获得
ServletContext sc = request.getServletContext();
2. 继承HttpServlet后,可以直接调用
ServletContext sc = getServletContext();
3.2 域对象(共享数据)
在当前整个服务器应用范围内,共享数据
-
生命周期
1. 何时创建? 项目加载时,创建唯一的一个ServletContext对象(全局唯一) 2. 何时销毁? 项目卸载时,销毁 3. 作用范围? 与项目共存亡(多个servlet和多次请求都可以操作它)
-
API方法
1. 存储数据 void setAttribute(String name,Object value) 2. 获取数据 Object getAttribute(String name) 3. 删除数据 void removeAttribute(String name)
@WebServlet("/ContextServlet01")
public class ContextServlet01 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 context = this.getServletContext();//当前方法就在Servlet内部,this表示当前Servlet对象
ServletContext context = getServletContext();// this是可以省略的
ServletContext context2 = request.getServletContext();
System.out.println("context:" + context);
System.out.println("context2:" + context2);
//域对象设置数据
context.setAttribute("user","jack");
}
}
@WebServlet("/ContextServlet02")
public class ContextServlet02 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 context3 = request.getServletContext();
System.out.println("context3:" + context3);
//域对象获取数据
Object user = context3.getAttribute("user");
System.out.println(user);
}
}
3.3 域对象案例:统计网站的访问次数
需求
一般个人博客的首页,都会显示你是第几位访问此网站…
/*
* 案例: 记录本网站访问次数的
* */
// loadOnStartup 服务器启动时创建本Servlet并调用init方法
@WebServlet(value = "/ContextServlet03",loadOnStartup = 4)
public class ContextServlet03 extends HttpServlet {
// 只执行一次
@Override
public void init() throws ServletException {
//初始化工作
ServletContext context = getServletContext();
context.setAttribute("count",0);
}
//相当于service方法: 浏览器每访问一次,就执行一次
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 访问次数+1
ServletContext context = getServletContext();
Integer count = (Integer) context.getAttribute("count");
count++; // Integer自动拆箱, 在计算时变成int
context.setAttribute("count",count);
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("<h1>欢迎来到我的qq空间</h1>");
response.getWriter().print("<div>第"+count+"次访问</div>");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
3.4 获取全局的配置参数(了解)
- 读取web.xml配置文件中标签信息,实现参数和代码的解耦(该项目中所有的servlet都可以获取)
获取web.xml中的初始化参数 getInitParameter(“encode”);
<?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">
<!--
web.xml配置全局参数(项目中任意Servlet都可以获取)
-->
<context-param>
<param-name>encode</param-name>
<param-value>gbk</param-value>
</context-param>
</web-app>
/*
* 参数放在配置文件, 然后在代码中获取配置文件中的参数
* (解耦)
* */
@WebServlet("/ContextServlet04")
public class ContextServlet04 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 context = request.getServletContext();
//获取web.xml中配置的全局参数
String encode = context.getInitParameter("encode");
System.out.println(encode);//gbk
}
}
3.5 获取资源在服务器的真实地址
可以实现web项目的移植性…动态获取文件真实路径
- API
String getRealPath(String path);
/*
* E:\myword\web0414\day10-response路径(源码):
* 1. src: java源码
* 2. web
* 1. html , css , js, img等静态资源
* 2. 特殊 web-inf : 浏览器不能直接访问
* a. web.xml 工程配置文件
* b. lib目录(jar: .class文件压缩包)
* c. classes
*
* 当我们在idea中启动项目的时候, idea会自动编译我们的项目
* project/out 存放项目编译文件(主要 .class)
* 编译规则:
* 1. 静态资源无需编译
* 2. .java -> .class
*
* out\artifacts\day10_response_war_exploded路径下(真实运行路径)
* 1. resource
* 2. web-inf(浏览器不能直接访问,安全)
* a. web.xml
* b. classes (存放字节码)
* c. lib(jar: 字节码)
*
* */
@WebServlet("/ContextServlet05")
public class ContextServlet05 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 {
//文件下载的功能
// 不应该直接从源码路径获取(E:\mywork\web0414\day10-response\web\ resource\1.zip)
// 应该从真实路径去获取 (E:\mywork\web0414\out\artifacts\day10_response_war_exploded resource\1.zip)
// 绝对路径: 在windows上从盘符开始(linux没有盘符) -> 开发中不用
// 相对路径: 相对它而言 E:\mywork\web0414\out\artifacts\day10_response_war_exploded (部署在不同的系统中,会动态变化)
ServletContext context = getServletContext();
//以相对路径的形式 去获取 真实路径 (复用性,项目部署在哪里都可以获取真实路径下的文件)
// 相对 E:\mywork\web0414\out\artifacts\day10_response_war_exploded
String realPath = context.getRealPath("resource/1.zip");
System.out.println(realPath);
// 获取资源的MIME类型
String mimeType = context.getMimeType("resource/3.txt");
System.out.println(mimeType); // txt -> text/plain html->text/html
}
}
3.6 获取资源的MIME类型
- 在互联网通信过程中定义的一种文件数据类型
- 格式:
大类型/小类型
例如:text/html -> html text/plain-> txt
三 综合案例
3.1 文件下载
需求
用户点击页面的链接,浏览器开始下载文件。
3.1.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="resource/1.zip">1.zip</a> <br>
<a href="resource/2.exe">2.exe</a> <br>
<a href="resource/3.txt">3.txt</a> <br>
<a href="resource/4.jpg">4.jpg</a> <br>
<h5>servlet下载</h5>
</body>
</html>
③ 缺点
- 完全是浏览器的行为, 浏览器对不可识别的文件进行下载 , 可识别的文件是直接打开而不是下载
- 资源直接对外暴露, 我们无法对资源下载进行限制(比如需要会员才能下载)
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>Title</title>
</head>
<body>
<h3> 浏览器下载</h3>
<!-- 让href直接指向静态资源位置 -->
<a href="resource/1.zip">1.zip</a> <br>
<a href="resource/2.exe">2.exe</a> <br>
<a href="resource/3.txt">3.txt</a> <br>
<a href="resource/4.jpg">4.jpg</a> <br>
<h3> 代码下载</h3>
<!-- 让href指向设置下载的Servlet
1. 只要看不到请求方式,默认为get请求
2. get请求的请求参数拼接url中
url?name=value&name=value
-->
<a href="/day10-response/DownLoadServlet?filename=1.zip">1.zip</a> <br>
<a href="/day10-response/DownLoadServlet?filename=2.exe">2.exe</a> <br>
<a href="/day10-response/DownLoadServlet?filename=3.txt">3.txt</a> <br>
<a href="/day10-response/DownLoadServlet?filename=4.jpg">4.jpg</a> <br>
<a href="/day10-response/DownLoadServlet?filename=葵花宝典.zip">葵花宝典.zip</a> <br>
</body>
</html>
② DownLoadServlet
package com.itheima06.example;
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;
@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 {
//获取请求参数: 知道浏览器要下载哪个文件
String filename = request.getParameter("filename"); //1.zip
System.out.println("要下载的文件是:" + filename);
//两个头
//1. 指定浏览器要下载文件,文件名为 x1.zip
/*
文件名如果是中文,那么会乱码,
google浏览器默认要使用url编码,火狐是base64编码
1. 判断用户是何种浏览器 -> 请求头User-Agent
2. 修改编码
*/
String newName = DownLoadUtils.getName(request, filename);
response.setHeader("content-disposition","attachment;filename=x" + newName);//x1.zip
//2. 告诉浏览器文件的mime类型(现在浏览器可以自动识别,这行可以不写)
//ServletContext可以根据文件后缀名 -> mime类型
String mimeType = getServletContext().getMimeType(filename);
response.setContentType(mimeType);
//两个流: 先读本地文件,后写出到响应体
String realPath = getServletContext().getRealPath("resource/" + filename);
FileInputStream is = new FileInputStream(realPath);
ServletOutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int length;
while((length = is.read(buffer)) != -1){
os.write(buffer,0,length);
}
is.close();
}
}
③ 中文乱码
* 如果该下载文件名是中文的话,会出现乱码...
谷歌和绝大多数的浏览器是通过 url编码
URLEncode() 编码
URLDecode() 解码
火狐浏览器 base64编码
* 我们就需要考虑浏览器兼容性问题....
资料提供了判断浏览器不同编码的工具类直接使用即可....
public class DownLoadUtils {
public static String getName(HttpServletRequest request, String filename) throws UnsupportedEncodingException {
// 获得请求头中的User-Agent
String agent = request.getHeader("User-Agent");
// 根据不同的客户端进行不同的编码
String filenameEncoder = "";
if (agent.contains("Firefox")) {
// 火狐浏览器
System.out.println("我是火狐");
BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
System.out.println("我是google");
filenameEncoder = URLEncoder.encode(filename, "utf-8");
}
return filenameEncoder;
}
}
3.2 点击切换验证码(了解)
需求
在页面展示登录验证码,点击此验证码可以更换新的验证码
作用:防止表单的恶意提交
本质上:就是一张随机图片
如何通过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属性 : 可以设置远程连接/本地连接
CheckcodeServlet : 生成一张验证码图片,并响应这张图片字节流
验证码的生成: java代码编写的(GUI技术: java中绘制界面的技术,被淘汰)
-->
验证码: <img src="/day10-response/CheckcodeServlet" id="img">
<script>
/*
* 点击切换验证码:
* 1. 事件驱动: 图片点击事件
* 2. 如果浏览器检测到网页中的标签或属性发生变化,会自动刷新(回顾轮播图)
*
* 3. 解决方式是: 通过给url设置一个无意义的时间参数,欺骗浏览器更新
* */
document.getElementById("img").onclick = function () {
//this就是img标签
let time = new Date().getTime()
this.src = "/day10-response/CheckcodeServlet?time=" + time
}
</script>
idea使用技巧
1. javaee工程调试技巧
新增Servlet,修改web.xml 配置 或 注解配置 -> 重启tomcat (点stop, 再点debug运行)
修改已有的类, 和新增html -> 直接部署即可(点绿色箭头)