Я делаю приложение для проекта колледжа, использую Spring-Boot для серверной части и обрабатываю все запросы из внешнего приложения.
Одной из функций приложения, упрощая его, будет управление различными типами платежей для пользователей и создание журнала в базе данных. Все это через эксклюзивный контроллер для всех конечных точек платежа, который будет вызывать платежный сервис.
Пока я создавал функцию, которая обрабатывает один из типов платежей в сервисе (который получает определенный DTO для этого типа платежа), я понял, что независимо от того, какой тип платежа я получаю, приложение всегда будет генерировать журнал платежей, поэтому я рассматриваю возможность инкапсулировать функциональность конкретного платежа, который я уже сделал, в метод и вызывать его из общего метода, который получает общий запрос платежа DTO (сокращенно gprDTO), проверяет его содержимое и тип и вызывает соответствующую функцию.
Тело общей функции будет примерно таким:
Код: Выделить всё
@Transactional
public void processGenericPayment(GenericPaymentRequestDTO request) throws AccessDeniedException, IllegalArgumentException{
//0. Check if the user has permission
User manager = userRepository.findById(email).orElseThrow(//handle exception);
if(!userService.checkAdminAccess(email)) {
throw new AccessDeniedException("Not allowed");
}
//1. Create the log
PaymentLog log = new PaymentLog();
//2. Check the type and call the specific function
switch(request.getType()) {
case TYPE_X-> {
if(request.getUserId() == null || request.getcouponId() == null) throw new IllegalArgumentException("Something");
processPaymentX(request.getUserId(), request.getCouponId());
log.setUser(userRepository.findById(request.getUserId()).orElsethrow(//handle exception)
log.setCoupon(couponRepository.findById(request.getCouponId()).orElseThrow(//handle exception))
}
case TYPE_Y-> {
if(request.getItemId() == null) throw new IllegalArgumentException("Something");
processTypeY(request.getItemId());
log.setItem(itemRepository.findById(request.getItemId()).orElseThrow(//handle exception))
}
case TYPE_Z-> {
if(request.getUserId() == null) throw new IllegalArgumentException("Something");
processTypeZ(request.getUserId());
log.setItem(itemRepository.findById(request.getUserId()).orElseThrow(//handle exception))
}
// All cases
}
//3. Finish the payment log
log.setDate(LocalDateTime.now());
log.setMessage(request.getMessage());
//All fields
//4. Save the log
logRepository.save(log)
}
Код: Выделить всё
@Getter
@Setter
@NoArgsConstructor
@Data
public class GenericPaymentRequestDTO {
@NotNull
private PaymentLogType type;
@NotNull
private Long managerId; //This is the user that has managed the payment (The service checks if it has the permissions to do this)
@NotNull
private String message;
@NotNull
private Double price;
private Long userId; //Used in payment type X
private Long itemId; //Used in payment type Y
private Long couponId; //Used in payment type X & Z
//All needed fields...
}
Код: Выделить всё
@Getter
@Setter
@Entity
@Table(name = "payment_logs")
public class PaymentLog implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "log_id", nullable = false)
private Long logId;
@NotNull
@Column(name = "price")
private Double price;
@NotNull
@Column(name = "date", nullable = false)
private LocalDateTime date;
@NotNull
@Column(name = "message")
private String message;
@NotNull
@Column(name="type", nullable = false, columnDefinition = "payment_log_type")
private PaymentLogType type;
@NotNull
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "manager_id", nullable = false)
private User manager;
//This fields will be null or not depending of the type.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private InventoryItem item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "coupon_id")
private Coupon coupon;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
//There are more fields, but for simplification, I only added these at the snipet.
}
И еще один вопрос: хорошо ли написан код, который получает объекты журнала платежей, которые не являются нулевыми (товар, купон, пользователь,...). Конкретные методы будут обрабатывать исключение, если объект не найден в базе данных, и, возможно, orElsethrow() внутри случаев переключателя является избыточным.
Мобильная версия