【问题标题】:JSP and SPRING Boot : Generate CSV file from JSON input?JSP 和 SPRING Boot:从 JSON 输入生成 CSV 文件?
【发布时间】:2017-10-20 16:28:36
【问题描述】:

我做了一些研究,但找不到解决方法。当用户在客户端单击“导出没有 mailId 的记录”时,我想提供将我的数据库中的一些记录导出到 CSV 的可能性。实现这一目标的最佳方法是什么?在我的研究中,我发现人们只使用 Servlet 作为示例,但对我而言,我不使用 Servlet。

这是我的控制器:

 @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;
    }
}

并将这个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"
   }
]

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

【问题讨论】:

  • 为什么不在控制器方法中将其转换为 CSV 并将生成的 CSV 字符串作为响应正文返回?
  • 您好,感谢您的回答。因为我无法做到。如果我立即在我的控制器中转换它也很好。您能否参考我的链接或示例如何实现它?谢谢

标签: java spring csv spring-boot


【解决方案1】:

如果仅需要一次性下载 CSV,则在控制器方法中转换相关对象可能是最简单的选择。但是,如果在多个地方都需要这样的下载,将来通过HttpMessageConverter 为 Spring MVC Rest 添加 CSV 支持可能会更有益。

第 1 步:可选,但推荐

使用 CSV 转换库,如 OpenCSVuniVocitySmooks(只是 CSV 解析器)将对象与 CSV 相互转换。使用好的库将节省大量样板代码,还可用于扩展对其他格式的支持,如制表符分隔值 (TSV) 和固定宽度的列。

第二步:实现GenericHttpMessageConverter

创建GenericHttpMessageConverter 的实现,以使用在步骤 1 中选择的 CSV 转换库将对象与 CSV 进行转换。这一步有点棘手,因为 HttpMessageConverter 通常用于将单个对象转换为所需的内容类型,而 CSV 内容是对象的集合(每一行代表一个对象)。但是,Spring 团队在 Jaxb2CollectionHttpMessageConverter 中提供了一个出色的示例,用于将对象集合转换为所需的内容类型。需要牢记以下几点:

  1. boolean canRead(Class&lt;?&gt;, MediaType) 方法应始终返回 false,因为 CSV 内容是对象的集合,因此无法读取到由类型指定的单个对象中。
  2. boolean canRead(Type, Class&lt;?&gt;, MediaType) 方法应检查 Type 以确保它指定了 Collection 类型,并且还指定了集合预期保存的元素类型。
  3. 应该实现T read(Type, Class&lt;?&gt;, HttpInputMessage) 方法来读取CSV 内容。
  4. 应该实现void write(T, Type, Class&lt;?&gt;, HttpInputMessage) 方法来写入CSV 内容。

第 3 步:应该在配置中注册 CSV 消息转换器

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

  super.addDefaultHttpMessageConverters(converters);
}

第 4 步:控制器方法应返回所需对象的集合

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

on Github 提供了一个示例应用程序,展示了这一点。启动应用程序,然后向http://localhost:8080/persons.csvhttp://localhost:8080/persons.json 发送请求,分别以 CSV 或 JSON 格式检索数据。

【讨论】:

    【解决方案2】:

    有多种方法可以转换为 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();
    }
    

    【讨论】:

      【解决方案3】:

      使用 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);
              }
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-01
        • 1970-01-01
        • 2019-06-24
        • 1970-01-01
        • 2017-12-12
        • 1970-01-01
        • 2015-05-17
        相关资源
        最近更新 更多