CRUD within Ajax
- Ajax는 비동기 방식이므로 하나의 주소에서 모든 입출력 Form을 작성하고, 이를 처리하는 back end(JSP에서 Action)만 다른 주소로 작성
DTO
public class MemoDto {
private String num;
private String writer;
private String story;
private String avatar;
private Timestamp writeday;
}
Insert Part
<body>
<div class="memo button">
<button type="button" id="btnadd">메모추가</button>
</div>
<div class="memo addform">
<form id="addfrm">
<table>
<tr>
<th>작성자</th>
<td>
<input type="text" name="writer" id="writer">
</td>
</tr>
<tr>
<th>메모</th>
<td>
<textarea name="story" id="story"></textarea>
</td>
</tr>
<tr>
<th>아바타</th>
<td>
<input type="hidden" name="avatar" id="avatar">
<script>
var s="";
for(var i=1;i<=5;i++)
{
s="<img src='../image/logoImg/icon0"+i+".png' class='avatar'>";
if(i==5){s+="<br>";}
document.write(s);
}
for(var i=1;i<=5;i++)
{
s="<img src='../image/logoImg/images0"+i+".jpg' class='avatar'>";
document.write(s);
}
</script>
</td>
</tr>
<tr>
<td colspan="2" align="center" class="dbsave">
DB에 저장하기
</td>
</tr>
</table>
</form>
</div>
</body>
- 선택자 활용하기 위해 모든 <div>와 <input>에 id 부여
- <input>은 name으로 입력된 value를 받아야 하므로 name 부여
- back end에 값을 넘겨야 하지만 Form에서 client에게 보여줄 필요 없는 데이터는 hidden 타입으로 처리(avatar 클래스의 이미지 경로는 숨기고 결과인 이미지는 선택하게 함)
- 출력된 이미지는 css style을 통해 hover 및 click 이벤트 부여
- 단순 출력은 document.write() 사용
DAO(Insert Part)
public class MemoDao {
DBConnect db=new DBConnect();
public void insertMemo(MemoDto dto) {
Connection conn=db.getConnection();
PreparedStatement pstmt=null;
String sql="insert into memo values(seq_1.nextval,?,?,?,sysdate)";
try {
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getStory());
pstmt.setString(3, dto.getAvatar());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.dbClose(pstmt, conn);
}
}
}
Action(Insert Part)
<%
MemoDao dao=new MemoDao();
//인코딩
request.setCharacterEncoding("utf-8");
//데이터 읽기(writer,story,avatar)
String writer=request.getParameter("writer");
String story=request.getParameter("story");
String avatar=request.getParameter("avatar");
//dto로 묶기
MemoDto dto=new MemoDto();
dto.setWriter(writer);
dto.setStory(story);
dto.setAvatar(avatar);
//insert
dao.insertMemo(dto);
%>
- Form에서 입력한 데이터를 ajax url로 넘겨 받아, DTO 멤버 변수 값 변경 후 DAO의 insert 메서드를 통해 DB에 insert
<script>
list();
$("div.addform").hide();
$("div.updateform").hide();
$("#btnadd").click(function(){
$("div.addform").slideToggle('slow');
});
$("img.avatar:eq(2)").addClass("select");
$("#avatar").val($("img.avatar:eq(2)").attr("src"));
$("img.avatar").click(function(){
$(this).siblings().removeClass("select");
$(this).addClass("select");
$("#avatar").val($(this).attr("src"));
});
</script>
- 처음 로딩 시 모든 <form> 태그 숨기기 위해 hide() 메서드 사용
- 버튼 이벤트를 통해 insert <form> 태그 점멸 위해 slideToggle() 메서드 사용
- 초기 선택 값으로 eq(2) (임의 지정)에 addClass() 메서드로 선택 이벤트 부여
- back end에 값을 넘기기 위해 존재하지만 hidden으로 숨겨둔 id avatar에 이미지 경로 데이터를 입력 필요
- 이를 위해 avatar id를 선택자로 이용해 val() 메서드로 value 값 부여
<script>
$("td.dbsave").click(function(){
var data=$("#addfrm").serialize();
$.ajax({
type:"post",
url:"memoInsert.jsp",
data:data,
dataType:"html",
success:function(){
list();
$("#writer").val("");
$("#story").val("");
$("img.avatar").removeClass("select");
$("img.avatar:eq(2)").addClass("select");
$("#avatar").val($("img.avatar:eq(2)").attr("src"));
}
});
});
</script>
Print Part
<body>
<div class="memo list">list</div>
</body>
DAO(Print Part)
public class MemoDao {
public List<MemoDto> getAllMemos() {
List<MemoDto> list=new Vector<MemoDto>();
Connection conn=db.getConnection();
Statement stmt=null;
ResultSet rs=null;
String sql="select * from memo order by num";
try {
stmt=conn.createStatement();
rs=stmt.executeQuery(sql);
while(rs.next())
{
MemoDto dto=new MemoDto();
dto.setNum(rs.getString("num"));
dto.setWriter(rs.getString("writer"));
dto.setStory(rs.getString("story"));
dto.setAvatar(rs.getString("avatar"));
dto.setWriteday(rs.getTimestamp("writeday"));
list.add(dto);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.dbClose(rs, stmt, conn);
}
return list;
}
}
- 전체 데이터 출력을 위해 DB에 존재하는 모든 데이터 조회
- List 인터페이스의 Vector 클래스 사용하여 조회된 데이터 전부 list 입력
Action(Print Part)
<%
MemoDao dao=new MemoDao();
//전체목록을 가져온다
List<MemoDto> list=dao.getAllMemos();
JSONArray arr=new JSONArray();
//arr에 먼저 size보내보자
/* JSONObject size=new JSONObject();
size.put("size",list.size());
arr.add(size); */
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
for(MemoDto dto:list)
{
JSONObject ob=new JSONObject();
ob.put("num",dto.getNum());
ob.put("writer",dto.getWriter());
ob.put("story",dto.getStory());
ob.put("avatar",dto.getAvatar());
ob.put("writeday",sdf.format(dto.getWriteday()));
//arr에 추가
arr.add(ob);
}
%>
<%=arr.toString() %>
- DAO의 전체 조회 메서드를 통해 DB의 전체 데이터 호출
- JSONObject 객체로 호출한 모든 데이터를 순차적으로 json 형태로 변환
- JSONArray 객체로 json 형태로 변환한 데이터를 json 배열에 입력
- toString() 메서드로 문자열 형태로 이를 출력(필수)
<script>
function list(){
$.ajax({
type:"get",
dataType:"json",
url:"memolist.jsp",
success:function(data){
var s="";
if(data.length==0)
s+"<h3>저장된 메모가 없습니다</h3>";
else
{
$.each(data,function(i,e){
s+="<table class='table'>";
s+="<tr><td>";
s+="<span class='writer'>작성자:"+e.writer+"</span>";
s+="<span class='writeday'>"+e.writeday+"</span>";
s+="<span class='mod' num="+e.num+">|수정</span>";
s+="<span class='del' num="+e.num+">|삭제</span>";
s+="<br>";
s+="<pre>"+e.story;
s+="<img src='"+e.avatar+"' align='right'></pre>";
s+="</td></tr></table><br>";
});
}
$("div.list").html(s);
}
});
</script>
- Action(Print Part)에 url 통해 접근하여 조회 처리 후 json 타입으로 변환하여 function의 인자 값으로 배열 가져옴
- 띄어쓰기 및 enter 처리를 그대로 받기 위해 <pre>태그 사용
- 배열의 값을 $.each()로 전체 호출 및 태그에 삽입 후, html() 객체로 이를 출력
Delete Part
- delete는 Form이 필요 없이 back end에서 처리만 하면 됨
DAO(Delete Part)
public class MemoDao {
public void deleteMemo(String num) {
Connection conn=db.getConnection();
PreparedStatement pstmt=null;
String sql="delete from memo where num=?";
try {
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, num);
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.dbClose(pstmt, conn);
}
}
}
Action(Delete Part)
<%
String num=request.getParameter("num");
MemoDao dao=new MemoDao();
dao.deleteMemo(num);
%>
- JSP와 달리 모든 입출력 Form이 하나의 주소에서 나타나므로, redirect로 주소 이동 필요 없음
<script>
$(document).on("click","span.del",function(){
var num=$(this).attr("num");
$.ajax({
type:"post",
url:"memoDelete.jsp",
dataType:"html",
data:{"num":num},
success:function(res){
list();
}
});
});
</script>
- 이벤트의 대상이 되는 <span>태그가 처음부터 존재하는 태그가 아닌, 이벤트의 결과로서 발생했으므로, 해당 태그에 이벤트를 부여하기 위해서는 동적 이벤트 필요(on() 메서드)
- on() 메서드에서는 지정자가 this 값에 해당
- ajax로 delete Action(url)에 값을 넘겨줌(data 형식에 맞춰 num 값 전송)
- Action에서 json 형태로 되받을 데이터가 없으므로 dataType은 html
- 삭제 성공 시 다시 모든 데이터 출력하기 위해 list() 함수(Print Part의 Form Function) 재선언
Update Part
<body>
<div class="memo updateform">
<form id="updatefrm">
<input type="hidden" name="unum" id="unum">
<table>
<tr>
<th>작성자</th>
<td>
<input type="text" name="uwriter" id="uwriter">
</td>
</tr>
<tr>
<th>메모</th>
<td>
<textarea name="ustory" id="ustory"></textarea>
</td>
</tr>
<tr>
<th>아바타</th>
<td>
<input type="hidden" name="uavatar" id="uavatar">
<script>
var s="";
for(var i=1;i<=5;i++)
{
s="<img src='../image/logoImg/icon0"+i+".png' class='uavatar'>";
if(i==5){s+="<br>";}
document.write(s);
}
for(var i=1;i<=5;i++)
{
s="<img src='../image/logoImg/images0"+i+".jpg' class='uavatar'>";
document.write(s);
}
</script>
</td>
</tr>
<tr>
<td colspan="2" align="center" class="dbupdate">
DB에 수정하기
</td>
</tr>
</table>
</form>
</div>
</body>
- update를 위해 insert form과 같은 양식의 input 태그 생성
- insert와 구별된 선택자를 부여하기 위해 모든 클래스와 name 명 앞에 u(update) 추가(동적 생성되는 태그도 포함)
- num(unum) 값으로 특정되는 데이터만 update해야 하므로 Action에 num 값을 넘겨주기 위해 이를 hidden 타입의 input으로 가져와서 전송
DAO(Update Part) : Get a Data
public class MemoDao {
public MemoDto getData(String num) {
MemoDto dto=new MemoDto();
Connection conn=db.getConnection();
PreparedStatement pstmt=null;
ResultSet rs=null;
String sql="select * from memo where num=?";
try {
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, num);
rs=pstmt.executeQuery();
if(rs.next())
{
dto.setNum(rs.getString("num"));
dto.setWriter(rs.getString("writer"));
dto.setStory(rs.getString("story"));
dto.setAvatar(rs.getString("avatar"));
dto.setWriteday(rs.getTimestamp("writeday"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.dbClose(rs, pstmt, conn);
}
return dto;
}
}
- update할 특정 데이터를 조회 및 호출하여 update form이 초기 값으로 설정하기 위한 메서드
Action(Update Part) : Get a Data
<%
String num=request.getParameter("num");
MemoDao dao=new MemoDao();
MemoDto dto=dao.getData(num);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
JSONObject ob=new JSONObject();
ob.put("num",dto.getNum());
ob.put("writer",dto.getWriter());
ob.put("story",dto.getStory());
ob.put("avatar",dto.getAvatar());
ob.put("writeday",sdf.format(dto.getWriteday()));
%>
<%=ob.toString() %>
- JSONObject 객체를 사용해 받아온 값을 json 형태로 변환 후 문자열 형태로 출력
<script>
$(document).on("click","span.mod",function(){
var num=$(this).attr("num");
$("#unum").val(num);
$.ajax({
type:"get",
url:"memoUpdate.jsp",
data:{"num":num},
dataType:"json",
success:function(data){
$("#uwriter").val(data.writer);
$("#ustory").val(data.story);
$("img.uavatar").each(function(i,e){
if($(this).attr("src")==data.avatar)
$(this).addClass("select");
else
$(this).removeClass("select");
});
$("div.addform").hide();
$("div.updateform").show();
$(document).on("click","img.uavatar",function(){
$("img.uavata").click(function(){
$(this).siblings().removeClass("select");
$(this).addClass("select");
$("#uavata").val($(this).attr("src"));
});
}
});
});
</script>
- update form에는 기존 입력한 데이터가 default 값으로 포함되어 있어야 하므로, 각 <input>의 val() 메서드를 통해 초기 값인 value 값 부여
- uavatar의 이미지는 insert form과 외견상 같지만 다른 form에 속한 태그이므로 이벤트 새로 부여
DAO(Update Part) : Update Execute
public class MemoDao {
public void updateMemo(MemoDto dto) {
Connection conn=db.getConnection();
PreparedStatement pstmt=null;
String sql="update memo set writer=?,story=?,avatar=? where num=?";
try {
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, dto.getWriter());
pstmt.setString(2, dto.getStory());
pstmt.setString(3, dto.getAvatar());
pstmt.setString(4, dto.getNum());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
Action(Update Part) : Update Execute
<%
request.setCharacterEncoding("utf-8");
String num=request.getParameter("unum");
String writer=request.getParameter("uwriter");
String story=request.getParameter("ustory");
String avatar=request.getParameter("uavatar");
MemoDto dto=new MemoDto();
dto.setNum(num);
dto.setWriter(writer);
dto.setStory(story);
dto.setAvatar(avatar);
MemoDao dao=new MemoDao();
dao.updateMemo(dto);
%>
<script>
$(document).on("click","td.dbupdate",function(){
var data=$("#updatefrm").serialize();
$.ajax({
type:"post",
url:"memoUpdateExe.jsp",
data:data,
dataType:"html",
success:function(data){
list();
$("div.updateform").hide();
}
});
});
</script>
- update form에 데이터를 입력 후 제출 시 update form은 숨기고 수정된 전체 데이터 list로 출력
- update 후 되받을 json 형태의 데이터 없으므로 dataType은 html
감사합니다. 이런 정보를 나눠주셔서 좋아요.