주소 요청에 대한 이해

Q1) 클라이언트 요청에 대한 주소 만들기

1
2
3
4
5
6
7
8
9
10
11
컨트롤러 인식을 위한 Controller 어노테이션 이용
주소 매핑 : RequestMapping
HTTP 메소드 : GET
리턴  : X
주소 : "/first-url"

@Controller
public class Controller {
    @RequestMapping(value = "/first-url", method = RequestMethod.GET)
    public void first() {}
}

Q2) 클라이언트 요청에 대한 주소와 문자열을 리턴하는 함수를 작성해 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
컨트롤러 인식을 위한 Controller 어노테이션 이용
주소 매핑 : RequestMapping
HTTP 메소드 : GET
요청 주소 : "helloworld"
리턴  : "hello world"
주소 : "/helloworld"
    
@Controller
public class Controller {
    @ResponseBody
    @RequestMapping("/helloworld")
    public String helloWorld() {
        return "hello world";
    }
}

Q3) 클라이언트 요청에 대한 주소에 대한 Rest 함수를 작성해 봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
컨트롤러 인식을 위한 Controller 어노테이션 이용
주소 매핑 : RequestMapping이 아닌 Rest 형식의 어노테이션 이용
HTTP 메소드 : GET
요청 주소 : "/hello-spring"
리턴  : "hello spring" 
문자열을 리턴하기 위한 어노테이션 이용

@RestController
public class Controller {
    @RequestMapping(value = "/hello-spring", method = RequestMethod.GET)
    public String helloSpring() {
        return "hello spring";
    }
}

:bulb:RestController(Json 반환) = Controller(View 반환) + ResponseBody(Data를 반환하기 위한 annotation)

Q4) 클라이언트 요청에 대한 Rest 형식의 함수를 작성해 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
Rest Controller 어노테이션 이용
주소 매핑 : Rest 형식의 어노테이션 이용
HTTP 메소드 : GET
요청 주소 : "/hello-rest"
리턴  : "hello rest"
    
@RestController
public class Controller {
    @GetMapping("/hello-rest")
    public String helloRest() {
        return "hello rest";
    }
}

Q5) 클라이언트 요청에 대한 Rest API 형식의 함수를 작성해 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
Rest Controller 어노테이션 이용
주소 매핑은 Rest 형식의 어노테이션 이용
HTTP 메소드 : GET
요청 주소 : "/api/helloworld"
리턴  : "hello rest api"
    
@RestController
public class Controller {
    @GetMapping("/api/helloworld")
    public String helloRestApi() {
        return "hello rest api";
    }
}

게시판 기본 목록

Q1) 공지사항 게시판의 목록에 대한 요청을 처리하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
REST API 형식으로 구현
HTTP METHOD : GET
요청 주소 : "/api/notice"
리턴값 : "공지사항입니다."
    
@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public String noticeString() {
        return "공지사항입니다.";
    }
}

Q2) 공지사항 게시판의 목록에 대한 요청을 처리하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
REST API 형식으로 구현
HTTP METHOD : GET
요청 주소 : "/api/notice"
리턴값 : 공지사항 게시판의 내용을 추상화한 모델(게시글ID, 제목, 내용, 등록일)이며 아래 내용을 리턴
게시글ID = 1, 제목 = 공지사항입니다, 내용 = 공지사항 내용입니다, 등록일 = 2024-1-31

@Setter
@Getter
public class NoticeModel {
    private int id;
    private String title;
    private String contents;
    private LocalDateTime regDate;
}

@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        LocalDateTime regDate = LocalDateTime.of(2024, 1, 31, 0, 0);

        NoticeModel notice = new NoticeModel();
        notice.setId(1);
        notice.setTitle("공지사항입니다.");
        notice.setContents("공지사항 내용입니다.");
        notice.setRegDate(regDate);

        return notice;
    }
}

