BACK END/Spring

[Spring] 스프링 정리9 - 게시판 만들기

circle kim 2021. 1. 19. 18:14

[목차]

11. 게시판 만들기

① DB 연결

② List 출력

③ 게시물 등록

④ 검색

⑤ 상세 페이지 보기

⑥ 게시글 수정

⑦ 게시글 삭제

⑧ 댓글 기능 추가


[내용]

① DB 연결

 = sprweb16_board

 - db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/happydb
username=root
password=123

 => 계정 정보 설정파일.

 

 

 - Configuration.xml

<configuration>
<typeAliases>
	<typeAlias type="pack.model.BoardDto" alias="dto"/>
	<typeAlias type="pack.controller.BoardBean" alias="formBean"/>
</typeAliases>
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 => DataMapper.xml 연결.

 

 

- DataMapper.xml

<mapper namespace="dev">
 <!-- 전체 검색 -->
 <select id="selectList" resultType="dto">
  	select * from board order by gnum desc, onum asc
 </select>
 
 <!-- 카워드 검색 -->
 <select id="searchList" parameterType="formBean" resultType="dto">
  	select * from board 
  	where ${searchName} like concat('%',#{searchValue},'%') 
  	order by gnum desc, onum asc
 </select>
 
 <!-- 번호로 검색 -->
 <select id="selectOne" parameterType="string" resultType="dto">
  	select * from board where num=#{num}
 </select>
 
 <!-- 추가 -->
 <insert id="insertData" parameterType="formBean">
 	insert into board 
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},0,0)
 </insert>
 
 <update id="updateData" parameterType="formBean">
 	update board 
 	set name=#{name},mail=#{mail},title=#{title},cont=#{cont}
 	where num=#{num}
 </update>
 
 <delete id="deleteData" parameterType="string">
 	delete from board where num=#{num}
 </delete>
 
 <!--  maxnum -->
 <select id="currentNum" resultType="integer">
 	select max(num) from board
 </select>
 
 <select id="totalCnt" resultType="integer">
 	select count(*) from board
 </select>
 
 <!-- readcnt -->
 <update id="updateReadcnt" parameterType="string">
 	update board set readcnt=readcnt + 1 
 	where num=#{num}
 </update>
 
 <!-- password -->
 <select id="selectPass" parameterType="string" resultType="string">
 	select pass from shopboard 
 	where num=#{num}
 </select>

 <!-- reply -->
 <update id="updateOnum" parameterType="formBean">
 	update board set onum=onum + 1
 	where onum >= #{onum} and gnum=#{gnum}
 </update>

 <insert id="insertReData" parameterType="formBean">
 	insert into board
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},#{onum},#{nested})
 </insert>
</mapper>

 => SQL문 작성.

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

 => 어노테이션 사용을 위한 패키지 스캔.

 

 

 - root-context.xml

<!-- PropertyPlaceholderConfigurer 사용 : 외부 프로퍼티의 정보를 설정파일에서 사용가능.-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<!-- locations 속성으로 db.properties를 read하도록 설정 -->
	<!-- db.properties의 프로퍼티를 ${프로퍼티값}으로 사용할 수 있다. -->
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>
<!-- SimpleDriverDataSource 사용 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<!--  -->
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>
<!-- SqlSessionFactoryBean 사용 -->
<!-- 복수개일 경우 id를 셋팅 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- SqlMapConfig의 SqlSession에  Configuration.xml 연결-->
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 => DB 연동을 위한 SqlSessionFactory 객체 생성.

 

 


② List 출력

 - index.jsp

<body>
	<h2>메인</h2>
	<ul>
		<li>쇼핑하기</li>
		<li>회원관리</li>
		<li>물류관리</li>
		<li><a href="list?page=1">게시판</a></li>
	</ul>
</body>

 => url (list), key=value(page=1) 전달(GET 방식).

 

 

- ListController

@Controller
public class ListController {
	@Autowired
	private BoardDaoInter boardInter;
	
	private int tot; // 전체 레코드 수
	private int plist=5; // 한 페이지 당 행의 수
	private int pageCount; // 전체 페이지 수
	
