본문 바로가기
개발 공부 Today I Learned

[국비 64일차 TIL] 이메일, 파일 업로드, 이미지 갤러리

by 개발자신입 2024. 2. 23.
반응형

 

 

 

* 제작 순서

  1. 메뉴 작업 
  2. 컨트롤러에 추가 또는 생성
  3. jsp 연결
  4. 화면 구성
  5. db로 보낼거면 service - repository - mybatis

 


이메일 


menu.jsp 

메뉴에 ./mail 추가

		<div class="collapse navbar-collapse" id="navbarResponsive">
				<ul class="navbar-nav text-uppercase ms-auto py-4 py-lg-0">
					<li class="nav-item"><a class="nav-link" href="./board">게시판</a></li>
					<li class="nav-item"><a class="nav-link" href="./mail">메일</a></li>
					<li class="nav-item"><a class="nav-link" href="./notice">공지사항</a></li>
					<c:choose>
						<c:when test="${sessionScope.mid ne null }">
							<li class="nav-item"><a class="nav-link" href="./myInfo@${sessionScope.mid }">${sessionScope.mname } 님</a></li>
							<li class="nav-item"><a class="nav-link" href="./logout">로그아웃</a></li>
						</c:when>
						<c:otherwise>
							<li class="nav-item"><a class="nav-link" href="./login">로그인</a></li>
						</c:otherwise>
					</c:choose>
					
				</ul>
			</div>

 

MailController.java

메일 컨트롤러 새로 생성해주기.

@Controller
public class MailController {
	
	@GetMapping("/mail")
	public String mail() {
		// 로그인 한 사용자만 접근 가능
		return "mail";
	}

 

mail.jsp

메일보내기 form 만들기

	<!-- 메일 보내기 -->
	<section class="container">
		<div class="row justify-content-center">
			<div class="col-md-6">
				<h2>비밀번호 찾기 인증번호 발송</h2>
				<form action="/mail" method="post">
					<div class="mb-3">
						<label for="email" class="form-label">받는 사람</label>
                        <input type="email" class="form-control" id="email" name="email" placeholder="youremail@example.com">
					</div>
					<div class="mb-3">
						<label for="title" class="form-label">제목</label>
                        <input type="text" class="form-control" id="title" name="title" placeholder="메일 제목을 입력하세요">
					</div>
					<div class="mb-3">
						<label for="content" class="form-label">본문</label>
                        <textarea class="form-control" id="content" name="content" rows="4" placeholder="메일 내용을 입력하세요"></textarea>
					</div>
					<button type="submit" class="btn btn-primary">전송</button>
				</form>
			</div>
		</div>
	</section>

메일 보내기 form

mail.jsp 기본 폼

	<section class="page-section" id="mail">
		<div class="container d-flex justify-content-center">
			<div class="text-center">
				<form action="/mail" method="post">
					받는 사람<input type="email" name="email">
					제목 : <input type="text" name="title">
					본문 : <textarea name="content"></textarea>
					<button type="submit">전송</button>
				</form>
			</div>
		</div>
	</section>

 

MailController.java

* post 추가
** 순서 : jsp -> controller -> service에서 메일 발송 (db로 갈 필요가 없음. 서비스까지만 감)

	@PostMapping("/mail")
	public String mail(@RequestParam("email") String email, 
			@RequestParam("title") String title, 
			@RequestParam("content") String content) {

		// 값이 제대로 오는지 확인
		System.out.println("email : " + email);
		System.out.println("title : " + title);
		System.out.println("content : " + content);

		return "redirect:/mail";
	}

 

-> 3개 값을 서비스에 보내서 작동시키기

-> MailService.java 파일 생성

-> 컨트롤러에도 연결하기

 

MailController.java

메일 서비스의 Autowired 생성
서비스에 있는 sendMail에게 일 시킴~

	@Autowired
	private MailService mailService;
	
	@PostMapping("/mail")
	public String mail(@RequestParam("email") String email, 
			@RequestParam("title") String title, 
			@RequestParam("content") String content) {
		
		mailService.sendMail(email, title, content);
		
		return "redirect:/mail";
	}

 

-> sendMail 생성 (MailService에 생성하기)

 

MailService.java

@Service
public class MailService {

