Spring MVC --响应字段默认值设置

实现

定义一个实现 ResponseBodyAdvice 接口的类作为 ControllerAdviceBean 在将 Controller 方法返回值写入响应体前设置字段的默认值就可以了。

这里我们使用User 类做测试,该类定义如下。

@Data
@Accessors(chain = true)
public class User {

    private String username;

    private String password;

    private Address address;

    private List<String> interests;

    private Map<String, Object> extra;
}

@Data
public class Address {

    private String province;

    private String city;

}

注意我们的 User 类字段包括普通的 String 类型,自定义的类型、List 类型 及 Map 类型。

接口返回的通用格式使用 Result 类表示。

@Data
public class Result<T> {

    private Integer code;

    private String message;

    private T data;

    public static <T> Result<T> ok(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("OK");
        result.setData(data);
        return result;
    }

}

 我们定义一个测试接口如下。

@RestController
public class UserController {

    @GetMapping("/login")
    public Result<User> login() {
        User user = new User();
        Result<User> result = Result.ok(user);
        return result;
    }
}

 为了将 login 方法返回的 Result<User> 写入到响应体前设置默认字段值,我们可以定义 ResponseBodyAdvice 实现如下。

import org.springframework.beans.BeanUtils;
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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@ControllerAdvice
public class ResponseBodyDefaultValueAdvice implements ResponseBodyAdvice<Result<?>> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    	// 仅处理 Result 类型
        return returnType.getParameterType() == Result.class;
    }

    @Override
    public Result<?> beforeBodyWrite(Result<?> result, MethodParameter methodParameter, MediaType mediaType,
                                     Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
                                     ServerHttpResponse serverHttpResponse) {
        Object data = result.getData();
        if (data == null) {
            data = BeanUtils.instantiateClass(ReflectionUtils.findField(result.getClass(), "data").getType());
        }
        setDefault(data);
        return result;
    }

    private void setDefault(Object obj) {
        ReflectionUtils.doWithFields(obj.getClass(), field -> {
            ReflectionUtils.makeAccessible(field);
            Object val = ReflectionUtils.getField(field, obj);
            if (val != null) {
                return;
            }
            // 字段默认值
            Object defaultValue = null;
            if (field.getType() == String.class) {
                defaultValue = "";
            } else if (field.getType() == List.class) {
                defaultValue = Collections.emptyList();
            } else if (field.getType() == Map.class) {
                defaultValue = Collections.emptyMap();
            } else if (field.getType().getPackage().getName().startsWith("com.weiah")) {
                defaultValue = BeanUtils.instantiateClass(field.getType());
                setDefault(defaultValue);
            }
            // 设置字段默认值
            ReflectionUtils.setField(field, obj, defaultValue);
        });
    }
}

这里我们只处理 Result 类型的 Controller 方法返回值,返回值写入响应前,如果字段值为 null 则进行处理,并将 String 类型的值设置为空字符串、List 类型的值设置为空列表、Map 类型的值设置为空 Map 值,以及递归处理了自定义的类型。

测试接口返回内容如下。
 

{
    "code": 200,
    "message": "OK",
    "data": {
        "username": "",
        "password": "",
        "address": {
            "province": "",
            "city": ""
        },
        "interests": [],
        "extra": {}
    }
}

String、List、Map 以及自定义的 Address 类型都进行了处理,前端同学再也不会吐槽后端接口返回 null 了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值