Blog-v3(리팩토링),CDN,댓글 작성하기

리팩토링
홍윤's avatar
Sep 09, 2024
Blog-v3(리팩토링),CDN,댓글 작성하기
 

CDN(Content Delivery Network)

💡
CDN(Content Delivery Network)은 전 세계에 분산된 서버 네트워크를 통해 웹 콘텐츠를 더 빠르고 효율적으로 사용자에게 전달하는 시스템입니다. CDN은 웹사이트의 성능을 향상시키고, 로딩 속도를 개선하며, 트래픽 부하를 분산시켜 서버 과부하를 방지하는 데 중요한 역할을 합니다.

주요 기능 및 작동 원리:

  1. 분산된 서버 네트워크: CDN은 전 세계 여러 지역에 위치한 서버들로 구성됩니다. 이를 "엣지 서버"라고도 부르는데, 사용자의 위치에 가까운 서버에서 콘텐츠를 제공하여 더 빠른 응답 시간을 제공합니다.
  1. 캐싱: CDN은 정적 콘텐츠(이미지, CSS, JavaScript 파일 등)를 캐싱합니다. 사용자가 웹사이트에 접근할 때, CDN 서버는 원본 서버에 요청하기 전에 사용자에게 가장 가까운 엣지 서버에서 캐시된 콘텐츠를 제공합니다. 이를 통해 웹사이트의 로딩 시간을 줄일 수 있습니다.
  1. 콘텐츠 가속: 동적 콘텐츠는 캐시하기 어려울 수 있지만, CDN은 네트워크 경로를 최적화하여 동적 콘텐츠의 전송 속도를 높입니다. 이를 통해 사용자 경험을 개선할 수 있습니다.
  1. 트래픽 부하 분산: CDN은 여러 서버에 웹사이트 트래픽을 분산시키므로, 특정 서버에 트래픽이 몰리는 것을 방지하고, 서버 다운타임을 최소화할 수 있습니다.
  1. 보안: CDN은 DDoS 공격을 방어하는 데도 효과적입니다. 분산된 서버 네트워크를 통해 트래픽을 분산시키기 때문에 특정 서버에 과도한 트래픽이 집중되지 않도록 보호할 수 있습니다. 또한, SSL 인증서도 CDN에서 관리하여 보안 연결을 제공합니다.

CDN을 사용하는 주요 이점:

  • 빠른 콘텐츠 로딩 시간
  • 전 세계 사용자에게 균일한 성능 제공
  • 서버 부하 감소
  • 대규모 트래픽 및 공격으로부터 보호
정리하자면, CDN은 웹사이트나 애플리케이션의 성능을 향상시키고, 전 세계적으로 빠르고 안전하게 콘텐츠를 제공하기 위해 사용하는 필수적인 기술입니다.
notion image

JQuery의 data() 메소드: 데이터 저장, 가져오기, 삭제 사용법

💡
JQuery에서 data() 메소드를 사용하면 HTML 요소에 데이터를 저장하거나 해당 데이터를 가져올 수 있습니다. data() 메소드는 DOM 요소에 메타 데이터를 저장하는 기능을 제공합니다.기본 사용법
  1. 데이터 저장하기data() 메소드를 사용해 특정 데이터 키와 값을 설정할 수 있습니다.
  1. 데이터 가져오기data() 메소드를 사용해 요소에 저장된 데이터를 가져올 수 있습니다.
