Java HTTP 통신에 대해서 알아보자

 

java.net 패키지내에 있는 HttpUrlConnection 클래스와 URL 클래스를 활용하여 HTTP 통신을  할 수 있다.

 

1. URL 클래스 

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URL.html

 

URL (Java SE 11 & JDK 11 )

Creates a URL object from the specified protocol, host, port number, and file. host can be expressed as a host name or a literal IP address. If IPv6 literal address is used, it should be enclosed in square brackets ('[' and ']'), as specified by RFC 2732;

docs.oracle.com

 

URL 클래스는 자원을 요청할 주소를 나타내는 클래스이다. URL 클래스를 살펴보면 Serializable 인터페이스를 구현하고 있어, 직렬화를 위한 조건을 갖추고 있다.

 

public final class URL implements java.io.Serializable {}

 

더보기

직렬화 (serialize)란 자바 언어에서 사용되는 Object 또는 Data를 다른 컴퓨터의 자바 시스템에서도 사용 할 수 있도록 바이트 스트림 (Stream of bytes) 형태로 연속적인(serial) 데이터로 변환하는 포맷 변환 기술을 말한다. 반대인 역직렬화는(Deserialize) 는 바이트로 변환된 데이터를 원래대로 자바 시스템의 Ojbect 또는 Data로 변환하는 기술이다.

 

* 바이트 스트림 이란?

 스트림은 클라이언트나 서버 간에 출발지 목적지로 입출력하기 위한 데이터가 흐르는 통로를 말한다. 자바는 스트림의 기본 단위를 바이트로  두고 있기 때문에, 네트워크, 데이터베이스로 전송하기 위해 최소 단위인 바이트 스트림으로 변환하여 처리한다.

 

그런데 JSON을 사용하지 않고 왜 직렬화하여 사용할까?

 첫번째는 직렬화는 자바의 고유 기술인 만큼 당연히 자바 시스템에서 개발에 최적화되어 있다.

두번째는, 자바의 광활한 레퍼런스 타입에 대해 제약 없이 외부에 내보낼 수 있다는 것이다.

 

 

 1) URL 객체 생성하기

 URL 클래스의 생성자는 다양한 형태로 선언되어 있다. 그 중에 가장 많이 이용되는 생성자는 URL을 문자열 형태로 나타낸 객체의 레퍼런스를 인자로 전달받는 생성자이다.

 

public URL(Stirng spec) throws MalformedURLException {,,,}

 

예를들어 https://www.naver.com 의 URL을 나타내는 URL 객체를 생성하고 싶다면 아래와 같이 작성하면 된다.

 

import java.net.URL;
...

URL url = new URL("https://wwww.naver.com");

 

공식 Java API 문서를 보면,  생성자를 비롯하여 모든 URL 클래스 객체의 생성자는 MalformedURLException 예외를 throws 하여 예외처리에 대한 책임을 전가하고 있다. MalformedURLException은 생성자의 인자로 받은 URL 문자열이 null 이거나 프로토콜을 알 수 없을 때 등의 상황에 발생한다. 따라서 URL 객체를 생성한 클래스에서 그 예외를 처리해주어야 한다.

 

try {
	URL url = new URL("https://www.naver.com");
} catch (MalformedURLException e) {
	e.printStackTrace();
}

 

 

2) 연결 객체 얻기

URL 클래스에 선언된 openConnection() 메소드는 URL 객체에 대한 연결을 담당하는 URLConnection 객체를 반환한다.

 

위에서 생성한 URL 객체에 대한 연결 객체를 얻으려면 아래와 같이 하면된다.

 

URLConnection connection = url.openConnection();

 

 

 

2. HttpURLConnection 클래스

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpURLConnection.html

 

HttpURLConnection (Java SE 11 & JDK 11 )

Returns the error stream if the connection failed but the server sent useful data nonetheless. The typical example is when an HTTP server responds with a 404, which will cause a FileNotFoundException to be thrown in connect, but the server sent an HTML hel

docs.oracle.com

 

HttpURLConnection 클래스는 HTTP 프로토콜 통신을 위한 클래스이다. 각각의 객체들은 하나의 요청을 위해 사용된다.

HttpURLConnection 클래스를 살펴보면 URLConnection 클래스를 확장한(상속받은) 추상클래스임을 알 수 있다.

 

1) HttpURLConnection 객체 생성

위에서 URL 객체의 openConnection() 메소드를 통해 URLConnection 객체를 얻을 수 있었다. HttpURLConnection 객체는 URLConnection 객체를 확장하고(상속받고)있기 때문에 Type Casting 을 통해 HttpURLConnection객체를 쉽게 얻을 수 있다.

 

URL에 연결하는 HTTP 연결 객체를 생성하고 싶다면 다음과 같이 코드를 작성하면 된다.

 

import java.net.URL;
import java.net.HttpURLConnection;
...

URL url = new URL("https://www.naver.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

 

 

2) 요청 메소드 설정

HTTP 요청을 위해서는 요청 메소드를 설정해야 한다. setRequestMethod() 메소드는 요청 메소드를 문자열 파라미터로 받아서 유요한 요청 메소드면 method 멤버 변수에 요청 메소드를 저장하고, 아니면 ProtocolException 예외를 발생시킨다. 처리 가능한 요청 메소드로는 GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE 가 있다.

