본문 바로가기
[ JAVA ]/JAVA Spring

[ Spring ] 메모장 만들기(STS)

by 환이s 2023. 4. 6.



Spring Tool Suite(STS)를 사용해서 간단한 메모장을 구현했습니다.

프로젝트 구조는 다음과 같습니다.

 

프로젝트 구조

 

 

프로젝트 흐름은 다음과 같습니다.

 

MemoController => MemoService = > MemoServiceImpl = > MemoDAO => memo_list.jsp

 

그럼 먼저 Table을 생성해서 DTO 생성을 합니다.


SQL memo Table

 

memo 테이블을 생성해서 연습용 데이터 두 개 정도 추가해 줍니다.

 

create table memo (
idx number not null primary key,
writer varchar2(50) not null,
memo varchar2(200) not null,
post_date date default sysdate
);

insert into memo(idx,writer,memo) values (1,'kim','첫번째 메모');
insert into memo(idx,writer,memo) values (2,'park','두번째 메모');

 

테이블 생성을 했다면 DTO 생성을 합니다.


Model.MemoDTO

 

DTO에서는 getter/setter , toString , 생성자 두 개를 생성하는데, 매개 변수로는 writer, memo 만 등록해 줍니다.

 

package com.example.spring.model.memo.dto;

import java.util.Date;

public class MemoDTO {

		private int idx;
		private String writer;
		private String memo;
		private Date post_date;
		
		
		public int getIdx() {
			return idx;
		}
		public void setIdx(int idx) {
			this.idx = idx;
		}
		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;
		}
		@Override
		public String toString() {
			return "MemoDTO [idx=" + idx + ", writer=" + writer + ", memo=" + memo + ", post_date=" + post_date + "]";
		}
		public MemoDTO(String writer, String memo) {
			
			this.writer = writer;
			this.memo = memo;
		}
		public MemoDTO() {
			
			
		}
		

}

 


menu.jsp

 

이전부터 index 페이지를 생성해서 데이터를 호출하는 방식으로 해왔습니다. 

메모장은 memu.jsp 페이지를 생성해서 include 방식으로 상단부에 있는 메뉴 클릭 시 데이터가 호출되는 방식으로 진행하겠습니다.

 

 menu.jsp 파일은 include 파일 안에 생성합니다.

 

다음으로 include로 호출할 수 있게 <a> 태그에 경로를 지정합니다.

 

 

memo 파일에 list.do 호출을 Controller에 요청을 보냈습니다. 

Controller에서 호출 값을 받습니다.

 


Controller

 

Spring에서 Controller를 사용하려면 빈으로 등록을 해야 합니다.

등록은 @(어노테이션) Controller로 등록합니다. 또한 세부적인 url 처리를 하기 위해 공통적인 url 설정도 해줘야 하는데, 공통적인 url이라고 하면 menu.jsp 에서 Controller에 요청 보낸 memo부터 뜻합니다. 

 

즉, 공통적인 url방식은 무조건 memo 파일 안에서 요청을 하기 때문에 @RequestMapping으로 url을 설정해 줍니다.

 

Controller 기능이 하나씩 추가될 때마다 중간 다리 역할을 합니다.

그렇다면 기능을 추가할 때마다 어디서 호출을 할까요?

 

그건 바로 프로그램 흐름처럼 Service를 호출합니다.

호출을 하기 위해 DI 주입 즉, 의존관계를 주입시켜야 하는데, DI@Inject를 사용해서 DI 설정을 합니다.

 

그럼 각 기능마다 Service에게 호출하는 코드를 확인합니다.

 

package com.example.spring.controller.memo;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.example.spring.model.memo.dto.MemoDTO;
import com.example.spring.service.memo.MemoService;

@Controller //스프링에게 컨트럴러빈으로 등록
@RequestMapping("memo/*") //공통적인 url pattern
public class MemoController {
	
	@Inject
	MemoService memoService;
	