1. 데이터 저장하기
javascript // 특정 요소에 데이터를 저장하는 방법 $('#myElement').data('key', 'value');
위 코드는 #myElement라는 요소에 key라는 데이터에 'value'라는 값을 저장합니다.2. 데이터 가져오기
javascript // 특정 요소에서 데이터를 가져오는 방법 var value = $('#myElement').data('key'); console.log(value); // 'value
이 코드는 #myElement에 저장된 key 데이터를 가져옵니다.3. 여러 데이터 저장하기
javascript $('#myElement').data({ key1: 'value1', key2: 'value2', key3: 'value3' });
이 코드는 한 번에 여러 개의 데이터를 저장하는 예제입니다.4. HTML5 data-* 속성과의 연동HTML5의 data-* 속성과 jQuery의 data() 메소드를 함께 사용할 수도 있습니다.
html <div id="myElement" data-key="initialValue"></div> javascript
// 이미 HTML에 정의된 data-* 속성을 가져올 수 있습니다. var value = $('#myElement').data('key'); console.log(value); // 'initialValue'
data-* 속성은 data() 메소드로도 접근이 가능하며, 그 값을 가져올 수 있습니다.5. 데이터 제거하기removeData() 메소드를 사용하여 요소에 저장된 데이터를 제거할 수 있습니다.
javascript $('#myElement').removeData('key');
위 코드는 #myElement에서 key 데이터를 제거합니다.이것이 기본적인 jQuery의 data() 메소드 사용법입니다.

순수 자바스크립트를 사용한 HTML5 data- 속성 처리 방법

💡
순수 자바스크립트에서는data-* 속성을 직접 사용하여 데이터를 저장하고 가져올 수 있습니다. HTML5에서는data-* 속성을 통해 사용자 정의 데이터를 HTML 요소에 저장할 수 있습니다. 이를 이용한 순수 자바스크립트 사용 방법을 설명하겠습니다.1. 데이터 저장하기 (setAttribute 사용)data-* 속성을 사용하여 데이터를 저장할 수 있습니다.
html <div id="myElement"></div> javascript
// 데이터를 저장하는 방법 var element = document.getElementById('myElement'); element.setAttribute('data-key', 'value');
위 코드는#myElement에 data-key="value" 속성을 추가합니다.2. 데이터 가져오기 (getAttribute 사용)저장된 데이터를 가져올 때는 getAttribute() 메소드를 사용합니다.
javascript // 데이터를 가져오는 방법 var value = element.getAttribute('data-key'); console.log(value); // 'value'
3. dataset 사용HTML5에서 도입된 dataset 속성은 data-* 속성에 더 간편하게 접근할 수 있도록 합니다. dataset은 자동으로 data-* 속성을 읽고, 객체 형태로 반환합니다.데이터 저장하기
javascript // dataset을 사용하여 데이터 저장하기 element.dataset.key = 'value';
위 코드는 #myElement에 data-key="value"를 추가합니다.데이터 가져오기
javascript // dataset을 사용하여 데이터 가져오기 var value = element.dataset.key; console.log(value); // 'value'
4. 여러 데이터 저장 및 가져오기HTML 요소에 여러 data-* 속성을 추가하고, 이를 통해 여러 데이터를 저장 및 가져올 수 있습니다.
html <div id="myElement" data-key1="value1" data-key2="value2"></div> javascript
// dataset을 사용하여 여러 데이터 접근 var element = document.getElementById('myElement'); console.log(element.dataset.key1); // 'value1' console.log(element.dataset.key2); // 'value2' // 데이터를 수정하기 element.dataset.key1 = 'newValue1'; console.log(element.dataset.key1); // 'newValue1'
5. 데이터 제거하기 (removeAttribute 사용)데이터 속성을 제거하려면 removeAttribute() 메소드를 사용할 수 있습니다.
javascript // 데이터 제거하기 element.removeAttribute('data-key');
이 코드는 data-key 속성을 제거합니다.요약
  • 데이터를 저장할 때는 setAttribute() 또는 dataset을 사용합니다.
  • 데이터를 가져올 때는 getAttribute() 또는 dataset을 사용합니다.
  • 데이터를 제거할 때는 removeAttribute()를 사용합니다.
이 방식으로 순수 자바스크립트에서 데이터를 처리할 수 있습니다

BlogV3 리팩토링

 

1.Reply Package

 

1. reply

@Builder public Reply(Integer id, String comment, User user, Board board, Timestamp createdAt) { this.id = id; this.comment = comment; this.user = user; this.board = board; this.createdAt = createdAt; }
  • 코드 설명
