[Practice] 메일 전송 (4)

2021. 4. 20. 15:53Spring/Practice

1. 문제

  • 문의 게시판 글에 답변을 달았을 때 메일로 답변 정보를 전송하는 API

 

 

 

2. 풀이

- schema.sql

...

create table BOARD
(
    ID            BIGINT auto_increment primary key,
    CONTENTS      CLOB,
    REG_DATE      TIMESTAMP,
    TITLE         VARCHAR(255),
    BOARD_TYPE_ID BIGINT,
    USER_ID       BIGINT,
    TOP_YN        BOOLEAN DEFAULT FALSE,
    PUBLISH_START_DATE    DATE,
    PUBLISH_END_DATE      DATE,
    REPLY_CONTENTS        CLOB,

    constraint FK_BOARD_BOARD_TYPE_ID foreign key (BOARD_TYPE_ID) references BOARD_TYPE (ID),
    constraint FK_BOARD_USER_ID foreign key (USER_ID) references USER (ID)
);

- data.sql

...

INSERT INTO MAIL_TEMPLATE(ID, TEMPLATE_ID, TITLE, CONTENTS, SEND_EMAIL, SEND_USER_NAME, REG_DATE) VALUES
    (1, 'USER_RESET_PASSWORD', '{USER_NAME}님의 비밀번호 초기화 요청입니다.', '<div><p>{USER_NAME}님 안녕하세요.</p><p>아래 링크를 클릭하여, 비밀번호를 초기화해주세요.</p><p><a href="{SERVER_URL}/reset?key={RESET_PASSWORD_KEY}">초기화</a></p></div>',
    'ozofweird@gmail.com', '관리자', '2021-01-01 01:01:01.000000'),
    (2, 'BOARD_ADD', '{USER_NAME}님이 글을 게시하였습니다.', '<div><p>제목: {BOARD_TITLE}</p><p>내용</p><div>{BOARD_CONTENTS}</div></div>',
    'ozofweird@gmail.com', '관리자', '2021-01-01 01:01:01.000000'),
    (3, 'BOARD_REPLY', '{USER_NAME}님이 글에 답변하였습니다.', '<p>제목: {BOARD_TITLE}</p><p>내용</p><div>{BOARD_CONTENTS}</div><p>답변</p><div>{BOARD_REPLY_CONTENTS}</div></div>',
    'ozofweird@gmail.com', '관리자', '2021-01-01 01:01:01.000000');

- Board.java

package com.example.jpa.sample.board.entity;

import com.example.jpa.sample.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne
    @JoinColumn
    private User user;

    @ManyToOne
    @JoinColumn
    private BoardType boardType;

    @Column
    private String title;

    @Column
    private String contents;

    @Column
    private LocalDateTime regDate;

    @Column
    private boolean topYn;

    @Column
    private LocalDate publishStartDate;

    @Column
    private LocalDate publishEndDate;

    @Column // 답변 내용
    private String replyContents;
}

- BoardReplyInput.java

package com.example.jpa.sample.board.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class BoardReplyInput {

    private String replyContents;
}

- board_reply.html (resource - mail-template)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{USER_NAME}님이 글에 답변하였습니다.</title>
</head>
<body>
<div>
    <p>제목: {BOARD_TITLE}</p>
    <p>내용</p>
    <div>
        {BOARD_CONTENTS}
    </div>
    <p>답변</p>
    <div>{BOARD_REPLY_CONTENTS}</div>
</div>

</body>
</html>

- BoardService.java

package com.example.jpa.sample.board.service;

import com.example.jpa.sample.board.entity.Board;
import com.example.jpa.sample.board.entity.BoardBadReport;
import com.example.jpa.sample.board.entity.BoardComment;
import com.example.jpa.sample.board.entity.BoardType;
import com.example.jpa.sample.board.model.*;

import java.util.List;

public interface BoardService {

    ...

    ServiceResult replyBoard(Long id, BoardReplyInput boardReplyInput);
}

- BoardServiceImpl.java

package com.example.jpa.sample.board.service;

import com.example.jpa.sample.board.entity.*;
import com.example.jpa.sample.board.model.*;
import com.example.jpa.sample.board.repository.*;
import com.example.jpa.sample.common.MailComponent;
import com.example.jpa.sample.common.exception.BizException;
import com.example.jpa.sample.mail.entity.MailTemplate;
import com.example.jpa.sample.mail.repository.MailTemplateRepository;
import com.example.jpa.sample.user.entity.User;
import com.example.jpa.sample.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService {

    private final BoardTypeRepository boardTypeRepository;
    private final BoardRepository boardRepository;
    private final BoardTypeCustomRepository boardTypeCustomRepository;
    private final BoardHitsRepository boardHitsRepository;
    private final BoardLikeRepository boardLikeRepository;
    private final BoardBadReportRepository boardBadReportRepository;
    private final BoardScrapRepository boardScrapRepository;
    private final BoardBookmarkRepository boardBookmarkRepository;
    private final BoardCommentsRepository boardCommentsRepository;

    private final UserRepository userRepository;

    private final MailTemplateRepository mailTemplateRepository;
    private final MailComponent mailComponent;

    ...

    @Override
    public ServiceResult replyBoard(Long id, BoardReplyInput boardReplyInput) {

        Optional<Board> optionalBoard = boardRepository.findById(id);
        if(!optionalBoard.isPresent()) {
            throw new BizException("게시글이 존재하지 않습니다.");
        }
        Board board = optionalBoard.get();

        board.setReplyContents(boardReplyInput.getReplyContents());
        boardRepository.save(board);

        // 메일 전송 로직
        Optional<MailTemplate> optionalMailTemplate = mailTemplateRepository.findByTemplateId("BOARD_ADD");
        optionalMailTemplate.ifPresent((e) -> {

            String fromEmail = e.getSendEmail();
            String fromName = e.getSendUserName();

            String title = e.getTitle().replaceAll("\\{USER_NAME\\}", board.getUser().getName());
            String contents = e.getContents().replaceAll("\\{BOARD_CONTENTS\\}", board.getContents())
                    .replaceAll("\\{BOARD_REPLY_CONTENTS\\}", boardReplyInput.getReplyContents());

            mailComponent.send(fromEmail, fromName, board.getUser().getEmail(), board.getUser().getName(), title, contents);
        });

        return ServiceResult.success();
    }
}

- ApiAdminBoardController.java

package com.example.jpa.sample.board.controller;

import com.example.jpa.sample.board.entity.BoardBadReport;
import com.example.jpa.sample.board.model.BoardReplyInput;
import com.example.jpa.sample.board.model.ServiceResult;
import com.example.jpa.sample.board.service.BoardService;
import com.example.jpa.sample.common.model.ResponseResult;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RequiredArgsConstructor
@RestController
public class ApiAdminBoardController {

    private final BoardService boardService;

    ...

    //------------------------------------------------------------------------------
    // 문제 4
    @PostMapping("/api/admin/board/{id}/reply")
    public ResponseEntity<?> reply(@PathVariable Long id, @RequestBody BoardReplyInput boardReplyInput) {

        ServiceResult result = boardService.replyBoard(id, boardReplyInput);
        return ResponseResult.success(result);
    }


}
728x90

'Spring > Practice' 카테고리의 다른 글

[Practice] 스케쥴러 활용 (2)  (0) 2021.04.20
[Practice] 스케쥴러 활용 (1)  (0) 2021.04.20
[Practice] 메일 전송 (3)  (0) 2021.04.20
[Practice] 메일 전송 (2)  (0) 2021.04.20