java实现点选汉字验证码(转)

java

package com.rd.p2p.web;

import java.awt.BasicStroke;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.geom.AffineTransform;

import java.awt.geom.Line2D;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Random;

import javax.imageio.ImageIO;

import javax.servlet.ServletOutputStream;

import org.apache.commons.lang3.StringUtils;

import org.apache.poi.ss.formula.functions.T;

import org.apache.struts2.convention.annotation.Action;

import com.alibaba.fastjson.JSON;

import com.rd.p2p.additional.redisCaptcha.util.ResponseUtil;

import com.rd.p2p.common.util.redis.RedisValidImgCodeUtils;

import com.rd.p2p.core.core.Global;

import com.rd.p2p.core.core.constant.Constant;

import com.rd.p2p.core.core.web.BaseAction;

public class CodeAction extends BaseAction<T> {

private static final String KEY = "randomCode";

//点选文字图片验证码刷新次数

private static final String KEY_TOTAL = "select_random_code_total";

//点选文字图片验证码验证通过次数

private static final String KEY_SUCC = "select_random_code_succ";

//点选文字图片验证码验证失败次数

private static final String KEY_FAIL = "select_random_code_fail";

//缓存时间单位秒 设置成7天

private static final int CACHE_SECONDS = 604800;

//定义点选文字图片验证码允许的误差值

private static final int ERROR_AMOUNT = 12;// 定义允许的误差值,单位是px

//生成汉字的个数

private static Integer[] arr = new Integer[] {1, 2, 3, 4, 5};

//汉字颜色随机范围

private static Color[] colors = {Color.GRAY, Color.LIGHT_GRAY, Color.CYAN};

/**

* 跳转页面

* @return

*/

@Action("/verification")

public String verification() {

request.setAttribute("web_url", Global.getString("web_url"));

return "verification";

}

/**生成验证码

* @param src

* @param x

* @param y

*/

@Action("/code/getVerificationCode")

public void readUsingImageReaderBigcH() {

ServletOutputStream outStream = null;

try {

// http://localhost:8080/gtop/img/149679.jpg

//String url = "d:/4.png";

//url = request.getSession().getServletContext().getRealPath("") + url;

/* InputStream source = new FileInputStream(src);

BufferedImage image = null;

image = ImageIO.read(source);*/

//生成背景图片

BufferedImage image = getBackGround();

int hight = image.getHeight();

Graphics graphics = image.getGraphics();

// 设置颜色

graphics.setColor(Color.red);

graphics.setFont(new Font("宋体", Font.BOLD, 30));

StringBuilder sb = new StringBuilder();

Random random = new Random();

//转成集合

List<Integer> intList = Arrays.asList(arr);

//重新随机排序

Collections.shuffle(intList);

//list参数坐标参数 用于校验是否验证通过

List<String> codeList = new ArrayList<String>();

int x = 0;

int y = 0;

//定义随机1到arr.length某一个字不参与校验

int num = random.nextInt(arr.length)+1;

for (int i = 0; i < arr.length; i++) { // 5个汉字,只点4个

String ch = getRandomChineseChar();

int place = intList.get(i);

if (place == 1) {

x = new Random().nextInt(30) + 40; // 自己定义的位子坐标

y = new Random().nextInt(30) + 40; // i=1的时候,y的值

}

if (place == 2) {

x = new Random().nextInt(40) + 120; // 自己定义的位子坐标

y = new Random().nextInt(30) + 50; // i=2的时候,y的值

}

if (place == 3) {

x = new Random().nextInt(70) + 200; // 自己定义的位子坐标

y = new Random().nextInt(50) + 100; // i=3的时候,y的值

}

if (place == 4) {

x = new Random().nextInt(70) + 80; // i=4的时候,x的值

y = new Random().nextInt(30) + 90; // 自己定义的位子坐标

}

if (place == 5) {

x = new Random().nextInt(70) + 180; // i=4的时候,x的值

y = new Random().nextInt(30) + 50; // 自己定义的位子坐标

}

Constant.LOGGER.info("x:" + x + ",y:" + y + ",hight:" + hight);

//字体颜色

graphics.setColor(colors[random.nextInt(colors.length)]);

graphics.drawString(ch, x, y);

if (place != num) {

sb.append(ch);

codeList.add(x + "_" + y); // jsp页面坐标原点在字的中间,drawString方法坐标原点在中间

}

}

Constant.LOGGER.info("汉字:" + sb);

//放入session

//将产生的随机汉字验证码存进session中进行保存

String sessionid = request.getSession().getId();

RedisValidImgCodeUtils.save(sessionid + KEY, codeList);

//增加验证码请求次数

RedisValidImgCodeUtils.increment(KEY_TOTAL, CACHE_SECONDS);

// 可以将图片合并传入前端 也可以直接传数据汉字给前端

// 创建顶部图片

BufferedImage bi = new BufferedImage(image.getWidth(), 25, BufferedImage.TYPE_INT_RGB);

Graphics gra = bi.getGraphics();

// 设置背景颜色

gra.setColor(Color.WHITE);

// 填充区域

gra.fillRect(0, 0, bi.getWidth(), bi.getHeight());

// 设置边框颜色

gra.setColor(Color.BLUE);

// 设置边框区域

gra.drawRect(1, 1, bi.getWidth() - 2, bi.getHeight() - 2);

// 设置文字背景颜色

Font font = new Font("Microsoft YaHei", Font.BOLD, 16);

gra.setFont(font);

gra.setColor(Color.BLACK);

gra.drawString("按顺序点击:" + sb.toString(), (bi.getWidth() - 10*font.getSize())/2, bi.getHeight()/2 + font.getSize()/2);//设置文字字体 与位子 居中

BufferedImage combined = new BufferedImage(image.getWidth(), image.getHeight() + bi.getHeight(), BufferedImage.TYPE_INT_RGB);

Graphics g = combined.getGraphics(); //合并

g.drawImage(bi, 0, 0, null);

g.drawImage(image, 0, bi.getHeight(), null);

outStream= response.getOutputStream();

ImageIO.write(combined, "jpg", outStream);

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (outStream != null) {

outStream.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

@Action("/code/verify")

public void verify() throws IOException {

Map<String, Object> data = new HashMap<String, Object>();

data.put("result", false);

String value = request.getParameter("code");

String sessionid = request.getSession().getId();

if (RedisValidImgCodeUtils.get(sessionid + KEY) == null) {

printWebJson(JSON.toJSONString(data));

return;

}

List<String> sValue = (List<String>) RedisValidImgCodeUtils.get(sessionid + KEY);

//取到数据后直接清掉redis

RedisValidImgCodeUtils.del(sessionid + KEY);

Constant.LOGGER.info("**前端请求数据***"+value);

Constant.LOGGER.info("**后端实际数据**"+sValue.toString());

//为null 或者"" 或者 " "

if (StringUtils.isBlank(value) || sValue == null || sValue.size() < 1) {

printWebJson(JSON.toJSONString(data));

return;

}

String [] valueStr = value.split(",");

if(valueStr.length != sValue.size() || valueStr.length != 4){

printWebJson(JSON.toJSONString(data));

return;

}

/*判断坐标参数是否正确*/

String str = "";

for (int i = 0; i < valueStr.length; i++) {

str = valueStr[i].toString();

if(StringUtils.isBlank(str) || StringUtils.isBlank(sValue.get(i).toString())){

printWebJson(JSON.toJSONString(data));

return;

}

String [] vL = valueStr[i].toString().split("_");

String [] svL = sValue.get(i).toString().split("_");

if(vL.length != svL.length || svL.length != 2){

printWebJson(JSON.toJSONString(data));

return;

}

//x轴 y轴判断 坐标点在左上角 ,图片宽度30px 点击范围扩大12px, 范围在 x-13 < x <x+13 ;

if(!(Integer.parseInt(svL[0])-ERROR_AMOUNT < Integer.parseInt(vL[0])-15 && Integer.parseInt(vL[0])-15 < Integer.parseInt(svL[0])+ERROR_AMOUNT )

|| !(Integer.parseInt(svL[1])-ERROR_AMOUNT < Integer.parseInt(vL[1])-15 && Integer.parseInt(vL[1])-15 < Integer.parseInt(svL[1])+ERROR_AMOUNT)){

//增加验证失败次数

RedisValidImgCodeUtils.increment(KEY_FAIL, CACHE_SECONDS);

printWebJson(JSON.toJSONString(data));

return;

}

}

//增加验证通过次数

RedisValidImgCodeUtils.increment(KEY_SUCC, CACHE_SECONDS);

data.put("result", true);

printWebJson(JSON.toJSONString(data));

}

/**

* 生成背景图片

* @return

*/

public BufferedImage getBackGround(){

int width=300; //指定生成验证码的宽度

int height=200; //指定生成验证码的高度

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = image.getGraphics();

Graphics2D g2d = (Graphics2D)g; //创建Graphics2D对象

Random random = new Random();

// Font mFont = new Font("黑体", Font.BOLD, 16); //定义字体样式

// g.setColor(getRandColor(200, 250)); //背景色

g.fillRect(0, 0, width, height); //绘制背景

// g.setFont(mFont); //设置字体

g.setColor(getRandColor(180, 200)); //线条色

//绘制88根位置和颜色全部为随机产生的线条,该线条为2f

for (int i = 0; i < 88; i++) {

int x = random.nextInt(width-1);

int y = random.nextInt(height-1);

int x1 = random.nextInt(100)+1;

int y1 = random.nextInt(120)+1;

BasicStroke bs = new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL);

Line2D line = new Line2D.Double(x,y,x+x1,y+y1);

g2d.setStroke(bs);

g2d.draw(line); //绘制直线

// g2d.setColor(getRandColor(random, 30, 150)); //随机每条线条的颜色

}

//输出生成的验证码图片

g.dispose();

return image;

}

private static Color getRandColor(Random random, int fc, int bc){

if (fc > 255)

fc = 255;

if (bc > 255)

bc = 255;

int r = fc + random.nextInt(bc - fc);

int g = fc + random.nextInt(bc - fc);

int b = fc + random.nextInt(bc - fc);

return new Color(r, g, b);

}

private static String[] generateCheckCode() {

String[] res = new String[2];

Random random = new Random();

int intTemp;

int intFirst = random.nextInt(100);

int intSec = random.nextInt(100);

String checkCode = "";

int result = 0;

switch (random.nextInt(6)) {

case 0:

if (intFirst < intSec) {

intTemp = intFirst;

intFirst = intSec;

intSec = intTemp;

}

checkCode = intFirst + " - " + intSec + " = ?";

result = intFirst-intSec;

break;

case 1:

if (intFirst < intSec) {

intTemp = intFirst;

intFirst = intSec;

intSec = intTemp;

}

checkCode = intFirst + " - ? = "+(intFirst-intSec);

result = intSec;

break;

case 2:

if (intFirst < intSec) {

intTemp = intFirst;

intFirst = intSec;

intSec = intTemp;

}

checkCode = "? - "+intSec+" = "+(intFirst-intSec);

result = intFirst;

break;

case 3:

checkCode = intFirst + " + " + intSec + " = ?";

result = intFirst + intSec;

break;

case 4:

checkCode = intFirst + " + ? ="+(intFirst+intSec);

result = intSec;

break;

case 5:

checkCode = "? + " + intSec + " ="+(intFirst+intSec);

result = intFirst;

break;

}

res[0] = checkCode;

res[1] = String.valueOf(result);

Constant.LOGGER.info("result=" + result);

return res;

}

@Action("/code/calc")

public void calcCode() throws IOException{

int width = 140, height = 37;

try {

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = image.getGraphics();

Random random = new Random();

g.setColor(getRandColor(random, 200, 250));

g.fillRect(0, 0, width, height);

String[] fontTypes = { "\u5b8b\u4f53", "\u65b0\u5b8b\u4f53", "\u9ed1\u4f53", "\u6977\u4f53", "\u96b6\u4e66" };

int fontTypesLength = fontTypes.length;

g.setColor(getRandColor(random, 160, 200));

g.setFont(new Font("Times New Roman", Font.PLAIN, 14 + random.nextInt(6)));

for (int i = 0; i < 255; i++) {

int x = random.nextInt(width);

int y = random.nextInt(height);

int xl = random.nextInt(12);

int yl = random.nextInt(12);

g.drawLine(x, y, x + xl, y + yl);

}

String[] result = generateCheckCode();

RedisValidImgCodeUtils.save(request.getSession().getId() + "calc_code", result[1]);

String [] baseChar = result[0].split(" ");

for (int i = 0; i < baseChar.length; i++) {

g.setColor(getRandColor(random, 30, 150));

g.setFont(new Font(fontTypes[random.nextInt(fontTypesLength)], Font.BOLD, 22 + random.nextInt(6)));

g.drawString(baseChar[i], 24 * i + 10, 24);

}

g.dispose();

//发送图片

ResponseUtil.sendImg(response, image, "image/jpeg", "code", "jpg");

} catch (IllegalStateException e) {

Constant.LOGGER.error(e.getMessage());

e.printStackTrace();

}

}

@Action("/code/getRandomCode")

public void getRandomCode() throws IOException{

// TODO Auto-generated method stub

//设置不缓存图片

response.setHeader("Pragma", "No-cache");

response.setHeader("Cache-Control", "No-cache");

response.setDateHeader("Expires", 0);

//指定生成的响应图片

response.setContentType("image/jpeg");

int width=140; //指定生成验证码的宽度

int height=37; //指定生成验证码的高度

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = image.getGraphics();

Graphics2D g2d = (Graphics2D)g; //创建Graphics2D对象

Random random = new Random();

Font mFont = new Font("黑体", Font.BOLD, 22); //定义字体样式

g.setColor(getRandColor(200, 250));

g.fillRect(0, 0, width, height); //绘制背景

g.setFont(mFont); //设置字体

g.setColor(getRandColor(180, 200));

//绘制100根位置和颜色全部为随机产生的线条,该线条为2f

for (int i = 0; i < 100; i++) {

int x = random.nextInt(width-1);

int y = random.nextInt(height-1);

int x1 = random.nextInt(6)+1;

int y1 = random.nextInt(12)+1;

BasicStroke bs = new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL);

Line2D line = new Line2D.Double(x,y,x+x1,y+y1);

g2d.setStroke(bs);

g2d.draw(line); //绘制直线

}

//输出由英文,数字和中文随机组成的验证文字,具体的组合方式根据生成随机数确定

String sRand = "";

//输出随机的验证文字

String ctmp = "";

int itmp = 0;

for(int i = 0;i<4;i++){

switch (random.nextInt(2)) {

case 0:

itmp = random.nextInt(26)+65; //生成A~Z的字母

ctmp = String.valueOf((char)itmp);

break;

default:

ctmp = String.valueOf(random.nextInt(8)+2); //生成2~9的数字

break;

}

sRand+=ctmp;

Color color = new Color(20+random.nextInt(110), 20+random.nextInt(110), 20+random.nextInt(110));

g.setColor(color);

//将生成的随机数进行随机缩放病旋转指定角度

//将文字旋转指定角度

Graphics2D g2d_word = (Graphics2D)g;

AffineTransform trans = new AffineTransform();

trans.rotate(random.nextInt(45)*3.14/180, 15*i+8, 7);

//缩放文字

/*float scaleSize = random.nextFloat()+0.8f;

if(scaleSize > 1f){

scaleSize = 1f;

}

trans.scale(scaleSize, scaleSize); */

g2d_word.setTransform(trans);

g.drawString(ctmp, 20*i+18, 18); //每个字的间距xy

}

//将生成的验证码保存道session中

RedisValidImgCodeUtils.save(request.getSession().getId() + "randCheckCode", sRand);

//输出生成的验证码图片

g.dispose();

ImageIO.write(image, "JPEG", response.getOutputStream());

}

public Color getRandColor(int s,int e){

Random random = new Random();

if(s>255)s = 255;

if(e>255)e = 255;

int r = s+random.nextInt(e-s);

int g = s+random.nextInt(e-s);

int b = s+random.nextInt(e-s);

return new Color(r, g, b);

}

public static String getRandomChineseChar() {

String str = null;

int hs, ls;

Random random = new Random();

hs = (176 + Math.abs(random.nextInt(39)));

ls = (161 + Math.abs(random.nextInt(93)));

byte[] b = new byte[2];

b[0] = (new Integer(hs).byteValue());

b[1] = (new Integer(ls).byteValue());

try {

str = new String(b, "GBk"); //转成中文

} catch (UnsupportedEncodingException ex) {

ex.printStackTrace();

}

return str;

}

}

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

<script src="${web_url}/api/themes/theme_default/media/js/jquery.js"></script>

<title>验证码</title>

</head>

<body>

<div style="text-align:center;position:relative;">

<!--<h2>这是点击的验证码</h2> -->

<!-- 这是点击的验证码 -->

<img id="codeT3" src="${web_url}/api/code/getVerificationCode.html?flag=" +Math.random()"/>

</br>

<!--

<input type="button" value="刷新" onclick="getCodeTree();" />

        

<input type="button" value="校验" onclick="cheakOutTree();" />

-->

<select id="codeSelect" style="display: none;"></select>

<img src="${web_url}/api/refresh.png" style="position:absolute;right:0;top:0; width:20px; height: 20px;" onclick="getCodeTree();" />

</div>

<script type="text/javascript">

//点击次数

var number=0;

//获取验证码3

function getCodeTree() {

number = 0;

$(".zhezhao").remove();

document.getElementById("codeSelect").options.length = 0;

$("#codeT3").attr("src","${web_url}/api/code/getVerificationCode.html?flag="+Math.random());

}

$(function() {

$("#codeT3").bind("click", function(ev) {

var oEvent = ev || event;

//var number = $("#codeSelect option").length;

number++;

if (number > 4) {

return;

}

var x = oEvent.pageX;

var y = oEvent.pageY;

var img = document.getElementById(\'codeT3\'); //获取图片的原点

var nodex = getNodePosition(img)[0];//原点x 与原点y

var nodey = getNodePosition(img)[1];

var xserver = parseInt(x) - parseInt(nodex);

var yserver = parseInt(y) - parseInt(nodey);

$("#codeSelect").append(

"<option value=\'"+ (parseInt(number)+1) +"\'>" + xserver + "_" + yserver

+ "</option>");

var oDiv = document.createElement(\'img\');

oDiv.style.left = (parseInt(x)-15) + \'px\'; // 指定创建的DIV在文档中距离左侧的位置 图片大小30 左右移动5

oDiv.style.top = (parseInt(y) -15) + \'px\'; // 指定创建的DIV在文档中距离顶部的位置

oDiv.style.border = \'1px solid #FF0000\'; // 设置边框

oDiv.style.position = \'absolute\'; // 为新创建的DIV指定绝对定位

oDiv.style.width = \'30px\'; // 指定宽度

oDiv.style.height = \'30px\'; // 指定高度

//oDiv.src = \'select.png\';

oDiv.style.opacity = \'0.5\'; //透明度

oDiv.className = \'zhezhao\';//加class 点刷新后删除遮罩

document.body.appendChild(oDiv);

//第四次点击后自动提交

if (number == 4) {

cheakOutTree();

}

});

})

//校验验证码

function cheakOutTree() {

var txt = "";

$("#codeSelect option").each(function (){

var text = $(this).text();

if(txt == ""){

txt = text;

}else{

txt = txt + "," + text;

}

});

$.ajax({

type:"post",

url:"${web_url}/api/code/verify.html",

data : {"code" : txt},

cache : false,

success : function(data) {

alert(data.result);

if (!data.result) {

getCodeTree();

}

}

});

}

function getNodePosition(node) {

var top = left = 0;

while (node) {

if (node.tagName) {

top = top + node.offsetTop;

left = left + node.offsetLeft;

node = node.offsetParent;

}

else {

node = node.parentNode;

}

}

return [left, top];

}

</script>

</body>

</html>

  

以上是 java实现点选汉字验证码(转) 的全部内容, 来源链接: utcz.com/z/392920.html

回到顶部