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

如何在Jackson序列化器中获取Quarkus请求的查询参数?

在Quarkus中实现基于请求参数的Jackson动态序列化

问题背景

我在Quarkus中开发一套可根据请求属性(如查询参数、请求头等)动态序列化JSON响应的方案,具体需求如下:

  • 用户发送包含指定语言的lang查询参数的GET请求:
@GET()
@Produces(MediaType.APPLICATION_JSON)
public Content getContent(
    @QueryParam("lang")
    @DefaultValue("en")
    Language language
) {
    // 从服务中获取并返回内容
}
  • Content类包含存储查找键的TranslatableString类型字段:
public @Value class TranslatableString {
    String key;
}
  • 自定义JsonSerializer需基于TranslatableString的键返回对应请求语言的翻译,但目前无法在序列化器内部获取请求的lang参数:
@ApplicationScoped
public class Serializer extends JsonSerializer<TranslatableString> {

    @Inject
    TranslationStore translations;

    @Override
    public void serialize(TranslatableString value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(
            translations.get(value.getKey(), /** ??-Language-?? **/ )
        );
    }
}

序列化器注册方式:

@Singleton
public class ObjectMapperConfig implements ObjectMapperCustomizer {

    @Inject
    Serializer serializer;

    @Override
    public void customize(ObjectMapper objectMapper) {
        objectMapper.registerModule(
            new SimpleModule()
                    .addSerializer(
                            TranslatableString.class,
                            serializer
                    )
        );
    }
}

核心疑问:有没有简便方法可以在Jackson的JsonSerializer内部获取用户提供的查询参数?

解决方案

方法1:使用请求作用域的语言上下文Bean

这是最贴合Quarkus依赖注入模型的方案,通过@RequestScoped Bean在请求生命周期内传递语言信息:

  1. 创建请求作用域的上下文Bean:
@RequestScoped
public class RequestLanguageContext {
    private Language currentLanguage;

    public Language getCurrentLanguage() {
        return currentLanguage;
    }

    public void setCurrentLanguage(Language currentLanguage) {
        this.currentLanguage = currentLanguage;
    }
}
  1. 在资源方法中注入并设置当前语言:
@GET()
@Produces(MediaType.APPLICATION_JSON)
public Content getContent(
    @QueryParam("lang")
    @DefaultValue("en")
    Language language,
    @Inject RequestLanguageContext languageContext
) {
    languageContext.setCurrentLanguage(language);
    // 从服务中获取并返回内容
}
  1. 在序列化器中注入上下文Bean获取语言:
@ApplicationScoped
public class Serializer extends JsonSerializer<TranslatableString> {

    @Inject
    TranslationStore translations;
    
    @Inject
    RequestLanguageContext languageContext;

    @Override
    public void serialize(TranslatableString value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(
            translations.get(value.getKey(), languageContext.getCurrentLanguage())
        );
    }
}

方法2:利用Quarkus RequestContextHolder访问请求属性

直接通过Quarkus提供的RequestContextHolder获取当前请求,从中取出预先设置的语言属性:

  1. 在资源方法中向请求属性存入语言:
@GET()
@Produces(MediaType.APPLICATION_JSON)
public Content getContent(
    @QueryParam("lang")
    @DefaultValue("en")
    Language language,
    @Context HttpServletRequest request
) {
    request.setAttribute("currentLang", language);
    // 从服务中获取并返回内容
}
  1. 在序列化器中获取请求并读取属性:
@ApplicationScoped
public class Serializer extends JsonSerializer<TranslatableString> {

    @Inject
    TranslationStore translations;

    @Override
    public void serialize(TranslatableString value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        HttpServletRequest request = (HttpServletRequest) RequestContextHolder.currentRequest().getAttribute("javax.servlet.request");
        Language language = (Language) request.getAttribute("currentLang");
        gen.writeString(
            translations.get(value.getKey(), language)
        );
    }
}

方法3:通过ThreadLocal传递语言上下文

如果不想依赖Quarkus的CDI或Servlet API,可以用ThreadLocal在请求线程内传递语言信息,注意要清理ThreadLocal避免内存泄漏:

  1. 创建ThreadLocal工具类:
public class LanguageContextHolder {
    private static final ThreadLocal<Language> LANG_HOLDER = new ThreadLocal<>();

    public static void setLanguage(Language language) {
        LANG_HOLDER.set(language);
    }

    public static Language getLanguage() {
        return LANG_HOLDER.get();
    }

    public static void clear() {
        LANG_HOLDER.remove();
    }
}
  1. 在资源方法中设置语言,并用过滤器自动清理:
@GET()
@Produces(MediaType.APPLICATION_JSON)
public Content getContent(
    @QueryParam("lang")
    @DefaultValue("en")
    Language language
) {
    LanguageContextHolder.setLanguage(language);
    // 从服务中获取并返回内容
}

// 添加过滤器确保请求结束后清理ThreadLocal
@WebFilter(urlPatterns = "/*")
public class LanguageCleanupFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } finally {
            LanguageContextHolder.clear();
        }
    }
}
  1. 在序列化器中获取语言:
@ApplicationScoped
public class Serializer extends JsonSerializer<TranslatableString> {

    @Inject
    TranslationStore translations;

    @Override
    public void serialize(TranslatableString value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        Language language = LanguageContextHolder.getLanguage();
        gen.writeString(
            translations.get(value.getKey(), language)
        );
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:35:42