spring

게시판 프로젝트- 2

kimkim615 2024. 7. 25. 00:47
전체 구조

 

접근 과정

 
1. 클라이언트에서 dto를 통해 요청이 들어온다
2. dto로 controller에 도착하면, controller에서 비즈니스 로직이 있는 service를 호출한다.
3. service에서 비즈니스 로직을 수행하는데, 이 때 DB 접근이 필요할 시 Repository로 이동한다.
4. Repository에서 쿼리문을 통한 트랜잭션 실행시 Domain을 호출한다
 

dto 

dto는 데이터를 저장해서 계층 간 데이터를 교환해준다.
로직이 없고, 순수한 데이터 객체이다.

Request DTO는 클라이언트로부터 전달받은 요청 데이터를 담고 있는 객체이며,
컨트롤러에서 사용되어 비즈니스 로직에서 필요한 데이터를 추출하여 서비스나 DAO에 전달하는 용도로 사용된다.

Response DTO 는 비즈니스 로직에서 생성된 데이터를 클라이언트에 반환하기 위한 객체이며, 컨트롤러에서 생성되어 클라이언트에 반환된다.
Response DTO 클래스는 클라이언트가 필요로 하는 최소한의 정보만을 전달하기 위해 사용된다.

BoardRequestDto

 
< Request DTO를 사용하는 이유 >

1. @RequestParam으로 데이터를 일일이 받을 필요 없이 객체 하나로 한꺼번에 받을 수 있다.
2. Bean Validation, Contoller에서 검증 기능 분리 가능
3. 엔티티 내부를 캡슐화할 수 있다. (엔티티의 값이 변경되지 않도록 한다)
 
 
@AllArgsConstructor : 모든 필드를 매개변수로 받는 생성자가 자동 생성된다. 
이는 DTO 객체를 쉽게 생성할 수 있게 해준다.
 
@Getter : 모든 필드에 대해 getter 메서드 자동 생성된다.
이는 객체의 필드 값을 읽을 때 유용하다. 예를 들어 getName() getTitle()과 같은 ...
 
 

BoardResponseDto

 
< Response DTO를 사용하는 이유 >
1. 넘겨줄 필요가 없는 데이터를 보내지 않을 수 있다. (화면에 꼭 필요한 데이터만 보내줄 수 있다)
2. 순환참조를 예방할 수 있다.
3. 엔티티 내부 캡슐화 가능
 
< BoardRequestDto에서는 id, createAt, modifiedAt이 없는 이유 >
id, createAt, modifiedAt 모두 서버에서 엔티티가 생성되거나 수정될 때 자동으로 할당되고 설정되는 값들이므로클라이언트가 요청할 때, 제공할 필요가 없는 것들이다.
 
< 생성자가 있는 이유 >
이 생성자는 Board 엔티티 객체를 받아서, 그 엔티티의 데이터를 BoardResponseDto에 설정한다.
생성자가 호출되면 Board 객체 값을 매개변수로 받고, id나 name과 같은 필드에다가 그 값을 설정한다.
 

Controller

클라이언트의 요청을 받고 비즈니스 로직이 있는 Service를 호출해서 처리를 위임한다.
그리고 그에 대한 처리 결과를 View를 통해 반환하는 역할을 한다.
 

 
@RestController : 이 클래스가 Restful 웹 서비스 컨트롤러임을 나타낸다.
이 클래스의 모든 메서드가 @ResponseBody의 의미를 가지게 된다.
이 어노테이션으로 HTTP 요청을 처리하고 JSON 형태로 응답을 반환한다. 
그리고 @Controller와 @ResponseBody를 동시에 적용할 수 있으므로,
HTTP 응답 본문에 직접 데이터 객체를 작성할 수 있으며 이는 일반적으로 JSON 또는 XML 형식으로 클라이언트에 전송함
 
