1. 서블릿(Servlet)이란?
서블릿이란 자바 어플리케이션에서 클라이언트의 요청을 처리하고 응답을 반환하는 역할을 하는 서버 측의 프로그램 형식이다. 주로 HTTP 요청/응답 처리를 할 때 사용을 하며, Spring MVC구조의 Controller 역할이라고 생각하면 된다.
Spring MVC는 DispatcherServlet을 사용하기에 별도의 Servlet 처리를 하지 않아도 HTTP 통신 및 엔드포인트 사용이 가능하지만 Spring MVC 환경이 아닌 그냥 이클립스 환경에서는 Servlet을 사용하여 구성해 주어야 HTTP 통신이 가능해진다.
2. 서블릿(Servlet)의 동작 원리
서블릿의 동작 원리 및 순서는 아래와 같다.
- 웹 브라우저(클라이언트)에서 웹 서버에 요청을 한다.
- 웹 서버는 요청을 받아 서블릿 컨테이너로 전달한다.
- 서블릿 컨테이너에서는 라이프싸이클을 관리하며, 요청을 전달 받은 후 생성, 처리, 응답, 소멸 등의 라이프싸이클을 통해 요청을 처리한다.
- 처리한 요청에 대한 응답 데이터를 웹 서버로 전달하고 이를 다시 웹 브라우저(클라이언트)로 전송한다.
서블릿은 HttpServlet 클래스를 상속받은 후 사용하며, 주로 아래와 같은 메서드를 오버라이드 하여 사용한다.
- doGet() : GET 요청 처리
- doPost() : POST 요청 처리
- init() : 서블릿이 초기화 될 때 호출
- destroy() : 서블릿이 소멸될 때 호출
3. 서블릿(Servlet)의 특징
그냥 Spring 사용하면 되지 저걸 왜 사용하냐라고 할 수도 있다. 하지만 사용하기에 따라 서블릿은 유용한 기술이라 생각된다. 예로 서블릿 서비스를 하나 구성하고 톰캣 서버와 JDK를 설치한 뒤 톰캣 서버만 구동하면 바로 JAVA 언어의 HTTP 통신을 사용할 수 있다.
이는 확장성 및 접근성이 좋고 쉬우며, 서블릿 자체가 서버 측에서 실행되기에 처리 속도 또한 클라이언트에 비해 상대적으로 빠르고 효율적이다. 특히, 해당 서버에 JDK와 톰캣만 설치하면 운영체제, 환경, 언어에 종속되지 않고 사용할 수 있다는게 정말 강력한 특징이자 장점으로 생각된다.
4. 서블릿(Servlet) 구현
간단하게 서블릿을 구현해보자. 우선 Eclipse에서 Dynamic Web Project를 생성해 준다.
다음에 아래와 같이 ServletManager 클래스를 간단하게 작성해 준다. String과 JSON으로 각각 요청이 들어왔을 때의 처리 방법을 예시의 샘플 코드로 작성해 보았다.
package comm;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
@WebServlet("/commServlet")
public class test extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet 으로 Class 및 method 호출 성공 => GET");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("GET 통신 성공");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet 으로 Class 및 method 호출 성공 => POST");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// String 형태로 요청이 들어올 때 ex. parameter1=HELLO¶meter2=WORLD
String test1 = request.getParameter("parameter1");
String test2 = request.getParameter("parameter2");
String result = test1 + test2;
out.print(result);
// <--------------------------------------------------------------------------------------------->
// JSON 형태로 요청이 들어올 때
BufferedReader br = null;
String line = "";
String comm = "";
String test1 = "";
String test2 = "";
String result = "";
JSONObject jsonObject2 = new JSONObject();
try {
if(request.getInputStream() != null) {
br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
comm = sb.toString();
}else {
System.out.println("Data 없음");
}
System.out.println("JSON DATA : " + comm);
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject1 = (JSONObject)jsonParser.parse(comm);
test1 = jsonObject1.get("parameter1").toString();
test2 = jsonObject1.get("parameter2").toString();
result = test1 + " " + test2;
jsonObject2.put("result", result);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.print(jsonObject2);
}
}
여기서 사용된 서블릿 관련 코드를 알아보자
첫 번째로 @WebServlet 어노테이션은 구현하려는 서블릿의 엔드포인트를 설정해 주는 것으로 생각하면 된다.
두 번째로 doGet, doPost 메서드를 HttpServlet에서 상속받아 작성해 준다. 메서드 이름과 같이 각각 GET 통신, POST 통신을 하기 위해 선언하는 것이다.
추가로 필수적인 요소는 아니지만 나는 테스트용 클라이언트를 NextJS로 구성할 예정이기에 통신을 진행하면 CORS 오류가 발생할 수도 있다. 그렇기에 CORSFilter 클래스를 추가로 작성하여 적용해 주자.
package comm;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, origin, content-type, accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
만일 통신 중 CORS 오류가 발생되면 위에 작성한 CORSFilter 클래스를 적용하여 사용해 주면 된다.
다음으로 web.xml을 설정해 준다. WEB-INF 디렉터리에 web.xml 파일을 생성해 주고 아래와 같이 작성해 준다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>comm.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>commServlet</servlet-name>
<servlet-class>comm.ServletManager</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>commServlet</servlet-name>
<url-pattern>/commServlet/*</url-pattern>
</servlet-mapping>
</web-app>
앞서 작성한 ServletManager 클래스와 CORSFilter 클래스를 추가하고 각각의 name과 매핑할 엔드포인트를 작성해 준다. 여기까지 작성하면 서블릿 구현은 끝난 것이다. 이제 해당 프로젝트를 톰캣을 통해 구동시켜 주자
1. 서버 탭에서 create a new server 클릭
2. apache에서 9.0 버전으로 진행
3. 프로젝트 추가 후 서버 구동 완료
이제 NextJS를 통해 간단하게 클라이언트단을 작성하여 통신 테스트를 해보자
'use client'
import { useState } from "react";
import axios from "axios";
const Home = () => {
const [result, setResult] = useState<string>("");
const handleClick = () => {
axios({
method: "GET",
url: 'http://localhost:8080/ServletTest/commServlet'
}).then((res):void => {
console.log(res.data);
setResult(res.data);
}).catch((err):void => {
console.log(err.message);
});
}
return (
<div>
<div>
<button onClick={() => handleClick()}>TEST</button>
</div>
<div>
{result}
</div>
</div>
);
}
export default Home;
통신 호출은 http://localhost:8080/{프로젝트명}/{엔드포인트} 으로 설정하여 테스트를 진행한다.
버튼 클릭 시 doGet에 설정했던 "GET 통신 완료" 메시지를 확인할 수 있다.
또한, CORSFilter를 통해 CORS 오류가 발생되지 않는 걸 확인할 수 있다.
POST로 통신할 때는 앞서 서블릿에 작성한 request.getParameter에 맞게끔 전송할 데이터를 세팅하여 통신한다.
&기호로 구분하여 request.getParameter에 명시된 값에 맞게끔 데이터를 세팅해 준다.
'use client'
import { useState } from "react";
import axios from "axios";
const Home = () => {
const [result, setResult] = useState<string>("");
const handleClick = () => {
const send:string = "test1=HELLO-&test2=WORLD"; // 전송할 데이터 세팅
axios({
method: "POST",
url: 'http://localhost:8080/ServletTest/commServlet',
data: send // 전송
}).then((res):void => {
console.log(res.data);
setResult(res.data);
}).catch((err):void => {
console.log(err.message);
});
}
return (
<div>
<div>
<button onClick={() => handleClick()}>TEST</button>
</div>
<div>
{result}
</div>
</div>
);
}
export default Home;
POST 통신 또한 정상적으로 진행되는 것을 확인할 수 있다.
'JAVA' 카테고리의 다른 글
[JAVA] 이메일 인증 구현하기 (0) | 2024.07.19 |
---|---|
[JAVA] HttpURLConnection, HttpClient 사용하기 (0) | 2024.07.08 |
[JAVA] 공공데이터 오픈 API 사용하기 (0) | 2024.06.25 |