일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Ajax
- 스프링
- 미로 생성 알고리즘
- Linked List
- 회원가입
- jsp
- 백엔드
- 웹서비스
- html5
- mybatis
- MVC
- 비밀번호찾기
- c programming
- 제이쿼리
- 오라클
- spring
- jQuery
- 웹개발
- dbms
- 마이바티스
- 풀스택
- javascript
- 로그인
- 프레임워크
- 서블릿
- 네비게이터
- Binding
- css3
- 프론트엔드
- 웹페이지
- Today
- Total
Programmer's Progress
도서 정보 제공 웹 서비스 - 메세지 보관함 구현하기 본문
메시지 보관함을 구현하기에 앞서 먼저 메시지 관련 DB 스키마를 변경했음을 밝힌다.

먼저 기존에는 SYS_GUID( ) 함수를 이용하여 중복될 확률이 거의 없는 난수 값을 사용하여
메시지 ID로 사용했었다. 물론, 이 방식도 나쁘지 않다고 생각했지만, 사용하면 할수록 불편하다는
느낌을 많이 받았다. 디버깅도 그렇고, DB 질의를 할 때에도 16바이트 난수 값을 가지고 처리하려니
상당히 어려웠다.
따라서 이를 INT타입으로 변경했는데, 사실 엄청 대단하고 규모가 큰 서비스도 아니고
간단한 웹 서비스를 구축하려는 것이기에, 게시글이며 메시지며 그 숫자가 21억을 넘지는 않을 것이라
판단하고 INT타입으로 데이터 타입을 변경했다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/LibraryService/resource/js/jquery.js"></script>
<script src="/LibraryService/resource/js/jquery-ui.js"></script>
<script src="/LibraryService/resource/js/jquery-cookie.js"></script>
<script src="/LibraryService/resource/js/receiveMessage.js"></script>
<link href="../css/receiveMessage.css" rel="stylesheet">
<title>메세지 받기</title>
</head>
<body>
<jsp:include page="/resource/jsp/sidebar.jsp"></jsp:include>
<c:if test= "${sessionScope.CUSTOMER == null}">
<jsp:forward page="/resource/jsp/main.jsp"/>
</c:if>
<div id="container" style="overflow: scroll;">
<div id="TOP_PANEL">
<div id="DELETE_BUTTON">삭제</div>
<input id="SEARCH"type="text" placeholder="메세지 검색" autocomplete="off" name="MESSAGE_SEARCH">
<div id="SEARCH_BUTTON">검색</div>
<div id="MESSAGE_SENT">송신</div>
<div id="MESSAGE_RECEIVED">수신</div>
</div>
<table id="LIST">
</table>
<div id="paging"></div>
</div>
</body>
</html>
위의 JSP코드에서 id가 LIST인 table태그에 메시지들을 동적으로 나타낼 것이다.
이때, 중요한 것은 동기 방식으로 메세지를 얻을 것인지, 비동기 방식으로 얻을 것인지를 고려해야 한다.
경험상, 동기방식으로 구현하게 되면 JS코드가 간단해질 수는 있겠지만, 그만큼 JSTL을 이용해서 메시지 목록을
보여주어야 하므로 JSP코드가 길어지고, 무엇보다도 페이지 새로고침이 발생하는 불편함을 겪을 것이다.
따라서 비동기 방식으로 페이지 새로고침 없이, 제이쿼리의 AJAX 메서드를 이용하여 컨트롤러에 메시지를 요청한다.
function receiveMessage(MESSAGE_BOX, ORDER_BY, section, page){
$.ajax({
"url":"/LibraryService/message/receiveMessage.do",
"dataType":"JSON",
"type":"POST",
"data":{
"MESSAGE_BOX":MESSAGE_BOX,
"ORDER_BY":ORDER_BY,
"section":section,
"page":page,
"SEARCH":SEARCH
},
"success":function(result){
checkAll=false;
if(result[0].FLAG=="TRUE"){
var TOTAL = result[0].TOTAL;
var i;
$("#LIST").empty();
$("#LIST").append("<tr class='row'><td class='col' id='SELECT_ALL_BUTTON'>전체</td><td class='col' id='FLAG'>"+(MESSAGE_BOX=="MESSAGE_RECEIVED"?"송신자":"수신자")+"</td><td id='TITLE' class='col'>제목</td><td id='DATE' class='col'>보낸시각</td></tr>");
for(i=1;i<result.length;i++){
var tr = $("<tr></tr>");
tr.append("<td><input type='checkbox' class='check' value='"+result[i].MESSAGE_ID+"'></td>");
tr.append("<td>"+result[i].CUSTOMER_ID+"</td>");
tr.append("<td><a href='#'>"+result[i].MESSAGE_TITLE+"</a></td>");
tr.append("<td>"+result[i].MESSAGE_DATE_STRING+"</td>");
$("#LIST").append(tr);
}
var maxSection = Math.ceil(TOTAL/100);
var maxPage = Math.ceil((TOTAL-(section-1)*100)/10)>=10?10:Math.ceil((TOTAL-(section-1)*100)/10);
$("#paging").off();
$("#paging").empty();
var tag;
if(section>=2){
tag = $("<a id='prev'>이전</a>");
$("#paging").on("click","#prev",function(){
section--;
page=1;
receiveMessage(MESSAGE_BOX, ORDER_BY, section, page);
})
$("#paging").append(tag);
}
for(var i=1; i<=maxPage;i++){
$("#paging").append($("<a id='idx"+i+"' value='"+i+"'>"+i+"</a>"));
$("#paging").on("click","#idx"+i,function(){
receiveMessage(MESSAGE_BOX, ORDER_BY, section, $(this).attr("value"))
page = $(this).attr("value");
})
}
$("#paging a").removeClass("active");
$("#idx"+page).addClass("active");
if(section<maxSection){
tag = $("<a id='next'>다음</a>");
$("#paging").on("click","#next",function(){
section++;
page=1;
receiveMessage(MESSAGE_BOX, ORDER_BY, section, page);
})
$("#paging").append(tag);
}
}else{
alert(result[0].CONTENT);
$("#LIST").empty();
$("#LIST").append("<tr class='row'><td class='col' id='SELECT_ALL_BUTTON'>전체</td><td class='col' id='FLAG'>"+(MESSAGE_BOX=="MESSAGE_RECEIVED"?"송신자":"수신자")+"</td><td id='TITLE' class='col'>제목</td><td id='DATE' class='col'>보낸시각</td></tr>");
}
},
"error":function(){
alert("에러");
}
});
}
JS 소스코드의 일부분, 컨트롤러에 메세지 목록을 요청할 때 전달하는 파라미터들은 다음과 같다.
1. 송신, 수신 메시지 여부
말 그대로 송신메시지를 조회할 것인지, 수신한 메시지를 조회할 것인지를 구분한다.
2. 섹션
1개의 섹션에는 최대 10개의 페이지가 존재한다.
3. 페이지
1개의 페이지에는 최대 10개의 메시지가 존재한다.
섹션과 페이지에 대해서는 이후에 설명한다.
4. 순서
메시지 제목, 메시지를 받는, 혹은 보낸 사람의 ID, 메시지를 보낸 날짜 등등
메시지의 애트리뷰트에 대해서 오름차, 내림차 순으로 정렬할 때 사용한다.
5. 검색 값
메시지 중에서 제목이나 내용, 수신자, 송신자 중에서 특정 값이 포함된 메시지를 조회할 때 사용한다.
package message;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.ArrayList;
import javax.servlet.ServletConfig;
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 customer.CustomerVO;
@WebServlet("/message/*")
public class MessageController extends HttpServlet {
MessageService messageServiceDAO;
public void init(ServletConfig config) throws ServletException {
messageServiceDAO = new MessageService();
}
public void destroy() {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
public void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
request.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
//컨트롤러에서 기능을 구분
String action = request.getPathInfo();
//메세지 전송
if(action.equals("/sendMessage.do")) {
PrintWriter out = response.getWriter();
CustomerVO CUSTOMER = (CustomerVO)request.getSession().getAttribute("CUSTOMER");
if(CUSTOMER!=null) {
JSONArray array = messageServiceDAO.sendMessage(CUSTOMER.getCUSTOMER_ID(), request.getParameter("RECEIVER_ID"), request.getParameter("MESSAGE_TITLE"), request.getParameter("MESSAGE_CONTENT"));
out.print(array);
}else {
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
json.put("FLAG", "LOGOFF");
json.put("CONTENT", "로그인 정보가 유효하지 않습니다.");
array.add(json);
out.print(array);
}
out.flush();
out.close();
}else if(action.equals("/receiveMessage.do")) {
PrintWriter out = response.getWriter();
CustomerVO CUSTOMER = (CustomerVO)request.getSession().getAttribute("CUSTOMER");
if(CUSTOMER!=null) {
int section, page;
try {
section = Integer.parseInt(request.getParameter("section"));
page = Integer.parseInt(request.getParameter("page"));
}catch(Exception e) {
section=1;
page=1;
e.printStackTrace();
}
ArrayList<MessageVO> list = messageServiceDAO.getMessageList(request.getParameter("MESSAGE_BOX"),CUSTOMER.getCUSTOMER_ID(),section,page, request.getParameter("SEARCH"),request.getParameter("ORDER_BY"));
int TOTAL = messageServiceDAO.getArticlesCount(CUSTOMER.getCUSTOMER_ID(),request.getParameter("MESSAGE_BOX"), request.getParameter("SEARCH"));
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
json.put("FLAG", "TRUE");
json.put("CONTENT", "메세지 조회에 성공했습니다.");
json.put("TOTAL", TOTAL);
array.add(json);
String targetID;
String MESSAGE_BOX = request.getParameter("MESSAGE_BOX");
for(int i=0;i<list.size();i++) {
MessageVO message = list.get(i);
json = new JSONObject();
json.put("FLAG", "TRUE");
json.put("MESSAGE_ID", message.getMESSAGE_ID());
if(MESSAGE_BOX.equals("MESSAGE_RECEIVED")) {
json.put("CUSTOMER_ID", message.getSENDER_ID());
}else {
json.put("CUSTOMER_ID", message.getRECEIVER_ID());
}
json.put("MESSAGE_TITLE", message.getMESSAGE_TITLE());
json.put("MESSAGE_CONTENT", message.getMESSAGE_CONTENT());
json.put("MESSAGE_DATE_STRING",message.getMESSAGE_DATE_STRING());
array.add(json);
}
out.print(array);
}else {
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
json.put("FLAG", "FALSE");
json.put("CONTENT", "로그인 정보가 유효하지 않습니다.");
array.add(json);
out.print(array);
}
out.flush();
out.close();
}else if(action.equals("/deleteMessage.do")) {
MessageDAO dao = new MessageDAO();
PrintWriter out = response.getWriter();
CustomerVO CUSTOMER = (CustomerVO)request.getSession().getAttribute("CUSTOMER");
if(CUSTOMER!=null) {
JSONArray array = dao.deleteMessage(request.getParameter("MESSAGE_BOX"),request.getParameter("MESSAGE_ID"));
out.print(array);
}else {
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
json.put("FLAG", "FALSE");
json.put("CONTENT", "로그인 정보가 유효하지 않습니다.");
array.add(json);
out.print(array);
}
out.flush();
out.close();
}else if(action.equals("/readMessage.do")) {
}
}
}
메시지와 관련한 요청을 처리할 컨트롤러의 소스코드다.
비동기 방식으로 처리 결과를 JSON의 형태로 전달한다.
이러한 요청을 실제로 수행하는 코드는 DAO클래스다.
package message;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class MessageDAO {
private DataSource dataSource;
public MessageDAO() {
try {
Context context = new InitialContext();
Context envContext = (Context) context.lookup("java:/comp/env");
dataSource = (DataSource) envContext.lookup("jdbc/oracle");
} catch (Exception e) {
e.printStackTrace();
}
}
public JSONArray sendMessage(String SENDER_ID, String RECEIVER_ID, String MESSAGE_TITLE, String MESSAGE_CONTENT) {
Connection connection;
PreparedStatement pstmt;
ResultSet rs;
String result=null;
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
try {
String query ="";
query += "SELECT CUSTOMER_ID RECEIVER_ID ";
query += "FROM CUSTOMER ";
query += "WHERE CUSTOMER_ID = '"+RECEIVER_ID+"'";
connection = dataSource.getConnection();
pstmt = connection.prepareStatement(query);
rs = pstmt.executeQuery();
if(rs.next()) {
result = rs.getString("RECEIVER_ID");
}
rs.close();
pstmt.close();
if(result == null) {
connection.close();
json.put("FLAG","FALSE");
json.put("CONTENT","해당 사용자의 아이디 정보가 없습니다.");
array.add(json);
return array;
}else {
query="INSERT INTO MESSAGE_SENT VALUES(?,?,?,?,?,SYSDATE)";
pstmt = connection.prepareStatement(query);
pstmt.setInt(1, getNewMessageID("MESSAGE_SENT"));
pstmt.setString(2, SENDER_ID);
pstmt.setString(3, RECEIVER_ID);
pstmt.setString(4, MESSAGE_TITLE);
pstmt.setString(5, MESSAGE_CONTENT);
pstmt.execute();
pstmt.close();
query="INSERT INTO MESSAGE_RECEIVED VALUES(?,?,?,?,?,SYSDATE)";
pstmt = connection.prepareStatement(query);
pstmt.setInt(1, getNewMessageID("MESSAGE_RECEIVED"));
pstmt.setString(2, SENDER_ID);
pstmt.setString(3, RECEIVER_ID);
pstmt.setString(4, MESSAGE_TITLE);
pstmt.setString(5, MESSAGE_CONTENT);
pstmt.execute();
rs.close();
pstmt.close();
connection.close();
json.put("FLAG","TRUE");
json.put("CONTENT","메세지를 전송했습니다.");
array.add(json);
return array;
}
} catch (Exception e) {
json.put("FLAG","ERROR");
json.put("CONTENT","오류가 발생했습니다.");
array.add(json);
e.printStackTrace();
return null;
}
}
public int getMessagesCount(String CUSTOMER_ID, String MESSAGE_BOX, String SEARCH) {
Connection connection;
PreparedStatement pstmt;
ResultSet rs;
String result=null;
String CUSTOMER, tCUSTOMER;
int num=-1;
if(MESSAGE_BOX.equals("MESSAGE_RECEIVED")) {
CUSTOMER = "RECEIVER_ID";
tCUSTOMER = "SENDER_ID";
}else {
CUSTOMER = "SENDER_ID";
tCUSTOMER="RECEIVER_ID";
}
try {
connection = dataSource.getConnection();
String query ="";
query += "SELECT COUNT(*) FROM "+MESSAGE_BOX+" WHERE "+CUSTOMER+"='"+CUSTOMER_ID+"' AND ("+tCUSTOMER+" LIKE '%"+SEARCH+"%' OR MESSAGE_TITLE LIKE '%"+SEARCH+"%' OR MESSAGE_CONTENT LIKE '%"+SEARCH+"%')";
pstmt = connection.prepareStatement(query);
rs = pstmt.executeQuery();
if(rs.next()) {
num = rs.getInt(1);
}
pstmt.close();
connection.close();
return num;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
public ArrayList<MessageVO> getMessageList(String MESSAGE_BOX, String CUSTOMER_ID, int section, int page, String SEARCH, String ORDER_BY) {
Connection con;
PreparedStatement pstmt;
ResultSet rs;
String result=null;
String CUSTOMER, tCUSTOMER, query;
ArrayList<MessageVO> list = new ArrayList<>();
if(MESSAGE_BOX.equals("MESSAGE_RECEIVED")) {
CUSTOMER = "RECEIVER_ID";
tCUSTOMER = "SENDER_ID";
}else {
CUSTOMER = "SENDER_ID";
tCUSTOMER = "RECEIVER_ID";
}
try {
query="";
query+="SELECT IDX, MESSAGE_ID, SENDER_ID, RECEIVER_ID, MESSAGE_TITLE, MESSAGE_CONTENT, TO_CHAR(MESSAGE_DATE,'YYYY.MM.DD / HH24:MI:SS') MESSAGE_DATE_STRING ";
query+="FROM (SELECT ROWNUM IDX, MESSAGE_ID, SENDER_ID, RECEIVER_ID, MESSAGE_TITLE, MESSAGE_CONTENT, MESSAGE_DATE FROM (SELECT * FROM "+MESSAGE_BOX+" ORDER BY "+ORDER_BY+") WHERE "+CUSTOMER+"='"+CUSTOMER_ID+"' AND (MESSAGE_TITLE LIKE '%"+SEARCH+"%' OR MESSAGE_CONTENT LIKE '%\"+SEARCH+\"%' OR "+tCUSTOMER+" LIKE '%\"+SEARCH+\"%') ORDER BY "+ORDER_BY+") ";
query+="WHERE IDX >= "+(((section-1)*100)+((page-1)*10)+1)+" AND IDX <= "+((section-1)*100+(page)*10)+" ";
con = dataSource.getConnection();
pstmt = con.prepareStatement(query);
rs = pstmt.executeQuery();
while(rs.next()) {
MessageVO message = new MessageVO();
message.setMESSAGE_ID(rs.getInt("MESSAGE_ID"));
message.setMESSAGE_TITLE(rs.getString("MESSAGE_TITLE"));
message.setMESSAGE_CONTENT(rs.getString("MESSAGE_CONTENT"));
message.setSENDER_ID(rs.getString("SENDER_ID"));
message.setRECEIVER_ID(rs.getString("RECEIVER_ID"));
message.setMESSAGE_DATE_STRING(rs.getString("MESSAGE_DATE_STRING"));
list.add(message);
}
rs.close();
pstmt.close();
con.close();
return list;
} catch (Exception e) {
e.printStackTrace();
return list;
}
}
public int getNewMessageID(String MESSAGE_BOX) {
Connection con;
PreparedStatement pstmt;
ResultSet rs;
int num=0;
try {
con = dataSource.getConnection();
String query ="SELECT MAX(MESSAGE_ID) FROM "+MESSAGE_BOX;
pstmt = con.prepareStatement(query);
rs = pstmt.executeQuery();
if(rs.next()) {
num = rs.getInt(1);
}
rs.close();
pstmt.close();
con.close();
return num+1;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
public JSONArray deleteMessage(String MESSAGE_BOX,String MESSAGE_ID) {
Connection connection;
PreparedStatement pstmt;
String result=null;
String CUSTOMER;
JSONArray array = new JSONArray();
JSONObject json = new JSONObject();
if(MESSAGE_BOX.equals("MESSAGE_RECEIVED")) {
CUSTOMER = "RECEIVER_ID";
}else {
CUSTOMER = "SENDER_ID";
}
try {
connection = dataSource.getConnection();
String query ="";
query += "DELETE ";
query += "FROM "+MESSAGE_BOX+" ";
query += "WHERE MESSAGE_ID = ?";
String[] arr = MESSAGE_ID.split(" ");
pstmt = connection.prepareStatement(query);
for(int i=0;i<arr.length;i++) {
pstmt.setInt(1, Integer.parseInt(arr[i]));
pstmt.addBatch();
pstmt.clearParameters();
}
pstmt.executeBatch();
json.put("FLAG", "TRUE");
array.add(json);
pstmt.close();
connection.close();
return array;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
위의 소스코드에서 주목해야 할 부분들은 아래와 같다
public int getNewMessageID(String MESSAGE_BOX) {
Connection con;
PreparedStatement pstmt;
ResultSet rs;
int num=0;
try {
con = dataSource.getConnection();
String query ="SELECT MAX(MESSAGE_ID) FROM "+MESSAGE_BOX;
pstmt = con.prepareStatement(query);
rs = pstmt.executeQuery();
if(rs.next()) {
num = rs.getInt(1);
}
rs.close();
pstmt.close();
con.close();
return num+1;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
이제는 SYS_GUID( ) 메서드로 메시지 ID를 부여하는 것이 아니기 때문에
메시지들 중에서 가장 높은 ID를 가진 메시지보다 +1된 값을 새로운 메시지의 ID로 사용하기 위함이다.
문제점이 존재한다면, 트랜잭션 처리가 되어있지 않다는 것이다.
물론 질의 자체는 DBMS가 동시성 제어를 해주지만, 문제는 두 번의 질의를 해야 한다는 것이다.
첫 번째로 새로운 메시지에게 할당할 ID값을 얻는 SELECT
두 번째로 실제로 메시지를 DB에 추가하는 INSERT
만약 두 명의 사용자가 동시에 SELECT 하여 같은 ID값을 얻고, INSERT를 진행했다면
ID값이 중복되기 때문에 기본키 제약조건에 따라서 한 명의 요청은 수행되지 않을 것이다.
이는 트랜잭션 처리를 배운 후 나중에 적용하도록 하겠다.
public ArrayList<MessageVO> getMessageList(String MESSAGE_BOX, String CUSTOMER_ID, int section, int page, String SEARCH, String ORDER_BY) {
Connection con;
PreparedStatement pstmt;
ResultSet rs;
String result=null;
String CUSTOMER, tCUSTOMER, query;
ArrayList<MessageVO> list = new ArrayList<>();
if(MESSAGE_BOX.equals("MESSAGE_RECEIVED")) {
CUSTOMER = "RECEIVER_ID";
tCUSTOMER = "SENDER_ID";
}else {
CUSTOMER = "SENDER_ID";
tCUSTOMER = "RECEIVER_ID";
}
try {
query="";
query+="SELECT IDX, MESSAGE_ID, SENDER_ID, RECEIVER_ID, MESSAGE_TITLE, MESSAGE_CONTENT, TO_CHAR(MESSAGE_DATE,'YYYY.MM.DD / HH24:MI:SS') MESSAGE_DATE_STRING ";
query+="FROM (SELECT ROWNUM IDX, MESSAGE_ID, SENDER_ID, RECEIVER_ID, MESSAGE_TITLE, MESSAGE_CONTENT, MESSAGE_DATE FROM (SELECT * FROM "+MESSAGE_BOX+" ORDER BY "+ORDER_BY+") WHERE "+CUSTOMER+"='"+CUSTOMER_ID+"' AND (MESSAGE_TITLE LIKE '%"+SEARCH+"%' OR MESSAGE_CONTENT LIKE '%\"+SEARCH+\"%' OR "+tCUSTOMER+" LIKE '%\"+SEARCH+\"%') ORDER BY "+ORDER_BY+") ";
query+="WHERE IDX >= "+(((section-1)*100)+((page-1)*10)+1)+" AND IDX <= "+((section-1)*100+(page)*10)+" ";
con = dataSource.getConnection();
pstmt = con.prepareStatement(query);
rs = pstmt.executeQuery();
while(rs.next()) {
MessageVO message = new MessageVO();
message.setMESSAGE_ID(rs.getInt("MESSAGE_ID"));
message.setMESSAGE_TITLE(rs.getString("MESSAGE_TITLE"));
message.setMESSAGE_CONTENT(rs.getString("MESSAGE_CONTENT"));
message.setSENDER_ID(rs.getString("SENDER_ID"));
message.setRECEIVER_ID(rs.getString("RECEIVER_ID"));
message.setMESSAGE_DATE_STRING(rs.getString("MESSAGE_DATE_STRING"));
list.add(message);
}
rs.close();
pstmt.close();
con.close();
return list;
} catch (Exception e) {
e.printStackTrace();
return list;
}
}
메시지들을 얻는 메서드, 유심히 살펴보아야 할 부분은 바로 query 문자열 생성과정이다.
WHERE IDX >= "+(((section-1)*100)+((page-1)*10)+1)+" AND IDX <= "+((section-1)*100+(page)*10)
앞서 언급했듯이, 하나의 섹션에는 최대 10개의 페이지가, 1개의 페이지에는 최대 10개의 메시지가 존재할 수 있다.

섹션 값이 1이므로 메시지들에게 차례로 ROWNUM을 부여했을 때
1~ 100의 값을 갖는 메시지를 얻을 수 있다.
이때 페이지 값이 1이므로 1 ~ 100번째 메시지 중
1 ~ 10번째 메시지를 얻어온 것이다.

섹션 값이 1이므로 메시지들에게 차례로 ROWNUM을 부여했을 때
1~ 100의 값을 갖는 메시지를 얻을 수 있다.
이때 페이지 값이 6이므로 1 ~ 100번째 메시지 중
51 ~ 60번째 메시지를 얻어온 것이다.

섹션 값이 1이므로 메시지들에게 차례로 ROWNUM을 부여했을 때
101~ 200의 값을 갖는 메시지를 얻을 수 있다.
이때 페이지 값이 1이므로 101 ~ 200번째 메시지 중
101 ~ 110번째 메시지를 얻어온 것이다.
이때 해당 섹션에는 고작 6개의 메시지밖에 없으므로 사실상
101 ~ 106번째 메시지를 얻어온 것이다.
이처럼 하나의 섹션에는 최대 10개의 페이지가,
하나의 페이지에는 최대 10개의 메시지가 포함되도록 페이징을 구현하였다.
WHERE IDX >= "+(((section-1)*100)+((page-1)*10)+1)+" AND IDX <= "+((section-1)*100+(page)*10)
다시 본론으로 들어가면, section과 page값이 주어지면, ROWNUM AS IDX 중에서 해당 범위에 포함되는
최대 10개의 메시지를 얻어오는 질의의 조건문은 위와 같다는 것이다.
var maxSection = Math.ceil(TOTAL/100);
var maxPage = Math.ceil((TOTAL-(section-1)*100)/10)>=10?10:Math.ceil((TOTAL-(section-1)*100)/10);
$("#paging").off();
$("#paging").empty();
var tag;
if(section>=2){
tag = $("<a id='prev'>이전</a>");
$("#paging").on("click","#prev",function(){
section--;
page=1;
receiveMessage(MESSAGE_BOX, ORDER_BY, section, page);
})
$("#paging").append(tag);
}
for(var i=1; i<=maxPage;i++){
$("#paging").append($("<a id='idx"+i+"' value='"+i+"'>"+i+"</a>"));
$("#paging").on("click","#idx"+i,function(){
receiveMessage(MESSAGE_BOX, ORDER_BY, section, $(this).attr("value"))
page = $(this).attr("value");
})
}
$("#paging a").removeClass("active");
$("#idx"+page).addClass("active");
if(section<maxSection){
tag = $("<a id='next'>다음</a>");
$("#paging").on("click","#next",function(){
section++;
page=1;
receiveMessage(MESSAGE_BOX, ORDER_BY, section, page);
})
$("#paging").append(tag);
}
그렇게 메시지를 AJAX로 얻고 나면, 그 메세 지수를 TOTAL변수에 담는다.
이 TOTAL변수를 아래와 같이 처리하면 해당 섹션에 총 몇 개의 페이지가 존재할 수 있는지 계산할 수 있다.
var maxSection = Math.ceil(TOTAL/100);
var maxPage = Math.ceil((TOTAL-(section-1)*100)/10)>=10? 10:Math.ceil((TOTAL-(section-1)*100)/10);
그렇게 총 섹션, 페이지수를 구하고 나면 a태그를 동적으로 생성하고
클릭이벤트를 담아서 메시지를 얻을 수 있도록 한다.
사이드바 및 여러 UI를 조금 더 깔끔하게 다시 디자인했다.
이전에는 너무 눈이 아프거나 덜 직관적이었다.
가령 사이드바를 열 때마다 매번 부 메뉴를 클릭하기 위해 주 메뉴를 다시 클릭해야 하는 번거로움이나
입력 박스를 클릭하면 표시가 되도록 변경하거나...
특히 폰트의 변경이 가장 큰 변화인 것 같다.
기존 폰트는 글자가 너무 작으면 뭉쳐보여서 잘 식별이 되지 않았었다.
따라서 글자 크기를 크게할 수 밖에 없는 문제가 있었다...
'Web Service > 도서 정보 제공 웹 서비스' 카테고리의 다른 글
도서 정보 제공 웹 서비스 - Gmail을 활용한 비밀번호 찾기 (0) | 2022.01.09 |
---|---|
도서 정보 제공 웹 서비스 - 메세지 읽기, Spring, Mybatis 프레임워크 (0) | 2022.01.06 |
도서 정보 제공 웹 서비스 - 메세지 전송 구현하기 (0) | 2021.12.07 |
도서 정보 제공 웹 서비스 - RSA, SHA-512 보안기능 제공하기 (0) | 2021.12.02 |
도서 정보 제공 웹 서비스 - 로그아웃, 아이디/비밀번호 찾기 구현하기 (0) | 2021.11.24 |