@RequestMapping("/api") : 이 컨트롤러의 모든 엔드포인트가 /api 경로로 시작된다.
* 엔드포인트: 웹 서비스에서 클라이언트가 접근할 수 있는 특정 경로를 의미하는데,
API 요청을 처리하는 URL과 HTTP 메서드를 결합한 것이다.
 
@RequiredArgsConstructor : final 필드에 대한 생성자 자동 생성 -> BoardServiceImpl에 대한 의존성 주입을 위해
 

1. 게시글 생성

클라이언트가 게시글 요청을 보내면 컨트롤러가 이를 받아 서비스 계층에 전달하고,
서비스 계층은 요청에 대한 작업(ex 게시글 생성 조회…)을 하고 데이터베이스에 저장한 뒤,
게시글의 데이터를 클라이언트에게 응답한다.
 
@PostMapping : HTTP POST 요청을 처리한다
ResponseEntity : HTTP 응답을 제어하고 구성할 수 있는 스프링 클래스이다.
응답본문(body), HTTP 상태 코드(status code), 헤더(headers) 등을 설정할 수 있게 해준다. 

과정

1.  클라이언트가 새로운 게시글 생성을 위해 /api/boards 경로로 POST 요청을 보낸다.
요청 본문에는 name, title, contents, password 가 포함된다.
 
2. 요청본문 @RequestBody가  BoardRequestDto 객체로 변환되어서, 서비스의 메서드 createBoard에 전달된다
 
3. 서비스의 메서드를 호출해서 새로운 게시글을 생성한다.
 
4. 생성된 게시글의 데이터를 포함한 BoardResponseDto와 HTTP 상태 코드 201 Created를 함께 클라이언트에 반환한다. 
 

2. 게시글 조회 - 전체

과정

 
1. 클라이언트가 전체 게시글 조회를 위해 /api/boards 경로로 GET 요청을 보낸다.
 
2. 서비스의 메서드를 호출해서 모든 게시글을 조회한다.
 
3. 모든 게시글을 조회한 데이터를 포함한 BoardResponseDto와 HTTP 상태 코드 200 OK를 함께 클라이언트에 반환한다.
 

3. 게시글 조회 - 특정 id

과정

1.  클라이언트가 특정 ID로 게시글을 조회하기 위해 /api/boards/{id} 경로로 GET 요청을 보낸다.
요청 본문에는 name, title, contents, password 가 포함된다.
 
2. @PathVariable에서 URL 경로의 id 부분이 서비스의 메서드 'id' 파라미터로 전달된다.
 
3. 서비스의 메서드를 호출해서 id로 게시글을 조회한다.
 
4. id로 조회된 게시글 데이터를 포함한 BoardResponseDto와 HTTP 상태 코드 200 OK를 함께 클라이언트에 반환한다. 
 

4. 게시글 조회 - 특정 이름

과정

 
1.  클라이언트가 특정 이름으로 게시글을 조회하기 위해 /api/boards?name={name} 경로로 GET 요청을 보낸다.
 
2. @RequestParam에서 URL 경로의 name 부분이 서비스의 메서드 'name' 파라미터로 전달된다.
 
3. 서비스의 메서드를 호출해서 name으로 게시글을 조회한다.
 
4. 이름으로 조회된 게시글 리스트를 포함한 List<BoardResponseDto>와 HTTP 상태 코드 200 OK와 함께
클라이언트에 반환한다. 
 

5. 게시글 조회 - 특정 제목

과정

 
1.  클라이언트가 특정 제목으로 게시글을 조회하기 위해 /api/boards?title={title} 경로로 GET 요청을 보낸다
 
2. @RequestParam에서 URL 경로의 title 부분이 서비스 메서드의 'title' 파라미터로 전달된다.
 
3. 서비스의 메서드를 호출해서 title으로 게시글을 조회한다.
 
4. 제목으로 조회된 게시글 리스트를 포함한 List<BoardResponseDto>와 HTTP 상태 코드 200 OK와 함께
클라이언트에 반환한다.
 

6. 게시글 수정

과정

 
1.  클라이언트가 특정 ID의 게시글을 수정하기 위해 /api/boards/{id} 경로로 PUT 요청을 보낸다
요청 본문에는 수정할 게시글 데이터 name, title, contents, password 가 포함된다. 
 
2. @PathVariable에서 URL 경로의 id 부분이 서비스 메서드의 'id' 파라미터로 전달된다.
 
3. 요청본문 @RequestBody가  BoardRequestDto 객체로 변환되어서, 서비스의 메서드 updateBoard에 전달된다
 
4. 서비스의 메서드를 호출해서 게시글을 수정한다.
 
4. 수정된 게시글의 데이터를 포함한 BoardResponseDto와 HTTP 상태 코드 200 OK를 함께 클라이언트에 반환한다.
 

7. 게시글 삭제

과정

 
1.  클라이언트가 특정 ID의 게시글을 삭제하기 위해 /api/boards/{id} 경로로 DELETE 요청을 보낸다
요청 본문에는 삭제를 위한 데이터 password가 포함된다.
 
2. @PathVariable에서 URL 경로의 id 부분이 서비스 메서드의 'id' 파라미터로 전달된다.
 
3. 요청본문 @RequestBody 가 BoardRequestDto 객체로 변환되어서, 서비스의 메서드 deleteBoard에 전달된다.
 
4. 서비스의 메서드를 호출해서 게시글을 삭제한다.
 
5. 삭제된 결과 메세지와 HTTP 상태 코드 200 OK를 함께 클라이언트에 반환한다.
 
 

Service

controller의 요청을 받아서, 그 요청에 알맞은 정보로 가공해서 DB로 전달한다.
또 DB에게 전달 받은 데이터를 가공해서 클라이언트에게 전달한다.
주로 비즈니스 로직을 처리한다.
 

BoardService.java

 
 

BoardServiceImpl.java (1)
BoardServiceImpl.java (2)
BoardServiceImpl.java (3)

BoardService

BoardService 인터페이스는 게시글 저장, 검색, 수정, 삭제 메서드들을 정의해서 서비스 계층에서 게시글과 관련된
비즈니스 로직을 처리할 수 있도록 한다.
 
1. 게시글 생성 createBoard 메서드
2. 게시글 조회- 전체 getAllBoards 메서드
3. 게시글 조회- id getBoardById 메서드
4. 게시글 조회- 이름 getBoardByName 메서드
5. 게시글 조회- 제목 getBoardByTitle 메서드
6. 게시글 수정 updateBoard 메서드
7. 게시글 삭제 deleteBoard 메서드
 
 

BoardServiceImpl

BoardServiceImpl 클래스는 PostService 인터페이스를 구현해서 게시글 생성, 검색, 수정, 삭제와 같은 비즈니스 로직을 처리한다. 
@Service : 해당 클래스가 서비스 컴포넌트임을 나타낸다. 그리고 Bean 객체로 등록해서 스프링이 이 클래스를 관리하고 사용할 수 있게 한다.
 
@Transactional : 이 클래스의 메서드들이 트랜잭션 관리 하에 실행됨을 나타낸다.
먼저 캐시에 반영해서 이상이 없으면 DB에 반영한다. 오류방지를 위해 사용한다
모든 데이터베이스 작업이 성공하면 커밋되고, 실패하면 롤백된다.
서비스에 트랜잭션을 다는 이유는, 트랜잭션을 커밋하거나 롤백하는 단위는 단순히 데이터베이스
접근이 아니라 비즈니스 로직이다. - 하나의 비즈니스 로직은 하나의 트랜잭션으로 동작한다...
그러므로 비즈니스 로직을 관리하는 곳인 서비스에 단다
 

1. 게시글 생성

