easycode

springboot(Maven 기반)에서 mailAPI 사용하기(클래스 이용) 본문

Spring

springboot(Maven 기반)에서 mailAPI 사용하기(클래스 이용)

ez() 2023. 5. 31. 10:46

파이널 프로젝트를 진행하던 중, 메일 api를 이용하여 사용자에게 임시 비밀번호를 발급하고, 그 임시 비밀번호를 받아와 DB에 업데이트 하는 기능을 만들기로 했다.

 

Intellij 2023.1(Ultimate 버전), Springboot(Maven 기반), 메일은 gmail을 사용하였다.(구글 앱 비밀번호를 설정하는 방법은 따로 설명하지 않겠습니다)

 

1. pom.xml에 의존성(dependency) 추가

<메일 api>

<!--      메일 api -->
      <dependency>
         <groupId>com.sun.mail</groupId>
         <artifactId>javax.mail</artifactId>
         <version>1.6.2</version>
      </dependency>

<랜덤 비밀번호 생성>

<!--      랜덤 비밀번호 생성 -->
      <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
         <version>3.12.0</version>
      </dependency>

나는 랜덤 비밀번호를 생성해주는 의존성까지 추가해줬다.

 

2. MailSender 클래스 추가

랜덤 비밀번호를 생성해서 메일로 보내주는 기능을 하는 클래스를 추가한다. 이 클래스가 메일 api 기능을 한다.

import org.apache.commons.lang3.RandomStringUtils;

//메일 api 기능들
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class MailSender {

    //임시 비밀번호 변수 선언
    static String randompass="";
    
    //임시 비밀번호로 쓸 난수 생성하는 메소드(size에 본인이 원하는 비밀번호의 길이를 쓴다)
    public static String getRamdomPassword(int size) {
        //RandomStringUtils.randomAlphanumeric를 쓰기 위해 위에서 denpendency를 추가해줬다
        String randomPw=RandomStringUtils.randomAlphanumeric(size);
        return randomPw;
    }

    //메일 보내는 함수(파라미터로 받는 사람의 email 주소를 넣어줬다)
    public static void mailSend(String email) {
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.gmail.com");
        props.put("mail.smtp.port", "587");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.ssl.trust", "smtp.gmail.com");

        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("자신의 메일주소(보내는이)", "구글 앱 비밀번호");
            }
        });

        //난수 생성 메소드를 통해 임시 비밀번호를 생성해준다. 본인은 10자로 했다
        randompass=getRamdomPassword(10);
        
        String receiver = email; // 메일 받을 주소
        String title = "메일 제목";
        String content = "<h2 style='color:blue'>"+randompass+"</h2><br>임시 비밀번호입니다.<br>이후 꼭 비밀번호를 변경해주세요.<br>";
        Message message = new MimeMessage(session);
        try {
            message.setFrom(new InternetAddress("자신의 메일주소(보내는이)", "받는 이에게 표시될 이름(예 : 관리자)", "utf-8"));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver));
            message.setSubject(title);
            message.setContent(content, "text/html; charset=utf-8");

            Transport.send(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //발급된 임시 비밀번호를 받아오는 메서드(이후 DB 업데이트를 위해 만들어줬다)
    public static String getRandompass() {
        return randompass;
    }

}

실행 후 콘솔에 따로 결과가 나타나진 않는다.

보낸 결과


 

컨트롤러는 아래와 같이 작성하였다(코드가 너무 더러우니 주의해주세요...)

더보기
 //임시 비밀번호 발급
    @GetMapping("/user/passSearchMailSender")
    @ResponseBody //ajax로 유저의 이메일이 존재하는지 값을 보내야 했기 때문에 사용했다
    public int passSearchMailSender(@RequestParam String email) {
  	//System.out.println(email);
	//유저가 입력한 이메일이 DB에 존재하는지 확인
        int checkEmail=service.isUserEmail(email);
	//System.out.println(checkEmail);
        if(checkEmail==1) { //만약 존재하면
            MailSender.mailSend(email); //유저가 입력한 이메일로 임시 비밀번호를 보낸다
            String randompass=MailSender.getRandompass(); //생성된 임시 비밀번호를 가져온다
	//System.out.println(randompass);
            service.updateTemporarilyPass(randompass,email); //임시 비밀번호를 db에 업데이트 시켜준다.
        }
        return checkEmail;
    }

MailSender 클래스에 컴포넌트를 사용해서 빈으로 등록 후, Autowired로 사용하려고 했는데 아무리 시도해도 메소드가 안불러지는 현상이 있었다. 내가 시도해본 것은

1. MailSender 클래스에 @Component 사용 후, 메소드에 @Bean 붙여주기. 이후 @Autowired로 의존성 주입 후 사용

2. MailSender 클래스에 @ComponentScan 사용, 이후 @Autowired로 의존성 주입 후 사용

3. MailSender 클래스에 1번 적용 후, 패키지를 동일한 곳으로 이동해보기(원래는 더 하위 패키지에 있었다)

    ( -> Application에서 선언한 ComponentScan 패키지 위치는 boot.mvc.* 이었고, MailSender 클래스는 boot.mvc.user.mailApi 패키지에 있었다.)

하지만 셋 다 모두 Autowired 사용 후에 메소드가 불러지지 않아 직접 호출로 쓰긴 했다...

직접 호출을 쓰게 되면 기능 간의 의존성이 심해지므로 좋은 객체 지향 프로그래밍이 아니다. 좋은 객체 지향 프로그래밍이라면, 기능을 유연하게 갈아끼울 수 있어야 하는데 각 기능들 간의 의존성이 높다면 수정을 하기가 힘들어진다.

 

다른 곳에서 원인을 찾아보니 빈 주입한 클래스 내에서 new 로 선언 후 사용해야 한다는데, 나는 해당되지 않아서 다른 방법을 찾아보기로 했다. 다음에 application.yml로 하는 방법을 공부해서 포스팅해봐야겠다.