The Debugging Chronicles : "코드의 미학"

[Spring] 비동기 검색창 본문

Spring

[Spring] 비동기 검색창

sweetseonah1004 2024. 10. 14. 22:12

searchContent.js를 만들어주고 ajax로 비동기 처리를 해준다. 여기서 ajax의 설정을 자세히 살펴보면

 

1. url: 'search.do'
설명: AJAX 요청이 전송될 서버의 엔드포인트 URL이다. 여기서는 search.do가 서버의 URL **엔드포인트이다.
2. method: 'POST'
설명: HTTP 요청 메서드를 지정한다. 여기서는 POST 요청을 사용하여 데이터를 서버로 전송한다.
3. data: JSON.stringify({ board_condition: condition, board_keyword: keyword })
설명: 서버로 전송할 데이터를 지정한다. 이 데이터는 자바스크립트 객체로 작성되어 있으며, JSON.stringify를 사용하여 JSON 문자열로 변환된다
board_condition: 전송할 조건 값을 담고 있는 변수.
board_keyword: 전송할 키워드 값을 담고 있는 변수.
4. contentType: 'application/json'
설명: 전송하는 데이터의 **MIME 타입을 지정한다. 여기서는 JSON 데이터를 전송하기 때문에 application/json으로 설정한다.
5. dataType: 'json'
설명: 서버로부터 응답받은 데이터 형식을 지정한다. 여기서는 JSON 형식의 응답을 기대하고 있다.
6. success: function(datas)
설명: AJAX 요청이 성공적으로 완료되었을 때 호출되는 콜백 함수이다
datas: 서버로부터 반환된 응답 데이터이더 이 데이터는 dataType에서 지정한 형식에 따라 파싱된다 (여기서는 JSON).

 



**엔드포인트

;클라이언트가 특정 리소스 또는 기능에 접근하기 위해 서버에 요청을 보낼 때 사용하는 경로를 의미한다.

https://www.example.com/api/users/123

 

1.기본 도메인 (Base URL):
https://www.example.com
서버의 주소입니다. 클라이언트는 이 주소를 통해 서버에 접근합니다.

 

2.엔드 포인트 (Endpoint):
/api/users/123
도메인 뒤에 오는 경로로, 특정 리소스 또는 기능을 지정합니다.
여기서 /api/users는 사용자 관련 리소스를 가리키며, 123은 특정 사용자의 ID를 나타냅니다.

 

**MIME 타입

;MIME 타입(Media Type)은 인터넷에서 전송되는 파일의 형식과 내용을 식별하기 위해 사용되는 표준 형식입니다. MIME 타입은 클라이언트와 서버 간의 데이터 통신에서 파일의 종류를 명확하게 알려주어, 클라이언트가 수신한 데이터를 어떻게 처리해야 할지를 결정할 수 있게 합니다.

 

예시 MIME 타입
text/html: HTML 문서
text/plain: 평문 텍스트
application/json: JSON 데이터
image/jpeg: JPEG 이미지
image/png: PNG 이미지

 

 


 

두번째로 만들 파일은 searchController.java이다. 비동기 처리를 더 이상 서블릿 파일로 만들필요가 없어졌다. POJO파일로 만든다.

여기서 살펴 보아야하는 것은 어노테이션 위주로 살펴봐야한다.

 

