You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot配置Gson序列化如何按请求指定版本适配@Since/@Until

动态配置Gson版本适配请求属性的Spring Boot实现

你可以通过自定义GsonHttpMessageConverter实现动态版本控制,无需手动返回String类型。核心思路是让Spring的消息转换器在序列化时,从当前请求上下文获取版本号,创建对应版本的Gson实例完成序列化。

1. 自定义版本化Gson消息转换器

继承Spring默认的GsonHttpMessageConverter,重写序列化方法,动态获取请求中的版本号并生成对应Gson实例:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class VersionedGsonHttpMessageConverter extends GsonHttpMessageConverter {

    // 缓存不同版本的Gson实例,避免重复创建浪费资源
    private final Map<Double, Gson> gsonCache = new ConcurrentHashMap<>();
    // 基础Gson配置,统一设置全局序列化规则
    private final GsonBuilder baseGsonBuilder = new GsonBuilder()
            .serializeNulls()
            .setDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            String versionStr = attributes.getAttribute("version", 0); // 从RequestScope获取version属性
            if (versionStr != null) {
                try {
                    double version = Double.parseDouble(versionStr);
                    // 缓存中不存在则创建对应版本的Gson实例
                    Gson versionedGson = gsonCache.computeIfAbsent(version, v -> 
                            baseGsonBuilder.setVersion(v).create());
                    // 执行序列化并写入响应
                    String json = versionedGson.toJson(object, type);
                    outputMessage.getBody().write(json.getBytes(getDefaultCharset()));
                    return;
                } catch (NumberFormatException e) {
                    // 版本格式错误时, fallback到默认逻辑
                }
            }
        }
        // 无有效版本时,使用默认Gson配置序列化
        super.writeInternal(object, type, outputMessage);
    }
}

2. 替换Spring默认的Gson转换器

在WebMvc配置类中注册自定义转换器,替换掉Spring自带的GsonHttpMessageConverter:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public GsonHttpMessageConverter versionedGsonHttpMessageConverter() {
        return new VersionedGsonHttpMessageConverter();
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 移除默认的Gson转换器
        converters.removeIf(converter -> converter instanceof GsonHttpMessageConverter);
        // 添加自定义版本化转换器
        converters.add(versionedGsonHttpMessageConverter());
    }
}

3. 确保请求属性version被正确设置

需要确保version属性在请求到达控制器之前存入请求上下文,比如通过拦截器从请求参数、Header等位置获取并设置:

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class VersionInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 示例:从请求参数中获取version,可根据实际需求改为Header或其他来源
        String version = request.getParameter("version");
        if (version != null) {
            request.setAttribute("version", version);
        }
        return true;
    }
}

然后在WebMvc配置类中注册拦截器:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    // ... 之前的转换器配置

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new VersionInterceptor());
    }
}

控制器使用方式

现在你的控制器可以直接返回User对象,转换器会自动根据请求中的version属性选择对应版本的Gson进行序列化:

@GetMapping("/users/{id}")
public User getUserById(@PathVariable("id") String id, @RequestAttribute(value = "version", required = false) String version) {
    User user = userRepository.getUserById(id);
    // 无需手动序列化,直接返回对象即可
    return user;
}

内容的提问来源于stack exchange,提问作者Felipe Quecole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 02:55:55