Model 1 Board

Model 1 refers to the code that makes the Java code in the JSP into a JavaBean. The bulletin board code in the previous section contains the JDBC code in the JSP. This code is called a nightmare, at least the JDBC code should be in JavaBean. Create Article JavaBean for the posting information as follows.

Article.java
package net.java_school.board;

import java.util.Date;

public class Article {
	public static final String LINE_SEPARATOR = System.getProperty("line.separator");

	private int no;
	private String title;
	private String content;
	private Date wdate;
	private int parent;
	private int indent;

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		if (content == null) content = "";
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getHtmlContent() {
		if (content == null) {
			return "";
		} else {
			return content.replaceAll(LINE_SEPARATOR, "<br />");
		}
	}

	public Date getWdate() {
		return wdate;
	}

	public void setWdate(Date wdate) {
		this.wdate = wdate;
	}

	public int getParent() {
		return parent;
	}

	public void setParent(int parent) {
		this.parent = parent;
	}

	public int getIndent() {
		return indent;
	}

	public void setIndent(int indent) {
		this.indent = indent;
	}
}

The fields in Article.java are mapped to columns in the board table. There is no indent column in the board table. The indent field is needed to indent the title of the post in the list (list.jsp).

The getHtmlContent() is a method that changes the newline character stored in the content column to <br />. This method is used in the detail view (view.jsp).

public static final String LINE_SEPARATOR = System.getProperty("line.separator");
The LINE_SEPARATOR constant is used in the getHtmlContent() method. Here are some tips for managing constants in Java programs.

WebContants.java
package net.java_school.commons;

public class WebContants {
	//Line Separator
	public final static String LINE_SEPARATOR = System.getProperty("line.separator");
}

This modification should remove the LINE_SEPARATOR declaration from the Article and correct the Article's getHtmlContent() method as follows:

//.. Omit ..

import net.java_school.commons.WebContants;

public class Article {
	//public static final String LINE_SEPARATOR = System.getProperty("line.separator"); //Remove it
	
	//.. Omit ..

	public String getHtmlContent() {
		if (content == null) {
			return "";
		} else {
			return content.replaceAll(WebContants.LINE_SEPARATOR, "<br />");
		}
	}

	//.. Omit ..
	
}

You can change the WebContants class to an enum like this:

WebContants.java
package net.java_school.commons;

public enum WebContants {
	lineSeparator (System.getProperty("line.separator"));
	
	public String value;
	
	WebContants (String value) {
		this.value = value;
	}
}

If you change it to enum, the Article class changes as follows.

//.. Omit ..

import net.java_school.commons.WebContants;

public class Article {

	//.. Omit ..

	public String getHtmlContent() {
		if (content == null) {
			return "";
		} else {
			return content.replaceAll(WebContants.lineSeparator.value, "<br />");
		}
	}

	//.. Omit ..
	
}

Next, create a BoardDao bean that is responsible for JDBC. Dao after the name is abbreviation of Data Access Object. Beans with this name should have only JDBC code. This is called a DAO pattern. I will not use the custom connection pool I used so far. Soon we will learn how to use open source connection pool. This section does not use the connection pool itself.

BoardDao.java
package net.java_school.board;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.ArrayList;

import net.java_school.util.Log;

public class BoardDao {
	private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
	private static final String USER = "scott";
	private static final String PASSWORD = "tiger";
	
