瀏覽代碼

Merge remote-tracking branch 'origin/main'

classic_blue 1 月之前
父節點
當前提交
f896977d80
共有 76 個文件被更改,包括 2999 次插入54 次删除
  1. 137 0
      edu-travel-api/edu-travel-api-admin/pom.xml
  2. 21 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/AdminApplication.java
  3. 32 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/MyAccessDeniedHandler.java
  4. 31 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/MyAuthenticationEntryPoint.java
  5. 39 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/ResourceServerConfig.java
  6. 48 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/TokenConfig.java
  7. 21 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/WebSecurityConfig.java
  8. 23 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/WebServerFactoryConfigs.java
  9. 61 0
      edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java
  10. 137 0
      edu-travel-api/edu-travel-api-web/pom.xml
  11. 17 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/WebApplication.java
  12. 32 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/MyAccessDeniedHandler.java
  13. 31 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/MyAuthenticationEntryPoint.java
  14. 39 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/ResourceServerConfig.java
  15. 48 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/TokenConfig.java
  16. 21 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/WebSecurityConfig.java
  17. 23 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/WebServerFactoryConfigs.java
  18. 61 0
      edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java
  19. 32 0
      edu-travel-api/pom.xml
  20. 3 29
      edu-travel-common/edu-travel-common-core/pom.xml
  21. 0 2
      edu-travel-common/edu-travel-common-core/src/main/java/edu/travel/model/PageDto.java
  22. 58 0
      edu-travel-common/edu-travel-common-elastic/pom.xml
  23. 69 0
      edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/ElasticsearchConfig.java
  24. 68 0
      edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/EsClient.java
  25. 111 0
      edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/EsIndexOperation.java
  26. 45 0
      edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/FileUtils.java
  27. 57 0
      edu-travel-common/edu-travel-common-upload/pom.xml
  28. 40 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/TencentCosClient.java
  29. 45 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/TencentCosUtils.java
  30. 27 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/property/CosProperties.java
  31. 23 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioClient.java
  32. 228 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioUtils.java
  33. 26 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/property/MinioProperties.java
  34. 20 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSClient.java
  35. 116 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSUtils.java
  36. 26 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/property/ObsProperties.java
  37. 24 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSClient.java
  38. 36 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSUtils.java
  39. 26 0
      edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/property/CloudOssProperty.java
  40. 2 0
      edu-travel-common/pom.xml
  41. 28 0
      edu-travel-remote/edu-travel-remote-base/pom.xml
  42. 32 0
      edu-travel-remote/edu-travel-remote-upload/pom.xml
  43. 52 0
      edu-travel-remote/edu-travel-remote-upload/src/main/java/edu/travel/remote/UploadRemoteController.java
  44. 2 0
      edu-travel-remote/pom.xml
  45. 32 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/MyAccessDeniedHandler.java
  46. 31 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/MyAuthenticationEntryPoint.java
  47. 39 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/ResourceServerConfig.java
  48. 48 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/TokenConfig.java
  49. 21 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/WebSecurityConfig.java
  50. 23 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/WebServerFactoryConfigs.java
  51. 12 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/entity/ShopProduct.java
  52. 42 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/exception/GlobalExceptionHandler.java
  53. 61 0
      edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/filter/TokenAuthenticationFilter.java
  54. 3 1
      edu-travel-service/edu-travel-service-commodity/src/main/resources/mapper/ShopProductMapper.xml
  55. 32 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/MyAccessDeniedHandler.java
  56. 31 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/MyAuthenticationEntryPoint.java
  57. 39 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/ResourceServerConfig.java
  58. 48 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/TokenConfig.java
  59. 21 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/WebSecurityConfig.java
  60. 23 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/WebServerFactoryConfigs.java
  61. 1 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/controller/ShopOrderController.java
  62. 42 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/exception/GlobalExceptionHandler.java
  63. 61 0
      edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/filter/TokenAuthenticationFilter.java
  64. 0 10
      edu-travel-service/edu-travel-service-tenement/pom.xml
  65. 20 0
      edu-travel-service/edu-travel-service-tenement/src/main/java/edu/travel/tenant/service/adpter/UploadAdpter.java
  66. 6 0
      edu-travel-service/edu-travel-service-upload/pom.xml
  67. 2 5
      edu-travel-service/edu-travel-service-upload/src/main/java/edu/travel/UploadApplication.java
  68. 32 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/MyAccessDeniedHandler.java
  69. 31 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/MyAuthenticationEntryPoint.java
  70. 39 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/ResourceServerConfig.java
  71. 48 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/TokenConfig.java
  72. 21 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/WebSecurityConfig.java
  73. 23 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/WebServerFactoryConfigs.java
  74. 42 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/exception/GlobalExceptionHandler.java
  75. 61 0
      edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/filter/TokenAuthenticationFilter.java
  76. 46 7
      pom.xml

+ 137 - 0
edu-travel-api/edu-travel-api-admin/pom.xml

@@ -0,0 +1,137 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-api</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-api-admin</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-api-admin</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-zipkin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-transport-simple-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-annotation-aspectj</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-datasource-nacos</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-web-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-remote-tenant</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-remote-upload</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-model-base</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-constant</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-cache</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 21 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/AdminApplication.java

@@ -0,0 +1,21 @@
+package edu.travel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+/**
+ * Hello world!
+ *
+ */
+@SpringBootApplication
+@EnableDiscoveryClient
+@EnableFeignClients
+public class AdminApplication
+{
+    public static void main( String[] args )
+    {
+       SpringApplication.run(AdminApplication.class, args);
+    }
+}

+ 32 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/MyAccessDeniedHandler.java

@@ -0,0 +1,32 @@
+package edu.travel.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAccessDeniedHandler  implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
+        resp.setContentType("application/json;charset=UTF-8");
+        Map map = new HashMap();
+        map.put("code", "450");
+        map.put("message", e.getMessage());
+        map.put("path", req.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        resp.setContentType("application/json");
+        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(resp.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 31 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/MyAuthenticationEntryPoint.java

@@ -0,0 +1,31 @@
+package edu.travel.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        Map map = new HashMap();
+        map.put("code", "451");
+        map.put("message", "无权限访问");
+        map.put("path", httpServletRequest.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        httpServletResponse.setContentType("application/json");
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(httpServletResponse.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 39 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/ResourceServerConfig.java

@@ -0,0 +1,39 @@
+package edu.travel.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+    private static  final String RESOURCE_ID = "admin";
+
+    @Autowired
+    private TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+                .tokenStore(tokenStore)
+                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
+                .accessDeniedHandler(new MyAccessDeniedHandler())
+//                .tokenServices(tokenService())//验证令牌的服务
+                .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+
+        http
+                .authorizeRequests()
+                .antMatchers("/**").permitAll()
+                .and().csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+    }
+}

+ 48 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/TokenConfig.java

@@ -0,0 +1,48 @@
+package edu.travel.config;
+
+import edu.travel.RSAUtill;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.security.PrivateKey;
+
+@Configuration
+public class TokenConfig {
+    @Value("${OAUTH_KEY}")
+    private String key;
+    @Value("${PRIVATE_KEY}")
+    private String privateKey;
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return NoOpPasswordEncoder.getInstance();
+    }
+    @Bean
+    public TokenStore tokenStore() {
+        //JWT令牌存储方案
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        try {
+            PrivateKey privateKeyFromString = RSAUtill.getPrivateKeyFromString(privateKey);
+            String decrypt = RSAUtill.decrypt(key, privateKeyFromString);
+            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+            //对称秘钥,资源服务器使用该秘钥来验证
+//        converter.setKeyPair(keyPair());
+            converter.setSigningKey(decrypt);
+            return converter;
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+}

+ 21 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/WebSecurityConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    //安全拦截机制(最重要)
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+                .authorizeRequests()
+                .anyRequest().authenticated()
+        ;
+
+
+    }
+}

+ 23 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/config/WebServerFactoryConfigs.java

@@ -0,0 +1,23 @@
+package edu.travel.config;
+
+import org.apache.catalina.connector.Connector;
+import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebServerFactoryConfigs {
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory() {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
+            @Override
+            public void customize(Connector connector) {
+                connector.setProperty("relaxedQueryChars", "|{}[]");
+            }
+        });
+        return factory;
+    }
+}

