README.md
@@ -24,6 +24,7 @@ * 容卿¹å¨ Tomcat æ¹ä¸º å¹¶åæ§è½æ´å¥½ç undertow * 代ç çææ¨¡æ¿ æ¹ä¸ºéé Mybatis-Plus ç代ç * 项ç®ä¿®æ¹ä¸º mavenå¤ç¯å¢é ç½® * éæ Hutool 5.X å¹¶éåRuoYié¨ååè½ * éæ Feign æ¥å£å管ç Http 请æ±(å¦ä¸æ¹è¯·æ± æ¯ä»,çä¿¡,æ¨éç) * å级MybatisPlus 3.4.2 * å¢å demo模å示ä¾(ç»ä¸ä¼å¢å 模åçå°ä¼ä¼´ååè) pom.xml
@@ -21,7 +21,6 @@ <druid.version>1.2.4</druid.version> <bitwalker.version>1.21</bitwalker.version> <swagger.version>2.9.2</swagger.version> <kaptcha.version>2.3.2</kaptcha.version> <pagehelper.boot.version>1.3.0</pagehelper.boot.version> <fastjson.version>1.2.75</fastjson.version> <oshi.version>5.6.0</oshi.version> @@ -32,7 +31,7 @@ <velocity.version>1.7</velocity.version> <jwt.version>0.9.1</jwt.version> <mybatis-plus.version>3.4.2</mybatis-plus.version> <hutool.version>5.4.0</hutool.version> <hutool.version>5.5.8</hutool.version> <feign.version>2.2.6.RELEASE</feign.version> <feign-okhttp.version>11.0</feign-okhttp.version> </properties> @@ -160,13 +159,6 @@ <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.version}</version> </dependency> <!--éªè¯ç --> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>${kaptcha.version}</version> </dependency> <dependency> ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -1,86 +1,120 @@ package com.ruoyi.web.controller.common; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import cn.hutool.captcha.CircleCaptcha; import cn.hutool.captcha.ICaptcha; import cn.hutool.captcha.LineCaptcha; import cn.hutool.captcha.ShearCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.captcha.generator.MathGenerator; import cn.hutool.captcha.generator.RandomGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import com.ruoyi.common.core.text.Convert; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.FastByteArrayOutputStream; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.google.code.kaptcha.Producer; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.sign.Base64; import com.ruoyi.common.utils.uuid.IdUtils; import javax.annotation.Resource; /** * éªè¯ç æä½å¤ç * * @author ruoyi * * @author Lion Li */ @RestController public class CaptchaController { @Resource(name = "captchaProducer") private Producer captchaProducer; public class CaptchaController { @Resource(name = "captchaProducerMath") private Producer captchaProducerMath; // ååå¹²æ°éªè¯ç @Resource(name = "CircleCaptcha") private CircleCaptcha circleCaptcha; // 线段干æ°çéªè¯ç @Resource(name = "LineCaptcha") private LineCaptcha lineCaptcha; // ææ²å¹²æ°éªè¯ç @Resource(name = "ShearCaptcha") private ShearCaptcha shearCaptcha; @Autowired private RedisCache redisCache; // éªè¯ç ç±»å @Value("${ruoyi.captchaType}") @Value("${captcha.captchaType}") private String captchaType; // éªè¯ç ç±»å« @Value("${captcha.captchaCategory}") private String captchaCategory; // æ°åéªè¯ç 使° @Value("${captcha.captchaNumberLength}") private int numberLength; // å符éªè¯ç é¿åº¦ @Value("${captcha.captchaCharLength}") private int charLength; /** * çæéªè¯ç */ @GetMapping("/captchaImage") public AjaxResult getCode(HttpServletResponse response) throws IOException { public AjaxResult getCode() { // ä¿åéªè¯ç ä¿¡æ¯ String uuid = IdUtils.simpleUUID(); String uuid = IdUtil.simpleUUID(); String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String capStr = null, code = null; BufferedImage image = null; // çæéªè¯ç if ("math".equals(captchaType)) { String capText = captchaProducerMath.createText(); capStr = capText.substring(0, capText.lastIndexOf("@")); code = capText.substring(capText.lastIndexOf("@") + 1); image = captchaProducerMath.createImage(capStr); CodeGenerator codeGenerator; if ("math".equals(captchaType)) { codeGenerator = new MathGenerator(numberLength); } else if ("char".equals(captchaType)) { codeGenerator = new RandomGenerator(charLength); } else { throw new IllegalArgumentException("éªè¯ç ç±»åå¼å¸¸"); } else if ("char".equals(captchaType)) { capStr = code = captchaProducer.createText(); image = captchaProducer.createImage(capStr); if ("line".equals(captchaCategory)) { lineCaptcha.setGenerator(codeGenerator); capStr = lineCaptcha.getCode(); } else if ("circle".equals(captchaCategory)) { circleCaptcha.setGenerator(codeGenerator); capStr = circleCaptcha.getCode(); } else if ("shear".equals(captchaCategory)) { shearCaptcha.setGenerator(codeGenerator); capStr = shearCaptcha.getCode(); } else { throw new IllegalArgumentException("éªè¯ç ç±»å«å¼å¸¸"); } if ("math".equals(captchaType)) { code = getCodeResult(capStr); } else if ("char".equals(captchaType)) { code = capStr; } redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); // è½¬æ¢æµä¿¡æ¯ååº FastByteArrayOutputStream os = new FastByteArrayOutputStream(); try { ImageIO.write(image, "jpg", os); } catch (IOException e) { return AjaxResult.error(e.getMessage()); } circleCaptcha.createImage(capStr); AjaxResult ajax = AjaxResult.success(); ajax.put("uuid", uuid); ajax.put("img", Base64.encode(os.toByteArray())); ajax.put("img", circleCaptcha.getImageBase64()); return ajax; } private String getCodeResult(String capStr) { int a = Convert.toInt(StrUtil.sub(capStr, 0, numberLength).trim()); char operator = capStr.charAt(numberLength); int b = Convert.toInt(StrUtil.sub(capStr, numberLength + 1, numberLength + 1 + numberLength).trim()); switch (operator) { case '*': return a * b + ""; case '+': return a + b + ""; case '-': return a - b + ""; default: return ""; } } } ruoyi-admin/src/main/resources/application.yml
@@ -12,8 +12,16 @@ profile: ${user.dir}/ruoyi/uploadPath # è·åipå°åå¼å ³ addressEnabled: false captcha: # éªè¯ç ç±»å math æ°ç»è®¡ç® char å符éªè¯ captchaType: math # line çº¿æ®µå¹²æ° circle ååå¹²æ° shear ææ²å¹²æ° captchaCategory: circle # æ°åéªè¯ç 使° captchaNumberLength: 1 # å符éªè¯ç é¿åº¦ captchaCharLength: 4 # å¼åç¯å¢é ç½® server: ruoyi-common/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java
ÎļþÒÑɾ³ý ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
@@ -2,6 +2,8 @@ import java.io.File; import java.io.IOException; import cn.hutool.core.util.IdUtil; import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.config.RuoYiConfig; @@ -11,7 +13,6 @@ import com.ruoyi.common.exception.file.InvalidExtensionException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.IdUtils; /** * æä»¶ä¸ä¼ å·¥å ·ç±» @@ -123,7 +124,7 @@ { String fileName = file.getOriginalFilename(); String extension = getExtension(file); fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; fileName = DateUtils.datePath() + "/" + IdUtil.fastUUID() + "." + extension; return fileName; } ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java
ÎļþÒÑɾ³ý ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
ÎļþÒÑɾ³ý ruoyi-framework/pom.xml
@@ -55,18 +55,6 @@ <artifactId>druid-spring-boot-starter</artifactId> </dependency> <!-- éªè¯ç --> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <exclusions> <exclusion> <artifactId>javax.servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion> </exclusions> </dependency> <!-- è·åç³»ç»ä¿¡æ¯ --> <dependency> <groupId>com.github.oshi</groupId> ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
@@ -1,83 +1,55 @@ package com.ruoyi.framework.config; import java.util.Properties; import java.awt.*; import cn.hutool.captcha.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; import static com.google.code.kaptcha.Constants.*; /** * éªè¯ç é ç½® * * @author ruoyi * * @author Lion Li */ @Configuration public class CaptchaConfig { @Bean(name = "captchaProducer") public DefaultKaptcha getKaptchaBean() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); // æ¯å¦æè¾¹æ¡ é»è®¤ä¸ºtrue æä»¬å¯ä»¥èªå·±è®¾ç½®yesï¼no properties.setProperty(KAPTCHA_BORDER, "yes"); // éªè¯ç ææ¬å符é¢è² é»è®¤ä¸ºColor.BLACK properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); // éªè¯ç å¾ç宽度 é»è®¤ä¸º200 properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); // éªè¯ç å¾çé«åº¦ é»è®¤ä¸º50 properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); // éªè¯ç ææ¬åç¬¦å¤§å° é»è®¤ä¸º40 properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); // KAPTCHA_SESSION_KEY properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); // éªè¯ç ææ¬å符é¿åº¦ é»è®¤ä¸º5 properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); // éªè¯ç ææ¬å使 ·å¼ é»è®¤ä¸ºnew Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); // å¾çæ ·å¼ æ°´çº¹com.google.code.kaptcha.impl.WaterRipple é±¼ç¼com.google.code.kaptcha.impl.FishEyeGimpy é´å½±com.google.code.kaptcha.impl.ShadowGimpy properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; public class CaptchaConfig { private final int width = 160; private final int height = 60; private final Color background = Color.PINK; private final Font font = new Font("Arial", Font.BOLD, 48); /** * ååå¹²æ°éªè¯ç */ @Bean(name = "CircleCaptcha") public CircleCaptcha getCircleCaptcha() { CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height); captcha.setBackground(background); captcha.setFont(font); return captcha; } @Bean(name = "captchaProducerMath") public DefaultKaptcha getKaptchaBeanMath() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); // æ¯å¦æè¾¹æ¡ é»è®¤ä¸ºtrue æä»¬å¯ä»¥èªå·±è®¾ç½®yesï¼no properties.setProperty(KAPTCHA_BORDER, "yes"); // è¾¹æ¡é¢è² é»è®¤ä¸ºColor.BLACK properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); // éªè¯ç ææ¬å符é¢è² é»è®¤ä¸ºColor.BLACK properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); // éªè¯ç å¾ç宽度 é»è®¤ä¸º200 properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); // éªè¯ç å¾çé«åº¦ é»è®¤ä¸º50 properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); // éªè¯ç ææ¬åç¬¦å¤§å° é»è®¤ä¸º40 properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); // KAPTCHA_SESSION_KEY properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); // éªè¯ç ææ¬çæå¨ properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator"); // éªè¯ç ææ¬å符é´è· é»è®¤ä¸º2 properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); // éªè¯ç ææ¬å符é¿åº¦ é»è®¤ä¸º5 properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); // éªè¯ç ææ¬å使 ·å¼ é»è®¤ä¸ºnew Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); // éªè¯ç åªç¹é¢è² é»è®¤ä¸ºColor.BLACK properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); // å¹²æ°å®ç°ç±» properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); // å¾çæ ·å¼ æ°´çº¹com.google.code.kaptcha.impl.WaterRipple é±¼ç¼com.google.code.kaptcha.impl.FishEyeGimpy é´å½±com.google.code.kaptcha.impl.ShadowGimpy properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; /** * 线段干æ°çéªè¯ç */ @Bean(name = "LineCaptcha") public LineCaptcha getLineCaptcha() { LineCaptcha captcha = CaptchaUtil.createLineCaptcha(width, height); captcha.setBackground(background); captcha.setFont(font); return captcha; } /** * ææ²å¹²æ°éªè¯ç */ @Bean(name = "ShearCaptcha") public ShearCaptcha getShearCaptcha() { ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height); captcha.setBackground(background); captcha.setFont(font); return captcha; } } ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
ÎļþÒÑɾ³ý ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
@@ -4,6 +4,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import cn.hutool.core.util.IdUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -14,7 +16,6 @@ import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.ip.AddressUtils; import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.common.utils.uuid.IdUtils; import eu.bitwalker.useragentutils.UserAgent; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; @@ -101,7 +102,7 @@ */ public String createToken(LoginUser loginUser) { String token = IdUtils.fastUUID(); String token = IdUtil.fastUUID(); loginUser.setToken(token); setUserAgent(loginUser); refreshToken(loginUser);