mirror of
https://github.com/201206030/novel.git
synced 2025-04-27 07:30:50 +00:00
feat: 增加获取图片验证码接口
This commit is contained in:
parent
7c2cd61af6
commit
0fb2459a0a
@ -0,0 +1,36 @@
|
|||||||
|
package io.github.xxyopen.novel.controller.front;
|
||||||
|
|
||||||
|
import io.github.xxyopen.novel.core.common.resp.RestResp;
|
||||||
|
import io.github.xxyopen.novel.core.common.util.IpUtils;
|
||||||
|
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
|
||||||
|
import io.github.xxyopen.novel.service.FileService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件相关 控制器
|
||||||
|
*
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/17
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(ApiRouterConsts.API_FRONT_FILE_URL_PREFIX)
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class FileController {
|
||||||
|
|
||||||
|
private final FileService fileService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图片验证码接口
|
||||||
|
*/
|
||||||
|
@GetMapping("imgVerifyCode")
|
||||||
|
public RestResp<String> getImgVerifyCode(HttpServletRequest request) throws IOException {
|
||||||
|
return RestResp.ok(fileService.getImgVerifyCode(IpUtils.getRealIp(request)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
package io.github.xxyopen.novel.core.common.util;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片验证码工具类
|
||||||
|
*
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/17
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class ImgVerifyCodeUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机产生只有数字的字符串
|
||||||
|
*/
|
||||||
|
private final String randNumber = "0123456789";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片宽
|
||||||
|
*/
|
||||||
|
private final int width = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片高
|
||||||
|
*/
|
||||||
|
private final int height = 38;
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得字体
|
||||||
|
*/
|
||||||
|
private Font getFont() {
|
||||||
|
return new Font("Fixed", Font.PLAIN, 23);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成校验码图片
|
||||||
|
*/
|
||||||
|
public String genVerifyCodeImg(String verifyCode) throws IOException {
|
||||||
|
// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
|
||||||
|
// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
|
||||||
|
Graphics g = image.getGraphics();
|
||||||
|
//图片大小
|
||||||
|
g.fillRect(0, 0, width, height);
|
||||||
|
//字体大小
|
||||||
|
//字体颜色
|
||||||
|
g.setColor(new Color(204, 204, 204));
|
||||||
|
// 绘制干扰线
|
||||||
|
// 干扰线数量
|
||||||
|
int lineSize = 40;
|
||||||
|
for (int i = 0; i <= lineSize; i++) {
|
||||||
|
drawLine(g);
|
||||||
|
}
|
||||||
|
// 绘制随机字符
|
||||||
|
drawString(g, verifyCode);
|
||||||
|
g.dispose();
|
||||||
|
//将图片转换成Base64字符串
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(image, "JPEG", stream);
|
||||||
|
return Base64.getEncoder().encodeToString(stream.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制字符串
|
||||||
|
*/
|
||||||
|
private void drawString(Graphics g, String verifyCode) {
|
||||||
|
for (int i = 1; i <= verifyCode.length(); i++) {
|
||||||
|
g.setFont(getFont());
|
||||||
|
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
|
||||||
|
.nextInt(121)));
|
||||||
|
g.translate(random.nextInt(3), random.nextInt(3));
|
||||||
|
g.drawString(String.valueOf(verifyCode.charAt(i - 1)), 13 * i, 23);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制干扰线
|
||||||
|
*/
|
||||||
|
private void drawLine(Graphics g) {
|
||||||
|
int x = random.nextInt(width);
|
||||||
|
int y = random.nextInt(height);
|
||||||
|
int xl = random.nextInt(13);
|
||||||
|
int yl = random.nextInt(15);
|
||||||
|
g.drawLine(x, y, x + xl, y + yl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取随机的校验码
|
||||||
|
*/
|
||||||
|
public String getRandomVerifyCode(int num) {
|
||||||
|
int randNumberSize = randNumber.length();
|
||||||
|
StringBuilder verifyCode = new StringBuilder();
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
String rand = String.valueOf(randNumber.charAt(random.nextInt(randNumberSize)));
|
||||||
|
verifyCode.append(rand);
|
||||||
|
}
|
||||||
|
return verifyCode.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package io.github.xxyopen.novel.core.common.util;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/17
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class IpUtils {
|
||||||
|
|
||||||
|
private static final String UNKNOWN_IP = "unknown";
|
||||||
|
|
||||||
|
private static final String IP_SEPARATOR = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取真实IP
|
||||||
|
* @return 真实IP
|
||||||
|
*/
|
||||||
|
public String getRealIp(HttpServletRequest request) {
|
||||||
|
// 这个一般是Nginx反向代理设置的参数
|
||||||
|
String ip = request.getHeader("X-Real-IP");
|
||||||
|
if (ip == null || ip.length() == 0 || UNKNOWN_IP.equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("X-Forwarded-For");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.length() == 0 || UNKNOWN_IP.equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.length() == 0 || UNKNOWN_IP.equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.length() == 0 || UNKNOWN_IP.equalsIgnoreCase(ip)) {
|
||||||
|
ip = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
// 处理多IP的情况(只取第一个IP)
|
||||||
|
if (ip != null && ip.contains(IP_SEPARATOR)) {
|
||||||
|
String[] ipArray = ip.split(IP_SEPARATOR);
|
||||||
|
ip = ipArray[0];
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,11 @@ public class ApiRouterConsts {
|
|||||||
* */
|
* */
|
||||||
public static final String USER_URL_PREFIX = "/user";
|
public static final String USER_URL_PREFIX = "/user";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件模块请求路径前缀
|
||||||
|
* */
|
||||||
|
public static final String FILE_URL_PREFIX = "/file";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前台门户首页API请求路径前缀
|
* 前台门户首页API请求路径前缀
|
||||||
*/
|
*/
|
||||||
@ -72,4 +77,9 @@ public class ApiRouterConsts {
|
|||||||
*/
|
*/
|
||||||
public static final String API_FRONT_USER_URL_PREFIX = API_FRONT_URL_PREFIX + USER_URL_PREFIX;
|
public static final String API_FRONT_USER_URL_PREFIX = API_FRONT_URL_PREFIX + USER_URL_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前台门户文件相关API请求路径前缀
|
||||||
|
*/
|
||||||
|
public static final String API_FRONT_FILE_URL_PREFIX = API_FRONT_URL_PREFIX + FILE_URL_PREFIX;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,10 @@ public class CacheConsts {
|
|||||||
* */
|
* */
|
||||||
public static final String LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME = "lastUpdateBookIdListCache";
|
public static final String LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME = "lastUpdateBookIdListCache";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片验证码缓存 KEY
|
||||||
|
* */
|
||||||
|
public static final String IMG_VERIFY_CODE_CACHE_KEY = REDIS_CACHE_PREFIX + "imgVerifyCodeCache::";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存配置常量
|
* 缓存配置常量
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package io.github.xxyopen.novel.manager;
|
||||||
|
|
||||||
|
import io.github.xxyopen.novel.core.common.util.ImgVerifyCodeUtils;
|
||||||
|
import io.github.xxyopen.novel.core.constant.CacheConsts;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码 管理类
|
||||||
|
*
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/12
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class VerifyCodeManager {
|
||||||
|
|
||||||
|
private final StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成图片验证码,并放入缓存中
|
||||||
|
*/
|
||||||
|
public String genImgVerifyCode(String userKey) throws IOException {
|
||||||
|
String verifyCode = ImgVerifyCodeUtils.getRandomVerifyCode(4);
|
||||||
|
String img = ImgVerifyCodeUtils.genVerifyCodeImg(verifyCode);
|
||||||
|
stringRedisTemplate.opsForValue().set(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + userKey
|
||||||
|
, verifyCode, Duration.ofMinutes(5));
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验图片验证码
|
||||||
|
*/
|
||||||
|
public boolean imgVerifyCodeOk(String userKey, String verifyCode) {
|
||||||
|
return Objects.equals(
|
||||||
|
stringRedisTemplate.opsForValue().get(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + userKey)
|
||||||
|
,verifyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package io.github.xxyopen.novel.service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件相关服务类
|
||||||
|
*
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/17
|
||||||
|
*/
|
||||||
|
public interface FileService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图片验证码
|
||||||
|
* @param userKey 请求用户的标识,表明该验证码属于谁
|
||||||
|
* @return Base64编码的图片
|
||||||
|
* */
|
||||||
|
String getImgVerifyCode(String userKey) throws IOException;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package io.github.xxyopen.novel.service.impl;
|
||||||
|
|
||||||
|
import io.github.xxyopen.novel.manager.VerifyCodeManager;
|
||||||
|
import io.github.xxyopen.novel.service.FileService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件相关服务实现类
|
||||||
|
*
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2022/5/17
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class FileServiceImpl implements FileService {
|
||||||
|
|
||||||
|
private final VerifyCodeManager verifyCodeManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImgVerifyCode(String userKey) throws IOException {
|
||||||
|
return verifyCodeManager.genImgVerifyCode(userKey);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user