Q3) 공지사항 게시판의 목록에 대한 요청을 처리하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
REST API 형식으로 구현
HTTP METHOD : GET
요청 주소 : "/api/notice"
리턴값 : 공지사항 게시판의 내용을 추상화한 모델(게시글ID, 제목, 내용, 등록일)이며 아래 내용을 리턴
게시글ID = 1, 제목 = 공지사항입니다, 내용 = 공지사항 내용입니다, 등록일 = 2024-1-30
게시글ID = 2, 제목 = 두번째 공지사항입니다, 내용 = 두번째 공지사항 내용입니다, 등록일 = 2024-1-31
    
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class NoticeModel {
    private int id;
    private String title;
    private String contents;
    private LocalDateTime regDate;
}

@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();

        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항입니다.")
                .contents("공지사항 내용입니다.")
                .regDate(LocalDateTime.of(2024, 1, 30, 0, 0))
                .build());

        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항입니다")
                .contents("두번째 공지사항 내용입니다")
                .regDate(LocalDateTime.of(2024, 1, 31, 0, 0))
                .build());

        return noticeList;
    }
}

Q4) 공지사항 게시판의 목록에 대한 요청을 처리하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
REST API 형식으로 구현
HTTP METHOD : GET
요청 주소 : "/api/notice"
리턴값 : 공지사항 게시판의 내용을 추상화한 모델(게시글ID, 제목, 내용, 등록일) 리턴
요청한 내용이 없다면  목록을 리턴
    
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class NoticeModel {
    private int id;
    private String title;
    private String contents;
    private LocalDateTime regDate;
}

@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
}

Q5) 공지사항 게시판의 목록 중 전체 개수 정보에 대한 요청을 처리하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
REST API 형식으로 구현
HTTP METHOD : GET
요청 주소 : "/api/notice/count"
리턴값 : 게시판의 게시글 개수(정수) 리턴
확인사항 : 컨트롤러에서 정수형을 리턴하였더라고 클라이언트에 내려가는 부분은 문자열
    
@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
}

:bulb:return 값이 int형이여도 웹페이지에서는 문자열로 반환된다.​

게시글 작성

Q1) 공지사항에 글을 등록하기 위해서 글작성에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
REST API 형식으로 구현
HTTP METHOD : POST
요청주소 : "/api/notice"
리턴값 : 입력된 형태에 게시글ID(1) 등록일자(현재시간) 추가하여 모델 형태로 리턴 
전달되는 파라미터는 x-www-form-urlencoded 형식의 제목, 내용을 입력 받음
파라미터는 추상화하지 않고 기본데이터 타입 형태로 전달 받음
    
@RestController
public class ApiNoticeController {
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, 
                                 @RequestParam String contents) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .contents(contents)
                .regDate(LocalDateTime.now()).build();
    }
}

:bulb:@RequestParam : form 또는 parameter로 값을 전달받을때 사용

Q2) 공지사항에 글을 등록하기 위해서 글작성에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
REST API 형식으로 구현
HTTP METHOD : POST
요청주소 : "/api/notice2"
리턴값 : 입력된 형태에 게시글ID(2) 등록일자(현재시간) 추가하여 모델 형태로 리턴 
전달되는 파라미터는 x-www-form-urlencoded 형식의 제목, 내용을 입력 받음
파라미터를 공지사항 모델로 추상화하여 전달받음

@RestController
public class ApiNoticeController {
@PostMapping("/api/notice2")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        
        return noticeModel;
    }
}

Q3) 공지사항에 글을 등록하기 위해서 글작성에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
REST API 형식으로 구현
HTTP METHOD : POST
요청주소 : "/api/notice3"
리턴값 : 입력된 형태에 게시글ID(3) 등록일자(현재시간) 추가하여 모델 형태로 리턴 
전달되는 파라미터는 application/json 형식의 제목, 내용을 입력 받음
파라미터를 공지사항 모델로 추상화하여 전달받음
    
@RestController
public class ApiNoticeController {
	@PostMapping("/api/notice3")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());

        return noticeModel;
    }
}

:bulb:@RequestBody : Data를 json 형태로 전달받을 때 사용