	public BoardDao() {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	private Connection getConnection() throws SQLException {
		return DriverManager.getConnection(URL, USER, PASSWORD);
	}
	
	private void close(ResultSet rs, PreparedStatement stmt, Connection con) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (con != null) {
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	public List<Article> getBoardList(int start, int end, String keyword) {
		Log log = new Log();
		List<Article> list = new ArrayList<Article>();
		String sql = null;
		
		if (keyword == null || keyword.equals("")) {
		    sql = "SELECT no, indent, parent, title, wdate FROM " +
		    "(SELECT ROWNUM R, A.* " +
		    "FROM " +
		    "(SELECT no, level as indent, parent, title, wdate FROM board " +
		    "START WITH parent = 0 " +
		    "CONNECT BY PRIOR no = parent " +
		    "ORDER SIBLINGS BY no DESC) A) " +
		    "WHERE R BETWEEN ? AND ?";
		
		} else {
			keyword = "%" + keyword + "%";
		    sql = "SELECT no, indent, parent, title, wdate FROM " +
		    "(SELECT ROWNUM R, A.* " +
		    "FROM " +
		    "(SELECT no, level as indent, parent, title, wdate FROM board " +
		    "WHERE title LIKE ? OR content LIKE ? " +
		    "START WITH parent = 0 " +
		    "CONNECT BY PRIOR no = parent " +
		    "ORDER SIBLINGS BY no DESC) A) " +
		    "WHERE R BETWEEN ? AND ?";
		}
		
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			stmt = con.prepareStatement(sql);
			if (keyword == null || keyword.equals("")) {
				stmt.setInt(1, start);
				stmt.setInt(2, end);
			} else {
				stmt.setString(1, keyword);
				stmt.setString(2, keyword);
				stmt.setInt(3, start);
				stmt.setInt(4, end);
			}
			rs = stmt.executeQuery();
			
			while (rs.next()) {
				Article article = new Article();
				article.setNo(rs.getInt("no"));
				article.setTitle(rs.getString("title"));
				article.setWdate(rs.getDate("wdate"));
				article.setIndent(rs.getInt("indent"));
				list.add(article);
			}
		} catch (SQLException e) {
			log.debug("Error Source : BoardDao.getBoardList() : SQLException");
			log.debug("SQLState : " + e.getSQLState());
			log.debug("Message : " + e.getMessage());
			log.debug("Oracle Error Code : " + e.getErrorCode());
			log.debug("sql : " + sql);
		} finally {
			close(rs, stmt, con);
			log.close();
		}
		
		return list;
	}
	
	public int getTotalRecord(String keyword) {
		Log log = new Log();
		int totalRecord = 0;
		String sql = null;
		
		if (keyword == null || keyword.equals("")) {
			sql = "SELECT count(*) FROM board";
		} else {
			sql = "SELECT count(*) FROM board " +
			"WHERE title LIKE ? OR content LIKE ?";
		}
				
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			stmt = con.prepareStatement(sql);
			if (keyword != null && !keyword.equals("")) {
				keyword = "%" + keyword + "%";
				stmt.setString(1, keyword);
				stmt.setString(2, keyword);
			}
			rs = stmt.executeQuery();
			rs.next();
			totalRecord = rs.getInt(1);
		} catch (SQLException e) {
			log.debug("Error Source : BoardDao.getTotalRecord() : SQLException");
			log.debug("SQLState : " + e.getSQLState());
			log.debug("Message : " + e.getMessage());
			log.debug("Oracle Error Code : " + e.getErrorCode());
			log.debug("sql : " + sql);
		} finally {
			close(rs, stmt, con);
			log.close();
		}
		
		return totalRecord;
	}
}

The following method produces the numbers needed to paginate the list.

public Map<String, Integer> getNumbersForPaging(int totalRecord, int curPage, int numPerPage, int pagePerBlock) {
	Map<String, Integer> map = new HashMap<String, Integer>();
	
	int totalPage = totalRecord / numPerPage;
	if (totalRecord % numPerPage != 0) totalPage++;
	int totalBlock = totalPage / pagePerBlock;
	if (totalPage % pagePerBlock != 0) totalBlock++;
	
	int block = curPage / pagePerBlock;
	if (curPage % pagePerBlock != 0) block++;
	
	int firstPage = (block - 1) * pagePerBlock + 1;
	int lastPage = block * pagePerBlock;
	
	int prevPage = 0;
	if (block > 1) {
		prevPage = firstPage - 1;
	}

	int nextPage = 0;
	if (block < totalBlock) {
		nextPage = lastPage + 1;
	}
	if (block >= totalBlock) {
		lastPage = totalPage;
	}

	int listItemNo = totalRecord - (curPage - 1) * numPerPage;
	int startRecord = (curPage - 1) * numPerPage + 1;
	int endRecord = curPage * numPerPage;

	map.put("totalPage", totalPage);
	map.put("firstPage", firstPage);
	map.put("lastPage", lastPage);
	map.put("prevPage", prevPage);
	map.put("nextPage", nextPage);
	map.put("listItemNo", listItemNo);
	map.put("startRecord", startRecord);
	map.put("endRecord", endRecord);

	return map;
}    

