仿12306系统学习
学习路线
12306 铁路购票系统学习总体分为三块:组件库开发、业务梳理以及业务系统开发。
组件库开发
组件库的产出源于对公共功能的封装,避免了在不同项目之间相互复制代码的情况。当然,如果这种复制代码的方式出现问题,那么需要同时对所有项目进行改造,从成本和优雅设计的角度来看并不可取。
为了统一各个项目可能使用的公共内容,我们在这里规划了常用且通用的功能点,供大家使用,以提高编码效率。如果有一些好的想法,在通用的前提下,可以联系我们将其加入到各自语义的起始包中。
组件库的开发宗旨是汇总资源,更高效地提供业务敏捷开发的能力,后续的迭代也将遵循这一原则。目前,这只是一个起点,是整体规划的一部分,还有许多可以提升的空间。
目前已有组件如下,可能新增加的组件更新不及时,实际以代码库 /frameworks
目录下为准。
业务梳理
在 12306 铁路购票系统中,包括会员、购票、订单、支付以及网关服务。
GatewayServiceApplication<网关服务>
自定义局部过滤器
/**
* SpringCloud Gateway Token 拦截器
*
* @公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
*/
@Component
public class TokenValidateGatewayFilterFactory extends AbstractGatewayFilterFactory<Config> {
public TokenValidateGatewayFilterFactory() {
super(Config.class);
}
/**
* 注销用户时需要传递 Token
*/
public static final String DELETION_PATH = "/api/user-service/deletion";
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String requestPath = request.getPath().toString();
if (isPathInBlackPreList(requestPath, config.getBlackPathPre())) {
String token = request.getHeaders().getFirst("Authorization");
// TODO 需要验证 Token 是否有效,有可能用户注销了账户,但是 Token 有效期还未过
UserInfoDTO userInfo = JWTUtil.parseJwtToken(token);
if (!validateToken(userInfo)) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
ServerHttpRequest.Builder builder = exchange.getRequest().mutate().headers(httpHeaders -> {
httpHeaders.set(UserConstant.USER_ID_KEY, userInfo.getUserId());
httpHeaders.set(UserConstant.USER_NAME_KEY, userInfo.getUsername());
httpHeaders.set(UserConstant.REAL_NAME_KEY, URLEncoder.encode(userInfo.getRealName(), StandardCharsets.UTF_8));
if (Objects.equals(requestPath, DELETION_PATH)) {
httpHeaders.set(UserConstant.USER_TOKEN_KEY, token);
}
});
return chain.filter(exchange.mutate().request(builder.build()).build());
}
return chain.filter(exchange);
};
}
private boolean isPathInBlackPreList(String requestPath, List<String> blackPathPre) {
if (CollectionUtils.isEmpty(blackPathPre)) {
return false;
}
return blackPathPre.stream().anyMatch(requestPath::startsWith);
}
private boolean validateToken(UserInfoDTO userInfo) {
return userInfo != null;
}
}
Gateway 分类:局部过滤器和全局过滤器。
- 局部过滤器(GatewayFilter):应用到单个路由或者一个分组的路由上。
- 全局过滤器(GlobalFilter):应用到所有的路由上。