为什么@RequestBody获取具有空属性的对象 [英] Why is the @RequestBody getting an object with null attributes
问题描述
我有一个springboot REST控制器,具有所示的PATCH和PUT的请求方法.由于某些原因,@ RequestBody"company"的字段/属性以空值形式出现.我想念什么?
I have a springboot REST controller with the request method for a PATCH and PUT as indicated. For some reason, the fields/attributes for @RequestBody "company" are coming in as null values. What am I missing?
我在前端使用angular8,并且正在执行PATCH调用.
I am using angular8 on the front end and it is performing a PATCH call.
我尝试了其他一些建议,但没有运气.如果这是一个重复的问题,请指出答案.
I have tried some of the other posts suggestions, but no luck. If this is a repeated question, please point me to the answer.
Spring Tool Suite 4
版本:4.1.0.RELEASE建立编号:201812201347
Version: 4.1.0.RELEASE Build Id: 201812201347
版权所有(c)2007-2018 Pivotal,Inc.版权所有.访问 http://spring.io/tools4
Copyright (c) 2007 - 2018 Pivotal, Inc. All rights reserved. Visit http://spring.io/tools4
我正在将pgAdmin 4.12用于Postgres.
I am using pgAdmin 4.12 for postgres.
这是我从Angular拨打的电话:
This is the call I am making from Angular:
this.companyService.patch$(this.currentId, this.appMenu.currentObject).subscribe(selectedCompany => {this.appMenu.currentObject = selectedCompany});
这是如上所示被调用的角度服务:
This is the angular service that is called as indicated above:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { Company } from '../models/company.model';
@Injectable({
providedIn: 'root'
})
export class CompanyService {
private url: string;
constructor(private http: HttpClient) {
this.url = "http://localhost:8080/niche/company";
}
getOne$ = (companyId: number): Observable<Company> => this.http.get<Company>(`${this.url}/${companyId}`);
get$ = (): Observable<Company[]> => this.http.get<Company[]>(this.url);
post$ = (company: Company): Observable<Company> => this.http.post<Company>(this.url, { company });
patch$ = (companyId: number, company: Company): Observable<Company> => this.http.patch<Company>(`${this.url}/${companyId}`, { company });
delete$ = (companyId: number): Observable<Company> => this.http.delete<Company>(`${this.url}/${companyId}`);
}
从Angular前端请求有效载荷:
Request Payload from Angular front end:
{company: {createdBy: "denis", createdDate: "2019-04-14T04:00:00.000+0000", updatedBy: "denis",…}}
company: {createdBy: "denis", createdDate: "2019-04-14T04:00:00.000+0000", updatedBy: "denis",…}
companyName: "Bull Winkle"
createdBy: "denis"
createdDate: "2019-04-14T04:00:00.000+0000"
email: "bullwinkle@mail.com"
id: 2
notes: "test"
phone: "999999999"
products: []
updatedBy: "denis"
updatedDate: "2019-05-14T04:00:00.000+0000"
webSite: "bullwilkle.com"
这是实际的JSON:
{"company":{"createdBy":"denis","createdDate":"2019-04-14T04:00:00.000+0000","updatedBy":"denis","updatedDate":"2019-05-14T04:00:00.000+0000","id":2,"email":"bullwinkle@mail.com","companyName":"Bull Winkle","webSite":"bullwilkle.com","phone":"999999999","notes":"test","products":[]}}
springboot后端控制器:
The springboot backend controller:
/**
*
*/
package com.ebusiness.niche.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import com.ebusiness.niche.entity.Company;
import com.ebusiness.niche.service.CompanyService;
//import com.sun.istack.internal.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author denisputnam
*
*/
@RestController
@RequestMapping( value = "/niche" )
public class CompanyController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private CompanyService companyService;
@ResponseBody
@RequestMapping(value = {"/company"}, method = { RequestMethod.GET })
@CrossOrigin(origins = "http://localhost:4200")
public ResponseEntity<List<Company>> getCompanys() {
log.info("getCompanys(): Called...");
List<Company> companyList = null;
companyList = this.companyService.findAll();
if( companyList == null || companyList.isEmpty() ) {
log.info("getCompanys(): returned a null or empty list.");
ResponseEntity<List<Company>> rVal = new ResponseEntity<List<Company>>(companyList, HttpStatus.NO_CONTENT);
return rVal;
}
return new ResponseEntity<List<Company>>(companyList, HttpStatus.OK);
}
@ResponseBody
@RequestMapping(value = {"/company/{id}"}, method = { RequestMethod.GET })
@CrossOrigin(origins = "http://localhost:4200")
public ResponseEntity<Company> getCompany(@PathVariable("id") Long id) {
log.info("getCompany(): Called...");
log.info("id=" + id);
// List<Company> companyList = null;
Optional<Company> optcompany = null;
Company company = null;
optcompany = this.companyService.findById(id);
if( optcompany == null ) {
log.info("getCompany(): returned a null.");
ResponseEntity<Company> rVal = new ResponseEntity<Company>(company, HttpStatus.NO_CONTENT);
return rVal;
} else {
company = optcompany.get();
}
return new ResponseEntity<Company>(company, HttpStatus.OK);
}
@ResponseBody
// @RequestMapping(value = {"/company/{id}"}, headers = {
// "content-type=application/json" }, consumes = MediaType.APPLICATION_JSON_VALUE, method = { RequestMethod.PATCH, RequestMethod.PUT, RequestMethod.POST })
@RequestMapping(value = {"/company/{id}"}, method = { RequestMethod.PATCH, RequestMethod.PUT })
@CrossOrigin(origins = {"http://localhost:4200"})
public ResponseEntity<Company> updateCompany(@PathVariable("id") Long id, @RequestBody Company company) {
log.info("updateCompany(): Called...");
log.info("id=" + id);
Optional<Company> currentCompany = this.companyService.findById(id);
Company dbCompany = null;
if( currentCompany == null ) {
log.error("Unable to update. The company with id {} not found.", id);
ResponseEntity<Company> rVal = new ResponseEntity<Company>(company, HttpStatus.NO_CONTENT);
return rVal;
}
dbCompany = currentCompany.get();
dbCompany.setCompanyName(company.getCompanyName());
dbCompany.setEmail(company.getEmail());
dbCompany.setNotes(company.getNotes());
dbCompany.setPhone(company.getPhone());
dbCompany.setWebSite(company.getWebSite());
this.companyService.update(dbCompany);
return new ResponseEntity<Company>(dbCompany, HttpStatus.OK);
}
}
springboot后端实体bean:
The springboot backend entity bean:
/**
*
*/
package com.ebusiness.niche.entity;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
/**
* @author denisputnam
*
*/
@Entity
@Table(
uniqueConstraints = {
@UniqueConstraint(columnNames = {"email"})
}
)
public class Company extends History implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1329304564033025946L;
@Id
@GeneratedValue
private Long id;
@Column
@NotNull
private String email;
@Column
@NotNull
private String companyName;
@Column
@NotNull
private String webSite;
@Column
@NotNull
private String phone;
@Column(length=4096)
private String notes;
@ManyToMany(mappedBy="companys")
Set<Product> products;
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getWebSite() {
return webSite;
}
public void setWebSite(String webSite) {
this.webSite = webSite;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
此History基类实体bean:
This History base class entity bean:
/**
*
*/
package com.ebusiness.niche.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
/**
* @author denisputnam
*
*/
//@Entity
@MappedSuperclass
public class History implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1136283585074348099L;
private String createdBy;
@Column(nullable = false)
@NotNull
private Date createdDate = new Date();
private String updatedBy;
private Date updatedDate;
/**
* @return the createdBy
*/
public String getCreatedBy() {
return createdBy;
}
/**
* @param createdBy the createdBy to set
*/
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
/**
* @return the createdDate
*/
public Date getCreatedDate() {
return createdDate;
}
/**
* @param createdDate the createdDate to set
*/
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
/**
* @return the updatedBy
*/
public String getUpdatedBy() {
return updatedBy;
}
/**
* @param updatedBy the updatedBy to set
*/
public void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}
/**
* @return the updatedDate
*/
public Date getUpdatedDate() {
return updatedDate;
}
/**
* @param updatedDate the updatedDate to set
*/
public void setUpdatedDate(Date updatedDate) {
this.updatedDate = updatedDate;
}
}
我对此进行了编辑,以添加控制台日志中的TRACE输出.我还简化了Company实体,使其不包含任何日期或与其他实体的任何其他关系,因此现在仅传递字符串.
I edited this to add the TRACE output from the console log. I also simplified the Company entity to not contain any dates or any other relationships to other entities, so now only strings are passed.
这是TRACE输出:
2019-09-18 15:52:19.591 TRACE 47732 --- [nio-8080-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl : Releasing JDBC resources
2019-09-18 15:52:19.591 TRACE 47732 --- [nio-8080-exec-1] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(true)
2019-09-18 15:52:19.591 TRACE 47732 --- [nio-8080-exec-1] .t.i.SynchronizationRegistryStandardImpl : SynchronizationRegistryStandardImpl.notifySynchronizationsAfterTransactionCompletion(3)
2019-09-18 15:52:19.591 TRACE 47732 --- [nio-8080-exec-1] org.hibernate.internal.SessionImpl : SessionImpl#afterTransactionCompletion(successful=true, delayed=false)
2019-09-18 15:52:19.594 DEBUG 47732 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [application/json, text/plain, */*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-09-18 15:52:19.594 TRACE 47732 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [[com.ebusiness.niche.entity.Company@ddb52f3, com.ebusiness.niche.entity.Company@73d5674e]]
2019-09-18 15:52:19.619 TRACE 47732 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No view rendering, null ModelAndView returned.
2019-09-18 15:52:19.619 TRACE 47732 --- [nio-8080-exec-1] org.hibernate.internal.SessionImpl : Closing session [f1652eeb-71a2-4776-8d94-9573336d60f3]
2019-09-18 15:52:19.619 TRACE 47732 --- [nio-8080-exec-1] o.h.e.jdbc.internal.JdbcCoordinatorImpl : Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@6effa4c8]
2019-09-18 15:52:19.619 TRACE 47732 --- [nio-8080-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl : Releasing JDBC resources
2019-09-18 15:52:19.619 TRACE 47732 --- [nio-8080-exec-1] o.h.r.j.i.LogicalConnectionManagedImpl : Closing logical connection
2019-09-18 15:52:19.620 TRACE 47732 --- [nio-8080-exec-1] o.h.r.j.i.ResourceRegistryStandardImpl : Releasing JDBC resources
2019-09-18 15:52:19.620 TRACE 47732 --- [nio-8080-exec-1] o.h.r.j.i.LogicalConnectionManagedImpl : Logical connection closed
2019-09-18 15:52:19.620 DEBUG 47732 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK, headers={masked}
2019-09-18 15:52:31.192 TRACE 47732 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<com.ebusiness.niche.entity.Company> com.ebusiness.niche.controller.CompanyController.updateCompany(java.lang.Long,com.ebusiness.niche.entity.Company)
2019-09-18 15:52:31.264 TRACE 47732 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<com.ebusiness.niche.entity.Company> com.ebusiness.niche.controller.CompanyController.updateCompany(java.lang.Long,com.ebusiness.niche.entity.Company)
2019-09-18 15:52:31.266 TRACE 47732 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : PUT "/niche/company/2", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2019-09-18 15:52:31.267 TRACE 47732 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<com.ebusiness.niche.entity.Company> com.ebusiness.niche.controller.CompanyController.updateCompany(java.lang.Long,com.ebusiness.niche.entity.Company)
2019-09-18 15:52:31.268 TRACE 47732 --- [nio-8080-exec-3] .i.SessionFactoryImpl$SessionBuilderImpl : Opening Hibernate Session. tenant=null, owner=null
2019-09-18 15:52:31.268 TRACE 47732 --- [nio-8080-exec-3] org.hibernate.internal.SessionImpl : Opened Session [740dabea-2970-4491-8ff7-d373afc649f6] at timestamp: 1568836351268
2019-09-18 15:52:31.268 TRACE 47732 --- [nio-8080-exec-3] o.s.web.cors.DefaultCorsProcessor : Skip: response already contains "Access-Control-Allow-Origin"
2019-09-18 15:52:31.312 TRACE 47732 --- [nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Read "application/json;charset=UTF-8" to [com.ebusiness.niche.entity.Company@46388186]
2019-09-18 15:52:31.320 TRACE 47732 --- [nio-8080-exec-3] .w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: [2, com.ebusiness.niche.entity.Company@46388186]
推荐答案
好,此问题是因为从前端应用程序
发送了JSON正文作为嵌套了公司的JSON对象. {公司}
OK, this issue was because from Front End application
was being sent a the JSON body as an JSON object that had nested a company. { company }
patch$ = (companyId: number, company: Company): Observable<Company>
=> this.http.patch<Company>(`${this.url}/${companyId}`, { company });
然后,当请求到达后端应用程序
时,字段值是 null
,因为它是 company
中的JSON对象.通过移除方括号 {}
可以解决此问题,以使 company
作为对象.
Then when the request was coming to Back End application
the fields values were null
since that it was a JSON object within company
. This was fixed by removing the brackets {}
in order to have company
as object.
patch$ = (companyId: number, company: Company): Observable<Company>
=> this.http.patch<Company>(`${this.url}/${companyId}`, company);
这篇关于为什么@RequestBody获取具有空属性的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!