	public ArrayList<BoardDto> getListData(ArrayList<BoardDto> list, int page){
		ArrayList<BoardDto> result = new ArrayList<BoardDto>();
		int start = (page - 1)*plist; // 해당 페이지의 첫 게시물의 index
		int size = plist <= list.size() - start ? plist : list.size() - start;
		// 한 페이지에 표시할 데이터가 5개 이하일 경우엔 size가 그 수에 따르도록 조건처리.
        
		for(int i=0; i<size;i++) { // list에 한 페이지당 표시할 데이터만 담아 리턴한다.
			result.add(i, list.get(start + i));
		}
		
		return result;
	}
	
	public int getPageCount() { // get 페이지 수
		pageCount = tot/plist;
		if(tot%plist > 0 ) pageCount+=1; 
		
		return pageCount;
	}
	
	@RequestMapping("list")
	public Model process(Model model, @RequestParam("page") int page) {
		tot = boardInter.totalCnt();
		ArrayList<BoardDto> list = boardInter.getList();
		ArrayList<BoardDto> result = getListData(list, page);
		model.addAttribute("data",result);
		model.addAttribute("pageCount",getPageCount());
		model.addAttribute("page",page);
		//model.addAttribute("data",list); // 페이징 없이 작업할 경우
		return model;
	}
}

 => totalCnt() : 

 => getList() : 전체 List 검색하여 list 리턴.

 => getListData() : 전체 리스트에서 한 페이지 당 표시할 데이터만 리턴값으로 가진다.

 => plist : 한 페이지 당  표시할 레코드 수를 설정.

 => getPageCount() : 페이지의 개수를 리턴.

 

 

- BoardBean

public class BoardBean {
	private String name,pass,mail,title,cont,bip,bdate;
	private int num,readcnt,gnum,onum,nested;
	private String searchName, searchValue;
	
	//getter/setter
}

 => FormBean 작성.

 

 

- BoardDto

public class BoardDto {
	private String name,pass,mail,title,cont,bip,bdate;
	private int num,readcnt,gnum,onum,nested;
	
	//getter/setter
}

=> DTO 작성.

 

 

- BoardDaoInter

public interface BoardDaoInter {
	ArrayList<BoardDto> getList();
	ArrayList<BoardDto> getSearch(BoardBean bean);
	boolean insert(BoardBean bean);
	BoardDto getDetail(String num);
	boolean update(BoardBean bean);
	boolean delete(String num);
	
	int currentNum();
	int totalCnt();
	boolean updateReadcnt(String num);
	String selectPass(String num);
	
	boolean updateOnum(BoardBean bean);
	boolean insertReply(BoardBean bean);
}

=> interface 작성.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	
	@Override
	public ArrayList<BoardDto> getList() {
		return (ArrayList)getSqlSession().selectList("selectList");
	}
    
	@Override
	public int totalCnt() {
		return getSqlSession().selectOne("totalCnt");
	}
	...
	
}

 => getList() : board 테이블의 모든 정보 list 리턴.

 => totalCnt() : 레코드 수를 리턴.

 <!-- 전체 검색 -->
 <select id="selectList" resultType="dto">
  	select * from board order by gnum desc, onum asc
 </select>

<select id="totalCnt" resultType="integer">
 	select count(*) from board
 </select>

 

 

 - list.jsp

<body>
<jsp:include page="./top.jsp"></jsp:include>
<table  class="table">
  <tr>
  	<td>
  		[<a href="list?page=1">최근목록</a>]&nbsp;
  		[<a href="insert">새글작성</a>]
  	</td>
  </tr>
</table>
<table class="table table-striped">
  <thead>
  <tr style="">
  	<th>번호</th><th>제  목</th><th>작성자</th><th>작성일</th><th>조회</th>
  </tr>
  </thead>
  <c:forEach var="b" items="${data}">
  	<!-- 댓글 들여쓰기 준비-->
  	<c:set var="tab" value=""/>
  	<c:forEach var="n" begin="1" end="${b.nested}">
  		<c:set var="tab" value="${tab}&nbsp;&nbsp;"/>
  	</c:forEach>
  <tr>
  	<td>${b.num}</td>
  	<td>
  		${tab}<a href="detail?num=${b.num}&page=${page}">${b.title}</a>
  	</td>
  	<td>${b.name}</td>
  	<td>${b.bdate}</td>
  	<td>${b.readcnt}</td>
  </tr>	
  </c:forEach>
  <!-- paging -->
  <tr style="text-align: center;">
  	<td colspan="5">
  	<c:forEach var="psu" begin="1" end="${pageCount}">
  		<c:if test="${psu==page}">
  			<b>${psu}</b>
  		</c:if>
  		<c:if test="${psu!=page}">
  			<a href="list?page=${psu}">${psu}</a>
  		</c:if>
  	</c:forEach>
  	</td>
  	
  </tr>
  <!-- search -->
  <tr style="text-align: center;">
  	<td colspan="5">
  	<br><br>
  	<form action="search" method="post">
  		<select name="searchName">
  			<option value="title" selected="selected">글제목</option>
  			<option value="name">작성자</option> 
  		</select>
  		<input type="text" name="searchValue">
  		<input type="submit" value="검색">
  	</form>
  	</td>
  </tr>