💡
Lombok의 @Builder 애너테이션을 사용하여 빌더 패턴을 적용한 Reply 클래스의 생성자 부분입니다. 빌더 패턴을 사용하면 복잡한 객체 생성 과정을 유연하게 처리할 수 있습니다

2. ReplyController

@PostMapping("/api/reply") public ResponseEntity<?> save(@RequestBody ReplyRequest.SaveDTO saveDTO){ // System.out.println(1); User sessionUser = (User) session.getAttribute("sessionUser"); // System.out.println(2); ReplyResponse.DTO replyDTO = replyService.댓글쓰기(saveDTO, sessionUser); // System.out.println(7); return ResponseEntity.ok(Resp.ok(replyDTO)); }
  • 코드설명
💡

1. public ResponseEntity<?> save(@RequestBody ReplyRequest.SaveDTO saveDTO)

  • 이 메소드는 댓글을 저장하는 역할을 합니다.
  • @RequestBody ReplyRequest.SaveDTO saveDTO:
    • 클라이언트에서 보내온 요청 데이터를 ReplyRequest.SaveDTO 객체로 변환합니다.
    • SaveDTO는 댓글 작성 시 필요한 데이터를 담는 DTO(Data Transfer Object)입니다.
    • 이 DTO에는 보통 댓글 내용, 게시물 ID 등이 포함될 것입니다.
  • ResponseEntity<?>:
    • 이 메소드는 응답으로 ResponseEntity를 반환합니다. ResponseEntity는 HTTP 응답의 상태 코드, 헤더, 본문을 모두 포함할 수 있습니다.
    • <?>는 반환 타입을 제네릭으로 설정하여 유연하게 여러 타입의 데이터를 반환할 수 있다는 것을 의미합니다.
    • 2. ReplyResponse.DTO replyDTO = replyService.댓글쓰기(saveDTO, sessionUser);

    • replyService.댓글쓰기(saveDTO, sessionUser):
      • replyService는 댓글과 관련된 로직을 처리하는 서비스입니다.
      • 댓글쓰기(saveDTO, sessionUser)는 댓글 작성 로직을 실행하는 메소드입니다. 이 메소드는 전달된 saveDTO와 로그인된 sessionUser 정보를 사용하여 새로운 댓글을 저장하는 역할을 합니다.
      • 이 메소드는 댓글 작성 후 작성된 댓글 정보를 반환합니다.
    • ReplyResponse.DTO replyDTO:
      • 댓글이 성공적으로 작성되면 ReplyResponse.DTO 객체에 댓글의 상세 정보가 담겨 반환됩니다. 이는 클라이언트에게 응답으로 보내기 위한 데이터입니다.
      • 3. return ResponseEntity.ok(Resp.ok(replyDTO));

      • ResponseEntity.ok(Resp.ok(replyDTO)):
        • ResponseEntity.ok()는 HTTP 응답 상태 코드 200 OK를 나타냅니다.
        • Resp.ok(replyDTO)는 응답 본문에 댓글 정보를 담아 클라이언트에게 반환합니다.
        • 이 응답에는 성공적으로 작성된 댓글의 상세 정보가 포함되어 있으며, 클라이언트는 이를 통해 댓글이 제대로 저장되었는지 확인할 수 있습니다.

3. ReplyRequest, ReplyResponse

public class ReplyRequest { @Data public static class SaveDTO{ private Integer boardId; private String comment; //to Entitiy 사용하기! //insert into reply_tb(comment, board_id, user_id, created_at) values('댓글1', 5, 1, now()); public Reply toEntity(User sessionUser, Board board){ return Reply.builder() .comment(comment) .user(sessionUser) .board(board) .build(); } } }
  • 코드설명
💡
ReplyRequest.SaveDTO 클래스에서 "to Entity" 패턴을 사용한다는 것은 DTO(Data Transfer Object) 객체를 도메인 객체(Entity)로 변환하는 메소드를 추가하여, 서비스나 컨트롤러에서 쉽게 DTO를 Entity로 변환할 수 있도록 하는 것입니다.
예를 들어, SaveDTO는 클라이언트로부터 받은 데이터(게시물 ID와 댓글 내용)를 포함하고 있지만, 이를 바로 데이터베이스에 저장할 수는 없습니다. 데이터베이스에 저장하기 위해서는 이 데이터를 Entity 객체로 변환해야 합니다.
 
 
public class ReplyResponse { @Data public static class DTO{ private Integer id; private String comment; private String username; public DTO(Reply reply) { this.id = reply.getId(); this.comment = reply.getComment(); this.username = reply.getUser().getUsername(); } } }
  • 코드설명
💡
이 코드는 댓글(Reply) 엔티티에서 DTO(Data Transfer Object)로 변환하기 위한 클래스입니다. DTO 클래스는 주로 클라이언트에게 필요한 정보만 전달하기 위해 사용됩니다. 이 클래스는 댓글에 대한 최소한의 정보를 담아 클라이언트에게 제공하며, Reply 엔티티를 받아서 DTO 객체로 변환합니다.

요약:

DTO 클래스는 댓글 엔티티 Reply에서 클라이언트에게 필요한 일부 필드만 추출하여 전달하는 용도로 사용됩니다. 엔티티 자체를 클라이언트에 노출하지 않고, 필요한 정보만 DTO로 전달하여 데이터 보호와 성능 최적화를 돕습니다.

 

4. ReplyService

@Transactional public ReplyResponse.DTO 댓글쓰기(ReplyRequest.SaveDTO saveDTO, User sessionUser) { System.out.println(3); // 1. 게시글 존재 유무 확인 Board boardPS = boardRepository.findById(saveDTO.getBoardId()) .orElseThrow(() -> new ExceptionApi404("게시글을 찾을 수 없습니다")); System.out.println(4); // 2. 비영속 댓글 객체 만들기 Reply reply = saveDTO.toEntity(sessionUser, boardPS); System.out.println(5); // 3. 댓글 저장 (reply가 영속화됨) replyRepository.save(reply); System.out.println(6); return new ReplyResponse.DTO(reply); }
  • 코드설명
💡
이 코드는 댓글 작성 요청을 처리하는 서비스 계층의 메소드입니다. Spring의 @Transactional 애너테이션을 통해 트랜잭션 내에서 데이터베이스 작업이 안전하게 이루어지며, 댓글을 작성한 후 해당 댓글의 정보를 ReplyResponse.DTO 형태로 반환합니다.
 
주요 부분 설명:
  1. public ReplyResponse.DTO 댓글쓰기(ReplyRequest.SaveDTO saveDTO, User sessionUser):
      • 댓글을 작성하는 서비스 메소드입니다.
      • 파라미터:
        • saveDTO: 클라이언트로부터 받은 댓글 작성 요청 데이터입니다.
        • sessionUser: 현재 세션에서 가져온 로그인된 사용자 정보입니다.
      • 반환 타입: ReplyResponse.DTO로 작성된 댓글의 정보를 반환합니다.
  1. 1. 게시글 존재 유무 확인:
      • 댓글을 달고자 하는 게시물이 존재하는지 확인하는 단계입니다.
      • boardRepository.findById(saveDTO.getBoardId())를 통해 saveDTO에서 전달받은 boardId로 게시물을 조회합니다.
      • 게시물이 존재하지 않으면 ExceptionApi404 예외가 발생하여 "게시글을 찾을 수 없습니다" 메시지를 반환합니다. 이로 인해 트랜잭션이 롤백됩니다.
  1. 2. 비영속 댓글 객체 만들기:
      • 게시물과 작성자 정보를 바탕으로 새로운 댓글 객체를 생성하는 단계입니다.
      • saveDTO.toEntity(sessionUser, boardPS)를 호출하여, 댓글 내용, 작성자(sessionUser), 게시물(boardPS)을 가지고 댓글 엔티티를 생성합니다.
      • 이 단계에서 생성된 reply 객체는 아직 데이터베이스에 저장되지 않은 비영속 상태입니다.
  1. 3. 댓글 저장 (reply가 영속화됨):
      • replyRepository.save(reply)를 통해 생성된 댓글을 데이터베이스에 저장합니다.
      • 이 과정에서 댓글은 영속화되며, 이제 데이터베이스에 존재하는 상태가 됩니다.
  1. return new ReplyResponse.DTO(reply):
      • 댓글이 성공적으로 저장되면 ReplyResponse.DTO 객체로 변환하여 클라이언트에게 반환합니다.
      • ReplyResponse.DTO(reply)는 댓글 엔티티(reply)를 받아 DTO로 변환하는 역할을 합니다. 이는 주로 댓글의 ID, 내용, 작성자 정보 등을 담아 클라이언트에 전달합니다.

요약:

  1. 게시물 존재 여부를 확인하고, 없으면 예외를 발생시킵니다.
  1. 댓글을 엔티티로 변환하여 데이터베이스에 저장하지 않은 상태로 생성합니다.
  1. 댓글을 데이터베이스에 저장하고 영속화합니다.
  1. 저장된 댓글 정보를 DTO로 변환하여 반환합니다.
이 메소드는 전체적으로 댓글 작성 프로세스를 처리하며, 트랜잭션을 통해 데이터베이스 작업이 안전하게 이루어지도록 보장합니다.

detail.mustache

<!-- 댓글 --> <div class="card mt-3"> <!-- 댓글등록 --> <div class="card-body"> <!-- form태그는 부분리로딩을 할 수 없다. 기능만 돌아가게 하는 것이다.--> <form> <!-- 유저 정보는 무조건 session에서 가져와야한다. form 태그에서 꼭 hidden을 써야한다!! --> <input type="hidden" value="{{model.id}}" id="boardId"> <textarea class="form-control" rows="2" id="comment"></textarea> <div class="d-flex justify-content-end"> <button onclick="saveReply()" type="button" class="btn btn-outline-primary mt-1">댓글등록</button> </div> </form> </div> <!-- 댓글목록 --> <div class="card-footer"> <b>댓글리스트</b> </div> <div class="list-group" id="reply-box"> {{#model.replies}} <!-- 댓글아이템 --> <div id="reply-{{id}}" class="list-group-item d-flex justify-content-between align-items-center"> <div class="d-flex"> <div class="px-1 me-1 bg-primary text-white rounded">{{username}}</div> <div>{{comment}}</div> </div> {{#isOwner}} <!-- 버튼타입으로 바꿔야한다. 이유는 submit이 되기 때문에--> <button onclick="deleteReply('{{id}}')" type="button" class="btn">🗑</button> {{/isOwner}} </div> {{/model.replies}} </div> </div> </div> <script> //1. 책임-> 디자인에 데이터를 바인딩 할 수 있다. function replyItem(reply){ return `<div id="reply-${reply.id}" class="list-group-item d-flex justify-content-between align-items-center"> <div class="d-flex"> <div class="px-1 me-1 bg-primary text-white rounded">${reply.username}</div> <div>${reply.comment}</div> </div> <button onclick="deleteReply('${reply.id}')" type="button" class="btn">🗑</button> </div>`; } // 1. 책임 -> 통신해서 데이터 요청하고 응답받으면 CSR하기 async function saveReply() { //1. Reply 객체 만들기 (id로 찾아서) let reply = { comment: $("#comment").val(), boardId: $("#boardId").val() }; //2. fetch 요청하기 let response = await fetch('/api/reply', { method: "post", body: JSON.stringify(reply), headers: { //들고가는 데이터를 "Content-type": "application/json; charset=utf-8" } }); let responseBody = await response.json(); // DTO!! console.log(responseBody); //3. CSR 하기 //$("#reply-box")에서 #은 jQuery에서 특정 HTML 요소를 선택하기 위한 ID 선택자를 의미합니다. 즉, id 속성이 reply-box인 요소를 선택하는 것입니다. // 만약 #을 제거하고 $("reply-box")로 사용하게 되면, jQuery는 tag name으로 해석하게 되어 <reply-box>라는 HTML 태그를 찾으려고 시도할 것입니다. // 하지만 일반적인 HTML 표준에는 reply-box라는 태그가 없으므로, 원하는 요소를 찾지 못하게 됩니다. //따라서 id가 reply-box인 요소를 선택하려면 반드시 #reply-box로 사용해야 합니다. 만약 클래스 선택자라면 .을 사용하여 .class-name처럼 접근해야 합니다. $("#reply-box").prepend(replyItem(responseBody.body)); $("textarea").val(""); } // let boardId = $("#boardId2").data("hello"); // console.log(boardId); //let boardId2 = document.querySelector("#boardId2").dataset.hello; //console.log(boardId2);
  • 코드설명
💡
이 코드는 댓글 시스템에서 댓글을 저장하고, 사용자 인터페이스에 실시간으로 표시하는 기능을 담당하는 JavaScript 코드입니다. 다음은 코드의 주요 부분에 대한 설명입니다.

1. replyItem(reply) 함수

  • 목적: 전달된 reply 데이터를 사용하여 HTML 구조를 생성하고 반환하는 함수입니다. 이 HTML은 댓글 목록에 추가되어 화면에 댓글을 보여주는 역할을 합니다.
  • 매개변수: reply라는 객체를 받아서, 해당 객체의 id, username, comment 값을 사용하여 댓글 요소를 만듭니다.
  • 작동 방식:
    • <div id="reply-${reply.id}">: 댓글에 고유한 id 값을 사용하여 div 요소를 생성합니다. 이 id는 각 댓글을 식별하는 데 사용됩니다.
    • 댓글의 usernamecomment가 포함된 HTML을 반환합니다.
    • 댓글을 삭제하는 버튼도 함께 만들어지며, 이 버튼을 클릭하면 해당 댓글을 삭제하는 deleteReply 함수가 호출됩니다.

2. saveReply() 함수

  • 목적: 댓글을 저장하고, 서버에 요청한 뒤, 서버 응답 데이터를 화면에 실시간으로 반영하는 함수입니다.
  • 작동 단계:
      1. Reply 객체 생성:
          • 사용자가 작성한 댓글 내용을 담은 Reply 객체를 만듭니다. 댓글 내용은 $("#comment").val()로 입력받고, 게시판 ID는 $("#boardId").val()에서 가져옵니다.
      1. fetch를 사용한 서버 요청:
          • fetch 함수로 /api/reply 엔드포인트에 POST 요청을 보냅니다. 이 요청의 본문에는 댓글 내용(reply)이 JSON 형식으로 포함됩니다.
          • 요청 헤더에는 콘텐츠 타입을 JSON으로 지정합니다.
      1. 서버 응답 처리:
          • 서버에서 받은 응답은 JSON 형식으로 변환됩니다(responseBody).
          • responseBody.body는 서버에서 반환한 댓글 데이터입니다.
      1. CSR(Client-Side Rendering):
          • 서버로부터 받은 댓글 데이터를 화면에 즉시 반영합니다.
          • $("#reply-box").prepend(replyItem(responseBody.body)): reply-box라는 div 요소의 시작 부분에 새 댓글을 추가합니다.
          • $("textarea").val("");: 댓글을 작성하는 텍스트 영역의 내용을 비웁니다.

3. 추가 설명

  • jQuery 선택자:
    • $("#reply-box"): idreply-box인 요소를 선택합니다. HTML 요소의 id 속성을 선택할 때는 #를 사용합니다.
    • $("textarea").val(""): <textarea> 태그 요소의 값을 비웁니다.
  • 서버 통신: 댓글 저장은 비동기로 이루어집니다. 서버에 요청을 보내고 응답을 받을 때까지 기다리며, 응답을 받은 후 화면에 즉시 반영됩니다(CSR).
  • CSR(Client-Side Rendering): 댓글이 서버에 저장되면 페이지 전체를 다시 로드하지 않고도 새로 추가된 댓글을 실시간으로 페이지에 표시합니다.
이 코드는 AJAX를 사용하여 서버와 통신하고, 댓글 데이터를 실시간으로 화면에 반영하는 전형적인 댓글 시스템의 기능을 구현한 예시입니다.
Share article

Uni