[英]How do I create a Spring boot object from the Angular front-end?
我正在开发一个电子商务,其后端采用 Spring 引导,前端采用 Angular 材料。 当我在浏览器的支付页面中,在按钮Pay
上的点击事件之后,我希望创建一个与发生点击事件的支付相关的订单,但我不知道怎么做这件事。 问题是,当我在点击事件后创建一个Payment
类型的 object 时,这个 object (由于Payment
和Order
之间的 1:1 关系)需要一个 object 和我在下面的实体中显示的Order
类型不知道如何从前端创建它并将其与相关的Payment
object 连接起来。
后端
订单实体:
@Getter
@Setter
@EqualsAndHashCode
@ToString
@Entity
@Table(name = "order", schema = "purchase")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private int id;
@Basic
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "order_time")
private Date orderTime;
@OneToMany(mappedBy = "order", cascade = CascadeType.MERGE)
private List<ProductInOrder> productsInOrder;
@ManyToOne
@JoinColumn(name = "buyer")
private User buyer;
@OneToOne(mappedBy= "order")
private TheReturn theReturn;
@OneToOne
@JoinColumn(name = "payment_id")
@JsonIgnore
private Payment payment;
@OneToOne
@JoinColumn(name = "cart_id")
private Cart cart;
}
支付实体:
@Getter
@Setter
@EqualsAndHashCode
@ToString
@Entity
@Table(name = "payment", schema = "purchase")
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private int id;
@Basic
@Column(name = "owner_name", nullable = true, length = 70)
private String ownerName;
@Basic
@Column(name = "owner_last_name", nullable = true, length = 70)
private String ownerLastName;
@Basic
@Column(name = "card_number", nullable = true, length = 16)
//il numero di una carta PayPal è di 16 cifre
private String cardNumber;
@Basic
@Temporal(TemporalType.DATE)
@Column(name = "expiration", nullable = true)
private Date expiration;
@Basic
@Column(name = "cvv", nullable = true, length = 3)
private String cvv;
@Basic
@Column(name = "total", nullable = true)
private float total;
@OneToOne(mappedBy = "payment")
private Order order;
@OneToOne(mappedBy = "payment")
private TheReturn theReturn;
}
订单服务:
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductInOrderRepository productInOrderRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private CartRepository cartRepository;
@Autowired
private PaymentRepository paymentRepository;
@Autowired
private EntityManager entityManager;
@Transactional(readOnly = false)
public Order addOrder(Order order) throws ProductUnavailableException, EmptyOrderException, UserNotFoundException, CartNotFoundException, CartAlreadyExistsException{//
if(order.getProductsInOrder()==null || order.getProductsInOrder().size()<=0){
throw new EmptyOrderException();
}
if(!userRepository.existsById(order.getBuyer().getId())){
throw new UserNotFoundException();
}
if(!cartRepository.existsById(order.getCart().getId())){
throw new CartNotFoundException();
}
if(orderRepository.findByCart(order.getCart())!=null){
throw new CartAlreadyExistsException();
}
Order result = orderRepository.save(order);
for(ProductInOrder p : result.getProductsInOrder()){
p.setOrder(result);
ProductInOrder justAdded = productInOrderRepository.save(p);
entityManager.refresh(justAdded);
Product product = justAdded.getProduct();
int newQuantity = product.getQuantity() - p.getQuantity();
if(newQuantity < 0){
orderRepository.delete(order);
p.setOrder(null);
productInOrderRepository.delete(p);
throw new ProductUnavailableException(product);
}
product.setQuantity(newQuantity);
entityManager.refresh(p);
}
entityManager.refresh(result);
return result;
}
订单控制器:
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/createOrder")
@ResponseStatus(code = HttpStatus.OK)
public ResponseEntity create(@RequestBody @Valid Order order){//Funziona
//System.out.println("Ordine in orderController: "+order+"\n");
try{
return new ResponseEntity<>(orderService.addOrder(order), HttpStatus.OK);
}catch (ProductUnavailableException e){
return new ResponseEntity<>(new ResponseMessage("The quantity of product: "+e.getProduct().getName()+" is unavailable!"), HttpStatus.BAD_REQUEST);
} catch (EmptyOrderException e) {
return new ResponseEntity<>(new ResponseMessage("The order has no products."), HttpStatus.BAD_REQUEST);
} catch (UserNotFoundException e) {
return new ResponseEntity<>(new ResponseMessage("User not found."), HttpStatus.BAD_REQUEST);
} catch (CartNotFoundException e) {
return new ResponseEntity<>(new ResponseMessage("Cart not found."), HttpStatus.BAD_REQUEST);
} catch (CartAlreadyExistsException e) {
return new ResponseEntity<>(new ResponseMessage("Cannot associate the same cart cart to more than one order."), HttpStatus.BAD_REQUEST);
}
}
支付服务:
@Service
public class PaymentService {
@Autowired
private PaymentRepository paymentRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
@Autowired
private EntityManager entityManager;
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public Payment addPayment(Payment p) throws PaymentAlreadyExistsException, IncorrectCardNumberException, IncorrectCvvException{//
if(paymentRepository.existsByCardNumber(p.getCardNumber())){
throw new PaymentAlreadyExistsException();
}
if(p.getCardNumber().length()!=16){
throw new IncorrectCardNumberException();
}
if(p.getCvv().length()!=3)
{
throw new IncorrectCvvException();
}
Order newOrder = new Order();
newOrder.setPayment(p);
Order justAdded=orderRepository.save(newOrder);
entityManager.refresh(justAdded);
p.setOrder(justAdded);
return paymentRepository.save(p);
}
支付控制器:
@RestController
@RequestMapping("/payments")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@PostMapping("/createPayment")//funziona
public ResponseEntity<Payment> create(@RequestBody @Valid Payment payment){
System.out.print("Sono in paymentController.");
try {
Payment added=paymentService.addPayment(payment);
return new ResponseEntity<>(added, HttpStatus.OK);
} catch (PaymentAlreadyExistsException e) {
return new ResponseEntity(new ResponseMessage("Payment already exists!"), HttpStatus.BAD_REQUEST);
} catch (IncorrectCardNumberException e) {
return new ResponseEntity(new ResponseMessage("Incorrect card number!"), HttpStatus.BAD_REQUEST);
} catch (IncorrectCvvException e) {
return new ResponseEntity(new ResponseMessage("Incorrect CVV"), HttpStatus.BAD_REQUEST);
}
}
前端
payment.component.html(在这个 html 文件中有我所说的点击事件):
<form #paymentForm="ngForm">
<div class="form-group">
<label for="ownerName">OwnerName*</label>
<input type="text" ngModel name="ownerName" class="form-control" id="ownerName" placeholder="OwnerName" required>
</div>
<div class="form-group">
<label for="ownerLastName">OwnerLastName*</label>
<input type="text" ngModel name="ownerLastName" class="form-control" id="ownerLastName" placeholder="OwnerLastName" required>
</div>
<div class="form-group">
<label for="cardNumber">CardNumber*</label>
<input type="text" ngModel name="cardNumber" class="form-control" id="cardNumber" placeholder="CardNumber" required>
</div>
<div class="form-group">
<label for="cvv">Cvv*</label>
<input type="text" ngModel name="cvv" class="form-control" id="cvv" placeholder="cvv" required>
</div>
<div class="form-group">
<label for="expiration">Expiration*</label>
<input type="date" ngModel name="expiration" class="form-control" id="expiration" placeholder="expiration" required>
</div>
<p>(Tutti i campi contrassegnati con * devono essere riempiti)</p>
<div class="modal-footer">
<button [disabled]="paymentForm.invalid" type="submit" class="btn btn-primary" (click)="createPayment('Payment successful!', 'ok', paymentForm)" routerLink="/orders" routerLinkActive="active">Pay</button>
</div>
</form>
payment.component.ts:
export class PaymentComponent implements OnInit {
public total:number=0;
public payment!: Payment;
ownerNameFormControl = new FormControl('', [Validators.required]);
ownerLastNameFormControl = new FormControl('', [Validators.required]);
constructor(private _snackBar: MatSnackBar, private paymentService:PaymentService, private shared: SharedService) { }
ngOnInit(): void {
this.shared.castTotal.subscribe(total=>this.total=total);
this.shared.castPayment.subscribe(payment=>this.payment=payment);
}
public createPayment(message:string, action:string, createForm:NgForm ) {
this.paymentService.createPayment(createForm.value).subscribe(
(response: Payment) => {
this.payment=response;
this.shared.setPayment(this.payment);
console.log(response);
this._snackBar.open(message, action);
createForm.reset();
},
(error: HttpErrorResponse)=>{
alert(error.message);
createForm.reset();
}
)
}
}
付款服务.ts:
@Injectable({
providedIn: 'root'
})
export class PaymentService {
constructor(private http: HttpClient) { }
public createPayment(payment: Payment): Observable<Payment> {
console.log("Sono in payment service");
return this.http.post<Payment>('http://localhost:8080/payments/createPayment', payment);
}
shared.service.ts:
export class SharedService {
public defaultPayment!: Payment;
private payment= new BehaviorSubject<Payment>(this.defaultPayment);
castPayment = this.payment.asObservable();
constructor() { }
setPayment(data: Payment){
this.payment.next(data); }
order.component.ts:
export class OrderComponent implements OnInit {
public payment!: Payment;
public cart!: Cart;
displayedColumns = ['img', 'name', 'description', 'price', 'quantity'];
constructor(private shared: SharedService) { }
ngOnInit(): void {
this.shared.castPayment.subscribe(payment=>this.payment=payment);
this.shared.castCart.subscribe(cart=>this.cart=cart);
}
}
order.service.ts:
export class OrderService {
constructor(private http: HttpClient) { }
public createOrder(order: Order): Observable<void> {
return this.http.post<void>('http://localhost:8080/orders/createOrder', order);
}
付款.ts:
export interface Payment{
id: number;
ownerName: string;
ownerLastName: string;
cardNumber: string;
expiration: Date;
cvv: string;
total: number;
order: Order;
theReturn: TheReturn;
}
从 FE 向 BE 发送请求基本上有 2 个步骤:
正如您在 Angular 文档中的示例中所见:
/** POST: add a new hero to the database */
addHero(hero: Hero): Observable<Hero> {
return this.http.post<Hero>(`http://localhost:portNumber/hero`, hero, httpOptions)
.pipe(
catchError(this.handleError('addHero', hero))
);
}
您只需将包含您需要的所有字段的 object 发送到后端。 发送时 - 它以 JSON 发送,这意味着如果 Hero class 具有字段name
和power
,它将像这样发送:
{
"name": "Superman",
"power": "Can disguise himself by wearing glasses"
}
在 Spring Controller 中,您只需要定义一个 controller 方法,该方法期望具有相同字段的 ZA8CFDE6331BD59EB66AC96F8911。 Spring 具有 Jackson 的依赖关系,它会自动为您反序列化 JSON,所以正如我所说,您只需要创建一个包含所有字段的 DTO。
class HeroDTO {
private String name;
private String power;
//getters, setters and noArg constructor - important to have for deserialization to work!
}
然后在 controller 方法中:
@PostMapping(value = "/hero", produces = APPLICATION_JSON_VALUE)
public ResponseEntity createHero(@RequestBody HeroDTO heroDTO) {
//do whatever
}
顺便说一句,您可能会收到 CORS 错误 - 这是正常的,可以通过将@CrossOrigin
添加到 Controller 的顶部来禁用 CORS。 更多在这里
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.