</table>
</body>

 => 페이지 처리된 list를 출력한다.

 => 제목을 누를 경우 요청명 detail로 num과 page 값을 전달한다.

 => 검색 버튼을 누를 경우 searchName(key)에 title or name(value), searchValue(key)에 값이 요청명 search로 전달.

      (post방식) 

 

 => 게시물 등록 하이퍼링크 클릭시 insert 요청명 전달.(GET방식)

 

 


③ 게시물 등록

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private BoardDaoInter boardInter;
	
	@RequestMapping(value="insert", method = RequestMethod.GET)
	public String insert() {
		return "insform";
	}
	...
}

 => GET방식 요청명 insert 받을 경우 inform.jsp 실행.

 

 

 - insform.jsp

<head>
	<script type="text/javascript">
		window.onload=function(){
			let btnIns = document.getElementById("btnIns");
			btnIns.addEventListener("click",checkData, false);
		}
		function checkData(){
			if(frm.name.value === ""){
				alert("작성자를 입력하세요");
				frm.name.focus();
				return;
			}else if(frm.pass.value === ""){
				alert("비밀번호를 입력하세요");
				frm.name.focus();
				return;
			}
			frm.submit();
		}
	</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<h4 style="text-align: center;">* 게시물 등록</h4>
<form action="insert" method="post" name="frm">
<table  class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name"></td>
  </tr>
  <tr>
  	<td>암호</td>
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<td><input type="text" name="title"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" cols="50" name="cont"></textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="hidden" name="bip" value="<%=request.getRemoteAddr()%>">
  		<input type="button" value="등록" id="btnIns">
  		<!-- <input type="button" value="등록" onclick="checkData()"> -->
  		<input type="button" value="목록" onclick="location.href='list?page=1'">
  	</td>
  </tr>
</table>
</form>
</body>

 => 등록 버튼 누를 경우 name/pass칸이 비어있을 경우 pop-up 발생.

     요청명 insert 전달.(post 방식)

 => location.href  : 목록버튼 누를 경우 list 출력 창 1 page로 이동.

      focus() : 커서가 해당 창으로 이동.

      submit() : submit 동작 진행.

 

 

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private BoardDaoInter boardInter;
	...
	@RequestMapping(value="insert", method = RequestMethod.POST)
	public String submit(BoardBean bean) {
		bean.setBdate();
		int newNum = boardInter.currentNum() + 1; // 새로 작성된 글의 번호
		bean.setNum(newNum);
		bean.setGnum(newNum);
		
		boolean b= boardInter.insert(bean);
		if(b) {
			return "redirect:/list?page=1";
		}else {
			return "redirect:/error";
		}
	}
}

 => POST방식 요청명 insert 받을 경우 실행.

 => <form>태그 데이터 FormBean에 set.

 => setBdate() : Calendar객체를 이용하여 오늘 날짜를 set한다.

 => currentNum() : 현재 테이블의 num값중 가장 큰 값을 받아와 +1하여 현재 num가 group num 값을 set한다.

 => insert() : data 추가.

 => insert 성공 시 전체 list 페이지로 이동, 실패 error 페이지로 이동.