public void setRequestMethod(String method) throws ProtocolException {
        if (connected) {
            throw new ProtocolException("Can't reset method: already connected");
        }
        // This restriction will prevent people from using this class to
        // experiment w/ new HTTP methods using java.  But it should
        // be placed for security - the request String could be
        // arbitrarily long.

        for (int i = 0; i < methods.length; i++) {
            if (methods[i].equals(method)) {
                if (method.equals("TRACE")) {
                    SecurityManager s = System.getSecurityManager();
                    if (s != null) {
                        s.checkPermission(new NetPermission("allowHttpTrace"));
                    }
                }
                this.method = method;
                return;
            }
        }
        throw new ProtocolException("Invalid HTTP method: " + method);
    }

 

method 멤버변수는 기본으로 "GET"으로 초기화되어있다. 따라서 setRequestMethod()를 통해 요청 메소드를 설정하지 않으면 GET 요청을 보내게 된다.

 

위에서 생성한 HttpURLConnection 객체로 POST 요청을 하고 싶다면 다음과 코드를 작성하면 된다.

connection.setReuqestMethod("POST");

 

 

3) 요청 헤더 설정

HttpURLConnection 클래스가 확장(상속)하는 URLConnection 클래스에 정의된 setRequestProperty() 메소드로 요청 헤더를 설정할 수 있다.

 

public void setRequestProperty(String key, String value) {
        checkConnected();
        if (key == null)
            throw new NullPointerException ("key is null");

        if (requests == null)
            requests = new MessageHeader();

        requests.set(key, value);
}

 

setRequestProperty() 메소드는 String 타입의 key, value 파라미터를 받는다. 각 파라미터를 통해 요청 헤더의 이름과 값을 설정할 수 있다. 만약 key값이 null 이라면 NullPointerException 예외를 발생시킨다.

 

Content-Type 및 HTTP 요청을 하는 사용자의 애플리케이션 타입, 운영 체제, 소프트웨어 벤더 또는 소프트웨어 버전 등을 식별할 수 있는 User-Agent 헤더를 설정하고 싶다면 다음과 같이 코드를 작성하면 된다.

 

private static final String USER_AGENT = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0";

...

connection.setRequestProperty("User-Agent", USER_AGENT);
connection.setReuqestProperty("Content-Type", "application/json; charset=utf-8");

 

 

4) POST 요청시 데이터 넘겨주기

POST 요청을 할 때에는 OutputStream 객체로 데이터를 전송한다. setDoOutPut() 메소드를 통해 OutputStream 객체로 전송할 데이터가 있다는 옵션을 설정해야 한다. checkConnected() 메소드에서는 연결 객체가 연결되어있는지 확인하고, 이미 연결되어있다면 IllegalStateException 예외를 발생시킨다.

 

public void setDoOutput(boolean dooutput) {
    checkConnected();
    doOutput = dooutput;
}

 

위처럼 setDoOutput() 메소드는 boolean 타입의 dooutput 파라미터를 받으 doOutput 멤버 변수에 저장한다. doOutput 변수가 true 이면 OutputStream 으로 데이터를 전송한다는 뜻이고, false이면 하지 않는다는 뜻인데, 기본적으로 false로 초기화되어있기 때문에 POST로 데이터를 전송하려면 꼭 옵션을 설정해줘야 한다.

 

getOutputStream() 메소드를 통해 연결에 사용할 OutputStream 객체를 얻을 수 있다. 프로토콜이 출력을 지원하지 않는다면 UnknownServiceException 예외를 발생시킨다.

 

public OutputStream getOutputStream() throws IOException {
     throw new UnknownServiceException("protocol doesn't support output");
}

 

전송할 데이터가 문자열일 경우는 OutputStream 클래스를 확장하는 DataOutputStream 클래스의 writebytes() 메소드를 활용하여 쉽게 데이터를 설정할 수 있습니다. DataOutputStream 클래스는 생성자에 OutptStream 객체를 전달하여 생성할 수 있습니다. 따라서 위에서 getOutputSteam() 메소드를 통해 얻은 객체를 바로 넣어줄 수 있다.

 

5) 응답 코드 얻기

getResponseCode() 메소드를 통해 응답 코드를 얻을 수 있습니다. 정상적인 응답일 경우 200이 반환됩니다.

 

 

6) 응답 데이터 얻기

getInputStream() 메소드를 통해 응답 데이터를 읽을 수 있는 InputStream객체를 얻을 수 있습니다. 응답을 문자열 타입으로 얻기 위해 BufferedReader 객체를 사용할 수 있습니다.

 

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer stringBuffer = new StringBuffer();
String inputLine;

while ((inputLine = bufferedReader.readLine()) != null)  {
     stringBuffer.append(inputLine);
}
bufferedReader.close();

String response = stringBuffer.toString();

'Back-End > Java' 카테고리의 다른 글

스레드  (1) 2024.07.05
프로세스  (0) 2024.07.04
Exception과 Transaction  (1) 2024.02.05
String, StringBuilder, StringBuffer 의 차이점  (1) 2023.10.26
스프링이란 무엇일까?  (0) 2023.09.16

REST(Representational State Transfer) 란 무엇일까?

REST는 분산 시스템을 위한 아키텍쳐 스타일 중 하나이다. 리소스를 표현하고 해당 리소스에 대한 상태를 전송하는 데 사용된다. 웹 서비스의 디자인에 널리 사용되며, 클라이언트와 서버 간의 통신을 위한 규칙과 제약을 정의한다.

 

REST의 주요 특징

 

