Search

파일 μ—…λ‘œλ“œ

β€’
λ°μ΄ν„°λ² μ΄μŠ€
β—¦
file.sql
β€’
μ†ŒμŠ€μ½”λ“œ
β—¦
둜직
β–ͺ
Board.java
β–ͺ
Files.java
β–ͺ
FileMapper.xml
β–ͺ
FileMapper.java
β–ͺ
FileService.java
β–ͺ
FileServiceImpl.java
β–ͺ
FileController.java
β—¦
ν™”λ©΄
β–ͺ
index.html
β–ͺ
board
β€’
list.html
β€’
create.html
β€’
detail.html
β€’
update.html

λ°μ΄ν„°λ² μ΄μŠ€

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
β€’
FileMapper.xml
β€’
FileMapper.java
β€’
FileService.java
β€’
FileServiceImpl.java
β€’
FileController.java
β€’
Board.java

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
β—¦
list.html
β—¦
create.html
β—¦
detail.html
β—¦
update.html

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
볡사
β€’
λ‹€κ΅­μ–΄ 파일 (ν•œκ΅­μ–΄)
kr.js
locales
β€’
μ‹œμž‘ μ½”λ“œ
<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
볡사