pom.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-admin/src/main/resources/application.yml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-generator/src/main/resources/vm/java/vo.java.vm | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-ui/package.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-ui/src/views/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
pom.xml
@@ -13,7 +13,7 @@ <description>RuoYi-Vue-Plusåå°ç®¡çç³»ç»</description> <properties> <ruoyi-vue-plus.version>2.3.0</ruoyi-vue-plus.version> <ruoyi-vue-plus.version>2.3.1</ruoyi-vue-plus.version> <spring-boot.version>2.3.11.RELEASE</spring-boot.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> ruoyi-admin/src/main/resources/application.yml
@@ -8,8 +8,8 @@ copyrightYear: 2021 # å®ä¾æ¼ç¤ºå¼å ³ demoEnabled: true # æä»¶è·¯å¾,使ç¨jvmç³»ç»åé,å ¼å®¹windowsålinux; profile: ${user.dir}/ruoyi/uploadPath # æä»¶è·¯å¾ profile: ./ruoyi/uploadPath # è·åipå°åå¼å ³ addressEnabled: false ruoyi-common/src/main/java/com/ruoyi/common/annotation/RedisLock.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,27 @@ package com.ruoyi.common.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * åå¸å¼éï¼æ³¨è§£æ¨¡å¼ï¼ä¸æ¨è使ç¨ï¼æå¥½ç¨éçå·¥å ·ç±»ï¼ * * @author shenxinquan */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RedisLock { /** * éè¿ææ¶é´ é»è®¤30ç§ */ int expireTime() default 30; /** * ékeyå¼ */ String key() default "redisLockKey"; } ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -43,9 +43,9 @@ public static final int DEFAULT_PAGE_NUM = 1; /** * æ¯é¡µæ¾ç¤ºè®°å½æ° é»è®¤å¼ * æ¯é¡µæ¾ç¤ºè®°å½æ° é»è®¤å¼ é»è®¤æ¥å ¨é¨ */ public static final int DEFAULT_PAGE_SIZE = 10; public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; /** * æå»º plus å页对象 ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,35 @@ package com.ruoyi.demo.controller; import com.ruoyi.common.annotation.RedisLock; import com.ruoyi.common.core.domain.AjaxResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * æµè¯åå¸å¼éçæ ·ä¾ * * @author shenxinquan */ @RestController @RequestMapping("/demo/redisLock") public class RedisLockController { /** * #p0 æ è¯å第ä¸ä¸ªåæ°ä¸ºrediséçkey */ @GetMapping("/getLock") @RedisLock(expireTime = 10, key = "#p0") public AjaxResult<String> getLock(String key, String value) { try { // åæ¶è¯·æ±æé // Thread.sleep(5000); // éè¶ æ¶æµè¯ Thread.sleep(11000); } catch (InterruptedException e) { e.printStackTrace(); } return AjaxResult.success("æä½æå",value); } } ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,167 @@ package com.ruoyi.framework.aspectj; import com.ruoyi.common.annotation.RedisLock; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; /** * åå¸å¼éï¼æ³¨è§£å®ç°çæ¬ï¼ * * @author shenxinquan */ @Slf4j @Aspect @Order(9) @Component public class RedisLockAspect { @Autowired private RedissonClient redissonClient; private static final String LOCK_TITLE = "RedisLock_"; @Pointcut("@annotation(com.ruoyi.common.annotation.RedisLock)") public void annotationPointcut() { } @Around("annotationPointcut()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { // è·å¾å½å访é®çclass Class<?> className = joinPoint.getTarget().getClass(); // è·å¾è®¿é®çæ¹æ³å String methodName = joinPoint.getSignature().getName(); // å¾å°æ¹æ³çåæ°çç±»å Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); Object[] args = joinPoint.getArgs(); String key = ""; // é»è®¤30ç§è¿ææ¶é´ int expireTime = 30; try { // å¾å°è®¿é®çæ¹æ³å¯¹è±¡ Method method = className.getMethod(methodName, argClass); method.setAccessible(true); // 夿æ¯å¦åå¨@RedisLock注解 if (method.isAnnotationPresent(RedisLock.class)) { RedisLock annotation = method.getAnnotation(RedisLock.class); key = getRedisKey(args, annotation.key()); expireTime = getExpireTime(annotation); } } catch (Exception e) { throw new RuntimeException("redisåå¸å¼éæ³¨è§£åæ°å¼å¸¸", e); } Object res; try { if (acquire(key, expireTime, TimeUnit.SECONDS)) { try { res = joinPoint.proceed(); return res; } catch (Exception e) { throw new RuntimeException(e); } finally { release(key); } } else { throw new RuntimeException("redisåå¸å¼éæ³¨è§£åæ°å¼å¸¸"); } } catch (IllegalMonitorStateException e) { log.error("lock timeout => key : " + key + " , ThreadName : " + Thread.currentThread().getName()); throw new RuntimeException("lock timeout => key : " + key); } catch (Exception e) { throw new Exception("redisåå¸å¼æªç¥å¼å¸¸", e); } } private int getExpireTime(RedisLock annotation) { return annotation.expireTime(); } private String getRedisKey(Object[] args, String primalKey) { if (args.length == 0) { return primalKey; } // è·å#p0...éå List<String> keyList = getKeyParsList(primalKey); for (String keyName : keyList) { int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", "")); Object parValue = args[keyIndex]; primalKey = primalKey.replace(keyName, String.valueOf(parValue)); } return primalKey.replace("+", "").replace("'", ""); } /** * è·åkeyä¸#p0ä¸çåæ°åç§° */ private static List<String> getKeyParsList(String key) { List<String> listPar = new ArrayList<>(); if (key.contains("#")) { int plusIndex = key.substring(key.indexOf("#")).indexOf("+"); int indexNext = 0; String parName; int indexPre = key.indexOf("#"); if (plusIndex > 0) { indexNext = key.indexOf("#") + plusIndex; parName = key.substring(indexPre, indexNext); } else { parName = key.substring(indexPre); } listPar.add(parName.trim()); key = key.substring(indexNext + 1); if (key.contains("#")) { listPar.addAll(getKeyParsList(key)); } } return listPar; } /** * å éï¼RLockï¼å¸¦è¶ æ¶æ¶é´ç */ private boolean acquire(String key, long expire, TimeUnit expireUnit) { //声ækey对象 key = LOCK_TITLE + key; try { //è·åé对象 RLock mylock = redissonClient.getLock(key); //å éï¼å¹¶ä¸è®¾ç½®éè¿ææ¶é´ï¼é²æ¢æ»éç产ç mylock.tryLock(expire, expire, expireUnit); } catch (InterruptedException e) { return false; } log.info("lock => key : " + key + " , ThreadName : " + Thread.currentThread().getName()); //å éæå return true; } /** * éçéæ¾ */ private void release(String lockName) { //å¿ é¡»æ¯åå éæ¶çåä¸ä¸ªkey String key = LOCK_TITLE + lockName; //è·åæå¯¹è±¡ RLock mylock = redissonClient.getLock(key); //éæ¾éï¼è§£éï¼ mylock.unlock(); log.info("unlock => key : " + key + " , ThreadName : " + Thread.currentThread().getName()); } } ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -29,7 +29,7 @@ private ${pkColumn.javaType} ${pkColumn.javaField}; #foreach ($column in $columns) #if($column.isList) #if($column.isList && $column.isPk!=1) /** $column.columnComment */ #set($parentheseIndex=$column.columnComment.indexOf("ï¼")) #if($parentheseIndex != -1) ruoyi-ui/package.json
@@ -1,6 +1,6 @@ { "name": "ruoyi-vue-plus", "version": "2.3.0", "version": "2.3.1", "description": "RuoYi-Vue-Plusåå°ç®¡çç³»ç»", "author": "LionLi", "license": "MIT", ruoyi-ui/src/views/index.vue
@@ -80,6 +80,18 @@ <span>æ´æ°æ¥å¿</span> </div> <el-collapse accordion> <el-collapse-item title="v2.3.1 - 2021-6-4"> <ol> <li>add å¢å redisson åå¸å¼é 注解ä¸demoæ¡ä¾</li> <li>add å¢å Oracle 忝</li> <li>update ä¼å redis 空å¯ç å ¼å®¹æ§</li> <li>update ä¼åå端代ç çææé®å¢å loading</li> <li>fix ä¿®å¤ redisson ä¸è½æ¹éå é¤çbug</li> <li>fix ä¿®å¤è¡¨åæå»ºéæ©ä¸æéæ©æ§å¶å°æ¥éé®é¢</li> <li>fix ä¿®å¤ vo 代ç çæ ä¸»é®å表æ¾ç¤º éå¤çæbug</li> <li>fix ä¿®å¤ä¸ä¼ è·¯å¾ win æå ç¼è¯ä¸º win è·¯å¾, linux æ¥ébug</li> </ol> </el-collapse-item> <el-collapse-item title="v2.3.0 - 2021-6-1"> <ol> <li>add å级 luttuce 为 redisson æ§è½æ´å¼º å·¥å ·æ´å ¨</li> @@ -195,12 +207,14 @@ </template> <script> import config from '../../package.json' export default { name: "index", data() { return { // çæ¬å· version: "2.3.0", version: config.version, }; }, methods: {