日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java web 自定义异常_Java web, service 层应该通过异常(自定义Exception)来中断业务吗?...

發布時間:2024/8/23 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java web 自定义异常_Java web, service 层应该通过异常(自定义Exception)来中断业务吗?... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

同意!但是不是最佳實踐還有待商榷,我這里給出自己一直使用的用異常控制流程的方案,分享討論一下吧。

由于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;

}

@Override

public 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捕獲就行了。

@RestControllerAdvice

public 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中簡單的代碼如下:

@Override

@Transactional(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,里面有錯誤碼和詳細信息,供前端展示。對于有復雜業務的操作,如不能簡單的使用成功或者失敗來表示的,就自己再針對業務和前端協商專門定義即可。

@PostMapping

public 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啊。

總結

以上是生活随笔為你收集整理的java web 自定义异常_Java web, service 层应该通过异常(自定义Exception)来中断业务吗?...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。