Controller层
这里一定要设置响应类型,否则不识别,
注释掉的部分是使用session存储,这里建议还是使用redis进行储存,解放服务器;如果想用session储存,需要把service部分生成图片部分拿回来,因为那里并行了一个StringBuilder收集验证码;
@Controller
@RequestMapping("/code")
public class CodeController {
@Autowired
private Code code;
@RequestMapping("/img")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer id){
//设置响应类型
response.setContentType("image/jpeg");
// 不缓存此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
try {
BufferedImage imge = code.getCode(id);
/* //这里使用Session保存验证码,建议在业务曾调用redis进行保存
HttpSession session = request.getSession();
session.removeAttribute("captcha");
session.setAttribute("captcha",code.toString());
session.setMaxInactiveInterval(-1);//设置session不会过期*/
//必须使用write才能写出验证码
ImageIO.write(imge,"JPEG",response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}
必须使用 ImageIO.write进行写入,否则无法显示
同样的也可以用于二维码等图片的回显;首先这里的image就是图片流,response.getOutputStream获取了一个响应输出流,通过他就可以在页面上直接响应,如果是使用的本地流就会生成在本地;
Service
这里生成了随机验证码,并缓存到了redis
@Service
public class Code {
@Autowired
private RedisTemplate<String,String> redisTemplate;
public BufferedImage getCode(Integer id){
String redisKey = id+"USERCODE";
int width = 250;
int height= 60;
//生成对应宽高的初始图片
BufferedImage verifyImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
//调用方法把画板给他,生成验证码字符串,加上随机线和噪点,返回值为验证码字符串
String ranCode = new Code().drawRandomText(width,height,verifyImg);
System.out.println("验证码为:"+ranCode);
//将验证码缓存到redis
redisTemplate.opsForValue().set(redisKey,ranCode, Duration.ofMinutes(5));
return verifyImg;
}
//图片处理
public String drawRandomText(int width,int height,BufferedImage verifyImg){
//在传过来的画板上开一个2d画笔
Graphics2D graphics =(Graphics2D)verifyImg.getGraphics();
//设置画笔颜色
graphics.setColor(Color.white);//这个给验证码背景好了
//用笔填充背景操作指定范围
graphics.fillRect(0,0,width,height);
//设置字体
graphics.setFont(new Font("黑体",Font.BOLD,40));
//设置一个字符池
String baseNumLetter="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
StringBuffer stringBuffer = new StringBuffer();
int x= 10;//原点的坐标
//预设一个空字符
String ch = "";
//来一个循环一次循环生成一个随机code字符
Random ran=new Random();
for (int i = 0; i < 5; i++) {
//先获取一个随机颜色,设置在画笔对象上
graphics.setColor(getRandomColor());
int degree = ran.nextInt()%30;//角度小于30度,生成随机+-30范围百,这里用来表示角度
//基于字符池长度生成随机索引,一会取字符用
int dot = ran.nextInt(baseNumLetter.length());
//根据随机取出的下标索引随机区一个字符
ch =baseNumLetter.charAt(dot)+"";
//将取出的字符追加上去。这里只是收集验证码最终结果而已,方便一会返回,下面写入的时候是按照临时的ch写入
stringBuffer.append(ch);
//操纵画笔正向旋转degree度。上面定义好的一个数字X为X轴坐标
graphics.rotate(degree*Math.PI/180,x,45);
//操纵画笔写下字符(内容,X轴,Y轴)
graphics.drawString(ch,x,45);
//将画笔旋转回来
graphics.rotate(-degree*Math.PI/180,x,45);
//推进画笔的x轴值。
x+=48;
}
//循环结束5个字符写上去了
//画干扰线画几条随便
for (int i = 0; i < 8; i++) {
//给画笔涂上随机颜色
graphics.setColor(getRandomColor());
//操纵画笔随机画线,传参设置线条的长度宽度距离边缘的长度宽度
graphics.drawLine(ran.nextInt(width),ran.nextInt(height),ran.nextInt(width),ran.nextInt(height));
}
//添加噪点,这个多整点
for (int i = 0; i < 40; i++) {
int xx = ran.nextInt(width);
int yy = ran.nextInt(height);
//给画笔涂上随机颜色
graphics.setColor(getRandomColor());
//下手画点,给出上面定义好的位置坐标,以及像素宽度长度
graphics.fillRect(xx,yy,2,2);
}
//画板已经画完了,顺便将收集好的验证码return出去;
return stringBuffer.toString();
}
//获取随机颜色的方法
private Color getRandomColor() {
Random ran=new Random();
Color color=new Color(ran.nextInt(256),ran.nextInt(256),ran.nextInt(256));
return color;
}
}
效果:
调用方法生成验证码并缓存结束后返回。。。复制即可用