일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- ddit
- python
- ibatis
- 단축키
- 자바
- 컬렉션프레임워크
- Mac
- crud
- 대덕인재개발원
- FastAPI
- 맥
- 생활코딩
- 반복문
- Homebrew
- 배열
- servlet
- jsp
- JDBC
- spring
- API
- Android
- nodejs
- Java
- 자바문제
- 객체지향
- html
- 이클립스
- Oracle
- Error
- pyqt
Archives
- Today
- Total
romworld
Spring 12 - Book 테이블도 파일업로드 해보자 본문
<aside.jsp>
도서 등록으로 이동했을 때 화면 깨짐을 수정해보자 !
<create.jsp>
- input name 속성의 값을 content에서 cont 로 바꿔주고, 스크립트도 수정 후 다시 실행시키면
- 정상적으로 출력된다. (name이 충돌됐기 때문에)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js">
</script>
<meta charset="UTF-8">
<title>책 등록하기</title>
</head>
<body>
<h1>책 등록</h1>
<!-- 폼페이지 -->
<!--
요청URI : /cretae?title=롬이야기&category=소설&price=10000
요청파라미터 : tilte=롬이야기&category=소설&price=10000
요청방식 : post
-->
<form action="/create" method="post">
<!-- 폼데이터 -->
<p>제목 : <input type="text" name="title" required /></p>
<p>카테고리 : <input type="text" name="category" required /></p>
<p>가격: <input type="number" name="price" required /></p>
<p>내용: <textarea name="cont" rows="5" cols="30"></textarea></p>
<p>
<input type="submit" value="저장" />
<input type="button" value="목록" />
</p>
</form>
<script type="text/javascript">
CKEDITOR.replace('cont');
</script>
</body>
</html>
이미지를 넣어보자!
<BookVO.java>
- private String cont;
- private MultipartFile[] multipartFiles;
- private List<AttachVO> attachVOList;
package kr.or.ddit.vo;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
// 자바빈 클래스
// 1) 멤버변수 2) 기본생성자 3) getter/setter메소드
public class BookVO {
private int rnum;
private int bookId;
private String title;
private String category;
private int price;
private Date insertDate;
private String content;
private String cont;
private MultipartFile[] multipartFiles;
//BookVO : AttachVO = 1 : N
private List<AttachVO> attachVOList;
// 기본생성자. 생략가능
public BookVO() {}
// getter/setter 메서드
public int getRnum() {
return rnum;
}
public void setRnum(int rnum) {
this.rnum = rnum;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Date getInsertDate() {
return insertDate;
}
public void setInsertDate(Date insertDate) {
this.insertDate = insertDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCont() {
return cont;
}
public void setCont(String cont) {
this.cont = cont;
}
public MultipartFile[] getMultipartFiles() {
return multipartFiles;
}
public void setMultipartFiles(MultipartFile[] multipartFiles) {
this.multipartFiles = multipartFiles;
}
public List<AttachVO> getAttachVOList() {
return attachVOList;
}
public void setAttachVOList(List<AttachVO> attachVOList) {
this.attachVOList = attachVOList;
}
@Override
public String toString() {
return "BookVO [rnum=" + rnum + ", bookId=" + bookId + ", title=" + title + ", category=" + category
+ ", price=" + price + ", insertDate=" + insertDate + ", content=" + content + ", cont=" + cont
+ ", multipartFiles=" + Arrays.toString(multipartFiles) + ", attachVOList=" + attachVOList + "]";
}
}
<create.jsp>
- enctype="multipart/form-data"
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js">
</script>
<meta charset="UTF-8">
<title>책 등록하기</title>
</head>
<body>
<h1>책 등록</h1>
<!-- 폼페이지 -->
<!--
요청URI : /cretae?title=롬이야기&category=소설&price=10000
요청파라미터 : tilte=롬이야기&category=소설&price=10000
요청방식 : post
-->
<form action="/create" method="post" enctype="multipart/form-data">
<!-- 폼데이터 -->
<div class="imgs_wrap"></div>
<p>제목 : <input type="text" name="title" required /></p>
<p>카테고리 : <input type="text" name="category" required /></p>
<p>가격: <input type="number" name="price" required /></p>
<p>내용: <textarea name="cont" rows="5" cols="30"></textarea></p>
<p>
책표지 : <input type="file" id="input_imgs" name="uploadfile" multiple />
</p>
<p>
<input type="submit" value="저장" />
<input type="button" value="목록" />
</p>
</form>
<script type="text/javascript">
CKEDITOR.replace('cont');
</script>
</body>
</html>
이미지 미리보기
<create.jsp>
- 이미지 미리보기 스크립트 추가
<script type="text/javascript">
$(function(){
// 이미지 미리보기 시작 -
$("#input_imgs").on("change", handleImgFileSelect);
// e: change 이벤트
function handleImgFileSelect(e){
// 파일객체에 파일들
let files = e.target.files;
// 이미지 배열
let fileArr = Array.prototype.slice.call(files);
// fileArr에서 하나 꺼내면 f(파일객체 1개)
fileArr.forEach(function(f){
// 이미지만 가능
if(!f.type.match("image.*")){
alert("이미지 확장자만 가능합니다.")
return;
}
// 이미지를 읽을 객체
let reader = new FileReader();
//reader.readAsDataURL(f);의 이벤트
reader.onload = function(e){
let img_html = "<img src=\"" + e.target.result +"\" stype='width:30%' />";
$(".imgs_wrap").append(img_html);
}
// 이미지를 읽는다.
reader.readAsDataURL(f);
});// end forEach
}
// 이미지 미리보기 끝 -
})
</script>
<BookController.java>
- createPost 메서드 수정
- // cont -> content로 복사
bookVO.setContent(bookVO.getCont()); - LprodController.getFolder() 는 스태틱이므로 접근이 가능하다.
- LprodController.checkImageType 도 스태틱이므로 접근 가능
/*
요청URI : /cretae?title=롬이야기&category=소설&price=10000
요청URL : /create
요청파라미터 : {title=롬이야기&category=소설&price=10000}
요청방식 : post
bookVO{bookId:null,title:롬이야기,category:소설price:10000,insertDate:null
content:null, cont: 내용, uploadfile:파일객체, attachVOList:null}
private int bookId;
private String title;
private String category;
private int price;
private Date insertDate;
private String content;
private String cont;
private MultipartFile[] uploadfile;
private List<AttachVO> attachVOList;
*/
@RequestMapping(value="/create", method=RequestMethod.POST)
public ModelAndView createPost(BookVO bookVO, ModelAndView mav) {
log.info("bookBO : " + bookVO.toString());
//<selectKey resultType="int" order="BEFORE" keyProperty="bookId">
//1 증가된 기본키 값을 받음
int bookId = bookService.createPost(bookVO);
log.info("bookId :" + bookId);
if(bookId <1) { // 등록 실패
// /create로 요청을 다시 함 => uri주소가 바뀜
mav.setViewName("redirect:/create");
}else {// 등록 성공 : 상세보기 페이지로 이동
mav.setViewName("redirect:/detail?bookId=" + bookId);
}
return mav;
}
<book_SQL.xml>
- lprod_SQL.xml에서 작성한 다중 insert를 가져온다
<!-- 다중 insert 시 update 태그를 사용
파라미터 : List<AttachVO attachVOList
insert, update, delete의 경우 resultType은 생략
separator=" " : 공백으로 구분
-->
<update id="createPostAttach" parameterType="java.util.List">
<!--
order="BEFORE"는 foreach 태그 실행 전에 selectKey부터 실행
-->
<selectKey resultType="int" order="BEFORE" keyProperty="seq">
SELECT NVL(MAX(SEQ),0)+1 FROM ATTACH
</selectKey>
<!-- index : 반복 시 index값. 0부터 시작. -->
<foreach collection="list" item="attachVO"
open="INSERT ALL" close="SELECT * FROM DUAL" separator=" "
index="idx" >
INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE, ETP_ID)
VALUES(#{idx}+#{seq},#{attachVO.filename},#{attachVO.filesize},'',sysdate,
#{attachVO.etpId})
</foreach>
</update>
<BookDao.java> 추가
// ATTACH 테이블에 insert all
public int createPostAttach(List<AttachVO> attachVOList) {
return this.sqlSessionTemplate.update("book.createPostAttach", attachVOList);
}
<BookServiceImpl.java>
- 컨트롤러에서 작성한 소스 잘라내서 붙히고 작성
package kr.or.ddit.service.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import kr.or.ddit.controller.LprodController;
import kr.or.ddit.dao.BookDao;
import kr.or.ddit.service.BookService;
import kr.or.ddit.vo.AttachVO;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnailator;
// 서비스 클래스 : 비즈니스 로직
// 스프링 MVC 구조에서 Controller와 DAO를 연결하는 역할
/*
스프링 프레임워크(디자인패턴 + 라이브러리)는 직접 클래스를 생성하는 것을 지양(싫음)하고,
인터페이스를 통해 접근하는 것을 권장하고 있기 때문에(확장성)
프링이는 인터페이스를 좋아해 ..
그래서 서비스 레이어는 인터페이스(BookService)와 클래스(BookServiceImpl)를 함께 사용함
Impl : implement의 약자
*/
// Service 어노테이션 : "프링아 이 클래스는 서비스 클래스야" 라고 알려줌.
// 프링이가 자바빈으로 등록해줌
@Slf4j
@Service
public class BookServiceImpl implements BookService {
// 데이터베이스에 접근하기 위해 BookDao 인스턴스를 주입받자
@Autowired
BookDao bookDao;
// 도서 테이블(Book)에 입력
//<insert id="createPost" parameterType="bookVO"> insert id와 메서드 명을 같게 설정
@Override
public int createPost(BookVO bookVO) {
//1) Book 테이블에 insert. bookId를 리턴받음
// bookVO의 bookId 멤버변수에 새로운 값이 들어있다.
int result = bookDao.createPost(bookVO);
// cont -> content로 복사
bookVO.setContent(bookVO.getCont());
String uploadFolder = "C:\\eclipse_202006\\workspace\\springProj\\src\\main\\webapp\\resources\\upload";
// make folder 시작 -
File uploadPath = new File(uploadFolder , LprodController.getFolder());
log.info("uploadPath : " + uploadPath);
//만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists()==false) {
uploadPath.mkdirs();
}
// make folder 끝 -
//List<AttachVO> attachVOList;에 데이터 넣기 시작 -
List<AttachVO> voList = new ArrayList<AttachVO>();
//<input type="file" id="input_imgs" name="uploadfile" nultiple />
MultipartFile[] multipartFiles = bookVO.getUploadfile();
// multipartFile : 파일객체1개
for(MultipartFile multipartFile : multipartFiles) {
AttachVO vo = new AttachVO();
// 실제 파일명
String uploadFileName = multipartFile.getOriginalFilename();
log.info("----------");
log.info("filename : " + uploadFileName);
log.info("filesize : " + multipartFile.getSize());
log.info("contentType : " + multipartFile.getContentType());
//UUID 처리 시작 -
UUID uuid = UUID.randomUUID();
uploadFileName = uuid.toString() + "_" + uploadFileName;
//UUID 처리 끝 -
// File 객체 설계(복사할 경로, 파일명)
File saveFile = new File(uploadPath, uploadFileName);
try {
// 파일 복사. 파일객체를 복사한다(대상경로 및 파일명으로)
multipartFile.transferTo(saveFile);
// 이미지인지 확인
if(LprodController.checkImageType(saveFile)) {
// 썸네일 파일설계
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath, "s_" + uploadFileName)
);
//썸네일 생성
Thumbnailator.createThumbnail(multipartFile.getInputStream(),
thumbnail,100,100);
thumbnail.close();
}
}catch(IllegalStateException e){
log.error(e.getMessage());
}catch(IOException e) {
log.error(e.getMessage());
}
// /2023/01/30/asdfasd_새롬이.jpg
String filename = "/" + LprodController.getFolder().replace("\\", "/") + "/" +
uploadFileName;
vo.setFilename(filename);
Long l = multipartFile.getSize();
vo.setFilesize(l.intValue());
// /2023/01/30/s_asdfasd_새롬이.jpg
String thumbFilename = "/" + LprodController.getFolder().replace("\\", "/") + "/s_" +
uploadFileName;
vo.setThumbnail(thumbFilename);
// 전사적 아이디
vo.setEtpId(bookVO.getBookId()+"");
voList.add(vo);
} //end for
//ATTACH 테이블에 insert하기 위한 최종목적
bookVO.setAttachVOList(voList);
//List<AttachVO> attachVOList;에 데이터 넣기 끝 -
//2) BookDao의 createPostAttach(List<AttachVO> attachVOList) 메소드 호출
this.bookDao.createPostAttach(bookVO.getAttachVOList());
return result;
}
// 책 상세보기
@Override
public BookVO detail(BookVO bookVO) {
return bookDao.detail(bookVO);
}
// 책 수정하기
@Override
public int updatePost(BookVO bookVO) {
return this.bookDao.updatePost(bookVO);
}
// 책 삭제하기
@Override
public int deletePost(BookVO bookVO) {
return this.bookDao.deletePost(bookVO);
}
// 책 목록
// 리턴 타입 :List<BookVO>
@Override
public List<BookVO> list(String keyword){
return this.bookDao.list(keyword);
}
}
실행시키면
파일을 선택해서 실행해보면 detail로 넘아가고
데이터 베이스에도 데이터가 잘 들어간다.
'Spring' 카테고리의 다른 글
Spring 14 - 페이징 처리, 검색 기능, 계층형 쿼리, LOOP을 이용한 UPDATE 쿼리문 (1) | 2023.02.01 |
---|---|
Spring 13 - 1:N 관계 테이블(BOOK,LPROD)을 이용하여 상세화면 구현 (0) | 2023.01.31 |
Spring 11 - LPROD, ATTACH 테이블 연결 (일대다 관계 ResultMap 사용) + 한글깨짐 해결하기 (0) | 2023.01.30 |
Spring 10 - LPROD를 이용한 파일 업로드, 썸네일 (0) | 2023.01.27 |
Spring 09 - LPROD 테이블을 이용한 CRUD (0) | 2023.01.25 |
Comments