Spring Content Negotiation / OpenCSV: получение пустого CSV

1

Я использую Spring Content Negotiation и OpenCSV для вывода CSV файла клиенту.

Итак, у меня есть этот контроллер:

@RequestMapping(value = { "", "/" }, method = RequestMethod.GET, produces = "text/csv")
@esponseStatus(HttpStatus.OK)
public Model getCustomersView(HttpServletRequest request, Model model)
    throws InvalidBusinessContractDataException {
    Customer[] customers = customerService.findCustomers();
    return model.addAttribute("customers", customers);
}

И этот Media Type Translator:

@Component("viewNameTranslator")
public final class MediaTypeRequestToViewTranslator implements
        RequestToViewNameTranslator {
    @Autowired
    private ContentNegotiationManager contentNegotiationManager;

    private DefaultRequestToViewNameTranslator defaultTranslator = new DefaultRequestToViewNameTranslator();

    // a list of media types to ignore - not output on the translated view
    private List<String> ignoredTypes = Arrays.asList("text/html");

    @Override
    public String getViewName(HttpServletRequest request) {
        // first resolve the media type (see below)
        String mediaType = resolveMediaType(request);

        // delegate to the default translator to get the view name
        String viewName = defaultTranslator.getViewName(request);

        // concatenate the resolved media type to the default name and return it
        return viewName + mediaType;
    }

    private String resolveMediaType(HttpServletRequest request) {
        try {
            // use the content negotiation manager to resolve the media type
            // from the request. The manager does it
            // according to its own search path and preferences - using the
            // suffix, using the Accept header and
            // preferring one of them. The result would always be a single type
            // or none at all, but it returns a list
            List<MediaType> types = contentNegotiationManager
                    .resolveMediaTypes(new ServletWebRequest(request));

            // resolve to a single type
            String type = types == null || types.size() == 0 ? "" : types
                    .get(0).toString();

            // if it not in the ignored media types - prepend a semi-colon and
            // return it
            return ignoredTypes.contains(type) ? "" : ";" + type;
        } catch (HttpMediaTypeNotAcceptableException e) {
            return "";
        }
    }
}

И эта точка зрения:

@Component("customers;text/csv")
public final class CustomerCsvView implements View {
    @Override
    public String getContentType() {
        return "text/csv";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        response.setContentType("text/csv");
        Customer[] customers = (Customer[]) model.get("customers");


        CSVWriter writer = new CSVWriter(new OutputStreamWriter(response
                .getOutputStream()));

        writer.writeNext(new String[] {"id", "fName", "lName"});
        for (Customer c : customers) {
                    System.out.println("FOO");
            writer.writeNext(new String[] {
                    new Long(c.getCustomerId()).toString(), c.getFirstName(), c.getLastName() });
        }
    }
}

Когда я нажимаю на этот контроллер с браузером, дважды появляется "FOO" на моей консоли, открывается диалоговое окно сохранения файла с загружаемым тестовым /CSV файлом и составляет 0 байт.

Это как изменения ответа не сохраняются.

Что?

  • 0
    ты используешь весну 3
Теги:
csv
spring

1 ответ

1
Лучший ответ

задайте тип содержимого и данные с флеша перед отправкой, затем закройте outputwriter

response.setContentType("text/csv;charset=utf-8")
response.setHeader("Content-Disposition","attachment; filename=\yourData.csv\"");


OutputStream resOs= response.getOutputStream();  
OutputStream buffOs= new BufferedOutputStream(resOs);   
OutputStreamWriter outputwriter = new OutputStreamWriter(buffOs);  

CsvWriter writer = new CsvWriter(outputwriter);  

 // write data in csvwrite in loop

наконец, закрыть флеш и закрыть его.

outputwriter.flush();   
outputwriter.close();

Будет лучше, если вы будете использовать @ResponseBody HttpMessageConverter с пружиной 3.0

В контроллере вам это нравится

@RequestMapping(value = "/getFullData2.html", method = RequestMethod.GET, consumes = "text/csv")
@ResponseBody // indicate to use a compatible HttpMessageConverter
public CsvResponse getFullData(HttpSession session) throws IOException {
      List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String) session.getAttribute("currentProject"));
      return new CsvResponse(allRecords, "yourData.csv");
}

Напишите HttpMessageConverter:

public class CsvMessageConverter extends AbstractHttpMessageConverter<CsvResponse> {
   public static final MediaType MEDIA_TYPE = new MediaType("text", "csv", Charset.forName("utf-8"));
   public CsvMessageConverter() {
       super(MEDIA_TYPE);
   }

   protected boolean supports(Class<?> clazz) {
       return CsvResponse.class.equals(clazz);
   }

   protected void writeInternal(CsvResponse response, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
       output.getHeaders().setContentType(MEDIA_TYPE);
       output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + response.getFilename() + "\"");
       OutputStream out = output.getBody();
       CsvWriter writer = new CsvWriter(new OutputStreamWriter(out), '\u0009');
       List<CompositeRequirement> allRecords = response.getRecords();
       for (int i = 1; i < allRecords.size(); i++) {
            CompositeRequirement aReq = allRecords.get(i);
            writer.write(aReq.toString());
       }
       writer.close();
   }
}

Простой объект для связывания

public class CsvResponse {    
   private final String filename;
   private final List<CompositeRequirement> records;

   public CsvResponse(List<CompositeRequirement> records, String filename) {
       this.records = records;
       this.filename = filename;
   }
   public String getFilename() {
       return filename;
   }
   public List<CompositeRequirement> getRecords() {
       return records;
   }
}
  • 0
    Конечно, / Facepalm. Итак, чем же HttpMessageConverter лучше, и можете ли вы указать мне на учебник?
  • 0
    обновить мой ответ

Ещё вопросы

Сообщество Overcoder
Наверх
Меню