我一直在摔跤如何實現一個窗體,在我使用Spring 3和Hibernate 4構建的Web應用程序中創建多對多關係。我是試圖用標記系統構建一個簡單的博客工具。我創建了一個型號爲BlogPost
,與型號Tags
具有多對多關係。當我創建一個新的BlogPost
對象時,標記的Web表單輸入是單行文本輸入。我希望能夠通過空白分割這個文本字符串,並使用它來創建Tag
對象。或者,在編輯現有的BlogPost
時,我希望能夠將Set
的Tag
對象與BlogPost
關聯,並將其轉換爲用作輸入元素值的String
。我的問題是在使用我的表單在文本輸入和參考的Tag
對象之間進行轉換。Spring + Hibernate:多對多的關係和web表單
綁定/獲取/更新與Web表單的多對多關係的最佳做法是什麼?有沒有簡單的方法來做到這一點,我不知道?
UPDATE
我決定,如在下面的回答表明,手動處理的形式和String
標籤值的對象模型所需的Set<Tag>
對象之間的對象的轉換。這裏是最後的工作代碼:
editBlogPost.jsp
...
<div class="form-group">
<label class="control-label col-lg-2" for="tagInput">Tags</label>
<div class="col-lg-7">
<input id="tagInput" name="tagString" type="text" class="form-control" maxlength="100" value="${tagString}" />
</div>
<form:errors path="tags" cssClass="help-inline spring-form-error" element="span" />
</div>
....
BlogController.java
@Controller
@SessionAttributes("blogPost")
public class BlogController {
@Autowired
private BlogService blogService;
@Autowired
private TagService tagService;
@ModelAttribute("blogPost")
public BlogPost getBlogPost(){
return new BlogPost();
}
//List Blog Posts
@RequestMapping(value="/admin/blog", method=RequestMethod.GET)
public String blogAdmin(ModelMap map, SessionStatus status){
status.setComplete();
List<BlogPost> postList = blogService.getAllBlogPosts();
map.addAttribute("postList", postList);
return "admin/blogPostList";
}
//Add new blog post
@RequestMapping(value="/admin/blog/new", method=RequestMethod.GET)
public String newPost(ModelMap map){
BlogPost blogPost = new BlogPost();
map.addAttribute("blogPost", blogPost);
return "admin/editBlogPost";
}
//Save new post
@RequestMapping(value="/admin/blog/new", method=RequestMethod.POST)
public String addPost(@Valid @ModelAttribute BlogPost blogPost,
BindingResult result,
@RequestParam("tagString") String tagString,
Model model,
SessionStatus status)
{
if (result.hasErrors()){
return "admin/editBlogPost";
}
else {
Set<Tag> tagSet = new HashSet();
for (String tag: tagString.split(" ")){
if (tag.equals("") || tag == null){
//pass
}
else {
//Check to see if the tag exists
Tag tagObj = tagService.getTagByName(tag);
//If not, add it
if (tagObj == null){
tagObj = new Tag();
tagObj.setTagName(tag);
tagService.saveTag(tagObj);
}
tagSet.add(tagObj);
}
}
blogPost.setPostDate(Calendar.getInstance());
blogPost.setTags(tagSet);
blogService.saveBlogPost(blogPost);
status.setComplete();
return "redirect:/admin/blog";
}
}
//Edit existing blog post
@Transactional
@RequestMapping(value="/admin/blog/{id}", method=RequestMethod.GET)
public String editPost(ModelMap map, @PathVariable("id") Integer postId){
BlogPost blogPost = blogService.getBlogPostById(postId);
map.addAttribute("blogPost", blogPost);
Hibernate.initialize(blogPost.getTags());
Set<Tag> tags = blogPost.getTags();
String tagString = "";
for (Tag tag: tags){
tagString = tagString + " " + tag.getTagName();
}
tagString = tagString.trim();
map.addAttribute("tagString", tagString);
return "admin/editBlogPost";
}
//Update post
@RequestMapping(value="/admin/blog/{id}", method=RequestMethod.POST)
public String savePostChanges(@Valid @ModelAttribute BlogPost blogPost, BindingResult result, @RequestParam("tagString") String tagString, Model model, SessionStatus status){
if (result.hasErrors()){
return "admin/editBlogPost";
}
else {
Set<Tag> tagSet = new HashSet();
for (String tag: tagString.split(" ")){
if (tag.equals("") || tag == null){
//pass
}
else {
//Check to see if the tag exists
Tag tagObj = tagService.getTagByName(tag);
//If not, add it
if (tagObj == null){
tagObj = new Tag();
tagObj.setTagName(tag);
tagService.saveTag(tagObj);
}
tagSet.add(tagObj);
}
}
blogPost.setTags(tagSet);
blogPost.setPostDate(Calendar.getInstance());
blogService.updateBlogPost(blogPost);
status.setComplete();
return "redirect:/admin/blog";
}
}
//Delete blog post
@RequestMapping(value="/admin/delete/blog/{id}", method=RequestMethod.POST)
public @ResponseBody String deleteBlogPost(@PathVariable("id") Integer id, SessionStatus status){
blogService.deleteBlogPost(id);
status.setComplete();
return "The item was deleted succesfully";
}
@RequestMapping(value="/admin/blog/cancel", method=RequestMethod.GET)
public String cancelBlogEdit(SessionStatus status){
status.setComplete();
return "redirect:/admin/blog";
}
}
BlogPost.java
@Entity
@Table(name="BLOG_POST")
public class BlogPost implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="POST_ID")
private Integer postId;
@NotNull
@NotEmpty
@Size(min=1, max=200)
@Column(name="TITLE")
private String title;
...
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@JoinTable(name="BLOG_POST_TAGS",
joinColumns={@JoinColumn(name="POST_ID")},
inverseJoinColumns={@JoinColumn(name="TAG_ID")})
private Set<Tag> tags = new HashSet<Tag>();
...
public Set<Tag> getTags() {
return tags;
}
public void setTags(Set<Tag> tags) {
this.tags = tags;
}
}
Tag.java
@Entity
@Table(name="TAG")
public class Tag implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="TAG_ID")
private Integer tagId;
@NotNull
@NotEmpty
@Size(min=1, max=20)
@Column(name="TAG_NAME")
private String tagName;
@ManyToMany(fetch = FetchType.LAZY, mappedBy="tags")
private Set<BlogPost> blogPosts = new HashSet<BlogPost>();
public Integer getTagId() {
return tagId;
}
public void setTagId(Integer tagId) {
this.tagId = tagId;
}
public String getTagName() {
return tagName;
}
public void setTagName(String tag) {
this.tagName = tag;
}
public Set<BlogPost> getBlogPosts() {
return blogPosts;
}
public void setBlogPosts(Set<BlogPost> blogPosts) {
this.blogPosts = blogPosts;
}
}
首先,改變你的方法'addPost',讓參數列表中的'BlogPost'參數後面有'BindingResult'參數。 –
@SotiriosDelimanolis:這個訂單爲什麼會有所作爲? – woemler
這是一個春季大會。想象一下你有多個命令對象和它們相應的'BindingResult'。 –