一、需求说明:

由于公司的项目接入了几个几个服务进来,因为这几个服务接口返回的结果对象没有统一,前端需要后端将返回结果对象统一。

二、解决方案:

在网关写一个全局过滤器去对接口返回结果对象进行重构然后返回给前端。

三、代码实现

package com.jzt.zyy.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @description:
 * 	全局拦截器,作用所有的微服务
 * 	处理原因:因为目前各个服务比较杂,有java、.net和php项目,
 * 	并且接口返回的结果结构不统一,所以需要在网关进行统一一下。
 *
 * @author: sukang
 * @date: 2020-08-24 11:24
 */
@Slf4j
@Component
public class ZyyResponseGlobalFilter implements GlobalFilter, Ordered {

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpResponse originalResponse = exchange.getResponse();
		DataBufferFactory bufferFactory = originalResponse.bufferFactory();
		ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
			@Override
			public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
				if (body instanceof Flux) {
					Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
					return super.writeWith(fluxBody.map(dataBuffer -> {
						// probably should reuse buffers
						byte[] content = new byte[dataBuffer.readableByteCount()];
						dataBuffer.read(content);
						//释放掉内存
						DataBufferUtils.release(dataBuffer);
						String s = new String(content, Charset.forName("UTF-8"));
						//修改response之后的字符串
						String lastStr = s;
						//修改response的值
						if(StrUtil.containsIgnoreCase(s, "code") && JSONUtil.isJson(s)){
							GlobalResponse globalResponse = getGlobalResponse(originalResponse, s);
							if(globalResponse != null){
								log.info("修改之后的Response:{}", globalResponse);
								lastStr = JSONUtil.toJsonStr(globalResponse);
							}
						}

						byte[] uppedContent = lastStr.getBytes();
						return bufferFactory.wrap(uppedContent);
					}));
				}
				// if body is not a flux. never got there.
				return super.writeWith(body);
			}
		};
		// replace response with decorator
		return chain.filter(exchange.mutate().response(decoratedResponse).build());
	}

	@Override
	public int getOrder() {
		return -2;
	}


	private GlobalResponse getGlobalResponse(ServerHttpResponse originalResponse, String originalResponseStr){
		log.info("原始Response:{}", originalResponseStr);
		JSONObject jsonObject = JSONUtil.parseObj(originalResponseStr, false);
		if(jsonObject.containsKey("code")){
			if(jsonObject.getInt("code") == 200 || jsonObject.getInt("code") == 0){
				GlobalResponse globalResponse = new GlobalResponse();
				globalResponse.setCode(HttpStatus.OK.value());
				globalResponse.setMsg("成功");
				globalResponse.setSuccess(true);

				if(jsonObject.containsKey("count")){
					Map<String, Object> map = new HashMap<>();
					map.put("total", jsonObject.getInt("count"));
					map.put("list", Optional.ofNullable(jsonObject.getObj("data")).orElse("[]"));
					globalResponse.setData(map);
				}else{
					globalResponse.setData(Optional.ofNullable(jsonObject.getObj("data")).orElse("[]"));
				}
				return globalResponse;
			}else{
				GlobalResponse globalResponse = new GlobalResponse();
				if(jsonObject.getInt("code") == 401){
					globalResponse.setCode(403);
					globalResponse.setMsg("处方平台token失效");
					globalResponse.setData("[]");
				}else{
					globalResponse.setCode(originalResponse.getStatusCode().value());
					globalResponse.setMsg(Optional.ofNullable(jsonObject.getStr("msg")).orElse(""));
					globalResponse.setData(Optional.ofNullable(jsonObject.getObj("data")).orElse("[]"));
				}
				return globalResponse;
			}
		}

		if(jsonObject.containsKey("Code")){
			if(jsonObject.getInt("Code") == 200){
				GlobalResponse globalResponse = new GlobalResponse();
				globalResponse.setCode(HttpStatus.OK.value());
				globalResponse.setMsg("成功");
				globalResponse.setSuccess(true);

				if(jsonObject.containsKey("Count") || jsonObject.containsKey("DataTotal")){
					int total = 0;
					if(jsonObject.containsKey("Count")){
						total = jsonObject.getInt("Count");
					}
					if(jsonObject.containsKey("DataTotal")){
						total = jsonObject.getInt("DataTotal");
					}

					Map<String, Object> map = new HashMap<>();
					map.put("total", total);
					map.put("list", Optional.ofNullable(jsonObject.getObj("Data")).orElse("[]"));
					globalResponse.setData(map);
				}else{
					globalResponse.setData(Optional.ofNullable(jsonObject.getObj("Data")).orElse("[]"));
				}
				return globalResponse;
			}else{
				GlobalResponse globalResponse = new GlobalResponse();
				if(jsonObject.getInt("Code") == 401){
					globalResponse.setCode(403);
					globalResponse.setMsg("处方平台token失效");
					globalResponse.setData("[]");
				}else{
					globalResponse.setCode(originalResponse.getStatusCode().value());
					globalResponse.setMsg(Optional.ofNullable(jsonObject.getStr("Msg")).orElse("处方平台查询失败"));
					globalResponse.setData(Optional.ofNullable(jsonObject.getObj("Data")).orElse("[]"));
				}
				return globalResponse;
			}
		}

		return null;
	}

	/**
	 * @description:
	 * 		返回给前端的统一格式
	 * @param
	 * @return:
	 * @author: sukang
	 * @date: 2020/8/24 15:36
	 */
	@Data
	private class GlobalResponse implements Serializable{
		private static final long serialVersionUID = 1L;

		private int code;

		private boolean success = false;

		private String msg = "";

		private Object data;
	}
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