当前位置: 首页 > news >正文

springboot-web进阶(三)——统一异常处理

补充

  springboot中也是一样的可以对结果进行统一格式的包装,这样也就方便了前台的统一接收处理了;

  1.结果集包装类 

package com.example.demo.bean;

/**
 * 结果包装
 *
 * @author zcc ON 2018/2/9
 **/
public class Result<T> {
    /**
     * 错误代码(可以设定例如500表示错误)
     */
    private Integer code;
    /**
     * 提示信息
     */
    private String msg;
    /**
     * 数据内容
     */
    private T data;

    public Result() {
    }

    public Integer getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
Resultde

 

    可以参考之前SSM中的包装类:http://www.cnblogs.com/jiangbei/p/7080955.html

  2.使用包装结果集

@PostMapping(value = "/girls")
    public Result<Girl> addGirl(@Valid Girl girl, BindingResult bindingResult) {
        Result<Girl> result = new Result<>();
        // 表单验证逻辑
        if (bindingResult.hasErrors()) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            StringBuffer sb = new StringBuffer();
            for (FieldError fieldError : fieldErrors) {
                sb.append(fieldError.getDefaultMessage());
            }
            result.setCode(500);
            result.setMsg(sb.toString());
            return result;
        }
        result.setCode(200);
        result.setMsg("success");
        result.setData(girlRepository.save(girl));
        return result;
    }

    3。改进结果集

      通过代码观察或者对比SSM中的示例,都发现这样写在代码中是挺傻的,这样,我们提供一个工具类(或者在结果集中直接封装)

/**
 * 结果集的工具类
 *
 * @author zcc ON 2018/2/9
 **/
public class ResultUtils {

    public static Result<Object> success(Object data) {
        Result<Object> result = new Result<>();
        result.setCode(200);
        result.setMsg("success");
        result.setData(data);

        return result;
    }

    public static Result<Object> error(String msg) {
        Result<Object> result = new Result<>();
        result.setCode(500);
        result.setMsg(msg);
        return result;
    }
}

    使用:

 @PostMapping(value = "/girls")
    public Result<Object> addGirl(@Valid Girl girl, BindingResult bindingResult) {
        // 表单验证逻辑
        if (bindingResult.hasErrors()) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            StringBuffer sb = new StringBuffer();
            for (FieldError fieldError : fieldErrors) {
                sb.append(fieldError.getDefaultMessage());
            }
            return ResultUtils.error(sb.toString());
        }
        return ResultUtils.success(girlRepository.save(girl));
    }

 

一、概述

  springboot提供了默认的统一异常处理,basicErrorController,这个controller提供了默认了错误处理方法,包括错误跳转的路径和渲染方法。

  因为默认的错误处理方法可能会不适合项目的需要,所以当需要自定义统一错误处理的时候,可以继承basicErrorController。或重新实现basicErrorController.

统一异常处理可配置400,404,500等状态异常错误处理。basicErrorController内部提供了针对accept=**的不同处理方法,可区别是普通调用还是ajax等其他调用。

  缺点:需要重写basicErrorController。并配置覆盖原来springboot的默认配置。当使用EmbeddedServletContainerCustomizer类配置400,404。500的时候,暂时不清楚调用springboot的处理方法。

