JAVA 기반 웹&앱 콘텐츠 융합 디지털 컨버전스 개발자 과정

[37~38일차] - 게시판 첨부파일 업로드/다운로드 기능

새싹개발자 2021. 1. 1. 22:31

첨부파일

CommonController

- uploadPath 경로 가져오기 

- 파일 확장자 체크 변수 

- 파일 업로드 메소드

- 파일 다운로드 메소드

 

 

업로드/다운로드 구현하기 전에, pom.xml파일 업로드 라이브러리를 추가한다.

<!-- 파일업로드 라이브러리 -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

 

또한, servlet-context.xml에 아래 코드를 추가한다. 

- uploadPath는 파일이 업로드/다운로드되는 경로이다.

<!-- html폼에서 첨부파일 업로드 설정 10메가 제한 -->
<beans:bean id="multipartResolver"
	class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="maxUploadSize" value="10485760"></beans:property>
</beans:bean>

<!-- 업로드한 파일이 저장되는 위치: 로컬PC용 --> 
<beans:bean id="uploadPath" class="java.lang.String">
    <beans:constructor-arg value="C:\\egov\\workspace\\upload" />
</beans:bean>

 

사전 설정이 끝났다.

 

1. 파일 업로드 구현 (CommonController.java)

- 첨부파일의 확장자를 확인하는 변수를 생성한다.

- 첨부파일 확장자를 확인하여, 이미지일 때 미리보기 가능, 아니라면 그냥 파일명만 보이게.

private ArrayList<String> extNameArray = new ArrayList<String>() {
  {
    add("gif");
    add("jpg");
    add("jpeg");
    add("png");
    add("bmp");
  }
};

public ArrayList<String> getCheckImgArray() {
  return checkImgArray;
}

public void setCheckImgArray(ArrayList<String> checkImgArray) {
  this.checkImgArray = checkImgArray;
}

 

- 파일을 업로드할 경로를 가져온다.

- 아래 경로는 servlet-context.xml에 빈으로 등록되어있는 uploadPath에서 가져온다.

@Resource(name="uploadPath")
private String uploadPath; 

public String getUploadPath() {
  return uploadPath;
}

public void setUploadPath(String uploadPath) {
  this.uploadPath = uploadPath;
}

 

- 파일 업로드를 구현할 메소드를 생성한다.

- servlet-context.xml에 지정한 폴더에 실제 파일을 저장하도록 구현

public String[] fileUpload(MultipartFile file) throws IOException {
  String realFileName = file.getOriginalFilename(); //jsp에서 전송한 파일명 -> 확장자 구할 때 사용
  //만약 파일이 여러개면 아래 부분에 변수 처리 로직이 더 들어가야 한다.
  //폴더에 저장할 PK용 파일명 만들기(아래)
  UUID uid = UUID.randomUUID(); //unique id 생성 : 폴더에 저장할 파일명으로 사용
  //String saveFileName = uid.toString()+"."+realFileName.split("\\.")[1]; //문제발생하여 아래코드로 대체
  String saveFileName = uid.toString()+"."+StringUtils.getFilenameExtension(realFileName);
  //realFileName.split("\\."); realFileName을 .으로 분할해서 파일변수로 만드는 메소드
  //ex. abc.jpg -> realFileName[0]=abc, realFileName[1]=jpg	
  String[] files = new String[] {saveFileName}; //saveFileName 스트링형을 배열변수 files로 형변환
  byte[] fileData = file.getBytes(); //jsp폼에서 전송된 파일이 fileData변수(메모리)에 저장된다.

  //uploadPath경로의 saveFileName이름을 가진 파일이 타겟이 된다.
  File target = new File(uploadPath,saveFileName); //파일 저장하기 바로 전 설정 저장
  FileCopyUtils.copy(fileData, target); //실제로 target폴더에 파일로 저장되는 메소드 = 업로드끝

  return files; // 1개 이상의 파일 업로드 시, 저장된 파일명을 배열로 저장한 변수
  //첨부파일이 한개 이상일 수 있기 때문에, BoardVO에 save_file_names가 배열형이기 때문에.
}

 - jsp에서 전송한 실제 파일명을 realFileName 변수에 저장한다.