1. Client-Server Architecture (클라이언트-서버 아키텍쳐) 

  클라이언트와 서버가 서로 독립적으로 개발되고 확장될 수 있도록 설계된다. 이를 통해 서버와 클라이언트의 역할을 분리하여 시스템의 유연성을 향상시킨다.

 

2. Statelessness (무상태성)

  각 요청은 클라이언트의 모든 정보를 포함하며, 서버에서 클라이언트의 상태를 유지하지 않는다. 이는 서버측의 부하를 줄이고 확장성을 향상시킨다.

 

3. Cacheability (캐시 가능성)

  HTTP 프로토콜을 사용하여 데이터를 캐싱할 수 있도록 한다. 이는 서버의 부하를 줄이고 네트워크 성능을 향상시킨다.

 

4. Uniform Interface (일관된  인터페이스)

  리소스에 대한 표현과 상호작용 방법이 일관성 있게 정의되어야 한다. 이를 통해 시스템의 분리성을 유지하고 상호 운용성을 향상시킨다.

 

5. Layered System (계층화 시스템)

  클라이언트는 서버와 직접 통신하는 대신, 중간에 프록시나 캐시 서버 등을 통해 통신할 수 있다. 이는 시스템의 확장성과 보안을 향상시킨다.

 

 

REST의 요소

 

1. 리소스(Resource)

  데이터를 나타내는 개체이다,. 모든  리소스는 고유한 URI(Uniform Resource Identifier)로 식별된다.

 

2. 메서드(Method) 

  HTTP 메서드 (GET,POST,PUT,DELETE 등)를 사용하여 리소스에 대한 행동을 정의한다.

 

3. 메시지(Message) 

  클라이언트와 서버 간의 통신에 사용되는 데이터이다. 일반적으로 JSON 또는 XML 형식으로 표현된다.

 

4. 표현(Representation) 

  클라이언트가 리소스에 접근할 때 얻는 데이터의 형식을 나타낸다. 일반적으로 JSON 또는 XML 형식으로 표현된다.

 

요약하자면 REST는 웹 서비스 및 분산 시스템의 디자인에 널리 사용되며, 간단하고 유연한 아키텍쳐 스타일을 제공하여 시스템의 확장성과 상호 운용성을 향상시킨다.

 

 

 

 

RESTful

RESTful은 REST 아키텍쳐 스타일을 따르는 웹 서비스를 설계하고 구현하는 방법을 의미한다. 즉 RESTful 한 웹 서비스는 REST의 원리와 제약을 준수하여 개발된 웹 서비스를 말한다. 클라이언트와 서버 간의 상호 작용을 위해 HTTP 프로토콜을 기반으로 하며, 자원을 표현하고 그 상태를 전송하기 위해 표준 HTTP 메서드 (GET,POST,PUT,DELETE 등)를 사용한다.

 

 

RESTful 웹 서비스의 장점

 

1. 간결한 인터페이스 

  HTTP 프로토콜을 사용하여 간단하고 직관적인 API 를 제공한다.

 

2. 유연성 

  다양한 플랫폼 및 기기에서 사용할 수 있으며, 다양한 데이터 형식을 지원한다 ex) 웹, 모바일 등 여러 시스템에서 사용 가능 

 

3. 확장성 

  클라이언트와 서버 간의 분리로 확정성이 향상된다.

 

4. 상호 운용성

  다른 시스템과의 통합이 쉽고 간단하다

 

5. 자유로운 사용

  웹 기술과 상호 운용이 용이하므로 다양한 언어와 프레임 워크로 개발할 수 있다.

 

 

그렇다면 예시를 통해  REST API 에 대해서  알아보자

 

REST API

REST API 설계 시 가장 중요한 항목은 다음의 2가지로 요약할 수 있다.

 

1. URI는 정보의 자원표현해야 한다.

2. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE) 로 표현한다.

 

 

- URI는 정보의 자원을 표현해야 한다. *리소스명은 동사보다는 명사를 사용해야 한다.

GET /members/delete/1

 

위와 같은 방식은 REST를 제대로 적용하지 않은 URI이다. URI는 자원을 표현하는데 중점을 두어야 한다. 행위에 대한 표현이 들어가서는 안된다.

 

자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE) 로 표현한다,.

위의 잘못 된 URI를 HTTP Method를 통해 수정해 보면

DELETE /members/1

 

 

이와 같이 수정할 수 있다. 

 

어떠한 정보를 가져올때는 GET, 회원 추가, 수정 등 행위를 표현하고자 할 때는 POST Method를 사용하여 표현할 수 있다.

 

회원정보를 가져오는 URI

GET /members/show/1 (x)
GET /members/1      (o)

 

회원을 추가할 때

GET /members/insert/2  (x) - GET 메서드는 리소스 생성에 맞지 않다.
POST /members/2 	   (o)

 

제품관리 

GET /products 		-- 모든 제품 목록을 가져온다
GET /products/{id}	-- 특정 제품의 정보를 가져온다
POST /products		-- 새로운 제품을 생성한다
PUT /products/{id}	-- 특정 제품의 정보를 업데이트한다
DELETE /products/{id} -- 특정 제품을 삭제한다

 

HTTP Method

 

URI 설계 시 주의할 점

 

1. 슬래시 구분자(/)는 계층 관계를 나타내는 데 사용한다.

2. URI 마지막 문자로 슬래시(/)를 포함하지 않는다.

3. 하이픈(-)은 URI 가독성을 높이는데 사용 (불가피하게 긴 URI 경로를 가지게 된 경우)

4. 밑줄(_)은 URI에 사용하지 않는다.

