简体   繁体   English

JSP和SPRING Boot:从JSON输入生成CSV文件吗?

[英]JSP and SPRING Boot : Generate CSV file from JSON input?

I did some research but could not find how to solve this. 我做了一些研究,但是找不到解决方法。 I want to give the possibility to export to CSV some records from my database when a user click on "Export Records withoud mailId" on clien side. 当用户单击客户侧的“使用mailId导出记录时”,我希望能够从数据库中将一些记录导出到CSV。 What is the best way to achieve this? 实现此目标的最佳方法是什么? In my research I find out that people use only Servlets as examples but for me I dont use Servlets. 在我的研究中,我发现人们仅使用Servlet作为示例,但对我而言,我不使用Servlet。

This is my controller: 这是我的控制器:

 @RequestMapping(value = "/eblnotif/exportMailId", method = RequestMethod.POST, produces = "application/json")
        public @ResponseBody List<EblNotifResource> exportMailIdCsv(@RequestBody Filters filters)
                throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
                SecurityException, IOException {

            List<EblNotif> eblnotif_list = accountSservice.exportMailIdCsv(filters);

            List<EblNotifResource> eblnotifres = new ArrayList<>();

            for (EblNotif eblNotif : eblnotif_list) {
                EblNotifResource eblres = new EblNotifResource();
                eblres.setFormName(eblNotif.getFormName());
                eblres.setSendingDate(eblNotif.getSendingDate());
                eblres.setMode(eblNotif.getMode());
                eblres.setLanguage(eblNotif.getLanguage());
                eblres.setGpart(eblNotif.getGpart());
                eblres.setEmail(eblNotif.getEmail());
                eblres.setMailId(eblNotif.getMailId());
                eblnotifres.add(eblres);
            }
            return eblnotifres;
    }
}

And gives back to the client (JSP) this json format: 并将此json格式返回给客户端(JSP):

 [
   {
      "formName":"FormName1",
      "mode":"S",
      "language":"F",
      "sendingDate":"2017-04-03",
      "gpart":"555",
      "email":"",
      "mailId":"96318"
   },
   {
      "formName":"FormName2",
      "mode":"S",
      "language":"F",
      "sendingDate":"2017-04-03",
      "gpart":"444",
      "email":"",
      "mailId":"96325"
   }
]

The desired output in the csv will be something like: 所需的csv输出如下所示:

formName;mode;language;sendingDate;gpart;email;mailId
FormName1;S;F;2017-04-03;555;testing@test;96318
FormName2;S;F;2017-04-03;444;testing@test;96325

If a CSV download is required only as a one-off case, converting the relevant objects inside the controller method is probably the easiest option. 如果只需要一次性下载CSV,则在控制器方法内部转换相关对象可能是最简单的选择。 However, if such download is required in multiple places, it may be more beneficial to add CSV support to Spring MVC Rest through an HttpMessageConverter in the future. 但是,如果需要在多个位置进行这种下载,则将来通过HttpMessageConverter向Spring MVC Rest添加CSV支持可能会更有益。

Step 1 : Optional, but recommended 第1步 :可选,但建议

Use a CSV conversion library like OpenCSV , uniVocity or Smooks (just the CSV parser) to convert objects to and from CSV. 使用OpenCSVuniVocitySmooks (仅CSV解析器)之类的CSV转换库在CSV之间进行对象转换。 Use of a good library will save a lot of boilerplate code, and can also be used to extend support for additional formats like tab-separated values (TSV) and fixed-width columns. 使用良好的库将节省大量样板代码,还可用于扩展对其他格式的支持,例如制表符分隔的值(TSV)和固定宽度的列。

Step 2 : Implement GenericHttpMessageConverter 步骤2 :实现GenericHttpMessageConverter

