서블릿
서블릿의 흐름을 최대한 이해하기 쉽게 작성하려고 노력했다. 코드영역과 설정부분은 최대한 배제하고 서블릿에서 스프링까지 디테일보다는 큰 개념을 잡는데 주력했다.
서블릿이 뭔가요?
사용자가 크롬에게 www.naver.com 입력한다. 크롬은 웹 서버에게 이 위치의 파일을 요청하고 웹 서버는 요청한 프로그램을 찾아서 작업을 수행한 뒤 그 결과를 웹 서버에게 돌려준다. 웹 서버는 HTTP형식에 맞게 크롬에게 응답하고 크롬은 사용자에게 화면을 보여준다.
웹 서버와 프로그램 사이의 데이터를 주고받는 규칙을 CGI라고 한다. CGI규칙에 따라 웹 서버와 데이터를 주고 받도록 작성된 프로그램을 CGI프로그램이라고 한다.
서블릿이란 자바로 만든 CGI프로그램이다.
서블릿 컨테이너 덕분에 개발자는 CGI규칙에 대해 알 필요가 없고 서블릿 컨테이너와 서블릿 사이의 규칙만 알면 된다.
태초에 서블릿이 있었다.
앞서 서블릿 컨테이너와 서블릿간의 규칙을 알아야 한다고 했다. 그 규칙이란게 뭘까?
서블릿 컨테이너가 서블릿에 대해서 호출할 메서드를 정의한 인터페이스가 Servlet인터페이스다.
내가 서블릿을 사용한다면 Servlet인터페이스를 반드시!!! 구현해야 한다.
💡 그래서 뭘 구현해야 하는데??
init()
service()
destroy()
필수적으로 이 세가지를 구현해야한다. 생각해보자 웹 어플리케이션에서 서블릿 파일은 수십 수백개 이상인데 이 메소드들을 매번 구현해야한다면?? 생각만해도 짜증이 난다.
거기다 매번 작동하는 것도 아니다. init()과 destroy()는 서블릿 컨테이너가 수행, 종료될 때 한번 씩만 호출된다. 정작 클라이언트가 요청할 때마다 호출되는 메서드는 service밖에 없다.
그렇다. 자바의 인터페이스, 다형성등을 활용해 init과 destroy는 치워버리고 service만 구현하도록 하면 어떨까?? 참 좋은 생각이다. 그 좋은 생각은 역시 누군가 만들어놨다.
GenericServlet
이 메소드는 init()과 destroy()를 구현해놨다. 사용자는 얘를 상속받아 service메소드만 구현하면 된다. 한 가지 주의할 점은 Servlet은 인터페이스고 이것을 구현한 GenericServlet은 추상클래스다. extends를 사용해야한다
Servlet ← GenericServlet ← 내가만든 서블릿
서블릿과 JDBC
◐JDBC란
JDBC는 자바에서 데이터베이스를 사용하게 도와주는 도구다.
서블릿 ↔ JDBC Driver ↔ 데이터베이스
JDBC Driver를 사용하려면 JDBC 드라이버를 설치해야한다.
◐서블릿에서 JDBC를 사용하기 위해서 필요한 메소드
서블릿에서 JDBC를 사용하려면 Connection, Statement, ResultSet을 생성해야 한다.
Connection객체로 DriverManager를 연결한다.
SQL을 삽입할 객체인 Statement를 생성한다.
ResultSet은 쿼리문을 서버로 보내고 결과값을 담는다.
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
conn = DriverManager.getConnection(
"jdbc:mysql://localhost/studydb", //JDBC URL
"study", // DBMS 사용자 아이디
"study"); // DBMS 사용자 암호
stmt = conn.createStatement();
rs = stmt.executeQuery(
"SELECT MNO,MNAME,EMAIL,CRE_DATE" +
" FROM MEMBERS" +
" ORDER BY MNO ASC");
PreparedStatement
Statement에서 진화하면 PreparedStatement이다. 입력과 매개변수를 분리해서 ?로 처리할 수 있고 질의가 많을수록 속도가 빠르다.
HttpServlet
웹 브라우저의 요청은 Get, Post 두 가지 방식이 있다. 서블릿에서 Get요청 따로 처리하고 Post요청 따로 처리할 순 없을까?
기존의 GenericServlet은 service메소드에서 모든 경우를 처리했다. 이 단점은 보완한 것이 HttpServlet이다
Servlet ← GenericServlet ←HttpServlet
HttpServlet을 사용할 땐 무조건 doXXX메소드를 구현해야 한다. doGet, doPost, doPut등 여러 종류가 있고 필요에 따라 구현하면 된다.
💡 service()메소드는 사용자의 요청 방식에 따라 Get이면 doGet(), Post이면 doPost()를 호출한다.
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
사용자가 요청한 값이 담긴 request와 사용자에게 보낼 응답이 담길 response를 사용해서 통신한다.
Request
사용자가 웹 주소안에 쿼리를 넣어서 주소를 입력(요청)했다면 (www.naver.com?name=minho&password=1234) name과 password를 받는 메소드는 request이다. request.getParameter(”name”)으로 name에 담긴 minho를 가져올 수 있다.
Response
사용자에게 보낼 데이터를 만든다면 response를 사용한다.
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html><head><title>회원 등록</title></head>");
out.println("<body><h1>회원 등록</h1>");
out.println("<form action='add' method='post'>");
out.println("이름: <input type='text' name='name'><br>");
out.println("이메일: <input type='text' name='email'><br>");
out.println("암호: <input type='password' name='password'><br>");
out.println("<input type='submit' value='추가'>");
out.println("<input type='reset' value='취소'>");
out.println("</form>");
out.println("</body></html>");
서블릿 초기화 매개변수
특정 서블릿에서만 사용하는 변수를 서블릿 초기화 매개변수라고 한다. 변경하기 쉬운 값들을 서블릿 초기화 매개변수로 선언한다면 값이 변경됐을 때 web.xml파일만 수정하면 되니 유지보수가 편해진다.
web.xml
<servlet>
<servlet-name>MemberUpdateServlet</servlet-name>
<servlet-class>spms.servlets.MemberUpdateServlet</servlet-class>
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost/studydb</param-value>
</init-param>
<init-param>
<param-name>username</param-name>
<param-value>study</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>study</param-value>
</init-param>
</servlet>
init-param으로 서블릿 초기화 매개변수를 선언할 수 있다.
Class.forName(this.getInitParameter("driver"));
conn = DriverManager.getConnection(
this.getInitParameter("url"),
this.getInitParameter("username"),
this.getInitParameter("password"));
stmt = conn.createStatement();
rs = stmt.executeQuery(
"SELECT MNO,EMAIL,MNAME,CRE_DATE FROM MEMBERS" +
" WHERE MNO=" + request.getParameter("no"));
rs.next();
this.getInitParameter로 매개변수의 값을 호출할 수 있다.
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
→
Class.forName(this.getInitParameter("driver"));
Class.forName을 사용해서 Driver를 구현한 클래스를 로딩하는 방식으로 변경했다.
컨텍스트 초기화 매개변수
데이터베이스가 매번 필요할 때 마다 서블릿 초기화 매개변수를 생성하는 것도 매우 불편하다. DB정보는 서블릿이 바뀐다고 바뀌는 정보가 아니므로 모든 서블릿에서 공유하는 변수로 선언하면 편하다. 이를 가능하게 하는 것이 컨텍스트 초기화 매개변수다.
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost/studydb</param-value>
</context-param>
<context-param>
<param-name>username</param-name>
<param-value>study</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>study</param-value>
</context-param>
사용법은 ServletContext sc = this.getServletContext();로 객체를 생성한다.
sc.getInitParameter(”url”)로 값을 가져오면 된다.
필터
필터는 서블릿 실행 전후에 어떤 작업을 하고자 할 때 사용하는 기술이다. 로그를 남기거나 자원을 미리 준비하는 작업을 필터를 통해 처리할 수 있다.
public class CharacterEncodingFilter implements Filter{
FilterConfig config;
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
@Override
public void doFilter(
ServletRequest request, ServletResponse response,
FilterChain nextFilter) throws IOException, ServletException {
request.setCharacterEncoding(config.getInitParameter("encoding"));
nextFilter.doFilter(request, response);
}
@Override
public void destroy() {}
}
서블릿과 마찬가지로 특정 인터페이스를 구현해야한다. 그리고 web.xml파일에 필터를 등록해야한다.
'IT > 스프링' 카테고리의 다른 글
MVC패턴 (0) | 2022.04.08 |
---|---|
스프링: 느슨한 결합력과 DI (0) | 2021.08.03 |