20240222 Spring 8 - REST, 이메일 전송

Leafy·2024년 2월 22일
1

중앙_자바

목록 보기
44/76

오늘 할 거

  • 읽음 수 올리기

summernote lite

툴바에 대해...

<script type="text/javascript">
	$(document).ready(function() {
	$('#summernote').summernote({
		height: 600,                 // 에디터 높이
		lang: 'ko-KR', // default: 'en-US'
		placeholder: "write here...", 
		fontNames : ['D2Coding', 'Arial Black', 'Comic Sans MS', 'Courier New'], // 폰트 나열
		toolbar: [
			// [groupName, [list of button]]
			['style', ['bold', 'italic', 'underline', 'clear']],
			/* ['font', ['strikethrough', 'superscript', 'subscript']], */
			['fontname', ['fontname','fontsize', 'color']],
			['para', ['ul', 'ol', 'paragraph']],
			/* ['height', ['height']] */
			['table', ['table','link', 'picture', 'video']],
			['view', ['fullscreen', 'codeview', 'help']]
		]
		});
	});
</script>

위 모양이었는데
툴바의 table 부분 한줄로 묶어서 보여주려면

<script type="text/javascript">
        $(document).ready(function() {
        	$('#summernote').summernote({
        		  height: 600,                 // 에디터 높이
        		  lang: 'ko-KR', // default: 'en-US'
        		  placeholder: "write here...", 
        		  fontNames : ['D2Coding', 'Arial Black', 'Comic Sans MS', 'Courier New'], // 폰트 나열
      			  toolbar: [
      			    // [groupName, [list of button]]
      			    ['style', ['bold', 'italic', 'underline', 'clear']],
      			    /* ['font', ['strikethrough', 'superscript', 'subscript']], */
      			    ['fontname', ['fontname','fontsize', 'color']],
      			    ['para', ['ul', 'ol', 'paragraph']],
      			    /* ['height', ['height']] */
      			    ['table', ['table','link', 'picture', 'video', 'fullscreen', 'codeview', 'help']]
      			  ]
        	});
        });
        </script>

읽음 수 올리기

BoardService

	public BoardDTO detail(int no) {
		//2024-02-22 psd 요구사항 확인
		//로그인 했어? -> 읽음 수 올리기
		if (util.getSession().getAttribute("mid") != null) {
			//DTO 객체 만들기 = 번호 + 아이디
			BoardDTO dto = new BoardDTO();
			dto.setBoard_no(no);
			dto.setMid(String.valueOf(util.getSession().getAttribute("mid")));
			//이미 읽은 사람은 조회수 안 올리기
            int result = boardDAO.alreadyRead(dto);
            if(result == 0) {
            	boardDAO.viewCount(dto);
            }
		}
		return boardDAO.detail(no);
	}

BoardDAO

	public int viewCount(BoardDTO dto) {
		return sqlSession.insert("board.viewCount", dto);
	}

	public int alreadyRead(BoardDTO dto) {
		return sqlSession.selectOne("board.viewCheck", dto);
	}

board-mapper.xml

