sendMessageWithAttachment(@ApiParam("接收人") String to,
+ @ApiParam("标题") String subject,
+ @ApiParam("内容") String text,
+ @ApiParam("附件路径") String filePath) {
+ MailUtils.sendText(to, subject, text, new File(filePath));
+ return R.ok();
+ }
+
+}
diff --git a/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
new file mode 100644
index 00000000..eda77c54
--- /dev/null
+++ b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
@@ -0,0 +1,101 @@
+package com.ruoyi.demo.controller;
+
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.redis.utils.RedisUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+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.time.Duration;
+
+/**
+ * spring-cache 演示案例
+ *
+ * @author Lion Li
+ */
+// 类级别 缓存统一配置
+//@CacheConfig(cacheNames = "redissonCacheMap")
+@Api(value = "spring-cache 演示案例", tags = {"spring-cache 演示案例"})
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/cache")
+public class RedisCacheController {
+
+ /**
+ * 测试 @Cacheable
+ *
+ * 表示这个方法有了缓存的功能,方法的返回值会被缓存下来
+ * 下一次调用该方法前,会去检查是否缓存中已经有值
+ * 如果有就直接返回,不调用方法
+ * 如果没有,就调用方法,然后把结果缓存起来
+ * 这个注解「一般用在查询方法上」
+ *
+ * 重点说明: 缓存注解严谨与其他筛选数据功能一起使用
+ * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
+ *
+ * cacheNames 为配置文件内 groupId
+ */
+ @ApiOperation("测试 @Cacheable")
+ @Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
+ @GetMapping("/test1")
+ public R test1(String key, String value) {
+ return R.ok("操作成功", value);
+ }
+
+ /**
+ * 测试 @CachePut
+ *
+ * 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
+ * 它「通常用在新增方法上」
+ *
+ * cacheNames 为 配置文件内 groupId
+ */
+ @ApiOperation("测试 @CachePut")
+ @CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
+ @GetMapping("/test2")
+ public R test2(String key, String value) {
+ return R.ok("操作成功", value);
+ }
+
+ /**
+ * 测试 @CacheEvict
+ *
+ * 使用了CacheEvict注解的方法,会清空指定缓存
+ * 「一般用在更新或者删除的方法上」
+ *
+ * cacheNames 为 配置文件内 groupId
+ */
+ @ApiOperation("测试 @CacheEvict")
+ @CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
+ @GetMapping("/test3")
+ public R test3(String key, String value) {
+ return R.ok("操作成功", value);
+ }
+
+ /**
+ * 测试设置过期时间
+ * 手动设置过期时间10秒
+ * 11秒后获取 判断是否相等
+ */
+ @ApiOperation("测试设置过期时间")
+ @GetMapping("/test6")
+ public R test6(String key, String value) {
+ RedisUtils.setCacheObject(key, value);
+ boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
+ System.out.println("***********" + flag);
+ try {
+ Thread.sleep(11 * 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Object obj = RedisUtils.getCacheObject(key);
+ return R.ok(value.equals(obj));
+ }
+
+}
diff --git a/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java
new file mode 100644
index 00000000..c31925a5
--- /dev/null
+++ b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java
@@ -0,0 +1,76 @@
+package com.ruoyi.demo.controller;
+
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
+import com.baomidou.lock.annotation.Lock4j;
+import com.baomidou.lock.executor.RedissonLockExecutor;
+import com.ruoyi.common.core.domain.R;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalTime;
+
+
+/**
+ * 测试分布式锁的样例
+ *
+ * @author shenxinquan
+ */
+@Api(value = "测试分布式锁的样例", tags = {"测试分布式锁的样例"})
+@Slf4j
+@RestController
+@RequestMapping("/demo/redisLock")
+public class RedisLockController {
+
+ @Autowired
+ private LockTemplate lockTemplate;
+
+ /**
+ * 测试lock4j 注解
+ */
+ @ApiOperation("测试lock4j 注解")
+ @Lock4j(keys = {"#key"})
+ @GetMapping("/testLock4j")
+ public R testLock4j(String key, String value) {
+ System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
+ return R.ok("操作成功", value);
+ }
+
+ /**
+ * 测试lock4j 工具
+ */
+ @ApiOperation("测试lock4j 工具")
+ @GetMapping("/testLock4jLockTemplate")
+ public R testLock4jLockTemplate(String key, String value) {
+ final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
+ if (null == lockInfo) {
+ throw new RuntimeException("业务处理中,请稍后再试");
+ }
+ // 获取锁成功,处理业务
+ try {
+ try {
+ Thread.sleep(8000);
+ } catch (InterruptedException e) {
+ //
+ }
+ System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName());
+ } finally {
+ //释放锁
+ lockTemplate.releaseLock(lockInfo);
+ }
+ //结束
+ return R.ok("操作成功", value);
+ }
+
+}
diff --git a/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisPubSubController.java b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisPubSubController.java
new file mode 100644
index 00000000..80dc615a
--- /dev/null
+++ b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisPubSubController.java
@@ -0,0 +1,42 @@
+package com.ruoyi.demo.controller;
+
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.redis.utils.RedisUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Redis 发布订阅 演示案例
+ *
+ * @author Lion Li
+ */
+@Api(value = "Redis发布订阅 演示案例", tags = {"Redis发布订阅"})
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/redis/pubsub")
+public class RedisPubSubController {
+
+ @ApiOperation("发布消息")
+ @GetMapping("/pub")
+ public R pub(@ApiParam("通道Key") String key, @ApiParam("发送内容") String value) {
+ RedisUtils.publish(key, value, consumer -> {
+ System.out.println("发布通道 => " + key + ", 发送值 => " + value);
+ });
+ return R.ok("操作成功");
+ }
+
+ @ApiOperation("订阅消息")
+ @GetMapping("/sub")
+ public R sub(@ApiParam("通道Key") String key) {
+ RedisUtils.subscribe(key, String.class, msg -> {
+ System.out.println("订阅通道 => " + key + ", 接收值 => " + msg);
+ });
+ return R.ok("操作成功");
+ }
+
+}
diff --git a/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/SmsController.java b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/SmsController.java
new file mode 100644
index 00000000..375cc482
--- /dev/null
+++ b/ruoyi-example/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/SmsController.java
@@ -0,0 +1,72 @@
+package com.ruoyi.demo.controller;
+
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.utils.SpringUtils;
+import com.ruoyi.common.sms.config.properties.SmsProperties;
+import com.ruoyi.common.sms.core.SmsTemplate;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 短信演示案例
+ * 请先阅读文档 否则无法使用
+ *
+ * @author Lion Li
+ * @version 4.2.0
+ */
+@Validated
+@Api(value = "短信演示案例", tags = {"短信演示案例"})
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/sms")
+public class SmsController {
+
+ private final SmsProperties smsProperties;
+// private final SmsTemplate smsTemplate; // 可以使用spring注入
+// private final AliyunSmsTemplate smsTemplate; // 也可以注入某个厂家的模板工具
+
+ @ApiOperation("发送短信Aliyun")
+ @GetMapping("/sendAliyun")
+ public R