package cmcc.jx.ict.xsgj.system.yzm.action;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import sun.font.FontDesignMetrics;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author 朱银涛
* @version : 2017年2月8日
*/
public class ValidateCodeAction extends ActionSupport{
//验证码存在session中的name
public static final String VALIDATE_CODE = "code";
//可选字体
String[] fontTypes = {"Arial","Arial Black","AvantGarde Bk BT","Calibri","Times New Roman","宋体","黑体","Arial Unicode MS","Lucida Sans"};
//随机字符的范围
char[] codeSeq = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J','K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};
//验证码长度
private final int CODE_LENGTH = 4;
//验证码的宽和高
private int w;
private int h = 25;
Random random = new Random();
public static boolean validate(HttpServletRequest request, String validateCode){
String code = (String)request.getSession().getAttribute(VALIDATE_CODE);
return validateCode.toUpperCase().equals(code);
}
public void validateCode(){
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
String rd = (String) request.getSession().getAttribute("rd");
String rd2 = request.getParameter("rd2");
System.out.println("session中的数字"+rd);
System.out.println("request中的数字"+rd2);
request.getSession().removeAttribute("rd"); //删除session中的数字
try {
if (rd != null && rd.equals(rd2)) {
createImage(request,response);
}else{
response.sendRedirect("error.jsp");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成图像数据
* */
private void createImage(HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
/*
* 得到参数高,宽,都为数字时,则使用设置高宽,否则使用默认值
*/
String width = request.getParameter("width");
String height = request.getParameter("height");
if ((width != null && "".equals(width))&&(height != null && "".equals(height))) {
w = Integer.valueOf(width);
h = Integer.valueOf(height);
}else{
w = CODE_LENGTH * 18 +20;
}
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
//获取图片上下文
Graphics g = image.getGraphics();
Graphics2D g2 = (Graphics2D) g;
/*
* 生成背景
*/
createBackground(g2);
/*
* 生成字符
*/
String s = createCharacter(g2);
request.getSession().setAttribute(VALIDATE_CODE, s);
g2.dispose();
OutputStream out = response.getOutputStream();
ImageIO.write(image, "JPEG", out);
out.close();
}
/**
* 生成随机颜色
* @param fc 产生颜色值下限
* @param bc 产生颜色值上限
* @return 生成的随机颜色对象
*/
private Color getRandColor(int fc,int bc) {
int f = fc;
int b = bc;
if(f>255) {
f=255;
}
if (f<1) {
f=1;
}
if(b>255) {
b=255;
}
if (b<1) {
b=1;
}
return new Color(f+random.nextInt(b-f),f+random.nextInt(b-f),f+random.nextInt(b-f));
}
private void createBackground(Graphics2D g) {
// 填充背景
g.setColor(getRandColor(220,250));
g.fillRect(0, 0, w, h);
// 加入干扰线条
for (int i = 0; i < 7; i++) {
g.setColor(getRandColor(40,150));
int x = random.nextInt(w);
int y = random.nextInt(h);
int x1 = random.nextInt(w);
int y1 = random.nextInt(h);
g.drawLine(x, y, x1, y1);
}
}
//生成随机字符并且返回
private String createCharacter(Graphics2D g) {
StringBuilder s = new StringBuilder();
int fontsize; //生成字符的字体大小
int charX = 0; //生成字符x的位置
int chartY = h - 5; //生成字符y的位置
Color color = g.getColor();
//旋转或扭曲
int rotateOrWarp = random.nextInt(2);
for (int i = 0; i < CODE_LENGTH; i++) {
String r = String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);//random.nextInt(10));
//随机设置字体颜色
g.setColor(new Color(50 + random.nextInt(100), 50 + random.nextInt(100), 50 + random.nextInt(100)));
//随机字体大小18-22
fontsize = Math.abs(18+random.nextInt(4));
Font font = new Font(fontTypes[random.nextInt(fontTypes.length)],Font.BOLD,fontsize);
g.setFont(font);
FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
int charWidth = fontMetrics.stringWidth("M"); //当前随机生成字符的宽度
int charsRealWidth = charWidth * CODE_LENGTH;
//第一次循环的时候初始化
if (i == 0) {
if(w > charsRealWidth){
charX = (w - charsRealWidth)/2;
}
}
if(rotateOrWarp == 0){
//画旋转文字
double radianPercent = 0D;
radianPercent = Math.PI * (random.nextInt(40)/180D);
if(random.nextBoolean()) radianPercent = -radianPercent;
g.rotate(radianPercent, charX + 9, chartY);
g.drawString(r, charX, chartY);
g.rotate(-radianPercent, charX + 9, chartY);
charX += charWidth;
}else{
g.drawString(r, charX, chartY);
charX += charWidth;
}
s.append(r);
}
if (rotateOrWarp == 1) {
//扭曲
shear(g, w, h, color);
}
return s.toString();
}
// 扭曲方法
private void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(8)+8;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
//验证码安全检验
public void safetyTest(){
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
String rd="";
Random random = new Random();
for(int i=0;i<5;i++){
rd += random.nextInt(10);
}
System.out.println("随机出的数字:"+rd);
request.getSession().setAttribute("rd", rd);
long d = new Date().getTime();
System.out.println("当前验证码的时间:"+d);
String json = rd+"-"+d;
try {
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
<package name="system-validateCode" extends="struts-default">
<action name="validateCode" class="validateCodeAction" method="validateCode">
</action>
<action name="safetyTest" class="validateCodeAction" method="safetyTest">
</action>
</package>
<%
//properties 配置文件名称
PropertyResourceBundle res = (PropertyResourceBundle) PropertyResourceBundle.getBundle("validateCode");
// 获取properties配置文件中的验证码过期时间的值
String oldTime = res.getString("validateCode.oldTime");
%>
<script src="./js/jquery-1.7.2.min.js"></script>
<script language="javascript">
$(document).ready(function (){
$("#validateCode2").trigger("click");
});
var ddd; //验证码生成的时间
var timeArray; //记录验证码每次刷新的时间 10秒钟最多刷新4次
function validateCodeRefresh(){
if(limitRefresh(10,4)){
$.post("safetyTest.action",function(data){
var data2 = data.split("-");
ddd = data2[1];
$("#validateCode2").attr("src","validateCode.action?"+new Date().getTime()+"&rd2="+data2[0]);
});
}else{
alert("刷新过于频繁,请稍后再试...");
}
}
//点击登录按钮
function mysubmit() {
var a = $("#validateCode").val();
if(a == "" || a == null){
alert("请输入验证码!");
return false;
}
var newDate = new Date().getTime();
var oldTime = parseInt("<%=oldTime %>");
if(isNaN(oldTime)){
oldTime = 10;
}
//验证码超时判断
if(ddd != "" && ddd != null && newDate - ddd >= oldTime*1000){
alert("验证码超时...");
$("#validateCode2").trigger("click");
}else{
//提交表单
}
return true;
}
function limitRefresh(allTime,count){
var newTime = new Date().getTime();
if (timeArray == undefined) {
timeArray = new Array();
}else{
var ttt = 0;
for (var i=0;i<timeArray.length;i++) {
if (newTime - timeArray[i] < allTime*1000) {
ttt++;
}else{
//每隔十秒就可以清空一次
timeArray = new Array();
break;
}
if (ttt >= count) {
return false;
}
}
}
timeArray.push(newTime);
return true;
}
</script>
<td height="30" align="right" nowrap><strong>验证码:</strong></td>
<td nowrap>
<input id="validateCode" name="j_code" maxlength="5" type="text" style="position:relative; top:1px;width:87px;">
<img id="validateCode2" onclick="validateCodeRefresh()" style="position:relative; top:4px;">
</td>