1. 程式人生 > >REST(三)處理HTTP狀態碼、異常和響應頭

REST(三)處理HTTP狀態碼、異常和響應頭

REST(三)處理HTTP狀態碼、異常和響應頭

之前的內容只是討論了正確的處理結果,而沒有討論當沒有找到資源時的處理或者發生異常時的處理。當發生資源找不到或者處理邏輯發生異常時,需要考慮的時返回給客戶端HTTP抓鬼你太嗎和錯誤訊息的問題。為了簡化這些開發,Spring提供了實體封裝類ResponseEntity和註解@ResponseStatusResponseEntity可以有效封裝錯誤訊息和狀態碼,通過@ResponseStatus可以配置指定的響應碼給客戶端。

HTTP狀態碼

在大部分情況下,後臺請求成功後會返回一個200的狀態碼,代表請求成功。但是有時候這些還不夠具體,例如,新增了使用者,200狀態碼固然沒錯,但是使用201會更具體一些。因為201代表著新增資源成功。200只是代表請求成功而已。這時就可以使用@ResponseEntity

類或者@ResponseStatus來標識本次請求的狀態碼。除了可以在HTTP響應頭中加入屬性響應碼之外,還可以給響應頭加入屬性來提供成功或者失敗的訊息。

下面修改新增使用者的方法,將狀態碼修改為201,並且插入響應頭的屬性來表示這次請求的結果。

    //使用狀態碼
    @PostMapping("/user2/entity")
    public ResponseEntity<UserVo> insertUserEntity(@RequestBody UserVo userVo){
        User user=this.changeToEntity(userVo)
; userService.inserUser(user); UserVo result=this.changeToVo(user); HttpHeaders headers=new HttpHeaders(); String success=(result==null||result.getId()==null)?"false":"true"; //設定響應頭,比較常用的方法 headers.add("success",success); //下面是使用集合LIST方式,不常用 //headers.put("success", Arrays.asList(success));
//返回建立成功的狀態碼 return new ResponseEntity<UserVo>(result,headers, HttpStatus.CREATED); } @PostMapping("/user2/annotation") //指定狀態碼為201 資源建立成功 @ResponseStatus(HttpStatus.CREATED) @ResponseBody public UserVo insertUserAnnotation(@RequestBody UserVo userVo){ User user=this.changeToEntity(userVo); userService.inserUser(user); UserVo result=this.changeToVo(user); return result; }

方法返回的是一個ResonseEntity<UserVo>的物件,這裡還生成了響應頭(HttpHeaders物件)。並且天了手續ingsuccess來表示請求是否成功,最後返回的時候生成了一個ResonseEntity<UserVo>物件,然後將查詢到的使用者物件和響應頭捆綁上,並且指定響應碼為201。

insertUserAnnotation方法上則是使用註解ResponseStatus講HTTP的響應碼標註為201。所以方法正常返回時將會響應碼設定為201。

為了測試,我們寫一段js指令碼

            //測試請求響應碼
            postStatus()
            function postStatus() {
                //請求體
                var params={
                    'userName':'user_name_new',
                    'sexCode':1,
                    'note':'note_new'
                }
                //var url='./user2/entity';
                var url='./user2/annotation';

                $.post({
                    url:url,
                    contentType:'application/json',
                    data:JSON.stringify(params),
                    success:function (result, status, jqXHR) {
                        //獲取響應頭
                        var success=jqXHR.getResponseHeader("success");
                        //獲取狀態嗎
                        var status=jqXHR.status;
                        alert("響應頭引數是:"+success+",狀態碼是:"+status);
                        if(result==null){
                            alert("插入失敗");
                            return;
                        }else {
                            alert("插入成功");
                        }
                    }
                })
            }

處理異常

有時候程式會出一些異常,例如,按照編號查詢使用者,可能查詢不到資料,這個時候就不能正常返回去處理了,又或者在執行的過程中產生了異常,這也是需要們進行處理的。

我你可以使用spring mvc註解@ControllerAdvice@ExceptionHandler@ControllerAdvice用來定義控制器通知,@ExceptionHandler則是指定異常發生的處理方法。利用這些就可以處理異常了。

我們先定義一個查詢失敗的異常

自定義異常類

package com.lay.rest.exception;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 0:07 2018/11/18
 * @Modified By:IntelliJ IDEA
 */
public class NotFoundException extends RuntimeException{
    private static final long serialVersionUid=1L;
    //異常編碼
    private Long code;
    //異常自定義資訊
    private String customMsg;

    public NotFoundException(){
    }

    public NotFoundException(Long code,String customMsg){
        super();
        this.code=code;
        this.customMsg=customMsg;
    }

    public static long getSerialVersionUid() {
        return serialVersionUid;
    }

    public Long getCode() {
        return code;
    }

    public void setCode(Long code) {
        this.code = code;
    }

    public String getCustomMsg() {
        return customMsg;
    }

    public void setCustomMsg(String customMsg) {
        this.customMsg = customMsg;
    }
}

它繼承了RuntimeException,所以可以在找不到使用者的時刻丟擲異常。而在控制器丟擲異常後,則可以在控制器通知(@Controller)中來處理這些異常,這個時候就需要使用註解@ExceptionHandler了。

定義控制器通知

package com.lay.rest.exception;


/**
 * @Description: 控制器通知
 * @Author: lay
 * @Date: Created in 0:14 2018/11/18
 * @Modified By:IntelliJ IDEA
 */

@ControllerAdvice(
        //指定攔截包的控制器
        basePackages = {"com.lay.rest.controller.*"},
        // 限定為標註為@Controller和@RestController的類才會被攔截
        annotations = {Controller.class, RestController.class})
public class VoControllerAdvice {

    //異常處理,可以定義異常型別進行攔截處理
    @ExceptionHandler(value = NotFoundException.class)
    //以json表示式響應
    @ResponseBody
    //定義伺服器錯誤狀態嗎
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Map<String,Object> exception(HttpServletRequest request,NotFoundException ex){
        Map<String,Object> msgMap=new HashMap<>();
        //獲取異常資訊
        msgMap.put("code",ex.getCode());
        msgMap.put("message",ex.getCustomMsg());
        return msgMap;
    }
    
    
    //異常處理,可以定義異常型別進行攔截處理
    @ExceptionHandler(value = RuntimeException.class)
    //以json表示式響應
    @ResponseBody
    //定義伺服器錯誤狀態嗎
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Map<String,Object> exceptionAll(HttpServletRequest request,Exception ex){
        Map<String,Object> msgMap=new HashMap<>();
        //獲取異常資訊
        msgMap.put("message",ex.getMessage());
        return msgMap;
    }
}

這裡使用了@ControllerAdvice來標註類,說明在定義一個控制器通知。配置了它所攔截的包,限定了攔截器的那些被標註為註解@Controller@RestController的控制器。

@ExceptionHandler定義了攔截器NotFoundException的異常。

測試控制器異常

    //測試控制器通知異常處理
    @GetMapping(value = "/user/exp/{id}",
                //產生Json資料集
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    //響應成功
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public UserVo getUserForExp(@PathVariable("id") Long id){
        User user=userService.getUser(id);
        //如果找不到使用者就丟擲異常,進入通知
        throw new NotFoundException(1L,"找不到使用者【"+id+"】資訊");

    }

github原始碼