	// 메일 보내기 (메일만 보내고 끝남 = void)
	public void sendTextMail(String email, String title, String content) throws EmailException  {
		String emailAddr = "----@outlook.kr"; // 보내는 사람 (outlook.kr)
		String name = "15번"; // 보내는 사람 이름
		String pw = ""; // 보내는 사람 pw
		String host = "smtp-mail.outlook.com";
		int port = 587;
		
		SimpleEmail mail = new SimpleEmail();  // 전송할 메인
		mail.setCharset("UTF-8");
		mail.setDebug(true);
		mail.setHostName(host); // 보내는 서버 설정 = 고정
		mail.setAuthentication(emailAddr, pw); // 보내는 사람 인증 = 고정
		mail.setSmtpPort(port); // 사용할 port번호
		mail.setStartTLSEnabled(true); // 인증방법 = 고정
		mail.setFrom(emailAddr, name); // throws (컨트롤러에서도 throws 필요함)
		mail.addTo(email); // 받는사람
		mail.setSubject(title); // 제목
		mail.setMsg(content); // 내용 text
		mail.send();
	}
}

 

-> 홈페이지의 메일 페이지에 가서 직접 이메일, 제목, 내용을 써서 발송하면 메일이 전송됨 

-> public void sendMail을 sendTextMail로 변경

 

MailController.java

		mailService.sendTextMail(email, title, content);
		mailService.sendHTMLMail(email, title, content);

 

-> sendHTMLMail 생성 (MailService)

 

MailService.java

	public void sendHTMLMail(String email, String title, String content) throws EmailException {
		String emailAddr = "-----@outlook.kr"; // 보내는 사람 (outlook.kr)
		String name = "15번"; // 보내는 사람 이름
		String pw = "-----"; // 보내는 사람 pw
		String host = "smtp-mail.outlook.com";
		int port = 587;
		
		HtmlEmail mail = new HtmlEmail();
		mail.setCharset("UTF-8");
		mail.setDebug(true);
		mail.setHostName(host); // 보내는 서버 설정 = 고정
		mail.setAuthentication(emailAddr, pw); // 보내는 사람 인증 = 고정
		mail.setSmtpPort(port); // 사용할 port번호
		mail.setStartTLSEnabled(true); // 인증방법 = 고정
		mail.setFrom(emailAddr, name); // throws (컨트롤러에서도 throws 필요함)
		mail.addTo(email); // 받는사람
		mail.setSubject(title); // 제목
		mail.setMsg(content); // 내용 text

		// 첨부파일
		EmailAttachment file = new EmailAttachment();
		file.setPath("c:\\temp\\img.png"); // 메일에 이 파일을 첨부해서 전송
		mail.attach(file);
		
		mail.send();
	}
}

 


이미지 게시판 만들기 (파일 업로드)


menu.jsp

<li class="nav-item"><a class="nav-link" href="./file">파일</a></li>

 

FileController.java 

@Controller
public class FileController {
	
	@GetMapping("/file")
	public String file() {
		return "file";
	}
}

file.jsp

	<!-- 파일 업로드 -->
	<section class="page-section" id="my-info">
		<div class="container d-flex justify-content-center">
			<div class="text-center">
				<form action="./file" method="post" enctype="multipart/form-data">
				<div class="input-group">
					<input type="file" class="form-control" name="file1" id="inputGroupFile04" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
					<button class="btn btn-outline-secondary" type="submit"	id="inputGroupFileAddon04">Button</button>
				</div>
				</form>
			</div>
		</div>
	</section>

 

FileController.java

파일 업로드하면 콘솔에 찍히는지 확인

@Controller
public class FileController {
	
	@GetMapping("/file")
	public String file() {
		return "file";
	}
	
	@PostMapping("file")
	public String file(@RequestParam("file1") MultipartFile upFile) {
		System.out.println("파일 이름 : " + upFile.getOriginalFilename());
		System.out.println("파일 사이즈 : " + upFile.getSize());
		System.out.println("파일 타입 : " + upFile.getContentType());
		
		return "redirect:/file";
	}
}

 

servlet-context.xml

기존의 db-context.xml을 *로 변경

<beans:import resource="classpath:/spring/*-context.xml" />

 

 

file-context.xml

db-context.xml 복사해서 생성

   <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" 
         id="multipartResolver">
      <property name="defaultEncoding" value="UTF-8"/>
      <property name="maxUploadSizePerFile" value="52428800"/>
      <property name="maxUploadSize" value="104857600"/>
   </bean>
   
</beans>

