반응형

DBCP(Database Connection Pooling)란 무엇인가?

**DBCP(Database Connection Pooling)**는 데이터베이스 연결을 효율적으로 관리하기 위해 사용되는 기술입니다. 데이터베이스와의 연결은 생성과 종료 시 큰 비용이 소모되는데, DBCP는 연결을 미리 생성해두고 재사용함으로써 성능을 향상시킵니다.


왜 DBCP가 필요한가?

  1. 성능 향상:
    • 매번 새로운 연결을 생성하는 비용을 절감합니다.
  2. 리소스 관리:
    • 일정 개수 이상의 연결 생성을 방지하여 데이터베이스 과부하를 방지합니다.
  3. 스레드 안전성:
    • 다중 스레드 환경에서도 안전하게 연결을 관리합니다.

HikariCP란?

HikariCP는 자바에서 가장 널리 사용되는 고성능 커넥션 풀 라이브러리입니다. 속도와 효율성이 뛰어나고 설정이 간단하다는 장점이 있습니다.

주요 특징:

  1. 가볍고 빠름: 낮은 대기 시간과 높은 처리량을 제공합니다.
  2. 효율적인 자원 관리: 연결 누수를 감지하고 빠르게 복구합니다.
  3. 유연한 설정: 다양한 설정 옵션으로 요구 사항에 맞는 커넥션 풀을 구성할 수 있습니다.

HikariCP를 이용한 자바 구현 예제

1. Maven 의존성 추가

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>

2. HikariCP 설정과 데이터베이스 연결

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class HikariCp {
    private static HikariDataSource dataSource;

    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mariadb://localhost:3306/dbname");
        config.setUsername("username");
        config.setPassword("userpwd");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.setMinimumIdle(5);
        config.setMaximumPoolSize(10);

        dataSource = new HikariDataSource(config);
    }

    private HikariCp() {
    }

    public static DataSource getDataSource() {
    	return dataSource;
    }

    public static Connection getConnection() throws SQLException {
    	return dataSource.getConnection();
    }

    public static void main(String[] args) {
        String query = "SELECT * FROM users WHERE id = ?";

        try (Connection connection = HikariCp.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(query)) {

            preparedStatement.setInt(1, 1);
            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                System.out.println("User ID: " + resultSet.getInt("id"));
                System.out.println("Username: " + resultSet.getString("username"));
            }

        } catch (SQLException e) {
	        e.printStackTrace();
        }
    }
}

3. 주요 설정 옵션

  • setJdbcUrl: 데이터베이스 URL 설정.
  • setUsername: 데이터베이스 사용자 이름.
  • setPassword: 데이터베이스 비밀번호.
  • setMinimumIdle: 유지할 최소 유휴 연결 수.
  • setMaximumPoolSize: 커넥션 풀에서 허용하는 최대 연결 수.
  • addDataSourceProperty: 데이터베이스 연결 속성 추가.

활용 예시

1. 사용자 인증 시스템

  • 로그인 요청 시 사용자 정보를 데이터베이스에서 빠르게 조회.

2. 대용량 데이터 처리

  • 다중 스레드 환경에서 데이터 분석 작업 수행.

3. 실시간 데이터 처리

  • 대기 시간이 중요한 실시간 애플리케이션에서 안정적인 데이터베이스 연결 제공.

결론

HikariCP를 활용한 DBCP는 자바 애플리케이션에서 데이터베이스 연결을 효율적으로 관리하는 데 필수적인 기술입니다. 간단한 설정으로 강력한 성능을 제공하며, 안정성과 확장성을 동시에 만족시킵니다. HikariCP를 프로젝트에 적용하여 더 나은 성능과 자원 관리를 경험해보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Spring] @Controller와 @RestController의 차이  (0) 2025.02.10
[Spring] IoC & DI  (0) 2025.02.04
[Java] Servlet Filter  (0) 2025.01.16
[Java] JSON  (0) 2025.01.16
[Java] HTTP 요청 처리하기  (0) 2025.01.16
반응형

Servlet Filter: 개념과 활용

Servlet Filter는 웹 애플리케이션에서 HTTP 요청 및 응답을 가로채 특정 작업을 수행할 수 있는 기능을 제공합니다. 주로 요청 데이터 검증, 응답 수정, 로깅, 인증 및 권한 검사 등에 사용됩니다.


Servlet Filter란?

주요 특징:

  1. 요청 및 응답 처리: 클라이언트 요청 전/후, 서블릿 호출 전/후에 작업 수행.
  2. 재사용 가능: 여러 서블릿에 동일한 필터를 적용 가능.
  3. 체이닝: 여러 필터를 순서대로 연결하여 처리 가능.

동작 흐름:

  1. 클라이언트가 요청을 보냄.
  2. 필터가 요청을 가로채고 처리.
  3. 필터 체인이 끝나면 서블릿으로 요청 전달.
  4. 서블릿에서 응답을 생성하여 필터 체인으로 반환.
  5. 필터가 응답을 처리하고 클라이언트로 반환.

자바에서 Servlet Filter 구현

1. 필터 인터페이스 구현

Servlet Filter를 구현하려면 javax.servlet.Filter 인터페이스를 구현해야 합니다.

예시: 로그인 인증 필터

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AuthenticationFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    // 초기화 작업 (필요 시 구현)
    }

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

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 세션에서 로그인 정보 확인
        if (httpRequest.getSession().getAttribute("user") == null) {
        	// 로그인되지 않은 경우 로그인 페이지로 리다이렉트
	        httpResponse.sendRedirect("/login.jsp");
        } else {
        	// 로그인된 경우 요청을 다음 필터나 서블릿으로 전달
    	    chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
    // 자원 정리 작업 (필요 시 구현)
    }
}

2. web.xml에 필터 등록

필터를 서블릿 컨테이너에 등록하고 URL 패턴을 매핑합니다.

<filter>
	<filter-name>AuthenticationFilter</filter-name>
	<filter-class>com.example.AuthenticationFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3. 애너테이션 기반 등록 (대체 방식)

Servlet 3.0 이상에서는 @WebFilter 애너테이션을 사용하여 필터를 등록할 수 있습니다.

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "AuthenticationFilter", urlPatterns = {"/protected/*", "/admin/*"})
public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        if (httpRequest.getSession().getAttribute("user") == null) {
	        httpResponse.sendRedirect("/login.jsp");
        } else {
    	    chain.doFilter(request, response);
        }
    }
}

이름 및 URL 패턴 지정 이유

필터 이름 지정:

  • 필터 이름(filterName)은 필터를 식별하는 데 사용됩니다. 프로젝트가 커지고 여러 필터를 사용할 때 유지보수성과 가독성을 높이기 위해 필수적입니다.

URL 패턴 지정:

  • urlPatterns는 필터를 적용할 경로를 지정합니다. 특정 요청에만 필터를 적용하여 불필요한 작업을 줄이고 성능을 최적화할 수 있습니다.
    • 예: /protected/*protected 디렉토리 아래의 모든 요청에 필터를 적용합니다.
    • 예: /admin/*는 관리자 전용 URL에만 필터를 적용하여 권한 관리를 강화합니다.

 


로그인 필터의 활용 시나리오

  1. 로그인 검증:
    • 사용자 요청이 들어올 때 세션을 확인하여 로그인 여부를 검증.
    • 로그인되지 않은 사용자를 로그인 페이지로 리다이렉트.
  2. 로깅:
    • 요청 및 응답의 메타데이터를 기록하여 디버깅 및 감사용 로그 생성.
  3. 권한 확인:
    • 사용자의 역할(Role)을 확인하여 권한 없는 요청 차단.

권한 확인 필터 예시:

if (httpRequest.getSession().getAttribute("role") == null ||
!httpRequest.getSession().getAttribute("role").equals("ADMIN")) {
    httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
    return;
}

결론

Servlet Filter는 요청과 응답을 가로채서 처리할 수 있는 강력한 도구입니다. 이를 활용하면 인증, 권한 검사, 로깅 등 다양한 작업을 중앙화하여 효율적인 웹 애플리케이션 관리가 가능합니다. 자바에서 Servlet Filter를 구현하여 깔끔하고 확장 가능한 코드를 작성해 보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Spring] IoC & DI  (0) 2025.02.04
[Java] DBCP  (0) 2025.01.16
[Java] JSON  (0) 2025.01.16
[Java] HTTP 요청 처리하기  (0) 2025.01.16
[Java] SQL Injection  (1) 2025.01.10
반응형

JSON: 개념과 활용, 그리고 자바와 자바스크립트에서의 사용법

JSON(JavaScript Object Notation)은 가볍고, 인간과 기계가 모두 읽기 쉬운 데이터 교환 형식입니다. 데이터를 키-값 쌍으로 표현하며, 주로 서버와 클라이언트 간 데이터 교환에 사용됩니다. 이번 글에서는 JSON의 개념, 구조, 자바스크립트와 자바에서 JSON을 다루는 방법을 살펴보겠습니다.


JSON이란 무엇인가?

JSON의 주요 특징:

  1. 간결성: 데이터를 표현하는 간단한 형식.
  2. 가독성: 사람과 기계가 쉽게 읽을 수 있음.
  3. 언어 독립적: 모든 프로그래밍 언어에서 사용 가능.

JSON 예제:

{
    "name": "John Doe",
    "age": 30,
    "isMarried": false,
    "children": ["Anna", "Billy"],
    "address": {
        "street": "123 Main St",
        "city": "New York"
    }
}

자바스크립트에서 JSON 다루기

1. JSON 문자열 생성

const jsonData = {
    name: "John Doe",
    age: 30,
    isMarried: false,
    children: ["Anna", "Billy"],
    address: {
        street: "123 Main St",
        city: "New York"
    }
};

// 객체를 JSON 문자열로 변환
const jsonString = JSON.stringify(jsonData);
console.log(jsonString);

2. JSON 문자열을 객체로 변환

const jsonString = '{"name":"John Doe","age":30}';

// JSON 문자열을 객체로 변환
const jsonObject = JSON.parse(jsonString);
console.log(jsonObject.name); // "John Doe"

3. JSON 데이터 보내고 받기 (AJAX 사용)

// 데이터 전송
fetch("https://example.com/api", {
    method: "POST",
    headers: {
	    "Content-Type": "application/json"
    },
    body: JSON.stringify({ name: "John Doe", age: 30 })
})
.then(response => response.json())
.then(data => console.log(data));

자바에서 JSON 다루기

자바에서는 Jackson Databind 라이브러리를 주로 사용하여 JSON 데이터를 처리합니다.

1. 의존성 추가 (Maven):

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.14.0</version>
</dependency>

2. JSON을 자바 객체로 변환

JSON 문자열:

{
    "name": "John Doe",
    "age": 30,
    "isMarried": false
}

자바 클래스:

public class Person {
    private String name;
    private int age;
    private boolean isMarried;

    // Getters and Setters
    public String getName() {
	    return name;
    }
    public void setName(String name) {
    	this.name = name;
    }
    public int getAge() {
    	return age;
    }
    public void setAge(int age) {
    	this.age = age;
    }
    public boolean isMarried() {
    	return isMarried;
    }
    public void setMarried(boolean married) {
    	isMarried = married;
    }
}

JSON을 객체로 변환:

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonToObjectExample {
    public static void main(String[] args) {
        String jsonString = "{\"name\":\"John Doe\",\"age\":30,\"isMarried\":false}";

        ObjectMapper objectMapper = new ObjectMapper();

        try {
            Person person = objectMapper.readValue(jsonString, Person.class);
            System.out.println("Name: " + person.getName());
            System.out.println("Age: " + person.getAge());
            System.out.println("Is Married: " + person.isMarried());
        } catch (Exception e) {
	        e.printStackTrace();
        }
    }
}

3. 자바 객체를 JSON으로 변환

import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectToJsonExample {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John Doe");
        person.setAge(30);
        person.setMarried(false);

        ObjectMapper objectMapper = new ObjectMapper();

        try {
            String jsonString = objectMapper.writeValueAsString(person);
            System.out.println("JSON String: " + jsonString);
        } catch (Exception e) {
	        e.printStackTrace();
        }
    }
}

JSON 데이터와 자바 클래스 매핑

복잡한 JSON 구조 예:

{
    "name": "John Doe",
    "age": 30,
    "children": ["Anna", "Billy"],
    "address": {
        "street": "123 Main St",
        "city": "New York"
    }
}

자바 클래스:

import java.util.List;

public class Person {
    private String name;
    private int age;
    private List<String> children;
    private Address address;

    // Getters and Setters
    // ...
}

class Address {
private String street;
private String city;

// Getters and Setters
// ...
}

결론

JSON은 간결하고 효율적인 데이터 교환 형식으로, 자바스크립트와 자바에서 쉽게 사용할 수 있습니다. Jackson 라이브러리를 활용하면 JSON 데이터를 객체로 변환하거나 객체를 JSON으로 변환하는 작업을 간단히 처리할 수 있습니다. 이를 통해 서버-클라이언트 간 데이터 교환을 더욱 효율적으로 관리해 보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] DBCP  (0) 2025.01.16
[Java] Servlet Filter  (0) 2025.01.16
[Java] HTTP 요청 처리하기  (0) 2025.01.16
[Java] SQL Injection  (1) 2025.01.10
[Java] 서블릿(Servlet)  (0) 2025.01.08
반응형

자바로 HTTP 요청 처리하기: GET, POST, HEADER 예제

HTTP 통신은 현대 애플리케이션에서 서버와 클라이언트 간 데이터 교환의 핵심입니다. 자바에서는 표준 라이브러리와 외부 라이브러리를 활용하여 HTTP 요청을 쉽게 처리할 수 있습니다. 이번 글에서는 HTTP GET, POST, HEADER를 사용하는 방법과 예제를 소개합니다.


HTTP 요청의 주요 메서드

  1. GET: 서버에서 데이터를 가져오는 데 사용.
  2. POST: 서버에 데이터를 전송하는 데 사용.
  3. HEADER: 요청 헤더를 통해 부가 정보를 서버에 전달.

1. GET 요청

HttpClient를 이용한 GET 요청:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpGetExample {
    public static void main(String[] args) {
        try {
            String url = "https://jsonplaceholder.typicode.com/posts/1";

            HttpClient client = HttpClient.newHttpClient();
            HttpRequest httpRequest = HttpRequest.newBuilder()
                                        .uri(URI.create(url))
                                        .GET()
                                        .build();

            HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

            System.out.println("Response Code: " + httpResponse.statusCode());
            System.out.println("Response Body: " + httpResponse.body());
        } catch (Exception e) {
	        e.printStackTrace();
        }
    }
}

출력 결과: JSON 데이터를 포함한 서버 응답.


2. POST 요청

HttpClient를 이용한 POST 요청:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpPostExample {
    public static void main(String[] args) {
        try {
            String url = "https://jsonplaceholder.typicode.com/posts";
            String body = "{"title": "foo", "body": "bar", "userId": 1}";

            HttpClient client = HttpClient.newHttpClient();
            HttpRequest httpRequest = HttpRequest.newBuilder()
                                        .uri(URI.create(url))
                                        .header("Content-Type", "application/json")
                                        .POST(HttpRequest.BodyPublishers.ofString(body))
                                        .build();

            HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

            System.out.println("Response Code: " + httpResponse.statusCode());
            System.out.println("Response Body: " + httpResponse.body());
        } catch (Exception e) {
	        e.printStackTrace();
        }
    }
}

출력 결과: 서버에 전송된 데이터와 응답 메시지.


3. HEADER 추가하기

HttpClient를 이용하여 헤더 추가:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpHeaderExample {
    public static void main(String[] args) {
        try {
            String url = "https://jsonplaceholder.typicode.com/posts/1";

            HttpClient client = HttpClient.newHttpClient();
            HttpRequest httpRequest = HttpRequest.newBuilder()
                                        .uri(URI.create(url))
                                        .header("Authorization", "Bearer token123")
                                        .GET()
                                        .build();

            HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

            System.out.println("Response Code: " + httpResponse.statusCode());
            System.out.println("Response Body: " + httpResponse.body());
        } catch (Exception e) {
	        e.printStackTrace();
        }
    }
}

출력 결과: 헤더를 포함한 요청에 대한 서버 응답.


결론

자바에서는 기본 API인 HttpClient를 활용하여 간단하고 직관적으로 HTTP 요청을 처리할 수 있습니다. GET, POST, HEADER를 적절히 활용하여 애플리케이션의 요구 사항을 충족해 보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] Servlet Filter  (0) 2025.01.16
[Java] JSON  (0) 2025.01.16
[Java] SQL Injection  (1) 2025.01.10
[Java] 서블릿(Servlet)  (0) 2025.01.08
[Java] 계층형 아키텍처 패턴 (Layered Architecture Pattern)  (0) 2025.01.07
반응형

SQL Injection: 개념과 방어 방법

SQL Injection은 사용자가 입력한 데이터를 통해 데이터베이스에 비정상적인 SQL 쿼리를 주입하는 보안 취약점 공격입니다. 이를 통해 공격자는 데이터베이스의 민감한 데이터를 조회, 수정, 삭제하거나 시스템에 대한 제어권을 얻을 수 있습니다.

이 글에서는 SQL Injection의 개념과 바이패스 방법, 그리고 이를 방어하는 다양한 기법을 자바 예제와 함께 설명하겠습니다.


SQL Injection이란?

SQL Injection은 주로 다음과 같은 방식으로 발생합니다:

  • 입력값을 SQL 쿼리 문자열에 그대로 삽입하여 실행.
  • 쿼리의 논리를 변조하여 의도하지 않은 결과를 유도.

예시: 취약한 코드

String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';";

공격자가 usernameadmin' --를 입력하면 쿼리는 다음과 같이 변조됩니다:

SELECT * FROM users WHERE username = 'admin' -- ' AND password = '';

--는 SQL에서 주석 처리를 의미하므로 비밀번호 조건이 무시됩니다.


SQL Injection 바이패스 방법

SQL Injection 바이패스는 데이터베이스의 입력 검증과 로직을 우회하여 공격하는 기법입니다.

바이패스 방법 예시:

  1. 논리 우회:
    • 입력값에 논리 연산자(OR 1=1)를 삽입하여 조건을 항상 참으로 만듦.
    • 예: username=admin' OR 1=1 --
  2. 유효성 검사 우회:
    • 특수문자, 인코딩 기법을 활용하여 필터링 로직을 우회.
    • 예: admin' OR '1'='1 (문자열 비교 이용).
  3. 스키마 정보 노출:
    • UNION 쿼리를 사용하여 추가적인 데이터베이스 정보를 조회.
    • 예: admin' UNION SELECT null, username, password FROM users --

SQL Injection 방어 방법

SQL Injection을 방지하기 위해 다음 기법을 사용할 수 있습니다.

1. 입력값 검증

입력값을 철저히 검증하여 예상치 못한 입력을 필터링합니다.

예제:

String username = request.getParameter("username");
String sanitizedUsername = username.replaceAll("[^a-zA-Z0-9]", "");

2. SQL 로직 검증

SQL 쿼리 작성 시 논리적 오류가 발생하지 않도록 구조를 점검합니다.

예제:

if (username.contains("'") || password.contains("'")) {
	throw new IllegalArgumentException("Invalid characters in input");
}

3. Prepared Statement 사용

Prepared Statement는 파라미터화된 쿼리를 사용하여 SQL Injection 공격을 원천적으로 차단합니다.

Statement와의 차이점:

  • Statement: 쿼리와 데이터를 결합하여 실행.
  • Prepared Statement: 쿼리와 데이터를 분리하여 처리.

취약한 Statement 예제:

Statement stmt = connection.createStatement();
String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';";
ResultSet rs = stmt.executeQuery(query);

안전한 Prepared Statement 예제:

String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();

4. ORM (Object-Relational Mapping) 사용

JPA, Hibernate 같은 ORM 프레임워크를 사용하여 SQL 쿼리를 직접 작성하지 않고 객체 지향적으로 데이터베이스와 상호작용.

예제:

@Entity
public class User {
    @Id
    private Long id;
    private String username;
    private String password;
}

public User findByUsernameAndPassword(String username, String password) {
    return entityManager.createQuery(
    "SELECT u FROM User u WHERE u.username = :username AND u.password = :password", User.class)
    .setParameter("username", username)
    .setParameter("password", password)
    .getSingleResult();
}

마무리: SQL Injection 방어의 중요성

SQL Injection은 잘못된 입력값 처리를 통해 발생하는 심각한 보안 취약점입니다. 이를 방지하려면 입력값 검증, 로직 점검, 그리고 Prepared Statement와 같은 안전한 프로그래밍 기법을 활용해야 합니다. 보안을 염두에 두고 코드를 작성하는 습관을 들여 안전한 애플리케이션을 개발하세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] JSON  (0) 2025.01.16
[Java] HTTP 요청 처리하기  (0) 2025.01.16
[Java] 서블릿(Servlet)  (0) 2025.01.08
[Java] 계층형 아키텍처 패턴 (Layered Architecture Pattern)  (0) 2025.01.07
[Java] MVC 패턴  (1) 2025.01.07
반응형

서블릿(Servlet)

**서블릿(Servlet)**은 자바 기반 웹 애플리케이션에서 클라이언트의 요청을 처리하고 동적 콘텐츠를 생성하는 서버 측 컴포넌트입니다. HTTP 프로토콜을 기반으로 하며, Java Servlet API를 통해 동작합니다. 주로 HTML, JSON, XML 등의 응답을 생성하여 클라이언트에 반환합니다.

이 글에서는 서블릿의 개념과 함께 클라이언트에서 데이터를 보내고 받는 방법, 그리고 서블릿에서 JSP를 통해 데이터를 반환하는 방법을 예제와 함께 설명합니다.


서블릿의 주요 기능

  1. 클라이언트 요청 처리:
    • GET, POST, PUT 등의 HTTP 요청을 처리합니다.
  2. 데이터 처리 및 로직 수행:
    • 서버에서 필요한 비즈니스 로직을 수행하고 데이터베이스와 상호작용합니다.
  3. 응답 생성:
    • 클라이언트가 이해할 수 있는 형식(HTML, JSON 등)으로 데이터를 반환합니다.

클라이언트에서 서블릿에 데이터 보내는 방법

클라이언트는 GET 또는 POST 요청을 통해 데이터를 서블릿에 보낼 수 있습니다.

1. GET 요청을 통한 데이터 전송

GET 요청은 URL에 데이터를 쿼리 문자열(Query String)로 포함하여 전송합니다.

- URL뒤에 ?와 &이용하여 데이터를 포함

 

클라이언트 요청 예시:

<a href="http://localhost:8080/MyServlet?name=John&age=30">Send Data</a>

서블릿에서 GET 요청 처리:

request.getParameter()이용하여 클라이언트가 보낸 데이터를 받습니다.

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
	    // 데이터 수신
        String name = request.getParameter("name");
        String age = request.getParameter("age");

        // 응답 작성
        response.setContentType("text/html");
        response.getWriter().println("<h1>Name: " + name + ", Age: " + age + "</h1>");
    }
}

2. POST 요청을 통한 데이터 전송

POST 요청은 데이터를 요청 본문(Body)에 포함하여 전송합니다.

- form 태그 이용하여 action에 URL, method에 POST 입력

- input 태그 이용하여 입력 받은 데이터를 요청 본문(Body)에 포함 

 

클라이언트 요청 예시:

<form action="http://localhost:8080/MyServlet" method="POST">
    <input type="text" name="name" placeholder="Enter your name">
    <input type="number" name="age" placeholder="Enter your age">
    <button type="submit">Submit</button>
</form>

서블릿에서 POST 요청 처리:

request.getParameter()이용하여 클라이언트가 보낸 데이터를 받습니다.

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;

public class MyServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 데이터 수신
        String name = request.getParameter("name");
        String age = request.getParameter("age");

        // 응답 작성
        response.setContentType("text/html");
        response.getWriter().println("<h1>Name: " + name + ", Age: " + age + "</h1>");
    }
}

서블릿에서 클라이언트에 데이터 보내는 방법 (JSP 사용)

서블릿은 JSP와 연동하여 동적 웹 페이지를 생성할 수 있습니다.

- request.setAttribute("dataName", Data)를 이용하여 JSP에 데이터 전송

 

1. 서블릿에서 JSP로 데이터 전달:

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 데이터 설정
        request.setAttribute("message", "Hello from Servlet!");

        // JSP로 포워딩
        RequestDispatcher dispatcher = request.getRequestDispatcher("/display.jsp");
        dispatcher.forward(request, response);
    }
}

2. JSP에서 데이터 출력:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Servlet to JSP</title>
</head>
<body>
<h1>Message from Servlet: ${message}</h1>
<h1>Message from Servlet: <%= message></h1>
</body>
</html>

 


서블릿과 JSP의 활용 예시

  1. 로그인 시스템:
    • 클라이언트가 로그인 폼에서 입력한 데이터를 서블릿으로 보내 검증 후 JSP로 결과를 반환.
  2. 데이터 조회 및 출력:
    • 데이터베이스에서 조회한 결과를 서블릿에서 처리하고 JSP에서 테이블 형식으로 출력.
  3. RESTful API와 연동:
    • 클라이언트에서 서블릿으로 JSON 데이터를 보내고 처리한 결과를 JSP 또는 JSON 형식으로 응답.

마치며

서블릿은 자바 기반 웹 애플리케이션에서 중요한 역할을 합니다. GET과 POST 요청을 통해 클라이언트와 데이터를 주고받고, JSP를 활용해 동적 콘텐츠를 생성하는 방법을 이해하면 더욱 효율적인 웹 개발이 가능합니다. 이를 실습하며 능력을 키워보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] HTTP 요청 처리하기  (0) 2025.01.16
[Java] SQL Injection  (1) 2025.01.10
[Java] 계층형 아키텍처 패턴 (Layered Architecture Pattern)  (0) 2025.01.07
[Java] MVC 패턴  (1) 2025.01.07
[Java] SOLID 원칙  (0) 2025.01.07
반응형

계층형 아키텍처 패턴

소프트웨어 설계에서 Layered Architecture (계층형 아키텍처) 패턴은 소프트웨어를 서로 독립적인 계층으로 나누어 설계하는 구조입니다. 이 글에서는 Layered 아키텍처의 개념, 필요성, 그리고 자바에서의 구현 방법을 예제를 통해 설명하겠습니다.


Layered 아키텍처 패턴이란?

Layered 아키텍처 패턴은 애플리케이션을 역할에 따라 계층으로 나누고, 각 계층이 특정한 책임만을 가지도록 설계하는 패턴입니다. 일반적으로 다음 네 가지 주요 계층으로 구성됩니다:

  1. Presentation Layer (표현 계층):
    • 사용자 인터페이스와 상호작용을 담당합니다.
    • 사용자 입력을 처리하고 응답을 표시합니다.
    • ex) UserController.java
  2. Application Layer (애플리케이션 계층):
    • 비즈니스 로직을 실행하고 데이터를 조합하여 처리합니다.
    • 비즈니스 규칙과 워크플로우를 정의합니다.
    • ex) UserService.java
  3. Domain Layer (도메인 계층):
    • 핵심 도메인 로직과 비즈니스 엔터티를 관리합니다.
    • 데이터의 상태와 관련된 규칙을 처리합니다.
    • ex) User.java
  4. Data Access Layer (데이터 접근 계층):
    • 데이터베이스와 상호작용하여 데이터를 읽고 씁니다.
    • 저장소 또는 외부 시스템과의 통신을 담당합니다.
    • ex) UserDao.java

Layered 아키텍처의 필요성

  1. 모듈화:
    • 각 계층이 독립적으로 개발 및 유지보수될 수 있습니다.
  2. 가독성:
    • 계층 간 역할이 명확히 구분되어 코드 이해가 쉽습니다.
  3. 재사용성:
    • 특정 계층을 다른 프로젝트에서 재사용할 수 있습니다.
  4. 테스트 용이성:
    • 계층별로 개별적인 테스트가 가능하여 품질이 향상됩니다.
  5. 확장성:
    • 새로운 기능 추가 시 기존 계층에 최소한의 영향을 줍니다.

자바에서 Layered 아키텍처 구현 예제

사용자 정보를 관리하는 간단한 애플리케이션을 Layered 아키텍처로 구현해 보겠습니다.

1. Presentation Layer (표현 계층)

public class UserController {
	private final UserService userService;

    public UserController(UserService userService) {
	    this.userService = userService;
    }

    public void createUser(String name, String email) {
    	userService.addUser(name, email);
    	System.out.println("User created successfully.");
    }

    public void displayUsers() {
    	userService.getAllUsers().forEach(user ->
    	System.out.println("Name: " + user.getName() + ", Email: " + user.getEmail()));
    }
}

2. Application Layer (애플리케이션 계층)

import java.util.List;

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
	    this.userRepository = userRepository;
    }

    public void addUser(String name, String email) {
    	User user = new User(name, email);
    	userRepository.save(user);
    }

    public List<User> getAllUsers() {
    	return userRepository.findAll();
    }
}

3. Domain Layer (도메인 계층)

public class User {
    private String name;
    private String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
	    return name;
    }

    public void setName(String name) {
    	this.name = name;
    }

    public String getEmail() {
    	return email;
    }

    public void setEmail(String email) {
    	this.email = email;
    }
}

4. Data Access Layer (데이터 접근 계층)

import java.util.ArrayList;
import java.util.List;

public class UserRepository {
    private final List<User> users = new ArrayList<>();

    public void save(User user) {
	    users.add(user);
    }

    public List<User> findAll() {
    	return new ArrayList<>(users);
    }
}

5. Main 클래스

public class LayeredArchitectureDemo {
    public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();
        UserService userService = new UserService(userRepository);
        UserController userController = new UserController(userService);

        // 사용자 생성
        userController.createUser("Alice", "alice@example.com");
        userController.createUser("Bob", "bob@example.com");

        // 사용자 목록 표시
        userController.displayUsers();
    }
}
출력 결과:
 
User created successfully.
User created successfully.
Name: Alice, Email: alice@example.com
Name: Bob, Email: bob@example.com

Layered 아키텍처의 활용 예시

  1. 기업 애플리케이션:
    • Spring Framework를 활용한 계층형 구조의 웹 애플리케이션.
  2. 마이크로서비스:
    • 서비스 간 역할을 명확히 나누어 각 서비스의 계층을 독립적으로 관리.
  3. 모바일 백엔드:
    • 데이터베이스와의 통신, 비즈니스 로직 처리, API 응답 구성을 분리하여 효율적인 유지보수.

마치며

Layered 아키텍처 패턴은 애플리케이션을 명확하게 구조화하여 유지보수성과 확장성을 크게 향상시킵니다. 자바에서 이를 구현하여 더 나은 소프트웨어를 개발해 보세요!

 

반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] SQL Injection  (1) 2025.01.10
[Java] 서블릿(Servlet)  (0) 2025.01.08
[Java] MVC 패턴  (1) 2025.01.07
[Java] SOLID 원칙  (0) 2025.01.07
[Java] JDBC (Java Database Connectivity)  (0) 2025.01.07
반응형

MVC 패턴

소프트웨어 설계에서 MVC(Model-View-Controller) 패턴은 애플리케이션을 세 가지 역할로 나누어 효율적이고 유지보수하기 쉬운 구조를 제공합니다. 이 글에서는 MVC 패턴의 개념, 필요성, 그리고 자바에서의 구현 방법과 예제를 살펴보겠습니다.


MVC 패턴이란 무엇인가?

**MVC(Model-View-Controller)**는 애플리케이션을 세 가지 주요 컴포넌트로 분리하는 디자인 패턴입니다:

  1. Model (모델):
    • 데이터와 비즈니스 로직을 관리합니다.
    • 애플리케이션의 상태를 표현하며, 데이터베이스와의 상호작용을 담당합니다.
  2. View (뷰):
    • 사용자 인터페이스를 담당합니다.
    • 모델 데이터를 화면에 표시하고, 사용자의 입력을 컨트롤러에 전달합니다.
  3. Controller (컨트롤러):
    • 사용자 입력을 처리하고, 이를 모델과 뷰로 전달합니다.
    • 모델과 뷰 간의 흐름을 조정하는 중간 역할을 합니다.

MVC 패턴이 왜 필요한가?

  1. 유지보수 용이성:
    • 모델, 뷰, 컨트롤러가 각각 독립적으로 변경 가능하여 유지보수가 쉽습니다.
  2. 모듈화:
    • 역할별로 코드가 분리되어 가독성이 향상됩니다.
  3. 확장성:
    • 새로운 기능 추가 시 기존 코드에 미치는 영향을 최소화합니다.
  4. 테스트 용이성:
    • 모델, 뷰, 컨트롤러를 개별적으로 테스트할 수 있어 품질이 향상됩니다.

자바에서 MVC 패턴 구현 방법

간단한 애플리케이션을 통해 MVC 패턴을 구현해 보겠습니다. 아래 예제는 학생 정보를 표시하는 애플리케이션입니다.

1. Model (모델)

public class Student {
    private String name;
    private int rollNo;

    public Student(String name, int rollNo) {
        this.name = name;
        this.rollNo = rollNo;
    }

    public String getName() {
	    return name;
    }

    public void setName(String name) {
    	this.name = name;
    }

    public int getRollNo() {
    	return rollNo;
    }

    public void setRollNo(int rollNo) {
    	this.rollNo = rollNo;
    }
}

2. View (뷰)

public class StudentView {
    public void printStudentDetails(String studentName, int studentRollNo) {
        System.out.println("Student:");
        System.out.println("Name: " + studentName);
        System.out.println("Roll No: " + studentRollNo);
    }
}

3. Controller (컨트롤러)

public class StudentController {
    private Student model;
    private StudentView view;

    public StudentController(Student model, StudentView view) {
        this.model = model;
        this.view = view;
    }

    public void setStudentName(String name) {
	    model.setName(name);
    }

    public String getStudentName() {
    	return model.getName();
    }

    public void setStudentRollNo(int rollNo) {
    	model.setRollNo(rollNo);
    }

    public int getStudentRollNo() {
    	return model.getRollNo();
    }

    public void updateView() {
    	view.printStudentDetails(model.getName(), model.getRollNo());
    }
}

4. Main 클래스

public class MVCPatternDemo {
    public static void main(String[] args) {
        // 모델 생성
        Student model = new Student("John", 10);

        // 뷰 생성
        StudentView view = new StudentView();

        // 컨트롤러 생성
        StudentController controller = new StudentController(model, view);

        // 초기 데이터 출력
        controller.updateView();

        // 데이터 업데이트
        controller.setStudentName("Doe");
        controller.setStudentRollNo(20);

        // 업데이트된 데이터 출력
        controller.updateView();
    }
}
출력 결과:
 
Student:
Name: John
Roll No: 10
 
Student:
Name: Doe
Roll No: 20

MVC 패턴의 다양한 활용 예시

  1. 웹 애플리케이션 개발:
    • Spring Framework에서 MVC 구조를 사용하여 컨트롤러, 서비스, 뷰를 구현.
  2. 데스크톱 애플리케이션:
    • JavaFX나 Swing 기반의 UI 애플리케이션에서 MVC 적용.
  3. 모바일 애플리케이션:
    • Android 개발에서 Activity를 컨트롤러, XML 레이아웃을 뷰, 비즈니스 로직을 모델로 구현.

마치며

MVC 패턴은 애플리케이션을 구조화하고 유지보수를 쉽게 만들어주는 강력한 도구입니다. 자바에서 이를 효과적으로 구현하여 더 나은 소프트웨어 설계를 경험해 보세요!

 

반응형
반응형

객체 지향 설계 원칙: SOLID

객체 지향 설계에서 SOLID 원칙은 유지보수성과 확장성이 높은 소프트웨어를 개발하기 위해 지켜야 할 다섯 가지 기본 원칙을 의미합니다. 이 글에서는 SOLID의 각 원칙을 자세히 설명하고, 이러한 원칙이 왜 중요한지 살펴보겠습니다.


SOLID란 무엇인가?

SOLID는 객체 지향 설계의 다섯 가지 원칙을 정의한 약어로, 다음과 같은 원칙들로 구성됩니다:

  1. S: 단일 책임 원칙 (Single Responsibility Principle)
  2. O: 개방-폐쇄 원칙 (Open/Closed Principle)
  3. L: 리스코프 치환 원칙 (Liskov Substitution Principle)
  4. I: 인터페이스 분리 원칙 (Interface Segregation Principle)
  5. D: 의존성 역전 원칙 (Dependency Inversion Principle)

이 원칙들은 소프트웨어를 더 유연하고 유지보수 가능하게 만들어줍니다.


1. 단일 책임 원칙 (SRP)

클래스는 단 하나의 책임만 가져야 한다.

설명:

클래스는 하나의 역할만 가져야 하며, 변경의 이유가 하나여야 합니다. 여러 책임이 한 클래스에 섞이면 수정이 어려워지고, 코드 재사용성이 떨어집니다.

예제:
class ReportGenerator {
    public void generateReport() {
    // 보고서 생성 로직
    }

    public void printReport() {
    // 보고서 출력 로직
    }
}

위 클래스는 보고서 생성과 출력 두 가지 책임을 가지고 있습니다. 이를 분리하면:

class ReportGenerator {
    public void generateReport() {
    // 보고서 생성 로직
    }
}

class ReportPrinter {
    public void printReport() {
    // 보고서 출력 로직
    }
}
장점:
  • 클래스가 더 간결해짐.
  • 특정 책임의 변경이 다른 부분에 영향을 미치지 않음.

2. 개방-폐쇄 원칙 (OCP)

클래스는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 한다.

설명:

새로운 기능이 추가될 때 기존 코드를 수정하지 않고 확장할 수 있어야 합니다. 이를 통해 기존 코드의 안정성을 보장할 수 있습니다.

예제:

기존 코드:

class Notification {
    public void send(String type) {
        if (type.equals("Email")) {
	        System.out.println("Send Email");
        } else if (type.equals("SMS")) {
    	    System.out.println("Send SMS");
        }
    }
}

OCP를 적용:

interface Notification {
	void send();
}

class EmailNotification implements Notification {
    @Override
    public void send() {
	    System.out.println("Send Email");
    }
}

class SMSNotification implements Notification {
    @Override
    public void send() {
	    System.out.println("Send SMS");
    }
}
장점:
  • 새로운 알림 타입 추가 시 기존 코드를 수정할 필요 없음.

3. 리스코프 치환 원칙 (LSP)

하위 클래스는 상위 클래스에서 기대하는 동작을 모두 수행할 수 있어야 한다.

설명:

상위 클래스의 객체를 하위 클래스 객체로 대체해도 프로그램의 동작에 문제가 없어야 합니다.

예제:

위반 사례:

class Rectangle {
    private int width;
    private int height;

    public void setWidth(int width) {
	    this.width = width;
    }

    public void setHeight(int height) {
    	this.height = height;
    }

    public int getArea() {
    	return width * height;
    }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
	    super.setWidth(width);
    	super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
    	super.setWidth(height);
    	super.setHeight(height);
	}
}

위 코드에서는 사각형(Rectangle) 객체를 기대하는 코드가 정사각형(Square) 객체에서 의도치 않은 동작을 경험할 수 있습니다.

해결:

직사각형과 정사각형을 별도 클래스로 설계.


4. 인터페이스 분리 원칙 (ISP)

클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.

설명:

하나의 거대한 인터페이스 대신, 더 작고 구체적인 인터페이스로 분리해야 합니다.

예제:

위반 사례:

interface Worker {
    void work();
    void eat();
}

class Robot implements Worker {
    @Override
    public void work() {
	    System.out.println("Robot working");
    }

    @Override
    public void eat() {
    	// 로봇은 먹지 않음
    }
}

ISP 적용:

interface Workable {
	void work();
}

interface Eatable {
	void eat();
}

class Robot implements Workable {
    @Override
    public void work() {
	    System.out.println("Robot working");
    }
}
장점:
  • 불필요한 메서드 의존 제거.

5. 의존성 역전 원칙 (DIP)

고수준 모듈은 저수준 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다.

설명:

구체적인 구현보다 인터페이스와 같은 추상화에 의존하도록 설계해야 합니다.

예제:

위반 사례:

class Keyboard {}
class Monitor {}

class Computer {
    private Keyboard keyboard;
    private Monitor monitor;

    public Computer() {
        this.keyboard = new Keyboard();
        this.monitor = new Monitor();
    }
}

DIP 적용:

interface InputDevice {}
class Keyboard implements InputDevice {}

interface OutputDevice {}
class Monitor implements OutputDevice {}

class Computer {
    private InputDevice inputDevice;
    private OutputDevice outputDevice;

    public Computer(InputDevice inputDevice, OutputDevice outputDevice) {
    	this.inputDevice = inputDevice;
    	this.outputDevice = outputDevice;
    }
}
장점:
  • 의존성 주입을 통해 유연성 증가.

SOLID 원칙이 필요한 이유

  1. 유지보수성: 코드를 더 쉽게 수정하고 확장할 수 있습니다.
  2. 재사용성: 모듈화된 설계를 통해 코드 재사용이 가능.
  3. 확장성: 요구사항 변경에 유연하게 대응.
  4. 가독성: 명확하고 직관적인 코드 작성.

SOLID 원칙을 준수하면, 변화에 강하고 확장 가능한 소프트웨어를 설계할 수 있습니다. 이를 실천함으로써 소프트웨어 개발의 품질을 한 단계 높여보세요!

 

 

반응형
반응형
 

JDBC: 개념과 활용

JDBC(Java Database Connectivity)는 자바에서 데이터베이스와 상호작용하기 위한 표준 API입니다. 이를 통해 애플리케이션에서 데이터베이스에 연결하고, 데이터를 조회하거나 수정할 수 있습니다. 이 글에서는 JDBC의 개념, 자바에서 사용하는 방법, 그리고 간단한 예제를 통해 JDBC 활용 방법을 알아보겠습니다.


JDBC란 무엇인가?

**JDBC(Java Database Connectivity)**는 자바 프로그램과 데이터베이스 간의 연결을 제공하는 API입니다. SQL 쿼리를 실행하고 데이터베이스로부터 데이터를 가져오거나 업데이트하는 작업을 수행할 수 있습니다.

JDBC의 특징:
  1. 플랫폼 독립성: 자바의 플랫폼 독립성처럼, JDBC는 다양한 데이터베이스와 호환됩니다.
  2. SQL 지원: 표준 SQL 문법을 사용하여 데이터베이스 작업 수행.
  3. 유연성: 다양한 데이터베이스 드라이버를 통해 연결 가능.
JDBC 구성 요소:
  1. DriverManager: 데이터베이스 드라이버를 관리.
  2. Connection: 데이터베이스 연결을 표현.
  3. Statement: SQL 문을 실행.
  4. ResultSet: SQL 쿼리 결과를 처리.

자바에서 JDBC 사용 방법

JDBC를 사용하여 데이터베이스와 상호작용하는 기본 흐름은 다음과 같습니다:

  1. 데이터베이스 드라이버 로드.
  2. 데이터베이스에 연결.
  3. SQL 문 실행.
  4. 결과 처리.
  5. 연결 종료.
예제: MySQL 데이터베이스 연결 및 데이터 조회
import java.sql.*;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/exampledb"; // 데이터베이스 URL
        String username = "root"; // 사용자 이름
        String password = "password"; // 비밀번호

        String query = "SELECT * FROM users";

        try {
            // 1. 드라이버 로드
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2. 데이터베이스 연결
            Connection connection = DriverManager.getConnection(url, username, password);

            // 3. SQL 문 실행
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);

            // 4. 결과 처리
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String email = resultSet.getString("email");

                System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
            }

            // 5. 연결 종료
            resultSet.close();
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
        	e.printStackTrace();
        }
    }
}
출력 결과 (예시):
 
ID: 1, Name: Alice, Email: alice@example.com
ID: 2, Name: Bob, Email: bob@example.com

PreparedStatement 사용

PreparedStatement는 SQL 문을 미리 컴파일하여 성능을 최적화하고, SQL 인젝션 공격을 방지합니다.

예제: PreparedStatement로 데이터 삽입
String insertQuery = "INSERT INTO users (name, email) VALUES (?, ?)";

try (Connection connection = DriverManager.getConnection(url, username, password);
    PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {

    preparedStatement.setString(1, "Charlie");
    preparedStatement.setString(2, "charlie@example.com");

    int rowsInserted = preparedStatement.executeUpdate();
    System.out.println(rowsInserted + " row(s) inserted.");

} catch (SQLException e) {
	e.printStackTrace();
}
출력 결과:
 
1 row(s) inserted.

트랜잭션 처리

JDBC는 트랜잭션 관리도 지원합니다. 여러 작업을 하나의 트랜잭션으로 묶어 처리할 수 있습니다.

예제: 트랜잭션 관리
try (Connection connection = DriverManager.getConnection(url, username, password)) {
    connection.setAutoCommit(false); // 자동 커밋 비활성화

    try (PreparedStatement stmt1 = connection.prepareStatement("UPDATE accounts SET balance = balance - ? WHERE id = ?");
        PreparedStatement stmt2 = connection.prepareStatement("UPDATE accounts SET balance = balance + ? WHERE id = ?")) {

        stmt1.setInt(1, 100);
        stmt1.setInt(2, 1);
        stmt1.executeUpdate();

        stmt2.setInt(1, 100);
        stmt2.setInt(2, 2);
        stmt2.executeUpdate();

        connection.commit(); // 트랜잭션 커밋
        System.out.println("Transaction committed successfully.");

    } catch (SQLException e) {
        connection.rollback(); // 트랜잭션 롤백
        System.out.println("Transaction rolled back due to error.");
        e.printStackTrace();
    }
} catch (SQLException e) {
	e.printStackTrace();
}
출력 결과 (성공 시):
 
Transaction committed successfully.

다양한 활용 예시

  1. 사용자 인증 시스템:
    • JDBC를 사용해 사용자 정보를 데이터베이스에서 검증.
  2. 데이터 분석:
    • 데이터베이스에서 대량의 데이터를 쿼리하여 분석.
  3. 로그 시스템:
    • 애플리케이션 로그를 데이터베이스에 저장.
  4. 보고서 생성:
    • 데이터베이스 데이터를 기반으로 보고서 생성.

마치며

JDBC는 데이터베이스와 상호작용하기 위한 강력하고 유연한 도구입니다. 데이터베이스 연결, 쿼리 실행, 트랜잭션 관리 등을 통해 강력한 데이터 중심 애플리케이션을 개발할 수 있습니다. 적절한 활용을 통해 데이터베이스 작업을 효율적으로 처리해 보세요!

 
반응형

'개발 부트캠프 > 백엔드' 카테고리의 다른 글

[Java] MVC 패턴  (1) 2025.01.07
[Java] SOLID 원칙  (0) 2025.01.07
[Java] 쓰레드(Thread)  (0) 2025.01.06
[Java] Collection(List / Set / Map)  (0) 2025.01.06
[Java] 의존성 역전 원칙(DIP)  (0) 2025.01.04
반응형
 

쓰레드(Thread): 개념과 활용

쓰레드(Thread)는 프로그램 내에서 독립적으로 실행되는 작업 단위입니다. 자바는 멀티쓰레드 프로그래밍을 지원하여 애플리케이션의 성능과 효율성을 극대화할 수 있습니다. 이 글에서는 쓰레드의 개념, 자바에서 쓰레드를 다루는 방법, 그리고 다양한 활용 예시를 소개합니다.


쓰레드(Thread)란?

**쓰레드(Thread)**는 프로세스 내에서 실행되는 가벼운 작업 단위입니다. 하나의 프로세스는 여러 쓰레드를 가질 수 있으며, 각 쓰레드는 독립적으로 실행됩니다. 자바에서 쓰레드는 멀티태스킹을 구현하거나 병렬 처리를 수행할 때 유용합니다.

쓰레드의 특징:
  1. 독립 실행: 각 쓰레드는 별도로 실행되며, 다른 쓰레드와 자원을 공유할 수 있음.
  2. 병렬 처리: 여러 작업을 동시에 처리하여 효율성 향상.
  3. 자원 공유: 메모리와 같은 자원을 공유하므로 동기화가 필요.

자바에서 쓰레드 다루기

자바에서 쓰레드를 생성하고 실행하는 방법은 크게 두 가지가 있습니다:

  1. Thread 클래스 상속
  2. Runnable 인터페이스 구현
예제 1: Thread 클래스 상속
class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
	        System.out.println(Thread.currentThread().getName() + " - Count: " + i);
        }
    }
}

public class ThreadExample1 {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        thread1.start();
        thread2.start();
	}
}
출력 결과 (순서 불확정):
 
Thread-0 - Count: 1
Thread-1 - Count: 1
...
예제 2: Runnable 인터페이스 구현
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
	        System.out.println(Thread.currentThread().getName() + " - Count: " + i);
        }
    }
}

public class ThreadExample2 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyRunnable());
        Thread thread2 = new Thread(new MyRunnable());

        thread1.start();
        thread2.start();
    }
}
출력 결과 (순서 불확정):
 
Thread-0 - Count: 1
Thread-1 - Count: 1
...

쓰레드 동기화

쓰레드가 공유 자원에 접근할 때는 동기화가 필요합니다. 자바는 synchronized 키워드를 제공하여 쓰레드 간의 자원 충돌을 방지합니다.

예제 3: 동기화
class SharedResource {
    public synchronized void printNumbers(String threadName) {
        for (int i = 1; i <= 5; i++) {
	        System.out.println(threadName + " - Number: " + i);
            try {
	            Thread.sleep(100); // 0.1초 대기
            } catch (InterruptedException e) {
    	        e.printStackTrace();
            }
        }
    }
}

class Worker implements Runnable {
    private SharedResource resource;

    public Worker(SharedResource resource) {
	    this.resource = resource;
    }

    @Override
    public void run() {
    	resource.printNumbers(Thread.currentThread().getName());
    }
}

public class SynchronizedExample {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread thread1 = new Thread(new Worker(resource));
        Thread thread2 = new Thread(new Worker(resource));

        thread1.start();
        thread2.start();
    }
}
출력 결과 (순서 보장):
 
Thread-0 - Number: 1
Thread-0 - Number: 2
...
Thread-1 - Number: 1
...

다양한 활용 예시

  1. 병렬 작업 처리:
    • 데이터베이스 쿼리 실행, 파일 처리 등에서 병렬 작업 수행.
  2. UI 애니메이션:
    • GUI 애플리케이션에서 애니메이션이나 타이머 구현.
  3. 멀티플레이어 게임:
    • 각 플레이어의 작업을 독립적으로 처리.
  4. 서버 클라이언트 통신:
    • 각 클라이언트 요청을 독립적으로 처리.
예제: 간단한 타이머 구현
public class TimerExample {
    public static void main(String[] args) {
        Runnable timerTask = () -> {
            for (int i = 10; i >= 1; i--) {
	            System.out.println("Countdown: " + i);
                try {
	                Thread.sleep(1000); // 1초 대기
                } catch (InterruptedException e) {
    	            e.printStackTrace();
                }
            }
            System.out.println("Time's up!");
        };

        Thread timerThread = new Thread(timerTask);
        timerThread.start();
    }
}
출력 결과:
 
Countdown: 10
Countdown: 9
...
Time's up!

마치며

자바 쓰레드는 멀티태스킹과 병렬 처리를 구현하는 데 매우 유용한 도구입니다. 쓰레드의 생성, 실행, 동기화, 다양한 활용 사례를 익히고 적절히 활용하여 효율적인 프로그램을 작성해 보세요!

 
반응형
반응형
 

컬렉션(Collection): 개념과 활용

컬렉션(Collection)은 데이터 그룹을 저장하고 관리하는 데 사용되는 자바 프레임워크입니다. 자바 컬렉션은 데이터 구조를 표준화하여 효율적인 데이터 처리와 관리를 가능하게 합니다. 이 글에서는 컬렉션의 개념, 종류, 자바에서 사용하는 방법, 그리고 다양한 활용 예시를 소개합니다.


컬렉션(Collection)이란?

**컬렉션(Collection)**은 객체 그룹을 저장하고 조작하기 위한 컨테이너입니다. 다양한 데이터 구조를 지원하며, 자바에서 데이터 그룹을 관리하기 위한 표준화된 API를 제공합니다.

컬렉션의 특징:
  1. 유연성: 다양한 데이터 구조를 지원.
  2. 표준화: 공통된 인터페이스를 통해 일관된 작업 제공.
  3. 다양한 구현체: 용도에 맞는 데이터 구조 선택 가능.
  4. 제네릭: 타입 안정성을 보장.

컬렉션의 종류

컬렉션은 크게 인터페이스구현체로 나뉩니다. 주요 인터페이스와 그 하위 구현체는 다음과 같습니다:

  1. List:
    • 순서가 있는 데이터 그룹.
    • 중복 허용.
    • 구현체: ArrayList, LinkedList, Vector.
  2. Set:
    • 중복을 허용하지 않는 데이터 그룹.
    • 순서 보장 안 함.
    • 구현체: HashSet, LinkedHashSet, TreeSet.
  3. Queue:
    • FIFO(First-In-First-Out) 방식으로 처리.
    • 구현체: PriorityQueue, LinkedList (Queue로 사용).
  4. Map:
    • 키-값 쌍으로 데이터를 저장.
    • 키는 중복 불가, 값은 중복 허용.
    • 구현체: HashMap, LinkedHashMap, TreeMap.

자바에서 컬렉션 다루기

예제 1: List 사용하기
import java.util.ArrayList;
import java.util.List;

public class ListExample {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        names.add("Alice"); // 중복 허용

    	for (String name : names) {
	    	System.out.println(name);
    	}
    }
}
출력 결과:
 
Alice
Bob
Charlie
Alice
예제 2: Set 사용하기
import java.util.HashSet;
import java.util.Set;

public class SetExample {
    public static void main(String[] args) {
        Set<String> names = new HashSet<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        names.add("Alice"); // 중복 제거됨

        for (String name : names) {
	        System.out.println(name);
        }
    }
}
출력 결과 (순서 불확정):
 
Alice
Bob
Charlie
예제 3: Map 사용하기
import java.util.HashMap;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        Map<Integer, String> userMap = new HashMap<>();
        userMap.put(1, "Alice");
        userMap.put(2, "Bob");
        userMap.put(3, "Charlie");

        for (Map.Entry<Integer, String> entry : userMap.entrySet()) {
	        System.out.println("ID: " + entry.getKey() + ", Name: " + entry.getValue());
        }
    }
}
출력 결과:
 
ID: 1, Name: Alice
ID: 2, Name: Bob
ID: 3, Name: Charlie

컬렉션의 주요 메서드

  1. List:
    • add(E e): 요소 추가.
    • get(int index): 특정 위치의 요소 가져오기.
    • remove(int index): 특정 위치의 요소 제거.
  2. Set:
    • add(E e): 요소 추가 (중복인 경우 추가되지 않음).
    • contains(Object o): 요소 포함 여부 확인.
  3. Map:
    • put(K key, V value): 키-값 추가.
    • get(Object key): 특정 키에 해당하는 값 반환.
    • remove(Object key): 특정 키 삭제.

다양한 활용 예시

  1. 학생 성적 관리:
    • List를 사용해 학생 명단 관리.
    • Map을 사용해 학생별 점수 저장.
  2. 중복 제거:
    • Set을 사용해 데이터 중복 제거.
  3. 우선순위 처리:
    • PriorityQueue를 사용해 작업을 우선순위에 따라 처리.
  4. 정렬된 데이터 관리:
    • TreeSet과 TreeMap을 사용해 정렬된 데이터 저장.

마치며

자바 컬렉션 프레임워크는 데이터 구조를 효과적으로 관리하고 처리할 수 있는 강력한 도구입니다. 컬렉션의 다양한 구현체와 메서드를 익히고 적절히 활용하여 효율적이고 유지보수 가능한 코드를 작성해 보세요!

 
반응형

+ Recent posts