如何使Spring MVC返回CSV与返回JSON一样方便

时间:2014-01-05 19:08:34

标签: spring spring-mvc gradle jackson

我知道Spring MVC可以轻松返回Json格式的模型;但是,我尝试了很多不同的方法来返回CSV格式的模型(通过杰克逊),但无法成功。

我该怎么办?

我附上我的模型代码,控制器代码和gradle.build,如下所示:

非常感谢!

型号:

@JsonPropertyOrder({ "staffName", "name" })
public class Greeter
{
    String name;
    String staffName[];

    public String getName()
    {
        return name;
    }

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

    public String[] getStaffName()
    {
        return staffName;
    }

    public void setStaffName(String[] staffName)
    {
        this.staffName = staffName;
    }
}

控制器:

@Controller
public class GreetingController {

    @RequestMapping(value = "/greeter/json", method = RequestMethod.GET)
    public @ResponseBody
    Greeter getGreeterInJSON() {

        Greeter greeter = new Greeter();

        greeter.setName("default");
        greeter.setStaffName(new String[] { "ye", "lichi" });

        return greeter;

    }

    @RequestMapping(value = "/greeter/csv", method = RequestMethod.GET, consumes = "text/csv")
    public @ResponseBody
    Greeter getGreeterInCSV(HttpServletResponse response) {
        Greeter greeter = new Greeter();

        greeter.setName("default");
        greeter.setStaffName(new String[] { "ye", "lichi" });

        CsvMapper mapper = new CsvMapper();
        CsvSchema schema = mapper.schemaFor(Greeter.class);

        ObjectWriter writer = mapper.writer(schema.withLineSeparator("\n"));

        File greeterCSV = new File("greeterCSV.csv");

        try {
            writer.writeValue(greeterCSV, greeter);
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return greeter;
    }
}

build.gradle依赖项:

dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'

    compile ('org.springframework:spring-context:4.0.0.RELEASE')
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M6")
    compile("org.thymeleaf:thymeleaf-spring3:2.0.17")

    // compile "org.codehaus.jackson:jackson-mapper-asl:1.9.13"
    compile 'com.fasterxml.jackson.core:jackson-databind:2.3.0'
    compile 'com.fasterxml.jackson.core:jackson-core:2.3.0'
    compile 'com.fasterxml.jackson.core:jackson-annotations:2.3.0'

    compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.3.0'

    testCompile group: 'junit', name: 'junit', version: '4.+'
    testCompile "org.mockito:mockito-all:1.9.5"
}

编辑:


Tomcat错误:

HTTP状态415 -

输入状态报告

消息

描述服务器拒绝了此请求,因为请求实体的格式不受所请求方法所请求资源的支持。

3 个答案:

答案 0 :(得分:3)

您不想消费,但生成 csv。你拥有它的方式,服务期望输入以csv格式提供,这就是为什么它抱怨“请求实体的格式不受支持”。关键是“请求” - 它需要一些csv格式的输入。 将“消费”改为“生产”应该可以解决您的问题。

答案 1 :(得分:0)

我一直在寻找这个问题的答案,但遗憾的是没有找到,所以我将在这里举例说明。

您需要添加一个 CSV 消息转换器。此 @Configuration 执行此操作:

@Configuration
public class CsvConfiguration {

  @Bean
  JacksonToCsvHttpMessageConverter csvMessageConverter() {
    CsvMapper mapper = new CsvMapper();
    // configure mapper here
    mapper.registerModule(new JavaTimeModule());
    return new JacksonToCsvHttpMessageConverter(mapper);
  }

}

和转换器本身:

请注意,此简化版本不支持过滤器或视图。但是,如果您研究覆盖的方法 writeInternal,您应该能够添加这些功能,如果您需要它们。此外,不支持空集合,但如果您想支持空系列,可以使用空数组。

public class JacksonToCsvHttpMessageConverter extends AbstractJackson2HttpMessageConverter {

    protected JacksonToCsvHttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper, MediaType.parseMediaType("text/csv"));
    }

    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        if (object instanceof MappingJacksonValue) object = ((MappingJacksonValue) object).getValue();
        CsvMapper mapper = (CsvMapper) getObjectMapper();
        Class<?> klass = getType(object);
        CsvSchema schema = mapper.schemaFor(klass).withHeader();
        JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
        try (CsvGenerator generator = mapper.getFactory().createGenerator(outputMessage.getBody(), encoding)) {
            ObjectWriter writer = mapper.writer().with(schema);
            writer.writeValue(generator, object);
        }
    }

    private Class<?> getType(Object object) {
        if (object instanceof Collection) {
            Collection<?> c = (Collection<?>) object;
            return c.iterator().next().getClass();
        }
        if (object.getClass().isArray()) return object.getClass().getComponentType();
        return object.getClass();
    }

}

这将使所有传统的控制器方法都可以通过 Accept 标头的方式返回 CSV。 Accept: application/json 将产生 JSON 而 Accept: text/csv 将产生 CSV。当然,所有的 CsvMapper 约束都将适用,所以没有嵌套对象等。

@RestController
public class CsvController {

    @GetMapping("/records*")
    public CsvRecord[] getRecords() {
        return new CsvRecord[] { new CsvRecord(), new CsvRecord() };
    }

    @GetMapping("/record")
    public CsvRecord getRecord() {
        return new CsvRecord();
    }

    @JsonAutoDetect(fieldVisibility = Visibility.PUBLIC_ONLY)
    public static class CsvRecord {
        public String name = "aa";
    }

}

使用此配置将导致您的应用为 Accept: */* 请求返回 CSV。这很少是有意的,因此您可以通过添加以下配置将默认内容类型设置为 JSON:

@Configuration
public class WebConfig implements WebMvcConfigurer {

  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
  }
}

答案 2 :(得分:-2)

您正在使用GET,因此您希望回复的内容为CSV,因此请务必使用produce = &#34; text / csv&#34; 而不是使用=&#34; text / CSV&#34) 在这里: -

@RequestMapping(value = "/greeter/csv", method = RequestMethod.GET, consumes = "text/csv")
    public @ResponseBody

我们在发送一些

时使用消费