5. URI 경로에는 소문자가 적합하다.

6. 파일 확장자는 URI에 포함시키지 않는다. (Accept Header 를 사용한다)

 

 

HTTP 응답코드

HTTP 상태코드

 

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

Kotlin 기본 문법  (1) 2025.03.05
Spring Boot와 Kotlin: 기본 개념과 시작하기  (3) 2025.03.01
Swagger  (1) 2023.11.08
Post API  (0) 2023.11.02
Spring Boot 기초  (0) 2023.11.01

Exception 과 Error

Exception 과 Error 는 한 마디로 개발자가 대응할 수 있냐 없냐로 구분할 수 있다.

 

- Exception : 프로그램을 실행 중 발생하는 예외 상황을 나타낸다. 예외는 프로그램이 실행되는 동안 발생할 수 있는 일반적인 에러를 포함한다. 예를 들어, 파일을 찾을 수 없는 경우, 네트워크 연결이 끊어진 경우, 잘못된 사용자 입력 등이 있다.

 

- Error : 프로그램이 더 이상 수행될 수 없는 심각한 예외 상황을 나타낸다. 일반적으로 Error는 시스템 수준의 문제를 나타내며, 프로그래머가 직접적으로 처리하기 어렵거나 불가능한 상황이다. 프로그램이 더 이상 복구할 수 없는 상황에서 발생하는데, 가장 흔한 예로는 OutOfMemoryError 가 있다.

 

자바에서는 이러한 예외를 처리하기 위해 'try', 'catch', 'finally', 'thorw', 'thorws' 등의 예외 처리 구문을 제공한다.

 

try {
	// 예외가 발생할 수 있는 코드 작성 
} catch {
	// 예외를 처리하는 코드 작성
} finally {
	// 항상 실행되는 코드 작성 (예외 발생 여부에 상관없이)
}

 

 

 

추가로 이러한 오류가 발생하는 시점에 따라 분류를 할 수도 있는데

   1. 컴파일 에러 (compile-time error): 컴파일시에 발생하는 에러

   2. 런타임 에러 (runtime error): 프로그램 실행시에 발생하는 에러

   3. 논리적 에러 (logical error): 실행은 되지만 의도와 다르게 동작하는 것

로 나뉜다. 

 

* 논리 에러 (logical error) 는 버그라고 생각하면 된다. 프로그램이 실행되고 작동하는데는 아무런 문제가 없는 오류지만, 결과가 예상과 달라 개발자가 의도한 작업을 수행하지 못하게 되어 서비스 이용에 지장이 생길 수 있다. 

이러한 논리 에러는 프로그램이 멀쩡하게 돌아가기 떄문에 따로 에러 메시지는 발생하지 않는다. 따라서 논리 에러를 피하기 위해서는 프로그램의 전반적인 코드와 알고리즘을 체크하고 테스트를 진행해야 한다.

 

* 컴파일 에러 (compile-time error) : 컴파일 에러는 컴파일 단계에서 오류를 발견하면 컴파일러가 에러 메시지를 출력해주는 것을 말한다. 대표적인 컴파일 에러 발생의 원인은 '문법 구문 오류 (syntax error)'를 들 수 있다.

 

* 런타임 에러 (runtime error) : 프로그램 실행 중에 에러가 발생하여 잘못된 결과를 얻는 경우 런타임 에러가 발생할 수 있다.

 

 

자바의 오류 클래스 계층 구조를 확인해보자

Exception 계층 구조

 

 

자바에서 다루는 모든 예외 처리는 Exception 클래스에서 처리한다. Exception 클래스는 RunTimeException 과 CompileException 으로 구분 할 수 있다.

 

그렇다면 RuntimeException 클래스의 종류에는 어떠한 것들이 있을까?

 

런타임 예외의 종류

 

 

@Transaction 어노테이션

@Transaction 어노테이션은 saveDataInTransaction 메서드에 적용되어있다. 이 메서드가 실행될때 스프링은 트랜잭션을 시작하고, 메서드가 완료되면 트랜잭션을 커밋한다. 만약 메서드 수행 중 예외가 발생하면 트랜잭션은 롤백된다. 

 

Spring @Transactional 선언 시 기본 속성은 아래와 같다.

@Transactional
//@Transactional(rollbackFro = {RuntimeException.class, Error.class}) 기본 속성
public void doSave(User userInfo) {
	 userInfoSaveDao.save(user);
}

 

RuntimeException 과 Error 가 발생했을 경우 기본적으로 rollback이 된다. 해당 2가지 경우가 아니면 rollback 되지 않는다. (컴파일 예외는 rollback되지 않는다)

 

하지만 트랜잭션을 rollback 하는 다른 방법들이 존재한다.

 

1. @Transactional 의 옵션 값을 변경

@Transactional(rollbackFor = {Exception.class})
public void doSave(User userInfo) {
	 userInfoSaveDao.save(user);
}

위와 같이 변경하면 모든 예외에 대해서 rollback을 진행하게 된다.

 

2. RuntimeException

@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void doSave(User userInfo) {
	 userInfoSaveDao.save(user);
}

 

3. 수동으로 하는 rollback

@Autowired
private DataSourceTransactionManager txm;


@Transactional(rollbackFor = {Exception.class})
public void doSave(User userInfo) {
	
    TransactionStatus tx = CommonUtils.getTransactionStatus(txm);

	try {
		 userInfoSaveDao.save(user);    
    } catch(Exception e) {
    	tx.rollback();
    }

}

