笔记来源于 2013 年尚硅谷的视频教程
1. 简易 session 版购物车
操作流程
1.1 在 web 下新建文件夹 cart
新建 step-1.jsp
<%--
Created by IntelliJ IDEA.
User: Admin
Date: 2020/7/23
Time: 21:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>step-1</title>
</head>
<body>
<h4>Step1: 选择要购买的图书</h4>
<p>开发的时候只能使用绝对路径,不可以用相对路径</p>
<p>name 必须一样</p>
<form action="<%= request.getContextPath() %>/processStep1Servlet" method="post">
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>书名</td>
<td>购买</td>
</tr>
<tr>
<td>Java</td>
<td> <input type="checkbox" name="book" value="Java"> </td>
</tr>
<tr>
<td>Oracle</td>
<td><input type="checkbox" name="book" value="Oracle"></td>
</tr>
<tr>
<td>Structs</td>
<td><input type="checkbox" name="book" value="Structs"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit" />
</td>
</tr>
</table>
</form>
</body>
</html>
新建 step-2.jsp
<%--
Created by IntelliJ IDEA.
User: Admin
Date: 2020/7/23
Time: 22:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>step-2</title>
</head>
<body>
<h4>step2: 请输入寄送地址和信用卡信息</h4>
<form action="<%= request.getContextPath() %>/processStep2Servlet" method="post">
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td colspan="2">寄送信息</td>
</tr>
<tr>
<td>姓名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>寄送地址:</td>
<td><input type="text" name="address"></td>
</tr>
<tr>
<td colspan="2">信用卡信息</td>
</tr>
<tr>
<td>种类:</td>
<td>
<input type="radio" name="cardType" value="Visa">Visa
<input type="radio" name="cardType" value="Master">Master
</td>
</tr>
<tr>
<td>卡号:</td>
<td><input type="text" name="card"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit">
</td>
</tr>
</table>
</form>
</body>
</html>
新建 confirm.jsp
<%@ page import="com.learn.session.cart.Customer" %><%--
Created by IntelliJ IDEA.
User: Admin
Date: 2020/7/24
Time: 0:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>confirm</title>
</head>
<body>
<form>
<%
Customer customer = (Customer) session.getAttribute("customer");
String[] books = (String[]) session.getAttribute("books");
%>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<td>name: </td>
<td><%= customer.getName() %></td>
</tr>
<tr>
<td>address: </td>
<td><%= customer.getAddress() %></td>
</tr>
<tr>
<td>cardType: </td>
<td><%= customer.getCardType() %></td>
</tr>
<tr>
<td>card: </td>
<td><%= customer.getCard() %></td>
</tr>
<tr>
<td>Books: </td>
<td>
<%
for (String book: books) {
out.print(book);
out.print("<br>");
}
%>
</td>
</tr>
</table>
</form>
</body>
</html>
1.2 在 src 下新建文件夹 cart
新建 ProcessStep1Servlet.java
package com.learn.session.cart;
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;
/**
* User: Admin
* Date: 2020/7/23
* Time: 22:21
* Author:
* Note:
*/
@WebServlet(name = "processStep1Servlet", urlPatterns = "/processStep1Servlet")
public class ProcessStep1Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取选中的图书的信息
String[] books = request.getParameterValues ( "book");
//2.把图书信息放入到HttpSession中
request.getSession(). setAttribute( "books", books);
//3.重定向页面到 cart/step-2.jsp
System.out.println(request.getContextPath() + "/learn.session.cart/step-2.jsp");
response.sendRedirect(request.getContextPath() + "/learn.session.cart/step-2.jsp");
}
}
新建 ProcessStep2Servlet.java
package com.learn.session.cart;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* User: Admin
* Date: 2020/7/23
* Time: 22:21
* Author:
* Note:
*/
@WebServlet(name = "processStep2Servlet", urlPatterns = "/processStep2Servlet")
public class ProcessStep2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求参数: name, address, cardType, card
String name = request.getParameter( "name") ;
String address = request.getParameter( "address");
String cardType = request.getParameter("cardType");
String card = request.getParameter("card");
Customer customer = new Customer(name, address, cardType, card);
//2.把请求信息存入到HttpSession中
HttpSession session = request.getSession();
session.setAttribute("customer", customer);
//3.重定向页面到confirm.jsp
response.sendRedirect(request.getContextPath() + "/learn.session.cart/confirm.jsp");
}
}
新建 Customer.java
package com.learn.session.cart;
/**
* User: Admin
* Date: 2020/7/23
* Time: 23:59
* Note:
*/
public class Customer {
private String name;
private String address;
private String cardType;
private String card;
public Customer() { }
public Customer(String name, String address, String cardType, String card) {
this.name = name;
this.address = address;
this.cardType = cardType;
this.card = card;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCardType() {
return cardType;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
}
1.3 运行结果
2. token 避免表单重复提交
首先创建一个提交表单 index.jsp
, 成功表单 success.jsp
和一个响应的 servlet
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<form action="<%= request.getContextPath() %>/tokenServlet" method="post">
name: <input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h4>Success Page</h4>
</body>
</html>
TokenServlet.java
package com.learn.session.token;
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;
/**
* User: Admin
* Date: 2020/7/24
* Time: 10:03
* Note:
*/
@WebServlet(name = "tokenServlet", urlPatterns = "/tokenServlet")
public class TokenServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
System.out.println("name: " + name);
// 请求转发
// req.getRequestDispatcher("/learn.session.token/success.jsp").forward(req, resp);
// 重定向
resp.sendRedirect(req.getContextPath() + "/learn.session.token/success.jsp");
}
}
2.1 重复提交的情况
① 在表单提交到一个Servlet, 而Servlet又通过请求转发的方式响应了一个JSP(HTML)页面, 此时地址栏还保留着Servlet的那个路径, 在响应页面点击"刷新".
② 在响应页面没有到达时重复点击"提交按钮"
③ 点击“返回",再点击"提交"
2.2 不是重复提交的情况
点击"返回",“刷新"原表单页面, 再"提交"
2.3 如何避免表单的重复提交
在表单中做一个标记,提交到Servlet时,检查标记是否存在且是否和预定义的标记致,
① 若一致,则受理请求,并销毁标记;
② 若不一致或没有标记,则直接响应提示信息: “重复提交”
2.3.1 Error
:仅提供一个隐藏域
// index.jsp 的 form 中添加
<input type="hidden" name="token" value="RongRong" />
// TokenServlet.java 中添加
String token = req.getParameter("token");
if ("RongRong".equals(token)) {
// 清除标记: 没有办法清除固定的请求参数
}
此方法行不通的理由:没有办法清除固定的请求参数
2.3.2 Error
:把标记放在 request 中
// index.jsp 的 form 中添加
<%
request.setAttribute("token", "tokenValue");
%>
// TokenServlet.java 中添加
Object token = req.getAttribute("token");
if (token != null) {
req.removeAttribute("token");
} else {
resp.sendRedirect(req.getContextPath() +
"/learn.session.token/token.jsp");
return;
}
token.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>token</title>
</head>
<body>
<h4>对不起,已经提交过了</h4>
</body>
</html>
此方法行不通的理由:因为表单页面制新后,request已经被销毁,再提交表单是一个新的request 。
2.3.3 Success
:把标记放在 session 中
// index.jsp 的 form 中添加
<%
session.setAttribute("token", "tokenValue");
%>
// TokenServlet.java 中添加
HttpSession session = req.getSession();
Object token = session.getAttribute("token");
if (token != null) {
session.removeAttribute("token");
} else {
resp.sendRedirect(req.getContextPath() + "/learn.session.token/token.jsp");
return;
}
此方法虽然可以但是不完美,缺陷很多。比如我们希望 token 的值是一个随机的值。
2.3.4 Perfect
:把随机值标记放在 session 中
在原表单页面,生成一个随机值token
在原表单页面,把token值放入session属性中
在原表单页面,把token值放入到隐藏城中。
在目标的Servlet中:获取session和隐藏城中的token值
比较两个值是否致:若致,受理请求,且把session域中的token羼性清除
若不一致,则直接响应提示页面: “重复提交”
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<%
String tokenValue = new Date() + "";
session.setAttribute("token", tokenValue);
%>
<form action="<%= request.getContextPath() %>/tokenServlet" method="post">
name: <input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
// TokenServlet.java 中添加
HttpSession session = req.getSession();
Object token = session.getAttribute("token");
String tokenValue = req.getParameter("token");
if (token != null && token.equals(tokenValue)) {
session.removeAttribute("token");
} else {
resp.sendRedirect(req.getContextPath() + "/learn.session.token/token.jsp");
return;
}
2.4 代码最终模样
index.jsp
<%@ page import="java.util.Date" %>
<%@ page import="com.learn.session.token.TokenProcessor" %><%--
Created by IntelliJ IDEA.
User: Admin
Date: 2020/7/24
Time: 10:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<%
String tokenValue = new Date().getTime() + "";
session.setAttribute("token", tokenValue);
%>
<form action="<%= request.getContextPath() %>/tokenServlet" method="post">
<input type="hidden" name="TOKEN_KEY"
value="<%= TokenProcessor.getInstance().saveToken(request) %>">
name: <input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h4>Success Page</h4>
</body>
</html>
token.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>token</title>
</head>
<body>
<h4>对不起,已经提交过了</h4>
</body>
</html>
TokenProcessor.java
package com.learn.session.token;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class TokenProcessor {
private static final String TOKEN_KEY = "TOKEN_KEY";
private static final String TRANSACTION_TOKEN_KEY = "TRANSACTION_TOKEN_KEY";
/**
* The singleton instance of this class.
*/
private static TokenProcessor instance = new TokenProcessor();
/**
* The timestamp used most recently to generate a token value.
*/
private long previous;
/**
* Protected constructor for TokenProcessor. Use TokenProcessor.getInstance()
* to obtain a reference to the processor.
*/
protected TokenProcessor() {
super();
}
/**
* Retrieves the singleton instance of this class.
*/
public static TokenProcessor getInstance() {
return instance;
}
public synchronized boolean isTokenValid(HttpServletRequest request) {
return this.isTokenValid(request, false);
}
/**
* @param request The servlet request we are processing
* @param reset Should we reset the token after checking it?
*/
public synchronized boolean isTokenValid(HttpServletRequest request,
boolean reset) {
// Retrieve the current session for this request
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
// Retrieve the transaction token from this session, and
// reset it if requested
String saved =
(String) session.getAttribute(TRANSACTION_TOKEN_KEY);
if (saved == null) {
return false;
}
if (reset) {
this.resetToken(request);
}
// Retrieve the transaction token included in this request
String token = request.getParameter(TOKEN_KEY);
if (token == null) {
return false;
}
return saved.equals(token);
}
/**
* Reset the saved transaction token in the user's session. This
* indicates that transactional token checking will not be needed on the
* next request that is submitted.
*
* @param request The servlet request we are processing
*/
public synchronized void resetToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(TRANSACTION_TOKEN_KEY);
}
/**
* Save a new transaction token in the user's current session, creating a
* new session if necessary.
*
* @param request The servlet request we are processing
*/
public synchronized String saveToken(HttpServletRequest request) {
HttpSession session = request.getSession();
String token = generateToken(request);
if (token != null) {
session.setAttribute(TRANSACTION_TOKEN_KEY, token);
}
return token;
}
/**
* Generate a new transaction token, to be used for enforcing a single
* request for a particular transaction.
*
* @param request The request we are processing
*/
public synchronized String generateToken(HttpServletRequest request) {
HttpSession session = request.getSession();
return generateToken(session.getId());
}
/**
* Generate a new transaction token, to be used for enforcing a single
* request for a particular transaction.
*
* @param id a unique Identifier for the session or other context in which
* this token is to be used.
*/
public synchronized String generateToken(String id) {
try {
long current = System.currentTimeMillis();
if (current == previous) {
current++;
}
previous = current;
byte[] now = new Long(current).toString().getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(id.getBytes());
md.update(now);
return toHex(md.digest());
} catch (NoSuchAlgorithmException e) {
return null;
}
}
/**
* Convert a byte array to a String of hexadecimal digits and return it.
*
* @param buffer The byte array to be converted
*/
private String toHex(byte[] buffer) {
StringBuffer sb = new StringBuffer(buffer.length * 2);
for (int i = 0; i < buffer.length; i++) {
sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
}
return sb.toString();
}
}
TokenServlet.java
package com.learn.session.token;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* User: Admin
* Date: 2020/7/24
* Time: 10:03
* Author:
* Note:
*/
@WebServlet(name = "tokenServlet", urlPatterns = "/tokenServlet")
public class TokenServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// String token = req.getParameter("token");
// if ("RongRong".equals(token)) {
// // 清除标记: 没有办法清除固定的请求参数
// }
// HttpSession session = req.getSession();
// Object token = session.getAttribute("token");
// String tokenValue = req.getParameter("token");
//
// if (token != null && token.equals(tokenValue)) {
// session.removeAttribute("token");
// } else {
// resp.sendRedirect(req.getContextPath() + "/learn.session.token/token.jsp");
// return;
// }
boolean valid = TokenProcessor.getInstance().isTokenValid(req);
if (valid) {
TokenProcessor.getInstance().resetToken(req);
} else {
resp.sendRedirect(req.getContextPath() + "/learn.session.token/token.jsp");
return;
}
String name = req.getParameter("name");
System.out.println("name: " + name);
// 请求转发
// req.getRequestDispatcher("/learn.session.token/success.jsp").forward(req, resp);
// 重定向
resp.sendRedirect(req.getContextPath() + "/learn.session.token/success.jsp");
}
}
3. 利用Session实现一次性验证码
在原表单页面,生成一个验证码的图片,生成图片的同时,需要把该图片中的字符串放入到session中.
在原表单页面,定义一个文本域,用于输入验证码。
在目标的Servlet中:获取session和表单域中的验证码的值
比较两个值是否一致:若一致,受理请求,且把session域中的验证码属性清除
若不一 致,则直接通过重定向的方式返回原表单页面,并提示用户"验证码错误“
3.1 代码
index.jsp
<%@ page import="java.util.Date" %>
<%@ page import="com.learn.session.token.TokenProcessor" %><%--
Created by IntelliJ IDEA.
User: Admin
Date: 2020/7/24
Time: 12:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<form color="red">
<%= session.getAttribute("message") == null ? "": session.getAttribute("message") %>
</form>
<form action="<%= request.getContextPath() %>/checkCodeServlet" method="post">
name: <input type="text" name="name" />
验证码: <input type="text" name="CHECK_CODE_PARAM_KEY">
<img alt="code" src="<%= request.getContextPath() %>/validateColorServlet">
<input type="submit" value="Submit" />
</form>
</body>
</html>
CheckCodeServlet.java
package com.learn.session.check;
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;
/**
* User: Admin
* Date: 2020/7/24
* Time: 14:59
* Note:
*/
@WebServlet(name = "checkCodeServlet", urlPatterns = "/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取请求参数: CHECK_CODE_PARAM_KEY
String paramCode = req.getParameter("CHECK_CODE_PARAM_KEY");
//2.获取session中的CHECK_CODE_KEY属性值
String sessionCode = (String)req.getSession().getAttribute("CHECK_CODE_KEY");
System.out.println("sessionCode = " + sessionCode + ", paramCode = " + paramCode);
//3.比对。看是否一致,若一致说明验证码正确,若不一致,说明验证码错误
if (paramCode != null && paramCode.equals(sessionCode)) {
// 必须使用 session
req.getSession().setAttribute("message", "YES: 验证码一致");
resp.sendRedirect(req.getContextPath() + "/learn.session.check/index.jsp");
return;
}
System.out.println("No: 验证码不一致!");
}
}
ValidateColorServlet.java
package com.learn.session.check;
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;
/**
* User: Admin
* Date: 2020/7/24
* Time: 11:59
* Note:
*/
@WebServlet(name = "validateColorServlet", urlPatterns = "/validateColorServlet")
public class ValidateColorServlet extends HttpServlet {
public static final String CHECK_CODE_KEY = "CHECK_CODE_KEY";
private static final long serialVersionUID = 1L;
//设置验证图片的宽度, 高度, 验证码的个数
private int width = 152;
private int height = 40;
private int codeCount = 6;
//验证码字体的高度
private int fontHeight = 4;
//验证码中的单个字符基线. 即:验证码中的单个字符位于验证码图形左上角的 (codeX, codeY) 位置处
private int codeX = 0;
private int codeY = 0;
//验证码由哪些字符组成
char [] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789".toCharArray();
// char[] codeSequence = "^[A-Za-z2-9]".toCharArray();
//初始化验证码图形属性
public void init(){
fontHeight = height - 2;
codeX = width / (codeCount + 2);
codeY = height - 4;
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//定义一个类型为 BufferedImage.TYPE_INT_BGR 类型的图像缓存
BufferedImage buffImg = null;
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
//在 buffImg 中创建一个 Graphics2D 图像
Graphics2D graphics = null;
graphics = buffImg.createGraphics();
//设置一个颜色, 使 Graphics2D 对象的后续图形使用这个颜色
graphics.setColor(Color.WHITE);
//填充一个指定的矩形: x - 要填充矩形的 x 坐标; y - 要填充矩形的 y 坐标; width - 要填充矩形的宽度; height - 要填充矩形的高度
graphics.fillRect(0, 0, width, height);
//创建一个 Font 对象: name - 字体名称; style - Font 的样式常量; size - Font 的点大小
Font font = null;
font = new Font("", Font.BOLD, fontHeight);
//使 Graphics2D 对象的后续图形使用此字体
graphics.setFont(font);
graphics.setColor(Color.BLACK);
//绘制指定矩形的边框, 绘制出的矩形将比构件宽一个也高一个像素
graphics.drawRect(0, 0, width - 1, height - 1);
//随机产生 15 条干扰线, 使图像中的认证码不易被其它程序探测到
Random random = null;
random = new Random();
graphics.setColor(Color.GREEN);
for(int i = 0; i < 55; i++){
int x = random.nextInt(width);
int y = random.nextInt(height);
int x1 = random.nextInt(20);
int y1 = random.nextInt(20);
graphics.drawLine(x, y, x + x1, y + y1);
}
//创建 randomCode 对象, 用于保存随机产生的验证码, 以便用户登录后进行验证
StringBuffer randomCode;
randomCode = new StringBuffer();
for(int i = 0; i < codeCount; i++){
//得到随机产生的验证码数字
String strRand = null;
strRand = String.valueOf(codeSequence[random.nextInt(36)]);
//把正在产生的随机字符放入到 StringBuffer 中
randomCode.append(strRand);
//用随机产生的颜色将验证码绘制到图像中
graphics.setColor(Color.BLUE);
graphics.drawString(strRand, (i + 1)* codeX, codeY);
}
//再把存放有所有随机字符的 StringBuffer 对应的字符串放入到 HttpSession 中
request.getSession().setAttribute(CHECK_CODE_KEY, randomCode.toString());
System.out.println("随机验证码 = " + randomCode.toString());
//禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
//将图像输出到输出流中
ServletOutputStream sos = null;
sos = response.getOutputStream();
ImageIO.write(buffImg, "jpeg", sos);
sos.close();
}
}
3.2 运行结果
代码中间可能有一些页面跳转的逻辑错误。