34일차(1)/jsp(19) : fetch, ajax 함수
- fetch : 익스플로러 안의 빌트인 함수
- fetch 함수의 사용법과, 왜 사용하는 것인지를 익히기
[ 웹브라우저에서 서버에 요청(request) 하는 방법 ]
1. 링크 클릭(get) → 페이지 이동 → 응답된 내용이 화면에 나타남
- 링크를 클릭하면 주소창에 변화가 생긴다(페이지가 이동된다)
- 서버는 클라이언트의 요청에 응답하고, 응답되는 내용이 화면에 나타난다.
2. 폼 제출(get or post) → 페이지 이동 → 응답된 내용이 화면에 나타남
- 폼 전송시에는 get/post 중 어떤 방식으로 전송할지 결정할 수 있다.
- 서버는 클라이언트의 요청에 응답하고, 응답되는 내용이 화면에 나타난다.
*** 웹브라우저에서 서버에 요청(request)을 하는 방법 중에 페이지 이동 없이
javascript로 요청을 하고 응답된 내용을 함수의 매개변수로 받아오는 방법이 있다.
- 그 중 하나가 fetch함수이다.
<test09.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/promise/test09.jsp</title>
</head>
<body>
<h1>fetch() 함수 테스트</h1>
<button id="myBtn">눌러보셈</button>
<a href="${pageContext.request.contextPath }/index.jsp">눌러보셈</a>
<script>
document.querySelector("#myBtn").addEventListener("click", function(){
//페이지 전환 없이 index.jsp 페이지로 요청하기
fetch("${pageContext.request.contextPath }/index.jsp")
.then(function(response){
return response.text();
})
.then(function(data){
//index.jsp 페이지가 응답하는 문자열이 함수의 인자로 전달된다.
console.log(data);
});
});
</script>
</body>
</html>

- 버튼을 누르면 콘솔에 뭔가 출력된다. 페이지 이동은 없다.
- 전체가 따옴표 " " 로 감싸진 문자열을 출력한 것이다.

- html형태로 보이지만, 이 문자열이 data 안에 " " 으로 들어가 있는 것.
- 저 내용은 jsp 페이지이다. jsp가 응답한 내용을 javascript가 문자열로 변환해서 받아낸 것이다.

- fetch 함수에 어디에 요청할지 요청 주소를 적으면 된다.
- 어느 servlet/jsp 페이지에 요청할지 적으면 promise 타입을 리턴한다.
저 요청에 대한 응답이 잘 오면 then 함수가 호출된다.

- response 안에는 object타입이 들어있다. { text:function(){ } , .... }
text 라는 key값으로 fuction(){} value값을 꺼내서 사용하는 것!
- 이 함수를 호출했을 때, text가 리턴해주는것은 promise type이다.
- 두번째 then 응답한 data가 console.log에 들어온다. 이것은 문자열이다!

- 이것을 Ajax Request (Ajax 요청) 이라고 부른다. 페이지 이동 없이 응답된 내용을 받아오는 것!
- 페이지전환 없이, 응답된 데이터를 화면상에 표시하지 않고, javascript 함수의 매개변수로 받아온다.

- 검사-Network에서 서버의 응답내용을 볼수있다.
- 상태(status) 200은 정상적인 응답이 되었다는뜻!!

- 요청이 잘못되면 404가 나온다.
- 보통은 페이지에 출력될 내용을 javascript함수로 받아낸 것이다!
ex) 일상생활의 ajax요청은 어떤 것이 있을까?
- 회원가입시 회원아이디가 사용이 가능한지 나오는 문구
- 페이지 전환 없이 정보를 서버에 보내서 사용가능/불가능 여부를 응답받은 것이다.
- 요청만 하는 것이 아니고 요청 파라미터를 같이 전달할 수 있다.
(get방식은 파라미터를 주소 뒤에 붙여서 달고 간다./post방식으로 전송하면 몸통에 파라미터를 달고 간다)
- 페이지 전환 없이 요청 파라미터를 보내는 것은 둘다 가능하다. 데이터도 보내고, 응답도 받을 수 있다.
- 파일업로드도 페이지전환 없이 할 수 있다.(input type="file" 인 폼)
- 일반 폼과의 차이점은 페이지 전환이 없다는 것이다. 이렇게 만들어야 하는 경우가 많다!

- fetch("https://daum.net") 은 가능할까? → 오류 발생. 다음 서버에서 응답을 거부한 것이다.
- 주소창에 직접 주소를 적으면 응답하지만, javascript로 보낸 요청에는 응답하지 않는다.