'Back-End > Java' 카테고리의 다른 글

스레드  (1) 2024.07.05
프로세스  (0) 2024.07.04
Java HTTP 통신  (4) 2024.06.12
String, StringBuilder, StringBuffer 의 차이점  (1) 2023.10.26
스프링이란 무엇일까?  (0) 2023.09.16

Swagger

- 협업을 위해 필요한 라이브러리

- 서버로 요청되는 API 리스트를 HTML 화면으로 문서화하여 테스트 할 수 있는 라이브러리

- 서버가 가동되면서 @RestController를 읽어 API를 분석하여 HTML 문서를 작성한다.

 

Swagger가  필요한 이유

- REST API의 스펙을 문서화 하는 것은 매우 중요하다. API를 변경할 때마다 Reference 문서를 계속 바꿔야하는 불편함이 있다.

 

Swagger 설정 방법

@Configuration : 어노테이션 기반의 환경 구성을 돕는 어노테이션 IoC Container에게 해당 클래스를 Bean 구성 Class 임을 알려준다.

 

@Bean : 개발자가 직접 제어가 불가능한 외부 라이브러리 등을 Bean으로 만들 경우에 사용

 

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

Spring Boot와 Kotlin: 기본 개념과 시작하기  (3) 2025.03.01
REST 와 RESTful  (0) 2024.02.07
Post API  (0) 2023.11.02
Spring Boot 기초  (0) 2023.11.01
REST API  (2) 2023.10.30

리소스를 추가하기 위해 사용되는 API

@PostMapping : POST API를 제작하기 위해 사용되는 어노테이션 @RequestMapping + POST method의 조합이다.

일반적으로 추가 하고자 하는 Resouce를 http body에 추가하여 서버에 요청한다. 그렇기 때문에 @RequestBody를 이용하여 body에 담겨있는 값을 받아야 한다.

 

// http://localhost:8080/api/test/vi/post-api/member
// 해당 URL로 member 데이터를 넘겨주면 해당 데이터의 키값과 value값을 return 하는 예제
@PostMapping(value="/member")
public String postMember(@RequestBody Map<String, Object> postData) {
	StringBuilder sb = new StringBuilder();
    
    postData.entrySet().forEach(map -> {
    	sb.append(map.getKey() + ":" + map.getValue() + "\n");
    });
    
    return sb.toString();
}





// DTO를 사용하는 방식
// key와 value가 정해져있지만, 받아야할 파라미터가 많을 경우 DTO객체를 사용한다.
// GetMapping 과 다른점은 @RequestBody를 꼭 붙여야 한다는 것이다.
@PostMapping(value-"/member2")
public String postMemberDto(@RequestBody MemberDto memberDto) {
	return memberDto.toString();
}

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

REST 와 RESTful  (0) 2024.02.07
Swagger  (1) 2023.11.08
Spring Boot 기초  (0) 2023.11.01
REST API  (2) 2023.10.30
Maven 과 Gradle  (0) 2023.10.29

컨트롤러 (Controller)

모델(Model)과 뷰(View) 사이에서 브릿지 역할을 수행한다. 앱의 사용자로부터 입력에 대한 응답으로 모델 및 뷰를 업데이트 하는 로직을 포함하여 사용자의 요청은 모두 컨트롤러를 통해 진행되어야 한다. 컨트롤러로 들어온 요청은 모델이 어떻게 처리할지 결정하여 모델로 요청을 전달한다.

 

@RestController

  • Spring Framework 4 버전부터 사용가능한 어노테이션
  • @Controller에 @ResponseBody가 결합된 어노테이션
  • 컨트롤러 클래스 하위 메소드에 @ResponseBody 어노테이션을 붙이지 않아도 문자열과 JSON 등을 전송할 수 있음
  • View를 거치지 않고 HTTP ResponseBody에 직접 Return 값을 담아 보내게 된다.

 

 

@RquestMapping

MVC의 핸들러 매핑(Handler Mappin)을 위해서 DefaultAnnotationHandlerMapping을 사용한다. DefaultAnnotationHandlerMapping 매핑정보로 @RequestMapping 어노테이션을 활용 클래스와 메소드의 RequestMapping을 통해 URL을 매핑하여 경로를 설정하여 해당 메소드에서 처리한다.

 

value : url 설정

method : GET, POST, DELETE, PUT, PATCH 등

 

스프링 4.3버전 부터 메소드를 지정하는 방식보다 간단하게 사용할 수 있는 어노테이션을 사용할 수 있음

  • @GetMapping
  • @PostMapping
  • @DeleteMapping
  • @PutMapping
  • @PatchMapping

 

 

 

 

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

REST 와 RESTful  (0) 2024.02.07
Swagger  (1) 2023.11.08
Post API  (0) 2023.11.02
REST API  (2) 2023.10.30
Maven 과 Gradle  (0) 2023.10.29

API 란?

Application Programming Interface 의 줄임말

응용 프로그램에서 사용할 수 있도록 다른 응용 프로그램을 제어할 수 있게 만든 인터페이스를 뜻한다. API를 사용하면 내부 구현 로직을 알지 못해도 정의되어 있는 기능을 쉽게 사용할 수 있다.

 

인터페이스(Interface)란 어떤 장치간 정보를 교환하기 위한 수단이나 방법을 의한다. 대표적인 예로는 마우스, 키보드, 터치패드 등이 있다.

 

REST 란?

REST는 Representational State Transfer의 줄임말

