자바에서 POI를 이용해서 엑셀을 내려주면 되지만..
굳이 CSV를 만들어서 내려달라는 요청이 있는 경우도 있다.
각 데이터를 콤마로 연결된 텍스트 문서로 만들어서 내려줘도 되지만
opencsv 라는 편한 라이브러리가 있으니 그걸 사용하면 된다.
build.gradle
implementation 'com.opencsv:opencsv:5.5'
데이터 형식을 List<String[]> 스트링 배열의 리스트로 담아서 라이브러리에 던지면 한번에
CSV파일을 만들어 다운로드 할 수 있다.
서비스 Class
package com.study.ljj.sample.service;
import com.study.ljj.member.MemberDTO;
import com.study.ljj.sample.repository.SampleMapper;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class SampleService {
private final SampleMapper sampleMapper;
public SampleService(SampleMapper sampleMapper) {
this.sampleMapper = sampleMapper;
}
public List<String[]> listMemberString() {
List<MemberDTO> list = sampleMapper.listMember();
List<String[]> listStrings = new ArrayList<>();
listStrings.add(new String[]{"아이디", "이름", "비밀번호", "등록일"});
for (MemberDTO member: list) {
String[] rowData = new String[4];
rowData[0] = member.getUserid();
rowData[1] = member.getName();
rowData[2] = member.getPassword();
rowData[3] = String.valueOf(member.getRegdate());
listStrings.add(rowData);
}
return listStrings;
}
}
DB 에서 필요한 정보를 검색해와 List<String[]> 배열 형태로 변경하여 리턴한다.
Controller Class
package com.study.ljj.sample.web;
import com.opencsv.CSVWriter;
import com.study.ljj.sample.service.SampleService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Controller
public class CsvDownController {
private final SampleService sampleService;
public CsvDownController(SampleService sampleService) {
this.sampleService = sampleService;
}
@GetMapping("/sample/csv/down")
public void csvDown(HttpServletResponse response) throws IOException {
response.setContentType("text/csv; charset=UTF-8"); // Set the character encoding
String fileName = URLEncoder.encode("회원정보.csv", "UTF-8");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + fileName + "\"");
OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(),
StandardCharsets.UTF_8);
writer.write("\uFEFF");
CSVWriter csvWriter = new CSVWriter(writer);
csvWriter.writeAll(sampleService.listMemberString());
csvWriter.close();
writer.close();
}
}
Header 정보에 CSV파일임을 명시하고, UTF-8임을 명시한다.
파일명도 한글이 깨질수 있으므로 URL인코더로 UTF-8로 변경한다.
CSV파일로 내릴 Stream도 UTF-8로 설정하고
UTF-8 중에서 UTF-8-BOM임을 표시하기 위해
writer.write("\uFEFF"); 을 추가한다. 해당 문자가 있으면 BOM형식임을 인식한다.
이후 서비스에서 받은 List<String[]> 정보를 opencsv 라이브러리에 보내면 CSV다운로드는 완료된다.
참고로
writer.write("\uFEFF"); 를 추가하지 않은 경우 UTF-8 파일로 제대로 내려와서 TEXT편집기로 읽는 경우 잘 나오지만
엑셀에서 읽는 경우 한글,중국어, 일본어, 아랍어등 UTF-8언어는 모두 깨진다.
위와 같이 모든 UTF-8 문자가 깨져서 보인다.
물론 엑셀에서 언어를 UTF-8로 설정하고 CSV를 임포하는 형식으로 하면 제대로 열린다.
깨지는것은 자동으로 열때 문자셋 정보가 완벽하지 않아서 깨지는 것이다.
writer.write("\uFEFF");
를 추가한 경우는
위와 같이 해당 언어가 UTF-8-BOM임을 명시하면
자동연결되어 엑셀로 열어도 문자가 깨지지 않는다.