SpringBoot適応例外処理

画像

画像

効果のデモンストレーション

最初にSpringbootデフォルトの効果を見てみましょう

ブラウザアクセス

画像

クライアントアクセス

画像

フォーカス!

しかし、会社のコードのほとんどは適応的に処理されていません。理由の大部分は、インターネットで検索してそのSpringboot全局异常处理ようなコードを見つけたためです。

@ControllerAdvice
public class MyControllerAdvice {
 
 
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<?> errorHandler(Exception ex) {
       // 处理异常
    }

 
}

最初に通常の検索エンジンで検索してから、会社のコードを調べて、このコードに類似しているかどうかを確認してから、下を確認することを強くお勧めします。

もちろん、多くの学生は、私たちがクライアントと良好な合意をしたと言うかもしれません、そして、あるだけですがjson、リターンhtmlシナリオはありませんしたがって、適応しなくても問題ありません。ただし、インフラストラクチャを使用している学生の場合は、会社全体のビジネス部門を接続しているため、この機能を実行する必要があります。Springbootで実行できます。同様の基本コンポーネントを実行できます。機能がSpringbootよりも悪い場合は、ビジネスクラスメートはどう思いますか?

もちろん、ほとんどの学生にとって、それをしないことは大きな問題ではありません。

しかし、この方法では、良い学習の機会を逃してしまいます。どのような学習の機会ですか?多くのクラスメートは、インタビューでロケットを作るといつも言っているので、職場で理解できない問題が発生した場合は、BaiduまたはGoogleをクリックするだけです。ただし、この問題はあまりよく検索されていません。言い換えれば、ほとんどの人は検索エンジン用にプログラミングしています。検索エンジンで解決できない問題に遭遇したとき、それはあなたが自分の価値を反映し、それを大切にするときです。

この機能を実行することは重要ではないと思います。この問題解決能力を発揮する貴重な機会は非常にまれです。結局のところ、ほとんどの機能は簡単な検索やフェイチャオ交換グループでの質問によって解決できるのは事実です。

適応原理

多くの学生は、それを見つけることができなかったので、決定的にソースコードの波から始めたと言いました。ただし、Springbootソースコード非常に多い場合、どこから始めればよいですか?これがポイントです!現時点では、公式文書の波を歩くことができます。

27.1.9エラー処理

Spring Boot provides an /error mapping by default that handles all errors in a sensible way, and it is registered as a ‘global’ error page in the servlet container. For machine clients it will produce a JSON response with details of the error, the HTTP status and the exception message. For browser clients there is a ‘whitelabel’ error view that renders the same data in HTML format (to customize it just add a View that resolves to ‘error’). To replace the default behaviour completely you can implement ErrorController and register a bean definition of that type, or simply add a bean of type ErrorAttributes to use the existing mechanism but replace the contents.

一些同学说,英文看不懂?我挑5个重点单词给你,都是小学单词,只要小学能毕业,我认为都能看懂。

clients JSON browser HTML ErrorController

肥朝小声逼逼:这里特别强调,并不是说看官方文档是最优解决问题方案。还是那句话,老司机都是看菜吃饭的,解决问题的套路有很多,时间有限,我就不把所有套路一个一个列出来(其实是怕套路全部告诉你们了,你们就取关了!),直入主题就行。

从文档和小学的英文单词我们把目标锁定在了ErrorController,给大家看一下关键代码

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

 @RequestMapping(produces = "text/html")
 public ModelAndView errorHtml(HttpServletRequest request,
   HttpServletResponse response)
 
{
  HttpStatus status = getStatus(request);
  Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
  response.setStatus(status.value());
  ModelAndView modelAndView = resolveErrorView(request, response, status, model);
  return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
 }

 @RequestMapping
 @ResponseBody
 public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
  Map<String, Object> body = getErrorAttributes(request,
    isIncludeStackTrace(request, MediaType.ALL));
  HttpStatus status = getStatus(request);
  return new ResponseEntity<Map<String, Object>>(body, status);
 }

}