자원의 이름으로 구분하여 해당 자원의 상태를 교환하는 것을 의미한다. REST는 서버와 클라이언트의 통신 방식 중 하나이다.

HTTP URI(Uniform Resource Identifier)를 통해 자원을 명시하고 HTTP Method를 통해 자원을 교환하는 것이다.

*HTTP Method : Create, Read, Update, Delete

 

REST 의 특징 

1. Server-Client 구조

  자원이 있는 쪽이 Server, 요청하는 쪽이 Client 

  클라이언트와 서버가 독립적으로 분리되어 있어야 한다.

 

2. Stateless

  요청 간에 클라이언트 정보가 서버에 저장되지 않아야 한다.

  서버는 각각의 요청을 완전히 별개의 것으로 인식하고 처리해야 한다.

 

3. Cacheable

  HTTP 프로토콜을 그대로 사용하기 때문에 HTTP의 특징인 캐싱 기능을 적용하였다.

  대량의 요청을 효율적으로 처리하기 위해 캐시를 사용한다.

 

4. 계층화 (Layered System)

  클라이언트는 서버의 구성과 상관 없이 REST API 서버로 요청.

  서버는 다중 계층으로 구성될 수 있다.(로드밸런싱, 보안 요소, 캐시 등)

 

5. Code on Demand

  요청을 받으면 서버에서 클라이언트로 코드 또는 스크립트를 전달하여 클라이언트 기능 확장

 

6. 인터페이스 연관성(Uniform Interface)

  정보가 표준 형식으로 전송되기 위해 구성 요소간 통합 인터페이스를 제공한다.

  HTTP 프로토콜을 따르는 모든 플랫폼에서 사용 가능하게끔 설계

 

 

REST 의 장점

 HTTP 표준 프로토콜을 사용하는 모든 플랫폼에서 호환 가능하다.

 서버와 클라이언트의 역할을 명확하게 분리해준다.

 여서 서비스 설계에서 발생하는 문제점을 최소화 해준다.

 

 

REST API 란?

 REST 아키텍쳐의 조건을 준수하는 어플리케이션 프로그래밍 인터페이스를 뜻한다. 

최근 많은 API 가 REST API로 제공되고 있다. 일반적으로 REST 아키텍쳐를 구현하는 웹 서비스를 RESTful 하다고 표현한다.

 

 

REST API 특징

REST 기반으로 시스템을 분산하여 확장성과 재사용성을 높인다. HTTP 표준을 따르고 있어 여러 프로그래밍 언어로 구현할 수 있다.

 

REST API 설계 규칙

1. 웹 기반의 REST API를 설계할 경우에는 URI 를 통해 자원을 표현해야 한다.

  ex ) https://thinkground.studio/member/589   

       Resource : member

       Resource id : 589

 

2. 자원에 대한 조작은 HTTP Method(CRUD)를 통해 표현해야 한다.

  URI 에 행위가 들어가서는 안되고, HEADER를 통해 CRUD를 표현하여 동작을 요청해야 한다.

 

3. 메세지를 통한 리소스 조작

  HEADER를 통해 content-type을 지정하여 데이터를 전달한다. 대표적 형식으로는 HTML, XML, JSON, TEXT 가 있다.

 

4. URI에는 소문자를 사용한다.

 

5. Resource의 이름이나 URI가 길어질 경우 하이픈(-)을 통해 가독성을 높일 수 있다.

 

6. 언더바(_)는 사용하지 않는다.

 

7. 파일 확장자를 표현하지 않는다.

 

 

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

REST 와 RESTful  (0) 2024.02.07
Swagger  (1) 2023.11.08
Post API  (0) 2023.11.02
Spring Boot 기초  (0) 2023.11.01
Maven 과 Gradle  (0) 2023.10.29

빌리 관리 도구란?

프로젝트에서 필요한 xml, properties, jar 파일들을 자동으로 인식하여 빌드해주는 도구 

소스 코드를 컴파일, 테스트, 정적분석 등을 하여 실행가능한 앱으로 빌드해줌

프로젝트 정보 관리, 테스트 빌드, 배포 등의 작업을 진행해줌

외부 라이브러리를 참조하여 자동으로 다운로드 및 업데이트의 관리해줌 

 

자바의 대표적인 빌드도구 : Ant, Maven, Gradle

 

 

메이븐 (Maven) 이란?

자바의 대표적인 관리 도구였던 Ant를 대체하기 위해 개발됨

프로젝트의 외부 라이브러리를 쉽게 참조할 수 있게 pom.xml 파일로 명시하여 관리 

참조한 외부 라이브러리에 연관된 다른 라이브러리도 자동으로 관리됨

 

메이븐을 사용하는 이유 

기존에 사용하던 Ant는 빌드의 기능만 가지고 있음

자동으로 라이브러리를 관리해주는 기능이 추가된 Maven을 사용

다운받아 사용하던 라이브러리에 변동 사항이 있으면 자동으로 업데이트 하여 적용됨

 

Ant

  • XML 기반의 빌드 스크립트
  • 자유로운 빌드 단위 지정
  • 간단하고 사용하기 쉬움
  • 대규모 프로젝트에서 복잡해지는 경향이 있음
  • 라이프 사이클이 없음

 

Maven

  • XML 기반의 빌드 스크립트
  • 라이프 사이클 도입
  • pom.xml로 편하게 Dependency 관리
  • 대규모 프로젝트에서 복잡해지는 경향이 있음
더보기

pom.xml의 역할

- 프로젝트 정보 관리

- 해당 프로젝트에서 사용하는 외부 라이브러리 관리

- 해당 프로젝트의 빌드 관련 설정

 

Maven의 대표 태그 설명

  • modelVersion : maven의 버전을 의미
  • groupId : 프로젝트 그룹 id를 뜻하며, 일반적으로 대표하는 사이트 도메인을 역순으로 적어 사용
  • artifactId : groupId외에 다른 프로젝트와는 구분될 수 있는 프로젝트의 id를 작성
  • version : 프로젝트의 버전을 의미하며 개발 단계에 따라 구분하여 작성
  • name : 프로젝트의 이름
  • description : 해당 프로젝트의 간략한 설명을 작성
  • properties : pom.xml 파일 내에서 빈번하게 사용되는 중복 상수를 정의하는 영역 해당 영역의 상수를 사용하기 위해서는 ${태그명} 의 형태로 사용한다.
  • dependendies : 해당 프로젝트에서 의존성을 가지고 사용하는 라이브러리를 정의하는 영역 각 라이브러리마다 <dependency> 태그를 사용하여 구분
  • build : 프로젝트 빌드와 관련된 정보를 설정하는 영역

 

Gradle 이란?

Groovy 스크립트를 활용한 빌드 관리 도구

안드로이드 프로젝트의 표준 빌드 시스템으로 채택

멀티 프로젝트(Multi-Project)의 빌드에 최적화 하여 설계됨

Maven에 비해 더 빠른 처리속도를 가지고 있음

Maven에 비해 더 간결한 구성이 가능함

 

Gradle과 Maven 비교

  • Gradle에 비해 Maven이 점유율이 더 높은 상황(점차 Gradle 점유율이 오르는 중)
  • Gradle에 비해 Maven 성능이 떨어짐
  • Maven에 비해 Gradle이 대규모 프로젝트에서의 성능이 좋음
  • Mavne : pom.xml  Gradle : build.gradle
  • Gradle은 설치 없이 사용할 수 있다. 

Gradle 대표 용어 설명

  • repositories : 라이브러리가 저장된 위치 등 설정
  • mavenCentral : 기본 Maven Repository
  • dependencies : 라이브러리 사용을 위한 의존성 설정

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

REST 와 RESTful  (0) 2024.02.07
Swagger  (1) 2023.11.08
Post API  (0) 2023.11.02
Spring Boot 기초  (0) 2023.11.01
REST API  (2) 2023.10.30

자바에서는 대표적으로 문자열을 처리하는 클래스로 String, StringBuilder, StringBuffer 라는 3가지 클래스를 제공한다.

3가지로 구분되는 이유는 무엇이며 무엇이 다른지 정리해보자.

 

가장 먼저 String 과 다른 클래스의 차이점은 String 은 immutable(불변), 다른 두 클래스는 mutable(가변)의 차이점이다.

 

String 자료형만으로도 + 연산이나 concat() 메소드로 문자열을 이어붙일 수 있다. 하지만 덧셈(+) 연산자를 이용해

String 인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운 String 인스턴스를 생성하게 되어 문자열을 많이 결합하면 할수록

공간의 낭비가 생기고 속도 또한 매우 느려지게 된다. 왜냐하면 초기 공간과 다른 값에 대한 연산에서 많은 시간과 자원을 사용하게 되기

때문이다.

 

String 으로 할당했을때 메모리 사용을 살펴보자

 

 

그래서 자바에서는 이러한 문자열 연산의 낭비를 막기 위해 문자열 전용 자료형을 제공해주는데 StringBuffer 이다.

StringBuffer 클래스는 내부적으로 Buffer 라고 하는 독립적인 공간을 가지게 되어, 문자열을 바로 추가할 수 있어 공간의

낭비도 없으며 문자열 연산 속도도 매우 빠르다는 특징이 있다.

 

StringBuffer sb = new StringBuffer(); // StringBuffer 객체 생성

sb.append("Hello");
sb.append(" "):
sb.append("Java");
String result = sb.toString();

System.out.println(result); // Hello Java

StringBuilder는 StringBuffer와 거의 비슷한 자료형인데 둘의 차이점은 

StringBuffer 는 멀티 스레드 환경에서 안전하다는 장점이 있고, StringBuilder 는 문자열 파싱 성능이 가장 우수하다는 장점이 있다.

 

정리하자면 

  • String은 짧은 문자열을 더할 경우 사용한다.
  • StringBuffer는 스레드에 안전한 프로그램을 개발할때, 개발 중인 시스템이 스레드에 안전한지 모를 경우 사용한다.
  • StringBuilder 는 스레드의 안전 여부가 상관 없는 프로그램을 개발할 때 사용하면 좋다.

 

StringBuffer 의 버퍼(데이터 공간)의 크기의 기본값은 16개의 문자열을 저장할 수 있는 크기이며, 생성자를 통해 그 크기를 

별도로 설정할 수도 있다. 

만약 문자열 연산중 할당된 버퍼의 크기를 넘겨도 상관없다. 자동으로 버퍼를 증가시켜 주기 때문이다.

 