- CORS에 의해 블록되었다고 나온다. CORS 정책에 어긋나서 응답하지 않는 것이다.(동일출처정책)

- 각각의 서버가 있고, 웹브라우저가 있을 때, 웹페이지는 응답을 받을 수 있다
- 브라우저에서 javascript 실행환경에서 ajax 요청을 하면 응답하지 않는다.
나에게 응답한 서버에 요청해야지 오는 것이다.

- ajax요청도 웹페이지를 받은 동일 서버에다가 해야한다.
- 이 웹페이지의 출처는 다른 서버이기 때문에 응답을 하지 않는 것이다. 이것을 CORS라고 부른다.

- 현재 이 PC에서는 Tomcat WebServer에게서 받은 서버명을 사용하고 있는데,
다른 외부서버에 요청하면 응답하지않는다. 기본 세팅이 그렇게 되어있다. 보안상의 문제로...

- 이렇게 작성하는 것은 fetch 함수를 사용하는 하나의 형식이다.
- fetch를 호출하면서 jsp나 서블릿을 요청
→ 응답하면 then 함수가 호출되고,
→ object 에 들어있는 text라는 함수를 호출해주면 data에 해당 문자열이 들어온다.
<test10.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/promise/test10.jsp</title>
</head>
<body>
<input type="text" id="msg" placeholder="메세지 입력..." />
<button id="sendBtn">전송</button>
<script>
/*
input 요소에 문자열을 입력하고 전송버튼을 누르면 입력한 문자열이 send.jsp페이지로
전송이 되도록 하려고 한다.
단, 페이지 전환 없이
*/
let result1;
let result2;
let result3;
document.querySelector("#sendBtn").addEventListener("click", function(){
//입력한 내용을 읽어온다.
let msg=document.querySelector("#msg").value;
//fetch 함수를 호출하면서 GET방식 파라미터로 send.jsp 페이지를 요청하면서 전달한다.
fetch("send.jsp?msg="+msg)
.then(function(response) {
return response.text();
})
.then(function(data){
console.log(data);
//함수의 매개변수에 전달할 문자열을 result1에 대입
result1=data;
//함수의 매개변수에 전달할 문자열을 object로 변환해서 result2에 대입
result2=JSON.parse(data);
//object를 json문자열로 변환해서 result3에 대입
result3=JSON.stringify(result2);
});
});
</script>
</body>
</html>
- 페이지 전환이 되면서 전송되려면 form을 구성하면 된다.
그런데 페이지 전환 없이 전송되려면?
<send.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//msg라는 파라미터명으로 전달되는 문자열을 읽어온다.
String msg=request.getParameter("msg");
//콘솔창에 출력하기
System.out.println(msg);
//응답!
%>
{"isSuccess":true}

- 클라이언트가 보낸 정보가 주소창 변화 없이 전송되어 이클립스의 콘솔창에 출력된다.

- 응답된 문자열이 브라우저의 콘솔창에 출력된다.

- 클라이언트 요청 → 서버 전달 → 서버에서 send.jsp 이어서 실행 → 클라이언트에게 응답을 되돌려줌
- 응답하는 것만이 아니라 함수의 매개변수로도 받아왔다.

- 서버가 msg를 읽어내면 응답이 문자열로 전달된다
- 응답되는 문자열이 함수의 매개변수로 받아진다.
- 첫번째 then에서 response.text 로 호출해 주어야만 저기에 값이 들어올 수 있다.
- 클라이언트(브라우저)의 동작 / 서버(jsp 파일)의 동작을 분리해서 생각하기.
- 페이지 전환 없이, 서버에 데이터를 보낼 수도 있고 응답을 받아올 수도 있다.
- 응답은 javascript의 매개변수로 받는다.
Q) response.text 가 왜 object타입인지?

A) fetch() 함수 안에서 작업의 결과를 object로 전달했기 때문에.
console.log로 찍어보면 response가 {key:value}가 들어있는 object타입이다.
promise에서 object 값을 넣어준 것이다. promise내부에서 작업을 하고 넣어준 값!

- fetch는 기본 object이다. 열어보면 여러 개의 방이 있다. text, json 등등의 방에는 함수가 들어있다
return response.text(); : text라는 방에서 호출한 것이 promise 타입인 것이다.(뒤에 .then이 나오므로)
return response.text(); 를 사용하는 것은 그냥 fetch 함수의 사용법이므로 따라야 한다...
response.text(); 는 response object 안에 있는 함수를 호출하는 표현식이다. 해당 함수를 호출하면 promise type이 리턴된다.
- 함수 기본 작성 양식을 따르면서 어디에 요청할 것인지, 응답된 데이터를 어떻게 사용할 것인지를 정하면 된다.

