일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- API
- nodejs
- ibatis
- FastAPI
- 반복문
- 객체지향
- 대덕인재개발원
- Android
- Java
- jsp
- servlet
- Oracle
- spring
- pyqt
- 이클립스
- Mac
- 맥
- Homebrew
- JDBC
- 단축키
- 생활코딩
- Error
- html
- ddit
- 배열
- python
- crud
- 자바
- 컬렉션프레임워크
- 자바문제
Archives
- Today
- Total
romworld
Spring 11 - LPROD, ATTACH 테이블 연결 (일대다 관계 ResultMap 사용) + 한글깨짐 해결하기 본문
Spring
Spring 11 - LPROD, ATTACH 테이블 연결 (일대다 관계 ResultMap 사용) + 한글깨짐 해결하기
inderrom 2023. 1. 30. 16:08관계차수
- 1:1
- 1:N
- N:M
N:M에 경우 Database에서 처리 불가
일대다의 관계를 추가해보자
<create.jsp>
- multiple 속성 추가
<LprodVO.java>
- 일대다 처리해주자
package kr.or.ddit.vo;
import java.util.Arrays;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class LprodVO {
private int lprodId;
private String lprodGu;
private String lprodNm;
private MultipartFile[] uploadFile;
// 상품분류 : 첨부파일 = 1: N
private List<AttachVO> attachVOList;
public LprodVO() {
}
public LprodVO(int lprodId) {
this.lprodId = lprodId;
}
public int getLprodId() {
return lprodId;
}
public void setLprodId(int lprodId) {
this.lprodId = lprodId;
}
public String getLprodGu() {
return lprodGu;
}
public void setLprodGu(String lprodGu) {
this.lprodGu = lprodGu;
}
public String getLprodNm() {
return lprodNm;
}
public void setLprodNm(String lprodNm) {
this.lprodNm = lprodNm;
}
public MultipartFile[] getUploadFile() {
return uploadFile;
}
public void setUploadFile(MultipartFile[] uploadFile) {
this.uploadFile = uploadFile;
}
public List<AttachVO> getAttachVOList() {
return attachVOList;
}
public void setAttachVOList(List<AttachVO> attachVOList) {
this.attachVOList = attachVOList;
}
@Override
public String toString() {
return "LprodVO [lprodId=" + lprodId + ", lprodGu=" + lprodGu + ", lprodNm=" + lprodNm + ", uploadFile="
+ Arrays.toString(uploadFile) + ", attachVOList=" + attachVOList + "]";
}
}
<LprodController.java>
- createPost 매서드를 수정해준다.
- 배열타입으로 바꾸기
- MultipartFile[] multipartFile = lprodVO.getUploadFile();
- 리스트에 넣어주기
/*
요청URI : /lprod/createPost
요청파라미터 : {"lprodId:"10","lprodGu:"P404""lprodNm:"간식류"}
요청방식 : post
*/
@PostMapping("/createPost")
public String createPost(@ModelAttribute LprodVO lprodVO,
Model model) {
log.info("lprodVO :" +lprodVO);
MultipartFile[] multipartFiles = lprodVO.getUploadFile();
log.info("multipartFile : " + multipartFiles);
List<AttachVO> voList = new ArrayList<AttachVO>();
int seq = 1;
//uploadFile 정보를 통해서 attachVOList에 값들을 setting해줘야함
//배열로부터 하나씩 파일을 꺼내오자
for(MultipartFile multipartFile : multipartFiles) {
AttachVO vo = new AttachVO();
log.info("------------");
log.info("fileName : " + multipartFile.getOriginalFilename());
log.info("fileSize : " + multipartFile.getSize());
log.info("contentType : " + multipartFile.getContentType()); //MIME타입
Long l = multipartFile.getSize();
vo.setSeq(seq++);
vo.setFilename(multipartFile.getOriginalFilename());
vo.setFilesize(l.intValue());
voList.add(vo);
}
lprodVO.setAttachVOList(voList);
log.info("(after) lprodVO : " + lprodVO);
int result = this.lprodService.createPost(lprodVO);
if(result > 0) { //입력 성공
return "redirect:/lprod/detail?lprodGu="+lprodVO.getLprodGu();
}else { // 입력 실패
model.addAttribute("data",lprodVO);
model.addAttribute("lprodId",lprodVO.getLprodId());
return "/lprod/create";
}
}
<LprodServiceImpl.java>
- createPost 메서드 수정
// 상품분류 정보 입력
@Override
public int createPost(LprodVO lprodVO){
//LPROD테이블에 INSERT
int result = this.lprodDao.createPost(lprodVO);
//Attach테이블에 insert(다중insert)
List<AttachVO> attachVOList = lprodVO.getAttachVOList();
return result;
}
mybatis에서 INSERT ALL 하는 방법 (다중 insert)
- 예
INSERT ALL
INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(2,'새롬이.jsp',12345,'',sysdate)
INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(3,'새롬이3.jsp',12346,'',sysdate)
INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(4,'새롬이4.jsp',12347,'',sysdate)
select * from dual;
<lprod_SQL.xml>
<!-- 다중 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)
VALUES(#{idx}+#{seq},#{attachVO.filename},#{attachVO.filesize},'',sysdate)
</foreach>
</update>
<lprodDao.java>
//다중 insert 시
public int createPostAttach(List<AttachVO> attachVOList) {
return this.sqlSessionTemplate.update("lprod.createPostAttach",attachVOList);
}
<lprodService.java>
<lprodServiceImpl.java> 수정
// 상품분류 정보 입력
@Override
public int createPost(LprodVO lprodVO){
//LPROD테이블에 INSERT
int result = this.lprodDao.createPost(lprodVO);
//Attach테이블에 insert(다중insert)
List<AttachVO> attachVOList = lprodVO.getAttachVOList();
result = result + this.lprodDao.createPostAttach(attachVOList);
log.info("result : " + result);
return result;
}
Multipart 한글깨짐 문제는
web.xml 에서 한글 처리한 필터 밑에 배치해주면 해결된다!
exERD를 이용해서 일대다 관계를 설정해보자
- 자바와 디비를 연결해서 erd를 만들 수 있다.
-- 기본키, 외래키 제외하고
--스키마구조 (컬럼,자료형,크기,제약사항,NOT NULL, CHECK) 및 데이터 복제
CREATE TABLE ATTACH_BAK
AS
SELECT * FROM ATTACH;
우선 ATTACH를 백업해두고
기존 ATTACH테이블 데이터를 전부 지운다.
ERD 에서 추가한 전사적아이디 컬럼을 추가해준다.
- 제약조건 삭제 X 표시 클릭
- 인덱스도 삭제표시 클릭 X
- 그 후에 열 카데고리 클릭 후 SEQ와 ETP_ID를 기본키 지정해준다
** 다시 제약 조건과 인덱스를 확인해보면 SEQ, ETP_ID 가 선택되어있는 것을 볼 수 있다.
ATTACH_BAK 테이블에 데이터를 집어넣어보자
INSERT INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE, ETP_ID)
SELECT SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE, 'P101'
FROM ATTACH_BAK;
COMMIT;
이제 etp_id를 추가해주자
<AttachVO.java>
package kr.or.ddit.vo;
import java.util.Date;
import lombok.Data;
// getter/setter를 생성시켜줌
// lombok의 힘을 빌림
// Pojo에 위반..
@Data
public class AttachVO {
private int seq;
private String filename;
private int filesize;
private String thumbnail;
private Date regdate;
//전사적 아이디
private String etpId;
}
<lprod_SQL.xml>에도 etp_id 추가해주기
<!-- 다중 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>
업로드 경로 설정
<LprodController.java>
- createPost 메서드 수정
/*
요청URI : /lprod/createPost
요청파라미터 : {"lprodId:"10","lprodGu:"P404""lprodNm:"간식류"}
요청방식 : post
*/
@PostMapping("/createPost")
public String createPost(@ModelAttribute LprodVO lprodVO,
Model model) {
String uploadFolder
="C:\\eclipse_202006\\workspace\\springProj\\src\\main\\webapp\\resources\\upload";
// - make folder 시작 -
File uploadPath = new File(uploadFolder , getFolder());
log.info("uploadPath : " + uploadPath);
// 만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists()==false) {
uploadPath.mkdirs();
}
// - make folder 끝 -
log.info("lprodVO :" +lprodVO);
MultipartFile[] multipartFiles = lprodVO.getUploadFile();
log.info("multipartFile : " + multipartFiles);
List<AttachVO> voList = new ArrayList<AttachVO>();
int seq = 1;
//uploadFile 정보를 통해서 attachVOList에 값들을 setting해줘야함
//배열로부터 하나씩 파일을 꺼내오자
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()); //MIME타입
//- 같은날 같은 이미지를 업로드 시 파일 중복 방지 시작 -
//java.util.UUID => 랜덤값 생성
UUID uuid = UUID.randomUUID(); //임의의 값을 생성
//원래의 파일 이름과 구분하기 위해 _를 붙힘
uploadFileName = uuid.toString() + "_" + uploadFileName;
//- 같은날 같은 이미지를 업로드 시 파일 중복 방지 끝 -
// 파일 객체 설계(복사할 대상 경로, 파일명)
File saveFile = new File(uploadPath, uploadFileName);
try {
//파일 복사가 일어남
multipartFile.transferTo(saveFile);
//썸네일 처리 시작-------------------
// 파일이 이미지인지 체킹
if(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());
return "0";
}catch(IOException e) {
log.error(e.getMessage());
return "0";
}
Long l = multipartFile.getSize();
vo.setSeq(seq++);
// 2023/01/30/sldlaksd_새롬이.jsp
String filename = "/" + getFolder().replace("\\", "/") + "/" +
uploadFileName;
vo.setFilename(filename);
vo.setFilesize(l.intValue());
// 2023/01/30/s_sldlaksd_새롬이.jsp
String thumbFileName = "/" + getFolder().replace("\\", "/") + "/s_" +
uploadFileName;
vo.setThumbnail(thumbFileName);
//전사적 아이디(ex)P301)
vo.setEtpId(lprodVO.getLprodGu());
voList.add(vo);
}
lprodVO.setAttachVOList(voList);
log.info("(after) lprodVO : " + lprodVO);
int result = this.lprodService.createPost(lprodVO);
if(result > 0) { //입력 성공
return "redirect:/lprod/detail?lprodGu="+lprodVO.getLprodGu();
}else { // 입력 실패
model.addAttribute("data",lprodVO);
model.addAttribute("lprodId",lprodVO.getLprodId());
return "/lprod/create";
}
}
- 하단에 썸네일을 처리를 위한 메서드도 추가
// 썸네일 처리 전 이미지 파일의 판단
// 용량이 큰 파일을 썸네일 처리를 하지 않으면
// 모바일과 같은 환경에서 많은 데이터를 소비해야 하므로
// 이미지의 경우 특별한 경우가 아니면 썸네일을 제작해야 함
// 썸네일은 이미지만 가능함
public static boolean checkImageType(File file) {
/*
.jpeg/ .jpg(JPEG 이미지)의 MIME 타입 : image/jpeg
*/
//MIME 타입을 통해 이미지 여부 확인
try {
//fle.toPath() : 파일 객체를 path객체로 변환
String contentType = Files.probeContentType(file.toPath());
log.info("contentType : " + contentType);
// MIME 타입 정보가 image로 시작하는지 여부를 return
return contentType.startsWith("image");
}catch(IOException e) {
log.error(e.getMessage());
}
// 이 파일이 이미지가 아닐 경우
return false;
}
++++
mac에서는 파일 확인이 안돼서
함수를 바꿔서 사용함
// 썸네일 처리 전 이미지 파일의 판단
// 용량이 큰 파일을 썸네일 처리를 하지 않으면
// 모바일과 같은 환경에서 많은 데이터를 소비해야 하므로
// 이미지의 경우 특별한 경우가 아니면 썸네일을 제작해야 함
// 썸네일은 이미지만 가능함
public static boolean checkImageType(File file) {
/*
.jpeg/ .jpg(JPEG 이미지)의 MIME 타입 : image/jpeg
*/
//MIME 타입을 통해 이미지 여부 확인
try {
//file.toPath() : 파일 객체를 path객체로 변환
// Path path = Paths.get(file.getPath());
// String contentType = Files.probeContentType(path);
MimetypesFileTypeMap mtm = new MimetypesFileTypeMap();
String contentType = mtm.getContentType(file.getPath());
log.info("contentType : " + contentType);
// MIME 타입 정보가 image로 시작하는지 여부를 return
return contentType.startsWith("image");
}catch(Exception e) {
log.error(e.getMessage());
}
// 이 파일이 이미지가 아닐 경우
return false;
}
마지막으로 화면 카테고리도 꾸며보자
'Spring' 카테고리의 다른 글
Spring 13 - 1:N 관계 테이블(BOOK,LPROD)을 이용하여 상세화면 구현 (0) | 2023.01.31 |
---|---|
Spring 12 - Book 테이블도 파일업로드 해보자 (0) | 2023.01.30 |
Spring 10 - LPROD를 이용한 파일 업로드, 썸네일 (0) | 2023.01.27 |
Spring 09 - LPROD 테이블을 이용한 CRUD (0) | 2023.01.25 |
Spring 08 - 도서 CRUD(7) - 부트스트랩 적용하기, 타일즈(Tiles) (1) | 2023.01.25 |
Comments