跨应用的全局封装经过模仿java的异常抛出实现,经过各个服务使用相同的接口返回格式实现服务消息的传递,在规范化的同时快速定位真正出现问题的服务。java
全局接口返回格式分为外部接口格式和内部接口格式,这里简化为内外接口格式一致。spring
总体流程以下:json
整个spring cloud服务的统一接口app
public class ResponseResult<T> implements Serializable { /** * */ private static final long serialVersionUID = 1679552421651455773L; private int status; //状态码,根据服务实际需求自定义 private String msg; private T data; private String url; //请求的url private Long host; //出现问题的根服务 public static ResponseResult ok(Object data, String url) { return new ResponseResult(ResponseStatusCode.OK, data, url, null); } public static ResponseResult ok(String msg, Object data, String url) { return new ResponseResult(ResponseStatusCode.OK, msg, data, url, null); } public static ResponseResult ok(String msg, String url) { return new ResponseResult(ResponseStatusCode.OK, msg, null, url, null); } public static ResponseResult fail(int status, String msg, String url, Long host) { return new ResponseResult(status, msg, url, host); } public ResponseResult() { } public ResponseResult(String msg, T data, String url, Long host) { this.msg = msg; this.data = data; this.url = url; this.host = host; } public ResponseResult(int status, String msg, String url, Long host) { this.status = status; this.msg = msg; this.url = url; this.host = host; } public ResponseResult(int status, T data, String url, Long host) { this.status = status; this.data = data; this.url = url; this.host = host; } public ResponseResult(int status, String msg, T data, String url, Long host) { this.status = status; this.msg = msg; this.data = data; this.url = url; this.host = host; } public ResponseResult(int status, String msg, T data, Long host) { this.status = status; this.msg = msg; this.data = data; this.host = host; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Long getHost() { return host; } public void setHost(Long host) { this.host = host; } }
这个类为总体服务定义的状态码,能够使用枚举实现ide
public class ResponseStatusCode { /** * OK */ public static final int OK = 0; /** * 未知异常 */ public static final int UNKNOW_EXCEPTION = 100; /** * 参数异常 */ public static final int ARGUMENT_EXCEPTION = 104; /** * 自定义异常 */ public static final int ARGUMENT_EXCEPTION = XXX; }
自定义异常类继承RuntimeExceptionthis
public class CustomException extends RuntimeException{ public static final long serialVersionUID = 1L; private int status; private Long host; public CustomException(int status) { this.status = status; } /** * 抛出异常使用自定义的异常码 * @param status 自定义异常码 * @param message 异常信息 */ public CustomException(int status, String message) { super(message); this.status = status; } public CustomException(String message, Throwable cause, int status) { super(message, cause); this.status = status; } public CustomException(Throwable cause, int status) { super(cause); this.status = status; } public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, int status) { super(message, cause, enableSuppression, writableStackTrace); this.status = status; } public CustomException(int status, Long host) { this.status = status; this.host = host; } /** * 抛出异常使用自定义的异常码 * @param status 自定义异常码 * @param message 异常信息 * @param host 主机 */ public CustomException(int status, String message, Long host) { super(message); this.status = status; this.host = host; } public CustomException(String message, Throwable cause, int status, Long host) { super(message, cause); this.status = status; this.host = host; } public CustomException(Throwable cause, int status, Long host) { super(cause); this.status = status; this.host = host; } public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, int status, Long host) { super(message, cause, enableSuppression, writableStackTrace); this.status = status; this.host = host; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public Long getHost() { return host; } public void setHost(Long host) { this.host = host; } }
使用spring自带controller响应处理类,使用全局封装类封装返回url
@ControllerAdvice public class CustomResponseAdivce implements ResponseBodyAdvice<Object> { // 这个方法表示对于哪些请求要执行beforeBodyWrite,返回true执行,返回false不执行 @Override public boolean supports(MethodParameter methodParameter, Class aClass) { return true; } // 对于返回的对象若是不是最终对象ResponseResult,则选包装一下 @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) serverHttpRequest; String url = servletServerHttpRequest.getServletRequest().getRequestURL().toString(); if (!(o instanceof ResponseResult)) { ResponseResult responseResult = null; // 由于handler处理类的返回类型是String,为了保证一致性,这里须要将ResponseResult转回去 if (o instanceof String) { responseResult = ResponseResult.ok(o, url); ObjectMapper mapper = new ObjectMapper(); String responseString = ""; try { responseString = mapper.writeValueAsString(responseResult); } catch (JsonProcessingException e) { e.printStackTrace(); } return responseString; }else { responseResult = ResponseResult.ok(o, url); return responseResult; } } return o; } }
业务中经过抛出异常的方式来处理错误,在此处能够全局处理spa
@RestControllerAdvice public class ExceptionAdvice { private Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 出错服务端口 */ @Value("${server.port}") private int servicePort; /** * 封装异常 * * @param req 请求 * @param e 异常类 * @return 返回封装类 */ @ExceptionHandler(value = Exception.class) public ResponseResult jsonErrorHandler(HttpServletRequest req, Exception e) { logger.error(req.getRequestURL().toString(), e); Long host = null; //分配异常码与host int status = ResponseStatusCode.UNKNOW_EXCEPTION; String msg = e.getMessage(); if (e instanceof IOException || e instanceof CustomIOException) { status = ResponseStatusCode.IO_EXCEPTION; if (e instanceof CustomIOException){ host = ((CustomIOException) e).getHost(); } } else if (e instanceof NullPointerException || e instanceof CustomNullPointerException) { status = ResponseStatusCode.NULL_EXCEPTION; if (e instanceof CustomNullPointerException){ host = ((CustomNullPointerException) e).getHost(); } } else if (e instanceof SQLException || e instanceof CustomSQLException) { status = ResponseStatusCode.SQL_EXCEPTION; if (e instanceof CustomSQLException){ host = ((CustomSQLException) e).getHost(); } } else if (e instanceof ArgumentException) { status = ResponseStatusCode.ARGUMENT_EXCEPTION; if (((ArgumentException) e).getHost() != null && !((ArgumentException) e).getHost().equals(0)){ host = ((ArgumentException) e).getHost(); } } else if (e instanceof CustomException) { status = ((CustomException) e).getStatus(); if (((CustomException) e).getHost() != null && !((CustomException) e).getHost().equals(0)){ host = ((CustomException) e).getHost(); } } else if (e instanceof UndeclaredThrowableException) { Throwable targetEx = ((UndeclaredThrowableException) e).getUndeclaredThrowable(); if (targetEx != null) { msg = targetEx.getMessage(); } } //获取出错服务ip int ip = 0; try { ip = Integer.valueOf( Arrays.stream( InetAddress.getLocalHost().getHostAddress() .split("\\.")).collect(Collectors.joining())); } catch (Exception e1) { } return ResponseResult.fail( status, msg, req.getRequestURL().toString(), host == null? Long.valueOf(String.valueOf(ip) + servicePort): host); } }
上游服务得到下游服务的响应的处理类3d
public class ResponseHandler<T> { /** * 处理调用远程接口的返回 * @param responseResult * @return */ public T handler(ResponseResult<?> responseResult) { int statusToken = responseResult.getStatus(); String msg = responseResult.getMsg(); Long host = responseResult.getHost(); if (ResponseStatusCode.OK != statusToken){ exceptionHandler(statusToken,msg, host); } return (T) responseResult.getData(); } /** * 处理异常 * @param statusToken 状态码 * @param msg 错误消息 * @param host 主机 */ private static void exceptionHandler(int statusToken, String msg, Long host) { if (ResponseStatusCode.IO_EXCEPTION == statusToken) { throw new CustomIOException(msg, host); } else if (ResponseStatusCode.NULL_EXCEPTION== statusToken) { throw new CustomNullPointerException(msg, host); } else if (ResponseStatusCode.SQL_EXCEPTION== statusToken) { throw new CustomSQLException(msg, host); } else if (ResponseStatusCode.ARGUMENT_EXCEPTION== statusToken) { throw new ArgumentException(msg, host); } else if (ResponseStatusCode.UNKNOW_EXCEPTION== statusToken) { throw new UnknowException(msg, host); } else { throw new CustomException(statusToken, msg, host); } } }
上面是全部服务都须要拥有的类,而后是几个调用的小例子code
@RestController @RefreshScope public class DcController { final ClientService clientService; @Autowired public DcController(ClientService clientService) { this.clientService = clientService; } @GetMapping("exception1") public String exception1() { throw new ArgumentException("错误"); } @GetMapping("exception2") public int exception2() { throw new CustomException(250, "业务异常,自定义异常码"); } @GetMapping("exception3") public int exception3(){ return new ResponseHandler<List<MetaVO>>().handler(clientService.generateList()).get(0).getDbid(); } @GetMapping("list") public List<MetaVO> generateList() { List<MetaVO> list = new ArrayList<>(); for (int i = 0; i < 2; i++) { MetaVO metaVO = new MetaVO(); metaVO.setDbid(i); list.add(metaVO); } return list; } }
以上就是spring cloud的全局封装实践,开发人员编写业务逻辑不须要考虑返回的封装,只须要考虑业务和自定义的状态码而已