- 이런 형태보다는 'json문자열'을 많이 받아서 쓴다.
- 그래야 javascript 함수로 사용하기가 편하다.
[ json (Java Script Object Notation) ] ★★★
- JSON : Java Script Object Notation (자바스크립트 객체 표기법) 을 따르는 문자열 형식
- xml 문자열 형식과 비교할 수 있다.

(필기하고 이미지 삭제하기)
ex) 회원의 번호, 이름, 성별을 xml로 표기하면
<!-- xml -->
<data>
<num>1</num>
<name>바나나</name>
<isMan>False</isMan>
</data>
<!-- or -->
<data num="1" name="바나나" isMan="false" />
- xml: 어떤정보를 구조화해서 가지고 있는 것. 속성, 자식 요소등으로 가지고 있을 수도 있다.
ex) 회원의 번호, 이름, 성별을 json형식으로 표기하면
<!-- JSON -->
{"num":1, "name":"바나나", "isMan":true}
{"num":1, "name":"바나나", "isMan":true)}
- javascript 객체의 표기법과 닮아있다. 단 반드시 key값을 " "으로 감싸야 한다.
- java라면 값을 각각 추출해서 int num, String name, boolean isMan 에 담은 형태로 사용할 것
- 위와 같은 문자열로 전달받아서 필요한 정보를 빼내는 작업을 할 것이다.
- java의 기능을 사용해서 빼내는데, 그러려면 문자열 형식이 맞아야 한다. → {key:value, key2:value, ...}
* key 값 : 반드시 " " 으로 감싸야한다.
* value의 형식 :
- 숫자: 10 or 20 or 10.1 or 10.2
- 문자: "abcd" or "xxxx"
- 논리: true or false
- 빈 값: null
- object : { }
- array : [ ]
- 함수 : 없음 (javascript가 아니기 때문에 value에 함수를 넣을 수는 없다)
- 이 형식에 어긋나면 error가 발생한다..
- 왜 위와같은 형식이 자주 쓰이는가? 저런 형식의 문자열은 app에서 주로 사용하는 문자열 형식이기 때문에.
- json문자열은 java에서 사용하기엔 좀 불편하지만, javascript에서 사용하기엔 유리한 모양이다.
- 이런 형식의 문자열은 쉽게 javascript 객체로 바꿀 수가 있다.
{"isSuccess":true} 를 입력하면 콘솔에 문자열이 들어온다.
[JSON으로 응답하기]
<test11.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/promise/test10.jsp</title>
</head>
<body>
<input type="text" id="msg" placeholder="메세지 입력..." />
<button id="sendBtn">전송</button>
<script>
/*
input 요소에 문자열을 입력하고 전송버튼을 누르면 입력한 문자열이 send.jsp페이지로
전송이 되도록 하려고 한다.
단, 페이지 전환 없이
*/
let result1;
let result2;
let result3;
document.querySelector("#sendBtn").addEventListener("click", function(){
//입력한 내용을 읽어온다.
let msg=document.querySelector("#msg").value;
//fetch 함수를 호출하면서 GET방식 파라미터로 send.jsp 페이지를 요청하면서 전달한다.
fetch("send2.jsp?msg="+msg)
.then(function(response) {
//서버에서 응답된 문자열이 json형식이면 response.json() 함수를 호출해서 리턴해준다.
return response.json();
})
.then(function(data){
//여기에 전달된 data는 바로 사용할 수 있는 object이다.
console.log(data);
console.log(data.isSuccess);
});
});
</script>
</body>
</html>
result1=data;
result2=JSON.parse(data);
- 전역변수를 만들어서 then 안에 넣어준다.

- JSON.parse 함수를 사용해서 변환한 값은 바로 true를 내보낸다.
- JSON이라는 기본 오브젝트가 있다. 여기의 parse 함수를 이용하면 JSON형식의 문자열을 실제 object로 바꿀 수 있다.

