Spring boot 控制器调用不支持内容类型“application/json;charset=UTF-8”

Posted

技术标签:

【中文标题】Spring boot 控制器调用不支持内容类型“application/json;charset=UTF-8”【英文标题】:Content type 'application/json;charset=UTF-8' not supported with Spring boot controller call 【发布时间】:2021-04-12 01:45:16 【问题描述】:

我在将数据从我的 Angular 表单发送到我的 Spring 启动控制器时遇到问题: 我收到此错误: ** WARN 15020 --- [nio-8181-exec-2] .cjMappingJackson2HttpMessageConverter:无法评估 Jackson 反序列化类型 [[simple type, class com.biblio.fr.biblio.entite.BookDTO]]:org.springframework.beans .factory.BeanCreationException:创建名为“com.biblio.fr.biblio.entite.BookDTODeserializer”的bean时出错:bean实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [com.biblio.fr.biblio.entite.BookDTODeserializer]:未找到默认构造函数;嵌套异常是 java.lang.NoSuchMethodException: com.biblio.fr.biblio.entite.BookDTODeserializer.()

WARN 15020 --- [nio-8181-exec-2] .cjMappingJackson2HttpMessageConverter:无法评估类型 [[simple type, class com.biblio.fr.biblio.entite.BookDTO]] 的 Jackson 反序列化:com。 fastxml.jackson.databind.JsonMappingException:com.biblio.fr.biblio.entite.BookDTODeserializer 类没有默认(无 arg)构造函数

