스프링부트 (2.7) & mybatis


1. pom.xml
<!-- 썸네일 라이브러리 --> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.17</version> </dependency> <!-- 파일 타입 체크 라이브러리 --> <dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-parsers</artifactId> <version>2.4.1</version> <type>pom</type> </dependency> <dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>2.4.1</version> </dependency>
2.TABLE
CREATE TABLE `T_UPLOAD_FILE` ( `UPLOAD_FILE_SEQ` bigint NOT NULL AUTO_INCREMENT COMMENT '파일테이블 PK', `BOARD_SEQ` bigint null COMMENT '게시판 테이블 PK', `BOARD_TYPE` varchar(255) DEFAULT 'NONE' COMMENT '게시판 종류', `PATHNAME` VARCHAR(100) NOT NULL COMMENT '전체경로', `FILENAME` VARCHAR(50) NOT NULL COMMENT '파일명' , `ORIGINAL_FILENAME` VARCHAR(100) NOT NULL COMMENT '원본 파일명' , `SIZE` INT(11) NOT NULL COMMENT '파일크기', `CONTENT_TYPE` VARCHAR(50) NOT NULL COMMENT '컨텐츠 종류' , `RESOURCE_PATHNAME` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '리소스 파일경로' , `THUMBNAIL_PATHNAME` VARCHAR(100) NULL COMMENT '썸네일 전체경로', `THUMBNAIL_RESOURCE_PATHNAME` VARCHAR(100) NULL DEFAULT '' COMMENT '썸네일 리소스파일경로' , `REG_DATE` timestamp NOT null DEFAULT CURRENT_TIMESTAMP() COMMENT '등록일', PRIMARY KEY (`UPLOAD_FILE_SEQ`) USING BTREE )ENGINE=InnoDB COLLATE='utf8mb4_unicode_ci' COMMENT='파일';
3.UploadFile
import java.util.Date;
import kr.net.macaronics.mvc.domain.enums.BoardType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UploadFile {
private int uploadFileSeq; //파일테이블 PK
private Integer boardSeq; //게시판 테이블 PK
private BoardType boardType; //게시판 종류
private String pathname; //전체경로
private String filename; //파일명
private String originalFilename; //원본 파일명
private int size; //파일크기
private String contentType; //컨텐츠 종류
private String resourcePathname; //리소스 파일경로
private String thumbnailPathname; //썸네일 전체경로
private String thumbnailResourcePathname; //썸네일 리소스파일경로
private Date regDate; //등록일
}
4.UploadFileDTO
import java.util.Date;
import kr.net.macaronics.mvc.domain.enums.BoardType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
/** 파일 데이터를 가져올시 파라미터 */
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UploadFileDTO {
private int uploadFileSeq; //파일테이블 PK
private Integer boardSeq; //게시판 테이블 PK
private BoardType boardType; //게시판 종류
private String pathname; //전체경로
private String filename; //파일명
private String originalFilename; //원본 파일명
private int size; //파일크기
private String contentType; //컨텐츠 종류
private String resourcePathname; //리소스 파일경로
private String thumbnailPathname; //썸네일 전체경로
private String thumbnailResourcePathname; //썸네일 리소스파일경로
private Date regDate; //등록일
}
5. UploadFileInsertDTO
import kr.net.macaronics.mvc.domain.enums.BoardTypeInsert;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
/** 등록시 파라미터 */
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UploadFileInsertDTO {
private int uploadFileSeq; //파일테이블 PK
private Integer boardSeq; //게시판 테이블 PK
private BoardTypeInsert boardType; //게시판 종류
private String pathname; //전체경로
private String filename; //파일명
private String originalFilename; //원본 파일명
private int size; //파일크기
private String contentType; //컨텐츠 종류
private String resourcePathname; //리소스 파일경로
private String thumbnailPathname; //썸네일 전체경로
private String thumbnailResourcePathname; //썸네일 리소스파일경로
@Builder
public UploadFileInsertDTO (Integer boardSeq ,BoardTypeInsert boardType, String pathname, String filename,
String originalFilename, int size, String contentType, String resourcePathname, String thumbnailPathname,
String thumbnailResourcePathname) {
this.boardSeq = boardSeq;
this.boardType = boardType;
this.pathname = pathname;
this.filename = filename;
this.originalFilename = originalFilename;
this.size = size;
this.contentType = contentType;
this.resourcePathname = resourcePathname;
this.thumbnailPathname = thumbnailPathname;
this.thumbnailResourcePathname = thumbnailResourcePathname;
}
}
6. 컨트롤러
1)UploadFileApiController
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Delete;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import kr.net.macaronics.configuration.GlobalConfig;
import kr.net.macaronics.configuration.exception.BaseException;
import kr.net.macaronics.configuration.http.BaseResponse;
import kr.net.macaronics.configuration.http.BaseResponseCode;
import kr.net.macaronics.mvc.domain.dto.UploadFileDTO;
import kr.net.macaronics.mvc.domain.dto.UploadFileInsertDTO;
import kr.net.macaronics.mvc.domain.enums.ThumbnailType;
import kr.net.macaronics.mvc.service.UploadFileService;
import kr.net.macaronics.utils.DownloadView;
import kr.net.macaronics.utils.pagination2.MysqlPageMaker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
@Slf4j
@RestController
@RequestMapping("/api/file")
@Api(tags="파일 업로드 API")
@RequiredArgsConstructor
public class UploadFileApiController {
private final GlobalConfig config;
private final UploadFileService uploadFileService;
@PostMapping("/save")
@ApiOperation(value="테스트-파일업로드", notes = "파일업로드 샘플1")
public BaseResponse<Boolean> save(@RequestParam("uploadFile") MultipartFile multipartFile) throws Exception {
if(multipartFile==null || multipartFile.isEmpty()) {
throw new BaseException(BaseResponseCode.DATA_IS_NULL.name());
}
//날짜폴더를 추가
String currentDate=new SimpleDateFormat("yyyyMMdd").format(Calendar.getInstance().getTime());
log.debug("config : {} ", config);
String uploadFilePath=config.getUploadFilePath()+currentDate+"/";
log.info("uploadFilePath : {} " , uploadFilePath);
String prefix=multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")+1, multipartFile.getOriginalFilename().length());
String filename=UUID.randomUUID().toString()+"."+prefix;
File folder =new File(uploadFilePath);
if(!folder.isDirectory()) {
folder.mkdirs();
}
String pathname=uploadFilePath +filename;
String resourcePathname =config.getUploadResourcePath()+currentDate+"/"+filename;
File dest=new File(pathname);
log.info("dest : {}", dest);
multipartFile.transferTo(dest);
//파일업로드 된 후 DB에 저장
UploadFileInsertDTO uploadFileDTO=UploadFileInsertDTO.builder()
.contentType(multipartFile.getContentType()) //컨텐츠 종류
.originalFilename(multipartFile.getOriginalFilename()) //원본파일명
.filename(filename) //저장파일명
.pathname(pathname) //실제파일 저장경로
.size((int)multipartFile.getSize()) //파일크기
.resourcePathname(resourcePathname) //static resource 접근 경로
.build();
uploadFileService.save(uploadFileDTO);
return new BaseResponse<Boolean>(true);
}
/**
* 업로드된 파일 썸네일 만들기 공통 throws Exception
* http://localhost:8080/api/file/thumbnail/make/1/WEB_MAIN
* */
@GetMapping("/thumbnail/make/{uploadFileSeq}/{thumbnailType}")
@ApiOperation(value="테스트-업로드된 파일 썸네일 만들기", notes = "파일업로드 샘플2")
public BaseResponse<String> thumb(@PathVariable int uploadFileSeq,
@PathVariable ThumbnailType thumbnailType
) throws Exception{
UploadFileDTO uploadFileDTO=uploadFileService.get(uploadFileSeq);
String pathname=uploadFileDTO.getPathname();
String thumbnailPathname=uploadFileDTO.getPathname().replace(".", thumbnailType.width()+"_"+thumbnailType.height()+".");
File thumbanilFile=new File(thumbnailPathname);
if(!thumbanilFile.isFile()) {
Thumbnails.of(new File(pathname))
.size(thumbnailType.width(), thumbnailType.height())
.toFile(new File(thumbnailPathname));
}
return new BaseResponse<String>(uploadFileDTO.getResourcePathname().replace(".", thumbnailType.width()+"_"+thumbnailType.height()+"."));
}
/**thumbnailator 라이브러리를 통한 업로드된 썸네일 이미지 출력
* http://localhost:8080/api/file/thumbnail/output/1/WIDTH_200
* */
@GetMapping("/thumbnail/output/{uploadFileSeq}/{thumbnailType}")
@ApiOperation(value="테스트-thumbnailator 라이브러리를 통한 업로드된 썸네일 이미지 출력", notes = "파일업로드 샘플3")
public void thumbnailOutput(@PathVariable int uploadFileSeq,
@PathVariable ThumbnailType thumbnailType,
HttpServletResponse response
) throws Exception{
UploadFileDTO uploadFileDTO=uploadFileService.get(uploadFileSeq);
String pathname=uploadFileDTO.getPathname();
String thumbanilPathname=uploadFileDTO.getPathname().replace(".", thumbnailType.width()+"_"+thumbnailType.height()+".");
File thumbanilFile=new File(thumbanilPathname);
if(!thumbanilFile.isFile()) {
Thumbnails.of(new File(pathname))
.size(thumbnailType.width(), thumbnailType.height())
.toFile(new File(thumbanilPathname));
}
response.setContentType(uploadFileDTO.getContentType());
FileCopyUtils.copy(new FileInputStream(thumbanilFile), response.getOutputStream());
}
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/** 파일업로드 - 이미지일 경우 썸네일등록 */
@PostMapping("/fileSave")
@ApiOperation(value="파일 등록 - 이미지일 경우 썸네일등록", notes = "서비스에서 작업 - MimeType 파일 위조 변조 체크")
public BaseResponse<UploadFileDTO> fileSave(@RequestParam("uploadFile") MultipartFile multipartFile) throws Exception {
int uploadFileSeq=uploadFileService.fileSave(multipartFile, null);
return new BaseResponse<UploadFileDTO>(uploadFileService.get(uploadFileSeq));
}
/** 멀티파일업로드 - 이미지일 경우 썸네일등록 */
@PostMapping("/multiFileSave")
@ApiOperation(value="멀티파일 등록 - 이미지일 경우 썸네일등록", notes = "멀티파일 등록")
public BaseResponse<List<UploadFileDTO>> multiFileSave(@RequestParam("uploadFile") List<MultipartFile> multipartFile) throws Exception {
List<UploadFileDTO> uploadFileDTOList=uploadFileService.multiFileSave(multipartFile, null);
return new BaseResponse<List<UploadFileDTO>>(uploadFileDTOList);
}
/** 전체 파일목록 불러오기
* http://localhost:8080/api/file/fileList
* */
@GetMapping({"/fileList"})
@ApiOperation(value="전체 파일목록 불러오기", notes="전체 파일목록 불러오기 ")
public BaseResponse<List<UploadFileDTO>> fileList(
@ApiParam MysqlPageMaker pageMaker
) throws Exception{
Map<String, Object> map=new HashMap<>();
map.put("pageMaker", pageMaker);
map.put("boardSeq", "");
pageMaker.setTotalCount(uploadFileService.getTotalCount(map));
return new BaseResponse<List<UploadFileDTO>>(uploadFileService.fileList(map), pageMaker);
}
/** 게시판 pk 파일목록 불러오기
* http://localhost:8080/api/file/boarddPkFileList/1
* */
@GetMapping({"/boarddPkFileList/{boardSeq}"})
@ApiOperation(value="게시판 번호에 따른 파일 목록 불러오기", notes="boardSeq 파일목록 불러오기 " )
public BaseResponse<List<UploadFileDTO>> boarddPkFileList(
@ApiParam MysqlPageMaker pageMaker,
@ApiParam @PathVariable int boardSeq
) throws Exception{
Map<String, Object> map=new HashMap<>();
map.put("pageMaker", pageMaker);
map.put("boardSeq", boardSeq);
int totalCount =uploadFileService.getTotalCount(map);
pageMaker.setTotalCount(totalCount);
return new BaseResponse<List<UploadFileDTO>>(uploadFileService.bordPkFileList(map), pageMaker);
}
/** 게시판 boardType 별 파일목록 불러오기 * */
@GetMapping({"/boardTypeFileList/{boardType}"})
@ApiOperation(value="게시판 타입별 파일 목록 불러오기", notes="boardType 별 파일목록 불러오기 ")
public BaseResponse<List<UploadFileDTO>> boardTypeFileList(
@ApiParam MysqlPageMaker pageMaker,
@ApiParam @PathVariable String boardType
) throws Exception{
Map<String, Object> map=new HashMap<>();
map.put("pageMaker", pageMaker);
map.put("boardSeq", "");
map.put("searchType", boardType);
log.info("map {} ", map.toString());
int totalCount =uploadFileService.getTotalCount(map);
pageMaker.setTotalCount(totalCount);
return new BaseResponse<List<UploadFileDTO>>(uploadFileService.bordPkFileList(map), pageMaker);
}
/** 파일정보가져오기 */
@GetMapping("/getFileInfo/{uploadFileSeq}")
@ApiOperation(value="파일 정보가져오기", notes = "파일 다운로드")
public BaseResponse<UploadFileDTO> getFileInfo(@PathVariable int uploadFileSeq , Model model) throws Exception {
UploadFileDTO uploadFileDTO=uploadFileService.get(uploadFileSeq);
if(uploadFileDTO==null) {
throw new BaseException("해당 파일이 존재하지 않습니다.");
}
return new BaseResponse<UploadFileDTO>(uploadFileDTO);
}
/** 파일 다운로드 */
@GetMapping(value = "/fileDownload/{uploadFileSeq}")
@ApiOperation(value="파일 다운로드", notes = "파일 다운로드")
public DownloadView fileDownload(@PathVariable int uploadFileSeq , Model model) throws Exception {
UploadFileDTO uploadFileDTO=uploadFileService.get(uploadFileSeq);
if(uploadFileDTO==null) {
throw new BaseException("해당 파일이 존재하지 않습니다.");
}
File file = new File(uploadFileDTO.getPathname());
model.addAttribute("downloadFile", file);
model.addAttribute("orignalName", uploadFileDTO.getOriginalFilename());
DownloadView downloadView=new DownloadView();
return downloadView;
}
/** 파일 삭제
* http://localhost:8080/api/file/fileDelate/1
* */
@DeleteMapping("/fileDelate/{uploadFileSeq}")
@ApiOperation(value="파일 삭제", notes = "파일 삭제")
public BaseResponse<String> fileDelete(@PathVariable int uploadFileSeq) throws Exception{
uploadFileService.fileDelete(uploadFileSeq);
return new BaseResponse<String>("success", BaseResponseCode.SUCCESS, "삭제 처리되었습니다.");
}
}
2) UploadFileController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/file")
public class UploadFileController {
/** 파일업로드 테스트 페이지 */
@GetMapping("/fileUpload")
public String fileUpload() {
return "file_upload";
}
/** 파일 목록 페이지 */
@GetMapping("/fileList")
public String fileList() {
return "file_list";
}
}
7.UploadFileService
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import kr.net.macaronics.configuration.GlobalConfig;
import kr.net.macaronics.configuration.exception.BaseException;
import kr.net.macaronics.configuration.http.BaseResponseCode;
import kr.net.macaronics.mvc.domain.dto.BoardDTO;
import kr.net.macaronics.mvc.domain.dto.BoardInsertDTO;
import kr.net.macaronics.mvc.domain.dto.UploadFileDTO;
import kr.net.macaronics.mvc.domain.dto.UploadFileInsertDTO;
import kr.net.macaronics.mvc.domain.enums.BoardTypeInsert;
import kr.net.macaronics.mvc.domain.enums.ThumbnailType;
import kr.net.macaronics.mvc.repository.UploadFileRepository;
import kr.net.macaronics.utils.FileFilter;
import kr.net.macaronics.utils.pagination2.MysqlPageMaker;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
/** 업로드파일 Service */
@Service
@Slf4j
public class UploadFileService {
@Autowired
private UploadFileRepository uploadFileRepository;
@Autowired
private GlobalConfig config;
/** 등록처리 */
public int save(UploadFileInsertDTO uploadFileInsertDTO) throws Exception{
return uploadFileRepository.save(uploadFileInsertDTO);
}
public UploadFileDTO get(int uploadFileSeq) throws Exception {
return uploadFileRepository.get(uploadFileSeq);
}
public int fileSave(MultipartFile multipartFile, BoardInsertDTO boardInsertDTO) throws Exception {
if(multipartFile==null || multipartFile.isEmpty()) {
throw new BaseException(BaseResponseCode.DATA_IS_NULL.name());
}
Integer boardSeq=null; //게시판 업로드일 파일 경우 - 게시판 테이블 PK
BoardTypeInsert boardType=BoardTypeInsert.NONE; //게시판 타입
if(boardInsertDTO!=null) {
boardSeq=boardInsertDTO.getBoardSeq();
boardType=boardInsertDTO.getBoardType();
}
//1.업로드 가능한지 파일인지 체크
if(!FileFilter.isPermisionFileMimeType(multipartFile)) {
throw new BaseException("업로드할 수 없는 파일입니다.");
};
//2.날짜폴더를 추가 - 이미지가 아닌파일은 files 디렉토리에 저장
String currentDate=new SimpleDateFormat("yyyyMMdd").format(Calendar.getInstance().getTime());
String uploadFilePath=config.getUploadFilePath()+"files/"+currentDate+"/";
//3.이미지파일 체크 - 이미지파일은 images 디렉토리에 저장
boolean isImage=false;
if(FileFilter.validImgFile(multipartFile)) {
isImage=true;
uploadFilePath=config.getUploadFilePath()+"images/"+currentDate+"/";
}
//4.랜덤 파일명 생성 및 디렉토리 생성
String prefix=multipartFile.getOriginalFilename().
substring(multipartFile.getOriginalFilename().lastIndexOf(".")+1, multipartFile.getOriginalFilename().length());
String filename=UUID.randomUUID().toString()+"."+prefix;
File folder =new File(uploadFilePath);
if(!folder.isDirectory()) {
folder.mkdirs();
}
//5.URL 주소에서 보여줄 파일경로
String pathname=uploadFilePath +filename;
String resourcePathname =config.getUploadResourcePath()+(isImage?"images/":"files/") +currentDate+"/"+filename;
File dest=new File(pathname);
//6.파일 생성
log.info("dest : {}", dest);
multipartFile.transferTo(dest);
String thumbnailPathname=null; //썸네일 전체경로
String thumbnailResourcePathname=null; //썸네일 리소스파일경로
//7.업로드 파일일 이미지 일경우 썸네일 생성
if(isImage){
thumbnailPathname=pathname.replace(".", "_"+ThumbnailType.WEB_MAIN.width()+"_"+ThumbnailType.WEB_MAIN.height()+".");
File thumbanilFile=new File(thumbnailPathname);
if(!thumbanilFile.isFile()) {
Thumbnails.of(new File(pathname))
.size(ThumbnailType.WEB_MAIN.width(), ThumbnailType.WEB_MAIN.height())
.toFile(new File(thumbnailPathname));
thumbnailResourcePathname =resourcePathname.replace(".", "_"+ThumbnailType.WEB_MAIN.width()+"_"+ThumbnailType.WEB_MAIN.height()+".");
}
}
//9.UploadFileInsertDTO 객체에 저장
UploadFileInsertDTO uploadFileInsertDTO=UploadFileInsertDTO.builder()
.boardSeq(boardSeq)
.boardType(boardType)
.contentType(multipartFile.getContentType()) //컨텐츠 종류
.originalFilename(multipartFile.getOriginalFilename()) //원본파일명
.filename(filename) //저장파일명
.pathname(pathname) //실제파일 저장경로
.size((int)multipartFile.getSize()) //파일크기
.resourcePathname(resourcePathname) //static resource 접근 경로
.thumbnailPathname(thumbnailPathname)
.thumbnailResourcePathname(thumbnailResourcePathname)
.build();
uploadFileRepository.save(uploadFileInsertDTO);
//9.파일업로드 된 후 DB에 저장후 반화
return uploadFileInsertDTO.getUploadFileSeq();
}
public int getTotalCount(Map<String, Object> map) throws Exception {
return uploadFileRepository.getTotalCount(map);
}
public List<UploadFileDTO> fileList(Map<String, Object> map) throws Exception {
return uploadFileRepository.fileList(map);
}
public List<UploadFileDTO> bordPkFileList(Map<String, Object> map) throws Exception {
return uploadFileRepository.bordPkFileList(map);
}
public void fileDelete(int uploadFileSeq) throws Exception {
UploadFileDTO uploadFileDTO=uploadFileRepository.get(uploadFileSeq);
if(uploadFileDTO==null) {
throw new BaseException("해당 파일이 존재하지 않습니다.");
}
File file=new File(uploadFileDTO.getPathname());
if(file.exists())file.delete();
else throw new BaseException("해당 파일이 존재하지 않습니다.");
//썸네일 삭제
if(!StringUtils.isEmpty(uploadFileDTO.getThumbnailPathname())) {
File thumbnailFile=new File(uploadFileDTO.getThumbnailPathname());
if(thumbnailFile.exists()) thumbnailFile.delete();
else throw new BaseException("해당 파일이 존재하지 않습니다.");
}
//DB에서 삭제처리
uploadFileRepository.fileDelete(uploadFileSeq);
}
public List<UploadFileDTO> multiFileSave(List<MultipartFile> multipartFile, BoardInsertDTO boardInsertDTO) throws Exception {
List<Integer> uploadFileSeq=new ArrayList<Integer>();
for(MultipartFile multiFile : multipartFile) {
uploadFileSeq.add(fileSave(multiFile, null));
}
return uploadFileRepository.fileSelectList(uploadFileSeq);
}
}
8.UploadFileRepository
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import kr.net.macaronics.mvc.domain.dto.UploadFileDTO;
import kr.net.macaronics.mvc.domain.dto.UploadFileInsertDTO;
/** 업로드 파일 Repository */
@Repository
public interface UploadFileRepository {
public int save(UploadFileInsertDTO uploadFileInsertDTO) throws Exception;
public UploadFileDTO get(int uploadFileSeq) throws Exception;
public int getTotalCount(Map<String, Object> map) throws Exception;
public List<UploadFileDTO> fileList(Map<String, Object> map) throws Exception;
public List<UploadFileDTO> bordPkFileList(Map<String, Object> map) throws Exception;
public void fileDelete(int uploadFileSeq) throws Exception;
public List<UploadFileDTO> fileSelectList(List<Integer> uploadFileSeq) throws Exception;
}
9.UploadFile.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.net.macaronics.mvc.repository.UploadFileRepository">
<insert id="save" parameterType="kr.net.macaronics.mvc.domain.dto.UploadFileInsertDTO" useGeneratedKeys="true" keyProperty="uploadFileSeq">
INSERT INTO T_UPLOAD_FILE
(BOARD_SEQ , BOARD_TYPE ,PATHNAME, FILENAME, ORIGINAL_FILENAME, `SIZE`, CONTENT_TYPE, RESOURCE_PATHNAME , THUMBNAIL_PATHNAME, THUMBNAIL_RESOURCE_PATHNAME)
VALUES(#{boardSeq}, #{boardType}, #{pathname}, #{filename}, #{originalFilename},
#{size}, #{contentType}, #{resourcePathname} , #{thumbnailPathname}, #{thumbnailResourcePathname})
</insert>
<select id="get" resultType="kr.net.macaronics.mvc.domain.dto.UploadFileDTO">
SELECT
UPLOAD_FILE_SEQ , BOARD_SEQ, BOARD_TYPE, PATHNAME, FILENAME, ORIGINAL_FILENAME, `SIZE`, CONTENT_TYPE,
RESOURCE_PATHNAME , THUMBNAIL_PATHNAME, THUMBNAIL_RESOURCE_PATHNAME, REG_DATE
FROM T_UPLOAD_FILE UF
WHERE UF.UPLOAD_FILE_SEQ =#{uploadFileSeq}
</select>
<select id="fileList" resultType="kr.net.macaronics.mvc.domain.dto.UploadFileDTO" parameterType="java.util.HashMap">
SELECT
UPLOAD_FILE_SEQ,
BOARD_SEQ,
BOARD_TYPE,
PATHNAME,
FILENAME,
ORIGINAL_FILENAME,
`SIZE`,
CONTENT_TYPE,
RESOURCE_PATHNAME,
THUMBNAIL_PATHNAME,
THUMBNAIL_RESOURCE_PATHNAME,
REG_DATE
FROM T_UPLOAD_FILE U
<include refid="searchSql"></include>
ORDER BY U.REG_DATE DESC
LIMIT #{pageMaker.pageStart} , #{pageMaker.perPageNum}
</select>
<sql id="searchSql" >
<where>
<if test='boardSeq !=null and !boardSeq.equals("")'>
AND U.BOARD_SEQ = #{boardSeq}
</if>
<if test="@org.apache.commons.lang3.StringUtils@isNotEmpty(searchType)">
<if test="searchType == 'NOTICE'.toString()">
AND U.BOARD_TYPE ='NOTICE'
</if>
<if test="searchType == 'FAQ'.toString()">
AND U.BOARD_TYPE ='FAQ'
</if>
<if test="searchType == 'INQUIRY'.toString()">
AND U.BOARD_TYPE ='INQUIRY'
</if>
</if>
</where>
</sql>
<select id="getTotalCount" resultType="int" parameterType="java.util.HashMap">
SELECT
COUNT(U.UPLOAD_FILE_SEQ) AS CNT
FROM T_UPLOAD_FILE U
<include refid="searchSql"></include>
</select>
<select id="bordPkFileList" resultType="kr.net.macaronics.mvc.domain.dto.UploadFileDTO">
SELECT
UPLOAD_FILE_SEQ,
BOARD_SEQ,
BOARD_TYPE,
PATHNAME,
FILENAME,
ORIGINAL_FILENAME,
`SIZE`,
CONTENT_TYPE,
RESOURCE_PATHNAME,
THUMBNAIL_PATHNAME,
THUMBNAIL_RESOURCE_PATHNAME,
REG_DATE
FROM T_UPLOAD_FILE U
<include refid="searchSql"></include>
ORDER BY U.REG_DATE DESC
LIMIT #{pageMaker.pageStart} , #{pageMaker.perPageNum}
</select>
<delete id="fileDelete">
DELETE FROM T_UPLOAD_FILE WHERE UPLOAD_FILE_SEQ =#{uploadFileSeq}
</delete>
<select id="fileSelectList" resultType="kr.net.macaronics.mvc.domain.dto.UploadFileDTO">
SELECT * FROM T_UPLOAD_FILE
WHERE UPLOAD_FILE_SEQ IN(
<foreach collection="uploadFileSeq" item="value" separator=",">
#{value}
</foreach>
)
</select>
</mapper>
10. 개발 환경에 따른 파일 출력 설정 GlobalConfig, WebMvcConfig
GlobalConfig
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* global ~.properties 값을 읽어와 글로벌 변수설정하는 클래스
*/
@Slf4j
@Data
public class GlobalConfig {
@Autowired
private ApplicationContext context;
@Autowired
private ResourceLoader resourceLoader;
private String uploadFilePath;//파일 저장 경로
private String schedulerCronExample1;//스케쥴처리
private String uploadResourcePath;//웹 브라우저 출력시 업로드파일경로
private boolean local;
private boolean dev;
private boolean prod;
/**
* @PostConstruct는 의존성 주입이 이루어진 후 초기화를 수행하는 메서드이다.
* @PostConstruct가 붙은 메서드는 클래스가 service를 수행하기 전에 발생한다.
* 이 메서드는 다른 리소스에서 호출되지 않는다해도 수행된다.
@PostConstruct의 사용 이유
1) 생성자가 호출되었을 때, 빈은 초기화되지 않았음(의존성 주입이 이루어지지 않았음)
이럴 때 @PostConstruct를 사용하면 의존성 주입이 끝나고 실행됨이 보장되므로 빈의 초기화에 대해서 걱정할 필요가 없다.
2) bean 의 생애주기에서 오직 한 번만 수행된다는 것을 보장한다. (어플리케이션이 실행될 때 한번만 실행됨)
따라서 bean이 여러 번 초기화되는 걸 방지할 수 있다
여기서는, ApplicationContext, ResourceLoader 가 의존성 주입이 완료되었는지에 대해 염려할 필요가 없다.
*/
@PostConstruct
public void init(){
log.info("GlobalConfig-init" );
String[] activeProfiles =context.getEnvironment().getActiveProfiles();
String activeProfile="local"; // 기본위치 local
if(ObjectUtils.isNotEmpty(activeProfiles)) {
activeProfile=activeProfiles[0];
}
String resourcePath=String.format("classpath:globals/global-%s.properties", activeProfile);
try {
Resource resource=resourceLoader.getResource(resourcePath);
Properties properties=PropertiesLoaderUtils.loadProperties(resource);
this.uploadFilePath=properties.getProperty("uploadFile.path");
this.schedulerCronExample1 =properties.getProperty("scheduler.cron.example1");
this.uploadResourcePath=properties.getProperty("uploadFile.resourcePath");
this.local=activeProfile.equals("local");
this.dev=activeProfile.equals("dev");
this.prod=activeProfile.equals("prod");
}catch (Exception e) {
log.error("e", e);
}
}
}
WebMvcConfig
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import kr.net.macaronics.configuration.handler.BaseHandlerInterceptor;
import kr.net.macaronics.utils.pagination.MySQLPageRequestHandleMethodArgumentResolver;
import lombok.extern.slf4j.Slf4j;
@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {
private static final String WINDOW_FILE ="file:///";
private static final String LINUX_FILE= "file:";
/** addResourceHandlers 설명)
WebMvcConfigurer interface를 상속받아 addResourceHandlers method를 오버 라이딩하고 리소스 등록 및 핸들러를 관리하는
객체인 ResourceHandlerRegistry를 통해 리소스의 위치와 리소스와 매칭 될 url을 설정.
addResourceHandler : 리소스와 연결될 URL path를 지정(클라이언트가 파일에 접근하기 위해 요청하는 url)
localhost:8080/imagePath/**
addResourceLocations: 실제 리소스가 존재하는 외부 경로를 지정합니다.
경로의 마지막은 반드시 " / "로 끝나야 하고, 로컬 디스크 경로일 경우 file:/// 접두어를 꼭 붙인다.
이렇게 설정하면 클라이언트로부터 http://호스트 주소:포트/imagePath/testImage.jpg 와 같은 요청이 들어 왔을 때 /home/uploadedImage/testImage.jpg 파일로 연결.
예)
private String connectPath = "/imagePath/**";
private String resourcePath = "file:///home/uploadedImage";
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(connectPath)
.addResourceLocations(resourcePath);
}
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//업로드 파일 static resource 접근 경로
String resourcePattern=config().getUploadResourcePath() +"**";
log.info("addResourceHandlers -resourcePattern {}", resourcePattern);
if(config().isLocal()) {
//로컬(윈도우환경)
registry.addResourceHandler(resourcePattern)
.addResourceLocations(WINDOW_FILE+config().getUploadFilePath());
log.info("윈도우 환경");
log.info(" resourcePattern - {}", resourcePattern);
log.info(" addResourceLocations - {}", WINDOW_FILE+config().getUploadFilePath() );
}if(config().isDev()) {
//개발환경(윈도우환경)
log.info("개발환경(윈도우환경)");
registry.addResourceHandler(resourcePattern)
.addResourceLocations(WINDOW_FILE+config().getUploadFilePath());
log.info(" resourcePattern - {}", resourcePattern);
log.info(" addResourceLocations - {}", WINDOW_FILE+config().getUploadFilePath() );
}else {
//리눅스 또는 유닉스 환경
log.info("리눅스 또는 유닉스 환경");
registry.addResourceHandler(resourcePattern)
.addResourceLocations(LINUX_FILE+config().getUploadFilePath());
}
}
}
11. 다운로드
DownloadView
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.view.AbstractView;
public class DownloadView extends AbstractView{
public DownloadView() {
setContentType("application/download; charset=utf-8");
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) throws Exception {
File file = (File)model.get("downloadFile");
String orignalName = (String)model.get("orignalName");
response.setContentType(getContentType());
response.setContentLength((int)file.length());
String fileName = null;
if (orignalName != null && orignalName.trim().length() > 0) {
fileName = orignalName;
} else {
fileName = file.getName();
}
fileName = URLEncoder.encode(fileName, "utf-8");
fileName = fileName.replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
response.setHeader("Content-Transfer-Encoding", "binary");
OutputStream out = response.getOutputStream();
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
FileCopyUtils.copy(fis, out);
} finally {
if(fis != null) {
try {
fis.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
out.flush();
}
}
12. Tika를 이용한 MimeType 파일 위조 변조 체크
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.apache.tika.Tika;
import org.springframework.web.multipart.MultipartFile;
import lombok.extern.slf4j.Slf4j;
/**업로드 파일체크
* Tika를 이용한 MimeType 파일 위조 변조 체크
* **/
@Slf4j
public class FileFilter {
private static final Tika tika = new Tika();
/** 이미지 파일체크 */
public static boolean validImgFile(MultipartFile multipartFile) throws Exception {
try {
List<String> notValidTypeList = Arrays.asList("image/gif", "image/jpeg", "image/png", "image/bmp");
String mimeType = tika.detect(multipartFile.getInputStream());
return notValidTypeList.stream().anyMatch(notValidType -> notValidType.equalsIgnoreCase(mimeType));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/** 업로드 가능한 파일 MimeType 체크 */
public static boolean isPermisionFileMimeType(MultipartFile multipartFile) throws Exception {
//MIME 타입의 전체 목록 - https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
try {
List<String> notValidTypeList = Arrays.asList(
"image/gif", "image/jpeg", "image/png", "image/bmp",
"application/pdf", "video/mp4" ,"application/zip" ,"application/x-zip-compressed" ,"application/x-tika-msoffice" ,
"video/quicktime"
);
//application/x-tika-msoffice => hwp , msoffice 파일
//video/quicktime mp4 파일
String mimeType = tika.detect(multipartFile.getInputStream());
log.info("MimeType : " + mimeType);
boolean isValid = notValidTypeList.stream().anyMatch(notValidType -> notValidType.equalsIgnoreCase(mimeType));
return isValid;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
13. 뷰
파일 등록
1) file_upload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일업로드 테스트</title>
{{>layout/head}}
<link rel="stylesheet" href="/css/file_upload.css" >
</head>
<body>
<div class="row mt-5" id="file-upload-container">
<div class="col-md-4 offset-md-2 text-center">
<div class="mb-5 d-flex justify-content-end">
<a class="btn btn-info text-white" href="fileList">파일목록</a>
</div>
<h2>1.파일 업로드 테스트</h2>
<form action="/file/save" enctype="multipart/form-data" method="post">
<div class="input-group">
<input type="file" class="form-control" name="uploadFile" id="uploadFile1" data-view="image_container1" onchange="setThumbnail(event);">
<button class="btn btn-primary" type="button" id="uploadBtn1">파일업로드</button>
</div>
</form>
<br>
<div class="imgView" id="image_container1"></div>
<br>
<br>
<br>
<br>
<br>
<h2>2.파일 업로드 테스트2</h2>
<form action="/file/fileSave" enctype="multipart/form-data" method="post">
<div class="input-group">
<input type="file" class="form-control" name="uploadFile" id="uploadFile2" data-view="image_container2" onchange="setThumbnail(event);">
<button class="btn btn-primary" type="button" id="uploadBtn2">파일업로드</button>
</div>
</form>
<br>
<div class="imgView" id="image_container2"></div>
<br>
<br>
<br>
<br>
<br>
<h2>3.멀티 파일 업로드 테스트</h2>
<form action="/file/fileSave" enctype="multipart/form-data" method="post">
<div class="input-group">
<input type="file" class="form-control" name="uploadFile" id="uploadFile3" data-view="image_container3" onchange="setThumbnail(event);" multiple>
<button class="btn btn-primary" type="button" id="uploadBtn3">파일업로드</button>
</div>
</form>
<br>
<div class="imgView" id="image_container3"></div>
</div>
</div>
{{>layout/footer}}
<script src="/js/file_upload.js"></script>
</body>
</html>
2) file_upload.js
let fileUpload= {
init:function(){
document.querySelector("#uploadBtn1").addEventListener("click", function(event){
fileUpload.uploadBtn1();
});
document.querySelector("#uploadBtn2").addEventListener("click", function(event){
fileUpload.uploadBtn2();
});
document.querySelector("#uploadBtn3").addEventListener("click", function(event){
fileUpload.uploadBtn3();
});
},
//1.파일 업로드 테스트
uploadBtn1:function(){
let formData = new FormData();
const inputFile =document.getElementById("uploadFile1");
const files = inputFile.files;
if(inputFile.value==undefined || inputFile.value==""){
return;
}
//formdata에 파일 데이터 추가
for(let i=0; i<files.length; i++){
if(!checkFileName(files[i].name, files[i].size)){
console.log("file error");
return false;
}
formData.append("uploadFile", files[i]);
}
const params={
method:"POST",
body:formData
}
fetch('/api/file/save', params).then((response)=>response.json())
.then((res)=>{
if(res.resState=="success"){
document.querySelector("#uploadFile1").value="";
document.querySelector("#image_container1").innerHTML="<textarea>"+JSON.stringify(res, null, 4) + "</textarea>";
alert("업로드 처리 되었습니다.");
}
}).catch((error)=>{
console.log("error:", error);
})
},
//2.파일 업로드 테스트2
uploadBtn2:function(){
let formData = new FormData();
const inputFile=document.getElementById("uploadFile2");
const files = inputFile.files;
if(inputFile.value==undefined || inputFile.value==""){
return;
}
//formdata에 파일 데이터 추가
for(let i=0; i<files.length; i++){
if(!checkFileName(files[i].name, files[i].size)){
console.log("file error");
return false;
}
formData.append("uploadFile", files[i]);
}
$.ajax({
type:"POST",
url : '/api/file/fileSave',
processData: false,
contentType: false,
data: formData,
success: function(res){
if(res.resState=="success"){
document.querySelector("#uploadFile2").value="";
document.querySelector("#image_container2").innerHTML="<textarea>"+JSON.stringify(res, null, 4) + "</textarea>";
alert("업로드 처리 되었습니다.");
}
},
error: function(err){
console.log("err:", err)
}
})
}
,
//3.멀티 파일 업로드 테스트
uploadBtn3:function(){
let formData = new FormData();
const inputFile = document.getElementById("uploadFile3");
const files = inputFile.files;
if(inputFile.value==undefined || inputFile.value==""){
return;
}
//formdata에 파일 데이터 추가
for(let i=0; i<files.length; i++){
if(!checkFileName(files[i].name, files[i].size)){
console.log("file error");
return false;
}
formData.append("uploadFile", files[i]);
}
const params={
method:"POST",
body:formData
}
fetch('/api/file/multiFileSave', params).then((response)=>response.json())
.then((res)=>{
if(res.resState=="success"){
document.querySelector("#uploadFile3").value="";
document.querySelector("#image_container3").innerHTML="<textarea>"+JSON.stringify(res, null, 4) + "</textarea>";
alert("업로드 처리 되었습니다.");
}
}).catch((error)=>{
console.log("error:", error);
})
}
}
//파일 확장자 체크 및 사이즈 체크
function checkFileName(str, fileSize){
//1. 확장자 체크
const ext = str.split('.').pop().toLowerCase();
const ableExts=['bmp' , 'hwp', 'jpg', 'pdf', 'png', 'xls', 'zip', 'pptx', 'xlsx', 'jpeg', 'doc', 'gif' ,'mp4'];
if( ableExts.indexOf(ext) ==-1 ) {
//alert(ext);
alert(ext+' 파일은 업로드 하실 수 없습니다.');
return false;
}
//2. 파일명에 특수문자 체크
const pattern = /[\{\}\/?,;:|*~`!^\+<>@\#$%&\\\=\'\"]/gi;
if(pattern.test(str) ){
//alert("파일명에 허용된 특수문자는 '-', '_', '(', ')', '[', ']', '.' 입니다.");
alert('파일명에 특수문자를 제거해주세요.');
return false;
}
const maxSize = 1024*1024*17; //517MB
if(fileSize >= maxSize){
alert("파일 사이즈 초과");
return false;
}
return true;
}
//이미지 미리보기
function setThumbnail(event) {
const dataView=$(event.target).attr("data-view");
document.querySelector("div#"+dataView).innerHTML="";
for (let image of event.target.files) {
// 확장자 체크
const ext = image.name.split('.').pop().toLowerCase();
const ableExt=['jpg','png','jpeg','gif'];
if(ableExt.indexOf(ext) > -1) {
//console.log("이미지");
const reader = new FileReader();
reader.onload = function(event) {
let img = document.createElement("img");
img.setAttribute("src", event.target.result);
img.style.width="auto";
img.style.height="100px";
document.querySelector("div#"+dataView).appendChild(img);
};
reader.readAsDataURL(image);
}
}
}
fileUpload.init();
파일 목록
1) file_list.html
<!DOCTYPE html>
<html>
<head>
{{>layout/head}}
<title>파일목록</title>
<link rel="stylesheet" href="/css/file_upload.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
</head>
<body>
<div class="container">
<div class="row mt-5">
<div class="col-md-12 text-center">
<div class="mb-5 d-flex justify-content-end">
<a class="btn btn-info text-white" href="fileUpload">파일등록</a>
</div>
<table class="table table-striped" id="fileUpload">
<thead>
<tr>
<th colspan="8">
<div id="displayCount" class="d-flex justify-content-end"></div>
</th>
</tr>
</thead>
<thead>
<tr>
<th>upload_file_seq</th>
<th>thumbnail_resource_pathname</th>
<th>board_seq</th>
<th>board_type</th>
<th>filename</th>
<th>original_filename</th>
<th>reg_date</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-center" colspan="8">등록된 데이터가 없습니다.</td>
</tr>
</tbody>
</table>
<ul id="pagingul">
</ul>
</div>
</div>
</div>
{{>layout/footer}}
<script src="/js/file_list.js"></script>
</body>
</html>
2) file_list.js
let totalData; //총 데이터 수
let dataPerPage; //한 페이지에 나타낼 글 수
let pageCount; //페이징에 나타낼 페이지 수
let currentPage; //현재 페이지
let fileList = {
init: function() {
this.list();
},
list: function(page) {
if (page == undefined || page == "") {
page = 1;
}
fetch("/api/file/fileList?page=" + page)
.then((response)=>response.json())
.then(res=>{
console.log(res.pageMaker);
totalData = res.pageMaker.totalCount;
dataPerPage = res.pageMaker.perPageNum;
pageCount = res.pageMaker.displayPageNum;
currentPage = res.pageMaker.page;
if (res.resState == "success") {
let html = "";
res.data.forEach(function(item) {
const regDate = item.regDate.replace('T', ' ').substring(0, 19);
const ext=item.originalFilename.split('.').pop().toLowerCase();
const ableExt=['jpg','png','jpeg','gif'];
let img=`<span class="material-symbols-outlined" style="font-size:90px" >file_Open</span>`;
if(ableExt.indexOf(ext) > -1) {
if(item.thumbnailResourcePathname==null){
img="썸네일 이미지 없음";
}else{
img=`<img class="img-thumbnail rounded max-auto d-inline" src="${item.thumbnailResourcePathname}">`;
}
}
html += `<tr>
<td>${item.uploadFileSeq}</td>
<td class="text-center">${img}</td>
<td>${item.boardSeq}</td>
<td>${item.boardType != null ? item.boardType.label : ""}</td>
<td>${item.filename}</td>
<td>${item.originalFilename}</td>
<td>${regDate}</td>
<th><button class="btn btn-sm btn-danger fileDeleteBtn" data-id="${item.uploadFileSeq}" >삭제</button></th>
</tr>
`;
});
document.querySelector("tbody").innerHTML = html;
}
//페이징 표시 호출
fileList.paging();
//삭제 이벤트 추가
let fileDeletes=document.querySelectorAll(".fileDeleteBtn");
for(let i=0; i<fileDeletes.length; i++){
fileDeletes[i].addEventListener("click", function(e){
fileList.fileDelete(e.target.getAttribute("data-id"));
});
}
}).catch(error=>console.log("error : {}", error));
},
//파일 삭제
fileDelete:function(uploadFileSeq){
if(confirm("정말 삭제 하시겠습니까?")){
console.log("파일 삭제 {} ",uploadFileSeq);
fetch("/api/file/fileDelate/"+uploadFileSeq,{
method:"DELETE"
})
.then((response)=>response.json())
.then((res)=>{
if(res.resState==="success"){
currentPage=1;
fileList.list();
}
});
}
},
// 페이징 표시 함수
//function(totalData, dataPerPage, pageCount, currentPage)
paging: function(){
console.log("currentPage : " + currentPage);
totalPage = Math.ceil(totalData / dataPerPage); //총 페이지 수
if (totalPage < pageCount) {
pageCount = totalPage;
}
let pageGroup = Math.ceil(currentPage / pageCount); // 페이지 그룹
let last = pageGroup * pageCount; //화면에 보여질 마지막 페이지 번호
if (last > totalPage) {
last = totalPage;
}
let first = last - (pageCount - 1); //화면에 보여질 첫번째 페이지 번호
let next = last + 1;
let prev = first - 1;
let pageHtml = "";
if (prev > 0) {
pageHtml += "<li><a href='#' id='prev'> « </a></li>";
}
//페이징 번호 표시
for (var i = first; i <= last; i++) {
if (currentPage == i) {
pageHtml +=
"<li class='on'><a href='#' id='" + i + "'>" + i + "</a></li>";
} else {
pageHtml += "<li><a href='#' id='" + i + "'>" + i + "</a></li>";
}
}
if (last < totalPage) {
pageHtml += "<li><a href='#' id='next'> » </a></li>";
}
document.querySelector("#pagingul").innerHTML = pageHtml;
let displayCount = "";
displayCount = "현재 1 - " + totalPage + " (" + currentPage + "페이지) / " + totalData + "건";
document.querySelector("#displayCount").innerText = displayCount;
//페이징 번호 클릭 이벤트
const paginationClass = document.querySelectorAll("#pagingul li a");
for (let i = 0; i < paginationClass.length; i++) {
paginationClass[i].addEventListener("click", function(e) {
e.preventDefault();
let $id = this.getAttribute("id")
selectedPage = this.innerText;
console.log("선택한 페이지 ", selectedPage);
if ($id == "next") selectedPage = next;
if ($id == "prev") selectedPage = prev;
fileList.list(selectedPage);
});
}
}
}
//파일 삭제
function fileDelete(uploadFileSeq){
alert(uploadFileSeq);
}
fileList.init();
소스 :

















댓글 ( 4)
댓글 남기기