从这里我们大致可以猜测出,要做一个自适应的全局异常处理,理论上是要这么写的。

@ControllerAdvice
public class MyExceptionHandler  {

    @ExceptionHandler(Exception.class)
    public String handleExceptionHtml(Exception e, HttpServletRequest httpServletRequest) {
        // 这里做一些你自己的处理,比如
        httpServletRequest.setAttribute("欢迎关注微信公众号","肥朝");
        return "forward:/error";
    }

}

果然调试一波,发现果真如此。当然具体怎么自定义这个错误界面之类的,网上一搜就有,所以这些不是肥朝的重点。那么这个自适应全局异常似乎美滋滋了?

遇到问题

我们知道了这个自适应的全局异常处理的原理,也很容易想到怎么弄出bug。比如,你在拦截器出现了异常的话。

@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
                throw new RuntimeException("这里假装抛出一个肥朝异常");
                //return true;
            }

            @Override
            public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

            }

            @Override
            public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

            }
        });
    }

}

那么就会出现,StackOverflowError

因为拦截器出现异常,会掉进你的全局异常处理,然后你的全局异常处理,又进行forward,又进入了拦截器,然后一直循环。

那么怎么解决这个问题呢?我们见招拆招,这个时候,我要演示常见的几种不优雅,但是平时大家都容易做的写法。

将配置写死

registry.addInterceptor(new HandlerInterceptor() {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        throw new RuntimeException("这里假装抛出一个肥朝异常");
        //return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}).excludePathPatterns("/error");

我们从

@RequestMapping("${server.error.path:${error.path:/error}}")

这里得知,这个error.path是可以配置的,很多同学图快,excludePathPatterns处写死了/error,这样一直用默认的自然没问题,一旦人家配置了error.path,就出问题了。

潜规则

这个潜规则的问题,是绝大部分同学写代码中最常见的问题。你想一下,你的自适应全局异常是解决了,但是,带来的影响却是,每一个拦截器都要加上excludePathPatterns这么一个配置。对于使用者来说,这个必须加上某个配置,就是一种潜规则,而且,对于新来的同事而言,他根本不知道这种潜规则,一旦潜规则的代码多了,后续很难维护。

拓展思考

那么不潜规则的代码应该是怎么样的?

もちろん、多くの場合、私たちは暗黙のルールを持っている必要があります!たとえば、ビッグデータの学生は、送信されるログにアプリケーション名が必要です。次に、ビジネス側では、アプリケーション名を構成する必要があります。それで、ビジネスの同僚にこの暗黙のルールを知らせる方法。もちろん、多くの学生が言った後、同僚に直接特定のパラメータを追加するように伝えます。フェイチャオの毎日のつぶやきさえ覚えていません。すべての同僚が覚えていることを保証できますか?

要約すると、次のようなタイプの問題が発生しました。

1.この記事のように、インターセプターのいくつかの暗黙のルールパラメーターを設定する必要があります。どのように暗黙のルールをエレガントにするのですか?

2.たとえば、インターセプターには順序要件があります。たとえば、基本的なフレームワークでtraceInterceptorインターセプターを定義する場合、このインターセプターを最初に配置する必要があります。したがって、問題は、これが最初であることをどのように確認するかです。何人かのクラスメートがちょうど言った、それから私は@Orderコントロールを使うそれから私はあなたのようなインターセプターを書きました、と呼ばれますfeichaoInterceptor、コードはあなたのものとまったく同じです、それはまったく同じなので、どうすればあなたが私の前にいることを確認できますか?

3.暗黙のルールが必要なシーンでは、抵抗している場合でも、どのようにしてそれに忍び込むことができますか?

これらの質問には次号でお答えします。



画像


おすすめ

転載: blog.51cto.com/15082403/2591224
おすすめ