열심히 끝까지

[코딩 과제] - 9/27 강사님 문제 - 사진 업로드 + 미리보기(추가사항) 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(과제)

[코딩 과제] - 9/27 강사님 문제 - 사진 업로드 + 미리보기(추가사항)

노유림 2022. 9. 28. 09:53

>> 사진 업로드 및 미리보기가 가능하도록 만드시오

[디바이스 융합 자바(Java) day74] 에도 올려 놓음

하지만 거기에 추가사항을 더함

추가사항 : 어떤 사진도 올리지 않으면 default 이미지로 뜨게 만들 것.

              >> 사실 그 과정을 추가했으나 sql문에서 추가하지 못하는 문제를 발견

                   - 이미 sql문을 만든 상태인데도 작동을 하지 않아 어쩔 수 없이 따로 추가해주어야 했음

                     변경 사항은 BoardController.java에 기제

 

사진을 넣기 위한 설정(MultipartFile)

pom.xml-------------------------------------------

<!--파일 업로드 관련 -->
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>

 

DispatcherServlet-servlet.xml---------------

<!-- 파일 업로드 관련 설정 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 아래 항목은 넣지 않아도 되지만 만약 400에러가 뜬다면 사용해 볼 것 -->
        <property name="defaultEncoding" value="UTF-8"></property>
	<property name="maxUploadSize" value="100000" />
</bean>

 

사진을 띄우고 넣기 위한 내부 로직

BOARD.sql---------------------------------------

CREATE TABLE BOARD(
   BID INT PRIMARY KEY,
   TITLE VARCHAR(20) NOT NULL,
   WRITER VARCHAR(20) NOT NULL,
   CONTENT VARCHAR(100) NOT NULL,
   CNT INT DEFAULT 0,
   REGDATE DATE DEFAULT SYSDATE,
   UPLOADFILE VARCHAR(50) DEFAULT 'default.jpg'
);

SELECT*FROM BOARD;

 

BoardVO.java-----------------------------------

package com.ryo.biz.board;

import org.springframework.web.multipart.MultipartFile;

public class BoardVO {
	private int bid;
	private String title;
	private String writer;
	private String content;
	private int cnt;
	private String regdate;
	// 테이블에서는 사용하지 않는 항목
	private String searchCondition; // 검색에 TITLE/WRITER 받아오는 항목
	private String searchContent; // 검색한 내용을 받아오는 항목
	private MultipartFile uploadFile;
	private String fileName; // requestParam으로 값 받아서 넘기는 것도 가능[MultipartFile]
	
	public int getBid() {
		return bid;
	}
	public void setBid(int bid) {
		this.bid = bid;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public int getCnt() {
		return cnt;
	}
	public void setCnt(int cnt) {
		this.cnt = cnt;
	}
	public String getRegdate() {
		return regdate;
	}
	public void setRegdate(String regdate) {
		this.regdate = regdate;
	}
	public String getSearchCondition() {
		return searchCondition;
	}
	public void setSearchCondition(String searchCondition) {
		this.searchCondition = searchCondition;
	}
	public String getSearchContent() {
		return searchContent;
	}
	public void setSearchContent(String searchContent) {
		this.searchContent = searchContent;
	}
	public MultipartFile getUploadFile() {
		return uploadFile;
	}
	public void setUploadFile(MultipartFile uploadFile) {
		this.uploadFile = uploadFile;
	}
	public String getFileName() {
		return fileName;
	}
	public void setFileName(String fileName) {
		this.fileName = fileName;
	}
	@Override
	public String toString() {
		return "BoardVO [bid=" + bid + ", title=" + title + ", writer=" + writer + ", content=" + content + ", cnt="
				+ cnt + ", regdate=" + regdate + ", searchCondition=" + searchCondition + ", searchContent="
				+ searchContent + ", uploadFile=" + uploadFile + "]";
	}
}

 

BoardDAO2.java-------------------------------

package com.ryo.biz.board.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.ryo.biz.board.BoardVO;

@Repository("boardDAO")
public class BoardDAO2 {
	
