개발환경

  • MacBook Air (M1, 2020)
  • OpenJDK 8
  • Eclipse 2021-12
  • tomcat 8.5
  • MySQL Workbench 8.0.19


기간

  • 2022.3.4 ~ 2022.4.6


주제

  • 웹 백엔드 수업 중 중간 과제로 개인 프로젝트를 진행하게 되었다.
  • 회원가입/로그인/탈퇴 등 기본적인 회원관리 시스템을 가진 웹 사이트를 만드는 것이다. 주어진 기한은 한 달
  • 나는 다음 카페를 소규모로 만들어 보기로 했다. 평소 자주 이용하기도 했고 과제의 평가 기준에서 요구하는 기능들을 다 담고 있기도 했기 때문에 이번 기회에 구현해 보면 그동안 배운 것들을 활용하기에 좋을 거 같았다.
  • 평가 기준에 사이트의 디자인 구현(HTML/CSS 등 프론트엔드)은 포함되지 않기 때문에 본인이 쓰고 싶은 HTML/CSS 템플릿을 구한 뒤 회원 관리 기능을 구현하면 된다.


진행상황

  • 사이트 관리자에게 메일을 보낼 수 있는 기능을 만들었다.
  • 자바 메일 API를 사용했다.
  • JSP 2.3 & Servlet 3.1 책을 참고했다.

자바 메일 API 추가

  • javax.mail.jar - javax.mail.jar만 다운로드 후 WEB-INF/lib에 넣으면 된다.
  • actication.jar - 여기서 jaf-1_1_1.zip 다운로드 후 압축 풀어서 activation.jar 파일만 WEB-INF/lib에 넣으면 된다.

contactUs.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">

<!-- Start Head -->
  <jsp:include page="../inc/top.jsp"></jsp:include>
  <script src="${pageContext.request.contextPath }/js/contactUs.js"></script>
<!-- End Head -->

<body class="modern">

<!--
START MODULE AREA 2: Menu 1
-->
  <jsp:include page="../inc/subTop.jsp"></jsp:include>
<!--
END MODULE AREA 2: Menu 1
-->

<!--
START MODULE AREA 3: Sub Navigation 1
-->
<section>
  <div data-layout="_r">
    <!-- <div data-layout="de6 ec5 ec-n3">
      <p></p>
    </div> -->
    <div data-layout="de10 ec-half">
      <h3>Contact us</h3>
      <form name="mail" action="./SendMailAction.bo" method="post" onsubmit="return finalCheck();">
        <div class="formRow">
          <label for="MOD_TEXTFORM_NameField">이름 </label><input id="MOD_TEXTFORM_NameField" type="text" name="name">
        </div>
        <div id="nameMsg"></div>
        <div class="formRow">
          <label for="MOD_TEXTFORM_EmailField">답변 받을 이메일 </label><input id="MOD_TEXTFORM_EmailField" type="email" name="email">
        </div>
        <div id="emailMsg"></div>
        <div class="formRow">
          <label for="MOD_TEXTFORM_TelField">제목 </label><input id="MOD_TEXTFORM_TelField" type="tel" name="title">
        </div>
        <div id="titleMsg"></div>
        <div class="formRow">
          <label for="MOD_TEXTFORM_MsgField">내용 </label><textarea id="MOD_TEXTFORM_MsgField" placeholder="내용을 입력하세요..." name="content"></textarea>
        </div>
        <div id></div>
        <button type="submit" class="btn">보내기</button>
      </form>
    </div>
  </div>
</section>
<!--
END MODULE AREA 3: Sub Navigation 1
-->

<!--
START MODULE AREA 5: Footer 2
-->
  <jsp:include page="../inc/bottom.jsp"></jsp:include>
<!--
END MODULE AREA 5: Footer 2
-->

<script src="${pageContext.request.contextPath }/js/index.js"></script>
</body>

</html>
  • 폼태그를 이용해 입력한 정보들을 서블릿으로 전송한다.

contactUs.js

function finalCheck()
{
    var mail = document.mail;
	
    if (mail.name.value.length <= 0)
    {
        alert('이름을 입력하세요!');
        mail.name.focus();
        return false;
    }
	
    if (mail.email.value.length <= 0)
    {
        alert('연락 받을 이메일을 입력하세요!');
        mail.email.focus();
        return false;
    }
	
    if (mail.title.value.length <= 0)
    {
        alert('제목을 입력하세요!');
        mail.title.focus();
        return false;
    }
	
    if (mail.content.value.length <= 0)
    {
        alert('내용을 입력하세요!');
        mail.content.focus();
        return false;
    }
}
  • 메일을 보내기 전 모든 필드가 입력되었는지 확인 후 모든 분기가 true일 때에만 서블릿으로 이동한다.

BoardFrontController.java

package com.project.cafe.board.action;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.project.cafe.action.Action;
import com.project.cafe.action.ActionForward;

