Java 使用Spring和Jackson实现JSON双重序列化

Java 使用Spring和Jackson实现JSON双重序列化,java,json,spring,hibernate,dto,Java,Json,Spring,Hibernate,Dto,我已经决定对我的所有实体使用DTO,这样我就不必使用@JSONIgnore注释来忽略JSON中的一些脆弱数据,如ID、用户密码等。我不确定这是否是正确的方法,但我想不出任何其他方法-如果你碰巧知道更好的方法,请告诉我 但说到这里,我有一个Book entity,它在其他字段中有一个价格-这是我将来唯一想更改的字段,标题/isbn等。不要更改(我知道它们不是一成不变的,但这是因为JPA-它需要setters/getter/非final字段,对吗?) Book.java(getter/setter命

我已经决定对我的所有实体使用DTO,这样我就不必使用@JSONIgnore注释来忽略JSON中的一些脆弱数据,如ID、用户密码等。我不确定这是否是正确的方法,但我想不出任何其他方法-如果你碰巧知道更好的方法,请告诉我

但说到这里,我有一个Book entity,它在其他字段中有一个价格-这是我将来唯一想更改的字段,标题/isbn等。不要更改(我知道它们不是一成不变的,但这是因为JPA-它需要setters/getter/非final字段,对吗?)

Book.java(getter/setter命令):

我决定创建BookDTO,这样我在发布新书时就不必发送ID(这样Jackson可以毫无怨言地反序列化我的JSON)

所以我将价格存储为BigDecimal,但我认为我可以在JSON中使用double,然后只使用
BigDecimal.valueOf(double newPrice)
来更改Book实体的价格

这是我的BookController.java

@RestController
public class BookController {
  private final BookService bookService;

  @Autowired
  public BookController(BookService bookService) {
    this.bookService = bookService;
  }

  @PutMapping("/books/{id}")
  public ResponseEntity<?> editToDo(@PathVariable("id") Long id, @RequestBody double newPrice) 
      return new ResponseEntity<>(bookService.changePrice(id, newPrice), HttpStatus.OK);
      }
   @Service
@Transactional
public class BookService {

  private final BookRepository bookRepository;

  @Autowired
  public BookService(BookRepository bookRepository) {
    this.bookRepository = bookRepository;
  }

  public Book addNewBook(BookDTO bookDTO) {
    if (bookRepository.findByIsbn(bookDTO.getIsbn()).isPresent()) {
      throw new BookException(
          String.format("Book with that ISBN already exists in database: %s", bookDTO.getIsbn()));
    }
    Book book = new Book();
    book.setAuthor(bookDTO.getAuthor());
    book.setGenre(bookDTO.getGenre());
    book.setIsbn(bookDTO.getIsbn());
    book.setPrice(bookDTO.getPrice());
    book.setPublicationYear(bookDTO.getPublicationYear());
    book.setTitle(bookDTO.getTitle());
    return bookRepository.save(book);
  }

  public Book changePrice(Long id, double price) {
    Book book = findBookById(id);
    book.setPrice(BigDecimal.valueOf(price));
    return book;
  }

  public void deleteBook(Long id) {
    bookRepository.delete(findBookById(id));
  }

  private Book findBookById(Long id) {
    if (bookRepository.findOne(id) == null) {
      throw new BookException(
          String.format("Book with that ID doesn't exist in the database: %s", id));
    }
    return bookRepository.findOne(id);
  }
}
当我用
{'price':30.00}
发布@localhost:8080/books/1时,我得到了以下错误:

    2017-03-07 13:12:11.502  INFO 8327 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor   : Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:471) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:667) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

2017-03-07 13:12:14.635  INFO 8327 --- [nio-8080-exec-3] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2017-03-07 13:12:38.529  WARN 8327 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]
2017-03-07 13:12:38.529  WARN 8327 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]
2017-03-07 13:13:23.069  WARN 8327 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]
2017-03-07 13:13:23.069  WARN 8327 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]

不是关于你问的问题,但是如果你可以毫无问题地使用
BigDecimal.valueOf(double newPrice)
,你可能根本不需要BigDecimal…使用
BigDecimal
可能是一种过度使用。在POST中出现错误的原因是单引号不是有效的json,您需要使用
{“price”:30.00}
您可以显示bookDTO的setter和getter吗?若要,可能会将双值作为字符串发送。
   @Service
@Transactional
public class BookService {

  private final BookRepository bookRepository;

  @Autowired
  public BookService(BookRepository bookRepository) {
    this.bookRepository = bookRepository;
  }

  public Book addNewBook(BookDTO bookDTO) {
    if (bookRepository.findByIsbn(bookDTO.getIsbn()).isPresent()) {
      throw new BookException(
          String.format("Book with that ISBN already exists in database: %s", bookDTO.getIsbn()));
    }
    Book book = new Book();
    book.setAuthor(bookDTO.getAuthor());
    book.setGenre(bookDTO.getGenre());
    book.setIsbn(bookDTO.getIsbn());
    book.setPrice(bookDTO.getPrice());
    book.setPublicationYear(bookDTO.getPublicationYear());
    book.setTitle(bookDTO.getTitle());
    return bookRepository.save(book);
  }

  public Book changePrice(Long id, double price) {
    Book book = findBookById(id);
    book.setPrice(BigDecimal.valueOf(price));
    return book;
  }

  public void deleteBook(Long id) {
    bookRepository.delete(findBookById(id));
  }

  private Book findBookById(Long id) {
    if (bookRepository.findOne(id) == null) {
      throw new BookException(
          String.format("Book with that ID doesn't exist in the database: %s", id));
    }
    return bookRepository.findOne(id);
  }
}
    2017-03-07 13:12:11.502  INFO 8327 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor   : Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:471) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:667) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

2017-03-07 13:12:14.635  INFO 8327 --- [nio-8080-exec-3] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2017-03-07 13:12:38.529  WARN 8327 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]
2017-03-07 13:12:38.529  WARN 8327 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@61fe4c68; line: 1, column: 1]
2017-03-07 13:13:23.069  WARN 8327 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]
2017-03-07 13:13:23.069  WARN 8327 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of double out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@6e8cb870; line: 1, column: 1]