Servlet

13. 서블릿 출력 형식을 지정해야 하는 이유

크롬으로 선택했을 때는 콘솔에서 출력되듯이 출력되는데
IE에서 실행햇을때는 줄바꿈이 적용되지 않고 만들어진다.

어디가 정상인가?
크롬처럼 내려쓰기 되는게 정상이아니다.
웹기반으로 오면 웹문서로 인식하는게 정상이다.
아무리 내려보기를 햇어도 브라우저가 웹문서로 봣을때는 밑으로 보여지면안된다.
html은 마크업 언어를 통해서 형태가 정해지는 것이다.

그런데 크롬으로보면 또 태그를 명령어가아닌 문자로 해석해서 같이 출력이된다.
브라우저에 컨텐츠 형식을 알려주지 않은 경우에는 자의적인 해석을 하기 때문에 이런 일이 발생한다.
IE는 기본적으로 html로 해석하고 크롬은 text로 해석한다.
그래서 문서를 보낼때 설정을 해줘야한다.

14. 한글과 콘텐츠 형식 출력하기

보내줄때 어떤 콘텐츠인지 알려줘야한다.
안녕 Servlet!!
을 출력해보자 그러면 밑처럼 출력된다.
?? Servlet!!
이렇게 출력됨 한글이 깨진것임.

한글이 왜 깨지는지 알아야한다.

1.웹서버에서 클라이언트로 보낼때 ISO-8859-1 유럽에서 사용하는 한글을 지원하지 않는 문자코드로 인코딩해서 보낸경우
한글은 2바이트씩 보내야하는데 ISO-8859-1은 1바이트씩만 보내서 오류가 발생한다.
2.웹서버에서는 UTF-8로 인코딩해서 보냈지만 브라우저가 다른코드로 잘못해석한 경우
2바이트씩 보냈는데 다른인코딩으로 받을때 1바이트씩 받앗으면 오류가 발생한다.

response.setCharacterEncoding("UTF-8");
UTF-8로 보낸다고 지정해주는 것이다.
이것은 사용자가 보내는것을 지정하는 것이다.
�덈뀞 Servlet!!
그런데 이렇게 읽는다.
이것은 인코딩방식이 한국어(EUC-KR)로 지정되어있어서 그렇다.
??일때는 그냥 보낼때부터 잘못보낸거고 �덈뀞은 받을때 인코딩을 다른방식으로 한것이다.

그래서 보낼때 클라이언트가 어떻게 읽을지도 지정해줘야한다.UTF-8로 읽어야해라고 지정해주자.
response.setContentType("text/html; charset=UTF-8");
charset=UTF-8은 UTF-8로보내니 이것으로 읽어라 하는것이고
text/html 컨텐츠가 html문서라는 것을 알려주는 것이다.
보낼때 어떻게 보낼지와 브라우저가 해석할때를 지정해줘야한다.

@WebServlet("/hi")
public class Nana extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();
        for (int i = 0; i < 100; i++) {
            out.println((i + 1) + "안녕 Servlet!!" + "<br>");
        }
    }
}

15. GET 요청과 쿼리스트링

출력방법을 배웠다. 반대로 사용자 입력을 할때 입력처리 방법을 배워야한다.

사용자입력이라는 것은 요청할때 입력이 이루어진다. 요청과 입력은 뗄레야 뗄수가없다.
요청할때 전달하는 값을 우리가 어떻게 받을 것인지가 중요하다.

사용자 요청에 가장 기본적인것은 GET요청이다.
기본적으로 웹이라는 것은 클라이언트가 웹브라우저로 요청을 한다. 즉 웹문서를 요청한다.
logcalhost/hello -> get
이문서를 요청할때 추가적인 인자를 전달 할 수 있다.
logcalhost/hello?cnt=3 -> get ?를쓰고 키값에 해당되는 값을 전달할수있다.
이것을 쿼리 스트링이라고 한다.
예를들어 커피를 시키는데 샷추가해주세요 같은 것이다.
추가적으로 옵션을 읽어서 옵션에 맞는 웹페이지를 제공해야한다.

이전까진 response출력도구만 사용했지만
이번에는 request입력도구 사용하면된다. request의 getParameter()메소드 사용할 수 있다.

사용자가 전달할때 ?cnt=3하면 쿼리의 키워드를 읽고 전달하는 것이다.
클라이언트와 서버가 합이 맞아야한다.
클라이언트가 cnt로 보낼것이다라는 것을 서버가 알아야하고 이것을 기반으로 처리를 해야한다.

무조건 문자열로 받기때문에 정수로 쓰고싶다면 타입변환 해줘야한다.

@WebServlet("/hi")
public class Nana15 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();

        int cnt = Integer.parseInt(request.getParameter("cnt"));

        for (int i = 0; i < cnt; i++) {
            out.println((i + 1) + "안녕 Servlet!!" + "<br>");
        }
    }
}

쿼리값을 무조건 받게 하면 cnt값을 안넣어주면 오류가 나서 기본값을 넣어줘야한다.
기본값을 넣는 방법은 다음 강의에서 알아보자.

16. 기본값 사용하기

입력값이 만약 전달이 안되면 오류가 생긴다. 그래서 기본값이 필요하다.
4가지 경우가 있다.
logcalhost/hello/?cnt=3 -> "3"
logcalhost/hello/?cnt= -> ""
logcalhost/hello/? -> null
logcalhost/hello -> null
각각에 기본값을 넣어줘야 한다.

먼저 null값인지 확인하고 null이 아니라면 변환해서 사용자가 원하는 값으로 바꿔주면된다.
빈문자열일때도 확인해줘야하니 빈문자열도 조건에 넣어주자.

@WebServlet("/hi")
public class Nana16 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();

        String temp = request.getParameter("cnt");

        int cnt = 100;

        if (temp != null && temp != "") {
            cnt = Integer.parseInt(temp);
        } 

        for (int i = 0; i < cnt; i++) {
            out.println((i + 1) + "안녕 Servlet!!" + "<br>");
        }
    }
}

그런데 사용자가 요청을 할때 주소창에 요청을 할일은 없다.
html페이지를 꾸며서 a태그에 주소를 넣어서 요청해보자.

<a href="hi">인사하기</a><br>
<a href="hi?cnt=3">인사하기</a><br>

17. 사용자 입력을 통한 GET 요청

이전에는 하이퍼링크에 고정된값이엇지만 get 요청을 할때 값을 사용자가 입력할 수 있도록 해보자.
사용자가 입력할 수 있는 입력 폼을 준비해야한다.
input박스의 태그 중 name하면 이 이름으로 전달하는 속성을 실어나르는 책임을 지게 되어있다.
name="cnt" 입력하고 클릭 -> get hello?cnt=3 -> hello문서생성 ->응답

html에 사용자 폼태그를 만들어줘야한다.
form안에 사용자 요청을 하는 인풋과 요청을 전달하는 submit버튼이 필요하다.

action에 서블릿매핑주소를 적어준다.
submit누르면 hi에게 요청이간다 브라우저가 이 액션명을보고 url을 작성하고 name의 키값으로 쿼리스트링을 만들어주게 되어 요청이된다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <div>
        <form action="hi">
            <div>
                <label>"안녕하세요"를 몇번 듣고 싶으세요?</label>
            </div>
            <div>
                <input type="text" name="cnt" /> 
                <input type="submit" value="출력" />
            </div>
        </form>
    </div>
</body>
</html>

18. 입력할 내용이 많은 경우는 POST 요청

입력값이 많은 경우가 있다.
주문할때 옵션이 많다면 다 기억하기 힘들다.
여러가지 주문 -> post입력폼-> 요청처리
게시물을 입력하거나 업무로 많이 할수있을경우 한번에 get으로 불가능해서 많이 사용한다.
처음에는 입력폼을 받기 위한 get요청을 하고 결과를 다시 post해야한다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <div>
        <form action="notice-reg">
            <div>
                <label>제목:</label> <input type="text" name = "title"/>
            </div>
                <div>
                <label>내용:</label>
                <textarea name= "content"></textarea>
            </div>
            <div>
                <input type="submit" value="등록" />
            </div>
        </form>
    </div>
</body>
</html>

제목을 입력받는 공간, 내용을 입력받는 공간이 있다.
이것에 대한 서블릿이 필요하게 된다. notice-reg서블릿을 작성해주자.
값을 받고 돌려주는 초간단 서블릿을 해보려고한다.

문제는 쿼리스트링에 값이 들어오고 있다.
만약에 이 쿼리스트링이 길어지면 url이 굉장히 지저분해질 것이다.
1.url글씨제한이 있어서 전달한 값이 다 안나올 수 있다.
2.쿼리스트링달라고하는 것이 문서의 옵션값인데 장문의 내용을 쿼리스트링으로 보내는 것은 잘하는게 아니다.

그래서 action을 해서 전달할때 옵션을 아무것도 전달안하면 쿼리값으로 전달하게된다.
<form action="notice-reg" method= "post">
하게되면 post로 보내지게 된다.
대장을 받은거고 사용자 입력받은것을 제출하게 되는 것이다.
url에 붙여서 전달하는게 아니라 요청바디에 붙여서 전달하게 된다.

이걸 어떻게 알 수 있나? 개발자 도구를 보면 알 수 있다.
개발자도구의 네트워크에서 캡쳐한 내용을 읽을 수 있다.

@WebServlet("/notice-reg")
public class NoticeReg extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");

        PrintWriter out = response.getWriter();

        String title = request.getParameter("title");
        String content = request.getParameter("content");

        out.println(title + "<br>");
        out.println(content);
    }
}

