提交 ce709e9c authored 作者: lvbencai's avatar lvbencai

合并分支 'qa' 到 'master'

增加18:15任务和pos任务,增加导出多维表格三列 查看合并请求 !6
......@@ -5,13 +5,13 @@
<parent>
<groupId>com.wangxiaolu</groupId>
<artifactId>wangxiaolu-promotion-parent</artifactId>
<version>0.0.3</version>
<version>0.0.4</version>
</parent>
<groupId>com.wangxiaolu</groupId>
<artifactId>wangxiaolu-promotion-gateway</artifactId>
<version>0.2.0</version>
<version>0.2.1</version>
<packaging>jar</packaging>
<name>wangxiaolu-promotion-gateway</name>
......@@ -19,11 +19,13 @@
<dependencies>
<dependency>
<groupId>com.wangxiaolu</groupId>
<artifactId>wangxiaolu-promotion-common</artifactId>
<version>0.0.3</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.wangxiaolu</groupId>-->
<!-- <artifactId>wangxiaolu-promotion-common</artifactId>-->
<!-- <version>0.0.3</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
......@@ -82,10 +84,10 @@
</dependency>
<!-- Web 场景启动器) 来为 Web 开发予以支持。spring-boot-starter-web 为我们提供了嵌入的 Servlet 容器以及 SpringMVC 的依赖,并为 Spring MVC 提供了大量自动配置,可以适用于大多数 Web 开发场景。-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
......@@ -190,6 +192,12 @@
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core -->
<dependency>
......@@ -215,6 +223,14 @@
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
......@@ -226,8 +242,19 @@
<artifactId>bcpkix-jdk15on</artifactId>
<groupId>org.bouncycastle</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- Maven 示例:排除 Tomcat,引入 Netty -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-webflux</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</dependency>
<!-- gateway 负载均衡-->
<dependency>
......
package com.promotion.gateway;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* @author John
* @date 2022/6/27
* @description 跨域配置
*/
@Configuration
public class CorsConfig {
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
HttpHeaders requestHeaders = request.getHeaders();
ServerHttpResponse response = ctx.getResponse();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
\ No newline at end of file
package com.promotion.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* @author John
* @date 2022/6/27
* @description 跨域配置
*/
@Configuration
public class CorsConfig {
// @Bean
// public WebFilter corsFilter() {
// return (ServerWebExchange ctx, WebFilterChain chain) -> {
// ServerHttpRequest request = ctx.getRequest();
// if (CorsUtils.isCorsRequest(request)) {
// HttpHeaders requestHeaders = request.getHeaders();
// ServerHttpResponse response = ctx.getResponse();
// HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
// HttpHeaders headers = response.getHeaders();
// headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
// headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
// requestHeaders.getAccessControlRequestHeaders());
// if (requestMethod != null) {
// headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
// }
// headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
// headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
// if (request.getMethod() == HttpMethod.OPTIONS) {
// response.setStatusCode(HttpStatus.OK);
// return Mono.empty();
// }
// }
// return chain.filter(ctx);
// };
// }
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 允许的域名(生产环境指定具体域名)
config.addAllowedMethod("*"); // 允许的方法
config.addAllowedHeader("*"); // 允许的请求头
config.setAllowCredentials(true); // 允许携带Cookie
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config); // 应用到所有路径
return new CorsWebFilter(source);
}
}
package com.wangxiaolu.promotion.result.basedata;
import com.promotion.gateway.constant.RCode;
import com.promotion.gateway.constant.StatusCode;
import lombok.Data;
/**
* @author : liqiulin
* @date : 2024-03-28 17
* @describe : 统一响应VO
*/
@Data
public class R {
/**
* 响应码
* 非0失败
*/
private int code;
/**
* 提示信息
*/
private String msg;
/**
* 返回对象
*/
private Object data;
/**
* 默认成功
*/
public R(Object data) {
this.code = RCode.SUCCESS.getCode();
this.msg = RCode.SUCCESS.getMsg();
this.data = data;
}
/**
* 默认成功
*/
public R() {
this.code = RCode.SUCCESS.getCode();
this.msg = RCode.SUCCESS.getMsg();
this.data = null;
}
/**
* 无数据返回
*/
public R(StatusCode statusCode) {
this.code = statusCode.getCode();
this.msg = statusCode.getMsg();
this.data = null;
}
/**
* 手动配置code、msg
*/
public R(Integer code, String msg) {
this.code = code;
this.msg = msg;
this.data = null;
}
/**
* 指定状态
*/
public R(StatusCode statusCode, Object data) {
this.code = statusCode.getCode();
this.msg = statusCode.getMsg();
this.data = data;
}
/**
* 手动设置
*/
public R(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static R success(Object data) {
return new R(data);
}
public static R success() {
return new R();
}
public static R fail() {
return new R(RCode.FAILED,null);
}
public static R fail(Object data) {
return new R(RCode.FAILED,data);
}
public static R fail(StatusCode statusCode) {
return new R(statusCode);
}
}
package com.promotion.gateway.constant;
import lombok.Data;
import lombok.Getter;
import lombok.ToString;
/**
* @author : liqiulin
* @date : 2024-03-28 17
* @describe : 返回状态编码
*/
@Getter
public enum RCode implements StatusCode{
/**
* 程序统一编码(不分模块)
* 1000+
*/
SUCCESS(0, "请求成功"),
FAILED(1001, "请求失败"),
PARAM_ERROR(1002, "参数错误"),
RESPONSE_PACK_ERROR(1003, "包装R失败"),
SELECT_PARAMS_ERROR(1004, "查询条件错误"),
REDIS_PUSH_DATA_NOT_EXIT(1005, "数据已过期或不存在,请重新上传;"),
/**
* 业务统一编码(不分模块)
* 2000+
*/
API_ERROR(2000, "业务异常"),
API_DATA_ERROR(2001, "业务数据异常"),
DATA_HAVE_ERROR(2002, "数据已存在,不可新增"),
STATUS_UPDATE_ERROR(2003, "当前状态不可修改"),
DATA_NOT_HAVE_ERROR(2004, "数据不存在"),
DATA_TOO_MANY_ERROR(2005, "唯一数据存在多条"),
READ_EXCEL_NULL_ERROR(2006, "表格为空或格式错误,请上传正确的文件"),
READ_FILE_PATH_NULL_ERROR(2007, "文件读取失败,未获取到有效地址"),
EXCEL_IS_XLS_OR_XLSX_FILE(2008, "请上传xls或xlsx表格文件"),
NEED_PARAM_ERROR(2009, "请指定需要操作的数据"),
/**
* user
* 3000+
*/
LOGIN_PARAM_ERROR(3000, "登录信息错误"),
ENROLL_PARAM_ERROR(3001, "注册信息错误"),
PHONE_PARAM_ERROR(3002, "手机号异常"),
USER_PHONE_UNIQUE_ERROR(3003, "手机号已注册"),
LOGIN_USER_IS_NULL_ERROR(3004, "账号未注册"),
CLOCK_DETAIL_ERROR(3005, "打卡信息错误"),
CLOCK_DETAIL_TIME_ERROR(3006, "不在打卡时间范围内"),
CHARGER_ID_ERROR(3007, "未找到战区或战区负责人"),
NOT_LOGIN_ERROR(3008, "您尚未登录"),
LOGIN_PASSWORD_ERROR(3009, "密码错误"),
USER_REPETITIVE_CLOCK_MINUTE(3010, "%s分钟内请勿重复打卡"),
IDEN_NUMBER_PARAM_ERROR(3011, "身份证号码错误"),
WX_OPENID_PARAM_ERROR(3012, "微信登录错误,请退出小程序重新登录"),
NOT_AVATAR_URL_PARAM_ERROR(3013, "请上传头像"),
NOT_USER_NAME_PARAM_ERROR(3014, "姓名不可为空"),
USER_WXOPENID_UNIQUE_ERROR(3015, "已使用其他手机号注册"),
LOGIN_PHONE_PARAM_ERROR(3016, "手机号错误"),
NOT_LOGIN_TIMEOUT_ERROR(3017, "您的登录已过期,请重新登录"),
EMP_PRIVILEGE_ERROR(3018, "账号权限错误"),
QC_USER_IS_NULL_ERROR(3019, "账号未在勤策中找到"),
/**
* promotion-模块异常
* 4000+
*/
PRO_NOT_QC_STORE_CLOCK_DISTANCE(4000,"打卡店铺距离偏差过大"),
PRO_FAR_QC_STORE_CLOCK_DISTANCE(4001,"请在距离店铺100米内打卡"),
SEND_BACK_REASON_NOT(4002,"请描述退回原因"),
APPROVE_STATUS_REPETITION(4003,"审批状态不可重复"),
MARKET_NUMBER_NOT_ERROR(4004,"数量不可为0"),
PRODUCT_CLASS_NOT_ERROR(4005,"商品类型不可为空"),
PRODUCT_CLASS_HAS_ERROR(4006,"商品类型已存在,不可新增"),
PROMOTION_STORE_SAVE_ERROR(4007, "%s分钟内请勿重复提交"),
PROMOTION_STORE_HAS_NAME(4008, "店铺名称重复,请修改"),
UPDATE_CLOCK_PHOTO_TIME_LONG_ERROR(4009, "距离打卡已超过30分钟,照片不可更改"),
PHOTO_IS_NULL_ERROR(4010, "打卡照片不可更改"),
BAR_CODE_IS_ERROR(4011, "识别异常,请手动选择商品"),
NOT_ADDRESS_ERROR(4012, "请刷新当前位置"),
NOT_CLOCK_PHOTO_ERROR(4013, "请上传打卡图片"),
NOT_CLOCK_ACTIVITY_PATTERN_ERROR(4014, "请选择活动模式"),
NOT_CLOCK_STORE_ERROR(4015, "请选择店铺"),
NOT_TGSH_PHOTO_ERROR(4016, "推广试吃照片数量过少"),
NOT_TGHD_PHOTO_ERROR(4017, "推广互动照片数量过少"),
NOT_TGCJ_PHOTO_ERROR(4018, "推广成交照片数量过少"),
NOT_POS_PHOTO_ERROR(4019, "POS机凭证照片未上传"),
NOT_MARKET_CELL_ERROR(4020, "商品出售记录未添加"),
ACTIVITY_DATA_NOT_HAVE_ERROR(4021, "售卖记录不存在"),
CLOCK_DATA_NOT_HAVE_ERROR(4022, "打卡记录不存在"),
QINCE_STORE_CODE_ERROR(4023, "编码或店名错误,请与勤策保持一致"),
QINCE_STORE_DEALER_ID_ERROR(4024, "经销商错误,请与勤策保持一致"),
LOGIN_PHONE_COUNT_MUCH(4025, "获取手机号超过5次,请手动填写"),
QINCE_STORE_DEALER_ERROR(4026, "所属经销商与修改前不一致,请重新选择"),
ACTIVITY_PLAN_DATETIME_ERROR(4027, "时间错误,正确规则:上班时间<午休下班时间<午休上班时间<下班时间;"),
/**
* manage-模块异常
* 5000+
*/
ACTIVITY_PLAN_MONTH_HAS(5000,"本月活动计划已上传,请删除后再次上传"),
ACTIVITY_PLAN_FILENAME_LONG(5001,"文件名过长,请少于20个字"),
ACTIVITY_PLAN_CELL_NOT_NULL(5002,"第%s行有空值,请改正后再次提交;"),
ACTIVITY_PLAN_TEM_ERROR(5003,"模板错误,请使用模板4.0;"),
ACTIVITY_PLAN_REPETITION_ERROR(5004,"活动计划列表中,有日期重复的计划;"),
ACTIVITY_PLAN_NOT_SELF_DELETE(5005,"以前计划/非归属本人计划,不可删除;"),
ACTIVITY_PLAN_NOT_DELETE(5005,"不可修改今日及以前活动;"),
ACTIVITY_PLAN_EXECUTE_ERROR(5006,"门店系统名称、经销商不可为空,请到勤策中修改;"),
ACTIVITY_PLAN_EMPLOYEE_ERROR(5007,"计划归属人只能是城市经理;"),
ACTIVITY_PLAN_IS_NULL(5008,"促销计划不存在;"),
ACTIVITY_NOT_START(5009,"计划未开始;"),
NEXT_MONTH_PLAN_CREATE_ERROR(5010, "只可创建次月计划;"),
ACTIVITY_PLAN_EMPLOYEE_CREATE(5011, "只能创建自己的计划;"),
FUNCTION_RESTRICT_ERROR(5012, "功能受限,请联系管理员;"),
ACTIVITY_IS_START(5013,"计划已被促销员执行;"),
ACTIVITY_ID_IS_START(5014,"「%s」号计划已被促销员执行;"),
ACTIVITY_PLAN_ID_NOT_DELETE(5015,"「%s」号已超上班时间1小时,不可修改;"),
ACTIVITY_PLAN_DATA_ERROR(5016,"活动日期必需是次日 至 月底"),
/**
* 腾讯云
* 3500+
*/
TENCENT_SMS_ERROR(3500, "短信发送失败"),
TENCENT_SMS_REPETITION(3501, "短信已发送"),
TENCENT_SMS_PHONE_CODE_ERROR(3502, "验证码错误"),
;
private int code;
private String msg;
RCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
package com.promotion.gateway.constant;
/**
* @author : liqiulin
* @date : 2024-03-28 17
* @describe :返回状态编码
*/
public interface StatusCode {
int getCode();
String getMsg();
}
package com.promotion.gateway.constant;
/**
* Token的Key常量
*
* @author ruoyi
*/
public class TokenConstants
{
/**
* 令牌自定义标识
*/
public static final String AUTHENTICATION = "Authorization";
/**
* 令牌前缀
*/
public static final String PREFIX = "Bearer ";
/**
* 令牌秘钥
*/
public final static String SECRET = "abcdefghijklmnopqrstuvwxyz";
/**
* 用户ID字段
*/
public static final String DETAILS_USER_ID = "user_id";
/**
* 用户名字段
*/
public static final String DETAILS_USERNAME = "username";
/**
* 用户标识
*/
public static final String USER_KEY = "user_key";
}
......@@ -2,7 +2,7 @@ package com.promotion.gateway.data.impl;
import com.alibaba.fastjson.JSONObject;
import com.promotion.gateway.data.UserDataService;
import com.wangxiaolu.promotion.common.redis.RedisKeys;
import com.promotion.gateway.domain.UserKeys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
......@@ -30,8 +30,8 @@ public class UserDataServiceImpl implements UserDataService {
@Override
public boolean hasKeyToken(String tokenKey) {
Boolean wb = redisTemplate.hasKey(RedisKeys.UserKeys.WXL_LINK_TOKEN.getKey() + tokenKey);
Boolean tb = redisTemplate.hasKey(RedisKeys.UserKeys.TEMPORARY_TOKEN.getKey() + tokenKey);
Boolean wb = redisTemplate.hasKey(UserKeys.WXL_LINK_TOKEN.getKey() + tokenKey);
Boolean tb = redisTemplate.hasKey(UserKeys.TEMPORARY_TOKEN.getKey() + tokenKey);
return wb || tb;
}
}
package com.promotion.gateway.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum UserKeys {
/**
* 用户接收手机验证码
*/
PHONE_VER_CODE("user:phone_code:phone_"),
/**
* 促销员小程序用户登录信息:token
*/
TEMPORARY_TOKEN("user:login_token:temporary:"),
WXL_LINK_TOKEN("login_tokens:"),
/**
* 组织数据 - 客户类数据 - 经销商
*/
DEALER_HAVE_LIST("user:clientele:dealer_all"),
;
String key;
}
......@@ -2,11 +2,11 @@ package com.promotion.gateway.filter;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.gson.Gson;
import com.promotion.gateway.util.JwtTokenUtils;
import com.promotion.gateway.constant.RCode;
import com.promotion.gateway.constant.StatusCode;
import com.promotion.gateway.data.UserDataService;
import com.wangxiaolu.promotion.common.util.JwtTokenUtils;
import com.wangxiaolu.promotion.result.basedata.R;
import com.wangxiaolu.promotion.result.basedata.RCode;
import com.wangxiaolu.promotion.result.basedata.StatusCode;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -56,7 +56,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
// 2、未登录请求跳转登录
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(token)) {
return loginError(exchange,RCode.NOT_LOGIN_ERROR);
return loginError(exchange, RCode.NOT_LOGIN_ERROR);
}
// 3、验证token
......@@ -75,6 +75,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
String username = JwtTokenUtils.getUserName(claims);
if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
{
log.error("鉴权失败,登录已过期:"+token);
return loginError(exchange,RCode.NOT_LOGIN_TIMEOUT_ERROR);
}
......@@ -95,4 +96,13 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
return response.writeWith(Flux.just(buffer));
}
// private Mono<Void> loginError(ServerWebExchange exchange, RCode statusCode) {
// ServerHttpResponse response = exchange.getResponse();
// response.setStatusCode(HttpStatus.OK);
// response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
// R res = new R(statusCode);
// DataBuffer buffer = response.bufferFactory().wrap(new Gson().toJson(res).getBytes(StandardCharsets.UTF_8));
// return response.writeWith(Flux.just(buffer));
// }
}
package com.promotion.gateway.util;
import com.promotion.gateway.constant.TokenConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Map;
/**
* @author : liqiulin
* @date : 2024-04-16 17
* @describe : java web token
*/
public class JwtTokenUtils {
private static String secret = TokenConstants.SECRET;
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
public static Claims parseToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
public static String createToken(Map<String, Object> claims)
{
String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 根据令牌获取用户标识
*
* @param claims 身份信息
* @return 用户ID
*/
public static String getUserKey(Claims claims) {
return getValue(claims, TokenConstants.USER_KEY);
}
/**
* 根据身份信息获取用户ID
*
* @param claims 身份信息
* @return 用户ID
*/
public static String getUserId(Claims claims) {
return getValue(claims, TokenConstants.DETAILS_USER_ID);
}
/**
* 根据身份信息获取用户名
*
* @param claims 身份信息
* @return 用户名
*/
public static String getUserName(Claims claims) {
return getValue(claims, TokenConstants.DETAILS_USERNAME);
}
/**
* 根据身份信息获取键值
*
* @param claims 身份信息
* @param key 键
* @return 值
*/
private static String getValue(Claims claims, String key) {
Object value = claims.get(key);
if (null == value) {
return "";
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}
}
......@@ -30,5 +30,21 @@ spring:
# uri: http://127.0.0.1:8011
predicates:
- Path=/**
# WebSocket 路由配置
- id: websocket_route
# 后端 WebSocket 服务的地址(lb:// 表示从注册中心发现服务,如 Nacos/Eureka)
# uri: lb://websocket-service # 服务名:websocket-service
# uri: lb://wangxiaolu-promotion-service
uri: lb://192.168.100.236:8011 # 服务名:websocket-service
# 匹配前端请求的路径(如前端连接 ws://gateway:8080/ws/123,会被转发)
predicates:
- Path=/ws/**
# 配置过滤器(可选,如路径重写)
filters:
# 将前端请求路径 /ws/{userId} 重写为后端服务的 /websocket/{userId}
- RewritePath=/ws/(?<segment>.*), /websocket/$\{segment}
# 关键:指定协议为 websocket(默认是 http,必须显式声明)
metadata:
protocol: websocket
logging:
config: classpath:logback-spring.xml
......@@ -30,5 +30,21 @@ spring:
# uri: http://127.0.0.1:8011
predicates:
- Path=/**
# WebSocket 路由配置
- id: websocket_route
# 后端 WebSocket 服务的地址(lb:// 表示从注册中心发现服务,如 Nacos/Eureka)
# uri: lb://websocket-service # 服务名:websocket-service
uri: lb://wangxiaolu-promotion-service
# 匹配前端请求的路径(如前端连接 ws://gateway:8080/ws/123,会被转发)
predicates:
- Path=/ws/**
# 配置过滤器(可选,如路径重写)
filters:
# 将前端请求路径 /ws/{userId} 重写为后端服务的 /websocket/{userId}
- RewritePath=/ws/(?<segment>.*), /websocket/$\{segment}
# 关键:指定协议为 websocket(默认是 http,必须显式声明)
metadata:
protocol: websocket
logging:
config: classpath:logback-spring.xml
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论