자바에서 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임을 명시하면

자동연결되어 엑셀로 열어도 문자가 깨지지 않는다.

+ Recent posts