Springboot 验证码生成图片格式和base64编码格式
生成验证码:
提供一个接口, 这个接口里,我们将生成的验证码存入session,然后将验证码以图片格式或者base64编码串返回给调用端。
校验验证码:
提供一个接口,这个接口里,我们收到调用端传过来的校验码,然后从session取出验证码,两个验证码都全部转小写,进行无大小写区分匹配校验,返回true/flase 。
存储验证码:
生成的验证码,在未生成图片的时候,就将4位验证码字符先存入session,以‘JCCODE’作为存取session的key。
先创建工具类,ValidateCodeUtil.java:
import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.util.Base64; import java.util.Random; public class ValidateCodeUtil { private static Random random = new Random(); private int width = 165; //验证码的宽 private int height = 45; //验证码的高 private int lineSize = 30; //验证码中夹杂的干扰线数量 private int randomStrNum = 4; //验证码字符个数 private String randomString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ"; private final String sessionKey = "JCCODE"; //字体的设置 private Font getFont() { return new Font("Times New Roman", Font.ROMAN_BASELINE, 40); } //颜色的设置 private static Color getRandomColor(int fc, int bc) { fc = Math.min(fc, 255); bc = Math.min(bc, 255); int r = fc + random.nextInt(bc - fc - 16); int g = fc + random.nextInt(bc - fc - 14); int b = fc + random.nextInt(bc - fc - 12); return new Color(r, g, b); } //干扰线的绘制 private void drawLine(Graphics g) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(20); int yl = random.nextInt(10); g.drawLine(x, y, x + xl, y + yl); } //随机字符的获取 private String getRandomString(int num){ num = num > 0 ? num : randomString.length(); return String.valueOf(randomString.charAt(random.nextInt(num))); } //字符串的绘制 private String drawString(Graphics g, String randomStr, int i) { g.setFont(getFont()); g.setColor(getRandomColor(108, 190)); //System.out.println(random.nextInt(randomString.length())); String rand = getRandomString(random.nextInt(randomString.length())); randomStr += rand; g.translate(random.nextInt(3), random.nextInt(6)); g.drawString(rand, 40 * i + 10, 25); return randomStr; } //生成随机图片 public void getRandomCodeImage(HttpServletRequest request, HttpServletResponse response){ HttpSession session = request.getSession(); // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); Graphics g = image.getGraphics(); g.fillRect(0, 0, width, height); g.setColor(getRandomColor(105, 189)); g.setFont(getFont()); // 干扰线 for (int i = 0; i < lineSize; i++) { drawLine(g); } // 随机字符 String randomStr = ""; for (int i = 0; i < randomStrNum; i++) { randomStr = drawString(g, randomStr, i); } System.out.println("随机字符:"+randomStr); g.dispose(); //移除之前的session中的验证码信息 session.removeAttribute(sessionKey); //重新将验证码放入session session.setAttribute(sessionKey, randomStr); try { // 将图片以png格式返回,返回的是图片 ImageIO.write(image, "PNG", response.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } //生成随机图片的base64编码字符串 public String getRandomCodeBase64(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); Graphics g = image.getGraphics(); g.fillRect(0, 0, width, height); g.setColor(getRandomColor(105, 189)); g.setFont(getFont()); //干扰线 for (int i = 0; i < lineSize; i++) { drawLine(g); } //随机字符 String randomStr = ""; for (int i = 0; i < randomStrNum; i++) { randomStr = drawString(g, randomStr, i); } System.out.println("随机字符:"+randomStr); g.dispose(); session.removeAttribute(sessionKey); session.setAttribute(sessionKey, randomStr); String base64String = ""; try { // 直接返回图片 // ImageIO.write(image, "PNG", response.getOutputStream()); //返回 base64 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(image, "PNG", bos); byte[] bytes = bos.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); base64String = encoder.encodeToString(bytes); } catch (Exception e) { e.printStackTrace(); } return base64String; } }
接下来写接口,创建一个ValidateCodeController.java,
先是生成验证码,返回图片的接口:
import com.example.demo.util.ValidateCodeUtil; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * @Author : JCccc * @CreateTime : 2019/9/25 * @Description : **/ @RestController public class ValidateCodeController { //返回验证码图片 @GetMapping("/getCaptchaImg") public void getCaptchaImg(HttpServletRequest request, HttpServletResponse response, HttpSession session) { try { response.setContentType("image/png"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Expire", "0"); response.setHeader("Pragma", "no-cache"); ValidateCodeUtil validateCode = new ValidateCodeUtil(); // getRandomCodeImage方法会直接将生成的验证码图片写入response validateCode.getRandomCodeImage(request, response); // System.out.println("session里面存储的验证码为:"+session.getAttribute("JCCODE")); } catch (Exception e) { e.printStackTrace(); } } }
用postman来调用下接口,
可以看到控制台的打印,这个验证码字符串已经存入了session(在后面的验证接口有介绍取值)
接下来是编写一个校验验证码接口:
//验证码校验 @GetMapping("/checkCaptcha") public boolean getCheckCaptcha(@RequestParam("code") String code, HttpSession session) { try { //toLowerCase() 不区分大小写进行验证码校验 String sessionCode= String.valueOf(session.getAttribute("JCCODE")).toLowerCase(); System.out.println("session里的验证码:"+sessionCode); String receivedCode=code.toLowerCase(); System.out.println("用户的验证码:"+receivedCode); return !sessionCode.equals("") && !receivedCode.equals("") && sessionCode.equals(receivedCode); } catch (Exception e) { return false; } }
用postman调下接口,先生成验证码模拟返回给页面了,
然后调用校验验证码接口,模拟用户在页面输入验证码,
可以看到校验正确。
返回base64编码串的接口:
// 生成验证码,返回的是 base64 @GetMapping("/getCaptchaBase64") public Object getCaptchaBase64(HttpServletRequest request, HttpServletResponse response) { Map result = new HashMap(); try { response.setContentType("image/png"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Expire", "0"); response.setHeader("Pragma", "no-cache"); ValidateCodeUtil validateCode = new ValidateCodeUtil(); // 返回base64 String base64String = validateCode.getRandomCodeBase64(request, response); result.put("url", "data:image/png;base64," + base64String); result.put("message", "created successfull"); //http://tool.chinaz.com/tools/imgtobase/ base64直接转为图片网站 System.out.println("结果:" + result.get("url")); } catch (Exception e) { System.out.println(e); } return result; }
用postman调用一下,
控制台打印:
将url取出来,
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKUAAAAtCAIAAABAqjw4AAACjklEQVR42u3bzW7DIAwHcB57x0l7hG67TVp37juySpFQlPDxj21sKEacWrRQfhDAsBDh9H372HIcJj3+vp45eoJTmNp7r+7wq3if4d1+Yu/74w3PPugX9fY5fkpvJranKb2liq25HdjXmeWdPunXD56KzSZWHt+VlcGwHSJVjO59wO6hvhGC3uPs/gW3Ce/32zML9lGKd9a130AHvfetXMr6u3/aczfmlI3n75KoCfnhZW64BZd66AHb3lt/Tdf0fsnAyyVv8Jf28lZbxtcn76nhS96lRYPNfkzTG1+Zz6h+yRskfwVvweXVln4/f7IZL5At5t4G3jh8kwq0JEi7d8cwS0W9yYkUUHufI+TTe3fdTbl3A/L5vEox2eWSQlgNeWM33/mC3s19udn45uwRNV/mODmhAAf77H2Ow1wd/cLe+8HN2SMOMrjB4VtfnwsG2irf2ninMtsjzzPijN7ICFbwphWQ8a7HzyuBLSlv5QPQJme2ABM7YvHUjt518soaLTHLeqvFuZDhm43JaHqD5IFQD8Kxt2w4c38AijyUfzDa5DwU4GPjY7e7N3OPy4QvHYCSa4J0Bdw7zegjeJ9/jrY3EtWivcy7HocgnGTvUodjemcbxMybjGR1ewn3Zg7uBC8yvg/NG+JUyfDqMT/WZvU+J95PbXZJNW+r3pY4S3P/mN6Rdj91HHVbb06Bft7IBHrtfurV6WdBb6mVuVS8RXW95v+xV98BCnrjNyCC2k8dsN35ZrJ/7WrsbP8VeEAV9Bt6zDEnZS9bwyz59pTsh2PFW1ZY1vWwR469o/j9NU+jdSz3Xp3cvZ3cvRcmd++1yMPg/dGTbKsGq8q5ugl5sK2fqyuT29xncnXlBk/5HyEm10e/qyfBAAAAAElFTkSuQmCC
去base64编码串转图片的网站去看看,对应的验证码图: