β’
λ°μ΄ν°λ² μ΄μ€
β¦
β’
μμ€μ½λ
β¦
λ‘μ§
βͺ
βͺ
βͺ
βͺ
βͺ
βͺ
βͺ
β¦
νλ©΄
βͺ
βͺ
board
β’
β’
β’
β’
λ°μ΄ν°λ² μ΄μ€
file.sql
-- νμΌ ν
μ΄λΈ
CREATE TABLE `file` (
`no` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`id` varchar(64) DEFAULT NULL UNIQUE,
`parent_table` varchar(100) NOT NULL,
`parent_no` int NOT NULL,
`name` text NOT NULL,
`path` text NOT NULL,
`size` bigint default NULL,
`content_type` varchar(100) default 'application/octet-stream', -- image/png, application/pdf ...
`sort_order` int default 0,
`is_main` tinyint(1) default false,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
SQL
볡μ¬
μμ€μ½λ
λ‘μ§
β’
β’
β’
β’
β’
β’
β’
Files.java
@Data
public class Files {
private Integer no;
private String id;
private String parentTable; // λΆλͺ¨ ν
μ΄λΈ
private Integer parentNo; // λΆλͺ¨ PK
private String name; // νμΌλͺ
private String path; // νμΌκ²½λ‘
private Long size; // μ©λ
private String contentType; // 컨ν
μΈ νμ
private Integer sortOrder; // μμ : 0~
private Boolean isMain; // λν μ¬λΆ (μΈλ€μΌ)
private Date createdAt;
private Date updatedAt;
public Files() {
this.id = UUID.randomUUID().toString();
}
}
Java
볡μ¬
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.aloha.board.mapper.FileMapper">
<select id="list" resultType="Files">
SELECT *
FROM file
ORDER BY created_at DESC
</select>
<!-- νμΌ μ‘°ν -->
<select id="select" resultType="Files">
SELECT *
FROM file
WHERE no = #{no}
</select>
<select id="selectById" resultType="Files">
SELECT *
FROM file
WHERE id = #{id}
</select>
<!-- νμΌ λ±λ‘ -->
<insert id="insert">
INSERT INTO file (
id, parent_table, parent_no, name, path, size, sort_order, is_main
)
VALUES (
#{id}, #{parentTable}, #{parentNo}, #{name}, #{path}, #{size}, #{sortOrder}, #{isMain}
)
</insert>
<!-- νμΌ μμ -->
<update id="update">
UPDATE file
<set>
<if test="parentTable != null">parent_table = #{parentTable},</if>
<if test="parentNo != null">parent_no = #{parentNo},</if>
<if test="name != null">name = #{name},</if>
<if test="path != null">path = #{path},</if>
<if test="size != null">size = #{size},</if>
<if test="contentType != null">content_type = #{contentType},</if>
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
<if test="isMain != null">is_main = #{isMain},</if>
</set>
WHERE no = #{no}
</update>
<update id="updateById">
UPDATE file
<set>
<if test="parentTable != null">parent_table = #{parentTable},</if>
<if test="parentNo != null">parent_no = #{parentNo},</if>
<if test="name != null">name = #{name},</if>
<if test="path != null">path = #{path},</if>
<if test="size != null">size = #{size},</if>
<if test="contentType != null">content_type = #{contentType},</if>
<if test="sortOrder != null">sort_order = #{sortOrder},</if>
<if test="isMain != null">is_main = #{isMain},</if>
</set>
WHERE id = #{id}
</update>
<!-- νμΌ μμ -->
<delete id="delete">
DELETE FROM file
WHERE no = #{no}
</delete>
<delete id="deleteById">
DELETE FROM file
WHERE id = #{id}
</delete>
</mapper>
XML
볡μ¬
FileMapper.java
@Mapper
public interface FileMapper {
// νμΌ λͺ©λ‘
List<Files> list() throws Exception;
// νμΌ μ‘°ν
Files select(Integer no) throws Exception;
Files selectById(String id) throws Exception;
// νμΌ λ±λ‘
int insert(Files board) throws Exception;
// νμΌ μμ
int update(Files board) throws Exception;
int updateById(Files board) throws Exception;
// νμΌ μμ
int delete(Integer no) throws Exception;
int deleteById(String id) throws Exception;
}
Java
볡μ¬
FileService.java
public interface FileService {
// νμΌ λͺ©λ‘
List<Files> list() throws Exception;
// νμΌ μ‘°ν
Files select(Integer no) throws Exception;
Files selectById(String id) throws Exception;
// νμΌ λ±λ‘
boolean insert(Files board) throws Exception;
// νμΌ μμ
boolean update(Files board) throws Exception;
boolean updateById(Files board) throws Exception;
// νμΌ μμ
boolean delete(Integer no) throws Exception;
boolean deleteById(String id) throws Exception;
// β νμΌ μ
λ‘λ
int upload(List<MultipartFile> files, ParentTable parentTable, Integer parentNo) throws Exception;
}
Java
볡μ¬
FileServiceImpl.java
@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {
private final FileMapper fileMapper;
@Value("${spring.servlet.multipart.location}")
private String uploadPath;
@Override
public List<Files> list() throws Exception {
List<Files> files = fileMapper.list();
return files;
}
@Override
public Files select(Integer no) throws Exception {
Files file = fileMapper.select(no);
return file;
}
@Override
public Files selectById(String id) throws Exception {
Files file = fileMapper.selectById(id);
return file;
}
@Override
public boolean insert(Files board) throws Exception {
int result = fileMapper.insert(board);
return result > 0;
}
@Override
public boolean update(Files board) throws Exception {
int result = fileMapper.update(board);
return result > 0;
}
@Override
public boolean updateById(Files board) throws Exception {
int result = fileMapper.updateById(board);
return result > 0;
}
@Override
public boolean delete(Integer no) throws Exception {
int result = fileMapper.delete(no);
return result > 0;
}
@Override
public boolean deleteById(String id) throws Exception {
int result = fileMapper.deleteById(id);
return result > 0;
}
@Override
public int upload(List<MultipartFile> files, ParentTable parentTable, Integer parentNo) throws Exception {
int sortOrder = 0;
if( files != null ) {
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename(); // μλ³ΈνμΌλͺ
String path = uploadPath + UUID.randomUUID().toString() + "_" + fileName;
// νμΌ μ μ₯
File realFile = new File(path);
byte[] fileData = file.getBytes();
FileCopyUtils.copy(fileData, realFile);
// DB μ μ₯
Files newFile = new Files();
newFile.setParentNo(parentNo);
newFile.setParentTable(parentTable.value());
newFile.setName(fileName);
newFile.setPath(path);
newFile.setContentType(file.getContentType());
newFile.setSortOrder(sortOrder++);
if( sortOrder == 1 )
newFile.setIsMain(true);
fileMapper.insert(newFile);
}
}
return sortOrder;
}
}
Java
볡μ¬
FileController.java
Java
볡μ¬
Board.java
@Data
public class Board {
private Integer no;
private String id;
private String title;
private String writer;
private String content;
private Date createdAt;
private Date updatedAt;
// μ
λ‘λ νμΌ λͺ©λ‘ β‘
private List<MultipartFile> files;
public Board() {
this.id = UUID.randomUUID().toString();
}
}
Java
볡μ¬
νλ©΄
β’
board
β¦
β¦
β¦
β¦
board
create.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>κ²μν νλ‘μ νΈ</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<main>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-6">
<h1 class="text-center">κ²μκΈ λ±λ‘</h1>
<form action="/board/create" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label for="" class="form-label">μ λͺ©</label>
<input type="text" class="form-control" name="title" id="title"
aria-describedby="helpTitle" placeholder="μ λͺ©μ μ
λ ₯ν΄μ£ΌμΈμ" required />
<small id="helpTitle" class="form-text text-muted">μ λͺ©μ μ
λ ₯ν΄μ£ΌμΈμ</small>
</div>
<div class="mb-3">
<label for="" class="form-label">μμ±μ</label>
<input type="text" class="form-control" name="writer" id="writer"
aria-describedby="helpWriter" placeholder="μμ±μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ" required />
<small id="helpWriter" class="form-text text-muted">μμ±μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ</small>
</div>
<div class="mb-3">
<label for="" class="form-label">λ΄μ©</label>
<textarea class="form-control" name="content" id="content" rows="5"></textarea>
</div>
<div class="mb-3">
<label for="" class="form-label">첨λΆνμΌ</label>
<input type="file" class="form-control" name="files" id="file" multiple />
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">λ±λ‘</button>
</div>
</form>
</div>
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
HTML
볡μ¬
bootstrap file input λΌμ΄λΈλ¬λ¦¬
β’
μ€μΉ
β’
λ°λͺ¨
νμν CDN
β’
CSS
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.min.css" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-fileinput@5.5.3/css/fileinput.min.css" rel="stylesheet">
HTML
볡μ¬
β’
JS
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-fileinput@5.5.3/js/fileinput.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-fileinput@5.5.3/themes/fas/theme.min.js"></script>
<script src="/js/locales/kr.js"></script>
HTML
볡μ¬
β’
λ€κ΅μ΄ νμΌ (νκ΅μ΄)
β’
μμ μ½λ
<script>
$("#file").fileinput({
theme: "fas",
language: "kr", // μΈμ΄ μ½λλ‘ μ€μ
showUpload: false, // AJAX μ
λ‘λ λ²νΌ μ¨κΉ (μ€μ)
showRemove: true,
browseLabel: "νμΌ μ ν",
allowedFileExtensions: ["jpg", "png", "pdf"],
maxFileSize: 10240, // 10MB (KB λ¨μ)
maxFileCount: 10
});
</script>
HTML
볡μ¬
create.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>κ²μν νλ‘μ νΈ</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<main>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-6">
<h1 class="text-center">κ²μκΈ λ±λ‘</h1>
<form action="/board/create" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label for="" class="form-label">μ λͺ©</label>
<input type="text" class="form-control" name="title" id="title"
aria-describedby="helpTitle" placeholder="μ λͺ©μ μ
λ ₯ν΄μ£ΌμΈμ" required />
<small id="helpTitle" class="form-text text-muted">μ λͺ©μ μ
λ ₯ν΄μ£ΌμΈμ</small>
</div>
<div class="mb-3">
<label for="" class="form-label">μμ±μ</label>
<input type="text" class="form-control" name="writer" id="writer"
aria-describedby="helpWriter" placeholder="μμ±μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ" required />
<small id="helpWriter" class="form-text text-muted">μμ±μλ₯Ό μ
λ ₯ν΄μ£ΌμΈμ</small>
</div>
<div class="mb-3">
<label for="" class="form-label">λ΄μ©</label>
<textarea class="form-control" name="content" id="content" rows="5"></textarea>
</div>
<div class="mb-3">
<label for="" class="form-label">첨λΆνμΌ</label>
<input type="file" class="form-control" name="files" id="file" multiple />
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">λ±λ‘</button>
</div>
</form>
</div>
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
HTML
볡μ¬