+ 61 - 0
edu-travel-api/edu-travel-api-admin/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,61 @@
+package edu.travel.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.EncryptUtil;
+import edu.travel.entity.EduTenantPO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String token = httpServletRequest.getHeader("token");
+//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYWRtaW4iXSwiZXhwIjoxNzQwMjAyNTcyLCJ1c2VyX25hbWUiOiIxNTk5ODk1NzA3NCIsImp0aSI6IjM0M2JjNGUzLTk5ZjMtNGE4Zi1iMmIxLTI1ZjRkMzBmNmJmYyIsImNsaWVudF9pZCI6ImFkbWluIiwic2NvcGUiOlsic2VydmVyIl19.MYoFq8gg832DQMX-wVMLN0JlIaWeuQZvl1z1NUNFspQ";
+        if (StringUtils.isNotBlank(token)){
+            String json = EncryptUtil.decodeUTF8StringBase64(token);
+            //将token转成json对象
+            JSONObject jsonObject = JSON.parseObject(json);
+            //用户身份信息
+            String username  = jsonObject.getString("principal");
+            Object object = redisTemplate.opsForValue().get(username + "_info");
+            if (object == null){
+                JSONObject resultObject = new JSONObject();
+                resultObject.put("code",401);
+                resultObject.put("msg","not found user");
+                resultObject.put("data",null);
+                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                httpServletResponse.setContentType("application/json;charset=utf-8");
+                httpServletResponse.getWriter().write(resultObject.toJSONString());
+                return;
+            }
+            EduTenantPO eduTenant = JSON.parseObject(object.toString(), EduTenantPO.class);
+            //用户权限
+            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
+            String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
+            //将用户信息和权限填充 到用户身份token对象中
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(eduTenant, null, AuthorityUtils.createAuthorityList(authorities));
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+            //将authenticationToken填充到安全上下文
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 137 - 0
edu-travel-api/edu-travel-api-web/pom.xml

@@ -0,0 +1,137 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-api</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-api-web</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-api-web</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-zipkin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-transport-simple-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-annotation-aspectj</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-datasource-nacos</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-web-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-remote-tenant</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-remote-upload</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-model-base</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-constant</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-cache</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 17 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/WebApplication.java

@@ -0,0 +1,17 @@
+package edu.travel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableDiscoveryClient
+@EnableFeignClients
+public class WebApplication
+{
+    public static void main( String[] args )
+    {
+        SpringApplication.run(WebApplication.class, args);
+    }
+}

+ 32 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/MyAccessDeniedHandler.java

@@ -0,0 +1,32 @@
+package edu.travel.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAccessDeniedHandler  implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
+        resp.setContentType("application/json;charset=UTF-8");
+        Map map = new HashMap();
+        map.put("code", "450");
+        map.put("message", e.getMessage());
+        map.put("path", req.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        resp.setContentType("application/json");
+        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(resp.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 31 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/MyAuthenticationEntryPoint.java

@@ -0,0 +1,31 @@
+package edu.travel.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        Map map = new HashMap();
+        map.put("code", "451");
+        map.put("message", "无权限访问");
+        map.put("path", httpServletRequest.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        httpServletResponse.setContentType("application/json");
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(httpServletResponse.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 39 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/ResourceServerConfig.java

@@ -0,0 +1,39 @@
+package edu.travel.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+    private static  final String RESOURCE_ID = "admin";
+
+    @Autowired
+    private TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+                .tokenStore(tokenStore)
+                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
+                .accessDeniedHandler(new MyAccessDeniedHandler())
+//                .tokenServices(tokenService())//验证令牌的服务
+                .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+
+        http
+                .authorizeRequests()
+                .antMatchers("/**").permitAll()
+                .and().csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+    }
+}

+ 48 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/TokenConfig.java

@@ -0,0 +1,48 @@
+package edu.travel.config;
+
+import edu.travel.RSAUtill;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.security.PrivateKey;
+
+@Configuration
+public class TokenConfig {
+    @Value("${OAUTH_KEY}")
+    private String key;
+    @Value("${PRIVATE_KEY}")
+    private String privateKey;
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return NoOpPasswordEncoder.getInstance();
+    }
+    @Bean
+    public TokenStore tokenStore() {
+        //JWT令牌存储方案
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        try {
+            PrivateKey privateKeyFromString = RSAUtill.getPrivateKeyFromString(privateKey);
+            String decrypt = RSAUtill.decrypt(key, privateKeyFromString);
+            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+            //对称秘钥,资源服务器使用该秘钥来验证
+//        converter.setKeyPair(keyPair());
+            converter.setSigningKey(decrypt);
+            return converter;
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+}

+ 21 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/WebSecurityConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    //安全拦截机制(最重要)
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+                .authorizeRequests()
+                .anyRequest().authenticated()
+        ;
+
+
+    }
+}

+ 23 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/config/WebServerFactoryConfigs.java

@@ -0,0 +1,23 @@
+package edu.travel.config;
+
+import org.apache.catalina.connector.Connector;
+import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebServerFactoryConfigs {
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory() {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
+            @Override
+            public void customize(Connector connector) {
+                connector.setProperty("relaxedQueryChars", "|{}[]");
+            }
+        });
+        return factory;
+    }
+}

+ 61 - 0
edu-travel-api/edu-travel-api-web/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,61 @@
+package edu.travel.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.EncryptUtil;
+import edu.travel.entity.EduTenantPO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String token = httpServletRequest.getHeader("token");
+//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYWRtaW4iXSwiZXhwIjoxNzQwMjAyNTcyLCJ1c2VyX25hbWUiOiIxNTk5ODk1NzA3NCIsImp0aSI6IjM0M2JjNGUzLTk5ZjMtNGE4Zi1iMmIxLTI1ZjRkMzBmNmJmYyIsImNsaWVudF9pZCI6ImFkbWluIiwic2NvcGUiOlsic2VydmVyIl19.MYoFq8gg832DQMX-wVMLN0JlIaWeuQZvl1z1NUNFspQ";
+        if (StringUtils.isNotBlank(token)){
+            String json = EncryptUtil.decodeUTF8StringBase64(token);
+            //将token转成json对象
+            JSONObject jsonObject = JSON.parseObject(json);
+            //用户身份信息
+            String username  = jsonObject.getString("principal");
+            Object object = redisTemplate.opsForValue().get(username + "_info");
+            if (object == null){
+                JSONObject resultObject = new JSONObject();
+                resultObject.put("code",401);
+                resultObject.put("msg","not found user");
+                resultObject.put("data",null);
+                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                httpServletResponse.setContentType("application/json;charset=utf-8");
+                httpServletResponse.getWriter().write(resultObject.toJSONString());
+                return;
+            }
+            EduTenantPO eduTenant = JSON.parseObject(object.toString(), EduTenantPO.class);
+            //用户权限
+            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
+            String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
+            //将用户信息和权限填充 到用户身份token对象中
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(eduTenant, null, AuthorityUtils.createAuthorityList(authorities));
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+            //将authenticationToken填充到安全上下文
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 32 - 0
edu-travel-api/pom.xml

@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>EduTravel</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-api</artifactId>
+    <packaging>pom</packaging>
+
+    <name>edu-travel-api</name>
+    <url>http://maven.apache.org</url>
+    <modules>
+        <module>edu-travel-api-web</module>
+        <module>edu-travel-api-admin</module>
+    </modules>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 3 - 29
edu-travel-common/edu-travel-common-core/pom.xml

@@ -21,48 +21,22 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-extension</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-tx</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>edu.travel</groupId>
             <artifactId>edu-travel-common-resp</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>jakarta.validation</groupId>
-            <artifactId>jakarta.validation-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.hibernate</groupId>
-            <artifactId>hibernate-validator</artifactId>
-            <version>6.0.13.Final</version>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jaxb</groupId>
-            <artifactId>jaxb-runtime</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid</artifactId>
-            <version>1.2.6</version>
-            <scope>compile</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid</artifactId>
-            <version>1.2.6</version>
-            <scope>compile</scope>
-        </dependency>
     </dependencies>
 </project>

+ 0 - 2
edu-travel-common/edu-travel-common-core/src/main/java/edu/travel/model/PageDto.java

@@ -1,7 +1,5 @@
 package edu.travel.model;
 
-import com.alibaba.druid.sql.repository.Schema;
-import com.sun.istack.internal.NotNull;
 import lombok.Data;
 
 import javax.validation.constraints.Max;

+ 58 - 0
edu-travel-common/edu-travel-common-elastic/pom.xml

@@ -0,0 +1,58 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-common-elastic</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-common-elastic</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <!--引入es-high-level-client相关依赖  start-->
+        <dependency>
+            <groupId>org.elasticsearch</groupId>
+            <artifactId>elasticsearch</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-high-level-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!--引入es-high-level-client相关依赖  end-->
+    </dependencies>
+</project>

+ 69 - 0
edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/ElasticsearchConfig.java

@@ -0,0 +1,69 @@
+package edu.travel.elastic;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * restHighLevelClient 客户端配置类
+ *
+ */
+@Slf4j
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "elasticsearch")
+public class ElasticsearchConfig {
+ 
+    /**
+     * es host ip 地址(集群)
+     */
+    private String hosts;
+    /**
+     * es用户名
+     */
+    private String userName;
+    /**
+     * es密码
+     */
+    private String password;
+    /**
+     * es 请求方式
+     */
+    private String scheme;
+    /**
+     * es 连接超时时间
+     */
+    private int connectTimeOut;
+    /**
+     * es socket 连接超时时间
+     */
+    private int socketTimeOut;
+    /**
+     * es 请求超时时间
+     */
+    private int connectionRequestTimeOut;
+    /**
+     * es 最大连接数
+     */
+    private int maxConnectNum;
+    /**
+     * es 每个路由的最大连接数
+     */
+    private int maxConnectNumPerRoute;
+ 
+ 
+
+}

