当前位置: 首页 > news >正文

黑马商城(四)网关

一、网关介绍

二、快速入门

路由规则配置:

package com.hmall.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}
server:port: 8080
spring:application:name: gatewaycloud:nacos:discovery:server-addr: 192.168.50.129:8848gateway:routes:- id: item-serviceuri: lb://item-servicepredicates:- Path=/items/**,/search/** #多controller情况- id: user-serviceuri: lb://user-servicepredicates:- Path=/users/**,/addresses/** #多controller情况- id: trade-serviceuri: lb://trade-servicepredicates:- Path=/orders/**- id: cart-serviceuri: lb://cart-servicepredicates:- Path=/carts/** #多controller情况

三、路由属性 

路由断言:

路由过滤器:

想要在其他路由中同样生效(全局过滤器)

四、网关登录校验

自定义过滤器:

GlobalFilter:

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic 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);}@Overridepublic int getOrder() {//设置过滤器的优先级return 0;}
}

GatewayFilter:

package com.hmall.gateway.filters;import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {@Overridepublic GatewayFilter apply(Object config) {
/*        //匿名内部类return new GatewayFilter() {//匿名内部类无法实现Ordered接口 来实现设置优先级@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("print any filter running");return chain.filter(exchange);}};*///能够实现Ordered接口的装饰类 --OrderedGatewayFilter return new OrderedGatewayFilter(new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("print any filter running");return chain.filter(exchange);}},1);}
}
server:port: 8080
spring:application:name: gatewaycloud:nacos:discovery:server-addr: 192.168.50.129:8848gateway:routes:- id: item-serviceuri: lb://item-servicepredicates:- Path=/items/**,/search/** #多controller情况- id: user-serviceuri: lb://user-servicepredicates:- Path=/users/**,/addresses/** #多controller情况- id: trade-serviceuri: lb://trade-servicepredicates:- Path=/orders/**- id: cart-serviceuri: lb://cart-servicepredicates:- Path=/carts/** - id: pay-serviceuri: lb://pay-servicepredicates:- Path=/pay-orders/** default-filters:- PrintAny

实现登录校验:

package com.hmall.gateway.filters;import com.hmall.common.exception.UnauthorizedException;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
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.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.List;@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {private final AuthProperties authProperties; //构造函数注入private final JwtTool jwtTool;private final AntPathMatcher antPathMatcher=new AntPathMatcher();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取用户信息--requestServerHttpRequest request = exchange.getRequest();//2.判断是否需要登录拦截if(isExclude(request.getPath().toString())){//是排除路径中 --放行return chain.filter(exchange);}//3.获取token/* HttpHeaders headers = request.getHeaders();*/String token= null;List<String> headers = (List<String>) request.getHeaders().get("authorization");if(headers!=null && !headers.isEmpty()){token =headers.get(0);}//4.校验并解析tokenLong userId=null;try {userId = jwtTool.parseToken(token);} catch (UnauthorizedException e) {//拦截 设置响应状态码401ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//TODO 5.传递用户信息System.out.println("userId = "+userId);//6.放行return chain.filter(exchange);}private boolean isExclude(String path) {for (String pathPattern : authProperties.getExcludePaths()){if(antPathMatcher.match(pathPattern,path)){//如果匹配上了return true;}}return false;}@Overridepublic int getOrder() {return 0;}
}

网关传递用户:

package com.hmall.common.interceptors;import cn.hutool.core.util.StrUtil;
import com.hmall.common.utils.UserContext;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class UserInfoInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.获取用户信息String userInfo = request.getHeader("user-info");//2.判断是否获取了用户,如果有,存入ThreadLocalif(StrUtil.isNotBlank(userInfo)){//不为空--存储信息到ThreadLocal中UserContext.setUser(Long.valueOf(userInfo));}//3.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//清理用户UserContext.removeUser();}
}
package com.hmall.common.config;import com.hmall.common.interceptors.UserInfoInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@ConditionalOnClass(DispatcherServlet.class) 
//网关同样引用了hmall-common 而网关模块并不是基于springmvc导致报错
//通过SpringBoot自动装配的条件注解 来防止在网关中自动装配导致报错
public class MvcConfig implements WebMvcConfigurer {//拦截器的注册器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserInfoInterceptor());}
}