Apply the above method to list.jsp.

/board/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%@ page import="java.util.*" %>
<%!
public Map<String, Integer> getNumbersForPaging(int totalRecord, int curPage, int numPerPage, int pagePerBlock) {

	Map<String, Integer> map = new HashMap<String, Integer>();
	
	int totalPage = totalRecord / numPerPage;
	if (totalRecord % numPerPage != 0) totalPage++;
	int totalBlock = totalPage / pagePerBlock;
	if (totalPage % pagePerBlock != 0) totalBlock++;
	
	int block = curPage / pagePerBlock;
	if (curPage % pagePerBlock != 0) block++;
	
	int firstPage = (block - 1) * pagePerBlock + 1;
	int lastPage = block * pagePerBlock;
	
	int prevPage = 0;
	if (block > 1) {
		prevPage = firstPage - 1;
	}

	int nextPage = 0;
	if (block < totalBlock) {
		nextPage = lastPage + 1;
	}
	if (block >= totalBlock) {
		lastPage = totalPage;
	}

	int listItemNo = totalRecord - (curPage - 1) * numPerPage;
	int startRecord = (curPage - 1) * numPerPage + 1;
	int endRecord = curPage * numPerPage;

	map.put("totalPage", totalPage);
	map.put("firstPage", firstPage);
	map.put("lastPage", lastPage);
	map.put("prevPage", prevPage);
	map.put("nextPage", nextPage);
	map.put("listItemNo", listItemNo);
	map.put("startRecord", startRecord);
	map.put("endRecord", endRecord);

	return map;
}
%>
<%
request.setCharacterEncoding("UTF-8");
int curPage = request.getParameter("curPage") == null ? 1 : Integer.parseInt(request.getParameter("curPage"));
String keyword = request.getParameter("keyword");
if (keyword == null) keyword = "";
BoardDao dao = new BoardDao();
int totalRecord = dao.getTotalRecord(keyword);
Map<String, Integer> numbers = this.getNumbersForPaging(totalRecord, curPage, 10, 5);
int startRecord = numbers.get("startRecord");
int endRecord = numbers.get("endRecord");
List<Article> list = dao.getBoardList(startRecord, endRecord, keyword);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>List</title>
</head>
<body style="font-size: 11px;">
<h1>List</h1>
<%
int listItemNo = numbers.get("listItemNo");//This value is the number assigned to the list item on the list page.It is not a value stored in the no column.
for (int i = 0; i < list.size(); i++) {
	Article article = list.get(i);
	int indent = article.getIndent();
	for (int j = 0; j < indent; j++) {
		out.println("&nbsp;&nbsp;");
	}
	if(indent != 1) {
		out.println("↳");
	}
%>
<%=listItemNo %>
<a href="view.jsp?no=<%=article.getNo() %>&curPage=<%=curPage %>&keyword=<%=keyword %>"><%=article.getTitle() %></a>
<%=article.getWdate() %><br />
<hr />
<%
listItemNo--;
}
int prevPage = numbers.get("prevPage");
if (prevPage != 0) {
%>
	<a href="list.jsp?curPage=<%=prevPage %>&keyword=<%=keyword %>">[<]</a>
<%
}
int firstPage = numbers.get("firstPage");
int lastPage = numbers.get("lastPage");
for (int i = firstPage; i <= lastPage; i++) {
%>
	<a href="list.jsp?curPage=<%=i %>&keyword=<%=keyword %>">[<%=i %>]</a>
<%
}
int nextPage = numbers.get("nextPage");
if (nextPage != 0) {
%>
	<a href="list.jsp?curPage=<%=nextPage %>&keyword=<%=keyword %>">[>]</a>
<%
}
%>				
<p>
<a href="write_form.jsp?curPage=<%=curPage %>&keyword=<%=keyword %>">New</a>
</p>
<form method="get">
	<input type="text" size="10" maxlength="30" name="keyword" />
	<input type="submit" value="Search" />
</form>
</body>
</html>

Article and BoardDao are all you need to create a simple bulletin board. But, most web programs often create a bean that acts as a front-end to the JSP. These beans name will end up with Service. Create a BoardService bean as shown below.

BoardService.java
package net.java_school.board;

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