public class BoardFrontController extends HttpServlet
{
    protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    {
        // 1. 전달되는 가상주소 계산
        // .. 생략
		
        // 2. 가상주소 매핑
        Action action = null;
        ActionForward forward = null;
		
        // .. 생략
        else if (command.equals("/SendMailAction.bo"))
        {
            System.out.println("C : /SendMailAction.bo 호출");
			
            action = new SendMailAction();
			
            try {
                forward = action.execute(request, response);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        // .. 생략
		
        // 3. 페이지 이동
        // .. 생략
    }
 
    // .. 생략
}
  • 컨트롤러에서 메일 전송 동작을 수행할 서블릿으로 연결한다.

SendMailAction.java

package com.project.cafe.board.action;

import java.io.PrintWriter;
import java.util.Date;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.project.cafe.action.Action;
import com.project.cafe.action.ActionForward;

public class SendMailAction implements Action 
{
    @Override
    public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception 
    {
        System.out.println("M : SendMailAction - execute() 호출");
		
        // 한글처리
        request.setCharacterEncoding("utf-8");
		
        // 파라미터 저장
        String sender = request.getParameter("email");
        String receiver = "메일을 받는데 사용할 관리자 메일주소";
        String title = request.getParameter("title");
        String content = request.getParameter("content");
        String name = request.getParameter("name");
		
        StringBuilder sb = new StringBuilder();
        sb.append("이름 : ");
        sb.append(name);
        sb.append("<br>");
        sb.append("메일주소 : ");
        sb.append(sender);
        sb.append("<br>");
        sb.append("내용 : ");
        sb.append(content);
		
        // 메일 보내는 동작 수행
        response.setContentType("text/html; charset=utf-8");
        PrintWriter out = response.getWriter();
		
        try {
            // 서버 정보를 Properies 객체에 저장
            Properties properties = System.getProperties();
			
            // Starttls Command를 사용할 수 있게 설정
            properties.put("mail.smtp.starttls.enable", "true");
			
            // SMTP 서버를 지정
            properties.put("mail.smtp.host", "smtp.gmail.com");
			
            // AUTH command를 사용하여 사용자 인증을 할 수 있게 하는 설정 부분
            properties.put("mail.smtp.auth", "true");
			
            // 서버 포트를 지정하는 부분
            properties.put("mail.smtp.port", "587");
			
            // 인증 정보 생성
            Authenticator auth = new GoogleAuthentication();
			
            // 메일을 전송하는 역할을 하는 단위인 Session 객체 생성
            Session s = Session.getDefaultInstance(properties, auth);
			
            // 생성한 Session 객체를 사용하여 전송할 Message 객체 생성
            Message message = new MimeMessage(s);
			
            // 메일을 송신할 송신 주소 생성
            Address senderAddr = new InternetAddress(sender);
			
            // 메일을 수신할 수신 주소 생성
            Address receiverAddr = new InternetAddress(receiver);
			
            // 메일 전송에 필요한 값들 설정
            message.setHeader("content-type", "text/html; charset=utf-8");
            message.setFrom(senderAddr);
            message.addRecipient(Message.RecipientType.TO, receiverAddr);
            message.setSubject(title);
            message.setContent(sb.toString(), "text/html; charset=utf-8");
            message.setSentDate(new Date());
			
            // 메시지를 메일로 전송
            Transport.send(message);
			
            out.print("<script>");
            out.print("alert('메일이 정상적으로 전송되었습니다.');");
            out.print("location.href='./Contact.bo';");
            out.print("</script>");
        }
        catch (Exception e) {
            out.print("SMTP 서버가 잘못 설정되었거나 서비스에 문제가 있습니다.");
            e.printStackTrace();
        }
		
        return null;
    }
}
  • 받은 메일을 열어볼 때 줄을 바꿔서 보여주기 위해서 <br> 태그를 추가했다.
  • 처음엔 \nSystem.lineSeparator() 등 자바에서 줄을 바꾸는 코드를 썼는데 메일을 받으면 줄이 바뀌지 않아서 한참 찾아 헤멨다.
  • 알고보니 메일이 출력되는 필드도 HTML이라 HTML태그로 줄바꿈을 작성해야 했다. message.setContent(sb.toString(), "text/html; charset=utf-8");이 구문의 "text/html; charset=utf-8"이 힌트였다…
  • 참고글

GoogleAuthentication.java

package com.project.cafe.board.action;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

public class GoogleAuthentication extends Authenticator 
{
    PasswordAuthentication passAuth;
	
    public GoogleAuthentication()
    {
        // 첫번째 인자는 구글 아이디, 두번째는 비밀번호
        passAuth = new PasswordAuthentication("구글아이디", "앱 비밀번호");
    }
	
    public PasswordAuthentication getPasswordAuthentication() {return passAuth;}
}
  • 구글 SMTP를 사용할 것이기 때문에 구글 계정 인증 정보를 받아오는 클래스를 만들었다.
  • 앱 비밀번호는 앱 비밀번호 설정 페이지에서 설정할 수 있다.

  • 이제 메일을 보내보면 작성한 대로 잘 간다! 👏


마감까지

  • D-5