如何将HTML表单数据映射到包含复合键的Spring Boot模型?

huangapple go评论80阅读模式
英文:

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:

&lt;dialog id=&quot;favDialog&quot;&gt;
    &lt;div id=&quot;feedback&quot;&gt;&lt;/div&gt;
    &lt;form id=&quot;add_watchlist_symbol_form&quot;&gt;
        &lt;label for=&quot;symbol&quot;&gt;Enter Symbol:&lt;/label&gt;
        &lt;input type=&quot;text&quot; class=&quot;form-control&quot; id=&quot;symbol&quot; placeholder=&quot;SYMB&quot;/&gt;&lt;br&gt;&lt;br&gt;
        &lt;button type=&quot;submit&quot; class=&quot;btn btn-default&quot; id=&quot;add-watchlist-symbol-btn&quot;&gt;Add&lt;/button&gt;
    &lt;/form&gt;
    &lt;button id=&quot;cancelBtn&quot; value=&quot;cancel&quot;&gt;Cancel&lt;/button&gt;
&lt;/dialog&gt;

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(&quot;Im in submit_watchlist_symbol&quot;);
    var formData = {
        symbol: $(&quot;#symbol&quot;).val(),
        name: &quot;My Portfolio&quot;
    }

     //$(&quot;#btn-search&quot;).prop(&quot;disabled&quot;, true);

    $.ajax({
        type: &quot;POST&quot;,
        contentType: &quot;application/json&quot;,
        url: &quot;/api/v1/AddSymbolToWatchlist&quot;,
        data: JSON.stringify(formData),
        dataType: &#39;json&#39;,
        success: function (result) {
            if(result.status==&quot;Done&quot;) {
                $(&#39;#feedback&#39;).html(result.data.symbol +&quot; added.&quot;);
            }
            else {
                $(&#39;#feedback&#39;).html(&quot;&lt;strong&gt;Error&lt;/strong&gt;&quot;);
            }
            console.log(&quot;ERROR: &quot;,e);
        },
        error: function (e) {
            alert(&quot;Error!&quot;)                    
            console.log(&quot;ERROR: &quot;,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 = &quot;watchlist&quot;)
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 &quot;watchlist:symbol=&quot; +getSymbol() +&quot;, name=&quot;+getName();
	}
}

where watchlistId contains the symbol and name, like this:

@Embeddable
public class WatchlistId implements Serializable {
	@Column(name=&quot;symbol&quot;)
	private String symbol;
	
	@Column(name=&quot;name&quot;)
	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) &amp;&amp; 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(&quot;/AddSymbolToWatchlist&quot;)
@ResponseBody
public AddWatchlistSymbolResponse addSymbolToWatchlist(@RequestBody Watchlist watchlist){
	System.out.println(&quot;made it to AddWatchlistSymbolResponse&quot;);
    // Create Response Object
	AddWatchlistSymbolResponse response = new AddWatchlistSymbolResponse(&quot;Done&quot;, 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 = &quot;/AddSymbolToWatchlist&quot;)
@ResponseBody
public WatchlistIdResponse addSymbolToWatchlist(@RequestBody WatchlistId watchlistId){
	System.out.println(&quot;made it to AddWatchlistSymbolResponse&quot;);
	watchlistService.addSymbolToWatchlist(watchlistId);
    // Create Response Object
	WatchlistIdResponse response = new WatchlistIdResponse(&quot;Done&quot;, 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.

huangapple
  • 本文由 发表于 2020年10月24日 05:08:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64507332.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定