一、环境
shenyu:2.5.0
二、场景
通常在业务系统需要定义统一出参,一般包括:
- 请求时间
- 请求路径
- 请求id
- 异常码
- 异常信息 6...
在业务代码编写过程,一般采用断言的方式将异常抛出,减少通用方法的二次解析code
在项目的异常使用的msg,shenyu使用的message,异常捕捉的异常码都统一设置为500,等等等
三、定位问题
在修改开源源码时,通常保证源码的继承性,保留原始逻辑,在此之上构建扩展
那么我看看shenyu是如何构建统一出参和异常捕捉的
通过查看plugin插件,发现统一通过ShenyuResultWrap来构造出参的
public final class ShenyuResultWrap {
private ShenyuResultWrap() {
}
/**
* Success object.
*
* @param exchange the exchange
* @param object the object
* @return the success object
*/
public static Object success(final ServerWebExchange exchange, final Object object) {
return shenyuResult().result(exchange, object);
}
/**
* Error object.
*
* @param exchange the exchange
* @param shenyuResult the shenyuResult
* @param object the object
* @return the object
*/
public static Object error(final ServerWebExchange exchange, final ShenyuResultEnum shenyuResult, final Object object) {
return shenyuResult().error(exchange, shenyuResult.getCode(), shenyuResult.getMsg(), object);
}
/**
* Error object.
*
* @param shenyuResult the shenyuResult
* @param object the object
* @return the object
*/
public static Object error(final ShenyuResultEnum shenyuResult, final Object object) {
return shenyuResult().error(shenyuResult.getCode(), shenyuResult.getMsg(), object);
}
/**
* Error object.
*
* @param exchange the exchange
* @param shenyuResult the shenyuResult
* @return the object
*/
public static Object error(final ServerWebExchange exchange, final ShenyuResultEnum shenyuResult) {
return shenyuResult().error(exchange, shenyuResult.getCode(), shenyuResult.getMsg(), null);
}
/**
* Error object.
*
* @param exchange the exchange
* @param code the code
* @param message the message
* @param object the object
* @return the object
*/
public static Object error(final ServerWebExchange exchange, final int code, final String message, final Object object) {
return shenyuResult().error(exchange, code, message, object);
}
/**
* shenyu result bean.
*
* @return the shenyu result bean.
*/
public static ShenyuResult<?> shenyuResult() {
return SpringBeanUtils.getInstance().getBean(ShenyuResult.class);
}
}
发现最终是从Spring容器中获取ShenyuResult来完成构建
public interface ShenyuResult<T> {
/**
* The response result.
*
* @param exchange the exchange
* @param formatted the formatted data that is origin data(basic、byte[]) or json string
* @return the result object
*/
default Object result(ServerWebExchange exchange, Object formatted) {
return formatted;
}
/**
* format the origin, default is json format except the basic and bytes.
*
* @param exchange the exchange
* @param origin the origin
* @return format origin
*/
default Object format(ServerWebExchange exchange, Object origin) {
// basic data or upstream data
if (ObjectTypeUtils.isBasicType(origin) || (origin instanceof byte[])) {
return origin;
}
// error result or rpc origin result.
return JsonUtils.toJson(origin);
}
/**
* the response context type, default is application/json.
*
* @param exchange the exchange
* @param formatted the formatted data that is origin data(basic、byte[]) or json string
* @return the context type
*/
default MediaType contentType(ServerWebExchange exchange, Object formatted) {
final ClientResponse clientResponse = exchange.getAttribute(Constants.CLIENT_RESPONSE_ATTR);
if (Objects.nonNull(clientResponse) && clientResponse.headers().contentType().isPresent()) {
return clientResponse.headers().contentType().get();
}
return MediaType.APPLICATION_JSON;
}
/**
* Error t.
*
* @param exchange the exchange
* @param code the code
* @param message the message
* @param object the object
* @return the t
*/
default T error(ServerWebExchange exchange, int code, String message, Object object) {
return error(code, message, object);
}
/**
* Error t.
*
* @param code the code
* @param message the message
* @param object the object
* @return the t
*/
default T error(int code, String message, Object object) {
return null;
}
查看实现类
public class DefaultShenyuResult implements ShenyuResult<DefaultShenyuEntity> {
@Override
public DefaultShenyuEntity error(final int code, final String message, final Object object) {
return DefaultShenyuEntity.error(code, message, object);
}
}
出参类是DefaultShenyuEntity
public class DefaultShenyuEntity implements Serializable {
private static final long serialVersionUID = -2792556188993845048L;
private static final int ERROR = 500;
private Integer code;
private String message;
@JsonBackReference
private Object data;
/**
* Instantiates a new shenyu result.
*
* @param code the code
* @param message the message
* @param data the data
*/
public DefaultShenyuEntity(final Integer code, final String message, final Object data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* Gets code.
*
* @return the code
*/
public Integer getCode() {
return code;
}
/**
* Sets code.
*
* @param code the code
*/
public void setCode(final Integer code) {
this.code = code;
}
/**
* Gets message.
*
* @return the message
*/
public String getMessage() {
return message;
}
/**
* Sets message.
*
* @param message the message
*/
public void setMessage(final String message) {
this.message = message;
}
/**
* Gets data.
*
* @return the data
*/
public Object getData() {
return data;
}
/**
* Sets data.
*
* @param data the data
*/
public void setData(final Object data) {
this.data = data;
}
/**
* return error .
*
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static DefaultShenyuEntity error(final String msg) {
return error(ERROR, msg);
}
/**
* return error .
*
* @param code error code
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static DefaultShenyuEntity error(final int code, final String msg) {
return get(code, msg, null);
}
/**
* return error .
*
* @param code error code
* @param msg error msg
* @param data the data
* @return {@linkplain DefaultShenyuEntity}
*/
public static DefaultShenyuEntity error(final int code, final String msg, final Object data) {
return get(code, msg, data);
}
/**
* return timeout .
*
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static DefaultShenyuEntity timeout(final String msg) {
return error(ERROR, msg);
}
private static DefaultShenyuEntity get(final int code, final String msg, final Object data) {
return new DefaultShenyuEntity(code, msg, data);
}
}
四、解决
思路就是继承ShenyuResult和DefaultShenyuEntity,然后屏蔽不需要的参数
4.1 统一出参
public class TeddyShenyuEntity extends DefaultShenyuEntity {
private static final long serialVersionUID = -6414981693206070036L;
/**
* 忽略message字段,修改成msg
*/
@JsonIgnore
private String message;
/**
* 展示异常
*/
private String msg = "系统异常";
private static final int ERROR = 500;
public TeddyShenyuEntity(Integer code, String message, Object data) {
super(code, message, data);
this.message = message;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String getMessage() {
return message;
}
@Override
public void setMessage(String message) {
this.message = message;
}
/**
* return error .
*
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static TeddyShenyuEntity error(final String msg) {
return error(ERROR, msg);
}
/**
* return error .
*
* @param code error code
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static TeddyShenyuEntity error(final int code, final String msg) {
return get(code, msg, null);
}
/**
* return error .
*
* @param code error code
* @param msg error msg
* @param data the data
* @return {@linkplain DefaultShenyuEntity}
*/
public static TeddyShenyuEntity error(final int code, final String msg, final Object data) {
return get(code, msg, data);
}
/**
* return timeout .
*
* @param msg error msg
* @return {@linkplain DefaultShenyuEntity}
*/
public static TeddyShenyuEntity timeout(final String msg) {
return error(ERROR, msg);
}
private static TeddyShenyuEntity get(final int code, final String msg, final Object data) {
return new TeddyShenyuEntity(code, msg, data);
}
}
public class TeddyShenyuResult implements ShenyuResult<DefaultShenyuEntity> {
@Override
public DefaultShenyuEntity error(final int code, final String message, final Object object) {
return TeddyShenyuEntity.error(code, message, object);
}
}
自动配置
@Configuration
public class TeddyShenyuConfiguration {
private static final Logger log = LoggerFactory.getLogger(TeddyShenyuConfiguration.class);
@Bean
@Primary
public TeddyShenyuResult teddyShenyuResult() {
log.info("TeddyShenyu统一出参增强")
return new TeddyShenyuResult();
}
}
4.2 全局异常处理
继承修改ErrorWebExceptionHandler即可,不再复述