前台调用生成验证码的Action类
package cn.hospital.action;
import java.io.ByteArrayInputStream;
import java.util.Map;
import cn.hospital.dao.util.SecurityCode;
import cn.hospital.dao.util.SecurityCode.SecurityCodeLevel;
import cn.hospital.dao.util.SecurityImage;
import com.opensymphony.xwork2.ActionContext;
/**
* 提供图片验证码
* @author 刘会
*/
public class SecurityCodeImageAction extends BaseAction{
private String yzm;
private String r;
public String getYzm() {
return yzm;
}
public void setYzm(String yzm) {
this.yzm = yzm;
}
public String getR() {
return r;
}
public void setR(String r) {
this.r = r;
}
/**
*
*/
private static final long serialVersionUID = -1836028049471716658L;
//图片流
private ByteArrayInputStream imageStream;
public ByteArrayInputStream getImageStream() {
return imageStream;
}
public void setImageStream(ByteArrayInputStream imageStream) {
this.imageStream = imageStream;
}
@SuppressWarnings("unchecked")
public String execute() {
//如果开启Hard模式,可以不区分大小写
String securityCode = SecurityCode.getSecurityCode(4,SecurityCodeLevel.Hard, false).toLowerCase();
//获取默认难度和长度的验证码
//String securityCode = SecurityCode.getSecurityCode();
imageStream = SecurityImage.getImageAsInputStream(securityCode);
//放入session中
session.put("SECURITY_CODE", securityCode);
return SUCCESS;
}
/**
* 检查验证码
*/
public void vertifyCode(){
Object str = session.get("SECURITY_CODE");
if(str.toString().equalsIgnoreCase(yzm)){
super.writeJson(true);
}else{
super.writeJson(false);
}
}
}
实际生成验证码的Util类
import java.util.Arrays;
/**
* 工具类,生成随机验证码字符串
* @version 1.0 2013/10/21
* @author 刘会
*
*/
public class SecurityCode {
/**
* 验证码难度级别,Simple只包含数字,Medium包含数字和小写英文,Hard包含数字和大小写英文
*/
public enum SecurityCodeLevel {Simple,Medium,Hard};
/**
* 产生默认验证码,4位中等难度
* @return String 验证码
*/
public static String getSecurityCode(){
return getSecurityCode(4,SecurityCodeLevel.Medium,false);
}
/**
* 产生长度和难度任意的验证码
* @param length 长度
* @param level 难度级别
* @param isCanRepeat 是否能够出现重复的字符,如果为true,则可能出现 5578这样包含两个5,如果为false,则不可能出现这种情况
* @return String 验证码
*/
public static String getSecurityCode(int length,SecurityCodeLevel level,boolean isCanRepeat){
//随机抽取len个字符
int len=length;
//字符集合(除去易混淆的数字0、数字1、字母l、字母o、字母O)
char[] codes={'1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i',
'j','k','m','n','p','q','r','s','t',
'u','v','w','x','y','z','A','B','C',
'D','E','F','G','H','I','J','K','L',
'M','N','P','Q','R','S','T','U','V',
'W','X','Y','Z'};
//根据不同的难度截取字符数组
if(level==SecurityCodeLevel.Simple){
codes=Arrays.copyOfRange(codes, 0,9);
}else if(level==SecurityCodeLevel.Medium){
codes=Arrays.copyOfRange(codes, 0,33);
}
//字符集合长度
int n=codes.length;
//抛出运行时异常
if(len>n&&isCanRepeat==false){
throw new RuntimeException(
String.format("调用SecurityCode.getSecurityCode(%1$s,%2$s,%3$s)出现异常," +
"当isCanRepeat为%3$s时,传入参数%1$s不能大于%4$s",
len,level,isCanRepeat,n));
}
//存放抽取出来的字符
char[] result=new char[len];
//判断能否出现重复的字符
if(isCanRepeat){
for(int i=0;i<result.length;i++){
//索引 0 and n-1
int r=(int)(Math.random()*n);
//将result中的第i个元素设置为codes[r]存放的数值
result[i]=codes[r];
}
}else{
for(int i=0;i<result.length;i++){
//索引 0 and n-1
int r=(int)(Math.random()*n);
//将result中的第i个元素设置为codes[r]存放的数值
result[i]=codes[r];
//必须确保不会再次抽取到那个字符,因为所有抽取的字符必须不相同。
//因此,这里用数组中的最后一个字符改写codes[r],并将n减1
codes[r]=codes[n-1];
n--;
}
}
return String.valueOf(result);
}
}
Struts.xml中验证码的Action配置:
<action name = "checkYzm" class = "cn.hospital.action.SecurityCodeImageAction" method="{1}">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">2048</param>
</result>
</action>
前台调用此上面Action生成图片:
<a href="#" title="看不清楚,点击换一张"><img style="cursor: pointer;height: 25px;width: 50px;"
src="${pageContext.request.contextPath}/checkYzm!execute.action?r="
id="registerVerifyCode" alt="验证码" /></a>
当图片看不清时,点击刷新
$(function() {
//点击图片更换验证码
$("#registerVerifyCode").click(function(){
$(this).attr("src","checkYzm!execute.action?r="+new Date().getTime());
});
});