<insert id="viewCount" parameterType="boardDTO">
	INSERT INTO visitcount (board_no, mno) 
	VALUES (#{board_no}, (SELECT mno FROM member WHERE mid=#{mid}))
</insert>
	
<select id="viewCheck" parameterType="boardDTO" resultType="Integer">
  SELECT COUNT(*) 
  FROM visitcount 
  WHERE board_no=#{board_no} AND mno=(SELECT mno FROM member WHERE mid=#{mid})
</select>

동적 쿼리로 변경(시도)

dynamic query는 select 결과 있을 때, 없을 때 쓰는 게 좋다...

public BoardDTO detail(int no) {
	if (util.getSession().getAttribute("mid") != null) {
		//DTO 객체 만들기 = 번호 + 아이디
		BoardDTO dto = new BoardDTO();
		dto.setBoard_no(no);
		dto.setMid(String.valueOf(util.getSession().getAttribute("mid")));
		//이미 읽은 사람은 조회수 안 올리기
		boardDAO.viewCount(dto);
	}
	return boardDAO.detail(no);
}
<insert id="viewCount" parameterType="boardDTO">
  <selectKey keyProperty="board_count" resultType="Integer" order="BEFORE">
    SELECT COUNT(*) 
    FROM visitcount 
    WHERE board_no=#{board_no} AND mno=(SELECT mno FROM member WHERE mid=#{mid})
  </selectKey>
  <if test="board_count == '0'">
    INSERT INTO visitcount (board_no, mno) 
    VALUES (#{board_no}, (SELECT mno FROM member WHERE mid=#{mid}))
  </if>
</insert>

if 아닐 때 실행할 쿼리가 없어서 안되는...

동작하는 동적 쿼리 (임시)

임시로 10번 글에 저장하는 쿼리로 해서 실행함
if test에 들어가는 board_count는 dto에 있는 거

<insert id="viewCount" parameterType="boardDTO">
  <selectKey keyProperty="board_count" resultType="Integer" order="BEFORE">
    SELECT COUNT(*) 
    FROM visitcount 
    WHERE board_no=#{board_no} AND mno=(SELECT mno FROM member WHERE mid=#{mid})
  </selectKey>
  <if test="board_count == 0">
    INSERT INTO visitcount (board_no, mno) 
    VALUES (#{board_no}, (SELECT mno FROM member WHERE mid=#{mid}))
  </if>
  <if test="board_count != 0">
    INSERT INTO visitcount (board_no, mno) 
    VALUES (10, (SELECT mno FROM member WHERE mid=#{mid}))
  </if>
</insert>
  • 땜빵 코드 바꿈
<insert id="viewCount" parameterType="boardDTO">
  <selectKey keyProperty="board_count" resultType="Integer" order="BEFORE">
    SELECT COUNT(*) 
    FROM visitcount 
    WHERE board_no=#{board_no} AND mno=(SELECT mno FROM member WHERE mid=#{mid})
  </selectKey>
  <if test="board_count == 0">
    INSERT INTO visitcount (board_no, mno) 
    VALUES (#{board_no}, (SELECT mno FROM member WHERE mid=#{mid}))
  </if>
  <if test="board_count != 0">
    SELECT COUNT(*) FROM dual
  </if>
</insert>

AOP 관점지향 프로그래밍

p446 AOP 스프링 3가지..? 중 하나
p487 파일 업로드
DB 암호화, 시큐리티...


가입하기, 이메일인증...


로그인 안했으면 댓글쓰기 창과 하트 버튼 기능 없애기

Spring) PathVariable

책 p366, p373. 경로 변수
Path Variable 사용법

myInfo 링크

menu.jsp

<li class="nav-item"><a class="nav-link" href="myInfo@${sessionScope.mid } }">Hello, ${sessionScope.mname }!</a></li>

@ 기준으로 자를 것. (위 링크에서는 / 기준으로 나눔)

이메일 보내기

pom.xml에 이메일

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-email</artifactId>
    <version>1.5</version>
</dependency>

outlook에서 msn 이메일 하나 만들기 (이거용) -> 이 이메일은 절대 깃허브 올리지 말기

naver, google 이메일 막힘? (사람이 보내는건 되는데 기계가 보내는건 막았다?)

outlook 이메일 사이트

SMTP, 포트번호 25


앱 및 장치에서 Outlook의 메시지를 삭제하도록 허용... (삭제는 안하고 메일만 보낼거라 안해도 된다)

여기 아래 숫자들 쓸 거

pom 연결되면 임포트 된다

import org.apache.commons.mail.SimpleEmail;
  • 이메일 전송
public void sendEmail(String email, String title, String key) throws EmailException {
	//mail 보내기 -> 지금은 controller에다 치지만 util로 보낼 것.
	String emailAddr = MailInfo.emailId;//이메일 주소 MailInfo.emailId <- 여기 변수로 보내는 사람 이메일주소
	String name = "하츄초콜릿";//보내는 사람 이름
	String passwd = MailInfo.emailPw;//암호 MailInfo.emailPw
	String hostName ="smtp-mail.outlook.com"; //SMTP server name
	int port = 587; //포트 번호

	SimpleEmail simpleEmail = new SimpleEmail(); // 전송할 메일
	simpleEmail.setCharset("UTF-8"); //언어셋 설정
	simpleEmail.setDebug(true); //화면 상에 메일 잘 가고 있는지 보여줌
	simpleEmail.setHostName(hostName);
	simpleEmail.setAuthentication(emailAddr, passwd);
	simpleEmail.setSmtpPort(port);
	simpleEmail.setStartTLSEnabled(true); //startTLS로 암호화하고 있다
	simpleEmail.setFrom(emailAddr, name);
	simpleEmail.addTo(email); //받는 사람 (우리 사이트에 가입한 회원)
	simpleEmail.setSubject(title); //제목
	simpleEmail.setMsg("인증번호는 [" + key + "] 입니다"); //본문 내용 text (우리 상황에선 text)
	simpleEmail.send(); //전송하기
}

Swal의 Toast

타이머 내려가는동안 뜨는... 알림창 있더라

//이거 만들어야 Toast가 된다.
const Toast = Swal.mixin({
  toast: true,
  position: 'center-center',
  showConfirmButton: false,
  timer: 3000,
  timerProgressBar: true,
  didOpen: (toast) => {
    toast.onmouseenter = Swal.stopTimer;
    toast.onmouseleave = Swal.resumeTimer;
  }
});
function emailAuth() {
  $.ajax({
    url: './emailAuth', //ajax용 rest controller에 만들자.
    type: 'post',
    dataType: 'text',
    //data: , //데이터 안 보내고 동작만 시킬 것
    success: function(result){
      if(result == 1) {
        Swal.fire("이메일을 발송했습니다.", "결과 : " + result, "success");
        
      } else {
        Toast.fire('통신문제', '통ㅇ신문제가 발생햇습니다.', 'info');
        //Swal.fire("이메일 발송 실패!", "문제가 발생했습니다.", "info");
      }
    },
    error: function(request, status, error){
      //접속불가거나 스테이터스나 에러
      Swal.fire("통신 실패", "문제가 발생했습니다 : " + error, "error");
    }
  });
}

RestController

파일 이름을... RestController.java로 하면 안된다. 어노테이션이랑 겹쳐서,,

@RestController 어노테이션 붙이면
그 아래 메소드들은 @ResponseBody를 뺄 수 있다. 어차피 다 Rest라서
(비동기통신 몰아넣는 파일용. API들 다 이렇게. json이나 xml이나...)
얘네는 view가 없다.

  • ajax로 한 거
    RestController(이름은 RestFullController로 바꿈) -> RestService -> RestDAO -> rest-mapper.xml로 가도록...
  • RestFullController.java
public class RestFullController {
	@Autowired
	private BoardService boardService;
	@Autowired
	private RestService restService; //REST service 다 몰아두자.

// 전에 했던 거
	@PostMapping("/restDetail")
	public BoardDTO restDetail(@Param("no") int no) {
		//System.out.println("restDetail : " + no);
		BoardDTO detail = boardService.detail(no); //dto는 autowired 안씀(어노테이션 없어서 그런가)
		
		System.out.println(detail.getBoard_title());
		//System.out.println(detail.getBoard_content());
		
		return detail;
	}
	
	@PostMapping("/emailAuth")
	public int emailAuth() {
		//로그인 검사, key 저장 등 service에서 한다.
		return restService.sendEmail();
	}
	
}
  • RestService.java
@Service
public class RestService {
	@Autowired
	private RestDAO restDAO;
	@Autowired
	private Util util;

	public int sendEmail() {
		//로그인검사 controller 말고 service에서
		if(util.getSession().getAttribute("mid") != null) {
			//메일 발송 + key 데이터베이스에 저장
			String email = getEmail(String.valueOf(util.getSession().getAttribute("mid")));
			//인증번호 생성
			String key = util.createKey();
			
			MemberDTO dto = new MemberDTO();
			dto.setMemail(email);
			dto.setMkey(key);
			dto.setMid(String.valueOf(util.getSession().getAttribute("mid")));
			restDAO.setKey(dto); //db에 키 저장하기
			
			//util.sendEmail(email, key); //너무 보내면 차단되니까 진짜 보내지는 않고...
			return 1;
		} else {
			return 0;
		}
	}
	//sendEmail()에서 쓸려고 만든...
	private String getEmail(String id) {
		return restDAO.getEmail(id);
	}
}
  • RestDAO.java
@Repository
public class RestDAO {
	@Autowired
	private SqlSession sqlSession;

	public String getEmail(String id) {
		return sqlSession.selectOne("rest.getEmail", id);
	}

	public void setKey(MemberDTO dto) {
		sqlSession.update("rest.setKey", dto);
	}
}
  • rest-mapper.xml
<mapper namespace="rest">
	
	<select id="getEmail" parameterType="String" resultType="String">
		SELECT memail FROM member WHERE mid=#{id}
	</select>
	
	<update id="setKey" parameterType="memberDTO">
		UPDATE member SET mkey=#{mkey} WHERE memail=#{memail} AND mid=#{mid}
	</update>
</mapper>

1개의 댓글

comment-user-thumbnail
2024년 2월 22일

답글 달기