Servlet
- 웹 클라이언트의 요청을 처리하는 클래스
- HttpServlet을 상속하여 만들어짐
- jsp파일 → Servlet으로 동작
- 클라이언트의 요청을 Servlet으로 직접 받을 수 있다.
- MVC에서 Controller 역할을 Servlet이 한다.
웹 프로젝트 생성 및 실행
웹 프로젝트 생성
MyWeb이라는 Dynamic Web Project를 생성했다.
프로젝트가 생성되면 다음과 같은 폴더 구조가 만들어진다. 이 중에서 src/main/java라는 소스 폴더와 src/main/webapp이라는 일반 폴더를 눈여겨보자.
- src/main/java: 소스 폴더 → 서블릿을 비롯한 일반적인 자바 클래스 파일 작성
- src/main/webapp: 일반 폴더 → HTML, 이미지, CSS, 자바스크립트, JSP파일 작성
웹 콘텐츠 작성 및 테스트
웹 애플리케이션의 두 가지 형태의 파일
- 정적인 파일 (HTML, 이미지 등)
- 동적인 파일 (JSP 등)
대표적인 정적 콘텐츠인 HTML 파일을 작성하고 실행해보자. src/main/webapp 폴더에 index.html 파일을 작성한다.
[index.html]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Hello MyWeb</h1>
<h2>안녕 MyWeb</h2>
<hr color="red">
<ul>
<li><a href="hi">Get방식 요청-HelloServlet</a></li>
<li><a href="form.html">POST방식 요청 - form을 통해 요청보내기</a></li>
<li><a href="member/join.html">회원가입 페이지 이동</a></li>
<li><a href="member/mypage.html">회원정보 관리 페이지 이동</a></li>
<li><a href="MemberList">회원목록 페이지 이동</a></li>
</ul>
</body>
</html>
1. Get방식 요청-HelloServlet
<li><a href="hi">Get방식 요청-HelloServlet</a></li>
src/main/java 소스 폴더에 my라는 하위 폴더를 만들고, 그 안에 또 com이라는 하위 폴더를 만든 뒤, HelloServlet.java 파일을 만들자.
서블릿 작성
- Servlet이 되기 위해서는 HttpServlet을 상속받는 클래스를 작성해야 한다. (extends HttpServlet)
- 메서드 오버라이드
doGet(), doPost(), doDelete(), doPut(), ... - 작성한 서블릿을 등록한다. <두 가지 방법>
- "컨텍스트/WEB-INF/web.xml"에 등록
- 어노테이션을 이용해 등록: 매번 web.xml 파일에 서블릿을 등록하는 것이 귀찮으면 @WebServlet을 사용해서 간단하게 매핑해도 된다.
[HelloServlet.java]
XML 설정
web.xml은 <web-app>을 루트 엘리먼트로 가지고 있으며, <web-app>에는 디폴트 네임페이스로http://xmlns.jcp.org/xml/ns/javaee가 선언되어 있다.
[web.xml]
- <display-name>은 생략이 가능하며 웹 애플리케이션의 이름을 지정한다.
- <welcome-file-list>에 <welcome-file>로 등록된 파일은 웹 애플리케이션의 웰컴 파일이 된다. 웰컴 파일은 사용자가 시스템에 접근할 때 시스템이 가장 먼저 제공하는 파일로서 요청 url에 굳이 명시하지 않아도 서버가 자동으로 인식한다.
- <servlet>은 작성된 서블릿 클래스를 등록할 때 사용하며, <servlet-name>과 <servlet-class>를 자식 엘리먼트로 사용한다.
- <servlet-name>은 생성된 서블릿 객체에 별칭을 부여하는 것으로, 서블릿 컨테이너는 <servlet-name>으로 설정된 서블릿의 이름을 기준으로 생성된 서블릿 객체들을 식별한다. 따라서 <servlet-name>은 중복을 허용하지 않는다.
- <servlet-class>에는 서블릿의 전체 경로를 등록한다.
- <servlet-mapping>은 브라우저의 요청 url과 서블릿을 매핑하는 설정이다.
- <servlet-name>을 이용하여 등록된 서블릿 중 하나를 고른다.
- <url-pattern>을 이용하여 url 형식을 지정하면 된다.
web.xml 파일을 수정하고 서버를 재구동한다. 그리고 브라우저에서 index.html화면을 새로고침한 후, Get방식 요청-HelloServlet을 클릭하면 정상적으로 HelloServlet 객체가 실행되는 것을 확인할 수 있다.
2. POST방식 요청 - form을 통해 요청보내기
<li><a href="form.html">POST방식 요청 - form을 통해 요청보내기</a></li>
src/main/webapp 소스 폴더에 form.html 파일을 만들자.
[form.html]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>form.html</title>
</head>
<body>
<div>
<h1>POST방식</h1>
<form method="post" action="PostServlet">
아이디: <input type="text" name="id"><br><br>
비밀번호: <input type="password" name="pw"><br><br>
<button>Login</button>
<button type="reset">Reset</button>
</form>
</div>
</body>
</html>
서블릿 작성
[PostServlet.java]
- 이번에는 web.xml에 서블릿을 등록하는 방법 대신에 어노테이션(@WebServlet)을 사용해보자.
- @WebServlet("/url-pattern"): [주의] url-pattern은 유니크한 값을 설정해야 한다.
PostServlet 클래스에 @WebServlet을 추가하여 "/PostServlet" 요청에 대해서 PostServlet 객체를 실행하도록 매핑했다. 서버를 재구동하고 아이디, 비밀번호를 입력해서 Login 버튼을 누르면 환영 메시지가 뜬다.
아이디: kim, 비밀번호: 123 입력
3. 회원가입 페이지 이동
<li><a href="member/join.html">회원가입 페이지 이동</a></li>
src/main/webapp 소스 폴더 하위에 member 폴더를 만들고, 거기에 join.html 파일을 만들자.
[join.html]
- <form>태그의 속성
- name: form의 이름. 서버로 제출된 폼 데이터(form data)를 참조하기 위해 사용됨
- method: 서버 페이지를 기술. form을 전송할 서버 쪽의 script 파일을 지정
전송되는 서버 url 또는 html 링크 - action: 전송 방식을 기술 (get[default], post, delete, put, options)
- GET방식: 서버에 전달한 uri 뒤에 물음표(?)를 추가하고 키(key)=값(value) 형태로 사용자가 입력한 정보를 전달하는데, 외부에 노출되기 때문에 로그인 같은 기능에서 절대 사용해서는 안된다. 사용자가 입력한 정보가 외부에 노출돼도 상관없는 경우는 GET 방식을 사용할 수 있다.
- POST방식: GET과 달리 쿼리 문자열이 uri가 아닌 message-body에 포함되어 전달되기 때문에 브라우저 uri에 사용자가 입력한 정보가 노출되지 않는다. 아이디, 비밀번호, 계좌번호 같은 중요한 데이터는 반드시 POST 방식으로 처리해야 한다.
- action = "../Signup"
- 상대경로: 지금 작업중인 파일인 join.html 파일에서 한 번 상위(밖으로) 나와 java 폴더 내의 SignupServlet으로 form을 전송
- SignupServlet.java에 @WebServlet("/Signup")으로 전송됨
URL: http://localhost:9090/MyWeb/member/join.html
HTTP 요청 URL
- http: => 프로토콜: 서버에 파일을 요청할 때 사용한 프로토콜
- // => 프로토콜 구분자: 프로토콜과 호스트 이름을 구분하는 구분자
- localhost => 호스트(도메인): 웹 서버가 설치된 컴퓨터(호스트) → localhost는 현재 사용 중인 컴퓨터를 의미
- 9090 => 호스트 컴퓨터에서 9090 포트를 사용하는 서버
- MyWeb => 웹 애플리케이션: MyWeb 웹 애플리케이션
- member => 디렉터리: MyWeb 애플리케이션의 member 디렉터리
- join.html => 파일: member 디렉터리에 있는 join.html 파일
서블릿 작성
src/main/java 소스 폴더에 member라는 하위 폴더를 만들고, SignupServlet.java 파일을 만들자.
1. 어노테이션
[join.html]
<form name="mf" method="post" action="../Signup">
[SignupServlet.java]
@WebServlet("/Signup")
SignupServlet 클래스에 @WebServlet을 추가하여 "/Signup" 요청에 대해서 SignupServlet 객체를 실행하도록 매핑
2. PrintWriter out = res.getWriter();
- Servlet에서 클라이언트의 요청(Request)에 대한 응답(Response) 형태는 문자(character) 또는 바이트(byte)가 될 수 있다.
- 클라이언트의 요청에 문자 형태로 응답하려면 데이터의 흐름(Stream)을 컨트롤 해야 한다. 즉 텍스트(==문자) 형태로 응답을 보내도록 설정해야 한다.
- HttpServletResponse 인터페이스의 상위 인터페이스인 ServletResponse의 getWriter() 메서드를 호출하면 스트림에 텍스트를 기록하는 것이 가능하다.
- getWriter() 메서드를 통해 응답으로 내보낼 출력 스트림을 얻어낸 후, out.print(HTML 태그) 형태로 작성하여 스트림에 텍스트를 기록할 수 있다.
3. 요청 처리 메서드
사용자가 입력한 정보를 추출하기 위해서는 HttpServletRequest 객체가 제공하는 메서드를 사용해야 한다. 다음은 사용자 입력 정보를 추출할 때 사용하는 메서드들이다.
- getQuertyString();
- getParameter(String name);
- getParameterValues(String name);
[SignupServlet.java]
[MemberVO.java]
package member.model;
//VO(Value Object): 값을 담는 객체, 도메인 객체 ==> MVC 중 Model에 해당
//java_member테이블
import java.sql.*;
public class MemberVO {
private String id;
private String pw;
private String name;
private String tel;
private java.sql.Date indate;
//기본 생성자
public MemberVO() {
}
//인자 생성자
public MemberVO(String id, String pw, String name, String tel, Date indate) {
this.id = id;
this.pw = pw;
this.name = name;
this.tel = tel;
this.indate = indate;
}
//setter, getter
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public java.sql.Date getIndate() {
return indate;
}
public void setIndate(java.sql.Date indate) {
this.indate = indate;
}
}
[MemberDAO.java]
package member.model;
import java.sql.*;
import java.util.*;
import common.db.DBUtil;
//DAO (Data Access Object): Database에 접근하여 CRUD로직을 수행하는 객체
//==> Data Layer (Persistence Layer)
//MVC 중 Model에 해당
//java_member에 INSERT
public class MemberDAO {
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
/** 회원가입 처리 - C (INSERT) */
public int insertMember(MemberVO user) throws SQLException{ //화면으로 넘기기 위해 throws
try {
con=DBUtil.getCon(); //드라이버 로드, 커넥션
String sql ="INSERT INTO java_member(id, name, pw, tel, indate)";
sql+=" VALUES(?, ?, ?, ?, SYSDATE)";
ps = con.prepareStatement(sql);
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPw());
ps.setString(4, user.getTel());
int n = ps.executeUpdate();
return n;
} finally {
close(); //자원 반납
}
}
실행해보기