FileController.java

	@PostMapping("file")
	public String file(@RequestParam("file1") MultipartFile upFile) {
		
		// 진짜 업로드 저장
		File f = new File("c:\\temp\\upfile", upFile.getOriginalFilename()); // "경로", "파일명"
		try {
			upFile.transferTo(f);
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return "redirect:/file";
	}

 

file.jsp

- 이미지 파일만 올리도록 확장자 막는 방법 : input에 accept="image/png, image/jpg" 또는 "image/*

          <div class="card-body">
            <div class="mb-3">
              <input type="file" accept="image/*" class="form-control" id="file1" name="file1">
            </div>

 

FilController.java

UUID(Universally Unique Identifier)
진짜 업로드 저장할 때 File f의 파일명에 newFileName 로 변경.

		// UUID 생성 (Universally Unique Identifier)
		UUID uuid = UUID.randomUUID();
		System.out.println("UUID : " + uuid);
		String newFileName = uuid.toString() + "-" + upFile.getOriginalFilename();
		System.out.println("새로 만들어진 파일명 : " + newFileName);
		
		// 진짜 업로드 저장
		File f = new File("c:\\temp\\upfile", newFileName); // "경로", "파일명"
		try {
			upFile.transferTo(f);
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return "redirect:/file";
	}
}

 

pom.xml

썸네일 만들기 : thumbnailator 코드 추가

<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.20</version>
</dependency>

 

FileController.java

-> 총 2개 파일 생성:  업로드한 파일 + s_ 붙은 썸네일(100x100) 파일도 생성됨. 

			// 썸네일 만들기 (파일명 앞에 s_ 붙이도록)
			FileOutputStream thumbnail = new FileOutputStream(new File("c:\\temp\\upfile", "s_"+newFileName));
			Thumbnailator.createThumbnail(upFile.getInputStream(), thumbnail, 100, 100);
			thumbnail.close();
			
			upFile.transferTo(f);

 

upfile 폴더 생성

webapp - resources - upfile 폴더 생성하기

 

servlet-context.xml 

<resources mapping="/assets/upfile/**" location="/resources/assets/upfile/" />

 

FileController.java

		// 경로
		String root = request.getSession().getServletContext().getRealPath("/");
		System.out.println("upfileURL : " + root);
		String upfile = root + "upfile/";
		System.out.println("upfile : " + upfile);

 

-> File f = new File의 경로를 upfile로 변경

 		// 진짜 업로드 저장
		File f = new File(upfile, newFileName); // "경로", "파일명"

 

< FileController.java 전체코드 >

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import net.coobird.thumbnailator.Thumbnailator;

@Controller
public class FileController {
	
	@GetMapping("/file")
	public String file() {
		return "file";
	}
	
	@PostMapping("file")
	public String file(@RequestParam("file1") MultipartFile upFile, HttpServletRequest request) {
		System.out.println("파일 이름 : " + upFile.getOriginalFilename());
		System.out.println("파일 사이즈 : " + upFile.getSize());
		System.out.println("파일 타입 : " + upFile.getContentType());
		
		// 경로
		String root = request.getSession().getServletContext().getRealPath("/");
		System.out.println("upfileURL : " + root);
		String upfile = root + "resources/upfile/";
		System.out.println("upfile : " + upfile);
		
//		upfileURL : C:\workspace-spring\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\feb15\
//		upfile : C:\workspace-spring\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\feb15\resources/upfile/

		
		// UUID 생성 (Universally Unique Identifier)
		UUID uuid = UUID.randomUUID();
		System.out.println("UUID : " + uuid);
		String newFileName = uuid.toString() + "-" + upFile.getOriginalFilename();
		System.out.println("새로 만들어진 파일명 : " + newFileName);
		
		// 진짜 업로드 저장
		File f = new File(upfile, newFileName); // "경로", "파일명"
		try {
			// 썸네일 만들기 (파일명 앞에 s_ 붙이도록)
			FileOutputStream thumbnail = new FileOutputStream(new File("c:\\temp\\upfile", "s_"+newFileName));
			Thumbnailator.createThumbnail(upFile.getInputStream(), thumbnail, 100, 100);
			thumbnail.close();
			
			upFile.transferTo(f); // 실제 저장
			
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return "redirect:/file";
	}
}

 

file.jsp

-> form에  onsubmit="fileCheck()" 추가하기

<form action="./file" method="post" enctype="multipart/form-data" onsubmit="fileCheck()">


-> fileCheck() function 생성 (var는 let으로 대체 가능, let이 더 나음)

<script type="text/javascript">
function fileCheck(){
	var fileVal = $("#file").val();
	if(fileVal == ""){
		alert('파일을 선택하세요.');
		return false;
	} else {
		var ext = fileVal.split('.').pop().toLowerCase();
		// 아래 확장자가 있는지 확인
		if($.inArray(ext, ['jpg','jpeg','gif','png']) == -1) {
			alert('jpg, gif, jpeg, png 파일만 업로드 할 수 있습니다.');
			return false;
		}
	}
}

</script>

파일 업로드 폼

 

파일을 업로드하면 upfile 폴더에 들어감

 


갤러리 만들기


menu.jsp

<li class="nav-item"><a class="nav-link" href="./gallery">갤러리</a></li>

GalleryController.java

@Controller
public class GalleryController {