Create an implementation of GenericHttpMessageConverter to convert objects to and from CSV using the CSV conversion library selected on step 1. This step is a bit tricky because an HttpMessageConverter is typically used to convert a single object to the desired content type, whereas CSV content is a collection of objects (each row representing an object). 创建GenericHttpMessageConverter的实现,以使用在步骤1中选择的CSV转换库将对象与CSV相互转换。此步骤有点棘手,因为HttpMessageConverter通常用于将单个对象转换为所需的内容类型,而CSV内容是对象的集合(每行代表一个对象)。 However, the Spring team has provided an excellent sample in Jaxb2CollectionHttpMessageConverter for converting collections of objects to the desired content type. 但是,Spring团队在Jaxb2CollectionHttpMessageConverter提供了一个出色的示例,用于将对象的集合转换为所需的内容类型。 The following points need to be kept in mind: 需要牢记以下几点:

  1. The boolean canRead(Class<?>, MediaType) method should be made to always return false as CSV content is a collection of objects so it cannot be read into a single object specified by a type. 可以使boolean canRead(Class<?>, MediaType)方法始终返回false因为CSV内容是对象的集合,因此无法将其读取为类型指定的单个对象。
  2. The boolean canRead(Type, Class<?>, MediaType) method should examine the Type to ensure that it specifies a Collection type and that the type of elements that the collection is expected to hold has also been specified. boolean canRead(Type, Class<?>, MediaType)方法应检查Type以确保它指定Collection类型,并且还指定了期望该collection保留的元素类型。
  3. The T read(Type, Class<?>, HttpInputMessage) method should be implemented to read CSV content. 应该实现T read(Type, Class<?>, HttpInputMessage)方法来读取CSV内容。
  4. The void write(T, Type, Class<?>, HttpInputMessage) method should be implemented to write CSV content. 应该实现void write(T, Type, Class<?>, HttpInputMessage)方法来写入CSV内容。

Step 3 : The CSV message converter should be registered in the configuration 步骤3 :CSV消息转换器应在配置中注册

@Override
protected void configureMessageConverters(final List<HttpMessageConverter<?>> converters)
{
  converters.add(csvMessageConverter());

  super.addDefaultHttpMessageConverters(converters);
}

Step 4 : Controller methods should be made to return a collection of the required objects 步骤4 :应使用控制器方法来返回所需对象的集合

public List<?> get() { ... }

A sample application is available on Github showing this in action. Github上有一个示例应用程序显示了这一功能。 Start the application and then send requests to http://localhost:8080/persons.csv or http://localhost:8080/persons.json to retrieve data in CSV or JSON formats respectively. 启动应用程序,然后将请求发送到http://localhost:8080/persons.csvhttp://localhost:8080/persons.json分别检索CSV或JSON格式的数据。

There are a number of ways to convert to a CSV but one way 有多种方法可以转换为CSV,但一种方法

    @RequestMapping(value = "/eblnotif/exportMailId", method = RequestMethod.POST, produces = "application/json")
public @ResponseBody String exportMailIdCsv(@RequestBody Filters filters) throws IllegalAccessException,
        IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {

    List<EblNotif> eblnotif_list = accountSservice.exportMailIdCsv(filters);

    String separator = ";";
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    StringBuilder sb = new StringBuilder();
    sb.append("formName;mode;language;sendingDate;gpart;email;mailId").append(System.lineSeparator());
    for (EblNotif eblNotif : eblnotif_list) {
        sb.append(eblNotif.getFormName()).append(separator);
        sb.append(eblNotif.getMode()).append(separator);
        sb.append(eblNotif.getLanguage()).append(separator);
        sb.append(dateFormat.format(eblNotif.getSendingDate())).append(separator);
        sb.append(eblNotif.getGpart()).append(separator);
        sb.append(eblNotif.getEmail()).append(separator);
        sb.append(eblNotif.getMailId()).append(separator);
        sb.append(System.lineSeparator());
    }
    return sb.toString();
}

Using Apache Commons CSV you can do something like: 使用Apache Commons CSV,您可以执行以下操作:

 @RequestMapping(value = "/download/eblnotif")
    public void download(@RequestBody @Valid Filters filter,
                         HttpServletResponse httpServletResponse) throws Exception {
        List<EblNotifResource> resources = //find from the fitler 
        CSVPrinter csvPrinter = CSVWriterUtil.transformResourcesToCSVPrinter(new BufferedWriter(httpServletResponse.getWriter()), resources);
        httpServletResponse.setHeader("Content-Disposition", "attachment; filename=\"file.csv\"");
        csvPrinter.flush();
        csvPrinter.close();
    }


    public final class CSVWriterUtil {

    private static final String NEW_LINE_SEPARATOR = "\n";

    private CSVWriterUtil() {
    }

    public static CSVPrinter transformResourcesToCSVPrinter(Writer writer, List<EblNotifResource> eblNotifResources) {
        try {
            CSVPrinter csvPrinter = new CSVPrinter(new BufferedWriter(writer), CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR));
            for (EblNotifResource eblNotifResource : eblNotifResources) {
                List<String> dataRecords = new ArrayList<>();
                dataRecords.add(eblNotifResource.getFormName());
                dataRecords.add(eblNotifResource.getSendingDate());
                //...etc 
                csvPrinter.printRecord(dataRecords);
            }
            return csvPrinter;
        } catch (IOException e) {
            throw new SystemException("Exception occurred while converting file", e);
        }
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM