baihe 8 miesięcy temu
rodzic
commit
71f951727e
32 zmienionych plików z 954 dodań i 390 usunięć
  1. 39 0
      component-common/src/main/java/com/gihon/component/config/ApplicationEventConfig.java
  2. 23 15
      component-common/src/main/java/com/gihon/component/config/BaseMybatisConfiguration.java
  3. 17 9
      component-common/src/main/java/com/gihon/component/config/MyMetaObjectHandler.java
  4. 15 19
      component-common/src/main/java/com/gihon/component/config/ScheduleConfig.java
  5. 8 10
      component-common/src/main/java/com/gihon/component/config/ThreadPoolConfig.java
  6. 34 33
      component-common/src/main/java/com/gihon/component/entity/BaseEntity.java
  7. 2 0
      component-common/src/main/java/com/gihon/component/entity/CompanyBaseEntity.java
  8. 21 22
      component-common/src/main/java/com/gihon/component/exception/BaseException.java
  9. 56 54
      component-common/src/main/java/com/gihon/component/response/Response.java
  10. 21 26
      component-common/src/main/java/com/gihon/component/response/ResponseStatus.java
  11. 17 0
      component-common/src/main/java/com/gihon/component/util/CommonContrants.java
  12. 8 0
      component-common/src/main/java/com/gihon/component/web/auth/AuthType.java
  13. 23 0
      component-common/src/main/java/com/gihon/component/web/auth/PreAuth.java
  14. 103 94
      component-common/src/main/java/com/gihon/component/web/config/CommonExceptionController.java
  15. 98 71
      component-common/src/main/java/com/gihon/component/web/config/CommonWebConfig.java
  16. 45 0
      component-common/src/main/java/com/gihon/component/web/config/LogFilter.java
  17. 30 1
      component-springboot/src/main/java/com/gihon/component/rbac/controller/UserController.java
  18. 17 0
      component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomePushlisher.java
  19. 25 0
      component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomerEvent.java
  20. 32 0
      component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomerHandler.java
  21. 11 0
      component-springboot/src/main/java/com/gihon/component/rbac/mapper/GihonUserRoleMapper.java
  22. 3 1
      component-springboot/src/main/java/com/gihon/component/rbac/service/GihonUserRoleService.java
  23. 27 3
      component-springboot/src/main/java/com/gihon/component/rbac/service/GihonUserService.java
  24. 8 1
      component-springboot/src/main/java/com/gihon/component/rbac/service/PermissionService.java
  25. 48 9
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonButtonServiceImpl.java
  26. 2 0
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonRoleButtonServiceImpl.java
  27. 29 12
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonRoleServiceImpl.java
  28. 21 4
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonUserRoleServiceImpl.java
  29. 42 1
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonUserServiceImpl.java
  30. 82 5
      component-springboot/src/main/java/com/gihon/component/rbac/service/impl/PermissionServiceImpl.java
  31. 21 0
      component-springboot/src/main/java/com/gihon/component/rbac/vo/UserRoleReq.java
  32. 26 0
      readme.md

+ 39 - 0
component-common/src/main/java/com/gihon/component/config/ApplicationEventConfig.java

@@ -0,0 +1,39 @@
+package com.gihon.component.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ApplicationEventMulticaster;
+import org.springframework.context.event.SimpleApplicationEventMulticaster;
+import org.springframework.core.task.TaskExecutor;
+
+/**
+ * <pre>
+ * 1、spring容器在创建bean的过程中,会判断bean是否为 ApplicationListener 类型,进而会将其作为监听器注册到 
+ * AbstractApplicationContext#applicationEventMulticaster 中
+ * org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization
+ * 2、EventListenerMethodProcessor实现了SmartInitializingSingleton接口,
+ * SmartInitializingSingleton接口中的 afterSingletonsInstantiated 
+ * 方法会在所有单例的bean创建完成之后被spring容器调用
+ * </pre>
+ * 
+ * @author baihe
+ * @date 2023/12/19
+ */
+@Configuration
+public class ApplicationEventConfig {
+
+    /**
+     * 此处会将EventListener的onApplicationEvent方法一步处理,否则默认同步处理
+     * 
+     * @return
+     */
+    @Bean
+    public ApplicationEventMulticaster applicationEventMulticaster(TaskExecutor taskExecutor) {
+        // 创建一个事件广播器
+        SimpleApplicationEventMulticaster result = new SimpleApplicationEventMulticaster();
+        // 给广播器提供一个线程池,通过这个线程池来调用事件监听器
+        // 设置异步执行器
+        result.setTaskExecutor(taskExecutor);
+        return result;
+    }
+}

+ 23 - 15
component-common/src/main/java/com/gihon/component/config/BaseMybatisConfiguration.java

@@ -7,19 +7,20 @@ import org.springframework.context.annotation.Configuration;
 
 import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.baomidou.mybatisplus.core.toolkit.Sequence;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import com.gihon.component.properties.GihonCommonProperties;
 
 @Configuration
-@EnableConfigurationProperties({ MybatisPlusProperties.class })
+@EnableConfigurationProperties({MybatisPlusProperties.class})
 public class BaseMybatisConfiguration {
 
-	/**
-	 * 分页插件
-	 * 
-	 * @return
-	 */
+    /**
+     * 分页插件
+     * 
+     * @return
+     */
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
@@ -27,13 +28,20 @@ public class BaseMybatisConfiguration {
         return interceptor;
     }
 
-	/**
-	 * Mybatis Plus 注入器
-	 */
-	@Bean("myMetaObjectHandler")
-	@ConditionalOnMissingBean
-	public MetaObjectHandler getMyMetaObjectHandler(GihonCommonProperties gihonCommonProperties) {
-		GihonCommonProperties.IdStrategy id = gihonCommonProperties.getIdStrategy();
-		return new MyMetaObjectHandler(id.getWorkerId(), id.getDataCenterId());
-	}
+    /**
+     * Mybatis Plus 注入器
+     */
+    @Bean("myMetaObjectHandler")
+    @ConditionalOnMissingBean
+    public MetaObjectHandler getMyMetaObjectHandler(GihonCommonProperties gihonCommonProperties) {
+        GihonCommonProperties.IdStrategy id = gihonCommonProperties.getIdStrategy();
+        return new MyMetaObjectHandler(id.getWorkerId(), id.getDataCenterId());
+    }
+
+    @Bean
+    public Sequence sequence(GihonCommonProperties gihonCommonProperties) {
+        return new Sequence(gihonCommonProperties.getIdStrategy().getWorkerId(),
+            gihonCommonProperties.getIdStrategy().getDataCenterId());
+    }
+
 }

+ 17 - 9
component-common/src/main/java/com/gihon/component/config/MyMetaObjectHandler.java

@@ -25,8 +25,11 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
     private static final String ID_TYPE = "java.lang.String";
 
     private static final String FIELD_ID = "id";
-    private static final String FIELD_COMPANYID= "companyId";
+
+    private static final String FIELD_COMPANYID = "companyId";
+
     private static final String FIELD_CREATE_USER = "createUser";
+
     private static final String FIELD_UPDATE_USER = "updateUser";
 
     private Snowflake snowflake;
@@ -55,11 +58,14 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
         // 设置创建时间和创建人
         this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
         this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
