페이지를 만들때 대부분 사진 파일 저장, 혹은 출력 기능을 만들어야한다.
이번에 설명할 것은 Spring Boot 에서 사진 파일을 저장, 출력하는 기능을 설명할것이다.
그다지 어렵지 않으니 잘 따라 오도록!
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- context path를 "cpath"라는 이름으로 저장해두기 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<% pageContext.setAttribute("cpath", request.getContextPath()); %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Forty by HTML5 UP</title>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--[if lte IE 8]><script src="${cpath}/assets/js/ie/html5shiv.js"></script><![endif]-->
<link rel="stylesheet" href="${cpath}/assets/css/main.css" />
<link rel="stylesheet" href="${cpath}/assets/css/board.css" />
<!--[if lte IE 9]><link rel="stylesheet" href="${cpath}/assets/css/ie9.css" /><![endif]-->
<!--[if lte IE 8]><link rel="stylesheet" href="${cpath}/assets/css/ie8.css" /><![endif]-->
</head>
<body>
<div id="board">
<h1>게시글 작성페이지</h1>
<%--게시글 작성 form태그 --%>
<%--데이터 전송에 필요한 form태그 3요소!! --%>
<form action="${cpath}/member/write" method="post" enctype="multipart/form-data">
<table id="list">
<tr>
<td>제목</td>
<td><input name="title" type="text"></td>
</tr>
<tr>
<td>작성자</td>
<td><input value="${user.email}" name="writer" type="text"></td>
</tr>
<tr>
<td>이미지</td>
<td><input name="file" type="file"></td>
</tr>
<tr>
<td colspan="2">내용</td>
</tr>
<tr>
<td colspan="2"><textarea name="content" rows="10" style="resize: none;"></textarea>
</td>
</tr>
<tr>
<td colspan="2"><input type="reset" value="초기화"> <input
type="submit" value="작성하기"></td>
</tr>
</table>
</form>
</div>
<!-- Scripts -->
<script src="${cpath}/assets/js/jquery.min.js"></script>
<script src="${cpath}/assets/js/jquery.scrolly.min.js"></script>
<script src="${cpath}/assets/js/jquery.scrollex.min.js"></script>
<script src="${cpath}/assets/js/skel.min.js"></script>
<script src="${cpath}/assets/js/util.js"></script>
<!--[if lte IE 8]><script src="${cpath}/assets/js/ie/respond.min.js"></script><![endif]-->
<script src="${cpath}/assets/js/main.js"></script>
</body>
</html>
이 jsp 파일에서는 form 태그가 가장 중요하다.
<form action="${cpath}/member/write" method="post" enctype="multipart/form-data">
사진 파일은 그냥 저장되는 것이 아니라 String 형식으로 incoding을 진행한 뒤 파일이 전달된다.
그렇다면 jsp 파일에서 값을 전달받은 controller를 살펴보자
@PostMapping("/write")
public String write(MultipartFile file,Tbl_board board) {
// 1. 데이터 수집
// 파일 저장하기
// 랜덤한 문자열을 생성해서 파일 이름앞에 붙이기(uid)
String uuid = UUID.randomUUID().toString();
String filename = uuid +"_"+ file.getOriginalFilename();
//파일을 저장하기 위한 경로 객체 만들기
//Path : 경로 객체
//Paths : 경로객체2
Path path = Paths.get(savePath+filename);
//해당 경로에 파일 저장
try {
file.transferTo(path);
board.setImg(filename);
}catch (Exception e){
e.printStackTrace();
}
// 2. 로직 실행
repo.save(board);
// 3. view 실행
return "redirect:/member/list";
}
가장 먼저 눈에 띄는 코드는
String uuid = UUID.randomUUID().toString();
이 코드일 것이다.
카카오톡에서 사진을 받아 저장할때 사진 이름 앞에 이상한 문자가 함께 적혀 저장된 것을 한번쯤을 봤을 것이다.
그 기능은 사용자가 서버에 파일을 업로드 할때 이름이 중복되면 파일이 덮어씌워져버리니까, 그 것을 해결하기위해 파일 이름 앞에 랜덤하게 값을 붙히는 것이다.
이 역할을 하는 코드가 위에서 보여주는 코드이다.
그 다음으로 사용자가 서버에 파일을 업로드 하면 서버에서 해당 파일을 저장할때 경로를 잘 지정해야한다.
일반적으로 경로로는 application.properties에 정의해놓은 데이터를 가져올 수 있다.
@Value("${save.path}")
private String savePath;
이 코드는 savePath 변수에 이미 정의해놓은 경로가 들어간다.
Path path = Paths.get(savePath+filename);
//해당 경로에 파일 저장
try {
file.transferTo(path);
board.setImg(filename);
}catch (Exception e){
e.printStackTrace();
}
이 코드가 지정된 경로에 파일 이름으로 저장한 것이고, 또 board객체에 파일 이름을 set 하여 DB에 저장한 코드이다.
마지막으로 redirect방식으로 전달하여 다시 list 페이지 요청을한다.
사용자가 게시글을 클릭하면 해당 게시글에 저장된 내용을 출력 해야한다.
package com.smhrd.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.springframework.data.annotation.Persistent;
import lombok.Data;
@Entity
@Data
@Persistent
public class Tbl_board {
//글번호
//JPA 쓸 때, 참조 자료형으로 선언하는 것이 좋다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //outo_increment
private Long idx;
//제목
@Column(length=100, nullable = false)
private String title;
//작성자(FK)
//실제 컬럼이름은 "컬럼명_참조받은컬럼명" 지정됨
@ManyToOne
@JoinColumn(referencedColumnName = "email")
private Tbl_Member writer;
//내용
@Column(length = 1000, nullable = false)
private String content;
//이미지
private String img;
//작성일
//default를 지정하는 법
@Column(columnDefinition = "datetime default now()", insertable = false, updatable = false)
private Date indate;
//조회수
@Column(columnDefinition = "int default 0", insertable=false)
private Long count;
//** 중요! 버그방지를 위해 이거 해야함 **
//FK 를 사용하는 경우 toString 메소드를 직접 Override 할것
@Override
public String toString() {
return "Tbl_Board_toString_method";
}
}
위 파일은 lombok 을 사용하고있다.
필드 내용으로는
게시글 idx
작성자
내용
이미지
조회수
이렇게 있다.
여기에 사용된 어노테이션을 살펴보겠다.
idx
@Id // 해당 칼럼이 Primary key 라고 지정해준다.
@GeneratedValue(strategy = GenerationType.IDENTITY) // 행이 생성될때 자동으로 increment 가 되도록 해준다.
writer
@ManyToOne // Forign 키를 설정한다. 작성자 한명이 여러 게시글을 작성할 수 있기 때문에 ManyToOne 이다.
@ JoinColummn(referencedColumnName = "email") // Member 테이블에 email을 참조한다는 뜻이다.
@Column(columnDefinition = "datetime default now()", insertable = false, updatable = false) // 현재 시간을 저장해주는 칼럼이며 자료형부터 새로 작성해줘야한다. 그리고 입력 가능여부와 업데이트 가능 여부를 false로 설정하여 막아둔다.
@RequestMapping("/view")
public String view(Long idx, Model model) {
// 1. 데이터 수집
// 2. 로직 실행
//Optional<>값을 리턴하기 때문에 뒤에 .get()을 해줘야함
Tbl_board board = repo.findById(idx).get();
// 3. view 선택
model.addAttribute("board",board);
return "member/viewBoard";
}
repo.findByID() 이 코드는 Optional<> 이라는 스프링만의 자료형으로 감싸서 리턴하기 때문에 .get() 메소드를 사용하여 DTO를 받아줘야한다.