Q4) 공지사항에 글을 등록하기 위해서 글작성에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
REST API 형식으로 구현
HTTP METHOD : POST
요청주소 : "/api/notice4"
리턴값 : 저장된 id값이 포함된 Entity 리턴
전달되는 값은 application/json 형식의 제목, 내용을 입력 받음
전달된 값을 저장하기 위한 JPA Repository와 Entity를 통해서 DB에 저장
    
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Notice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id;
    private String title;
    private String contents;
    private LocalDateTime regDate;
}

@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
    // ...
}

@Getter
@Builder
public class NoticeInput {
    private String title;
    private String contents;
}

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

    @PostMapping("/api/notice4")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .contents(noticeInput.getContents())
                .regDate(LocalDateTime.now()).build();

        noticeRepository.save(notice);
        return notice;
    }
}

Q5) 공지사항에 글을 등록하기 위해서 글작성에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
REST API 형식으로 구현
HTTP METHOD : POST
요청주소 : "/api/notice5"
리턴값 : 저장된 id값이 포함된 Entity 리턴
전달되는 값은 application/json 형식의 제목, 내용을 입력 받음
전달된 값을 저장하기 위한 JPA Repository와 Entity를 통해서 DB에 저장
공지사항 등록일은 현재시간을 저장, 공지사항 조회수와 좋아요수는 초기값을 0으로 설정

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Notice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String title;

    @Column
    private String contents;

    @Column
    private LocalDateTime regDate;
    
    @Column
    private int hits;

    @Column 
    private int likes;
}

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

    @PostMapping("/api/notice5")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .contents(noticeInput.getContents())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();

        return noticeRepository.save(notice);
    }
}

게시글 수정

Q1) 공지사항에 글을 수정하기 위한 상세정보 요청에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
REST API 형식으로 구현
HTTP METHOD : GET
요청주소 : "api/notice/{id}"
프로그램 실행  H2DB에 INSERT
조회된 결과가 있는 경우 Entity 리턴, 없을 경우 null 리턴

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

	@GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        Optional<Notice> notice = noticeRepository.findById(id);
        return notice.orElse(null);
    }
}

:bulb:@PathVariable : 주소에서 값을 전달받을 경우 사용

Q2) 공지사항에 글을 수정하기 위한 글수정에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
REST API 형식으로 구현
HTTP METHOD : PUT
요청주소 : "api/notice/{id}"
전달되는 값을 json 형식의 글ID, 제목, 내용을 입력 받음
공지사항 수정일을 현재 시간을 저장, 조회수와 좋아요  변경하지 않음
데이터를 수정하는 경우 Data 매핑에 대한 Entity로 필요없는 항목까지 받지 말고 필요한 데이터만 입력 
전달된 값을 수정하기 위한 JPA Repository와 Entity를 통해서 DB에 수정

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Notice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String title;

    @Column
    private String contents;

    @Column
    private LocalDateTime regDate;

    @Column
    private LocalDateTime updateDate;

    @Column
    private int hits;

    @Column
    private int likes;

}

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

	@PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,
                             @RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if (notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContents(noticeInput.getContents());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
}

Q3) 공지사항에 글을 수정하기 위한 글수정에 대한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
REST API 형식으로 구현
HTTP METHOD : PUT
요청주소 : "api/notice/{id}"
전달되는 값을 json 형식의 글ID, 제목, 내용을 입력 받음
공지사항 수정일을 현재 시간을 저장, 조회수와 좋아요 수는 변경하지 않음
데이터를 수정하는 경우 Data 매핑에 대한 Entity로 필요없는 항목까지 받지 말고 필요한 데이터만 입력 
전달된 값을 수정하기 위한 JPA Repository와 Entity를 통해서 DB에 수정
예외처리는 ExceptionHandler를 통해서 구현하고, 발생하는 예외에 대해서는 400, 예외 메세지를 리턴함

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

	@PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,
                             @RequestBody NoticeInput noticeInput) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("게시글이 존재하지 않습니다."));

        notice.setTitle(noticeInput.getTitle());
        notice.setContents(noticeInput.getContents());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }


    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(
        NoticeNotFoundException e) {
        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
    }
}
public class NoticeNotFoundException extends RuntimeException {
    public NoticeNotFoundException(String message) {
        super(message);
    }
}

