英文:
How to map html form data to a Spring Boot model containing a composite key?
问题
我在HTML中有一个弹出表单,看起来像这样:
<dialog id="favDialog">
<div id="feedback"></div>
<form id="add_watchlist_symbol_form">
<label for="symbol">Enter Symbol:</label>
<input type="text" class="form-control" id="symbol" placeholder="SYMB"/><br><br>
<button type="submit" class="btn btn-default" id="add-watchlist-symbol-btn">Add</button>
</form>
<button id="cancelBtn" value="cancel">Cancel</button>
</dialog>
当我点击一个按钮时,对话框成功弹出。
对话框中有一个名为 "Add" 的按钮。它的点击事件由 JavaScript 处理,会发送一个包含表单字段值的 Ajax POST 请求到 Spring Boot,像这样:
function submit_watchlist_symbol() {
console.log("Im in submit_watchlist_symbol");
var formData = {
symbol: $("#symbol").val(),
name: "My Portfolio"
}
$.ajax({
type: "POST",
contentType: "application/json",
url: "/api/v1/AddSymbolToWatchlist",
data: JSON.stringify(formData),
dataType: 'json',
success: function (result) {
if(result.status=="Done") {
$('#feedback').html(result.data.symbol + " added.");
}
else {
$('#feedback').html("<strong>Error</strong>");
}
console.log("ERROR: ", e);
},
error: function (e) {
alert("Error!");
console.log("ERROR: ", e);
}
});
// 重置表单数据
resetData();
}
当我点击该按钮时,我收到 Spring Boot 的错误:
已解析
[org.springframework.http.converter.HttpMessageNotReadableException:
JSON 解析错误:null;嵌套异常为
com.fasterxml.jackson.databind.JsonMappingException:N/A 位于 [源:
(PushbackInputStream);行:1,列:11](通过引用链:
net.tekknow.moneymachine.model.Watchlist["symbol"])]
我怀疑表单数据没有正确映射到 Watchlist.java 模型,可能是由于模型包含一个复合键,像这样:
@Entity
@Table(name = "watchlist")
public class Watchlist {
@EmbeddedId
public WatchlistId watchlistId;
public String getSymbol() {
return watchlistId.getSymbol();
}
public void setSymbol(String symbol) {
watchlistId.setSymbol(symbol);
}
public String getName() {
return watchlistId.getName();
}
public void setName(String watchlistName) {
watchlistId.setName(watchlistName);
}
public String toString() {
return "watchlist:symbol=" + getSymbol() + ", name=" + getName();
}
}
其中 watchlistId 包含 symbol 和 name,像这样:
@Embeddable
public class WatchlistId implements Serializable {
@Column(name="symbol")
private String symbol;
@Column(name="name")
private String name;
WatchlistId() {
}
WatchlistId(String symbol, String name) {
this.symbol = symbol;
this.name = name;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WatchlistId that = (WatchlistId) o;
return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(symbol, name);
}
}
这是处理请求的 Spring Boot 控制器:
@PostMapping("/AddSymbolToWatchlist")
@ResponseBody
public AddWatchlistSymbolResponse addSymbolToWatchlist(@RequestBody Watchlist watchlist){
System.out.println("made it to AddWatchlistSymbolResponse");
// 创建响应对象
AddWatchlistSymbolResponse response = new AddWatchlistSymbolResponse("Done", watchlist);
return response;
}
AddWatchlistSymbolResponse 类如下:
public class AddWatchlistSymbolResponse {
private String status;
private Object data;
public AddWatchlistSymbolResponse(){
}
public AddWatchlistSymbolResponse(String status, Object data){
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
有什么建议吗?
英文:
I have popup form in my html that looks like this:
<dialog id="favDialog">
<div id="feedback"></div>
<form id="add_watchlist_symbol_form">
<label for="symbol">Enter Symbol:</label>
<input type="text" class="form-control" id="symbol" placeholder="SYMB"/><br><br>
<button type="submit" class="btn btn-default" id="add-watchlist-symbol-btn">Add</button>
</form>
<button id="cancelBtn" value="cancel">Cancel</button>
</dialog>
The dialog pops up successfully when I click a button.
The dialog contains a button called Add. It's click event is handled by javascript which sends an ajax POST request containing the form field values to Spring Boot like this:
function submit_watchlist_symbol() {
console.log("Im in submit_watchlist_symbol");
var formData = {
symbol: $("#symbol").val(),
name: "My Portfolio"
}
//$("#btn-search").prop("disabled", true);
$.ajax({
type: "POST",
contentType: "application/json",
url: "/api/v1/AddSymbolToWatchlist",
data: JSON.stringify(formData),
dataType: 'json',
success: function (result) {
if(result.status=="Done") {
$('#feedback').html(result.data.symbol +" added.");
}
else {
$('#feedback').html("<strong>Error</strong>");
}
console.log("ERROR: ",e);
},
error: function (e) {
alert("Error!")
console.log("ERROR: ",e);
}
});
// Reset FormData after Posting
resetData();
}
When I click that button I get Spring Boot error:
> Resolved
> [org.springframework.http.converter.HttpMessageNotReadableException:
> JSON parse error: null; nested exception is
> com.fasterxml.jackson.databind.JsonMappingException: N/A at [Source:
> (PushbackInputStream); line: 1, column: 11] (through reference chain:
> net.tekknow.moneymachine.model.Watchlist["symbol"])]
I suspect the form data is not being mapped correctly to the Watchlist.java model due to the model containing a composite key, like this:
@Entity
@Table(name = "watchlist")
public class Watchlist {
@EmbeddedId
public WatchlistId watchlistId;
public String getSymbol() {
return watchlistId.getSymbol();
}
public void setSymbol(String symbol) {
watchlistId.setSymbol(symbol);
}
public String getName() {
return watchlistId.getName();
}
public void setName(String watchlistName) {
watchlistId.setName(watchlistName);
}
public String toString() {
return "watchlist:symbol=" +getSymbol() +", name="+getName();
}
}
where watchlistId contains the symbol and name, like this:
@Embeddable
public class WatchlistId implements Serializable {
@Column(name="symbol")
private String symbol;
@Column(name="name")
private String name;
WatchlistId() {
}
WatchlistId(String symbol, String name) {
this.symbol = symbol;
this.name = name;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WatchlistId that = (WatchlistId) o;
return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(symbol, name);
}
}
Here is the Spring Boot controller that handles the request:
@PostMapping("/AddSymbolToWatchlist")
@ResponseBody
public AddWatchlistSymbolResponse addSymbolToWatchlist(@RequestBody Watchlist watchlist){
System.out.println("made it to AddWatchlistSymbolResponse");
// Create Response Object
AddWatchlistSymbolResponse response = new AddWatchlistSymbolResponse("Done", watchlist);
return response;
}
The AddWatchlistSymbolResponse class looks like this:
public class AddWatchlistSymbolResponse {
private String status;
private Object data;
public AddWatchlistSymbolResponse(){
}
public AddWatchlistSymbolResponse(String status, Object data){
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
Suggestions?
答案1
得分: 0
我弄清楚了。我将控制器更改为以下内容:
@PostMapping(value = "/AddSymbolToWatchlist")
@ResponseBody
public WatchlistIdResponse addSymbolToWatchlist(@RequestBody WatchlistId watchlistId){
System.out.println("已到达AddWatchlistSymbolResponse");
watchlistService.addSymbolToWatchlist(watchlistId);
// 创建响应对象
WatchlistIdResponse response = new WatchlistIdResponse("完成", watchlistId);
return response;
}
并为WatchlistId创建了一个单独的响应类WatchlistIdResponse.java:
package net.tekknow.moneymachine.model;
public class WatchlistIdResponse {
private String status;
private Object data;
public WatchlistIdResponse() {
}
public WatchlistIdResponse(String status, Object data) {
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
原因是Watchlist类仅包含WatchlistId属性。WatchlistId包含构成复合索引的symbol和name属性。
英文:
I figured it out. I changed the controller to this:
@PostMapping(value = "/AddSymbolToWatchlist")
@ResponseBody
public WatchlistIdResponse addSymbolToWatchlist(@RequestBody WatchlistId watchlistId){
System.out.println("made it to AddWatchlistSymbolResponse");
watchlistService.addSymbolToWatchlist(watchlistId);
// Create Response Object
WatchlistIdResponse response = new WatchlistIdResponse("Done", watchlistId);
return response;
}
And created a separate response for WatchlistId called WatchlistIdResponse.java:
package net.tekknow.moneymachine.model;
public class WatchlistIdResponse {
private String status;
private Object data;
public WatchlistIdResponse() {
}
public WatchlistIdResponse(String status, Object data) {
this.status = status;
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
The reason is that the Watchlist class contains only the WatchlistId property. WatchlistId contains the symbol and name properties that make up the composite index.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论