gpt4 book ai didi

spring - 在 Spring Boot 中自动将 Rest Controller 序列化为 CSV 而不是 JSON

转载 作者:行者123 更新时间:2023-12-03 23:53:45 35 4
gpt4 key购买 nike

我正在寻找一个快速/简单的解决方案,如何将 Rest Controller 输出自动序列化为 CSV 而不是 JSON。我有最简单的 Spring Boot 应用程序:

@SpringBootApplication
public class CsvExportApplication {

public static void main(String[] args) {
SpringApplication.run(CsvExportApplication.class, args);
}
}

class User {
String name;
String surname;

public User(String name, String surname) {
this.name = name;
this.surname = surname;
}

public void setName(String name) {
this.name = name;
}

public void setSurname(String surname) {
this.surname = surname;
}

public String getName() {
return name;
}

public String getSurname() {
return surname;
}
}

@RestController
class UserController {
@GetMapping(value = "/users")
List<User> list() {
return Arrays.asList(new User("adam", "kowalsky"), new User("john", "smith"));
}
}

我用过 jackson-dataformat-csv并想出了以下序列化 List<User> 的代码至 String ,但理想情况下我不想更改其余 Controller 代码:
CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(User.class).withHeader();
mapper.writerFor(List.class).with(schema).writeValueAsString(users);

理想情况下,我希望我的 Controller 能够根据请求中的 Accept header 以 JSON 或 CSV 格式返回输出。

最佳答案

我设法通过以下方式实现我想要的:

  • 为 application/csv 定义自定义转换器
  • 转换器只能写入CSV(不支持读取)
  • 转换器使用 Jackon 的 ObjectMapper (以确保 CSV 和 JSON 输出使用例如相同的日期格式)
  • 转换器构建 jackson-dateformat-csv动态模式,因为当前不支持无模式写入:https://github.com/FasterXML/jackson-dataformats-text/issues/114

  • 代码:
    class CsvConverter<T> extends AbstractHttpMessageConverter<T> {

    private final ObjectMapper objectMapper;

    CsvConverter(ObjectMapper objectMapper) {
    super(new MediaType("application", "csv"));
    this.objectMapper = objectMapper;
    }

    @Override
    protected boolean supports(Class<?> clazz) {
    return true;
    }

    @Override
    protected T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
    throws IOException, HttpMessageNotReadableException {
    return null;
    }

    @Override
    protected void writeInternal(T object, HttpOutputMessage outputMessage)
    throws IOException, HttpMessageNotWritableException {
    try {
    ObjectWriter objectWriter = getCsvWriter(object);
    try (PrintWriter outputWriter = new PrintWriter(outputMessage.getBody())) {
    outputWriter.write(objectWriter.writeValueAsString(object));
    }
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }

    ObjectWriter getCsvWriter(T object) {
    Set<String> fields = getUniqueFieldNames(object);
    CsvSchema.Builder schemaBuilder = CsvSchema.builder().setUseHeader(true);
    for (String field : fields) {
    schemaBuilder.addColumn(field);
    }
    return new CsvMapper().writerFor(List.class).with(schemaBuilder.build());
    }

    Set<String> getUniqueFieldNames(T object) {
    try {
    JsonNode root = objectMapper.readTree(objectMapper.writeValueAsString(object));
    Set<String> uniqueFieldNames = new LinkedHashSet<>();
    root.forEach(element -> {
    Iterator<String> it = element.fieldNames();
    while (it.hasNext()) {
    String field = it.next();
    uniqueFieldNames.add(field);
    }
    });
    return uniqueFieldNames;
    } catch (IOException ex) {
    throw new RuntimeException(ex);
    }
    }
    }

    @Configuration
    class AppConfig implements WebMvcConfigurer {

    private final ObjectMapper objectMapper;

    AppConfig(ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(new CsvConverter<>(objectMapper));
    }
    }

    关于spring - 在 Spring Boot 中自动将 Rest Controller 序列化为 CSV 而不是 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53174072/

    35 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com