后端返回数据全局处理

本文介绍了一种通过使用Spring Boot框架中的ResponseBodyAdvice接口来统一处理HTTP响应的方法,这种方法能够简化服务端代码并提升项目的可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

返回值全局拦截

前言

现在项目中,软件开发采用前后端分离模式是越来越普遍,后端人员更加专注数据,前端(包括html和app开发人员)更加注重数据展示和部分前端逻辑控制。目前跟前端人员约定的数据返回格式如下:

  {
    "code": "200",
    "message": "成功",
    "data": T
  }

我们生成一个实体类,命名BaseResponse,如下:

@Data
public class BaseResponse<T>(){
  private int code;
  private String message;
  private T data;
}

无全局拦截

代码逻辑很混乱,重用性很低…
下面的代码基于SpringBoot1.0的框架。跟spring+springmvc差别不大。
这是controller层:

/**
 * function :用户控制器
 * @author :mayao
 * @date :2018/4/14
 */
@RestController
@RequestMapping("/user")
public class UserCtrl extends BaseCtrl {

    @Autowired
    private IUserService iUserService;

    @PostMapping("/add")
    public BaseResponse<Integer> addUser(User user){
        return iUserService.addUser(user);
    }
}

1.一直清楚ctrl里面不能里面有太多逻辑,所以在service层进行了数据的封装处理,那么问题来了,我service的返回结果都是BaseResponse…如下,返回的数据结构辨识度就下降了不少:

public interface IUserService {
    BaseResponse<Integer> addUser(User user);
    BaseResponse<List<User>> userList(User user);
    int updateUserInfo(User user);
}

2.我的service实现里面还要判断各种逻辑业务逻辑混乱,并封装,是不是有种吐血的冲动….,如下:

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public BaseResponse<Integer> addUser(User user) {
        BaseResponse baseResponse = new BaseResponse();
        //判断参数缺失
        if(StringUtils.isEmpty(user.getUserName())){
            baseResponse.setCode(40001);
            baseResponse.setMessage("参数缺失");
            baseResponse.setData(0);
            return baseResponse;
        }
        //异常捕捉
        int code;
        String msg;
        int data=0;
        try{
            data = userMapper.addUser(user);
            code=200;
            msg="成功";
        }catch (Exception e){
            code=500;
            msg="服务器异常";
        }
        baseResponse.setCode(code);
        baseResponse.setMessage(msg);
        baseResponse.setData(data);
        return baseResponse;
    }
} 

3.更有甚者,不按约定来的也有,不是返回的BaseResponse,返回其他类型的(第一种)。
4.不易于扩展。后面数据结构需要调整的话,改起来也是费神。
5.其他…

注:隐去了部分相关注释,其实有些重复代码也可以再封装一下什么的,就不多去追究了,重点不在那。上面的代码点夸张的嫌疑,但是的确有这种接口开发的存在。虽然我不想承认几年前我真的干过,那时候前后端分离开发还没这么普及….

采用全局拦截

统一拦截,大家其实很容易想到的是AOP和拦截器做,其实更倾向于AOP,其实是可以做的。但是!Spring已经提供了一个类用于处理这种事情,就是:ResponseBodyAdvice,全包名:org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;意思很明确:返回体建议。

就直接上代码了:

@RestController
@RequestMapping("/user")
public class UserCtrl extends BaseCtrl {

    @Autowired
    private IUserService iUserService;

    @PostMapping("/add")
    public int addUser(User user){
        return iUserService.addUser(user);
    }

    @PostMapping("/list")
    public BaseResponse<List<User>> userList(User user){
        return iUserService.userList(user);
    }

}
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int addUser(User user) {
        return userMapper.addUser(user);
    }

    @Override
    public BaseResponse<List<User>> userList(User user) {
        BaseResponse<List<User>> baseResponse = new BaseResponse<>();
        baseResponse.setCode(200);
        baseResponse.setData(userMapper.userList(user));
        baseResponse.setMessage("成功");
        return baseResponse;
    }
}  

拦截返回体:

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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;

/**
 * function :返回值拦截自定义
 * @author :mayao
 * @date :2018/4/14
 */
@Slf4j
@ControllerAdvice(basePackages = { "com.mayao.ctrls"})
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        //判断支持的类型,因为我们定义的BaseResponse 里面的data可能是任何类型,这里就不判断统一放过
        //如果你想对执行的返回体进行操作,可将上方的Object换成你自己的类型
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
                                            ServerHttpResponse serverHttpResponse) {

        //注解@Slf4j所带,属于非常推荐的lombok项目,可以去看看我的idea插件去了解一下
        log.info("请求返回数据类型class={}",body.getClass().getName());
        BaseResponse result=null;
        //兼容原来的接口返回
        if(body instanceof BaseResponse){
            result=(BaseResponse)body;
        }else{
            result=new BaseResponse();
            if(null!=body&&!"".equals(body)){
                result.setCode(200);
                result.setMessage("成功");
                result.setData(body);
            }
        }
        if(log.isDebugEnabled()){
            log.debug("响应参数:{} ", JSONUtil.toJson(result));
        }
        return result;
    }
}

末:
这里,全局统一拦截返回兼容了原来的老接口的返回。
至于接口异常的情况。异常的自定义,及异常的全局处理就是必不可少了的。
自定义异常及异常全局处理;

### 如何在前端解析和渲染来自后端的Markdown数据 对于在前端解析并渲染由后端返回的Markdown内容,可以采用Vue框架配合`vue-markdown`插件的方式完成这一需求[^1]。 #### 安装依赖库 首先需确保项目环境中已安装必要的npm包。通过命令行工具执行如下指令以获取所需资源: ```bash npm install vue-markdown --save ``` #### 配置Vue应用 接着,在Vue实例或单文件组件中引入刚才添加的`vue-markdown`模块,并将其作为局部/全局组件注册以便后续调用: ```javascript import VueMarkdown from 'vue-markdown' export default { components: { VueMarkdown // 注册组件 }, data() { return { mdContent: '' // 存储从服务器接收到的Markdown文本 } }, methods: { async fetchMarkdownData() { try { const response = await axios.get('/api/markdown'); // 假设这是获取Markdown数据的服务接口路径 this.mdContent = response.data; // 将服务端响应的数据赋值给data属性中的变量 } catch (error) { console.error('Failed to load markdown content', error); } } }, mounted() { this.fetchMarkdownData(); // 组件挂载完成后立即请求加载Markdown数据 } } ``` 上述代码片段展示了如何创建一个异步函数用于向指定URL发起GET请求从而取得远程存储的Markdown文档;一旦成功接收,则更新视图模型内的对应字段,触发界面刷新显示转换后的HTML结构。 为了安全起见,建议对输入做适当过滤防止XSS攻击等问题的发生。此外,考虑到用户体验优化方面的需求,可以在发送AJAX之前展示loading动画提示用户正在等待内容加载完毕再呈现最终效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值