public void setBdate() {
	Calendar cal = Calendar.getInstance();
	int year = cal.get(Calendar.YEAR);
	int month = cal.get(Calendar.MONTH) + 1;
	int day = cal.get(Calendar.DATE);
	this.bdate = year + "-" + month + "-" + day;
}

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...	
	@Override
	public boolean insert(BoardBean bean) {
		int result = getSqlSession().insert("insertData",bean);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}
	...
	@Override
	public int currentNum() {
		//insert시 번호 자동 증가를 위해 현재 레코드 중 가장 큰 번호 얻기.
		if(getSqlSession().selectOne("currentNum") == null) {
			return 0;
		}else {
			return getSqlSession().selectOne("currentNum");
		}
	}
	...
}

 => insert() : insert에 성공 시 true, 실패 시 false 리턴.

 => currentNum() : 레코드가 없을 경우 현재 가장 큰 num값을 0으로 리턴.

...
<!-- 추가 -->
<insert id="insertData" parameterType="formBean">
	insert into board 
	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
	#{bip},#{bdate},0,#{gnum},0,0)
</insert>
...
<!--  maxnum -->
<select id="currentNum" resultType="integer">
	select max(num) from board
</select>
...

 => Data insert

 => board테이블의 num중 가장 큰 값 리턴.

 

 

 - ErrorController

@Controller
public class ErrorController {
	
	@RequestMapping("error")
	public String err() {
		return "error";
	}
}

 => error.jsp 실행

 

 

 - error.jsp

<body>
	<h2>에러 발생</h2>
	<a href="list?page=1">목록보기</a>
</body>

 => error 페이지 출력.

 

 


④ 검색

- SearchController

@Controller
public class SearchController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("search")
	public ModelAndView searchProcess(BoardBean bean) {
		ArrayList<BoardDto> list = inter.getSearch(bean); 
		ModelAndView view = new ModelAndView("list", "data", list);
		view.addObject("page","1");
		return view;
	}
}

=> list.jsp에서 검색 버튼을 누를 경우 searchName(key), searchValue(key)가 전달된다.

=> getSearch() : searchName(key), searchValue(key)에 맞는 값을 검색하여 리스트로 출력한다.

=> 리턴 값을 list.jsp에 출력.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...	
	@Override
	public ArrayList<BoardDto> getSearch(BoardBean bean) {
		return (ArrayList)getSqlSession().selectList("searchList", bean);
	}
	...
}

 => getSearch() : 검색 후 ArrayList 리턴.

 

 

- DataMapper.xml

 ...
 <!-- 카워드 검색 -->
 <select id="searchList" parameterType="formBean" resultType="dto">
  	select * from board 
  	where ${searchName} like concat('%',#{searchValue},'%') 
  	order by gnum desc, onum asc
 </select>
 ...

 => searchName의 Column에서 searchValue의 키워드가 있을 경우 리스트를 리턴한다.

 

 


⑤ 상세 페이지 보기

- DetailController

@Controller
public class DetailController {
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("detail")
	public ModelAndView detailProcess(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		
		// 조회수 증가 작업 선행
		boolean b = inter.updateReadcnt(num);
		
		// 상세보기 진행 후 jsp로 출력
		ModelAndView view = new ModelAndView("detail");
		view.addObject("data", inter.getDetail(num));
		view.addObject("page", page);
		return view;
		
	}
}

 => list.jsp에서 제목을 누를 경우 요청명 detail로 num과 page 값을 전달받는다.

 => @RequestParam : request.getParameter()와 동일.

 => updateReadcnt() : 조회수를 +1한다.

 => getDetail() : 해당 num의 한 레코드 값을 리턴하여 detail.jsp 실행.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public BoardDto getDetail(String num) {
		// 글 내용보기, 글 수정 시 데이터 받아오기
		return getSqlSession().selectOne("selectOne",num);
	}
	...
	@Override
	public boolean updateReadcnt(String num) {
		//상세보기 전 조회수 증가
		int result = getSqlSession().update("updateReadcnt",num);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}
	...
}

 => getDetail() : 게시글의 내용을 받아온다.

 => updateReadcnt() : 업데이트 성공시 true, 실패 시 false 리턴

 

 

- DataMapper.xml

 ...
 <!-- 번호로 검색 -->
 <select id="selectOne" parameterType="string" resultType="dto">
  	select * from board where num=#{num}
 </select>
 ...
 <!-- readcnt -->
 <update id="updateReadcnt" parameterType="string">
 	update board set readcnt=readcnt + 1 
 	where num=#{num}
 </update>
 ...

 => num값과 동일한 레코드 리턴.

 => num과 동일한 레코드의 조회수 +1.

 

 

