(不侵入接口代码)SpringBoot统一处理返回结果和异常情况(json格式)

大多数项目都已经前后端分离,前端的小伙伴们当然希望接口的定义更规范,更方便。所以接口返回的数据包含至少包含以下三个属性:

  • code:请求接口的返回码,比如200表示成功,500表示异常。
  • msg:请求接口的描述,本次请求后台返回的信息。
  • data:请求接口成功,返回的结果。

封装前后结果对比:

String:

map:

pageInfo

怎么实现?

实现思路:1.定义返回实体Resp,2.所有接口统一返回Resp(真实情况会用3替代)

进阶思路:使用上面的方法索然实现了统一处理返回值,但是会有一些问题,比如老接口怎么办?解决办法:3.自定义拦截器处理 或者交由springmvc的MappingJackson2HttpMessageConverter处理

再次进阶:正常数据都处理好了,遇到异常怎么办?4.自定义异常处理

大致如下:

具体实现

一.定义返回实体Resp

import lombok.Data;

/**
 *
 */
@Data
public class Resp<T> {

	/**响应码  200:成功   非200:异常*/
	private String code="200";

	/** 前端提示信息 */
	private String msg="成功";

	/** 数据体:对象数组或者字符串,根据接口区分 */
	private T data;
}

二.接口统一定义返回类型

这种方法不推荐,后边通过spring代替这种手动处理

    /**
     * 统一格式的返回结果
     * @param req
     * @return
     */
    @RequestMapping("test1")
    public Resp test1(@Valid @RequestBody ProjectGoodExampleReq req) {
        Resp resp = new Resp();
        resp.setData("123");
        return resp;
    }

三(一).自定义拦截器处理

package com.ridge.project.core.convert;

import com.ridge.project.core.resp.Resp;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 使用 @ControllerAdvice & ResponseBodyAdvice
 * 拦截Controller方法默认返回参数,统一处理返回值/响应体
 */
@ControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> {



    // 判断是否要执行 beforeBodyWrite 方法,true为执行,false不执行,有注解标记的时候处理返回值
    @Override
    public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1) {
        return true;
    }

    // 对返回值做包装处理
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter arg1, MediaType arg2,
                                  Class<? extends HttpMessageConverter<?>> arg3, ServerHttpRequest arg4, ServerHttpResponse arg5) {
        Resp resp = new Resp();
        if (body instanceof Resp) {
            return body;
        } else if (body instanceof String) {
            return body;
        }
        resp.setData(body);
        return resp;
    }
}

三(二).继承springmvc的MappingJackson2HttpMessageConverter,重写writeInternal方法



import com.fasterxml.jackson.core.JsonGenerator;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.ridge.project.core.exception.CODE;
import com.ridge.project.core.page.BizDataPage;
import com.ridge.project.core.resp.Resp;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

/**
 * 消息转换器
 **/
@Configuration
public class JsonMessageConverter extends MappingJackson2HttpMessageConverter {
    public JsonMessageConverter() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        //设置日期格式
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(smt);
        //**数字转成字符串*//*
        objectMapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);

        //**不返回值为null的属性*//*
        //objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);

       //设置中文编码格式
        List<MediaType> list = new ArrayList<>();
        list.add(MediaType.APPLICATION_JSON_UTF8);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);

    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        Resp resEntity = new Resp();
        if (object instanceof Resp) {
            super.writeInternal(object, type, outputMessage);
            return;
        } else if (object instanceof PageInfo || object instanceof Page) {
            resEntity.setCode(CODE.success.getCode());
            resEntity.setData(new BizDataPage<>(object));
        } else {
            resEntity.setCode(CODE.success.getCode());
            resEntity.setData(object);
        }
        super.writeInternal(resEntity, type, outputMessage);
    }
}

注意:这里推荐用三(二)这种方法,因为即使用来三(一),最后的处理结果还是有三(二)来执行的

四.统一异常处理

继承RuntimeException,在需要的地方直接抛异常就可以了



import lombok.Getter;


public class BizException extends RuntimeException{
	@Getter
	CODE code;

	public BizException(CODE code){
		super(code.getMsg());
		this.code = code;
	}

	/**
	 * 处理自定义错误信息
	 * @param code
	 * @param message  自定义错误提示信息
	 */
	public BizException(CODE code,String message){
		super(message);
		code.setMsg(message);
		this.code = code;
	}

	public BizException(CODE code,Exception e){
		super(e);
		this.code = code;
	}

}

抛异常示例

    /**
     * 统一格式的返回结果-异常处理
     * @param req
     * @return
     */
    @RequestMapping("test1")
    public String test1(@Valid @RequestBody ProjectGoodExampleReq req) {
        throw new BizException(CODE.biz_error, "测试");
    }

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

buyaopingbixiazai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值