	//memo/list.do
	@RequestMapping("list.do") //세부적인 url pattern //목록
	public ModelAndView list(ModelAndView mav) {
		List<MemoDTO> items=memoService.list();
		//views/memo/memo_list.jsp
		mav.setViewName("memo/memo_list"); 
		//포워딩할 뷰의 이름
		mav.addObject("list", items); 
		//전달할 데이터(모델)
		return mav; 
		// return new ModelAndView("memo/memo_list", "list",items);
	}
	
	@RequestMapping("insert.do") // 추가
	public String insert(@ModelAttribute MemoDTO dto) {
		memoService.insert(dto);
		return "redirect:/memo/list.do";//목록갱신요청
	}
	
	@RequestMapping("view/{idx}") // 메모 상세보기
	public ModelAndView view(@PathVariable int idx, ModelAndView mav) {
		mav.setViewName("memo/view");//포워딩하는 뷰이름
		mav.addObject("dto", memoService.memo_view(idx));
		return mav;
	}
	
	@RequestMapping("update/{idx}") // 수정
	public String update(@PathVariable int idx, @ModelAttribute MemoDTO dto) {
		memoService.update(dto);
		return "redirect:/memo/list.do";//목록갱신요청
	}
	
	@RequestMapping("delete/{idx}") // 삭제
	public String delete(@PathVariable int idx) {
		memoService.delete(idx);
		return "redirect:/memo/list.do";//목록갱신요청
	}

}

 

다음으로 Controller에서 호출한 Service 코드입니다.

 


Service / ServiceImpl

 

먼저 필요한 기능들의 타입에 맞게 생성합니다.

 

package com.example.spring.service.memo;

import java.util.List;

import com.example.spring.model.memo.dto.MemoDTO;

public interface MemoService {
	
	public List<MemoDTO> list();
	public void insert(MemoDTO dto);
	public MemoDTO memo_view(int idx);
	public void update(MemoDTO dto);
	public void delete(int idx);

}

 

기능에 맞게 매개변수, 타입 설정이 끝났다면 Override 해줍니다.

 

package com.example.spring.service.memo;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import com.example.spring.model.memo.dao.MemoDAO;
import com.example.spring.model.memo.dto.MemoDTO;

@Service // bean 등록
public class MemoServiceImpl implements MemoService {

	//Service가 DAO를 호출
	@Inject //의존관계 주입(DI)
	MemoDAO memoDao;

	@Override
	public List<MemoDTO> list() {
		return memoDao.list();
		//list()는 완성된 인터페이스가 아닌데도
		//쓸 수 있는 이유는 스프링이 root-context.xml에서 지정한 mybatis객체를
		//메모리에 올려 셋팅에 의해 생성된 객체를 자동 결합시키며 ArrayList로 받아 처리한다.
	}

	@Override
	public void insert(MemoDTO dto) {
		memoDao.insert(dto.getWriter(), dto.getMemo());
	}

	@Override
	public MemoDTO memo_view(int idx) {
		return memoDao.memo_view(idx);
	}

	@Override
	public void update(MemoDTO dto) {
		memoDao.update(dto);
	}

	@Override
	public void delete(int idx) {
		memoDao.delete(idx);
	}

}

 

Service에서는 DAO를 호출하는 역할만 해줍니다. 

Controller와 동일하게 DAO를 호출할 수 있게 DI 설정을 해줍니다.

 

다음으로 DAO 생성을 합니다.

 


Model.MemoDAO 

 

이전 포스팅에서는 mybatis를 활용해서 mapper 파일에서 처리할 수 있게 DAO에서도 호출만 할 수 있게 했습니다.

이번에는 mapper 파일을 생성하지 않고 DAO에서 SQL 작업을 해보겠습니다.

 

package com.example.spring.model.memo.dao;

import java.util.List;

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

import com.example.spring.model.memo.dto.MemoDTO;

//mybatis interface mapper
public interface MemoDAO {
	@Select("select * from memo order by idx desc")
	public List<MemoDTO> list();
	