- unique id를 랜덤으로 생성하여 uid 변수에 저장한다.

- 생성한 uid + realFileName의 확장자를 saveFileName 변수에 저장한다.

- saveFileName을 files 배열 변수에 반환한다.

- jsp 폼에서 전송된 파일이 fileData변수(메모리)에 저장한다.

- File 클래스형 target 변수에 uploadPath 경로의 saveFileName라는 이름을 가진 파일을 저장한다.

- FileCopyUtils 메소드를 사용하여 target 파일에 fileData 내용을 복사한다. = 업로드 끝

FileCopyUtils.copy(File in, File out) 
-  지정한 입력 File내용을 지정한 출력 File에 복사한다. 리턴값은 복사한 byte수.

- 업로드 후, files 반환(saveFileName 저장되어있는 배열 변수)

 

- BoardVO에 저장 파일 이름과 실제 파일 이름을 저장할 멤버변수를 생성한다.

private String[] save_file_names; // 폴더에 저장되는 실제파일명을 배열형으로 변경할 때 사용한 변수
private String[] real_file_names; // DB에 저장되는 한글파일명을 배열형으로 변경할 때 사용한 변수

public String[] getReal_file_names() {
  return real_file_names;
}

public void setReal_file_names(String[] real_file_names) {
  this.real_file_names = real_file_names;
}

 

- boardMapper.xmlinsertAttach 쿼리를 추가한다.

<insert id="insertAttach">
insert into tbl_attach(save_file_name, real_file_name, bno)
values (#{save_file_name},#{real_file_name},(select bno from tbl_board order by bno desc limit 1))
</insert>

- select bno from tbl_board order by bno desc limit 1

- 업로드 할 때는 입력된 bno가 없기 때문에 bno=#{bno} 사용 불가능하다. 따라서 위의 쿼리를 사용하여 bno를 검색하여 입력한다.

 

- IF_BoardDAO.javaBoardDAOImpl 

public void insertAttach(String save_file_name, String real_file_name) throws Exception;

- BoardDAOImpl에는 insertBoard 안에 추가한다.

@Transactional
@Override
public void insertBoard(BoardVO boardVO) throws Exception {
  // 게시물 등록 DAO연결(아래)
  boardDAO.insertBoard(boardVO);
  // 첨부파일 등록 DAO연결(아래)
  String[] save_file_names = boardVO.getSave_file_names();
  String[] real_file_names = boardVO.getReal_file_names();


  //첨부파일이 여러개일 때 상황 대비
  if(save_file_names == null) {return;} //첨부파일 없을때
  int index = 0;
  String real_file_name="";
  for(String save_file_name:save_file_names) {
    real_file_name=real_file_names[index];
    boardDAO.insertAttach(save_file_name, real_file_name);
    index=index+1;
  }
}		

 

 

- AdminController.java oard_write에 업로드 관련 소스를 추가한다.

 

 


2. 파일 다운로드 구현 (CommonController.java)

- 파일 다운로드를 구현할 메소드를 생성한다.

@RequestMapping(value="/download", method=RequestMethod.GET)
@ResponseBody //이 어노테이션으로 지정된 메소드는 페이지 이동처리 아니고, RestAPI처럼 현재 페이지에서 구현 결과 내용을 전송 받음
public FileSystemResource download(
  @RequestParam("save_file_name") String save_file_name,
  @RequestParam("real_file_name") String real_file_name,
  HttpServletResponse response 
) throws Exception { //파일시스템리소스로 현재 페이지에서 반환받음.
    File file = new File(uploadPath + "/"+ save_file_name); //다운받을 파일 경로 지정
    response.setContentType("application/download; utf-8"); //파일"내용" 중 한글이 깨지는 것 방지
    real_file_name = URLEncoder.encode(real_file_name, "UTF-8").replaceAll("\\+", "%20");
    //위의 URLEncoder는 파일"명"이 한글(일본어, 베트남어)일 떄, 깨지는 것 방지.
    response.setHeader("Content-Disposition", "attachment; filename="+real_file_name);
    return new FileSystemResource(file); //실제 다운로드 시작
}

- File 클래스형 file 변수에 uploadPath에서 지정한 경로의 save_file_name을 저장한다.