VueJS로 CURD 게시판 만들기 (코드만 정리)

부트캠프(END)/-Spring|2022. 9. 16. 15:43

BoardVO.java(Class)

package doo.doo.vo;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardVO {
  private int no, hit;
  private String name, subject, content, dbday;
}

 

 

BoardController.java (Class) -  단순 화면 이동

package doo.doo.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.*;
import doo.doo.dao.*;
import doo.doo.vo.*;

@Controller //화면 이동!
public class BoardController {
  @Autowired
  private BoardDAO dao;

  @GetMapping("board/list.do")
  public String board_list(String page, Model model) {
    return "board/list";
  }
  @GetMapping("board/insert.do")
  public String board_insert() {
    return "board/insert";
  }
  @GetMapping("board/detail.do")
  public String board_detail(int no, Model model) {
    model.addAttribute("no", no);
    return "board/detail";
  }
  @GetMapping("board/update.do")
  public String board_update(int no, Model model) {
    model.addAttribute("no", no);
    return "board/update";
  }
  @GetMapping("board/delete.do")
  public String board_delete(int no, Model model) {
    model.addAttribute("no", no);
    return "board/delete";
  }
}

 

 

글 목록 출력

BoardMapper.java (Interface)

package doo.doo.mapper;
import java.util.*;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;
import org.apache.ibatis.annotations.Update;

import doo.doo.vo.*;

public interface BoardMapper {
  @Select("SELECT no, subject, name, TO_CHAR(regdate,'YYYY-MM-DD') as dbday, hit, num " +
    "FROM (SELECT no, subject, name, regdate, hit, rownum as num " +
    "FROM (SELECT no, subject, name, regdate, hit " +
    "FROM spring_board ORDER BY no DESC)) " +
    "WHERE num BETWEEN #{start} AND #{end}")
  public List < BoardVO > boardListData(Map map);

  @Select("SELECT CEIL(COUNT(*)/10.0) FROM spring_board")
  public int boardTotalPage();
}

 

BoardDAO.java (Class)

package doo.doo.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import doo.doo.mapper.BoardMapper;
import doo.doo.vo.BoardVO;
@Repository
public class BoardDAO {
  @Autowired
  private BoardMapper mapper;

  public List < BoardVO > boardListData(Map map) {
    return mapper.boardListData(map);
  }
  public int boardTotalPage() {
    return mapper.boardTotalPage();
  }
}

BoardRestController.java (Class) - 자바와 자바스크립트 융합

package doo.doo.web;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import doo.doo.dao.*;
import doo.doo.vo.*;

@RestController
public class BoardRestController {
  @Autowired
  private BoardDAO dao;

