1. 先看前端页面的验证码图片与html代码:/register.jsp
注册校验
输入校验码: | ||
看不清换一张 |
2. 根据上面代码可以看到验证码图片的src地址指向了一个名为"imageCode"的Servlet。此Servlet代码如下:ImageCodeServlet.java
@SuppressWarnings("serial")
@WebServlet("/imageCode")
public class ImageCodeServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
//req.setCharacterEncoding("utf-8");
//res.setContentType("text/html;charset=utf-8");
// 设置http响应的文件MIME类型为图片
res.setContentType("image/jpeg");
// 不让浏览器记录此图片的缓存
res.setDateHeader("expries", -1);
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
// 这里调用了一个工具类VerifyCodeUtils来生成指定位数(也可指定内容)的验证码字符串
String verifyCode = VerifyCodeUtils.generateVerifyCode(5);
// 将生成验证码字符串保存到session域中,方面进行表单验证
req.getSession().setAttribute("verifyCode", verifyCode);
// 生成图片并写到响应输出流里. 因为register.jsp页面里的验证码图片宽高分别为180,30.这里使保持一致
VerifyCodeUtils.outputImage(180, 30, res.getOutputStream(), verifyCode);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGet(req, res);
}
}
3. 生成验证码图片的工具类--VerifyUtils.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;
import javax.imageio.ImageIO;
public class VerifyCodeUtils{
// 可自定义验证码字符源
public static final String VERIFY_CODES = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* 使用系统默认字符源生成验证码
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize){
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources){
if(sources == null || sources.length() == 0){
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for(int i = 0; i < verifySize; i++){
verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
}
return verifyCode.toString();
}
/**
* 生成随机验证码文件,并返回验证码值
* @param w 图片宽(像素)
* @param h 图片高(像素)
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, outputFile, verifyCode);
return verifyCode;
}
/**
* 输出随机验证码图片流,并返回验证码值
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, os, verifyCode);
return verifyCode;
}
/**
* 生成指定验证码图像文件
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
if(outputFile == null){
return;
}
File dir = outputFile.getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
try{
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
outputImage(w, h, fos, code);
fos.close();
} catch(IOException e){
throw e;
}
}
/**
* 输出指定验证码图片流
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w,
int h,
OutputStream os,
String code) throws IOException{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for(int i = 0; i < colors.length; i++){
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
Paint linearPaint = new LinearGradientPaint(0, 0, w, h, fractions, colors);
Paint linearPaint2 = new LinearGradientPaint(0, 0, w, h, new float[]{0.3f, .6f, .8f, .9f}, new Color[]{Color.BLUE, Color.BLACK, Color.GREEN, Color.BLUE});
//设置图片背景为白色
g2.setPaint(Color.WHITE);
g2.fillRect(0, 0, w, h);
//设置图片渐变背景
g2.setPaint(linearPaint);
g2.fillRoundRect(0, 0, w, h, 5, 5);
g2.setPaint(linearPaint2);
int fontSize = (int) (Math.min(w/verifySize, h));
Font font = new Font("微软雅黑", Font.BOLD, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for(int i = 0; i < verifySize; i++){
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, (w / verifySize) * i, h/2 + fontSize /2);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
public static void main(String[] args) throws IOException{
File dir = new File("F:/verifies");
int w = 200, h = 80;
for(int i = 0; i < 100; i++){
String verifyCode = generateVerifyCode(4);
File file = new File(dir, verifyCode + ".jpg");
outputImage(w, h, file, verifyCode);
}
}
}
4. 实现点击"看不清楚,换一图片"功能的js代码:/register.jsp:
function changeImage() {
document.getElementById("img").src = "${pageContext.request.contextPath}/imageCode?time=" + new Date().getTime();
}