오늘 게시물에서는 Ajax를 이용한 검색기능 구현을 설명 하도록 하겠습니다.
우선 Ajax란?
-Ajax(Asynchronous JavaScript and XML, 에이잭스)는 비동기적인 웹 애플리케이션의 제작을 위해 아래와 같은 조합을 이용하는 웹 개발 기법입니다.(위키백과) 즉 서버에서 자료를 요청한뒤 뷰에서 다시 보여질 시 새로고침없이 비동기 식으로 뿌리는 식의 기법입니다. 이는 서버로의 접근 횟수를 줄여 준다는 장점이 있습니다.
하지만 지원하지 않는 브라우저가 있다는 점, 남발 시 서버 부하가 걸릴 수 있다는 점 등 단점이 있습니다.
우선 제가 짠 코드들의 동작 순서는 다음과 같습니다.
1. list.jsp 에서 검색창에 문자를 입력하거나 검색 버튼을 누르면 List.js에 설정해놓은
searchFunction() 를 실행 시켜 SearchListController로 이동합니다
2.SearchListController 에서 해당 input 값을 파라미터로 받아 boardDAO의 메소드에 값을 넣어
해당 입력값에 맞는 제목을 가진 글들을 리턴값으로 받아 JSON 형식으로 변환 시킨 후
List.js 단으로 뿌려준 후 JSON 형식의 데이터를 파싱하여 LIst.jsp 에 보여준다.
다음은 코드로 한번 보겠습니다.
List.js
var request = new XMLHttpRequest();
function searchFunction() {
request.open("Post", "./SearchListController?bwriter="+ encodeURIComponent(document.getElementById("bwriter").value),true);
request.onreadystatechange = searchProcess;
request.send(null);
}
function searchProcess() {
var table= document.getElementById("list_table");
var tableHTML =""
console.log(request.readyState);
if(request.readyState ==4 && request.status ==200 ) {
console.log("request.responseText는 :"+request.responseText);
var obj = JSON.parse(request.responseText);
for(var i = 0; i < obj.inf.length ; i++) {
var bid = obj.inf[i]["bid"];
var order = i+1;
var btitle = obj.inf[i]["btitle"];
var bwriter= obj.inf[i]["bwriter"];
var bdate = obj.inf[i]["bdate"];
var hit = obj.inf[i]["hit"];
tableHTML+= "<tr><td>"+order+"</td>";
tableHTML+= "<td onclick='detail("+bid+")'><a>"+btitle+"</a></td>";
tableHTML+= "<td>"+bwriter+"</td>";
tableHTML+= "<td>"+bdate+"</td>";
tableHTML+= "<td>"+hit+"</td></tr>";
}
table.innerHTML =tableHTML;
}
}
SearchListController.java
package list.controller;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import board.model.BoardDAO;
import board.model.BoardVo;
@WebServlet("/SearchListController")
public class SearchListController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset = UTF-8");
String bwriter = request.getParameter("bwriter");
response.getWriter().write(jsonadd(bwriter));
}
public String jsonadd(String userName) {
String json = "";
BoardDAO boardDAO = new BoardDAO();
ArrayList<BoardVo> boardList = new ArrayList<>();
boardList = boardDAO.searchBoard(userName);
SimpleDateFormat transFormat = new SimpleDateFormat("yyyy-MM-dd");
JSONArray innerList = new JSONArray();
JSONObject outer = new JSONObject();
for(int i = 0 ; i< boardList.size() ; i++) {
String bdate = transFormat.format(boardList.get(i).getBdate());
JSONObject inner = new JSONObject();
inner.put("bid", boardList.get(i).getBid());
inner.put("btitle",boardList.get(i).getBtitle());
inner.put("bwriter", boardList.get(i).getBwriter());
inner.put("bdate", bdate);
inner.put("hit",boardList.get(i).getHit());
System.out.println("inner : "+inner);
innerList.add(i, inner);
}
System.out.println("innerList : "+innerList);
// JSON객체를 String으로 변환
outer.put("inf", innerList);
json += outer.toJSONString();
System.out.println("생성된 제이슨 : "+json);
return json;
}
}
동작 순서대로 코드를 보겠습니다.
function searchFunction() {
request.open("Post", "./SearchListController?bwriter="+ encodeURIComponent(document.getElementById("bwriter").value),true);
request.onreadystatechange = searchProcess; request.send(null);
}
1. input에 값이나 검색 버튼을 눌렀을 시
우선 해당 코드를 보면 request.open("전송방식","요청보낼 주소",비동기통신 여부) 의 인자를 갖습니다.
/SearchListController에 bwriter의 내용을 bwriter변수에 담아 파라미터를 비동기 POST 방식으로 보내겠다라는 의미 입니다.
그후 request.onreadystatechange = searchProcess 는 서버로 부터 응답이 오면 searchProcess라는 함수를 동작 시키겠다는 코드입니다.
다음 request.send(null) 은 ajax에 대한 요청을 서버로 전달하는 메소드입니다. 지금 상황에서는 서버로 전송 할 내용이 없으므로 null값으로 두겠습니다.
2. 그 후 요청 받은 SearchListController를 보겠습니다.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset = UTF-8");
String bwriter = request.getParameter("bwriter");
response.getWriter().write(jsonadd(bwriter));
}
우선 포스트를 받아 수행하는 부분에서 요청인코딩을 해주고 js에서 날라온 파라미터 변수를 bwriter에 넣어 줍니다.
그후 응답을 해주는데 jsonadd라는 메소드에 bwriter를 매개변수로 넣어 나온 리턴값을 같이 넘겨주겠다는 코드입니다.
JSON 형식 데이터를 만들기 전에
mvnrepository.com/artifact/com.googlecode.json-simple/json-simple/1.1.1
에 접속하여 자바에서 JSON 형식 데이터를 쉽게 다루기 위한 json-simple.jar를 다운 받아줍니다.
여기서 View All를 눌러 다운 받아준 후 진행하고 있는 프로젝트의 lib 폴더에 복사 해줍니다.
jsonadd에서는
boardDAO 객체, DAO에서 퀴리 실행 결과 값을 저장해 줄 ArrayList 를 설정해줍니다. DATE 타입을 String 타입으로 변환 시켜줄 DateFormat 객체도 하나 만들어 줍니다. ( JSON에 DATE 형식을 그대로 넣으려니 오류가 떠서 바꿔주게 되었습니다.) 그리고 검색 결과가 여러개가 나올 수 있으므로 JSONArray 객체를 만들어 줍니다.
그리고 JSONObject 형의 outer를 선언해 줍니다.
JSON 데이터를 만들 떄는 그냥 하나의 Object에 넣어 전송해도되지만 혹시나의 오류를 방지하기위해
inner outer 두 객체를 만든 후 inner db정보를 JSON 형식으로 바꾸어 넣어놓고 데이터 변환이 끝난 뒤 outer에 그 정보를 넣은 후 스트링으로 변환하여 응답해주는 방식으로 하겠습니다.
public String jsonadd(String userName) {
String json = "";
BoardDAO boardDAO = new BoardDAO();
ArrayList<BoardVo> boardList = new ArrayList<>();
boardList = boardDAO.searchBoard(userName);
SimpleDateFormat transFormat = new SimpleDateFormat("yyyy-MM-dd");
JSONArray innerList = new JSONArray();
JSONObject outer = new JSONObject();
for(int i = 0 ; i< boardList.size() ; i++) {
String bdate = transFormat.format(boardList.get(i).getBdate());
JSONObject inner = new JSONObject();
inner.put("bid", boardList.get(i).getBid());
inner.put("btitle",boardList.get(i).getBtitle());
inner.put("bwriter", boardList.get(i).getBwriter());
inner.put("bdate", bdate);
inner.put("hit",boardList.get(i).getHit());
System.out.println("inner : "+inner);
innerList.add(i, inner);
}
System.out.println("innerList : "+innerList);
// JSON객체를 String으로 변환
outer.put("inf", innerList);
json += outer.toJSONString();
System.out.println("생성된 제이슨 : "+json);
return json;
}
for(int i = 0 ; i< boardList.size() ; i++) {
String bdate = transFormat.format(boardList.get(i).getBdate());
JSONObject inner = new JSONObject();
inner.put("bid", boardList.get(i).getBid());
inner.put("btitle",boardList.get(i).getBtitle());
inner.put("bwriter", boardList.get(i).getBwriter());
inner.put("bdate", bdate);
inner.put("hit",boardList.get(i).getHit());
System.out.println("inner : "+inner);
innerList.add(i, inner);
}
boardDAO로 부터 검색 결과를 리턴받아 boardList에 담은 후 inner객체에 그 결과 값을 하나 씩 넣어 줍니다.
JSONObject 객체는 Map과 같이 (Key,value) 형식입니다.
inner객체 생성 후 각각의 데이터들을 inner. 안으로 넣어줍니다.
for문을 다 돈 후 inner를 찍어보면 다음과 같이 나옵니다.
inner : {"hit":4,"bdate":"2021-04-11","btitle":"검색되낭","bid":67,"bwriter":"박가은"}
검색 결과 값이 여러개면 inner에 여러개의 값이 들어가 있습니다. 이를 innerrList에 넣어줍니다.
outer.put("inf", innerList);
json += outer.toJSONString();
System.out.println("생성된 제이슨 : "+json);
return json;
for문을 다 돌고 난 후 outer에 값들을 저장해놓은 innerList를 inf라는 키로 넣습니다.
그 후 String json 에 해당 outer를 String으로 변환 후 넣습니다.
여기서 json을 찍어보면
생성된 제이슨 : {"inf":[{"hit":4,"bdate":"2021-04-11","btitle":"검색되낭","bid":67,"bwriter":"박가은"}]}
이 나옵니다. 이 json 형식을 return해주어 위
response.getWriter().write(jsonadd(bwriter));
부분을 통해 List.js로 응답합니다.
응답을 받은 후 onreadystatechange를 통해 searchProcess 함수를 실행시킵니다.
function searchFunction() {
request.open("Post", "./SearchListController?bwriter="+ encodeURIComponent(document.getElementById("bwriter").value),true);
request.onreadystatechange = searchProcess;
request.send(null);
}
function searchProcess() {
var table= document.getElementById("list_table");
var tableHTML =""
console.log(request.readyState);
if(request.readyState ==4 && request.status ==200 ) {
console.log("request.responseText는 :"+request.responseText);
var obj = JSON.parse(request.responseText);
for(var i = 0; i < obj.inf.length ; i++) {
var bid = obj.inf[i]["bid"];
var order = i+1;
var btitle = obj.inf[i]["btitle"];
var bwriter= obj.inf[i]["bwriter"];
var bdate = obj.inf[i]["bdate"];
var hit = obj.inf[i]["hit"];
tableHTML+= "<tr><td>"+order+"</td>";
tableHTML+= "<td onclick='detail("+bid+")'><a>"+btitle+"</a></td>";
tableHTML+= "<td>"+bwriter+"</td>";
tableHTML+= "<td>"+bdate+"</td>";
tableHTML+= "<td>"+hit+"</td></tr>";
}
table.innerHTML =tableHTML;
}
}
searchProcess()
List.jsp 의 tbody에 id 값을 주어 변수로 선언해줍니다.
if(request.readyState ==4 && request.status ==200 )
request.readyState 결과에 따라 수행해줍니다.
request.readyState는 다음과 같습니다.
console.log(readyState)하여
검색 input 창에 글을 작성해보면 다음과 같이 1,2,3,4 가 순서대로 동작하는것을 볼 수 있습니다.
if(request.readyState ==4 && request.status ==200 ) {
console.log("request.responseText는 :"+request.responseText);
var obj = JSON.parse(request.responseText);
for(var i = 0; i < obj.inf.length ; i++) {
var bid = obj.inf[i]["bid"];
var order = i+1;
var btitle = obj.inf[i]["btitle"];
var bwriter= obj.inf[i]["bwriter"];
var bdate = obj.inf[i]["bdate"];
var hit = obj.inf[i]["hit"];
tableHTML+= "<tr><td>"+order+"</td>";
tableHTML+= "<td onclick='detail("+bid+")'><a>"+btitle+"</a></td>";
tableHTML+= "<td>"+bwriter+"</td>";
tableHTML+= "<td>"+bdate+"</td>";
tableHTML+= "<td>"+hit+"</td></tr>";
}
table.innerHTML =tableHTML;
}
응답이 정상적으로 되엇을 시 request.responseText를 통해 서블릿에서 보낸 String json을 받아
JSON.parse를 통해 파싱 해줍니다.
이때 json를 console.log(obj) 해보면
{"inf":[{"hit":7,"bdate":"2021-04-11","btitle":"아~ 무료하당","bid":66,"bwriter":"박천규"},{"hit":17,"bdate":"2021-04-09","btitle":"테스트2","bid":65,"bwriter":"박천규"}]}
로 나옵니다 이를 JSON 형식으로 보면(jsonlint.com/) 밑 사이트에서 해당 String이 올바른 JSON 형식인지 확인 할 수 있습니다.
The JSON Validator
JSONLint is the free online validator and reformatter tool for JSON, a lightweight data-interchange format.
jsonlint.com
{
"inf": [{
"hit": 7,
"bdate": "2021-04-11",
"btitle": "아~ 무료하당",
"bid": 66,
"bwriter": "박천규"
}, {
"hit": 17,
"bdate": "2021-04-09",
"btitle": "테스트2",
"bid": 65,
"bwriter": "박천규"
}]
}
구조를 보면 obj라는 변수 안에 inf라는 이름의 가진 배열 안에 2개의 데이터가 들어있습니다.
이에 접근 하기 위해서는
obj.inf[i]["변수명"] 을 해주면됩니다.
obj 안에 inf배열 안 i번째 데이터의 변수명의 있는 데이터을 가져오겠다가 되겠습니다.
이를 이용해 배열 inf의 길이 만큼 for문을 돌려 안에 있는 데이터를
table 안에 입력해주면 됩니다. 또한 btitle부분에 onclick 함수를 써 제목 클릭 시
detail정보를 볼 수 있게 하였습니다.
원래 list.jsp에서처럼 a태그로 링크를 걸려고 했으나.. 오류가 떠 onclick 형식으로 바꿧습니다.
추후 오류를 잡으면 수정 하겠습니다.
for(var i = 0; i < obj.inf.length ; i++) {
var bid = obj.inf[i]["bid"];
var order = i+1;
var btitle = obj.inf[i]["btitle"];
var bwriter= obj.inf[i]["bwriter"];
var bdate = obj.inf[i]["bdate"];
var hit = obj.inf[i]["hit"];
tableHTML+= "<tr><td>"+order+"</td>";
tableHTML+= "<td onclick='detail("+bid+")'><a>"+btitle+"</a></td>";
tableHTML+= "<td>"+bwriter+"</td>";
tableHTML+= "<td>"+bdate+"</td>";
tableHTML+= "<td>"+hit+"</td></tr>";
}
function detail(bid) {
location.href="/list/detail?bid="+bid;
}
자 이런식으로 작성 후 서버를 돌려 검색창에 입력 해보시면
입력한 값에 맞는 제목의 글들이 나오시는걸 확인 할 수 있습니다.!
자! 이렇게 ajax를 활용한 검색기능에 대해서 알아봤는데요! 저도 이번에 ajax를 처음 써보는거라 삽질도 많이하고 어려움을 많이 겪었습니다..ㅠㅠ 마땅히 어디에다 적용해야 좋을지도 많이 헤맸습니다. 그러던 중 검색기능에 많이 쓰신다고하여 접목하게되었습니다. 다음에는 더 많이 공부하여 다양한 부분에 접목해보겠습니다.
언제나 질문과 피드백은 환영입니다.!
'자바 > JSP기초(이클립스)' 카테고리의 다른 글
JSP 게시판 만들기 No7 (0) | 2021.04.13 |
---|---|
JSP 게시판 만들기 No6 (0) | 2021.04.12 |
JSP 게시판 만들기 No4 (0) | 2021.04.11 |
JSP 게시판 만들기 No3 (0) | 2021.04.09 |
JSP 게시판 만들기 No2 (0) | 2021.04.09 |