基础接口规范前言 该接口规范旨在达到以下目的
接口请求参数规范
接口响应参数规范
请求参数校验规范
通用异常处理规范
适用场景
接口返回值规范 所有对外服务接口必须使用 Result Bean 封装响应的结果
响应基类BaseResult
public class BaseResult<T> implements IResult { private Boolean isSuccess;// 本次调用是否成功 private IStatusCode code;// 状态编码 private String message = "";// private String stackTrace = ""; ... }
通用响应类
public class ResultMsg<T> extends BaseResult<T>{ private T data = null; // 返回数据 /**成功,有结果数据 * @param data */ public ResultMsg(T result){ this.setIsSuccess(true); this.setData(result); } ... }
分页类型响应类
public class PageResult<T> extends BaseResult<T>{ private Integer pageSize = 0;//分页大小 private Integer page = 1;//当前页 private Integer total = 0;//总条数 private List rows = null;//分页列表数据 ...
响应码规范 响应需要有对应的响应码,对于业务异常、系统可预知异常需要定义好异常码,并使用 包装异常 ,不同模块需要定义自身的异常枚举,并实现接口IStatusCode
/** * @说明 系统状态码定义抽象接口<br> * 子模块或者系统需要定义自己的系统状态码<br> * @StatusCode 为基础模块定义的基本码值,1~500 目前已经被占用 * @author jeef * */ public interface IStatusCode { /** * 状态码 * @return */ public String getCode() ; /** * 异常信息 * @return */ public String getMsg() ; /** * 系统编码 * @return */ public String getSystem() ; }
基础响应码实现 /** * @说明 基础系统状态码定义 */ public enum StatusCode implements IStatusCode{ SUCCESS("200","成功"), SYSTEM_ERROR("500","系统异常"), TIMEOUT("401","访问超时"), NO_ACCESS("403","访问受限"), PARAM_ILLEGAL("100","参数校验不通过"); private String code; private String msg; private String system; StatusCode(String code,String msg){ this.setCode(code); this.setMsg(msg); this.setSystem("BASE"); } public String getCode() { return code; } .... }
异常定义规范 AgileBPM 异常定义均在 com.dstz.base.api.exception
包,各个业务模块不需要定义特殊的异常类,均通过异常码来标识异常! 异常分三种
业务消息 BusinessMessage
业务异常 BusinessException
系统异常BusinessError
业务消息异常 通常为直接通知用户 业务消息,通常用于业务代码反馈,非系统异常! 如,保存用户时,后端校验 账号已存在 ,可以直接抛出业务异常 BusinessMessage ,并返回定义好的状态码
普通异常 业务逻辑异常,常常为可预料异常情况的抛出或者非法操作的信息提示。比如: 流程表单丢失!
系统异常 BusinessError
系统异常,常常用于强制捕获的异常的包装,是相对紧急程度高或者比较严重异常
所有异常均会中断事务,业务消息不会记录异常堆栈、日志 ,会直接提示到前端用户错误信息 其他则会详细记录请求信息、堆栈信息,并返回异常码,不会返回具体异常信息,前端应给予“系统服务异常”的提示
请求异常捕获与校验 当我们需要对一个请求接口的异常情况进行统一处理的时候,可以使用该注解 当方法体出现异常时,会包装标准的异常 resultMsg 进行反馈给调用者,并记录日志
比如前端请求、RPC 调用者等一些场景,省去了我们异常捕获的动作,也规范对于前端的响应 Rest 当然也可以对Controller层全局异常处理,但目前我们没这么做。
eg:@CatchErr("保存用户失败") @ParamValidate public ResultMsg<String> saveUser(@RequestBody User user){ if (userManager.isUserExist(user)){ throw new BusinessMessage("用户在系统中已存在!"); } // do save return getSuccessResult(user.getId(), "保存成功"); }
注解CatchErr介绍 /** * @描述 <p>如果该注解的方法出现异常,则会反馈标准的异常结果【ResultMsg.java】给前端或者服务调用方</p> * @提示 <p>使用该注解需要注意事物问题更多信息请查看ErrAspect.java</p> * * @param write2response 是否写入到response 用于http请求中,方法会从入参中获取response,然后写入resultMsg<br> * @param needStackTrace 是否需要反馈异常堆栈信息,默认不反馈堆栈异常,但是堆栈异常会进行日志记录 * @param value 方法体异常描述 * @create 2017-11-19 20:31:00 * @author jeff */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CatchErr { String value() default ""; boolean write2response() default false ; boolean needStackTrace() default false; }
请求参数校验 请求参数校验使用的 javax validate3.0规范 hibernate-validator 的一个实现
@CatchErr @ParamValidate public PageResult<String> getRolesByUser(User user){ List<String> roles = Arrays.asList("1,2,3,4,5,6,7,8,9".split(",")); PageList<String> pageList = new PageList<String>(2, 10, 100, roles); PageResult<String> msg = new PageResult<String>(pageList); return msg; }
public class User { @NotBlank(message = "姓名不能为空") private String name = ""; @NotBlank(message = "账号不能为空") private String account = ""; ... }
ParamValidate 会对user对象进行校验 校验不通过则会反馈标准的resultMsg给调用者
引入CatchErr、@ParamValidate 注意事项 需注意必须在 springMVC的配置页配置 注解拦截器 否则将无法在controller层拦截处理异常
<aop:aspectj-autoproxy proxy-target-class="true"/>
前端统一处理 前端一些配套js 对jQuery进行扩展增加一些公共的 result 解析方法,用来提示系统错误,如 util.js getResultData 方法
/** * @说明 获取请求响应的数据 * @失败 默认toast 提示错误信息 * @成功 不展示成功信息自己处理 */ getResultData : function(defer,fn){ defer.then(function(result){ if(!result.isok){ toast.error(result.message); console.error(result.stackTrace); return; } //返回结果 fn(result.data); },function(status){ alert("加载失败!"+status); } ); },
前端如此使用 var defer=baseService.get(dataUrl); $.getResultData(defer,function(data){ //这里直接使用data });