Browse Source

租户和fegin封装请求

yq 2 years ago
parent
commit
ca207a7825
14 changed files with 185 additions and 49 deletions
  1. 3 3
      base-modules/service-system/service-system-api/src/main/java/com/usky/system/RemoteTenantService.java
  2. 4 5
      base-modules/service-system/service-system-api/src/main/java/com/usky/system/factory/RemoteTenantFallbackFactory.java
  3. 4 7
      base-modules/service-system/service-system-biz/src/main/java/com/usky/system/controller/api/SysTenantControllerApi.java
  4. 2 2
      base-modules/service-system/service-system-biz/src/main/resources/bootstrap.yml
  5. 21 0
      usky-common/usky-common-mybatis/src/main/java/com/usky/common/mybatis/config/UskyMybatisAutoConfiguration.java
  6. 51 0
      usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/BaseResponseAdvice.java
  7. 12 0
      usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/FeignAutoConfiguration.java
  8. 16 1
      usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/FeignRequestInterceptor.java
  9. 40 0
      usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/OpenFeignErrorDecoder.java
  10. 1 2
      usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/config/UskyTenantAutoConfiguration.java
  11. 7 4
      usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/db/TenantDatabaseInterceptor.java
  12. 14 12
      usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/security/TenantSecurityWebFilter.java
  13. 2 4
      usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/service/TenantFrameworkService.java
  14. 8 9
      usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/service/TenantFrameworkServiceImpl.java

+ 3 - 3
base-modules/service-system/service-system-api/src/main/java/com/usky/system/RemoteTenantService.java

@@ -1,9 +1,9 @@
 package com.usky.system;
 
-import com.usky.common.core.bean.ApiResult;
 import com.usky.system.factory.RemoteUserFallbackFactory;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.List;
 
@@ -20,7 +20,7 @@ public interface RemoteTenantService {
      * @return 租户编号数组
      */
     @GetMapping("/getTenantIds")
-    ApiResult<List<Integer>> getTenantIds();
+    List<Integer> getTenantIds();
 
     /**
      * 校验租户是否合法
@@ -28,5 +28,5 @@ public interface RemoteTenantService {
      * @param id 租户编号
      */
     @GetMapping("/validTenant")
-    ApiResult<Void> validTenant(Integer id);
+    Boolean validTenant(@RequestParam("id") Integer id);
 }

+ 4 - 5
base-modules/service-system/service-system-api/src/main/java/com/usky/system/factory/RemoteTenantFallbackFactory.java

@@ -1,6 +1,5 @@
 package com.usky.system.factory;
 