	// 의존 관계 + 의존성 주입 필요
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	final String sql_selectOne="SELECT * FROM BOARD WHERE BID=?";
	final String sql_selectAll="SELECT * FROM BOARD ORDER BY BID DESC";
	final String sql_selectAll_T="SELECT * FROM BOARD WHERE TITLE LIKE '%'||?||'%' ORDER BY BID DESC";
	final String sql_selectAll_W="SELECT * FROM BOARD WHERE WRITER LIKE '%'||?||'%' ORDER BY BID DESC";
	final String sql_insert="INSERT INTO BOARD(BID,TITLE,WRITER,CONTENT,UPLOADFILE) VALUES((SELECT NVL(MAX(BID),0)+1 FROM BOARD),?,?,?,?)";
	final String sql_update="UPDATE BOARD SET TITLE=?, CONTENT=?, UPLOADFILE=? WHERE BID=?";
	final String sql_delete="DELETE BOARD WHERE BID=?";

	// 글 하나 보기
	public BoardVO selectOneBoard(BoardVO vo) {
		Object[] args= {vo.getBid()};
		return jdbcTemplate.queryForObject(sql_selectOne,args,new BoardRowMapper());
	}
    
	// 글 모두 보기
	public List<BoardVO> selectAllBoard(BoardVO vo) {
		System.out.println("BoardDAO2 작동★");
		Object[] args = {vo.getSearchContent()};
		if(vo.getSearchCondition()==null) {
			return jdbcTemplate.query(sql_selectAll_T,args ,new BoardRowMapper());
		}
		else {
			return jdbcTemplate.query(sql_selectAll_W,args ,new BoardRowMapper());
		}
	}
    
	// 전체 및 검색 글을 보이는 내 방법
	public List<BoardVO> selectAllConditionBoard(BoardVO vo) {
		if(vo.getSearchCondition()==null) {
			vo.setSearchCondition("TITLE");
		}
		if(vo.getSearchContent()==null) {
			vo.setSearchContent("");
		}
		String sql_selectAll=sql_selectAll_T;
		if(vo.getSearchCondition().equals("WRITER")){
			sql_selectAll=sql_selectAll_W;
		}
		return jdbcTemplate.query(sql_selectAll, new BoardRowMapper(), vo.getSearchContent());	
	}
	
	
	// 글 추가
	public void insertBoard(BoardVO vo) {
		System.out.println("★");
		jdbcTemplate.update(sql_insert,vo.getTitle(),vo.getWriter(),vo.getContent(),vo.getFileName());
	}
    
	// 글 업데이트
	public void updateBoard(BoardVO vo) {
		jdbcTemplate.update(sql_update,vo.getTitle(),vo.getContent(),vo.getFileName(), vo.getBid());
	}
    
	// 글 삭제
	public void deleteBoard(BoardVO vo) {
		jdbcTemplate.update(sql_delete,vo.getBid());
	}	
}

// 글의 값들을 저장하는 Mapper
class BoardRowMapper implements RowMapper<BoardVO>{

	@Override
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		// 알아서 rowNum을 판단하기 때문에 걱정하지 말 것
		BoardVO data=new BoardVO();
		data.setBid(rs.getInt("BID"));
		data.setContent(rs.getString("CONTENT"));
		data.setTitle(rs.getString("TITLE"));
		data.setWriter(rs.getString("WRITER"));
		data.setCnt(rs.getInt("CNT"));
		data.setFileName(rs.getString("UPLOADFILE"));
		data.setRegdate(rs.getString("REGDATE"));
		return data;
	}
}

 

BoardController.java--------------------------

package com.ryo.biz.controller;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.ryo.biz.board.BoardService;
import com.ryo.biz.board.BoardVO;

@Controller
@SessionAttributes("data") // "data"라는 이름의 데이터가 Model 객체에 세팅이 된다면, 그 것을 session에 기억시키겠다.
public class BoardController{
	
	@Autowired
	private BoardService boardService; // 비즈니스 컴포넌트, DAO를 직접 이용하지 않을 것!

	// main에 넣을 구분값
	@ModelAttribute("scMap")
	public Map<String,String> searchConditionMap(){
		Map<String,String> scMap = new HashMap<String,String>();
		scMap.put("제목", "TITLE");
		scMap.put("작성자", "WRITER");
		return scMap;
	}
	