1. @PostMapping("/search.do")
역할: 특정 URL 경로 (/search.do)에 대한 HTTP POST 요청을 처리하는 메서드임을 표시합니다.
사용: 이 어노테이션은 POST 방식의 요청만을 처리하기 때문에, GET, PUT, DELETE 등 다른 HTTP 메서드는 이 메서드에서 처리되지 않습니다.
예시: 클라이언트가 /search.do 경로로 POST 요청을 보내면 이 메서드가 호출됩니다.
2. @ResponseBody
역할: 메서드의 반환값을 HTTP 응답 본문에 직접 삽입합니다.
사용: 이 어노테이션이 부착된 경우, 반환하는 List<BoardDTO> 객체는 JSON 형태로 변환되어 클라이언트에게 전달됩니다.
예시: 메서드가 반환하는 List<BoardDTO> 객체가 JSON 형식으로 **직렬화되고 클라이언트에게 전송됩니다.
3. @RequestBody
역할: 클라이언트가 전송한 HTTP 요청 본문을 자바 객체 (BoardDTO)로 변환합니다.
사용: JSON, XML 등 다양한 형태의 데이터를 자바 객체로 매핑할 때 사용됩니다.
예시: 클라이언트가 보낸 JSON 데이터가 BoardDTO 객체로 변환되어 search 메서드의 인자로 전달됩니다.
적용: 메서드 인자 boardDTO 앞에 붙음으로써, 클라이언트가 전송한 JSON 요청 본문을 BoardDTO 타입 객체로 변환합니다.

 


 

**직렬화

;직렬화(Serialization)는 객체 상태를 저장하거나 전송하기 위한 형식으로 변환하는 과정을 의미합니다. 주로 객체를 바이트 스트림 또는 텍스트 형식으로 변환하여 데이터베이스에 저장하거나 네트워크를 통해 전송할 때 사용됩니다.

 

직렬화의 의미와 과정

 

1. 객체를 직렬화:
자바 객체(예: List<BoardDTO>)를 JSON 또는 XML 등의 문자열로 변환합니다.
필요성: 객체 형태를 바이트 스트림이나 문자열로 변환해야 파일 저장, 네트워크 전송 등 다양한 작업을 수행할 수 있습니다.

 

2. 직렬화 과정:
객체의 멤버 변수와 속성 값을 특정 형식(JSON, XML, 등)으로 변환하는 것입니다.
예시: 자바 객체인 List<BoardDTO>를 JSON 문자열로 변환하여 클라이언트에 전송합니다.

직렬화 예시
List<BoardDTO> 객체가 JSON 형식으로 직렬화되는 예제를 통해 설명드리겠습니다.

먼저 자바 객체 리스트를 봅시다.

public class BoardDTO {
    private String title;
    private String content;
    private String author;
}

 

그리고, List<BoardDTO> 객체 생성:

List<BoardDTO> boardList = new ArrayList<>();
boardList.add(new BoardDTO("Title1", "Content1", "Author1"));
boardList.add(new BoardDTO("Title2", "Content2", "Author2"));

 

직렬화 코드
이제 List<BoardDTO> 객체를 JSON으로 직렬화 해보겠습니다.
자바에서는 Jackson 라이브러리를 사용해 JSON으로 직렬화할 수 있습니다:

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(boardList);
System.out.println(jsonString);

위의 코드를 실행하면, boardList 객체는 다음과 같은 JSON 문자열로 변환됩니다:

[
    {
        "title": "Title1",
        "content": "Content1",
        "author": "Author1"
    },
    {
        "title": "Title2",
        "content": "Content2",
        "author": "Author2"
    }
]

 

직렬화 과정 개요
객체 생성:
List<BoardDTO> 객체를 생성하고 초기화합니다.
직렬화 라이브러리 사용:
Jackson 등의 직렬화 라이브러리를 사용하여 객체를 JSON 형식으로 변환합니다.
직렬화된 데이터 전송:
직렬화된 JSON 문자열을 클라이언트에 전송합니다.
Spring MVC에서의 직렬화
Spring에서 @ResponseBody를 사용하면, Spring이 자동으로 객체를 직렬화하여 HTTP 응답 본문에 추가해줍니다:

@PostMapping("/search.do")
public @ResponseBody List<BoardDTO> search(@RequestBody BoardDTO boardDTO) {
    List<BoardDTO> datas = boardService.selectAll(boardDTO);
    return datas;
}

위 코드에서는 @ResponseBody 어노테이션이 List<BoardDTO> 객체를 JSON 형식으로 자동 직렬화하여 클라이언트에게 전송합니다. 이를 위해 Spring은 내부적으로 Jackson 또는 Gson 라이브러리를 사용합니다

 


main.jsp에서 주요하게 볼점은 param으로 데이터를 받은 점이다.

 

