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;

	//각각의 setters and getters 생략
}

Insert Part

Form Input(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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			db.dbClose(pstmt, conn);
		}
	}
}
  • insert 메서드

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

Form Function(Insert Part)

<script>
	//처음로딩시 목록 출력하기
		list();
		
		$("div.addform").hide();
		$("div.updateform").hide();
		
		//메모추가 버튼 누르면 addform나타나기
		$("#btnadd").click(function(){
			$("div.addform").slideToggle('slow');
		});
		
		//아바타 2번인덱스에 select클래스 추가
		$("img.avatar:eq(2)").addClass("select");
		//아바타 2번인덱스에 src값을 얻어서 input태그에 넣어주기
		$("#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>
	//저장(insert)...추가성공시 list호출
		$("td.dbsave").click(function(){
			var data=$("#addfrm").serialize();
			//alert(data);
			$.ajax({
				type:"post", //대용량의 데이터 전송
				url:"memoInsert.jsp",
				data:data,
				dataType:"html",
				success:function(){
					//추가성공시 다시 목록 출력
					list();
					//입력값지우기 초기화
					$("#writer").val("");
					$("#story").val("");
					
					//선택된 아바타 클래스 제거
					$("img.avatar").removeClass("select");
					//선택된 2번인덱스에 select클래스 추가
					$("img.avatar:eq(2)").addClass("select");
					//아바타 2번인덱스에 src값을 얻어서 input태그에 넣어주기
					$("#avatar").val($("img.avatar:eq(2)").attr("src"));
				}
			});
		});
</script>

Form(Print Part)

<body>
	<div class="memo list">list</div>
</body>
  • 모든 출력을 담당하는 <div>태그

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) {
			// TODO Auto-generated catch block
			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() 메서드로 문자열 형태로 이를 출력(필수)

Form Function(Print Part)

<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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			db.dbClose(pstmt, conn);
		}
	}
}
  • delete 메서드

Action(Delete Part)

<%
String num=request.getParameter("num");

MemoDao dao=new MemoDao();
dao.deleteMemo(num);
%>
  • JSP와 달리 모든 입출력 Form이 하나의 주소에서 나타나므로, redirect로 주소 이동 필요 없음

Form Function(Delete Part)

<script>
	$(document).on("click","span.del",function(){
			var num=$(this).attr("num");
			//alert(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

Form input(Update Part)

<body>
	<div class="memo updateform">
		<form id="updatefrm">
			<!--hidden-->
			<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 {

	//num에 해당하는 dto반환
	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) {
			// TODO Auto-generated catch block
			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 형태로 변환 후 문자열 형태로 출력

Form Function(Update Part) : Get a Data

<script>
	$(document).on("click","span.mod",function(){
			var num=$(this).attr("num");
			//alert(num);
			
			//수정폼의 unum에 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);
					
					//해당이미지에 select클래스 추가
					$("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) {
			// TODO Auto-generated catch block
			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);
%>

Form Function(Update Part) : Update Execute

<script>
	$(document).on("click","td.dbupdate",function(){
			var data=$("#updatefrm").serialize();
			//alert(data);
			$.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
profile
초보개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 8일

감사합니다. 이런 정보를 나눠주셔서 좋아요.

답글 달기