簡體   English   中英

Spring MVC復雜對象數據綁定

[英]Spring MVC complex object data binding

我仍然在為Spring MVC奮斗,這應該是一個相當簡單的問題,但是在Spring MVC文檔中似乎很少記錄。

我的項目使用Spring MVC和Thymeleaf作為視圖,但是視圖渲染引擎與該問題並不真正相關。

我的應用程序以一個Activity類為中心,該Activity類對一個(室內或室外)活動進行建模,該活動由成員組織並且其他成員可以訂閱。 一個Activity有一個Category字段和Region字段,它們是下拉字段,由Hibernate建模為包含ID和description字段的DB查找表的多對一實體。

Activity實體類的代碼如下,省略了不相關的字段以縮短代碼:

package nl.drsklaus.activiteitensite.model;

//imports

@Entity
@Table(name="activity")
public class Activity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Integer id;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="organizer_id")
private Member organizer;

@Size(min=5, max=50)
@Column(name = "title", nullable = false)
private String title;

@Size(min=5, max=500)
@Column(name = "description", nullable = false)
private String description;

@ManyToOne
@JoinColumn(name="category_id")
private ActivityCategory category;

@ManyToOne
@JoinColumn(name="region_id")
private ActivityRegion region;


@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name="member_activity_subscription", 
           joinColumns = {@JoinColumn(name="activity_id")}, 
           inverseJoinColumns={@JoinColumn(name="member_id")})
private List<Member> participants = new ArrayList<Member>();

//getters and setters   

@Override
public int hashCode() {
  ...
}

@Override
public boolean equals(Object obj) {
  ...
}
}

在視圖中,用戶應該能夠從選擇框中選擇地區和類別。 選項在類級別上使用@ModelAttribute注解方法放入模型中。

問題是框​​綁定到查找屬性字段。

例如,類別字段是ActivityCategory類型,它是一個包含id和description屬性的實體類。

在視圖中,選擇框填充有可能的選項列表(all類別包含ActivityCategory實例),Thymeleaf負責通過將“ value”屬性值與列表進行匹配來選擇當前值:

<label>Categorie</label>
<select th:field="*{category}">
  <option th:each="cat : ${allCategories}"
          th:value="${cat}"
          th:text="${cat.description}">
  </option>
</select>

生成的HTML如下所示:

<select id="category" name="category">
      <option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@20">Actief en sportief</option>
      <option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@21">Uitgaan en nachtleven</option>
      <option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@22" selected="selected">Kunst en cultuur</option>
      <option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@23">Eten en drinken</option>
      <option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@24" selected="selected">Ontspanning en gezelligheid</option>
</select>

如我們所見,value屬性包含對象本身的字符串表示形式,這顯然是不希望的,為了顯示id值,我們可以使用$ {cat.id}代替$ {cat},但是可以選擇當前值(設置'selected =“ selected”'屬性)不再起作用。 在此之前,我實現了一個Converter,該Converter將ActivityCategory對象轉換為int(id值)。 在Thymeleaf中,通過使用雙贊{{}}來調用轉換器:

th:value="${{cat}}"

轉換器已創建並添加到Spring:

public class LookupConverter implements Converter<LookupEntity, String> {
  public String convert(LookupEntity source) {
     return String.valueOf(source.getId());
  }
}

//在MvcConfig類中

@Override
public void addFormatters(FormatterRegistry registry) {
  registry.addConverter(new LookupConverter());
}

現在,HTML顯示了選項的id值,這更加合乎邏輯:

<select id="category" name="category">
      <option value="1">Actief en sportief</option>
      <option value="2">Uitgaan en nachtleven</option>
      <option value="3" selected="selected">Kunst en cultuur</option>
      <option value="4">Eten en drinken</option>
      <option value="5">Ontspanning en gezelligheid</option>
</select>

但是在提交后仍然錯誤,ID值不能綁定到期望使用ActivityCategory的Activity對象(如果是整數值),因此會生成typeMismatch驗證錯誤。

我的處理程序方法如下所示:

@RequestMapping(value = "/{id}/submit", method = RequestMethod.POST)
public String submitForm(@ModelAttribute("activity") Activity activity, BindingResult result, ModelMap model) {

    if (result.hasErrors()) {
        return "activityform";
    } else {

        if (activity.getId() == null) {
            this.service.saveActivity(activity);
        } else {
            this.service.mergeWithExistingAndUpdate(activity);
        }

        return "redirect:/activity/" + activity.getId() + "/detail";
    }
}

我看過很多帖子,但仍然找不到針對恕我直言的瑣碎問題的解決方案。 包含id的String值如何被處理程序方法接受並正確轉換? 還是我們不能為此目的使用id值? 尋找一些提示...

我認為您不能使用實體模型將數據從表單提交到MVC控制器。 嘗試創建一個與表單數據匹配的單獨的表單對象,並編寫服務方法以將其轉換為可以在數據庫中保留的實體。

在另一個論壇的幫助下,我找到了最優雅的解決方案! 代替轉換器,我們使用格式化程序,該格式化程序可以將特定對象類型轉換為字符串,反之亦然。 格式化程序已注冊到Spring,並從Thymeleaf自動調用,並將id字段轉換為僅設置了id值的ActivityCategory實例。 因此,我們無需從數據庫中查找實際實例,因為在這里我們不需要描述,因為Hober吃了這個ID足以創建查詢。

我的格式化程序看起來像:

public class ActivityCategoryFormatter implements Formatter<ActivityCategory> {

@Override
public String print(ActivityCategory ac, Locale locale) {
    // TODO Auto-generated method stub
    return Integer.toString(ac.getId());
}

@Override
public ActivityCategory parse(final String text, Locale locale) throws ParseException {
    // TODO Auto-generated method stub
    int id = Integer.parseInt(text);
    ActivityCategory ac = new ActivityCategory(id);

    return ac;
}
} 

並通過以下方式注冊到Spring(與ActivityRegionFormatter一起用於其他查找字段):

@Override
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(new LookupConverter());
registry.addFormatter(new ActivityCategoryFormatter());
registry.addFormatter(new ActivityRegionFormatter());
}

現在,它可以正常工作了!

唯一剩下的問題是我們有一些代碼重復,因為兩個Formatter類幾乎相同,它們只是在傳入的通用類中有所不同。我試圖通過使用由兩個實現的通用接口LookupEntity來解決此問題。查找實體類(ActivityCategory和RegionCategory),並使用此公共接口定義格式化程序,但不幸的是,這沒有用...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM