• 1. 소스코드
• 2. 데이터 베이스(Mysql)
• 3. FrontEnd(React.js)
• 3. Backend
o 3-1 CONTROLLER
o 3-2 DTO
o 3-3 ENTITY
o 3-4 Repository
o 3-5 Service
o 3-6 application.yml
React.js 소스 코드
https://github.com/eternityhwan/osc-board-front
도커 이미지
https://hub.docker.com/repository/docker/mirrorkyh/oscboardfront
SpringBoot 소스 코드
https://github.com/eternityhwan/osc-board-back
도커 이미지
https://hub.docker.com/repository/docker/mirrorkyh/oscboard
3-1 CONTROLLER
@RestController
@Slf4j
@CrossOrigin(origins = "*") // 프론트앤드와 통신 CORS 문제 해결
@Tag(name = "게시판", description = "게시판")
public class BoardApiController {
@Autowired // DI 생성 객체를 가져와 연결.
private ArticleService articleService;
// FindAll Get
@Operation(summary = "게시물 전체건수 조회", description = "게시물 전체건수를 조회합니다.")
@GetMapping(value = "/api/boards")
public List<Article> index() {
return articleService.index();
}
// Get by id
@Operation(summary = "게시물 개별건수 조회", description = "게시물 개별건수를 조회합니다.")
@GetMapping(value = "/api/boards/{id}")
public Article search(@PathVariable Long id) {
return articleService.search(id);
}
// POST
// @RequsestBody로 Dto 클래스를 받는다
@Operation(summary = "게시물 작성 ", description = "게시물을 작성합니다.")
@PostMapping(value = "/api/boards/posts")
public ResponseEntity<Article> post(@RequestBody ArticleDto dto) {
Article posts = articleService.dbPosts(dto);
return (posts != null) ?
ResponseEntity.status(HttpStatus.OK).body(posts) :
ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
// PATCH
@Operation(summary = "개별 게시믈 수정", description = "게시믈 수정합니다.")
@PatchMapping(value = "/api/boardsR/{id}")
public ResponseEntity<Article> update(
@PathVariable Long id,
@RequestBody ArticleDto dto) {
// 서비스에게 revision 메소드를 시킨다(파라메터 id와 dto를 넘겨준다)
// updated 객체로 넘겨준다.
// Controller는 Controller의 코드만 가지고 있는다.
// 뭘 받고 뭘 리턴하는지만 알면 된다.
Article updated = articleService.revision(id, dto);
return (updated != null) ?
ResponseEntity.status(HttpStatus.OK).body(updated) :
ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
// 굿 요청 ResponseEntity 상태 ok를 넣어주고 body에 update 객체를 반환해준다.
// 배드 요청 ResponseEntity 상태 bad를 넣고 몸통없이 빌드해서 보여주면된다.
}
// DELETE
@Operation(summary = "게시믈 삭제", description = "게시믈을 삭제합니다.")
@DeleteMapping(value = "/api/boardsD/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
Article deleted = articleService.delete(id);
return (deleted != null) ?
ResponseEntity.status(HttpStatus.NO_CONTENT).build() :
ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
}
3-2 DTO
@AllArgsConstructor
@ToString
public class ArticleDto {
private Long id;
private String title;
private String content;
public Article toEntity() {
return new Article(id, title, content);
// Entity 클래스의 객체 Article 선언
}
}
3-3 ENTITY
@Entity // 엔티티 어노테이션을 붙여줘야 객체를 인식한다.
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Getter
public class Article {
@Id // 대표값을 지정 고유의 값
@GeneratedValue // 자동 생성
private Long id;
@Column // DB에서 인식하게 컬럼을 붙여준다 세로줄.
private String title;
@Column
private String content;
public void patch(Article article) {
if ( article.title != null)
this.title = article.title;
if (article.content != null)
this.content = article.content;
}
}
3-4 Repository
JPA 활용을 위해 CrudRepository 사용하였고
findall 의 반환 타입을 수정하였습니다.
@Repository
public interface ArticleRepository extends CrudRepository<Article, Long> {
// <관리대상엔티티, 대표값의 타입(Article의 대표값 id의 타입은 long)> 입력
@Override
List<Article> findAll();
}
3-5 Service
@Service // 서비스 선언 (서비스 객체를 스프링부트에 생성)
@Slf4j
public class ArticleService {
@Autowired // 의존성 주입, 서비스는 레파지토리만 바라본다.
private ArticleRepository articleRepository;
// get all
public List<Article> index() {
return articleRepository.findAll();
}
// get id
public Article search(Long id) {
return articleRepository.findById(id).orElse(null);
}
// post
public Article dbPosts(ArticleDto dto) {
// 1. dto를 받았으면 dto를 entity로 바꾸고
// 1-1.Entity article 객체로 바꾼다
Article article = dto.toEntity();
// article가 null이 아니면 null을 반환해라
// 수정이 안되게 아이디가 존재한다면 null을 반환해라 명령
if (article.getId() != null) {
return null;
}
// Entity 객체인 article 객체롤 DB에 저장하면된다
return articleRepository.save(article);
}
public Article revision(Long id, ArticleDto dto) {
// 1. 수정용 엔티티 생성
Article article = dto.toEntity();
log.info("id: {}, article: {}", id, article.toString());
// 2. 대상 엔티티를 조회
Article targetEntity = articleRepository.findById(id).orElse(null);
// 3. 잘못된 요청 처리 (대상이 없거나, id가 다른경우)
if (targetEntity == null || id != article.getId()) {
log.info("잘못된 요청 : id: {}, article: {}", id, article.toString());
return null;
}
// 4. 업데이트
targetEntity.patch(article);
Article updated = articleRepository.save(targetEntity);
return updated;
}
public Article delete(Long id) {
// 1. 대상 찾기
Article targetEntity = articleRepository.findById(id).orElse(null);
// 1-1 잘못된 요청 처리
if (targetEntity == null) {
return null;
}
// 2. 대상 삭제
articleRepository.delete(targetEntity);
return targetEntity;
}
}
}
3-6 application.yml
# MySQL8 설정
spring:
datasource :
driver-class-name : com.mysql.cj.jdbc.Driver
url: jdbc:mysql://ec2-3-38-111-117.ap-northeast-2.compute.amazonaws.com:3306/oscboard?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 1q2w3e4r
# 콘솔에 SQL 출력 여부
jpa:
show-sql: true
database-platform: org.hibernate.dialect.MySQL8Dialect
# hibernate 설정
database : mysql
hibernate.ddl-auto : update
hibernate.naming.strategy : org.hibernate.cfg.ImprovedNamingStrategy
hibernate.naming.physical-strategy : org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
generate-ddl : false
properties.hibernate.format_sql : true
properties.hibernate.enable_lazy_load_no_trans : true
느낀점.
1. 과제를 최대한 쉬운 방법으로 진행할 수 있게 배려 주신 이사님에게 감사드립니다.
2. 충분한 시간이었으나 여유롭지 않았습니다.
3. 코드 작성하면서 다시 한번 아는 것을 복습하는 기회가 되었습니다.
4. 구현은 하였지만 문서로 정리하면서 더 구체적으로 복기하는 기회를 주셨으면 합니다.