IT/스프링

서블릿과 JDBC

은세고화 2022. 3. 16. 09:12
반응형

서블릿

서블릿의 흐름을 최대한 이해하기 쉽게 작성하려고 노력했다. 코드영역과 설정부분은 최대한 배제하고 서블릿에서 스프링까지 디테일보다는 큰 개념을 잡는데 주력했다.

 

 

 

 

서블릿이 뭔가요?


사용자가 크롬에게 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파일에 필터를 등록해야한다.

 

 

 

참조: http://www.yes24.com/Product/Goods/13159413

반응형