클라이언트는 서버에 다양한 요청을 날리게 되고
서버는 그러한 요청이 올바른 요청인지 확인을 거치고 응답을 하게 된다.
이러한 요청과 응답이 세트로 일어날 때 크게 두가지 방식으로 진행되는데
하나는 동기이고 하나는 비동기이다.
동기는 화면이 갱신된다는 특징이 있고
비동기는 화면 갱신 없이, 즉, 새로고침없이 응답을 페이지에 노출시킬 수 있다는 특징이 있다.
그리고 새로고침없이 응답을 view에 뿌려주는 작업을 해주는 대표적인 자바스크립트 라이브러리가 Ajax이다.
Ajax 는 Asynchronous Javascript And Xml의 약자이다.
JavaScript를 사용한 비동기 통신, 클라이언트와 서버간에 XML 데이터를 주고받는 기술인 셈이다.
이 Ajax를 사용하는 이유는 단순히 view단에 뿌려줄 때 화면 갱신이 없어서 그런 것은 아니다.
기본적으로 비동기라는 것은 아래와 같은 장점이 있다.
- 필요한 부분만 불러와 사용할 수 있어 불 필요한 리소스 낭비를 줄일 수 있다.
아무튼 오늘은 이 Ajax를 이용하여 DB에 접속 및 데이터를 추가/수정하는 방법을 알아보고
추가된/변경된 데이터를 새로고침(화면 깜빡임) 없이 부분 갱신하는 방법을 알아볼 것이다.
MyBatis, Thymeleaf 기준
아래는 샘플 Ajax 형식이다.
$.ajax({
// 추가 or 수정이기에 POST
type: 'POST',
url: '/컨트롤러 매핑 경로',
data: 보낼 데이터 변수,
success: function (data) {
//Ajax 통신이 성공했을 때 쓰고 싶은 로직은 여기에
}
});
우리는 여기서 ajax 요청이 제대로 통신만 됐다면 실행시킬 로직에 조건문을 달아줄 것이다.
그 조건은 data가 1일 경우이며 임의로 data가 1일 경우에만 로직을 실행하도록 만드는 것이다.
success: function (data) {
if(data === 1){
// Controller에서 응답한 값이 1이라면, 1번 조건일 경우, 실행시키는 로직
}
}
이렇게 되면 컨트롤러에서 한번 검증을 거치고 나서 원하는 로직이 올바르게 실행됐을 경우에만 1이라는 숫자를 응답하도록 할 수 있고 자바스크립트 라이브러리인 Ajax에서 추가 로직을 진행할 수 있는 것이다.
아래는 샘플 컨트롤러이다.
@ResponseBody
@PostMapping("/경로")
public Integer 함수명(@ModelAttribute Dto클래스명 Dto참조변수) {
// 서비스의 함수를 호출했을 때 리턴값이 1번인 경우 1을 응답
if(서비스 참조변수명.서비스 함수명(Dto참조변수) == 1){
return 1;
// 서비스의 함수를 호출했을 때 리턴값이 2번인 경우 2를 응답
}else if(서비스 참조변수명.서비스 함수명(Dto참조변수) == 2){
return 2;
}else{
return null;
}
}
기본적으로 Controller는 템플릿 엔진에 기반하여 resources 폴더 밑 view 파일을 띄우는 게 일반적이다.
하지만 view를 띄우는 것이 아니라 요청을 한 바로 그 곳으로 특정 데이터 타입의 값을 그대로 응답하길 바랄 때가 있을 것이다. 특정 view 를 다시 띄우는 것이 아니라 부분갱신을 하고 싶다거나, 자바스크립트 ajax에서 다른 view로 redirect 하고 싶을 때 유용할 것이다.
아무튼 @ResponseBody라는 애노테이션을 통해 원하는 값만 응답할 수 있다.
참고로 이는 @Controller 기준이며
@RestController에서는 기본적으로 @ResponseBody가 붙어있기 때문에 해당 애노테이션이 불필요하다.
아래는 샘플 서비스 혹은 서비스 impl ( a.k.a implementation)이다.
CRUD 중 Update를 하는 것을 샘플로 지정했다.
public Integer 함수명(Dto클래스명 Dto참조변수) {
if(Dto참조변수.get칼럼명==조건 1번) {
sqlSession.update("매퍼", Dto참조변수);
return 1;
}else if((Dto참조변수.get칼럼명==조건 2번){
sqlSession.update("매퍼", Dto참조변수);
return 2;
}else{
return null;
}
- 서비스에서 매퍼를 호출하고
- 매퍼에 있는 쿼리를 받아 DB에 연결하고
- DB에서 원하는 동작을 수행하고
- 조건에 따라 각각 다른 정수를 return 하게 했으니,
- return 되는 정수는 자신을 호출한 컨트롤러로 돌아 가게 되고
- 컨트롤러는 응답받은 정수에 따라 다시 호출한 Ajax에 조건에 부합하는 정수를 return 한다.
그래서 궁극적으로 1번 조건에 부합한다는 가정하에 1이라는 숫자가 return 될 것이고
1이 응답됐다면 아래 코드가 동작하게 될 것이다.
success: function (data) {
if(data === 1){
// Controller에서 응답한 값이 1이라면, 1번 조건일 경우, 실행시키는 로직
}
}
이제 추가든 수정이든 DB에 데이터를 추가/조작하는 로직을 성공적으로 실행했고 페이지에서 비동기적으로
새로고침 혹은 리로드 없이 부분적으로 갱신하는 일만 남았다.
그 방법은 놀랍게도 Ajax 안에 Ajax를 넣는 것이다.
말 그대로 처음 추가 혹은 수정 작업을 할 때의 Ajax는 그저 DB에 침투하여 원하는 작업을 하는 것이었고
원하는 작업이 성공적이었다면? 이번에는 변경된 데이터를 긁어오는 작업을 하는 것이다.
아래는 샘플 Ajax 코드이다.
if (data === 1) {
$.ajax({
type: 'GET',
url: '/경로',
success: function (data) {
$('#부분 갱신하고 싶은 DIV의 ID').replaceWith(data);
}
});
}
이제 컨트롤러를 보자.
@GetMapping("/경로")
public String 함수명(Model model) {
model.addAttribute("담을 변수", 서비스 참조변수.변경된 데이터를 가져오는 서비스 함수);
return "/HTML 이름 :: #부분 갱신하고 싶은 DIV의 ID";
}
두번째 Ajax에서 Get으로 해당 경로에 호출을 했고 해당 컨트롤러에서 변경된 데이터를 긁어오는 함수를 호출했으니
그 함수가 올바르게 작동했다면 변경된 데이터를 응답받아
key:value로 동작하는 model.addAttribute라는 메소드를 통해
지정한 변수(key)에 가져온 데이터(value)를 삽입하고
그 변수를 return하는 HTML 의 선택된 부분으로 쏴주게 되고
그 부분에서 데이터를 모두 담은 변수를 반복문을 통해 순차적으로 풀어주면?
HTML 에 선택된 부분만 새로고침 없이 갱신되는 것이다.
눈여겨볼 것은 HTML 이름 다음 :: 인데 이렇게 return 할 경우 해당 html의 특정 부분으로만 return 되는 것을 알 수 있고 Ajax에서 그 data를 받아와서 추가적으로 그 데이터를 아래처럼 특정 DIV에 갈아끼우는 것이다.
$('#부분 갱신하고 싶은 DIV의 ID').replaceWith(data);
아래는 기본적인 부트스트랩 테이블을 기준으로 변경된 데이터가 담긴 변수를 어떻게 뿌려주는지와
부분 갱신하고 싶은 곳의 ID는 어떻게 되어있는지 나와있는 HTML 샘플 코드이다.
<div class="card-box table-responsive" id="부분 갱신하고 싶은 곳의 ID">
<table class="table table-hover">
<thead>
<tr class="table-row">
<th class="table-head">1</th>
<th class="table-head">2</th>
<th class="table-head">3</th>
</tr>
</thead>
<tbody class="table-content">
<tr th:each="반복 변수(상태변수) : ${컨트롤러에서 응답받은 데이터를 담은 변수}">
<td th:text="${반복 변수.칼럼명}"></td>
<td th:text="${반복 변수.칼럼명}"></td>
<td th:text="${반복 변수.칼럼명}"></td>
</tr>
</tbody>
</table>
</div>
위 코드에 나온 것 처럼 컨트롤러에서 응답받은 값을 한 테이블을 크게 묶어주는 DIV의 ID에 연결시켰고
//컨트롤러
return "/HTML 이름 :: #부분 갱신하고 싶은 DIV의 ID";
//HTML 안의 DIV ID
<div class="card-box table-responsive" id="부분 갱신하고 싶은 DIV의 ID">
그 응답받은 값을 모아서 담은 변수를 table row를 나타내는 tr에서 th:each 라는 반복문을 통해 반복 변수에 담아주었다.
//컨트롤러
model.addAttribute("담을 변수", 서비스 참조변수.변경된 데이터를 가져오는 서비스 함수);
// HTML 안의 TABLE 안의 TR
<tr th:each="반복 변수(상태변수) : ${컨트롤러에서 응답받은 데이터를 담은 변수}">
이후 table data를 나타내는 td에 반복 변수.칼럼명으로 순차적으로 표시하는 것을 볼 수 있다.
아래는 예시이다.
<tr th:each="product : ${productList}">
<td th:text="${product.name}"></td>
<td th:text="${product.price}"></td>
<td th:text="${product.size}"></td>
끗
'개발자 전향 프로젝트' 카테고리의 다른 글
Querydsl + Spring 3.0 + Java17 업데이트 내용! [Maven+Gradle] (10) | 2022.12.20 |
---|---|
[JAVA] JPA 활용법 -2 (QueryDSL 활용해보기) (0) | 2022.12.06 |
[마이바티스+오라클] 검색할 때 종종 막히는 바인딩 변수 (0) | 2022.11.07 |
프레임워크와 라이브러리의 차이가 뭔가요? [ 면접 질문 ] (0) | 2022.10.29 |
[SpringBoot Data JPA] 중복은 있을 수 없어 -1 (0) | 2022.10.26 |