+ 68 - 0
edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/EsClient.java

@@ -0,0 +1,68 @@
+package edu.travel.elastic;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+@Configuration
+public class EsClient {
+    @Autowired
+    private ElasticsearchConfig elasticsearchConfig;
+    /**
+     * 如果@Bean没有指定bean的名称,那么方法名就是bean的名称
+     */
+    @Bean(name = "restHighLevelClient")
+    public RestHighLevelClient restHighLevelClient() {
+        // 构建连接对象
+        RestClientBuilder builder = RestClient.builder(getEsHost());
+
+        // 连接延时配置
+        builder.setRequestConfigCallback(requestConfigBuilder -> {
+            requestConfigBuilder.setConnectTimeout(elasticsearchConfig.getConnectTimeOut());
+            requestConfigBuilder.setSocketTimeout(elasticsearchConfig.getSocketTimeOut());
+            requestConfigBuilder.setConnectionRequestTimeout(elasticsearchConfig.getConnectionRequestTimeOut());
+            return requestConfigBuilder;
+        });
+
+        // 连接数配置
+        builder.setHttpClientConfigCallback(httpClientBuilder -> {
+            httpClientBuilder.setMaxConnTotal(elasticsearchConfig.getMaxConnectNum());
+            httpClientBuilder.setMaxConnPerRoute(elasticsearchConfig.getMaxConnectNumPerRoute());
+            httpClientBuilder.setDefaultCredentialsProvider(getCredentialsProvider());
+            return httpClientBuilder;
+        });
+
+        return new RestHighLevelClient(builder);
+    }
+
+    private HttpHost[] getEsHost() {
+        // 拆分地址(es为多节点时,不同host以逗号间隔)
+        List<HttpHost> hostLists = new ArrayList<>();
+        String[] hostList = elasticsearchConfig.getHosts().split(",");
+        for (String addr : hostList) {
+            String host = addr.split(":")[0];
+            String port = addr.split(":")[1];
+            hostLists.add(new HttpHost(host, Integer.parseInt(port), elasticsearchConfig.getScheme()));
+        }
+        // 转换成 HttpHost 数组
+        return hostLists.toArray(new HttpHost[]{});
+    }
+
+    private CredentialsProvider getCredentialsProvider() {
+        // 设置用户名、密码
+        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(elasticsearchConfig.getUserName(), elasticsearchConfig.getPassword()));
+        return credentialsProvider;
+    }
+}

+ 111 - 0
edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/EsIndexOperation.java

@@ -0,0 +1,111 @@
+package edu.travel.elastic;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.client.indices.CreateIndexRequest;
+import org.elasticsearch.client.indices.GetIndexRequest;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+
+/**
+ * 操作ES索引
+ *
+ */
+@Slf4j
+@Service
+public class EsIndexOperation {
+ 
+    @Autowired
+    private RestHighLevelClient restHighLevelClient;
+    private final RequestOptions options = RequestOptions.DEFAULT;
+ 
+    /**
+     * 判断索引是否存在
+     */
+    public boolean checkIndex(String index) {
+        try {
+            return restHighLevelClient.indices().exists(new GetIndexRequest(index), options);
+        } catch (Exception e) {
+            log.error("EsIndexOperation checkIndex error.", e);
+        }
+        return Boolean.FALSE;
+    }
+ 
+    /**
+     * 创建索引
+     *
+     * @param indexName         es索引名
+     * @param esSettingFilePath es索引的alias、settings和mapping的配置文件
+     */
+    public boolean createIndex(String indexName, String esSettingFilePath) {
+        String aliases = null;
+        String mappings = null;
+        String settings = null;
+        if (StringUtils.isNotBlank(esSettingFilePath)) {
+            try {
+                String fileContent = FileUtils.readFileContent(esSettingFilePath);
+                if (StringUtils.isNotBlank(fileContent)) {
+                    JSONObject jsonObject = JSON.parseObject(fileContent);
+                    aliases = jsonObject.getString("aliases");
+                    mappings = jsonObject.getString("mappings");
+                    settings = jsonObject.getString("settings");
+                }
+            } catch (Exception e) {
+                log.error("createIndex error.", e);
+                return false;
+            }
+        }
+ 
+        if (checkIndex(indexName)) {
+            log.error("createIndex indexName:[{}]已存在", indexName);
+            return false;
+        }
+ 
+        CreateIndexRequest request = new CreateIndexRequest(indexName);
+        if ((StringUtils.isNotBlank(aliases))) {
+            request.aliases(aliases, XContentType.JSON);
+        }
+ 
+        if (StringUtils.isNotBlank(mappings)) {
+            request.mapping(mappings, XContentType.JSON);
+        }
+ 
+        if (StringUtils.isNotBlank(settings)) {
+            request.settings(settings, XContentType.JSON);
+        }
+ 
+        try {
+            this.restHighLevelClient.indices().create(request, options);
+            return true;
+        } catch (IOException e) {
+            log.error("EsIndexOperation createIndex error.", e);
+            return false;
+        }
+    }
+ 
+    /**
+     * 删除索引
+     */
+    public boolean deleteIndex(String indexName) {
+        try {
+            if (checkIndex(indexName)) {
+                DeleteIndexRequest request = new DeleteIndexRequest(indexName);
+                AcknowledgedResponse response = restHighLevelClient.indices().delete(request, options);
+                return response.isAcknowledged();
+            }
+        } catch (Exception e) {
+            log.error("EsIndexOperation deleteIndex error.", e);
+        }
+        return Boolean.FALSE;
+    }
+}

+ 45 - 0
edu-travel-common/edu-travel-common-elastic/src/main/java/edu/travel/elastic/FileUtils.java

@@ -0,0 +1,45 @@
+package edu.travel.elastic;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * 文件操作类
+ */
+@Slf4j
+public class FileUtils {
+ 
+    /**
+     * 读取项目resources文件夹下的文件
+     *
+     * @param filePath 文件路径
+     * @return 文件内容
+     */
+    public static String readFileContent(String filePath) {
+        try {
+            BufferedReader reader = new BufferedReader(new FileReader(filePath));
+            String line;
+            StringBuilder stringBuilder = new StringBuilder();
+            while ((line = reader.readLine()) != null) {
+                stringBuilder.append(line);
+            }
+ 
+            reader.close();
+            return stringBuilder.toString();
+        } catch (IOException e) {
+            log.error("readFileContent error.", e);
+        }
+ 
+        return null;
+    }
+    
+ 
+    public static void main(String[] args) {
+        String filePath = "src/main/resources/es/mappings_test20231216.txt";
+        String fileContent = readFileContent(filePath);
+    }
+ 
+}

+ 57 - 0
edu-travel-common/edu-travel-common-upload/pom.xml

@@ -0,0 +1,57 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-common-upload</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-common-upload</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.huaweicloud</groupId>
+            <artifactId>esdk-obs-java</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 40 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/TencentCosClient.java

