[Spring Boot] Ajax 통신 기초

Use_Silver·2022년 2월 15일
0

Spring

목록 보기
10/10
post-thumbnail

Ajax란?

  • JavaScript를 사용한 비동기 서버 통신 방식, 클라이언트와 서버간 XML, JSON, TEXT 등 데이터를 주고받는 기술
  • Ajax를 사용하면 웹 전체 페이지를 새로고침하지 않아도 뷰를 갱신할 수 있음

예시) 구글 검색

google에 검색할 때 새로고침을 하지 않아도 검색어의 목록(뷰가)이 변경됨

비동기(Asynchronous)란?

  • 작업을 요청 하고 작업 결과가 오기 전까지 다른 작업을 처리하는 것 -> 자원을 효율적으로 활용할 수 있음
  • 서버에 요청(Request)해놓고 응답이 오기 전까지 다른 작업을 처리함. 응답이 오면 정해놓은 함수(콜백함수)를 호출해 실행

Ajax를 사용하는 이유

  • 위의 예시와 같이 WEB화면에서 단순히 데이터를 조회하고 싶을 때 페이지를 전체 새로고침 하지 않기 위해 사용한다.
  • 동작이 일어났을 때, 일부분만 업데이트해서 사용할 수 있기 때문에 자원과 시간을 아낄 수 있다. (JSON이나 XML 형태로 필요한 데이터만 받아서 갱신)

Ajax 주요 작업

  1. 웹 페이지 새로고침 없이 서버에 요청(Request)
    • XMLHttpRequest Object 생성
      request를 보낼 준비를 브라우저에게 시키는 과정
      필요한 method를 갖춘 object 필요
  2. 서버로부터 데이터를 받고 작업 수행
    • callback 함수 생성
      서버에서 response가 왔을 때 실행시키는 함수
      HTML 페이지 업데이트

Ajax 예시

function loadDoc() {
  const xhttp = new XMLHttpRequest();
  xhttp.onload = function() {
    document.getElementById("demo").innerHTML = this.responseText;
    }
  xhttp.open("GET", "ajax_info.txt", true);
  xhttp.send();
}


[ 참고 url ]
https://www.w3schools.com/
https://www.w3schools.com/js/js_ajax_intro.asp


Rest API를 적용한 비동기 실습

  • Spring Starter
  1. 실습 프로젝트 구조

  2. Project Dependency (pom.xml 수정)
    pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>playdata</groupId>
	<artifactId>step01-basic</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>step01-basic</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>
  1. 이외의 소스코드

3.1 Step01BasicApplication.java (자동 생성)

/* spring boot 프로젝트 생성시 자동 생성되는 핵심 실행 클래스
 * 1. 서버 실행
 * 2. 구현된 application을 서버 내에 배포 
 * 3. 1+2로 인해 client는 브라우저로 요청/응답 서비스가 가능 
 * 
 * 4. 주요 사항 
 * 	단, 해당 package 내부의 sub package만 자동 인식 
 * 	만일 package가 다를 경우 스캔 에노테이션으로 스캔 지시 
 * 				@ComponentScan 설정 추가 
 * 
 */
package kr.pe.playdata;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Step01BasicApplication {

	public static void main(String[] args) {
		SpringApplication.run(Step01BasicApplication.class, args);
	}

}

3.2 Spring Controller (REST API) - BookController.java

//DB 연동 등 다 구현되었다 가정 

package kr.pe.playdata.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import kr.pe.playdata.domain.Book;

@RestController
public class BookController{
	
	// http://ip:port/hello
	//Get - 검색 
	@GetMapping("hello")
	public String m1() {
		// ...
		System.out.println("get");
		return "Get";
	}
	
	//Post - 수정  
	@PostMapping("hello")
	public String m2() {
		// ...
		System.out.println("post");

		return "post";
	}
	//Put - 생성 
	@PutMapping("hello")
	public String m3() {
		// ...
		System.out.println("put");

		return "put";
	}
	//Delete - 삭제
	@DeleteMapping("hello")
	public String m4() {
		// ...
		System.out.println("delete");

		return "delete";
	}
	
	
	// 10개의 Book 객체를 생성해서 List에 저장 후에 반환 
	// db에서 select 한 데이터라 가정 
	@GetMapping("books") // url
	public List<Book> m5(){
		List<Book> all = new ArrayList<>();
		
		for (int i=1; i < 11; i++ ) {
			all.add(new Book(i,"sb"+i,"재석"+i));
		}
		return all; // JSON 배열 형식으로 문자열 반환 (JSON.parse()로 JSON 객체로 실 변환)
	}
	

	// client가 요청시 parameter 값 받아서 해당 데이터 검색해 응답해주는 실습 
	// parameter : 주고 받는 데이터(메소드 또는 생성자의 ())
	
	// get - isbn값으로 해당 책 정보 select 해서 book 객체 반환
	
	/* isbn 어떻게 받을것인가? Book 단수 객체 반환시 어떤 포맷으로 응답 ? json 포맷의 문자열 
	 * 
	 * http://ip:port/one?isbn=1
	 * ? 기준으로 web query string 이며, key로 value를 구분 
	 * server는 web query string 받아서 key로 value를 뽑아 활용
	 */

