diff --git a/README.md b/README.md index b877e68c4..312f3e1fd 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ * 文档框架 knife4j 美化接口文档 * 代码生成器 一键生成前后端代码 +## 参考文档 +[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) + ## 修改RuoYi功能 ### 依赖改动 @@ -43,6 +46,8 @@ * 项目修改为 maven多环境配置 * 项目配置修改为 application.yml 统一管理 * 数据权限修改为 适配支持单表、多表 +* 使用 redisson 实现 spring-cache 整合 +* 增加 mybatis-plus 二级缓存 redis 存储 ### 其他 @@ -59,38 +64,6 @@ -## 重点注意事项 - -若依文档对事务注解的描述 [关于事务](https://doc.ruoyi.vip/ruoyi/document/htsc.html#%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86) 以下对多数据源事务做补充: -* 同一个事务下是无法切换数据源的 -* 禁止 父方法使用 @Transactional 创建事务 子方法使用 @DataSource 切换数据源 -* 正确用法: 子方法单独创建事务 或 父方法使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 为所有子方法创建新事务 - -关于如何使用Tomcat -* 查看ruoyi-framework模块的pom.xml文件,根据注释更改依赖 -* 查看ruoyi-admin模块中的application.yml文件,根据注释更改配置 - -关于如何创建新模块 -* 参考ruoyi-demo模块 -* 需要改动: 父pom 与 admin模块pom - -关于树表生成 -* 直接在mysql表中 添加 parentId orderNum 等字段(根据需要参考 TreeEntity类) -* 代码生成选择树表生成即可 - -关于数据权限 -* 创建表 需预留 dept_id 字段 如需用户权限 还需预留 user_id 字段 -* 支持 Mybatis-Plus 方式注入 参考 demo 模块用法(需导入 test.sql 文件) -* 支持 XML 方式注入 参考 system 模块用法 - -关于vue与boot整合部署 -* [前端静态资源如何整合到后端访问](https://doc.ruoyi.vip/ruoyi-vue/other/faq.html#前端静态资源如何整合到后端访问) - -关于修改包名 -* 将文件夹全部修改为 com.xxx -* 使用IDEA全局替换 com.ruoyi 替换为 com.xxx -* 严禁手动修改 - ## 内置功能 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 diff --git a/pom.xml b/pom.xml index f50e460e5..4a73f1eac 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ RuoYi-Vue-Plus后台管理系统 - 2.3.1 + 2.3.2 2.3.11.RELEASE UTF-8 UTF-8 @@ -21,7 +21,6 @@ 3.1.1 1.2.6 3.0.2 - 1.5.22 1.2.76 4.1.2 1.7 @@ -47,7 +46,7 @@ import - + com.alibaba druid-spring-boot-starter @@ -58,18 +57,6 @@ com.github.xiaoymin knife4j-spring-boot-starter ${knife4j.version} - - - swagger-annotations - io.swagger - - - - - - io.swagger - swagger-annotations - ${swagger-annotations.version} @@ -79,7 +66,7 @@ ${poi.version} - + org.apache.velocity velocity @@ -93,7 +80,7 @@ ${fastjson.version} - + io.jsonwebtoken jjwt @@ -139,6 +126,13 @@ ${spring-boot-admin.version} + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + com.ruoyi @@ -181,13 +175,6 @@ ${ruoyi-vue-plus.version} - - - org.redisson - redisson-spring-boot-starter - ${redisson.version} - - diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 9dc13c220..58cf695a3 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -289,8 +289,6 @@ spring: url: http://localhost:${server.port}${spring.boot.admin.context-path} instance: prefer-ip: true # 注册实例时,优先使用 IP - # username: ruoyi - # password: 123456 # Spring Boot Admin Server 服务端的相关配置 context-path: /admin # 配置 Spring diff --git a/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml b/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml deleted file mode 100644 index e69de29bb..000000000 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 2c75fcd1b..c6275c250 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -136,11 +136,6 @@ knife4j-spring-boot-starter - - io.swagger - swagger-annotations - - org.springframework.boot spring-boot-starter-actuator diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java index 9313674a0..f176f5721 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java @@ -52,8 +52,8 @@ public class SysRole implements Serializable @NotBlank(message = "显示顺序不能为空") private String roleSort; - /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限) */ - @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限") + /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */ + @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") private String dataScope; /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/MybatisPlusRedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/MybatisPlusRedisCache.java new file mode 100644 index 000000000..6ff6a982b --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/MybatisPlusRedisCache.java @@ -0,0 +1,102 @@ +package com.ruoyi.common.core.mybatisplus; + +import cn.hutool.extra.spring.SpringUtil; +import com.ruoyi.common.core.redis.RedisCache; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.cache.Cache; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * mybatis-redis 二级缓存 + * + * @author Lion Li + */ +@Slf4j +public class MybatisPlusRedisCache implements Cache { + + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); + + private RedisCache redisCache; + + private String id; + + public MybatisPlusRedisCache(final String id) { + if (id == null) { + throw new IllegalArgumentException("Cache instances require an ID"); + } + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + @Override + public void putObject(Object key, Object value) { + if (redisCache == null) { + redisCache = SpringUtil.getBean(RedisCache.class); + } + if (value != null) { + redisCache.setCacheObject(key.toString(), value); + } + } + + @Override + public Object getObject(Object key) { + if (redisCache == null) { + //由于启动期间注入失败,只能运行期间注入,这段代码可以删除 + redisCache = SpringUtil.getBean(RedisCache.class); + } + try { + if (key != null) { + return redisCache.getCacheObject(key.toString()); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("缓存出错"); + } + return null; + } + + @Override + public Object removeObject(Object key) { + if (redisCache == null) { + redisCache = SpringUtil.getBean(RedisCache.class); + } + if (key != null) { + redisCache.deleteObject(key.toString()); + } + return null; + } + + @Override + public void clear() { + log.debug("清空缓存"); + if (redisCache == null) { + redisCache = SpringUtil.getBean(RedisCache.class); + } + Collection keys = redisCache.keys("*:" + this.id + "*"); + if (!CollectionUtils.isEmpty(keys)) { + redisCache.deleteObject(keys); + } + } + + @Override + public int getSize() { + RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate"); + Long size = redisTemplate.execute(RedisServerCommands::dbSize); + return size.intValue(); + } + + @Override + public ReadWriteLock getReadWriteLock() { + return this.readWriteLock; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java index 812a683d6..79d889cf0 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java @@ -10,6 +10,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +/** + * 分页 Page 增强对象 + * + * @param 数据库实体 + * @param vo实体 + * @author Lion Li + */ @Data @Accessors(chain = true) public class PagePlus implements IPage { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockManager.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockManager.java new file mode 100644 index 000000000..0688bb1c5 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisLockManager.java @@ -0,0 +1,170 @@ +package com.ruoyi.common.core.redis; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import org.redisson.api.RCountDownLatch; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * redis 锁管理类 + * + * @author shenxinquan + */ +@Component +public class RedisLockManager { + + @Autowired + private RedissonClient redissonClient; + + /** + * 通用锁 + */ + private final static Integer BASE_LOCK = 1; + + /** + * 公平锁 + */ + private final static Integer FAIR_LOCK = 2; + + /** + * 存放当前线程获取锁的类型 + */ + private final ThreadLocal threadLocal = new ThreadLocal<>(); + + /** + * 获取锁 + */ + private RLock getLock(String key, Integer lockType) { + Assert.isTrue(StrUtil.isNotBlank(key), "key不能为空"); + threadLocal.set(lockType); + RLock lock; + if (BASE_LOCK.equals(lockType)) { + lock = redissonClient.getLock(key); + } else if (FAIR_LOCK.equals(lockType)) { + lock = redissonClient.getFairLock(key); + } else { + throw new RuntimeException("锁不存在!"); + } + return lock; + } + + /** + * 获取锁(不用设置超时时间,一直等待) + */ + public boolean getLock(String key) { + RLock lock = getLock(key, BASE_LOCK); + return lock.tryLock(); + } + + /** + * 设置过期时间 + * + * @param key + * @param time 过期时间 + * @param expireUnit 时间单位 + */ + public boolean getLock(String key, long time, TimeUnit expireUnit) { + Assert.isTrue(time > 0, "过期时间必须大于0"); + Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空"); + RLock lock = getLock(key, BASE_LOCK); + try { + return lock.tryLock(time, expireUnit); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 设置过期时间 + * + * @param key + * @param waitTime 获取锁等待时间 + * @param leaseTime 保留锁的时间 + * @param expireUnit 时间单位 + */ + public boolean getLock(String key, long waitTime, long leaseTime, TimeUnit expireUnit) { + Assert.isTrue(waitTime > 0, "获取锁等待时间必须大于0"); + Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0"); + Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空"); + RLock lock = getLock(key, BASE_LOCK); + try { + return lock.tryLock(waitTime, leaseTime, expireUnit); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 获取计数器锁 + * + * @param key + * @param count countDownLatch 的数量 + */ + public RCountDownLatch getCountDownLatch(String key, long count) { + Assert.isTrue(count >= 0, "count数量必须大于等于0"); + RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch(key); + rCountDownLatch.trySetCount(count); + return rCountDownLatch; + } + + /** + * 获取公平锁 + * + * @param key + * @param waitTime 获取锁等待时间 + * @param leaseTime 持有锁的时间 + * @param expireUnit 时间单位 + * @return + * @throws InterruptedException + */ + public boolean getFairLock(String key, long waitTime, long leaseTime, TimeUnit expireUnit) { + Assert.isTrue(waitTime > 0, "获取锁等待时间必须大于0"); + Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0"); + Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空"); + RLock lock = getLock(key, FAIR_LOCK); + try { + return lock.tryLock(waitTime, leaseTime, expireUnit); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 获取公平锁 + * + * @param key + * @param leaseTime 持有锁的时间 + * @param expireUnit 时间单位 + */ + public boolean getFairLock(String key, long leaseTime, TimeUnit expireUnit) { + Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0"); + Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空"); + RLock lock = getLock(key, FAIR_LOCK); + try { + return lock.tryLock(leaseTime, expireUnit); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 释放锁(统一释放) + */ + public void unLock(String key) { + Integer lockType = threadLocal.get(); + RLock lock = getLock(key, lockType); + lock.unlock(); + threadLocal.remove(); + } +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestAddBo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestAddBo.java new file mode 100644 index 000000000..d8c406f5a --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestAddBo.java @@ -0,0 +1,50 @@ +package com.ruoyi.demo.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + + + +/** + * 测试添加对象 chkj_test + * + * @author Lion Li + * @date 2021-05-14 + */ +@Data +@ApiModel("测试添加对象") +public class ChkjTestAddBo { + + /** key键 */ + @ApiModelProperty("key键") + @NotBlank(message = "key键不能为空") + private String testKey; + /** 值 */ + @ApiModelProperty("值") + @NotBlank(message = "值不能为空") + private String value; + /** 版本 */ + @ApiModelProperty("版本") + private Long version; + /** 创建时间 */ + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + /** 删除标志 */ + @ApiModelProperty("删除标志") + private Long deleted; + /** 父id */ + @ApiModelProperty("父id") + @NotNull(message = "父id不能为空") + private Long parentId; + /** 排序号 */ + @ApiModelProperty("排序号") + @NotNull(message = "排序号不能为空") + private Long orderNum; +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestEditBo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestEditBo.java new file mode 100644 index 000000000..acabd9f2e --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestEditBo.java @@ -0,0 +1,61 @@ +package com.ruoyi.demo.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + + +/** + * 测试编辑对象 chkj_test + * + * @author Lion Li + * @date 2021-05-14 + */ +@Data +@ApiModel("测试编辑对象") +public class ChkjTestEditBo { + + + /** 主键 */ + @ApiModelProperty("主键") + @NotNull(message = "主键不能为空") + private Long id; + + /** key键 */ + @ApiModelProperty("key键") + @NotBlank(message = "key键不能为空") + private String testKey; + + /** 值 */ + @ApiModelProperty("值") + @NotBlank(message = "值不能为空") + private String value; + + /** 版本 */ + @ApiModelProperty("版本") + private Long version; + + /** 创建时间 */ + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 删除标志 */ + @ApiModelProperty("删除标志") + private Long deleted; + + /** 父id */ + @ApiModelProperty("父id") + @NotNull(message = "父id不能为空") + private Long parentId; + + /** 排序号 */ + @ApiModelProperty("排序号") + @NotNull(message = "排序号不能为空") + private Long orderNum; +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestQueryBo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestQueryBo.java new file mode 100644 index 000000000..bc71509d8 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/bo/ChkjTestQueryBo.java @@ -0,0 +1,53 @@ +package com.ruoyi.demo.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 测试分页查询对象 chkj_test + * + * @author Lion Li + * @date 2021-05-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("测试分页查询对象") +public class ChkjTestQueryBo extends BaseEntity { + + /** 分页大小 */ + @ApiModelProperty("分页大小") + private Integer pageSize; + /** 当前页数 */ + @ApiModelProperty("当前页数") + private Integer pageNum; + /** 排序列 */ + @ApiModelProperty("排序列") + private String orderByColumn; + /** 排序的方向desc或者asc */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + + + /** key键 */ + @ApiModelProperty("key键") + private String testKey; + /** 值 */ + @ApiModelProperty("值") + private String value; + /** 版本 */ + @ApiModelProperty("版本") + private Long version; + /** 删除标志 */ + @ApiModelProperty("删除标志") + private Long deleted; + /** 父id */ + @ApiModelProperty("父id") + private Long parentId; + /** 排序号 */ + @ApiModelProperty("排序号") + private Long orderNum; + +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/ChkjTestController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/ChkjTestController.java new file mode 100644 index 000000000..429db8fab --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/ChkjTestController.java @@ -0,0 +1,108 @@ +package com.ruoyi.demo.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.demo.bo.ChkjTestAddBo; +import com.ruoyi.demo.bo.ChkjTestEditBo; +import com.ruoyi.demo.bo.ChkjTestQueryBo; +import com.ruoyi.demo.service.IChkjTestService; +import com.ruoyi.demo.vo.ChkjTestVo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 测试Controller + * + * @author Lion Li + * @date 2021-05-14 + */ +@Api(value = "测试控制器", tags = {"测试管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/demo/test") +public class ChkjTestController extends BaseController { + + private final IChkjTestService iChkjTestService; + + /** + * 查询测试列表 + */ + @ApiOperation("查询测试列表") + @PreAuthorize("@ss.hasPermi('demo:test:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated ChkjTestQueryBo bo) { + return iChkjTestService.queryPageList(bo); + } + + /** + * 导出测试列表 + */ + @ApiOperation("导出测试列表") + @PreAuthorize("@ss.hasPermi('demo:test:export')") + @Log(title = "测试", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(@Validated ChkjTestQueryBo bo) { + List list = iChkjTestService.queryList(bo); + ExcelUtil util = new ExcelUtil(ChkjTestVo.class); + return util.exportExcel(list, "测试"); + } + + /** + * 获取测试详细信息 + */ + @ApiOperation("获取测试详细信息") + @PreAuthorize("@ss.hasPermi('demo:test:query')") + @GetMapping("/{id}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("id") Long id) { + return AjaxResult.success(iChkjTestService.queryById(id)); + } + + /** + * 新增测试 + */ + @ApiOperation("新增测试") + @PreAuthorize("@ss.hasPermi('demo:test:add')") + @Log(title = "测试", businessType = BusinessType.INSERT) + @PostMapping() + public AjaxResult add(@Validated @RequestBody ChkjTestAddBo bo) { + return toAjax(iChkjTestService.insertByAddBo(bo) ? 1 : 0); + } + + /** + * 修改测试 + */ + @ApiOperation("修改测试") + @PreAuthorize("@ss.hasPermi('demo:test:edit')") + @Log(title = "测试", businessType = BusinessType.UPDATE) + @PutMapping() + public AjaxResult edit(@Validated @RequestBody ChkjTestEditBo bo) { + return toAjax(iChkjTestService.updateByEditBo(bo) ? 1 : 0); + } + + /** + * 删除测试 + */ + @ApiOperation("删除测试") + @PreAuthorize("@ss.hasPermi('demo:test:remove')") + @Log(title = "测试" , businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iChkjTestService.deleteWithValidByIds(Arrays.asList(ids), true) ? 1 : 0); + } +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java index 7792784a1..c3c71efc4 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java @@ -2,26 +2,36 @@ package com.ruoyi.demo.controller; import com.ruoyi.common.annotation.RedisLock; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.redis.RedisLockManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.concurrent.TimeUnit; + /** * 测试分布式锁的样例 * * @author shenxinquan */ +@Slf4j @RestController @RequestMapping("/demo/redisLock") public class RedisLockController { + @Autowired + private RedisLockManager redisLockManager; + /** * #p0 标识取第一个参数为redis锁的key */ - @GetMapping("/getLock") + @GetMapping("/testLock1") @RedisLock(expireTime = 10, key = "#p0") - public AjaxResult getLock(String key, String value) { + public AjaxResult testLock1(String key, String value) { try { // 同时请求排队 // Thread.sleep(5000); @@ -32,4 +42,34 @@ public class RedisLockController { } return AjaxResult.success("操作成功",value); } + + /** + * 测试锁工具类 + */ + @GetMapping("/testLock2") + public AjaxResult testLock(String key, Long time) { + try { + boolean flag = redisLockManager.getLock(key, time, TimeUnit.SECONDS); + if (flag) { + log.info("获取锁成功: " + key); + Thread.sleep(3000); + redisLockManager.unLock(key); + log.info("释放锁成功: " + key); + } else { + log.error("获取锁失败: " + key); + } + } catch (InterruptedException e) { + log.error(e.getMessage()); + } + return AjaxResult.success(); + } + + /** + * 测试spring-cache注解 + */ + @Cacheable(value = "test", key = "#key") + @GetMapping("/testCache") + public AjaxResult testCache(String key) { + return AjaxResult.success("操作成功", key); + } } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ChkjTest.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ChkjTest.java new file mode 100644 index 000000000..ca46d5b68 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ChkjTest.java @@ -0,0 +1,55 @@ +package com.ruoyi.demo.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 测试对象 chkj_test + * + * @author Lion Li + * @date 2021-05-14 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("chkj_test") +public class ChkjTest implements Serializable { + +private static final long serialVersionUID=1L; + + + /** 主键 */ + @TableId(value = "id") + private Long id; + + /** key键 */ + private String testKey; + + /** 值 */ + private String value; + + /** 版本 */ + private Long version; + + /** 创建时间 */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** 删除标志 */ + private Long deleted; + + /** 父id */ + private Long parentId; + + /** 排序号 */ + private Long orderNum; + +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/ChkjTestMapper.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/ChkjTestMapper.java new file mode 100644 index 000000000..87422971e --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/ChkjTestMapper.java @@ -0,0 +1,14 @@ +package com.ruoyi.demo.mapper; + +import com.ruoyi.demo.domain.ChkjTest; +import com.ruoyi.common.core.page.BaseMapperPlus; + +/** + * 测试Mapper接口 + * + * @author Lion Li + * @date 2021-05-14 + */ +public interface ChkjTestMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java index 2416f0efc..5cfb9f69c 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java @@ -1,7 +1,9 @@ package com.ruoyi.demo.mapper; -import com.ruoyi.demo.domain.TestDemo; +import com.ruoyi.common.core.mybatisplus.MybatisPlusRedisCache; import com.ruoyi.common.core.page.BaseMapperPlus; +import com.ruoyi.demo.domain.TestDemo; +import org.apache.ibatis.annotations.CacheNamespace; /** * 测试单表Mapper接口 @@ -9,6 +11,7 @@ import com.ruoyi.common.core.page.BaseMapperPlus; * @author Lion Li * @date 2021-05-30 */ +@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class) public interface TestDemoMapper extends BaseMapperPlus { } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java index 6dd75c50d..0635ebc06 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java @@ -1,7 +1,9 @@ package com.ruoyi.demo.mapper; -import com.ruoyi.demo.domain.TestTree; +import com.ruoyi.common.core.mybatisplus.MybatisPlusRedisCache; import com.ruoyi.common.core.page.BaseMapperPlus; +import com.ruoyi.demo.domain.TestTree; +import org.apache.ibatis.annotations.CacheNamespace; /** * 测试树表Mapper接口 @@ -9,6 +11,7 @@ import com.ruoyi.common.core.page.BaseMapperPlus; * @author Lion Li * @date 2021-05-30 */ +@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class) public interface TestTreeMapper extends BaseMapperPlus { } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/IChkjTestService.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/IChkjTestService.java new file mode 100644 index 000000000..8896714ba --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/IChkjTestService.java @@ -0,0 +1,57 @@ +package com.ruoyi.demo.service; + +import com.ruoyi.demo.domain.ChkjTest; +import com.ruoyi.demo.vo.ChkjTestVo; +import com.ruoyi.demo.bo.ChkjTestQueryBo; +import com.ruoyi.demo.bo.ChkjTestAddBo; +import com.ruoyi.demo.bo.ChkjTestEditBo; +import com.ruoyi.common.core.page.IServicePlus; +import com.ruoyi.common.core.page.TableDataInfo; + +import java.util.Collection; +import java.util.List; + +/** + * 测试Service接口 + * + * @author Lion Li + * @date 2021-05-14 + */ +public interface IChkjTestService extends IServicePlus { + /** + * 查询单个 + * @return + */ + ChkjTestVo queryById(Long id); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(ChkjTestQueryBo bo); + /** + * 查询列表 + */ + List queryList(ChkjTestQueryBo bo); + + /** + * 根据新增业务对象插入测试 + * @param bo 测试新增业务对象 + * @return + */ + Boolean insertByAddBo(ChkjTestAddBo bo); + + /** + * 根据编辑业务对象修改测试 + * @param bo 测试编辑业务对象 + * @return + */ + Boolean updateByEditBo(ChkjTestEditBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/ChkjTestServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/ChkjTestServiceImpl.java new file mode 100644 index 000000000..9808d27a8 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/ChkjTestServiceImpl.java @@ -0,0 +1,93 @@ +package com.ruoyi.demo.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.page.PagePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.demo.bo.ChkjTestAddBo; +import com.ruoyi.demo.bo.ChkjTestEditBo; +import com.ruoyi.demo.bo.ChkjTestQueryBo; +import com.ruoyi.demo.domain.ChkjTest; +import com.ruoyi.demo.mapper.ChkjTestMapper; +import com.ruoyi.demo.service.IChkjTestService; +import com.ruoyi.demo.vo.ChkjTestVo; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 测试Service业务层处理 + * + * @author Lion Li + * @date 2021-05-14 + */ +@Service +public class ChkjTestServiceImpl extends ServiceImpl implements IChkjTestService { + + @Override + public ChkjTestVo queryById(Long id){ + return getVoById(id, obj -> BeanUtil.toBean(obj, ChkjTestVo.class)); + } + + @Override + public TableDataInfo queryPageList(ChkjTestQueryBo bo) { + PagePlus result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo), ChkjTestVo.class); + return PageUtils.buildDataInfo(result); + } + + @Override + public List queryList(ChkjTestQueryBo bo) { + return listVo(buildQueryWrapper(bo), ChkjTestVo.class); + } + + private LambdaQueryWrapper buildQueryWrapper(ChkjTestQueryBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StrUtil.isNotBlank(bo.getTestKey()), ChkjTest::getTestKey, bo.getTestKey()); + lqw.eq(StrUtil.isNotBlank(bo.getValue()), ChkjTest::getValue, bo.getValue()); + lqw.eq(bo.getVersion() != null, ChkjTest::getVersion, bo.getVersion()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + ChkjTest::getCreateTime ,params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.eq(bo.getDeleted() != null, ChkjTest::getDeleted, bo.getDeleted()); + lqw.eq(bo.getParentId() != null, ChkjTest::getParentId, bo.getParentId()); + lqw.eq(bo.getOrderNum() != null, ChkjTest::getOrderNum, bo.getOrderNum()); + return lqw; + } + + @Override + public Boolean insertByAddBo(ChkjTestAddBo bo) { + ChkjTest add = BeanUtil.toBean(bo, ChkjTest.class); + validEntityBeforeSave(add); + return save(add); + } + + @Override + public Boolean updateByEditBo(ChkjTestEditBo bo) { + ChkjTest update = BeanUtil.toBean(bo, ChkjTest.class); + validEntityBeforeSave(update); + return updateById(update); + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(ChkjTest entity){ + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return removeByIds(ids); + } +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/vo/ChkjTestVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/vo/ChkjTestVo.java new file mode 100644 index 000000000..e283a811c --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/vo/ChkjTestVo.java @@ -0,0 +1,57 @@ +package com.ruoyi.demo.vo; + +import com.ruoyi.common.annotation.Excel; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.util.Date; + + + +/** + * 测试视图对象 mall_package + * + * @author Lion Li + * @date 2021-05-14 + */ +@Data +@ApiModel("测试视图对象") +public class ChkjTestVo { + private static final long serialVersionUID = 1L; + + /** 主键 */ + @ApiModelProperty("主键") + private Long id; + + /** key键 */ + @Excel(name = "key键") + @ApiModelProperty("key键") + private String testKey; + /** 值 */ + @Excel(name = "值") + @ApiModelProperty("值") + private String value; + /** 版本 */ + @Excel(name = "版本") + @ApiModelProperty("版本") + private Long version; + /** 创建时间 */ + @Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("创建时间") + private Date createTime; + /** 删除标志 */ + @Excel(name = "删除标志") + @ApiModelProperty("删除标志") + private Long deleted; + /** 父id */ + @Excel(name = "父id") + @ApiModelProperty("父id") + private Long parentId; + /** 排序号 */ + @Excel(name = "排序号") + @ApiModelProperty("排序号") + private Long orderNum; + +} diff --git a/ruoyi-demo/src/main/resources/mapper/demo/ChkjTestMapper.xml b/ruoyi-demo/src/main/resources/mapper/demo/ChkjTestMapper.xml new file mode 100644 index 000000000..2b59b3fbd --- /dev/null +++ b/ruoyi-demo/src/main/resources/mapper/demo/ChkjTestMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java index 0af3844ff..d81c3ca88 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RedisLockAspect.java @@ -3,6 +3,7 @@ package com.ruoyi.framework.aspectj; import com.ruoyi.common.annotation.RedisLock; import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.redis.RedisLockManager; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -33,7 +34,7 @@ import java.util.concurrent.TimeUnit; public class RedisLockAspect { @Autowired - private RedissonClient redissonClient; + private RedisLockManager redisLockManager; @Pointcut("@annotation(com.ruoyi.common.annotation.RedisLock)") public void annotationPointcut() { @@ -70,14 +71,16 @@ public class RedisLockAspect { key = Constants.REDIS_LOCK_KEY + key; Object res; try { - if (acquire(key, expireTime, TimeUnit.SECONDS)) { + if (redisLockManager.getLock(key, expireTime, TimeUnit.SECONDS)) { + log.info("lock => key : " + key + " , ThreadName : " + Thread.currentThread().getName()); try { res = joinPoint.proceed(); return res; } catch (Exception e) { throw new RuntimeException(e); } finally { - release(key); + redisLockManager.unLock(key); + log.info("unlock => key : " + key + " , ThreadName : " + Thread.currentThread().getName()); } } else { throw new RuntimeException("redis分布式锁注解参数异常"); @@ -133,32 +136,4 @@ public class RedisLockAspect { return listPar; } - /** - * 加锁(RLock)带超时时间的 - */ - private boolean acquire(String key, long expire, TimeUnit expireUnit) { - 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) { - //获取所对象 - RLock mylock = redissonClient.getLock(lockName); - //释放锁(解锁) - mylock.unlock(); - log.info("unlock => key : " + lockName + " , ThreadName : " + Thread.currentThread().getName()); - } - } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java index 568260209..5c11ae67a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java @@ -11,6 +11,11 @@ import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +/** + * 异步配置 + * + * @author Lion Li + */ @EnableAsync @Configuration public class AsyncConfig extends AsyncConfigurerSupport { diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java index e86f5bc03..95c7572fd 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java @@ -6,15 +6,20 @@ import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; +import org.redisson.spring.cache.CacheConfig; +import org.redisson.spring.cache.RedissonSpringCacheManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * redis配置 @@ -67,4 +72,15 @@ public class RedisConfig extends CachingConfigurerSupport { .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval()); return Redisson.create(config); } + + /** + * 整合spring-cache + */ + @Bean + public CacheManager cacheManager(RedissonClient redissonClient) { + Map config = new HashMap<>(); + config.put("redissonCacheMap", new CacheConfig(30*60*1000, 10*60*1000)); + return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE); + } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java index 7f0a629bc..005f03235 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java @@ -15,7 +15,7 @@ import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /** * 通用配置 - * + * * @author ruoyi */ @Configuration @@ -31,8 +31,7 @@ public class ResourcesConfig implements WebMvcConfigurer registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); /** swagger配置 */ - registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); - registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); } /** @@ -63,4 +62,4 @@ public class ResourcesConfig implements WebMvcConfigurer source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } -} \ No newline at end of file +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java index 1a92ca088..2c65ac69d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java @@ -3,6 +3,7 @@ package com.ruoyi.framework.config; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import com.ruoyi.framework.config.properties.SwaggerProperties; import io.swagger.annotations.ApiOperation; +import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,18 +14,16 @@ import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; /** - * Swagger2的接口配置 + * Swagger 文档配置 * * @author Lion Li */ @Configuration -@EnableSwagger2 @EnableKnife4j public class SwaggerConfig { @@ -36,7 +35,7 @@ public class SwaggerConfig { */ @Bean public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) + return new Docket(DocumentationType.OAS_30) .enable(swaggerProperties.getEnabled()) // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) .apiInfo(apiInfo()) @@ -60,7 +59,7 @@ public class SwaggerConfig { */ private List securitySchemes() { List apiKeyList = new ArrayList(); - apiKeyList.add(new ApiKey("Authorization", "Authorization", "header")); + apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); return apiKeyList; } @@ -72,7 +71,7 @@ public class SwaggerConfig { securityContexts.add( SecurityContext.builder() .securityReferences(defaultAuth()) - .forPaths(PathSelectors.regex("^(?!auth).*$")) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) .build()); return securityContexts; } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/SwaggerProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/SwaggerProperties.java index f99c3da15..ece75efef 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/SwaggerProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/SwaggerProperties.java @@ -6,7 +6,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** - * 验证码 配置属性 + * swagger 配置属性 * * @author Lion Li */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ThreadPoolProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ThreadPoolProperties.java index 68cb09337..08b6842aa 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ThreadPoolProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ThreadPoolProperties.java @@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** - * 验证码 配置属性 + * 线程池 配置属性 * * @author Lion Li */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java index d582e5407..f695c1c62 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/TokenProperties.java @@ -4,6 +4,11 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +/** + * token 配置属性 + * + * @author Lion Li + */ @Data @Component @ConfigurationProperties(prefix = "token") diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/XssProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/XssProperties.java index 35ae2e4ff..d8a68a86a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/XssProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/XssProperties.java @@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** - * 验证码 配置属性 + * xss过滤 配置属性 * * @author Lion Li */ diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm index b40b497ad..900f51017 100644 --- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -9,6 +9,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -28,7 +29,7 @@ import io.swagger.annotations.ApiOperation; /** * ${functionName}Controller - * + * * @author ${author} * @date ${datetime} */ @@ -87,6 +88,7 @@ public class ${ClassName}Controller extends BaseController { @ApiOperation("新增${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @RepeatSubmit @PostMapping() public AjaxResult add(@Validated @RequestBody ${ClassName}AddBo bo) { return toAjax(i${ClassName}Service.insertByAddBo(bo) ? 1 : 0); @@ -98,6 +100,7 @@ public class ${ClassName}Controller extends BaseController { @ApiOperation("修改${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @RepeatSubmit @PutMapping() public AjaxResult edit(@Validated @RequestBody ${ClassName}EditBo bo) { return toAjax(i${ClassName}Service.updateByEditBo(bo) ? 1 : 0); diff --git a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm index 600841891..36a98642c 100644 --- a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm @@ -2,6 +2,8 @@ package ${packageName}.mapper; import ${packageName}.domain.${ClassName}; import com.ruoyi.common.core.page.BaseMapperPlus; +import com.ruoyi.common.core.mybatisplus.MybatisPlusRedisCache; +import org.apache.ibatis.annotations.CacheNamespace; /** * ${functionName}Mapper接口 @@ -9,6 +11,7 @@ import com.ruoyi.common.core.page.BaseMapperPlus; * @author ${author} * @date ${datetime} */ +@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class) public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}> { } diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm index f1247aba3..0b971b281 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -541,7 +541,7 @@ export default { this.loading = false; this.getList(); this.msgSuccess("删除成功"); - }) + }).catch(() => {}); } } }; diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm index 9f58575bd..d6b311c19 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -599,7 +599,7 @@ export default { this.loading = false; this.getList(); this.msgSuccess("删除成功"); - }) + }).catch(() => {}); }, #if($table.sub) /** ${subTable.functionName}序号 */ @@ -648,7 +648,7 @@ export default { }).then(response => { this.download(response.msg); this.exportLoading = false; - }) + }).catch(() => {}); } } }; diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index 52551a4cc..d90fdbac6 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-plus", - "version": "2.3.1", + "version": "2.3.2", "description": "RuoYi-Vue-Plus后台管理系统", "author": "LionLi", "license": "MIT", diff --git a/ruoyi-ui/src/api/demo/test.js b/ruoyi-ui/src/api/demo/test.js new file mode 100644 index 000000000..f4c642115 --- /dev/null +++ b/ruoyi-ui/src/api/demo/test.js @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 查询测试列表 +export function listTest(query) { + return request({ + url: '/demo/test/list', + method: 'get', + params: query + }) +} + +// 查询测试详细 +export function getTest(id) { + return request({ + url: '/demo/test/' + id, + method: 'get' + }) +} + +// 新增测试 +export function addTest(data) { + return request({ + url: '/demo/test', + method: 'post', + data: data + }) +} + +// 修改测试 +export function updateTest(data) { + return request({ + url: '/demo/test', + method: 'put', + data: data + }) +} + +// 删除测试 +export function delTest(id) { + return request({ + url: '/demo/test/' + id, + method: 'delete' + }) +} + +// 导出测试 +export function exportTest(query) { + return request({ + url: '/demo/test/export', + method: 'get', + params: query + }) +} \ No newline at end of file diff --git a/ruoyi-ui/src/components/Editor/index.vue b/ruoyi-ui/src/components/Editor/index.vue index 640049ca0..d63a48d12 100644 --- a/ruoyi-ui/src/components/Editor/index.vue +++ b/ruoyi-ui/src/components/Editor/index.vue @@ -75,7 +75,7 @@ export default { [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 [{ align: [] }], // 对齐方式 ["clean"], // 清除文本格式 - ["link", "image"] // 链接、图片 + ["link", "image", "video"] // 链接、图片、视频 ], }, placeholder: "请输入内容", diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue index 9d220e90b..466cd981e 100644 --- a/ruoyi-ui/src/layout/components/Navbar.vue +++ b/ruoyi-ui/src/layout/components/Navbar.vue @@ -8,7 +8,7 @@