계산기 웹 프로그램 구현
package org.example;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
new CustomWebApplicationServer(8080).start();
System.out.println("Aa");
}
}
IoExceoption 은 파일 입출력과 관련된 예외를 처리하기 위한 클래스 이다.
public static void main(String[] args) throws IOException {
throws IOException 부분의 메서드에서 IOEception 예외를 던질 수 있다는 것을 나타낸다
이 예외는 입출력과 관련된 문제가 발생할 수 있다는 것을 의미한다.
new CustomWebApplicationServer(8080).start();
이줄은 CustomWebApplicationServer 클래스의 새 인스턴스를 생성하고, 생성자에 8080을 전달하여 서버를 생성한다
그런 다음 start 메서드를 호출하여 서버를 시작한다. 이 부분은 사용자 정의 서버를 초기화하고 시작하는 부분이다.
위 코드들의 목적은 사용자 정의 웹 애플리케이션 서버를 시작하고 Aa 를 출력하는 것이다.
웹 서버를 시작하라고 무엇인가를 처리하는 애플리케이션 시작점인것이다.
package org.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CustomWebApplicationServer {
private final int port;
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
private static final Logger logger = LoggerFactory.getLogger(CustomWebApplicationServer.class);
public CustomWebApplicationServer(int port) {
this.port = port;
}
public void start() throws IOException {
try (ServerSocket serverSocket = new ServerSocket(port)) {
logger.info("[CustomWebApplicationServer] started {} port.", port);
Socket clientSocket;
logger.info("[CustomWebApplicationServer] waiting for client.");
while ((clientSocket = serverSocket.accept()) != null) {
logger.info("[CustomWebApplicationServer] client connected!");
/**
* Step3 - Thread Pool을 적용해 안정적인 서비스가 가능하도록 한다.
*/
executorService.execute(new ClientRequestHandler(clientSocket));
}
}
}
}
이 서버는 클라이언트 요청을 처리하고 멀티스레딩을 사용하여 안정적인 서비스를 제공한다.
private final int port;
이 부분은 서버가 사용할 포트 번호를 저장하는 멤버 변수 port 를 선언한다.
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService 라는 스레드 풀을 생성한다 이스레드 풀은 최대 10개의 스레드를 가질 수 있으며 클라이언트 요청을 병렬로 처리하기 위해 사용된다.
스레드 풀 :
여러 스레드를 관리하고 재사용하는 메커니즘을 제공 하는 소프트웨어 디자인 패턴이다 스레드 풀은 다음 과같은 주요 목적을 가지고 있다.
1. 스레드 생성과 제거 최적화 : 스레드를 생성하고 제거하는 비용은 비싸기 때문에 스레드풀은 미리 생성된 스레드를 유지하고 재사용하여 이러한 오버헤드를 줄인다.
2. 작업 분배 : 스레드 풀은 동시에 처리해야 하는 작업들을 스레드들 사이에 분배 한다 이로써 여러 작업을 병렬로 처리할수있다.
3. 스레드 수 제한 : 스레드 풀은 동시에 실행할 수 있는 스레드의 최대 수를 제한함으로써 시스템의 리소스 사용을 효율적으로 관리한다 이를 통해 과도한 스레드 생성을 방지하고 시스템 안정성을 유지한다.
- 스레드 풀은 주로 다음과 같은 상황에서 사용된다.
1. 네트워크 서버 : 클라이언트 요청을 병렬로 처리하고 응답 속도를 항상시키는 데 사용 된다.
2. 웹 서버 : 웹 요청을 처리하고 다수의 사용자에게 서비스를 제공하는 데 사용된다.
3. 백그라운드 작업 : 데이터베이스 조회 , 파일 처리 , 이미지 처리 등과 같은 백그라운드 작업을 병렬로 처리하는데 사용
4. 다수를 스레드를 사용해야 하는 다른 멀티슬레드 애플리케이션들
스레드 풀은 스레드 생성과 관리에 필요한 복잡성을 숨기고 , 스레드의 생명주기와 동작을 간소화 하며, 시스템의 자원을 효율적으로 활용하는데 도움을 준다 Java 에서는 java.util.concurrent.ExecutorService 인터페이스와 이를 구현한 클래스를 사용하여 스레드 풀을 생성하고 관리할 수 있다 일반적으로 스레드 풀을 사용하면 멀티스레드 애플리케이션을 보다 효율적으로 작성할 수있다.
private static final Logger logger = LoggerFactory.getLogger(CustomWebApplicationServer.class);
이 부분은 logger 를 설정하고 LoggerFactory.getLogger() 메서드를 사용 하여 CustomWebApplicationServer 클래스를
대상으로 한 로거를 생성한다 이로거는 서버 동작 중에 로그 메시지를 기록하는 데 사용된다.
public CustomWebApplicationServer(int port) {
this.port = port;
}
이 부분은 CustomWebApplicationServer 클래스의 생성자 이다 생성자는 포트 번호를 매개변수로 받아서 port 멤버 변수에 저장한다.
public void start() throws IOException {
start 메서드는 서버를 시작하기 위한 메서드로 , IOException 을 던질 수 있다고 선언한다.
try (ServerSocket serverSocket = new ServerSocket(port)) {
이부분은 ServerSocket 을 생성하고 해당 포트 번호로 서버 소켓을 열고 클라이언트 연결을 대기한다
try-with-resources 문을 사용하여 serverSocket 을 자동으로 닫는다.
logger.info("[CustomWebApplicationServer] started {} port.", port);
서버가 시작됐음을 나타내는 로그 메시지를 기록한다.
Socket clientSocket;
logger.info("[CustomWebApplicationServer] waiting for client.");
while ((clientSocket = serverSocket.accept()) != null) {
while 루프를 사용하여 클라이언트의 연결을 계속해서 대기하고 있다 클라이언트가 연결되면 clientSocket 에 클라이언트와의 통신을 위한 소켓이 할당된다.
logger.info("[CustomWebApplicationServer] client connected!");
클라이언트가 연결되었음을 로그 메시지로 표시한다.
executorService.execute(new ClientRequestHandler(clientSocket));
클라이언트 요청을 처리하기 위해 executorService 를 사용하여 ClientRequestHandler 클래스의 인스턴스를 생성하고 해당 스레드 풀에서 실행한다 이를 통해 클라이언트 요청을 병렬로 처리할 수 있다.
이렇게 구현된 CustomWebApplicationServer 클래스는 지정된 포트에서 클라이언트의 연결을 수락하고 각 클라이언트 요청을 별도의 스레드에서 처리하여 안정적인 서비를 제공하는 웹 애플리케이션 서버를 나타낸다 로깅을 통해 서버 동작 상황을 추적하고 모니터링할 수 있다.
// GET /calculate?operand1=11&operator=*&operand2=55
GET http://localhost:8088/calculate?operand1=11&operator=*&operand2=55
test.http 를 만들어준다
GET : 이 부분은 HTTP 요청 메서드를 나타낸다 HTTP 요청 메서드는 클라이언트가 서버에게 어떤 동작을 수행해야 하는 지 알려주는 것이다 GET 은 서버로부터 리소스(일방적인 웹 페이지)를 가져오는 요청을 의미한다 클라이언트 정보를 요청하고 서버는 그 정보를 응답으로 제공한다.
http://localhost:8088/calculate?operand1=11&operator=*&operand2=55 : 이 부분은 실제로 요청하는 리소스의 URL 이다 여기에서 중요한 부분은 다음과 같다.
http://localhost:8088 : 이 부분은 서버의 주소와 포트를 나타낸다 http 는 통신 프로토콜을 나타내며 localhost 는 서버의 호스트 이름 또는 IP 주소를 나타낸다 8088은 서버 리스닝(대기)하는 포트 번호를 나타낸다.
/calculate : 이 부분은 웹 애플리케이션에서 처리할 리소스 ( 도는 엔드포인트) 의 경로를 나타낸다 일반적으로 이 부분은 서버에서 어떤 동작을 수행해야 하는지 결정하는 데 사용된다.
operand1=11&operator=*&operand2=55: 이 부분은 요청의 쿼리 문자열 (Query String) 이다. 쿼리 문자열은 리소스에 대한 추가적인 매개변수나 데이터를 전달할 때 사용된다 여기에서는 세 개의 매개변수가 포함되어 있다.
operand1=11 : 첫번째 피연산자(operand1) 의 값은 11이다.
operator=* : 연산자(operator) 의 값은 * (곱셈) 이다.
operand2=55 : 두 번째 피연산자(operand2) 의 값은 55 이다.
이 요청은 클라이언트가 서버에게 http://localhost:8088 서버의 /calculate 경로로 이동하여 첫 번째 피연산자와 두 번째 피연산자를 곱하는 연산을 요청하는 것이다 이러한 종류의 요청은 주로 웹 애플리케이션에서 사용자의 입력을 기반으로 계산을 수행하거나 데이터를 검색하는 데 사용된다 서버는 이 요청을 처리하고 적절한 응답을 생성하여 클라이언트에게 전달된다.
package org.example;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class RequestLineTest {
@Test
void create() {
RequestLine requestLine = new RequestLine("GET /calculate?operand1=11&operator=*&operand2=55 HTTP/1.1");
assertThat(requestLine).isNotNull();
assertThat(requestLine).isEqualTo(new RequestLine("GET", "/calculate", "operand1=11&operator=*&operand2=55"));
}
}
RequestLine 클래스의 create 메서드에 대한 테스트를 수행한다.
테스트는 RequestLine 객체를 생성하고 생성된 객체가 예상한대로 동작하는 지 확인한다
RequestLine requestLine = new RequestLine("GET /calculate?operand1=11&operator=*&operand2=55 HTTP/1.1");
이 줄은 RequestLine 클래스의 생성자를 호출하여 새 RequestLine객체를 생성하고 HTTP 요청 라인을 나타내는 문자열을 전달한다 . RequestLine 클래스는 이 문자열을 분석하여 HTTP 메서드 경로 및 쿼리 문자열을 추출하고 내부적으로 저장한다.
assertThat(requestLine).isNotNull();
이 줄은 assertThat 메서드를 사용하여 requestLine 객체가 null이 아닌지를 확인한다 만약 requestLine 이 null 이라면 테스트는 실패하게 된다.
assertThat(requestLine).isEqualTo(new RequestLine("GET", "/calculate", "operand1=11&operator=*&operand2=55"));
이 줄은 assertThat 및 isEqualTo 메서드를 사용하여 requestLine 객체가 주어진 값과 일치하는지 확인한다.
new RequestLine("GET", "/claculate", "operand1=11&operator=*&operand2=55") 는 예상되는 requestLine 객체를 나타낸다 즉 테스트는 requestLine 객체가 예상한 대로 HTTP 메서드 경로 및 쿼리 문자열을 분석하고 저장하는지 확인한다.
테스트를 실행하면 , 코드의 RequestLine 클래스가 제대로 동작하는지를 확인하고 , 코드 변경시에도 예상한 동작을 유지하도록 검증한다.
package org.example;
import java.util.Objects;
// GET /calculate?operand1=11&operator=*&operand2=55 HTTP/1.1
public class RequestLine {
private final String method; // GET
private final String urlPath; // /calculate
private QueryStrings queryStrings; // operand1=11&operator=*&operand2=55
public RequestLine(String method, String urlPath, String queryStrings) {
this.method = method;
this.urlPath = urlPath;
this.queryStrings = new QueryStrings(queryStrings);
}
public RequestLine(String requestLine) {
String[] tokens = requestLine.split(" ");
this.method = tokens[0];
String[] urlPathTokens = tokens[1].split("\\?");
this.urlPath = urlPathTokens[0];
if (urlPathTokens.length == 2) {
this.queryStrings = new QueryStrings(urlPathTokens[1]);
}
}
public boolean isGetRequest() {
return "GET".equals(this.method);
}
public boolean matchPath(String requestPath) {
return urlPath.equals(requestPath);
}
public QueryStrings getQueryStrings() {
return this.queryStrings;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RequestLine that = (RequestLine) o;
return Objects.equals(method, that.method) && Objects.equals(urlPath, that.urlPath) && Objects.equals(queryStrings, that.queryStrings);
}
@Override
public int hashCode() {
return Objects.hash(method, urlPath, queryStrings);
}
}
위 코드는 HTTP 요청 라인을 파싱하고 이를 나타내는 RequestLine 클래스를 구현한 것이다. 이 클래스는 주어진 HTTP 요청 라인에서 HTTP 메서드 URL 경로 및 쿼리 문자열을 추출하고 저장한다.
private final String method; // GET
private final String urlPath; // /calculate
private QueryStrings queryStrings; // operand1=11&operator=*&operand2=55
이 부분은 RequestLine 클래스의 멤버 변수를 정의한다 method 변수는 HTTP 메서드를 저장하고 urlPath 변수는 URL 경로를 저장한다 또한 queryStrings 변수는 QueryStrings 객체를 저장하며 이 객체는 쿠러 문자열을 파싱한 결과를 저장하는 데 사용된다.
public RequestLine(String method, String urlPath, String queryStrings) {
this.method = method;
this.urlPath = urlPath;
this.queryStrings = new QueryStrings(queryStrings);
}
이 부분은 RequestLine 클래스의 생성자 중 하나를 정의하고 있다 이 생성자는 HTTP 메서드 URL 경로 및 쿼리 문자열을 받아서 RequestLine 객체를 초기화한다.
public RequestLine(String requestLine) {
String[] tokens = requestLine.split(" ");
this.method = tokens[0];
String[] urlPathTokens = tokens[1].split("\\?");
this.urlPath = urlPathTokens[0];
if (urlPathTokens.length == 2) {
this.queryStrings = new QueryStrings(urlPathTokens[1]);
}
}
또 다른 생성자는 HTTP 요청 라인을 받아서 해당 라인을 파싱하여
RequestLine 객체를 초기화 한다 requestLine 문자열을 공백을 기준으로 나누어 HTTP 메서드와 URL 경로를 다시 ? 문자열 기준으로 나누어 쿼 문자열을 추출하고 QueryString 객체로 초기화 한다.
public boolean isGetRequest() {
return "GET".equals(this.method);
}
isGetRequest 메서드는 현재 RequestLine 객체의 HTTP 메서드가 GET 인지를 확인한다 만약 HTTP 메서드가 GET 이라면 true 를 반환하고 그렇지 않으면 false를 반환한다.
public boolean matchPath(String requestPath) {
return urlPath.equals(requestPath);
}
matchPath 메서드는 현재 RequestLine 객체의 URL 경로가 주어진 requestPath 와 일치하는지를 확인한다 일치하면 true 반환 그렇지 않으면 false를 반환.
public QueryStrings getQueryStrings() {
return this.queryStrings;
}
getQueryStrings 메서드는 현재 RequestLine 객체의 쿼리 문자열을 나타내는 QueryString 객체를 반환
마지막으로 equals 및 hashCode 메서드는 객체의 동등성 비교를 위해 오버라이드되어 있다. 객체의 속성들을 비교하여 동등성을 판단하고 hashCOde 메서드는 객체의 해시 코드를 생성한다
이 RequestLine 클래스는 주어진 HTTP 요청 라인에서 필요한 정보를 추출하고 저장하는 데 사용될 수 있으며 HTTP 요청을 처리하고 분석하는 웹 서버 또는 애플리케이션에서 유용하게 활용될 수 있다.
package org.example;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class QueryStringTest {
@Test
void createTest() {
QueryString queryString = new QueryString("operand1", "11");
assertThat(queryString).isNotNull();
}
}
QueryString 클래스의 createTest 메서드를 테스트 하는 코드이다 QueryString 객체르 생성하고 해당 객체가 예상대로 동작하는지 확인한다.
QueryString queryString = new QueryString("operand1", "11");
이 줄은 queryString 클래스의 생성자를 호출하여 QueryString 객체를 생성하고 operand1 을 이름과 11 을 값으로 가지는 쿼리 문자열을 생성한다.
assertThat(queryString).isNotNull();
이 줄은 assertThat 메서드를 사용하여 queryString 객체가 null이 아닌지를 확인
만약 queryString이 null이라면 테스트는 실패
이 테스트는 QueryString 클래스의 생성자가 주어진 이름과 값으로 쿼리 문자열을 올바르게 생성하고, 객체가 null이 아닌지를 확인하는데 사용된다 이러한 종류의 테스트는 클래스나 메서드가 예상대로 동작하는지 확인한데 도움이 되며 코드 변경시 예상한 동작을 유지하도록 검증한다.
package org.example;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class QueryStringsTest {
@Test
void createTest() {
QueryStrings queryStrings = new QueryStrings("operand1=11&operator=*&operand2=55"); // List<QueryString>
assertThat(queryStrings).isNotNull();
}
}
QueryStrings 클래스의 createTest 메서드를 테스트하는 코드이다 QueryStrings 객체를 생성하고 해당 객체가 예상대로 동작하는지 확인
QueryStrings queryStrings = new QueryStrings("operand1=11&operator=*&operand2=55"); // List<QueryString>
이줄은 QueryStrings 클래스의 생성자를 호출하여 QueryStrings 객체를 생성하고, operand1=11&operator=*&operand2=55 와 같은 쿼리 문자열을 생성 이 쿼리 문자열은 여러 개의 QueryString 객체를 포함하는 것을 가정한다.
package org.example;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class QueryStrings {
private List<QueryString> queryStrings = new ArrayList<>();
// "operand1=11 operator=* operand2=55"
public QueryStrings(String queryStringLine) {
String[] queryStringTokens = queryStringLine.split("&");
Arrays.stream(queryStringTokens)
.forEach(queryString -> {
String[] values = queryString.split("=");
if (values.length != 2) {
throw new IllegalArgumentException("잘못된 QueryString 포맷을 가진 문자열입니다.");
}
queryStrings.add(new QueryString(values[0], values[1]));
});
}
public String getValue(String key) {
return this.queryStrings.stream()
.filter(queryString -> queryString.exists(key))
.map(QueryString::getValue)
.findFirst()
.orElse(null);
}
}
쿼리 문자열(Query Strings)을 처리하는 QueryStrings 클래스를 정의한 것 이 클래스는 쿼리 문자열을 파싱하고, 각 쿼리 문자열 요소를 QueryString 객체로 변환하여 저장한다.
public class QueryStrings {
private List<QueryString> queryStrings = new ArrayList<>();
이 줄은 QueryString 클래스를 정의하고 queryString 라는 이름의 QueryString 객체를 저장할 리스트를 생성한다
이 리스트는 쿼리 문자열에서 파실한 QueryString 객체를 보유한다.
public QueryStrings(String queryStringLine) {
String[] queryStringTokens = queryStringLine.split("&");
Arrays.stream(queryStringTokens)
.forEach(queryString -> {
String[] values = queryString.split("=");
if (values.length != 2) {
throw new IllegalArgumentException("잘못된 QueryString 포맷을 가진 문자열입니다.");
}
queryStrings.add(new QueryString(values[0], values[1]));
});
}
이 부분은 QueryStrings 클래스의 생성자이다 . 생성자는 쿼리 문자열을 받아서 파싱하고 각 쿼리 문자열 요소를 QueryString 객체로 변환하여 queryStrings 리스트에 추가한다 쿼리 문자열은 & 문자로 분리되며 각 요소는 = 문자로 이름과 값으로 분리 된다.
values.length != 2 조건을 통해 잘못된 쿼리 문자열 형식인 경우 예외를 던지고 처리한다.
QueryStrings 클래스는 쿼리 문자열을 처리하고 각 요소를 QueryStrings 객체로 추출하여 사용할 수 있도록 도와준다
이것은 주로 웹 애플리케이션에서 URL 에서 파라미터를 추출하거나 사용자가 입력한 데이터를 처리하는 데 유용하다.
package org.example;
import java.io.BufferedReader;
import java.io.IOException;
public class HttpRequest {
private final RequestLine requestLine;
// private final HttpHeaders httpHeaders;
// private final Body body;
public HttpRequest(BufferedReader br) throws IOException {
this.requestLine = new RequestLine(br.readLine());
}
public boolean isGetRequest() {
return requestLine.isGetRequest();
}
public boolean matchPath(String requestPath) {
return requestLine.matchPath(requestPath);
}
public QueryStrings getQueryStrings() {
return requestLine.getQueryStrings();
}
}
주어진 코드는 HTTP 요청을 나타내는 HttpRequest 클래스를 정의한 것
이 클래스는 HTTP 요청 라인을 파싱하고, 해당 요청에 관련된 정보를 추출하는 데 사용된다.
public class HttpRequest {
private final RequestLine requestLine;
// private final HttpHeaders httpHeaders;
// private final Body body;
이 부분은 HttpRequest 클래스를 정의하고있다
requestLine은 요청 라인을 나타내는 RequestLine 객체를 저장하는 멤버 변수이고
주석 처리된 부분은 헤더 및 본문과 관련된 부분으로, 현재는 주석 처리되어 있어 사용되지 않고 있다.
public HttpRequest(BufferedReader br) throws IOException {
this.requestLine = new RequestLine(br.readLine());
}
이 부분은 HttpRequest 클래스의 생성자이다 생성자는 BufferedReader를 인수로 받아서 HTTP 요청 라인을 읽어와서 RequestLine 객체를 생성하고 초기화한다.
요청 라인은 br.readLine()을 통해 읽어오고
RequestLine 객체는 요청 라인을 파싱하고 HTTP 메서드, URL 경로 및 쿼리 문자열을 추출하여 저장한다.
public boolean isGetRequest() {
return requestLine.isGetRequest();
}
isGetRequest 메서드는 현재 HttpRequest 객체가 GET 요청인지 여부를 확인하는 역할을 한다.
이 메서드는 내부적으로 RequestLine 객체의 isGetRequest 메서드를 호출하여 결과를 반환한다.
public boolean matchPath(String requestPath) {
return requestLine.matchPath(requestPath);
}
matchPath 메서드는 현재 HttpRequest 객체의 URL 경로가 주어진 requestPath와 일치하는지를 확인하는 역할을 한다
이 메서드는 내부적으로 RequestLine 객체의 matchPath 메서드를 호출하여 결과를 반환한다.
public QueryStrings getQueryStrings() {
return requestLine.getQueryStrings();
}
getQueryStrings 메서드는 현재 HttpRequest 객체의 쿼리 문자열을 나타내는 QueryStrings 객체를 반환한다.
이 메서드는 내부적으로 RequestLine 객체의 getQueryStrings 메서드를 호출하여 결과를 반환!
이 HttpRequest 클래스는 HTTP 요청을 파싱하고, 해당 요청과 관련된 정보를 추출하는 데 사용되며
이 정보는 주로 웹 서버나 웹 애플리케이션에서 클라이언트의 요청을 이해하고 처리하는 데 사용된다.
package org.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.DataOutputStream;
import java.io.IOException;
public class HttpResponse {
private static final Logger logger = LoggerFactory.getLogger(HttpResponse.class);
private final DataOutputStream dos;
public HttpResponse(DataOutputStream dos) {
this.dos = dos;
}
public void response200Header(String contentType, int lengthOfBodyContent) {
try {
dos.writeBytes("HTTP/1.1 200 OK \r\n");
dos.writeBytes("Content-Type: " + contentType + ";charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
} catch (IOException e) {
logger.error(e.getMessage());
}
}
public void responseBody(byte[] body) {
try {
dos.write(body, 0, body.length);
dos.flush();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
주어진 코드는 HTTP 응답을 처리하는 HttpResponse 클래스를 정의한 것이며 이 클래스는 HTTP 응답 헤더 및 바디를 작성하고 클라이언트에게 전송하는 데 사용된다.
public class HttpResponse {
private static final Logger logger = LoggerFactory.getLogger(HttpResponse.class);
private final DataOutputStream dos;
이 부분은 HttpResponse 클래스를 정의하고 있고 클래스 내에서 logger 변수는 로깅을 위해 사용되고, DataOutputStream 객체인 dos는 응답을 클라이언트에게 보내는 데 사용된다.
public HttpResponse(DataOutputStream dos) {
this.dos = dos;
}
이 부분은 HttpResponse 클래스의 생성자이다 생성자는 DataOutputStream 객체를 인수로 받아서 HttpResponse 객체를 초기화한다 이렇게 초기화된 HttpResponse 객체는 주어진 DataOutputStream을 사용하여 응답을 클라이언트에게 전송할 수 있다.
public void response200Header(String contentType, int lengthOfBodyContent) {
try {
dos.writeBytes("HTTP/1.1 200 OK \r\n");
dos.writeBytes("Content-Type: " + contentType + ";charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
} catch (IOException e) {
logger.error(e.getMessage());
}
}
response200Header 메서드는 200 OK 응답 헤더를 작성하는 역할을한다
이 메서드는 HTTP 상태 코드, Content-Type 및 Content-Length 헤더를 작성
dos.writeBytes를 사용하여 헤더를 작성하고, 예외 처리를 통해 오류를 처리
이 헤더는 클라이언트에게 요청이 성공했음을 알리고 응답 본문의 속성을 정의
public void responseBody(byte[] body) {
try {
dos.write(body, 0, body.length);
dos.flush();
} catch (IOException e) {
logger.error(e.getMessage());
}
responseBody 메서드는 응답 바디를 작성하는 역할을 한다.
이 메서드는 주어진 바디 데이터를 dos.write를 사용하여 작성하고
dos.flush를 호출하여 버퍼를 비움 이로써 응답 본문이 클라이언트로 전송된다.
HttpResponse 클래스는 HTTP 응답을 작성하고 클라이언트에게 전송하는 데 사용되며, 웹 서버나 웹 애플리케이션에서 클라이언트 요청에 대한 응답을 생성하는 데 유용 이 클래스는 주로 웹 서버에서 사용되며, 클라이언트의 요청에 대해 서버에서 생성된 응답을 클라이언트에게 반환하는 데 활용된다.
package org.example.calculator.tobe;
import org.example.calculator.domain.PositiveNumber;
public class SubtractionOperator implements ArithmeticOperator {
@Override
public boolean supports(String operator) {
return "-".equals(operator);
}
@Override
public int calculate(PositiveNumber operand1, PositiveNumber operand2) {
return operand1.toInt() - operand2.toInt();
}
}
주어진 코드는 뺄셈(-) 연산을 수행하는 SubtractionOperator 클래스를 나타낸다.
이 클래스는 ArithmeticOperator 인터페이스를 구현하여 두 양수(PositiveNumber)를 받아서 뺄셈 연산을 수행
@Override
public boolean supports(String operator) {
return "-".equals(operator);
}
supports 메서드는 주어진 연산자 문자열이 이 연산자(뺄셈)을 지원하는지 여부를 확인하고
연산자 문자열이 "-"와 일치하는 경우만 지원된다고 판단하고 true를 반환.
@Override
public int calculate(PositiveNumber operand1, PositiveNumber operand2) {
return operand1.toInt() - operand2.toInt();
calculate 메서드는 두 양수(PositiveNumber)를 받아서 뺄셈 연산을 수행한다.
operand1과 operand2의 toInt 메서드를 사용하여 각각의 양수를 정수로 변환한 후, 이 값을 뺄셈하여 결과를 반환
이 결과 값은 두 양수를 뺀 값이 된다.
SubtractionOperator 클래스는 두 양수의 뺄셈 연산을 수행하는 클래스로, 주어진 연산자 문자열이 "-"인 경우에만 지원
'JAVA > 웹 애플리케이션' 카테고리의 다른 글
서블릿 프로그래밍 (0) | 2023.11.02 |
---|---|
CGI 프로그램과 서블릿 (0) | 2023.11.02 |
웹 애플리케이션 (1) 개념 (0) | 2023.11.01 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!