}
public int getRawStatusCode() {
return 0;
}
public MultiValueMap<String, ResponseCookie> getCookies() {
return null;
}
}
public class ModifyResponseGatewayFilter implements GatewayFilter, Ordered {
private final ModifyResponseBodyGatewayFilterFactory.Config config;
public ModifyResponseGatewayFilter(ModifyResponseBodyGatewayFilterFactory.Config config) {
this.config = config;
}
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
public Mono writeWith(Publisher<? extends DataBuffer> body) {
Class inClass = ModifyResponseGatewayFilter.this.config.getInClass();
Class outClass = ModifyResponseGatewayFilter.this.config.getOutClass();
MediaType originalResponseContentType = (MediaType)exchange.getAttribute(“original_response_content_type”);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(originalResponseContentType);
ModifyResponseBodyGatewayFilterFactory.ResponseAdapter responseAdapter = ModifyResponseBodyGatewayFilterFactory.this.new ResponseAdapter(body, httpHeaders);
DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
Mono modifiedBody = clientResponse.bodyToMono(inClass).flatMap((originalBody) -> {
return ModifyResponseGatewayFilter.this.config.rewriteFunction.apply(exchange, originalBody);
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
long contentLength1 = this.getDelegate().getHeaders().getContentLength();
Flux messageBody = outputMessage.getBody();
HttpHeaders headers = this.getDelegate().getHeaders();
if (!headers.containsKey(“Transfer-Encoding”)) {
messageBody = messageBody.doOnNext((data) -> {
headers.setContentLength((long)data.readableByteCount());
});
}
return this.getDelegate().writeWith(messageBody);
}));
}
public Mono writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return this.writeWith(Flux.from(body).flatMapSequential(§ -> {
return p;
}));
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
public int getOrder() {
return -2;
}
}
}
复制代码
实现代码
====
根据源码示例,可以在网关过滤器添加类似逻辑,实现修改响应数据。
ResponseFilter
@Component
@Slf4j
public class ResponseFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
URI uri = request.getURI();
String url = uri.getPath();
HttpStatus statusCode = exchange.getResponse().getStatusCode();
if(Objects.equals(statusCode, HttpStatus.BAD_REQUEST) || Objects.equals(statusCode, HttpStatus.TOO_MANY_REQUESTS)){
// 如果是特殊的请求,已处理响应内容,这里不再处理
return chain.filter(exchange);
}
// 根据具体业务内容,修改响应体
return modifyResponseBody(exchange, chain);
}
/**
-
修改响应体
-
@param exchange
-
@param chain
-
@return
*/
private Mono modifyResponseBody(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
public Mono writeWith(Publisher<? extends DataBuffer> body) {
MediaType originalResponseContentType = (MediaType)exchange.getAttribute(“original_response_content_type”);
HttpHeaders httpHeaders = new HttpHeaders();
AtomicBoolean isHttpCodeOK = new AtomicBoolean(true);
httpHeaders.setContentType(originalResponseContentType);
ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders);
HttpStatus statusCode = this.getStatusCode();
// 修改后的响应体
Mono modifiedBody = getModifiedBody(statusCode, isHttpCodeOK, responseAdapter, exchange);
// 业务上的开关,表示是否开启加密,如果开启,就需要修改响应体,将响应体数据加密。开关从上下文获取。这里只关心是一个boolean值即可。
Boolean flag;
BodyInserter bodyInserter;
if(!flag) {
// 不需要修改响应数据
bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
}else {
// 需要修改响应数据
// 这里最后采用了 ByteArrayResource 类去处理
bodyInserter = BodyInserters.fromPublisher(modifiedBody, ByteArrayResource.class);
}
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, httpHeaders);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
Flux messageBody = outputMessage.getBody();
ServerHttpResponse httpResponse = this.getDelegate();
HttpHeaders headers = httpResponse.getHeaders();
if (!headers.containsKey(“Transfer-Encoding”)) {
messageBody = messageBody.doOnNext((data) -> {
headers.setContentLength((long)data.readableByteCount());
});
}
if(!isHttpCodeOK.get()){
// 业务处理不是200,说明有异常,设置httpCode状态码是500
httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
}
return httpResponse.writeWith(messageBody);
}));
}
public Mono writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return this.writeWith(Flux.from(body).flatMapSequential(§ -> {
return p;
}));
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
public class ResponseAdapter implements ClientHttpResponse {
private final Flux flux;
private final HttpHeaders headers;
public ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {
this.headers = headers;
if (body instanceof Flux) {
this.flux = (Flux)body;
} else {
this.flux = ((Mono)body).flux();
}
}
public Flux getBody() {
return this.flux;
}
public HttpHeaders getHeaders() {
return this.headers;
}
public HttpStatus getStatusCode() {
return null;
}
public int getRawStatusCode() {
return 0;
}
public MultiValueMap<String, ResponseCookie> getCookies() {
return null;
}
}
@Override
public int getOrder() {
return FilterOrderConstant.getOrder(this.getClass().getName());
}
private Mono getModifiedBody(HttpStatus httpStatus, AtomicBoolean isHttpCodeOK, ResponseAdapter responseAdapter, ServerWebExchange exchange){
switch (httpStatus){
// 业务上需要特殊处理的状态码
case BAD_REQUEST:
case METHOD_NOT_ALLOWED:
isHttpCodeOK.set(false);
return getMono(HttpCode.BAD_REQUEST, exchange);
case INTERNAL_SERVER_ERROR:
isHttpCodeOK.set(false);
return getMono(HttpCode.SERVER_ERROR, exchange);
default:
// 主要处理流程
return getNormalBody(isHttpCodeOK, responseAdapter, exchange);
}
}
private Mono getNormalBody(AtomicBoolean isHttpCodeOK, ResponseAdapter responseAdapter, ServerWebExchange exchange){
DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
return clientResponse.bodyToMono(String.class).flatMap((originalBody) -> {
// 业务上的开关,表示是否开启加密,如果开启,就需要修改响应体,将响应体数据加密。开关从上下文获取。这里只关心是一个boolean值即可。
Boolean flag;
ObjectMapper objectMapper = new ObjectMapper();
try {
R r = objectMapper.readValue(originalBody, R.class);
/**
- 异常处理流程
*/
if(!r.getCode().equals(HttpCode.SUCCESS.getCode())){
// 业务处理不是200,说明有异常,直接返回对应错误
isHttpCodeOK.set(false);
ErrorR errorR = new ErrorR()
.setCode(r.getCode())
.setMsg(r.getMsg());
String json = objectMapper.writeValueAsString(errorR);
log.info(“json = {}”, json);
if(!flag) {
// 不需要加密,则不修改响应体
return Mono.just(json);
}else {
// 对返回数据进行加密 EncryptionUtil.encrypt(json, key)
// 具体加密逻辑不再阐述,这里可以理解成string 转成 byte[] 处理
byte[] encrypt = EncryptionUtil.encrypt(“{}”, key);
ByteArrayResource byteArrayResource = new ByteArrayResource(encrypt);
// 修改响应体,使用 byteArrayResource 封装
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/f7afb7a5387c0dbb5c65c986ee6efcbe.jpeg)
最后的内容
在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)
如何准备面试?
1、前期铺垫(技术沉积)
程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。
下面是我会看的一些资料笔记,希望能帮助大家由浅入深,由点到面的学习Java,应对大厂面试官的灵魂追问
这部分内容过多,小编只贴出部分内容展示给大家了,见谅见谅!
- Java程序员必看《Java开发核心笔记(华山版)》
- Redis学习笔记
- Java并发编程学习笔记
四部分,详细拆分并发编程——并发编程+模式篇+应用篇+原理篇
- Java程序员必看书籍《深入理解 ava虚拟机第3版》(pdf版)
- 大厂面试必问——数据结构与算法汇集笔记
其他像Spring,SpringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。
2、狂刷面试题
技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。
①大厂高频45道笔试题(智商题)
②BAT大厂面试总结(部分内容截图)
③面试总结
3、结合实际,修改简历
程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:
以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
③面试总结
[外链图片转存中…(img-KFqMjX03-1712727002489)]
[外链图片转存中…(img-GpstnrQ9-1712727002489)]
3、结合实际,修改简历
程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:
[外链图片转存中…(img-KGxfuUTT-1712727002489)]
以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!