最近需要生成一個動態的驗證碼,在登入頁面使用,並在前後端進行校驗;
實現原理:
後端生成動態二維碼,儲存在 session 裡面;
前端調取介面,展示在登入頁面;
前端登入時候,把驗證碼傳給後端,後端和 session 裡面的值進行對比。
1 生成動態驗證碼圖片
新建一個 class
類 ValidateCode
:
package hello;
import org.apache.commons.io.FileUtils;
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.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
// 生成隨機驗證碼
public class ValidateCode {
private static Random random = new Random();
private int width = 160;// 寬
private int height = 40;// 高
private int lineSize = 30;// 干擾線數量
private int stringNum = 4;//隨機產生字元的個數
private String randomString = "0123456789abcdefghijklmnopqrstuvwxyz";
private final String sessionKey = "RANDOMKEY";
/*
* 獲取字型
*/
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 random_string = "";
for (int i = 0; i < stringNum; i++) {
random_string = drawString(g, random_string, i);
}
System.out.println(random_string);
g.dispose();
session.removeAttribute(sessionKey);
session.setAttribute(sessionKey, random_string);
String base64String = "";
try {
// 直接返回圖片
ImageIO.write(image, "PNG", response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
複製程式碼
接下來寫個 Controller
, 提供個介面給前端:
package hello;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/user")
public class ValidateCodeController {
// 生成驗證碼圖片
@RequestMapping("/getCaptchaImage")
@ResponseBody
public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
try {
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expire", "0");
response.setHeader("Pragma", "no-cache");
ValidateCode validateCode = new ValidateCode();
// 直接返回圖片
validateCode.getRandomCodeImage(request, response);
} catch (Exception e) {
System.out.println(e);
}
}
}
複製程式碼
2 前端調取介面
結果如圖:3 返回 base64 字串
有時候我們不能直接返回圖片,需要返回一個 json 的資料比如:
這時候我們就需要把 image
轉化為 base64
;
具體程式碼如下:
在之前的 ValidateCode
類中新增一個方法:
/*
* 生成隨機圖片,返回 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 random_string = "";
for (int i = 0; i < stringNum; i++) {
random_string = drawString(g, random_string, i);
}
System.out.println(random_string);
g.dispose();
session.removeAttribute(sessionKey);
session.setAttribute(sessionKey, random_string);
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;
}
複製程式碼
在 Controller 新增另外一個路由介面:
// 生成驗證碼,返回的是 base64
@RequestMapping("/getCaptchaBase64")
@ResponseBody
public Object getCaptchaBase64(HttpServletRequest request, HttpServletResponse response) {
Map result = new HashMap();
Response response1 = new Response();
try {
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expire", "0");
response.setHeader("Pragma", "no-cache");
ValidateCode validateCode = new ValidateCode();
// 直接返回圖片
// validateCode.getRandomCode(request, response);
// 返回base64
String base64String = validateCode.getRandomCodeBase64(request, response);
result.put("url", "data:image/png;base64," + base64String);
result.put("message", "created successfull");
System.out.println("test=" + result.get("url"));
response1.setData(0, result);
} catch (Exception e) {
System.out.println(e);
}
return response1.getResult();
}
複製程式碼
呼叫結果:
在前端頁面中,只要把URL
放到 image
的 URL
中,即可顯示,這裡不再演示。
3 驗證驗證碼
生成:
驗證: