简体   繁体   中英

Angular 13 - 400 Error (Bad Request) when using PUT

I'm using Angular and Java with SpringBoot to edit a component. Backend works fine, checked it with postman. However, when trying to edit a component it throws a 400 Error.

The html of the edit page:

<div class="container" *ngIf="expLab">   <div class="row">
        <form  (ngSubmit)="onUpdate()" novalidate #f="ngForm" [formGroup]="form">
          <div class="mb-3">
            <div class="form group">
              <label for="img" class="form-label">Logo</label>
              <input class="form-control form-control-sm" id="img" type="text" formControlName="img" [(ngModel)]="expLab.img">
          </div>
        </div>
            <div class="mb-3">
              <div class="form group">
              <label for="nombreE" class="form-label">Nombre del lugar</label>
              <input class="form-control form-control-sm" id="nombreE" formControlName="nombreE" type="text" [(ngModel)]="expLab.nombreE">
            </div>
          </div>
            <div class="mb-3">
              <div class="form group">
                <label for="inicio" class="form-label">Año de inicio</label>
                <input class="form-control form-control-sm" id="inicio" formControlName="inicio" type="text" [(ngModel)]="expLab.inicio">
              </div>
            </div>
              <div class="mb-3">
                <div class="form group">
                <label for="fin" class="form-label">Año de fin</label>
                <input class="form-control form-control-sm" id="fin" formControlName="fin" type="text" [(ngModel)]="expLab.fin">
              </div>
            </div>
                <div class="mb-3">
                  <div class="form group">
                  <label for="descripcionE" class="form-label">Descripción</label>
                  <textarea class="form-control" id="descripcionE" formControlName="descripcionE" rows="3" [(ngModel)]="expLab.descripcionE"></textarea>
                </div>
              </div>    
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
        <button type="submit" class="btn btn-primary" (click)="onEnviar($event)" >Actualizar</button>
    </form>   </div>   </div>

And the TS file:
   export class EditresumeComponent implements OnInit {
   expLab : Experiencia = null;
   form: FormGroup;
     constructor(public router: Router, private sExperiencia: ExperienciaService, private activatedrouter: ActivatedRoute, private formBuilder: FormBuilder) {
       this.form= this.formBuilder.group({
         nombreE:[''],
         inicio:[''],
         fin:[''],
         descripcionE:[''],
         img:[''],
      })
     }
   
     ngOnInit(): void {
      const id = this.activatedrouter.snapshot.params['id'];
       this.sExperiencia.detail(id).subscribe(
         data =>{
           this.expLab = data;
         }
       )
     }
   onUpdate(): void{
     const id = this.activatedrouter.snapshot.params['id'];
     this.sExperiencia.update(id, this.expLab).subscribe(
       data=>{
         this.router.navigateByUrl('/dashboard');
       }, err =>{
         this.router.navigateByUrl('/dashboard');
       }
     )
   }
     
   onEnviar(event: Event){
     event.preventDefault; 
    if (this.form.valid){
       alert("Todo salio bien ¡Enviar formuario!")
     }else{    
       this.form.markAllAsTouched(); 
     }
   
   }

The model:

    export class Experiencia {
        id? : number;
        nombreE : string;
        descripcionE : string;
        inicio : string;
        fin : string;
        localidad : string;
        img: string;
        
    
        constructor(nombreE: string, descripcionE: string, inicio:string, fin:string, localidad:string, img:string){
            this.nombreE = nombreE;
            this.descripcionE = descripcionE;
            this.inicio = inicio;
            this.fin = fin;
            this.localidad = localidad;
            this.img = img;
        }
    }

And the Service:

export class ExperienciaService {
  expURL = 'http://localhost:8080/experiencialaboral/';
  constructor(private httpCliente: HttpClient) { }

  public lista(): Observable<Experiencia[]>{
    return this.httpCliente.get<Experiencia[]>(this.expURL + 'lista');
  }

   public detail(id: number): Observable<Experiencia>{
    return this.httpCliente.get<Experiencia>(this.expURL + `detail/${id}`);
   }

   public save(experiencia: Experiencia): Observable<any>{
    return this.httpCliente.post<any>(this.expURL + 'nueva', experiencia);
   }

   public update(id: number, experiencia: Experiencia): Observable<any>{
    return this.httpCliente.put<any>(this.expURL + `editar/${id}`, experiencia)
   }

   public delete(id: number): Observable<any>{
    return this.httpCliente.delete<any>(this.expURL + `borrar/${id}`)
   }

   
}

Any idea what's generating this?

I tried changing the Img type from "file" to type "text" but it didn't work.

Adding the backend Endpoints (the ones i'm calling):

 @PutMapping ("/editar/{id}")
    public Experiencia editExperiencia (@PathVariable int id,
                                @RequestParam("nombreE") String nuevoNombreE,
                                @RequestParam("descripcionE") String nuevaDescripcion,
                                @RequestParam("inicio") String nuevoInicio,
                                @RequestParam("fin") String nuevoFin,
                                @RequestParam("localidad") String nuevaLocalidad,
                                @RequestParam("img") String nuevaImagen) {
       
        Experiencia expe = servexp.findExperiencia(id);
        
        expe.setNombreE(nuevoNombreE);
        expe.setDescripcionE(nuevaDescripcion);
        expe.setInicio(nuevoInicio);
        expe.setFin(nuevoFin);
        expe.setLocalidad(nuevaLocalidad);
        expe.setImg(nuevaImagen);
        
        servexp.saveExperiencia(expe);
        //reconoce la nueva Persona
        return expe;
        }

@GetMapping("/detail/{id}")
    public ResponseEntity<Experiencia> getById(@PathVariable int id) {
       if (!servexp.existsById(id)){
           return new ResponseEntity(HttpStatus.BAD_REQUEST);
       }
    Experiencia expe = servexp.getOne(id).get();
    return new ResponseEntity(expe, HttpStatus.OK);
    }

In your Angular code you are submitting your data with this function:

public update(id: number, experiencia: Experiencia): Observable<any>{
  return this.httpCliente.put<any>(this.expURL + `editar/${id}`, experiencia)
}

which means you are submitting experiencia as the body of the request.

However, in your Spring Controller, you have this signature for the mapped URL

@PutMapping ("/editar/{id}")
public Experiencia editExperiencia (@PathVariable int id,
                                    @RequestParam("nombreE") String nuevoNombreE,
                                    @RequestParam("descripcionE") String nuevaDescripcion,
                                    @RequestParam("inicio") String nuevoInicio,
                                    @RequestParam("fin") String nuevoFin,
                                    @RequestParam("localidad") String nuevaLocalidad,
                                    @RequestParam("img") String nuevaImagen) {
...
}

which basically is expecting multiple parameters (not just one payload set in the body ) - I think if you change your signature to something like this:

@PutMapping ("/editar/{id}")
public Experiencia editExperiencia (@PathVariable final int id,
                                    @RequestBody Experiencia nuevaExperiencia {
...
}

Where you indicate in the signature to get the request body (and then get the different values from it) - you will achieve what you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM