diff --git a/server/like-admin/pom.xml b/server/like-admin/pom.xml
index f6a85e82..3555915a 100644
--- a/server/like-admin/pom.xml
+++ b/server/like-admin/pom.xml
@@ -30,6 +30,12 @@
1.0.0
+
+
+ com.github.penggle
+ kaptcha
+
+
cn.dev33
diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/AdminConfig.java b/server/like-admin/src/main/java/com/mdd/admin/config/AdminConfig.java
index 49941c75..4411b016 100644
--- a/server/like-admin/src/main/java/com/mdd/admin/config/AdminConfig.java
+++ b/server/like-admin/src/main/java/com/mdd/admin/config/AdminConfig.java
@@ -13,8 +13,9 @@ public class AdminConfig {
// 免登录验证
public static String[] notLoginUri = new String[]{
- "system:login", // 登录接口
- "index:config" // 配置接口
+ "system:captcha", // 验证码
+ "system:login", // 登录接口
+ "index:config" // 配置接口
};
// 免权限验证
diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/KaptChaConfig.java b/server/like-admin/src/main/java/com/mdd/admin/config/KaptChaConfig.java
new file mode 100644
index 00000000..b2541b2e
--- /dev/null
+++ b/server/like-admin/src/main/java/com/mdd/admin/config/KaptChaConfig.java
@@ -0,0 +1,45 @@
+package com.mdd.admin.config;
+
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+import static com.google.code.kaptcha.Constants.*;
+
+/**
+ * 验证码配置
+ */
+@Configuration
+public class KaptChaConfig {
+
+ @Bean(name = "captchaProducer")
+ public DefaultKaptcha getKaptchaBean() {
+ DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+ Properties properties = new Properties();
+ // 是否边框
+ properties.setProperty(KAPTCHA_BORDER, "yes");
+ // 字符颜色
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
+ // 图片宽度
+ properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+ // 图片高度
+ properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+ // 字符大小
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
+ // 验证键码
+ properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
+ // 字符长度
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
+ // 字体样式
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+ // 图片样式
+ properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+ Config config = new Config(properties);
+ defaultKaptcha.setConfig(config);
+ return defaultKaptcha;
+ }
+}
+
diff --git a/server/like-admin/src/main/java/com/mdd/admin/controller/system/SystemLoginController.java b/server/like-admin/src/main/java/com/mdd/admin/controller/system/SystemLoginController.java
index 4401d038..b0896d22 100644
--- a/server/like-admin/src/main/java/com/mdd/admin/controller/system/SystemLoginController.java
+++ b/server/like-admin/src/main/java/com/mdd/admin/controller/system/SystemLoginController.java
@@ -2,17 +2,14 @@ package com.mdd.admin.controller.system;
import com.mdd.admin.service.ISystemLoginService;
import com.mdd.admin.validate.system.SystemAdminLoginsValidate;
+import com.mdd.admin.vo.system.SystemCaptchaVo;
import com.mdd.admin.vo.system.SystemLoginVo;
import com.mdd.common.core.AjaxResult;
import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
/**
* 系统登录管理
@@ -24,6 +21,18 @@ public class SystemLoginController {
@Resource
ISystemLoginService iSystemLoginService;
+ /**
+ * 验证码
+ *
+ * @author fzr
+ * @return AjaxResult
+ */
+ @GetMapping("/captcha")
+ public AjaxResult captcha() {
+ SystemCaptchaVo vo = iSystemLoginService.captcha();
+ return AjaxResult.success(vo);
+ }
+
/**
* 登录系统
*
diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/ISystemLoginService.java b/server/like-admin/src/main/java/com/mdd/admin/service/ISystemLoginService.java
index 7e4be333..b9113754 100644
--- a/server/like-admin/src/main/java/com/mdd/admin/service/ISystemLoginService.java
+++ b/server/like-admin/src/main/java/com/mdd/admin/service/ISystemLoginService.java
@@ -1,6 +1,7 @@
package com.mdd.admin.service;
import com.mdd.admin.validate.system.SystemAdminLoginsValidate;
+import com.mdd.admin.vo.system.SystemCaptchaVo;
import com.mdd.admin.vo.system.SystemLoginVo;
import java.util.Map;
@@ -10,6 +11,14 @@ import java.util.Map;
*/
public interface ISystemLoginService {
+ /**
+ * 验证码
+ *
+ * @author fzr
+ * @return SystemCaptchaVo
+ */
+ SystemCaptchaVo captcha();
+
/**
* 登录
*
diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/SystemLoginServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/SystemLoginServiceImpl.java
index 777ab434..18fcba72 100644
--- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/SystemLoginServiceImpl.java
+++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/SystemLoginServiceImpl.java
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mdd.admin.service.ISystemAuthAdminService;
import com.mdd.admin.service.ISystemLoginService;
import com.mdd.admin.validate.system.SystemAdminLoginsValidate;
+import com.mdd.admin.vo.system.SystemCaptchaVo;
import com.mdd.admin.vo.system.SystemLoginVo;
import com.mdd.common.entity.system.SystemAuthAdmin;
import com.mdd.common.entity.system.SystemLogLogin;
@@ -14,13 +15,19 @@ import com.mdd.common.exception.OperateException;
import com.mdd.common.mapper.system.SystemAuthAdminMapper;
import com.mdd.common.mapper.system.SystemLogLoginMapper;
import com.mdd.common.util.*;
+import com.google.code.kaptcha.Producer;
import nl.bitwalker.useragentutils.UserAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+import org.springframework.util.FastByteArrayOutputStream;
import javax.annotation.Resource;
+import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
import java.util.*;
/**
@@ -29,6 +36,9 @@ import java.util.*;
@Service
public class SystemLoginServiceImpl implements ISystemLoginService {
+ @Resource
+ Producer captchaProducer;
+
@Resource
SystemLogLoginMapper systemLogLoginMapper;
@@ -41,6 +51,42 @@ public class SystemLoginServiceImpl implements ISystemLoginService {
private static final Logger log = LoggerFactory.getLogger(SystemLoginServiceImpl.class);
+ /**
+ * 验证码
+ *
+ * @author fzr
+ * @return SystemCaptchaVo
+ */
+ @Override
+ public SystemCaptchaVo captcha() {
+ // 验证码信息
+ String capStr, code;
+ BufferedImage image;
+ String uuid = ToolsUtils.makeUUID();
+ String ip = IpUtils.getIpAddress().replaceAll("\\.", "");
+ String verifyKey = YmlUtils.get("like.captcha.token") + ip + ":" + uuid;
+ long expireTime = Long.parseLong(YmlUtils.get("like.captcha.expire"));
+
+ // 生成验证码
+ capStr = code = captchaProducer.createText();
+ image = captchaProducer.createImage(capStr);
+ RedisUtils.set(verifyKey, code.toLowerCase(), expireTime);
+ FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+ try {
+ ImageIO.write(image, "jpg", os);
+ } catch (IOException e) {
+ log.error("verifyCode Error:" + e.getMessage());
+ throw new OperateException(e.getMessage());
+ }
+
+ // 返回验证码
+ String base64 = "data:image/jpeg;base64,"+ Base64Util.encode(os.toByteArray());
+ SystemCaptchaVo vo = new SystemCaptchaVo();
+ vo.setUuid(uuid);
+ vo.setImg(base64);
+ return vo;
+ }
+
/**
* 登录
*
@@ -53,6 +99,19 @@ public class SystemLoginServiceImpl implements ISystemLoginService {
String username = loginsValidate.getUsername();
String password = loginsValidate.getPassword();
+ String captchaStatus = YmlUtils.get("like.captcha.status");
+ if (StringUtils.isNotNull(captchaStatus) && captchaStatus.equals("true")) {
+ Assert.notNull(loginsValidate.getCode(), "code参数缺失");
+ Assert.notNull(loginsValidate.getUuid(), "uuid参数缺失");
+ String ip = IpUtils.getIpAddress().replaceAll("\\.", "");
+ String captchaKey = YmlUtils.get("like.captcha.token") + ip + ":" + loginsValidate.getUuid();
+ Object code = RedisUtils.get(captchaKey);
+ RedisUtils.del(captchaKey);
+ if (StringUtils.isNull(code) || StringUtils.isEmpty(code.toString()) || !loginsValidate.getCode().equals(code.toString())) {
+ throw new LoginException(HttpEnum.CAPTCHA_ERROR.getCode(), HttpEnum.CAPTCHA_ERROR.getMsg());
+ }
+ }
+
SystemAuthAdmin sysAdmin = systemAuthAdminMapper.selectOne(new QueryWrapper()
.eq("username", username)
.last("limit 1"));
diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/system/SystemAdminLoginsValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/system/SystemAdminLoginsValidate.java
index bbacd8e1..1f501028 100644
--- a/server/like-admin/src/main/java/com/mdd/admin/validate/system/SystemAdminLoginsValidate.java
+++ b/server/like-admin/src/main/java/com/mdd/admin/validate/system/SystemAdminLoginsValidate.java
@@ -22,4 +22,8 @@ public class SystemAdminLoginsValidate implements Serializable {
@Length(min = 6, max = 18, message = "账号或密码错误")
private String password;
+ private String code;
+
+ private String uuid;
+
}
diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/system/SystemCaptchaVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/system/SystemCaptchaVo.java
new file mode 100644
index 00000000..17793f6e
--- /dev/null
+++ b/server/like-admin/src/main/java/com/mdd/admin/vo/system/SystemCaptchaVo.java
@@ -0,0 +1,14 @@
+package com.mdd.admin.vo.system;
+
+import lombok.Data;
+
+/**
+ * 验证码
+ */
+@Data
+public class SystemCaptchaVo {
+
+ private String uuid;
+ private String img;
+
+}
diff --git a/server/like-admin/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/server/like-admin/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index 379bbd72..dde58ec5 100644
--- a/server/like-admin/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/server/like-admin/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -9,6 +9,21 @@
"name": "like.production",
"type": "java.lang.String",
"description": "Description for like.production."
+ },
+ {
+ "name": "like.captcha.status",
+ "type": "java.lang.String",
+ "description": "Description for like.captcha.status."
+ },
+ {
+ "name": "like.captcha.expire",
+ "type": "java.lang.String",
+ "description": "Description for like.captcha.expire."
+ },
+ {
+ "name": "like.captcha.token",
+ "type": "java.lang.String",
+ "description": "Description for like.captcha.token."
}
]
}
\ No newline at end of file
diff --git a/server/like-admin/src/main/resources/application.yml b/server/like-admin/src/main/resources/application.yml
index d079e679..f65f928d 100644
--- a/server/like-admin/src/main/resources/application.yml
+++ b/server/like-admin/src/main/resources/application.yml
@@ -1,6 +1,14 @@
# 项目配置
like:
upload-directory: /www/uploads/likeadmin-java/ # 上传目录
+ # 验证码配置
+ captcha:
+ # 是否开启验证码
+ status: true
+ # 验证码有效时长
+ expire: 120
+ # 验证码缓存键名
+ token: "captcha:key:"
# 服务配置
server:
diff --git a/server/like-common/src/main/java/com/mdd/common/enums/HttpEnum.java b/server/like-common/src/main/java/com/mdd/common/enums/HttpEnum.java
index 79c61a6d..893d6c7d 100644
--- a/server/like-common/src/main/java/com/mdd/common/enums/HttpEnum.java
+++ b/server/like-common/src/main/java/com/mdd/common/enums/HttpEnum.java
@@ -14,6 +14,7 @@ public enum HttpEnum {
LOGIN_DISABLE_ERROR(331, "登录账号已被禁用了"),
TOKEN_EMPTY(332, "token参数为空"),
TOKEN_INVALID(333, "token参数无效"),
+ CAPTCHA_ERROR(334, "验证码错误"),
NO_PERMISSION(403, "无相关权限"),
REQUEST_404_ERROR(404, "请求接口不存在"),
diff --git a/server/like-common/src/main/java/com/mdd/common/util/Base64Util.java b/server/like-common/src/main/java/com/mdd/common/util/Base64Util.java
new file mode 100644
index 00000000..30d8ada1
--- /dev/null
+++ b/server/like-common/src/main/java/com/mdd/common/util/Base64Util.java
@@ -0,0 +1,266 @@
+package com.mdd.common.util;
+
+/**
+ * Base64工具类
+ */
+public final class Base64Util
+{
+ static private final int BASE_LENGTH = 128;
+ static private final int LOOK_UP_LENGTH = 64;
+ static private final int TWENTY_FOUR_BIT_GROUP = 24;
+ static private final int EIGHT_BIT = 8;
+ static private final int SIXTEEN_BIT = 16;
+ static private final int FOUR_BYTE = 4;
+ static private final int SIGN = -128;
+ static private final char PAD = '=';
+ static final private byte[] base64Alphabet = new byte[BASE_LENGTH];
+ static final private char[] lookUpBase64Alphabet = new char[LOOK_UP_LENGTH];
+
+ static {
+ for (int i = 0; i < BASE_LENGTH; ++i) {
+ base64Alphabet[i] = -1;
+ }
+
+ for (int i = 'Z'; i >= 'A'; i--) {
+ base64Alphabet[i] = (byte) (i - 'A');
+ }
+
+ for (int i = 'z'; i >= 'a'; i--) {
+ base64Alphabet[i] = (byte) (i - 'a' + 26);
+ }
+
+ for (int i = '9'; i >= '0'; i--) {
+ base64Alphabet[i] = (byte) (i - '0' + 52);
+ }
+
+ base64Alphabet['+'] = 62;
+ base64Alphabet['/'] = 63;
+
+ for (int i = 0; i <= 25; i++) {
+ lookUpBase64Alphabet[i] = (char) ('A' + i);
+ }
+
+ for (int i = 26, j = 0; i <= 51; i++, j++) {
+ lookUpBase64Alphabet[i] = (char) ('a' + j);
+ }
+
+ for (int i = 52, j = 0; i <= 61; i++, j++) {
+ lookUpBase64Alphabet[i] = (char) ('0' + j);
+ }
+
+ lookUpBase64Alphabet[62] = '+';
+ lookUpBase64Alphabet[63] = '/';
+ }
+
+ /**
+ * 转码
+ *
+ * @param binaryData 未转码数据
+ * @return 转码后数据串
+ */
+ public static String encode(byte[] binaryData) {
+ if (binaryData == null) {
+ return null;
+ }
+
+ int lengthDataBits = binaryData.length * EIGHT_BIT;
+ if (lengthDataBits == 0) {
+ return "";
+ }
+
+ int fewerThan24bits = lengthDataBits % TWENTY_FOUR_BIT_GROUP;
+ int numberTriplets = lengthDataBits / TWENTY_FOUR_BIT_GROUP;
+ int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
+ char[] encodedData;
+
+ encodedData = new char[numberQuartet * 4];
+
+ byte k, l, b1, b2, b3;
+ int encodedIndex = 0;
+ int dataIndex = 0;
+
+ for (int i = 0; i < numberTriplets; i++) {
+ b1 = binaryData[dataIndex++];
+ b2 = binaryData[dataIndex++];
+ b3 = binaryData[dataIndex++];
+
+ k = (byte) (b1 & 0x03);
+ l = (byte) (b2 & 0x0f);
+
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+ byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
+ }
+
+ if (fewerThan24bits == EIGHT_BIT) {
+ b1 = binaryData[dataIndex];
+ k = (byte) (b1 & 0x03);
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
+ encodedData[encodedIndex++] = PAD;
+ encodedData[encodedIndex++] = PAD;
+ } else if (fewerThan24bits == SIXTEEN_BIT) {
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex + 1];
+ l = (byte) (b2 & 0x0f);
+ k = (byte) (b1 & 0x03);
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
+ encodedData[encodedIndex++] = PAD;
+ }
+ return new String(encodedData);
+ }
+
+ /**
+ * 解码
+ *
+ * @param encoded 已转码数据
+ * @return 解码后数据
+ */
+ public static byte[] decode(String encoded) {
+ if (encoded == null) {
+ return null;
+ }
+
+ char[] base64Data = encoded.toCharArray();
+ int len = removeWhiteSpace(base64Data);
+
+ if (len % FOUR_BYTE != 0) {
+ return null;
+ }
+
+ int numberQuadruple = (len / FOUR_BYTE);
+ if (numberQuadruple == 0) {
+ return new byte[0];
+ }
+
+ byte[] decodedData;
+ byte b1, b2, b3, b4;
+ char d1, d2, d3, d4;
+
+ int i = 0;
+ int encodedIndex = 0;
+ int dataIndex = 0;
+ decodedData = new byte[(numberQuadruple) * 3];
+
+ for (; i < numberQuadruple - 1; i++) {
+
+ if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
+ || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
+ {
+ return null;
+ }
+
+ b1 = base64Alphabet[d1];
+ b2 = base64Alphabet[d2];
+ b3 = base64Alphabet[d3];
+ b4 = base64Alphabet[d4];
+
+ decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+ decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+ }
+
+ if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
+ return null;
+ }
+
+ b1 = base64Alphabet[d1];
+ b2 = base64Alphabet[d2];
+ d3 = base64Data[dataIndex++];
+ d4 = base64Data[dataIndex++];
+ if (!isData((d3)) || !isData((d4))) {
+ if (isPad(d3) && isPad(d4)) {
+ if ((b2 & 0xf) != 0) {
+ return null;
+ }
+ byte[] tmp = new byte[i * 3 + 1];
+ System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+ tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ return tmp;
+ } else if (!isPad(d3) && isPad(d4)) {
+ b3 = base64Alphabet[d3];
+ if ((b3 & 0x3) != 0) {
+ return null;
+ }
+ byte[] tmp = new byte[i * 3 + 2];
+ System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+ tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+ tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+ return tmp;
+ } else {
+ return null;
+ }
+ } else {
+ b3 = base64Alphabet[d3];
+ b4 = base64Alphabet[d4];
+ decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+ decodedData[encodedIndex++] = (byte) (b4 | b3 << 6);
+
+ }
+ return decodedData;
+ }
+
+ /**
+ * 是否空白
+ *
+ * @param octEct 位
+ * @return boolean
+ */
+ private static boolean isWhiteSpace(char octEct) {
+ return (octEct == 0x20 || octEct == 0xd || octEct == 0xa || octEct == 0x9);
+ }
+
+ /**
+ * 是否填充
+ *
+ * @param octEct 位
+ * @return boolean
+ */
+ private static boolean isPad(char octEct) {
+ return (octEct == PAD);
+ }
+
+ /**
+ * 是否数据
+ *
+ * @param octEct 位
+ * @return Boolean
+ */
+ private static Boolean isData(char octEct) {
+ return (octEct < BASE_LENGTH && base64Alphabet[octEct] != -1);
+ }
+
+ /**
+ * 移除空白
+ *
+ * @param data 数据
+ * @return int
+ */
+ private static int removeWhiteSpace(char[] data) {
+ if (data == null) {
+ return 0;
+ }
+
+ int newSize = 0;
+ int len = data.length;
+ for (int i = 0; i < len; i++) {
+ if (!isWhiteSpace(data[i])) {
+ data[newSize++] = data[i];
+ }
+ }
+ return newSize;
+ }
+
+}
diff --git a/server/pom.xml b/server/pom.xml
index 3f6b82bf..f153e314 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -39,6 +39,7 @@
2.11.1
2.9.0
+ 2.3.2
1.2.4
6.1.2
1.32.0
@@ -116,6 +117,13 @@
${fastJson2.version}
+
+
+ com.github.penggle
+ kaptcha
+ ${kaptcha.version}
+
+
cn.dev33