问题描述
easy-captcha的算术验证码在进行减法计算时,可能会生成负数的结果,但我们并不希望它出现负数。
代码实现
本文有两种方案解决负数问题,都利用了继承。
方法一 重复生成验证码直到非负为止
生成验证码时,如果得到负数的结果,就再重新生成,直到为正数为止。
可利用继承,重写checkAlpha方法,代码如下:
ArithmeticCaptchaComponent.java
import com.wf.captcha.ArithmeticCaptcha;
import java.awt.*;
public class ArithmeticCaptchaComponent extends ArithmeticCaptcha {
public ArithmeticCaptchaComponent() {
super();
}
public ArithmeticCaptchaComponent(int width, int height) {
this();
setWidth(width);
setHeight(height);
}
public ArithmeticCaptchaComponent(int width, int height, int len) {
this(width, height);
setLen(len);
}
@Override
public void checkAlpha() {
// 生成验证码直到非负为止
while(chars == null || Integer.parseInt(chars) < 0) {
alphas();
}
}
}
使用方法参考:
// ...
ArithmeticCaptchaComponent captcha = new ArithmeticCaptchaComponent(130, 48);
captcha.setLen(2);
String code = captcha.text(); //text方法会调用重写的checkAlpha方法,生成一个非负结果的验证码。
captcha.out(os);
// ...
说明:只要将原来的ArithmeticCaptcha换成ArithmeticCaptchaComponent来实例化对象即可,其它操作不变。
这种方式适合生成负数的几率小的情况,比较简单。如果生成负数的几率比较大,建议使用方法二。
方法二 重写alphas方法,当生成负数结果时将减号换成其它运算符
生成验证码时,如果得到负数的结果,就将减号改成其它符号(如+号)。
也是利用继承,重写alphas方法,代码如下:
ArithmeticCaptchaComponent.java
import com.wf.captcha.ArithmeticCaptcha;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.awt.*;
public class ArithmeticCaptchaComponent extends ArithmeticCaptcha {
public ArithmeticCaptchaComponent() {
super();
}
public ArithmeticCaptchaComponent(int width, int height) {
this();
setWidth(width);
setHeight(height);
}
public ArithmeticCaptchaComponent(int width, int height, int len) {
this(width, height);
setLen(len);
}
@Override
protected char[] alphas() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
sb.append(num(10));
if (i < len - 1) {
int type = num(1, 4);
if (type == 1) {
sb.append("+");
} else if (type == 2) {
sb.append("-");
} else if (type == 3) {
sb.append("x");
}
}
}
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
try {
chars = String.valueOf(engine.eval(sb.toString().replaceAll("x", "*")));
if(Integer.parseInt(chars) < 0) { // 结果为负数,将所有减号换成加号
int index = sb.indexOf("-");
while(index != -1) {
sb.setCharAt(index, '+');
index = sb.indexOf("-");
}
chars = String.valueOf(engine.eval(sb.toString().replaceAll("x", "*")));
}
} catch (ScriptException e) {
e.printStackTrace();
}
sb.append("=?");
setArithmeticString(sb.toString());
return chars.toCharArray();
}
}
使用方法参考:(和 方法一 相同)
// ...
ArithmeticCaptchaComponent captcha = new ArithmeticCaptchaComponent(130, 48);
captcha.setLen(2);
String code = captcha.text(); //text方法会调用重写的alphas方法,生成一个非负结果的验证码。
captcha.out(os);
// ...
说明:只要将原来的ArithmeticCaptcha换成ArithmeticCaptchaComponent来实例化对象即可,其它操作不变。
可能还有更优的算法替换减号。
这种方式直接将运算符替换,只执行一次alphas方法就必定能生成非负的验证码。
方法一更容易理解些,建议使用,算术验证码算式不会太复杂的,就重复生成直到非负即可。