-
20221005 TIL 인터페이스가 먼저다TIL 2022. 10. 5. 20:58
강의 반복 과제 인출에 성공했다!
어제까지만 해도 못 할 것 같았는데,
그 비결은 바로 인터페이스였다.
인터페이스 짱짱맨http://m.ezday.co.kr/bbs/view_board.html?q_sq_board=6828758 인터페이스에 맞춰 구현을 해야되는 것이고, 구현에 인터페이스가 딸려가면 안된다.
따라서 일단 필요한 게 뭔지 생각한다.
인터페이스를 깔끔하게 만들어 준다.
그 후 그걸 구현하면 끝!
정말 쉽죠?
코드를 보면서 살펴보자.
1. 웹 어플리케이션 서버를 자바로 만들고 싶기 때문에 httpServer를 만들어줘야 한다.
따라서 아래와 같은 코드를 생성한다.HttpServer httpServer = HttpServer.create(...);
그런데 create안에 address를 넣어줘야 한다.
2. 따라서 필요한 address를 만들어주자.InetSocketAddress address = new InetSocketAddress(8000);
8000번 포트로 접속하고 싶기 때문에 address를 위와 같이 만들어서 통신할 수 있는 통로를 만들어주자.
이제 create에 맞는 값을 제대로 넣어준다.HttpServer httpServer = HttpServer.create(address, 0); // 0은 소켓 백로그를 시스템의 기본 값으로 쓰겠다는 의미
서버를 왜 만들었는지 생각해보면 서버에서 우리가 원하는 값을 보여주기 위해 만든 것이다.
3. 따라서 httpServer에 원하는 값을 넣어주기 위해 context를 만들어주자.httpServer.createContext("/", exchange -> { ... })
값을 보여주려면 리스폰스 헤더를 무조건 보내줘야 한다.
4. 리스폰스 헤더를 보내자.httpServer.createContext("/", exchange -> { String content = ""; // 원하는 값 넣어주기 exchange.sendResponseHeaders(200, content.getBytes().length); });
이제 컨텐츠를 보여주기 위해 컨텐츠를 response 바디에 써줘야 한다.
5. 리스폰스 바디에 원하는 내용을 써주자.httpServer.createContext("/", exchange -> { String content = ""; exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); });
이제 서버를 시작해줘야 한다.
6. 서버 시작httpServer.start();
서버가 제대로 시작됐다는 것을 터미널에서 확인하기 위해 메시지를 출력해주자.
7. 메시지 출력System.out.println("Server is listening... http://localhost:8000/");
기본 틀은 갖춰졌다.
그런데 웹사이트에서 root path(/)만 사용하지 않을 거라면, 즉 path에 따라 다른 페이지들을 보여주고 싶다면,
path에 따라 분기를 해줘야 되기 때문에 path가 필요하다.
8. path를 받자.httpServer.createContext("/", exchange -> { URI requestURI = exchange.getRequestURI(); // 요기 String path = requestURI.getPath(); // 요기 String content = ""; exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); });
path에 따라 다른 페이지들을 content에 String으로 넣어주면 된다.
그런데 만약 사용자의 입력을 받는 form이 있다고 하자.
이 경우 동일한 URL에 대해 GET이 아닌 POST 메소드를 이용한다면,
메소드에 따라 GET은 페이지를 불러오기만 하면 되고,
POST는 실제로 form을 submit했을 때 일어날 일들도 처리해야되기 때문에 분기를 해야한다.
9. 따라서 메소드를 받자.httpServer.createContext("/", exchange -> { URI requestURI = exchange.getRequestURI(); String path = requestURI.getPath(); String method = exchange.getRequestMethod(); // 요기 String content = ""; exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); });
메소드에 따라 다른 일들을 처리해주면 된다.
form에서 입력을 받은 내용을 처리하려면 내용을 받아와야 한다.
10. form에서 입력받은 내용을 받아오자.httpServer.createContext("/", exchange -> { URI requestURI = exchange.getRequestURI(); String path = requestURI.getPath(); String method = exchange.getRequestMethod(); String requestBody = ""; InputStream inputStream = exchange.getRequestBody(); // 요기가 핵심 Scanner scanner = new Scanner(inputStream); while (scanner.hasNextLine()) { requestBody += scanner.nextLine(); } String content = ""; exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); });
이런식으로 받아올 수 있을 것이다.
requestBody가 key=value 형태로 들어오기 때문에, 파싱을 해줘야 한다.
11. 파싱을 해서 formData를 Map형태로 받자.httpServer.createContext("/", exchange -> { URI requestURI = exchange.getRequestURI(); String path = requestURI.getPath(); String method = exchange.getRequestMethod(); String requestBody = ""; InputStream inputStream = exchange.getRequestBody(); Scanner scanner = new Scanner(inputStream); while (scanner.hasNextLine()) { requestBody += scanner.nextLine(); } Map<String, String> formData = formParser.parse(requestBody); //요기 String content = ""; exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); });
FormParser클래스를 만들고 parse 메소드를 만들어서 Map<String, String>형태로 반환하게끔 잘 구현해주자.
이제 formData를 이용해서 마음껏 원하는 것들을 해주면 된다.
끝.
12. 리팩토링
httpServer.createContext에 너무 뭐가 많다.
적절히 추상화를 해주자.String requestBody = ""; InputStream inputStream = exchange.getRequestBody(); Scanner scanner = new Scanner(inputStream); while (scanner.hasNextLine()) { requestBody += scanner.nextLine(); }
이 만큼은 RequestBody를 읽어오는 역할을 한다.
RequestBodyReader클래스를 만들어서RequestBodyReader requestBodyReader = new RequestBodyReader(exchange); String requestBody = requestBodyReader.body();
위와 같은 인터페이스를 만들어주고, RequestBodyReader의 body 메소드를 구현해주자.
이 때, exchange를 넘겨줘야 하는데, 만약 클래스 전반적으로 사용될 값이라면 exchange를 생성자에서 받게 해주고,
특정 메소드에서만 쓸 것이라면 메소드에 넣어준다.
exchange.sendResponseHeaders(200, content.getBytes().length); OutputStream outputStream = exchange.getResponseBody(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close();
이 부분은 리스폰스 메시지를 작성하는 역할을 한다.
MessageWriter클래스를 만들어서MessageWriter messageWriter = new MessageWriter(exchange); messageWriter.write(content);
위와 같은 인터페이스를 만들어주고, 구현해주자.
그러면 이런 모양의 코드가 탄생한다.InetSocketAddress address = new InetSocketAddress(8000); HttpServer httpServer = HttpServer.create(address, 0); httpServer.createContext("/", exchange -> { URI requestURI = exchange.getRequestURI(); String path = requestURI.getPath(); String method = exchange.getRequestMethod(); RequestBodyReader requestBodyReader = new RequestBodyReader(exchange); String requestBody = requestBodyReader.body(); Map<String, String> formData = formParser.parse(requestBody); PageGenerator pageGenerator = process(path, method, formData); MessageWriter messageWriter = new MessageWriter(exchange); messageWriter.write(pageGenerator.html()); // pageGenerator.html() 이 앞의 코드들의 content인 것이다. }); httpServer.start(); System.out.println("Server is listening... http://localhost:8000/");
PageGenerator ~~~ 줄은 path, method, formData에 따라 다른 페이지를 만들어줘야되기 때문에 인터페이스를 저렇게 만든 것이다.
process메소드에서 path, method, formData를 이용해서 적절한 페이지를 만들어주면 된다.
걱정하지 말고 미래의 나를 믿자.
지금의 나는 못하더라도 미래의 나는 할 수 있을 것이라는 믿음을 가지고 오늘 하루를 충실하게 살자.
할 수 있다.
화이팅.'TIL' 카테고리의 다른 글
20221007 TIL 코테 기출 문제 분석하기 (1) 2022.10.07 20221006 TIL 꼬리에 꼬리를 무는 꼬리 재귀 (0) 2022.10.06 20221004 TIL 더 나은 Repository를 위하여 (0) 2022.10.04 20221003 TIL 포워드 프록시 & 리버스 프록시 (0) 2022.10.03 20221002 TIL 잊지 말고 해피해피 띵 (0) 2022.10.02