	// 	http://ip:port/one?isbn=1
	@GetMapping("one")
	public Book m5(String isbn) {
		
		// select 했다 가정 
		System.out.println("m5()--------"+isbn);
		return new Book(1, "sb1", "재석1");
		
	}

	
	// RestAPI로 개발시 parameter로 선언된 변수에 web query string값 자동 대입
	// 장점 : 형변환 즉 String 타입으로 client로부터 server 전송된다 할지라도 API가 자체적으로 
	// Integer.parseInt()로 String 타입의 데이터를 int로 변환해서 parameter 변수에 대입 
	// 	http://ip:port/one?isbn=1&age=20
	@GetMapping("one")
	public Book m5(String isbn, int age) {
		// select 했다 가정 
		System.out.println("m5()--------"+isbn+" "+age);
		return new Book(1, "sb1", "재석1");
		
	}
	
	// http://ip:port/one
	// post는 안보여야함 
	@PostMapping("one")
	public Book m6(String isbn, int age) {
		System.out.println("m6()--------"+isbn+" "+age);
		return new Book(1, "sb1", "재석1");
		
	}
	// 동기 메소드들 구현도 추가로 가능 
}

3.2.1 Postman 이용한 단위테스트

  • GET test
  • POST test
    Params로 parameter 따로 지정

3.3 application.properties

server.port=80

3.4 Step01BasicApplicationTests.java (자동 생성)

  • 단위 테스트 가능하게 해주는 클래스
package kr.pe.playdata;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Step01BasicApplicationTests {

	@Test
	void contextLoads() {
	}

}

3.5 reqres.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>reqres.html</title>
</head>
<body>

	<h3>step01-basic 비동기 학습</h3>
	<hr>

	버튼 클릭시에 브라우저에 서버로부터 받아온 책들 정보 출력<br>
	
	<button onclick="loadDoc()">isbn이 2인 책이름만 출력</button>
	<div id="nameView"></div>
	
	<script type="text/javascript">
	
		function loadDoc() {
		  	const xhttp = new XMLHttpRequest(); //매우 중요
			xhttp.onload = function() {   //매우 중요
				//f12 로 브라우저의 개발자 tool 실행후 콘솔창에서 확인 가능한 명령어
				//server 가 응답한 데이터는 순수 문자열로 받음
				//key(name)로 value값 활용하기 위해서는 문자열 -> JSON 객체로 변환		
				
				var data = this.responseText; //매우중요
				
				console.log(data);
				console.log(data[0]); // [
				console.log(data[1]); // { 
				console.log(data[2]); // " 
				
				data = JSON.parse(data);  //매우 중요
				console.log(data[0]);
				console.log(data[0].title);
				
				/* document : html 문서 자체를 제어하는 상위 객체
					getEleme	ntById("tag의 고유한 id(key)") : id값으로 해당 tag(element) 검색
					innerHTML : div와 p 라는 tag 내부에 html 형식을 추가 할수 있는 속성
					innerText : div와 p 라는 tag 내부 일반 text 추가 할수 있는 속성 */
			    document.getElementById("nameView").innerHTML = data[1].title;
			}
				
			xhttp.open("GET", "books", true); //매우 중요
		    xhttp.send();  //매우 중요
		}
	
	</script>


	<hr color="red">

<!-- 	isbn <input type="text" id="isbn" value="1"><br> -->
	age <input type="text" id="age" value="100"><br>

	<button onclick="getReq()">get방식 요청</button><br>
	<button onclick="postReq()">post방식 요청</button><br>
	
	<script type="text/javascript">
		//client가 실시간 가변적으로 입력하는 data로
		//web query string으로 구성해서 server에 전송
		
		//getReq()
		function getReq(){
			//client가 input tag에 입력한 데이터 read
			let isbn = document.getElementById("isbn").value;
			let age = document.getElementById("age").value;
			
	
			const xhttp = new XMLHttpRequest(); 
			xhttp.onload = function() {
				var data = this.responseText;
				console.log(data);
			}
			//http://ip:port/reqres.html ->
			//http://ip:port/one
			//http://ip:port/one?isbn=1&age=20
			//encodeURIComponent()로 전송시 한글 인코딩 간혹 필요
			xhttp.open("GET", "one?isbn="+isbn+"&age="+age, true); 
		    xhttp.send();  
		}
		
		//postReq()
		function postReq(){
			let isbn = document.getElementById("isbn").value;
			let age = document.getElementById("age").value;
			
	
			const xhttp = new XMLHttpRequest(); 
			xhttp.onload = function() {
				var data = this.responseText;
				console.log(data);
			}
			
			xhttp.open("POST", "one", true); 
			//생략시 post로 데이터 전송이 불가 - 데이터만 전송이 안됨
			//web query string값 서버에 전송시 필수필수필수!!
			//https://www.w3schools.com/js/js_ajax_http_send.asp
			xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			//query string 데이터가 반드시 parameter로 적용
		    xhttp.send("isbn="+isbn+"&age="+age);  
		}	
	</script>
	
	<hr color="blue">
	
	isbn <input type="text" id="isbn" value="100"><br>
	title <input type="text" id="title" value="sb100"><br>
	author <input type="text" id="author" value="재석100"><br>
	
	<button onclick="newInsert()">book 추가</button>
	
	<script type="text/javascript">
		function newInsert(){
			let isbn = document.getElementById("isbn").value;
			let title = document.getElementById("title").value;
			let author = document.getElementById("author").value;
			
	
			const xhttp = new XMLHttpRequest(); 
			xhttp.onload = function() {
				var data = this.responseText;
				console.log(data);
			}
			
			xhttp.open("POST", "one2", true); 
			xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		    xhttp.send("isbn="+isbn+"&title="+title+"&author="+author);  
		}
	
	</script>
</body>
</html>


🎈 Reference

profile
과정은 힘들지만😨 성장은 즐겁습니다🎵

0개의 댓글