public class BoardService {

	private BoardDao dao = new BoardDao();
	
	public BoardService() {}
	
	public Map<String, Integer> getNumbersForPaging(int totalRecord, int curPage, int numPerPage, int pagePerBlock) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		
		int totalPage = totalRecord / numPerPage;
		if (totalRecord % numPerPage != 0) totalPage++;
		int totalBlock = totalPage / pagePerBlock;
		if (totalPage % pagePerBlock != 0) totalBlock++;
		
		int block = curPage / pagePerBlock;
		if (curPage % pagePerBlock != 0) block++;
		
		int firstPage = (block - 1) * pagePerBlock + 1;
		int lastPage = block * pagePerBlock;
		
		int prevPage = 0;
		if (block > 1) {
			prevPage = firstPage - 1;
		}
	
		int nextPage = 0;
		if (block < totalBlock) {
			nextPage = lastPage + 1;
		}
		if (block >= totalBlock) {
			lastPage = totalPage;
		}
	
		int listItemNo = totalRecord - (curPage - 1) * numPerPage;
		int startRecord = (curPage - 1) * numPerPage + 1;
		int endRecord = curPage * numPerPage;
	
		map.put("totalPage", totalPage);
		map.put("firstPage", firstPage);
		map.put("lastPage", lastPage);
		map.put("prevPage", prevPage);
		map.put("nextPage", nextPage);
		map.put("listItemNo", listItemNo);
		map.put("startRecord", startRecord);
		map.put("endRecord", endRecord);
	
		return map;
	}
	
	public List<Article> getBoardList(int startRecord, int endRecord, String keyword) {
        return dao.getBoardList(startRecord, endRecord, keyword);
    }
    
    public int getTotalRecord(String keyword) {
    	return dao.getTotalRecord(keyword);
    }
}

When you create a BoardService, JSPs only uses the BoardService bean. Notice that the getNumbersForPaging() method declared in list.jsp has been moved to BoardService.

Modify the list.jsp to use only BoardService bean.

/board/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%@ page import="net.java_school.commons.*" %>
<%@ page import="java.util.*" %>
<%
request.setCharacterEncoding("UTF-8");
int curPage = (request.getParameter("curPage") == null ? 1 : Integer.parseInt(request.getParameter("curPage")));
String keyword = request.getParameter("keyword");
if (keyword == null) keyword = "";
BoardService service = new BoardService();
int totalRecord = service.getTotalRecord(keyword);
Map<String, Integer> numbers = service.getNumbersForPaging(totalRecord, curPage, 10, 5);
int startRecord = numbers.get("startRecord");
int endRecord = numbers.get("endRecord");
List<Article> list = service.getBoardList(startRecord, endRecord, keyword);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>List</title>
</head>
<body style="font-size: 11px;">
<h1>List</h1>
<%
int listItemNo = numbers.get("listItemNo");
for (int i = 0; i < list.size(); i++) {
	Article article = list.get(i);
	int indent = article.getIndent();
	for (int j = 0; j < indent; j++) {
		out.println("&nbsp;&nbsp;");
	}
	if(indent != 1) {
		out.println("↳");
	}
%>
<%=listItemNo %>
<a href="view.jsp?no=<%=article.getNo() %>&curPage=<%=curPage %>&keyword=<%=keyword %>"><%=article.getTitle() %></a>
<%=article.getWdate() %><br />
<hr />
<%
listItemNo--;
}
int prevPage = numbers.get("prevPage");
if (prevPage != 0) {
%>
	<a href="list.jsp?curPage=<%=prevPage %>&keyword=<%=keyword %>">[<]</a>
<%
}
int firstPage = numbers.get("firstPage");
int lastPage = numbers.get("lastPage");
for (int i = firstPage; i <= lastPage; i++) {
%>
	<a href="list.jsp?curPage=<%=i %>&keyword=<%=keyword %>">[<%=i %>]</a>
<%
}
int nextPage = numbers.get("nextPage");
if (nextPage != 0) {
%>
	<a href="list.jsp?curPage=<%=nextPage %>&keyword=<%=keyword %>">[>]</a>
<%
}
%>				
<p>
<a href="write_form.jsp?curPage=<%=curPage %>&keyword=<%=keyword %>">New</a>
</p>
<form method="get">
	<input type="text" size="10" maxlength="30" name="keyword" />
	<input type="submit" value="Search" />
