Browse Source

feat(登录):
用户登录后更新最后登录信息
新增验证码登录
新增短信模块
fix(代码生成):
代码生成器前端api路径错误修复
删除代码生成器自动生成目录的问题

18339543638 2 years ago
parent
commit
6342e60f4d
33 changed files with 492 additions and 66 deletions
  1. 15 0
      tr-dependencies/pom.xml
  2. 1 1
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/impl/GenBasicServiceImpl.java
  3. 13 1
      tr-modules/tr-module-system/pom.xml
  4. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/excel/DictExcelHandlerAdapter.java
  5. 29 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsChannelRefreshConsumer.java
  6. 3 3
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsConsumer.java
  7. 29 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsTemplateRefreshConsumer.java
  8. 22 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsChannelRefreshMessage.java
  9. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsSendMessage.java
  10. 23 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsTemplateRefreshMessage.java
  11. 30 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/producer/sms/SmsProducer.java
  12. 4 3
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/producer/sms/SmsSupplier.java
  13. 6 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/SysUserOnlineController.java
  14. 64 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/config/CaptchaOperator.java
  15. 44 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/CaptchaController.java
  16. 5 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2PswReqDTO.java
  17. 21 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java
  18. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/ISmsSendService.java
  19. 5 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/ISysSmsTempService.java
  20. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SmsSendServiceImpl.java
  21. 18 9
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SysSmsChannelServiceImpl.java
  22. 34 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SysSmsTempServiceImpl.java
  23. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysPortalController.java
  24. 10 10
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/provider/SysMenuApiProvider.java
  25. 9 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysUserService.java
  26. 24 19
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java
  27. 1 0
      tr-plugins/pom.xml
  28. 23 0
      tr-plugins/tr-spring-boot-starter-plugin-bus/pom.xml
  29. 41 0
      tr-plugins/tr-spring-boot-starter-plugin-bus/src/main/java/cn/tr/plugin/bus/AbstractBusProducer.java
  30. 0 1
      tr-plugins/tr-spring-boot-starter-plugin-sms/pom.xml
  31. 7 1
      tr-test/src/main/java/cn/tr/test/WebApplication.java
  32. 4 1
      tr-test/src/main/resources/application-stream.yml
  33. 1 1
      tr-test/src/main/resources/application.yml

+ 15 - 0
tr-dependencies/pom.xml

@@ -68,6 +68,8 @@
         <oshi.core.version>6.2.2</oshi.core.version>
         <oshi.core.version>6.2.2</oshi.core.version>
 
 
         <stream-rabbit.version>3.2.6</stream-rabbit.version>
         <stream-rabbit.version>3.2.6</stream-rabbit.version>
+
+        <bus-rabbit.version>3.1.2</bus-rabbit.version>
     </properties>
     </properties>
 
 
 
 
@@ -439,6 +441,13 @@
                 <version>${revision}</version>
                 <version>${revision}</version>
             </dependency>
             </dependency>
 
 
+            <!--消息总线模块-->
+            <dependency>
+                <groupId>cn.tr</groupId>
+                <artifactId>tr-spring-boot-starter-plugin-bus</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
             <!--短信模块-->
             <!--短信模块-->
             <dependency>
             <dependency>
                 <groupId>cn.tr</groupId>
                 <groupId>cn.tr</groupId>
@@ -466,6 +475,12 @@
                 <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
                 <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
                 <version>${stream-rabbit.version}</version>
                 <version>${stream-rabbit.version}</version>
             </dependency>
             </dependency>
+
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-bus-amqp</artifactId>
+                <version>${bus-rabbit.version}</version>
+            </dependency>
         </dependencies>
         </dependencies>
     </dependencyManagement>
     </dependencyManagement>
 </project>
 </project>

+ 1 - 1
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/impl/GenBasicServiceImpl.java

@@ -548,7 +548,7 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
         bindingJsonObject.set("genTime", DateUtil.format(DateTime.now(), " yyyy/MM/dd HH:mm"));
         bindingJsonObject.set("genTime", DateUtil.format(DateTime.now(), " yyyy/MM/dd HH:mm"));
         String pathPrefix="";
         String pathPrefix="";
         if(StrUtil.contains(genBasic.getPackageName(),"sys")&&!StrUtil.equals(genBasic.getBackendModuleName(),"sys")){
         if(StrUtil.contains(genBasic.getPackageName(),"sys")&&!StrUtil.equals(genBasic.getBackendModuleName(),"sys")){
-            pathPrefix="/"+genBasic.getPackageName();
+            pathPrefix="/sys";
         }
         }
         pathPrefix=pathPrefix+"/"+genBasic.getBackendModuleName()+"/"+genBasic.getBusName();
         pathPrefix=pathPrefix+"/"+genBasic.getBackendModuleName()+"/"+genBasic.getBusName();
         //路径前缀
         //路径前缀

+ 13 - 1
tr-modules/tr-module-system/pom.xml

@@ -42,7 +42,7 @@
             <groupId>cn.tr</groupId>
             <groupId>cn.tr</groupId>
             <artifactId>tr-spring-boot-starter-plugin-biz-excel</artifactId>
             <artifactId>tr-spring-boot-starter-plugin-biz-excel</artifactId>
         </dependency>
         </dependency>
-        
+
         <dependency>
         <dependency>
             <groupId>cn.tr</groupId>
             <groupId>cn.tr</groupId>
             <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
             <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
@@ -92,5 +92,17 @@
             <groupId>org.springframework.cloud</groupId>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
             <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
         </dependency>
         </dependency>
+
+        <dependency>
+            <groupId>cn.tr</groupId>
+            <artifactId>tr-spring-boot-starter-plugin-bus</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
     </dependencies>
     </dependencies>
 </project>
 </project>

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/core/excel/DictExcelHandlerAdapter.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/excel/DictExcelHandlerAdapter.java

@@ -1,4 +1,4 @@
-package cn.tr.module.core.excel;
+package cn.tr.module.sys.core.excel;
 
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;

+ 29 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsChannelRefreshConsumer.java

@@ -0,0 +1,29 @@
+package cn.tr.module.sys.core.mq.consumer.sms;
+
+import cn.tr.module.sys.core.mq.message.sms.SmsChannelRefreshMessage;
+import cn.tr.module.sys.sms.service.ISysSmsChannelService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 针对 {@link SmsChannelRefreshMessage} 的消费者
+ *
+ * @author 芋道源码
+ */
+@Component
+@Slf4j
+public class SmsChannelRefreshConsumer {
+
+    @Resource
+    private ISysSmsChannelService smsChannelService;
+
+    @EventListener
+    public void execute(SmsChannelRefreshMessage message) {
+        log.info("[execute][收到 SmsChannel 刷新消息]");
+        smsChannelService.initLocalCache();
+    }
+
+}

+ 3 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/core/mq/consumer/sms/SmsConsumer.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsConsumer.java

@@ -1,7 +1,7 @@
-package cn.tr.module.core.mq.consumer.sms;
+package cn.tr.module.sys.core.mq.consumer.sms;
 
 
-import cn.tr.module.core.mq.message.sms.SmsSendMessage;
-import cn.tr.module.core.mq.producer.sms.SmsSupplier;
+import cn.tr.module.sys.core.mq.message.sms.SmsSendMessage;
+import cn.tr.module.sys.core.mq.producer.sms.SmsSupplier;
 import cn.tr.module.sys.sms.service.ISmsSendService;
 import cn.tr.module.sys.sms.service.ISmsSendService;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;

+ 29 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/consumer/sms/SmsTemplateRefreshConsumer.java

@@ -0,0 +1,29 @@
+package cn.tr.module.sys.core.mq.consumer.sms;
+
+import cn.tr.module.sys.core.mq.message.sms.SmsTemplateRefreshMessage;
+import cn.tr.module.sys.sms.service.ISysSmsTempService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 针对 {@link SmsTemplateRefreshMessage} 的消费者
+ *
+ * @author 芋道源码
+ */
+@Component
+@Slf4j
+public class SmsTemplateRefreshConsumer {
+
+    @Resource
+    private ISysSmsTempService smsTemplateService;
+
+    @EventListener
+    public void execute(SmsTemplateRefreshMessage message) {
+        log.info("[execute][收到 SmsTemplate 刷新消息]");
+        smsTemplateService.initLocalCache();
+    }
+
+}

+ 22 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsChannelRefreshMessage.java

@@ -0,0 +1,22 @@
+package cn.tr.module.sys.core.mq.message.sms;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.cloud.bus.event.RemoteApplicationEvent;
+
+/**
+ * 短信渠道的数据刷新 Message
+ *
+ * @author 芋道源码
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SmsChannelRefreshMessage extends RemoteApplicationEvent {
+
+    public SmsChannelRefreshMessage() {
+    }
+    public SmsChannelRefreshMessage(Object source, String originService, String destinationService) {
+        super(source, originService, DEFAULT_DESTINATION_FACTORY.getDestination(destinationService));
+    }
+
+}

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/core/mq/message/sms/SmsSendMessage.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsSendMessage.java

@@ -1,4 +1,4 @@
-package cn.tr.module.core.mq.message.sms;
+package cn.tr.module.sys.core.mq.message.sms;
 
 
 import cn.tr.core.pojo.KeyValue;
 import cn.tr.core.pojo.KeyValue;
 import lombok.Data;
 import lombok.Data;

+ 23 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/message/sms/SmsTemplateRefreshMessage.java

@@ -0,0 +1,23 @@
+package cn.tr.module.sys.core.mq.message.sms;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.cloud.bus.event.RemoteApplicationEvent;
+
+/**
+ * 短信模板的数据刷新 Message
+ *
+ * @author 芋道源码
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SmsTemplateRefreshMessage extends RemoteApplicationEvent {
+
+    public SmsTemplateRefreshMessage() {
+    }
+
+    public SmsTemplateRefreshMessage(Object source, String originService, String destinationService) {
+        super(source, originService, DEFAULT_DESTINATION_FACTORY.getDestination(destinationService));
+    }
+
+}

+ 30 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/producer/sms/SmsProducer.java

@@ -0,0 +1,30 @@
+package cn.tr.module.sys.core.mq.producer.sms;
+
+import cn.tr.module.sys.core.mq.message.sms.SmsChannelRefreshMessage;
+import cn.tr.module.sys.core.mq.message.sms.SmsTemplateRefreshMessage;
+import cn.tr.plugin.bus.AbstractBusProducer;
+import org.springframework.stereotype.Component;
+
+/**
+ * @ClassName : SmsProducer
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月25日
+ */
+@Component
+public class SmsProducer extends AbstractBusProducer {
+
+    /**
+     * 发送 {@link SmsChannelRefreshMessage} 消息
+     */
+    public void sendSmsChannelRefreshMessage() {
+        publishEvent(new SmsChannelRefreshMessage(this, getBusId(), selfDestinationService()));
+    }
+
+    /**
+     * 发送 {@link SmsTemplateRefreshMessage} 消息
+     */
+    public void sendSmsTemplateRefreshMessage() {
+        publishEvent(new SmsTemplateRefreshMessage(this, getBusId(), selfDestinationService()));
+    }
+}

+ 4 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/core/mq/producer/sms/SmsSupplier.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/core/mq/producer/sms/SmsSupplier.java

@@ -1,7 +1,8 @@
-package cn.tr.module.core.mq.producer.sms;
+package cn.tr.module.sys.core.mq.producer.sms;
 
 
 import cn.tr.core.pojo.KeyValue;
 import cn.tr.core.pojo.KeyValue;