二、问题提出

  假设需要根据girl的不同age作出不同的动作,controller如下:

 @GetMapping(value = "/girls/getAge/{id}")
    public void getAge(@PathVariable("id") Integer id) {
        // 判断应该交给service
        

  service:

public void getAge(Integer id) {
        Integer age = girlRepository.findOne(id).getAge();
        if (age < 12) {
            // 小学生
        } else {
            // 上初中了
        }
    }

  如果只是简单的判断,不同年龄返回不同信息给前台,那确实可以通过返回一个String来进行

  但是,如果业务比较复杂,需要的不仅仅是返回一个字符串,而是需要其他动作,这个时候就显得有点力不从心了!

三、统一异常处理

   1.基本用法

   controller调用service,抛出异常即可:

 @GetMapping(value = "/girls/getAge/{id}")
    public void getAge(@PathVariable("id") Integer id) throws Exception{
        // 判断应该交给service
        girlService.getAge(id);
    }

  service也是,该抛异常就抛出异常:

public void getAge(Integer id) throws Exception{
        Integer age = girlRepository.findOne(id).getAge();
        if (age < 12) {
            // 小学生
            throw new Exception("小学生!");
        } else {
            // 上初中了
            throw new Exception("初中生!");
        }
    }

  统一异常处理类:

package com.example.demo.handle;

import com.example.demo.bean.Result;
import com.example.demo.utils.ResultUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 异常处理类
 * 添加@ControllerAdvice标记为异常处理类
 * @author zcc ON 2018/2/9
 **/
@ControllerAdvice
public class MyExceptionHandler {

    /**
     * 如果不在这里加@ResponseBody,则需要在类上加
     * @param e 异常
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e) {
        return ResultUtils.error(e.getMessage());
    }
}

  2.自定义异常

    写自定义异常还是之前的基础篇的老套路,基本就是几个构造方法的编写,再根据需要加上自己的变量!

 

package com.example.demo.exception;

/**
 * 自定义异常
 * 继承RuntimeException才能使得spring进行异常时的回滚
 * @author zcc ON 2018/2/9
 **/
public class MyException extends RuntimeException{
    private Integer code;

    public MyException(Integer code, String msg) {
        super(msg);
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }

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

 

    异常处理类:

package com.example.demo.handle;

import com.example.demo.bean.Result;
import com.example.demo.exception.MyException;
import com.example.demo.utils.ResultUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 异常处理类
 * 添加@ControllerAdvice标记为异常处理类
 * @author zcc ON 2018/2/9
 **/
@ControllerAdvice
public class MyExceptionHandler {

    /**
     * 如果不在这里加@ResponseBody,则需要在类上加
     * @param e 异常
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e) {
        // 先判断捕获的是不是我们定义的异常
        if (e instanceof MyException) {
            MyException me = (MyException) e;
            return ResultUtils.exp(me.getCode(), me.getMessage());
        } else {
            return ResultUtils.error("未知错误!");
        }
    }
}

  其他地方需要注意:

    既然MyException继承RuntimeException了,那controller和service就不用抛出异常了

    ResultUtils根据需要微调一些

  统一404、500异常处理

 

  @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseData defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        logger.error("", e);
        ResponseData r = new ResponseData();
        r.setMessage(e.getMessage());
        if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) {
             r.setCode(404);
        } else {
             r.setCode(500);
        }

 

 

 

三、使用枚举优化管理

  1.枚举

package com.example.demo.enums;

/**
 * 结果集的枚举管理类
 * 不用给出setter了,因为枚举不会再去set了
 * @author zcc
 **/
public enum ResultEnum {
    UNKNOWN(-1, "未知错误"),
    SUCCESS(200, "success"),
    PRIMARY(100, "小学生"),
    MIDDLE(101, "中学生");

    private Integer code;
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

  更多枚举基础知识,参考:http://www.cnblogs.com/jiangbei/p/7580482.html

 

  2.调整自定义异常的构造方法

/**
 * 自定义异常
 * 继承RuntimeException才能使得spring进行异常时的回滚
 * @author zcc ON 2018/2/9
 **/
public class MyException extends RuntimeException{
    private Integer code;

    public MyException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
    }

    public Integer getCode() {
        return code;
    }

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

  3.使用自定义枚举统一管理错误代码和错误信息之间的关系

 public void getAge(Integer id) {
        Integer age = girlRepository.findOne(id).getAge();
        if (age < 12) {
            // 小学生
            throw new MyException(ResultEnum.PRIMARY);
        } else {
            // 上初中了
            throw new MyException(ResultEnum.MIDDLE);
        }
    }

 

转载于:https://www.cnblogs.com/jiangbei/p/8436565.html

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • SPA页面性能优化
  • Java单元测试之JUnit篇
  • Lagom学习(一)
  • docker 部署 flask(二)编写及生成镜像。
  • HDU 1846.Brave Game-巴什博奕
  • VC++ GetSafeHwnd()和GetSafeHandle()
  • hibernate框架学习笔记5:缓存
  • Spring 的autowired大坑
  • X86汇编快速入门
  • 块存储,文件存储,对象存储的层次关系
  • HDU.3032.Nim or not Nim?(博弈论 Lasker's Nim)
  • VM CentOS Docker 安装
  • 004
  • spark深入:配置文件与日志
  • 微信支付
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 【附node操作实例】redis简明入门系列—字符串类型
  • Apache Pulsar 2.1 重磅发布
  • Fabric架构演变之路
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • PHP 7 修改了什么呢 -- 2
  • Python_OOP
  • Redis学习笔记 - pipline(流水线、管道)
  • socket.io+express实现聊天室的思考(三)
  • vue-router的history模式发布配置
  • 聊聊sentinel的DegradeSlot
  • 排序算法学习笔记
  • 思考 CSS 架构
  • 与 ConTeXt MkIV 官方文档的接驳
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #HarmonyOS:Web组件的使用
  • (13)DroneCAN 适配器节点(一)
  • (33)STM32——485实验笔记
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (poj1.2.1)1970(筛选法模拟)
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (四)React组件、useState、组件样式
  • (五)activiti-modeler 编辑器初步优化
  • (一)认识微服务
  • (转)关于pipe()的详细解析
  • (转)原始图像数据和PDF中的图像数据
  • **PHP二维数组遍历时同时赋值
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .NET Core 发展历程和版本迭代
  • .net dataexcel winform控件 更新 日志
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 发展历程
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