</form>	
</body>
</html>

Modify the action attribute value of the form tag in /board/write_form.jsp file to write.jsp.

/board/write_form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("UTF-8");
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>New</title>
</head>
<body>
<h1>New</h1>
<form action="write.jsp" method="post">
<table>
<tr>
	<td>Title</td>
	<td><input type="text" name="title" size="50"></td>
</tr>
<tr>
	<td colspan="2">
		<textarea name="content" rows="20" cols="100"></textarea>
	</td>
</tr>
<tr>
	<td colspan="2">
		<input type="submit" value="Submit">
		<input type="reset" value="Reset">
		<a href="list.jsp?curPage=<%=curPage %>&keyword=<%=keyword %>">List</a>
	</td>
</tr>
</table>
</form>
</body>
</html>

Add the following method to BoardDao.

BoardDao.java
public void insert(Article article) {
	Log log = new Log();
	String sql = "INSERT INTO board (no, title, content, wdate, parent) "
		+ "VALUES (board_no_seq.nextval, ?, ?, sysdate, 0)";
		
	Connection con = null;
	PreparedStatement stmt = null;
	
	try {
		con = getConnection();
		stmt = con.prepareStatement(sql);
		stmt.setString(1, article.getTitle());
		stmt.setString(2, article.getContent());
		stmt.executeUpdate();
	} catch (SQLException e) {
		log.debug("Error Source : BoardDao.insert() : SQLException");
		log.debug("SQLState : " + e.getSQLState());
		log.debug("Message : " + e.getMessage());
		log.debug("Oracle Error Code : " + e.getErrorCode());
		log.debug("sql : " + sql);
	} finally {
		close(null, stmt, con);
		log.close();
	}
}

Add the following method to BoardService.

BoardService.java
public void write(Article article) {
	dao.insert(article);
}

Create write.jsp as shown below.

/board/write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");
String title = request.getParameter("title");
String content = request.getParameter("content");

Article article = new Article();
article.setTitle(title);
article.setContent(content);

BoardService service= new BoardService();
service.write(article);

response.sendRedirect("list.jsp");
%>

Next, let's implement the details view. Add the selectOne() method to BoardDao.

BoardDao.java
public Article selectOne(int no) {
	Log log = new Log();
	
	Article article = null;
	String sql = "SELECT no, title, content, wdate FROM board WHERE no = ?";
	
	Connection con = null;
	PreparedStatement stmt = null;
	ResultSet rs = null;
	
	try {
		con = getConnection();
		stmt = con.prepareStatement(sql);
		stmt.setInt(1, no);
		rs = stmt.executeQuery();
		while (rs.next()) {
			article = new Article();
			article.setNo(rs.getInt("no"));
			article.setTitle(rs.getString("title"));
			article.setContent(rs.getString("content"));
			article.setWdate(rs.getDate("wdate"));
		}
	} catch (SQLException e) {
		log.debug("Error Source : BoardDao.selectOne() : SQLException");
		log.debug("SQLState : " + e.getSQLState());
		log.debug("Message : " + e.getMessage());
		log.debug("Oracle Error Code : " + e.getErrorCode());
		log.debug("sql : " + sql);
	} finally {
		close(rs, stmt, con);
		log.close();
	}

	return article;
}

Add the following method to BoardService.

BoardService.java
public Article getArticle(int no) {
	return dao.selectOne(no);
}

Modify view.jsp as shown below.

/board/view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");
int no = Integer.parseInt(request.getParameter("no"));
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");
if (keyword == null) keyword = "";
BoardService service = new BoardService();
Article article = service.getArticle(no);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>View</title>
<script type="text/javascript">
function goModify(no,curPage,keyword) {
	location.href="modify_form.jsp?no=" + no + "&curPage=" + curPage + "&keyword=" + keyword;
}

