> 技术文档 > 【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务


1. 什么是网关

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

2. 网关路由——快速入门

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

server: port: 8080spring: application: name: gateway cloud: nacos: server-addr: 192.168.10.100:8848 gateway: routes: - id: item # 路由规则id,自定义,唯一 uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表 predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务 - Path=/items/**,/search/** # 这里是以请求路径作为判断规则 - id: cart uri: lb://cart-service predicates: - Path=/carts/** - id: user uri: lb://user-service predicates: - Path=/users/**,/addresses/** - id: trade uri: lb://trade-service predicates: - Path=/orders/** - id: pay uri: lb://pay-service predicates: - Path=/pay-orders/**

需要干的两件事,第一把商品的searchcontroller复制到item服务里面去。这里我不用之前的8858了,因为不知道为啥连接不上,就用我之前自己配的nacos了。

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
前后端联调也没问题-正常登录

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

3. 网关路由——路由属性

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
全局生效过滤器:

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

4. 网关登录校验——思路分析

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

4. 网关登录校验——自定义GlobalFilter

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

@Componentpublic class MyGlobalFilter implements GlobalFilter, Ordered{ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //TODO 模拟登录校验的逻辑 ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); System.out.println(\"headers = \" + headers); // 放行 return chain.filter(exchange); } @Override public int getOrder() { return 0; }}

5. 网关登录校验——自定义GatewayFilter

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

@Componentpublic class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> { @Override public GatewayFilter apply(Config config) { return new OrderedGatewayFilter(new GatewayFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取config值 String a = config.getA(); String b = config.getB(); String c = config.getC(); // 编写过滤器逻辑 System.out.println(\"a = \" + a); System.out.println(\"b = \" + b); System.out.println(\"c = \" + c); // 放行 return chain.filter(exchange); } },1); } // 自定义配置属性,成员变量名称很重要,下面会用到 @Data static class Config{ private String a; private String b; private String c; } // 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取 @Override public List<String> shortcutFieldOrder() { return List.of(\"a\", \"b\", \"c\"); } // 返回当前配置类的类型,也就是内部的Config @Override public Class<Config> getConfigClass() { return Config.class; }}

5. 网关登录校验——实现登录校验

@Component@RequiredArgsConstructor@EnableConfigurationProperties(AuthProperties.class)public class AuthGlobalFilter implements GlobalFilter, Ordered { private final JwtTool jwtTool; private final AuthProperties authProperties; private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1.获取Request ServerHttpRequest request = exchange.getRequest(); // 2.判断是否不需要拦截 if(isExclude(request.getPath().toString())){ // 无需拦截,直接放行 return chain.filter(exchange); } // 3.获取请求头中的token String token = null; List<String> headers = request.getHeaders().get(\"authorization\"); if (!CollUtils.isEmpty(headers)) { token = headers.get(0); } // 4.校验并解析token Long userId = null; try { userId = jwtTool.parseToken(token); } catch (UnauthorizedException e) { // 如果无效,拦截 ServerHttpResponse response = exchange.getResponse(); response.setRawStatusCode(401); return response.setComplete(); } // TODO 5.如果有效,传递用户信息 System.out.println(\"userId = \" + userId); // 6.放行 return chain.filter(exchange); } private boolean isExclude(String antPath) { for (String pathPattern : authProperties.getExcludePaths()) { if(antPathMatcher.match(pathPattern, antPath)){ return true; } } return false; } @Override public int getOrder() { return 0; }}

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

6. 网关登录校验——网关传递用户到微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

 // TODO 5.如果有效,传递用户信息 System.out.println(\"userId = \" + userId); String userInfo = userId.toString(); ServerWebExchange swe = exchange.mutate() .request(builder -> builder.header(\"user-info\", userInfo)) .build(); // 6.放行 return chain.filter(swe);

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

public class UserInfoInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.获取请求头中的用户信息 String userInfo = request.getHeader(\"user-info\"); // 2.判断是否为空 if (StrUtil.isNotBlank(userInfo)) { // 不为空,保存到ThreadLocal UserContext.setUser(Long.valueOf(userInfo)); } // 3.放行 return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 移除用户 UserContext.removeUser(); }}
@Configuration@ConditionalOnClass(DispatcherServlet.class)public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new UserInfoInterceptor()); }}

不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是com.hmall.common.config,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。
基于SpringBoot的自动装配原理,我们要将其添加到resources目录下的META-INF/spring.factories文件中:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\ com.hmall.common.config.MyBatisConfig,\\ com.hmall.common.config.MvcConfig,\\ com.hmall.common.config.JsonConfig
 @Override public List<CartVO> queryMyCarts() { // 1.查询我的购物车列表 List<Cart> carts = lambdaQuery().eq(Cart::getUserId, UserContext.getUser()).list();// List carts = lambdaQuery().eq(Cart::getUserId, 1L).list(); if (CollUtils.isEmpty(carts)) { return CollUtils.emptyList(); } // 2.转换VO List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class); // 3.处理VO中的商品信息 handleCartItems(vos); // 4.返回 return vos; }

分别用jack和rose登录效果:
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

7. 网关登录校验——openfeign传递用户信息

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

public class DefaultFeignConfig { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.FULL; } @Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor() { @Override public void apply(RequestTemplate template) { // 获取登录用户 Long userId = UserContext.getUser(); if(userId == null) {  // 如果为空则直接跳过  return; } // 如果不为空则放入请求头中,传递给下游微服务 template.header(\"user-info\", userId.toString()); } }; }}

提交订单会删除rose对应为2用户的购物车:
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

8. 配置管理——什么是配置管理

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

9. 配置管理——共享配置

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

shared-jdbc.yaml

spring: datasource: url: jdbc:mysql://${hm.db.host:192.168.150.101}:${hm.db.port:3306}/${hm.db.database}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver username: ${hm.db.un:root} password: ${hm.db.pw:123}mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler global-config: db-config: update-strategy: not_null id-type: auto

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

shared-log.yaml

logging: level: com.hmall: debug pattern: dateformat: HH:mm:ss:SSS file: path: \"logs/${spring.application.name}\"

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

shared-swagger.yaml

knife4j: enable: true openapi: title: ${hm.swagger.title:黑马商城接口文档} description: ${hm.swagger.description:黑马商城接口文档} email: ${hm.swagger.email:zhanghuyi@itcast.cn} concat: ${hm.swagger.concat:虎哥} url: https://www.itcast.cn version: v1.0.0 group: default: group-name: default api-rule: package api-rule-resources: - ${hm.swagger.package}

配置文件里面

hm: db: database: hm-cart

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

  <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-bootstrap</artifactId> </dependency>

在cart-service中的resources目录新建一个bootstrap.yaml文件:

spring: application: name: cart-service # 服务名称 profiles: active: dev cloud: nacos: server-addr: 192.168.10.100:8848 # nacos地址 config: file-extension: yaml # 文件后缀名 shared-configs: # 共享配置 - dataId: shared-jdbc.yaml # 共享mybatis配置 - dataId: shared-log.yaml # 共享日志配置 - dataId: shared-swagger.yaml # 共享日志配置

cart模块的yaml文件修改后:

server: port: 8082feign: okhttp: enabled: true # 开启OKHttp功能hm: db: database: hm-cart swagger: title: \"黑马商城购物车服务接口文档\" package: com.hmall.cart.controller

9. 配置管理——配置热更新

【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务
【黑马SpringCloud微服务开发与实战】(四)微服务02_黑马微服务

@Data@Component@ConfigurationProperties(prefix = \"hm.cart\")public class CartProperties { private Integer maxAmount;}
 private void checkCartsFull(Long userId) { int count = lambdaQuery().eq(Cart::getUserId, userId).count(); if (count >= cartProperties.getMaxAmount()) { throw new BizIllegalException(StrUtil.format(\"用户购物车课程不能超过{}\", 10)); } }

配置nacos

cart-service.yaml

hm: cart: maxAmount: 10 # 购物车商品数量上限

还有一节后面补充吧,电脑有点卡。。。。。。刷算法去