在学习Java的数据类型时曾发现int型可以直接强制转换成为char型。这个样子我们是不是可以利用random的伪随机数来生成一个网页上的英文验证码呢?
首先查询JavaDOC关于int型和char型的转换机制,发现int中的97~122的ASICS编码对应char中的a~z的小写字母。所以,基于此,我们可以这样子来生成一个六位验证码。
设计强制类型转换的实例如下:
public class RandomStr {
public static void main (String []args) {
String result = "";//定义一个空字符串
//进行六次循环
for (int i = 0; i<6;i++) {
//生成一个97~122的int型整数
int intVal = (int)(Math.random()*26 + 97);
//将intValue强制转换成char后连接到result后面
result = result + (char)intVal;
}
//输出随机字符串
System.out.println("你要的验证码为:" + result);
}
}
进行测试,成功输出6位的英文字符串,测试成功喽。
基于此,俺不由得玩心胜起。一个验证码怎么只有生成没有验证呢?所以我们再来个验证。
应用了循环嵌套+分支后设计代码如下:
import java.util.Scanner;
public class RandomStr {
public static void main (String []args) {
int k = 0;//定义一个int型变量来做开关,控制是否继续验证
while (k < 1) {
String result = "";//定义一个空字符串
//进行六次循环
int i = 0;
while (i <= 5) {
//生成一个97~122的int型整数
int intVal = (int)(Math.random()*26 + 97);
//将intValue强制转换成char后连接到result后面
result = result + (char)intVal;
i++;
}
//输出随机字符串
System.out.println("你要的验证码为:" + result + "\n");
Scanner scan = new Scanner(System.in);//调用Scanner类的使用System.in的方法实例化一个对象scan
System.out.println("请输入你看到的验证码:");
String input = scan.next();//将输入的字母转换成一个名为input的String类
if (input.equals(result)) {//调用String类的equals()方法进行比较
System.out.println("验证通过。");
k = 1;//跳出验证循环
//break; //这个也可以
} else {
System.out.println("验证失败,请重新输入");
}
}
System.out.println("验证成功就不会一直重复循环验证喽!");
}
}
运行测试,可以生成6位的验证码,并且可以比较你的输入是否正确,如果错误就会一直验证下去。
可是我还是觉得这个程序不够完美,为什么呢?因为它从头到尾都是纯文字的,没有图形化的输入。而且 ,一般验证码的验证是有错误次数限制的,一般为三次。所以,在闲的无聊的情况下我们可以将它图形化。
怎么图形化呢?查询API后发现这个就得使用Swing框架进行编程,我们引入javax.swing.JOptionPane包。使用它来实现图形化。设计代码如下:
import javax.swing.JOptionPane;
public class RandomStr {
public static void main (String []args) {
boolean Ifcontionue = true;//定义一个boolean型变量来做开关,控制是否继续验证
int Errcount = 0;//统计验证错误次数
while (Ifcontionue) {//由boolean参数生成的验证循环
String result = "";//验证字符串的声明。定义一个空字符串。
for (int i = 0 ; i <= 5 ; i++) {//这两行实现五次循环
int temp = (int)(Math.random() * 26 +97);//生成一个97~122的一个随机数。
result = result + (char)temp;//由于97~122的int型对应a~z的char型,所以使用强制类型转换。获得a~z的随机字母
}
String input = JOptionPane.showInputDialog("请输入验证码:"+result);
if (input.equals(result)) {//使用String的方法进行输入的比较。相同为true,反之为false
JOptionPane.showMessageDialog(null,"验证通过","正确提示",JOptionPane.INFORMATION_MESSAGE);
Ifcontionue = false;//此参数跳出验证的循环,也可使用break;
//break;
} else {
Errcount++;
JOptionPane.showMessageDialog(null,"验证失败,请重新验证!\n当前错误次数:"+Errcount,"错误提示", JOptionPane.ERROR_MESSAGE);
}
if (Errcount >= 3) {
JOptionPane.showMessageDialog(null,"错误次数超过3次,程序自动退出。","o(︶︿︶)o 唉", JOptionPane.WARNING_MESSAGE);
Ifcontionue = false;
//break;
}
}
}
}
运行测试:可以使用对话框输入,并且给予是否正确的提示,自动计算错误次数,实现3次自动退出。
但是还是不够完美,为什么?1、验证码不是大写的。2、在验证码是大写的前提下,如何忽略大小写。3、没有自定义生成的验证码长度。
第三个很好解决,主要会用到Integer包装类。前两个呢?进行查询API文档之后我发现String下面早就为我们准备好了相关方法。也就是toUpperCase()方法将字符串按一定规则变为大写字母,equalsIgnoreCase()就是忽略大小写的比较方法。所以设计出来的代码如下:
import javax.swing.JOptionPane;
public class RandomStr {
public static void main (String []args) {
boolean Ifcontinue = true;
int Errcount = 0;//统计验证错误次数
String length = JOptionPane.showInputDialog("请输入你要生成的验证码长度:");
int finallength = Integer.parseInt(length);//使用包装类实现验证码长度的定义
while (Ifcontinue) {//由Ifcontinue参数定义的验证循环
String result = "";//验证字符串的声明。定义一个空字符串。
for (int i = 0; i < finallength; i++) {//实现自定义次循环产生验证码
int temp = (int)(Math.random() * 26 +97);//生成一个97~122的一个随机数。
result = result + (char)temp;//由于97~122的int型对应a~z的char型,所以使用强制类型转换。获得a~z的随机字母
}
result = result.toUpperCase();
String input = JOptionPane.showInputDialog("请输入验证码:"+result+"\n(不记大小写)");
if (input.equalsIgnoreCase(result)) {//使用String的方法进行输入的比较。相同为true,反之为false
JOptionPane.showMessageDialog(null,"验证通过","正确提示",JOptionPane.INFORMATION_MESSAGE);
Ifcontinue = false;//此参数跳出验证的循环,也可使用break;
//break;
} else {
Errcount++;
JOptionPane.showMessageDialog(null,"验证失败,请重新验证!\n当前错误次数:"+Errcount,"错误提示", JOptionPane.ERROR_MESSAGE);
}
if (Errcount >= 3) {
JOptionPane.showMessageDialog(null,"错误次数超过3次,程序自动退出。","o(︶︿︶)o 唉", JOptionPane.WARNING_MESSAGE);
Ifcontinue = false;
//break;
}
}
}
}
运行测试:这个样子实现了自定义验证码长度,并且验证码显示为大写,可以忽略你输入的大小写。
可是还是不够完美啊。一般的验证码怎么可以没有数字,怎么可以只有大写英文字母。应该大小写英文字母都有才可以。
这些怎么办?怎么弄?其实都很简单哦,就是用之前的伪随机数。大家可以试试。
想出来了吗?没有?可以参考我的设计,设计代码如下:
import javax.swing.JOptionPane;
public class RandomStr {
public static void main (String []args) {
boolean Ifcontinue = true;
int Errcount = 0;//统计验证错误次数
String length = JOptionPane.showInputDialog("请输入你要生成的验证码长度:");
int finallength = Integer.parseInt(length);//使用包装类实现验证码长度的定义
while (Ifcontinue) {//由Ifcontinue参数定义的验证循环
String result = "";//验证字符串的声明。定义一个空字符串。
for (int i = 0; i < finallength; i++) {//实现自定义次循环产生验证码
int temp = 0;//定义一个中间变量存放验证码随机数
int Ifnum = (int)(Math.random()*2);//用来判断是否生成数字,由于Ifnum的结果只能为0,1且概率都为50%。所以1为数字随机,0为字母随机
if (Ifnum == 0) {//字母部分
temp = (int)(Math.random() * 26 +97);//生成一个97~122的一个随机数。
int Ifuppercase = (int)(Math.random()*2);//用来判断是否生将字母大小写。1为小写,0为大写
if (Ifuppercase == 0) {//大写字母部分
String uppTemp = "";//定义一个名为uppTemp的String类以存放转换为大写中间量
uppTemp = uppTemp +(char)temp;//获得a~z的随机字母,赋予uppTemp中间变量
uppTemp = uppTemp.toUpperCase();//获得大写随机字母
result = result + uppTemp;
} else {//小写字母部分
result = result + (char)temp;//由于97~122的int型对应a~z的char型,所以使用强制类型转换。获得a~z的随机字母
}
}
if (Ifnum == 1) {//数字部分,此处也可写为 else {
temp = (int)(Math.random()*10);//随机生成0~9
result = result + temp;//由自动类型转换得知,int型自动转换为String类
}
}
String input = JOptionPane.showInputDialog("请输入验证码:"+result+"\n(不记大小写)");
if (input.equalsIgnoreCase(result)) {//使用String的方法进行输入的比较。相同为true,反之为false
JOptionPane.showMessageDialog(null,"验证通过","正确提示",JOptionPane.INFORMATION_MESSAGE);
Ifcontinue = false;//此参数跳出验证的循环,也可使用break;
//break;
} else {
Errcount++;
JOptionPane.showMessageDialog(null,"验证失败,请重新验证!\n当前错误次数:"+Errcount,"错误提示", JOptionPane.ERROR_MESSAGE);
}
if (Errcount >= 3) {
JOptionPane.showMessageDialog(null,"错误次数超过3次,程序自动退出。","o(︶︿︶)o 唉", JOptionPane.WARNING_MESSAGE);
Ifcontinue = false;
//break;
}
}
}
}
运行结果,应该是目前比较完美的验证码生成+验证。(个人这么认为)
应用:这个看似没有用处。可是以面向对象的思路我们可以将其编写成为一个类用来专门生成验证码,并提供几个方法。现在假设我们定义一个creat(int length)来生成验证码的长度;verify()来确认是否验证正确,正确的话返回true,错误来返回false。以此来应用实际程序中,可谓是一个不错的思路。
现在我们就来设计这样的一个类(PS.懒得画类图了)
由此我们设计出来的类可以是这个样子:
/**
* Copyleft ? 2011 Syhily
* @author Syhily
* @author Syhily@gmail.com
* @version 1.4
*/
import javax.swing.JOptionPane;
public class RandomStr {
private int length = 6;// 定义 length 用于指定验证码的长度
int ErrNum = 3;// 定义 ErrNum 用于指定可以错误的次数,默认是3次。由于要打印错误次数所以不能private
private boolean IfNum = false;// 定义一个 IfNum 用于确认生成的验证码是否含有数字,默认没有
private boolean IfEng = true;// 定义一个 IfEng 用于确认生成的验证码是否含有字母,默认为true
private boolean IfEngSize = false;// 定义一个 IfEngSize
// 用于确认生成的验证码是否需要大小写字母,默认不需要
private String result = ""; // 定义一个 result来存放最终生成的字符串
int ErrCount = 0;// 定义一个 ErrCount 来统计错误的次数。由于要打印当前错误次数所以不能private
private boolean IfVerEngSize = false;// 定义一个 IfVerEngSize
// 用于确认比较验证码时是否需要比较字母大小写,默认为false
/**
* <pre>
* 定义一个构造方法,指定生成对象的验证码长度
* </pre>
*
* @param 由构造方法里的int型变量确定验证码长度
* @return 没有返回值
*/
public RandomStr(int a) {
length = a;
}
/**
* <pre>
* 定义一个方法,指定验证码允许的验证失败的次数
* </pre>
*
* @param 由构造方法里的int型变量确定验证失败的次数
* ,不指定时默认为3次
* @return 没有返回值
*/
public void definErrNum(int d) {
ErrNum = d;
}
/**
* <pre>
* 定义一个方法,指定验证码是否可以包含数字
* </pre>
*
* @param 由构造方法里的boolean型变量确定验证码是否可以包含数字
* ,true时将会包含数字。默认不包含
* @return 没有返回值
*/
public void ifNum(boolean f) {
IfNum = f;
}
/**
* <pre>
* 定义一个方法,指定验证码是否可以包含字母
* </pre>
*
* @param 由构造方法里的boolean型变量确定验证码是否可以包含字母
* ,true时将会包含字母。默认包含
* @return 没有返回值
*/
public void ifEng(boolean g) {
IfEng = g;
}
/**
* <pre>
* 定义一个方法,指定生成的验证码是否需要字母大小写
* </pre>
*
* @param 由构造方法里的boolean型变量确定验证码是否需要字母大小写
* ,true时将会生成有大小写字母的验证码。默认为大写
* @return 没有返回值
*/
public void ifEngSize(boolean h) {
IfEngSize = h;
}
/**
* <pre>
* 定义一个方法,指定比较验证码时否需要比较字母大小写
* </pre>
*
* @param 由构造方法里的boolean型变量确定比较验证码时否需要比较字母大小写
* ,true时将会比较字母的大小写。默认忽略大小写
* @return 没有返回值
*/
public void ifVerEngSize(boolean i) {
IfVerEngSize = i;
}
/**
* <pre>
* 定义一个方法,以此获得验证码
* </pre>
*
* @param 由构造方法里没有指定参数
* ,调用内部的CreatString()方法生成字符串 ,使用此方法将会返回一个随机的String类的验证码
* @return 返回生成的一个随机验证码
*/
public String getStr() {
CreatString();
return result;
}
/**
* <pre>
* 定义一个方法,比较你输入的验证码和之前获得验证码是否相同
* </pre>
*
* @param 由构造方法里的String类同之前getStr
* ()方法生成的字符串进行比较,默认忽略大小写
* @see getStr()
* @return 返回生成的一个随机验证码
*/
public boolean compareStr(String e) {
boolean Ifequal = false;// 定义返回的boolean,也就是验证是否相等
if (IfVerEngSize) {
Ifequal = result.equals(e);
} else {
Ifequal = result.equalsIgnoreCase(e);
}
return Ifequal;
}
/**
* <pre>
* 定义一个方法,比较你输入的验证码和之前获得验证码是否相同
* </pre>
*
* @param 由构造方法里的String类同之前getStr
* ()方法生成的字符串进行比较,默认忽略大小写
* @see getStr()
* @see compareStr(String e)
* @return 返回生成的一个随机验证码
*/
public boolean startVer(boolean b, boolean c) {
IfNum = b;
IfEngSize = c;
boolean Ifsuccess = false;// 定义返回的boolean,也就是验证是否成功
boolean Ifcontinue = true;// 定义Ifcontinue这个boolean类型的值用于确定是否继续验证
/*
* 这个部分同getStr()一样就是生成一个验证码喽。调用CreatString()方法生成
*/
while (Ifcontinue) {
result = "";
CreatString();
/*
* 这个部分同compareStr(String e)类似,只是将以对话框的形式进行确认。代码选用之前设计的RandomStr
*/
if (IfVerEngSize) {
String input = JOptionPane.showInputDialog("请输入验证码:" + result
+ "\n(区分大小写)");
if (input.equals(result)) {// 使用String的方法进行输入的比较。相同为true,反之为false
JOptionPane.showMessageDialog(null, "验证通过", "输入正确",
JOptionPane.INFORMATION_MESSAGE);
Ifsuccess = true;// 确定返回量为true
Ifcontinue = false;// 此参数跳出验证的循环,也可使用break;
// break;
} else {
ErrCount++;
JOptionPane.showMessageDialog(null, "验证失败,请重新验证!\n当前错误次数:"
+ ErrCount, "输入错误", JOptionPane.ERROR_MESSAGE);
}
if (ErrCount >= ErrNum) {
JOptionPane.showMessageDialog(null, "错误次数超过" + ErrNum
+ "次,程序自动退出。", "o(︶︿︶)o 唉",
JOptionPane.WARNING_MESSAGE);
Ifcontinue = false;
// break;
}
} else {
String input = JOptionPane.showInputDialog("请输入验证码:" + result
+ "\n(不记大小写)");
if (input.equalsIgnoreCase(result)) {// 使用String的方法进行输入的比较。相同为true,反之为false
JOptionPane.showMessageDialog(null, "验证通过", "输入正确",
JOptionPane.INFORMATION_MESSAGE);
Ifsuccess = true;// 确定返回量为true
Ifcontinue = false;// 此参数跳出验证的循环,也可使用break;
// break;
} else {
ErrCount++;
JOptionPane.showMessageDialog(null, "验证失败,请重新验证!\n当前错误次数:"
+ ErrCount, "输入错误", JOptionPane.ERROR_MESSAGE);
}
if (ErrCount >= ErrNum) {
JOptionPane.showMessageDialog(null, "错误次数超过" + ErrNum
+ "次,程序自动退出。", "o(︶︿︶)o 唉",
JOptionPane.WARNING_MESSAGE);
Ifcontinue = false;
// break;
}
}
}
return Ifsuccess;
}
/**
* <pre>
* 定义一个方法,根据预设好的参数来生成验证码字符串。
* </pre>
*
* @param 根据预设好的参数变量来生成验证码字符串
* 。不可以直接被外部类访问只能通过内部类调用产生相应的字符串。
* @return 返回String类的字符串验证码
*/
private String CreatString() {
for (int i = 0; i < length; i++) {// 实现自定义次循环产生验证码
int temp = 0;// 定义一个中间变量存放验证码随机数
if (IfNum && IfEng && IfEngSize) {
int Ifnum = (int) (Math.random() * 2);// 用来判断是否生成数字,由于Ifnum的结果只能为0,1且概率都为50%。所以1为数字随机,0为字母随机
if (Ifnum == 0) {// 字母部分
temp = (int) (Math.random() * 26 + 97);// 生成一个97~122的一个随机数。
int Ifuppercase = (int) (Math.random() * 2);// 用来判断是否生将字母大小写。1为小写,0为大写
if (Ifuppercase == 0) {// 大写字母部分
String uppTemp = "";// 定义一个名为uppTemp的String类以存放转换为大写中间量
uppTemp = uppTemp + (char) temp;// 获得a~z的随机字母,赋予uppTemp中间变量
uppTemp = uppTemp.toUpperCase();// 获得大写随机字母
result = result + uppTemp;
} else {// 小写字母部分
result = result + (char) temp;// 由于97~122的int型对应a~z的char型,所以使用强制类型转换。获得a~z的随机字母
}
}
if (Ifnum == 1) {// 数字部分,此处也可写为 else {
temp = (int) (Math.random() * 10);// 随机生成0~9
result = result + temp;// 由自动类型转换得知,int型自动转换为String类
}
} else {
if (IfNum && IfEng) {
int Ifnum = (int) (Math.random() * 2);// 用来判断是否生成数字,由于Ifnum的结果只能为0,1且概率都为50%。所以1为数字随机,0为字母随机
if (Ifnum == 0) {// 字母部分
temp = (int) (Math.random() * 26 + 97);// 生成一个97~122的一个随机数。
String uppTemp = "";// 定义一个名为uppTemp的String类以存放转换为大写中间量
uppTemp = uppTemp + (char) temp;// 获得a~z的随机字母,赋予uppTemp中间变量
uppTemp = uppTemp.toUpperCase();// 获得大写随机字母
result = result + uppTemp;
}
if (Ifnum == 1) {// 数字部分,此处也可写为 else {
temp = (int) (Math.random() * 10);// 随机生成0~9
result = result + temp;// 由自动类型转换得知,int型自动转换为String类
}
} else {
if (IfNum) {
temp = (int) (Math.random() * 10);// 随机生成0~9
result = result + temp;// 由自动类型转换得知,int型自动转换为String类
}
}
if (IfEng && IfEngSize && IfNum == false) {
temp = (int) (Math.random() * 26 + 97);// 生成一个97~122的一个随机数。
int Ifuppercase = (int) (Math.random() * 2);// 用来判断是否生将字母大小写。1为小写,0为大写
if (Ifuppercase == 0) {// 大写字母部分
String uppTemp = "";// 定义一个名为uppTemp的String类以存放转换为大写中间量
uppTemp = uppTemp + (char) temp;// 获得a~z的随机字母,赋予uppTemp中间变量
uppTemp = uppTemp.toUpperCase();// 获得大写随机字母
result = result + uppTemp;
} else {// 小写字母部分
result = result + (char) temp;// 由于97~122的int型对应a~z的char型,所以使用强制类型转换。获得a~z的随机字母
}
} else {
if (IfEng && IfNum == false) {
temp = (int) (Math.random() * 26 + 97);// 生成一个97~122的一个随机数。
String uppTemp = "";// 定义一个名为uppTemp的String类以存放转换为大写中间量
uppTemp = uppTemp + (char) temp;// 获得a~z的随机字母,赋予uppTemp中间变量
uppTemp = uppTemp.toUpperCase();// 获得大写随机字母
result = result + uppTemp;
}
}
}
}
return result;
}
}
至于怎么使用这个类,我们可以编写一个驱动类来调用:
学习心得:一个简单的强制类型转换的实例玩出这么多的花样,这个本来也是我所没有想到的。但是这样也体现出了程序世界的精彩。同时,此次实践最关键的是API文档的查询。一切基础就是JavaDOC,通过它我们找到各种类库,和它们提供的方法,以此来实现我们的编程。当然程序的各种判定也体现了Java这种面向对象编程语言在“类”这个结构下面的结构化编程,分支循环的利用可以使你的程序更加人性化、健壮。
最后我要小小的吐槽一下,ITeye的日志编辑器编辑代码真的很蛋疼!