-import cn.tr.module.core.mq.message.sms.SmsSendMessage;
+import cn.tr.module.sys.core.mq.message.sms.SmsSendMessage;
+import cn.tr.plugin.bus.AbstractBusProducer;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
@@ -17,7 +18,7 @@ import java.util.function.Supplier;
  */
  */
 @Slf4j
 @Slf4j
 @Component
 @Component
-public class SmsSupplier implements Supplier<Flux<SmsSendMessage>> {
+public class SmsSupplier extends AbstractBusProducer implements Supplier<Flux<SmsSendMessage>> {
     private Sinks.Many<SmsSendMessage> sink = Sinks.many().unicast().onBackpressureBuffer();
     private Sinks.Many<SmsSendMessage> sink = Sinks.many().unicast().onBackpressureBuffer();
     /**
     /**
      * 发送 {@link SmsSendMessage} 消息
      * 发送 {@link SmsSendMessage} 消息

+ 6 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/SysUserOnlineController.java

@@ -2,6 +2,7 @@ package cn.tr.module.sys.monitor.controller;
 
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.session.SaSession;
 import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.session.TokenSign;
 import cn.dev33.satoken.stp.StpLogic;
 import cn.dev33.satoken.stp.StpLogic;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.PageUtil;
 import cn.hutool.core.util.PageUtil;
@@ -73,6 +74,11 @@ public class SysUserOnlineController extends BaseController {
         }
         }
         if(CollectionUtil.isNotEmpty(source.getSessionIds())){
         if(CollectionUtil.isNotEmpty(source.getSessionIds())){
             source.getSessionIds().parallelStream().map(stpLogic::getSessionBySessionId)
             source.getSessionIds().parallelStream().map(stpLogic::getSessionBySessionId)
+                    .peek(session -> {
+                        session.getTokenSignList().stream()
+                                .map(TokenSign::getValue)
+                                .forEach(stpLogic::logoutByTokenValue);
+                    })
                     .forEach(SaSession::logout);
                     .forEach(SaSession::logout);
         }
         }
         return CommonResult.success();
         return CommonResult.success();

+ 64 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/config/CaptchaOperator.java

@@ -0,0 +1,64 @@
+package cn.tr.module.sys.oauth2.config;
+
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import com.wf.captcha.base.Captcha;
+import com.wf.captcha.utils.CaptchaUtil;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName CaptureUtil.java
+ * @Description TODO
+ * @createTime 2022年08月24日 09:58:00
+ */
+@Component
+public class CaptchaOperator {
+    private RedisTemplate<String,String> redisTemplate;
+    public CaptchaOperator(RedisTemplate redisTemplate) {
+        this.redisTemplate=redisTemplate;
+    }
+
+    /**
+     * 输出验证码
+     * @param key
+     * @param captcha  Captcha
+     * @param request  HttpServletRequest
+     * @param response HttpServletResponse
+     * @throws IOException IO异常
+     */
+    public void out(String key, Captcha captcha, int expire, HttpServletRequest request, HttpServletResponse response)
+            throws IOException {
+        CaptchaUtil.setHeader(response);
+        //验证码放入缓存30分钟
+        redisTemplate.boundValueOps("captcha:"+key).set(captcha.text().toLowerCase(), expire);
+        captcha.out(response.getOutputStream());
+    }
+
+
+    public boolean ver(String key,String code){
+        BoundValueOperations<String, String> operations = redisTemplate.boundValueOps("captcha:" + key);
+        if(StrUtil.isBlank(code)){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"验证码不能为空");
+        }
+
+        Object cacheCode = operations.get();
+        if (Objects.nonNull(cacheCode)) {
+            if (Objects.equals(cacheCode,code)) {
+                operations.getAndDelete();
+                return true;
+            }
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"验证码错误");
+        }
+        throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"验证码已失效");
+    }
+}

+ 44 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/CaptchaController.java

@@ -0,0 +1,44 @@
+package cn.tr.module.sys.oauth2.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.module.sys.oauth2.config.CaptchaOperator;
+import com.wf.captcha.ArithmeticCaptcha;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.*;
+import java.io.IOException;
+
+/**
+ * 验证码
+ *
+ * @author tr
+ */
+@Api(tags =  "验证码")
+@RestController
+@RequestMapping("/auth/captcha")
+@AllArgsConstructor
+public class CaptchaController {
+
+    private final CaptchaOperator captchaTool;
+
+    @GetMapping
+    @SaIgnore
+    @ApiOperation("获取验证码")
+    public void get(@RequestParam("key")String key, HttpServletRequest request, HttpServletResponse response){
+        // 算术类型
+        ArithmeticCaptcha captcha = new ArithmeticCaptcha(140,38);
+        try {
+            new Font("Verdana", Font.PLAIN, 32);
+            captchaTool.out(key,captcha,300,request,response);
+        } catch (IOException e) {
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"系统繁忙,请稍后再试");
+        }
+    }
+
+}

+ 5 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2PswReqDTO.java

@@ -35,6 +35,9 @@ public class OAuth2PswReqDTO extends OAuth2DTO {
 	@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
 	@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
 	private String password;
 	private String password;
 
 
-	@ApiModelProperty(value = "验证码,验证码开启时,需要传递")
-	private String captchaVerification;
+	@ApiModelProperty("验证码")
+	String captchaCode;
+
+	@ApiModelProperty("验证码key")
+	String captchaKey;
 }
 }

+ 21 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java

@@ -13,6 +13,9 @@ import cn.tr.core.strategy.LoginUserStrategy;
 import cn.tr.core.utils.IpUtil;
 import cn.tr.core.utils.IpUtil;
 import cn.tr.core.utils.PswUtils;
 import cn.tr.core.utils.PswUtils;
 import cn.tr.core.utils.ServletUtils;
 import cn.tr.core.utils.ServletUtils;