WARN 15020 --- [nio-8181-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : 已解决 [org.springframework.web.HttpMediaTypeNotSupportedException: 内容类型 'application/json;charset=UTF-8' 不支持] **

这是我的java代码:

@RequestMapping(value = "/addBook", method = RequestMethod.POST, produces = "application/json")
    @ApiOperation(value = "Add a new Book in the Library", response = BookDTO.class)
    @ApiResponses(value =  @ApiResponse(code = 409, message = "Conflict: the book already exist"),
            @ApiResponse(code = 201, message = "Created: the book is successfully inserted"),
            @ApiResponse(code = 304, message = "Not Modified: the book is unsuccessfully inserted") )
    public ResponseEntity<BookDTO> createNewBook(@RequestBody BookDTO bookDTORequest) 
        // , UriComponentsBuilder uriComponentBuilder
        Book existingBook = bookService.findBookByIsbn(bookDTORequest.getIsbn());
        if (existingBook != null) 
            return new ResponseEntity<BookDTO>(HttpStatus.CONFLICT);
        
        Book bookRequest = mapBookDTOToBook(bookDTORequest);
        Book book = bookService.saveBook(bookRequest);
        if (book != null && book.getId() != null) 
            BookDTO bookDTO = mapBookToBookDTO(book);
            return new ResponseEntity<BookDTO>(bookDTO, HttpStatus.CREATED);
        
        return new ResponseEntity<BookDTO>(HttpStatus.NOT_MODIFIED);
 
    
 
    private BookDTO mapBookToBookDTO(Book book) 
        ModelMapper mapper = new ModelMapper();
        BookDTO bookDTO = mapper.map(book, BookDTO.class);
        if (book.getCategory() != null) 
            bookDTO.setCategory(new CategoryDTO(book.getCategory().getCode(), book.getCategory().getLabel()));
        
        return bookDTO;
    
 
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(using = BookDTODeserializer.class)
@Data
@AllArgsConstructors
public class BookDTO implements Comparable<BookDTO> 
    @ApiModelProperty(value = "Book id")
    private Integer id;
 
    @ApiModelProperty(value = "Book title")
    private String title;
 
    @ApiModelProperty(value = "Book isbn")
    private String isbn;
 
    @ApiModelProperty(value = "Book release date by the editor")
    private LocalDate releaseDate;
 
    @ApiModelProperty(value = "Book register date in the library")
    private LocalDate registerDate;
 
    @ApiModelProperty(value = "Book total examplaries")
    private Integer totalExamplaries;
 
    @ApiModelProperty(value = "Book author")
    private String author;
 
    @ApiModelProperty(value = "Book category")
    private CategoryDTO category;
 
 
    @Override
    public int compareTo(BookDTO o) 
        return title.compareToIgnoreCase(o.getTitle());
    
 
    public BookDTO() 
        super();
    
 

 
@Entity
@Data
@AllArgsConstructors
public class Book 
    private static final long serialVersionUID = 425345L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
 
    private String title;
    private String author;
    private String publisher;
    private String publicationDate;
    private String language;
    private String category;
    private int numberOfPages;
    private String format;
    private String isbn;
    private double shippingWeight;
    private double listPrice;
    private double ourPrice;
    private boolean active = true;
 
    @Column(columnDefinition = "text")
    private String description;
    private int inStockNumber;
 
    @Transient
    private MultipartFile bookImage;

 
@Data
@AllArgsConstructors
@JsonDeserialize(using = CategoryDTODeserializer.class)
public class CategoryDTO implements Comparable<CategoryDTO> 
    public CategoryDTO() 
    
 
    public CategoryDTO(String code, String label) 
        super();
        this.code = code;
        this.label = label;
    
 
    @ApiModelProperty(value = "Category code")
    private String code;
 
    @ApiModelProperty(value = "Category label")
    private String label;
 

 
@Entity
@Table(name = "CATEGORY")
public class Category 
    public Category() 
    
 
    public Category(String code, String label) 
        super();
        this.code = code;
        this.label = label;
    
 
    private String code;
 
    private String label;
 
    @Id
    @Column(name = "CODE")
    public String getCode() 
        return code;
    
 
    public void setCode(String code) 
        this.code = code;
    
 
    @Column(name = "LABEL", nullable = false)
    public String getLabel() 
        return label;
    
 
    public void setLabel(String label) 
        this.label = label;
    

 
public class BookDTODeserializer extends StdDeserializer<BookDTO> 
 
    @Override
    public BookDTO deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException 
        // TODO Auto-generated method stub
        JsonNode node = p.getCodec().readTree(p);
        Integer id = (Integer) ((IntNode) node.get("id")).numberValue();
        String title = node.get("title").asText();
        String isbn = node.get("isbn").asText();
        LocalDate releaseDate = LocalDate.parse(node.get("releaseDate").asText());
        LocalDate registerDate = LocalDate.parse(node.get("registerDate").asText());
        Integer totalExamplaries = (Integer) ((IntNode) node.get("totalExamplaries")).numberValue();
        String author = node.get("author").asText();
        String codeCategory = node.get("code").asText();
        String labelCategory = node.get("label").asText();
 
        return new BookDTO(id, title, isbn, releaseDate, registerDate, totalExamplaries, author,
                new CategoryDTO(codeCategory, labelCategory));
        // return null;
    
 
    public BookDTODeserializer(Class<?> vc) 
        super(vc);
        // TODO Auto-generated constructor stub
    
 
    public BookDTODeserializer(JavaType valueType) 
        super(valueType);
        // TODO Auto-generated constructor stub
    
 
    public BookDTODeserializer(StdDeserializer<?> src) 
        super(src);
        // TODO Auto-generated constructor stub
    
 

 
public class CategoryDTODeserializer extends StdDeserializer<CategoryDTO> 
 
    @Override
    public CategoryDTO deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException 
        JsonNode node = p.getCodec().readTree(p);
        String codeCategory = node.get("code").asText();
        String labelCategory = node.get("label").asText();
        return new CategoryDTO(codeCategory, labelCategory);
    
 
    public CategoryDTODeserializer(Class<?> vc) 
        super(vc);
        // TODO Auto-generated constructor stub
    
 
    public CategoryDTODeserializer(JavaType valueType) 
        super(valueType);
        // TODO Auto-generated constructor stub
    
 
    public CategoryDTODeserializer(StdDeserializer<?> src) 
        super(src);
        // TODO Auto-generated constructor stub
    
 

还有我的角码

saveBook(book: Book): Observable<Book>
      let headers = new HttpHeaders();
      headers.append('content-type', 'application/json');
      headers.append('accept', 'application/json');
      return this.http.post<Book>(environment.apiUrl+'/rest/book/api/addBook', book, headers: headers);
     

有什么想法吗?

【问题讨论】:

【参考方案1】:

根据警告/错误消息,您缺少以下内容:

    未找到默认构造函数;嵌套异常是 java.lang.NoSuchMethodException: com.biblio.fr.biblio.entite.BookDTODeserializer

使用 @NoArgsConstructor 声明 BookDTODeserializer

    也将消费添加为 JSON。 @RequestMapping(value = "/addBook", method = RequestMethod.POST,produces = "application/json", consumes = "application/json")

考虑到您已经在请求正文中以 JSON 形式接收 DTO,我不明白为什么需要这个“手动”反序列化器。

【讨论】:

嗨@EZequiel,我在 BookDTODeserializer 解析 localDate LocalDate releaseDate = LocalDate.parse(node.get("releaseDate").asText());Text '2021-01-14T00 时遇到错误: 00:00.000Z' 无法解析,在索引 10 处找到未解析的文本 嗨@obela06,您需要设置日期格式。对于您的情况,我找不到默认格式,因此建议使用模式: LocalDate.parse(node.get("releaseDate").asText(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh :mm:ss.nnn'Z'"));【参考方案2】:

Spring 引导控制器调用不支持内容类型 'application/json;charset=UTF-8'

不是这里的问题

问题是:

com.biblio.fr.biblio.entite.BookDTODeserializer 没有默认(无 arg)构造函数

public class BookDTODeserializer extends StdDeserializer<BookDTO> 
    public BookDTODeserializer() 
        super(BookDTO.class);
    
    ...

直接加@NoArgsConstructor对你没有帮助,会报错:

There is no default constructor available in 'com.fasterxml.jackson.databind.deser.std.StdDeserializer'

【讨论】:

嗨@Hùng Phan Viêt,我在BookDTODeserializer 中遇到错误,无法解析localDate LocalDate releaseDate = LocalDate.parse(node.get("releaseDate").asText());Text '2021-01- 14T00:00:00.000Z' 无法解析,在索引 10 处找到未解析的文本

以上是关于Spring boot 控制器调用不支持内容类型“application/json;charset=UTF-8”的主要内容,如果未能解决你的问题,请参考以下文章

spring boot mvc - 不支持内容类型'application/json;charset = UTF-8'

内容类型'text/plain;charset = UTF-8'在RestController类中的spring boot中不支持错误

Spring Boot oauth:不支持的授权类型

不支持 Spring/Postman 内容类型“application/octet-stream”

Spring RESTTemplate getForObject 方法不支持返回的内容类型“null”

使用 @RestController 在 Spring Boot 中发布数据时出错