2020-12-02 TIL
html과 서블릿
- html 폼에 바뀌지 않는다면 html로 만드는 것이 속도 면에선는 더 빠르다
- html이 웹 서버를 통해 바로 정보를 읽어오는 것이 서블릿을 실행하는 것보다 빠르기 때문이다.
- 하지만 만약 html 폼이 바뀐다면 서블릿으로 만드는 것이 낫다.
get, post
- 무엇이 get이고 무엇이 post인지 알아야 한다.
- 주소창이 변화하는 것, 링크, 검색 등은 get
redirect
- httpServlet과 관련있는 기술
-
여기의 루트는 브라우저가 읽어야 하는 루트이기 때문에 서버 루트로 시작한다.
- 그러므로 앞에 정확하게 이름을 명시해줘야 한다.
- 컨텍스트 루트 = /bitcamp-java-project-server
ServletContext servletContext = request.getServletContext();
String contextRootPath = servletContext.getContextPath();
// httpResponse.sendRedirect("/bitcamp-java-project-server/auth/form.html");
httpResponse.sendRedirect(contextRootPath + "/auth/form.html");
서블릿 초기화 파라미터
애노테이션으로 지정
- 서블릿 컨테이너 —호출—> init(ServletConfig config) —호출—> init() <사용
// 서블릿이 사용할 값을 DD 설정으로 지정할 수 있다.
//
//@WebServlet(//
// value = "/ex06/s3",
// loadOnStartup = 1, <- 클라이언트가 요청하지 않아도 서블릿 객체를 자동으로 만든다.
// initParams = {
// @WebInitParam(name = "jdbc.driver", value = "org.mariadb.jdbc.Driver"),
// @WebInitParam(name = "jdbc.url", value = "jdbc:mariadb://localhost/studydb"),
// @WebInitParam(name = "jdbc.username", value = "study"),
// @WebInitParam(name = "jdbc.password", value = "1111")})
//@SuppressWarnings("serial")
public class Servlet03 extends HttpServlet {
// @Override
// public void init(ServletConfig config) throws ServletException {
// // 서블릿 객체가 생성될 때 뭔가 준비하는 작업을 해야 한다면,
// // 보통 이 메서드를 오버라이딩 할 것이다.
// //
// // 문제는 이 메서드가 호출될 때 넘어오는 값(config)은 나중에 사용할 수 있도록
// // 인스턴스 필드에 보관해 둔다.
// // 즉, getServletConfig()가 호출될 때 리턴하도록 코드를 작성한다.
// this.config = config;
// // 그런데 init()를 오버라이딩 할 때 마다 이렇게
// // config 객체를 인스턴스 필드에 저장하도록 코딩하는 것은 매우 번거롭다.
// //
// // 이런 불편함을 없애기 위해서 GenericServlet은
// // 미리 이 메서드에 해당 코드를 작성해 두었다.
// // 그리고 추가적으로 파라미터 값을 받지 않는 init()를 호출하도록
// // 구현하였다.
// //
// // 결론?
// // => 그러니 개발자는 서블릿 객체가 생성될 때 뭔가 작업을 수행하고 싶다면,
// // 이 메서드를 직접 오버라이딩 하지 말고,
// // 이 메서드가 호출하는 다른 init()를 오버라이딩 하라!
// //
// //
// super.init(config);
// }
@Override
public void init() throws ServletException {
System.out.println("/ex06/s3 ==> init()");
// 이 객체가 생성될 때 DB에 연결한다고 가정하자!
// DB에 연결하려면 JDBC Driver 이름과 JDBC URL, 사용자 아이디, 암호를
// 알아야 한다.
//
// 그런데 다음과 같이 자바 소스 코드에 그 값을 직접 작성하면,
// 나중에 DB 연결 정보가 바뀌었을 때
// 이 소스를 변경하고 다시 컴파일 해야 하는 번거로움이 있다.
// => 소스에 변할 수 있는 값을 작성하는 것은 바람직하지 않다.
// => 보통 이렇게 값을 직접 작성하는 것을 "하드(hard) 코딩"이라 부른다.
// String jdbcDriver = "org.mariadb.jdbc.Driver";
// String jdbcUrl = "jdbc:mariadb://localhost:3306/studydb";
// String username = "study";
// String password = "1111";
// 위의 코드처럼 언제든 변경될 수 있는 값을
// 소스코드에 직접 작성하는 방식은 좋지 않다.
// 해결책?
// => 이런 변경 값들은 외부에 두는 것이 관리에 편하다.
// => 값이 바뀌더라도 소스를 변경할 필요가 없다.
// => 보통 DD 파일(web.xml)에 둔다.
// => 다만 이 예제에서는 애노테이션으로도 설정할 수 있다는 것을
// 보여주기 위해 서블릿 상단에 애노테이션으로 설정하였다.
// => 예)
// @WebInitParam(name = "jdbc.driver", value = "org.mariadb.jdbc.Driver")
// => 애노테이션에 설정된 값을 꺼내기 위해서는 ServletConfig 객체가 필요하다.
//
ServletConfig config = this.getServletConfig();
// 이렇게 @WebInitParam()으로 설정된 값을
// "서블릿 초기화 파라미터"라 부른다.
String jdbcDriver = config.getInitParameter("jdbc.driver");
String jdbcUrl = config.getInitParameter("jdbc.url");
String username = config.getInitParameter("jdbc.username");
String password = config.getInitParameter("jdbc.password");
System.out.println(jdbcDriver);
System.out.println(jdbcUrl);
System.out.println(username);
System.out.println(password);
}
}
- 값이 변경될 가능성이 있는 데이터를 바로 소스 코드에 넣지 않는다. = 하드코딩
- 값이 변경되면 컴파일을 다시 해야하고 배포도 다시 해야하기 때문에 불편하다.
- 변경될 값들은 외부에 둔다.
web.xml에 지정
- 서블릿 초기화 파라미터는 서블릿을 등록할 때 같이 넣는다.
- 컨텍스트 초기화 파라미터 값을 꺼내는 방법은 다양한다.
- 리턴 받은 값은 전부 다 같은 것이다.
- 웹 애플리케이션 당 서블릿 컨텍스트는 딱 하나 뿐이다.
ServletContext sc = this.getServletContext();
ServletContext sc2 = req.getServletContext();
ServletContext sc3 = this.getServletConfig().getServletContext();
forward, include