과정

 
1.  클라이언트가 새로운 게시글 생성을 요청한다.
 
2. passwordEncoder.encode를 호출해서 비밀번호를 암호화한다
 
3. 게시글 엔티티 Board 객체를 생성한다.
 
4. 암호화된 비밀번호를 Board 객체에 설정한다.
 
5. Board 객체를 데이터베이스 boardRepository에 저장한다.
 
6. 저장된 게시글 데이터가 담긴 saveBoard를 BoardResponseDto로 변환해서 반환한다.
 

2. 게시글 조회 - 전체

과정

 
1. findAllByOrderByModifiedAtDesc()를 호출해서 데이터베이스에서 모든 게시글을 조회한다.
 
2. 조회된 Board 엔티티 리스트를 BoardResponseDto 리스트로 변환한다.
 
3. 변환된 리스트를 클라이언트에 반환한다.
 

3. 게시글 조회 - 특정 id

과정

 
1.  findBoard 메서드로 특정 ID 게시글을 조회한다
 
2. 조회한 데이터가 있는 Board 객체를 BoardResponseDto로 변환한다.
 
3. 변환된 DTO를 클라이언트에 반환한다.
 
 

4. 게시글 조회 - 특정 이름

과정

 
1.  findByName을 호출해서 특정 이름 게시글을 데이터베이스에서 조회한다.
 
2. 조회된 Board 엔티티 리스트를 BoardResponseDto 리스트로 변환한다.
 
3. 변환된 리스트를 클라이언트에 반환한다.
 

5. 게시글 조회 - 특정 제목

과정

 
1.  findByTitle을 호출해서 특정 제목의 게시글을 데이터베이스에서 조회한다.
 
2. 조회된 Board 엔티티 리스트를 BoardResponseDto 리스트로 변환한다.
 
3. 변환된 리스트를 클라이언트에 반환한다.
 

6. 게시글 수정

과정

 
1.  클라이언트가 특정 ID의 게시글을 수정하기 위해 PUT 요청을 보내는데, 요청 본문에는 수정할 게시글의
비밀번호 데이터가 포함되어 있다.
 
2. 요청 본문에서 password 데이터를 추출한다.
 
3. findBoard 메서드를 호출해서, 데이터베이스에서 해당 ID의 게시글을 조회한다.
 
4. 입력된 비밀번호랑, 게시글에 저장된 비밀번호랑 일치하는지 확인한다.
비밀번호는 암호화되어 있으므로 matches 메서드를 사용한다
 
5. 비밀번호가 일치하면 requestDto의 내용을 사용해서 Board 객체의 필드를 수정한다.
 
6. 수정한 게시글의 id를 반환한다
 

7. 게시글 삭제

과정

 
1.  클라이언트가 특정 ID의 게시글을 삭제하기 위해 DELETE 요청을 보내는데, 요청 본문에는 삭제를 위한 데이터 password가 포함된다.
 
2. 요청 본문에서 password 데이터를 추출한다.
 
3.  findBoard 메서드를 호출해서, 데이터베이스에서 해당 ID의 게시글을 조회한다.
 
4. 입력된 비밀번호랑, 게시글에 저장된 비밀번호랑 일치하는지 확인한다.
비밀번호는 암호화되어 있으므로 matches 메서드를 사용한다
 
5. 비밀번호가 일치하면 boardRepository.delete(board)를 호출해서 삭제한다.
 
6. 삭제 완료 메세지를 반환한다.
 
+ 게시글 찾기 메서드 :
데이터 베이스에서 조회해서 특정 id의 게시글을 조회하고, 게시글 없으면 예외 발생시킨다.
있으면 조회한 Board 객체 반환시킨다.
 
 

Repository

Entity에 의해 생성된 DB에 접근하는 메서드를 사용하기 위해, 그리고 DB에 CRUD의 명령을 실행하게 만드는 인터페이스이다. 
 