- detail.jsp

<script type="text/javascript">
	window.onload=function(){
	document.getElementById("btnDel").onclick = chkDeleData;
	}
	function chkDeleData(){
		
		let pass = prompt("비밀번호를 입력하세요");
		location.href="delete?num=${data.num}&page=${page}&pass="+pass;
	}
</script>
</head>
<body>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${msg != null}">
	<script type="text/javascript">
		(function msg(){
			alert("${msg}");
		})();
	</script>
</c:if>
<jsp:include page="./top.jsp"></jsp:include>
<div class="container">
<h4 style="text-align: center;">* 상세보기</h4>
<table class="table" style="width: 80%">
  <tr>
  	<td>비밀번호 : ${data.pass}</td>
  	<td style="text-align: right;">
  		<a href="reply?num=${data.num}&page=${page}">
  			<img src="./resources/images/reply.gif" />
  		</a>
  		<a href="update?num=${data.num}&page=${page}">
  			<img src="./resources/images/edit.gif" />
  		</a>
  		<button id="btnDel"><img src="./resources/images/del.gif" /></button>
  		<!-- 
  		<a href="delete?num=${data.num}&page=${page}">
  			<img src="./resources/images/del.gif" />
  		</a>
  		 -->
  		<a href="list?page=${page}">
  			<img src="./resources/images/list.gif" />
  		</a>
  	</td>
  </tr>
</table>

<table border="1" style="width: 80%">
  <tr>
  	<td>
  		작성자 : <a href="mailto:${data.mail}">${data.name}</a>
  		(ip : ${data.bip})
  	</td>
  	<td>작성일 : ${data.bdate}</td>
  	<td>조회수 : ${data.readcnt}</td>
  </tr>
  <tr>
  	<td colspan="3">제목 : ${data.title}</td>
  </tr>
  <tr>
  	<td colspan="3">
  		<textarea rows="5" readonly="readonly" style="width:99%">${data.cont}</textarea>
  	</td>
  </tr>
</table>
</div>
</body>

 => 댓글 기능 : 요청명 reply로 num과 page 값 전달.

 => 수정 기능 : 요청명 update로 num과 page 값 전달.(GET방식)

 => 삭제 기능 : 비밀번호 입력 prompt 출력 후 입력시 요청명 delete로 num, page, password 값 전달.

 => 목록 보기 기능 : 전체 list 출력 페이지로 이동.

 => msg가 있을 경우 pop-up창으로 발생.

 

 


⑥ 게시글 수정

- UpdateController

@Controller
public class UpdateController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping(value="update", method=RequestMethod.GET)
	public ModelAndView edit(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		
		// 모델에서 수정할 자료 읽기
		BoardDto dto = inter.getDetail(num);
		
		ModelAndView view = new ModelAndView("update");
		view.addObject("data", dto);
		view.addObject("page", page);
		return view;
	}
	...
}

=> 상세 페이지에서 수정 버튼 클릭시 실행.

=> getDetail() : 해당 데이터값 리턴.

=> update.jsp 실행.

 

 

- update.jsp

<script type="text/javascript">
	window.onload=function(){
	document.getElementById("btnUp").onclick = chkUpData;
	}
	function chkUpData(){
		if(upFrm.pass.value === ""){
			upFrm.pass.focus();
			alert("비밀번호를 입력하세요");
			return;
		}
		if(confirm("정말 수정할까요?")){
			upFrm.submit();
		}
	}
</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${msg != null}">
	<script type="text/javascript">
		(function msg(){
			alert("${msg}");
		})();
		location.href="list?page=${page}";
	</script>
</c:if>
<div class="container">
<h4 style="text-align: center;">- 수정 -</h4>
<form action="update" method="post" name="upFrm">
<input type="hidden" name="num" value="${data.num}">
<input type="hidden" name="page" value="${page}">
<table class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name" value="${data.name}"></td>
  </tr>
  <tr>
  	<td>암호</td>	
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail" value="${data.mail}"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<td><input type="text" name="title" value="${data.title}"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" cols="50" name="cont">${data.cont}</textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="button" value="수정" id="btnUp">
  		<input type="button" value="목록" onclick="location.href='list?page=${page}'">
  	</td>
  </tr>
