1. Component

 - Reac의 가장 큰 특징이자 장점은 Component-based, 컴포넌트 기반이라는 것이다. 컴포넌트란 하나의 의미를 가진 독립적인 단위의 모듈로 나만의 HTML이라고 생각할 수 있다. UI의 일부를 제어하는 재사용 가능한 코드이다. 또 JavaScript에서 함수의 역할을 React에게서 담당하는 것과 같다. 

  • 함수형 컴포넌트
  • 클래스 컴포넌트

  1-1 함수형 컴포넌트

function Welcome(props) {
	return <h1> Hello, {props.name} </h1>;
}

 위 예시에서 Welcome은 함수형 컴포넌트로, props를 인수로 받아 React 요소를 반환한다.

 

 1-2 클래스 컴포넌트

class Welcome extends React.Component {
	render() {
    	return <h1>Hello, {this.props.name}</h1>;
    }
}

 

클래스 컴포넌트의 경우 더 복잡하고 더 많은 기능을 제공한다. render 메서드를 포함해야 한다.

 

*함수형 컴포넌트에서 React Hooks 사용

  React Hooks는 함수 컴포넌트에서 상태와 다른 React 기능을 사용할 수 있도록 하는 함수이다. 클래스 컴포넌트로 변환하지 않고도 함수 컴포넌트에서 사용가능하다.

 

 * useState와 useEffect Hooks 이해

  useState와 useEffect는 React Hooks를 사용하는데 기본적인 역할을 한다.

  • useState : 컴포넌트에 상태를 추가하는 데 사용한다. 초기 상태를 인수로 받고 현재 상태와 상태를 업데이트하는 함수로 구성된 배열을 반환한다.
const [count, setCount] = useState(0);

// 해당 예시에서 const는 현재 상태이고 setCount는 상태를 업데이트하는 함수이다.
  • useEffect : 이 훅은 클래스 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount 라이프사이클 메서드와 같은 역할을 한다. 기본적으로 첫 번째 렌더링을 포함하여 모든 렌더링 이후에 실행된다.
useEffect(() => {
	document.title = `You clicked ${count} times`;
}, [count]);

// 이 예시에서 useEffect 혹은 count 상태가 변경될 때마다 문서 제목을 업데이트한다.

 

 

 

2. Props

props는 상위 컴포넌트가 하위 컴포넌트에게 내려주는 데이터이다. props는 객체이다. props는 읽기 전용이며, 받은 컴포넌트에서 변경해서는 안된다.

function Greeting(props) {
	return <h1>Hello, {props.name}</h1>;
}

위 예제에서 Alice 문자열을 Greeting 컴포넌트에 props로 전달한다.컴포넌트 내부에서는 이 props를 props.name으로 접근할 수 있다. 이러한 Props는 왜 사용하는 것일까?

  1. 데이터 흐름 : React에서 데이터 흐름은 단방향적이다. 즉, 데이터는 부모 컴포넌트에서 자식 컴포넌트로 흐르는 구조이다. 이로써 데이터 흐름이 예측 가능하고 추적하기 쉬워지며, 디버깅이나 테스트 시에 유용하다.
  2. 컴포넌트 재사용성: props를 사용하면 재사용 가능한 컴포넌트를 만들 수 있다. 컴포넌트에 값을 하드코딩하는 대신, props를 사용하여 동일한 컴포넌트에 다른 데이터를 전달함으로써 컴포넌트를 동적이고 재사용 가능하게 만들 수 있다.
  3. 관심사의 분리 : props를 사용하면 컴포넌트가 더 독립적이고 캡슐화된 형태가 된다. 컴포넌트는 앱의  다른 상태를 알 필요가 없으며, 자신의 데이터를 표시하고 자체 상태를 처리하는 데 집중할 수 있다.
  4. 컴포넌트간의 통신 : props를 통해 데이터뿐만 아니라 함수도 자식 컴포넌트로 전달할 수 있다. 이는 자식 컴포넌트가 props로 전달받은 함수를 호출하여 부모 컴포넌트에게 통신할 수 있는 것을 의미한다.

* PropTypes를 사용한 프롭스 유효성 검사

import PropTypes from 'prop-types';

function Greeting(props) {
	return <h1>Hello, {props.name}</h1>;
}

Greeting.propTypes = {
	name: PropTypes.string.isRequired,
};

PropTypes는 JavaScript 객체의 유형을 검사하는 데 사용되는 라이브러리이다. 해당 라이브러리를 사용하여 컴포넌트가 받는 프롭스가 올바른 유형인지 확인할 수 있다. 

 

 

3. State

state는 컴포넌트가 독립적으로 갖는 상태이다. 이 역시 객체의 형태로, 컴포넌트 안에서만 제어되어 보관, 관리된다.

welcome 메세지 뒤에 메세지가 렌더링 될 때의 현재 시각을 알려주는 메세지를 같이 렌더링 해보자.

class CLock extends React.Component {
	constructor(props) {
    	super(props)l
        this.state = {date : new Date()};
    }
    
render() {
	return (
    	<div>
        	<h1>Hello, {this.props.name}</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
        </div>
    );
 }
}

ReactDOM.render(
	<Clock name="Jaon"/>,
    document.getElementById('root')
);


// Clock 이라는 컴포넌트를 만들고 date라는 state를 지정해주면 

// Hello, world!
// it is 오후 4:16:26.

// 이렇게 출력이 된다.

'Front-End > React&Next.js' 카테고리의 다른 글

Promise / async / await  (1) 2024.04.03

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

+ Recent posts