[ajax & Struts2] 방명록 만들기
by 무작정 개발반응형
2022.03.18(59일 차_금요일)
이번에는 Struts 2 프레임워크랑 ajax를 사용하여 방명록 게시판을 만들 것이다.
최종 완성 화면은 맨 하단에 첨부하였다.
DB 테이블 생성
create table iguest(
num NUMBER(9),
name VARCHAR2(25),
email VARCHAR2(50),
content VARCHAR2(4000),
ipAddr VARCHAR2(50),
created DATE,
CONSTRAINT pk_iguest_num PRIMARY KEY(num));
GuestDTO 클래스 생성
package com.iguest;
public class GuestDTO {
private int listNum;//일련번호
private int num;
private String name;
private String email;
private String content;
private String ipAddr; // 아이피는 db에 저장 클라이언트에 보여줄필요는없다. (누가접근했는지알기위해)
private String created;
private String pageNum; // 부수적으로 만듬
//getter/setter 생성
}
iguest_sqlMap.xml 생성 - (DAO 역할) & 등록하기
- Struts랑 iBatis xml을 만들었으면 xml을 등록해줘야 한다.
iguest_sqlMap.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="iguest">
<!-- numMax : 게시물 번호 -->
<select id="numMax" resultClass="int">
select nvl(max(num),0) from iguest
</select>
<!-- insertData : 방명록 추가 -->
<insert id="insertData" parameterClass="com.iguest.GuestDTO">
insert into iguest (num,name,email,content,ipAddr,created)
values (#num#,#name#,#email#,#content#,#ipAddr#,sysdate)
</insert>
<!-- dataCount : 게시물 갯수 -->
<select id="dataCount" resultClass="int">
select nvl(count(*),0) from iguest
</select>
<!-- listData : 게시물 리스트 출력 -->
<select id="listData" resultClass="com.iguest.GuestDTO" parameterClass="map" >
select * from (
select rownum rnum, data.* from (
select num,name,email,content,ipAddr,created
from iguest order by num desc) data)
<![CDATA[
where rnum>=#start# and rnum<=#end#
]]>
</select>
<!-- deleteData : 게시물 삭제 -->
<delete id="deleteData" parameterClass="int">
delete iguest where num=#num#
</delete>
</sqlMap>
★ Action에서 namespace로 id에 접근한다. ★
sqlMapConfig.xml에 등록하기
<sqlMap resource="com/util/sqlMap/iguest_sqlMap.xml"/>
struts-iguest.xml 생성 및 등록
- struts-iguest.xml을 생성했으면 struts.xml에 등록해줘야 한다.
- 컨트롤러 역할
- 이번에는 ajax를 써서 redirect가 필요 없다.
struts-iguest.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- 컨트롤러 -->
<!-- ajax를 써서 리다이렉트가 필요 x -->
<struts>
<package name="iguest" extends="default" namespace="/guest">
<action name="guest">
<result>/iguest/guest.jsp</result>
</action>
<action name="created" class="com.iguest.GuestAction" method="created">
<result>/iguest/list.jsp</result>
</action>
<action name="list" class="com.iguest.GuestAction" method="list">
<result>/iguest/list.jsp</result>
</action>
<action name="deleted" class="com.iguest.GuestAction" method="deleted">
<result>/iguest/list.jsp</result>
</action>
</package>
</struts>
struts.xml에 등록하기
<include file="struts-iguest.xml"/>
GuestAction 생성하기
package com.iguest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.util.MyUtil;
import com.util.dao.CommonDAO;
import com.util.dao.CommonDAOImpl;
//Struts2는 DTO가 데이터를 넘기지만 Struts2+ajax로 만들 때는 ajax가 데이터를 넘긴다.
//Struts2가 데이터를 넘길 필요가 없어진다.그래서 dto의 getter가 필요없다.
public class GuestAction extends ActionSupport
implements Preparable,ModelDriven<GuestDTO> {
private static final long serialVersionUID = 1L;
private GuestDTO dto;
//데이터는 ajax가 넘기기때문에 이건 필요없당
/*public GuestDTO getDto() {
return dto;
}*/
@Override
public GuestDTO getModel() {
return dto;
}
@Override
public void prepare() throws Exception {
dto = new GuestDTO();
}
public String created() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
CommonDAO dao = CommonDAOImpl.getInstance();
int numMax = dao.getIntValue("iguest.numMax");
dto.setNum(numMax + 1);
dto.setIpAddr(request.getRemoteAddr());
dao.insertData("iguest.insertData", dto);
return list(); //반환값은 직접찾아가고자하는 list() 메서드를 써주면 된다.
}
public String list() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();//request를 가져온것
// DB연결자
CommonDAO dao = CommonDAOImpl.getInstance();
MyUtil myUtil = new MyUtil();
//페이징 처리
int numPerPage = 3;//하나의 페이지에 표시할 데이터 갯수
int totalPage = 0;
int totalDataCount = 0;
String pageNum = request.getParameter("pageNum");
int currentPage = 1; //currentPage는 1페이지를 뿌린다.
if(pageNum!=null && !pageNum.equals("")) {
currentPage = Integer.parseInt(pageNum);
}
totalDataCount = dao.getIntValue("iguest.dataCount");//ModelDriven이 움직여준다.
if(totalDataCount!=0) {
totalPage = myUtil.getPageCount(numPerPage, totalDataCount);
}
if(currentPage>totalPage) { //삭제했을때 마지막페이지를 현재 페이지로 맞춰줌
currentPage = totalPage;
}
Map<String, Object> hMap = new HashMap<String, Object>();
//start와 end는 게시물의 시작과 끝을 뜻함
int start = (currentPage-1)*numPerPage+1;
int end = currentPage*numPerPage;
hMap.put("start", start);//hMap에 start와 end를 넣은것
hMap.put("end", end);
//iguest의 listsData를 실행시키는데 hMap을 넘겨준다.
List<Object> lists = dao.getListData("iguest.listData", hMap);
//일련번호 정렬
int listNum,n = 0;
Iterator<Object> it = lists.iterator();
while(it.hasNext()) {
GuestDTO vo = (GuestDTO)it.next();
listNum = totalDataCount-(start+n-1);
vo.setListNum(listNum);
vo.setContent(vo.getContent().replaceAll("\n", "<br/>"));
n++;
}
//JS로 만든 페이징 처리 호출
String pageIndexList = myUtil.pageIndexList(currentPage, totalPage);
request.setAttribute("lists", lists);
request.setAttribute("pageIndexList", pageIndexList);
request.setAttribute("totalDataCount", totalDataCount);
request.setAttribute("pageNum", currentPage);
return SUCCESS; // select는 리다이렉트가 필요없기때문에 SUCCESS값만 반환하면 된다.
// insert/delete는 리다이렉트가 필요
}
public String deleted() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
CommonDAO dao = CommonDAOImpl.getInstance();
int num = Integer.parseInt(request.getParameter("num"));
dao.deleteData("iguest.deleteData", num);
return list();//반환값은 직접찾아가고자하는 list() 메서드를 써주면 된다.
}
}
MyUtil 클래스 생성 - (페이징 처리)
- 기존에 만들었던 MyUtil 클래스에 pageIndexList 메서드(자바스크립트로 페이징 처리) 생성
package com.util;
public class MyUtil {
// currentPageSetup page numPerBlock
//전체페이지
public int getPageCount(int numPerPage,int dataCount) {
// 3 34
// numPerPage : 한 페이지에 몇개의 데이터
// 전체 데이터 개수와 몇개를 뿌릴건지
// 34개와 하나의 페이지에 몇개를 뿌릴건지
int pageCount = 0;
// 전체 데이터 개수를 하나의 페이지에 몇개를 뿌릴건지 나눔
pageCount = dataCount / numPerPage; // 페이지 몇장이 필요한지 알아냄
if(dataCount % numPerPage != 0) { // 34 % 3 == 0으로 떨어지지않으면 페이지 하나더 필요
pageCount++;
}
return pageCount; // 전체 페이지 개수
}
// 페이지 처리 메소드
// 현재 내가 어떤페이지를 보고있는지 , 전체페이지 몇장 , list.jsp
public String pageIndexList(int currentPage, int totalPage, String listUrl) {
int numPerBlock = 5; // 5개 표시 ◀이전 6 7 8 9 10 다음▶
int currentPageSetup; // ◀ 내가 이전을 누르게되면 5페이지가 나옴 (왼쪽 화살표 값)
int page; // for문의 i 6 7 8 9 10
StringBuffer sb = new StringBuffer();
if(currentPage == 0 || totalPage == 0) {
// 현재페이지또는 전체페이지 0이면 null 반환
return "null";
}
// list.jsp?pageNum=2 이거나
// list.jsp 오면서 ?검색했을때 있으면
// list.jsp? searchKey=subject & searchValue=aa & pageNum=2
// 로 String listUrl로 매개변수로 오게됨
// ? 가 있는지 찾아본다.
if(listUrl.indexOf("?") != -1) {
// ?가 있으면
listUrl = listUrl + "&";
} else {
// 물음표가 없으면 물음표를 붙임
listUrl = listUrl + "?";
}
// ◀이전 6 7 8 9 10 다음▶
// 현재 8페이지를 5개씩으므로 numPerBlock = 5 하면 나머지 3에 5를 곱합
// 5 = 1 * 5
// 1 2 3 4 5 다음▶
// ◀이전 6 7 8 9 10 다음▶
// ◀이전 값을 구하는 공식
// ◀이전값 5 6 5 5
currentPageSetup = (currentPage/numPerBlock)*numPerBlock;
// 10 5
if(currentPage % numPerBlock == 0) { // 10으로 나눴을때 0이므로
// 5 5 5
currentPageSetup = currentPageSetup - numPerBlock; // 10이여도 5가 나옴
}
// 위에 공식으로 5가 들어가면 ◀이전
// ◀이전
// 12 5 뒤에 조건 5 이면 ◀이전 만들어라.
//
//◀이전 필요하면 한번만 만들고 필요하지않으면 안만듬
// 15 5 6
if(totalPage > numPerBlock && currentPageSetup > 0) {
// 조건에 만족하면 ◀이전 만듬
//<a href="list.jsp?pageNum=2>◀이전</a>"를 만드는 코딩
sb.append("<a href=\"" + listUrl + "pageNum="
+ currentPageSetup + "\">◀이전</a> ");
}
// 바로가기 페이지 6 7 8 9 10
// 5개찍어야함
// page = 현재페이지
// 6 5
page = currentPageSetup + 1; // 시작값 ◀이전 부터 6,7,8,9,10
// 6 12 6 5(◀이전값) 5
while(page <= totalPage && page <= (currentPageSetup + numPerBlock)) {
// 만족하면 6부터 10까지 찍힘
// 현재 페이지가 내가 보고있는 페이지랑 같으면 색깔로 지정
if(page == currentPage) {
sb.append("<font color=\"Fuchsia\">" + page + "</font> ");
//<font color="Fuchsia">9</font>
} else {
// 같지않으면
// 7 페이지면?
//<a href="list.jsp?pageNum=7">7</a>
sb.append("<a href=\"" + listUrl + "pageNum=" + page +
"\">" + page + "</a> ");
}
page++; // 6 7 8 9 10 찍음
}
// 다음▶
// ◀이전 6 7 8 9 10 다음▶
// ◀이전 11 12
//(위에꺼) 12 5 5 다음버튼생김
//(밑에꺼) 35 10 5 다음버튼안생김
if(totalPage - currentPageSetup > numPerBlock) {
//<a href="list.jsp?pageNum=11">다음▶</a>
sb.append("<a href=\"" + listUrl + "pageNum=" +
page + "\">다음▶</a> ");
}
return sb.toString();
}
//-------------------------------------------------------------------------------------------------------
// 자바스크립트로 페이징 처리 하기
// listUrl이 필요없다.
public String pageIndexList(int currentPage, int totalPage ) {
int numPerBlock = 5;
int currentPageSetup;
int page;
String strList = "";
if(currentPage==0) {
return "";
}
//표시할 첫 페이지
// 이전페이지 구함
currentPageSetup = (currentPage/numPerBlock) * numPerBlock;
// 5 % 5 == 0
if(currentPage % numPerBlock == 0) {
currentPageSetup = currentPageSetup - numPerBlock;
}
// ◀ 이전
if(totalPage > numPerBlock && currentPageSetup>0) {
strList = "<a onclick='listPage(" + currentPageSetup + ");'>◀이전</a> ";
}
// 페이지
page = currentPageSetup + 1;
while((page<=totalPage) && (page<=currentPageSetup + numPerBlock)) {
if(page==currentPage) {
strList += "<font color='Fuchsia'>" + page + "</font> ";
} else {
// 모든 페이지작업을 list한테 넘긴다.
strList += "<a onclick='listPage(" + page +");'>" +
page +"</a> ";
}
page++;
}
// 다음 ▶
if(totalPage-currentPageSetup>numPerBlock) {
strList += "<a onclick='listPage(" + page + ");'>다음▶</a> ";
}
return strList;
}
}
JSP 페이지 생성하기 - (list.jsp , guest.jsp)
guest.jsp - (방명록 작성 / 조회 페이지)
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Ajax 방명록</title>
<link rel="stylesheet" type="text/css" href="<%=cp %>/data/css/style.css"/>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script type="text/javascript">
$(function(){
listPage(1); /* 1페이지를 호출한다. */
});
$(document).ready(function(){
$("#sendButton").click(function() {
var params = "name=" + $("#name").val()
+ "&email=" + $("#email").val()
+ "&content=" + $("#content").val();
$.ajax({
type:"POST",
/* 가상의 주소를 적어줌 */
url:"<%=cp%>/guest/created.action",
data:params,
//애는 insert하고 list돌아왔을때 실행하는함수
success:function(args) { /* 함수성공하면 데이터는 args로 들어옴 그러면 listData에 뿌려줘야함*/
$("#listData").html(args);
/* null로 바꿔줘야지 데이터가 지워진다. */
/* 아작스는 새로고침이 안되기 때문에 */
/* 코딩으로 삭제해줘야한다. */
$("#name").val("");
$("#email").val("");
$("#content").val("");
$("#name").focus();
},
beforeSend:showRequest, // false가 오면 실행안됨 true가 와야 실행된다.
//갔다와서 에러가 나면
error:function(e) {
alert(e.responseText);
}
});
});
});
function showRequest() {
/* 제이쿼리 함수 양쪽의 공백을 제거 */
var name = $.trim($("#name").val()); // name의 값을 양쪽공백 제거후 name에 넣음
var email = $.trim($("#email").val()); // name의 값을 양쪽공백 제거후 name에 넣음
var content = $.trim($("#content").val()); // name의 값을 양쪽공백 제거후 name에 넣음
if(!name) {
alert("\n이름을 입력하세요");
$("#name").focus();
return false;
}
if(!email) {
alert("\n이메일을 입력하세요");
$("#email").focus();
return false;
}
if(!content) {
alert("\n내용을 입력하세요");
$("#content").focus();
return false;
}
if(content.length>=200) {
alert("\n내용은 200자 까지만 가능합니다.");
$("#content").focus();
return false;
}
// 다 체크해서 통과했으면 true가 돌아가야지 계속 실행됨
return true;
}
function listPage(page){ // 1 이 오게됨
var url = "<%=cp%>/guest/list.action";
//리스트가 왔을때 실행될 함수(비동기 메서드) -갔다오면 args에 데이터가 담겨서온다.
//POST 방식은 json- param
$.post(url,{pageNum:page},function(args){ //json방식으로 넘긴 pageNum을 GuestAction에서 받아준다.
$("#listData").html(args);
});
$("#listData").show();//display: none;" 밑에서 이렇게 하는 이유는
//문제가 생겼을때 데이터를 안보여줄려고 none 대신 block를 쓰고
//이 줄을 주석처리해도 된다.
}
function deleteData(num,page) {
var url = "<%=cp%>/guest/deleted.action";
//삭제하고 리스트 왔을때 실행될 함수(비동기 메서드)
$.post(url,{num:num,pageNum:page},function(args) {
$("#listData").html(args);
});
}
</script>
</head>
<body>
<br/><br/>
<table width="700" border="2" cellpadding="0" cellspacing="0"
bordercolor="#00D8FF" style="margin: auto;">
<tr height="40">
<td style="padding-left: 20px;"><b>방명록</b></td>
</tr>
</table>
<!-- 겉모습 만듬 -->
<br/><br/>
<table width="700" border="0" cellpadding="0" cellspacing="0" style="margin : auto;">
<tr>
<!-- colsplan 4칸합침 선 -->
<td width="600" colspan="4" height="3" bgcolor="#00D8FF"></td>
</tr>
<tr>
<td width="60" height="30" bgcolor="#00D8FF" align="center">작성자</td>
<td width="240" height="30" style="padding-left: 10px;">
<input type="text" id="name" size="35" maxlength="20" class="boxTF"/>
</td>
<td width="60" height="30" bgcolor="#00D8FF" align="center">이메일</td>
<td width="240" height="30" style="padding-left: 10px;">
<input type="text" id="email" size="35" maxlength="50" class="boxTF"/>
</td>
</tr>
<tr>
<td width="600" colspan="4" height="1" bgcolor="#00D8FF"></td>
</tr>
<tr>
<td width="60" height="30" bgcolor="#00D8FF" align="center">내용</td>
<td width="540" colspan="3" style="padding-left: 10px;">
<textarea rows="3" cols="90" class="boxTA"
style="height: 50px;" id="content"></textarea>
</td>
</tr>
<tr>
<td width="600" colspan="4" height="1" bgcolor="#00D8FF"></td>
</tr>
<tr>
<td width="600" colspan="4" height="30" align="right"
style="padding-right: 15px;">
<input type="button" value="등록하기" class="btn2" id="sendButton"/> <!-- 제이쿼리로 읽어내기 위해서 id -->
</td>
</tr>
</table>
<br/>
<span id="listData" style="display: none;"></span> <!-- none 안보임 -->
</body>
</html>
list.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("UTF-8");
String cp = request.getContextPath();
//여긴 html소스가 필요가없다. 왜냐하면 list.jsp에는 ajax로 데이터를 뿌려주기때문
%>
<c:if test="${totalDataCount!=0 }">
<table width="700" border="0" cellpadding="0" cellspacing="0"
style=" margin: auto;">
<c:forEach var="dto" items="${lists }">
<tr>
<td colspan="2" bgcolor="#00D8FF" height="1"></td>
</tr>
<tr height="30" bgcolor="#00D8FF">
<td width="300" style="padding-left: 10px;">
<b>No ${dto.listNum }. ${dto.name }
(<a href="mailto:${dto.email }">${dto.email }</a>)</b>
</td>
<td width="300" align="right" style="padding-right: 10px;">
${dto.created }
<a href="javascript:deleteData('${dto.num }','${pageNum }');">삭제</a>
</td>
</tr>
<tr>
<td height="50" style="padding-left: 10px" colspan="2">
${dto.content }
</td>
</tr>
</c:forEach>
<tr>
<td colspan="2" bgcolor="#00D8FF" height="2"></td>
</tr>
<tr height="30">
<td align="center" colspan="2">${pageIndexList }</td>
</tr>
</table>
</c:if>
실행화면
반응형
'Front-End > jQuery(ajax)' 카테고리의 다른 글
[Javascript] JSON을 활용해서 javascript 객체 생성하기 (2) | 2022.03.18 |
---|---|
[Javascript] DOM(Document Object Model) , XML 데이터 가져오기 (0) | 2022.03.17 |
[Ajax] 유효한 ID체크 , 자주 사용하는 Javascript 함수 만들기 (0) | 2022.03.17 |
[Ajax] GET 방식, POST 방식으로 데이터 보내기 (0) | 2022.03.17 |
[JQuery] 세팅 및 jQuery & Ajax를 이용한 텍스트 데이터 전송 (2) | 2022.03.15 |
블로그의 정보
무작정 개발
무작정 개발