19. 한글입력문제

한글이 전달되는 것을 서버에서 받지 못하는 문제 서버에서 출력하면서 한글이 깨진건지? 전달할때 깨진건지 알아야한다.
이전에 출력에 대해서는 한글 문제를 해결했기 때문에 전달할때 문제가 발생한 것이라고 할 수 있다.

UTF-8는 멀티바이트 문자이다. 문자 하나당 영문자 1바이트 한글 중 일 2바이트
입력 UTF-8 -> POST -> URL Ecoding할때 2바이트씩 했지만 웹서버에서 읽을때 2바이트를 1바이트씩 ISO-8859-1로 읽는다.
읽을때 "UTF-8"로 읽어달라
request.setCharacterEncoding("UTF-8")라고 써줘야한다.

만약 이게 귀찮으면?
톰캣 환경설정의 서버.XML 커넥터에 코딩방식을 UTF-8로 바꿔버려야한다.
그런데 톰캣서버는 여러개의 서비스를 돌리기때문에 보통 마음대로 바꾸지 않는다.
그래서 서버에서 인코딩이 필요하면 그 서버에서만 한다.

20. 서블릿 필터

톰캣이 사용자로부터 요청이 들어오면 적절한 서블릿을 실행시킨다.
웹서버 <-> WAS ->request servlet container
서블릿을 실행하면 메모리상에 존재하게 되는데 이공간을 servlet container라고한다.
여기에 담아두고 다시 웹서버에 보내준다. 사용하지 않게 되면 삭제한다.

request.setCharacterEncoding("UTF-8");을했엇는데 우리는 한글을 사용하니까 입력받을때는 무조건해줘야한다.
그러면 귀찮아서 서버.XML을 바꾸면? 위에서 언급햇듯이 다른 서버들도 영향을 받으니 안고치는게 낫다.
그러나 서블릿마다 작업하는 것은 귀찮으니 요청과 응답사이에 Filter를 만들어줘서 먼저실행이 된후 서블릿이 실행되도록 할 수 있다.
그리고 filter가 다시 응답을 보낼때 실행할지 안할지를 정해주고 보내준다.

또한 인증이나 권한이 있는지 권한을 줄까말까의 일도 하게 된다.
이것을 한번만 설정하게 되면 다른 서블릿들에도 영향을 받게할 수 있다.
사전과 사후에 필요한 처리가 있다면은 filter를 이용해서 할 수 있게 되는 것이다.

filter패키지를 따로 만들고 CharacterEncodingFilter 클래스를 생성해준다.
만들때 인터페이스 filter를 구현하도록 넣어준다.

이 필터를 만들고나면 설정만하면 자동으로 작동한다. 톰캣이 처음실행할때, 요청이 올때마다 출력된다.
web.xml을 가서 설정해줘야한다. 서블릿을 매핑하듯이 만들어주면된다.

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.newlecture.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

특정 url만 작성할수도 있고 모든 url에 적용하려면 /*로 표시해준다.
설정이 끝나고 무조건 뭔가 요청하게 되면 이것이 실행이된다.

이러고 실행해보면 페이지에 아무것도 뜨지 않는다
필터가 동작하는데 실행된다음 서블릿으로 전이할지 말지를 정하지 않았기 때문이다.
이흐름을 연결할건지는 chain이 정하게 된다.

chain.doFilter(request, response);하면 흐름을 넘기는 것이다.
흐름을 넘겨서 다음 필터 서블릿이 실행되게 한다.

사전검사를 하면 위에것을 하고 사후검사를 하고 아래것을 출력해주면된다.
서블릿이 실행되기전이면 위에적고 실행후에 응답할때 필요하면 아래에 작성해주면된다.

인코딩 필터링은 실행되기 전에 해야하니 이전에 넣어주자.

이것또한 web.xml을 설정하는 것이아니라 어노테이션으로 설정할 수도잇다.


@WebFilter("/*")
설정방법이 매우 쉬워지고 불필요한 작업을 줄일 수있다.

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        //System.out.println("before filter");
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
        //System.out.println("after filter");
    }
}

2023.03.15 후기

서블릿 필터와 한글 설정 기본적인 get요청과 post요청에 대해서 알아보았다.
매우 기본이지만 매우 중요하다. 웹을 하면서 요청을 주고 받는 것은 모든 것에서의 기초가 된다.
기초를 잊지 않도록 해애할 것 같다.

'기초단계 > JSP&Servlet' 카테고리의 다른 글

2023.03.19 Servlet  (0) 2023.03.20
2023.03.18 Servlet  (0) 2023.03.19
2023.03.14 Servlet  (0) 2023.03.15
2023.01.06 JSP & Servlet  (0) 2023.01.07
2023.01.04 JSP & Servlet  (0) 2023.01.05

+ Recent posts