	// main
	// API 분석 때 필요할 것, VO에 넣는 것이 좋음
	@RequestMapping("/main.do")
	public String main(@RequestParam(value="searchCondition", defaultValue="TITLE", required=false)String searchCondition, @RequestParam(value="searchContent", defaultValue="", required=false)String searchContent,BoardVO bVO, Model model){

		// 검색을 위한 것
		if(bVO.getSearchCondition()==null) {
			bVO.setSearchCondition("TITLE");
		}
		if(bVO.getSearchContent()==null) {
			bVO.setSearchContent("");
		}
		System.out.println("검색조건: "+searchCondition);
	    System.out.println("검색어: "+searchContent);
		List<BoardVO> datas = boardService.selectAllBoard(bVO);
		
		model.addAttribute("datas", datas);
		return "main.jsp";
	}
	
	// 글 하나 선택
	@RequestMapping("/board.do")
	public String board(BoardVO bVO, Model model){

		bVO=boardService.selectOneBoard(bVO);
		model.addAttribute("data", bVO);
		return "board.jsp";
	}
	
	// 글 추가.jsp로 이동
	@RequestMapping(value="/binsert.do", method=RequestMethod.GET)
	public String binsertin() {
		return "insertBoard.jsp";
	}
	
	@RequestMapping(value="/binsert.do", method=RequestMethod.POST)
	public String binsert(BoardVO bVO) throws IllegalStateException, IOException{
		System.out.println("binsert 진행 : " + bVO);
		
		MultipartFile uploadFile = bVO.getUploadFile();
		if(!uploadFile.isEmpty()){// 업로드한 파일 존재여부 확인
			String fileName=uploadFile.getOriginalFilename(); // 업로드한 파일명
			bVO.setFileName(fileName);
			System.out.println(bVO.getFileName());
			uploadFile.transferTo(new File("파일을 저장할 파일주소"+fileName)); // 최종 저장  목적지 설정
		}
		else {
			bVO.setFileName("default.jpg");
		}
		
		boardService.insertBoard(bVO);
		
		return "redirect:main.do";
	}

	// 글 삭제
	@RequestMapping("/bdelete.do")
	public String bdelete(BoardVO bVO) {
		
		boardService.deleteBoard(bVO);
		
		return "redirect:main.do";
	}
	
	// 글 업데이트
	@RequestMapping("/bupdate.do")
	public String bupdate(@ModelAttribute("data")BoardVO bVO) throws IllegalStateException, IOException{
		
		MultipartFile uploadFile = bVO.getUploadFile();
		if(!uploadFile.isEmpty()){// 업로드한 파일 존재여부 확인
			String fileName=uploadFile.getOriginalFilename(); // 업로드한 파일명
			bVO.setFileName(fileName);
			System.out.println(bVO.getFileName());
			uploadFile.transferTo(new File("파일을 저장할 파일 주소"+fileName)); // 최종 저장  목적지 설정
		}
		
		boardService.updateBoard(bVO);
		
		return "redirect:main.do";
	}
}

 

insertBoard.jsp---------------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<!--
	Stellar by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>insertBoard</title>
<meta charset="utf-8" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
<noscript>
	<link rel="stylesheet" href="assets/css/noscript.css" />
</noscript>
</head>
<body class="is-preload">

	<!-- Wrapper -->
	<div id="wrapper">

		<!-- Main -->
		<div id="main">

			<!-- Introduction -->
			<section id="intro" class="main">
				<div class="spotlight">
					<div class="content">
						<header class="major">
							<h2>write</h2>
						</header>
						<form action="binsert.do" method="post"
							enctype="multipart/form-data">
							<table class="alt">
								<tbody>
									<tr>
										<td>제목</td>
										<td colspan="2"><input type="text" name="title"
											value="제목" required></td>
									</tr>
									<tr>
										<td>작성자</td>
										<td colspan="2"><input type="text" name="writer"
											value="${user.name}" required readonly></td>
									</tr>
									<tr>
										<td>내용</td>
										<td colspan="2"><input type="text" name="content"
											value="글쓰기" required></td>
									</tr>
									<tr>
										<td>파일</td>
										<td colspan="2"><input type="file" name="uploadFile"
											onchange="loadFile(this);"></td>
									</tr>
									<tr>
										<td colspan="3" align="right"><input type="submit"
											class="button primary" value="글쓰기"></td>
									</tr>
								</tbody>
							</table>
						</form>
						<a href="main.do">메인으로</a>
					</div>
					<span class="image"><img src="images/pic01.jpg" alt="미리보기"
						id="preview" /></span>
				</div>
			</section>
		</div>
	</div>

	<!-- 사진 미리보기 js -->
	<script type="text/javascript">
	function loadFile(input){
		//console.log('로그1');
		if(input.files && input.files[0]){ // 파일을 여러 개 들어올 것을 예상해서
			//console.log('로그2');
			var fr=new FileReader();
			fr.onload=function(event){
				//console.log=('로그3');
				document.getElementById('preview').src = event.target.result;
			};
			fr.readAsDataURL(input.files[0]);
		}
		else{
			// 필수 속성이니까 공백값을 주는 것이 기본
			//console.log('로그4');
			document.getElementById('preview').src="";
		}
	}
        </script>


	<!-- Scripts -->
	<script src="assets/js/jquery.min.js"></script>
	<script src="assets/js/jquery.scrollex.min.js"></script>
	<script src="assets/js/jquery.scrolly.min.js"></script>
	<script src="assets/js/browser.min.js"></script>
	<script src="assets/js/breakpoints.min.js"></script>
	<script src="assets/js/util.js"></script>
	<script src="assets/js/main.js"></script>