  @GetMapping(value = "board/list_vue.do", produces = "text/plain;charset=UTF-8")
  public String board_list_vue(String page) {
    if (page == null)
      page = "1";
    int curpage = Integer.parseInt(page);
    Map map = new HashMap();
    int rowsize = 10;
    int start = rowsize * curpage - rowsize + 1;
    int end = rowsize * curpage;

    map.put("start", start);
    map.put("end", end);

    List < BoardVO > list = dao.boardListData(map);
    int totalpage = dao.boardTotalPage();

    //Javascript로 데이터를 전송
    String result = "";
    try {
      JSONArray arr = new JSONArray();
      //[{no:"1",name:"kim",..},{...},..] 이렇게
      int k = 0;
      for (BoardVO vo: list) {
        JSONObject obj = new JSONObject(); //==VO
        //JSONObject에 값을 채워 JSONArray로 넘겨 주면 VO의 ArrayList와 동일하게 작동한다.
        obj.put("no", vo.getNo());
        obj.put("subject", vo.getSubject());
        obj.put("name", vo.getName());
        obj.put("dbday", vo.getDbday());
        obj.put("hit", vo.getHit());
        //맨 첫번째 객체에 페이지 정보를 담아 넘긴다.
        if (k == 0) {
          obj.put("curpage", curpage);
          obj.put("totalpage", totalpage);
        }
        arr.add(obj);
        k++;
      }
      result = arr.toJSONString();
    } catch (Exception ex) {}
    return result;
  }
}

 

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.row1{
  width:850px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div class="container">
    <h1 class="text-center">글 목록</h1>
    <div class="row row1">
      <table class="table">
        <tr>
          <td>
            <a href="../board/insert.do" class="btn btn-sm btn-primary">새글</a>
          </td>
        </tr>
        <tr>
          <th width=10% class="text-center">번호</th>
          <th width=45% class="text-center">제목</th>
          <th width=15% class="text-center">작성자</th>
          <th width=20% class="text-center">작성일</th>
          <th width=10% class="text-center">조회수</th>
        </tr>
        <tr v-for="vo in board_list">
          <td width=10% class="text-center">{{vo.no}}</td>
          <td width=45%><a :href="'../board/detail.do?no='+vo.no">{{vo.subject}}</a></td>
          <td width=15% class="text-center">{{vo.name}}</td>
          <td width=20% class="text-center">{{vo.dbday}}</td>
          <td width=10% class="text-center">{{vo.hit}}</td>
        </tr>
      </table>
      <table class="table">
        <tr>
          <td class="text-center">
            <input type=button value="이전" class="btn btn-sm btn-danger">
            {{curpage}} page / {{totalpage}} pages
            <input type=button value="다음" class="btn btn-sm btn-danger">
          </td>
        </tr>
      </table>
    </div>
  </div>
  <script>
  new Vue({
    el:'.container',
    data:{
      board_list:[],
      curpage:1,
      totalpage:0
    },
    mounted:function(){
      axios.get("http://localhost:8080/web/board/list_vue.do",{
        params:{
          page:this.curpage
        }
      }).then(result=>{
        this.board_list = result.data;
        this.curpage = this.board_list[0].curpage;
        this.totalpage = this.board_list[0].totalpage;
      })
    }
  })
  </script>
</body>
</html>

 

 

 

글 쓰기

BoardMapper.java (Interface)

@SelectKey(keyProperty = "no", resultType = int.class, before = true,
    statement = "SELECT NVL(MAX(no)+1,1) as no FROM spring_board")
@Insert("INSERT INTO spring_board VALUES(#{no},#{name},#{subject},#{content},#{pwd},SYSDATE,0)")
  public void boardInsert(BoardVO vo);

 

BoardDAO.java (Class)

public void boardInsert(BoardVO vo) {
  mapper.boardInsert(vo);
}

BoardRestController.java (Class) - 자바와 자바스크립트 융합

@GetMapping(value = "board/insert_vue.do", produces = "text/plain;charset=UTF-8")
public String board_insert_vue(BoardVO vo) {
  dao.boardInsert(vo);
  return "OK";
}

insert.jsp

id, name 부여 필요없음. v-model에

form태그도 필요없음 

:어쩌고는 v-bind:의 생략임

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.row1{
  margin : 0px auto;
  width : 900px;
}
h1{
  text-align:center;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div class="container">
    <h1>글쓰기</h1>
    <div class="row row1">
      <table class="table">
        <tr>
          <th width=20% class="text-right">이름</th>
          <td width=80%>
            <input type=text v-model="name" ref="name" size=20 class="input-sm">
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">제목</th>
          <td width=80%>
            <input type=text v-model="subject" ref="subject" size=50 class="input-sm">
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">내용</th>
          <td width=80%>
            <textarea v-model="content" rows="10" cols="50" ref="content"></textarea>
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">비밀번호</th>
          <td width=80%>
            <input type=password v-model="pwd" ref="pwd" size=15 class="input-sm">
          </td>
        </tr>
        <tr>
          <td colspan="2" class="text-center">
            <input type=button value="글쓰기" class="btn btn-sm btn-warning" v-on:click="boardWrite()">
            <input type=button value="취소" class="btn btn-sm btn-danger"
              onclick="javascript:history.back()">
          </td>
        </tr>
      </table>
    </div>
  </div>
  <script>
    new Vue({
      el:'.container',
      data:{ //v-model의 입력값을 아래 변수에 채워라
        name:'',
        subject:'',
        content:'',
        pwd:''
      },
      methods:{
        boardWrite:function(){
          console.log("함수호출");
          //유효성 검사
          if(this.name.trim()==""){
            //태그를 가져올 때는 ref를 이용해 가져옴
            this.$refs.name.focus();
            return;
          }
          if(this.subject.trim()==""){
            this.$refs.subject.focus();
            return;
          }
          if(this.content.trim()==""){
            this.$refs.content.focus();
            return;
          }
          if(this.pwd.trim()==""){
            this.$refs.pwd.focus();
            return;
          }
          console.log("유효성 검사 끝");
          //전송
          axios.get("http://localhost:8080/web/board/insert_vue.do",{
            params:{
              name:this.name,
              subject:this.subject,
              content:this.content,
              pwd:this.pwd
            }
          }).then(result=>{
            location.href="../board/list.do";
          })
        }
      }
    })
  </script>
</body>
</html>

 

 

 

글 상세보기 

BoardMapper.java (Interface)

@Update("UPDATE spring_board SET hit=hit+1 WHERE no=#{no}")
  public void boardHitIncrement(int no);
@Select("SELECT no, subject, name, content, TO_CHAR(regdate,'YYYY-MM-DD') as dbday, hit " +
    "FROM spring_board WHERE no=#{no}")
  public BoardVO boardDetailData(int no);

 

BoardDAO.java (Class)

public BoardVO boardDetailData(int no) {
  mapper.boardHitIncrement(no);
  return mapper.boardDetailData(no);
}

BoardRestController.java (Class) - 자바와 자바스크립트 융합

@GetMapping(value = "board/detail_vue.do", produces = "text/plain;charset=UTF-8")
public String board_detail_vue(int no) {
  String result = "";
  BoardVO vo = dao.boardDetailData(no);
  JSONObject obj = new JSONObject();
  obj.put("no", vo.getNo());
  obj.put("subject", vo.getSubject());
  obj.put("content", vo.getContent());
  obj.put("name", vo.getName());
  obj.put("dbday", vo.getDbday());
  obj.put("hit", vo.getHit());

  result = obj.toJSONString();
  return result;
}

detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.row1{
  margin: 0px auto;
  width: 800px;
  width : 650px;
}
h1{
  text-align:center;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div class="container">
    <h1>상세보기</h1>
    <div class="row row1">
      <table class="table">
        <tr>
          <th width=20% class="text-center warning">번호</th>
          <td width=30% class="text-center">{{vo.no}}</td>
          <th width=20% class="text-center warning">작성일</th>
          <td width=30% class="text-center">{{vo.dbday}}</td>
        </tr>
        <tr>
          <th width=20% class="text-center warning">이름</th>
          <td width=30% class="text-center">{{vo.name}}</td>
          <th width=20% class="text-center warning">조회수</th>
          <td width=30% class="text-center">{{vo.hit}}</td>
        </tr>
        <tr>
          <th width=20% class="text-center warning">제목</th>
          <td colspan="3">{{vo.subject}}</td>
        </tr>
        <tr>
          <td colspan="4" class="text-left" valign="top" height="200">
            <pre style="white-space:pre-wrap; border:none; background-color:white;">{{vo.content}}</pre>
          </td>
        </tr>
        <tr>
          <td colspan="4" class="text-right">
            <a :href="'update.do?no='+no" class="btn btn-xs btn-info">수정</a>
            <a href="#" class="btn btn-xs btn-success">답글</a>
            <a :href="'delete.do?no='+vo.no" class="btn btn-xs btn-danger">삭제</a>
            <a href="../board/list.do" class="btn btn-xs btn-primary">목록</a>
          </td>
        </tr>
      </table>
    </div>
  </div>
<script>
 new Vue({
   el:'.container',
   data:{
     vo:{},
     no:${no} //Controller에서 보내준거(EL)를 no에 넣어줌
   },
   mounted:function(){
     let _this=this;
     // 요청 
     axios.get("http://localhost:8080/web/board/detail_vue.do",{
       params:{
         no:_this.no
       }
     // 요청 처리 결과값 읽기 => 데이터값 변경 (상태변경) 상태 관리 프로그램 
     }).then(function(result){
       _this.vo=result.data;
     })
   }
 })
</script>
</body>
</html>

 

 

 

글 수정

BoardMapper.java (Interface)

@Select("SELECT pwd FROM spring_board WHERE no=#{no}")
  public String boardGetPassword(int no);
@Update("UPDATE spring_board SET " +
    "name=#{name}, subject=#{subject}, content=#{content} WHERE no=#{no}")
  public String boardUpdate(BoardVO vo);

 

BoardDAO.java (Class)

public BoardVO boardUpdateData(int no) {
  return mapper.boardDetailData(no);
}
public String boardUpdate(BoardVO vo) {
  String result = "no";
  String db_pwd = mapper.boardGetPassword(vo.getNo());
  if (db_pwd.equals(vo.getPwd())) {
    result = "yes";
    mapper.boardUpdate(vo);
  }
  return result;
}

BoardRestController.java (Class) - 자바와 자바스크립트 융합

@GetMapping(value = "board/update_vue.do", produces = "text/plain;charset=UTF-8")
public String board_update_vue(int no) {
  String result = "";
  BoardVO vo = dao.boardUpdateData(no);
  JSONObject obj = new JSONObject();
  System.out.println(vo.getContent());
  obj.put("no", vo.getNo());
  obj.put("subject", vo.getSubject());
  obj.put("content", vo.getContent());
  obj.put("name", vo.getName());

  result = obj.toJSONString();
  return result;
}
@GetMapping(value = "board/update_vue_ok.do", produces = "text/plain;charset=UTF-8")
public String board_update_vue_ok(BoardVO vo) {
  String result = dao.boardUpdate(vo);
  return result;
}

update.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style type="text/css">
.container{
  margin-top: 50px;
}
.row{
  margin : 0px auto;
  width : 900px;
}
h1{
  text-align:center;
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">
$(function(){
  $('#writeBtn').click(function(){
    let name = $('#name').val();
    if(name.trim()==""){
      $('#name').focus();
      return;
    }
    let subject = $('#subject').val();
    if(subject.trim()==""){
      $('#subject').focus();
      return;
    }
    let content = $('#content').val();
    if(content.trim()==""){
      $('#content').focus();
      return;
    }
    let pwd = $('#pwd').val();
    if(pwd.trim()==""){
      $('#pwd').focus();
      return;
    }
    
    $('#frm').submit();
  })
})
</script>
</head>
<body>
  <div class="container">
    <h1>글 수정하기</h1>
    <div class="row">
    <form method=post action="update_ok.do" id="frm">
      <table class="table">
        <tr>
          <th width=20% class="text-right">이름</th>
          <td width=80%>
            <input type=text name=name id=name size=20 class="input-sm" value="${vo.name }">
            <input type=hidden name=no value=${vo.no }>
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">제목</th>
          <td width=80%>
            <input type=text name=subject id=subject size=50 class="input-sm" value="${vo.subject }">
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">내용</th>
          <td width=80%>
            <textarea rows="10" cols="50" name=content id=content>${vo.content }</textarea>
          </td>
        </tr>
        <tr>
          <th width=20% class="text-right">비밀번호</th>
          <td width=80%>
            <input type=password name=pwd id=pwd size=15 class="input-sm">
          </td>
        </tr>
        <tr>
          <td colspan="2" class="text-center">
            <input type=button value="수정하기" class="btn btn-sm btn-warning" id="writeBtn">
            <input type=button value="취소" class="btn btn-sm btn-danger"
              onclick="javascript:history.back()">
          </td>
        </tr>
      </table>
    </form>
    </div>
  </div>
</body>
</html>

 

 

 

글 삭제

BoardMapper.java (Interface)

@Delete("DELETE FROM spring_board WHERE no=#{no}")
  public void boardDelete(int no);

 

BoardDAO.java (Class)

public String boardDelete(String pwd, int no) {
  String result = "no";
  String db_pwd = mapper.boardGetPassword(no);
  if (db_pwd.equals(pwd)) {
    result = "yes";
    mapper.boardDelete(no);;
  }
  return result;
}

BoardRestController.java (Class) - 자바와 자바스크립트 융합

@GetMapping(value = "board/delete_vue_ok.do", produces = "text/plain;charset=UTF-8")
public String board_delete_vue_ok(String pwd, int no) {
  String result = dao.boardDelete(pwd, no);
  return result;
}

delete.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.row1{
  margin : 0px auto;
  width : 450px;
}
h1{
  text-align:center;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div class="container">
  <h1>글 삭제하기</h1>
    <div class="row row1">
      <table class="table">
        <tr>
          <th width=20% class="text-right">비밀번호</th>
          <td width=80%>
            <input type=password v-model="pwd" ref="pwd" size=15 class="input-sm">
          </td>
        </tr>
        <tr>
          <td colspan="2" class="text-center">
            <input type=submit value="삭제" class="btn btn-sm btn-warning" v-on:click="boardDelete()">
            <input type=button value="취소" class="btn btn-sm btn-info" onclick="javascript:history.back()">
          </td>
        </tr>
      </table>
    </div>
  </div>
<script>
  new Vue({
    el:'.container',
    data:{
      no:${no},
      pwd:'',
      res:''
    },
    methods:{
      boardDelete:function(){
        let _this=this;
        axios.get("http://localhost:8080/web/board/delete_vue_ok.do",{
          params:{
            no:_this.no,
            pwd:_this.pwd
          }
        }).then(function(result){
          _this.res = result.data
          if(_this.res=='yes'){
            location.href="../board/list.do"
          }else{
            alert("비밀번호 확인하셈!!!");
            _this.pwd = "";
            _this.$refs.pwd.focus();
          }
        })
      }
    }
  })
</script>
</body>
</html>

 

 

댓글()