result1=data; (문자열 그대로 출력)
result2=JSON.parse(data); (문자열을 object로)
result3=JSON.stringify(result2); (object를 String으로)
- 전역변수 3개를 만들어 출력되는 형태를 비교하기.
- json데이터는 result2와 같이 변환해서 사용하면 편리하다. (바로 점 찍어서 사용가능!)
return response.json();
- text가 아닌 json함수를 호출한다.
- text면 문자열 리턴, json이면 object 리턴
- json을 호출하면 알아서 parse() 작업까지 해서 저기에 전달해준다. . 점을 찍어서 바로 사용할 수 있다.
- text로 호출하는 경우보다 좀더 편리하게 사용 가능하다.
<send2>
<%@ page language="java" contentType="application/json; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//msg라는 파라미터명으로 전달되는 문자열을 읽어온다.
String msg=request.getParameter("msg");
//콘솔창에 출력하기
System.out.println(msg);
//응답!
%>
{"isSuccess":true}
- json을 쓰지 않으면 무조건 text를 호출해야 한다. json을 호출할 수도 있다.(json이 편리하다...)
- json을 응답할 예정이면 위의 <% %>을 아래와 같이 바꿔주어야한다.
<%@ page language="java" contentType="application/json"; charset=UTF-8" pageEncoding="UTF-8"%>
- 앞으로 json문서를 많이 사용하게 될 것...
ex) 일상생활에서 사용하는 버스도착정보 등도 json으로 날아온다. 서버에 값을 전달하는 것은 json형식.
그중 원하는 값을 빼내서 화면 UI에 보여주는 것이다.
webapp-js 폴더 생성
webapp/js/sy_util.js 라는 파일 생성 (외부 js파일)
<sy_util.js>
// webapp/js/sy_util.js
/*
ajaxPromise("요청url", "요청메소드", query string or object)
와 같은 형식으로 사용하고
Promise type 을 리턴해주는 함수
*/
function ajaxPromise(url, method, data){
//만일 필요한 값이 전달 되지 않으면 기본값을 method 와 data 에 넣어준다.
if(method == undefined || method == null){
method="GET";
}
if(data == undefined || data == null){
data={};
}
let queryString;
if(typeof data == "string"){
queryString=data;
}else{
queryString=toQueryString(data);
}
// Promise 객체를 담을 변수 만들기
let promise;
if(method=="GET" || method=="get"){//만일 GET 방식 전송이면
//fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다.
promise=fetch(url+"?"+queryString);
}else if(method=="POST" || method=="post"){//만일 POST 방식 전송이면
//fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다.
promise=fetch(url,{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
body:queryString
});
}
return promise;
}
//함수의 인자로 ajax 전송할 폼의 참조값을 넣어주면 알아서 ajax 전송되도록 하는 함수
function ajaxFormPromise(form){
const url=form.getAttribute("action");
const method=form.getAttribute("method");
// Promise 객체를 담을 변수 만들기
let promise;
//파일 업로드 폼인지 확인해서
if(form.getAttribute("enctype") == "multipart/form-data"){
//폼에 입력한 데이터를 FormData 에 담고
let data=new FormData(form);
// fetch() 함수가 리턴하는 Promise 객체를
promise=fetch(url,{
method:"post",
body:data
});
return promise;//리턴해 준다 (여기서 함수가 종료 된다.)
}
const queryString=new URLSearchParams(new FormData(form)).toString();
if(method=="GET" || method=="get"){//만일 GET 방식 전송이면
//fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다.
promise=fetch(url+"?"+queryString);
}else if(method=="POST" || method=="post"){//만일 POST 방식 전송이면
//fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다.
promise=fetch(url,{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
body:queryString
});
}
return promise;
}
//함수의 인자로 요청 url 과 ajax 전송할 내용이 있는 input 요소의 참조값을 전달하면 ajax 전송해주는 함수
function ajaxInputPromise(url, input){
const type=input.getAttribute("type");
const name=input.getAttribute("name");
let promise;
if(type=="file"){ // input type="file" 인 경우
let data=new FormData();
data.append(name, input.files[0]);
promise=fetch(url,{
method:"post",
body:data
});
}else{ //아닌경우
//전송할 쿼리 문자열 구성
const data=name+"="+encodeURIComponent(input.value);
promise=fetch(url,{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
body:data
});
}
return promise;
}
//인자로 전달하는 object 를 이용해서 query 문자열을 만들어서 리턴해주는 함수
function toQueryString(obj){
//빈배열을 일단 만든다.
let arr=[];
//반복문 돌면서 obj 에 있는 정보를 "key=value" 형태로 만들어서 배열에 저장한다.
for(let key in obj){
//value 는 인코딩도 해준다.
let tmp=key+"="+encodeURIComponent(obj[key]);
arr.push(tmp);
}
//query 문자열을 얻어낸다
let queryString=arr.join("&");
//결과를 리턴해준다.
return queryString;
}
- 유틸리티처럼 쓸 수 있는 함수가 몇개 들어있다.
- ajaxPromise, ajaxFormPromise, ajaxInputPromise

