springMvc中@ControllerAdvice和ErrorController接口使用

springMvc中@ControllerAdvice和ErrorController接口使用

一、簡介

springMvc中對全局的處理,可以使用aop。這裏介紹另外一種方式,藉助springMvc的ControllerAdvice註解和ErrorController接口。

二、ControllerAdvice註解

@ControllerAdvice(直接返回請求體,可以使用@RestControllerAdvice)可以對控制器進行全局處理,通常藉助@ExceptionHandler、@InitBinder、@ModelAttribute處理。

2.1 @ExceptionHandler

@ExceptionHandler用於全局處理控制器異常。示例如下:

2.1.1 使用

定義控制器異常捕獲類,類用@ControllerAdvice註解修飾,處理方法用@ExceptionHandler修飾。

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class ExceptionControllerAdvice {
    //通過註解@ExceptionHandler捕獲所有異常
    @ResponseBody
    @ExceptionHandler(value = {Exception.class})
    public Object exceptionDispose(Exception e, HttpServletRequest req, HttpServletResponse res) {
        Map<String, Object> result = new HashMap<>();
        result.put("exception", e.getClass().getName());
        result.put("uri", req.getRequestURI());
        return result;
    }
}

定義會拋異常的控制器:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("ex")
public class ExceptionController {
    //異常
    @RequestMapping("exception")
    public Object exception(String exClassName) throws Exception {
        throw (Exception) Class.forName(exClassName).newInstance();
    }
}
2.1.2 測試

請求:

### 空指針異常測試
GET http://localhost:9090/ex/exception?id=002&exClassName=java.lang.NullPointerException
Accept: application/json

響應:

{
  "exception": "java.lang.NullPointerException",
  "uri": "/ex/exception"
}

2.2 @ModelAttribute

@ModelAttribute用於全局參數綁定,可提前綁定參數到所有請求中。示例如下:

2.2.1 使用

定義綁定參數處理類,類用@ControllerAdvice註解修飾,處理方法用@ModelAttributer修飾。

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@ControllerAdvice
public class ModelAttributeControllerAdvice {
    //通過註解@ExceptionHandler捕獲所有異常
    @ModelAttribute
    public void modelAttributeDispose(Model model, HttpServletRequest req, HttpServletResponse res) {
        model.addAttribute("token", UUID.randomUUID());
    }
}

定義測試控制器:

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;

@RestController
@RequestMapping("ma")
public class ModelAttributeController {
    //參數綁定
    @RequestMapping("modelAttribute")
    public Object modelAttribute(Model model, HttpServletRequest req, HttpServletResponse res) throws Exception {
        return new HashMap<>(model.asMap());
    }
}
2.2.2 測試

請求:

### 全局參數測試
GET http://localhost:9090/ma/modelAttribute?id=003
Accept: application/json

響應:

{
  "token": "9143f492-e501-4c4f-8c17-637ed7bd048a"
}

2.3 @InitBinder

@InitBinder用於參數綁定處理,可對參數進行轉換等處理。

2.3.1 使用

定義參數處理類,類用@ControllerAdvice註解修飾,處理方法用@InitBinder修飾。

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

@ControllerAdvice
public class InitBinderControllerAdvice {
    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    @InitBinder
    public void initBinder(WebDataBinder wdb, HttpServletRequest req, HttpServletResponse res) {
        CustomDateEditor cde = new CustomDateEditor(df, true);
        wdb.registerCustomEditor(Date.class, cde);
    }
}

定義參數綁定轉換測試控制器。

import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;

@RestController
@RequestMapping("ib")
public class InitBinderController {
    //參數轉換綁定
    @RequestMapping("initBind")
    public Object initBind(Date dt) throws Exception {
        return DateFormatUtils.format(dt, "yyyy-MM-dd");
    }
}
2.3.2 測試

請求:

### 全局參數測試
GET http://localhost:9090/ib/initBind?dt=2020-06-29
Accept: application/json

響應:

2020-06-29

三、ErrorController接口

ErrorController接口可以對尚未進入控制器的請求錯誤進行捕獲處理,使用中通過繼承ErrorController接口,實現getErrorPath方法,指定錯誤處理路徑,然後在錯誤路徑控制器方法中處理。示例如下:

3.1 使用示例

定義錯誤處理控制器類,繼承ErrorController,在實現方法getErrorPath中指定錯誤處理路徑。

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RestController
public class JsonErrorController implements ErrorController {
    @Override
    public String getErrorPath() {
        //指定錯誤處理路徑
        return "/error";
    }

    //錯誤處理
    @RequestMapping("error")
    public Object errorDispose(HttpServletRequest req) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", req.getAttribute("javax.servlet.error.status_code"));
        result.put("uri", req.getRequestURI());
        result.put("param", req.getParameterMap());
        return result;
    }
}

3.2 測試

請求:

### 測試輸入不存在地址的錯誤捕獲
GET http://localhost:9090/xx?id=001
Accept: application/json

響應:

{
  "code": 404,
  "param": {
    "id": [
      "001"
    ]
  },
  "uri": "/error"
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章