function goDelete(no,curPage,keyword) {
	var check = confirm("Are you sure you want to delete it?");
	if (check) {
		location.href="del.jsp?no=" + no + "&curPage=" + curPage + "&keyword=" + keyword;
	}
}
</script>
</head>
<body>
<h1>View</h1>
<h2>Title: <%=article.getTitle() %>, Date created: <%=article.getWdate() %></h2>
<p>
<%=article.getHtmlContent() %>
</p>
<a href="list.jsp?curPage=<%=curPage %>&keyword=<%=keyword %>">List</a>
<input type="button" value="Modify" onclick="javascript:goModify('<%=no %>','<%=curPage %>','<%=keyword %>')">
<input type="button" value="Delete" onclick="javascript:goDelete('<%=no %>','<%=curPage %>','<%=keyword %>')">
<a href="reply_form.jsp?no=<%=no %>&curPage=<%=curPage %>&keyword=<%=keyword %>">Reply</a>
</body>
</html>

Next, let's implement the post modification. Add the following update() method to BoardDao.

BoardDao.java
public void update(Article article) {
	Log log = new Log();
	String sql = "UPDATE board SET title = ?, content = ? WHERE no = ?";		
	Connection con = null;
	PreparedStatement stmt = null;
	try {
		con = getConnection();
		stmt = con.prepareStatement(sql);
		stmt.setString(1, article.getTitle());
		stmt.setString(2, article.getContent());
		stmt.setInt(3, article.getNo());
		stmt.executeUpdate();
	} catch (SQLException e) {
		log.debug("Error Source : BoardDao.update() : SQLException");
		log.debug("SQLState : " + e.getSQLState());
		log.debug("Message : " + e.getMessage());
		log.debug("Oracle Error Code : " + e.getErrorCode());
		log.debug("sql : " + sql);
	} finally {
		close(null, stmt, con);
		log.close();
	}
}
BoardService.java
public void modify(Article article) {
	dao.update(article);
}

Modify modify_form.jsp to use only BoardService.

/board/modify_form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.sql.*" %>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");

int no = Integer.parseInt(request.getParameter("no"));
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");

BoardService service = new BoardService();
Article article = service.getArticle(no);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Edit posts</title>
</head>
<body>
<h1>Edit posts</h1>
<form action="modify.jsp" method="post">
<input type="hidden" name="no" value="<%=no %>">
<input type="hidden" name="curPage" value="<%=curPage %>">
<input type="hidden" name="keyword" value="<%=keyword %>">
<table>
<tr>
	<td>Title</td>
	<td><input type="text" name="title" size="50" value="<%=article.getTitle() %>" /></td>
</tr>
<tr>
	<td colspan="2">
		<textarea name="content" rows="30" cols="100"><%=article.getContent() %></textarea>
	</td>
</tr>
<tr>
	<td colspan="2">
		<input type="submit" value="Submit">
		<input type="reset" value="Reset">
		<a href="view.jsp?no=<%=no %>&curPage=<%=curPage %>&keyword=<%=keyword %>">View</a>
	</td>
</tr>
</table>
</form>
</body>
</html>

Create modify.jsp as shown below.

/board/modify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");
int no = Integer.parseInt(request.getParameter("no"));
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");
String title = request.getParameter("title");
String content = request.getParameter("content");

Article article = new Article();
article.setNo(no);
article.setTitle(title);
article.setContent(content);

BoardService service= new BoardService();
service.modify(article);
keyword = java.net.URLEncoder.encode(keyword,"UTF-8");
response.sendRedirect("view.jsp?no=" + no + "&curPage=" + curPage + "&keyword=" +  keyword);
%>

Next, let's implement delete the post. Add a delete() method to BoardDao.

BoardDao.java
public void delete(int no) {
	Log log = new Log();
	
	String sql1 = "SELECT count(*) FROM board WHERE parent = ?";
	String sql2 = "DELETE FROM board WHERE no = ?";
	
	Connection con = null;
	PreparedStatement stmt1 = null;
	PreparedStatement stmt2 = null;
	ResultSet rs = null;
	
	boolean check = false; //If true, delete post
	
	try {
		con = getConnection();
		stmt1 = con.prepareStatement(sql1);
		stmt1.setInt(1, no);
		rs = stmt1.executeQuery();
		rs.next();
		int num = rs.getInt(1);
		if (num == 0) {
			check = true;
		}
		if (check == true) {
			stmt2 = con.prepareStatement(sql2);
			stmt2.setInt(1, no);
			stmt2.executeUpdate();
		}
	} catch (SQLException e) {
		log.debug("Error Source : BoardDao.delete() : SQLException");
		log.debug("SQLState : " + e.getSQLState());
		log.debug("Message : " + e.getMessage());
		log.debug("Oracle Error Code : " + e.getErrorCode());
		log.debug("sql : " + sql1);
	} finally {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {}
		}
		if (stmt1 != null) {
			try {
				stmt1.close();
			} catch (SQLException e) {}
		}
		if (stmt2 != null) {
			try {
				stmt2.close();
			} catch (SQLException e) {}
		}
		if (con != null) {
			try {
				con.close();
			} catch (SQLException e) {}
		}
		log.close();
	}
}