JSP(JavaServer Pages) 코드에서 param 객체를 사용하여 데이터를 받는 이유는 

클라이언트가 서버에 요청을 보낼 때 전달한 요청 파라미터 값을 쉽게 접근하고 처리하기 위함입니다.

 

JSP에서 param 객체의 역할
param 객체는 JSP에서 HTTP 요청 파라미터에 접근할 수 있게 해주는 내장 객체입니다. 

이 객체는 클라이언트가 GET 또는 POST 요청을 통해 서버로 전송한 데이터를 읽을 수 있게 합니다.

 

1. 요청 파라미터 읽기
클라이언트가 URL에 쿼리 파라미터를 추가하거나 폼 데이터를 POST 요청으로 전송할 때, 

서버는 이 데이터를 param 객체를 통해 읽을 수 있습니다. 

예를 들어:
요청 URL: http://example.com/search?board_condition=CONTENT
여기서, param.board_condition은 "CONTENT" 값을 가지게 됩니다.

 

2. 조건에 따라 선택 상태 유지
${param.board_condition eq 'CONTENT' ? 'selected' : ''} 표현식은 조건부 표현식을 사용하여, 

클라이언트가 board_condition 파라미터에 "CONTENT" 값을 보냈을 경우 해당 <option> 태그를 선택된 상태(selected)로 만듭니다.

 

이처럼, param 객체를 사용하여 클라이언트의 요청 데이터를 읽고

조건에 따라 HTML 요소의 상태를 동적으로 설정함으로써 사용자에게 더 나은 경험을 제공할 수 있습니다.

 


main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>메인 페이지</title>
<script src="http://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="js/searchContent.js"></script>
</head>
<body>

<h1>${userID}님, 안녕하세요! :D</h1>
${boardDTO} | ${boardDTO.board_writer_id} | ${boardDTO.board_title}

<hr>

<a href="logout.do">로그아웃</a>

<hr>

<h3>글 목록</h3>

<select name="board_condition" id="condition">
	<option value="CONTENT" ${param.board_condition eq 'CONTENT' ? 'selected' : ''}>내용</option>
	<option value="WRITER" ${param.board_condition eq 'WRITER' ? 'selected' : ''}>작성자</option>
</select>
<input type="text" id="keyword" placeholder="검색어를 입력해 주세요.">
<input type="button" value="검색" id="search">

<ul id="listContent">
	<c:if test="${empty datas}">
		<li>검색결과가 없습니다.</li>
	</c:if>
	<c:if test="${not empty datas}">
		<c:forEach var="data" items="${datas}">
			<li>${data}</li>
		</c:forEach>
	</c:if>
</ul>

<hr>

<a href="insertBoard.do">글 작성</a>

</body>
</html>

 

searchContent.js

$(document).ready(function () {
    $('#search').click(function(){
        var condition = $('#condition').val();
        var keyword = $('#keyword').val();
        console.log("condtion" + condition);
        console.log("keyword" + keyword);
        $.ajax({
            url: 'search.do',
            method: 'POST',
            data: JSON.stringify({ board_condition: condition, board_keyword: keyword }),
            contentType:'application/json',
            dataType:'json',
            success: function(datas) {

                $('#listContent').empty();

                datas.forEach((data,index)=>{

                    $('#listContent').append(
                        '<li>'+data.board_num+data.board_title+data.board_writer_id+'</li>'
                    );
                });

            }
        });
    })
})

 

searchController.java

package com.koreait.app.view.board;

import com.koreait.app.biz.board.BoardDTO;
import com.koreait.app.biz.board.BoardService;
import com.koreait.app.biz.member.MemberDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
public class SearchController {

    @Autowired
    BoardService boardService;

    @PostMapping("/search.do")
    public @ResponseBody List<BoardDTO> search(@RequestBody BoardDTO boardDTO) {
        System.out.println("com.koreait.app.view.board.SearchController 비동기 처리 로그");

        List<BoardDTO> datas = boardService.selectAll(boardDTO);

        for(BoardDTO data: datas) {
            System.out.println(data);
        }
        return datas;
    }
}