<!-- 验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
import java.util.Random;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
/**
* 验证码文本生成器
*
* @author ruoyi
*/
public class KaptchaTextCreator extends DefaultTextCreator
{
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText()
{
Integer result = 0;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2);
if (randomoperands == 0)
{
result = x * y;
suChinese.append(CNUMBERS[x]);
suChinese.append("*");
suChinese.append(CNUMBERS[y]);
}
else if (randomoperands == 1)
{
if (!(x == 0) && y % x == 0)
{
result = y / x;
suChinese.append(CNUMBERS[y]);
suChinese.append("/");
suChinese.append(CNUMBERS[x]);
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
}
else if (randomoperands == 2)
{
if (x >= y)
{
result = x - y;
suChinese.append(CNUMBERS[x]);
suChinese.append("-");
suChinese.append(CNUMBERS[y]);
}
else
{
result = y - x;
suChinese.append(CNUMBERS[y]);
suChinese.append("-");
suChinese.append(CNUMBERS[x]);
}
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result);
return suChinese.toString();
}
}
//数字版文字
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
//数字
@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "45");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
// 验证码文本生成器 没特殊设置就是默认的
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
// 验证码文本字符间距 默认为2
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "5");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑");
//properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
// 干扰实现类
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
//properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
String capStr = null, code = null;
BufferedImage image = null;
String captchaType = captchaProperties.getType();
// 生成验证码
if ("math".equals(captchaType))
{
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try
{
ImageIO.write(image, "jpg", os);
}
catch (IOException e)
{
return AjaxResult.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
<img src="data:image/gif;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAA8AKADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtrW1ga1hZoIySikkoOeKsCztv+feL/vgU2z/484P+ua/yqyKiMY8q0IjGPKtCIWdr/wA+0P8A3wKeLK1/59of+/YqUU4U+WPYfLHsRCytP+fWH/v2KcLG0/59YP8Av2KrX2uaVpTBb/Uba3c9EklAY/Qdat2d5bX0AntJ45oj0eNgRRyx7Byx7Ciws/8An1g/79inCws/+fSD/v2KnFOFHLHsHLHsQjT7L/n0t/8Av2P8KcNOsv8Anzt/+/S/4VOKeKOWPYOWPYgGnWP/AD52/wD36X/CnDTbH/nyt/8Av0v+FWBShlOMMORkc9RRyx7Byx7EA0yw/wCfK2/79L/hTxplh/z423/fpf8ACp0IYZUgj1BqQUcsewcsexWGl6f/AM+Nt/35X/CnjStP/wCfC1/78r/hVkU8UcsewcsexVGlad/z4Wv/AH5X/CnDSdO/6B9r/wB+V/wqw8iRRtJI6oijJZjgD8az7fxNoNzdC2h1mwknJwI1uFyx9hnn8KOWPYOWPYtjSdN/6B9p/wB+V/wqtqel6fHpF66WNqrrA5VhCoIO08jitYVV1b/kC3//AF7yf+gmlKMeV6ClGPK9DkrP/jzg/wCua/yqyKr2f/HnB/1zX+VWRTj8KHH4UOFeSeMviLqd7ro8M+FfluHk8lrgYyW7hc9B7164K+YvENlqvgnxxJchWSSOczQSsMq4JP8AjVFHc3vwZMeiXWo3+tSzaisbTP8AL8mQMkZJyfr+lZvwS1S8i8QzacpZraeMthj8qlcEn64NU9c+Lup654fOlm2itpJvlmnQnlfQDtmvSvhb4f0PT9EW7067S9uJDmSYcFTgZXHagD0IU4UgpwoAcK4fx747bwtaubaBbhgNj/fGxj05Ax+o/pXazXENsm+eaOJc43OwAz+NfO/xglCa5JbnrkMG2jp2X2wOuOp69aAH6P4t8ZeK78fZpHmeNjscqm5BjoGCZBOPYHHIzXTxaL48U4a5jUxsGG0NjlcCRcnKnPBA9xjHS38OfEfhrwp4MiW+1C2hupGJdA4JJxx0JHpz/I5Fb8Xxh8Ky3awC5I3MFDEHByfb+tAHWeG7G9sNGij1E25vm+e4a3zsZ+5Gee1bIqpp+oWmp2q3NnOk0TZwynryRn8wa4DxZ8VpvB2uLa3uhvNZuzKs0chVuMcgEYPB9RQB6aKeK4LSfjB4K1WME6r9jkPWK8jKEfjyv5GptT+LngnS4ix1lLp+0dqhkLfiOB+JFAG14y8Nt4s8OSaOLx7RJpEMkiddqnJA+uK4C5/Z48PyWhW21S/huQPlkbayk+645/Aiui8B/E638eazf2lnpk1tb2sQkWWaQFnycYKgYH5mu5u7220+0kurudIYIxlnc4AoA+bf+Er8afCHxANG1C5N/YqA0ccpJV4/VCeV+le9af4htPFPgSXV7PIintZMqeqnacg184/FLxOnj7xpBHo8TzRwJ9ngKjmQk5zj61754Q8Ny+FPhb/Zdx/x8LayySj0ZlJIqZfCyZfCxln/AMeUH/XNf5VZFV7L/jyg/wCua/yqyKI/Cgj8KBmVEZ2OFUZJ9BXhOr6xdfFDx3baFCwg0uKU9B8xVfvMff0r3dkWRGRhlWGCPUV8ybdV+GnjpZ3hLNbudpcYWeM5BwfcH86oo9Z1X4L+HL2L/QTPZTDGCr7lP1BrzbwZqN74G8f/AGGeXMZDxTxZ4dtpKj2O7aK626+N017ALbRtCla8kGAXkyFPsAOf0rJ8M/DnxFr2vf2xriNArtvcycM/+H+NAHpHjq88X2sWn3nhOIzKwJuYmRW4428Hnuc49K45NZ+LmtEW8VqlgGwGkECqQOMnLZ9e3vXtQp4oA8i0z4R6vcalb6j4h103kpBEqOWkIVl5Ck9CDwPqDxjBwfjBoE9mfPt4t1rvaRykeNhY5JOOOeMnodq9DnPvorD8YeGIvFegyadI4jY5KOUVtrYIz8ynHXtg+9AHlXwu8D6V4i0WG+1CzgnQK6sHVyXbcBkt0GFHAH97J6CqfxQ+G+m6Cv2/Ska3gKBhFuLZwH3nnpjEXf8AiapfAGv3nw88Q3fhrWAxtXfchWF/vDgld2CAeOx6Vs/Ebxppus6Stpp8kU00mUQoA+5sgj5ugVchiR1IUdMggCfAjU55LWSyaU+XGJGZWOdwJjEePTaVmznH3x1rt/Fvj7RfDeoLput2UstpMoDSiIPGGOTtYH2Cnv1PpWN8IfC8ujaSZrhJlmblt/yjJ+6NuMjapP4yEHOBj0HVNE0zW7U22pWUNzESDtkXPI6c/wCetAHnH/CJfCbxh/pFjLZwyNyRaXHkH/v2eB/3yKcPA3wn8Kf6TqNxaysvIF5eeYT9I1PzfkabqnwC8O3cnmadeXdhn+AESKOnrz2PfvTdK/Z88PW0ok1LUb6+A/5ZqREp+uMn8iKAOh8I/Enwrrmvjw54etZY0SJpEdYFhhIXHCr17+g6Vxv7QR1+Yafb2drdvpCxGS4lhjZk35wAxHTAGefWvWNE8JeH/Dqj+ydItLRwMeYkYMhHu5+Y/ia534neO9Q8A2ul39rYwXdrPM0U6SEq2cZXaw6dG6g0Ac18A/Culp4YHiJ4Vl1CaZ0DsM+UFOMD375969b1f/kCX/8A17Sf+gmuW+HHjfSfG2m3k+mac2nyQSj7RCQuCzD7wK9c46kA8V1Wr/8AIEv/APr2k/8AQTUy+Fky+FnJWX/Hlb/9c1/lVkVzMWtXMUSRqkRCKFGQe341J/b91/zzh/75P+NZRrRsjONWNkdKKr3umWOpxiO+s4LlB0WaMMB+dYf/AAkN3/zzg/75P+NL/wAJFd/884P++T/jVe2iP20TesdMsNOQpZWcFup6+VGFz9cdauiuV/4SS8/55Qf98n/Gl/4SW8/55Qf98n/Gj20Q9tE6wU8VyP8Awk97/wA8rf8A75b/ABpf+Eovf+eVv/3y3+NHtoh7aJ14p4rjv+Eqvv8Anlb/APfLf40v/CV33/PK2/75b/Gj20Q9tE2df8Mab4kthHfW8cjoD5TSLuCE98ZFY2j/AAy0bTLxLlg0sihRkcBgvRcckIMD5cnOBnOBS/8ACW3/APzxtv8Avlv8aX/hL9Q/5423/fLf/FUe2iHtonaRRpEm1FCrknA9Sck/nUorh/8AhMNQ/wCeNr/3y3/xVL/wmWo/88bX/vlv/iqPbRD20TuhTxXB/wDCZ6j/AM8bX/vhv/iqX/hNdS/54Wn/AHw3/wAVR7aIe2id6KZc2dtfW7W95bw3EDfejmQOp+oPFcN/wm2pf88LT/vhv/iqX/hONT/54Wn/AHw3/wAVR7aIe2idNoXhDQvDV1eXGjaelk15t89YmIRtuduFzgY3HpjrWjq//ID1D/r2k/8AQTXFf8Jzqf8AzwtP++G/+KqO58Z6jdWs1u8NqElRkYqrZAIxx81TKtGzFKrGzP/Z"></img>
</html>
前端用base64接,节省一个http调用,且这个地址可以直接在url调用。