-import com.usky.common.core.bean.ApiResult;
 import com.usky.system.RemoteTenantService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,13 +24,13 @@ public class RemoteTenantFallbackFactory implements FallbackFactory<RemoteTenant
         {
 
             @Override
-            public ApiResult<List<Integer>> getTenantIds() {
-                return ApiResult.error("500","获取租户失败:" + throwable.getMessage());
+            public List<Integer> getTenantIds() {
+                return null;
             }
 
             @Override
-            public ApiResult<Void> validTenant(Integer id) {
-                return ApiResult.error("500","校验租失败:" + throwable.getMessage());
+            public Boolean validTenant(Integer id) {
+                return false;
             }
         };
     }

+ 4 - 7
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/controller/api/SysTenantControllerApi.java

@@ -2,14 +2,12 @@ package com.usky.system.controller.api;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.constants.CommonConst;
 import com.usky.common.core.exception.BusinessException;
 import com.usky.system.RemoteTenantService;
 import com.usky.system.domain.SysTenant;
 import com.usky.system.service.SysTenantService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -19,21 +17,20 @@ import java.util.stream.Collectors;
  * @author yq
  * @date 2022/7/12 13:21
  */
-@RequestMapping("/tenantApi")
 @RestController
 public class SysTenantControllerApi implements RemoteTenantService {
 
     @Autowired
     private SysTenantService sysTenantService;
     @Override
-    public ApiResult<List<Integer>> getTenantIds() {
+    public List<Integer> getTenantIds() {
         LambdaQueryWrapper<SysTenant> queryWrapper = Wrappers.lambdaQuery();
         queryWrapper.select(SysTenant::getId);
-        return ApiResult.success(sysTenantService.list(queryWrapper).stream().map(SysTenant::getId).collect(Collectors.toList()));
+        return sysTenantService.list(queryWrapper).stream().map(SysTenant::getId).collect(Collectors.toList());
     }
 
     @Override
-    public ApiResult<Void> validTenant(Integer id) {
+    public Boolean validTenant(Integer id) {
         SysTenant tenant = sysTenantService.getById(id);
         if (tenant == null) {
              throw new BusinessException("租户信息为空");
@@ -41,6 +38,6 @@ public class SysTenantControllerApi implements RemoteTenantService {
         if (tenant.getStatus().equals(CommonConst.FALSE_NUM_STR)) {
             throw new BusinessException("租户已被停用");
         }
-        return ApiResult.success();
+        return true;
     }
 }

+ 2 - 2
base-modules/service-system/service-system-biz/src/main/resources/bootstrap.yml

@@ -14,10 +14,10 @@ spring:
     nacos:
       discovery:
         # 服务注册地址
-        server-addr: usky-cloud-nacos:8848
+        server-addr: 172.16.120.165:8848
       config:
         # 配置中心地址
-        server-addr: usky-cloud-nacos:8848
+        server-addr: 172.16.120.165:8848
         # 配置文件格式
         file-extension: yml
         # 共享配置

+ 21 - 0
usky-common/usky-common-mybatis/src/main/java/com/usky/common/mybatis/config/UskyMybatisAutoConfiguration.java

@@ -0,0 +1,21 @@
+package com.usky.common.mybatis.config;
+
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yq
+ * @date 2022/8/8 13:26
+ */
+@Configuration
+public class UskyMybatisAutoConfiguration {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
+        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
+        return mybatisPlusInterceptor;
+    }
+}

+ 51 - 0
usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/BaseResponseAdvice.java

@@ -0,0 +1,51 @@
+package com.usky.common.security.feign;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.usky.common.core.bean.ApiResult;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import static com.usky.common.security.feign.FeignAutoConfiguration.T_REQUEST_ID;
+
+@RestControllerAdvice(basePackages = "com.usky")
+@Slf4j
+public class BaseResponseAdvice implements ResponseBodyAdvice<Object> {
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Override
+    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
+        return true;
+    }
+
+    @SneakyThrows
+    @Override
+    public Object beforeBodyWrite(Object object, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
+
+        //Feign请求时通过拦截器设置请求头,如果是Feign请求则直接返回实体对象
+        boolean isFeign = serverHttpRequest.getHeaders().containsKey(T_REQUEST_ID);
+
+        if(isFeign){
+            return object;
+        }
+
+        if(object instanceof String){
+            return objectMapper.writeValueAsString(ApiResult.success(object));
+        }
+
+        if(object instanceof ApiResult){
+            return object;
+        }
+
+        return ApiResult.success(object);
+    }
+
+}

+ 12 - 0
usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/FeignAutoConfiguration.java

@@ -1,6 +1,7 @@
 package com.usky.common.security.feign;
 
 import feign.RequestInterceptor;
+import feign.codec.ErrorDecoder;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -12,9 +13,20 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class FeignAutoConfiguration
 {
+    public final static String T_REQUEST_ID = "T_REQUEST_ID";
+
     @Bean
     public RequestInterceptor requestInterceptor()
     {
         return new FeignRequestInterceptor();
     }
+
+    /**
+     * 自定义异常解码器
+     * @return OpenFeignErrorDecoder
+     */
+    @Bean
+    public ErrorDecoder errorDecoder(){
+        return new OpenFeignErrorDecoder();
+    }
 }

+ 16 - 1
usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/FeignRequestInterceptor.java

@@ -8,10 +8,15 @@ import com.usky.common.core.util.StringUtils;
 import feign.RequestInterceptor;
 import feign.RequestTemplate;
 import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.Map;
 import java.util.Objects;
+import java.util.UUID;
+
+import static com.usky.common.security.feign.FeignAutoConfiguration.T_REQUEST_ID;
 
 /**
  * feign 请求拦截器
@@ -44,9 +49,19 @@ public class FeignRequestInterceptor implements RequestInterceptor
             {
                 requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
             }
-
             // 配置客户端IP
             requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr(ServletUtils.getRequest()));
         }
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        if(null != attributes){
+            HttpServletRequest request = attributes.getRequest();
+            // 微服务之间传递的唯一标识,区分大小写所以通过httpServletRequest获取
+            if (request.getHeader(T_REQUEST_ID)==null) {
+                String sid = String.valueOf(UUID.randomUUID());
+                requestTemplate.header(T_REQUEST_ID, sid);
+            }
+
+        }
+
     }
 }

+ 40 - 0
usky-common/usky-common-security/src/main/java/com/usky/common/security/feign/OpenFeignErrorDecoder.java

@@ -0,0 +1,40 @@
+package com.usky.common.security.feign;
+
+import com.alibaba.fastjson.JSON;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.exception.BusinessException;
+import feign.Response;
+import feign.Util;
+import feign.codec.ErrorDecoder;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+@Slf4j
+public class OpenFeignErrorDecoder implements ErrorDecoder {
+    /**
+     * Feign异常解析
+     * @param methodKey 方法名
+     * @param response 响应体
+     * @return BizException
+     */
+    @Override
+    public Exception decode(String methodKey, Response response) {
+        log.error("feign client error,response is {}:",response);
+        try {
+            //获取数据
+            String body = Util.toString(response.body().asReader(Charset.defaultCharset()));
+
+            ApiResult<?> resultData = JSON.parseObject(body,ApiResult.class);
+            if(!resultData.isSuccess()){
+                return new BusinessException(resultData.getMsg());
+            }
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return new BusinessException("Feign client 调用异常");
+    }
+}

+ 1 - 2
usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/config/UskyTenantAutoConfiguration.java

@@ -40,8 +40,7 @@ public class UskyTenantAutoConfiguration {
     // ========== DB ==========
 
     @Bean
-    public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties properties,
-                                                                 MybatisPlusInterceptor interceptor) {
+    public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties properties,MybatisPlusInterceptor interceptor) {
         TenantLineInnerInterceptor inner = new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(properties));
         // 添加到 interceptor 中
         // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定

+ 7 - 4
usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/db/TenantDatabaseInterceptor.java

@@ -1,6 +1,7 @@
 package com.usky.common.tenant.core.db;
 
 import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
 import com.usky.common.tenant.config.TenantProperties;
 import com.usky.common.tenant.core.context.TenantContextHolder;
@@ -23,10 +24,12 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
 
     public TenantDatabaseInterceptor(TenantProperties properties) {
         // 不同 DB 下,大小写的习惯不同,所以需要都添加进去
-        properties.getIgnoreTables().forEach(table -> {
-            ignoreTables.add(table.toLowerCase());
-            ignoreTables.add(table.toUpperCase());
-        });
+        if (CollectionUtils.isNotEmpty(properties.getIgnoreTables())){
+            properties.getIgnoreTables().forEach(table -> {
+                ignoreTables.add(table.toLowerCase());
+                ignoreTables.add(table.toUpperCase());
+            });
+        }
         // 在 OracleKeyGenerator 中,生成主键时,会查询这个表,查询这个表后,会自动拼接 TENANT_ID 导致报错
         ignoreTables.add("DUAL");
     }

+ 14 - 12
usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/security/TenantSecurityWebFilter.java

@@ -1,8 +1,10 @@
 package com.usky.common.tenant.core.security;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSON;
 import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.exception.BusinessException;
 import com.usky.common.core.util.ServletUtils;
 import com.usky.common.security.utils.SecurityUtils;
 import com.usky.common.tenant.config.TenantProperties;
@@ -76,12 +78,10 @@ public class TenantSecurityWebFilter extends OncePerRequestFilter {
             }
             // 3. 校验租户是合法,例如说被禁用、到期
             try {
-                ApiResult<Void> validResult = tenantFrameworkService.validTenant(tenantId);
-                if (ApiResult.ResultStatus.ERROR.equals(validResult.getStatus())){
-                    ServletUtils.renderString(response, JSON.toJSONString(ApiResult.error(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), validResult.getMsg())));
-                }
+                tenantFrameworkService.validTenant(tenantId);
             } catch (Throwable ex) {
-                String msg = "系统异常"+ex.getMessage();
+                BusinessException businessException = (BusinessException)ex.getCause();
+                String msg = businessException.getCustomMessage();
                 ServletUtils.renderString(response, JSON.toJSONString(ApiResult.error(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), msg)));
                 return;
             }
@@ -96,15 +96,17 @@ public class TenantSecurityWebFilter extends OncePerRequestFilter {
     }
 
     private boolean isIgnoreUrl(HttpServletRequest request) {
-        // 快速匹配,保证性能
-        if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
-            return true;
-        }
-        // 逐个 Ant 路径匹配
-        for (String url : tenantProperties.getIgnoreUrls()) {
-            if (pathMatcher.match(url, request.getRequestURI())) {
+        if (CollectionUtil.isNotEmpty(tenantProperties.getIgnoreUrls())){
+            // 快速匹配,保证性能
+            if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
                 return true;
             }
+            // 逐个 Ant 路径匹配
+            for (String url : tenantProperties.getIgnoreUrls()) {
+                if (pathMatcher.match(url, request.getRequestURI())) {
+                    return true;
+                }
+            }
         }
         return false;
     }

+ 2 - 4
usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/service/TenantFrameworkService.java

@@ -1,7 +1,5 @@
 package com.usky.common.tenant.core.service;
 
-import com.usky.common.core.bean.ApiResult;
-
 import java.util.List;
 
 /**
@@ -16,13 +14,13 @@ public interface TenantFrameworkService {
      *
      * @return 租户编号数组
      */
-    ApiResult<List<Integer>> getTenantIds();
+    List<Integer> getTenantIds();
 
     /**
      * 校验租户是否合法
      *
      * @param id 租户编号
      */
-    ApiResult<Void> validTenant(Integer id);
+    Boolean validTenant(Integer id);
 
 }