JpaRepository를 상속하는 이유는 JPA에서 Repository 인터페이스를 생성 후,
JpaRepository<Entity, 기본키 타입>을 상속받으면 기본적인 Create, Read, Update, Delete가 자동으로 생성된다.
또, 메서드 이름에 따라 SQL 쿼리를 자동으로 생성해주어서, 데이터베이스에서 필요한 데이터를 조회할 수 있다.
 
 

BoardRepository.java

 
 
findById 메서드 :
데이터베이스에 해당 id의 게시글이 존재하면 Board 객체를 포함하고, 없으면 비어있는 Optional 객체를 반환한다
 
findByName 메서드 :
데이터베이스에 해당 이름의 게시글 존재시 Board 객체 리스트 포함, 없으면 비어있는 Optional 객체 반환
 
findByTitle 메서드 :
데이터베이스에 해당 제목의 게시글 존재시 Board 객체 리스트 포함, 없으면 비어있는 Optional 객체 반환
 
각 메서드는 주어진 조건에 따라 데이터베이스에서 게시글을 조회하고, 조회 결과를 Optional 객체나 리스트 형태로 반환해서 이후 서비스 계층에서 이를 활용할 수 있도록 한다.

Optional<T>는 null이 올 수 있는 값을 감싸는 Wrapper 클래스로, 참조하더라도 NPE가 발생하지 않도록 도와준다. Optional 클래스는 아래와 같은 value에 값을 저장하기 때문에 값이 null이더라도 바로 NPE가 발생하지 않는다.
 

Domain

JPA를 사용하여 데이터베이스의 board 테이블과 매핑되는 엔티티이다. 하나의 객체가 DB의 하나의 Column처럼 작용한다.

 
name, title, contents, password는 각각 board 테이블의 컬럼에 매핑되며 null 값을 허용하지 않는다.
생성자는 BoardRequestDto 객체를 사용해서 새로운 Board 객체를 생성할 때 초기 값을 설정한다.
update 메서드는 BoardRequestDto 객체를 받아서 기존 Board 엔티티의 특정 필드를 업데이트한다.
-> 그래서 password 필드는 업데이트되지 않는다.
 
 

 
 
@EntityListeners(AuditingEntityListener.class): JPA의 Auditing 기능을 추가해서 엔티티가 생성되거나 수정될 때 AuditingEntityListener가 타임스탬프를 자동으로 기록한다
 
 
 

Config

 
Spring Security를 사용하여 애플리케이션에서 비밀번호를 안전하게 관리하기 위한 설정을 정의한다.
비밀번호를 안전하게 저장하기 위해 해싱(hashing) 알고리즘을 사용하고,
이를 Spring Security의 PasswordEncoder 인터페이스를 통해 구현한다.
그리고 비밀번호를 안전하게 해싱하는 데 필요한 BCryptPasswordEncoder를 스프링 컨텍스트에 빈(bean)으로 등록한다.
 
* 해싱 (Hashing): 입력 데이터를 고정 길이의 문자열로 변환하는 과정으로, 보안 목적으로 주로 사용. 해싱된 값은 원래 데이터를 복원할 수 없다
 
@Configuration: 이 클래스가 하나 이상의 스프링 빈을 정의하고, 스프링 IoC 컨테이너에서 빈으로 등록될 것임을 나타낸다.
@Bean: 메서드가 스프링 컨텍스트에 의해 관리되는 빈을 반환할 것임을 나타낸다. 이 메서드에서 반환된 객체는 스프링 컨테이너에 빈으로 등록된다.

'spring' 카테고리의 다른 글

[Spring MVC 1편] 웹 애플리케이션 이해  (4) 2024.07.30
Port 8080 was already in use. 에러 해결  (7) 2024.07.25
RequestDto, ResponseDto  (3) 2024.07.23
게시판 프로젝트  (0) 2024.07.18
entity와 domain, dto  (0) 2024.07.18