	//mybatis query에 전달할 변수는 @Param으로 처리
	@Insert("insert into memo (idx,writer,memo) values "
			+ "( (select nvl(max(idx)+1,1) from memo)"
			+ ", #{writer}, #{memo} )")
	public void insert(@Param("writer") String writer
			, @Param("memo") String memo);
	
	@Select("select * from memo where idx=#{idx}")
	public MemoDTO memo_view(@Param("idx") int idx);
	
	//위 insert와는 달리 개별적인 @Param대신 dto로 묶어서 전달할 수 있음
	@Update("update memo set writer=#{writer}, memo=#{memo} where idx=#{idx}")
	public void update(MemoDTO dto);
	
	@Delete("delete from memo where idx=#{idx}")
	public void delete(@Param("idx") int idx);
}

 

DAO 코드 작업까지 끝냈다면, 마지막으로 VIEW 단 호출 페이지를 생성합니다.

연습용이라서 간단하게 생성합니다.

 


memo_list.jsp / view.jsp

 

먼저 목록 페이지를 생성합니다.

 

< memo_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>
<%@ include file="../include/header.jsp" %>
<script type="text/javascript">
function memo_view(idx) {
	location.href="${path}/memo/view/"+idx;
	//REST(Representational state transfer)방식, 또는 RESTful한 URI방식
	//게시물로 고유한 주소값을 가짐, 게시물하나가 주소1개이다.
	// http://localhost/spring02/memo/view/1 번게시물
	// http://localhost/spring02/memo/view/2
	// 따라서 이런방식에서는 스프링에서 @PathVariable을 적용

	// jsp방식에서는 파라미터가 바뀔뿐이지 주소가 바뀌는것은 아니었다.
	// http://localhost/spring02/memo/view.do?idx=1
	// http://localhost/spring02/memo/view.do?idx=2
}
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>메모장</h2>
<form action="${path}/memo/insert.do">
 이름 : <input name="writer" size="10"><br>
 메모 : <input id="memo" name="memo" size="40">
 <input type="submit" value="확인">
</form>

<table border="1">
  <tr>
    <th>번호</th>
    <th>이름</th>
    <th>메모</th>
    <th>날짜</th>
  </tr>
<c:forEach var="row" items="${list}">  
  <tr>
    <td>${row.idx}</td>
    <td>${row.writer}</td>
    <td><a href="#" onclick="memo_view('${row.idx}')">${row.memo}</a></td>
    <td><fmt:formatDate value="${row.post_date}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
  </tr>
</c:forEach>  
</table>



</body>
</html>

 

다음으로는 memo 클릭 시 수정/삭제 기능이 있는 상세 화면 페이지 생성을 합니다.

 

< view.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>
<%@ include file="../include/header.jsp" %>
<script type="text/javascript">
$(function() {
	$("#btnUpdate").click(function() {
		document.form1.action="${path}/memo/update/${dto.idx}";
		document.form1.submit();
	});
	$("#btnDelete").click(function() {
		if(confirm("삭제하시겠습니까?")){
		document.form1.action="${path}/memo/delete/${dto.idx}";
		document.form1.submit();
		}
	});
})

</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>메모 보기</h2>
<form name="form1" method="post">
<table border="1">
	<tr>
		<td>번호</td>
		<td>${dto.idx}</td>
	</tr>
		<tr>
		<td>이름</td>
		<td><input name="writer" value="${dto.writer}"></td>
	</tr>
		<tr>
		<td>메모</td>
		<td><input name="memo" value="${dto.memo}" size="40"></td>
	</tr>
	<tr align="center">
	<td colspan="2">
		<input type="hidden" name="idx" value="${dto.idx }">
		<input type="button" value="수정" id="btnUpdate">
		<input type="button" value="삭제" id="btnDelete">
	</td>
	</tr>
</table>
</form>
</body>
</html>

 

그럼 결과를 확인해 봅니다.


출력 

 

<menu.jsp>

 


< 목록 페이지 >

 


< insert > 

 


< view >

 


< update >

 


< delete >

 

 


마치며

 

오늘은 STS를 사용해서 간단한 메모장을 구현했습니다.

다음 포스팅에서 뵙겠습니다.

728x90