</body>
</html>

 

board.jsp-----------------------------------------

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<!--
	Stellar by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>board</title>
<meta charset="utf-8" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
<noscript>
	<link rel="stylesheet" href="assets/css/noscript.css" />
</noscript>
</head>
<body class="is-preload">

	<!-- Wrapper -->
	<div id="wrapper">

		<!-- Main -->
		<div id="main">

			<!-- Introduction -->
			<section id="intro" class="main">
				<div class="spotlight">
					<div class="content">
						<header class="major">
							<h2>board</h2>
						</header>
						<div class="table-wrapper">
							<form action="bupdate.do" method="post"
								enctype="multipart/form-data">
								<table class="alt">
									<tbody>
										<tr>
											<td>제목</td>
											<td colspan="2"><input type="text" name="title"
												value="${data.title}" required></td>
										</tr>
										<tr>
											<td>작성자</td>
											<td colspan="2">${data.writer}</td>
										</tr>
										<tr>
											<td>내용</td>
											<td colspan="2"><input type="text" name="content"
												value="${data.content}" required></td>
										</tr>
										<tr>
											<td>파일</td>
											<td colspan="2"><input type="file" name="uploadFile" onchange="loadFile(this);"></td>
										</tr>
										<tr>
											<td>글 업로드 시간</td>
											<td><input type="datetime-local" name="regdate"
												value="${data.regdate}"></td>
										</tr>
										<tr>
											<td colspan="3" align="right"><input type="submit"
												class="button primary" value="글 변경"><a href="bdelete.do?bid=${data.bid}"><input type="button"class="button primary" value="글 삭제"></a></td>
										</tr>
									</tbody>
								</table>
							</form>
							<a href="main.do">메인으로</a>
						</div>
					</div>
					<span class="image"><img src="images/${data.fileName}"
								alt="" /></span>
				</div>
			</section>
		</div>
	</div>
	
	<!-- 사진 미리보기 js -->
	<script type="text/javascript">
	function loadFile(input){
		//console.log('로그1');
		if(input.files && input.files[0]){ // 파일을 여러 개 들어올 것을 예상해서
			//console.log('로그2');
			var fr=new FileReader();
			fr.onload=function(event){
				//console.log=('로그3');
				document.getElementById('preview').src = event.target.result;
			};
			fr.readAsDataURL(input.files[0]);
		}
		else{
			// 필수 속성이니까 공백값을 주는 것이 기본
			//console.log('로그4');
			document.getElementById('preview').src="";
		}
	}
       </script>

	<!-- Scripts -->
	<script src="assets/js/jquery.min.js"></script>
	<script src="assets/js/jquery.scrollex.min.js"></script>
	<script src="assets/js/jquery.scrolly.min.js"></script>
	<script src="assets/js/browser.min.js"></script>
	<script src="assets/js/breakpoints.min.js"></script>
	<script src="assets/js/util.js"></script>
	<script src="assets/js/main.js"></script>

</body>
</html>

 

 

BoardController에 사진 값 null일 때의 else값을 넣기 이전 결과-------------------

BoardController에 사진 값 null일 때의 else값을 넣은 이후 결과-------------------

위 사진은 default.jpg로 값이 들어가지 않으면 넣도록 만든 사진