</table>
</form>
</div>
</body>

 => 수정버튼을 누를 경우 비밀번호가 빈칸일 경우 팝업 발생. 있을 경우 요청명 update 전달.(post방식)

 => msg가 있을 경우 pop-up내용 출력 후 list 페이지로 이동.

 

 

 

- UpdateController

@Controller
public class UpdateController {
	
	@Autowired
	private BoardDaoInter inter;
	...
	@RequestMapping(value="update", method=RequestMethod.POST)
	public ModelAndView editSubmit(BoardBean bean,
			@RequestParam("page") String page) {
		// 비밀번호 체크
		String pass = inter.selectPass(Integer.toString(bean.getNum()));
		
		ModelAndView view = new ModelAndView();
		if(bean.getPass().equalsIgnoreCase(pass)) { // 사용자 비밀번호와 db의 비밀번호 비교
			boolean b = inter.update(bean);
			if(b) {
				//view.setViewName("redirect:/list?page="+page);
				view.setViewName("redirect:/detail?num="+bean.getNum()+"&page="+page);
			}else {
				view.setViewName("redirect:/error");
			}
		}else {
			view.setViewName("update");
			view.addObject("msg", "비밀번호 불일치");
			view.addObject("page", page);
		}
		return view;
	}
}

=> 수정 페이지에서 수정 버튼 누를 경우 실행.

=> selectPass() : 해당 num의 password 리턴.

=> 입력 패스트워드와 DB의 저장된 비밀 번호가 일치 할 경우 update()메소드 실행.

                                                               불일치 시 error msg를 전달하여 update 페이지 실행.

=> update 성공 시 수정 진행한 detail 페이지로 이동. 실패 시 error.jsp 실행.

 

 

 - BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean update(BoardBean bean) {
		try {
			int result = getSqlSession().update("updateData", bean);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("update err"+e);
			return false;
		}
	}
	...
	@Override
	public String selectPass(String num) { // 수정용 : 비밀 번호 비교
		return getSqlSession().selectOne("selectPass", num);
	}
	...
}

=> update() : 업데이트 성공 시 true, 실패시 false 리턴.

=> selectPass() : 해당 num의 password 리턴.

 

 

-DataMapper.xml

 ...
 <update id="updateData" parameterType="formBean">
 	update board 
 	set name=#{name},mail=#{mail},title=#{title},cont=#{cont}
 	where num=#{num}
 </update>
 ...
 <!-- password -->
 <select id="selectPass" parameterType="string" resultType="string">
 	select pass from board 
 	where num=#{num}
 </select>
 ...

=> update() : 해당 데이터로 수정.

=> selectPass() : 해당 num의 password 리턴.

 

 


⑦ 게시글 삭제

- DeleteController

@Controller
public class DeleteController {
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("delete")
	public ModelAndView del(@RequestParam("num") String num,
			@RequestParam("page") String page,
			@RequestParam("pass") String pass) {
		BoardDto dto = inter.getDetail(num);
		ModelAndView view = new ModelAndView();
		System.out.println(pass);
		if(dto.getPass().equalsIgnoreCase(pass)) { // 사용자 비밀번호와 db의 비밀번호 비교
			boolean b = inter.delete(num);
			if(b) {
				view.setViewName("redirect:/list?page="+page);
			}else {
				view.setViewName("redirect:/error");
			}
		}else {
			view.setViewName("detail");
			view.addObject("data", dto);
			view.addObject("msg", "비밀번호 불일치");
			view.addObject("page", page);
		}
		return view;
	}
}

 => 상세 페이지에서 delete 버튼 클릭시 실행.

 => 해당 패스워드와 일치 시 delete()메소드 실행.

                            불일치 시 detail 페이지로 이동하여 error msg 팝업 발생.

 => 데이터 삭제 성공 시 전체 페이지 보기로 이동. 실패 시 error.jsp로 이동.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public BoardDto getDetail(String num) {
		// 글 내용보기, 글 수정 시 데이터 받아오기
		return getSqlSession().selectOne("selectOne",num);
	}
	...
	@Override
	public boolean delete(String num) {
		try {
			int result = getSqlSession().delete("deleteData", num);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("delete err"+e);
			return false;
		}
	}
	...
}

 => delete() : 삭제 성공시 true, 실패시 false 리턴.

 

 

 - DataMapper.xml

 <delete id="deleteData" parameterType="string">
 	delete from board where num=#{num}
 </delete>

 => 데이터 삭제.

 


