【问题标题】:Jax-rs json pretty outputJax-rs json 漂亮的输出
【发布时间】:2012-05-18 22:05:15
【问题描述】:

当我使用 Java 时

@Produces("application/json")

注释输出未格式化为人类可读的形式。我如何做到这一点?

【问题讨论】:

  • 你用的是什么 json-serializer?
  • 只使用 netbeans 标准。使用向导“来自实体类的新 RESTful Web 服务”创建我是新手,但我认为它是杰克逊?
  • 所以问题是我在哪里可以更改 netbeans 中的输出格式。我在谷歌上找到了一些信息。但它只是关于 ObjectMapper。 Netbeans 隐藏了所有这些。我必须扩展哪个类或要覆盖的方法?那我该如何让它发挥作用呢?
  • 你使用哪台服务器,为什么要使用漂亮的打印?

标签: java jax-rs jackson pretty-print


【解决方案1】:

Jersey 1.x 的替代方案:

org.codehaus.jackson.map.ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);

【讨论】:

    【解决方案2】:

    如果你使用 jersey-media-json-binding 依赖,它使用 Yasson(JSR-367 的官方 RI)和 JAVAX-JSON,你可以引入漂亮的打印如下:

    import javax.json.bind.Jsonb;
    import javax.json.bind.JsonbBuilder;
    import javax.json.bind.JsonbConfig;
    import javax.ws.rs.ext.ContextResolver;
    import javax.ws.rs.ext.Provider;
    
    @Provider
    public class RandomConfig implements ContextResolver<Jsonb> {
        private final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withFormatting(true));
    
        public RandomConfig() { }
    
        @Override
        public Jsonb getContext(Class<?> objectType) {
            return jsonb;
        }
    }
    

    【讨论】:

    • 这个问题是多年前提出的,这是目前最好的开箱即用方式。我要补充一点,您可以通过在构造函数中接受 @Context UriInfo uriInfo 并根据 uriInfo 属性返回不同的 Jsonb 实例,从而以 URL 查询参数为条件。
    【解决方案3】:

    仅作记录,如果您只想为某些资源启用漂亮输出,您可以在资源方法上使用the @JacksonFeatures annotation

    示例如下:

    @Produces(MediaType.APPLICATION_JSON)
    @JacksonFeatures(serializationEnable =  { SerializationFeature.INDENT_OUTPUT })
    public Bean resource() {
        return new Bean();
    }
    

    【讨论】:

    • @JacksonFeatures 仅适用于方法,而非类。
    【解决方案4】:

    如果你使用的是Spring,那么你可以全局设置属性

    spring.jackson.serialization.INDENT_OUTPUT=true
    

    更多信息https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html

    【讨论】:

      【解决方案5】:

      这就是如何根据查询字符串中“pretty”的存在正确地进行条件漂亮/非漂亮 json 输出。

      创建一个实现ContainerResponseFilterPrettyFilter,它将在每个请求上执行:

      @Provider
      public class PrettyFilter implements ContainerResponseFilter {
      
          @Override
          public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException {
      
              UriInfo uriInfo = reqCtx.getUriInfo();
              //log.info("prettyFilter: "+uriInfo.getPath());
      
              MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
              if(queryParameters.containsKey("pretty")) {
                  ObjectWriterInjector.set(new IndentingModifier(true));
              }
      
          }
      
          public static class IndentingModifier extends ObjectWriterModifier {
      
              private final boolean indent;
      
              public IndentingModifier(boolean indent) {
                  this.indent = indent;
              }
      
      
              @Override
              public ObjectWriter modify(EndpointConfigBase<?> endpointConfigBase, MultivaluedMap<String, Object> multivaluedMap, Object o, ObjectWriter objectWriter, JsonGenerator jsonGenerator) throws IOException {
                  if(indent) jsonGenerator.useDefaultPrettyPrinter();
                  return objectWriter;
              }
          }
      }
      

      差不多就是这样!

      您需要确保 Jersey 通过自动包扫描或手动注册来使用此类。

      花了几个小时试图实现这一目标,发现之前没有人发布过现成的解决方案。

      【讨论】:

      • 这是迄今为止最好的解决方案,我希望我能投票两次。不要忘记在您的ResourceConfig 中使用register(PrettyFilter.class)
      【解决方案6】:

      基于有用的 DaTroop 的回答,这里是另一个版本,它允许根据“漂亮”参数的缺失或存在在优化的 json 和格式化的 json 之间进行选择:

      package test;
      
      
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.Context;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.core.MultivaluedMap;
      import javax.ws.rs.core.UriInfo;
      import javax.ws.rs.ext.ContextResolver;
      import javax.ws.rs.ext.Provider;
      
      import org.codehaus.jackson.map.ObjectMapper;
      import org.codehaus.jackson.map.SerializationConfig;
      
      @Provider
      @Produces(MediaType.APPLICATION_JSON)
      public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
      
          private ObjectMapper prettyPrintObjectMapper;
          private UriInfo uriInfoContext;
      
          public JacksonContextResolver(@Context UriInfo uriInfoContext) throws Exception {
              this.uriInfoContext = uriInfoContext;
      
              this.prettyPrintObjectMapper = new ObjectMapper();
              this.prettyPrintObjectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
          }
      
          @Override
          public ObjectMapper getContext(Class<?> objectType) {
      
              try {
                  MultivaluedMap<String, String> queryParameters = uriInfoContext.getQueryParameters();
                  if(queryParameters.containsKey("pretty")) {
                      return prettyPrintObjectMapper;
                  }
      
              } catch(Exception e) {
                  // protect from invalid access to uriInfoContext.getQueryParameters()
              }
      
              return null; // use default mapper
          }
      }
      

      【讨论】:

      • 虽然这是一个很好的解决方案 - 它只在第一次调用资源时起作用。在那之后,提供者已经注册并且你被困在漂亮的印刷品上(或没有)。要获得真正的灵活性,请选择过滤器解决方案。
      【解决方案7】:

      在项目的任何位置创建此类。它将在部署时加载。请注意 .configure(SerializationConfig.Feature.INDENT_OUTPUT, true); 配置映射器以格式化输出。

      对于 Jackson 2.0 及更高版本,将两个 .configure() 行替换为: .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false) .configure(SerializationFeature.INDENT_OUTPUT, true);

      并相应地更改您的导入。

      package com.secret;
      
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.ext.ContextResolver;
      import javax.ws.rs.ext.Provider;
      import org.codehaus.jackson.map.DeserializationConfig;
      import org.codehaus.jackson.map.ObjectMapper;
      import org.codehaus.jackson.map.SerializationConfig;
      
      /**
       *
       * @author secret
       */
      @Provider
      @Produces(MediaType.APPLICATION_JSON)
      public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
          private ObjectMapper objectMapper;
      
          public JacksonContextResolver() throws Exception {
              this.objectMapper = new ObjectMapper();
          this.objectMapper
              .configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
              .configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
          }
      
          @Override
          public ObjectMapper getContext(Class<?> objectType) {
              return objectMapper;
          }
      }
      

      请记住,格式化会对性能产生负面影响。

      【讨论】:

      • Jersey 如何知道使用这个上下文解析器,而不是 Jackson 内置的 JAXRS 提供程序?
      • 带有注解@Provider
      猜你喜欢
      • 2014-12-13
      • 2015-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多