SpringCloud微服务项目的搭建

1.新建项目

  1. 新建一个新的Java Maven项目,将src目录全部删除

  2. 留下pom.mxl作为父项目的总依赖

  3. 使用 <dependencyManagement></dependencyManagement>对其进行统一管理

  4. 导入对应的依赖,这里使用 spring-cloud-alibaba

    • <!-- springcloud的依赖-->
      <dependencies>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>2022.0.0</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      
          <!--spring-cloud-alibaba-->
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-alibaba-dependencies</artifactId>
              <version>2022.0.0.0-RC1</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      
          <!-- springboot的依赖-->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-dependencies</artifactId>
              <version>3.0.0</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
      
  5. 新建新的Springboot项目

    image-20250619095127695.png

  6. 导入对应的依赖

    • <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter</artifactId>
          </dependency>
      
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
              <scope>test</scope>
          </dependency>
      
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
          </dependency>
      
          <!-- nacos-->
          <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>
          <!-- sentinel -->
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
          </dependency>
      
          <!-- 公共模块 -->
          <dependency>
              <groupId>com.cxwl</groupId>
              <artifactId>cxwl-common</artifactId>
              <version>1.0.0</version>
          </dependency>
      
          <!-- openfeign-->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-openfeign</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-loadbalancer</artifactId>
          </dependency>
      </dependencies>
      
  7. 修改 <parent>

    • <parent>
          <groupId>com.cxwl</groupId>
          <artifactId>cxwl-tkds-platform</artifactId>
          <version>1.0.0</version>
          <relativePath/>
      </parent>
      
  8. 最后回到父工程的 pom.xml中,加入对应的模块

    • <modules>
          <module>common</module>
          <module>gateway</module>
          <module>agriculture</module>
          <module>emergency</module>
          <module>environmental</module>
          <module>user</module>
      </modules>
      

2.Nacos注册中心

  1. 进入Nacos官网,点击快速开始,去发布历史

  2. 找到父工程pom.xml中 <version>2022.0.0</version>对应的版本

    <!-- springcloud的依赖-->
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-dependencies</artifactId>
    	<version>2022.0.0</version>
    	<type>pom</type>
    	<scope>import</scope>
    </dependency>
    
  3. 下载,找到对应的手册

3.Nacos配置中心

spring:
  application:
    name: cxwl-user
  config:
    import: nacos:user-dev.yml
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yml

4.OpenFegin服务调用

<!-- openfeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

5.负载均衡

6.GateWay网关路由

<!-- gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

7.GateWay鉴权

在网关中设置拦截器

package com.cxwl.gateway.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class GlobalFilterConfig implements GlobalFilter, Ordered {
    @Value("${config.redisTimeout}")
    private Long redisTimeout;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String HEADER_NAME = "Access-Token";
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    // 定义白名单路径列表
    private static final List<String> ANONYMOUS_PATHS = new ArrayList<String>() {{
        // 登录注册相关
        add("/user/login");
        add("/register");
        add("/captchaImage");
        add("/pcPhoneLogin");
        add("/getCompanyListByPhone");
        add("/sendMessage");
      
        // 微信相关接口
        add("/wx/user/login");
        add("/wx/user/test-login");
        add("/wx/user/decrypt-phone");
        add("/wx/auth");
        add("/wx/beforeLoginSelect");
        add("/wx/beforeAuthSelect");
        add("/common/wxUploadImage");
      
        // 系统配置相关
        add("/system/config/configKey2/**");
        add("/exam/h5/**");
        add("/common/download");
        add("/rdArnQT3wW.txt");
        add("/inventory/scanCodeCheckInventory");
        add("/system/user/getBxDealUserList");
      
        // Swagger文档
        add("/swagger-ui.html");
        add("/swagger-resources/**");
        add("/webjars/**");
        add("/*/api-docs");
        add("/druid/**");
      
        // WebSocket
        add("/webSocket");
      
        // 其他公开接口
        add("/getCompanyListByLogin");
        add("/work/manage");
        add("/system/user/checkPhoneCode");
        add("/system/user/updatePasswordByUserName");
        add("/system/user/sendUpdatePasswordMessage");
    }};

    // 定义静态资源路径
    private static final List<String> STATIC_PATHS = new ArrayList<String>() {{
        add("/");
        add("/*.html");
        add("/**/*.html");
        add("/**/*.css");
        add("/**/*.js");
        add("/profile/**");
    }};

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String url = request.getURI().getPath();

        // 如果是OPTIONS请求或白名单路径,直接放行
        if (isWhitelistPath(url, request)) {
            return chain.filter(exchange);
        }

        String token = request.getHeaders().getFirst(HEADER_NAME);
        if (StringUtils.isEmpty(token)) {
            return unAuthorize(exchange);
        }

        if (!redisTemplate.hasKey(token)) {
            return unAuthorize(exchange);
        }

        redisTemplate.expire(token, redisTimeout, TimeUnit.SECONDS);
        String userId = String.valueOf(redisTemplate.opsForValue().get(token));

        ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, token).build();
        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(newExchange);
    }

    private boolean isWhitelistPath(String url, ServerHttpRequest request) {
        // 处理OPTIONS请求
        if ("OPTIONS".equals(request.getMethodValue())) {
            return true;
        }

        // 检查是否是静态资源
        for (String pattern : STATIC_PATHS) {
            if (pathMatcher.match(pattern, url)) {
                return true;
            }
        }

        // 检查是否在白名单中
        for (String pattern : ANONYMOUS_PATHS) {
            if (pathMatcher.match(pattern, url)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> unAuthorize(ServerWebExchange exchange) {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String errorMsg = "{\"code\": 401, \"message\": \"用户未登录或登录超时,请重新登录\"}"; 
        return exchange.getResponse()
                .writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(errorMsg.getBytes())));
    }
}

8.GateWay+Sentinel

  1. 在需要加入到Sentinel的服务中加入依赖

    • <!-- sentinel -->
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      </dependency>
      
  2. 进入Sentinel官网,下载对应的jar包

  3. 输入x.x.x.x:8080,可以看到加入到Sentinel中的服务

image-20250619103040376.png

9.Sentinel流控熔断

10.Sentinel热点限流

11.Sentinel授权规则

java -jar -Dspring.profiles.active=prod your-app.jar