	@GetMapping("/gallery")
	public String gallery() {
		return "gallery";
	}

	@GetMapping("/galleryInsert")
	public String galleryInsert() {
		return "galleryInsert";
	}

	@PostMapping("/galleryInsert")
	public String galleryInsert(GalleryDTO dto) {
		return "redirect:/gallery";
	}
	
}

GalleryDTO.java

import lombok.Data;

@Data
public class GalleryDTO {
	private int gno, gcount, glike, gdel;
	private String gtitle, gcontent, gfile, gthumbnail, gdate;
}

db 테이블 생성

CREATE TABLE gallery (
    gno INT AUTO_INCREMENT PRIMARY KEY,
    glike INT,
    gdel INT,
    gtitle VARCHAR(255),
    gcontent TEXT,
    gfile VARCHAR(255),
    gdate TIMESTAMP,
    mno INT,
);

 

세부 조건들은 아래의 이미지와 맞추기.

gallery table

 

GalleryDAO.java

@Repository
public class GalleryDAO {

	@Autowired
	private SqlSession sqlSession;
	
	public int galleryInsert(GalleryDTO dto) {
		return sqlSession.insert("gallery.galleryInsert", dto);
	}
}

GalleryService.java

@Service
public class GalleryService {

	@Autowired
	private GalleryDAO galleryDAO;
	
	@Autowired
	private Util util;
	
	public int galleryInsert(GalleryDTO dto) {
		if(util.getSession().getAttribute("mid") != null) {
			dto.setMid((String) util.getSession().getAttribute("mid"));
			return galleryDAO.galleryInsert(dto);
			
		} else {
			return 0;
		}
	}
}

GalleryController.java

	@Autowired
	private GalleryService galleryService;



	@PostMapping("/galleryInsert")
	public String galleryInsert(GalleryDTO dto) {
		int result = galleryService.galleryInsert(dto);
		return "redirect:/gallery";
	}

gallery-mapper.xml

<mapper namespace="gallery">

	<insert id="galleryInsert" parameterType="galleryDTO"> <!--  -->
		INSERT INTO gallery (gtitle, gcontent, mno) 
		VALUES (#{gtitle}, #{gcontent}, #{mid})
	</insert>

</mapper>

mybatis-config.xml

<typeAlias type="org.-----.dto.GalleryDTO" alias="galleryDTO"/>

 

jsp 파일 생성

gallery (이미지 리스트) / galleryInsert (실제 업로드 화면)

 

GalleryController.java

	@Autowired
	private Util util;



	@PostMapping("/galleryInsert")
	public String galleryInsert(GalleryDTO dto, @RequestParam("file1") MultipartFile upFile) {
		System.out.println(dto.getGtitle());
		System.out.println(dto.getGcontent());
		System.out.println(upFile.getOriginalFilename());
		dto.setGfile(upFile.getOriginalFilename());
		
		// 파일 업로드 -> util
		String newFileName = util.fileUpload(upFile);
		
		dto.setGfile(newFileName);  // UUID
		
		
		int result = galleryService.galleryInsert(dto);
		return "redirect:/gallery";
	}
	
}

 

gallery-mapper.xml