-        this.setFieldValByName("state", 0, metaObject);
-        Long userId = AuthUtils.getUserId();
-        if (userId != null) {
-            this.setFieldValByName(FIELD_CREATE_USER, userId, metaObject);
-            this.setFieldValByName(FIELD_UPDATE_USER, userId, metaObject);
+        this.setFieldValByName("state", 1, metaObject);
+
+        if (metaObject.hasSetter(FIELD_CREATE_USER) || metaObject.hasSetter(FIELD_UPDATE_USER)) {
+            Long userId = AuthUtils.getUserId();
+            if (userId != null) {
+                this.setFieldValByName(FIELD_CREATE_USER, userId, metaObject);
+                this.setFieldValByName(FIELD_UPDATE_USER, userId, metaObject);
+            }
         }
         if (metaObject.hasGetter(FIELD_COMPANYID) && this.getFieldValByName(FIELD_COMPANYID, metaObject) == null) {
             this.setFieldValByName(FIELD_COMPANYID, AuthUtils.getCompanyId(), metaObject);
@@ -98,9 +104,11 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
     @Override
     public void updateFill(MetaObject metaObject) {
         this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
-        Long userId = AuthUtils.getUserId();
-        if (userId != null) {
-            this.setFieldValByName(FIELD_UPDATE_USER, userId, metaObject);
+        if (metaObject.hasSetter(FIELD_UPDATE_USER)) {
+            Long userId = AuthUtils.getUserId();
+            if (userId != null) {
+                this.setFieldValByName(FIELD_UPDATE_USER, userId, metaObject);
+            }
         }
 
     }

+ 15 - 19
component-common/src/main/java/com/gihon/component/config/ScheduleConfig.java

@@ -7,51 +7,47 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.SchedulingConfigurer;
 import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 
+import com.gihon.component.util.CommonContrants;
+
 /**
- * Springboot 开启async 使用的线程池
- * 默认是个单线程的
+ * Springboot 开启schedule 使用的线程池 默认是个单线程的
  * 
  * @author baihe
  * @date 2023/03/20
  */
-@ConditionalOnProperty(prefix = "gihon.common",havingValue = "true",matchIfMissing = false,name = "async")
+@ConditionalOnProperty(prefix = "jiheng.common", havingValue = "true", matchIfMissing = false, name = "schedule")
+@EnableScheduling
 @Configuration
 public class ScheduleConfig implements SchedulingConfigurer {
-    /**
-     * I/O密集
-     */
-    private static final int BATCH_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;
     /**
      * 容易造成线程爆满,最好定制实现一个ScheduledExecutorService
      */
     @Override
     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
-    	ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(BATCH_SIZE,new NameableThreadFactory("scheduled"));
+        ScheduledExecutorService scheduler =
+            Executors.newScheduledThreadPool(CommonContrants.CPU_NUM * 2 + 1, new NameableThreadFactory("scheduled"));
         taskRegistrar.setScheduler(scheduler);
     }
-    static class NameableThreadFactory implements ThreadFactory{
+
+    static class NameableThreadFactory implements ThreadFactory {
         private static final AtomicInteger poolNumber = new AtomicInteger(1);
         private final ThreadGroup group;
         private final AtomicInteger threadNumber = new AtomicInteger(1);
         private final String namePrefix;
- 
+
         NameableThreadFactory(String name) {
             SecurityManager s = System.getSecurityManager();
-            group = (s != null) ? s.getThreadGroup() :
-                    Thread.currentThread().getThreadGroup();
-            namePrefix = name+"-pool-" +
-                    poolNumber.getAndIncrement() +
-                    "-thread-";
+            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+            namePrefix = name + "-pool-" + poolNumber.getAndIncrement() + "-thread-";
         }
- 
+
         @Override
         public Thread newThread(Runnable r) {
-            Thread t = new Thread(group, r,
-                    namePrefix + threadNumber.getAndIncrement(),
-                    0);
+            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
             if (t.isDaemon())
                 t.setDaemon(false);
             if (t.getPriority() != Thread.NORM_PRIORITY)

+ 8 - 10
component-common/src/main/java/com/gihon/component/config/ThreadPoolConfig.java

@@ -10,20 +10,17 @@ import org.springframework.core.task.TaskExecutor;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
 /**
- * Springboot 配置schedule的线程池
+ * Springboot 配置aync和listener的线程池
+ * 
  * @author baihe
  * @date 2023/03/20
  */
-@ConditionalOnProperty(prefix = "gihon.common",havingValue = "true",matchIfMissing = false,name = "executor")
+@ConditionalOnProperty(prefix = "jiheng.common", havingValue = "true", matchIfMissing = false, name = "async")
 @Configuration
 public class ThreadPoolConfig {
-    /**
-     * I/O密集
-     */
-    private static final int BATCH_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;
-    
+
     @Bean
-	@ConditionalOnMissingBean(ThreadPoolTaskExecutor.class)
+    @ConditionalOnMissingBean(ThreadPoolTaskExecutor.class)
     public TaskExecutor taskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         // 设置核心线程数
@@ -35,11 +32,12 @@ public class ThreadPoolConfig {
         // 设置线程活跃时间(秒)
         executor.setKeepAliveSeconds(60);
         // 设置默认线程名称
-        executor.setThreadNamePrefix("Schedule-");
+        executor.setThreadNamePrefix("Async-");
         // 设置拒绝策略
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         // 等待所有任务结束后再关闭线程池
         executor.setWaitForTasksToCompleteOnShutdown(true);
         return executor;
     }
-}
+
+}

+ 34 - 33
component-common/src/main/java/com/gihon/component/entity/BaseEntity.java

@@ -3,6 +3,7 @@ package com.gihon.component.entity;
 import java.time.LocalDateTime;
 
 import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -23,38 +24,38 @@ import lombok.Setter;
 @Setter
 public class BaseEntity {
 
-	@TableId(value = "id", type = IdType.AUTO)
-	@ApiModelProperty(value = "主键")
-	protected Long id;
-
-	@ApiModelProperty(value = "创建时间")
-	@TableField(value = "create_time", fill = FieldFill.INSERT)
-	protected LocalDateTime createTime;
-	
-	@ApiModelProperty(value = "修改时间")
-	@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
-	protected LocalDateTime updateTime;
-
-	@JsonIgnore
-	@ApiModelProperty(value = "创建人", hidden = true)
-	@TableField(value = "create_user", fill = FieldFill.INSERT)
-	protected Long createUser;
-	
-	@JsonIgnore
-	@ApiModelProperty(value = "修改人", hidden = true)
-	@TableField(value = "update_user", fill = FieldFill.INSERT_UPDATE)
-	protected Long updateUser;
-
-	@ApiModelProperty(value = "创建人名称")
-	@TableField(exist = false)
-	protected String createUserName;
-	
-	@ApiModelProperty(value = "修改人名称")
-	@TableField(exist = false)
-	protected String updateUserName;
-
-	@ApiModelProperty(value = "逻辑删除", hidden = true)
-	@TableLogic
-	protected Integer state;
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    protected Long id;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "create_time", fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER)
+    protected LocalDateTime createTime;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "update_time", fill = FieldFill.UPDATE)
+    protected LocalDateTime updateTime;
+
+    @JsonIgnore
+    @ApiModelProperty(value = "创建人", hidden = true)
+    @TableField(value = "create_user", fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER)
+    protected Long createUser;
+
+    @JsonIgnore
+    @ApiModelProperty(value = "修改人", hidden = true)
+    @TableField(value = "update_user", fill = FieldFill.UPDATE)
+    protected Long updateUser;
+
+    @ApiModelProperty(value = "创建人名称")
+    @TableField(exist = false)
+    protected String createUserName;
+
+    @ApiModelProperty(value = "修改人名称")
+    @TableField(exist = false)
+    protected String updateUserName;
+
+    @ApiModelProperty(value = "逻辑删除", hidden = true)
+    @TableLogic
+    protected Integer state;
 
 }

+ 2 - 0
component-common/src/main/java/com/gihon/component/entity/CompanyBaseEntity.java

@@ -2,6 +2,7 @@ package com.gihon.component.entity;
 
 import javax.validation.constraints.NotNull;
 
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 
 import io.swagger.annotations.ApiModelProperty;
@@ -19,6 +20,7 @@ public class CompanyBaseEntity extends BaseEntity{
 	
     @NotNull(message="所属公司必选")
 	@ApiModelProperty(value = "公司Id(支持SAAS)")
+    @TableField(updateStrategy = FieldStrategy.NEVER)
 	protected Long companyId;
 	
 	@TableField(exist = false)

+ 21 - 22
component-common/src/main/java/com/gihon/component/exception/BaseException.java

@@ -10,26 +10,25 @@ import com.gihon.component.response.ResponseStatus;
  */
 public class BaseException extends RuntimeException {
 
-	private static final long serialVersionUID = -7215389847384607920L;
-	
-	protected ResponseStatus status;
-
-	public BaseException(String message) {
-		super(message);
-	}
-
-	public BaseException(ResponseStatus status) {
-		this(status.getDesc());
-		this.status=status;
-	}
-
-	public ResponseStatus getStatus() {
-		return status==null?ResponseStatus.ERROR:status;
-	}
-
-	public void setStatus(ResponseStatus status) {
-		this.status = status;
-	}
-	
-	
+    private static final long serialVersionUID = -7215389847384607920L;
+
+    protected ResponseStatus status;
+
+    public BaseException(String message) {
+        super(message);
+    }
+
+    public BaseException(ResponseStatus status) {
+        this(status.getMessage());
+        this.status = status;
+    }
+
+    public ResponseStatus getStatus() {
+        return status == null ? ResponseStatus.ERROR : status;
+    }
+
+    public void setStatus(ResponseStatus status) {
+        this.status = status;
+    }
+
 }

+ 56 - 54
component-common/src/main/java/com/gihon/component/response/Response.java

@@ -22,58 +22,60 @@ import lombok.Data;
 @ApiModel("响应实体")
 public class Response<T> {
 
-	@ApiModelProperty(value = "返回标志")
-	private int status;
-	@ApiModelProperty(value = "描述")
-	private String message;
-	@ApiModelProperty(value = "数据")
-	private T data;
-
-	protected Response() {
-	}
-
-	protected Response(int status) {
-		this.status = status;
-	}
-
-	protected Response(int status, String message) {
-		this.status = status;
-		this.message = message;
-	}
-
-	protected Response(int status, T data) {
-		this.status = status;
-		this.data = data;
-	}
-
-	protected Response(int status, String message, T data) {
-		this.status = status;
-		this.data = data;
-		this.message = message;
-	}
-
-	public static <T> Response<T> ok() {
-		return ok(null);
-	}
-
-	public static <T> Response<T> ok(T data) {
-		return new Response<T>(SUCCESS.getCode(), SUCCESS.getDesc(), data);
-	}
-
-	public static <T> Response<T> noData() {
-		return new Response<T>(NO_DATA.getCode(), NO_DATA.getDesc(), null);
-	}
-
-	public static <T> Response<T> error(ResponseStatus status, String message) {
-		return new Response<T>(status.getCode(), message, null);
-	}
-
-	public static <T> Response<T> error(ResponseStatus status) {
-		return error(status, status.getDesc());
-	}
-
-	public static <T> Response<PageBean<T>> okPage(IPage<T> data) {
-		PageBean<T> pageBean = new PageBean<T>(data);
-		return new Response<PageBean<T>>(SUCCESS.getCode(), SUCCESS.getDesc(), pageBean);
-	}
+    @ApiModelProperty(value = "返回标志")
+    private int status;
+
+    @ApiModelProperty(value = "描述")
+    private String message;
+
+    @ApiModelProperty(value = "数据")
+    private T data;
+
+    protected Response() {}
+
+    protected Response(int status) {
+        this.status = status;
+    }
+
+    protected Response(int status, String message) {
+        this.status = status;
+        this.message = message;
+    }
+
+    protected Response(int status, T data) {
+        this.status = status;
+        this.data = data;
+    }
+
+    protected Response(int status, String message, T data) {
+        this.status = status;
+        this.data = data;
+        this.message = message;
+    }
+
+    public static <T> Response<T> ok() {
+        return ok(null);
+    }
+
+    public static <T> Response<T> ok(T data) {
+        return new Response<>(SUCCESS.getCode(), SUCCESS.getMessage(), data);
+    }
+
+    public static <T> Response<T> noData() {
+        return new Response<>(NO_DATA.getCode(), NO_DATA.getMessage(), null);
+    }
+
+    public static <T> Response<T> error(ResponseStatus status, String message) {
+        return new Response<>(status.getCode(), message, null);
+    }
+
+    public static <T> Response<T> error(ResponseStatus status) {
+        return error(status, status.getMessage());
+    }
+
+    public static <T> Response<PageBean<T>> okPage(IPage<T> data) {
+        PageBean<T> pageBean = new PageBean<>(data);
+        return new Response<>(SUCCESS.getCode(), SUCCESS.getMessage(), pageBean);
+    }
+
 }

+ 21 - 26
component-common/src/main/java/com/gihon/component/response/ResponseStatus.java

@@ -1,37 +1,32 @@
 package com.gihon.component.response;
 
+import lombok.Getter;
+
+@Getter
 public enum ResponseStatus {
 
-	SUCCESS(200, "成功"), 
-	NO_DATA(202, "没有数据"),
-	BUSINESS_ERROR(300, "业务错误"), // 业务错误 例 : 参数不匹配或参数验证不正确
-	LOGIN_ERROR(300, "账号密码错误"), //
-	VALIDCODE_ERROR(300, "验证码错误"), //
-	VALID_ERROR(300, "统一验证参数异常"), // 业务错误 例 : 参数不匹配或参数验证不正确
-	PARAM_ERROR(300, "参数类型解析异常"), 
-	TOKEN_EXPIRED(301, "Token已过期"), //
-	REFRESH_TOKEN_EXPIRED(301, "RereshToken已过期"), //
-	RESOURCE_ERROR(400, "资源错误"), // 资源不不存在
-	UNAUTHORIATION(401, "未登录"),
-	FORBIDDEN(403, "没有权限"),
-	SQL_ERROR(500, "SQL运行异常"), 
-	ERROR(500, "服务器错误");
+    SUCCESS(200, "成功"),
+    NO_DATA(202, "没有数据"),
+    BUSINESS_ERROR(300, "业务错误"), // 业务错误 例 : 参数不匹配或参数验证不正确
+    LOGIN_ERROR(300, "账号密码错误"), //
+    VALIDCODE_ERROR(300, "验证码错误"), //
+    VALID_ERROR(300, "统一验证参数异常"), // 业务错误 例 : 参数不匹配或参数验证不正确
+    PARAM_ERROR(300, "参数类型解析异常"),
+    TOKEN_EXPIRED(301, "Token已过期"), //
+    REFRESH_TOKEN_EXPIRED(301, "RereshToken已过期"), //
+    RESOURCE_ERROR(400, "资源错误"), // 资源不不存在
+    UNAUTHORIATION(401, "未登录"),
+    FORBIDDEN(403, "没有权限"),
+    SQL_ERROR(500, "SQL运行异常"),
+    ERROR(500, "服务器错误");
+
+    private String message;
 
-    private String desc;
-    
     private int code;
 
-    ResponseStatus(int code, String desc) {
-        this.desc = desc;
+    ResponseStatus(int code, String message) {
+        this.message = message;
         this.code = code;
     }
 
-    public String getDesc() {
-        return desc;
-    }
-
-    public int getCode() {
-        return code;
-    }
-
 }

+ 17 - 0
component-common/src/main/java/com/gihon/component/util/CommonContrants.java

@@ -0,0 +1,17 @@
+package com.gihon.component.util;
+
+public final class CommonContrants {
+
+    private CommonContrants() {}
+
+    /**
+     * I/O密集 CPU_NUM * 2 + 1;
+     */
+    public static final int CPU_NUM = Runtime.getRuntime().availableProcessors();
+    
+    public static final String HEADER_TRACE_ID = "TRACE_ID";
+    
+    public static final String HEADER_SIGNATURE = "signature";
+    
+
+}

+ 8 - 0
component-common/src/main/java/com/gihon/component/web/auth/AuthType.java

@@ -0,0 +1,8 @@
+package com.gihon.component.web.auth;
+
+public enum AuthType {
+
+    NONE,//不需要
+    LOGIN,//只要登录
+    AUTH;//权限按钮
+}

+ 23 - 0
component-common/src/main/java/com/gihon/component/web/auth/PreAuth.java

@@ -0,0 +1,23 @@
+package com.gihon.component.web.auth;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Controller 模块菜单权限注解
+ * @author baihe
+ * @date 2023/07/21
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PreAuth {
+
+    String name() default "";//名称
+    
+    String btnCode() default "";//所属的按钮权限Code,如果有Code直接用Code比较按钮的权限的Code,否则用访问的路径匹配
+    
+    AuthType authType() default AuthType.LOGIN;
+}

+ 103 - 94
component-common/src/main/java/com/gihon/component/web/config/CommonExceptionController.java

@@ -12,6 +12,7 @@ import javax.validation.ConstraintViolationException;
 
 import org.apache.ibatis.exceptions.PersistenceException;
 import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.dao.DataAccessException;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -35,114 +36,82 @@ import com.gihon.component.response.Response;
 import com.gihon.component.response.ResponseStatus;
 
 import lombok.extern.slf4j.Slf4j;
+
 /**
  * 基本的全局异常处理器
+ * 
  * @author baihe
  *
  */
 @Slf4j
 @ControllerAdvice(annotations = {RestController.class, Controller.class})
 @ResponseBody
-@SuppressWarnings({ "unused", "rawtypes" })
+@SuppressWarnings({"unused", "rawtypes"})
 public class CommonExceptionController {
-	
-	//通过Handler获取到Controller的返回值类型
-	private ResponseEntity<Response> createResponse(HandlerMethod handler,ResponseStatus status,String message) {
-		Response r = Response.error(status,message);
-		return new ResponseEntity<>(r, HttpStatus.OK);
-	}
-	
-	
-	@ExceptionHandler(BaseException.class)
-	public Response handleBaseException(HttpServletRequest req,HandlerMethod handler,BaseException e){
-		log.error("["+e.getMessage()+"]",e);
-		return Response.error(e.getStatus(),e.getMessage());
-	}
-	
-	@ExceptionHandler(Throwable.class)
-	public Response handleThrowable(HttpServletRequest req,HandlerMethod handler,Throwable e){
-		log.error("["+e.getMessage()+"]",e);
-		return Response.error(ResponseStatus.ERROR,ResponseStatus.ERROR.getDesc());
-	}
-	@ExceptionHandler(AccessDeniedException.class)
-	public Response handleThrowable(HttpServletRequest req,HandlerMethod handler,AccessDeniedException e){
-		log.error("["+e.getMessage()+"]",e);
-		return Response.error(ResponseStatus.FORBIDDEN,ResponseStatus.FORBIDDEN.getDesc());
-	}
-	
-	/**
-	 * 在controller中使用 @Valid or @Validator 抛出的异常
-	 * @param req
-	 * @param e
-	 * @return
-	 */
-	@ExceptionHandler(MethodArgumentNotValidException.class)
-    public Response MethodArgumentNotValidExceptionHandler(HttpServletRequest req,HandlerMethod handler,MethodArgumentNotValidException e) {
-		log.error("[MethodArgumentNotValidException] ",e);
-		StringBuilder message = new StringBuilder();
-		for (ObjectError error : e.getBindingResult().getAllErrors()) {
-			message.append(error.getDefaultMessage()).append("\n");
-        }
-		return Response.error(ResponseStatus.VALID_ERROR,message.toString());
+
+    // 通过Handler获取到Controller的返回值类型
+    private ResponseEntity<Response> createResponse(HandlerMethod handler, ResponseStatus status, String message) {
+        Response r = Response.error(status, message);
+        return new ResponseEntity<>(r, HttpStatus.OK);
     }
-	@ExceptionHandler(HttpMessageNotReadableException.class)
-    public Response httpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
-        log.error("[HttpMessageNotReadableException] ",e);
-        String message = e.getMessage();
-        String msg="参数解析失败";
-        if (StringUtils.substringMatch(message, 0, "Could not read document:")) {
-        	int index = message.indexOf("Could not read document:");
-        	int index2 = message.indexOf(" at ");
-            msg = String.format("无法正确的解析json类型的参数:%s", message.substring(index+24, index2));
+
+    @ExceptionHandler(Throwable.class)
+    public Response handleThrowable(HttpServletRequest req, HandlerMethod handler, Throwable e) {
+        log.error("[" + e.getMessage() + "]", e);
+        return Response.error(ResponseStatus.ERROR, ResponseStatus.ERROR.getMessage());
+    }
+
+    @ExceptionHandler(BaseException.class)
+    public Response handleBaseException(HttpServletRequest req, HandlerMethod handler, BaseException e) {
+        log.error("[" + e.getMessage() + "]", e);
+        return Response.error(e.getStatus(), e.getMessage());
+    }
+
+    /**
+     * JSON方式 @Valid or @Validated 抛出的异常
+     * 
+     * @param req
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Response methodArgumentNotValidExceptionHandler(HttpServletRequest req, HandlerMethod handler,
+        MethodArgumentNotValidException e) {
+        log.error("[MethodArgumentNotValidException] ", e);
+        StringBuilder message = new StringBuilder();
+        for (ObjectError error : e.getBindingResult().getAllErrors()) {
+            message.append(error.getDefaultMessage()).append("\n");
         }
-        return Response.error(ResponseStatus.PARAM_ERROR,msg);
+        return Response.error(ResponseStatus.VALID_ERROR, message.toString());
     }
 
+    /**
+     * form data 方式接受参数 @Valid
+     * 
+     * @param e
+     * @param request
+     * @return
+     */
     @ExceptionHandler(BindException.class)
     public Response bindException(BindException e, HttpServletRequest request) {
-        log.error("[BindException] ",e);
+        log.error("[BindException] ", e);
         try {
             String msgs = e.getBindingResult().getFieldError().getDefaultMessage();
-            if (!StringUtils.isEmpty(msgs)) {
+            if (StringUtils.hasText(msgs)) {
                 return Response.error(ResponseStatus.PARAM_ERROR, msgs);
             }
         } catch (Exception ee) {
         }
         StringBuilder msg = new StringBuilder();
         List<FieldError> fieldErrors = e.getFieldErrors();
-        fieldErrors.forEach((oe) ->
-                msg.append("参数:[").append(oe.getObjectName())
-                        .append(".").append(oe.getField())
-                        .append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配.")
-        );
-        return Response.error(ResponseStatus.PARAM_ERROR,msg.toString());
-    }
-
-
-    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
-    public Response methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
-        log.error("[MethodArgumentTypeMismatchException] ",e);
-        MethodArgumentTypeMismatchException eee = (MethodArgumentTypeMismatchException) e;
-        StringBuilder msg = new StringBuilder("参数:[").append(eee.getName())
-                .append("]的传入值:[").append(eee.getValue())
-                .append("]与预期的字段类型:[").append(eee.getRequiredType().getName()).append("]不匹配");
-        return Response.error(ResponseStatus.PARAM_ERROR,msg.toString());
+        fieldErrors.forEach((oe) -> msg.append("参数:[").append(oe.getObjectName()).append(".").append(oe.getField())
+            .append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配."));
+        return Response.error(ResponseStatus.PARAM_ERROR, msg.toString());
     }
 
-   
-
-    @ExceptionHandler(MissingServletRequestParameterException.class)
-    public Response missingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest request) {
-        log.error("[MissingServletRequestParameterException]", e);
-        StringBuilder msg = new StringBuilder();
-        msg.append("缺少必须的[").append(e.getParameterType()).append("]类型的参数[").append(e.getParameterName()).append("]");
-        return Response.error(ResponseStatus.PARAM_ERROR,msg.toString());
-    }
-
-
     /**
-     * jsr 规范中的验证异常
-     *
+     * jsr 规范中的验证异常 单个参数校验异常抛出ConstraintViolationException
+     * 
      * @param e
      * @return
      */
@@ -150,21 +119,61 @@ public class CommonExceptionController {
     public Response constraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
         log.error("[ConstraintViolationException]", e);
         Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
-        String message = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
-        return Response.error(ResponseStatus.VALID_ERROR,message);
+        String message = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("\n"));
+        return Response.error(ResponseStatus.VALID_ERROR, message);
     }
 
+    /**
+     * 参数读取失败
+     * 
+     * @param e
+     * @param request
+     * @return
+     */
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public Response httpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
+        log.error("[HttpMessageNotReadableException] ", e);
+        String message = e.getMessage();
+        String msg = "参数解析失败";
+        if (StringUtils.substringMatch(message, 0, "Could not read document:")) {
+            int index = message.indexOf("Could not read document:");
+            int index2 = message.indexOf(" at ");
+            msg = String.format("无法正确的解析json类型的参数:%s", message.substring(index + 24, index2));
+        }
+        return Response.error(ResponseStatus.PARAM_ERROR, msg);
+    }
 
-    @ExceptionHandler(PersistenceException.class)
-    public Response persistenceException(PersistenceException e, HttpServletRequest request) {
-        log.error("[PersistenceException]", e);
-        return Response.error(ResponseStatus.SQL_ERROR);
+    /**
+     * 参数类型不正确不能解析
+     * 
+     * @param e
+     * @param request
+     * @return
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public Response methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
+        HttpServletRequest request) {
+        log.error("[MethodArgumentTypeMismatchException] ", e);
+        MethodArgumentTypeMismatchException eee = (MethodArgumentTypeMismatchException)e;
+        StringBuilder msg = new StringBuilder("参数:[").append(eee.getName()).append("]的传入值:[").append(eee.getValue())
+            .append("]与预期的字段类型:[").append(eee.getRequiredType().getName()).append("]不匹配");
+        return Response.error(ResponseStatus.PARAM_ERROR, msg.toString());
     }
 
-    @ExceptionHandler(MyBatisSystemException.class)
-    public Response myBatisSystemException(MyBatisSystemException e, HttpServletRequest request) {
-        log.error("[PersistenceException]", e);
-        return Response.error(ResponseStatus.SQL_ERROR);
+    /**
+     * 缺少必须的url参数 @RequestParam 注解
+     * 
+     * @param e
+     * @param request
+     * @return
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    public Response missingServletRequestParameterException(MissingServletRequestParameterException e,
+        HttpServletRequest request) {
+        log.error("[MissingServletRequestParameterException]", e);
+        StringBuilder msg = new StringBuilder();
+        msg.append("缺少必须的[").append(e.getParameterType()).append("]类型的参数[").append(e.getParameterName()).append("]");
+        return Response.error(ResponseStatus.PARAM_ERROR, msg.toString());
     }
 
     @ExceptionHandler(SQLException.class)
@@ -173,8 +182,8 @@ public class CommonExceptionController {
         return Response.error(ResponseStatus.SQL_ERROR);
     }
 
-    @ExceptionHandler(DataIntegrityViolationException.class)
-    public Response dataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request) {
+    @ExceptionHandler(DataAccessException.class)
+    public Response dataIntegrityViolationException(DataAccessException e, HttpServletRequest request) {
         log.error("[DataIntegrityViolationException]", e);
         return Response.error(ResponseStatus.SQL_ERROR);
     }

+ 98 - 71
component-common/src/main/java/com/gihon/component/web/config/CommonWebConfig.java

@@ -26,10 +26,11 @@ import org.apache.http.ssl.TrustStrategy;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.boot.jackson.JsonComponent;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Primary;
+import org.springframework.core.Ordered;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 import org.springframework.http.converter.HttpMessageConverter;
@@ -39,7 +40,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 import org.springframework.web.filter.CorsFilter;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -48,67 +48,73 @@ import com.gihon.component.util.JacksonJsonUtils;
 @Configuration
 public class CommonWebConfig implements WebMvcConfigurer {
 
-	/**
-	 * 此类创建ObjectMapper
-	 * 解决Date,LocalDateTime,Long的解析
-	 * @return
-	 */
-	@Bean
-	public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
-		return JacksonJsonUtils::configureBuilder;
-	}
-
-	@Bean
-	@Primary
-	@ConditionalOnClass(ObjectMapper.class)
-	@ConditionalOnMissingBean({ ObjectMapper.class })
-	public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
-		ObjectMapper objectMapper = builder.createXmlMapper(false).build();
-		objectMapper.setLocale(Locale.CHINA);
-		return objectMapper;
-	}
-
-	@Bean
-	@Primary
-	public RestTemplate restTemplate(ObjectMapper objectMapper) throws Exception {
-
-		SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
-			@Override
-			public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
-				return true;
-			}
-		}).build();
-
-		SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
-				NoopHostnameVerifier.INSTANCE);
-		CloseableHttpClient httpClient2 = HttpClients.custom().setSSLSocketFactory(csf).build();
-		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
-		requestFactory.setHttpClient(httpClient2);
-		requestFactory.setReadTimeout(600000);// 超时时间增加为10分钟
-		requestFactory.setConnectTimeout(60000);// 连接时间增加为1分钟
-		RestTemplate restTemplate = new RestTemplate(requestFactory);
-		// 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为
-		// "ISO-8859-1")
-		List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
-		Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
-		while (iterator.hasNext()) {
-			HttpMessageConverter<?> converter = iterator.next();
-			if (converter instanceof StringHttpMessageConverter) {
-				((StringHttpMessageConverter) converter).setDefaultCharset(Charset.forName("UTF-8"));
-			} else if (converter instanceof MappingJackson2HttpMessageConverter) {
-				((MappingJackson2HttpMessageConverter) converter).setObjectMapper(objectMapper);
-			}
-		}
-		return restTemplate;
-	}
-	 /**
-     * attention:简单跨域就是GET,HEAD和POST请求,但是POST请求的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain
+    /**
+     * 此类创建ObjectMapper
+     * 解决Date,LocalDateTime,Long的解析
+     * 
+     * @return
+     */
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
+        return JacksonJsonUtils::configureBuilder;
+    }
+
+    @Bean
+    @Primary
+    @ConditionalOnClass(ObjectMapper.class)
+    @ConditionalOnMissingBean({ObjectMapper.class})
+    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
+        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
+        objectMapper.setLocale(Locale.CHINA);
+        return objectMapper;
+    }
+
+    @Bean
+    @Primary
+    public RestTemplate restTemplate(ObjectMapper objectMapper) throws Exception {
+
+        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+
+            @Override
+            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                return true;
+            }
+
+        }).build();
+
+        SSLConnectionSocketFactory csf =
+            new SSLConnectionSocketFactory(sslContext, new String[] {"TLSv1"}, null, NoopHostnameVerifier.INSTANCE);
+        CloseableHttpClient httpClient2 = HttpClients.custom().setSSLSocketFactory(csf).build();
+        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
+        requestFactory.setHttpClient(httpClient2);
+        requestFactory.setReadTimeout(600000);// 超时时间增加为10分钟
+        requestFactory.setConnectTimeout(60000);// 连接时间增加为1分钟
+        RestTemplate restTemplate = new RestTemplate(requestFactory);
+        // 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为
+        // "ISO-8859-1")
+        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
+        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
+        while (iterator.hasNext()) {
+            HttpMessageConverter<?> converter = iterator.next();
+            if (converter instanceof StringHttpMessageConverter) {
+                ((StringHttpMessageConverter)converter).setDefaultCharset(Charset.forName("UTF-8"));
+            } else if (converter instanceof MappingJackson2HttpMessageConverter) {
+                ((MappingJackson2HttpMessageConverter)converter).setObjectMapper(objectMapper);
+            }
+        }
+        return restTemplate;
+    }
+
+    /**
+     * attention:简单跨域就是GET,HEAD和POST请求,但是POST请求的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data
+     * 或 text/plain
      * 反之,就是非简单跨域,此跨域有一个预检机制,说直白点,就是会发两次请求,一次OPTIONS请求,一次真正的请求
      */
     @Bean
     public CorsFilter corsFilter() {
         final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        final org.springframework.web.cors.CorsConfiguration config = new org.springframework.web.cors.CorsConfiguration();
+        final org.springframework.web.cors.CorsConfiguration config =
+            new org.springframework.web.cors.CorsConfiguration();
         // 允许cookies跨域
         config.setAllowCredentials(true);
         // #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
@@ -129,8 +135,8 @@ public class CommonWebConfig implements WebMvcConfigurer {
         source.registerCorsConfiguration("/**", config);
         return new CorsFilter(source);
     }
-    
-    /********普通请求参数中的时间转换******/
+
+    /******** 普通请求参数中的时间转换 ******/
     @Bean
     public StringToLocalDateTimeConverter localDateTimeConverter() {
         return new StringToLocalDateTimeConverter();
@@ -147,46 +153,67 @@ public class CommonWebConfig implements WebMvcConfigurer {
     }
 
     private static class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
+
         @Override
         public LocalDateTime convert(String source) {
             try {
-                if(!StringUtils.isBlank(source)) {
-                    if(source.length()==10) {
-                        return LocalDateTime.of(LocalDate.parse(source, YEAR_MONTH_DAY_FORMATTER),LocalTime.MIN);
-                    }else {
-                        return LocalDateTime.parse(source,FULL_TIME_FORMATTER);
+                if (!StringUtils.isBlank(source)) {
+                    if (source.length() == 10) {
+                        return LocalDateTime.of(LocalDate.parse(source, YEAR_MONTH_DAY_FORMATTER), LocalTime.MIN);
+                    } else {
+                        return LocalDateTime.parse(source, FULL_TIME_FORMATTER);
                     }
                 }
-            }catch (Exception e) {
-               
+            } catch (Exception e) {
+
             }
             return null;
         }
+
     }
 
     private static class StringToLocalDateConverter implements Converter<String, LocalDate> {
+
         @Override
         public LocalDate convert(String source) {
-            if(!StringUtils.isBlank(source)) {
+            if (!StringUtils.isBlank(source)) {
                 try {
                     return LocalDate.parse(source, YEAR_MONTH_DAY_FORMATTER);
-                }catch (Exception e) {
+                } catch (Exception e) {
                 }
             }
             return null;
         }
+
     }
 
     private static class StringToLocalTimeConverter implements Converter<String, LocalTime> {
+
         @Override
         public LocalTime convert(String source) {
-            if(!StringUtils.isBlank(source)) {
+            if (!StringUtils.isBlank(source)) {
                 try {
                     return LocalTime.parse(source, TIME_FORMATTER);
-                }catch (Exception e) {
+                } catch (Exception e) {
                 }
             }
             return null;
         }
+
     }
+
+    @Bean
+    public FilterRegistrationBean<LogFilter> logFilterRegister() {
+        FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<>();
+        // 注入过滤器
+        registration.setFilter(new LogFilter());
+        // 拦截规则
+        registration.addUrlPatterns("/*");
+        // 过滤器名称
+        registration.setName("LogFilter");
+        // 过滤器顺序
+        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
+        return registration;
+    }
+
 }

+ 45 - 0
component-common/src/main/java/com/gihon/component/web/config/LogFilter.java

@@ -0,0 +1,45 @@
+package com.gihon.component.web.config;
+
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.gihon.component.util.CommonContrants;
+import com.gihon.component.util.HttpContextUtils;
+import com.gihon.component.util.UUIDGenerater;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class LogFilter implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+        LocalDateTime startTime = LocalDateTime.now();
+        HttpServletRequest req = (HttpServletRequest)request;
+        HttpServletResponse res = (HttpServletResponse)response;
+        String traceId = req.getHeader(CommonContrants.HEADER_TRACE_ID);
+        if (traceId == null) {
+            traceId = UUIDGenerater.genUUID();
+        }
+        request.setAttribute(CommonContrants.HEADER_TRACE_ID, traceId);
+        String uri = req.getRequestURI();
+        String ip = HttpContextUtils.getIpAddr(req);
+        log.info("[trace-id:{}] [method:{}] [path:{}] [client-ip:{}]", traceId, req.getMethod(), uri, ip);
+        chain.doFilter(request, response);
+        log.info("[trace-id:{}] [method:{}] [path:{}] [cost:{}] [status:{}]", traceId, req.getMethod(), uri,
+            Duration.between(startTime, LocalDateTime.now()).toMillis(), res.getStatus());
+    }
+
+
+}

+ 30 - 1
component-springboot/src/main/java/com/gihon/component/rbac/controller/UserController.java

@@ -1,5 +1,9 @@
 package com.gihon.component.rbac.controller;
 
+import java.util.List;
+
+import javax.validation.constraints.NotNull;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -7,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -14,10 +19,13 @@ import com.gihon.component.exception.BusinessException;
 import com.gihon.component.rbac.entity.GihonUser;
 import com.gihon.component.rbac.service.GihonUserService;
 import com.gihon.component.rbac.vo.UserListReq;
+import com.gihon.component.rbac.vo.UserRoleReq;
 import com.gihon.component.response.PageBean;
 import com.gihon.component.response.Response;
 import com.gihon.component.response.ResponseStatus;
+import com.gihon.component.web.auth.AuthType;
 import com.gihon.component.web.auth.AuthUtils;
+import com.gihon.component.web.auth.PreAuth;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -83,5 +91,26 @@ public class UserController {
         gihonUserService.updateUser(user);
         return Response.ok();
     }
-
+    
+    @PreAuth(authType = AuthType.AUTH,btnCode = "user_edit")
+    @ApiOperation("USER:用户获取角色")
+    @GetMapping("role/get")
+    public Response<List<Long>> getUserRole(@RequestParam Long userId) {
+        return Response.ok(gihonUserService.getUserRole(userId));
+    }
+    
+    @PreAuth(authType = AuthType.AUTH,btnCode = "user_edit")
+    @ApiOperation("USER:用户设置角色")
+    @PostMapping("role/set")
+    public Response<Void> setUserRole(@Validated @RequestBody UserRoleReq userRole) {
+        gihonUserService.setUserRole(userRole);
+        return Response.ok();
+    }
+    @PreAuth(authType = AuthType.AUTH,btnCode = "user_reset")
+    @ApiOperation("USER:用户重置密码")
+    @PostMapping("reset")
+    public Response<Void> resetPassword(@NotNull @RequestParam Long userId) {
+        gihonUserService.resetPassword(userId);
+        return Response.ok();
+    }
 }

+ 17 - 0
component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomePushlisher.java

@@ -0,0 +1,17 @@
+package com.gihon.component.rbac.listener;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomePushlisher {
+
+    @Autowired
+    private ApplicationContext applicationContext;
+    
+    public void publish(ApplicationEvent event) {
+        applicationContext.publishEvent(event);
+    }
+}

+ 25 - 0
component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomerEvent.java

@@ -0,0 +1,25 @@
+package com.gihon.component.rbac.listener;
+
+import org.springframework.context.ApplicationEvent;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@SuppressWarnings("serial")
+public class CustomerEvent extends ApplicationEvent {
+    
+    private Long id;
+    /**
+     * 1 用户变更角色
+     * 2 删除角色
+     * 3 角色变更或者模块下按钮变更
+     */
+    private int type;
+
+    public CustomerEvent(Object source) {
+        super(source);
+    }
+
+}

+ 32 - 0
component-springboot/src/main/java/com/gihon/component/rbac/listener/CustomerHandler.java

@@ -0,0 +1,32 @@
+package com.gihon.component.rbac.listener;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import com.gihon.component.rbac.service.PermissionService;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class CustomerHandler  {
+
+    @Autowired
+    private PermissionService permissionService;
+
+    @TransactionalEventListener
+    public void onApplicationEvent(CustomerEvent event) {
+        handlerEvent(event);
+    }
+
+    private void handlerEvent(CustomerEvent event) {
+        if (event.getType() == 1) {
+            permissionService.refreshUser(event.getId());
+        } else if (event.getType() == 2) {
+            permissionService.refreshModule(event.getId());
+        } else {
+            permissionService.refreshModule(event.getId());
+        }
+    }
+}

+ 11 - 0
component-springboot/src/main/java/com/gihon/component/rbac/mapper/GihonUserRoleMapper.java

@@ -1,6 +1,10 @@
 package com.gihon.component.rbac.mapper;
 
+import java.util.List;
+
+import org.apache.ibatis.annotations.Insert;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.gihon.component.rbac.entity.GihonUserRole;
@@ -8,4 +12,11 @@ import com.gihon.component.rbac.entity.GihonUserRole;
 @Mapper
 public interface GihonUserRoleMapper extends BaseMapper<GihonUserRole>{
 
+
+    @Insert({"<script>",
+        "insert ignore into gihon_user_role_tr (user_id,role_id) values ",
+        "<foreach collection=\"roleList\"  item=\"item\" separator=\",\" >",
+        "(#{userId},#{item})", "</foreach>",
+        "</script>"})
+    boolean insertUserRole(@Param("userId") Long userId, @Param("roleList") List<Long> roleList);
 }

+ 3 - 1
component-springboot/src/main/java/com/gihon/component/rbac/service/GihonUserRoleService.java

@@ -15,5 +15,7 @@ public interface GihonUserRoleService extends IService<GihonUserRole> {
     /**
      * 删除某个用户的全部角色
      */
-    public boolean removeRoleByUserId(Long id);
+    public boolean removeRoleByUserId(Long id, List<Long> roleList);
+    
+    public boolean insertUserRole(Long id, List<Long> roleList);
 }

+ 27 - 3
component-springboot/src/main/java/com/gihon/component/rbac/service/GihonUserService.java

@@ -1,21 +1,24 @@
 package com.gihon.component.rbac.service;
 
+import java.util.List;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.gihon.component.exception.BusinessException;
 import com.gihon.component.rbac.entity.GihonUser;
 import com.gihon.component.rbac.vo.UserListReq;
+import com.gihon.component.rbac.vo.UserRoleReq;
 import com.gihon.component.util.PasswordUtils;
 
 public interface GihonUserService extends IService<GihonUser> {
 
     IPage<GihonUser> getUserlistPage(UserListReq search);
-    
+
     default boolean enableCompany(Long userId, boolean enableFlag) {
         return this.lambdaUpdate().eq(GihonUser::getId, userId).eq(GihonUser::getCompanyAdmin, !enableFlag)
             .set(GihonUser::getCompanyAdmin, enableFlag).update();
     }
-    
+
     /**
      * 新增
      */
@@ -39,7 +42,7 @@ public interface GihonUserService extends IService<GihonUser> {
         if (compnayOld == null) {
             throw new BusinessException("账号不存在");
         }
-        
+
         GihonUser userUpdate = new GihonUser();
         userUpdate.setId(user.getId());
         userUpdate.setNickName(user.getNickName());
@@ -48,4 +51,25 @@ public interface GihonUserService extends IService<GihonUser> {
         return this.updateById(userUpdate);
 
     }
+
+    /**
+     * 重置密码
+     */
+    default boolean resetPassword(Long userId) {
+        GihonUser user = this.getById(userId);
+        if (user == null) {
+            throw new BusinessException("账号不存在");
+        }
+        GihonUser userUpdate = new GihonUser();
+        userUpdate.setId(user.getId());
+        userUpdate.setPassword(PasswordUtils.makePassword("123456", user.getUsername()));
+
+        return this.updateById(userUpdate);
+
+    }
+
+    boolean setUserRole(UserRoleReq userRole);
+
+    List<Long> getUserRole(Long userId);
+
 }

+ 8 - 1
component-springboot/src/main/java/com/gihon/component/rbac/service/PermissionService.java

@@ -6,5 +6,12 @@ import com.gihon.component.web.vo.MenuVO;
 
 public interface PermissionService {
 
-    List<MenuVO> getPermission(String moduleCode,int moduleType);
+    List<MenuVO> getPermission(String moduleCode, int moduleType);
+
+    void refreshUser(Long id);
+
+    void refreshRole(Long id);
+
+    void refreshModule(Long id);
+
 }

+ 48 - 9
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonButtonServiceImpl.java

@@ -2,14 +2,19 @@ package com.gihon.component.rbac.service.impl;
 
 import java.util.List;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gihon.component.exception.BusinessException;
 import com.gihon.component.rbac.entity.GihonButton;
 import com.gihon.component.rbac.entity.GihonMenu;
+import com.gihon.component.rbac.listener.CustomePushlisher;
+import com.gihon.component.rbac.listener.CustomerEvent;
 import com.gihon.component.rbac.mapper.GihonButtonMapper;
+import com.gihon.component.rbac.mapper.GihonMenuMapper;
 import com.gihon.component.rbac.service.GihonButtonService;
 import com.google.common.collect.Lists;
 
@@ -22,6 +27,12 @@ import com.google.common.collect.Lists;
 @Service
 public class GihonButtonServiceImpl extends ServiceImpl<GihonButtonMapper, GihonButton> implements GihonButtonService {
 
+    @Autowired
+    protected CustomePushlisher customePushlisher;
+
+    @Autowired
+    private GihonMenuMapper gihonMenuMapper;
+
     /**
      * 获取菜单下按钮权限
      */
@@ -32,27 +43,36 @@ public class GihonButtonServiceImpl extends ServiceImpl<GihonButtonMapper, Gihon
     /**
      * 获取菜单列表下按钮权限
      */
-    public List<GihonButton> getMenuButton(List<Long> menuIdList,boolean idOnly) {
+    public List<GihonButton> getMenuButton(List<Long> menuIdList, boolean idOnly) {
         if (menuIdList.isEmpty()) {
             return Lists.newArrayList();
         }
-        LambdaQueryChainWrapper<GihonButton> wrapper = this.lambdaQuery().in(GihonButton::getMenuId, menuIdList).orderByAsc(GihonButton::getOrderNum);
-        if(idOnly) {
-    		wrapper.select(GihonButton::getId);
-    	}
+        LambdaQueryChainWrapper<GihonButton> wrapper =
+            this.lambdaQuery().in(GihonButton::getMenuId, menuIdList).orderByAsc(GihonButton::getOrderNum);
+        if (idOnly) {
+            wrapper.select(GihonButton::getId);
+        }
         return wrapper.list();
     }
 
     /**
      * 新增按钮权限
      */
+    @Transactional(rollbackFor = Exception.class)
     public boolean saveButton(GihonButton button) {
         int count = this.lambdaQuery().eq(GihonButton::getMenuId, button.getMenuId()).and(p -> {
-            p.eq(GihonButton::getButtonName, button.getButtonName()).or().eq(GihonButton::getButtonCode, button.getButtonCode());
+            p.eq(GihonButton::getButtonName, button.getButtonName()).or().eq(GihonButton::getButtonCode,
+                button.getButtonCode());
         }).count();
         if (count > 0) {
             throw new BusinessException("按钮编码或者名称重复");
         }
+        GihonMenu menu = gihonMenuMapper.selectById(button.getMenuId());
+        CustomerEvent event = new CustomerEvent(menu.getModuleId());
+        event.setType(3);
+        event.setId(menu.getModuleId());
+        customePushlisher.publish(event);
+        
         return this.save(button);
 
     }
@@ -60,14 +80,17 @@ public class GihonButtonServiceImpl extends ServiceImpl<GihonButtonMapper, Gihon
     /**
      * 更新按钮权限
      */
+    @Transactional(rollbackFor = Exception.class)
     public boolean updateButton(GihonButton button) {
         GihonButton buttonOld = this.getById(button.getId());
         if (buttonOld == null) {
             throw new BusinessException("按钮不存在");
         }
-        int count = this.lambdaQuery().eq(GihonButton::getMenuId, buttonOld.getMenuId()).ne(GihonButton::getId, button.getId()).and(p -> {
-            p.eq(GihonButton::getButtonName, button.getButtonName()).or().eq(GihonButton::getButtonCode, button.getButtonCode());
-        }).count();
+        int count = this.lambdaQuery().eq(GihonButton::getMenuId, buttonOld.getMenuId())
+            .ne(GihonButton::getId, button.getId()).and(p -> {
+                p.eq(GihonButton::getButtonName, button.getButtonName()).or().eq(GihonButton::getButtonCode,
+                    button.getButtonCode());
+            }).count();
         if (count > 0) {
             throw new BusinessException("按钮编码或者名称重复");
         }
@@ -76,4 +99,20 @@ public class GihonButtonServiceImpl extends ServiceImpl<GihonButtonMapper, Gihon
         return this.updateById(button);
 
     }
+
+    @Transactional(rollbackFor = Exception.class)
+    public boolean removeEntity(Long id) {
+        GihonButton buttonOld = this.getById(id);
+        if (buttonOld == null) {
+            throw new BusinessException("按钮权限不存在");
+        }
+        this.removeById(id);
+        GihonMenu menu = gihonMenuMapper.selectById(buttonOld.getMenuId());
+        CustomerEvent event = new CustomerEvent(menu.getModuleId());
+        event.setType(3);
+        event.setId(menu.getModuleId());
+        customePushlisher.publish(event);
+        return true;
+    }
+
 }

+ 2 - 0
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonRoleButtonServiceImpl.java

@@ -3,10 +3,12 @@ package com.gihon.component.rbac.service.impl;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gihon.component.rbac.entity.GihonRoleButton;
+import com.gihon.component.rbac.listener.CustomePushlisher;
 import com.gihon.component.rbac.mapper.GihonRoleButtonMapper;
 import com.gihon.component.rbac.service.GihonRoleButtonService;
 

+ 29 - 12
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonRoleServiceImpl.java

@@ -9,14 +9,17 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gihon.component.entity.BaseEntity;
 import com.gihon.component.exception.BusinessException;
 import com.gihon.component.rbac.entity.GihonButton;
-import com.gihon.component.rbac.entity.GihonCompany;
 import com.gihon.component.rbac.entity.GihonRole;
+import com.gihon.component.rbac.entity.GihonUserRole;
+import com.gihon.component.rbac.listener.CustomePushlisher;
+import com.gihon.component.rbac.listener.CustomerEvent;
 import com.gihon.component.rbac.mapper.GihonRoleMapper;
 import com.gihon.component.rbac.service.GihonRoleService;
 import com.gihon.component.rbac.vo.RoleButtonReq;
@@ -44,6 +47,9 @@ public class GihonRoleServiceImpl extends ServiceImpl<GihonRoleMapper, GihonRole
     @Autowired
     private GihonMenuServiceImpl gihonMenuService;
 
+    @Autowired
+    protected CustomePushlisher customePushlisher;
+
     /**
      * 获取用户的角色列表
      */
@@ -124,7 +130,16 @@ public class GihonRoleServiceImpl extends ServiceImpl<GihonRoleMapper, GihonRole
         }
         // 异步通知
         gihonRoleButtonService.removeButtonByRoleId(roleId, null);
-        gihonUserRoleService.removeRoleByUserId(roleId);
+        
+        LambdaQueryWrapper<GihonUserRole> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(GihonUserRole::getRoleId, roleId);
+        gihonUserRoleService.remove(wrapper);
+
+        CustomerEvent event = new CustomerEvent(roleId);
+        event.setType(2);
+        event.setId(roleId);
+        customePushlisher.publish(event);
+
         return this.removeById(roleId);
     }
 
@@ -152,10 +167,11 @@ public class GihonRoleServiceImpl extends ServiceImpl<GihonRoleMapper, GihonRole
         List<Long> btnoldList = gihonRoleButtonService.getButtonListByRole(req.getRoleId());
         btnoldList.retainAll(allbtnList);// 求交集,属于当前模块的角色配置
         req.getButtonList().retainAll(allbtnList);
+        boolean flag = true;
         if (req.getButtonList().isEmpty()) {
-            return gihonRoleButtonService.removeButtonByRoleId(req.getRoleId(), btnoldList);
+            flag = gihonRoleButtonService.removeButtonByRoleId(req.getRoleId(), btnoldList);
         } else if (btnoldList.isEmpty()) {
-            return gihonRoleButtonService.insertRoleButton(req.getRoleId(), req.getButtonList());
+            flag = gihonRoleButtonService.insertRoleButton(req.getRoleId(), req.getButtonList());
         } else {
             List<Long> tempList = new ArrayList<>();
             tempList.addAll(req.getButtonList());
@@ -164,18 +180,19 @@ public class GihonRoleServiceImpl extends ServiceImpl<GihonRoleMapper, GihonRole
             gihonRoleButtonService.insertRoleButton(req.getRoleId(), tempList);
             gihonRoleButtonService.removeButtonByRoleId(req.getRoleId(), btnoldList);
         }
-
-        return true;
+        CustomerEvent event = new CustomerEvent(req.getModuleId());
+        event.setType(3);
+        event.setId(req.getModuleId());
+        customePushlisher.publish(event);
+        return flag;
     }
 
     @Override
     public List<SelectVal> labelAndValue(Long companyId, String roleName) {
-        return this.lambdaQuery()
-            .like(StringUtils.hasText(roleName), GihonRole::getRoleName, roleName)
-            .eq(companyId != null, GihonRole::getId, companyId)
-            .orderByDesc(GihonRole::getRoleName)
-            .list().stream().map(c -> SelectVal.builder().value(c.getId().toString()).label(c.getRoleName()).build())
+        return this.lambdaQuery().like(StringUtils.hasText(roleName), GihonRole::getRoleName, roleName)
+            .eq(companyId != null, GihonRole::getId, companyId).orderByDesc(GihonRole::getRoleName).list().stream()
+            .map(c -> SelectVal.builder().value(c.getId().toString()).label(c.getRoleName()).build())
             .collect(Collectors.toList());
     }
