학원에서는 예제를 통해 jsp, 서블릿을 이용한 Ajax 비동기 통신을 배웠는데, 스프링을 이용한 통신도 궁금해 서치하며 공부해봤다.
동기식 / 비동기식 통신
동기식 통신 : 요청 전송 후 응답을 받은 후에야 다음 동작이 이뤄짐
비동기식 통신 : 요청 보내면 응답과 상관없이 동작함 => http 전송 중에도 클라이언트가 웹 애플리케이션과 상호작용 가능
- 동기식 통신
Synchronous : 동시에 일어난다
=> 요청을 전송하면 얼마나 시간이 걸리든 그 자리에서 응답을 받음
=> 두 서버 사이의 트랜잭션을 맞춤
요청 보낸 스레드는 응답 도착 전까지 아무것도 못하는 Block 상태가 됨
=> 요청값, 응답값 순서 보장 + 보낸 요청에 대한 처리 결과값 보장
응답 지연 시 요청을 보낸 스레드는 응답을 계속 기다리는 상태가 됨
=> 이후 요청들은 연결 가능한 스레드가 없어 연결맺지 못하는 성능 이슈 발생 가능
- 비동기식 통신
Asynchronous : 동시에 수행하지 않는다
=> 요청만 보내면 응답은 언제 받아도 상관없는 상태가 됨
요청 보낸 스레드는 응답을 기다리지 않음 → Non-block 상태
스레드가 여러 요청 전송 시 더 늦게 보낸 요청이 먼저 처리됐다면 그 응답값이 먼저 올 수 있음
=> 순서 보장 X
동기식 방식보다 성능적으로 좋으나 응답에 대한 처리 결과를 보장받고 동작해야 하는 서비스에는 부적합
Ajax (Asynchronous Javascript and XML)
자바스크립트를 이용해 서버, 브라우저가 비동기 방식으로 데이터를 교환할 수 있는 통신 기능
=> 자바스크립트를 통해 서버에 데이터를 비동기 방식으로 요청
- 장점
페이지 갱신 없이 클라이언트-서버 간 비동기 통신 가능하게 함 (페이지 리로드 => 전체 리소스를 다시 불러와 불필요한 리소스 낭비 발생)
화면이 새로 로딩되는 것이 아니므로 속도, 성능 개선
별도 플러그인 사용하지 않음
http 전송 중에도 클라이언트가 웹 애플리케이션과 상호작용 가능
- 단점
히스토리 관리가 안됨
페이지 이동 없는 통신으로 인한 보안상 문제 발생 가능
연속으로 데이터 요청 시 서버 부하 발생 가능
- 사용법
$.ajax({
url : requestUrl,
type : 'DELETE',
async : true,
data : JSON.stringify(requestParam),
dataType : "json",
timeout : 10000,
contentType : "application/json",
beforeSend : function(){},
complete : function(){},
success : function(response, status, request){},
error : function(){},
fail : function(){}
});
url : 요청 url => 해당 주소로 데이터 보냄 (요청 전달)
type : 요청 방식 (get, post, put, delete)
async : 디폴트값 true (false : 동기 통신)
data : 보낼 데이터 => 받는 쪽에서는 파라미터에서 넘어온 값으로 인식, getParameter() 사용 가능 (결과 처리)
dataType : 서버에서 반환되는 데이터 형식 (text, html, xml, json, jsonp, script)
timeout : 제한시간 설정
contentType : 서버에서 데이터 보낼 때 사용 (content-type 헤더 값)
beforeSend : ajax 통신 보내기 전 실행할 함수
complete : 통신 성공 여부 상관없이 무조건 실행
success : ajax 통신 성공 시 실행할 함수 => ajax 통해 응답받은 데이터가 매개변수에 들어옴 (응답 받기)
※ success 시 함수의 매개변수
response: 응답받는 데이터 / status: http 코드 / request: 요청한 데이터
일반적으로 응답받는 데이터만 매개변수에 넣음 ex. success : function(data){..
https://developer.mozilla.org/ko/docs/Web/Guide/AJAX/Getting_Started
cf. 자바스크립트
<script>
(function() {
var httpRequest;
document.getElementById("ajaxButton").addEventListener('click', makeRequest);
function makeRequest() {
httpRequest = new XMLHttpRequest();
if(!httpRequest) {
alert('XMLHTTP 인스턴스를 만들 수가 없어요 ㅠㅠ');
return false;
}
httpRequest.onreadystatechange = alertContents; //onreadystatechange에 alertContents() 함수 설정
httpRequest.open('GET', 'test.html');
httpRequest.send();
}
function alertContents() {
try{
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText); //test.html 파일의 내용 alert
} else {
alert('request에 뭔가 문제가 있어요.');
}
}
}catch( e ) {
alert('Caught Exception: ' + e.description);
}
})();
</script>
※ 정적 HTML 파일이 아닌 XML 파일을 받기 위한 request를 보내려면 응답 헤더를 반드시 설정해야 함
헤더에 Content-Type: application/xml을 설정 X → XML 요소에 접근할 때 "Object Expected" 예외 에러 발생
※ 헤더에 Cache-Control: no-cache 설정 X
→ 브라우저는 응답 캐싱해 다시 요청 안 할 수도
※ try, catch 로 에러 방지
통신 에러 (서버 다운 등) 때 status 필드 접근 => onreadystatechange 메서드에서 예외 에러를 발생
=> try, catch문 사용
jsp, 서블릿을 이용한 Ajax 비동기 통신
뷰에서 개인정보 입력
→ AJAX로 서버에 요청 데이터 전달됨
→ 서버는 DB 연결해 결과 처리
→ 서버는 응답 데이터를 요청 페이지에 전달 (페이지 이동 X)
- 기본 데이터 교환
- ajax1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ajax1</title>
<script src="jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#sendBtn").on("click", function(){
$.ajax({
type:"get",
url:"send.jsp",
data: { pages : "1", num : "3", name : "user" },
dataType:"text",
contentType:"application/x-www-form-urlencoded;charset=UTF-8",
error:function(){console.log('오류 발생');
},
success:function(data){
console.log('통신 성공 : '+data);
$("body").append(data);
}
});
});
});
//javascript
/* function sendRequest(){
let httpRequest = new XMLHttpRequest();
httpRequest.open("GET", "send.jsp", true);
httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
httpRequest.send("page=1&num=3&name=user");
httpRequest.onreadystatechange = function(){
if(httpRequest.readyState == XMLHttpRequest.DONE && httpRequest.status == 200){
document.getElementById("text").innerHTML = httpRequest.responseText;
}
}
} */
</script>
</head>
<body>
<button id="sendBtn">ajax 전송</button>
</html>
//
콘술 => jsp 전체 내용 출력
현 페이지 => 페이지 : 1 번호 : 1 이름 : user 출력
- send.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ajax1</title>
</head>
<body>
<%
/* request객체에서 받아온 파라미터값 저장 */
String pages = request.getParameter("pages");
String num = request.getParameter("num");
String name = request.getParameter("name");
/* out 객체를 통해 응답 */
out.println("페이지 : " + pages);
out.println("번호 : " + num);
out.println("이름 : " + name);
%>
</body>
</html>
- 아이디 중복 여부 체크
- idCheck.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-3.6.0.min.js"></script>
<script>
$(function () {
$("#checkBtn").on("click", function() {
const id = $("#id").val();
if(id.length === 0 || id === null) {return alert("아이디를 입력하세요")};
$.ajax({
type:"post",
async:true, //안 적어도 기본값 true
url:"http://localhost:8070/ajax_jsp/loginCheck",
dataType:"text",
data:{id:id},
success: function(data) { //응답받은 데이터
if(data === "usable") {
$("#message").text("사용할 수 있는 ID입니다.");
$("#checkBtn").prop("disabled", true) //버튼 비활성화
} else {
$("#message").text("이미 사용 중인 아이디입니다.");
}
},
error:function () {
console.log("error");
}
});//ajax
});
});
</script>
</head>
<body>
<form method="post">
<input type="text" id="id" name="id" placeholder="아이디를 입력하세요" >
<input type="button" id="checkBtn" value="중복확인" >
</form>
<div id="message"></div>
</body>
</html>
- loginCheck
package ajax_jsp.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/loginCheck")
public class LoginCheck extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
MemberDAO dao = new MemberDAO();
String id = request.getParameter("id");
PrintWriter out = response.getWriter();
boolean checkID = dao.idCheck(id); //아이디 존재 여부 확인
if(checkID) { //결과 응답으로 전달
out.print("not-usable");
} else {
out.print("usable");
}
}
}
- MemberDAO
package ajax_jsp.ex01;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class MemberDAO {
private Connection con;
private PreparedStatement pstmt;
private DataSource ds;
//DataSource 연결
public MemberDAO() {
try {
Context context = new InitialContext();
Context envContext = (Context) context.lookup("java:/comp/env");
ds = (DataSource) envContext.lookup("jdbc/oracle");
} catch (Exception e) {
e.printStackTrace();
}
} //MemberDAO()
//아이디 존재 여부 확인
public boolean idCheck(String id) {
if(id == null || id.length() == 0) throw new NullPointerException("아이디가 없습니다.");
System.out.println("id : " + id);
String query = "select decode(count(*),1, 'true', 'false') as result from member_list where id = ?";
//1개 추출 시 'true' 반환, 해당 없으면 'false' 반환
System.out.println("query : " + query);
try {
con = ds.getConnection();
pstmt = con.prepareStatement(query);
pstmt.setString(1, id); //?에 id 세팅
ResultSet rs = pstmt.executeQuery(); //쿼리 실행, ResultSet에 추가
rs.next(); //ResultSet에서 데이터 꺼내기
String result = rs.getString(1); //1번째 컬럼 값 추출
System.out.println("result : " +result);
rs.close();
pstmt.close();
con.close();
return Boolean.parseBoolean(result); //쿼리 결과로 얻은 true / false 값 불린으로 변환 후 리턴
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
- 실시간 아이디 중복 체크
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-3.6.0.min.js"></script>
<script>
$(function () {
$("#id").on("keyup", function() { /////
const id = $("#id").val();
//if(id.length === 0 || id === null) {return alert("아이디를 입력하세요")};
$.ajax({
type:"post",
url:"http://localhost:8070/ajax_jsp/loginCheck",
dataType:"text",
data:{id:id},
success: function(data) {
if(data === "usable") {
$("#message").text("사용할 수 있는 ID입니다.");
$("#checkBtn").prop("disabled", true); //사용할 수 있는 ID => 버튼 비활성화
} else {
$("#message").text("이미 사용 중인 아이디입니다.");
$("#checkBtn").prop("disabled", false); //버튼 활성화
}
},
error:function () {
console.log("error");
}
});//ajax
});
});
</script>
</head>
<body>
<form method="post">
<input type="text" id="id" name="id" placeholder="아이디를 입력하세요" >
<input type="button" id="checkBtn" value="중복확인" >
</form>
<div id="message"></div>
</body>
</html>
=> 상단 사례와 비교했을 때 자바스크립트 이벤트 타겟(버튼 → 인풋), 종류(클릭 → 키업)만 변경하면 된다
- 실시간 자동완성
- google.html
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Google</title>
</head>
<script>
function startSuggest(){
setTimeout("sendKeyword()", 500) // 500은 0.5초
}
function sendKeyword(){
const keyword = document.search.keyword.value;
console.log(keyword)
if(keyword!=''){
let httpRequest = new XMLHttpRequest();
httpRequest.open("POST", "command.jsp", true); ////요청방식, 보내는 주소, 비동기식 여부
httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
httpRequest.send("keyword="+encodeURIComponent(keyword));
httpRequest.onreadystatechange = function(){
if(httpRequest.readyState == XMLHttpRequest.DONE && httpRequest.status == 200){
document.getElementById("suggestList").innerHTML = httpRequest.responseText; ////
}
show();
}
}else{
hide();
}
}
function show(){
const s = document.getElementById("suggest");
s.style.display = '';
}
function hide(){
const s = document.getElementById("suggest");
s.style.display = 'none';
}
</script>
<body>
<img src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"/>
<form name="search">
<input type="text" name="keyword" id="keyword" autocomplete="off" onkeydown="startSuggest()">
<div id="suggest" name="suggest">
<div id="suggestList" name="suggestList" style="padding-left: 10px;"> ////
</div>
</div>
</form>
</body>
</html>
- command.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
String keyword = request.getParameter("keyword"); ////
String[] keywords = {
"AJAX", "AJAX실전프로그래밍", "자라", "자바프로그래밍",
"자바서버페이지", "자바스터디", "자바서비스", "자바캔"};
String line = "<div>";
for(int i = 0 ; i < keywords.length; i++){
if(keywords[i].contains(keyword))
line +="<a href '" + keywords[i] + ".jsp'>" + keywords[i] + "</a><br>";
}
line+="</div>";
%><%=line%>
제이쿼리, AJAX 통한 JSON 데이터 교환
https://code.google.com/archive/p/json-simple/downloads
json-simple.jar 다운로드
- JSON
경량화된 데이터 교환 형식 (프로그래밍 언어 X 데이터 표기 방식 O)
name:value 형태의 구조 (map 구조)
객체는 중괄호 { }, 배열은 대괄호 [ ]로 감쌈
//JSONObject (JSON 객체)
[
"mycar":{"brand":"Ferrari","color":"Red","price":"65000"},
"momcar":{"brand":"Genesis","color":"Black","price":"8000"}
]
※ toJsonString() : JSON 객체 (JSONObject) → 문자열
※ stringify() : 자바스크립트 객체/값 → 문자열
※ parse() : 문자열 → 자바스크립트 객체/값
- 자바스크립트 통해 Json 객체 생성, 서블릿으로 전송
- json6.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSON 자료형</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
function fn_json(){
$.ajax({
type:"post",
url:"${contextPath}/json2",
success: function(data){ //연결 성공 시 서블릿으로부터 파라미터 받아옴
let jsonInfo=JSON.parse(data); //문자열-> 자스 객체/값
let memInfo="<h2>회원정보</h2>";
memInfo+="-------------<br>";
for (var i in jsonInfo.members){
memInfo+="이름 : " + jsonInfo.members[i].name +"<br>";
memInfo+="나이 : " + jsonInfo.members[i].age +"<br>";
memInfo+="핸드폰 : " + jsonInfo.members[i].hp +"<br>";
memInfo+="이메일 : " + jsonInfo.members[i].email +"<br><br>";
}
$("#output").html(memInfo);
},
error: function(data, textStatus){}
});
}
</script>
</head>
<body>
<input type="button" onclick="fn_json();" value="데이터를 서버로부터 전송받기">
<div id="output"></div>
</body>
</html>
- JsonServlet02
package ajax_jsp.ex02;
import java.io.IOException;
import java.io.PrintWriter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/json2")
public class JsonServlet02 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
JSONObject totObject = new JSONObject(); //전체 회원정보 배열 저장할 최종 JSONObject 객체
JSONArray memArray = new JSONArray(); //각 회원정보 객체들 HashMap 구조로 저장할 JSONArray 객체
JSONObject memberInfo = new JSONObject(); //하나의 회원정보 저장할 JSONObject 객체
memberInfo.put("name", "홍길동");
memberInfo.put("age", 50);
memberInfo.put("hp", "010-1234-5678");
memberInfo.put("email", "hong@gmail.com");
memArray.add(memberInfo);
memberInfo = new JSONObject(); //두번째 회원정보
memberInfo.put("name", "김철수");
memberInfo.put("age", 30);
memberInfo.put("hp", "010-1111-2222");
memberInfo.put("email", "kim@gmail.com");
memArray.add(memberInfo); //배열에 두 회원정보 저장
totObject.put("members", memArray); //최종 객체에 배열 저장
/*
* totObject =
*
*
* {
* "members":
* [
* {"name":"홍길동", "age":50, "hp":"010-1234-5678", "email":"hong@gmail.com"},
* {"name":"김철수", "age":30, "hp":"010-1111-2222", "email":"kim@gmail.com"}
* ]
* }
* */
String jsonStr = totObject.toJSONString(); //JSONObject 객체 -> 문자열
out.print(jsonStr);
}
}
스프링 이용한 Ajax 비동기 통신
'Programming > 국비학원' 카테고리의 다른 글
221027 - MVC - 회원정보 수정, 삭제 / 문의게시판 (미완) (0) | 2022.10.28 |
---|---|
221026 - AJAX - JSON 데이터 교환 / MVC - 회원정보 조회, 회원 등록 (0) | 2022.10.27 |
221024 - 리눅스 - GNOME, GRUB2, nautilus (0) | 2022.10.25 |
221021 - 리눅스 - 작업 스케줄링, 네트워크 명령어, 파이프/필터/리디렉션, 프로세스, 응급 복구, GRUB (0) | 2022.10.22 |
221020 - 리눅스 - 권한/소유권, 링크, 마운트, 패키지, 파일 압축 (0) | 2022.10.21 |