Spring Boot와 MongoDB 연동 실습 (한줄메모장)
Back-End/Spring 2019. 7. 9. 17:27한줄메모장 만들기
MongoDB는 테이블을 사전에 만들 필요가없고, 코딩에 의해 테이블이 즉각적으로 생겨나고 자료가 삽입된다.
비정형 데이터를 넣는것에 적합한 DB이다.
한줄메모장 구조 -글목록- 1. home.jsp에 include된 menu.jsp 페이지에 있는 "메모장" 버튼을 누르면 MemoController.java에 있는 memo.do메소드로 맵핑된다. 2. 맵핑된 메소드에서 memo.jsp 페이지로 이동시킨다. 3. memo.jsp 페이지가 호출될때 가장먼저 memo_list() 함수가 호출되고, ajax방식이고, 컨트롤러에 memo_list.do와 맵핑되는데 데이터만 넘어가고 화면은 바뀌지 않는다. 4. memo_list.do와 맵핑된 컨트롤러의 메소드에서는 서비스에서 메모목록을 가져와 hashmap에 저장하고, memo_list.jsp 페이지로 이동시키고, 아까 map변수에 담은 list도 같이 넘겨준다. 5. memo_list.jsp 페이지에서는 넘겨받은 map에 있는 게시글번호, 작성자 이름, 작성글내용, 작성날짜를 출력한다.
-글쓰기- 1. memo.jsp 페이지에서 "이름" 과 "메모" 를 작성한 후에 "확인" 버튼을 누르면 해당되는 id값 (btnWrite)가 넘어가서 id값에 맞는 자바스크립트 함수가 실행되고, 이 함수는 memo_insert()함수를 호출한다. 2. memo_insert() 함수에서 작성자의 이름과 메모를 각각 변수에 담고, ajax방식으로 페이지를 안바꾸고 데이터만 post방식으로 컨트롤러에 memo_insert.do로 맵핑시킨다. 3. memo_insert.do에 맵핑된 메소드에서는 서비스를 호출해서 dto값을 담고 memo.do로 다시 맵핑시킨다. 4. memo.do로 맵핑된 메소드에서는 다시 memo.jsp 페이지로 이동시킨다. 5. 아까 memo_inset() 함수가 정상적으로 실행되서 자료가 전달되었으므로, success문 하위에 있는 memo_list()함수가 실행된다. 6. memo_list()함수가 실행되면 ajax방식으로 컨트롤러에 memo_list.do와 맵핑되고, 거기에서 list를 map로 받아온다. 7. memo_list()함수에서 자료 전달이 성공적으로 됬으므로 success문을 실행해서 컨트롤러에서 받아온 map값을 result 변수에 저장하고, id가 #memoList인 태그에 컨트롤러로부터 넘겨받은 map를 출력시키면 메모글이 추가된다. -글삭제- 1. memo_view 페이지에서 "삭제" 버튼을 누르면 id값인 btnDelete가 위쪽 자바스크립트 함수와 맵핑되어서 자바스크립트 함수에서 컨트롤러에 있는 memo_delete.do로 맵핑되면서 자료를 넘겨준다. 2. memo_delete.do로 맵핑된 메소드에서 서비스에 _id(키값)을 매개변수로 넘겨서 레코드를 삭제하고 memo.do로 리턴시킨다. 3. memo.do로 맵핑된 메소드에선 memo.jsp 페이지로 이동시킨다. 4. memo.jsp 가 호출되었으므로 memo_list() 함수가 호출되어서 ajax방식으로 컨트롤러에 있는 memo_list.do로 맵핑된다. 5. memo_list.do에선 아까 갱신(삭제한) 리스트를 다시 map에 담아서 memo_list.jsp 페이지로 리턴한다. (map)와 함께 6. memo_list.jsp 에선 map에 있는 자료를 차례로 출력하면 아까 삭제한 글을 제외하고 리스트로 출력되게 된다. -글수정- 1. memo_view 페이지에서 자료를 수정하고 "수정" 버튼을 누르면 id값인 btnUpdate가 위쪽 자바스크립트 함수와 맵핑되어서 자바스크립트 함수에서컨트롤러에 있는 memo_update.do로 맵핑된다. 2. memo_update.do와 맵핑된 메소드에선 서비스를 호출해서 memoUpdate메소드에 dto에 담긴값들을 매개변수로 담고, memo.do로 리턴한다. 3. memo.do와 맵핑된 메소드에선 다시 memo.jsp 페이지로 이동시킨다. 4. memo.jsp 페이지가 실행되었으므로 memo_list()함수가 실행된다. 5. memo_list()함수에서는 ajax방식으로 memo_list.do와 맵핑되서 화면은 바뀌지 않고 데이터만 컨트롤러로 넘긴다. 6. memo_list.do와 맵핑된 컨트롤러에 있는 메소드에서는 서비스를 호출해 list를 hashmap에 저장하고, memo_list.jsp 페이지로 자료를 넘기고, 페이지를 이동시킨다. 7. memo.jsp 페이지에서는 ajax방식으로 자료를 보내는데에 성공했으므로 success구문이 실행되서 컨트롤러가 받아온 값을 result변수에 저장하고, id가 #memoList인 태그에 넘어온 값을 출력시킨다. (그러니까 memo.jsp페이지에서 메모리스트(memo_list)를 보여줌
|
MemoDTO.java 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | package com.example.spring04.model.memo.dto; import java.util.Date; public class MemoDTO { private String _id; //id는 pk이므로 _id로 하여야한다. private String writer; //작성자 private String memo; //메모내용 private Date post_date; //날짜 //getter/setter,toString() public String get_id() { return _id; } public void set_id(String _id) { this._id = _id; } public String getWriter() { return writer; } public void setWriter(String writer) { this.writer = writer; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } public Date getPost_date() { return post_date; } public void setPost_date(Date post_date) { this.post_date = post_date; } public MemoDTO(String _id, String writer, String memo, Date post_date) { super(); this._id = _id; this.writer = writer; this.memo = memo; this.post_date = post_date; } } | cs |
MemoDAO.java 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.example.spring04.model.memo.dao; import java.util.List; import com.example.spring04.model.memo.dto.MemoDTO; public interface MemoDAO { List<MemoDTO> getMemoList(); //목록보기 void memoInsert(MemoDTO dto); //글쓰기 MemoDTO memoDetail(String _id); //상세화면 void memoUpdate(MemoDTO dto); //글수정 void memoDelete(String _id); //글삭제 } | cs |
MemoDAOImpl.java 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | package com.example.spring04.model.memo.dao; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; import com.example.spring04.model.memo.dto.MemoDTO; @Repository //DAO 사용 어노테이션 선언 public class MemoDAOImpl implements MemoDAO { @Autowired //MongoDB사용을 하기위해 의존성을 주입한다. MongoTemplate mongoTemplate; String COLLECTION_NAME="memo"; //컬렉션(테이블) 이름을 "memo"라고 한다, @Override public List<MemoDTO> getMemoList() { //목록을 뽑을때 사용하는 클래스 (query) Query query=new Query(); query.with(new Sort(Sort.Direction.DESC, "post_date")); //날짜기준 내림차순 정렬 return (List<MemoDTO>)mongoTemplate.find(//memo테이블에서 날짜기준으로 내림차순 정렬시킨 값을 DTO타입으로 저장해 리스트를 만들어 리턴하라는 의미이다. query, MemoDTO.class, COLLECTION_NAME); } @Override public void memoInsert(MemoDTO dto) {//저장할때 날짜를 따로 입력해서 저장하지 않기 때문에 dto.setPost_date(new Date()); //java.util.Date // insert( 추가할객체, 컬렉션이름 ) mongoTemplate.insert(dto, COLLECTION_NAME); //코드로 날짜를 집어넣고 insert를 하면 된다. } @Override public MemoDTO memoDetail(String _id) { //id에 해당하는 값 (레코드) 1개를 찾을 경우에는 findById(_id, 클래스, 테이블이름) 사용 return mongoTemplate.findById( _id, MemoDTO.class, COLLECTION_NAME); //id에 해당되는 자료를 COLLECTION_NAME테이블에서 가져와서 DTO에 저장 } @Override public void memoUpdate(MemoDTO dto) { // update 테이블 set 필드=값, 필드=값 where 필드=값 // where 조건 Query query=new Query( new Criteria("_id").is(dto.get_id())); //테이블에 있는 id와 내가적은 id가 같을경우에 글을 수정할 수 있다. //수정할 내용 Update update=new Update(); update.set("writer", dto.getWriter()); update.set("memo", dto.getMemo()); // upsert : update or insert //없으면 추가하고, 있으면 수정한다는 의미이다. mongoTemplate.upsert( query, update, MemoDTO.class, COLLECTION_NAME); } @Override public void memoDelete(String _id) { Query query=new Query(new Criteria("_id").is(_id)); //저장되있는 아이디가 내가 입력한 아이디와 같을경우에 mongoTemplate.remove(query, COLLECTION_NAME); //테이블에 있는 쿼리를 삭제함 } } |
MemoService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.example.spring04.service.memo; import java.util.List; import com.example.spring04.model.memo.dto.MemoDTO; public interface MemoService { List<MemoDTO> getMemoList(); //메모 목록 void memoInsert(MemoDTO dto); //메모 저장 MemoDTO memoDetail(String _id); //메모 상세 내용 보기 void memoUpdate(MemoDTO dto); //메모 수정 void memoDelete(String _id); //메모 삭제 } | cs |
MemoServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package com.example.spring04.service.memo; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.spring04.model.memo.dao.MemoDAO; import com.example.spring04.model.memo.dto.MemoDTO; @Service //서비스 어노테이션 public class MemoServiceImpl implements MemoService { @Autowired //스프링프레임워크 의존성 주입, dao를 호출하기위해 의존성을 주입 MemoDAO memoDao; @Override public List<MemoDTO> getMemoList() { //메모 목록 리턴 return memoDao.getMemoList(); } @Override public void memoInsert(MemoDTO dto) { memoDao.memoInsert(dto); } @Override public MemoDTO memoDetail(String _id) { return memoDao.memoDetail(_id); } @Override public void memoUpdate(MemoDTO dto) { memoDao.memoUpdate(dto); } @Override public void memoDelete(String _id) { memoDao.memoDelete(_id); } } | cs |
menu.jsp에서 메모장 링크를 눌렀을때, memo.do로 맵핑되서 메모 목록을 얻어서 화면에 출력시킬 예정
menu.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- HOME, 메모장, 방명록페이지로 가는 링크를 추가 --> <a href="${path}/">Home</a> | <a href="${path}/memo.do">메모장</a> | <a href="${path}/guestbook.do">방명록</a> | <div style="text-align:right;"> <c:choose> <!-- 세션에 저장된 유저의 아이디가 NULL이면 로그인페이지로 이동 --> <c:when test="${sessionScope.userid == null }"> <!-- 로그인 페이지로 이동하는 링크 --> <a href="${path}/member/login.do">로그인</a> </c:when> <c:otherwise> <!-- 세션에 저장된 유저의 아이디가 NULL이 아니라면 로그인 중이라는 메시지를 출력한다. --> ${sessionScope.name}님이 로그인중입니다. <!-- 로그인중이므로 로그아웃 할 수 있는 링크를 추가한다. --> <a href="${path}/member/logout.do">로그아웃</a> </c:otherwise> </c:choose> </div> <hr> | cs |
MemoController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package com.example.spring04.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring04.model.memo.dto.MemoDTO; import com.example.spring04.service.memo.MemoService; @Controller //컨트롤러 빈 선언 public class MemoController { @Autowired // @Inject, 서비스를 호출하기위해 의존성을 주입 MemoService memoService; @RequestMapping("/memo.do") public String memo() { return "memo/memo"; //memo디렉토리에 memo jsp파일로 가서 목록을 다시 얻어온다. } @RequestMapping("/memo_list.do") //게시물 리스트 public ModelAndView memo_list() { Map<String,Object> map=new HashMap<>(); List<MemoDTO> list=memoService.getMemoList(); //서비스에서 메모목록을 가져온다. map.put("items", list); //값이 여러개기때문에 hashmap로 담아서 ModelAndView로 넘기고, 거기에서 memo_list jsp페이지에 "memo"라는 변수명으로 보내 출력시킨다. return new ModelAndView("memo/memo_list", "map", map); } @RequestMapping("/memo_insert.do") //게시물 삽입 public String memo_insert(@ModelAttribute MemoDTO dto) { memoService.memoInsert(dto); return "redirect:/memo.do"; } @RequestMapping("/memo_view.do") public ModelAndView memo_view(String _id) { MemoDTO dto=memoService.memoDetail(_id); return new ModelAndView("memo/memo_view", "dto", dto); } @RequestMapping("/memo_update.do") public String memo_update(@ModelAttribute MemoDTO dto) { memoService.memoUpdate(dto); return "redirect:/memo.do"; } @RequestMapping("/memo_delete.do") public String memo_delete(String _id) { memoService.memoDelete(_id); return "redirect:/memo.do"; } } | cs |
View 파일들
memo.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp" %> <script> //이 페이지가 호출되었을때 memo_list()가 맨처음 실행 $(function(){ memo_list(); //메모를 쓰고 난다음 확인버튼을 누르면 밑에있는 코드에 id값 :btnWrite가 이 태그로 맵핑되고, memo_insert()함수가 실행된다. $("#btnWrite").click(function(){ memo_insert(); }); }); function memo_insert(){ var writer=$("#writer").val(); // 메모를 작성한 작성자의 이름이 writer변수에 담긴다. var memo=$("#memo").val(); // 작성한 메모가 memo변수에 저장된다. $.ajax({ //ajax방식은 페이지가 바뀌지 않고 데이터만 주고 받을 수 있는 방식 type: "post", //post방식으로 넘김 data: {"writer":writer, "memo":memo},//각각 값들을 저장함 url: "${path}/memo_insert.do", //memo_insert.do (컨트롤러로) 맵핑됨 success: function(){ //위의 구문이 성공했을시에 실행되는 함수 memo_list(); //목록 갱신 $("#writer").val(""); //writer에 value값에 ""(공백) 값을 넣는다. $("#memo").val(""); //memo에 value값에 ""(공백) 값을 넣는다. } }); } //맨 처음 실행되는 함수 ajax방식으로 실행되고, memo_list.do와 맵핑 (다시 데이터만 컨트롤러로 넘어감, 화면은 안바뀜) function memo_list(){ //ajax방식은 화면이 안바뀌고 백그라운드에서만 실행되는것. $.ajax({ url: "${path}/memo_list.do", success: function(result){ //컨트롤러가 받아온 값을 result변수에 저장하고, id가 #memoList인 태그에 넘어온값을 출력시킬 예정 $("#memoList").html(result); } }); } function memo_view(num){ // memo_view.do?_id=5 location.href="${path}/memo_view.do?_id="+num; } </script> </head> <body> <%@ include file="../include/menu.jsp" %> <h2>한줄메모장</h2> 이름 : <input id="writer"> 메모 : <input id="memo" size="50"> <input type="button" value="확인" id="btnWrite"> <div id="memoList"></div> </body> </html> | cs |
memo_list.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <table border="1" width="700px"> <tr> <th>No</th> <th>이름</th> <th>메모</th> <th>날짜</th> </tr> <c:forEach var="row" items="${map.items}" varStatus="status"> <!-- varStatus는 변수명을 붙인것 --> <!-- 컨트롤러에서 보낸 map의 items안에 있는 값들을 하나씩 출력 --> <tr> <td>${status.count}</td> <!-- 원래 {row._id}가 키값인데 이렇게 쓰면 숫자 뒤에 소수점이 붙어서 나오고, status를 쓰면 중간에 값이 빠질일이 없이 제대로 출력된다.--> <!-- index 0부터, count 1부터이기 때문에 count를 사용해서 소수점을 제외하고 출력시킨다.--> <td>${row.writer}</td> <!--작성자이름을 호출한다.--> <td> <a href="#" onclick="memo_view('${row._id}')">${row.memo}</a> <!-- _id가 키값이기 때문에 id를 넘겨서 메모내용으로 넘어간다.--> </td> <td> <!-- 날짜가 나오는 형식을 지정하기 위해 formatDate태그와 패턴을 사용한다. --> <fmt:formatDate value="${row.post_date}" pattern="yyyy-MM-dd HH:mm:ss" /></td> </tr> </c:forEach> </table> | cs |
memo_view.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp" %> <script> $(function(){ //수정버튼을 클릭하면 실행되는 함수, 밑에 코드에서 맵핑되어서 //컨트롤러의 memo_update.do url로 맵핑시킨다. $("#btnUpdate").click(function(){ document.form1.action="${path}/memo_update.do"; document.form1.submit(); }); //삭제버튼을 클릭하면 실행되는 함수, 밑에 코드에서 맵핑되어서 //컨트롤러에 memo_delete.do url로 맵핑시킨다. $("#btnDelete").click(function(){ if(confirm("삭제하시겠습니까?")){ document.form1.action="${path}/memo_delete.do"; document.form1.submit(); } }); }); </script> </head> <body> <%@ include file="../include/menu.jsp" %> <h2>메모장</h2> <form name="form1" method="post"> <!--키값이 id이기 때문에 _id를 dto에서 받아서 히든타입으로 자료를 넘겨준다. --> <input type="hidden" name="_id" value="${dto._id}"> 이름 <input name="writer" value="${dto.writer}"><br> <!-- dto에 저장된 작성자이름 출력 --> 메모 <input name="memo" value="${dto.memo}" size="50"><br><!-- dto에 저장된 메모 출력 --> <input type="button" value="수정" id="btnUpdate"> <!-- 수정버튼을 누르면 id값이 위쪽에 있는 자바스크립트 함수에 맵핑되서 자바스크립트문에서 컨트롤러로 이동시킴--> <input type="button" value="삭제" id="btnDelete"> <!-- 삭제버튼을 누르면 id값이 위쪽에 있는 자바스크립트 함수에 맵핑되서 자바스크립트문에서 컨트롤러로 이동시킴--> <input type="button" value="목록" id="btnList" onclick="location.href='${path}/memo.do'"> <!-- 목록 버튼을 누르면 id값인 btnList가 컨트롤러로 맵핑됨 (memo.do URL로) --> </form> </body> </html> | cs |
mongo DB에서 서버를 실행하고, 프로젝트를 run해서 메모장에 값들을 집어넣어본후에 mongoDB에서 자료를
검색해보면 _id값이 고유번호인 uuid로 나오는 것을 확인해볼 수 있다.
(왜냐하면 글번호는 작성자가 집어넣는게 아니기 때문이고, _id값을 따로 정해주지
않았기때문에 서버에서 임의적으로 정해서출력된 값이기 때문이다.)
'Back-End > Spring' 카테고리의 다른 글
Spring와 SQL Server 연동 (2) | 2019.07.10 |
---|---|
Spring Boot와 MongoDB 연동 실습 (방명록) (0) | 2019.07.10 |
Spring 어노테이션 정리 (0) | 2019.07.08 |
Spring Boot와 MongoDB 연동해서 회원관리 예제 (회원가입, 로그인, 로그아웃) (1) | 2019.07.08 |
Spring Boot와 MongoDB 연동 (0) | 2019.07.08 |