+import cn.tr.module.sys.config.SysConfigManager;
+import cn.tr.module.sys.config.SysConfigProperties;
+import cn.tr.module.sys.oauth2.config.CaptchaOperator;
 import cn.tr.module.sys.oauth2.mapper.OAuth2Mapper;
 import cn.tr.module.sys.oauth2.mapper.OAuth2Mapper;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.user.dto.SysUserDTO;
 import cn.tr.module.sys.user.dto.SysUserDTO;
@@ -24,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
-
 import java.util.Date;
 import java.util.Date;
 import java.util.Optional;
 import java.util.Optional;
 
 
@@ -41,6 +43,12 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
     private LoginOAuth2PswUserOperator self;
     private LoginOAuth2PswUserOperator self;
     @Autowired
     @Autowired
     private ISysUserService sysUserService;
     private ISysUserService sysUserService;
+
+    @Autowired
+    private SysConfigManager configManager;
+
+    @Autowired
+    private CaptchaOperator captchaOperator;
     @Override
     @Override
     @TenantIgnore
     @TenantIgnore
     public String auth(OAuth2PswReqDTO source) {
     public String auth(OAuth2PswReqDTO source) {
@@ -61,6 +69,17 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
             //用户都被禁用
             //用户都被禁用
             throw new ServiceException(TRExcCode.USER_ERROR_A0202);
             throw new ServiceException(TRExcCode.USER_ERROR_A0202);
         }
         }
+        //验证码校验
+        SysConfigProperties current = configManager.getCurrent();
+        if (Boolean.TRUE.equals(current.isCaptchaOpen())) {
+            String captchaCode = source.getCaptchaCode();
+            if(StrUtil.isEmpty(captchaCode)){
+                throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"验证码不能为空");
+            }
+            if(!captchaOperator.ver(source.getCaptchaKey(),source.getCaptchaCode())){
+                throw new ServiceException(TRExcCode.USER_ERROR_A0240);
+            }
+        }
         StpLogic stpUtil = SaTokenUtils.getStpUtil();
         StpLogic stpUtil = SaTokenUtils.getStpUtil();
         stpUtil.login(user.getId());
         stpUtil.login(user.getId());
         Date loginTime = new Date();
         Date loginTime = new Date();
@@ -72,7 +91,7 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
         updateUser.setLastLoginDate(loginTime);
         updateUser.setLastLoginDate(loginTime);
         updateUser.setLastLoginIp(ip);
         updateUser.setLastLoginIp(ip);
         updateUser.setLastLoginAddress(cityInfo);
         updateUser.setLastLoginAddress(cityInfo);
-//        sysUserService.updateSysUserById(updateUser);
+        sysUserService.updateLastLoginInfo(user.getId(),loginTime,ip,cityInfo);
         //清除缓存
         //清除缓存
         self.delUserLoginInfoCache(user.getId());
         self.delUserLoginInfoCache(user.getId());
 
 

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/ISmsSendService.java

@@ -1,6 +1,6 @@
 package cn.tr.module.sys.sms.service;
 package cn.tr.module.sys.sms.service;
 
 
-import cn.tr.module.core.mq.message.sms.SmsSendMessage;
+import cn.tr.module.sys.core.mq.message.sms.SmsSendMessage;
 
 
 import java.util.Map;
 import java.util.Map;
 
 

+ 5 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/ISysSmsTempService.java

