오늘이라도

[Spring] 10. 웹사이트 만들기 ⑨ : 공지사항에 첨부 파일 기능 추가 본문

취업성공패키지 SW 개발자 교육/Spring

[Spring] 10. 웹사이트 만들기 ⑨ : 공지사항에 첨부 파일 기능 추가

upcake_ 2020. 7. 13. 09:35
반응형

 

https://github.com/upcake/Class_Examples

교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다. 

gif 파일은 클릭해서 보는 것이 정확합니다.


 - 웹사이트 만들기 ⑨ : 공지사항에 첨부 파일 기능 추가 -

▲작동 화면

 

▲생성된 폴더

 

▲업로드된 파일

 

package com.hanul.iot;

import java.util.HashMap;

import javax.servlet.http.HttpSession;

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

import common.CommonService;
import member.MemberServiceImpl;
import member.MemberVO;
import notice.NoticeServiceImpl;
import notice.NoticeVO;

@Controller
public class NoticeController {
	@Autowired private NoticeServiceImpl service;
	@Autowired private MemberServiceImpl member;
	@Autowired private CommonService common;
	
	//공지사항 목록화면 요청
	@RequestMapping("/list.no")
	public String list(Model model, HttpSession session) {
		//공지사항 클릭 하면 admin으로 자동 로그인
		HashMap<String, String> map = new HashMap<String, String>();
		//HashMap : 데이터를 담을 자료 구조
		map.put("id", "admin");
		map.put("pw", "1234");
		session.setAttribute("login_info", member.member_login(map));
		session.setAttribute("category", "no");
		//DB에서 공지 글 목록을 조회해와 목록 화면에 출력
		model.addAttribute("list", service.notice_list());
		
		return "notice/list";
	}
	
	//신규 공지 글 작성 화면 요청
	@RequestMapping("/new.no")
	public String notice() {
		return "notice/new";
	}
	
	//신규 공지 글 저장 처리 요청
	@RequestMapping("/insert.no")
	public String insert(MultipartFile file, NoticeVO vo, HttpSession session) {
		//첨부한 파일을 서버 시스템에 업로드하는 처리
		if( !file.isEmpty() ) {
			vo.setFilepath(common.upload("notice", file, session));
			vo.setFilename(file.getOriginalFilename());
		}
		
		vo.setWriter( ((MemberVO) session.getAttribute("login_info")).getId() );
		//화면에서 입력한 정보를 DB에 저장한 후
		service.notice_insert(vo);
		//목록 화면으로 연결
		return "redirect:list.no";
	}
}

▲NoticeController.java

 

