简体   繁体   中英

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. 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.

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:

 [
   {
      "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:

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. 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.

Step 1 : Optional, but recommended

Use a CSV conversion library like OpenCSV , uniVocity or Smooks (just the CSV parser) to convert objects to and from 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.

Step 2 : Implement 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). However, the Spring team has provided an excellent sample in Jaxb2CollectionHttpMessageConverter for converting collections of objects to the desired content type. 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.
  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.
  3. The T read(Type, Class<?>, HttpInputMessage) method should be implemented to read CSV content.
  4. The void write(T, Type, Class<?>, HttpInputMessage) method should be implemented to write CSV content.

Step 3 : The CSV message converter should be registered in the configuration

@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

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

A sample application is available on Github showing this in action. 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.

There are a number of ways to convert to a CSV but one way

    @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:

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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