⑧ 댓글 기능 추가

 - ReplyController

@Controller
public class ReplyController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping(value="reply", method=RequestMethod.GET)
	public ModelAndView reply(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		ModelAndView view = new ModelAndView("reply");
		view.addObject("data", inter.getDetail(num)); // 원글의 데이터
		return view;
	}
	...
}

 => 상세 페이지의 댓글 버튼 클릭시 실행.

 => 원본 글의 데이터를 저장 후 reply.jsp 실행.

 

 

 - reply.jsp

<head>
	<script type="text/javascript">
	window.onload=function(){
		document.getElementById("btnReply").onclick = chk;
	}
	function chk(){
		if(reFrm.name.value === ""){
			alert("작성자 이름을 입력하세요");
			reFrm.name.focus();
		}
		// 입력자료 오류 검사
		reFrm.submit();
	}
	</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<h4 style="text-align: center;">* 댓글 쓰기</h4>
<form action="reply" method="post" name="reFrm">
<input type="hidden" name="num" value="${data.num}">
<input type="hidden" name="page" value="${page}">
<input type="hidden" name="gnum" value="${data.gnum}">
<input type="hidden" name="onum" value="${data.onum}">
<input type="hidden" name="nested" value="${data.nested}">
<input type="hidden" name="bip" value="<%=request.getRemoteAddr()%>">

<table class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name"></td>
  </tr>
  <tr>
  	<td>암호</td>
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
  	<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  	<c:set var="title" value="${data.title}"/>
  	<td><input type="text" name="title" value="[Re]:${fn:substring(title,0,8)}"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" style="width:99%" name="cont"></textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="button" value="작성" id="btnReply">
  		<input type="button" value="목록" onclick="location.href='list?page=${page}'">
  	</td>
  </tr>
</table>
</form>
</body>

 => 댓글 제목이 8보다 클 경우 substring하여 출력.

 => 작성 버튼 클릭 시 작성자이 비어 있을 경우 팝업 발생. 성공 시 reply 요청명 전달(post방식)

 

 

- ReplyController

@Controller
public class ReplyController {
	
	@Autowired
	private BoardDaoInter inter;
	...
	@RequestMapping(value="reply", method=RequestMethod.POST)
	public String replySubmit(BoardBean bean,
			@RequestParam("page") String page) {
		// onum 갱신
		bean.setOnum(bean.getOnum() + 1);
		inter.updateOnum(bean); // 반환값 처리 필요.
		
		// 댓글 저장
		bean.setBdate(); // 작성일 set
		bean.setNum(inter.currentNum() + 1); // 새로운 글의 번호
		bean.setNested(bean.getNested() + 1); // 들여쓰기
		
		if(inter.insertReply(bean)) {
			return "redirect:list?page="+page; // 추가 후 글 목록 보기			
		}else {
			return "redirect:error";
		}
		
	}
}

 => updateOnum() : 원글 내 댓글 번호를 업데이트 한다.

 => insertReply() : 작성일, num+1, 들여쓰기+1하여 댓글을 추가 한다.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean updateOnum(BoardBean bean) {
		//댓글에서 onum 갱신
		int result = getSqlSession().update("updateOnum", bean);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}

	@Override
	public boolean insertReply(BoardBean bean) {
		try {
			int result = getSqlSession().insert("insertReData", bean);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("insertReply err"+e);
			return false;
		}
	}
}

 => updateOnum() : 업데이트 성공 시 true, 실패 시 false 리턴.

 => insertReply() : 추가 성공 시 true, 실패 시 false 리턴.

 

 

 ...
 <!-- reply -->
 <update id="updateOnum" parameterType="formBean">
 	update board set onum=onum + 1
 	where onum >= #{onum} and gnum=#{gnum}
 </update>

 <insert id="insertReData" parameterType="formBean">
 	insert into board
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},#{onum},#{nested})
 </insert>
</mapper>

 => 모든 데이터 중 onum이 group num이 같고 onum이 클 경우 onum을 +1한다.

 => 댓글 정보를 추가한다.