如何在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在请求生命周期内传递语言信息:
- 创建请求作用域的上下文Bean:
@RequestScoped public class RequestLanguageContext { private Language currentLanguage; public Language getCurrentLanguage() { return currentLanguage; } public void setCurrentLanguage(Language currentLanguage) { this.currentLanguage = currentLanguage; } }
- 在资源方法中注入并设置当前语言:
@GET() @Produces(MediaType.APPLICATION_JSON) public Content getContent( @QueryParam("lang") @DefaultValue("en") Language language, @Inject RequestLanguageContext languageContext ) { languageContext.setCurrentLanguage(language); // 从服务中获取并返回内容 }
- 在序列化器中注入上下文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获取当前请求,从中取出预先设置的语言属性:
- 在资源方法中向请求属性存入语言:
@GET() @Produces(MediaType.APPLICATION_JSON) public Content getContent( @QueryParam("lang") @DefaultValue("en") Language language, @Context HttpServletRequest request ) { request.setAttribute("currentLang", language); // 从服务中获取并返回内容 }
- 在序列化器中获取请求并读取属性:
@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避免内存泄漏:
- 创建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(); } }
- 在资源方法中设置语言,并用过滤器自动清理:
@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(); } } }
- 在序列化器中获取语言:
@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
相关产品推荐
相关产品推荐