package notice;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class NoticeServiceImpl implements NoticeService {
	@Autowired private NoticeDAO dao;
	
	@Override
	public void notice_insert(NoticeVO vo) {
		dao.notice_insert(vo);
	}

	@Override
	public List<NoticeVO> notice_list() {
		return dao.notice_list();
	}

	@Override
	public NoticeVO notice_detail(int id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void notice_update(NoticeVO vo) {
		// TODO Auto-generated method stub

	}

	@Override
	public void notice_delete(int id) {
		// TODO Auto-generated method stub

	}
}

▲NoticeServiceImpl.java

 

package notice;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class NoticeDAO implements NoticeService {
	@Autowired private SqlSession sql;
	
	@Override
	public void notice_insert(NoticeVO vo) {
		sql.insert("notice.mapper.insert", vo);
	}

	@Override
	public List<NoticeVO> notice_list() {
		return sql.selectList("notice.mapper.list");
	}

	@Override
	public NoticeVO notice_detail(int id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void notice_update(NoticeVO vo) {
		// TODO Auto-generated method stub

	}

	@Override
	public void notice_delete(int id) {
		// TODO Auto-generated method stub

	}

}

▲NoticeDAO.java

 

<?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="notice.mapper" >
	<select id="list" resultType="notice.NoticeVO">
		SELECT ROWNUM no, n.* 
		FROM (SELECT * FROM notice ORDER BY id) n
		ORDER BY no desc
	</select>
	
	<insert id="insert">
		INSERT INTO notice (title, content, writer, filename, filepath)
		VALUES (#{title }, #{content }, #{writer }, #{filename }, #{filepath}) 
	</insert>
</mapper>

▲notice-mapper.xml

 

package notice;

import java.sql.Date;

public class NoticeVO {
	private int id, readcnt, no;
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	private String title, content, writer, filename, filepath;
	private Date writedate;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getReadcnt() {
		return readcnt;
	}
	public void setReadcnt(int readcnt) {
		this.readcnt = readcnt;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getFilename() {
		return filename;
	}
	public void setFilename(String filename) {
		this.filename = filename;
	}
	public String getFilepath() {
		return filepath;
	}
	public void setFilepath(String filepath) {
		this.filepath = filepath;
	}
	public Date getWritedate() {
		return writedate;
	}
	public void setWritedate(Date writedate) {
		this.writedate = writedate;
	}
	
	
}

▲NoticeVO.java

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list JSP</title>
</head>
<body>
<h3>공지사항</h3>

<div id="list-top">
	<div>
		<ul>
			<core:if test="${login_info.admin eq 'Y' }">
				<li><a class="btn-fill" href="new.no">글쓰기</a></li>
			</core:if>
		</ul>
	</div>
</div>

<table>
	<tr>
		<th class="w-px60">번호</th>
		<th>제목</th>
		<th class="w-px100">작성자</th>
		<th class="w-px120">작성일자</th>
		<th class="w-px60">첨부파일</th>
	</tr>
	<core:forEach items="${list }" var="vo">
		<tr>
			<td>${vo. no }</td>
			<td>${vo.title }</td>
			<td>${vo.writer }</td>
			<td>${vo.writedate }</td>
			<td></td>
		</tr>
	</core:forEach>
</table>
</body>
</html>

▲list.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>new JSP</title>
</head>
<body>
<h3>신규 공지 글</h3>
<!-- 
 - 파일 첨부 시 form 반드시 갖고 있어야 할 속성 
	1. 반드시 method는 post이어야만 한다.
	2. enctype을 지정한다. ▶ enctype='multipart/form-data'

-->
<form action="insert.no" method="post" enctype="multipart/form-data">
	<table>
		<tr>
			<th class="w-px160">제목</th>
			<td><input type="text" name="title" class="need"/></td>
		</tr>
		<tr>
			<th>작성자</th>
			<td>${login_info.name }</td>
		</tr>
		<tr>
			<th>내용</th>
			<td><textarea name="content" class="need"></textarea></td>
		</tr>
		<tr>
			<th>파일 첨부</th>
			<td class="left">
				<label>
					<input type="file" name="file" id="attach-file"/>
					<img src='img/select.png' class="file-img" />
				</label>
				<span id="file-name"></span>
				<span id="delete-file" style="color: red; margin-left: 20px;" ><i class="fas fa-times font-img"></i></span>
			</td>
		</tr>
	</table>
</form>
<div class="btnSet">
	<a class="btn-fill" onclick="if(necessary()) $('form').submit()">저장</a>
	<a class="btn-empty" href="list.no">취소</a>
</div>

<script type="text/javascript" src="js/need_check.js"></script>
<script type="text/javascript" src="js/file_attach.js"></script>
</body>
</html>

▲new.jsp

 

@charset "UTF-8";
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap');

body {
	margin: 0 auto;
	text-align: center;
	font-size: 16px;
	font-family: 'Noto Sans KR', sans-serif;
}

a:link, a:visited {
	text-decoration: none;
	color: #000;
}

#content {
	padding: 20px 0;
	min-width: 1024px;	/* 창의 최소 크기 지정 */
}

img {
	vertical-align: middle;	/* 세로축 가운데 정렬 */
}

table {
	width: 80%;
	margin: 0 auto;
	border: 1px solid;
	border-collapse: collapse;	/* 테두리 겹침 설정 collapse: 겹치지 않게 처리 */
}

table th, table td {
	border: 1px solid;
	padding: 5px 10px;
}

table td a:hover { font-weight: bold; }

.btnSet { margin-top: 20px;	}

a.btn-fill, a.btn-empty {
	text-align: center;
	padding: 3px 10px;
	border:1px solid #3367d6;
	border-radius: 3px;
	box-shadow: 2px 2px 3px #022d72;
	/* 오른쪽, 아래쪽, 번진 정도 */
}

a.btn-fill { 
	background-color: #3367d6;
	color: #fff;
}

a.btn-empty { 
	background-color: #fff;
	color: #3367d6
}

a.btn-fill-s, a.btn-empty-s {
	text-align: center;
	padding: 1px 10px;
	border:1px solid #c4dafc
	border-radius: 3px;
	box-shadow: 2px 2px 3px #022d72;
	font-size: 13px;
}

a.btn-fill-s { 
	background-color: #bacdfa;
}

a.btn-empty-s { 
	background-color: #fff;
}

.btnSet a:not(:first-child) {
	margin-left: 3px;
}

a:hover { cursor:pointer; }

input {
	height: 22px;
	padding: 3px 5px;
	font-size: 15px;
}

input[type=radio] {
	width: 18px;
	margin: 0 5px 3px;
	vertical-align: middle;
}

table tr td label:not(:last-child) {
	margin-right: 20px;	
}

.w-pct60 { width: 60% }
.w-pct70 { width: 70% }
.w-pct80 { width: 80% }
.w-px40 { width: 40px }
.w-px60 { width: 60px }
.w-px80 { width: 80px }
.w-px100 { width: 100px }
.w-px120 { width: 120px }
.w-px140 { width: 140px }
.w-px160 { width: 160px }
.w-px180 { width: 180px }
.w-px200 { width: 200px }

.left { text-align: left }
.right { text-align: right }

.font-img { cursor: pointer; }

ul { list-style: none; padding: 0; }
#list-top{ width: 80%; padding: 20px 10%;}
#list-top ul { margin:0; display:flex; }
#list-top ul:last-child { float: right; }
#list-top div { width: 100%;  }
#list-top ul li * { vertical-align:middle; }

input[name=title] { width:calc(100% - 14px) }
textarea[name=content] { width:calc(100% - 6px); height: 150px; resize: none;}

/* 파일 첨부 */
.file-img { width: 18px; height:18px; cursor:poinrter; }
#attach-file, #delete-file { display:none; }

▲common.css

 

/**
 * 첨부파일 관련 처리
 */
 /* 파일을 선택했을 때 파일명이 보이게 처리 */
 $('#attach-file').on('change', function(){
 	$('#file-name').text( this.files[0].name );
 	$('#delete-file').css('display', 'inline');
 });
 $('#delete-file').on('click', function(){
 	$('#file-name').text('');
	$('#delete-file').css('display', 'none');
	$('#attach-file').val('');
 });

▲file_attach.js

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%> <!-- 타일을 사용하기 위한 라이브러리 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${category eq 'cu' ? '고객 관리' : (category eq 'no' ? '공지사항' : (category eq 'bo' ? '방명록' : (category eq 'da' ? '공공 데이터' : (category eq 'join' ? '회원가입' : '') ) ) ) } ${empty category ? '' : ' : ' }IoT</title>
<!-- 브라우저 탭의 작은 아이콘 설정 -->
<link rel="icon" type="image/x-icon" href="img/icon.ico" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.1/js/all.min.js"></script>
<!-- cdnjs.com에서 가져온 fontawesome cdn 라이브러리 -->
<!-- 모든 화면에서 사용하기 위해 join.jsp에 있던 코드를 layout.jsp로 옮겨온다. -->
</head>
<body>
<!-- 각 jsp 파일의 인클루드 단을 없애도 된다. -->
<tiles:insertAttribute name="header" />

<!-- 각 jsp 파일의 div id="content" 부분을 없애도 된다. -->
<div id="content">
	<tiles:insertAttribute name="content" />
</div>

<tiles:insertAttribute name="footer" />
</body>
</html>

▲layout.jsp

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.hanul</groupId>
	<artifactId>iot</artifactId>
	<name>iot</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.8</java-version>
		<org.springframework-version>5.2.2.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>       
		
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<!-- 스프링에서 JDBC를 사용하기 위한 dependency -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>5.2.2.RELEASE</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
		<!-- DBCP dependency -->
		<dependency>
		    <groupId>commons-dbcp</groupId>
		    <artifactId>commons-dbcp</artifactId>
		    <version>1.4</version>
		</dependency>
	
	
		<!-- https://mvnrepository.com/artifact/com.oracle.ojdbc/ojdbc8 -->
		<!-- 오라클용 jdbc ojdbc8 -->
		<dependency>
		    <groupId>com.oracle.ojdbc</groupId>
		    <artifactId>ojdbc8</artifactId>
		    <version>19.3.0.0</version>
		</dependency>
			
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<!-- Mybatis 프레임워크를 사용하기 위한 dependency -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.3</version>
		</dependency>
			
			
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<!-- MyBatis 스프링 dependency -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>2.0.3</version>
		</dependency>
			
		<!-- 화면에 template를 지정하는 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-jsp -->
		<dependency>
		    <groupId>org.apache.tiles</groupId>
		    <artifactId>tiles-jsp</artifactId>
		    <version>3.0.8</version>
		</dependency>

		<!-- boolean 타입 데이터를 문자 타입으로 자동 변환해주는 라이브러리 -->		
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-databind</artifactId>
		    <version>2.11.0</version>
		</dependency>
		
		<!-- 이메일 전송 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email -->
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-email</artifactId>
		    <version>1.5</version>
		</dependency>
		
		<!-- 파일 첨부(업로드) 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
		<dependency>
		    <groupId>commons-fileupload</groupId>
		    <artifactId>commons-fileupload</artifactId>
		    <version>1.4</version>
		</dependency>		
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

▲pom.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<!-- context : 외부 파일을 사용 할 수 있도록 경로를 설정 -->
<context:property-placeholder location="classpath:data/db.properties" />

<!-- 빈을 등록해놓을 설정 파일 -->
<!-- id를 지정하면 다른 빈에서 참조할 수 있음 -->
<bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource">
	<!-- property : 데이터를 담을 필드를 의미 -->
	<property name="driverClassName" value="${db.driver}" />
	<property name="url" value="${db.url}" />
	<property name="username" value="${db.username}" />
	<property name="password" value="${db.password}" />
</bean>

<!-- myBatis 등록하는 빈 -->
<!-- DB연결, 쿼리문 역할 -->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dbcp"></property>
	<property name="mapperLocations" value="classpath:sqlmap/*-mapper.xml"></property>
</bean>

<!-- Setter가 있다면 property로 필드에 데이터를 넣을 수 있지만 (자동 완성 기능으로 확인가능) -->
<!-- Setter가 없다면 생성자를 만들어서 데이터를 넣는다. -->
<bean class="org.mybatis.spring.SqlSessionTemplate">
	<constructor-arg name="sqlSessionFactory"  ref="factory"/>
</bean>

<!-- 파일 업로드 객체 생성 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="defaultEncoding" value="utf-8" />
</bean>
</beans>

▲default.xml

 

package common;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

import javax.servlet.http.HttpSession;

import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class CommonService {
	public void sendEmail(String email, String name, HttpSession session) {
		//1. 기본 이메일 전송 처리
		//sendSimple(email, name);
		
		//2. 첨부 파일 있는 이메일 전송 처리
		//session이 있어야 파일 첨부가 가능
		//sendAttach(email, name, session);
		
		//3. HTML 태그 이메일 전송 처리
		sendHtml(email, name, session);
	};
	
	private void sendSimple(String email, String name) {
		SimpleEmail mail = new SimpleEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("회원가입 축하"); //메일 제목
			mail.setMsg(name + "님! 가입을 축하드립니다!"); //메일 내용
			
			mail.send(); //메일 발송 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void sendAttach(String email, String name, HttpSession session) {
		MultiPartEmail mail = new MultiPartEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("첨부 파일 테스트"); //메일 제목
			mail.setMsg(name + "님! 가입을 축하드립니다!\n 첨부 파일 테스트"); //메일 내용
			
			//파일 첨부하기
			EmailAttachment file = new EmailAttachment();
			
			//① 물리적 디스크내 파일 첨부
			file.setPath("D:\\이력서-자소서-양식.hwp");
			mail.attach(file);
			
			//② 프로젝트 내의 파일 첨부
			file = new EmailAttachment();
			file.setPath(session.getServletContext().getRealPath("resources/images/logo.png"));
			mail.attach(file);
			
			//③ URL을 통해 파일 첨부
			file = new EmailAttachment();
			file.setURL(new URL("https://mvnrepository.com/assets/images/392dffac024b9632664e6f2c0cac6fe5-logo.png"));
			mail.attach(file);
			
			mail.send(); //메일 발송 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void sendHtml(String email, String name, HttpSession session) {
		HtmlEmail mail = new HtmlEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("HTML 메일 테스트");
			
			StringBuffer msg = new StringBuffer();
			msg.append("<html>");
			msg.append("<body>");
			msg.append("<a href='https://mvnrepository.com'><img src='https://mvnrepository.com/assets/images/392dffac024b9632664e6f2c0cac6fe5-logo.png' /></a>");
			msg.append("<hr>");
			msg.append("<h3>HTML 메일 테스트</h3>");
			msg.append("<p>가입을 축하드립니다.</p>");
			msg.append("<p>HTML 메일 테스트</p>");
			msg.append("</body>");
			msg.append("</html>");
			mail.setHtmlMsg(msg.toString());
			
			EmailAttachment file = new EmailAttachment();
			file.setPath(session.getServletContext().getRealPath("resources/css/common.css"));
			mail.attach(file);
			
			file = new EmailAttachment();
			file.setURL(new URL("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"));
			mail.attach(file);
			
			mail.send();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	//첨부 파일 업로드 처리////////////////////////////////////////////////////////
	public String upload(String category, MultipartFile file, HttpSession session) {
		//서버의 업로드할 물리적 위치
		// workspace/.metadata/....../wtpwebapps/iot/resources
		String resources = session.getServletContext().getRealPath("resources");
		String upload = resources + "/upload";
		
		//업로드할 파일의 형태 : .../upload/notice/2020/07/13/abc.txt
		//String folder = upload + "/upload/2020/07/13";
		String folder = upload + "/" + category + "/" + new SimpleDateFormat("yyyy/MM/dd").format(new Date());
		
		//폴더가 없다면 폴더를 생성
		File f = new File(folder);
		if(!f.exists()) { f.mkdirs(); } //폴더가 존재하지 않으면 경로 생성
		
		//동시 다발적 동일명의 파일 업로드를 위한 고유 ID 부여: afd324adfa_abc.txt
		String uuid = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
		try {
			file.transferTo( new File(folder, uuid) );
		} catch (Exception e) {
			System.out.println(e.getMessage());		
		}
		
		// /upload/.../asdfadsfsa_abc.txt ▶ 업로드한 파일의 경로를 반환
		// ① folder.replace(resources, "")
		// ② folder.substring(resources.length()) + "/" + uuid;
		return folder.substring(resources.length()) + "/" + uuid;
	}
}

▲CommonService.java

 

 

 

반응형