Add the following delete() method to BoardService.

BoardService.java
public void delete(int no) {
	dao.delete(no);
}

Create del.jsp as follows.

/board/del.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");
int no = Integer.parseInt(request.getParameter("no"));
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");

BoardService service= new BoardService();
service.delete(no);
keyword = java.net.URLEncoder.encode(keyword,"UTF-8");
response.sendRedirect("list.jsp?curPage=" + curPage + "&keyword=" +  keyword);
%>

Next, let's implement reply. Add the following reply() method to BoardDao.

BoardDao.java
public void reply(Article article) {
	Log log = new Log();
	
	String sql = "INSERT INTO board " + 
			"(no, parent, title, content, wdate) " + 
			"VALUES (board_no_seq.nextval, ?, ?, ?, sysdate)";
			
	Connection con = null;
	PreparedStatement stmt = null;
	
	try {
		con = getConnection();
		stmt = con.prepareStatement(sql);
		stmt.setInt(1, article.getParent());
		stmt.setString(2, article.getTitle());
		stmt.setString(3, article.getContent());
		stmt.executeUpdate();
	} catch (SQLException e) {
		log.debug("Error Source:BoardDao.reply() : SQLException");
		log.debug("SQLState : " + e.getSQLState());
		log.debug("Message : " + e.getMessage());
		log.debug("Oracle Error Code : " + e.getErrorCode());
		log.debug("sql : " + sql);
	} finally {
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (con != null) {
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		log.close();
	}
}

Add the following reply() method to BoardService.

BoardService.java
public void reply(Article article) {
	dao.reply(article);
}
/board/reply_form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%@ page import="net.java_school.commons.*" %>
<%
request.setCharacterEncoding("UTF-8");

int no = Integer.parseInt(request.getParameter("no"));
String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");

BoardService service = new BoardService();
Article article = service.getArticle(no);
String content = article.getContent();

//Add > for each line of the parent content.
content = content.replaceAll(WebContants.lineSeparator.value, WebContants.lineSeparator.value + ">");
content = WebContants.lineSeparator.value + WebContants.lineSeparator.value + ">" + content;
%>
<html>
<head>
<meta charset="UTF-8" />
<title>Reply</title>
</head>
<body>

<h1>Reply</h1>

<form action="reply.jsp" method="post">
<input type="hidden" name="no" value="<%=no %>" />
<input type="hidden" name="curPage" value="<%=curPage %>" />
<input type="hidden" name="keyword" value="<%=keyword %>" />
제목 : <input type="text" name="title" size="45" value="<%=article.getTitle() %>" /><br />
<textarea name="content" rows="10" cols="60"><%=content %></textarea><br />
<input type="submit" value="Submit" />
<input type="reset" value="Reset" /><br />
</form>
<a href="view.jsp?no=<%=no %>&curPage=<%=curPage %>&keyword=<%=keyword %>">View</a>
</body>
</html>

Create reply.jsp as shown below.

/board/reply.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="net.java_school.board.*" %>
<%
request.setCharacterEncoding("UTF-8");

int parent = Integer.parseInt(request.getParameter("no"));
String title = request.getParameter("title");
String content = request.getParameter("content");

String curPage = request.getParameter("curPage");
String keyword = request.getParameter("keyword");

Article article = new Article();
article.setParent(parent);
article.setTitle(title);
article.setContent(content);

BoardService service= new BoardService();
service.reply(article);

keyword = java.net.URLEncoder.encode(keyword,"UTF-8");
response.sendRedirect("list.jsp?curPage=" + curPage + "&keyword=" + keyword);
%>