Member테이블에 칼럼 추가 ( FILE_GROUP_NO)
외래키로 FILE_GROUP과 연결
해당 과정에서 좀 더 추가
JSP
register2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<h2>파일업로드</h2>
<!-- spring form 태그 생성 -->
<!-- 필수! modelAttribute = "폼객체의 속성명(VO)" (mybatis) -->
<c:set value="${memberVO.fgvo}" var="fileGroupVO"/>
<form:form action="/item/registerPost2" method="post" enctype="multipart/form-data"
modelAttribute="memberVO"> <!-- 폼 객체의 속성명을 addAttribute 속성에 지정 (같은 이름으로) -->
<!-- MemberVO의 객체의 memName과 연동 -->
<!-- path = memberVo의 프로퍼티명
폼 항목에 바인딩(메모리에 데이터가 올라감)되는 폼 객체의 프로퍼티를 지정함
disabled : 폼 항목을 비활성화 할 때 사용. 기본값 false
readonly : 폼 항목을 읽기 전용으로 만들 때 사용. 기본값 false -->
<p>아이디: <form:input path="memId" disabled="false"/>
<p>이름 : <form:input path="memName" readonly="true"/></p>
<!-- submit으로 정보를 전달 할 시 form태그를 사용하지 않아도 정보가 전달됨 -->
<!-- form 태그를 사용하지않고 el태그를 통해 값을 받음 -->
<p>주민번호1 : <input type="text" name="memRegno1" value="${memberVO.memRegno1}"> </p>
<c:forEach var="fileDetailVO" items="${fileGroupVO.fileDetailVoList}">
<img src="${fileDetailVO.fileSaveLocate}">
</c:forEach>
<input type="file" name="fileImage" />
<button type="submit">파일업로드</button>
</form:form>
JAVA
MemberVO.java
package kr.or.ddit.vo;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
@Data
public class MemberVO {
private String memId;
private String memPass;
private String memName;
private String memRegno1;
private String memRegno2;
private Date memBir;
private String memBirStr;
private String memZip;
private String memAdd1;
private String memAdd2;
private String memHometel;
private String memComtel;
private String memHp;
private String memMail;
private String memJob;
private String memLike;
private String memMemorial;
private Date memMemorialday;
private int memMileage;
private String memDelete;
private MultipartFile fileImage;
private long fileGroupNo;
private FileGroupVO fgvo;
}
MemberMapper.java
package kr.or.ddit.mapper;
import org.apache.ibatis.annotations.Mapper;
import kr.or.ddit.vo.MemberVO;
@Mapper
public interface MemberMapper {
public int updateMember(MemberVO memVo);
public MemberVO getMemberFile(MemberVO memVo);
}
ItemController.java
package kr.or.ddit.controller;
import java.io.File;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import kr.or.ddit.service.ItemService;
import kr.or.ddit.vo.MemberVO;
import lombok.extern.slf4j.Slf4j;
@RequestMapping("/item")
@Slf4j
@Controller
public class ItemController {
//DI(의존성 주입), IoC(제어의 역전)
// root-context에 있는 value값 c:\\upload
@Autowired
String uploadPath;
@Autowired
String uploadFolder;
@Autowired
ItemService service;
// 파일 등록 폼
@GetMapping("/register")
public String register() {
return "item/register";
}
// // 파일 등록 폼
// @GetMapping("/register2")
// public String register2(Model model) {
// MemberVO mem = new MemberVO();
// mem.setMemName("오리");
// mem.setMemId("a001");
// model.addAttribute("memberVo", mem);
// return "item/register2";
// }
// 컨트롤러는 기본적으로 자바빈즈 규칙에 맞는 객체 VO는
// 다시 화면으로 폼객체를 전달함
// 폼 객체의 속성명은 직접 지정하지 않으면 폼 객체의 클래스명의
// 맨처음 문자를 소문자로 변환하여 처리함 (memberVO)
// 속성명 지정 @ModelAttribute("이름")
@GetMapping("/register2")
public String register2(@ModelAttribute("memberVO") MemberVO memberVO) {
memberVO.setMemName("오리");
memberVO.setMemId("a001");
memberVO.setMemRegno1("123123");
return "item/register2";
}
@ResponseBody
@PostMapping("/registerPost")
// public String registerPost(@RequestParam("uploadFile") MultipartFile uploadFile) {
// name 값이 그대로 와야함
public String registerPost(MultipartFile uploadFile) {
//MultipartFile : 스프링에서 제공해주는 타입
/*
--잘 씀
String getOriginalFileName() : 업로드 되는 파일의 이름(실제 파일명)
boolean isEmpty() : 파일이 없다면 true
long getSize() : 업로드되는 파일의 크기
transferTo(File file) : 파일을 저장
--잘 안씀..
String getName() : <input type="file" name="uploadFile" 에서 uploadFile을 가져옴
byte[] getBytes() : byte[]로 파일 데이터 반환
inputStream getInputStream() : 파일데이터와 연결된 InputStream을 반환
*/
log.info("filename : "+uploadFile.getOriginalFilename());
log.info("contentType : "+uploadFile.getContentType());
log.info("size : "+uploadFile.getSize());
// 계획 ( 경로와 파일이름 )
File uploadPath = new File(this.uploadPath, uploadFile.getOriginalFilename());
log.info("uploadPath : "+uploadPath);
// 파일 복사 실행
// 파일객체.transferTo(계획)
try {
uploadFile.transferTo(uploadPath);
} catch (IllegalStateException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return uploadFile.getOriginalFilename();
}
/*
// disabled한 파라미터의 값은 전달되지않음
@PostMapping("/registerPost2")
public String registerPost2(@ModelAttribute("memberVO") MemberVO memberVO) {
MultipartFile fileImage = memberVO.getFileImage();
// 계획 ( 경로와 파일이름 )
log.info("memName : "+ memberVO.getMemName());
log.info("memId : "+memberVO.getMemId());
log.info("mem "+memberVO);
//MIME(Multipurpose Internet Mail Extensions)타입
// Multipurpose Internet Mail Extensions의 약자로 간단히 말하면
// 파일 변환을 의미한다.현재는 웹을 통해 여러 형태의 파일을 전달하는데 사용하고 있지만
// 이 용어가 생길 땐 이메일과 함께 동봉할 파일을 텍스트 문자로 전환해서 이메일 시스템을
// 통해 전달하기 위해 개발되어 Internet Mail Extensions라고 불리기 시작했다고 한다.
log.info("filename : "+fileImage.getOriginalFilename());
log.info("contentType : "+fileImage.getContentType());
log.info("size : "+fileImage.getSize());
long size = fileImage.getSize();
File uploadFolder = new File(this.uploadFolder, getFolder());
if(!uploadFolder.exists()) {
uploadFolder.mkdirs();
}
// 같은날 같은 이미지 업로드 시 파일 중복 방지!!
UUID uuid = UUID.randomUUID();
String fileName = uuid.toString()+"_"+fileImage.getOriginalFilename();
File upload = new File(uploadFolder, fileName);
// 파일 복사 실행
// 파일객체.transferTo(계획)
try {
fileImage.transferTo(upload);
// 썸네일 처리
if(checkImageType(upload)) { // 이미지인 경우
FileOutputStream thumbnail = new FileOutputStream(new File(uploadFolder, "s_"+fileName));
// 라이브러리 사용 (파일 객체, 계획, 가로크기, 세로크기)
Thumbnailator.createThumbnail(fileImage.getInputStream(), thumbnail, 100, 100);
thumbnail.close();
}
} catch (IllegalStateException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "item/register2";
}
*/
// disabled한 파라미터의 값은 전달되지않음
@PostMapping("/registerPost2")
public String registerPost2(Model model, @ModelAttribute("memberVO") MemberVO memberVO) {
// 계획 ( 경로와 파일이름 )
int result = this.service.registerPost2(memberVO);
log.info("result >> "+result);
memberVO = this.service.getMemberFile(memberVO);
model.addAttribute("memberVO", memberVO);
return "item/register2";
}
}
ItemService.java
package kr.or.ddit.service;
import kr.or.ddit.vo.MemberVO;
public interface ItemService {
public int registerPost2(MemberVO memberVO);
public MemberVO getMemberFile(MemberVO memberVO);
}
ItemServiceImpl.java
package kr.or.ddit.service.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
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.mapper.FileGroupMapper;
import kr.or.ddit.mapper.MemberMapper;
import kr.or.ddit.service.ItemService;
import kr.or.ddit.vo.FileDetailVO;
import kr.or.ddit.vo.FileGroupVO;
import kr.or.ddit.vo.MemberVO;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnailator;
@Slf4j
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
String uploadPath;
// 매퍼 xml이 inject됨
@Autowired
FileGroupMapper mapper;
@Autowired
MemberMapper memMapper;
@Override
public int registerPost2(MemberVO memberVO) {
int result = 0;
// memberVO 객체로부터 파일객체를 꺼내보자
MultipartFile multipartFile = memberVO.getFileImage();
// 파일명
String fileName = multipartFile.getOriginalFilename();
// MIME(Multipurpose Internet Mail Extensions)타입
/*
* Multipurpose Internet Mail Extensions의 약자로 간단히 말하면 파일 변환을 의미한다.현재는 웹을 통해 여러
* 형태의 파일을 전달하는데 사용하고 있지만 이 용어가 생길 땐 이메일과 함께 동봉할 파일을 텍스트 문자로 전환해서 이메일 시스템을 통해
* 전달하기 위해 개발되어 Internet Mail Extensions라고 불리기 시작했다고 한다.
*/
String contentType = multipartFile.getContentType();
// 파일 크기. byte(1) short(2) int(4) long(8)
long size = multipartFile.getSize();
log.info("====================");
log.info("fileName : " + fileName);
log.info("contentType : " + contentType);
log.info("size : " + size);
log.info("====================");
// 서버의 어디로 파일을 복사할것인지?
// 연월일 폴더 생성
// C:\\upload
// , : + \\ +
// 2024\\08\\06
File uploadFolder = new File(this.uploadPath, getFolder());
if (!uploadFolder.exists()) {
uploadFolder.mkdirs();
}
// 만약 폴더가 없으면 자동 생성
if (uploadFolder.exists() == false) {
uploadFolder.mkdirs();
}
// 같은날 같은 이미지 업로드 시 파일 중복 방지 시작 /////
// java.util.UUID => 랜덤값 생성
UUID uuid = UUID.randomUUID();
// 원래의 파일 이름과 구분하기 위해 _를 붙임(asdfasdfsdfa_개똥이.jpg)
fileName = uuid.toString() + "_" + fileName;
// 같은날 같은 이미지 업로드 시 파일 중복 방지 끝 /////
// File객체 설계(복사할 대상 경로, 파일명)
// C:\\upload\\2024\\08\\06 + "\\" + asdfafds_개똥이.jpg
File saveFile = new File(uploadFolder, fileName);
try {
// 파일객체.transferTo(설계)
multipartFile.transferTo(saveFile);
// 썸네일 처리
// 이미지인지 체킹
// C:\\upload\\2024\\08\\06 + "\\" + s_asffasd_개똥이.jpg
if (checkImageType(saveFile)) {// 이미지라면
// 계획
FileOutputStream thumbnail = new FileOutputStream(new File(uploadFolder, "s_" + fileName));
// 썸네일 생성(파일객체,계획,가로크기,세로크기)
Thumbnailator.createThumbnail(multipartFile.getInputStream(), thumbnail, 100, 100);
thumbnail.close();
}
FileGroupVO fgvo = new FileGroupVO();
// File_group 테이블에 insert
// selectkey에서 받은 fileGroupNo가 fgvo값에 들어옴
result += this.mapper.insertFileGroup(fgvo);
FileDetailVO fdvo = new FileDetailVO();
int i = 1;
fdvo.setFileSn(i++);
fdvo.setFileGroupNo(fgvo.getFileGroupNo());
fdvo.setFileOriginalName(multipartFile.getOriginalFilename());
fdvo.setFileSaveName(fileName);
fdvo.setFileSaveLocate("/upload/"+getFolder().replace("\\", "/")+"/"+fileName); // 웹경로+uuid_파일명
fdvo.setFileSize(size);
fdvo.setFileExt(fileName.substring(fileName.lastIndexOf(".")+1));
fdvo.setFileMime(contentType);
// 팬시 크기
fdvo.setFileFancysize("0");
result+= this.mapper.insertFileDetail(fdvo);
// member테이블 업데이트
memberVO.setFileGroupNo(fgvo.getFileGroupNo());
result+=this.memMapper.updateMember(memberVO);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
// 연 / 월 / 일 폴더 생성
public String getFolder() {
// 2024-08-06 형식(format)지정
// 간단한 날짜 형식
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date today = new Date();
String str = sdf.format(today);
// 2024-08-06 > 2024\\08\\06
return str.replace("-", File.separator);
}
public boolean checkImageType(File file) {
// MIME(Multipurpose Internet Mail Extensions) : 문서, 파일 또는 바이트 집합의 성격과 형식. 표준화
// MIME 타입 알아냄. .jpeg / .jpg의 MIME타입 : image/jpeg
String contentType;
try {
contentType = Files.probeContentType(file.toPath());
// image로 시작
return contentType.startsWith("image");
} catch (Exception e) {
log.error(e.getMessage());
}
return false;
}
@Override
public MemberVO getMemberFile(MemberVO memberVO) {
return this.memMapper.getMemberFile(memberVO);
}
}
Mybatis
member_SQL.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.MemberMapper">
<update id="updateMember" parameterType="memVo">
update member
set file_group_no = #{fileGroupNo},
mem_name = #{memName},
mem_regNo1 = #{memRegno1}
where mem_id=#{memId}
</update>
<resultMap type="memVo" id="memberMap">
<result property="memId" column="MEM_ID"/>
<result property="memPass" column="MEM_PASS"/>
<result property="memName" column="MEM_NAME"/>
<result property="memRegno1" column="MEM_REGNO1"/>
<result property="memRegno2" column="MEM_REGNO2"/>
<result property="memBir" column="MEM_BIR"/>
<result property="memZip" column="MEM_ZIP"/>
<result property="memAdd1" column="MEM_ADD1"/>
<result property="memAdd2" column="MEM_ADD2"/>
<result property="memHometel" column="MEM_HOMETEL"/>
<result property="memComtel" column="MEM_COMTEL"/>
<result property="memHp" column="MEM_HP"/>
<result property="memMail" column="MEM_MAIL"/>
<result property="memJob" column="MEM_JOB"/>
<result property="memLike" column="MEM_LIKE"/>
<result property="memMemorial" column="MEM_MEMORIAL"/>
<result property="memMemorialday" column="MEM_MEMORIALDAY"/>
<result property="memMileage" column="MEM_MILEAGE"/>
<result property="memDelete" column="MEM_DELETE"/>
<result property="fileGroupNo" column="FILE_GROUP_NO" />
<association property="fgvo" resultMap="fileGroupMap"></association>
</resultMap>
<resultMap type="fileGroupVo" id="fileGroupMap">
<result property="fileGroupNo" column="FILE_GROUP_NO"/>
<result property="fileRegdate" column="FILE_REGDATE"/>
<association property="fileDetailVoList" resultMap="fileDetailMap"></association>
</resultMap>
<resultMap type="fileDetailVo" id="fileDetailMap">
<result property="fileSn" column="FILE_SN"/>
<result property="fileGroupNo" column="FILE_GROUP_NO"/>
<result property="fileOriginalName" column="FILE_ORIGINAL_NAME"/>
<result property="fileSaveName" column="FILE_SAVE_NAME"/>
<result property="fileSaveLocate" column="FILE_SAVE_LOCATE"/>
<result property="fileSize" column="FILE_SIZE"/>
<result property="fileExt" column="FILE_EXT"/>
<result property="fileMime" column="FILE_MIME"/>
<result property="fileFancysize" column="FILE_FANCYSIZE"/>
<result property="fileSaveDate" column="FILE_SAVE_DATE"/>
<result property="fileDowncount" column="FILE_DOWNCOUNT"/>
</resultMap>
<select id="getMemberFile" resultMap="memberMap" parameterType="memVo">
SELECT A.MEM_ID, A.MEM_PASS, A.MEM_NAME, A.MEM_REGNO1, A.MEM_REGNO2
, A.MEM_BIR, A.MEM_ZIP, A.MEM_ADD1, A.MEM_ADD2, A.MEM_HOMETEL
, A.MEM_COMTEL, A.MEM_HP, A.MEM_MAIL, A.MEM_JOB, A.MEM_LIKE
, A.MEM_MEMORIAL, A.MEM_MEMORIALDAY, A.MEM_MILEAGE, A.MEM_DELETE
, A.FILE_GROUP_NO
, B.FILE_GROUP_NO, B.FILE_REGDATE
, C.FILE_SN, C.FILE_GROUP_NO, C.FILE_ORIGINAL_NAME
, C.FILE_SAVE_NAME, C.FILE_SAVE_LOCATE, C.FILE_SIZE
, C.FILE_EXT, C.FILE_MIME, C.FILE_FANCYSIZE
, C.FILE_SAVE_DATE, C.FILE_DOWNCOUNT
FROM MEMBER A LEFT OUTER JOIN FILE_GROUP B ON(A.FILE_GROUP_NO = B.FILE_GROUP_NO)
LEFT OUTER JOIN FILE_DETAIL C ON(B.FILE_GROUP_NO = C.FILE_GROUP_NO)
WHERE A.MEM_ID = #{memId}
</select>
</mapper>
'Spring' 카테고리의 다른 글
[Spring] prod mapper로 변경 + 상품 추가 (0) | 2024.08.07 |
---|---|
[Spring] sql delete한 데이터 불러오기 (0) | 2024.08.07 |
[Spring] mapper interface (0) | 2024.08.06 |
[Spring] 스프링 form 태그, 이미지 저장(썸네일) (0) | 2024.08.05 |
[Spring] 파일 업로드 구현 (0) | 2024.08.05 |