网站开发原型工具,遵义网站建设价格,东莞微信网站建设推荐,品牌建设典型案例和品牌故事同意#xff01;但是不是最佳实践还有待商榷#xff0c;我这里给出自己一直使用的用异常控制流程的方案#xff0c;分享讨论一下吧。由于JAVA只能有一个返回值#xff0c;但有时候一个service方法除了返回结果外还真的需要有一些附加信息#xff0c;比如用户非法操作时要中…同意但是不是最佳实践还有待商榷我这里给出自己一直使用的用异常控制流程的方案分享讨论一下吧。由于JAVA只能有一个返回值但有时候一个service方法除了返回结果外还真的需要有一些附加信息比如用户非法操作时要中断流程并给出错误信息。如果你不想在service方法中充满着各种大多时候都无用的ResultBean或者让人看见就头大的Map异常的确值得去尝试一下。异常最大的优势就是可以中断方法并返回附加信息方便统一管理使你的代码更简洁。缺点就是性能至于差多少还没测试过希望有人可以去测一下。下面开始主题内容1.定义异常我理解的业务异常是指用户非法操作(如注册用户名重复)需要中断操作并给用户返回合理信息的异常。定义如下先定义一个继承自RuntimeException的异常主要在最后一个构造方法后面两个值为false,false。意思就是不调用fillIStackTrace()方法和不添加suppressException因为我们主要关注错误信息并不在意栈轨迹所以禁用他们用来提高性能。当然也可以通过复写特定方法来实现我只是觉得用构造方法更简单。public class UnFillStackTraceException extends RuntimeException {private static final long serialVersionUID -3181827538683088424L;public UnFillStackTraceException() {this(null, null);}public UnFillStackTraceException(String message) {this(message, null);}public UnFillStackTraceException(Throwable cause) {this(null, cause);}public UnFillStackTraceException(String message, Throwable cause) {super(message, cause, false, false);}}接下来定义业务异常public class APIException extends UnFillStackTraceException {private static final long serialVersionUID -1043498038361659805L;private final StatusCode statusCode;public APIException(StatusCode statusCode) {this.statusCode statusCode;}public APIException(StatusCode statusCode, String message) {super(message);this.statusCode statusCode;}public StatusCode getStatusCode() {return this.statusCode;}Overridepublic String getMessage() {return StringUtils.defaultIfBlank(super.getMessage(), statusCode.defaultMessage);}}很简单上面的看一下就明白。因为我们说了业务异常必须是明确可以给用户提示的错误所以要构造APIException必须设置相应的StatusCode。2. StatusCode的设计业务异常之中肯定要包含相应的错误信息一般用代码来表示代码设计的方式有好多种这里我采用的方案是基于HttpStatusCode的基础上扩展三位。好处就是可以和HTTP状态码相互转换因为我们前台返回的时候都是基于http状态码的。代码如下public enum StatusCode {/*** 服务器未知异常*/ERROR(500000, 服务器异常),//授权异常DISABLE_ACCOUNT(401001, 账户已被冻结),INVALID_TOKEN(401002, 无效的身份凭证),EXPIRED_TOKEN(401003, 身份凭证已过期),NO_PERMISSION(401004, 无权限进行该操作),BAD_CREDENTIALS(401005, 密码错误),ILLEGAL_OPERATION(400001, 非法操作),NOT_FOUND(404000,访问的资源不存在),INVALID_PARAM(422001, 参数无效);public final int code;public final String defaultMessage;StatusCode(int code, String defaultMessage) {this.code code;this.defaultMessage defaultMessage;}public int getHttpStatusCode(){return convertToHttpStatus(this);}public static StatusCode valueOf(int code) {for (StatusCode value : StatusCode.values()) {if (value.code code) {return value;}}throw new IllegalArgumentException(没有符合 code 的StatusCode);}public static int convertToHttpStatus(StatusCode statusCode) {return statusCode.code / 1000;}public static int convertToHttpStatus(int code) {return convertToHttpStatus(valueOf(code));}}3. 捕获异常这一步基本上没啥说的统一用ControllerAdvice捕获就行了。RestControllerAdvicepublic class ControllerExceptionHandler {public static final Logger log LoggerFactory.getLogger(ControllerExceptionHandler.class);ExceptionHandler(APIException.class)public ResponseEntity handleBusinessException(APIException apiException){return ResponseEntity.status(apiException.getStatusCode().getHttpStatusCode()).body(new ErrorBody(apiException));}ExceptionHandler(Exception.class)ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public ErrorBody handleUnknownException(Exception e){log.error(服务器未知异常,e);return new ErrorBody(StatusCode.ERROR);}}4. 使用定义好这些东西后就可愉快的使用了Service中简单的代码如下OverrideTransactional(rollbackFor Exception.class)public SecurityAccount registerAccount(AccountRegister register) {accountRepository.findUserByUsername(register.getUsername()).ifPresent(eac-{throw new InvalidParamException(用户名 register.getUsername() 已被使用);});Account account BeanUtil.copyBean(register,Account.class);if (StringUtils.isNotBlank(register.getPassword())){account.setPassword(passwordEncoder.encode(register.getPassword()));} else {throw new InvalidParamException(密码不能为空);}account.setCreateTime(LocalDateTime.now());accountRepository.save(account);return convertToSecurity(account);}InvalidParamException是继承自ApiException并在构造函数中设置好状态码方便使用。Controller层代码:Controller层没有对返回结果再做封装因为大多时候根本没必要。尽量利用http状态码即可对前端使用很舒服。如果发生错误再统一返回ErrorBody里面有错误码和详细信息供前端展示。对于有复杂业务的操作如不能简单的使用成功或者失败来表示的就自己再针对业务和前端协商专门定义即可。PostMappingpublic long registerAccount(Validated RequestBody AccountRegister accountRegister,BindingResult result) {checkBindingResult(result);return accountService.registerAccount(accountRegister).getId();}使用http状态码返回错误后前端使用相当舒服不用再为业务异常捕获一次为http错误再捕获一次,统一进catch即可$http.post(system/accounts, this.editInfo).then(res {this.$message.success(操作成功);this.cancelDialog();this.loadData();}).catch(reason {if (!reason.handled) {this.$message.error(reason.response.data.message);}})这些只是我个人习惯中总结下来的实践并非最佳实践。放在这里供大家讨论一下希望能多指出不足一起学习改进。另外说一句知乎的电脑端编辑器好难用好像有不少bug啊。