@@ -0,0 +1,40 @@
+package edu.travel.upload.cos;
+
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.region.Region;
+import edu.travel.upload.cos.property.CosProperties;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(COSClient.class)
+public class TencentCosClient {
+    @Autowired
+    private CosProperties cosProperties;
+    private static PoolingHttpClientConnectionManager connectionManager;
+    public static void initializeConnectionManager() {
+        // 在这里初始化连接池
+        connectionManager = createConnectionManager();
+    }
+
+    private static PoolingHttpClientConnectionManager createConnectionManager() {
+        // 创建并配置连接池
+        return new PoolingHttpClientConnectionManager();
+    }
+
+    @Bean
+    public COSClient getCosClient() {
+        initializeConnectionManager();
+        COSCredentials cred = new BasicCOSCredentials(cosProperties.getAccessKey(), cosProperties.getSecretKey());
+        ClientConfig clientConfig = new ClientConfig(new Region(cosProperties.getRegionName()));
+        COSClient cosClient = new COSClient(cred, clientConfig);
+        return cosClient;
+    }
+}

+ 45 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/TencentCosUtils.java

@@ -0,0 +1,45 @@
+package edu.travel.upload.cos;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.model.PutObjectRequest;
+import com.qcloud.cos.transfer.TransferManager;
+import com.qcloud.cos.transfer.Upload;
+import edu.travel.upload.cos.property.CosProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+@Configuration
+@ConditionalOnClass(COSClient.class)
+public class TencentCosUtils {
+    @Autowired
+    private CosProperties cosProperties;
+    @Autowired
+    private COSClient cosClient;
+
+    /**
+     * 上传文件到COS
+     *
+     * @param inputStream 流
+     * @param key 文件名称
+     * @return
+     */
+    public  String uploadFileToCOS(InputStream inputStream, String key) throws InterruptedException, IOException, NoSuchAlgorithmException, KeyStoreException {
+        // 每次上传前重新初始化连接池
+        PutObjectRequest putObjectRequest = new PutObjectRequest(cosProperties.getBucketName(), key, inputStream, null);
+        TransferManager transferManager = new TransferManager(cosClient);
+        try {
+            Upload upload = transferManager.upload(putObjectRequest);
+            upload.waitForCompletion(); // 等待上传完成
+            String filePath = cosProperties.getBaseUrl() + "/" + key;
+            return filePath;
+        } finally {
+//            cosClient.shutdown(); // 关闭 COS 客户端
+        }
+    }
+}

+ 27 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/cos/property/CosProperties.java

@@ -0,0 +1,27 @@
+package edu.travel.upload.cos.property;
+
+
+import com.qcloud.cos.COSClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "tencent.cos")
+@ConditionalOnClass(COSClient.class)
+public class CosProperties {
+   private String baseUrl;
+   private String  accessKey;
+   private String  secretKey;
+   private String  regionName;
+   private String  bucketName;
+   private String  folderPrefix;
+}

+ 23 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioClient.java

@@ -0,0 +1,23 @@
+package edu.travel.upload.minio;
+
+import edu.travel.upload.minio.property.MinioProperties;
+import io.minio.MinioClient;
+import io.minio.errors.InvalidEndpointException;
+import io.minio.errors.InvalidPortException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(MinioClient.class)
+public class CloudMinioClient {
+    @Autowired
+    public MinioProperties minioProperties;
+
+    @Bean
+    public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {
+        MinioClient minioClient = new MinioClient(minioProperties.getHost(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
+        return minioClient;
+    }
+}

+ 228 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioUtils.java

@@ -0,0 +1,228 @@
+package edu.travel.upload.minio;
+
+import edu.travel.upload.minio.property.MinioProperties;
+import io.minio.MinioClient;
+import io.minio.ObjectStat;
+import io.minio.PutObjectOptions;
+import io.minio.Result;
+import io.minio.messages.Bucket;
+import io.minio.messages.Item;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.util.UriUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+@Configuration
+@ConditionalOnClass(MinioClient.class)
+public class CloudMinioUtils {
+    @Autowired
+    private MinioClient minioClient;
+    @Autowired
+    private MinioProperties minioProperties;
+    /**
+     * 上传
+     */
+    public String putObject(MultipartFile multipartFile) throws Exception {
+        // bucket 不存在,创建
+        if (!minioClient.bucketExists(minioProperties.getBucket())) {
+            minioClient.makeBucket(minioProperties.getBucket());
+        }
+        try (InputStream inputStream = multipartFile.getInputStream()) {
+            // 上传文件的名称
+            String fileName = multipartFile.getOriginalFilename();
+            // PutObjectOptions,上传配置(文件大小,内存中文件分片大小)
+            PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
+            // 文件的ContentType
+            putObjectOptions.setContentType(multipartFile.getContentType());
+            minioClient.putObject(minioProperties.getBucket(), fileName, inputStream, putObjectOptions);
+            // 返回访问路径
+            return minioProperties.getUrl() + UriUtils.encode(fileName, StandardCharsets.UTF_8);
+        }
+    }
+    /**
+     * 文件下载
+     */
+    public void download(String fileName, HttpServletResponse response){
+        // 从链接中得到文件名
+        InputStream inputStream;
+        try {
+
+            ObjectStat stat = minioClient.statObject(minioProperties.getBucket(), fileName);
+            inputStream = minioClient.getObject(minioProperties.getBucket(), fileName);
+            response.setContentType(stat.contentType());
+            response.setCharacterEncoding("UTF-8");
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = inputStream.read(buffer)) > 0) {
+                response.getOutputStream().write(buffer, 0, length);
+            }
+            inputStream.close();
+        } catch (Exception e){
+            e.printStackTrace();
+            System.out.println("有异常:" + e);
+        }
+    }
+    /**
+     * 列出所有存储桶名称
+     *
+     * @return
+     * @throws Exception
+     */
+    public List<String> listBucketNames()
+            throws Exception {
+        List<Bucket> bucketList = listBuckets();
+        List<String> bucketListName = new ArrayList<>();
+        for (Bucket bucket : bucketList) {
+            bucketListName.add(bucket.name());
+        }
+        return bucketListName;
+    }
+
+    /**
+     * 查看所有桶
+     *
+     * @return
+     * @throws Exception
+     */
+    public List<Bucket> listBuckets()
+            throws Exception {
+        return minioClient.listBuckets();
+    }
+    /**
+     * 检查存储桶是否存在
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean bucketExists(String bucketName) throws Exception {
+        boolean flag = minioClient.bucketExists(bucketName);
+        if (flag) {
+            return true;
+        }
+        return false;
+    }
+    /**
+     * 创建存储桶
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean makeBucket(String bucketName)
+            throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (!flag) {
+            minioClient.makeBucket(bucketName);
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * 删除桶
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean removeBucket(String bucketName)
+            throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            Iterable<Result<Item>> myObjects = listObjects(bucketName);
+            for (Result<Item> result : myObjects) {
+                Item item = result.get();
+                // 有对象文件,则删除失败
+                if (item.size() > 0) {
+                    return false;
+                }
+            }
+            // 删除存储桶,注意,只有存储桶为空时才能删除成功。
+            minioClient.removeBucket(bucketName);
+            flag = bucketExists(bucketName);
+            if (!flag) {
+                return true;
+            }
+        }
+        return false;
+    }
+    /**
+     * 列出存储桶中的所有对象
+     *
+     * @param bucketName 存储桶名称
+     * @return
+     * @throws Exception
+     */
+    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            return minioClient.listObjects(bucketName);
+        }
+        return null;
+    }
+    /**
+     * 列出存储桶中的所有对象名称
+     *
+     * @param bucketName 存储桶名称
+     * @return
+     * @throws Exception
+     */
+    public List<String> listObjectNames(String bucketName) throws Exception {
+        List<String> listObjectNames = new ArrayList<>();
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            Iterable<Result<Item>> myObjects = listObjects(bucketName);
+            for (Result<Item> result : myObjects) {
+                Item item = result.get();
+                listObjectNames.add(item.objectName());
+            }
+        }
+        return listObjectNames;
+    }
+    /**
+     * 删除一个对象
+     *
+     * @param bucketName 存储桶名称
+     * @param objectName 存储桶里的对象名称
+     * @throws Exception
+     */
+    public boolean removeObject(String bucketName, String objectName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            List<String> objectList = listObjectNames(bucketName);
+            for (String s : objectList) {
+                if(s.equals(objectName)){
+                    minioClient.removeObject(bucketName, objectName);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    /**
+     * 文件访问路径
+     *
+     * @param bucketName 存储桶名称
+     * @param objectName 存储桶里的对象名称
+     * @return
+     * @throws Exception
+     */
+    public String getObjectUrl(String bucketName, String objectName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        String url = "";
+        if (flag) {
+            url = minioClient.getObjectUrl(bucketName, objectName);
+        }
+        return url;
+    }
+
+}

+ 26 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/minio/property/MinioProperties.java

@@ -0,0 +1,26 @@
+package edu.travel.upload.minio.property;
+
+import io.minio.MinioClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@ConditionalOnClass(MinioClient.class)
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "minio")
+public class MinioProperties {
+    private String bucket;
+    private String host;
+    private String url;
+    private String accessKey;
+    private String secretKey;
+
+}

+ 20 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSClient.java

@@ -0,0 +1,20 @@
+package edu.travel.upload.obs;
+
+import com.obs.services.ObsClient;
+import edu.travel.upload.obs.property.ObsProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConditionalOnClass(ObsClient.class)
+public class HuaweiOBSClient {
+    @Autowired
+    private ObsProperties obsProperties;
+    @Bean
+    public ObsClient obsClient() {
+      ObsClient  obsClient = new ObsClient(obsProperties.getAccessKey(), obsProperties.getSecretAccessKey(),obsProperties.getEndpoint());
+      return obsClient;
+    }
+}

+ 116 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSUtils.java

@@ -0,0 +1,116 @@
+package edu.travel.upload.obs;
+
+import com.obs.services.ObsClient;
+import com.obs.services.exception.ObsException;
+import com.obs.services.internal.ServiceException;
+import com.obs.services.model.*;
+import edu.travel.upload.obs.property.ObsProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.Optional;
+
+@Component
+@ConditionalOnClass(ObsClient.class)
+public class HuaweiOBSUtils {
+    Logger log = LoggerFactory.getLogger(HuaweiOBSUtils.class);
+    @Autowired
+    private ObsClient obsClient;
+    @Autowired
+    private ObsProperties obsProperties;
+    //注意这里传进来的参数是处理后的图片 base64 参数,处理方法只需要调用 api,这里不做过多解释,可以上网查询转换方法,另外是指定的文件名称和bucket名称,上传后的文件将是以该 fileName 存在于该bucket 内
+    //此方法是用于上传文件,内部调用了 obs 的含有 MD5 参数校验的api方法
+    public void uploadPic(String base64, String fileName) {
+        byte[] bytes = Base64.getDecoder().decode(base64);
+        ObjectMetadata meta = new ObjectMetadata();
+        // 设置MD5校验。
+        String md5 = toBase64String(calculateMd5(bytes));
+        meta.setContentMd5(md5);
+        try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
+            PutObjectResult result = obsClient.putObject(obsProperties.getBucketName(), fileName, inputStream,meta);
+        } catch (Exception e) {
+            log.error("Upload failed: ", e);
+        }
+    }
+
+    // 计算 MD5 值的方法
+    private static byte[] calculateMd5(byte[] data) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            return md.digest(data);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5 algorithm not found.", e);
+        }
+    }
+
+    // 将字节数组转换为 Base64 编码的字符串
+    private static String toBase64String(byte[] bytes) {
+        return Base64.getEncoder().encodeToString(bytes);
+    }
+
+    //该方法是用于检查bucket 内是否有指定文件,内部调用了 obs 的获取文件方法
+    public Boolean checkExist(String fileName,String bucketName) {
+        ObsObject object = null;
+        InputStream inputStream = null;
+        try {
+            object = obsClient.getObject(bucketName, fileName);
+            inputStream = object.getObjectContent();
+            if (inputStream != null) {
+                return true;
+            }
+        } catch (Exception e) {
+            log.error("请求异常:{}", fileName, e);
+            return false;
+        } finally {
+            // 确保关闭 InputStream
+            try {
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+            } catch (IOException e) {
+                log.error("关闭 InputStream 异常", e);
+            }
+        }
+        return false;
+    }
+
+
+    //该方法是用于获取指定时间内的文件下载链接
+    public String getPicViewUrlByInternal(String fileName) {
+        Boolean aBoolean = checkExist(fileName,obsProperties.getBucketName());
+        if (!aBoolean) {
+            return null;
+        }
+        // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
+        String url = generatePresignedUrl(obsProperties.getExpiration(), fileName,obsProperties.getBucketName());
+        return url;
+    }
+
+    private  String generatePresignedUrl(Long expire,String fileName,String bucketName) {
+        TemporarySignatureResponse response = null;
+        try {
+            // URL有效期,3600秒
+            //long expireSeconds = 3600L;
+            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expire);
+            request.setBucketName(bucketName);
+            request.setObjectKey(fileName);
+            response = obsClient.createTemporarySignature(request);
+        } catch (ObsException e) {
+            log.error("get obs failed :{}", e.getMessage());
+            throw new ServiceException(e.getMessage());
+        }
+        return Optional.ofNullable(response)
+                .map(TemporarySignatureResponse::getSignedUrl)
+                .orElse(null);
+    }
+
+}