通过SpringBoot自动装配的原理将该配置类放到factories文件中实现自动装配(底层会读取该文件对文件中路径的类进行自动装配) 拦截器并没有注册成Bean而是在配置文件中直接new,区别:

OpenFeign传递用户: 

用户之间传递通过OpenFeign实现,OpenFeign内置了一个拦截器接口用于拦截各种请求,并对请求进行处理,可以将用户之间的请求拦截,并添加请求头依次来传递用户信息。

package com.hmall.api.config;import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {Long userId = UserContext.getUser();if(userId!=null) {requestTemplate.header("user-info", userId.toString());}}};}
}

五、配置管理

Nacos集成了配置管理服务的功能

配置共享:

配置热更新:

案例-实现购物车添加商品上限的配置热更新:

package com.hmall.cart.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@ConfigurationProperties(prefix = "hm.cart")
@Component //注册成bean才能让配置文件生效
@Data
public class CartProperties {private Integer maxItems;
}

动态路由:

NacosConfigManager是依赖中创建好的bean,已经实现了getConfigService方法

因此直接注入即可

 


 

新增依赖:

 

 

package com.hmall.gateway.routers;import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {private final NacosConfigManager nacosConfigManager;private final RouteDefinitionWriter routeDefinitionWriter;private final Set<String> routeIds = new HashSet<>();  //保存每次更新后的routeIdprivate final String dataId ="gateway-routes.json";private final String group ="DEFAULT_GROUP";@PostConstruct//在 DynamicRouteLoader 这个bean初始化之后执行public void initRouteConfigListener() throws NacosException {//1.项目启动,先拉取一次配置,并且添加配置监听器String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {//2.监听到配置更新,需要去更新路由表updateConfigInfo(configInfo);}});//3.第一次读取到配置表,也需要更新到路由表updateConfigInfo(configInfo);}public void updateConfigInfo(String configInfo){log.debug("监听到路由配置信息: {}",configInfo);// 1 解析配置信息,转化为RouteDefinition类型List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);// 2 删除旧的路由表for (String routeId : routeIds) {routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();}routeIds.clear(); //清空id表// 3 更新路由表for (RouteDefinition routeDefinition : routeDefinitions) {//3.1 更新路由表routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();//3.2 记录路由id,便于下一次更新删除routeIds.add(routeDefinition.getId());}}
}

bootstrap.yaml文件 

spring:application:name: gateway-service #微服务名称profiles:active: devcloud:nacos:discovery:server-addr: 192.168.50.129:8848config:server-addr: 192.168.50.129:8848file-extension: yamlshared-configs:- data-id: shared-log.yaml

相关文章:

  • velocity模板引擎
  • C语言用if else求三个数最小值的一题多解
  • 页内碎片和页外碎片的区别
  • 第十届团体程序设计天梯赛-上理赛点随笔
  • @Validated与@Valid的正确使用姿势
  • Python制作简易PDF查看工具PDFViewerV1.0显示优化
  • 【生态与未来】立足原生仓颉:Cangjie Magic 的生态位与未来发展潜力分析
  • 基于 GPT-SoVITS 实现个性化语音复刻的API服务调用:让小说朗读拥有专属声线
  • 静态成员相关知识
  • AOSP的Doze模式-LightIdle初识
  • 测试基础笔记第六天
  • 『Linux_网络』 第二章 UDP_Socket编程
  • 从《周游记3》演绎歌剧版《菊花台》,周杰伦婚礼曲目意大利文版惊喜亮相
  • docker 搭建nacos 2.2.1版本单机版
  • 下一代互联网
  • java怎么完善注册,如果邮箱中途更换,能否判断
  • 2025/4/19 数据库的流程控制函数
  • Redis客户端下载使用
  • 【操作系统原理01】操作系统引论
  • Mysql从入门到上手(二)-全面了解增删改查(CRUD).
  • 广东音像城清退,发烧友紧急“淘宝”,曾见证广州音乐黄金期
  • 市民建议公交广播增加“请勿大声喧哗”提示,上海交通委回复
  • 特朗普就防卫负担施压日本,石破茂:防卫费应由我们自主决定
  • 观察|药企竞逐千亿抗癌药赛道,AI有多大助力?
  • 习近平会见柬埔寨太后莫尼列
  • 《素食者》的植物隐喻仍暗含“肉食”逻辑