forward

- 웹 브라우저 —요청—> 서블릿 컨테이너 —service()—> S1 —service()(S1에서 버퍼에 출력한 데이터는 버린다)—> S2 ——> (멈추지 않고 바로 서블릿 컨테이너로 이동) 서블릿 컨테이너 —응답—> 웹 브라우저
- 활용 : 작업을 위임할 때
include

- 웹 브라우저 —요청—> 서블릿 컨테이너 —service()—> S1 —service()(S1이 버퍼에 출력한 데이터에 이어서 S2가 출력한다)—> S2 ——> (잠시 멈췄다가 서블릿 컨테이너로 이동) 서블릿 컨테이너 —응답—> 웹 브라우저
forward vs include

Refresh

- 브라우저의 응답을 출력한다.
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 테스트 방법:
// => http://localhost:8080/java-web/ex08/s1
//
// 리프래시
// => 서버로부터 응답을 받고 "내용을 출력"한 후
// 지정된 시간이 경과되면 특정 URL을 자동으로 요청하도록 만들 수 있다.
// => 보통 웹 페이지를 자동으로 이동시키고 싶을 때 사용한다.
// => 예
// 예1: 로그인 후 메인페이지로 자동 이동
// 예2: 메일을 전송한 후 메일 목록 페이지로 자동 이동
// 예3: 게시글 등록한 후 게시글 목록으로 자동 이동
// 예4: 결제 완료 후 결제 상태 페이지로 자동 이동
//
response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("안녕하세요! - /ex08/s1");
// 응답 헤더에 Refresh 정보를 추가한다.
//
// 위에서 벌써 클라이언트에게 응답을 했는데 어떻게 응답 헤더를 출력할 수 있나요?
// => 잊지 말자! out.println()이 출력한 것은 출력스트림 버퍼에 보관되어 있다.
// 따라서 아직 클라이언트에게 응답한 상태가 아니다.
// 그래서 다음과 같이 출력을 한 후에 응답 헤더 값을 추가하거나 변경할 수 있는 것이다.
// 메서드 호출이 완료될 때 비로소 클라이언트로 응답헤더와
// 버퍼에 저장된 message-body가 출력된다.
//
// 만약 out.println()/out.printf()/out.print() 등에서 출력한 내용이
// 버퍼를 꽉 채웠다면 어떻게 하나요?
// => 그러면 자동으로 클라이언트에게 응답한다.
// 따라서 일단 클라이언트에게 응답을 하면
// 헤더를 추가하거나 변경하는 코드는 적용되지 않는다.
// 즉 응답을 완료한 후에 헤더 값을 변경하거나 바꿀 수 없기 때문이다.
// 소용이 없다.
//
// 다음은 일부러 버퍼를 채우는 코드이다.
// 버퍼가 꽉차면 자동으로 출력하는 것을 확인해보자!
// for (int i = 0; i < 200; i++) {
// // 약 40 바이트씩 100번 출력하면 아직 버퍼에 차지 않았기 때문에
// // 클라이언트로 출력되지 않는다.
// // 따라서 반복문 아래에 있는 응답 헤더 설정이 유효하다.
// // 그러나 200번 출력하면 헤더 값과 이전에 출력한 값,
// // 그리고 반복문에서 출력한 데이터가 8KB 버퍼를 꽉 채우기 때문에
// // 즉시 클라이언트로 응답한다.
// // 즉 반복문 다음에 헤더를 설정하기 전에 이미 버퍼 내용이 출력된다.
// // 응답이 완료된 후에 응답 헤더의 값을 변경하거나 추가해봐야 소용없다.
// //
// out.println(i + " ===> 1234567890123456789012345678901234567890");
// }
response.setHeader("Refresh", "3;url=s100");
// 이 service() 메서드의 호출이 끝나면
// 비로서 응답 프로토콜에 맞춰
// 클라이언트로 헤더와 내용을 전송한다.
}
}
// HTTP 응답 프로토콜 예:
//
// HTTP/1.1 200
// Refresh: 3;url=s100 <--- 웹 브라우저는 이 헤더의 정보에 따라 다시 요청한다.
// Content-Type: text/plain;charset=UTF-8
// Content-Length: 28
// Date: Tue, 07 Apr 2020 06:46:25 GMT
// Keep-Alive: timeout=20
// Connection: keep-alive
//
// 안녕하세요! - /ex08/s1
- 만약 버퍼가 가득 차도록 메세지 바디를 설정한다면 그 뒤에 헤더 값을 넣어도 소용이 없다.
Redirect

