💡 공지사항 기능
요구사항
PostMan API Docs 작성
https://documenter.getpostman.com/view/23682055/2s8ZDU6jkR
Open-Session-in-view 옵션: false (트랜잭션 내부의 프록시객체 초기화 필요)
연관관계 : Member 1 < - > Notice N
@ManyToOne 단방향 매핑으로 진행
FetchType : Lazy
1. 공지사항 생성
2. 공지사항 수정
3. 공지사항 단건조회
4. 공지사항 전체조회(Pagenation)
5. 공지사항 삭제
6. 조회수 카운트(Update Query)
공지사항 생성
- 공지사항 생성 시, HttpServletRequest를 파라미터로 받아
유저의 Role (Admin, User, Counselor)을 검증 후 Admin Role이 아니면 Exception을 던짐
공지사항 수정
- 쿼리파라미터로 Notice의 식별자를 입력받아 Entity에서 생성한 update 메서드를 이용해 필드값 수정
- Member 프록시 객체 초기화 로직 필요
공지사항 단건조회
- 쿼리파라미터로 Notice의 식별자를 입력받아 조회
- Member 프록시 객체 초기화 로직 필요
- @Transactional(readOnly = true)
공지사항 전체 조회
- Pagenation을 이용하여 쿼리파라미터로 page, size를 입력받아 페이지 출력
- Member 프록시 객체 초기화 로직 필요
- @Transactional(readOnly = true)
공지사항 삭제
- 쿼리파라미터로 Notice의 식별자를 입력받아 삭제
조회수 증가 로직
- Repository 인터페이스에 JQPL을 이용한 Update Query 작성
💡 소스코드
Entity
@Getter @Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Notice extends BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long noticeId;
@Column(nullable = false, length = 50)
private String title;
@Column(nullable = false)
private String content;
@Column(columnDefinition = "integer default 0" ,nullable = false)
private int views;
// ------------------ 연관관계 매핑 ------------------
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "MEMBER_ID")
@JsonIgnore
private Member member;
public void setMember(Member member) {
this.member = member;
}
public void update(String title, String content) {
this.title = title;
this.content = content;
}
}
DTO
public class NoticeDto {
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class Post {
private String title;
private String content;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class Patch {
private long noticeId;
private String title;
private String content;
public void setNoticeId(long noticeId) {
this.noticeId = noticeId;
}
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SingleResponse {
private long noticeId;
private String title;
private String content;
private int views;
private String writer;
private LocalDateTime createdTime;
public static SingleResponse of(Notice notice) {
return SingleResponse.builder()
.noticeId(notice.getNoticeId())
.title(notice.getTitle())
.content(notice.getContent())
.views(notice.getViews())
.writer(notice.getMember().getMemberName())
.createdTime(notice.getCreateTime())
.build();
}
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class MultiResponse {
private long noticeId;
private String title;
private int views;
private String writer;
private LocalDateTime createdTime;
public static MultiResponse of(Notice notice) {
return MultiResponse.builder()
.noticeId(notice.getNoticeId())
.title(notice.getTitle())
.views(notice.getViews())
.writer(notice.getMember().getMemberName())
.createdTime(notice.getCreateTime())
.build();
}
}
}
Mapper
@Mapper(componentModel = "spring")
public interface NoticeMapper {
Notice postToEntity(NoticeDto.Post post);
Notice patchToEntity(NoticeDto.Patch patch);
default NoticeDto.SingleResponse entityToSingleResponse(Notice notice) {
return NoticeDto.SingleResponse.of(notice);
}
default List<NoticeDto.MultiResponse> entityToMultiResponse(List<Notice> notices) {
List<NoticeDto.MultiResponse> list = new ArrayList<NoticeDto.MultiResponse>(notices.size());
for (Notice a : notices) {
list.add(NoticeDto.MultiResponse.of(a));
}
return list;
}
}
Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
// @Modifying
// @Query("update Notice n set n.views = n.views + 1 where n.noticeId = :noticeId")
// void updateViews(@Param("noticeId") Long noticeId);
@Query(value = "select n FROM Notice n WHERE n.noticeId = :noticeId")
Optional<Notice> findById(long noticeId);
}
Service
@Service
@Transactional
@RequiredArgsConstructor
public class NoticeService {
// ----------------- DI ---------------------
private final NoticeRepository noticeRepository;
private final MemberService memberService;
// ----------------- DI ---------------------
// 공지 등록
public Notice create(Notice notice, Member member) {
notice.setMember(member);
if (!member.getRole().equals(Role.ADMIN)) {
throw new BusinessException(ErrorCode.FORBIDDEN_ADMIN);
} else {
notice.setMember(member);
return noticeRepository.save(notice);
}
}
// 공지 수정
public Notice update(Notice notice) {
Notice findNotice = findVerifiedNotice(notice.getNoticeId());
String memberName = findNotice.getMember().getMemberName();
findNotice.update(notice.getTitle(), notice.getContent());
return noticeRepository.save(findNotice);
}
// 공지 1건 조회
@Transactional(readOnly = true)
public Notice find(long noticeId) {
Notice notice = findVerifiedNotice(noticeId);
String writer = notice.getMember().getMemberName();
updateViews(noticeId);
return notice;
}
// 공지 전체 조회
@Transactional(readOnly = true)
public Page<Notice> findAll(int page, int size) {
Page<Notice> pageNotice = noticeRepository.findAll(PageRequest.of(page, size, Sort.by("noticeId").descending()));
List<Notice> listNotice = pageNotice.getContent();
for (Notice a : listNotice) {
a.getMember().getMemberName();
}
return pageNotice;
}
// 공지 삭제
public void delete(long noticeId) {
Notice notice = findVerifiedNotice(noticeId);
if (!notice.getMember().getRole().equals(Role.ADMIN)) {
throw new BusinessException(ErrorCode.FORBIDDEN_ADMIN);
} else {
noticeRepository.deleteById(noticeId);
}
}
// 조회수 증가 로직
public void updateViews(Long id) {
Notice notice = findVerifiedNotice(id);
int findViews = notice.getViews() + 1;
notice.setViews(findViews);
noticeRepository.save(notice);
}
// 공지 검증
public Notice findVerifiedNotice(long noticeId) {
Optional<Notice> optNotice = noticeRepository.findById(noticeId);
return optNotice.orElseThrow(() -> new EntityNotFoundException("글이 없습니다"));
}
}
Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/notices")
public class NoticeController {
private final NoticeMapper mapper;
private final NoticeService noticeService;
private final MemberService memberService;
@PostMapping("/post")
public ResponseEntity postNotice(@Valid @RequestBody NoticeDto.Post post,
HttpServletRequest request) {
Member member = memberService.getLoginMember(request);
Notice findNotice = noticeService.create(mapper.postToEntity(post), member);
return new ResponseEntity<>(new SingleResponseDto<>(mapper.entityToSingleResponse(findNotice)), HttpStatus.CREATED);
}
@PatchMapping("/patch/{notice-id}")
public ResponseEntity patchNotice(@PathVariable("notice-id") @Positive long noticeId,
@Valid @RequestBody NoticeDto.Patch patch) {
patch.setNoticeId(noticeId);
Notice update = noticeService.update(mapper.patchToEntity(patch));
return new ResponseEntity<>(new SingleResponseDto<>(mapper.entityToSingleResponse(update)), HttpStatus.OK);
}
@GetMapping("/lookup/{notice-id}")
public ResponseEntity get(@PathVariable("notice-id") @Positive long noticeId) {
Notice findNotice = noticeService.find(noticeId);
return new ResponseEntity(new SingleResponseDto<>(mapper.entityToSingleResponse(findNotice)), HttpStatus.OK);
}
@GetMapping("/lookup/list")
public ResponseEntity getAll(@Positive @RequestParam(defaultValue = "1") int page,
@Positive @RequestParam(defaultValue = "10") int size) {
Page<Notice> pageNotice = noticeService.findAll(page-1, size);
List<Notice> notices = pageNotice.getContent();
return new ResponseEntity<>(new MultiResponseDto<>(mapper.entityToMultiResponse(notices), pageNotice), HttpStatus.OK);
}
@DeleteMapping("/delete/{notice-id}")
public ResponseEntity delete(@PathVariable("notice-id") @Positive long noticeId) {
noticeService.delete(noticeId);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
'Project > Main Project' 카테고리의 다른 글
💻 기능 개발 - 프로그램 (0) | 2023.01.27 |
---|---|
💻 기능 개발 - 상담사 (0) | 2023.01.27 |
💻 기능 개발 - 게시물 (0) | 2023.01.26 |
💻 기능 개발 - 회원 (0) | 2023.01.26 |
📄 API 명세서 - 상담프로그램 & 결제 & 예약 (0) | 2023.01.26 |