Spring Boot 사진 파일 저장, 출력

장준휴·2024년 1월 12일
1

Spring Boot

목록 보기
3/4

페이지를 만들때 대부분 사진 파일 저장, 혹은 출력 기능을 만들어야한다.

이번에 설명할 것은 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를 살펴보자


write mapping

	@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";
		

		
	}

부분코드 1

가장 먼저 눈에 띄는 코드는

String uuid = UUID.randomUUID().toString();

이 코드일 것이다.

카카오톡에서 사진을 받아 저장할때 사진 이름 앞에 이상한 문자가 함께 적혀 저장된 것을 한번쯤을 봤을 것이다.

그 기능은 사용자가 서버에 파일을 업로드 할때 이름이 중복되면 파일이 덮어씌워져버리니까, 그 것을 해결하기위해 파일 이름 앞에 랜덤하게 값을 붙히는 것이다.

이 역할을 하는 코드가 위에서 보여주는 코드이다.


부분코드 2

그 다음으로 사용자가 서버에 파일을 업로드 하면 서버에서 해당 파일을 저장할때 경로를 잘 지정해야한다.

일반적으로 경로로는 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 페이지 요청을한다.




저장된 이미지 출력하기


사용자가 게시글을 클릭하면 해당 게시글에 저장된 내용을 출력 해야한다.

게시글 DTO 코드

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
작성자
내용
이미지
조회수

이렇게 있다.

여기에 사용된 어노테이션을 살펴보겠다.

  1. idx
    @Id // 해당 칼럼이 Primary key 라고 지정해준다.
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 행이 생성될때 자동으로 increment 가 되도록 해준다.

  2. writer
    @ManyToOne // Forign 키를 설정한다. 작성자 한명이 여러 게시글을 작성할 수 있기 때문에 ManyToOne 이다.
    @ JoinColummn(referencedColumnName = "email") // Member 테이블에 email을 참조한다는 뜻이다.

  3. @Column(columnDefinition = "datetime default now()", insertable = false, updatable = false) // 현재 시간을 저장해주는 칼럼이며 자료형부터 새로 작성해줘야한다. 그리고 입력 가능여부와 업데이트 가능 여부를 false로 설정하여 막아둔다.

BoardController 코드

	@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를 받아줘야한다.

profile
나는야 토마토

0개의 댓글