๊ฒ์ํ - ํ์ผ ์ ๋ก๋
์คํ ์ข ๋๋ฌ์ฃผ์ธ์
Spring Boot (Back-End)
Spring Boot ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค.
๊ตฌํ ๊ธฐ๋ฅ
โข
โฆ
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฑ๋ก
โฆ
ํ์ผ ์์คํ
์ ๋ฑ๋ก
โข
โฆ
ํ์ผ ๋ชฉ๋ก ์กฐํ
โฆ
๋ค์ด๋ก๋
โฆ
์ธ๋ค์ผ ์ด๋ฏธ์ง ๋ณด๊ธฐ
โข
โฆ
๊ฒ์๊ธ์ ์ข
์๋ ์ฌ๋ฌ ํ์ผ ์ญ์
โฆ
์ ํ ํ์ผ ์ญ์
โฆ
๊ฐ๋ณ ํ์ผ ์ญ์
React (Front-End)
React ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ UI ๋ฐ API ๋ฅผ ๊ตฌํํฉ๋๋ค.
โข
โฆ
ํ์ผ ๋ฑ๋ก UI ์ถ๊ฐ
โฆ
ํ์ผ ์
๋ก๋ ์์ฒญ API
โข
โฆ
ํ์ผ ๋ชฉ๋ก ์กฐํ UI ๋ฐ API ์ถ๊ฐ
โฆ
๋ค์ด๋ก๋ UI ๋ฐ API ์ถ๊ฐ
โฆ
์ธ๋ค์ผ ์ด๋ฏธ์ง UI ์ถ๊ฐ
โข
โฆ
๊ฒ์๊ธ์ ์ข
์๋ ์ฌ๋ฌ ํ์ผ ์ญ์ (๊ฒ์๊ธ ์ญ์ ์, ๋ฐฑ์๋์์ ์ฒ๋ฆฌํจ)
โฆ
์ญ์ ํ ํ์ผ ์ฒดํฌ๋ฐ์ค UI ์ถ๊ฐ ๋ฐ ์์ ์์ฒญ ์, ์ญ์ ํ ํ์ผ ๋ฒํธ ๋ฆฌ์คํธ ๋ฐ์ดํฐ ์ถ๊ฐ
โฆ
๊ฐ๋ณ ํ์ผ ์ญ์ UI ๋ฐ API ์ถ๊ฐ
Spring Boot (Back-End)
Spring Boot ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค.
ํ์ผ ์
๋ก๋
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฑ๋ก
1.
๋ฐ์ดํฐ ๋ฒ ์ด์ค - ํ
์ด๋ธ ์์ฑ
2.
SQL ์ฟผ๋ฆฌ Mapper ์์ฑ
3.
DTO
4.
Mapper
5.
Service
6.
Controller
๋ฐ์ดํฐ ๋ฒ ์ด์ค - ํ ์ด๋ธ ์์ฑ
CREATE TABLE `file` (
`no` int NOT NULL AUTO_INCREMENT, -- ํ์ผ ๋ฒํธ (์๋์ฆ๊ฐ)
`parent_table` varchar(45) NOT NULL, -- ๋ถ๋ชจ ํ
์ด๋ธ๋ช
(์: 'board')
`parent_no` int NOT NULL, -- ๋ถ๋ชจ ํ
์ด๋ธ์์์ ๋ฒํธ
`file_name` text NOT NULL, -- ์ ์ฅ๋ ํ์ผ๋ช
`origin_name` text, -- ์๋ณธ ํ์ผ๋ช
`file_path` text NOT NULL, -- ํ์ผ ๊ฒฝ๋ก
`file_size` int NOT NULL DEFAULT '0', -- ํ์ผ ํฌ๊ธฐ (๊ธฐ๋ณธ๊ฐ 0)
`reg_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- ๋ฑ๋ก์ผ์
`upd_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- ์์ ์ผ์
`file_code` int NOT NULL DEFAULT '0', -- ํ์ผ ์ฝ๋ (๊ธฐ๋ณธ๊ฐ 0)
PRIMARY KEY (`no`) -- ์ฃผํค ์ค์
) COMMENT='ํ์ผ';
SQL
๋ณต์ฌ
SQL ์ฟผ๋ฆฌ Mapper ์์ฑ
โข
FileMapper.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">
<!-- namespace="๋งคํผ ์ธํฐํ์ด์ค ๊ฒฝ๋ก" -->
<mapper namespace="com.joeun.server.mapper.FileMapper">
<!-- ํ์ผ ๋ชฉ๋ก -->
<select id="list" resultType="Files">
SELECT *
FROM file
ORDER BY reg_date DESC
</select>
<!-- ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ํ
์ด๋ธ ๊ธฐ์ค -->
<!-- * ํ์ผ์ด ์ข
์๋๋ ํ
์ด๋ธ์ ๊ธฐ์ค์ผ๋ก ํ์ผ ๋ชฉ๋ก์ ์กฐํ -->
<!-- * ๊ฒ์๊ธ ๋ฒํธ 10
๐ ํ์ผ ๋ฒํธ 1
๐ ํ์ผ ๋ฒํธ 2
๐ ํ์ผ ๋ฒํธ 3
-->
<select id="listByParent" resultType="Files">
SELECT *
FROM file
WHERE parent_table = #{parentTable}
AND parent_no = #{parentNo}
ORDER BY reg_date DESC
</select>
<!-- ํ์ผ ์กฐํ -->
<select id="select" resultType="Files">
SELECT *
FROM file
WHERE no = #{no}
</select>
<!-- ํ์ผ ๋ฑ๋ก -->
<insert id="insert">
INSERT INTO file( parent_table, parent_no, file_name, origin_name, file_path, file_size, file_code )
VALUES ( #{parentTable}, #{parentNo}, #{fileName}, #{originName}, #{filePath}, #{fileSize}, #{fileCode} )
</insert>
<!-- ํ์ผ ์์ -->
<update id="update">
UPDATE file
SET parent_table = #{parentTable}
,parent_no = #{parentNo}
,file_name = #{fileName}
,origin_name = #{originName}
,file_path = #{filePath}
,file_size = #{fileSize}
,file_code = #{fileCode}
WHERE no = #{no}
</update>
<!-- ํ์ผ ์ญ์ -->
<delete id="delete">
DELETE FROM file
WHERE no = #{no}
</delete>
<!-- ํ์ผ ๋ชฉ๋ก ์ญ์ - ๋ถ๋ชจ ํ
์ด๋ธ ๊ธฐ์ค ํ์ผ ๋ชฉ๋ก ์ญ์ -->
<delete id="deleteByParent">
DELETE FROM file
WHERE parent_table = #{parentTable}
AND parent_no = #{parentNo}
</delete>
<!-- ๊ฒ์๊ธ ๋ฒํธ ์ต๋๊ฐ -->
<select id="maxPk" resultType="int">
SELECT MAX(no)
FROM file
</select>
</mapper>
SQL
๋ณต์ฌ
DTO
โข
Files.java
package com.joeun.server.dto;
import java.util.Date;
import lombok.Data;
@Data
public class Files {
private int no;
private String parentTable;
private int parentNo;
private String fileName;
private String originName;
private String filePath;
private long fileSize;
private Date regDate;
private Date updDate;
private int fileCode;
}
Java
๋ณต์ฌ
Mapper
โข
FileMapper.java
package com.joeun.server.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.joeun.server.dto.Files;
@Mapper
public interface FileMapper {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ๋ฒํธ(๊ธฐ๋ณธํค) ์ต๋๊ฐ
public int maxPk() throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files file) throws Exception;
}
Java
๋ณต์ฌ
Service
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file );
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
// DB ์ ๋ฐ์ดํฐ ๋ฑ๋ก
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
// โ
(New) ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
// โ
(New) ํ์ผ ์
๋ก๋
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
}
Java
๋ณต์ฌ
Controller
โข
FileController.java
package com.joeun.server.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
}
Java
๋ณต์ฌ
ํ์ผ ์์คํ ์ ๋ฑ๋ก
1.
DTO
2.
Service
DTO
โข
Files.java
package com.joeun.server.dto;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
@Data
public class Files {
private int no;
private String parentTable;
private int parentNo;
private String fileName;
private String originName;
private String filePath;
private long fileSize;
private Date regDate;
private Date updDate;
private int fileCode;
MultipartFile file; // โ
์ถ๊ฐ
}
Java
๋ณต์ฌ
Service
โข
FileServiceImpl.java
// โ
(New) ํ์ผ์
๋ก๋
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// โ
(New) ํ์ผ์
๋ก๋
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
๏ธ ํ์ผ ์กฐํ
ํ์ผ ๋ชฉ๋ก ์กฐํ
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
BoardController.java
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// โ
(New) ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// โ
(New) - ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
}
Java
๋ณต์ฌ
BoardController.java
@GetMapping("/{no}")
public ResponseEntity<?> getOne(@PathVariable Integer no, Files files) {
log.info("[GET] - /boards/" + no + " - ๊ฒ์๊ธ ์กฐํ");
try {
Board board = boardService.select(no);
files.setParentTable("board");
files.setParentNo(no);
List<Files> fileList = fileService.listByParent(files); // ํ์ผ ์ ๋ณด
Map<String, Object> response = new HashMap<>();
response.put("board", board);
response.put("fileList", fileList);
if( board == null ) {
board = new Board();
board.setTitle("๋ฐ์ดํฐ ์์");
}
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Java
๋ณต์ฌ
package com.joeun.server.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.service.BoardService;
import com.joeun.server.service.FileService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/boards")
public class BoardController {
@Autowired
private BoardService boardService;
@Autowired
private FileService fileService;
// ๐ฉโ๐ป CRUD ๋ฉ์๋ ์๋ ์์ฑ : sp-crud
// ๐ฉโ๐ป ์๋ import : alt + shift + O
// ๐ฉโ๐ป ํ ์ค ์ญ์ : ctrl + shift + K
@GetMapping()
public ResponseEntity<?> getAll() {
log.info("[GET] - /boards - ๊ฒ์๊ธ ๋ชฉ๋ก");
try {
List<Board> boardList = boardService.list();
if( boardList == null )
log.info("์กฐํ๋ ๊ฒ์๊ธ ์์");
else
log.info("๊ฒ์๊ธ ์ : " + boardList.size());
return new ResponseEntity<>(boardList, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/{no}")
public ResponseEntity<?> getOne(@PathVariable Integer no, Files files) {
log.info("[GET] - /boards/" + no + " - ๊ฒ์๊ธ ์กฐํ");
try {
Board board = boardService.select(no);
files.setParentTable("board");
files.setParentNo(no);
List<Files> fileList = fileService.listByParent(files); // ํ์ผ ์ ๋ณด
Map<String, Object> response = new HashMap<>();
response.put("board", board);
response.put("fileList", fileList);
if( board == null ) {
board = new Board();
board.setTitle("๋ฐ์ดํฐ ์์");
}
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping()
// public ResponseEntity<?> create(@RequestBody Board board) { // Content-Type : application/json
public ResponseEntity<?> create(Board board) { // Content-Type : multipart/form-data
log.info("[POST] - /boards - ๊ฒ์๊ธ ๋ฑ๋ก");
log.info("board : " + board.toString());
List<MultipartFile> files = board.getFiles();
if( files != null )
for (MultipartFile file : files) {
log.info("file : " + file.getOriginalFilename());
}
try {
int result = boardService.insert(board);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ๋ฑ๋ก ์๋ฃ", HttpStatus.CREATED); // 201
else
return new ResponseEntity<>("๊ฒ์๊ธ ๋ฑ๋ก ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping()
// public ResponseEntity<?> update(@RequestBody Board board) { // Content-Type : application/json
public ResponseEntity<?> update(Board board) { // Content-Type : multipart/form-data
log.info("[PUT] - /boards - ๊ฒ์๊ธ ์์ ");
try {
int result = boardService.update(board);
log.info("์์ : " + board);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ์์ ์๋ฃ", HttpStatus.OK);
else
return new ResponseEntity<>("๊ฒ์๊ธ ์์ ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@DeleteMapping("/{no}")
public ResponseEntity<?> destroy(@PathVariable Integer no) {
log.info("[DELETE] - /boards/" + no + " - ๊ฒ์๊ธ ์ญ์ ");
try {
int result = boardService.delete(no);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ์ญ์ ์๋ฃ", HttpStatus.OK);
else
return new ResponseEntity<>("๊ฒ์๊ธ ์ญ์ ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Java
๋ณต์ฌ
๋ค์ด๋ก๋
โข
FileService.java
โข
FileServiceImpl.java
โข
FileController.java
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// โ
(New) - ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
}
Java
๋ณต์ฌ
FileController.java
package com.joeun.server.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
}
Java
๋ณต์ฌ
์ธ๋ค์ผ ์ด๋ฏธ์ง ๋ณด๊ธฐ
โข
FileController.java
FileController.java
package com.joeun.server.controller;
import java.io.File;
import java.io.FileInputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 com.joeun.server.dto.Files;
import com.joeun.server.service.FileService;
import com.joeun.server.utils.MediaUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private ResourceLoader resourceLoader;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
/**
* ์ด๋ฏธ์ง ์ธ๋ค์ผ
* @param no
* @param response
* @throws Exception
*/
@GetMapping("/img/{no}")
public void showImg(@PathVariable Integer no, HttpServletResponse response) throws Exception {
Files file = fileService.select(no);
String filePath = (file != null) ? file.getFilePath() : null;
Resource resource = resourceLoader.getResource("classpath:static/img/no-image.png");
File imgFile;
if (filePath == null || !(imgFile = new File(filePath)).exists()) {
// ํ์ผ์ด ์กด์ฌํ์ง ์๊ฑฐ๋ ํ์ผ ๊ฒฝ๋ก๊ฐ null์ธ ๊ฒฝ์ฐ
imgFile = resource.getFile();
}
String ext = filePath.substring(filePath.lastIndexOf(".") + 1);
MediaType mType = MediaUtil.getMediaType(ext);
if (mType == null) {
// ์ด๋ฏธ์ง ํ์
์ด ์๋ ๊ฒฝ์ฐ
response.setContentType(MediaType.IMAGE_PNG_VALUE); // ๊ธฐ๋ณธ์ ์ผ๋ก PNG๋ก ์ค์
imgFile = resource.getFile();
} else {
// ์ด๋ฏธ์ง ํ์
์ผ ๊ฒฝ์ฐ
response.setContentType(mType.toString());
}
FileInputStream fis = new FileInputStream(imgFile);
ServletOutputStream sos = response.getOutputStream();
FileCopyUtils.copy(fis, sos);
}
}
Java
๋ณต์ฌ
ํ์ผ ์ญ์
๊ฒ์๊ธ์ ์ข ์๋ ์ฌ๋ฌ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throwsdeleteByParent Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// โ
(New) ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
// โ
(New) - ๊ฒ์๊ธ์ ์ข
์๋ ํ์ผ ์ญ์
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
}
Java
๋ณต์ฌ
์ ํ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
// ํ์ผ ์ญ์ - noList ๊ธฐ์ค
public int deleteByNoList(List<Integer> noList) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
// ๊ฐ๋ณ ํ์ผ ์ญ์
List<Integer> deleteFileNoList = board.getDeleteFileNoList();
result += fileService.deleteByNoList(deleteFileNoList);
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
// โ
(New) ๊ฐ๋ณ ํ์ผ ์ญ์
List<Integer> deleteFileNoList = board.getDeleteFileNoList();
result += fileService.deleteByNoList(deleteFileNoList);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
}
Java
๋ณต์ฌ
๊ฐ๋ณ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
FileController.java
FileService.java
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
// ํ์ผ ์ญ์ - noList ๊ธฐ์ค
public int deleteByNoList(List<Integer> noList) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
@Override
public int delete(int no) throws Exception {
Files file = fileMapper.select(no);
if( file == null ) return 0;
String filePath = file.getFilePath();
File deleteFile = new File(filePath);
if( !deleteFile.exists() ) return 0;
boolean deleted = deleteFile.delete();
int result = 0;
if( deleted ) {
result = fileMapper.delete(no);
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public int delete(int no) throws Exception {
Files file = fileMapper.select(no);
if( file == null ) return 0;
String filePath = file.getFilePath();
File deleteFile = new File(filePath);
if( !deleteFile.exists() ) return 0;
boolean deleted = deleteFile.delete();
int result = 0;
if( deleted ) {
result = fileMapper.delete(no);
}
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
// byte[] buffer = new byte[1024]; // 1024bytes = 1KB ๋จ์ ๋ฒํผ
// int data;
// while( (data = fis.read(buffer)) != -1 ) { // 1KB ์ฉ ํ์ผ์
๋ ฅ
// sos.write(buffer, 0, data); // 1KB ์ฉ ํ์ผ์ถ๋ ฅ
// }
fis.close();
sos.close();
return 1;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
FileController.java
package com.joeun.server.controller;
import java.io.File;
import java.io.FileInputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 com.joeun.server.dto.Files;
import com.joeun.server.service.FileService;
import com.joeun.server.utils.MediaUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private ResourceLoader resourceLoader;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
/**
* ์ด๋ฏธ์ง ์ธ๋ค์ผ
* @param no
* @param response
* @throws Exception
*/
@GetMapping("/img/{no}")
public void showImg(@PathVariable Integer no, HttpServletResponse response) throws Exception {
Files file = fileService.select(no);
String filePath = (file != null) ? file.getFilePath() : null;
Resource resource = resourceLoader.getResource("classpath:static/img/no-image.png");
File imgFile;
if (filePath == null || !(imgFile = new File(filePath)).exists()) {
// ํ์ผ์ด ์กด์ฌํ์ง ์๊ฑฐ๋ ํ์ผ ๊ฒฝ๋ก๊ฐ null์ธ ๊ฒฝ์ฐ
imgFile = resource.getFile();
}
String ext = filePath.substring(filePath.lastIndexOf(".") + 1);
MediaType mType = MediaUtil.getMediaType(ext);
if (mType == null) {
// ์ด๋ฏธ์ง ํ์
์ด ์๋ ๊ฒฝ์ฐ
response.setContentType(MediaType.IMAGE_PNG_VALUE); // ๊ธฐ๋ณธ์ ์ผ๋ก PNG๋ก ์ค์
imgFile = resource.getFile();
} else {
// ์ด๋ฏธ์ง ํ์
์ผ ๊ฒฝ์ฐ
response.setContentType(mType.toString());
}
FileInputStream fis = new FileInputStream(imgFile);
ServletOutputStream sos = response.getOutputStream();
FileCopyUtils.copy(fis, sos);
}
/**
* ํ์ผ ์ญ์
* @param file
* @return
* @throws Exception
*/
@DeleteMapping("/{no}")
public ResponseEntity<String> deleteFile(@PathVariable Integer no) throws Exception {
log.info("[DELETE] - /file");
int fileNo = no;
log.info("fileNo : " + fileNo);
if( fileNo == 0 )
return new ResponseEntity<String>("FAIL", HttpStatus.BAD_REQUEST);
int result = fileService.delete(fileNo);
if( result == 0 )
return new ResponseEntity<String>("FAIL", HttpStatus.OK);
return new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
}
}
Java
๋ณต์ฌ
React (Front-End)
React ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ UI ๋ฐ API ๋ฅผ ๊ตฌํํฉ๋๋ค.
ํ์ผ ์
๋ก๋
ํ์ผ ๋ฑ๋ก UI ์ถ๊ฐ
BoardInsertForm.jsx
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import './BoardInsertForm.css'
const BoardInsertForm = ({ onInsert }) => {
// state ์ค์
const [title, setTitle] = useState('');
const [writer, setWriter] = useState('');
const [content, setContent] = useState('');
const [files, setFiles] = useState(null); // โ
files state ์ถ๊ฐ
const handleChangeTitle = (e) => {
setTitle(e.target.value)
}
const handleChangeWriter = (e) => {
setWriter(e.target.value)
}
const handleChangeContent = (e) => {
setContent(e.target.value)
}
// โ
ํ์ผ ํธ๋ค๋ฌ ์ถ๊ฐ
const handleFileChange = (e) => {
setFiles(e.target.files);
};
const onSubmit = () => {
const formData = new FormData();
formData.append('title', title);
formData.append('writer', writer);
formData.append('content', content);
const headers = {
headers: {
'Content-Type' : 'multipart/form-data',
},
};
if (files) {
for (let i = 0; i < files.length; i++) {
formData.append(`files[${i}]`, files[i]);
}
}
// onInsert(title, writer, content)
// onInsert({title,writer,content,files}, headers) // formData ์ฌ์ฉ โ
onInsert(formData, headers) // formData ์ฌ์ฉ โญ
}
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ๋ฑ๋ก</h1>
<table className='table'>
<tbody>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text"
className='form-input'
value={title}
onChange={handleChangeTitle} />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text"
className='form-input'
value={writer}
onChange={handleChangeWriter} />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={content}
onChange={handleChangeContent}
></textarea>
</td>
</tr>
<tr>
<td>ํ์ผ</td>
<td>
<input type='file' onChange={handleFileChange} multiple />
</td>
</tr>
</tbody>
</table>
<div className='btn-box'>
<Link to="/boards" className='btn'>๋ชฉ๋ก</Link>
<button onClick={ onSubmit } className='btn'>๋ฑ๋ก</button>
</div>
</div>
)
}
export default BoardInsertForm
JavaScript
๋ณต์ฌ
ํ์ผ ์ ๋ก๋ ์์ฒญ API
files.js
import axios from 'axios';
// ์
๋ก๋
export const upload = (formData, headers) => axios.post(`/file/upload`, formData, headers)
JavaScript
๋ณต์ฌ
๏ธ ํ์ผ ์กฐํ
ํ์ผ ๋ชฉ๋ก ์กฐํ UI ๋ฐ API ์ถ๊ฐ
BoardReadContainer.jsx
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import * as boards from '../apis/boards';
import BoardRead from '../components/BoardRead/BoardRead';
// ๐ฉโ๐ป ๊ฒ์๊ธ ์กฐํ
const BoardReadContainer = () => {
const { no } = useParams()
const [board, setBoard] = useState({});
const [fileList, setFileList] = useState([]);
const [isLoading, setLoading] = useState(false);
const getBoard = async () => {
setLoading(true)
try {
const response = await boards.select(no);
const data = response.data;
console.log(data);
const board = data.board;
const fileList = data.fileList;
setBoard(board);
setFileList(fileList);
}
catch(e) {
console.log(e);
}
setLoading(false)
}
useEffect( () => {
getBoard()
},[])
return (<BoardRead no={no}
board={board}
fileList={fileList}
isLoading={isLoading}
/>)
}
export default BoardReadContainer
JavaScript
๋ณต์ฌ
BoardRead.jsx
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import * as format from '../../apis/format';
import './BoardRead.css';
const BoardRead = ({ no, board, fileList, isLoading }) => {
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์กฐํ</h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={format.formatDate( board.regDate )} readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={board.title} readOnly />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={board.writer} readOnly />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={board.content}
readOnly></textarea>
</td>
</tr>
<tr>
<td colSpan={2}>ํ์ผ</td>
</tr>
<tr>
<td colSpan={2}>
{ fileList.map( (file) => (
<div className='file-box' key={file.no}>
<div className="item">
<img src={`/file/img/${file.no}`} alt={file.fileName} />
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
</div>
</div>
))}
</td>
</tr>
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<Link className='btn' to="/boards">๋ชฉ๋ก</Link>
<Link className='btn' to={`/boards/update/${no}`}>์์ </Link>
</div>
</div>
)
}
export default BoardRead
JavaScript
๋ณต์ฌ
๋ค์ด๋ก๋ UI ๋ฐ API ์ถ๊ฐ
BoardRead.jsx
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import * as format from '../../apis/format';
import './BoardRead.css';
const BoardRead = ({ no, board, fileList, isLoading }) => {
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์กฐํ</h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={format.formatDate( board.regDate )} readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={board.title} readOnly />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={board.writer} readOnly />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={board.content}
readOnly></textarea>
</td>
</tr>
<tr>
<td colSpan={2}>ํ์ผ</td>
</tr>
<tr>
<td colSpan={2}>
{ fileList.map( (file) => (
<div className='file-box' key={file.no}>
<div className="item">
<img src={`/file/img/${file.no}`} alt={file.fileName} />
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
<button className="btn" onClick={() => handleDownload(file.no, file.originName)}>๋ค์ด๋ก๋</button>
</div>
</div>
))}
</td>
</tr>
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<Link className='btn' to="/boards">๋ชฉ๋ก</Link>
<Link className='btn' to={`/boards/update/${no}`}>์์ </Link>
</div>
</div>
)
}
export default BoardRead
JavaScript
๋ณต์ฌ
files.js
JavaScript
๋ณต์ฌ
์ธ๋ค์ผ ์ด๋ฏธ์ง UI ์ถ๊ฐ
ํ์ผ ์ญ์
์ญ์ ํ ํ์ผ ์ฒดํฌ๋ฐ์ค UI ์ถ๊ฐ ๋ฐ ์์ ์์ฒญ ์, ์ญ์ ํ ํ์ผ ๋ฒํธ ๋ฆฌ์คํธ ๋ฐ์ดํฐ ์ถ๊ฐ
๊ฐ๋ณ ํ์ผ ์ญ์ UI ๋ฐ API ์ถ๊ฐ
๊ฒ์ํ - ํ์ผ ์ ๋ก๋
Spring Boot (Back-End)
Spring Boot ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค.
๊ตฌํ ๊ธฐ๋ฅ
โข
โฆ
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฑ๋ก
โฆ
ํ์ผ ์์คํ
์ ๋ฑ๋ก
โข
โฆ
ํ์ผ ๋ชฉ๋ก ์กฐํ
โฆ
๋ค์ด๋ก๋
โฆ
์ธ๋ค์ผ ์ด๋ฏธ์ง ๋ณด๊ธฐ
โข
โฆ
๊ฒ์๊ธ์ ์ข
์๋ ์ฌ๋ฌ ํ์ผ ์ญ์
โฆ
์ ํ ํ์ผ ์ญ์
โฆ
๊ฐ๋ณ ํ์ผ ์ญ์
React (Front-End)
React ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ UI ๋ฐ API ๋ฅผ ๊ตฌํํฉ๋๋ค.
โข
โฆ
ํ์ผ ๋ฑ๋ก UI ์ถ๊ฐ
โฆ
ํ์ผ ์
๋ก๋ ์์ฒญ API
โข
โฆ
ํ์ผ ๋ชฉ๋ก ์กฐํ UI ๋ฐ API ์ถ๊ฐ
โฆ
๋ค์ด๋ก๋ UI ๋ฐ API ์ถ๊ฐ
โฆ
์ธ๋ค์ผ ์ด๋ฏธ์ง UI ์ถ๊ฐ
โข
โฆ
๊ฒ์๊ธ์ ์ข
์๋ ์ฌ๋ฌ ํ์ผ ์ญ์ (๊ฒ์๊ธ ์ญ์ ์, ๋ฐฑ์๋์์ ์ฒ๋ฆฌํจ)
โฆ
์ญ์ ํ ํ์ผ ์ฒดํฌ๋ฐ์ค UI ์ถ๊ฐ ๋ฐ ์์ ์์ฒญ ์, ์ญ์ ํ ํ์ผ ๋ฒํธ ๋ฆฌ์คํธ ๋ฐ์ดํฐ ์ถ๊ฐ
โฆ
๊ฐ๋ณ ํ์ผ ์ญ์ UI ๋ฐ API ์ถ๊ฐ
Spring Boot (Back-End)
Spring Boot ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค.
ํ์ผ ์
๋ก๋
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฑ๋ก
1.
๋ฐ์ดํฐ ๋ฒ ์ด์ค - ํ
์ด๋ธ ์์ฑ
2.
SQL ์ฟผ๋ฆฌ Mapper ์์ฑ
3.
DTO
4.
Mapper
5.
Service
6.
Controller
๋ฐ์ดํฐ ๋ฒ ์ด์ค - ํ ์ด๋ธ ์์ฑ
CREATE TABLE `file` (
`no` int NOT NULL AUTO_INCREMENT, -- ํ์ผ ๋ฒํธ (์๋์ฆ๊ฐ)
`parent_table` varchar(45) NOT NULL, -- ๋ถ๋ชจ ํ
์ด๋ธ๋ช
(์: 'board')
`parent_no` int NOT NULL, -- ๋ถ๋ชจ ํ
์ด๋ธ์์์ ๋ฒํธ
`file_name` text NOT NULL, -- ์ ์ฅ๋ ํ์ผ๋ช
`origin_name` text, -- ์๋ณธ ํ์ผ๋ช
`file_path` text NOT NULL, -- ํ์ผ ๊ฒฝ๋ก
`file_size` int NOT NULL DEFAULT '0', -- ํ์ผ ํฌ๊ธฐ (๊ธฐ๋ณธ๊ฐ 0)
`reg_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- ๋ฑ๋ก์ผ์
`upd_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- ์์ ์ผ์
`file_code` int NOT NULL DEFAULT '0', -- ํ์ผ ์ฝ๋ (๊ธฐ๋ณธ๊ฐ 0)
PRIMARY KEY (`no`) -- ์ฃผํค ์ค์
) COMMENT='ํ์ผ';
SQL
๋ณต์ฌ
SQL ์ฟผ๋ฆฌ Mapper ์์ฑ
โข
FileMapper.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">
<!-- namespace="๋งคํผ ์ธํฐํ์ด์ค ๊ฒฝ๋ก" -->
<mapper namespace="com.joeun.server.mapper.FileMapper">
<!-- ํ์ผ ๋ชฉ๋ก -->
<select id="list" resultType="Files">
SELECT *
FROM file
ORDER BY reg_date DESC
</select>
<!-- ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ํ
์ด๋ธ ๊ธฐ์ค -->
<!-- * ํ์ผ์ด ์ข
์๋๋ ํ
์ด๋ธ์ ๊ธฐ์ค์ผ๋ก ํ์ผ ๋ชฉ๋ก์ ์กฐํ -->
<!-- * ๊ฒ์๊ธ ๋ฒํธ 10
๐ ํ์ผ ๋ฒํธ 1
๐ ํ์ผ ๋ฒํธ 2
๐ ํ์ผ ๋ฒํธ 3
-->
<select id="listByParent" resultType="Files">
SELECT *
FROM file
WHERE parent_table = #{parentTable}
AND parent_no = #{parentNo}
ORDER BY reg_date DESC
</select>
<!-- ํ์ผ ์กฐํ -->
<select id="select" resultType="Files">
SELECT *
FROM file
WHERE no = #{no}
</select>
<!-- ํ์ผ ๋ฑ๋ก -->
<insert id="insert">
INSERT INTO file( parent_table, parent_no, file_name, origin_name, file_path, file_size, file_code )
VALUES ( #{parentTable}, #{parentNo}, #{fileName}, #{originName}, #{filePath}, #{fileSize}, #{fileCode} )
</insert>
<!-- ํ์ผ ์์ -->
<update id="update">
UPDATE file
SET parent_table = #{parentTable}
,parent_no = #{parentNo}
,file_name = #{fileName}
,origin_name = #{originName}
,file_path = #{filePath}
,file_size = #{fileSize}
,file_code = #{fileCode}
WHERE no = #{no}
</update>
<!-- ํ์ผ ์ญ์ -->
<delete id="delete">
DELETE FROM file
WHERE no = #{no}
</delete>
<!-- ํ์ผ ๋ชฉ๋ก ์ญ์ - ๋ถ๋ชจ ํ
์ด๋ธ ๊ธฐ์ค ํ์ผ ๋ชฉ๋ก ์ญ์ -->
<delete id="deleteByParent">
DELETE FROM file
WHERE parent_table = #{parentTable}
AND parent_no = #{parentNo}
</delete>
<!-- ๊ฒ์๊ธ ๋ฒํธ ์ต๋๊ฐ -->
<select id="maxPk" resultType="int">
SELECT MAX(no)
FROM file
</select>
</mapper>
SQL
๋ณต์ฌ
DTO
โข
Files.java
package com.joeun.server.dto;
import java.util.Date;
import lombok.Data;
@Data
public class Files {
private int no;
private String parentTable;
private int parentNo;
private String fileName;
private String originName;
private String filePath;
private long fileSize;
private Date regDate;
private Date updDate;
private int fileCode;
}
Java
๋ณต์ฌ
Mapper
โข
FileMapper.java
package com.joeun.server.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.joeun.server.dto.Files;
@Mapper
public interface FileMapper {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ๋ฒํธ(๊ธฐ๋ณธํค) ์ต๋๊ฐ
public int maxPk() throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files file) throws Exception;
}
Java
๋ณต์ฌ
Service
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file );
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
// DB ์ ๋ฐ์ดํฐ ๋ฑ๋ก
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
// โ
(New) ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
// โ
(New) ํ์ผ ์
๋ก๋
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
}
Java
๋ณต์ฌ
Controller
โข
FileController.java
package com.joeun.server.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
}
Java
๋ณต์ฌ
ํ์ผ ์์คํ ์ ๋ฑ๋ก
1.
DTO
2.
Service
DTO
โข
Files.java
package com.joeun.server.dto;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
@Data
public class Files {
private int no;
private String parentTable;
private int parentNo;
private String fileName;
private String originName;
private String filePath;
private long fileSize;
private Date regDate;
private Date updDate;
private int fileCode;
MultipartFile file; // โ
์ถ๊ฐ
}
Java
๋ณต์ฌ
Service
โข
FileServiceImpl.java
// โ
(New) ํ์ผ์
๋ก๋
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// โ
(New) ํ์ผ์
๋ก๋
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
๏ธ ํ์ผ ์กฐํ
ํ์ผ ๋ชฉ๋ก ์กฐํ
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
BoardController.java
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// โ
(New) ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// โ
(New) - ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
}
Java
๋ณต์ฌ
BoardController.java
@GetMapping("/{no}")
public ResponseEntity<?> getOne(@PathVariable Integer no, Files files) {
log.info("[GET] - /boards/" + no + " - ๊ฒ์๊ธ ์กฐํ");
try {
Board board = boardService.select(no);
files.setParentTable("board");
files.setParentNo(no);
List<Files> fileList = fileService.listByParent(files); // ํ์ผ ์ ๋ณด
Map<String, Object> response = new HashMap<>();
response.put("board", board);
response.put("fileList", fileList);
if( board == null ) {
board = new Board();
board.setTitle("๋ฐ์ดํฐ ์์");
}
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Java
๋ณต์ฌ
package com.joeun.server.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.service.BoardService;
import com.joeun.server.service.FileService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/boards")
public class BoardController {
@Autowired
private BoardService boardService;
@Autowired
private FileService fileService;
// ๐ฉโ๐ป CRUD ๋ฉ์๋ ์๋ ์์ฑ : sp-crud
// ๐ฉโ๐ป ์๋ import : alt + shift + O
// ๐ฉโ๐ป ํ ์ค ์ญ์ : ctrl + shift + K
@GetMapping()
public ResponseEntity<?> getAll() {
log.info("[GET] - /boards - ๊ฒ์๊ธ ๋ชฉ๋ก");
try {
List<Board> boardList = boardService.list();
if( boardList == null )
log.info("์กฐํ๋ ๊ฒ์๊ธ ์์");
else
log.info("๊ฒ์๊ธ ์ : " + boardList.size());
return new ResponseEntity<>(boardList, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/{no}")
public ResponseEntity<?> getOne(@PathVariable Integer no, Files files) {
log.info("[GET] - /boards/" + no + " - ๊ฒ์๊ธ ์กฐํ");
try {
Board board = boardService.select(no);
files.setParentTable("board");
files.setParentNo(no);
List<Files> fileList = fileService.listByParent(files); // ํ์ผ ์ ๋ณด
Map<String, Object> response = new HashMap<>();
response.put("board", board);
response.put("fileList", fileList);
if( board == null ) {
board = new Board();
board.setTitle("๋ฐ์ดํฐ ์์");
}
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping()
// public ResponseEntity<?> create(@RequestBody Board board) { // Content-Type : application/json
public ResponseEntity<?> create(Board board) { // Content-Type : multipart/form-data
log.info("[POST] - /boards - ๊ฒ์๊ธ ๋ฑ๋ก");
log.info("board : " + board.toString());
List<MultipartFile> files = board.getFiles();
if( files != null )
for (MultipartFile file : files) {
log.info("file : " + file.getOriginalFilename());
}
try {
int result = boardService.insert(board);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ๋ฑ๋ก ์๋ฃ", HttpStatus.CREATED); // 201
else
return new ResponseEntity<>("๊ฒ์๊ธ ๋ฑ๋ก ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping()
// public ResponseEntity<?> update(@RequestBody Board board) { // Content-Type : application/json
public ResponseEntity<?> update(Board board) { // Content-Type : multipart/form-data
log.info("[PUT] - /boards - ๊ฒ์๊ธ ์์ ");
try {
int result = boardService.update(board);
log.info("์์ : " + board);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ์์ ์๋ฃ", HttpStatus.OK);
else
return new ResponseEntity<>("๊ฒ์๊ธ ์์ ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@DeleteMapping("/{no}")
public ResponseEntity<?> destroy(@PathVariable Integer no) {
log.info("[DELETE] - /boards/" + no + " - ๊ฒ์๊ธ ์ญ์ ");
try {
int result = boardService.delete(no);
if( result > 0 )
return new ResponseEntity<>("๊ฒ์๊ธ ์ญ์ ์๋ฃ", HttpStatus.OK);
else
return new ResponseEntity<>("๊ฒ์๊ธ ์ญ์ ์คํจ", HttpStatus.OK);
} catch (Exception e) {
log.error(null, e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Java
๋ณต์ฌ
๋ค์ด๋ก๋
โข
FileService.java
โข
FileServiceImpl.java
โข
FileController.java
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// โ
(New) - ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
}
Java
๋ณต์ฌ
FileController.java
package com.joeun.server.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
}
Java
๋ณต์ฌ
์ธ๋ค์ผ ์ด๋ฏธ์ง ๋ณด๊ธฐ
โข
FileController.java
FileController.java
package com.joeun.server.controller;
import java.io.File;
import java.io.FileInputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 com.joeun.server.dto.Files;
import com.joeun.server.service.FileService;
import com.joeun.server.utils.MediaUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private ResourceLoader resourceLoader;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
/**
* ์ด๋ฏธ์ง ์ธ๋ค์ผ
* @param no
* @param response
* @throws Exception
*/
@GetMapping("/img/{no}")
public void showImg(@PathVariable Integer no, HttpServletResponse response) throws Exception {
Files file = fileService.select(no);
String filePath = (file != null) ? file.getFilePath() : null;
Resource resource = resourceLoader.getResource("classpath:static/img/no-image.png");
File imgFile;
if (filePath == null || !(imgFile = new File(filePath)).exists()) {
// ํ์ผ์ด ์กด์ฌํ์ง ์๊ฑฐ๋ ํ์ผ ๊ฒฝ๋ก๊ฐ null์ธ ๊ฒฝ์ฐ
imgFile = resource.getFile();
}
String ext = filePath.substring(filePath.lastIndexOf(".") + 1);
MediaType mType = MediaUtil.getMediaType(ext);
if (mType == null) {
// ์ด๋ฏธ์ง ํ์
์ด ์๋ ๊ฒฝ์ฐ
response.setContentType(MediaType.IMAGE_PNG_VALUE); // ๊ธฐ๋ณธ์ ์ผ๋ก PNG๋ก ์ค์
imgFile = resource.getFile();
} else {
// ์ด๋ฏธ์ง ํ์
์ผ ๊ฒฝ์ฐ
response.setContentType(mType.toString());
}
FileInputStream fis = new FileInputStream(imgFile);
ServletOutputStream sos = response.getOutputStream();
FileCopyUtils.copy(fis, sos);
}
}
Java
๋ณต์ฌ
ํ์ผ ์ญ์
๊ฒ์๊ธ์ ์ข ์๋ ์ฌ๋ฌ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throwsdeleteByParent Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// โ
(New) ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
// โ
(New) - ๊ฒ์๊ธ์ ์ข
์๋ ํ์ผ ์ญ์
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
}
Java
๋ณต์ฌ
์ ํ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
BoardServiceImpl.java
โข
FileService.java
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
// ํ์ผ ์ญ์ - noList ๊ธฐ์ค
public int deleteByNoList(List<Integer> noList) throws Exception;
}
Java
๋ณต์ฌ
โข
FileServiceImpl.java
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
// ํ์ผ ๋ชฉ๋ก ์กฐํ
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
fis.close();
sos.close();
return 1;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
}
Java
๋ณต์ฌ
โข
BoardServiceImpl.java
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
// ๊ฐ๋ณ ํ์ผ ์ญ์
List<Integer> deleteFileNoList = board.getDeleteFileNoList();
result += fileService.deleteByNoList(deleteFileNoList);
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
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 com.joeun.server.dto.Board;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Autowired
private FileService fileService;
@Override
public List<Board> list() throws Exception {
List<Board> boardList = boardMapper.list();
return boardList;
}
@Override
public Board select(int no) throws Exception {
Board board = boardMapper.select(no);
return board;
}
@Override
@Transactional
public int insert(Board board) throws Exception {
int result = boardMapper.insert(board); // ์๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ pk ๊ฐ์ ธ์ด
int parentNo = boardMapper.maxPk();
board.setNo(parentNo);
result += uploadFiles(board);
return result;
}
@Override
public int update(Board board) throws Exception {
int result = boardMapper.update(board);
// ํ์ผ ์
๋ก๋
result += uploadFiles(board);
// โ
(New) ๊ฐ๋ณ ํ์ผ ์ญ์
List<Integer> deleteFileNoList = board.getDeleteFileNoList();
result += fileService.deleteByNoList(deleteFileNoList);
return result;
}
@Override
public int updateViews(int count, int no) throws Exception {
int result = boardMapper.updateViews(count, no);
return result;
}
public int uploadFiles(Board board) throws Exception {
String parentTable = "board";
int parentNo = board.getNo();
int result = 0;
List<MultipartFile> fileList = board.getFiles();
if( fileList != null && !fileList.isEmpty() ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
result = fileService.uploadFiles(fileInfo, fileList);
}
return result;
}
@Override
@Transactional
public int delete(int no) throws Exception {
int result = boardMapper.delete(no);
String parentTable = "board";
int parentNo = no;
if( result > 0 ) {
Files fileInfo = new Files();
fileInfo.setParentTable(parentTable);
fileInfo.setParentNo(parentNo);
int fileResult = fileService.deleteByParent(fileInfo);
result = fileResult;
}
return result;
}
}
Java
๋ณต์ฌ
๊ฐ๋ณ ํ์ผ ์ญ์
โข
FileService.java
โข
FileServiceImpl.java
โข
FileController.java
FileService.java
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import jakarta.servlet.http.HttpServletResponse;
public interface FileService {
// ํ์ผ ๋ชฉ๋ก
public List<Files> list() throws Exception;
// ํ์ผ ์กฐํ
public Files select(int no) throws Exception;
// ํ์ผ ๋ฑ๋ก
public int insert(Files file) throws Exception;
// ํ์ผ ์์
public int update(Files file) throws Exception;
// ํ์ผ ์ญ์
public int delete(int no) throws Exception;
// ํ์ผ ์
๋ก๋
public int uploadFiles(Files file, List<MultipartFile> fileList) throws Exception;
// ํ์ผ ์
๋ก๋
public int upload(Files file) throws Exception;
// ํ์ผ ๋ชฉ๋ก - ๋ถ๋ชจ ๊ธฐ์ค
public List<Files> listByParent(Files file) throws Exception;
// ํ์ผ ๋ค์ด๋ก๋
public int download(int no, HttpServletResponse response) throws Exception;
// ํ์ผ ์ญ์ - ๋ถ๋ชจ ๊ธฐ์ค
public int deleteByParent(Files fileInfo) throws Exception;
// ํ์ผ ์ญ์ - noList ๊ธฐ์ค
public int deleteByNoList(List<Integer> noList) throws Exception;
}
Java
๋ณต์ฌ
FileServiceImpl.java
@Override
public int delete(int no) throws Exception {
Files file = fileMapper.select(no);
if( file == null ) return 0;
String filePath = file.getFilePath();
File deleteFile = new File(filePath);
if( !deleteFile.exists() ) return 0;
boolean deleted = deleteFile.delete();
int result = 0;
if( deleted ) {
result = fileMapper.delete(no);
}
return result;
}
Java
๋ณต์ฌ
package com.joeun.server.service;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import com.joeun.server.dto.Files;
import com.joeun.server.mapper.FileMapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Value("${upload.path}") // application.properties ์ ์ค์ ํ ์
๋ก๋ ๊ฒฝ๋ก ์์ฑ๋ช
private String uploadPath; // ์
๋ก๋ ๊ฒฝ๋ก
@Override
public List<Files> list() throws Exception {
List<Files> fileList = fileMapper.list();
return fileList;
}
@Override
public Files select(int no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public int insert(Files file) throws Exception {
int result = fileMapper.insert(file);
return result;
}
@Override
public int update(Files file) throws Exception {
int result = fileMapper.update(file);
return result;
}
@Override
public int delete(int no) throws Exception {
Files file = fileMapper.select(no);
if( file == null ) return 0;
String filePath = file.getFilePath();
File deleteFile = new File(filePath);
if( !deleteFile.exists() ) return 0;
boolean deleted = deleteFile.delete();
int result = 0;
if( deleted ) {
result = fileMapper.delete(no);
}
return result;
}
@Override
public List<Files> listByParent(Files file) throws Exception {
List<Files> fileList = fileMapper.listByParent(file);
return fileList;
}
@Override
public int deleteByParent(Files fileInfo) throws Exception {
int result = 0;
List<Files> fileList = fileMapper.listByParent(fileInfo);
for (Files file : fileList) {
File deleteFile = new File(file.getFilePath());
if( !deleteFile.exists() ) continue;
if( !deleteFile.delete() ) continue;
int deleted = fileMapper.delete(file.getNo());
if( deleted > 0 ) result++;
}
log.info(result + "๊ฐ์ ํ์ผ์ ์ญ์ ํ์์ต๋๋ค.");
return result;
}
@Override
public int download(int fileNo, HttpServletResponse response) throws Exception {
// result
// 0 : ํ์ผ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ ์คํจ
// 1 : ํ์ผ ๋ค์ด๋ก๋ ์ฑ๊ณต
Files file = fileMapper.select(fileNo);
if( file == null ) {
// BAD_REQUEST : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋
// response.setStatus(response.SC_BAD_REQUEST);
return 0;
}
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
String fileName = file.getFileName(); // ํ์ผ ์ด๋ฆ
// ๋ค์ด๋ก๋ ์๋ต์ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-stream
// - Content-Disposition : attachment, filename="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ๋ค์ด๋ก๋
// - ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
// - ํ์ผ ์ถ๋ ฅ
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
// byte[] buffer = new byte[1024]; // 1024bytes = 1KB ๋จ์ ๋ฒํผ
// int data;
// while( (data = fis.read(buffer)) != -1 ) { // 1KB ์ฉ ํ์ผ์
๋ ฅ
// sos.write(buffer, 0, data); // 1KB ์ฉ ํ์ผ์ถ๋ ฅ
// }
fis.close();
sos.close();
return 1;
}
@Override
public int uploadFiles(Files fileInfo, List<MultipartFile> fileList) throws Exception {
int result = 0;
for (MultipartFile file : fileList) {
result += uploadFile( fileInfo, file);
}
log.info(result + "๊ฐ ํ์ผ์ ์
๋ก๋ํ์์ต๋๋ค.");
return result;
}
@Override
public int deleteByNoList(List<Integer> deleteFileNoList) throws Exception {
int result = 0;
if( deleteFileNoList != null && !deleteFileNoList.isEmpty() )
for (Integer deleteFileNo : deleteFileNoList) {
if( deleteFileNo == null ) continue;
fileMapper.delete(deleteFileNo);
log.info(deleteFileNo + "๋ฒ ํ์ผ ์ญ์ ");
result++;
}
return result;
}
@Override
@Transactional
public int upload(Files file) throws Exception {
int result = uploadFile(file, file.getFile());
if( result > 0 )
result = fileMapper.maxPk();
return result;
}
public int uploadFile(Files fileInfo, MultipartFile file) throws Exception {
int result = 0;
if( file.isEmpty() ) return result;
// ํ์ผ ์ ๋ณด : ์๋ณธํ์ผ๋ช
, ํ์ผ ์ฉ๋, ํ์ผ ๋ฐ์ดํฐ
String originName = file.getOriginalFilename();
long fileSize = file.getSize();
byte[] fileData = file.getBytes();
// ์
๋ก๋ ๊ฒฝ๋ก
// ํ์ผ๋ช
์ค๋ณต ๋ฐฉ์ง ๋ฐฉ๋ฒ(์ ์ฑ
)
// - ๋ ์ง_ํ์ผ๋ช
.ํ์ฅ์
// - UID_ํ์ผ๋ช
.ํ์ฅ์
// UID_๊ฐ์์ง.png
String fileName = UUID.randomUUID().toString() + "_" + originName;
// c:/upload/UID_๊ฐ์์ง.png
String filePath = uploadPath + "/" + fileName;
// - ์๋ฒ ์ธก, ํ์ผ ์์คํ
์ ํ์ผ ๋ณต์ฌ
File uploadFile = new File(uploadPath, fileName);
FileCopyUtils.copy(fileData, uploadFile); // ํ์ผ ์
๋ก๋
// - DB ์ ํ์ผ ์ ๋ณด ๋ฑ๋ก
Files uploadedFile = new Files();
uploadedFile.setParentTable(fileInfo.getParentTable());
uploadedFile.setParentNo(fileInfo.getParentNo());
uploadedFile.setFileName(fileName);
uploadedFile.setFilePath(filePath);
uploadedFile.setOriginName(originName);
uploadedFile.setFileSize(fileSize);
uploadedFile.setFileCode(0);
result = fileMapper.insert(uploadedFile);
return result;
}
}
Java
๋ณต์ฌ
FileController.java
package com.joeun.server.controller;
import java.io.File;
import java.io.FileInputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 com.joeun.server.dto.Files;
import com.joeun.server.service.FileService;
import com.joeun.server.utils.MediaUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("/file")
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private ResourceLoader resourceLoader;
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{no}")
public void fileDownload(@PathVariable("no") int no
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.select(no);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
/**
* ์ด๋ฏธ์ง ์ธ๋ค์ผ
* @param no
* @param response
* @throws Exception
*/
@GetMapping("/img/{no}")
public void showImg(@PathVariable Integer no, HttpServletResponse response) throws Exception {
Files file = fileService.select(no);
String filePath = (file != null) ? file.getFilePath() : null;
Resource resource = resourceLoader.getResource("classpath:static/img/no-image.png");
File imgFile;
if (filePath == null || !(imgFile = new File(filePath)).exists()) {
// ํ์ผ์ด ์กด์ฌํ์ง ์๊ฑฐ๋ ํ์ผ ๊ฒฝ๋ก๊ฐ null์ธ ๊ฒฝ์ฐ
imgFile = resource.getFile();
}
String ext = filePath.substring(filePath.lastIndexOf(".") + 1);
MediaType mType = MediaUtil.getMediaType(ext);
if (mType == null) {
// ์ด๋ฏธ์ง ํ์
์ด ์๋ ๊ฒฝ์ฐ
response.setContentType(MediaType.IMAGE_PNG_VALUE); // ๊ธฐ๋ณธ์ ์ผ๋ก PNG๋ก ์ค์
imgFile = resource.getFile();
} else {
// ์ด๋ฏธ์ง ํ์
์ผ ๊ฒฝ์ฐ
response.setContentType(mType.toString());
}
FileInputStream fis = new FileInputStream(imgFile);
ServletOutputStream sos = response.getOutputStream();
FileCopyUtils.copy(fis, sos);
}
/**
* ํ์ผ ์ญ์
* @param file
* @return
* @throws Exception
*/
@DeleteMapping("/{no}")
public ResponseEntity<String> deleteFile(@PathVariable Integer no) throws Exception {
log.info("[DELETE] - /file");
int fileNo = no;
log.info("fileNo : " + fileNo);
if( fileNo == 0 )
return new ResponseEntity<String>("FAIL", HttpStatus.BAD_REQUEST);
int result = fileService.delete(fileNo);
if( result == 0 )
return new ResponseEntity<String>("FAIL", HttpStatus.OK);
return new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
}
}
Java
๋ณต์ฌ
React (Front-End)
React ๋ก ํ์ผ ์
๋ก๋, ์กฐํ, ์ญ์ UI ๋ฐ API ๋ฅผ ๊ตฌํํฉ๋๋ค.
ํ์ผ ์
๋ก๋
ํ์ผ ๋ฑ๋ก UI ์ถ๊ฐ
BoardInsertForm.jsx
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import './BoardInsertForm.css'
const BoardInsertForm = ({ onInsert }) => {
// state ์ค์
const [title, setTitle] = useState('');
const [writer, setWriter] = useState('');
const [content, setContent] = useState('');
const [files, setFiles] = useState(null); // โ
files state ์ถ๊ฐ
const handleChangeTitle = (e) => {
setTitle(e.target.value)
}
const handleChangeWriter = (e) => {
setWriter(e.target.value)
}
const handleChangeContent = (e) => {
setContent(e.target.value)
}
// โ
ํ์ผ ํธ๋ค๋ฌ ์ถ๊ฐ
const handleFileChange = (e) => {
setFiles(e.target.files);
};
const onSubmit = () => {
const formData = new FormData();
formData.append('title', title);
formData.append('writer', writer);
formData.append('content', content);
const headers = {
headers: {
'Content-Type' : 'multipart/form-data',
},
};
if (files) {
for (let i = 0; i < files.length; i++) {
formData.append(`files[${i}]`, files[i]);
}
}
// onInsert(title, writer, content)
// onInsert({title,writer,content,files}, headers) // formData ์ฌ์ฉ โ
onInsert(formData, headers) // formData ์ฌ์ฉ โญ
}
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ๋ฑ๋ก</h1>
<table className='table'>
<tbody>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text"
className='form-input'
value={title}
onChange={handleChangeTitle} />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text"
className='form-input'
value={writer}
onChange={handleChangeWriter} />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={content}
onChange={handleChangeContent}
></textarea>
</td>
</tr>
<tr>
<td>ํ์ผ</td>
<td>
<input type='file' onChange={handleFileChange} multiple />
</td>
</tr>
</tbody>
</table>
<div className='btn-box'>
<Link to="/boards" className='btn'>๋ชฉ๋ก</Link>
<button onClick={ onSubmit } className='btn'>๋ฑ๋ก</button>
</div>
</div>
)
}
export default BoardInsertForm
JavaScript
๋ณต์ฌ
ํ์ผ ์ ๋ก๋ ์์ฒญ API
files.js
import axios from 'axios';
// ์
๋ก๋
export const upload = (formData, headers) => axios.post(`/file/upload`, formData, headers)
JavaScript
๋ณต์ฌ
๏ธ ํ์ผ ์กฐํ
ํ์ผ ๋ชฉ๋ก ์กฐํ UI ๋ฐ API ์ถ๊ฐ
BoardReadContainer.jsx
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import * as boards from '../apis/boards';
import BoardRead from '../components/BoardRead/BoardRead';
// ๐ฉโ๐ป ๊ฒ์๊ธ ์กฐํ
const BoardReadContainer = () => {
const { no } = useParams()
const [board, setBoard] = useState({});
const [fileList, setFileList] = useState([]);
const [isLoading, setLoading] = useState(false);
const getBoard = async () => {
setLoading(true)
try {
const response = await boards.select(no);
const data = response.data;
console.log(data);
const board = data.board;
const fileList = data.fileList;
setBoard(board);
setFileList(fileList);
}
catch(e) {
console.log(e);
}
setLoading(false)
}
useEffect( () => {
getBoard()
},[])
return (<BoardRead no={no}
board={board}
fileList={fileList}
isLoading={isLoading}
/>)
}
export default BoardReadContainer
JavaScript
๋ณต์ฌ
BoardRead.jsx
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import * as format from '../../apis/format';
import './BoardRead.css';
const BoardRead = ({ no, board, fileList, isLoading }) => {
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์กฐํ</h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={format.formatDate( board.regDate )} readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={board.title} readOnly />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={board.writer} readOnly />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={board.content}
readOnly></textarea>
</td>
</tr>
<tr>
<td colSpan={2}>ํ์ผ</td>
</tr>
<tr>
<td colSpan={2}>
{ fileList.map( (file) => (
<div className='file-box' key={file.no}>
<div className="item">
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
</div>
</div>
))}
</td>
</tr>
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<Link className='btn' to="/boards">๋ชฉ๋ก</Link>
<Link className='btn' to={`/boards/update/${no}`}>์์ </Link>
</div>
</div>
)
}
export default BoardRead
JavaScript
๋ณต์ฌ
๋ค์ด๋ก๋ UI ๋ฐ API ์ถ๊ฐ
BoardRead.jsx
<button className="btn" onClick={() => handleDownload(file.no, file.originName)}>๋ค์ด๋ก๋</button>
JavaScript
๋ณต์ฌ
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import * as format from '../../apis/format';
import './BoardRead.css';
const BoardRead = ({ no, board, fileList, isLoading }) => {
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์กฐํ</h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={format.formatDate( board.regDate )} readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={board.title} readOnly />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={board.writer} readOnly />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={board.content}
readOnly></textarea>
</td>
</tr>
<tr>
<td colSpan={2}>ํ์ผ</td>
</tr>
<tr>
<td colSpan={2}>
{ fileList.map( (file) => (
<div className='file-box' key={file.no}>
<div className="item">
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
<button className="btn" onClick={() => handleDownload(file.no, file.originName)}>๋ค์ด๋ก๋</button>
</div>
</div>
))}
</td>
</tr>
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<Link className='btn' to="/boards">๋ชฉ๋ก</Link>
<Link className='btn' to={`/boards/update/${no}`}>์์ </Link>
</div>
</div>
)
}
export default BoardRead
JavaScript
๋ณต์ฌ
files.js
import axios from 'axios';
// ์
๋ก๋
export const upload = (formData, headers) => axios.post(`/file/upload`, formData, headers)
// ๋ค์ด๋ก๋
export const download = (fileNo) => axios.get(`/file/${fileNo}`, {responseType: 'blob',} )
JavaScript
๋ณต์ฌ
์ธ๋ค์ผ ์ด๋ฏธ์ง UI ์ถ๊ฐ
BoardRead.jsx
<img src={`/file/img/${file.no}`} alt={file.fileName} />
JavaScript
๋ณต์ฌ
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import * as format from '../../apis/format';
import './BoardRead.css';
const BoardRead = ({ no, board, fileList, isLoading }) => {
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์กฐํ</h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={format.formatDate( board.regDate )} readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={board.title} readOnly />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={board.writer} readOnly />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={board.content}
readOnly></textarea>
</td>
</tr>
<tr>
<td colSpan={2}>ํ์ผ</td>
</tr>
<tr>
<td colSpan={2}>
{ fileList.map( (file) => (
<div className='file-box' key={file.no}>
<div className="item">
<img src={`/file/img/${file.no}`} alt={file.fileName} />
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
<button className="btn" onClick={() => handleDownload(file.no, file.originName)}>๋ค์ด๋ก๋</button>
</div>
</div>
))}
</td>
</tr>
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<Link className='btn' to="/boards">๋ชฉ๋ก</Link>
<Link className='btn' to={`/boards/update/${no}`}>์์ </Link>
</div>
</div>
)
}
export default BoardRead
JavaScript
๋ณต์ฌ
ํ์ผ ์ญ์
์ญ์ ํ ํ์ผ ์ฒดํฌ๋ฐ์ค UI ์ถ๊ฐ, ํ์ผ ์ญ์ ๋ฒํผ UI ๋ฐ API ์ถ๊ฐ
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import * as format from '../../apis/format'
const BoardUpdateForm = ({ no, board, fileList, onUpdate, onDelete, isLoading, onDownload, onDeleteFile }) => {
// state ์ค์
const [title, setTitle] = useState('')
const [writer, setWriter] = useState('')
const [content, setContent] = useState('')
const [files, setFiles] = useState(null); // โ
files state ์ถ๊ฐ
const [fileNoList, setFileList] = useState([]) // โ
ํ์ผ ์ ํ ์ญ์ - deleteFileNoList
const handleChangeTitle = (e) => {
setTitle(e.target.value)
}
const handleChangeWriter = (e) => {
setWriter(e.target.value)
}
const handleChangeContent = (e) => {
setContent(e.target.value)
}
const onSubmit = () => {
const formData = new FormData();
formData.append('no', no);
formData.append('title', title);
formData.append('writer', writer);
formData.append('content', content);
console.log(`fileNoList --------------------------------------`);
console.log(fileNoList);
formData.append('deleteFileNoList', fileNoList);
const headers = {
headers: {
'Content-Type' : 'multipart/form-data',
},
};
if (files) {
for (let i = 0; i < files.length; i++) {
formData.append(`files[${i}]`, files[i]);
}
}
// onUpdate(no, title, writer, content);
// onUpdate({no, title, writer, content}, headers);
onUpdate(formData, headers);
}
const handleDelete = () => {
const check = window.confirm('์ ๋ง๋ก ์ญ์ ํ์๊ฒ ์ต๋๊น?')
if( check )
onDelete(no)
}
const handleDownload = (fileNo, fileName) => {
onDownload(fileNo, fileName)
}
const handleDeleteFile =(fileNo) => {
const check = window.confirm('์ ๋ง๋ก ์ญ์ ํ์๊ฒ ์ต๋๊น?')
if( check )
onDeleteFile(fileNo)
}
// โ
ํ์ผ ํธ๋ค๋ฌ ์ถ๊ฐ
const handleFileChange = (e) => {
setFiles(e.target.files);
};
// ํ์ผ ๋ฒํธ ์ฒดํฌ
const checkFileNo = (no) => {
setFileList( [...fileNoList, no] )
}
useEffect( () => {
if( board ) {
setTitle(board.title);
setWriter(board.writer)
setContent(board.content)
}
}, [board])
return (
<div className='container'>
<h1 className='title'>๊ฒ์๊ธ ์์ </h1>
<h3>๋ฒํธ : {no}</h3>
<hr/>
{ isLoading &&
<div>
<img src="/img/loading.webp" alt="loading" />
</div>
}
{ !isLoading && board && (
<table border={1} className='table'>
<tbody>
<tr>
<td>๋ฒํธ</td>
<td>
<input type="text" className='form-input' value={board.no} readOnly />
</td>
</tr>
<tr>
<td>๋ฑ๋ก์ผ์</td>
<td>
<input type="text" className='form-input' value={ format.formatDate(board.regDate) } readOnly />
</td>
</tr>
<tr>
<td>์ ๋ชฉ</td>
<td>
<input type="text" className='form-input' value={title} onChange={handleChangeTitle} />
</td>
</tr>
<tr>
<td>์์ฑ์</td>
<td>
<input type="text" className='form-input' value={writer} onChange={handleChangeWriter} />
</td>
</tr>
<tr>
<td colSpan={2}>๋ด์ฉ</td>
</tr>
<tr>
<td colSpan={2}>
<textarea cols="40" rows="10"
className='form-input'
value={content}
onChange={handleChangeContent}></textarea>
</td>
</tr>
<tr>
<td>ํ์ผ ์
๋ก๋</td>
<td>
<input type='file' onChange={handleFileChange} multiple />
</td>
</tr>
{ fileList && fileList.length > 0 &&
<tr>
<td>์ญ์ </td>
<td>ํ์ผ</td>
</tr>
}
{ fileList.length == 0 &&
<tr>
<td colSpan={2} align='center'>
์
๋ก๋๋ ํ์ผ์ด ์์ต๋๋ค.
</td>
</tr>
}
{ fileList.map( (file) => (
<tr>
<td>
<input type="checkbox" onChange={ () => checkFileNo(file.no) } />
</td>
<td>
<div className='file-box' key={file.no}>
<div className="item">
<img src={`/file/img/${file.no}`} alt={file.fileName} />
<span>{file.originName}({ format.byteToUnit(file.fileSize) })</span>
</div>
<div className="item">
<button className="btn" onClick={() => handleDownload(file.no, file.originName)}>๋ค์ด๋ก๋</button>
<button className="btn" onClick={() => handleDeleteFile(file.no)}>์ญ์ </button>
</div>
</div>
</td>
</tr>
))}
</tbody>
</table>
)}
<hr />
<div className="btn-box">
<div className="item">
<Link to="/boards" className='btn'>๋ชฉ๋ก</Link>
</div>
<div className="item">
<button className='btn' onClick={ handleDelete }>์ญ์ </button>
<button className='btn' tton onClick={ onSubmit }>์์ </button>
</div>
</div>
</div>
)
}
export default BoardUpdateForm
JavaScript
๋ณต์ฌ