实战笔记(一):统一返回数据格式与统一异常处理

  • 先感慨一下:要改掉不做笔记的坏毛病呀! 先提一嘴:spring boot 配置 Filter 有两种方式,一种是编程方式(spring
    boot 最开始支持的方式), 另一种是注解方式(spring boot 后来又加了的一种配置方式)。 这几个月加班实在厉害,
    看了点东西,却没有做笔记, 后续会补上, 并且后面会一直做笔记了,也希望看到这篇博客的搬砖新老同志们也做做笔记啊!
    之前在一个自己的练手项目中使用第一种配置方式配置过, 但是没有做笔记,今天又要配置了, 想了想看看以前的吧, 找了好久,就是没找到,
    (不对呀!肯定配过, 怎么就没了呢!啊!!!) 言归正传

  • 统一返回数据格式
    统一返回数据格式, 顾名思义, 同一个项目中所有返回的数据格式相同, 使前端(iOS Android, Web)对数据的操作更轻松一些, 前台需要拿到后台返回到前台的状态信息, 来响应的做处理, 如通讯异常, 操作成功, 存储失败等!
    统一返回数据格式也没有一个具体的格式, 只要能描述清楚返回数据状态以及要返回的具体数据就可以:

/**
 - 统一返回实体
 -  - @author zhangchenzhao
 - @create 2018-08-08  下午11:25
 */
public class ResponseData<T>  {
    /**
     * @Author : Zcz
     * @Description: 状态码
     * @Date: 2018/8/19 - 下午2:48
     */
    private String code;
    /**
     * @Author : Zcz
     * @Description: 是否成功
     * @Date: 2018/8/19 - 下午2:48
     */
    private Boolean status;
    /**
     * @Author : Zcz
     * @Description: 状态信息
     * @Date: 2018/8/19 - 下午2:48
     */
    private String msg; //
    /**
     * @Author : Zcz
     * @Description: :返回数据
     * @Date: 2018/8/19 - 下午2:47
     */
    public T data;

    public String getCode() {
        return code;
    }

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

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    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;
    }

    public ResponseData(T data) {
        this.code = "000000";
        this.msg = "成功";
        this.status = true;
        this.data = data;
    }

    public ResponseData() {
        this.code = "000000";
        this.msg = "成功";
        this.status = true;
    }

    public ResponseData(String code, Boolean status, String msg, T data) {
        this.code = code;
        this.status = status;
        this.msg = msg;
        this.data = data;
    }
    public ResponseData(ResponseEnum responseEnum, T data){
        this.code = responseEnum.getCode();
        this.status = responseEnum.getStatus();
        this.msg = responseEnum.getMsg();
        this.data = data;
    }

    public ResponseData(Exception e){
        this.code = "000012";
        this.status = false;
        this.msg = e.getMessage();
    }
    @Override
    public String toString() {
        return "ResponseData{" +
                "code='" + code + '\'' +
                ", status=" + status +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }

}
  • 我这里就只写了四个属性 code、status、msg、data 分别描述返回数据的状态码, 比如00000表示正确状态, 00001
    表示数据存储更新失败, 00002表示数据删除失败等…; status是一个 Boolean 值, 前端若指向知道是否成功或失败,
    不关心具体失败原因, 只用 status 做判断, msg 是信息描述, 简单描述此次通讯的信息, 如成功, 失败, 存储失败,
    连接失败…等; data 这个属性最重要, 是前端需要的数据, 前端需要用这个数据做显示, 或重要操作, 但类型不定,
    多以使用泛型表示
/**
 * 返回信息枚举
 *  * @author zhangchenzhao
 * @create 2018-08-08  下午11:42
 */
public enum ResponseEnum {
    SUCCESS("000000", true, "成功"),
    SAVE_ERROR("000001", false, "保存数据失败"),
    DELETE_ERROR("000002", false, "删除数据失败"),
    UPDATE_ERROR("000003", false, "更新数据失败"),
    SELECT_ERROR("000004", false, "查询数据失败");


    private String code;
    private Boolean status;
    private String msg;

    public String getCode() {
        return code;
    }

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

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

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

