[SPRING] Spring MVC 컨트롤러가 클라이언트에게 파일을 보내도록 설정하기
SPRINGSpring MVC 컨트롤러가 클라이언트에게 파일을 보내도록 설정하기
내 시나리오는 꽤 흔한 것 같아. 데이타베이스를 가지고 있고 Spring MVC 응용 프로그램이 컨트롤러에서 요청을 받아들이고 DB 서비스를 호출하여 데이터를 가져오고 그 데이터를 클라이언트에 CSV 파일로 보내길 원합니다. JavaCSV 라이브러리를 사용하여이 프로세스를 지원합니다. http://sourceforge.net/projects/javacsv/
나는 비슷한 일을하는 사람들의 몇 가지 예를 발견하고 올바른 것으로 보이는 것을 함께 수선했다. 내가이 방법을 쳤을 때, 실제로 아무 일도 일어나지 않았다.
HttpServletResponse의 outputStream에 데이터를 쓰는 것만으로 충분할 것이라고 생각했지만 분명히 뭔가 빠졌습니다.
여기 내 컨트롤러 코드 :
@RequestMapping(value="/getFullData.html", method = RequestMethod.GET)
public void getFullData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String)session.getAttribute("currentProject"));
response.setContentType("data: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, '\u0009');
for(int i=1;i <allRecords.size();i++){
CompositeRequirement aReq=allRecords.get(i);
writer.write(aReq.toString());
}
outputwriter.flush();
outputwriter.close();
};
내가 누명을 쓴 것은 무엇입니까? 기본적으로 그물 효과는 ... 아무것도 아닙니다. 헤더와 컨텐트 유형을 설정하면 브라우저가 응답을 받고 파일 다운로드 동작을 트리거하게됩니다.
해결법
-
==============================
1.Content-type이 잘못 설정 되었기 때문에 response.setContentType ( "data : text / csv; charset = utf-8) 대신 response.setContentType ("text / csv; charset = utf-8 " ").
Content-type이 잘못 설정 되었기 때문에 response.setContentType ( "data : text / csv; charset = utf-8) 대신 response.setContentType ("text / csv; charset = utf-8 " ").
또한 Spring 3를 사용하는 경우 코드 재사용을 위해 @ResponseBody HttpMessageConverter를 사용해야합니다. 예 :
-
==============================
2.피에르 대답을 바탕으로, 나는 변환기를했다. 다음은 전달 된 모든 객체에서 작동하는 전체 코드입니다.
피에르 대답을 바탕으로, 나는 변환기를했다. 다음은 전달 된 모든 객체에서 작동하는 전체 코드입니다.
public class TsvMessageConverter extends AbstractHttpMessageConverter<TsvResponse> { public static final MediaType MEDIA_TYPE = new MediaType("text", "tsv", Charset.forName("utf-8")); private static final Logger logger = LoggerFactory.getLogger(TsvMessageConverter.class); public TsvMessageConverter() { super(MEDIA_TYPE); } protected boolean supports(Class<?> clazz) { return TsvResponse.class.equals(clazz); } @Override protected TsvResponse readInternal(Class<? extends TsvResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return null; } protected void writeInternal(TsvResponse tsvResponse, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException { output.getHeaders().setContentType(MEDIA_TYPE); output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + tsvResponse.getFilename() + "\""); final OutputStream out = output.getBody(); writeColumnTitles(tsvResponse, out); if (tsvResponse.getRecords() != null && tsvResponse.getRecords().size() != 0) { writeRecords(tsvResponse, out); } out.close(); } private void writeRecords(TsvResponse response, OutputStream out) throws IOException { List<String> getters = getObjectGetters(response); for (final Object record : response.getRecords()) { for (String getter : getters) { try { Method method = ReflectionUtils.findMethod(record.getClass(), getter); out.write(method.invoke(record).toString().getBytes(Charset.forName("utf-8"))); out.write('\t'); } catch (IllegalAccessException | InvocationTargetException e) { logger.error("Erro ao transformar em CSV", e); } } out.write('\n'); } } private List<String> getObjectGetters(TsvResponse response) { List<String> getters = new ArrayList<>(); for (Method method : ReflectionUtils.getAllDeclaredMethods(response.getRecords().get(0).getClass())) { String methodName = method.getName(); if (methodName.startsWith("get") && !methodName.equals("getClass")) { getters.add(methodName); } } sort(getters); return getters; } private void writeColumnTitles(TsvResponse response, OutputStream out) throws IOException { for (String columnTitle : response.getColumnTitles()) { out.write(columnTitle.getBytes()); out.write('\t'); } out.write('\n'); } }
public class TsvResponse { private final String filename; private final List records; private final String[] columnTitles; public TsvResponse(List records, String filename, String ... columnTitles) { this.records = records; this.filename = filename; this.columnTitles = columnTitles; } public String getFilename() { return filename; } public List getRecords() { return records; } public String[] getColumnTitles() { return columnTitles; } }
Spring Context.xml에서 다음을 추가합니다.
<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="com.mypackage.TsvMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven>
따라서 다음과 같이 컨트롤러에서 사용할 수 있습니다.
@RequestMapping(value="/tsv", method= RequestMethod.GET, produces = "text/tsv") @ResponseBody public TsvResponse tsv() { return new TsvResponse(myListOfPojos, "fileName.tsv", "Name", "Email", "Phone", "Mobile"); }
from https://stackoverflow.com/questions/9913732/configuring-spring-mvc-controller-to-send-file-to-client by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring-data-mongodb는 하나의 Mongo 인스턴스에서 여러 데이터베이스에 연결합니다. (0) | 2019.01.11 |
---|---|
[SPRING] hbm.xml을 사용하는 대신 Hibernate 엔티티에 대한 패키지를 검사하는 방법은 무엇입니까? (0) | 2019.01.11 |
[SPRING] @PropertySources는 Spring 프로필에 의해 선택 될 수 있습니까? (0) | 2019.01.11 |
[SPRING] Spring MVC PATCH 메소드 : 부분 업데이트 (0) | 2019.01.11 |
[SPRING] com.sun.jdi.InvocationException 메서드 호출 중 발생했습니다. (0) | 2019.01.11 |