Q4) 공지사항에 글의 조회수를 증가시키는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
REST API 형식으로 구현
HTTP METHOD : PATCH
요청주소 : "api/notice/{id}/hits"

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
	@PatchMapping("/api/notice/{id}/hits")
    public void noticeHIts(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("게시글이 존재하지 않습니다."));

        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
}

게시글 삭제

Q1) 공지사항의 글을 삭제하기 위한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
REST API 형식으로 구현
HTTP METHOD : DELETE
요청주소 : "api/notice/{id}"

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
	@DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
            .orElseThrow(() -> new NoticeNotFoundException("게시글이 존재하지 않습니다."));
        
        noticeRepository.delete(notice);
    }
}

Q2) 공지사항의 글을 삭제하기 위한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
REST API 형식으로 구현
HTTP METHOD : DELETE
요청주소 : "api/notice/{id}"
게시판의 글을 물리적으로 삭제하지 않고 삭제 플래그값을 이용하여 삭제를 진행
삭제일시는 현재 시간으로 설정
공지사항의 글이 이미 삭제된 경우는 200코드와 "이미 삭제된 글입니다." 라는 메세지를 리턴

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Notice {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String title;

    @Column
    private String contents;

    @Column
    private LocalDateTime regDate;

    @Column
    private LocalDateTime updateDate;

    @Column
    private int hits;

    @Column
    private int likes;

    @Column
    private boolean deleted;

    @Column
    private LocalDateTime deletedDate;
}

public class AlreadyDeletedException extends RuntimeException {
    public AlreadyDeletedException(String message) {
        super(message);
    }
}



@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
    @ExceptionHandler(NoticeNotFoundException.class)
        public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.OK);
        }

    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("게시글이 존재하지 않습니다."));

        if (notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 글입니다.");
        }

        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
}

Q3) 공지사항의 글을 삭제하기 위한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
REST API 형식으로 구현
HTTP METHOD : DELETE
요청주소 : "api/notice"
여러개의 글을 동시에 삭제하기 위해서 noticeId 목록을 파라미터로 받아서 해당 공지사항 글을 삭제

@Data
public class NoticeDeleteInput {
    private List<Long> idList;
}

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
    @DeleteMapping("/api/notice")
        public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
            List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                    .orElseThrow(() -> new NoticeNotFoundException("게시글이 존재하지 않습니다."));

            noticeList.stream().forEach(e -> {
                e.setDeleted(true);
                e.setDeletedDate(LocalDateTime.now());
            });

            noticeRepository.saveAll(noticeList);
        }
}

Q4) 공지사항의 모든 글을 삭제하기 위한 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
REST API 형식으로 구현
HTTP METHOD : DELETE
요청주소 : "api/notice/all"

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
	@DeleteMapping("/api/notice/all")
    public void deleteAll() {
        noticeRepository.deleteAll();
    }
}

게시판 추가 기능

Q1) 글을 작성할 때 제목과 내용을 받아서 저장하는 API를 만들어보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
입력값은 입력DTO를 통해서 입력받음
제목과 내용을 필수 입력 조건임(입력되지 않은 경우 400 리턴)
예외 발생시 각각의 에러를 취합하여 콜렉션 형태로 리턴

@Getter
@Builder
public class NoticeInput {
    @NotBlank(message = "제목은 필수 항목입니다.")
    private String title;
    @NotBlank(message = "내용은 필수 항목입니다.")
    private String contents;
}

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseError {
    private String field;
    private String message;

    public static ResponseError of(ObjectError e) {
        return ResponseError.builder()
                .field(((FieldError) e).getField())
                .message(e.getDefaultMessage())
                .build();
    }
}
    