    ResponseEnum(String code, Boolean status, String msg) {
        this.code = code;
        this.status = status;
        this.msg = msg;
    }
}
  • 用枚举做一些常见返回类型的状态信息, 以便开发时使用!

  • 下面是spring boot 做统一异常处理 统一异常处理, 我们在开发中,肯定会遇到抛出异常和捕获异常的代码,
    以防止因为不必要的错误导致整个程序崩溃, 使程序作出异常记录,但程序仍能正常运行, 这里使用 filter
    作为统一异常处理的拦截方式(话说原生的 filter和 listener 还是超好用的); 原理: filter 监听 servlet
    的声明周期活动 init dofilter destory 三个方法***(init和 destory不知道它俩有啥鸟用,若有大神见到此废话, 希望留下箴言教诲, 以使小渣本人有所提高, 感激不尽)*** , 其中
    dofilter(ServletRequest req, ServletResponse rsp, Filterchain chain)
    这个方法及其重要,

这里写图片描述

  • 前台发送Http请求, filter 会根据 uri 的匹配拦截相应的请求, 通过 filterChain.dofilter()放行,
    处理实线部分的 Controller service dao 等操作, 当 controller 返回数据后就是
    dofilter()处理接触, 继续 dofilter 后面的操作, 此时可以通过捕获 dofilter 的异常来统一处理所有
    controller 执行操作的异常 第一种spring boot 代码方式配置 filter:

import com.bbuilder.personal.config.filter.UnifyExceptionFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

/**
 * @author zhangchenzhao
 */
@SpringBootApplication
public class PersonalApplication {

	public static void main(String[] args) {
		SpringApplication.run(PersonalApplication.class, args);
	}
	@Bean
	public FilterRegistrationBean exceptionFilter(){
		FilterRegistrationBean registration = new FilterRegistrationBean();
		registration.setFilter(new UnifyExceptionFilter());
		registration.addUrlPatterns("/*");
//		registration.addInitParameter("paramName", "paramValue");
		registration.setName("exceptionFilter");
		registration.setOrder(1);
		return registration;
	}
}
  • 使用@Bean 配置FilterRegistrationBean 过滤器注册 bean 到 springcontext 中,使过滤器生效
    第二种方式 原生注解方式
/**
 * @author zhangchenzhao
 */
@SpringBootApplication
@ServletComponentScan
public class PersonalApplication {
	public static void main(String[] args) {
		SpringApplication.run(PersonalApplication.class, args);
	}
}
  • 这里最终要的注解是 @ServletComponentScan, 他会扫描 application
    启动同包,及以下子包中的注解@WebFilter @Order @WebInitParam() 等
/**
 * 统一异常处理过滤器
 *
 * @author zhangchenzhao
 * @create 2018-08-19  下午3:23
 */
@WebFilter(filterName = "exceptionFilter", urlPatterns = "/*")
@Order(1)
public class UnifyExceptionFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        try {
            filterChain.doFilter(servletRequest ,servletResponse);
        }catch (BaseException e){
            exceptionDataHandel((HttpServletResponse)servletResponse, e);
        }catch (Exception e){

            exceptionDataHandel((HttpServletResponse)servletResponse, (BaseException) e);
        }catch (Error error){
            System.out.println(error.getCause());
        }


    }

/**
 * @Author : Zcz
 * @Description: 整理异常数据
 * @Date: 2018/8/20 - 上午12:22
 */
    public void exceptionDataHandel(HttpServletResponse response, BaseException e)
            throws ServletException, IOException {
        String msg = e.getMessage();
        if(e.getObjects()!=null && e.getObjects().length != 0){
            msg = msg+": [";
            for (Object obj :
                    e.getObjects()) {
                msg = msg + obj.toString()+",";
            }
            msg = msg .substring(0, msg.length()-1);
        }
        responseExceptionMsg(response, msg);
    }
    /**
     * @Author : Zcz
     * @Description: 返回异常时前端需要的数据
     * @Date: 2018/8/20 - 上午12:22
     */
    public void responseExceptionMsg(HttpServletResponse response, String msg)
            throws ServletException, IOException {
            response.getWriter().write(msg);
    }
}

注:@webFilter 注解是servlet3.0的原生注解,并不是spring boot的注解, 但这种注册方式仍然是与代码配置方式相同
参考: https://blog.csdn.net/king_is_everyone/article/details/53116744

  • 两种效果相同, 选择其一即可!
  • 刚刚粗劣的看了看源码, 没看太明白, @ServletComponentScan 扫描包下注解类, 将Filter直接通过BeanDefined 注册到BeanDefinitionRegistry中, 而代码注册是直接实例化Filter 放到FilterRegistrationBean , 但最终效果相同, 还没理解…
  • 网上的各位老猿, 请多赐教! 祝大家前程似锦!
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值