REST(三)处理HTTP状态码、异常和响应头

版权声明:From Lay https://blog.csdn.net/Sadlay/article/details/84383194

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的控制器。

扫描二维码关注公众号,回复: 4300594 查看本文章

@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源码

猜你喜欢

转载自blog.csdn.net/Sadlay/article/details/84383194