+ 26 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/obs/property/ObsProperties.java

@@ -0,0 +1,26 @@
+package edu.travel.upload.obs.property;
+
+import com.obs.services.ObsClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "huawei.obs")
+@ConditionalOnClass(ObsClient.class)
+public class ObsProperties {
+ 
+    private String endpoint;
+    private String accessKey;
+    private String secretAccessKey;
+    private String bucketName;
+    private Long expiration;
+}

+ 24 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSClient.java

@@ -0,0 +1,24 @@
+package edu.travel.upload.oss;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import edu.travel.upload.oss.property.CloudOssProperty;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(OSS.class)
+public class AlibabaOSSClient {
+    @Autowired
+    private CloudOssProperty cloudOssProperty;
+
+    @Bean
+    public OSS ossClient() {
+        OSS ossClient = new OSSClientBuilder().build(cloudOssProperty.getEndpoint(), cloudOssProperty.getAccessKeyId(), cloudOssProperty.getAccessKeySecret());
+        return ossClient;
+    }
+
+}

+ 36 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSUtils.java

@@ -0,0 +1,36 @@
+package edu.travel.upload.oss;
+
+import com.aliyun.oss.OSS;
+import edu.travel.upload.obs.HuaweiOBSUtils;
+import edu.travel.upload.oss.property.CloudOssProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.stereotype.Component;
+
+import java.io.InputStream;
+import java.util.UUID;
+
+@Component
+@ConditionalOnClass(OSS.class)
+public class AlibabaOSSUtils {
+    Logger log = LoggerFactory.getLogger(AlibabaOSSUtils.class);
+
+    @Autowired
+    private OSS ossClient;
+    @Autowired
+    private CloudOssProperty cloudOssProperty;
+
+    public String uploadToOss(InputStream inputStream, String originalFilename){
+        // 生成唯一文件名
+        String filename = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
+        // 上传文件
+        ossClient.putObject(cloudOssProperty.getBucketName(), filename, inputStream);
+        // 返回文件的URL
+        return "https://" + cloudOssProperty.getBucketName() + "." + cloudOssProperty.getEndpoint() + "/" + filename;
+    }
+
+
+
+}

+ 26 - 0
edu-travel-common/edu-travel-common-upload/src/main/java/edu/travel/upload/oss/property/CloudOssProperty.java

@@ -0,0 +1,26 @@
+package edu.travel.upload.oss.property;
+
+import com.aliyun.oss.OSS;
+import com.obs.services.ObsClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "alibaba.obs")
+@ConditionalOnClass(OSS.class)
+public class CloudOssProperty {
+    private String endpoint;
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String bucketName;
+
+}

+ 2 - 0
edu-travel-common/pom.xml

@@ -22,6 +22,8 @@
         <module>edu-travel-common-util</module>
         <module>edu-travel-common-openfeign</module>
         <module>edu-travel-common-cache</module>
+        <module>edu-travel-common-upload</module>
+        <module>edu-travel-common-elastic</module>
     </modules>
 
     <properties>

+ 28 - 0
edu-travel-remote/edu-travel-remote-base/pom.xml

@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-remote</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-remote-base</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-remote-base</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 32 - 0
edu-travel-remote/edu-travel-remote-upload/pom.xml

@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>edu-travel-remote</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>edu-travel-remote-upload</artifactId>
+    <packaging>jar</packaging>
+
+    <name>edu-travel-remote-upload</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-resp</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-openfeign</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 52 - 0
edu-travel-remote/edu-travel-remote-upload/src/main/java/edu/travel/remote/UploadRemoteController.java