- fetch 함수를 사용해서 promise를 리턴해주고 있다.
- 위의 3개 함수를 사용해서 ajax요청을 편하게 할 수 있다.
- jsp파일에서 이 파일을 사용하려면 아래 한줄을 추가해주면 된다.
<script src="${pageContext.request.contextPath }/js/sy_util.js"></script>
- 이렇게 추가해두면 그 js파일 안의 함수를 사용할 수 있다.

ajaxInputPromise("send2.jsp", document.querySelector("#msg"){ })
- url과 input요소의 참조값을 받는 함수
- 단, name 값이 필수이다! name="msg" 추가
- fetch함수가 promise 객체를 리턴해주고 있다.
<test12>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/promise/test12.jsp</title>
</head>
<body>
<h3>ajax form 예제</h3>
<form action="insert.jsp" method="post" id="myForm">
<input type="text" name="name" placeholder="이름 입력..." />
<input type="text" name="addr" placeholder="주소 입력..." />
<button type="submit">추가</button>
</form>
<script src="${pageContext.request.contextPath }/js/sy_util.js"></script>
<script>
//id가 myForm인 요소에 "submit"이벤트가 일어나면 실행할 함수 등록
document.querySelector("#myForm").addEventListener("submit", function(event){
//폼 제출을 강제로 막기
event.preventDefault();
//sy_util.js에 있는 함수를 이용해서 폼에 입력한 내용을 ajax 요청을 통해 전송한다.
//this대신에 document.querySelector("#myForm") 해도 된다.
ajaxFormPromise(this) // 여기서 this는 submit이벤트가 일어난 폼의 참조값이다.
.then(function(response){
return response.json();
})
.then(function(data){
console.log(data);
});
});
</script>
</body>
</html>
<insert.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//요청 파라미터 추출
String name=request.getParameter("name");
String addr=request.getParameter("addr");
//추출한 문자열을 콘솔창에 출력
System.out.println(name+" | "+addr);
//응답
%>
{"isSuccess":true}
- {"isSuccess":true}에는 ; 를 붙이면 안 된다.
- 이름, 주소를 읽어와서 이클립스 콘솔에 출력해주는 코드

- 콘솔에 출력되고, 브라우저에도 페이지 전환이 일어나면서 응답이 나타난다.
- 그런데 이걸 페이지 전환 없이 하고 싶다면?
- 폼 안에서 submit 버튼을 누르면 폼에 submit event가 일어난다. 마치 click 이벤트처럼!
document.querySelector("#myForm").addEventListener("submit", function(event){
});
- 이벤트 오브젝트가 매개변수로 전달되는 함수를 javascript로 만들어준다.
- 폼 전송을 강제로 막아두고 ajax로 처리되도록 한다.
- 모든 input 요소의 값을 얻어내서 전송해준다.

- 폼 전송도 되고, 응답도 받을 수 있다.
ajaxInputPromise() : input요소에 입력한 내용을 전송해 주는 함수
ajaxFormPromise() : form요소에 입력한 모든 내용을 전송해주는 함수

- Promise의 이 형태를 외워두기!
- 호출하면서 참조값을 넘겨주면 ajaxformpromise 함수 안에서 알아서 ajax로 전송해 준다.
- 응답된 데이터를 console.log에서 받아서 쓰면 된다.
- sy_util.js 에 이미 대부분의 메소드가 만들어져있다.
- 파일을 전송하는 폼이면 알아서 이 함수안에서 해준다. 이미 코딩이 되어 있다.
- 안에서 여러 작업을 하고(조건절 등), fetch해서 promise를 리턴해준다.

- get방식과 post방식의 전송방식 차이도 이미 만들어져 있다. 참고해서 코딩하기.
'국비교육(22-23)' 카테고리의 다른 글
35일차(1)/jsp(21) : 게시판 목록 보기, 새 글 작성, 글 상세보기 기능 구현 (0) | 2022.11.25 |
---|---|
34일차(2)/jsp(20) : 회원 프로필 이미지 등록, 수정 기능 구현 (0) | 2022.11.25 |
33일차(4)/javascript : Promise (0) | 2022.11.24 |
33일차(3)/jsp(18) : 자료실 게시판 페이징 처리 (0) | 2022.11.24 |
33일차(2)/jsp(17) : 자료실 파일 삭제 기능 구현, GIT 연습 (0) | 2022.11.24 |