https://intheham.tistory.com/88
GuestBookVo
- 롬복 어노테이션으로 Vo를 간단하게 작성.
- 생성자는 따로 만들진 않고 Dao에서 ResultMap으로 변수에 값을 넣어줌.
package com.example.demo.guestbook;
import java.sql.Date;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
public class GuestBookVo {
private int num;
private String writer;
private Date w_date;
private String pwd;
private String content;
private int cnt;
}
GuestDao
- 시퀀스 번호를 불러와서 map에 넣음.
public Map selectNextval() {
String sql = "select seq_guestbook.nextval as num from dual"; //시퀀스 번호 생성문
return temp.queryForMap(sql);
}
public void insert(GuestBookVo vo) {
String sql = "insert into guestbook values(?,?,sysdate,?,?,0)";
temp.update(sql, new Object[] {vo.getNum(), vo.getWriter(), vo.getPwd(), vo.getContent()});
}
- 좋아요에 쓰일 cnt를 map(JSON)으로 불러오는 메서드를 Dao에 추가함.
public Map selectCnt(long num) {
String sql = "select cnt from guestbook where num=?";
return temp.queryForMap(sql, num);
}
GuestService
- map에 담긴 시퀀스 번호를 Num에 넣고 vo를 생성한 뒤 Num을 반환한다.
public long addBook(GuestBookVo vo) {//작성자, 글내용, pwd
Map map = dao.selectNextval();
long num = ((BigDecimal) map.get("num")).longValue();
vo.setNum(num);//vo에 생성한 시퀀스 번호 저장. 이 글의 번호로 사용됨
dao.insert(vo);//db에 저장
return num; //방금 추가된 글의 번호 반환
}
- map에 담긴 cnt를 반환함.
public int getCnt(long num) {
Map map = dao.selectCnt(num);
int cnt = (int) map.get("cnt");
return cnt;
}
GuestController
package com.example.demo.guestbook;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class GuestController {
@Autowired
private GuestService service;
//컨트롤러: 요청url을 등록하고 각 url별 실행할 메서드 맵핑
@RequestMapping("/") //외부에서 요청하는 url. 사용자가 웹브라우저에 url치고 들어가거나, form action값, a href 값, ajax요청 url
public String home(ModelMap map) {
ArrayList<GuestBookVo> list = service.getAll();
map.addAttribute("list", list);
return "index"; //뷰 페이지 경로: 내부에서 이동할 뷰 페이지를 지정. 컨트롤러 메서드의 리턴값
}
@ResponseBody
@RequestMapping("/add")
public Map add(GuestBookVo vo) { // GuestBookVo에 파람 없는 생성자로 객체를 먼저 생성. 폼파라메터와 동일한 이름의 setter를 호출하여 값을 넣어줌.
long num = service.addBook(vo); // db에 저장. 방금 추가한 글번호가 반환됨.
Map map = new HashMap();
map.put("obj", service.getBook(num)); // 방금 추가된 글을 번호로 검색하여 ajax 응답으로 보내줌.(JSON 형태로)
return map;
}
@ResponseBody
@PostMapping("/edit")
public Map edit(GuestBookVo vo) { // 글 번호와 새 내용을 받아옴
boolean flag = true;
try {
service.editBook(vo); // db에서 새 내용으로 변경
}catch(Exception e) {
flag = false; // 만약 오류가 생기면 false 해라~
}
Map map = new HashMap();
map.put("flag", flag); // {"flag":true} 처리 결과만 json으로 보냄~
return map;
}
@ResponseBody
@PostMapping("/del")
public Map del(int num) {
boolean flag = true;
try {
service.delBook(num);
}catch(Exception e) {
flag = false;
}
Map map = new HashMap();
map.put("flag", flag); // 처리 결과만 json으로 보냄~
return map;
}
@ResponseBody
@PostMapping("/like")
public Map like(int num) {
service.editCnt(num);
int cnt = service.getCnt(num);
Map map = new HashMap();
map.put("cnt", cnt);
return map;
}
}
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#savebtn').click(function(){
$.ajax({
url:'/add',
type:'post',
data:{'writer':$('#writer').val(), 'pwd':$('#pwd').val(), 'content':$('#content').val()},
dataType:'json',
success:function(result){ //{"obj":{"num":1, "writer":"aaa", "pwd":"111"}}
let obj = result.obj;
let txt = '<table border="1" id="t_'+obj.num+'">';
txt += '<tr><th>num</th><td>'+obj.num+'</td></tr>';
txt += '<tr><th>like</th><td><span id="likespan_'+obj.num+'">'+obj.cnt+'</span>';
txt += '<input type="button" value="좋아요" class="likebtn" num="'+obj.num+'"></td></tr>';
txt += '<tr><th>writer</th><td>'+obj.writer+'</td></tr>';
txt += '<tr><th>작성일</th><td>'+obj.w_date+'</td></tr>';
txt += '<tr><th>content</th><td><span id="cont_'+obj.num +'">'+obj.content+'</span></td></tr>';
txt += '<tr><th>편집</th> <td><input type="button" class="editbtn" value="수정" num="'+obj.num+'" pwd="'+obj.pwd+'">';
txt += '<input type="button" class="delbtn" value="삭제" num="'+obj.num+'" pwd="'+obj.pwd+'"></td></tr>';
txt += '</table>';
$('#list').append(txt); // 방금 추가한 글 하나만 리스트 밑에 붙여라.
//작성폼 초기화
$('#writer').val('');
$('#pwd').val('');
$('#content').val('');
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
});
// $('.editbtn').click(function(){}) -- ajax로 생성된 버튼은 작동 안함.
// 이벤트 핸들러: 이벤트가 발생하면 자동으로 호출되는 함수
$(document).on('click', '.editbtn', function(e){
// 수정에 필요한 값을 버튼의 속성 값으로 넣어주고 불러오기~
let num = $(this).attr('num'); // this : 방금 이벤트가 발생한 소스
let pwd = $(this).attr('pwd');
// 수정폼이 마우스 위치에 뜨게 하기
$('#editf').css('top', e.pageY);
$('#editf').css('left', e.pageX);
$('#editf').css('display', 'block'); // 디스플레이가 맨 앞으로 포개지듯 나타나게 하기.
$('#editcont').val($('#cont_'+num).text()); // span 태그 사이값을 읽어서 넣어주기
// 수정완료할 때 필요한 정보값을 수정완료버튼의 속성값으로 넣어주기
$('#editb').attr('pwd', pwd);
$('#editb').attr('num', num);
});
$(document).on('click', '.delbtn', function(){
let num = $(this).attr('num');
let pwd = $(this).attr('pwd');
let pwd2 = prompt("pwd:", "0000");
if(pwd==pwd2){
$('#t_'+num).remove(); // 글 테이블 전체 지우기
$.ajax({
url:'/del',
type:'post',
data:{'num':num},
dataType:'json',
success:function(result){
if(!result.flag){
alert('삭제가 완료되지 않았다');
}
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
}else{
alert('패스워드 불일치. 삭제 취소');
}
});
$('#editcancel').click(function(){
$('#editf').css('display', 'none');
});
// 수정폼에서 수정완료 버튼 눌렀을 때.
$('#editb').click(function(){
let num = $(this).attr('num');
let pwd1 = $(this).attr('pwd'); // 원글 비밀번호
let pwd2 = $('#editpwd').val(); // 수정폼에 입력한 확인용 비밀번호
//alert(pwd1+':'+pwd2);
if(pwd1 == pwd2){
let newcont = $('#editcont').val();
$('#cont_'+num).text(newcont); // 원글 내용을 새 입력값으로 변경
$.ajax({
url:'/edit',
type:'post',
data:{'num':num, 'content':newcont},
dataType:'json',
success:function(result){
if(result.flag){
$('#editf').css('display', 'none');
}else{
alert('수정이 완료되지 않았다');
}
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
}else{
alert('패스워드 불일치. 수정 취소');
}
});
$(document).on('click', '.likebtn', function(){
let num = $(this).attr('num');
$.ajax({
url:'/like',
type:'post',
data:{'num':num},
dataType:'json',
success:function(result){
$('#likespan_'+num).text(result.cnt);
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
});
});
// $.mktbl = (obj) => {
// xCVzxfv
// };
// const f1 = () => {
// };
</script>
</head>
<body>
<h3>방명록</h3>
<div id="editf" style="position:absolute;top:150px;left:30px;border:1px solid blue;display:none;background-color:white">
pwd:<input type="password" id="editpwd"><br/>
new content:<input type="text" id="editcont"><br/>
<input type="button" id="editb" value="수정저장"><input type="button" id="editcancel" value="수정취소">
</div>
<div id="writeForm" style="border:1px solid black">
<table border="1">
<tr><th>writer</th><td><input type="text" id="writer" name="writer"></td></tr>
<tr><th>pwd</th><td><input type="password" id="pwd" name="pwd"></td></tr>
<tr><th>content</th><td><input type="text" id="content" name="content"></td></tr>
<tr><th>작성</th><td><input type="button" id="savebtn" value="작성"></td></tr>
</table>
</div>
<h3>글목록</h3>
<div id="list">
<c:forEach var="vo" items="${list }">
<table border="1" id="t_${vo.num }">
<tr><th>num</th><td>${vo.num }</td></tr>
<tr><th>like</th><td><span id="likespan_${vo.num }">${vo.cnt }</span>
<input type="button" value="좋아요" class="likebtn" num="${vo.num }"></td></tr>
<tr><th>writer</th><td>${vo.writer }</td></tr>
<tr><th>작성일</th><td>${vo.w_date }</td></tr>
<tr><th>content</th><td><span id="cont_${vo.num }">${vo.content }</span></td></tr>
<tr><th>편집</th>
<td><input type="button" class="editbtn" value="수정" num="${vo.num }" pwd="${vo.pwd }">
<input type="button" class="delbtn" value="삭제" num="${vo.num }" pwd="${vo.pwd }"></td></tr>
</table>
</c:forEach>
</div>
</body>
</html>
0. 총코드
GuestDao.java
더보기
package com.example.demo.guestbook;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
@Repository
public class GuestDao {
@Autowired
private JdbcTemplate temp;
//resultMap 클래스
public class GuestMapper implements RowMapper<GuestBookVo>{
@Override
public GuestBookVo mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
GuestBookVo vo = new GuestBookVo();
vo.setNum(rs.getInt(1));
vo.setWriter(rs.getString(2));
vo.setW_date(rs.getDate(3));
vo.setPwd(rs.getString(4));
vo.setContent(rs.getString(5));
vo.setCnt(rs.getInt(6));
return vo;
}
}
public Map selectNextval() {
String sql = "select seq_guestbook.nextval as num from dual"; //시퀀스 번호 생성문
// map.put("num", 1);
// map.put("컬럼명", 컬럼값);
// map.put("컬럼명", 컬럼값);
return temp.queryForMap(sql);
}
public void insert(GuestBookVo vo) {
String sql = "insert into guestbook values(?,?,sysdate,?,?,0)";
temp.update(sql, new Object[] {vo.getNum(), vo.getWriter(), vo.getPwd(), vo.getContent()});
}
public GuestBookVo select(long num) {
String sql = "select * from guestbook where num=?";
return temp.queryForObject(sql, new GuestMapper(), num);
}
public ArrayList<GuestBookVo> selectAll() {
String sql = "select * from guestbook order by num desc";
return (ArrayList<GuestBookVo>) temp.query(sql, new GuestMapper());
}
public void update(GuestBookVo vo) {
String sql = "update guestbook set content=? where num=?";
temp.update(sql, new Object[] {vo.getContent(), vo.getNum()});
}
public void delete(long num) {
String sql = "delete from guestbook where num=?";
temp.update(sql, num);
}
public void updateCnt(long num) {
String sql = "update guestbook set cnt=cnt+1 where num=?";
temp.update(sql, num);
}
public Map selectCnt(long num) {
String sql = "select cnt from guestbook where num=?";
return temp.queryForMap(sql, num);
}
}
GuestService.java
더보기
package com.example.demo.guestbook;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GuestService {
@Autowired
private GuestDao dao;
public long addBook(GuestBookVo vo) {//작성자, 글내용, pwd
Map map = dao.selectNextval();
long num = ((BigDecimal) map.get("num")).longValue();
vo.setNum(num);//vo에 생성한 시퀀스 번호 저장. 이 글의 번호로 사용됨
dao.insert(vo);//db에 저장
return num; //방금 추가된 글의 번호 반환
}
public GuestBookVo getBook(long num) {
return dao.select(num);
}
public ArrayList<GuestBookVo> getAll(){
return dao.selectAll();
}
public void editBook(GuestBookVo vo) {
dao.update(vo);
}
public void delBook(long num) {
dao.delete(num);
}
public void editCnt(long num) {
dao.updateCnt(num);
}
public int getCnt(long num) {
Map map = dao.selectCnt(num);
int cnt = (int) map.get("cnt");
return cnt;
}
}