	<insert id="galleryInsert" parameterType="galleryDTO"> <!-- -->
		INSERT INTO gallery
		(gtitle, gcontent, gfile, mno) VALUES
		(#{gtitle}, #{gcontent}, #{gfile}, (SELECT mno FROM member WHERE mid=#{mid}))
	</insert>

 

Util.java

-> fileUpload 생성 (util)

	public String fileUpload(MultipartFile upFile) {
	    // 경로저장
	    String root = req().getSession().getServletContext().getRealPath("/");
	    String upfilePath = root + "resources\\upfile\\";

	    // UUID 뽑기
	    UUID uuid = UUID.randomUUID();

	    // UUID를 포함한 파일명
	    String newFileName = uuid.toString() + upFile.getOriginalFilename();

	    // 실제 업로드
	    File file = new File(upfilePath, newFileName);
	    try {
	        upFile.transferTo(file);
	    } catch (IllegalStateException | IOException e) {
	        e.printStackTrace();
	    }

	    return newFileName;
	}

}

 

=> 로그인을 해야지 업로드가 되고 db에 저장이 됨.

 

Util.java

file.mkdirs(); 코드 추가

	    // 실제 업로드
	    File file = new File(upfilePath, newFileName);

	    if(file.exists() == false) {
	    	file.mkdirs(); // 경로가 없다면 다 만들어주기.
	    }

	    try {
	    	FileOutputStream thumbnail = new FileOutputStream(new File(upfilePath, "s_"+newFileName)); // 경로, s_붙인 파일명
	    	Thumbnailator.createThumbnail(upFile.getInputStream(), thumbnail, 100, 100);
	    	thumbnail.close();
	        upFile.transferTo(file);
	    } catch (IllegalStateException | IOException e) {
	        e.printStackTrace();
	    }

 

-> 업로드한 이미지 화면에 띄우기

 

GalleryController.java

@Controller
public class GalleryController {
	
	@Autowired
	private GalleryService galleryService;
	
	@Autowired
	private Util util;

	@GetMapping("/gallery")
	public String gallery(Model model) {
		List<GalleryDTO> list = galleryService.galleryList();
		model.addAttribute("list",list);
		return "gallery";
	}

 

-> galleryList() 생성 : GalleryService, GalleryDAO

 

GalleryService.java

	public List<GalleryDTO> galleryList() {
		return galleryDAO.galleryList();
	}

GalleryDAO

	public List<GalleryDTO> galleryList() {
		return sqlSession.selectList("gallery.galleryList");
	}

gallery-mapper.xml

	<select id="galleryList" resultType="galleryDTO">
		SELECT * FROM gallery
	</select>

gallery.jsp

<script type="text/javascript">
function fileCheck(){
	location.href = './galleryInsert';
	return false; // form의 실제 submit 동작 방지
}
</script>


	<section class="page-section" id="gallery">
		<div class="container d-flex justify-content-center">
			<div class="col-md-6">
				<table>
					<thead>
					<tr>
						<th>번호</th>
						<th>제목</th>
						<th>이미지</th>
						<th>등록일</th>
						<th>좋아요</th>
					</tr>
					</thead>
					<tbody>
					<c:forEach items="${list }" var="row">
						<tr>
							<td>${row.gno }</td>
							<td>${row.gtitle }</td>
							<td>
								<img alt="thumbnail" src="./resources/upfile/s_${row.gfile }">
							</td>
							<td>${row.gdate }</td>
							<td>${row.glike }</td>
						</tr>
					</c:forEach>
					</tbody>
				</table>
				<div class="d-flex justify-content-end">
					<button type="submit" class="btn btn-primary btn-lg" onclick="location.href='./galleryInsert'">글쓰기</button>
				</div>
			</div>
		</div>
	</section>

 

이미지 갤러리 (미완성)

galleryInsert.jsp

	<!-- 갤러리 업로드 폼 -->
	<section class="page-section" id="gallery">
		<div class="container d-flex justify-content-center">
			<div class="col-md-6">
				<h2 class="text-center mb-4 mt-4">갤러리</h2>
				<form action="/galleryInsert" method="post"
					enctype="multipart/form-data" id="galleryForm">
					<div class="mb-3">
						<label for="gtitle" class="form-label">제목</label> <input
							type="text" class="form-control" id="gtitle" name="gtitle">
					</div>
					<div class="mb-3">
						<label for="gcontent" class="form-label">본문</label>
						<textarea class="form-control" id="gcontent" name="gcontent"
							rows="4" placeholder="내용을 입력하세요"></textarea>
					</div>
					<div class="mb-3">
						<label for="file1" class="form-label">이미지 업로드</label> <input
							type="file" accept="image/*" class="form-control" id="file1"
							name="file1">
					</div>
					<div class="d-flex justify-content-end">
						<button type="submit" class="btn btn-primary"
							onclick="fileCheck()">전송</button>
					</div>
				</form>
			</div>
		</div>
	</section>

이미지 업로드 화면

 

반응형

댓글