feat(notification): [API] 사용자 고유번호로 조회

This commit is contained in:
bum12ark
2022-03-09 14:06:29 +09:00
parent d3a26c5538
commit e757c626cd
14 changed files with 334 additions and 2 deletions

View File

@@ -34,7 +34,6 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
/*implementation 'org.springframework.boot:spring-boot-starter-amqp'*/
/*implementation 'org.springframework.boot:spring-boot-starter-security'*/
/*implementation 'org.springframework.cloud:spring-cloud-starter-config'*/
/*implementation 'org.springframework.kafka:spring-kafka'*/
// https://mvnrepository.com/artifact/com.github.gavlyukovskiy/p6spy-spring-boot-starter

View File

@@ -0,0 +1,28 @@
package com.justpickup.notificationservice.domain.notification.dto;
import com.justpickup.notificationservice.domain.notification.entity.Notification;
import com.justpickup.notificationservice.global.dto.Yn;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@Getter
@AllArgsConstructor(staticName = "of")
public class FindNotificationDto {
private Long id;
private Long userId;
private String message;
private String title;
private Yn readYn;
private LocalDateTime createdAt;
public FindNotificationDto(Notification entity) {
this.id = entity.getId();
this.userId = entity.getUserId();
this.message = entity.getMessage();
this.title = entity.getTitle();
this.readYn = entity.getReadYn();
this.createdAt = entity.getCreatedAt();
}
}

View File

