-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* rebase * rebase * #36 refactor(AnnouncementService): @validated 추가, ModelMapper 제거 * #36 refactor(AnnouncementCommand): DTO 리팩토링 * #36 refactor(AnnouncementService): 서비스 리팩토링 * #36 refactor(AnnouncementController): 컨트롤러 리팩토링 * #36 test(AnnouncementServiceTest): 테스트코드 추가 * #36 refactor(AnnouncementService): 유효성 검사 추가 * Fix test
- Loading branch information
Showing
10 changed files
with
390 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/api/announcement/AnnouncementRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.api.announcement; | ||
|
||
import com.example.api.domain.Announcement; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
@Repository | ||
public interface AnnouncementRepository extends JpaRepository<Announcement, Long> { | ||
List<Announcement> findByAnnouncementTitleContaining(final String keyword); | ||
} |
89 changes: 89 additions & 0 deletions
89
src/main/java/com/example/api/announcement/AnnouncementService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.example.api.announcement; | ||
|
||
import com.example.api.announcement.dto.AnnouncementCommand; | ||
import com.example.api.announcement.dto.AnnouncementResponse; | ||
import com.example.api.domain.Announcement; | ||
import jakarta.transaction.Transactional; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.validation.annotation.Validated; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AnnouncementService { | ||
private final AnnouncementRepository announcementRepository; | ||
|
||
@Transactional | ||
public AnnouncementResponse createAnnouncement( | ||
@Validated final AnnouncementCommand command | ||
) { | ||
Announcement announcement = new Announcement(); | ||
announcement.setAnnouncementTitle(command.announcementTitle()); | ||
announcement.setAnnouncementType(command.announcementType()); | ||
announcement.setAnnouncementContent(command.announcementContent()); | ||
Announcement savedAnnouncement = announcementRepository.save(announcement); | ||
return new AnnouncementResponse(savedAnnouncement); | ||
} | ||
|
||
@Transactional | ||
public List<AnnouncementResponse> getAllAnnouncements() { | ||
final List<Announcement> announcements = announcementRepository.findAll(); | ||
return announcements.stream() | ||
.map(AnnouncementResponse::new) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
@Transactional | ||
public AnnouncementResponse getAnnouncement( | ||
@Validated final Long announcementId | ||
) { | ||
final Announcement announcement = findAnnouncementById(announcementId); | ||
return new AnnouncementResponse(announcement); | ||
} | ||
|
||
@Transactional | ||
public AnnouncementResponse updateAnnouncement( | ||
@Validated final Long announcementId, | ||
@Validated final AnnouncementCommand command | ||
) { | ||
Announcement announcement = findAnnouncementById(announcementId); | ||
announcement.setAnnouncementTitle(command.announcementTitle()); | ||
announcement.setAnnouncementType(command.announcementType()); | ||
announcement.setAnnouncementContent(command.announcementContent()); | ||
Announcement updatedAnnouncement = announcementRepository.save(announcement); | ||
return new AnnouncementResponse(updatedAnnouncement); | ||
} | ||
|
||
@Transactional | ||
public void deleteAnnouncement( | ||
@Validated final Long announcementId | ||
) { | ||
final Announcement announcement = findAnnouncementById(announcementId); | ||
announcementRepository.delete(announcement); | ||
} | ||
|
||
@Transactional | ||
public List<AnnouncementResponse> searchAnnouncements( | ||
@Validated final String keyword | ||
) { | ||
final List<Announcement> announcements = announcementRepository.findByAnnouncementTitleContaining(keyword); | ||
return announcements.stream() | ||
.map(AnnouncementResponse::new) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private Announcement findAnnouncementById( | ||
@Validated final Long announcementId | ||
) { | ||
return announcementRepository.findById(announcementId) | ||
.orElseThrow(() -> new RuntimeException(getErrorMessage("announcement.not.found"))); | ||
} | ||
|
||
private String getErrorMessage(final String key) { | ||
return key; | ||
} | ||
} | ||
|
||
|
68 changes: 68 additions & 0 deletions
68
src/main/java/com/example/api/announcement/controller/AnnouncementController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.example.api.announcement.controller; | ||
|
||
import com.example.api.announcement.AnnouncementService; | ||
import com.example.api.announcement.dto.AnnouncementCommand; | ||
import com.example.api.announcement.dto.AnnouncementRequest; | ||
import com.example.api.announcement.dto.AnnouncementResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/support/announcements") | ||
public class AnnouncementController { | ||
private final AnnouncementService announcementService; | ||
|
||
@PostMapping | ||
public ResponseEntity<AnnouncementResponse> createAnnouncement( | ||
@RequestBody final AnnouncementRequest request | ||
) { | ||
final AnnouncementCommand command = request.toCommand(); | ||
final AnnouncementResponse response = announcementService.createAnnouncement(command); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@GetMapping | ||
public ResponseEntity<List<AnnouncementResponse>> getAnnouncements() { | ||
final List<AnnouncementResponse> responses = announcementService.getAllAnnouncements(); | ||
return ResponseEntity.ok(responses); | ||
} | ||
|
||
@GetMapping("/{announcementId}") | ||
public ResponseEntity<AnnouncementResponse> getAnnouncement( | ||
@PathVariable(required = true) final Long announcementId | ||
) { | ||
final AnnouncementResponse response = announcementService.getAnnouncement(announcementId); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@PutMapping("/{announcementId}") | ||
public ResponseEntity<AnnouncementResponse> updateAnnouncement( | ||
@PathVariable(required = true) final Long announcementId, | ||
@RequestBody final AnnouncementRequest request | ||
) { | ||
final AnnouncementCommand command = request.toCommand(); | ||
final AnnouncementResponse response = announcementService.updateAnnouncement( | ||
announcementId, command); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@DeleteMapping("/{announcementId}") | ||
public ResponseEntity<Void> deleteAnnouncement( | ||
@PathVariable(required = true) final Long announcementId | ||
) { | ||
announcementService.deleteAnnouncement(announcementId); | ||
return ResponseEntity.ok().build(); | ||
} | ||
|
||
@GetMapping("/search") | ||
public ResponseEntity<List<AnnouncementResponse>> searchAnnouncements( | ||
@RequestParam(required = true) final String keyword | ||
) { | ||
final List<AnnouncementResponse> responses = announcementService.searchAnnouncements(keyword); | ||
return ResponseEntity.ok(responses); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/example/api/announcement/dto/AnnouncementCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.example.api.announcement.dto; | ||
|
||
import lombok.NonNull; | ||
|
||
public record AnnouncementCommand( | ||
@NonNull | ||
String announcementTitle, | ||
String announcementType, | ||
String announcementContent | ||
) {} |
19 changes: 19 additions & 0 deletions
19
src/main/java/com/example/api/announcement/dto/AnnouncementRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.example.api.announcement.dto; | ||
|
||
import lombok.NonNull; | ||
|
||
public record AnnouncementRequest( | ||
@NonNull | ||
String announcementTitle, | ||
String announcementType, | ||
String announcementContent | ||
) { | ||
public AnnouncementCommand toCommand() { | ||
return new AnnouncementCommand( | ||
this.announcementTitle, | ||
this.announcementType, | ||
this.announcementContent | ||
); | ||
} | ||
} | ||
|
22 changes: 22 additions & 0 deletions
22
src/main/java/com/example/api/announcement/dto/AnnouncementResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.example.api.announcement.dto; | ||
|
||
import com.example.api.domain.Announcement; | ||
|
||
public record AnnouncementResponse( | ||
Long announcementId, | ||
String announcementTitle, | ||
String announcementType, | ||
String announcementContent, | ||
int viewCount | ||
) { | ||
public AnnouncementResponse(Announcement announcement) { | ||
this( | ||
announcement.getAnnouncementId(), | ||
announcement.getAnnouncementTitle(), | ||
announcement.getAnnouncementType(), | ||
announcement.getAnnouncementContent(), | ||
announcement.getViewCount() | ||
); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
src/test/java/com/example/api/announcement/AnnouncementControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.example.api.announcement; | ||
|
||
import com.example.api.announcement.controller.AnnouncementController; | ||
import com.example.api.announcement.dto.AnnouncementRequest; | ||
import com.example.api.announcement.dto.AnnouncementResponse; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
import org.springframework.http.ResponseEntity; | ||
import java.util.List; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.*; | ||
|
||
class AnnouncementControllerTest { | ||
@InjectMocks | ||
private AnnouncementController announcementController; | ||
@Mock | ||
private AnnouncementService announcementService; | ||
private static final String DEFAULT_TITLE = "공지사항 제목"; | ||
private static final String DEFAULT_TYPE = "공지사항"; | ||
private static final String DEFAULT_CONTENT = "공지사항 내용"; | ||
private static final int DEFAULT_VIEW_COUNT = 100; | ||
@BeforeEach | ||
void setUp() { | ||
MockitoAnnotations.openMocks(this); | ||
} | ||
|
||
@Test | ||
void createAnnouncement_success() { | ||
final AnnouncementRequest request = createMockRequest(); | ||
final AnnouncementResponse response = createMockResponse(); | ||
when(announcementService.createAnnouncement(any())) | ||
.thenReturn(response); | ||
ResponseEntity<AnnouncementResponse> result = announcementController.createAnnouncement(request); | ||
assertCreateAnnouncementResponse(result); | ||
verify(announcementService, times(1)).createAnnouncement(any()); | ||
} | ||
|
||
@Test | ||
void getAnnouncements_success() { | ||
final AnnouncementResponse response = createMockResponse(); | ||
when(announcementService.getAllAnnouncements()) | ||
.thenReturn(List.of(response)); | ||
ResponseEntity<List<AnnouncementResponse>> result = announcementController.getAnnouncements(); | ||
assertGetAnnouncementsResponse(result); | ||
verify(announcementService, times(1)).getAllAnnouncements(); | ||
} | ||
|
||
private AnnouncementRequest createMockRequest() { | ||
return new AnnouncementRequest(DEFAULT_TITLE, DEFAULT_TYPE, DEFAULT_CONTENT); | ||
} | ||
|
||
private AnnouncementResponse createMockResponse() { | ||
return new AnnouncementResponse(1L, DEFAULT_TITLE, DEFAULT_TYPE, DEFAULT_CONTENT, DEFAULT_VIEW_COUNT); | ||
} | ||
|
||
private void assertCreateAnnouncementResponse(ResponseEntity<AnnouncementResponse> result) { | ||
assertThat(result.getStatusCodeValue()).isEqualTo(200); | ||
assertThat(result.getBody().announcementTitle()).isEqualTo(DEFAULT_TITLE); | ||
} | ||
|
||
private void assertGetAnnouncementsResponse(ResponseEntity<List<AnnouncementResponse>> result) { | ||
assertThat(result.getStatusCodeValue()).isEqualTo(200); | ||
assertThat(result.getBody()).hasSize(1); | ||
} | ||
} |
Oops, something went wrong.