-    
+
 }

+ 21 - 4
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonUserRoleServiceImpl.java

@@ -17,20 +17,37 @@ import com.gihon.component.rbac.service.GihonUserRoleService;
  *
  */
 @Service
-public class GihonUserRoleServiceImpl extends ServiceImpl<GihonUserRoleMapper, GihonUserRole> implements GihonUserRoleService{
+public class GihonUserRoleServiceImpl extends ServiceImpl<GihonUserRoleMapper, GihonUserRole>
+    implements GihonUserRoleService {
 
     /**
      * 获取某个用户的全部角色
      */
     public List<Long> roleListByUserId(Long id) {
-        List<GihonUserRole> roleList = this.lambdaQuery().eq(GihonUserRole::getUserId, id).select(GihonUserRole::getRoleId).list();
+        List<GihonUserRole> roleList =
+            this.lambdaQuery().eq(GihonUserRole::getUserId, id).select(GihonUserRole::getRoleId).list();
         return roleList.stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
     }
 
     /**
      * 删除某个用户的全部角色
      */
-    public boolean removeRoleByUserId(Long id) {
-        return this.lambdaUpdate().eq(GihonUserRole::getUserId, id).remove();
+    public boolean removeRoleByUserId(Long id, List<Long> roleList) {
+        if (roleList != null && roleList.isEmpty()) {
+            return false;
+        }
+        return this.lambdaUpdate().eq(GihonUserRole::getUserId, id)
+            .in(roleList != null, GihonUserRole::getRoleId, roleList).remove();
     }
+
+    /**
+     * 新增角色关联的按钮
+     */
+    public boolean insertUserRole(Long id, List<Long> roleList) {
+        if (roleList == null || roleList.isEmpty()) {
+            return false;
+        }
+        return this.baseMapper.insertUserRole(id, roleList);
+    }
+
 }

+ 42 - 1
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/GihonUserServiceImpl.java

@@ -1,5 +1,8 @@
 package com.gihon.component.rbac.service.impl;
 
+import java.util.Iterator;
+import java.util.List;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
@@ -9,10 +12,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.gihon.component.rbac.entity.GihonCompany;
 import com.gihon.component.rbac.entity.GihonUser;
+import com.gihon.component.rbac.listener.CustomePushlisher;
+import com.gihon.component.rbac.listener.CustomerEvent;
 import com.gihon.component.rbac.mapper.GihonUserMapper;
 import com.gihon.component.rbac.service.GihonCompanyService;
+import com.gihon.component.rbac.service.GihonUserRoleService;
 import com.gihon.component.rbac.service.GihonUserService;
 import com.gihon.component.rbac.vo.UserListReq;
+import com.gihon.component.rbac.vo.UserRoleReq;
 
 /**
  * 直接继承没有多实现处理
@@ -23,9 +30,14 @@ import com.gihon.component.rbac.vo.UserListReq;
 @Service
 public class GihonUserServiceImpl extends ServiceImpl<GihonUserMapper, GihonUser> implements GihonUserService {
 
+    @Autowired
+    protected CustomePushlisher customePushlisher;
+    
     @Autowired
     private GihonCompanyService gihonCompanyService;
-
+    @Autowired
+    private GihonUserRoleService gihonUserRoleService;
+    
     public IPage<GihonUser> getUserlistPage(UserListReq search) {
         Page<GihonUser> page = new Page<>(search.getPageIndex(), search.getPageSize());
         IPage<GihonUser> result = this.lambdaQuery()
@@ -42,5 +54,34 @@ public class GihonUserServiceImpl extends ServiceImpl<GihonUserMapper, GihonUser
         }); 
         return result;
     }
+    @Override
+    public boolean setUserRole(UserRoleReq userRole) {
 
+        List<Long> roleList = gihonUserRoleService.roleListByUserId(userRole.getUserId());
+        Iterator<Long> it = roleList.iterator();
+        while (it.hasNext()) {
+            Long id = it.next();
+            if (userRole.getRoleList().remove(id)) {
+                it.remove();
+            }
+        }
+
+        if (!userRole.getRoleList().isEmpty()) {
+            gihonUserRoleService.insertUserRole(userRole.getUserId(), userRole.getRoleList());
+        }
+        if (!roleList.isEmpty()) {
+            gihonUserRoleService.removeRoleByUserId(userRole.getUserId(), roleList);
+        }
+        // TODO 通知权限刷新
+        CustomerEvent event = new CustomerEvent(userRole.getUserId());
+        event.setType(1);
+        event.setId(userRole.getUserId());
+        customePushlisher.publish(event);
+        return true;
+    }
+
+    @Override
+    public List<Long> getUserRole(Long userId) {
+        return gihonUserRoleService.roleListByUserId(userId);
+    }
 }

+ 82 - 5
component-springboot/src/main/java/com/gihon/component/rbac/service/impl/PermissionServiceImpl.java

@@ -1,6 +1,5 @@
 package com.gihon.component.rbac.service.impl;
 
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -20,16 +19,19 @@ import com.gihon.component.rbac.entity.GihonButton;
 import com.gihon.component.rbac.entity.GihonMenu;
 import com.gihon.component.rbac.entity.GihonModule;
 import com.gihon.component.rbac.entity.GihonRole;
+import com.gihon.component.rbac.entity.GihonUser;
 import com.gihon.component.rbac.service.GihonButtonService;
 import com.gihon.component.rbac.service.GihonMenuService;
 import com.gihon.component.rbac.service.GihonModuleService;
 import com.gihon.component.rbac.service.GihonRoleButtonService;
 import com.gihon.component.rbac.service.GihonRoleService;
+import com.gihon.component.rbac.service.GihonUserService;
 import com.gihon.component.rbac.service.PermissionService;
 import com.gihon.component.util.JacksonJsonUtils;
 import com.gihon.component.web.auth.AuthConstans;
 import com.gihon.component.web.auth.AuthUser;
 import com.gihon.component.web.auth.AuthUtils;
+import com.gihon.component.web.service.TokenService;
 import com.gihon.component.web.vo.MenuVO;
 import com.gihon.component.web.vo.PermissionVO;
 
@@ -57,18 +59,21 @@ public class PermissionServiceImpl implements PermissionService {
     @Autowired
     private GihonRoleService gihonRoleService;
 
+    @Autowired
+    private GihonUserService gihonUserService;
+
     @Override
-    public List<MenuVO> getPermission(String moduleCode,int moduleType) {
+    public List<MenuVO> getPermission(String moduleCode, int moduleType) {
 
-        String menuJson = (String)stringRedisTemplate.opsForHash().get(RedisConstants.MENU_TREE_REDIS, moduleCode + RedisConstants.SEP + moduleType);
+        String menuJson = (String)stringRedisTemplate.opsForHash().get(RedisConstants.MENU_TREE_REDIS,
+            moduleCode + RedisConstants.SEP + moduleType);
         TypeReference<List<MenuVO>> valueTypeRef = new TypeReference<List<MenuVO>>() {};
         List<MenuVO> root = JacksonJsonUtils.readObject(menuJson, valueTypeRef);
         // 原始
         List<MenuVO> list = new ArrayList<>(root.size());
 
         AuthUser user = AuthUtils.getUser();
-        if (AuthConstans.SUPER_ADMIN.equals(user.getUsername())
-            && moduleType == ModuleType.WEB.getCode()) {
+        if (AuthConstans.SUPER_ADMIN.equals(user.getUsername()) && moduleType == ModuleType.WEB.getCode()) {
 
             return root;
         }
@@ -117,6 +122,77 @@ public class PermissionServiceImpl implements PermissionService {
         }
     }
 
+    /**
+     * 删除用户信息缓存
+     */
+    @Override
+    public void refreshUser(Long id) {
+        GihonUser user = gihonUserService.getById(id);
+        stringRedisTemplate.opsForHash().delete(TokenService.USER_STORE, user.getUsername());
+    }
+
+    @Override
+    public void refreshRole(Long id) {
+        this.init();
+    }
+    @Override
+    public void refreshModule(Long id) {
+        GihonModule module = gihonModuleService.getById(id);
+        this.setModule(module);
+    }
+
+    private void setModule(GihonModule module) {
+        List<GihonMenu> menuList = gihonMenuService.getAllMenu(module.getId(), false);
+
+        List<MenuVO> menus = new ArrayList<>();
+
+        MenuVO root = new MenuVO();
+        root.setMenuCode(module.getModuleCode());
+        root.setMenuId(-1L);
+
+        menus.add(root);
+        MenuVO mp = new MenuVO();
+
+        menuList.forEach(m -> {
+            MenuVO mv = new MenuVO();
+            mv.setMenuCode(m.getMenuCode());
+            mv.setMenuId(m.getId());
+            menus.add(mv);
+        });
+        List<GihonButton> buttonList = gihonButtonService
+            .getMenuButton(menuList.stream().map(BaseEntity::getId).collect(Collectors.toList()), false);
+        List<PermissionVO> plist = new ArrayList<>();
+        for (GihonButton btn : buttonList) {
+            List<Long> rbtnList = gihonRoleButtonService.getRoleListByBtn(btn.getId());
+            PermissionVO pvo = new PermissionVO();
+            pvo.setUrl(btn.getPath());
+            pvo.setMethod(btn.getMethod());
+            pvo.setBtnCode(btn.getButtonCode());
+            pvo.setBtnName(btn.getButtonName());
+            if (!rbtnList.isEmpty()) {
+                List<GihonRole> rl = gihonRoleService.getRoleListByIds(rbtnList);
+                pvo.setRoleList(rl.stream().map(GihonRole::getRoleCode).collect(Collectors.toList()));
+            } else {
+                pvo.setRoleList(new ArrayList<>(0));
+            }
+            mp.setMenuId(btn.getMenuId());
+            int index = menus.indexOf(mp);
+            if (index > 0) {
+                menus.get(index).addPermission(pvo);
+            }
+            if (StringUtils.isBlank(btn.getPath())) {
+                continue;
+            }
+            plist.add(pvo);
+        }
+        // 用于拦截器的访问权限按钮
+        stringRedisTemplate.opsForHash().put(RedisConstants.PERMISSN_REDIS, module.getModuleCode(),
+            JacksonJsonUtils.writeObject(plist));
+        // 用于拦截器的访问权限菜单
+        stringRedisTemplate.opsForHash().put(RedisConstants.MENU_TREE_REDIS, module.getModuleCode(),
+            JacksonJsonUtils.writeObject(menus));
+    }
+
     // 定时刷新或者AOP通知
     @PostConstruct
     public void init() {
@@ -186,4 +262,5 @@ public class PermissionServiceImpl implements PermissionService {
             log.error("初始化模块菜单失败:", e);
         }
     }
+
 }

+ 21 - 0
component-springboot/src/main/java/com/gihon/component/rbac/vo/UserRoleReq.java

@@ -0,0 +1,21 @@
+package com.gihon.component.rbac.vo;
+
+import java.util.List;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@ApiModel("用户角色设置")
+public class UserRoleReq {
+
+    @ApiModelProperty("角色ID")
+    private Long userId;
+
+    @ApiModelProperty("角色ID")
+    private List<Long> roleList;
+
+}

+ 26 - 0
readme.md

@@ -0,0 +1,26 @@
+## 吉亨管理后台通用组件
+
+### 2024年3月26日
+
+    租户形式的微服务
+    使用自定义的注解全局配置返回类型的包装类
+    使用自定义权限注解配置菜单权限和路由
+    模块1
+    |-菜单1
+    |-菜单路由1
+    |   |- 查询按钮权限
+    |   |- 新增按钮权限
+    |   |- 修改按钮权限
+    |-菜单路由1
+        |- 查询按钮权限
+        |- 新增按钮权限
+        |- 修改按钮权限
+        
+component-common:通用组件
+component-springboot:管理端微服务/多模块微服务样例
+
+## 管理端前端代码
+
+```
+git clone http://git.jihengcc.cn/baihe/vue-manage -b common
+```