@@ -0,0 +1,52 @@
+package edu.travel.remote;
+
+import edu.travel.rpc.RPCBaseResponse;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+@FeignClient(name = "upload",path = "/upload")
+public interface UploadRemoteController {
+    /**
+     * 文件是否存在
+     * @param md5
+     * @return
+     */
+    @GetMapping("/exits/md5")
+    RPCBaseResponse exitsFile(@RequestParam("md5") String md5);
+
+    /**
+     * 上传过哪些分片
+     * @param md5
+     * @return
+     */
+    @GetMapping("/exits/blob")
+    RPCBaseResponse exitsBlob(@RequestParam("md5") String md5);
+
+    /**
+     * 上传大文件分片
+     * @param file
+     * @return
+     */
+    @PostMapping(value = "/uploadBlob",headers = {"content-type=multipart/form-data"})
+    RPCBaseResponse uploadBigFile(@RequestParam("file") MultipartFile file);
+
+    /**
+     * 合并大文件
+     * @param json
+     * @return
+     */
+    @PostMapping(value = "/mergeFile")
+    RPCBaseResponse mergeFile(@RequestBody String json);
+
+    /**
+     * 上传小文件
+     * @param file
+     * @return
+     */
+    @PostMapping(value = "/upload",headers = {"content-type=multipart/form-data"})
+    RPCBaseResponse uploadFile(@RequestParam("file") MultipartFile file);
+}

+ 2 - 0
edu-travel-remote/pom.xml

@@ -14,6 +14,8 @@
     <url>http://maven.apache.org</url>
     <modules>
         <module>edu-travel-remote-tenant</module>
+        <module>edu-travel-remote-upload</module>
+        <module>edu-travel-remote-base</module>
     </modules>
 
     <properties>

+ 32 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/MyAccessDeniedHandler.java

@@ -0,0 +1,32 @@
+package edu.travel.commodity.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAccessDeniedHandler  implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
+        resp.setContentType("application/json;charset=UTF-8");
+        Map map = new HashMap();
+        map.put("code", "450");
+        map.put("message", e.getMessage());
+        map.put("path", req.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        resp.setContentType("application/json");
+        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(resp.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 31 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/MyAuthenticationEntryPoint.java

@@ -0,0 +1,31 @@
+package edu.travel.commodity.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        Map map = new HashMap();
+        map.put("code", "451");
+        map.put("message", "无权限访问");
+        map.put("path", httpServletRequest.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        httpServletResponse.setContentType("application/json");
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(httpServletResponse.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 39 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/ResourceServerConfig.java

@@ -0,0 +1,39 @@
+package edu.travel.commodity.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+    private static  final String RESOURCE_ID = "admin";
+
+    @Autowired
+    private TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+                .tokenStore(tokenStore)
+                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
+                .accessDeniedHandler(new MyAccessDeniedHandler())
+//                .tokenServices(tokenService())//验证令牌的服务
+                .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+
+        http
+                .authorizeRequests()
+                .antMatchers("/**").permitAll()
+                .and().csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+    }
+}

+ 48 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/TokenConfig.java

@@ -0,0 +1,48 @@
+package edu.travel.commodity.config;
+
+import edu.travel.RSAUtill;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.security.PrivateKey;
+
+@Configuration
+public class TokenConfig {
+    @Value("${OAUTH_KEY}")
+    private String key;
+    @Value("${PRIVATE_KEY}")
+    private String privateKey;
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return NoOpPasswordEncoder.getInstance();
+    }
+    @Bean
+    public TokenStore tokenStore() {
+        //JWT令牌存储方案
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        try {
+            PrivateKey privateKeyFromString = RSAUtill.getPrivateKeyFromString(privateKey);
+            String decrypt = RSAUtill.decrypt(key, privateKeyFromString);
+            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+            //对称秘钥,资源服务器使用该秘钥来验证
+//        converter.setKeyPair(keyPair());
+            converter.setSigningKey(decrypt);
+            return converter;
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+}

+ 21 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/WebSecurityConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.commodity.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    //安全拦截机制(最重要)
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+                .authorizeRequests()
+                .anyRequest().authenticated()
+        ;
+
+
+    }
+}

+ 23 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/config/WebServerFactoryConfigs.java

@@ -0,0 +1,23 @@
+package edu.travel.commodity.config;
+
+import org.apache.catalina.connector.Connector;
+import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebServerFactoryConfigs {
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory() {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
+            @Override
+            public void customize(Connector connector) {
+                connector.setProperty("relaxedQueryChars", "|{}[]");
+            }
+        });
+        return factory;
+    }
+}

+ 12 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/entity/ShopProduct.java

@@ -115,4 +115,16 @@ public class ShopProduct extends BaseEntity {
      */
     @TableField(value = "delete_flag")
     private Integer deleteFlag;
+
+    /**
+     * 0 上架 1 下架
+     */
+    @TableField(value = "`country_id`")
+    private Integer countryId;
+
+    /**
+     * 评分满分五分
+     */
+    @TableField(value = "`scoring`")
+    private Integer scoring;
 }

+ 42 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/exception/GlobalExceptionHandler.java

@@ -0,0 +1,42 @@
+package edu.travel.commodity.exception;
+
+import edu.travel.emun.ResponseCode;
+import edu.travel.exception.BaseException;
+import edu.travel.resp.BaseResponse;
+import edu.travel.resp.PageResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * GlobalExceptionHandler 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    @ExceptionHandler(BaseException.class)
+    public BaseResponse<Object> handleUserInfoException(BaseException e){
+        e.printStackTrace();
+        return  PageResponse.out(e.getCode(),e.getMessage(),null);
+    }
+
+    @ExceptionHandler(IllegalArgumentException.class)
+    public BaseResponse<Object> handleException(IllegalArgumentException e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.LOGIC_ERROR.getCode(), e.getMessage(),null);
+    }
+
+    @ExceptionHandler(Throwable.class)
+    public BaseResponse<Object> handleException(Exception e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.ERROR.getCode(),e.getMessage(),null);
+    }
+
+}

