2022/11/14 (월)
(1) 저번 주에 web.xml을 수정하여 Servlet 매핑 하는 방법에 대해 학습했고, 이번에는 annotation을 활용하여 Servlet 매핑을 하자.
@WebServlet("/hi")
public class Nana extends HttpServlet {
@Override
protected void service(...) throws ... {
...
}
}
}
위 코드처럼 Servlet 클래스 위에 "@WebServlet("매핑할 url")"로 annotation을 표기한다. 더 이상 web.xml을 수정하지 않고도 Servlet 매핑을 할 수 있다.
단, 아래의 두 가지 설정을 반드시 해야 한다.
㉮. web.xml 파일의 <web-app> 태그 내의 metadata-complete="true"를 metadata-complete="false"로 수정한다. true는 모든 설정이 web.xml에 있음을 의미하고, false는 xml 파일 외부에도 설정이 존재함을 의미한다.
㉯. javax.servlet.annotation.WebServlet; 을 import 한다.
(2) 서블릿 출력 형식
브라우저에 컨텐츠 출력 형식을 알려주지 않으면, 브라우저는 해당 컨텐츠를 자의적으로 해석한다. 브라우저에 따라 html로 해석하거나, text해석할 수 있다. (ex. text로 해석할 경우 HTML 태그가 text로 그대로 출력된다)
한글도 마찬가지이다. Servlet으로 한글을 출력할 경우 HTML에서 한글이 깨지는 모습을 확인할 수 있는데, 해당 문제의 원인은 다음과 같다.
㉮. 서버에서 한글을 지원하지 않는 문자코드로 인코딩한 경우
→ 기본적으로 1byte씩 컨텐츠를 전달하는데, 한글은 2byte가 필요하기 때문에 제대로 인코딩되지 않는다.
→ 이를 해결하기 위해서는 아래 코드를 추가해야 한다.
response.setCharacterEncoding("UTF-8");
(HttpServletResponse response 라고 가정)
㉯. ㉮를 해결한 후에도 서버에서 UTF-8로 인코딩해서 브라우저로 보냈는데, 브라우저가 다른 코드로 잘못 해석한 경우가 발생하여 한글이 출력되지 않을 수 있다.
→ 이를 해결하기 위해서는 아래 코드도 추가해야 한다.
response.setContentType("text/html; charset=UTF-8");
그러므로 Servlet에서는 출력 형식을 반드시 설정해야 한다.
2022/11/15 (화)
(1) 서버에서 클라이언트가 보낸 데이터를 얻어 오기 위해 "Query String"을 활용한다. Query String은 url 뒤에 입력 데이터를 함께 제공하며 "url?이름=값&이름=값&이름=값..." 형식을 가진다.
클라이언트의 데이터는 HTML <form> 태그를 활용하여 얻을 수 있으며 그 방식은 GET, POST 방식으로 나누어 진다.
→ GET 방식은 url에 사용자가 입력한 내용을 공개한다
→ POST 방식은 입력한 내용을 url에 공개하지 않는다.
그러므로 입력할 내용이 너무 많은 경우, 보안을 지켜야 하는 경우 POST 방식을 활용한다.
<form> 태그의 method 속성으로 GET을 활용할지 POST를 활용할지 결정할 수 있다.
또한, action 속성에 form을 전송할 서버 쪽 스크립트 파일을 지정한다.
<form method="get" action="호출할서블릿"> </form>
or
<form method="post" action="호출할서블릿"> </form>
입력은 form 태그 내부의 input 태그로 받으며, 데이터를 전송하기 위해 input type="submit" 버튼이 클릭되어야 한다.
public class Nana extends HttpServlet {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();
int cnt = Integer.pareseInt(req.getParameter("cnt"));
for(int i = 0; i < cnt; i++) {
out.println((i+1)+ ": hello <br >");
}
}
}
다음과 같이 사용자의 입력에 따라 hello를 출력하는 서블릿이 있다고 가정하자. 사용자가 5를 입력할 경우 서버는 사용자에게 hello를 5번 출력한 결과를 제공할 것이다.
하지만, 사용자가 아무 입력을 하지 않았을 경우 HTTP 상태 500 이라는 내부 서버 오류가 발생함을 확인할 수 있는데, 이를 해결하기 위해 사용자의 입력이 null 이거나 "" 일 경우 기본값을 출력할 수 있도록 설정한다.
단, req.getParameter()는 '문자열'을 반환함에 유의하자.
public class Nana extends HttpServlet {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();
String cnt_ = req.getParameter("cnt");
int cnt = 10; // 기본값 설정
if(cnt_ != null && cnt_.equals(""))
cnt = Integer.pareseInt(cnt_);
for(int i = 0; i < cnt; i++) {
out.println((i+1)+ ": hello <br >");
}
}
}
위 코드처럼 기본값을 설정할 수 있다.
2022/11/16 (수)
(1) 한글 '입력' 문제
한글 출력 문제는 response.setCharacterEncoding(); 과 response.setContentType(); 으로 해결할 수 있었다.
하지만, GET, POST 방식으로 사용자의 입력 데이터를 받을 때 형식을 설정하지 않으면 한글이 깨지는 것을 확인할 수 있다.
이를 해결할 수 있는 방법으로는 두 가지가 있다.
㉮. 톰캣 서버 설정 자체를 바꾸기
→ 하나의 톰캣 서버는 여러 개의 웹 사이트를 돌릴 수 있으므로 톰캣 서버 설정을 변경하는 것은 모든 사이트에 영향을 미치게 된다. 다른 방법을 활용하자.
㉯. Servlet에서 아래 코드를 추가하기
request.setCharacterEncoding("UTF-8");
(HttpServletRequest request 라고 가정)
2022/11/17 (목)
(1) 서블릿 필터(Servlet Filter)
공통적인 기능들을 서블릿이 호출되기 전에 수행(전처리)하고 싶거나 서블릿이 호출된 후 수행(후처리)하고 싶다면, 그 공통적인 기능들을 서블릿 필터로 구현한다.
- 기본구조
public class myServletFilter implements Filter {
@Override
public void doFilter(ServletRequest request
, ServletResponse response
, FilterChain chain)
throws IOException, ServletException {
//전처리 수행
chain.doFilter(request, response);
//후처리 수행
}
}
우선 서블릿 필터는 javax.servlet.Filter를 import하여 Filter 인터페이스를 구현해야 한다.
doFilter 메소드는 서블릿 클래스의 service 메소드의 역할과 비슷하며, 서블릿 필터는 실행 요청을 받으면
→ doFilter의 매개변수인 chain의 doFilter를 수행전까지의 코드를 실행(전처리)
→ chain.doFilter(request, response)는 서블릿으로 request와 response를 넘겨준다. (즉, 서블릿 실행)
→ 서블릿이 실행된 후 다시 서블릿 필터로 응답객체와 제어권이 넘어오고 chain.doFilter 아래의 코드가 실행(후처리)
의 흐름으로 실행된다. 그러므로 서블릿 필터는 전처리와 후처리 기능을 수행할 수 있다.
- 설정방법 (2가지)
서블릿 필터의 설정방법은 2가지가 있으며 서블릿을 설정하는 방법과 같다.
㉮. web.xml에서 서블릿 필터 매핑
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>com.csh.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
해당 서블릿 필터를 모든 url에 적용하고 싶다면 <url-pattern> 을 "/*"로 설정하자.
㉯. annotation 활용
서블릿과 마찬가지로 서블릿 필터 클래스 바로 위에 annotation을 활용한다
@WebFilter("/*")
public class myServletFilter implements Filter {
@Override
public void doFilter(ServletRequest request
, ServletResponse response
, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
}
모든 url에 해당 서블릿 필터를 적용하려면 @WebFilter("/*")로 설정한다.
2022/11/18 (금)
(1) 여러 개의 submit 버튼 사용하기
여러 개의 submit 버튼에 따라 다른 결과를 출력하고 싶다면 submit 버튼들의 name을 같게 설정하고, submit 버튼의 value에 따라 다른 기능을 수행하도록 하자.
HTML에서 input으로 x, y 값을 넘겨주고, add 버튼을 누르면 덧셈 결과를, sub 버튼을 누르면 뺄셈 결과를 출력하는 프로그램이 있다고 가정하자.
<div>
<input type="submit" name="operator" value="add">
<input type="submit" name="operator" value="sub">
</div>
위 코드는 <form action="cal" method="post"> ... </form> 내부에 있으며 이와 연결되는 서블릿 코드는 아래와 같이 작성할 수 있다.
@WebServlet("/cal")
public class Calculator extends HttpServlet {
@Override
protected void service(HttpServletRequest req
, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter out = resp.getWriter();
String x_ = req.getParameter("x");
String y_ = req.getParameter("y");
String op = req.getParameter("operator");
int x = 0;
int y = 0;
int result = 0;
if(x_ != null && !x_.equals("")) {
x = Integer.parseInt(x_);
}
if(y_ != null && !y_.equals("")) {
y = Integer.parseInt(y_);
}
if(op.equals("add")) {
result = x + y;
}
else {
result = x - y;
}
out.printf("계산 결과는 : %d", result);
}
}
2022/11/19 (토)
(1) 입력 데이터 배열로 받기
위의 간단한 계산기 예제는 입력 데이터가 두개밖에 없지만, 만약 입력 데이터가 동적으로 늘어나는 계산기라면 어떻게 구현해야 할까? 모든 입력 데이터에 다른 name을 설정하여 값을 받는 것은 비효율적일 것이다.
이를 해결하기 위해 Servlet에는 같은 name으로 전달된 입력데이터를 서버에서 배열로 받을 수 있는 메소드가 존재한다.
String[] num_ = req.getParameterValues("num");
int result = 0;
for(int i = 0; i < num_.length; i++) {
int num = Integer.parseInt(num_[i]);
result += num;
}
위 코드처럼 request 객체의 getParameterValues(); 를 활용한다면 같은 name을 가진 입력 데이터를 배열로 받을 수 있다.
cf) Java에서 length는 배열의 길이를, length()는 문자열의 길이를 구할 때 활용된다.
'나에 대한 기록' 카테고리의 다른 글
[독서 기록] 스프링5 프로그래밍 입문 - 최범균 저 (5) | 2023.01.29 |
---|---|
[기록] 1월 둘째 주 질문 정리 (1) | 2023.01.16 |
[기록] 매일 코딩하기 - 11월 둘째 주 (Servlet 기초) (1) | 2022.11.11 |
[기록] 매일 코딩하기 - 11월 첫째 주(웹 기초, tomcat) (1) | 2022.11.07 |
[기록] 매일 코딩하기 - 10월 말 (1) | 2022.10.30 |