메서드 설명
StringBuffer() 버퍼의 길이를 지정하지 않으면 크기가 16인 버퍼를 생성한다.
StringBuffer(int length) length 길이를 가진 StringBuffer 클래스의 인스턴스(buffer)를 생성
StringBuffer(String str) 지정한 문자열 (str)의 길이보다 16 만큼 더 큰 버퍼를 생성
StringBuffer append() 매개변수로 입력된 값을 문자열로 변환하여 StringBuffer 인스턴스가 저장하고 있는 
문자열의 뒤에 덧붙임
int capacity() StringBuffer 인스턴스의 버퍼크기 반환
int length() StringBuffer 인스턴스에 저장된 문자열의 길이 반환
char charAt(int index) 지정된 위치(index) 에 있는 문자를 반환
StringBuffer delete(int short, int end) 시작위치(start) 부터 끝 위치(end) 사이에 있는 문자를 제거, 단 end 위치의 문자는 제외
StringBuffer deleteCharAt(int index) 지정된 위치(index)의 문자를 제거
StringBuffer insert(int pos, boolean b)
StringBuffer insert(int pos, String str) 

등등
두 번째 매개변수로 받은 값을 문자열로 변황하여 지정된 위치(pos)에 추가 
StringBuffer replace(int start, int end, String str) 지정된 범위 (start ~ end) 의 문자들을 주어진 문자열로 변경
String toString() StringBuffer 인스턴스의 문자열을 String 으로 변환
void setLength(int newLength) 지정된 길이로 문자열의 길이를 변경 
길이를 늘리는 경우에는 나머지 빈공간들을 널문자(\u000)로 채운다.
String subString(int start) 지정된 밤위 내의 문자열을 String 으로 뽑아서 반환

StringBuffer 클래스의 메서드와 StringBuilder 클래스 메서드 사용법은 동일하다.

 

StringBuffer / StringBuilder 의 메모리공간을 살펴보자

따라서 값이 변경될 때마다 새롭게 객체를 만드는 String 보다는 문자열의 추가,수정,삭제가 빈번하게 발생한다면

StringBuffer / StringBuilder 를 사용하는것이 좋다.

 

간단하지만 이해하기 쉬운 예제로 for문을 돌면서 *을 추가하는 예제를 들 수 있다.

String str = "*";

for (int i = 1; i < 10; i++) {
	str += "*";
}
StringBuffer sb = new StringBuffer("*");

for(int i = 1; i < 10; i++) {
	sb.append("*");
}

String 객체일 경우 매번 * 문자열이 업데이트 될때마다 계속해서 메모리 블럭이 추가되게 되고, 일회용으로 사용된 이 매모리들은 후에 

Garbage Collector (GC)의 제거 대상이 되어 빈번하게 Minor GC를 일으켜 Full GC(Major GC)를 일으킬 수 있는 원인이 된다.

'Back-End > Java' 카테고리의 다른 글

스레드  (1) 2024.07.05
프로세스  (0) 2024.07.04
Java HTTP 통신  (4) 2024.06.12
Exception과 Transaction  (1) 2024.02.05
스프링이란 무엇일까?  (0) 2023.09.16

인덱스 수직적 탐색

정렬된 인덱스 레코드 중 조건을 만족하는 첫 번째 레코드를 찾는 과정이다. 즉, 인덱스 스캔 시작점을 찾는 과정이다.

 

인덱스 수직적 탐색은 루트(Root) 블록에서부터 시작한다. 루트를 포함해 브랜치(Branch) 블록에 저장된 각 인덱스 레코드는 하위 블록에 대한 주소값을 갖는다. 루트에서 시작하여 리프(Leaf) 블록까지 수직적 탐색이 가능한 이유다.

 

수직적 탐색 과정에 찾고자 하는 값보다 크거나 같은 값을 만나면, 바로 직전 레코드가 가리키는 하위 블록으로 이동한다.

여기서 중요한 것은 수직적 탐색은 조건을 만족하는 레코드를 찾는 과정이 아니라 조건을 만족하는 첫 번째 레코드를 찾는 과정임을 반드시 기억해야 한다.

 

 

인덱스 수평적 탐색 

수직적 탐색을 통해 스캔 시작점을 찾았다면, 찾고자 하는 데이터가 더 안 나타날 때까지 인덱스 리프 블록을 수평적으로 스캔한다. 인덱스에서 본격적으로 데이터를 찾는 과정이다. 인덱스 리프 블록끼리는 서로 앞뒤 블록에 대한 주소값을 갖는다. 즉, 양방향 연결 리스트(double linked list) 구조다. 좌에서 우로, 또는 우에서 좌로 수평적 탐색이 가능한 이유다.

 

인덱스를 수평적으로 탐색하는 이유는 첫째, 조건절을 만족하는 데이터를 모두 찾기 위해서고 둘째, ROWID를 얻기 위해서다. 필요한 컬럼을 인덱스가 모두 갖고 있어 인덱스만 스캔하고 끝나는 경우도 있지만, 일반적으로 인덱스를 스캔하고서 테이블도 액세스 한다. 이때 ROWID가 필요하다.

 

 

인덱스는 WHERE 절에 자주 등장하는 컬럼에 지정하거나, ORDER BY에 자주 사용되는 컬럼에 사용해주면 좋다.

 

선택도가 낮은 컬럼을 앞쪽에 두고 결합인덱스를 생성해야 검사 횟수를 줄일 수  있어 성능에 유리하다.

'Back-End > DB' 카테고리의 다른 글

SQL 파싱과 최적화  (3) 2024.07.25
Lock 과 트랜잭션 동시성 제어 (Oracle)  (3) 2024.07.23
인덱스의 기본  (3) 2023.10.11
인덱스를 사용하는 이유  (0) 2023.09.14
DB 설계를 잘못하면 생기는 일  (1) 2023.09.13

+ Recent posts