序文
今日のJavaのWeb MVCプロジェクトは、トランザクションのロールバックのためのカスタム例外といくつかの珍しい事故が発生、を含む、通常我々は、すべての統一例外がスローされるサービス層、構築されたマルチモードであり、呼び出し側のサービスコントローラ彼は防衛対話型のWebフロントエンドの最後の行であるため、例外処理の責任を負い、この時点で処理されていない場合は、その後、ユーザーがページ上の無知に見えることを余儀なく表示されます
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at cn.keats.TestAdd.main(TestAdd.java:20)
これは、次のような欠点があります
- 非常にフレンドリーなユーザーエクスペリエンス、ユーザーがTucaoものであってもよい:XXのウェブサイトは何ですか。そして、もはや訪問していません
- ユーザーはピアがある場合は、彼だけではなく、他見下される境界例外のうち非常に低い指標である建設プロジェクトのコードを見て、投げを参照してください
- ユーザーは、製品を見つけるために、顧客サービス、顧客サービスと呼ばれる、問題のサイトを参照してくださいあなたのためのゲームをプレイ/睡眠を覚まします。だけでなく、あなたがゲームプレイを終えるよく眠れするコードを変更することはできません批判されなければなりませんでした
ねえ、本当に苦しみました。だから、一般的に我々のアプローチは、このようなものになるだろう。
例外処理
一般的なコントローラプロセス
次のようにサービスコードは次のとおりです。
@Service
public class DemoService {
public String respException(String param){
if(StringUtils.isEmpty(param)){
throw new MyException(ExceptionEnum.PARAM_EXCEPTION);
}
int i = 1/0;
return "你看不见我!";
}
}
次のようにコントローラのコードは次のとおりです。
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@PostMapping("respException")
public Result respException(){
try {
return Result.OK(demoService.respException(null));
} catch (MyException e){
return Result.Exception(e, null);
}
catch (Exception e) {
return Result.Error();
}
}
}
この時点で、次の要求を送信する場合:
http://localhost/respException
サーバが異常MyExceptionカスタム例外復帰JSON文字列パラメータを取得されます。
{
"code": 1,
"msg": "参数异常",
"data": null
}
そして、我々はパラメータを構成するとき:
http://localhost/respException?param=zhangsan
ゼロ例外でキャッチサーバーは、フロントページの不明なエラーに戻ります
{
"code": -1,
"msg": "未知错误",
"data": null
}
これにより、ユーザーはそのパラメータを変更できるようにすることができます学生は、一般的にキャリブレーションパラメータのフロントページを作成する必要があると、サーバは要求を再送信すると、当然のことながら、パラメータが、合格していますこのようなパラメータエラーとしてある程度の問題のいくつかを避けることができます一方では、一方では、両当事者の事前の保存時の問題を、サーバー上の圧力を減らします。しかし、異常な方法でのコントローラのセクションの全てが同じで、コードが非常に冗長であることを書いた欠点があります。そしてないメンテナンスを助長し、一部の学生は、例外メカニズムに精通していないだけで遊んで、例外がスローをキャッチとして、責任を転嫁再び投げると再び再び戻ってくるのが好きかもしれません。。。(私は一度ハンドル例外にこの方法を足の同級生コードを引き継いだ、そしてそれは異常隠すことと、それを求めるだろう!嫌いは)我々は、サービスのグローバル・トランザクションを持っているシステムでは、処理全体のログを有していてもよく、これらは春に基づいていますビッグキル:AOP(アスペクト指向プログラミング)の実装、AOPそれは何ですか?
AOP
スプリングフレームワークAOPは、AOPは、「クロス」技術と呼ばれる使用、多機能ビジネスプロセスは、一般的な抽出を伴い、個々に独立したセクションを形成するためにパッケージ化され、適切なタイミングでこれらのファセットカットを横切る、アスペクト指向プログラミングと考えられていますビジネスプロセスに場所を指定しました。我々はOOPのアイデアは、上から下にビジネスプロセスを実行することで使用される場合、その後、AOPは、以下のように、我々は、クロスカッティングナイフのビジネスを実行する場合に相当します。
アドバイス(通知)事前通知(前)、通知後(afterReturning)、異常通知(AfterThrowing)に、AOPは思っ重要な用語ですが、最後の通知(後)とサラウンド通知(周り)は5です。特定の通知の意義は、私が言及した春の基本原則について説明しますオンライン、ここで詳細には触れません示されました。そして、我々はサービスのトランザクションが実際にトランザクションロールバックAOP AfterThrowing通知達成に基づいています知っています。私たちは、カスタムの処理も異なる通知異なる入学要件に応じてカスタマイズすることができ、ログインします。ケースということを、なぜ私たちは、カスタムグローバル例外ハンドラは、私たちのコードを簡素化することでカットしませんか?しかし、待って、と見下し続けています。
エレガントなハンドルの例外
バージョン3.2での春には、すでに私たちのための機能を提供します。@ControllerAdviceコメントを。この注釈層は@ExceptionHandlerアノテーション構成に従ってコントローラスローされた例外、および例外処理方法を捕捉します。次のように次の構成の一例であり、メインコードは:
タイプの結果:
検索結果を使用して、この一般的な方法、パラメータ外に闊歩の構成を容易にします。静的ファクトリメソッドを使用することだけをもっと見る意図初期化されたオブジェクトの名前です。Errorオブジェクトの場合は(全体のプロジェクトは、それがより快適に初期化されていない実行するために、もちろん、より良いの。)、二重サーバリソースを節約するためのロック怠惰なシングルトンを確認し、共有変数の問題は存在しません。
package cn.keats.util;
import cn.keats.exception.MyException;
import lombok.Data;
/**
* 功能:统一返回结果,直接调用对应的工厂方法
*
* @author Keats
* @date 2019/11/29 18:20
*/
@Data
public class Result<T> {
private Integer code;
private String msg;
private T data;
/**
* 功能:响应成功
*
* @param data 响应的数据
* @return woke.cloud.property.transformat.Result
* @author Keats
* @date 2019/11/30 8:54
*/
public static <T> Result<T> OK(T data){
return new Result<>(0, "响应成功", data);
}
private static Result errorResult;
/**
* 功能:返回错误,此错误不可定制,全局唯一。一般是代码出了问题,需要修改代码
*
* @param
* @return Result
* @author Keats
* @date 2019/11/30 8:55
*/
public static Result Error(){
if(errorResult == null){
synchronized (Result.class){
if(errorResult == null){
synchronized (Result.class){
errorResult = new Result<>(-1, "未知错误", null);
}
}
}
}
return errorResult;
}
/**
* 功能:返回异常,直接甩自定义异常类进来
*
* @param e 自定义异常类
* @param data 数据,如果没有填入 null 即可
* @return woke.cloud.property.transformat.Result<T>
* @author Keats
* @date 2019/11/30 8:55
*/
public static <T> Result<T> Exception(MyException e, T data){
return new Result<>(e.getCode(), e.getMsg(), data);
}
/**
* 功能:为了方便使用,使用静态工厂方法创建对象。如需新的构造方式,请添加对应的静态工厂方法
*
* @author Keats
* @date 2019/11/30 8:56
*/
private Result(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
カスタム例外クラス:
package cn.keats.exception;
import lombok.Getter;
/**
* 功能:系统自定义异常类。继承自RuntimeException,方便Spring进行事务回滚
*
* @author Keats
* @date 2019/11/29 18:50
*/
@Getter
public class MyException extends RuntimeException{
private Integer code;
private String msg;
public MyException(ExceptionEnum eEnum) {
this.code = eEnum.getCode();
this.msg = eEnum.getMsg();
}
}
例外コードの列挙クラス:
package cn.keats.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 功能:异常枚举
*
* @author Keats
* @date 2019/11/29 18:49
*/
@Getter
@AllArgsConstructor
public enum ExceptionEnum {
PARAM_EXCEPTION(1,"参数异常"),
USER_NOT_LOGIN(2,"用户未登录"),
FILE_NOT_FOUND(3,"文件不存在,请重新选择");
private Integer code;
private String msg;
}
異常セクション:
これは、新しい注釈を追加@ControllerAdviceと@ResponseBodyは@RestControllerと@Controllerの関係と同様の方法を速記されたスプリング@RestControllerAdvice 4.3であります
package cn.keats.advice;
import cn.keats.exception.MyException;
import cn.keats.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 功能:全局异常处理器,Controller异常直接抛出
*
* @return
* @author Keats
* @date 2019/11/30 10:28
*/
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {
/**
* 功能:其余非预先规避的异常返回错误
*
* @param e
* @return woke.cloud.property.transformat.Result
* @author Keats
* @date 2019/11/30 10:08
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result ResponseException(Exception e) {
log.error("未知错误,错误信息:", e);
return Result.Error();
}
/**
* 功能:捕捉到 MyException 返回对应的消息
*
* @param e
* @return woke.cloud.property.transformat.Result
* @author Keats
* @date 2019/11/30 10:07
*/
@ExceptionHandler(value = MyException.class)
@ResponseBody
public Result myException(MyException e) {
log.info("返回自定义异常:异常代码:" + e.getCode() + "异常信息:" + e.getMsg());
return Result.Exception(e, null);
}
}
この時点で、コントローラのメソッドを書くことができます。
package cn.keats.controller;
import cn.keats.service.DemoService;
import cn.keats.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@PostMapping("respException")
public Result respException(String param) throws Exception {
return Result.OK(demoService.respException(param));
}
@PostMapping("respError")
public Result respError() throws Exception {
return Result.OK(demoService.respException(null));
}
}
私たちは、コードの品質を向上させるために、一方で、ビジネスに集中する必要があるので、例外処理コードのほとんどは、読みやすさは、それはまた、私たちの開発のスピードを向上させ、省略します。宮!
プロジェクトを開始し、何の問題をテストしていません。
私は限られた技術与えられ、キーツ、技術プログラマの愛だ、任意の傷や紙Xiongtaiがある場合は、他のより良いアドバイス/実装があり、コメントを残すことを歓迎し、ありがとうございます!