+ 61 - 0
edu-travel-service/edu-travel-service-commodity/src/main/java/edu/travel/commodity/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,61 @@
+package edu.travel.commodity.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.EncryptUtil;
+import edu.travel.entity.EduTenantPO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String token = httpServletRequest.getHeader("token");
+//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYWRtaW4iXSwiZXhwIjoxNzQwMjAyNTcyLCJ1c2VyX25hbWUiOiIxNTk5ODk1NzA3NCIsImp0aSI6IjM0M2JjNGUzLTk5ZjMtNGE4Zi1iMmIxLTI1ZjRkMzBmNmJmYyIsImNsaWVudF9pZCI6ImFkbWluIiwic2NvcGUiOlsic2VydmVyIl19.MYoFq8gg832DQMX-wVMLN0JlIaWeuQZvl1z1NUNFspQ";
+        if (StringUtils.isNotBlank(token)){
+            String json = EncryptUtil.decodeUTF8StringBase64(token);
+            //将token转成json对象
+            JSONObject jsonObject = JSON.parseObject(json);
+            //用户身份信息
+            String username  = jsonObject.getString("principal");
+            Object object = redisTemplate.opsForValue().get(username + "_info");
+            if (object == null){
+                JSONObject resultObject = new JSONObject();
+                resultObject.put("code",401);
+                resultObject.put("msg","not found user");
+                resultObject.put("data",null);
+                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                httpServletResponse.setContentType("application/json;charset=utf-8");
+                httpServletResponse.getWriter().write(resultObject.toJSONString());
+                return;
+            }
+            EduTenantPO eduTenant = JSON.parseObject(object.toString(), EduTenantPO.class);
+            //用户权限
+            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
+            String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
+            //将用户信息和权限填充 到用户身份token对象中
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(eduTenant, null, AuthorityUtils.createAuthorityList(authorities));
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+            //将authenticationToken填充到安全上下文
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 3 - 1
edu-travel-service/edu-travel-service-commodity/src/main/resources/mapper/ShopProductMapper.xml

@@ -12,6 +12,8 @@
     <result column="main_image_url" jdbcType="VARCHAR" property="mainImageUrl" />
     <result column="heat_value" jdbcType="INTEGER" property="heatValue" />
     <result column="sales_volume" jdbcType="INTEGER" property="salesVolume" />
+    <result column="country_id" jdbcType="INTEGER" property="countryId" />
+    <result column="scoring" jdbcType="INTEGER" property="scoring" />
     <result column="status" jdbcType="INTEGER" property="status" />
     <result column="default_price" jdbcType="DECIMAL" property="defaultPrice" />
     <result column="project" jdbcType="VARCHAR" property="project" />
@@ -23,7 +25,7 @@
   </resultMap>
   <sql id="Base_Column_List">
     <!--@mbg.generated-->
-    id, category_id, category_name, product_name, description, main_image_url, heat_value, 
+    id, category_id, category_name, product_name, description, main_image_url, heat_value, `scoring`,`country_id`
     sales_volume, `status`, default_price, project, create_time, create_user_id, update_time, 
     update_user_id, delete_flag
   </sql>

+ 32 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/MyAccessDeniedHandler.java

@@ -0,0 +1,32 @@
+package edu.travel.order.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAccessDeniedHandler  implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
+        resp.setContentType("application/json;charset=UTF-8");
+        Map map = new HashMap();
+        map.put("code", "450");
+        map.put("message", e.getMessage());
+        map.put("path", req.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        resp.setContentType("application/json");
+        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(resp.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 31 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/MyAuthenticationEntryPoint.java

@@ -0,0 +1,31 @@
+package edu.travel.order.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        Map map = new HashMap();
+        map.put("code", "451");
+        map.put("message", "无权限访问");
+        map.put("path", httpServletRequest.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        httpServletResponse.setContentType("application/json");
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(httpServletResponse.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 39 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/ResourceServerConfig.java

@@ -0,0 +1,39 @@
+package edu.travel.order.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+    private static  final String RESOURCE_ID = "admin";
+
+    @Autowired
+    private TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+                .tokenStore(tokenStore)
+                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
+                .accessDeniedHandler(new MyAccessDeniedHandler())
+//                .tokenServices(tokenService())//验证令牌的服务
+                .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+
+        http
+                .authorizeRequests()
+                .antMatchers("/**").permitAll()
+                .and().csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+    }
+}

+ 48 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/TokenConfig.java

@@ -0,0 +1,48 @@
+package edu.travel.order.config;
+
+import edu.travel.RSAUtill;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.security.PrivateKey;
+
+@Configuration
+public class TokenConfig {
+    @Value("${OAUTH_KEY}")
+    private String key;
+    @Value("${PRIVATE_KEY}")
+    private String privateKey;
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return NoOpPasswordEncoder.getInstance();
+    }
+    @Bean
+    public TokenStore tokenStore() {
+        //JWT令牌存储方案
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        try {
+            PrivateKey privateKeyFromString = RSAUtill.getPrivateKeyFromString(privateKey);
+            String decrypt = RSAUtill.decrypt(key, privateKeyFromString);
+            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+            //对称秘钥,资源服务器使用该秘钥来验证
+//        converter.setKeyPair(keyPair());
+            converter.setSigningKey(decrypt);
+            return converter;
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+}

+ 21 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/WebSecurityConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.order.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    //安全拦截机制(最重要)
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+                .authorizeRequests()
+                .anyRequest().authenticated()
+        ;
+
+
+    }
+}

+ 23 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/config/WebServerFactoryConfigs.java

@@ -0,0 +1,23 @@
+package edu.travel.order.config;
+
+import org.apache.catalina.connector.Connector;
+import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebServerFactoryConfigs {
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory() {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
+            @Override
+            public void customize(Connector connector) {
+                connector.setProperty("relaxedQueryChars", "|{}[]");
+            }
+        });
+        return factory;
+    }
+}

+ 1 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/controller/ShopOrderController.java

@@ -2,6 +2,7 @@ package edu.travel.order.controller;
 
 import edu.travel.order.entity.ShopOrder;
 import edu.travel.web.BaseController;
+import org.checkerframework.checker.units.qual.A;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 

+ 42 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/exception/GlobalExceptionHandler.java

@@ -0,0 +1,42 @@
+package edu.travel.order.exception;
+
+import edu.travel.emun.ResponseCode;
+import edu.travel.exception.BaseException;
+import edu.travel.resp.BaseResponse;
+import edu.travel.resp.PageResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * GlobalExceptionHandler 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    @ExceptionHandler(BaseException.class)
+    public BaseResponse<Object> handleUserInfoException(BaseException e){
+        e.printStackTrace();
+        return  PageResponse.out(e.getCode(),e.getMessage(),null);
+    }
+
+    @ExceptionHandler(IllegalArgumentException.class)
+    public BaseResponse<Object> handleException(IllegalArgumentException e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.LOGIC_ERROR.getCode(), e.getMessage(),null);
+    }
+
+    @ExceptionHandler(Throwable.class)
+    public BaseResponse<Object> handleException(Exception e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.ERROR.getCode(),e.getMessage(),null);
+    }
+
+}

+ 61 - 0
edu-travel-service/edu-travel-service-order/src/main/java/edu/travel/order/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,61 @@
+package edu.travel.order.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.EncryptUtil;
+import edu.travel.entity.EduTenantPO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String token = httpServletRequest.getHeader("token");
+//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYWRtaW4iXSwiZXhwIjoxNzQwMjAyNTcyLCJ1c2VyX25hbWUiOiIxNTk5ODk1NzA3NCIsImp0aSI6IjM0M2JjNGUzLTk5ZjMtNGE4Zi1iMmIxLTI1ZjRkMzBmNmJmYyIsImNsaWVudF9pZCI6ImFkbWluIiwic2NvcGUiOlsic2VydmVyIl19.MYoFq8gg832DQMX-wVMLN0JlIaWeuQZvl1z1NUNFspQ";
+        if (StringUtils.isNotBlank(token)){
+            String json = EncryptUtil.decodeUTF8StringBase64(token);
+            //将token转成json对象
+            JSONObject jsonObject = JSON.parseObject(json);
+            //用户身份信息
+            String username  = jsonObject.getString("principal");
+            Object object = redisTemplate.opsForValue().get(username + "_info");
+            if (object == null){
+                JSONObject resultObject = new JSONObject();
+                resultObject.put("code",401);
+                resultObject.put("msg","not found user");
+                resultObject.put("data",null);
+                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                httpServletResponse.setContentType("application/json;charset=utf-8");
+                httpServletResponse.getWriter().write(resultObject.toJSONString());
+                return;
+            }
+            EduTenantPO eduTenant = JSON.parseObject(object.toString(), EduTenantPO.class);
+            //用户权限
+            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
+            String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
+            //将用户信息和权限填充 到用户身份token对象中
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(eduTenant, null, AuthorityUtils.createAuthorityList(authorities));
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+            //将authenticationToken填充到安全上下文
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 0 - 10
edu-travel-service/edu-travel-service-tenement/pom.xml

@@ -133,16 +133,6 @@
             <artifactId>edu-travel-common-cache</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid</artifactId>
-            <version>1.2.6</version>
-            <scope>compile</scope>
-        </dependency>
-<!--        <dependency>-->
-<!--            <groupId>jakarta.validation</groupId>-->
-<!--            <artifactId>jakarta.validation-api</artifactId>-->
-<!--        </dependency>-->
 
     </dependencies>
     <profiles>

+ 20 - 0
edu-travel-service/edu-travel-service-tenement/src/main/java/edu/travel/tenant/service/adpter/UploadAdpter.java

@@ -0,0 +1,20 @@
+package edu.travel.tenant.service.adpter;
+
+import edu.travel.remote.UploadRemoteController;
+import edu.travel.rpc.RPCBaseResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+@Component
+public class UploadAdpter {
+    @Autowired
+    private UploadRemoteController uploadRemoteController;
+
+    public RPCBaseResponse uploadAdpter(MultipartFile file) {
+        //性能打印
+        //参数转换
+        RPCBaseResponse rpcBaseResponse = uploadRemoteController.uploadBigFile(file);
+        return rpcBaseResponse;
+    }
+}

+ 6 - 0
edu-travel-service/edu-travel-service-upload/pom.xml

@@ -42,6 +42,7 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-oauth2</artifactId>
         </dependency>
+
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
@@ -105,6 +106,11 @@
         </dependency>
         <dependency>
             <groupId>edu.travel</groupId>
+            <artifactId>edu-travel-common-upload</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
             <artifactId>edu-travel-common-util</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>

+ 2 - 5
edu-travel-service/edu-travel-service-upload/src/main/java/edu/travel/UploadApplication.java

@@ -2,14 +2,11 @@ package edu.travel;
 
 import edu.travel.cache.annotation.EnableRedisCache;
 import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 
-/**
- * Hello world!
- *
- */
 @SpringBootApplication
 @EnableDiscoveryClient
 @EnableFeignClients
@@ -19,6 +16,6 @@ public class UploadApplication
 {
     public static void main( String[] args )
     {
-        System.out.println( "Hello World!" );
+       SpringApplication.run(UploadApplication.class, args);
     }
 }

+ 32 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/MyAccessDeniedHandler.java

@@ -0,0 +1,32 @@
+package edu.travel.warehouse.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAccessDeniedHandler  implements AccessDeniedHandler {
+    @Override
+    public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
+        resp.setContentType("application/json;charset=UTF-8");
+        Map map = new HashMap();
+        map.put("code", "450");
+        map.put("message", e.getMessage());
+        map.put("path", req.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        resp.setContentType("application/json");
+        resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(resp.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 31 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/MyAuthenticationEntryPoint.java

@@ -0,0 +1,31 @@
+package edu.travel.warehouse.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        Map map = new HashMap();
+        map.put("code", "451");
+        map.put("message", "无权限访问");
+        map.put("path", httpServletRequest.getServletPath());
+        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
+        httpServletResponse.setContentType("application/json");
+        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.writeValue(httpServletResponse.getOutputStream(), map);
+        } catch (Exception ex) {
+            throw new ServletException();
+        }
+    }
+}

+ 39 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/ResourceServerConfig.java

@@ -0,0 +1,39 @@
+package edu.travel.warehouse.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+    private static  final String RESOURCE_ID = "admin";
+
+    @Autowired
+    private TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+                .tokenStore(tokenStore)
+                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
+                .accessDeniedHandler(new MyAccessDeniedHandler())
+//                .tokenServices(tokenService())//验证令牌的服务
+                .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+
+        http
+                .authorizeRequests()
+                .antMatchers("/**").permitAll()
+                .and().csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+    }
+}