@@ -15,6 +15,11 @@ import java.util.Map;
  **/
  **/
 public interface ISysSmsTempService{
 public interface ISysSmsTempService{
 
 
+    /**
+     * 初始化操作
+     */
+    void initLocalCache();
+
     /**
     /**
      * 根据条件查询短信模板
      * 根据条件查询短信模板
      * @param    query 查询参数
      * @param    query 查询参数

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SmsSendServiceImpl.java

@@ -7,8 +7,8 @@ import cn.tr.core.enums.UserTypeEnum;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.pojo.KeyValue;
 import cn.tr.core.pojo.KeyValue;
-import cn.tr.module.core.mq.message.sms.SmsSendMessage;
-import cn.tr.module.core.mq.producer.sms.SmsSupplier;
+import cn.tr.module.sys.core.mq.message.sms.SmsSendMessage;
+import cn.tr.module.sys.core.mq.producer.sms.SmsSupplier;
 import cn.tr.module.sys.sms.dto.SysSmsChannelDTO;
 import cn.tr.module.sys.sms.dto.SysSmsChannelDTO;
 import cn.tr.module.sys.sms.dto.SysSmsTempDTO;
 import cn.tr.module.sys.sms.dto.SysSmsTempDTO;
 import cn.tr.module.sys.sms.service.ISmsSendService;
 import cn.tr.module.sys.sms.service.ISmsSendService;

+ 18 - 9
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SysSmsChannelServiceImpl.java

@@ -1,6 +1,7 @@
 package cn.tr.module.sys.sms.service.impl;
 package cn.tr.module.sys.sms.service.impl;
 
 
 import cn.tr.core.utils.JsonUtils;
 import cn.tr.core.utils.JsonUtils;
+import cn.tr.module.sys.core.mq.producer.sms.SmsProducer;
 import cn.tr.plugin.sms.config.SmsClientFactory;
 import cn.tr.plugin.sms.config.SmsClientFactory;
 import cn.tr.plugin.sms.properties.SmsChannelProperties;
 import cn.tr.plugin.sms.properties.SmsChannelProperties;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
@@ -32,6 +33,10 @@ public class SysSmsChannelServiceImpl implements ISysSmsChannelService {
 
 
     @Autowired
     @Autowired
     private SmsClientFactory smsClientFactory;
     private SmsClientFactory smsClientFactory;
+
+    @Autowired
+    private SmsProducer smsProducer;
+
     @Override
     @Override
     @PostConstruct
     @PostConstruct
     public void initLocalCache() {
     public void initLocalCache() {
@@ -88,7 +93,11 @@ public class SysSmsChannelServiceImpl implements ISysSmsChannelService {
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     @Override
     @Override
     public boolean updateSysSmsChannelById(SysSmsChannelDTO source){
     public boolean updateSysSmsChannelById(SysSmsChannelDTO source){
-        return baseRepository.updateById(SysSmsChannelMapper.INSTANCE.convertPO(source))!=0;
+        boolean result = baseRepository.updateById(SysSmsChannelMapper.INSTANCE.convertPO(source)) != 0;
+        if(result){
+            smsProducer.sendSmsChannelRefreshMessage();
+        }
+        return result;
     };
     };
 
 
     /**
     /**
@@ -100,7 +109,11 @@ public class SysSmsChannelServiceImpl implements ISysSmsChannelService {
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public boolean insertSysSmsChannel(SysSmsChannelDTO source){
     public boolean insertSysSmsChannel(SysSmsChannelDTO source){
-        return baseRepository.insert(SysSmsChannelMapper.INSTANCE.convertPO(source))!=0;
+        boolean result = baseRepository.insert(SysSmsChannelMapper.INSTANCE.convertPO(source)) != 0;
+        if(result){
+            smsProducer.sendSmsChannelRefreshMessage();
+        }
+        return result;
     };
     };
 
 
     /**
     /**
@@ -112,12 +125,8 @@ public class SysSmsChannelServiceImpl implements ISysSmsChannelService {
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public int removeSysSmsChannelByIds(Collection<String> ids){
     public int removeSysSmsChannelByIds(Collection<String> ids){
-        return baseRepository.deleteBatchIds(ids);
+        int result = baseRepository.deleteBatchIds(ids);
+        smsProducer.sendSmsChannelRefreshMessage();
+        return result;
     };
     };
-
-
-    private void refreshLocalCache(SysSmsChannelDTO smsChannel){
-        //校验配置
-
-    }
 }
 }

+ 34 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/sms/service/impl/SysSmsTempServiceImpl.java

@@ -1,8 +1,10 @@
 package cn.tr.module.sys.sms.service.impl;
 package cn.tr.module.sys.sms.service.impl;
 
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.exception.TRExcCode;
+import cn.tr.module.sys.core.mq.producer.sms.SmsProducer;
 import cn.tr.module.sys.sms.mapper.SysSmsTempMapper;
 import cn.tr.module.sys.sms.mapper.SysSmsTempMapper;
 import cn.tr.module.sys.sms.dto.SysSmsTempDTO;
 import cn.tr.module.sys.sms.dto.SysSmsTempDTO;
 import cn.tr.module.sys.sms.dto.SysSmsTempQueryDTO;
 import cn.tr.module.sys.sms.dto.SysSmsTempQueryDTO;
@@ -11,6 +13,7 @@ import cn.tr.module.sys.sms.repository.SysSmsTempRepository;
 import cn.tr.module.sys.sms.service.ISysSmsTempService;
 import cn.tr.module.sys.sms.service.ISysSmsTempService;
 import cn.tr.module.sys.user.enums.CreateEnum;
 import cn.tr.module.sys.user.enums.CreateEnum;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -19,6 +22,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 短信模板Service接口实现类
  * 短信模板Service接口实现类
@@ -27,10 +32,25 @@ import java.util.Objects;
  * @date  2023/04/21 10:29
  * @date  2023/04/21 10:29
  **/
  **/
 @Service
 @Service
+@Slf4j
 public class SysSmsTempServiceImpl implements ISysSmsTempService {
 public class SysSmsTempServiceImpl implements ISysSmsTempService {
     @Autowired
     @Autowired
     private SysSmsTempRepository baseRepository;
     private SysSmsTempRepository baseRepository;
 
 
+    @Autowired
+    private SmsProducer smsProducer;
+    /**
+     * 根据编码对模板进行缓存操作
+     */
+    private volatile  Map<String,SysSmsTempPO> tempMapByCode=new ConcurrentHashMap<>();
+
+    @Override
+    public void initLocalCache() {
+        List<SysSmsTempPO> temps = baseRepository.selectList(new LambdaQueryWrapper<>());
+        log.info("[initLocalCache][缓存短信模版,数量为:{}]", temps.size());
+        tempMapByCode= temps.stream()
+                .collect(Collectors.groupingBy(SysSmsTempPO::getCode, Collectors.collectingAndThen(Collectors.toList(), CollectionUtil::getFirst)));
+    }
 
 
     /**
     /**
      * 根据条件查询短信模板
      * 根据条件查询短信模板
@@ -71,7 +91,11 @@ public class SysSmsTempServiceImpl implements ISysSmsTempService {
     @Override
     @Override
     public boolean updateSysSmsTempById(SysSmsTempDTO source){
     public boolean updateSysSmsTempById(SysSmsTempDTO source){
         validateSmsTempSource(source);
         validateSmsTempSource(source);
-        return baseRepository.updateById(SysSmsTempMapper.INSTANCE.convertPO(source))!=0;
+        boolean result = baseRepository.updateById(SysSmsTempMapper.INSTANCE.convertPO(source)) != 0;
+        if(result){
+            smsProducer.sendSmsTemplateRefreshMessage();
+        }
+        return result;
     };
     };
 
 
     /**
     /**
@@ -84,7 +108,11 @@ public class SysSmsTempServiceImpl implements ISysSmsTempService {
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public boolean insertSysSmsTemp(SysSmsTempDTO source){
     public boolean insertSysSmsTemp(SysSmsTempDTO source){
         validateSmsTempSource(source);
         validateSmsTempSource(source);
-        return baseRepository.insert(SysSmsTempMapper.INSTANCE.convertPO(source))!=0;
+        boolean result = baseRepository.insert(SysSmsTempMapper.INSTANCE.convertPO(source)) != 0;
+        if(result){
+            smsProducer.sendSmsTemplateRefreshMessage();
+        }
+        return result;
     };
     };
 
 
     /**
     /**
@@ -102,7 +130,9 @@ public class SysSmsTempServiceImpl implements ISysSmsTempService {
                 throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"无法删除系统模板");
                 throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"无法删除系统模板");
             }
             }
         }
         }
-        return baseRepository.deleteBatchIds(ids);
+        int result = baseRepository.deleteBatchIds(ids);
+        smsProducer.sendSmsTemplateRefreshMessage();
+        return result;
     }
     }
 
 
     @Override
     @Override
@@ -112,9 +142,7 @@ public class SysSmsTempServiceImpl implements ISysSmsTempService {
 
 
     @Override
     @Override
     public SysSmsTempDTO selectSysSmsTempByTemplateCode(String templateCode) {
     public SysSmsTempDTO selectSysSmsTempByTemplateCode(String templateCode) {
-        return SysSmsTempMapper.INSTANCE.convertDto(baseRepository.selectOne(new LambdaQueryWrapper<SysSmsTempPO>()
-                .eq(SysSmsTempPO::getCode,templateCode)
-                .last("limit 1")));
+        return SysSmsTempMapper.INSTANCE.convertDto(tempMapByCode.get(templateCode));
     }
     }
 
 
     ;
     ;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysPortalController.java

@@ -88,7 +88,7 @@ public class SysPortalController extends BaseController {
         return CommonResult.success(portalService.insertSysPortal(source));
         return CommonResult.success(portalService.insertSysPortal(source));
     }
     }
 
 
-    @PostMapping("/deleteByIds")
+    @PostMapping("/removeByIds")
     @ApiOperationSupport(author = "lf")
     @ApiOperationSupport(author = "lf")
     @ApiOperation(value = "删除门户",notes = "权限: sys:portal:del")
     @ApiOperation(value = "删除门户",notes = "权限: sys:portal:del")
     @SaCheckPermission("sys:portal:del")
     @SaCheckPermission("sys:portal:del")

+ 10 - 10
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/provider/SysMenuApiProvider.java

@@ -93,16 +93,16 @@ public class SysMenuApiProvider implements SysMenuApi {
         menu.setIcon("appstore-outlined");
         menu.setIcon("appstore-outlined");
         menu.setSort(999);
         menu.setSort(999);
         SysMenuDTO menuDTO = SysMenuMapper.INSTANCE.toSysMenuDTO(menu);
         SysMenuDTO menuDTO = SysMenuMapper.INSTANCE.toSysMenuDTO(menu);
-        if(insert){
-            menuService.insertSysMenu(menuDTO);
-            menu = menuRepository.selectOne(new LambdaQueryWrapper<SysMenuPO>()
-                    .eq(SysMenuPO::getName, functionName)
-                    .eq(SysMenuPO::getMenuType, "menu"));
-            addForGenButton(menu.getId(),permissionPrefix,functionName);
-
-        }else {
-            menuService.updateSysMenuById(menuDTO);
-        }
+//        if(insert){
+//            menuService.insertSysMenu(menuDTO);
+//            menu = menuRepository.selectOne(new LambdaQueryWrapper<SysMenuPO>()
+//                    .eq(SysMenuPO::getName, functionName)
+//                    .eq(SysMenuPO::getMenuType, "menu"));
+//            addForGenButton(menu.getId(),permissionPrefix,functionName);
+//
+//        }else {
+//            menuService.updateSysMenuById(menuDTO);
+//        }
         return Pair.of(menu.getId(), componentPath);
         return Pair.of(menu.getId(), componentPath);
     }
     }
 
 

+ 9 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysUserService.java

@@ -71,4 +71,13 @@ public interface ISysUserService {
      * @return 删除数量
      * @return 删除数量
      */
      */
     int deleteSysUserByIds(Collection<String> ids);
     int deleteSysUserByIds(Collection<String> ids);
+
+    /**
+     * 更新用户最后登录信息
+     * @param id
+     * @param loginTime
+     * @param ip
+     * @param cityInfo
+     */
+    void updateLastLoginInfo(String id, Date loginTime, String ip, String cityInfo);
 }
 }

+ 24 - 19
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java

@@ -10,20 +10,18 @@ import cn.tr.module.sys.user.dto.SysUserDTO;
 import cn.tr.module.sys.user.dto.SysUserEditDTO;
 import cn.tr.module.sys.user.dto.SysUserEditDTO;
 import cn.tr.module.sys.user.dto.SysUserQueryDTO;
 import cn.tr.module.sys.user.dto.SysUserQueryDTO;
 import cn.tr.module.sys.user.dto.SysUserRoleDTO;
 import cn.tr.module.sys.user.dto.SysUserRoleDTO;
+import cn.tr.module.sys.user.repository.SysUserRepository;
 import cn.tr.module.sys.user.service.ISysUserRoleService;
 import cn.tr.module.sys.user.service.ISysUserRoleService;
 import cn.tr.module.sys.user.service.ISysUserService;
 import cn.tr.module.sys.user.service.ISysUserService;
 import cn.tr.module.sys.user.po.SysUserPO;
 import cn.tr.module.sys.user.po.SysUserPO;
-import cn.tr.module.sys.user.repository.SysUserRepository;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 /**
 /**
@@ -33,9 +31,7 @@ import java.util.stream.Collectors;
  * @Date: 2023年03月31日
  * @Date: 2023年03月31日
  */
  */
 @Service
 @Service
-public class SysUserServiceImpl implements ISysUserService {
-    @Autowired
-    private  SysUserRepository userRepository;
+public class SysUserServiceImpl extends ServiceImpl<SysUserRepository,SysUserPO> implements ISysUserService {
 
 
     @Autowired
     @Autowired
     @Lazy
     @Lazy
@@ -45,14 +41,14 @@ public class SysUserServiceImpl implements ISysUserService {
     private ISysUserRoleService userRoleService;
     private ISysUserRoleService userRoleService;
     @Override
     @Override
     public List<SysUserDTO> selectSysUserList(SysUserQueryDTO query) {
     public List<SysUserDTO> selectSysUserList(SysUserQueryDTO query) {
-        return SysUserMapper.INSTANCE.toUserDTOList(userRepository.selectList(
+        return SysUserMapper.INSTANCE.toUserDTOList(baseMapper.selectList(
                 new LambdaQueryWrapper<SysUserPO>()
                 new LambdaQueryWrapper<SysUserPO>()
         ));
         ));
     }
     }
 
 
     @Override
     @Override
     public SysUserDTO selectSysUserById(String id) {
     public SysUserDTO selectSysUserById(String id) {
-        SysUserDTO result = SysUserMapper.INSTANCE.toUserDTO(userRepository.selectById(id));
+        SysUserDTO result = SysUserMapper.INSTANCE.toUserDTO(baseMapper.selectById(id));
         if(result==null){
         if(result==null){
             return result;
             return result;
         }
         }
@@ -76,7 +72,7 @@ public class SysUserServiceImpl implements ISysUserService {
 
 
     @Override
     @Override
     public SysUserDTO selectUserByUsername(String username) {
     public SysUserDTO selectUserByUsername(String username) {
-        return SysUserMapper.INSTANCE.toUserDTO(userRepository.selectOne(new LambdaQueryWrapper<SysUserPO>()
+        return SysUserMapper.INSTANCE.toUserDTO(baseMapper.selectOne(new LambdaQueryWrapper<SysUserPO>()
                 .eq(SysUserPO::getUsername,username)
                 .eq(SysUserPO::getUsername,username)
                 .last("limit 1")));
                 .last("limit 1")));
     }
     }
@@ -84,7 +80,7 @@ public class SysUserServiceImpl implements ISysUserService {
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public boolean updatePsw(String username, String oldPsw, String newPsw) {
     public boolean updatePsw(String username, String oldPsw, String newPsw) {
-        SysUserPO user = userRepository.selectOne(new LambdaQueryWrapper<SysUserPO>()
+        SysUserPO user = baseMapper.selectOne(new LambdaQueryWrapper<SysUserPO>()
                 .eq(SysUserPO::getUsername, username)
                 .eq(SysUserPO::getUsername, username)
                 .last("limit 1"));
                 .last("limit 1"));
         if(user==null){
         if(user==null){
@@ -96,7 +92,7 @@ public class SysUserServiceImpl implements ISysUserService {
         SysUserPO updateUser = new SysUserPO();
         SysUserPO updateUser = new SysUserPO();
         updateUser.setId(user.getId());
         updateUser.setId(user.getId());
         updateUser.setPassword(PswUtils.encryptPassword(newPsw));
         updateUser.setPassword(PswUtils.encryptPassword(newPsw));
-        return  userRepository.updateById(updateUser) != 0;
+        return  baseMapper.updateById(updateUser) != 0;
     }
     }
 
 
     @Override
     @Override
@@ -111,13 +107,13 @@ public class SysUserServiceImpl implements ISysUserService {
             throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("系统中已存在账户{%s},不可重复添加",source.getUsername()));
             throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("系统中已存在账户{%s},不可重复添加",source.getUsername()));
         }
         }
         //当前租户下的账号
         //当前租户下的账号
-        SysUserPO delUser = userRepository.selectUserByUsernameIgnoreDel(source.getUsername());
+        SysUserPO delUser = baseMapper.selectUserByUsernameIgnoreDel(source.getUsername());
         if(delUser==null){
         if(delUser==null){
-            result= userRepository.insert(insertUser)!=0;
+            result= baseMapper.insert(insertUser)!=0;
         }else {
         }else {
             if(Boolean.TRUE.equals(delUser.getDeleted())){
             if(Boolean.TRUE.equals(delUser.getDeleted())){
-                userRepository.recoverBatch(Arrays.asList(delUser));
-                result= userRepository.updateById(insertUser)!=0;
+                baseMapper.recoverBatch(Arrays.asList(delUser));
+                result= baseMapper.updateById(insertUser)!=0;
             }else {
             }else {
                 throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("当前租户中已存在账户{%s},不可重复添加",source.getUsername()));
                 throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("当前租户中已存在账户{%s},不可重复添加",source.getUsername()));
             }
             }
@@ -131,14 +127,23 @@ public class SysUserServiceImpl implements ISysUserService {
     @Override
     @Override
     @TenantIgnore
     @TenantIgnore
     public List<SysUserDTO> selectUserByUsernameIgnoreTenant(String username) {
     public List<SysUserDTO> selectUserByUsernameIgnoreTenant(String username) {
-        return SysUserMapper.INSTANCE.toUserDTOList(userRepository.selectList(new LambdaQueryWrapper<SysUserPO>()
+        return SysUserMapper.INSTANCE.toUserDTOList(baseMapper.selectList(new LambdaQueryWrapper<SysUserPO>()
                 .eq(SysUserPO::getUsername,username)));
                 .eq(SysUserPO::getUsername,username)));
     }
     }
 
 
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public int deleteSysUserByIds(Collection<String> ids) {
     public int deleteSysUserByIds(Collection<String> ids) {
-        return userRepository.deleteBatchIds(ids);
+        return baseMapper.deleteBatchIds(ids);
+    }
+
+    @Override
+    public void updateLastLoginInfo(String id, Date loginTime, String ip, String cityInfo) {
+        SysUserPO user = this.getById(id);
+        user.setLastLoginDate(loginTime);
+        user.setLastLoginIp(ip);
+        user.setLastLoginAddress(cityInfo);
+        this.updateById(user);
     }
     }
 
 
 
 

+ 1 - 0
tr-plugins/pom.xml

@@ -37,6 +37,7 @@
         <module>tr-spring-boot-starter-plugin-biz-bean-mapper</module>
         <module>tr-spring-boot-starter-plugin-biz-bean-mapper</module>
         <module>tr-spring-boot-starter-plugin-biz-constant</module>
         <module>tr-spring-boot-starter-plugin-biz-constant</module>
         <module>tr-spring-boot-starter-plugin-numbering-strategy</module>
         <module>tr-spring-boot-starter-plugin-numbering-strategy</module>
+        <module>tr-spring-boot-starter-plugin-bus</module>
     </modules>
     </modules>
 
 
 </project>
 </project>

+ 23 - 0
tr-plugins/tr-spring-boot-starter-plugin-bus/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tr-plugins</artifactId>
+        <groupId>cn.tr</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <version>${revision}</version>
+    <artifactId>tr-spring-boot-starter-plugin-bus</artifactId>
+
+    <description>使用消息总线作为系统内部配置动态刷新</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 41 - 0
tr-plugins/tr-spring-boot-starter-plugin-bus/src/main/java/cn/tr/plugin/bus/AbstractBusProducer.java

@@ -0,0 +1,41 @@
+package cn.tr.plugin.bus;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.bus.ServiceMatcher;
+import org.springframework.cloud.bus.event.RemoteApplicationEvent;
+import org.springframework.context.ApplicationEventPublisher;
+
+import javax.annotation.Resource;
+
+/**
+ * 基于 Spring Cloud Bus 实现的 Producer 抽象类
+ *
+ * @author tr
+ */
+public abstract class AbstractBusProducer {
+
+    @Resource
+    protected ApplicationEventPublisher applicationEventPublisher;
+
+    @Resource
+    protected ServiceMatcher serviceMatcher;
+
+    @Value("${spring.application.name}")
+    protected String applicationName;
+
+    protected void publishEvent(RemoteApplicationEvent event) {
+        applicationEventPublisher.publishEvent(event);
+    }
+
+    /**
+     * @return 只广播给自己服务的实例
+     */
+    protected String selfDestinationService() {
+        return applicationName + ":**";
+    }
+
+    protected String getBusId() {
+        return serviceMatcher.getBusId();
+    }
+
+}

+ 0 - 1
tr-plugins/tr-spring-boot-starter-plugin-sms/pom.xml

@@ -35,7 +35,6 @@
         <dependency>
         <dependency>
             <groupId>com.aliyun</groupId>
             <groupId>com.aliyun</groupId>
             <artifactId>dysmsapi20170525</artifactId>
             <artifactId>dysmsapi20170525</artifactId>
-            <version>2.0.23</version>
         </dependency>
         </dependency>
     </dependencies>
     </dependencies>
 </project>
 </project>

+ 7 - 1
tr-test/src/main/java/cn/tr/test/WebApplication.java

@@ -1,9 +1,14 @@
 package cn.tr.test;
 package cn.tr.test;
 
 
 import cn.dev33.satoken.strategy.SaStrategy;
 import cn.dev33.satoken.strategy.SaStrategy;
+import cn.tr.module.sys.core.mq.consumer.sms.SmsChannelRefreshConsumer;
+import cn.tr.module.sys.core.mq.consumer.sms.SmsTemplateRefreshConsumer;
+import cn.tr.module.sys.core.mq.message.sms.SmsChannelRefreshMessage;
+import cn.tr.module.sys.core.mq.message.sms.SmsTemplateRefreshMessage;
 import org.mybatis.spring.annotation.MapperScan;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
 
 
 /**
 /**
  * @ClassName : WebApplication
  * @ClassName : WebApplication
@@ -13,9 +18,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
  */
  */
 @SpringBootApplication(scanBasePackages = "cn.tr.module.*")
 @SpringBootApplication(scanBasePackages = "cn.tr.module.*")
 @MapperScan({"cn.tr.module.sys.*.repository","cn.tr.module.gen.modular.*.mapper"})
 @MapperScan({"cn.tr.module.sys.*.repository","cn.tr.module.gen.modular.*.mapper"})
+@RemoteApplicationEventScan(basePackageClasses = {SmsChannelRefreshMessage.class, SmsTemplateRefreshMessage.class})
 public class WebApplication {
 public class WebApplication {
     public static void main(String[] args) {
     public static void main(String[] args) {
         SaStrategy.me.checkElementAnnotation=c->{};
         SaStrategy.me.checkElementAnnotation=c->{};
         SpringApplication.run(WebApplication.class);
         SpringApplication.run(WebApplication.class);
     }
     }
-}
+}

+ 4 - 1
tr-test/src/main/resources/application-stream.yml

@@ -13,4 +13,7 @@ spring:
           destination: smsSend
           destination: smsSend
           group: sms               #分组
           group: sms               #分组
     function:
     function:
-      definition: smsSupplier;smsConsumer
+      definition: smsSupplier;smsConsumer
+    bus:
+      enabled: true # 是否开启,默认为 true
+      id: ${spring.application.name}:${server.port} # 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式

+ 1 - 1
tr-test/src/main/resources/application.yml

@@ -75,7 +75,7 @@ sa-token:
   # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
   # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
   is-concurrent: true
   is-concurrent: true
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
-  is-share: true
+  is-share: false
   # 是否打开续签
   # 是否打开续签
   auto-renew: true
   auto-renew: true
   # 是否输出操作日志
   # 是否输出操作日志