@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;

    @PostMapping("/api/notice")
    public ResponseEntity<List<ResponseError>> addNotice(
            @RequestBody @Valid NoticeInput noticeInput, Errors errors) {

        if (errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();

            errors.getAllErrors().forEach(e -> {
                responseErrors.add(ResponseError.of(e));
            });

            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }

        noticeRepository.save(Notice.builder()
                .title(noticeInput.getTitle())
                .contents(noticeInput.getContents())
                .hits(0)
                .likes(0)
                .regDate(LocalDateTime.now())
                .build());

        return ResponseEntity.ok().build();
    }
}

Q2) 글을 작성할 때 제목과 내용을 받아서 저장하는 API를 만들어보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
입력값은 입력DTO를 통해서 입력받음
제목과 내용을 필수 입력 조건임(입력되지 않은 경우 400 리턴)
제목의 경우 10자이상 100 이하로 입력
내용의 경우 50 이상 1000 이하로 입력
예외 발생시 각각의 에러를 취합하여 콜렉션 형태로 리턴

@Getter
@Builder
public class NoticeInput {
    @Size(min = 10,max = 100, message = "제목은 10-100자 사이의 값입니다.")
    @NotBlank(message = "제목은 필수 항목입니다.")
    private String title;

    @Size(min = 50,max = 1000, message = "내용은 50-1000자 사이의 값입니다.")
    @NotBlank(message = "내용은 필수 항목입니다.")
    private String contents;
}

:bulb:@Min, @Max : 숫자에 관한 값 설정 / @Size : 문자의 값 설정

Q3) 데이터베이스에서 공지사항 목록중에서 파라미터로 전달된 개수만큼 리턴하는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseError {
    private String field;
    private String message;

    public static ResponseError of(ObjectError e) {
        return ResponseError.builder()
                .field(((FieldError) e).getField())
                .message(e.getDefaultMessage())
                .build();
    }
}

@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
    @GetMapping("/api/notice/latest/{size}")
    public Page<Notice> noticeList(@PathVariable int size) {
        return noticeRepository.findAll(PageRequest.of(0, 10, Sort.Direction.DESC, "regDate"));

    }
}

Q4) 공지사항의 내용을 등록 후 바로 동일한 제목과 내용의 공지사항을 등록을 막는 API를 만들어 보세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
중복 : 동일제목, 동일내용과 등록일이 현재시간 기준 1 이내의 경우
예외발생 : DuplicateNoticeException

@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
    Optional<List<Notice>> findByIdIn(List<Long> idList);
	// 제목동일, 내용동일, 등록시간이 체크시간보다 크다.
   int countByTitleAndContentsAndRegDateIsGreaterThanEqual(String title, String contents, LocalDateTime regDate);

}

public class DuplicateNoticeException extends RuntimeException {
    public DuplicateNoticeException(String message) {
        super(message);
    }
}

public class ApiNoticeController {
    private final NoticeRepository noticeRepository;
    
    @ExceptionHandler(DuplicateNoticeException.class)
    public ResponseEntity<?> handlerDuplicateNoticeException(DuplicateNoticeException e) {
        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
    }
    
    @PostMapping("/api/notice")
    public void addNotice(@RequestBody NoticeInput noticeInput) {
        LocalDateTime checkDate = LocalDateTime.now().minusMinutes(1);

        int noticeCount = noticeRepository.countByTitleAndContentsAndRegDateIsGreaterThanEqual(
                noticeInput.getTitle(), noticeInput.getContents(), checkDate);
        if (noticeCount > 0) {
            throw new DuplicateNoticeException("1분이내에 등록된 동일한 공지사항이 존재합니다.");
        }

        noticeRepository.save(Notice.builder()
                .title(noticeInput.getTitle())
                .contents(noticeInput.getContents())
                .hits(0)
                .likes(0)
                .regDate(LocalDateTime.now())
                .build());
    }   
}

카테고리:

업데이트:

댓글남기기