在 Web 开发中,动态生成图片并通过 API 传递给前端展示是一个常见需求,例如验证码生成、动态图表等。本文将以 Java 的 Spring Boot 框架和 anji-captcha
依赖为例,详细讲解如何生成验证码图片、如何通过 JSON 传递给前端、前端如何渲染,以及前端判定成功后如何回传结果。同时,我们会解答一个有趣的问题:JSON 不是通常用来传递文本的吗?为什么可以传递图片?图片又是如何通过 Base64 编码实现的?
1. 后端如何生成图片:基于 anji-captcha
anji-captcha
是一个轻量级的验证码生成工具,支持滑块验证码和点击验证码等形式。它内置了图片生成逻辑,我们只需通过配置将其集成到 Spring Boot 项目中。
依赖配置
首先,在 pom.xml
中引入 anji-captcha
依赖:
xml
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>captcha-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
后端实现
在 Spring Boot 中,我们通过控制器调用 anji-captcha
的服务生成验证码图片。以下是一个简单的实现:
java
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CaptchaController {
@Autowired
private CaptchaService captchaService;
@GetMapping("/generate-captcha")
public ResponseModel generateCaptcha() {
CaptchaVO captchaVO = new CaptchaVO();
captchaVO.setCaptchaType("blockPuzzle"); // 设置验证码类型为滑块验证码
ResponseModel response = captchaService.get(captchaVO);
return response;
}
}
运行这段代码后,captchaService.get()
会返回一个 ResponseModel
,其中包含验证码图片的 Base64 编码字符串。anji-captcha
内部已经将生成的图片(通常是 PNG 格式)转换为 Base64 格式。
返回的 JSON 格式
假设我们请求 /generate-captcha
,后端返回的 JSON 可能是这样的:
json
{
"success": true,
"repCode": "0000",
"repData": {
"captchaId": "abc123",
"originalImageBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADp90t...",
"jigsawImageBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADp90t...",
"token": "xyz789"
},
"repMsg": "操作成功"
}
originalImageBase64
:背景图片的 Base64 编码。jigsawImageBase64
:滑块图片的 Base64 编码。captchaId
和token
:用于后续验证。
2. 如何将图片传递给前端
在上面的 JSON 中,图片数据通过 originalImageBase64
和 jigsawImageBase64
字段传递。这些字段的值是图片的 Base64 编码字符串,前面带有 MIME 类型前缀 data:image/png;base64,
,告诉前端这是一个 PNG 格式的图片数据。
这种方法的好处是:
- JSON 本身是文本格式,Base64 编码将二进制图片数据转为文本,完美兼容 JSON。
- 前端无需额外请求图片资源,直接从 JSON 中提取并渲染。
3. 前端如何渲染图片
前端拿到 JSON 后,可以直接使用 <img>
标签渲染 Base64 编码的图片。以下是一个简单的 JavaScript 和 HTML 示例:
html
<!DOCTYPE html>
<html>
<head>
<title>Captcha Demo</title>
</head>
<body>
<img id="background" alt="Background Image">
<img id="jigsaw" alt="Jigsaw Image">
<button onclick="verifyCaptcha()">验证</button>
<script>
// 获取验证码图片
fetch('/generate-captcha')
.then(response => response.json())
.then(data => {
if (data.success) {
let repData = data.repData;
document.getElementById('background').src = repData.originalImageBase64;
document.getElementById('jigsaw').src = repData.jigsawImageBase64;
window.captchaId = repData.captchaId; // 保存 captchaId 用于验证
window.token = repData.token; // 保存 token 用于验证
}
});
// 模拟用户拖动滑块后的验证逻辑
function verifyCaptcha() {
let verifyData = {
captchaId: window.captchaId,
token: window.token,
point: { x: 150, y: 50 } // 假设用户拖动到这个位置
};
fetch('/verify-captcha', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(verifyData)
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert('验证成功!');
} else {
alert('验证失败!');
}
});
}
</script>
</body>
</html>
- 渲染 :
img.src
直接赋值为 Base64 字符串,前端浏览器会自动解码并显示图片。 - 用户交互 :用户拖动滑块后,前端记录滑块位置(如
{x: 150, y: 50}
)。
4. 前端判定成功与否后如何回传
用户完成滑块操作后,前端将验证数据回传给后端。回传的 JSON 示例:
json
{
"captchaId": "abc123",
"token": "xyz789",
"point": {
"x": 150,
"y": 50
}
}
后端验证逻辑(基于 anji-captcha
):
java
@PostMapping("/verify-captcha")
public ResponseModel verifyCaptcha(@RequestBody CaptchaVO captchaVO) {
return captchaService.check(captchaVO);
}
captchaService.check()
会校验用户提交的滑块位置是否正确,并返回结果:
json
{
"success": true,
"repCode": "0000",
"repMsg": "验证成功"
}
前端根据 success
字段判断验证是否成功。
5. JSON 为什么能传递图片?Base64 编码是怎么回事?
你可能好奇:JSON 不是用来传递文本的吗?怎么能传递图片呢?
实际上,JSON 本身只支持文本数据,而图片是二进制数据。要解决这个矛盾,我们需要将图片的二进制数据转换为文本形式,这就是 Base64 编码 的作用。
Base64 编码原理
Base64 是一种将二进制数据编码为 ASCII 字符串的方法:
- 它将每 3 个字节(24 位)的二进制数据分成 4 个 6 位单元。
- 每个 6 位单元映射到一个由 64 个字符(A-Z、a-z、0-9、+、/)组成的字符表。
- 编码后的字符串长度会增加约 33%,因为 3 个字节变成 4 个字符。
在 Java 中,anji-captcha
内部使用类似以下代码生成 Base64:
java
import java.util.Base64;
byte[] imageBytes = /* 图片的字节数据 */;
String base64String = Base64.getEncoder().encodeToString(imageBytes);
// 前端可识别的格式
String dataUrl = "data:image/png;base64," + base64String;
为什么用 Base64?
- 兼容性:JSON 要求数据是文本,Base64 将二进制转为文本。
- 简单性:无需额外请求图片文件,减少 HTTP 请求。
- 局限性:Base64 字符串比原始二进制数据大,适合小型图片(如验证码),不适合大文件。
总结
通过 Spring Boot 和 anji-captcha
,我们实现了一个完整的图片生成与交互流程:
- 后端生成验证码图片并转为 Base64 编码,通过 JSON 传递。
- 前端直接用
<img>
标签渲染 Base64 图片。 - 用户操作后,前端回传验证数据,后端返回结果。
!