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

如何在Java Spring接口中避免使用StringHolder类仍保留指定JSON输出结构?

优雅替代StringHolder类返回指定JSON结构的方案

你现在是为了返回{"fileS3Id": "xxx"}这种JSON结构,不得不专门定义了StringHolder类,觉得这个类有点多余对吧?这里有几种更优雅的方案可以帮你避免创建这个冗余类:

方案1:直接返回Map<String, String>

这是最简单直接的方式,Spring的消息转换器会自动把Map序列化成你需要的JSON结构,完全不需要额外类:

@GetMapping("/{campaign}")
@SneakyThrows
public Map<String, String> downloadRawFactDataS3(@PathVariable Integer campaign) {
    String selectDataQuery = new RawFactSelectTemplate(campaign).translate().getSqlQuery();
    String s3Id = service.downloadDataFilledTemplate(campaign, selectDataQuery);
    
    Map<String, String> result = new HashMap<>();
    result.put("fileS3Id", s3Id);
    return result;
}

方案2:用匿名类配合ResponseEntity

如果你想保持对象语义又不想写单独的类,可以用匿名内部类,Spring的Jackson序列化器能完美处理这种结构:

@GetMapping("/{campaign}")
@SneakyThrows
public ResponseEntity<?> downloadRawFactDataS3(@PathVariable Integer campaign) {
    String selectDataQuery = new RawFactSelectTemplate(campaign).translate().getSqlQuery();
    String s3Id = service.downloadDataFilledTemplate(campaign, selectDataQuery);
    
    return ResponseEntity.ok(new Object() {
        public final String fileS3Id = s3Id;
    });
}

注意这里把字段声明为final,确保序列化时能被Jackson正确识别。

方案3:使用Jackson的ObjectNode

如果你的项目依赖Jackson(Spring Boot默认集成),可以直接用ObjectNode来构建JSON结构,这种方式对JSON的控制更灵活,适合需要动态调整字段的场景:

@GetMapping("/{campaign}")
@SneakyThrows
public ObjectNode downloadRawFactDataS3(@PathVariable Integer campaign) {
    String selectDataQuery = new RawFactSelectTemplate(campaign).translate().getSqlQuery();
    String s3Id = service.downloadDataFilledTemplate(campaign, selectDataQuery);
    
    ObjectMapper objectMapper = new ObjectMapper();
    ObjectNode resultNode = objectMapper.createObjectNode();
    resultNode.put("fileS3Id", s3Id);
    return resultNode;
}

方案4:使用Java 16+的Record特性

如果你的项目使用Java 16或更高版本,Record是兼顾优雅和规范的最佳选择——它是Java官方提供的轻量级数据载体,比Lombok注解的POJO简洁太多,甚至可以直接在接口类内部定义:

// 直接在接口类里定义这个Record,无需单独创建文件
private record StringHolder(String fileS3Id) {}

@GetMapping("/{campaign}")
@SneakyThrows
public StringHolder downloadRawFactDataS3(@PathVariable Integer campaign) {
    String selectDataQuery = new RawFactSelectTemplate(campaign).translate().getSqlQuery();
    String s3Id = service.downloadDataFilledTemplate(campaign, selectDataQuery);
    return new StringHolder(s3Id);
}

虽然还是定义了一个载体,但Record只需要一行代码,语义清晰且完全符合Java规范。

总结

  • 简单场景选Map,零额外代码;
  • 想保持对象语义选匿名类;
  • 需要动态JSON操作选ObjectNode;
  • Java 16+推荐用Record,优雅又规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:34:05