I'm using Angular 12 CLI and Spring Boot 2.5.5. Using an Angular service, I'm trying to pass a JSON from a component to Spring Boot, using a POST http request. After the JSON arrives in Spring Boot, I need to print it in console, but I can't get it to work. Using Postman, I correctly visualize the JSON, so I think the problem is front-end side. Here's some code:
users.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from 'src/user';
@Injectable({
providedIn: 'root'
})
export class UsersService {
constructor(private http: HttpClient) { }
getUsers(): Observable<User[]>{
return this.http.get<User[]>("http://localhost:8080/user/all")
}
addNewUser(user: User): void {
const httpOptions = {
headers: new HttpHeaders(
{ 'Content-Type': 'application/json' }
)
};
let userJSON = JSON.stringify(user);
this.http.post("http://localhost:8080/user/add", userJSON, httpOptions);
}
}
UserController
package com.sporthub.backend.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.sporthub.backend.model.Role;
import com.sporthub.backend.model.User;
import com.sporthub.backend.repository.RoleRepository;
import com.sporthub.backend.repository.UserRepository;
@Controller
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping("/user")
public class UserController {
@Autowired
private UserRepository userRepo;
@Autowired
private RoleRepository roleRepo;
@GetMapping("/all")
public @ResponseBody Iterable<User> getUsers(){
return userRepo.findAll();
}
@PostMapping("/add")
public @ResponseBody String addUser(@RequestBody String user) {
System.out.println(user);
return user;
}
}
HTML Form
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
<div>
<label for="name">
Name
</label>
<input type="text" id="name" formControlName="name">
</div>
<div>
<label for="lastname">
lastname
</label>
<input type="text" id="lastname" formControlName="lastname">
</div>
<input type="submit" value="Add new user">
</form>
Users Component
import { Component, OnInit } from '@angular/core';
import { User } from 'src/user';
import { UsersService } from '../users.service';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
users : User[] = [];
checkoutForm = this.formBuilder.group({
name: '',
lastname: ''
});
constructor(
private usersService: UsersService,
private formBuilder: FormBuilder
) { }
onSubmit(): void {
let name = this.checkoutForm.get('name')?.value;
let lastname = this.checkoutForm.get('lastname')?.value;
let user: User = {
"name": name,
"lastname": lastname
};
console.log(user);
this.usersService.addNewUser(user);
}
ngOnInit(): void {
this.getUtenti();
console.log(this.users);
}
getUsers() : void{
this.usersService.getUsers().subscribe(users => this.users = users);
}
}
CodePudding user response:
You're adding a Content Type header in your client side's webservice, but not telling your backend about it.
I think you should refactor your @PostMapping
method to:
@PostMapping(path = "/add", produces = MediaType.APPLICATION_JSON_VALUE) // <- here
public @ResponseBody String addUser(@RequestBody String user) {
System.out.println(user);
return user;
}
Alternatively, you can add it to the @RequestMapping
, so that it would be applicable for all controller's methods.
BTW: you're returning a String not an object (that would be parsed to a json)
So I suggest that you change your @RequestBody String user
to @RequestBody YourUserDtoBackendType user
and remove JSON.stringify(user)
and pass a user
directly in the webservice's client side body, then the serialization/deserialization should be automatically executed via Jackson
(which Spring Boot provides a builtin support for it)
CodePudding user response:
EDIT: SOLVED.
Used an Observable as return type for my addNewUser function inside my UsersService
addNewUser(user: User): Observable<User> {
return this.http.post<User>("http://localhost:8080/user/add", user, this.httpOptions);
}
Then I added a .subscribe() method in my onSubmit() function inside my component.
this.usersService.addNewUser(user).subscribe(user => console.log(user));