系列文章目录
构建SpringCloud alibaba项目(一、构建父工程、公共库、网关)
构建SpringCloud alibaba项目(二、构建微服务鉴权子工程store-authority-service)
文章目录
1、概要
本章节讲解如何构建SpringCloud alibaba项目,以父子工程形式搭建。
- 父工程规范Springboot版本、SpringCloud版本、SpringCloud alibaba版本;
- 子工程包括公共方法库(公共的DTO、http统一返回类(枚举code码等)),Gateway网关(集成Sentinel)、内网微服务统一接口层、内网微服务发布方、内网微服务调用方等;
2、整体架构流程
2.1、技术结构组成部分
此次框架选型是对Spring Cloud Netflix 框架组件的升级与替换。
Spring Cloud alibaba组件包括:Nacos (discovery、config)、Sentinel
Spring Cloud 组件包括:OpenFeign+ LoadBalancer 、Sleuth、Gateway
其他组件:RabbitMQ 、redis、mybatis-plus、knife4j、JWT、ShardingSphere-jdbc
3、技术名词解释
例如:
- Nacos discovery: 英文全称为 Dynamic Naming and Configuration Service,是一个由阿里巴巴团队使用 Java 语言开发的开源项目,有注册中心、服务注册、发现功能。
- Nacos config: 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。
- Sentinel:是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控制组件
- Sleuth:可以将一次分布式请求还原成调用链路,进行日志记录,性能监控并将一次分布式请求的调用情况集中展示。
- OpenFeign: 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件。我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用,结合LoadBalancer 一起使用。
- RabbitMQ:RabbitMQ整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。常用于系统解耦、削峰使用,常见于微服务、业务活动等场景。
- mybatis-plus:数据库操作工具;
- knife4j:基于swagger升级的文档管理工具。
- JWT:JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,基于JSON的开发标准,用户信息加密到token里,服务器不保存任何用户信息。
- Apache ShardingSphere : 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强
4、技术细节
4.1、构建父工程
4.1.1、选择构建Maven项目
4.1.2、修改父工程文件
- 删除src目录及底下的所有文件
- 保留pom.xml
4.1.3、修改父工程pom.xml配置
4.1.3.1、添加springboot支持
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.10</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.kelvin</groupId><artifactId>onlinestore</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging>
4.1.3.2、修改JDK版本、编码、springboot版本配置
<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>2.7.10</spring-boot.version></properties>
4.1.3.3、添加Spring Cloud、Spring Cloud alibaba版本规范配置
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2021.0.5</version><type>pom</type><scope>import</scope></dependency><!--spring cloud alibaba 依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2021.0.4.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
4.1.3.4、增加lombok依赖配置
<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>compile</scope></dependency></dependencies>
4.1.3.5、增加build配置,整个工程使用maven打包
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration></plugin></plugins></build>
4.2、构建公共子工程
4.2.1、添加子工程store-common
4.2.2、修改文件
- 删除test文件夹
- pom.xml去掉junit
4.2.3、添加统一返回类
packagecom.kelvin.common.http;/***
* @title HttpStatusInfoInterface
* @desctption HTTP状态信息接口
* @author Administrator
* @create 2023/5/18 10:28
**/publicinterfaceHttpStatusInfoInterface{intgetCode();StringgetMessage();}
packagecom.kelvin.common.http;/***
* @title HttpStatusEnum
* @desctption Http状态码
* @author Administrator
* @create 2023/5/18 10:30
**/publicenumHttpStatusEnumimplementsHttpStatusInfoInterface{//定义状态枚举值SUCCESS(200,"成功!"),NOROLE(300,"权限不足!"),USER_TOKEN_NOT_EXISTS(301,"无效的token信息!"),PRODUCT_STOCK_NOT_ENOUGH(302,"商品的库存不足!"),BODY_NOT_MATCH(400,"数据格式不匹配!"),NOT_FOUND(404,"访问资源不存在!"),FLOW_LIMIT(490,"接口流量已超出,限制访问!"),INTERNAM_SERVER_ERROR(500,"服务器内部错误!"),SERVER_BUSY(503,"服务器正忙,请稍后再试!"),REQUEST_METHOD_SUPPORT_ERROR(10001,"当前请求方法不支持!"),REQUEST_DATA_NULL(10002,"当前请求参数为空!"),USER_NOT_EXISTS(10003,"该用户不存在!"),USER_INVALID(10004,"当前登录信息已失效,请重新登录!"),PASSWORD_ERROR(10005,"密码错误!"),USER_NAME_LOCK(10006,"该账号已被锁定!");//状态码privateint code;//提示信息privateString message;HttpStatusEnum(int code,String message){this.code = code;this.message = message;}@OverridepublicintgetCode(){returnthis.code;}@OverridepublicStringgetMessage(){returnthis.message;}}
packagecom.kelvin.common.http;importlombok.Data;/***
* @title ResultDTO
* @desctption 控制器的统一返回类
* @author Administrator
* @create 2023/5/16 9:48
**/@DatapublicclassResultDTO<T>{privateInteger code ;privateString message;privateT data;publicResultDTO(){}publicResultDTO(Integer code,String message,T data){this.code = code;this.message = message;this.data = data;}}
packagecom.kelvin.common.http;/***
* @title HttpResultGenerator
* @desctption <TODO description class purpose>
* @author Administrator
* @create 2023/5/18 10:43
**/publicclassHttpResultGenerator{//正常返回时调用方法publicstaticResultDTOsuccess(Object data){returnnewResultDTO(HttpStatusEnum.SUCCESS.getCode(),"接口调用成功!", data);}//失败时调用方法(入参是异常枚举)publicstaticResultDTOfail(HttpStatusEnum httpStatusEnum){returnnewResultDTO(httpStatusEnum.getCode(), httpStatusEnum.getMessage(),null);}//失败时调用方法(提供给GlobalExceptionHandler类使用)publicstaticResultDTOfail(int code ,String message){returnnewResultDTO(code , message ,null);}}
4.2.4、添加token辅助类
packagecom.kelvin.common.dto;importlombok.Data;/***
* @title TokenDTO
* @desctption <TODO description class purpose>
* @author Administrator
* @create 2023/6/8 10:01
**/@DatapublicclassTokenDTO{privateString token;}
4.3、构建网关子工程
4.3.1、修改pom.xml配置
修改父工程指向
<parent><groupId>com.kelvin</groupId><artifactId>onlinestore</artifactId><version>1.0-SNAPSHOT</version></parent>
<dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><version>1.8.5</version></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>1.8.6</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><dependency><groupId>com.kelvin</groupId><artifactId>store-common</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-loadbalancer --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
4.3.2、修改application.yml配置
server:port:80spring:main:web-application-type: reactive
application:name: gateway-service
cloud:nacos:discovery:server-addr: localhost:8848#Nacos server 的地址gateway:#网关路由配置routes:#将 drp-user-service 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 80-id: user-api_routh #路由 id,没有固定规则,但唯一,建议与服务名对应uri: lb://user-api #匹配后提供服务的路由地址predicates:#以下是断言条件,必选全部符合条件- Path=/user/**#断言,路径匹配 注意:Path 中 P 为大写- Method=GET,POST #只能时 GET 请求时,才能访问metadata:connect-timeout:10#单位毫秒response-timeout:10000-id: authority-service_routh #路由 id,没有固定规则,但唯一,建议与服务名对应uri: lb://auth-service #匹配后提供服务的路由地址predicates:#以下是断言条件,必选全部符合条件- Path=/auth/**#断言,路径匹配 注意:Path 中 P 为大写- Method=GET,POST #只能时 GET 请求时,才能访问metadata:connect-timeout:10#单位毫秒response-timeout:10000sentinel:transport:#配置 Sentinel dashboard 地址dashboard: localhost:8080#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口port:8719#开启除了controller层其他链路调用web-context-unify:false
4.3.3、网关解决跨域问题
packagecom.kelvin.storegateway.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.reactive.CorsConfigurationSource;importorg.springframework.web.cors.reactive.CorsWebFilter;importorg.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;importjava.util.Arrays;@ConfigurationpublicclassWebConfig{@BeanpublicCorsConfigurationSourcecorsConfigurationSource(){CorsConfiguration configuration =newCorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowedHeaders(Arrays.asList("content-type","token"));UrlBasedCorsConfigurationSource source =newUrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);return source;}@BeanpublicCorsWebFiltercorsWebFilter(CorsConfigurationSource corsConfigurationSource){returnnewCorsWebFilter(corsConfigurationSource);}@BeanpublicWebMvcConfigurercorsConfigurer(){returnnewWebMvcConfigurer(){@OverridepublicvoidaddCorsMappings(CorsRegistry registry){
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*").allowedHeaders("*").allowCredentials(true);}};}}
4.3.4、网关增加鉴权功能AuthService
packagecom.kelvin.storegateway.service;importcom.kelvin.common.dto.TokenDTO;importorg.springframework.cloud.openfeign.FeignClient;importorg.springframework.stereotype.Component;importorg.springframework.web.bind.annotation.PostMapping;/***
* @title AuthService
* @desctption <TODO description class purpose>
* @author Administrator
* @create 2023/6/8 10:04
**/@Component@FeignClient(value ="auth-service")publicinterfaceAuthService{@PostMapping("auth/isTokenExpiration")publicBooleanvalidateToken(TokenDTO token);}
4.3.5、增加网关登录验证拦截GatewayWebFilter
packagecom.kelvin.storegateway.filter;importcom.kelvin.common.dto.TokenDTO;importcom.kelvin.storegateway.service.AuthService;importorg.springframework.beans.factory.ObjectProvider;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.boot.autoconfigure.http.HttpMessageConverters;importorg.springframework.cloud.gateway.filter.GatewayFilterChain;importorg.springframework.cloud.gateway.filter.GlobalFilter;importorg.springframework.context.annotation.Bean;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpStatus;importorg.springframework.http.converter.HttpMessageConverter;importorg.springframework.http.server.reactive.ServerHttpRequest;importorg.springframework.http.server.reactive.ServerHttpResponse;importorg.springframework.stereotype.Component;importorg.springframework.util.StringUtils;importorg.springframework.web.server.ServerWebExchange;importreactor.core.publisher.Mono;importjavax.annotation.Resource;importjava.util.stream.Collectors;/***
* @title DrfGlobalFilter
* @desctption 登录验证
* @author Administrator
* @create 2023/5/15 14:17
**/@ComponentpublicclassGatewayWebFilterimplementsGlobalFilter{@ResourceprivateAuthService authService;@Bean@ConditionalOnMissingBeanpublicHttpMessageConvertersmessageConverters(ObjectProvider<HttpMessageConverter<?>> converters){returnnewHttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));}@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){ServerHttpRequest request = exchange.getRequest();//如果登录请求,不用验证tokenString path = request.getURI().getPath();if(!path.contains("login")){HttpHeaders headers = request.getHeaders();String token = headers.getFirst("token");if(StringUtils.isEmpty(token)){ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}else{TokenDTO tokenDTO =newTokenDTO();
tokenDTO.setToken(token);//token验证不通过,返回给前端401Boolean aBoolean = authService.validateToken(tokenDTO);if(aBoolean){ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}}}return chain.filter(exchange);}}
4.3、构建微服务鉴权子工程store-authority-service
4.4、构建微服务提供服务方子工程store-user-service
4.5、构建微服务调用方子工程store-api
小结
通过上述操作可以轻松搭建出微服务架构,扩展十分容易。
父子工程构建已可用,持续更新中…
版权归原作者 青花锁 所有, 如有侵权,请联系我们删除。