2026.04.08
라이브러리는 애플리케이션 개발에 필요한 클래스, 함수 등을 모아 놓은 코드의 모음을 의미함.
라이브러리 장점
개발자가 복잡한 코드를 직접 작성하지 않아서 개발 생산성이 높아짐.
라이브러리 단점
프레임워크는 소프트웨어 개발을 간편하게 만들기 위한 소프트웨어 개발 환경임.
프레임워크는 일하기 위한 틀을 제공함. 개발자는 해당 틀 안에서 개발을 해야함.
프레임워크 장점
프레임워크 단점
프레임워크는 라이브러리들의 모음임.
프레임워크라는 틀 안에서 라이브러리들을 모두 호환 가능하도록 세팅을 해두었기 때문에 개발자는 더 빠르게 비즈니스 로직에 집중하여 빠르게 개발을 진행할 수 있음.
📌 프레임 워크
📌 라이브러리
Spring 프레임워크는 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크임. (간단하게 스프링이라고 부름.)
스프링을 사용하는 이유는 코드로 직접보면 체감할 수 있음.
import java.net.*;
import java.io.*;
public class RawSocketHandler {
public void handleRequest(Socket clientSocket) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream());
try {
String requestLine = in.readLine();
if (requestLine == null) return;
String[] requestParts = requestLine.split(" ");
String method = requestParts[0];
String path = requestParts[1];
String headerLine;
int contentLength = 0;
while ((headerLine = in.readLine()) != null && !headerLine.isEmpty()) {
if (headerLine.startsWith("Content-Length:")) {
contentLength = Integer.parseInt(headerLine.substring(15).trim());
}
}
char[] bodyChars = new char[contentLength];
in.read(bodyChars, 0, contentLength);
String body = new String(bodyChars);
String responseBody = "";
String statusLine = "HTTP/1.1 200 OK";
if ("/api/add".equals(path) && "POST".equals(method)) {
// JSON 파싱 - {"a": 10, "b": 20}
String json = body.replaceAll("[{}\"\\s]", "");
String[] pairs = json.split(",");
int a = 0, b = 0;
for (String pair : pairs) {
String[] keyValue = pair.split(":");
if (keyValue[0].equals("a")) {
a = Integer.parseInt(keyValue[1]);
} else if (keyValue[0].equals("b")) {
b = Integer.parseInt(keyValue[1]);
}
}
int result = a + b;
responseBody = "{\"result\":" + result + "}";
} else if (!"/api/add".equals(path)) {
statusLine = "HTTP/1.1 404 Not Found";
responseBody = "{\"error\":\"Not found\"}";
} else {
statusLine = "HTTP/1.1 405 Method Not Allowed";
responseBody = "{\"error\":\"Method not allowed\"}";
}
out.println(statusLine);
out.println("Content-Type: application/json");
out.println("Content-Length: " + responseBody.length());
out.println("Connection: close");
out.println();
out.print(responseBody);
out.flush();
} catch (Exception e) {
String errorResponse = "{\"error\":\"Server error\"}";
out.println("HTTP/1.1 500 Internal Server Error");
out.println("Content-Type: application/json");
out.println("Content-Length: " + errorResponse.length());
out.println();
out.print(errorResponse);
out.flush();
} finally {
clientSocket.close();
}
}
}import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class SpringCalculator {
@PostMapping("/api/add")
public Map<String, Integer> add(@RequestBody Map<String, Integer> numbers) {
int result = numbers.get("a") + numbers.get("b");
return Map.of("result", result);
}
}이 처럼 스프링은 복잡한 것을 대신 해주는 편리한 도구임!
HTTP는 웹에서 데이터를 주고받기 위한 통신 규약임.
편지를 주고받는 것과 비슷하게, 보내는 사람, 받는 사람, 내용이 정해진 형식으로 전달됨.
HTTP 동작 순서
클라이언트는 Request(요청)을 보내고, 응답을 기다림.
서버는 요청에 대한 처리를 수행 후 결과를 Response(응답)함.
서버는 클라이언트의 상태(State)를 보존하지 않음.
📌 장점
Scale Out 수평 확장성이 높음.
갑자기 요청량이 증가하여도 서버를 증설하기 쉬움.
📌 단점
클라이언트가 데이터를 추가적으로 전송해야함.
📌 한계점
무상태로 설계할 수 없는 경우가 있음.
로그인은 어떻게 해야할까?
HTTP Message는 요청 메세지 , 응답 메세지 두 가지 종류가 있고 구조가 각각 다름.
HTTP Message 구조
GET/event1.1spartacodingclub.kr클라이언트 - 서버 사이에 이루어지는 요청, 응답 데이터를 전송하는 방식을 뜻함.
POST
GET
PUT
PATCH
DELETE
속성으로는 3가지가 있음.
캐시(Cache)란
클라이언트가 서버에 한번 요청했던 데이터에 대해서 매번 요청할 때마다 다시 전송할 필요가 없도록 임시적으로 데이터를 보관하고 있는 장소임.
200 OK : 요청 성공201 Created : 새로운 리소스 생성202 Accepted : 요청이 수신되었으나 데이터 처리가 완료되지 않음204 No Content : 요청은 성공했지만, 응답 데이터가 없음400 Bad Request : 클라이언트가 HTTP 요청 내용을 수정 후 보내야함401 Unauthorized : 클라이언트가 리소스에 대한 인증(Authentication)이 필요함. (로그인같은거)403 Forbidden : 서버가 요청을 받았지만 승인 거부404 Not Found : 요청한 리소스가 서버에 없음. (이것을 이요해서 리소스를 숨겨놓기도 함. 있는데 없는척 가능)500 Internal Server Error : 대부분 500으로 처리함503 Service Unavailable : 서비스 이용 불가API (Application Programming Interface) 는 프로그램끼리 대화하는 방법임.
클라이언트와 서버는 Interface의 명세대로만 통신하는 것이 바로 API임.
REST는 서버 구현을 알지 못하는 클라이언트가 API를 잘 이용할 수 있을지에 대한 고민의 결과임. (그래서 반드시 지켜야하는 규칙은 아님.)
1. 동사보단 명사를, 단수보단 복수를
❌ /member/get/item/hello
✅ /members/items
2. 마지막에 / 넣지 않기
❌ /members/
✅ /members
3. _ 대신 - 사용 + 대문자 사용하지 않기
❌ /restful_services
✅ /restful-services
4. 확장자 포함하지 않기(svg, png, exe 등)
❌ /image.svg
✅ /images
5. 계층화 하기
❌ /items/{memberId}/members/{itemId} (x)
✅ /members/{memberId}/items/{itemId}
설명이 어려워서 예시로 확인하는게 쉬움.
대표적인 예시로 인터페이스에서 봤던 @Override 가 있음.
public interface Mouse {
void leftClick();
void rightClick();
void scrollWheel();
}
public class LogitechMouse implements Mouse {
@Override
public void leftClick() {
// 로지텍 좌클릭 로직 구현
}
@Override
public void rightClick() {
// 로지텍 우클릭 로직 구현
}
@Override
public void scrollWheel() {
// 로지텍 스크롤휠 로직 구현
}
}
간단하게 정리하면 어노테이션을 활용하면 복잡한 기능도 쉽게 사용할 수 있음!
롬복은 게터나 세터같은 메서드들을 작성하지 않고 어노테이션으로 코드의 가독성이나 유지보수성을 높여줌. 눈으로 보기에도 코드가 깔끔해짐!!
@getter @setter
이 녀석이 코드가 가장 보기 싫게 만들어주는 듯. 게터와 세터를 하나씩 메서드를 작성하지 않고 속성부분 위에 어노테이션을 달아주면 자동으로 게터와 세터를 생성해서 사용할 수 있게 만들어줌.
@ToString
이녀석은 객체를 String으로 변환해주는 역할을 하는데 자동으로 toString() 메서드를 자동으로 생성해줌.
@NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor
@NoArgsConstructor 이것은 기본 생성자를 생성해줌.
@AllArgsConstructor 이건 모든 필드를 매개변수로 하는 생성자를 생성해줌.
@RequiredArgsConstructor 이건 필수(final) 필드만을 매개변수로 하는 생성자를 생성해줌.
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
}
@Slf4j
이 녀석은 클래스에 로그를 남기기 위한 Logger 객체를 자동으로 생성해줌.
@Slf4j
public class UserService {
public void logMessage() {
log.info("This is a log message");
}
}
Spring Initializr(스프링 이니셜라이저)는 스프링 부트 기반의 프로젝트를 쉽고 빠르게 생성할 수 있도록 도와주는 웹 기반 도구 및 서비스임.
근데 이건 인텔리제이 유료버전을 사용하는 나에게는 필요 없음 ㅋ
스프링 프로젝트를 만드는 법은 우선 인텔리제이 유료버전을 키고 새로운 프로젝트 생성을 해줌.

왼쪽에 자바가 아닌 스프링 부트를 선택하고 이름이나 언어 타입 등은 사진이랑 똑같이 맞춰줌.
그리고 다음 누르고,

Lombok 이랑 Spring Web 추가 해주고 만들어주면 끝~!
여기서 Lombok 이랑 Spring Web을 추가 한 것이 의존성임!
이 의존성을 이미 만들어진 프로젝트에 추가 할 수도 있음. 예를 들어서 SpringDoc OpenAPI Starter WebMVC UI 라는 라이브러리를 의존성에 추가 하고 싶다고 한다면
https://mvnrepository.com/
이 사이트로 들어가서 SpringDoc OpenAPI Starter WebMVC UI 이걸 검색해줌.

클릭해서 들어가면 버전을 선택할 수 있는게 뜸.

여기서 가장 최신 버전을 눌러서 들어가보면

Gradle을 선택해서 나오는 URL을 복사해서
인텔리제이 스프링 프로젝트에 build.gradle 안에 이렇게 붙여넣기 해주면 됨!

그럼 오른쪽 위에 코끼리가 뜸!!

이 코끼리를 눌러면 끝! (코끼리를 꼭 눌러줘야 의존성에 추가가됨.)
서블릿은 서버에서 실행되서 클라이언트의 요청을 처리하고, 그 결과를 동적으로 생성하여 응답하는 자바 프로그램임.
즉, 정적인 데이터가 아니라, 요청에 따라 다른 결과를 만들어내는 똑똑한 자바 클래스!
jakarta.servlet.http.HttpServlet 클래스를 상속받아 구현그냥 만든 서블릿 클래스는 스스로 실행 될 수 없기 때문에 이 서블릿을 실행하고 관리하고 웹 서버랑 통신하게 해주는 전문적인 환경이 서블릿 컨테이너임!
대표적인 서블릿 컨데이넉가 톰캣(Tomcat)임.
이 과정에서 개발자가 하는 일은 Request 객체에서 요청 정보를 꺼내 비지니스 로직을 수행하고 Response 객체를 만들기

