명함관리 웹 애플리케이션
본격적으로 서블릿/JSP를 공부하기 전에 JDBC에서 예제로 다루었던 명함관리를 웹 애플리케이션으로 바꾸는 실습을 한다.
이 실습믜 목표는 순수 자바 애플리케이션과 웹 애플리케이션의 차이에 대한 이해와 웹 환경 체험이다.
자세한 설명은 곧 다루니 이 절에선 목표에 충실하자.
명함관리를 웹 애플리케이션으로 바꾸기 위한 준비작업
1. 오라클 JDBC 드라이버를 CATALINA_HOME/lib 에 복사한다.
JDBC 드라이버는 특별한 이유1 때문에 웹 애플리케이션의 WEB-INF/lib 가 아닌 CATALINA_HOME/lib 에 있어야 한다.
다시 말해, WEB-INF/lib 에는 JDBC 드라이버가 없어야 한다.
오라클 JDBC 드라이버인 ojdbc6.jar 파일을 CATALINA_HOME/lib 에 복사한다.
2. 웹 애플리케이션을 위한 디렉토리 구조를 마련한다.
C:/www/namecard 를 명함관리 웹 애플리케이션의 최상위 디렉토리로 정했다면
C:/www/namecard 아래 다음과 같은 서브 디렉토리를 만들어야 한다.
- WEB-INF
- WEB-INF/classes
- WEB-INF/lib
3. web.xml 파일을 WEB-INF 디렉토리에 만든다.
CATALINA_HOME/webapps/ROOT/WEB-INF/web.xml 을 복사하여 C:/www/namecard/WEB-INF/에 붙여넣는다.
복사한 후 C:/www/namecard/WEB-INF/web.xml 파일을 편집기로 열고
web-app 엘리먼트 안에 있는 모든 내용을 지운다.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> </web-app>
4. namecard.xml 컨텍스트 파일 만든다.
아래 내용대로 namecard.xml 파일을 만든 다음 CATALINA_HOME/conf/Catalina/localhost 로 옮긴다.
<?xml version="1.0" encoding="UTF-8"?> <Context docBase="C:/www/namecard" reloadable="true"> </Context>
명함관리 웹 애플리케이션 테스트
첫 번째 테스트
명함관리에서 실습했던 명함관리 Namecard 와 NamecardDao 바이트코드를 WEB-INF/classes 에 복사한다.
C:/www/namecard/WEB-INF/classes
└── net
└── java_school
└── namecard - Namecard.class
- NamecardDao.class
아래 JSP 파일을 도큐먼트 베이스인 C:/www/namecard에 생성한다.
이클립스가 아닌 일반 에디터로 작업한다.
/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="net.java_school.namecard.*" %> <%@ page import="java.util.*" %> <!DOCTYPE html> <% NamecardDao dao = new NamecardDao(); ArrayList<Namecard> list = dao.selectAll(); %> <html> <head> <meta charset="UTF-8"> <title>명함목록</title> </head> <body> <table border="1"> <tr> <td>번호</td> <td>이름</td> <td>손전화</td> <td>이메일</td> <td>회사</td> </tr> <% int size = list.size(); for(int i = 0;i < size;i++) { Namecard card = list.get(i); %> <tr> <td><%=card.getNo() %></td> <td><%=card.getName() %></td> <td><%=card.getMobile() %></td> <td><%=card.getEmail() %></td> <td><%=card.getCompany() %></td> </tr> <% } %> </table> <p> <input type="button" value="추가" onclick="location.href='write.jsp'" /> </p> </body> </html>
톰캣을 재실행한다.
http://localhost:8080/namecard/list.jsp를 방문하여 테스트한다.
두번째 테스트
첫 번째 테스트처럼 자바 클래스 소스를 웹 애플리케이션이 위치한 곳과 전혀 상관없는 곳에 두어도 된다.
현재 소스는 'JDBC'에서 실습한 디렉토리(이를테면 C:/java/namecard/src)에 있다.
하지만 이 경우, 시간이 지나면 소스의 위치를 잊을 수 있으며 소스를 지우는 실수를 할 수 있다.
두번째 테스트는 소스를 웹 애플리케이션의 영역안에 옮기고 그 소스를 컴파일하는 테스트이다.
먼저 자바 소스를 어디에 두어야 할지를 정해야 하는데,
WEB-INF 아래에 두면 웹브라우저로 직접 접근할 수 없으니 소스 디렉토리를 WEB-INF/src로 정하겠다.
이제 JDBC에서 실습했던 명함관리 src 디렉토리를 복사하여 WEB-INF 에 붙여 넣는다.
다음으로 명령프롬프트에서 C:\www\namecad\WEB-INF\src\net\java_school\namecard
로 이동하여 다음과 같이 컴파일을 수행한다.2
javac -d C:/www/namecard/WEB-INF/classes *.java
http://localhost:8080/namecard/list.jsp를 방문하여 테스트한다.
세번째 테스트
이클립스를 이용해서 작업하는 방법을 설명한다.
이클립스를 실행한다.
워크스페이스를 C:/www로 선택한다.
퍼스펙티브가 java3 인 상태에서 File - New - Java Project 메뉴를 차례로 선택하여 새로운 자바 프로젝트를 namecard란 이름으로 만든다.
우리는 순수 자바 애플리케이션 아닌 웹 애플리케이션을 작성하고 있으므로 이클립스가 디폴트로 셋팅해준 src와 bin를 그대로 사용해서는 안 된다.
프로젝트에 마우스를 선택한 상태에서 마우스 오른쪽 버튼을 클릭한다.
Build Path - Configure Build Path..를 선택한다.
Source탭에서 Source folder 는 WEB-INF/src 를 선택한다.
Default output folder 는 WEB-INF/classes 를 선택해야 한다.
이제 이클립스에서 소스를 수정하면 따로 컴파일하지 않아도 바이트 코드가 WEB-INF/classes에 생긴다.
http://localhost:8080/namecard/list.jsp를 방문하여 테스트한다.
테스트가 성공했다면 명함을 등록하는 JSP파일을 C:/www/namecard 에 만든다.
먼저 이클립스의 JSP 템플릿의 캐릭터셋을 EUC-KR 에서 UTF-8로 변경한다.
이클립스에서 Windows - Preferences - Web - JSP Files 선택하고 인코딩 박스에서 UTF-8를 선택하고 Apply 클릭한다.
아래 write.jsp 소스에서 강조된 부분이 여러분이 직접 입력해야 하는 부분이다.
/write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>명함 추가</title> </head> <body> <h1>명함 추가하기</h1> <form action="write_proc.jsp" method="post"> 이름 : <input type="text" name="name" /><br /> 손전화 : <input type="text" name="mobile" /><br /> 이메일 : <input type="text" name="email" /><br /> 회사 : <input type="text" name="company" /><br /> <input type="submit" value="전송" /> <input type="button" value="취소" onclick="location.href='list.jsp'" /> </form> </body> </html>
다음은 write_proc.jsp 파일을 만든다.
이 페이지는 write.jsp 에서 전송받은 값으로 명함을 추가한다.
아래 소스에서 강조된 부분이 여러분이 직접 입력해야 하는 부분이다.
/write_proc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="net.java_school.namecard.*" %> <!DOCTYPE html> <% request.setCharacterEncoding("UTF-8"); String name = request.getParameter("name"); String mobile = request.getParameter("mobile"); String email = request.getParameter("email"); String company = request.getParameter("company"); Namecard namecard = new Namecard(name,mobile,email,company); NamecardDao dao = new NamecardDao(); dao.insert(namecard); %> <html> <head> <meta charset="UTF-8"> <title>명함 추가</title> </head> <body> 명함이 추가되었습니다.<a href="list.jsp">목록</a> </body> </html>
http://localhost:8080/namecard/list.jsp를 방문한다.
명함목록에서 등록버튼을 클릭하여 새로운 명함 등록을 추가하는 테스트를 한다.
다음은 삭제기능을 구현한다.
먼저 list.jsp 에서 아래를 참조해서 테이블의 열를 추가한다.
/list.jsp
<!-- .. 중간 생략 .. --> <td>번호</td> <td>이름</td> <td>손전화</td> <td>이메일</td> <td>회사</td> <td>관리</td> <!-- .. 중간 생략 .. --> <td><%=card.getNo() %></td> <td><%=card.getName() %></td> <td><%=card.getMobile() %></td> <td><%=card.getEmail() %></td> <td><%=card.getCompany() %></td> <td><a href="delete.jsp?no=<%=card.getNo() %>">삭제</a></td> <!-- .. 중간 생략 .. -->
다음은 delete.jsp 작성한다.
delete.jsp 는 list.jsp에서 명함의 Primary key 에 해당하는 값을 전달받아 삭제를 수행한다.
아래 소스에서 강조된 부분이 직접 입력해야 하는 부분이다.
/delete.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="net.java_school.namecard.*" %> <!DOCTYPE html> <% int no = Integer.parseInt(request.getParameter("no")); NamecardDao dao = new NamecardDao(); dao.delete(no); %> <html> <head> <meta charset="UTF-8"> <title>명함 삭제</title> </head> <body> 명함이 삭제되었습니다.<a href="list.jsp">목록</a> </body> </html>
http://localhost:8080/namecard/list.jsp를 방문한다.
명함을 삭제하는 테스트를 수행한다.
다음으로 수정기능 구현한다.
NamecardDao.java 에 수정을 담당하는 메소드는 아래와 같다.
NamecardDao.java
public void update(Namecard card) { String sql = "UPDATE namecard " + "SET name = ? " + ",mobile = ? " + ",email = ? " + ",company = ? " + "WHERE no = ?"; Connection con = null; PreparedStatement pstmt = null; try { con = getConnection(); pstmt = con.prepareStatement(sql); pstmt.setString(1, card.getName()); pstmt.setString(2, card.getMobile()); pstmt.setString(3, card.getEmail()); pstmt.setString(4, card.getCompany()); pstmt.setInt(5, card.getNo()); pstmt.executeUpdate(); //.. 중간 생략 ..
list.jsp 파일에서 수정양식을 보여주는 페이지로 이동하는 링크를 삭제링크 옆에 작성한다.
아래를 참고한다.
/list.jsp
<td> <a href="delete.jsp?no=<%=card.getNo() %>">삭제</a> <a href="modify.jsp?no=<%=card.getNo() %>">수정</a> </td>
다음은 modify.jsp 파일을 작성한다.
참고로 modify.jsp 는 사용자 UI 통일성을 주기 위해서 wirte.jsp 소스를 copy & paste 한후
약간의 추가 작업을 하여 만들었다.
/modify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="net.java_school.namecard.*" %>
<!DOCTYPE html>
<%
int no = Integer.parseInt(request.getParameter("no"));
NamecardDao dao = new NamecardDao();
Namecard card = dao.selectOne(no);
%>
<html>
<head>
<meta charset="UTF-8">
<title>명함 수정</title>
</head>
<body>
<h1>명함 수정하기</h1>
<form action="modify_proc.jsp" method="post">
<input type="hidden" name="no" value="<%=no %>" />
이름 : <input type="text" name="name" value="<%=card.getName() %>" /><br />
손전화 : <input type="text" name="mobile" value="<%=card.getMobile() %>" /><br />
이메일 : <input type="text" name="email" value="<%=card.getEmail() %>" /><br />
이메일 : <input type="text" name="company" value="<%=card.getCompany() %>" /><br />
<input type="submit" value="전송" />
<input type="button" value="취소" onclick="location.href='list.jsp'" />
</form>
</body>
</html>
<input type="hidden" name="no" value="<%=no %>" />
이 부분이 폼태그에 반드시 있어야 한다.
다음은 modify_proc.jsp 파일을 작성한다.
이 페이지는 modify.jsp에서 전송된 값으로 명함을 수정하는 페이지이다.
modify_proc.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="net.java_school.namecard.*" %> <!DOCTYPE html> <% request.setCharacterEncoding("UTF-8"); int no = Integer.parseInt(request.getParameter("no")); String name = request.getParameter("name"); String mobile = request.getParameter("mobile"); String email = request.getParameter("email"); String company = request.getParameter("company"); Namecard card = new Namecard(); card.setNo(no); card.setName(name); card.setMobile(mobile); card.setEmail(email); card.setCompany(company); NamecardDao dao = new NamecardDao(); dao.update(card); %> <html> <head> <meta charset="UTF-8"> <title>명함 수정</title> </head> <body> 명함이 수정되었습니다. <a href="list.jsp">목록</a> </body> </html>
http://localhost:8080/namecard/list.jsp를 방문하여 수정을 테스트한다.
다음으로 list.jsp 에 검색기능을 추가한다.
list.jsp 열고 </body> 전에 다음 폼을 추가한다.
/list.jsp
<form action="list.jsp" method="post"> <input type="text" name="keyword" /> <input type="submit" value="검색" /> </form>
검색을 위해서 NamecardDao.java 에 selectByKeyword(String keyword) 메소드를 추가한다.
NamecardDao.java
public ArrayList<Namecard> selectByKeyword(String keyword) { keyword = "%" + keyword + "%"; ArrayList<Namecard> matched = new ArrayList<Namecard>(); String sql ="SELECT no,name,mobile,email,company " + "FROM namecard " + "WHERE name LIKE ? " + "OR mobile LIKE ? " + "OR email LIKE ? " + "OR company LIKE ? " + "ORDER BY no DESC"; Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; try { con = getConnection(); pstmt = con.prepareStatement(sql); pstmt.setString(1, keyword); pstmt.setString(2, keyword); pstmt.setString(3, keyword); pstmt.setString(4, keyword); rs = pstmt.executeQuery(); while(rs.next()) { int no = rs.getInt("no"); String sname = rs.getString("name"); String mobile = rs.getString("mobile"); String email = rs.getString("email"); String company = rs.getString("company"); Namecard namecard = new Namecard(no,name,mobile,email,company); matched.add(namecard); } } catch (SQLException e) { e.printStackTrace(); System.out.println(sql); } finally { close(rs,pstmt,con); } return matched; }
검색을 테스트하기 위해 list.jsp 을 방문하면 null로 검색이 되는 버그가 있다.
list.jsp 를 웹브라우저의 주소창에서 처음 방문할 때는 keyword 가 null 이 되기 때문이다.
그리고 list.jsp 파일에서 검색필드에 아무런 값도 넣지 않고 검색 버튼을 클릭했다면 keyword 는 ""(공백문자)이다.
list.jsp 을 열고 아래 코드를 참고하여 수정한다.
/list.jsp
<% //기존 코드는 주석처리한다. //NamecardDao dao = new NamecardDao(); //ArrayList<Namecard> list = dao.selectAll(); request.setCharacterEncoding("UTF-8"); String keyword = request.getParameter("keyword"); NamecardDao dao = new NamecardDao(); ArrayList<Namecard> list = null; if (keyword == null) { keyword = ""; } if (keyword.equals("")) { list = dao.selectAll(); } else { list = dao.selectByKeyword(keyword); } %>
모두 작성했다면
http://localhost:8080/namecard/list.jsp를 방문하여 테스트한다.
- 각각의 웹 애플리케이션의 WEB-INF/lib 에 JDBC 드라이버 파일을 두면 메모리 누수문제가 일어날 수 있다.
- 만약 NamecardDao 클래스가 커넥션 풀을 이용한다면 커넥션풀관련 클래스를 앞서 컴파일 해야한다.
- 이와는 달리 대부분이 책에서 퍼스펙티브가 Java EE 에서 Dynamic Web Project 로 프로젝트를 생성하는 방법을 설명한다. 본 사이트에서 제공하는 기초 과정을 모두 공부한 다음이 아니고, 이클립스보다 서블릿/JSP에 초점을 맞추려면 본 사이트에서 제시한 방법이 더 낫다.