+ 48 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/TokenConfig.java

@@ -0,0 +1,48 @@
+package edu.travel.warehouse.config;
+
+import edu.travel.RSAUtill;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.security.PrivateKey;
+
+@Configuration
+public class TokenConfig {
+    @Value("${OAUTH_KEY}")
+    private String key;
+    @Value("${PRIVATE_KEY}")
+    private String privateKey;
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return NoOpPasswordEncoder.getInstance();
+    }
+    @Bean
+    public TokenStore tokenStore() {
+        //JWT令牌存储方案
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        try {
+            PrivateKey privateKeyFromString = RSAUtill.getPrivateKeyFromString(privateKey);
+            String decrypt = RSAUtill.decrypt(key, privateKeyFromString);
+            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+            //对称秘钥,资源服务器使用该秘钥来验证
+//        converter.setKeyPair(keyPair());
+            converter.setSigningKey(decrypt);
+            return converter;
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+}

+ 21 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/WebSecurityConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.warehouse.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    //安全拦截机制(最重要)
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+                .authorizeRequests()
+                .anyRequest().authenticated()
+        ;
+
+
+    }
+}

+ 23 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/config/WebServerFactoryConfigs.java

@@ -0,0 +1,23 @@
+package edu.travel.warehouse.config;
+
+import org.apache.catalina.connector.Connector;
+import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebServerFactoryConfigs {
+    @Bean
+    public ConfigurableServletWebServerFactory webServerFactory() {
+        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
+            @Override
+            public void customize(Connector connector) {
+                connector.setProperty("relaxedQueryChars", "|{}[]");
+            }
+        });
+        return factory;
+    }
+}

+ 42 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/exception/GlobalExceptionHandler.java

@@ -0,0 +1,42 @@
+package edu.travel.warehouse.exception;
+
+import edu.travel.emun.ResponseCode;
+import edu.travel.exception.BaseException;
+import edu.travel.resp.BaseResponse;
+import edu.travel.resp.PageResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * GlobalExceptionHandler 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    @ExceptionHandler(BaseException.class)
+    public BaseResponse<Object> handleUserInfoException(BaseException e){
+        e.printStackTrace();
+        return  PageResponse.out(e.getCode(),e.getMessage(),null);
+    }
+
+    @ExceptionHandler(IllegalArgumentException.class)
+    public BaseResponse<Object> handleException(IllegalArgumentException e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.LOGIC_ERROR.getCode(), e.getMessage(),null);
+    }
+
+    @ExceptionHandler(Throwable.class)
+    public BaseResponse<Object> handleException(Exception e){
+        e.printStackTrace();
+        return PageResponse.out(ResponseCode.ERROR.getCode(),e.getMessage(),null);
+    }
+
+}

+ 61 - 0
edu-travel-service/edu-travel-service-warehouse/src/main/java/edu/travel/warehouse/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,61 @@
+package edu.travel.warehouse.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.EncryptUtil;
+import edu.travel.entity.EduTenantPO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String token = httpServletRequest.getHeader("token");
+//token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYWRtaW4iXSwiZXhwIjoxNzQwMjAyNTcyLCJ1c2VyX25hbWUiOiIxNTk5ODk1NzA3NCIsImp0aSI6IjM0M2JjNGUzLTk5ZjMtNGE4Zi1iMmIxLTI1ZjRkMzBmNmJmYyIsImNsaWVudF9pZCI6ImFkbWluIiwic2NvcGUiOlsic2VydmVyIl19.MYoFq8gg832DQMX-wVMLN0JlIaWeuQZvl1z1NUNFspQ";
+        if (StringUtils.isNotBlank(token)){
+            String json = EncryptUtil.decodeUTF8StringBase64(token);
+            //将token转成json对象
+            JSONObject jsonObject = JSON.parseObject(json);
+            //用户身份信息
+            String username  = jsonObject.getString("principal");
+            Object object = redisTemplate.opsForValue().get(username + "_info");
+            if (object == null){
+                JSONObject resultObject = new JSONObject();
+                resultObject.put("code",401);
+                resultObject.put("msg","not found user");
+                resultObject.put("data",null);
+                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                httpServletResponse.setContentType("application/json;charset=utf-8");
+                httpServletResponse.getWriter().write(resultObject.toJSONString());
+                return;
+            }
+            EduTenantPO eduTenant = JSON.parseObject(object.toString(), EduTenantPO.class);
+            //用户权限
+            JSONArray authoritiesArray = jsonObject.getJSONArray("authorities");
+            String[] authorities = authoritiesArray.toArray(new String[authoritiesArray.size()]);
+            //将用户信息和权限填充 到用户身份token对象中
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(eduTenant, null, AuthorityUtils.createAuthorityList(authorities));
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+            //将authenticationToken填充到安全上下文
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 46 - 7
pom.xml

@@ -13,9 +13,7 @@
     <module>edu-travel-remote</module>
     <module>edu-travel-oauth</module>
     <module>edu-travel-model</module>
-      <module>edu-travel-service/edu-travel-service-commodity</module>
-      <module>edu-travel-service/edu-travel-service-warehouse</module>
-      <module>edu-travel-service/edu-travel-service-order</module>
+      <module>edu-travel-api</module>
   </modules>
   <parent>
     <groupId>org.springframework.boot</groupId>
@@ -38,14 +36,55 @@
     <bootstrap.version>4.1.3</bootstrap.version>
     <pg.version>42.6.0</pg.version>
     <sharding.sphere.version>5.1.0</sharding.sphere.version>
-
+    <obs.version>3.20.6.1</obs.version>
+    <oss.version>3.10.2</oss.version>
+    <cos.version>5.6.54</cos.version>
+    <minio.version>7.0.2</minio.version>
+    <elasticsearch.version>7.10.0</elasticsearch.version>
   </properties>
   <dependencyManagement>
+
     <dependencies>
+      <!--引入es-high-level-client相关依赖  start-->
+      <dependency>
+        <groupId>org.elasticsearch</groupId>
+        <artifactId>elasticsearch</artifactId>
+        <version>${elasticsearch.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.elasticsearch.client</groupId>
+        <artifactId>elasticsearch-rest-client</artifactId>
+        <version>${elasticsearch.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.elasticsearch.client</groupId>
+        <artifactId>elasticsearch-rest-high-level-client</artifactId>
+        <version>${elasticsearch.version}</version>
+      </dependency>
+      <!--引入es-high-level-client相关依赖  end-->
+      <dependency>
+        <groupId>io.minio</groupId>
+        <artifactId>minio</artifactId>
+        <version>${minio.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.aliyun.oss</groupId>
+        <artifactId>aliyun-sdk-oss</artifactId>
+        <version>${oss.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.qcloud</groupId>
+        <artifactId>cos_api</artifactId>
+        <version>${cos.version}</version>
+        <scope>provided</scope>
+      </dependency>
       <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-validation</artifactId>
-        <version>2.3.12.RELEASE</version>
+        <groupId>com.huaweicloud</groupId>
+        <artifactId>esdk-obs-java</artifactId>
+        <version>${obs.version}</version>
       </dependency>
 
       <dependency>