앞에서 만들었던 프로젝트에서 사진과 같은 경로로 HelloServlet 클래스를 만들어주고 아래 코드를 복붙해줌.
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 요청 정보는 필요없으므로 요청 정보를 꺼내지는 않습니다.
// 비즈니스 로직 또한 따로 없으므로 작성하지 않습니다.
resp.setContentType("text/plain; charset=UTF-8"); // 응답 정보 타입 설정
resp.getWriter().print("hello"); // Response 객체에 응답 정보인 'hello'를 담아줍니다.
}
}
그리고 메인 클래스에 @ServletComponentScan 이걸 넣어줌.

그리고 프로그램을 실행해보면

알 수 없는 요상한게 뜸.
여기서 포스트맨을 사용해서 열어볼거임!
포스트맨에서 새로운 컬렉션 생성해주고 hello라고 만들었음.
그 안에 add request 눌러서 자동으로 조회할 수 있는 API가 만들어짐 거기에 기본으로 설정되있는 아래 주소를 넣고
http://localhost:8080
뒤에 /hello를 붙여서

이렇게 넣어줌.
그러고 저장하고 Send 누르면

이렇게 hello가 잘 나오는 걸 볼 수 있음!
레스토랑을 예시로 다시 설명을 해보자면 손님이 클라이언트, 주방이 서버 인데 손님이 주문을 하려면 메뉴판이 있어야함.
이때 API 명세서가 메뉴판의 역할임. (API 문서라고도 함.)
API 명세서 작성
| API | Parameters | Request Body | Response | Status |
|---|---|---|---|---|
GET /movies/recommendation | - | - | { “title”: “쇼생크 탈출” } | 200 |
코드 작성
import tools.jackson.databind.ObjectMapper;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@WebServlet("/movies/recommendation")
public class MovieRecommendationServlet extends HttpServlet {
private final List<String> recommendedMovies = List.of(
"쇼생크 탈출",
"대부",
"다크 나이트",
"인생은 아름다워"
);
// 1. Map을 JSON으로 바꾸기 위해 필요한 ObjectMapper를 생성합니다.
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 2. 랜덤으로 영화 하나를 선택합니다.
int randomIndex = (int) (Math.random() * recommendedMovies.size());
String randomMovie = recommendedMovies.get(randomIndex);
Map<String, String> movieMap = Map.of("title", randomMovie);
// 3. 응답 속성을 설정합니다.
response.setContentType("application/json; charset=UTF-8");
// 4. ObjectMapper를 사용해 JSON 문자열로 변환합니다.
String json = objectMapper.writeValueAsString(movieMap);
// 5. 생성된 JSON을 클라이언트에게 응답으로 보냅니다.
response.getWriter().print(json);
}
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
이렇게 코드를 넣어주고 포스트맨으로 가서 테스트 해보겠음.
주소 입력 칸에는
http://localhost:8080/movies/recommendation
이렇게 넣어주고 실행을 시켜보면 랜덤으로 저장된 영화 이름이 뜨는걸 볼 수 있음.