- 브라우저의 응답을 출력하지 않는다. = 메세지 바디가 없다.
- 그러므로 브라우저에서 출력하지 않고 바로 다음 서블릿에게 요청을 실행한다.
forward/include, refresh/redirect

보관소

- ServletContext : 웹 어플리케이션 시작(서버 시작) 시 생성, 웹 어플리케이션 종료(서버 종료) 시 삭제
- 웹 어플리케이션 하나 당 하나
- 서비스 객체, Dao 객체 <— 서블릿, 필터 등이 공유하는 객체
- HttpSession : 세션 생성(로그인) 시 생성, 세션 종료(로그아웃) 시 삭제
- 로그인 정보 <—특정 클라이언트 전용 객체 저장
- 한 컴퓨터에 여러 httpSession이 가능하다.
- 브라우저(클라이언트) 당 httpSession을 하나
- 크롬 창을 여러개 생성해도 하나의 브라우저로 인식한다.
- 시크릿 창은 다른 브라우저로 인식
- 크롬, 사파리, 파이어폭스 브라우저를 띄우면 각각의 클라이언트로 취급하기 때문에 httpSession이 세개 생성된다.
- 크롬 창을 여러개 생성해도 하나의 브라우저로 인식한다.
- ServletRequest : 요청이 들어왔을 때 생성, 응답 완료 시 삭제
- 요청을 처리하는 동안 공유할 객체
- 리프레시, 리다이렉트는 요청, 응답 후 다시 요청하기 때문에 ServletRequest 객체를 공유할 수 없다.
- ServeltContext, HttpSession, ServletRequest는 보관소의 역할을 하기 때문에 set, getAttribute가 존재한다.