+ 8 - 9
usky-common/usky-common-tenant/src/main/java/com/usky/common/tenant/core/service/TenantFrameworkServiceImpl.java

@@ -2,7 +2,6 @@ package com.usky.common.tenant.core.service;
 
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
-import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.util.CacheUtils;
 import com.usky.system.RemoteTenantService;
 import lombok.RequiredArgsConstructor;
@@ -25,11 +24,11 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
     /**
      * 针对 {@link #getTenantIds()} 的缓存
      */
-    private final LoadingCache<Object, ApiResult<List<Integer>>> getTenantIdsCache = CacheUtils.buildAsyncReloadingCache(
+    private final LoadingCache<Object, List<Integer>> getTenantIdsCache = CacheUtils.buildAsyncReloadingCache(
             Duration.ofMinutes(1L), // 过期时间 1 分钟
-            new CacheLoader<Object, ApiResult<List<Integer>>>() {
+            new CacheLoader<Object, List<Integer>>() {
                 @Override
-                public ApiResult<List<Integer>> load(Object key) {
+                public List<Integer> load(Object key) {
                     return remoteTenantService.getTenantIds();
                 }
             });
@@ -37,12 +36,12 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
     /**
      * 针对校验结果的缓存
       */
-    private final LoadingCache<Integer, ApiResult<Void>> validTenantCache = CacheUtils.buildAsyncReloadingCache(
+    private final LoadingCache<Integer, Boolean> validTenantCache = CacheUtils.buildAsyncReloadingCache(
             Duration.ofMinutes(1L), // 过期时间 1 分钟
-            new CacheLoader<Integer, ApiResult<Void>>() {
+            new CacheLoader<Integer, Boolean>() {
 
                 @Override
-                public ApiResult<Void> load(Integer id) {
+                public Boolean load(Integer id) {
                     return remoteTenantService.validTenant(id);
                 }
 
@@ -50,12 +49,12 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
 
     @Override
     @SneakyThrows
-    public ApiResult<List<Integer>> getTenantIds() {
+    public List<Integer> getTenantIds() {
         return getTenantIdsCache.get(Boolean.TRUE);
     }
 
     @Override
-    public ApiResult<Void> validTenant(Integer id) {
+    public Boolean validTenant(Integer id) {
         return validTenantCache.getUnchecked(id);
     }