@@ -1,5 +1,6 @@
package com.justpickup.notificationservice.domain.notification.entity;
import com.justpickup.notificationservice.global.dto.Yn;
import com.justpickup.notificationservice.global.entity.BaseEntity;
import lombok.AccessLevel;
import lombok.Getter;
@@ -13,7 +14,7 @@ import javax.persistence.*;
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Notification extends BaseEntity {
@Id @GeneratedValue
@Id @GeneratedValue
@Column(name = "notification_id")
private Long id;
@@ -22,4 +23,28 @@ public class Notification extends BaseEntity {
*/
private Long userId;
private String title;
private String message;
@Enumerated(EnumType.STRING)
private Yn readYn;
// == 생성 메소드 == //
public static Notification of(Long userId, String message, String title) {
Notification notification = new Notification();
notification.userId = userId;
notification.message = message;
notification.title = title;
notification.readYn = Yn.N;
return notification;
}
public void modifyReadY() {
this.readYn = Yn.Y;
}
public void modifyReadN() {
this.readYn = Yn.N;
}
}

View File

@@ -0,0 +1,10 @@
package com.justpickup.notificationservice.domain.notification.repository;
import com.justpickup.notificationservice.domain.notification.entity.Notification;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface NotificationRepository extends JpaRepository<Notification, Long> {
List<Notification> findByUserId(Long userId);
}

View File

@@ -0,0 +1,9 @@
package com.justpickup.notificationservice.domain.notification.service;
import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto;
import java.util.List;
public interface NotificationService {
List<FindNotificationDto> findNotificationByUserId(Long id);
}

View File

@@ -0,0 +1,24 @@
package com.justpickup.notificationservice.domain.notification.service;
import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto;
import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class NotificationServiceImpl implements NotificationService {
private final NotificationRepository notificationRepository;
@Override
public List<FindNotificationDto> findNotificationByUserId(Long userId) {
return notificationRepository.findByUserId(userId)
.stream()
.map(FindNotificationDto::new)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,59 @@
package com.justpickup.notificationservice.domain.notification.web;
import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto;
import com.justpickup.notificationservice.domain.notification.service.NotificationService;
import com.justpickup.notificationservice.global.dto.Result;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
@RequestMapping("/notification")
public class NotificationController {
private final NotificationService notificationService;
@GetMapping("")
public ResponseEntity<Result> getNotificationByUserId(@RequestHeader("user-id") String userIdHeader) {
Long userId = Long.valueOf(userIdHeader);
List<FindNotificationDto> notifications = notificationService.findNotificationByUserId(userId);
GetNotificationResponse response = new GetNotificationResponse(notifications);
return ResponseEntity.ok(Result.createSuccessResult(response));
}
@Data @NoArgsConstructor
static class GetNotificationResponse {
private List<_Notification> notifications;
public GetNotificationResponse(List<FindNotificationDto> notifications) {
this.notifications =
notifications.stream().map(_Notification::new).collect(Collectors.toList());
}
@Data
static class _Notification {
private Long id;
private String message;
private String title;
private boolean read;
private String time;
public _Notification(FindNotificationDto dto) {
this.id = dto.getId();
this.message = dto.getMessage();
this.title = dto.getTitle();
this.read = dto.getReadYn().isY();
this.time = dto.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
}
}
}
}

View File

@@ -0,0 +1,36 @@
package com.justpickup.notificationservice.global;
import com.justpickup.notificationservice.domain.notification.entity.Notification;
import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Component
@RequiredArgsConstructor
public class SqlCommandLineRunner implements CommandLineRunner {
private final NotificationRepository notificationRepository;
@Override
@Transactional
public void run(String... args) throws Exception {
for (long userId = 1; userId < 10; userId++) {
List<Notification> notifications = new ArrayList<>();
for (int notification = 1; notification <= 5; notification++) {
Notification of = Notification.of(userId, notification + "번 매장의 주문이 수락되었습니다.", "주문이 수락되었어요");
notifications.add(of);
}
for (int notification = 6; notification <= 10; notification++) {
Notification of = Notification.of(userId, notification + "번 매장의 주문이 수락되었습니다.", "주문이 수락되었어요");
of.modifyReadY();
notifications.add(of);
}
notificationRepository.saveAll(notifications);
}
}
}

View File

@@ -0,0 +1,5 @@
package com.justpickup.notificationservice.global.dto;
public enum Code {
SUCCESS, ERROR
}

View File

@@ -0,0 +1,44 @@
package com.justpickup.notificationservice.global.dto;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data @NoArgsConstructor
public class Result<T> {
private Code code;
private String message;
private T data;
@Builder
public Result(Code code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static Result createErrorResult(String message) {
return Result.builder()
.code(Code.ERROR)
.message(message)
.data(null)
.build();
}
// 해당 <T> 는 클래스의 T와 다름
public static <T> Result createSuccessResult(T data) {
return Result.builder()
.code(Code.SUCCESS)
.message("")
.data(data)
.build();
}
public static Result success(){
return Result.builder()
.code(Code.SUCCESS)
.message("성공")
.data(null)
.build();
}
}

View File

@@ -0,0 +1,14 @@
package com.justpickup.notificationservice.global.dto;
import lombok.Getter;
@Getter
public enum Yn {
Y(true), N(false);
private boolean y;
Yn(boolean y) {
this.y = y;
}
}

View File

@@ -1,14 +1,21 @@
package com.justpickup.notificationservice.global.entity;
import lombok.Getter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
@Getter
public abstract class BaseEntity {
@CreationTimestamp
private LocalDateTime createdAt;
private Long createdBy;
@UpdateTimestamp
private LocalDateTime lastModifiedAt;
private Long lastModifiedBy;

View File

@@ -0,0 +1,17 @@
package com.justpickup.notificationservice.global.exception;
import com.justpickup.notificationservice.global.dto.Result;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public class CustomException extends RuntimeException {
private HttpStatus status;
private Result errorResult;
protected CustomException(HttpStatus status, String message) {
this.status = status;
this.errorResult = Result.createErrorResult(message);
}
}

View File

@@ -0,0 +1,55 @@
package com.justpickup.notificationservice.global.exception;
import com.justpickup.notificationservice.global.dto.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity customExceptionHandler(CustomException ce) {
HttpStatus status = ce.getStatus();
Result errorResult = ce.getErrorResult();
return ResponseEntity.status(status)
.body(errorResult);
}
@ExceptionHandler(BindException.class)
public ResponseEntity bindExceptionHandler(BindException exception) {
return getValidationErrorBody(exception);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) {
return getValidationErrorBody(exception);
}
private ResponseEntity getValidationErrorBody(BindException exception) {
BindingResult bindingResult = exception.getBindingResult();
StringBuilder builder = new StringBuilder();
bindingResult.getFieldErrors()
.forEach(fieldError -> {
builder.append("[");
builder.append(fieldError.getField());
builder.append("](은)는 ");
builder.append(fieldError.getDefaultMessage());
builder.append(" 입력된 값: [");
builder.append(fieldError.getRejectedValue());
builder.append("]");
});
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Result.createErrorResult(builder.toString()));
}
}