Java高级工程师
一切的业务开发都是基于需求的,首先看看需求:
核心代码,注释必读
//download:
3w ukoou com
</>复制代码
对访问网关的请求进行token校验,只有当token校验通过时,才转发到后端服务,否则直接返回401
本文给出的示例代码适用场景:
</>复制代码
token存放在redis中, key为用户的uid
依赖的pom.xml
</>复制代码
4.0.0
com.winture
api-gateway
0.0.1-SNAPSHOT
jar
api-gateway
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
Finchley.SR1
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
在Spring Cloud Gateway中,主要有两种类型的过滤器:GlobalFilter 和 GatewayFilter
GlobalFilter : 全局过滤器,对所有的路由均起作用
GatewayFilter : 只对指定的路由起作用
1、自定义GatewayFilter
自定义GatewayFilter又有两种实现方式,一种是直接 实现GatewayFilter接口,另一种是 继承AbstractGatewayFilterFactory类 ,任意选一种即可
1.1 实现GatewayFilter接口
</>复制代码
package com.winture.gateway.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
- token校验过滤器
- @Version V1.0
*/
public class AuthorizeGatewayFilter implements GatewayFilter, Ordered {
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
首先从header头信息中获取uid和token信息,如果token或者uid为null,则从请求参数中尝试再次获取,如果依然不存在token或者uid,则直接返回401状态吗,同时结束请求;如果两者都存在,则根据uid从redis中读取保存的authToken,并和请求中传输的token进行比对,比对一样则继续通过过滤器链,否则直接结束请求,返回401.
如何应用 AuthorizeGatewayFilter 呢?
</>复制代码
package com.winture.gateway;
import com.winture.gateway.filter.AuthorizeGatewayFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r ->
r.path("/user/list")
.uri("http://localhost:8077/api/user/list")
.filters(new AuthorizeGatewayFilter())
.id("user-service"))
.build();
}
}
1.2 继承AbstractGatewayFilterFactory类
</>复制代码
package com.winture.gateway.filter.factory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
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 java.util.Arrays;
import java.util.List;
@Component
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory {
private static final Log logger = LogFactory.getLog(AuthorizeGatewayFilterFactory.class);
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
public AuthorizeGatewayFilterFactory() {
super(Config.class);
logger.info("Loaded GatewayFilterFactory [Authorize]");
}
@Override
public List shortcutFieldOrder() {
return Arrays.asList("enabled");
}
@Override
public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) {
return (exchange, chain) -> {
if (!config.isEnabled()) {
return chain.filter(exchange);
}
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
};
}
public static class Config {
// 控制是否开启认证
private boolean enabled;
public Config() {}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}
如何应用 AuthorizeGatewayFilterFactory 呢?
</>复制代码
网关路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8077/api/user/list
predicates:
- Path=/user/list
filters:
关键在下面一句,值为true则开启认证,false则不开启
这种配置方式和spring cloud gateway内置的GatewayFilterFactory一致
- Authorize=true
上面的两种方式都可以实现对访问网关的 特定请求 进行token校验,如果想对 所有的请求 都进行token校验,那么可以采用实现 GlobalFilter 方式。
2、自定义GlobalFilter
package com.winture.gateway.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
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.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* token校验全局过滤器
* @Version V1.0
*/
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
private static final String AUTHORIZE_TOKEN = "token";
private static final String AUTHORIZE_UID = "uid";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(AUTHORIZE_TOKEN);
String uid = headers.getFirst(AUTHORIZE_UID);
if (token == null) {
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if (uid == null) {
uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
}
ServerHttpResponse response = exchange.getResponse();
if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String authToken = stringRedisTemplate.opsForValue().get(uid);
if (authToken == null || !authToken.equals(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
如何应用 AuthorizeFilter 呢?
只需要添加 @Component 注解,不需要进行任何额外的配置,实现GlobalFilter接口,自动会对所有的路由起作用
3、总结
由于刚接触Spring Cloud Gateway,有些地方也不是特别熟悉,上面的示例代码仅仅作为参考,如果有错误的地方,还望指正。
备注:
运行上面的代码,需要先启动redis服务,由于没有配置redis的地址和端口,默认采用localhost和6379端口,如果不一致,请自行在application.yml文件中配置即可;
网关的端口采用默认的8080;
慕课网Java高级工程师 - Java 工作2年后需要达到怎么样的技术水平
有人回答说这只能是大企业或者互联网企业的工程师才能拿到。也许是的,小公司或者非互联网企业拿两万的不太可能是码农了,应该是已经转管理后才有可能。还有区域问题,这个不在我的考虑范围内,因为除了北上广深杭,其他地方也很难。
还有人提到这个水平不止2w,其实工资是跟面试表现有关的,也跟其他综合水平有关,比如你是985,top10,或者研究生学历,也或者懂点node,Android等等的,或者表达能力强,击中面试官痛点肯定加分是吧。如果你达到我说的水准,我们谈的起薪就是2w,有其他优秀的表现我们在这个基础上加点。但纯JAVA方面待遇是比较吻合的,毕竟这几个企业我都待过或面试过。SSH真的不是我要黑,2w水平的面试几乎很少问SSH的知识,要问也是问架构层次的还有设计模式的。例如mybatis是如何管理session和cache的。spring里面有哪些你熟悉的设计模式,你怎么理解和应用的。
其实互联网相关的知识去互联网公司后很容易接触,并不是什么难点。如果你是在一线业务部门,我说的几个点几乎时时伴随着你,你完全不用担心自己不会。我司很多刚来的大学生在半年内都能把一些中间件系统摸的很明白,并不是说有多难,只是接触少,对未知的东西感到害怕疑惑而已。我在这里可以给那些想学习这方面的同学提供几本书,这几本书对互联网的知识能很快入门和了解全景。不是广告。
大型网站技术架构-核心原理与案例分析。@李智慧大牛的书
大型分布式网站架构-设计与实践。作者:陈康贤
大型网站系统与java中间件实践。作者: 曾宪杰(原淘宝技术,现在蘑菇街)
然后再推荐一个网站并发编程网 - ifeve.com。这个网站的知识绝对够你面试一个阿里P7,京东T3-2,腾讯T3-1。
好吧,我也不知道为什么都是推荐淘宝系的东西。巧合哦?!
这也是我最后一次更新答案,希望给那些需要这些信息的人帮助。那些质疑我的人去面试一下就明白我说的对不对,不要随便就质疑。如果有机会可以再开一题,来谈谈互联网的JAVA面试题,我可以把90%的题目全部给你列出来。还有那个京东的工程师也说这个技能树不止2W,可我想说的是京东的水平真的很一般,现在一直处于模仿抄袭阶段。那个saf就封装了一层dubbo,后面加了一个序列化协议就变成jsf了,用了别人的就用了,有这么不好意思吗?架构师的水平真的太差了,很多都是机器堆的,当然你们有钱。有的业务一半的机器就可以很好的满足现有巅峰的场景,东哥是被11年的事故搞怕了吗?我其实不怀疑我说的这些技能树能拿到25K或者30K的可能,但现在互联网这么泡沫,给自己一条踏实的路就那么难么?
首先两万的月薪在BAT实在太普遍了,一般是高级工程师和资深工程师的职位。在阿里是p6~p7左右,在百度是t5左右,腾讯是t2-3左右,京东是t3-1,美团是p6左右,其他的我不了解。这种级别是他们主要码农层级,加班多,能解决大部分问题,但对系统的整体架构能力和深入分析瓶颈的能力还需要培养。
其次掌握的技能树主要有三个方面:
第一个是基础。比如对集合类,并发包,IO/NIO,JVM,内存模型,泛型,异常,反射,等有深入了解,最好是看过源码了解底层的设计。比如一般面试都会问ConcurrentHashMap,CopyOnWrite,线程池,CAS,AQS,虚拟机优化等知识点,因为这些对互联网的企业是绝对重要的。而且一般人这关都过不了,还发闹骚说这些没什么用,为什么要面试
Java高级工程师 - SpringBoot&Cloud&Alibaba版本依赖兼
SpringCloudAlibaba依赖管理
Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本
RELEASE 版本
如果需要使用 Spring Cloud 2020 版本,请在 dependencyManagement 中添加如下内容:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
复制代码
Spring Cloud Hoxton
如果需要使用 Spring Cloud Hoxton 版本,请在 dependencyManagement 中添加如下内容
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
复制代码
Spring Cloud Greenwich
如果需要使用 Spring Cloud Greenwich 版本,请在 dependencyManagement 中添加如下内容
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
复制代码
Spring Cloud Finchley
如果需要使用 Spring Cloud Finchley 版本,请在 dependencyManagement 中添加如下内容
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.0.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
复制代码
Spring Cloud Edgware
如果需要使用 Spring Cloud Edgware 版本,请在 dependencyManagement 中添加如下内容
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>1.5.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>