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;
}
}