2017-04-13 79 views
1

我試圖創建一個html「編輯/新建」頁面來編輯或添加新的發佈者。其中一個細節將是subPublishers的ArrayList。儘管如果發佈者沒有subPublishers,或者如果我添加新的發佈者,ArrayList可能是空的。Thymeleaf:空列表不顯示輸入字段

我的問題是與輸入字段。我試圖顯示的ArrayList如下...

<form id="publisherForm" th:object="${publisherForm}" th:action="@{/publishers/publishers-edit/}" method="post" class="form-horizontal"> 
    <input type="hidden" th:field="*{id}" /> 
    <div class="row"> 
     <div class="col-sm-6 b-r"> 
      <div class="form-group"> 
       <label class="col-sm-3 control-label">Publisher name: </label> 
       <div class="col-sm-9"> 
        <input th:field="*{publisherName}" type="text" class="form-control" th:maxlength="45"/> 
       </div> 
      </div> 
      <div class="form-group"> 
       <label class="col-sm-3 control-label">Description: </label> 
       <div class="col-sm-9"> 
        <input th:field="*{description}" type="text" class="form-control" th:maxlength="200"/> 
       </div> 
      </div> 
      <div class="form-group"> 
       <label class="col-sm-3 control-label">Enabled: </label> 
       <div class="col-sm-9"> 
        <input th:field="*{status}" value="ENABLED" type="checkbox"/> 
       </div> 
      </div> 
      <div class="form-group"> 
       <label class="col-sm-3 control-label">Website URL: </label> 
       <div class="col-sm-9"> 
        <input th:field="*{websiteURL}" type="text" class="form-control" th:maxlength="50"/> 
       </div> 
      </div> 
      <div class="form-group"> 
       <label class="col-sm-3 control-label">Subpublishers: </label> 
       <div class="col-sm-9">                
        <div class="table-responsive"> 
         <table class="table table-bordered table-striped"> 
          <thead> 
           <th> 
            <button class="btn btn-white" type="submit" name="addRow">+</button> 
           </th> 
          </thead> 
          <tbody> 
           <tr th:each="subPublisher,stat : *{subPublishers}"> 
            <td> 
             <input type="text" class="form-control" th:field="*{subPublishers[__${stat.index}__].name}" /> 
            </td> 
            <td> 

             <button class="btn btn-white" type="submit" name="removeRow" th:value="${stat.index}">-</button> 
            </td> 
           </tr> 
          </tbody> 
         </table> 
        </div> 
       </div> 
      </div> 
     </div>          
    </div> 
    <div class="row"> 
     <div class="col-sm-6"> 
      <div class="form-group"> 
       <div class="col-sm-9 col-sm-offset-3"> 
        <button class="btn btn-primary" type="submit">Save</button>             
        <a class="btn btn-white" th:href="@{/publishers}">Cancel</a>             
       </div> 
      </div> 
     </div> 
    </div> 
</form> 

控制器

@MenuController(value = "/publisher", item = Item.Publishers) 
public class PublisherController { 

    private PublisherService publisherService; 
    private PublisherConverter publisherConverter; 
    private SubPublisherConverter subPublisherConverter; 

    public PublisherController(PublisherService publisherService, PublisherConverter publisherConverter, SubPublisherConverter subPublisherConverter) { 
     this.publisherService = publisherService; 
     this.publisherConverter = publisherConverter; 
     this.subPublisherConverter = subPublisherConverter; 
    } 

    @GetMapping 
    public String newPublisher(Model model) { 

     PublisherResource publisher = new PublisherResource(); 
     publisher.setStatus(true); 
     publisher.setSubPublishers(new ArrayList<SubPublisherResource>()); 

     return showPage(publisher, model); 
    } 

    protected String showPage(PublisherResource publisher, Model model) { 

     model.addAttribute("publisherForm", publisher); 

     return "publishers/publishers-edit"; 
    } 

    @PostMapping 
    public String createPublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if (result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(0, resource); 
    } 

    @GetMapping("/{publisherId}") 
    public String editPublisher(@PathVariable int publisherId, Model model) { 

     Publisher publisher = publisherService.getPublisher(publisherId); 
     PublisherResource res = publisherConverter.convert(publisher); 
     res.setSubPublishers(publisherService.getSubPublishers(publisher).stream() 
       .map(s -> subPublisherConverter.convert(s)) 
       .collect(Collectors.toList()) 
       ); 

     return showPage(res, model); 
    } 


    @PostMapping("/{publisherId}") 
    public String updatePublisher(@PathVariable int publisherId, @ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if (result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(publisherId, resource); 
    } 

    protected String savePublisher(int publisherId, PublisherResource resource) { 
     Publisher publisher = populatePublisher(publisherId, resource); 
     List<SubPublisher> subPublishers = populateSubPublishers(resource); 

     if (publisherId == 0) { 
      publisherService.createPublisher(publisher, subPublishers); 
     } else { 
      publisherService.updatePublisher(publisher, subPublishers); 
     } 

     return "redirect:/publishers"; 
    } 

    protected Publisher populatePublisher(int publisherId, PublisherResource resource) { 
     Publisher publisher = null; 
     if (publisherId == 0) { 
      publisher = new Publisher(); 
      publisher.setTimeAdded(new Date()); 
     } else { 
      publisher = publisherService.getPublisher(publisherId); 
     } 

     publisher.setPublisherName(resource.getPublisherName()); 
     publisher.setDescription(resource.getDescription()); 
     publisher.setStatus(resource.isStatus()); 
     publisher.setWebsiteURL(resource.getWebsiteURL()); 

     return publisher; 
    } 

    protected List<SubPublisher> populateSubPublishers(PublisherResource resource){ 
     if(resource.getSubPublishers() != null){ 
      return resource.getSubPublishers().stream() 
        .map(s -> { 
         SubPublisher subPublisher = new SubPublisher(); 
         subPublisher.setName(s.getName()); 
         return subPublisher; 
        }) 
        .collect(Collectors.toList()); 
     } 
     return Collections.emptyList(); 
    } 

    @PostMapping(params={"addRow"}) 
    public String addRow(final PublisherResource publisher, final BindingResult bindingResult, Model model) { 
     publisher.getSubPublishers().add(new SubPublisherResource()); 
     return showPage(publisher, model); 
    } 

    @PostMapping(params={"removeRow"}) 
    public String removeRow(final PublisherResource publisher, final BindingResult bindingResult, 
      final HttpServletRequest req, Model model) { 
     final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); 
     publisher.getSubPublishers().remove(rowId.intValue()); 
     return showPage(publisher, model); 
    } 
} 

PublisherResource

public class PublisherResource { 

    private int id; 
    private String publisherName; 
    private String description; 
    private boolean status; 
    private String websiteURL; 
    private List<SubPublisherResource> subPublishers = new ArrayList<>(); 

    public int getId() { 
     return id; 
    } 
    public void setId(int id) { 
     this.id = id; 
    } 
    public String getPublisherName() { 
     return publisherName; 
    } 
    public void setPublisherName(String publisherName) { 
     this.publisherName = publisherName; 
    } 
    public String getDescription() { 
     return description; 
    } 
    public void setDescription(String description) { 
     this.description = description; 
    } 
    public boolean isStatus() { 
     return status; 
    } 
    public void setStatus(boolean status) { 
     this.status = status; 
    } 
    public String getWebsiteURL() { 
     return websiteURL; 
    } 
    public void setWebsiteURL(String websiteURL) { 
     this.websiteURL = websiteURL; 
    } 
    public List<SubPublisherResource> getSubPublishers() { 
     return subPublishers; 
    } 
    public void setSubPublishers(List<SubPublisherResource> subPublishers) { 
     this.subPublishers = subPublishers; 
    } 
} 

我用exampel從thymeleaf文檔http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dynamic-fields

問題是,當ArrayList爲空時,輸入字段不會顯示在頁面上!此外,當編輯發佈商擁有子發佈商時,如果我將其全部刪除,則會丟失輸入字段,並且我無法添加任何其他子發佈商。這幾乎無法添加子發佈者。

這是如何處理與Thymeleaf?

更新控制器

@MenuController(value = "/publisher", item = Item.Publishers) 
public class PublisherController { 

    private PublisherResource publisherResource; 
    private PublisherService publisherService; 
    private PublisherConverter publisherConverter; 
    private SubPublisherConverter subPublisherConverter; 


    public PublisherController(PublisherResource publisherResource, PublisherService publisherService, 
      PublisherConverter publisherConverter, SubPublisherConverter subPublisherConverter) { 
     this.publisherResource = publisherResource; 
     this.publisherService = publisherService; 
     this.publisherConverter = publisherConverter; 
     this.subPublisherConverter = subPublisherConverter; 
    } 

    @GetMapping 
    public String newPublisher(Model model) { 

     PublisherResource publisher = new PublisherResource(); 
     publisher.setStatus(true); 
     publisher.setSubPublishers(new ArrayList<SubPublisherResource>()); 

     return showPage(publisher, model); 
    } 

    protected String showPage(PublisherResource publisher, Model model) { 

     model.addAttribute("publisherForm", publisher); 

     return "publishers/publishers-edit"; 
    } 

    @PostMapping 
    public String createPublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if (result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(0, resource); 
    } 

    @GetMapping 
    public String editPublisher(Model model) { 

     Publisher publisher = publisherService.getPublisher(publisherResource.getId()); 
     PublisherResource res = publisherConverter.convert(publisher); 
     res.setSubPublishers(publisherService.getSubPublishers(publisher).stream() 
       .map(s -> subPublisherConverter.convert(s)) 
       .collect(Collectors.toList()) 
       ); 

     return showPage(res, model); 
    } 


    @PostMapping 
    public String updatePublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if (result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(publisherResource.getId(), resource); 
    } 

    protected String savePublisher(int publisherId, PublisherResource resource) { 
     Publisher publisher = populatePublisher(publisherId, resource); 
     List<SubPublisher> subPublishers = populateSubPublishers(resource); 

     if (publisherId == 0) { 
      publisherService.createPublisher(publisher, subPublishers); 
     } else { 
      publisherService.updatePublisher(publisher, subPublishers); 
     } 

     return "redirect:/publishers"; 
    } 

    protected Publisher populatePublisher(int publisherId, PublisherResource resource) { 
     Publisher publisher = null; 
     if (publisherId == 0) { 
      publisher = new Publisher(); 
      publisher.setTimeAdded(new Date()); 
     } else { 
      publisher = publisherService.getPublisher(publisherId); 
     } 

     publisher.setPublisherName(resource.getPublisherName()); 
     publisher.setDescription(resource.getDescription()); 
     publisher.setStatus(resource.isStatus()); 
     publisher.setWebsiteURL(resource.getWebsiteURL()); 

     return publisher; 
    } 

    protected List<SubPublisher> populateSubPublishers(PublisherResource resource){ 
     if(resource.getSubPublishers() != null){ 
      return resource.getSubPublishers().stream() 
        .map(s -> { 
         SubPublisher subPublisher = new SubPublisher(); 
         subPublisher.setName(s.getName()); 
         return subPublisher; 
        }) 
        .collect(Collectors.toList()); 
     } 
     return Collections.emptyList(); 
    } 

    @PostMapping(params={"addRow"}) 
    public String addRow(final PublisherResource publisher, final BindingResult bindingResult, Model model) { 
     publisher.getSubPublishers().add(new SubPublisherResource()); 
     return showPage(publisher, model); 
    } 

    @PostMapping(params={"removeRow"}) 
    public String removeRow(final PublisherResource publisher, final BindingResult bindingResult, 
      final HttpServletRequest req, Model model) { 
     final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); 
     publisher.getSubPublishers().remove(rowId.intValue()); 
     return showPage(publisher, model); 
    } 
} 

更新2 - 所有代碼:

實體出版商和SubPublisher:

@Entity 
@Table(name = "publisher") 
public class Publisher { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id") 
    private int id; 

    @Column(name = "name") 
    private String publisherName; 

    @Column(name = "description") 
    private String description; 

    @Column(name = "status") 
    private boolean status; 

    @Column(name = "website_url") 
    private String websiteURL; 

    @Column(name = "time_added") 
    private Date timeAdded; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getPublisherName() { 
     return publisherName; 
    } 

    public void setPublisherName(String publisherName) { 
     this.publisherName = publisherName; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public boolean isStatus() { 
     return status; 
    } 

    public void setStatus(boolean status) { 
     this.status = status; 
    } 

    public String getWebsiteURL() { 
     return websiteURL; 
    } 

    public void setWebsiteURL(String websiteURL) { 
     this.websiteURL = websiteURL; 
    } 

    public Date getTimeAdded() { 
     return timeAdded; 
    } 

    public void setTimeAdded(Date timeAdded) { 
     this.timeAdded = timeAdded; 
    } 
} 

@Entity 
@Table(name = "sub_publisher") 
public class SubPublisher { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id") 
    private int id; 

    @OneToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "publisher_id") 
    private Publisher publisher; 

    @Column(name = "name") 
    private String name; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public Publisher getPublisher() { 
     return publisher; 
    } 

    public void setPublisher(Publisher publisher) { 
     this.publisher = publisher; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

public interface PublisherRepository extends JpaDataTableRepository<Publisher, Integer> { 

    public Publisher findById(int id); 
} 

public interface SubPublisherRepository extends JpaRepository<SubPublisher, Integer> { 

    List<SubPublisher> findByPublisher(Publisher publisher); 
    void deleteByPublisher(Publisher publisher); 
} 

PublisherResource

public class PublisherResource { 

    private int id; 
    private String publisherName; 
    private String description; 
    private boolean status; 
    private String websiteURL; 
    private List<SubPublisherResource> subPublishers = new ArrayList<>(); 

    public int getId() { 
     return id; 
    } 
    public void setId(int id) { 
     this.id = id; 
    } 
    public String getPublisherName() { 
     return publisherName; 
    } 
    public void setPublisherName(String publisherName) { 
     this.publisherName = publisherName; 
    } 
    public String getDescription() { 
     return description; 
    } 
    public void setDescription(String description) { 
     this.description = description; 
    } 
    public boolean isStatus() { 
     return status; 
    } 
    public void setStatus(boolean status) { 
     this.status = status; 
    } 
    public String getWebsiteURL() { 
     return websiteURL; 
    } 
    public void setWebsiteURL(String websiteURL) { 
     this.websiteURL = websiteURL; 
    } 
    public List<SubPublisherResource> getSubPublishers() { 
     return subPublishers; 
    } 
    public void setSubPublishers(List<SubPublisherResource> subPublishers) { 
     this.subPublishers = subPublishers; 
    } 
} 

SubPublisherResource

public class SubPublisherResource { 

    private String name; 

    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 
} 

PublisherController

@Controller 
@RequestMapping("/publisher") 
public class PublisherController { 

    private PublisherService publisherService; 
    private PublisherConverter publisherConverter; 
    private SubPublisherConverter subPublisherConverter; 

    @Autowired 
    public PublisherController(PublisherService publisherService, PublisherConverter publisherConverter, SubPublisherConverter subPublisherConverter) { 
     this.publisherService = publisherService; 
     this.publisherConverter = publisherConverter; 
     this.subPublisherConverter = subPublisherConverter; 
    } 

    @GetMapping 
    public String newPublisher(Model model) { 
     PublisherResource publisher = new PublisherResource(); 
     publisher.setStatus(true); 
     return showPage(publisher, model); 
    } 

    protected String showPage(PublisherResource publisher, Model model) { 
     model.addAttribute("publisherForm", publisher); 
     return "/publishers/publishers-edit"; 
    } 

    @PostMapping 
    public String createPublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if(result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(resource); 
    } 

    @GetMapping("/{id}") 
    public String editPublisher(@PathVariable("id") Integer id, Model model) { 
     Publisher publisher = publisherService.getPublisher(id); 
     PublisherResource res = publisherConverter.convert(publisher); 
     res.setSubPublishers(publisherService.getSubPublishers(publisher).stream().map(s->subPublisherConverter.convert(s)).collect(Collectors.toList())); 
     return showPage(res, model); 
    } 

    protected String savePublisher(PublisherResource resource) { 
     Publisher publisher = populatePublisher(resource); 
     List<SubPublisher> subPublishers = populateSubPublishers(resource); 
     if(resource.getId() == 0) { 
      publisherService.createPublisher(publisher, subPublishers); 
     } else { 
      publisherService.updatePublisher(publisher, subPublishers); 
     } 
     return "redirect:/publishers"; 
    } 

    protected Publisher populatePublisher(PublisherResource resource) { 
     Publisher publisher; 
     if(resource.getId() == 0) { 
      publisher = new Publisher(); 
      publisher.setTimeAdded(new Date()); 
     } else { 
      publisher = publisherService.getPublisher(resource.getId()); 
     } 
     publisher.setPublisherName(resource.getPublisherName()); 
     publisher.setDescription(resource.getDescription()); 
     publisher.setStatus(resource.isStatus()); 
     publisher.setWebsiteURL(resource.getWebsiteURL()); 
     return publisher; 
    } 

    protected List<SubPublisher> populateSubPublishers(PublisherResource resource) { 
     if(resource.getSubPublishers() != null) { 
      return resource.getSubPublishers().stream().map(s->{ 
       SubPublisher subPublisher = new SubPublisher(); 
       subPublisher.setName(s.getName()); 
       return subPublisher; 
      }).collect(Collectors.toList()); 
     } 
     return Collections.emptyList(); 
    } 

    @PostMapping(params = { "addRow" }) 
    public String addRow(final PublisherResource publisher, Model model) { 
     publisher.getSubPublishers().add(new SubPublisher()); 
     return showPage(publisher, model); 
    } 

    @PostMapping(params = { "removeRow" }) 
    public String removeRow(final PublisherResource publisher, final HttpServletRequest req, Model model) { 
     final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); 
     publisher.getSubPublishers().remove(rowId.intValue()); 
     return showPage(publisher, model); 
    } 
} 

PublishersController

@MenuController(value = "/publishers", item = Item.Publishers) 
public class PublishersController { 

    private PublisherService publisherService; 
    private PublisherConverter publisherConverter; 

    public PublishersController(PublisherService publisherService, PublisherConverter publisherConverter) { 
     this.publisherService = publisherService; 
     this.publisherConverter = publisherConverter; 
    } 

    @GetMapping 
    public String showPage() { 
     return "publishers/publishers"; 
    } 

    @PostMapping("/data") 
    public @ResponseBody DataTableResponse<PublisherResource> getPublishers(@RequestBody DataTableRequest request) { 
     return publisherConverter.convertResponse(publisherService.getPublishers(request)); 
    } 

    @DeleteMapping("/{publisherIds}") 
    @ResponseStatus(HttpStatus.NO_CONTENT) 
    public void deletePublishers(@PathVariable Integer[] publisherIds) { 
     for (Integer publisherId: publisherIds) { 
      publisherService.deletePublisher(publisherId); 
     } 
    } 

    @PutMapping("/{publisherIds}/disable") 
    @ResponseStatus(HttpStatus.ACCEPTED) 
    public void disablePublishers(@PathVariable Integer[] publisherIds) { 
     changeStatus(publisherIds); 
    } 

    @PutMapping("/{publisherIds}/enable") 
    @ResponseStatus(HttpStatus.ACCEPTED) 
    public void enablePublishers(@PathVariable Integer[] publisherIds) { 
     changeStatus(publisherIds); 
    } 

    protected void changeStatus(Integer[] publisherIds) { 
     for (Integer publisherId: publisherIds) { 
      publisherService.updateStatus(publisherId); 
     } 
    } 
} 

PublisherConverter

@Component 
public class PublisherConverter implements ResourceConverter<Publisher, PublisherResource> { 

    public PublisherResource convert(Publisher publisher) { 

     PublisherResource resource = new PublisherResource(); 

     resource.setId(publisher.getId()); 
     resource.setPublisherName(publisher.getPublisherName()); 
     resource.setDescription(publisher.getDescription()); 
     resource.setStatus(publisher.isStatus()); 
     resource.setWebsiteURL(publisher.getWebsiteURL()); 

     return resource; 
    } 
} 

PublisherService

@Service 
public class PublisherService { 

    private PublisherRepository publisherRepository; 
    private SubPublisherRepository subPublisherRepository; 


    public PublisherService(PublisherRepository publisherRepository, SubPublisherRepository subPublisherRepository) { 
     this.publisherRepository = publisherRepository; 
     this.subPublisherRepository = subPublisherRepository; 
    } 

    public DataTableResponse<Publisher> getPublishers(DataTableRequest request) { 

     return publisherRepository.findAll(request); 
    } 

    @Transactional 
    public Publisher getPublisher(int publisherId) { 
     Publisher publisher = publisherRepository.findById(publisherId);   

     if(publisher != null){ 
      List<SubPublisher> subPublishers = subPublisherRepository.findByPublisher(publisher); 
      //populateSubPublishers(subPublishers); 

      subPublishers.stream().forEach(s -> { 
       if(s.getId() == 0){ 
        s.setPublisher(publisher); 
        subPublisherRepository.save(s); 
       } 
      }); 
     } 

     if(publisher == null) { 
      throw new NotFoundException("Publisher " + publisherId + " not found."); 
     } 

     return publisher; 
    } 

    private void populateSubPublishers(List<SubPublisher> subPublishers) { 
     for(SubPublisher subPublisher : subPublishers){ 
      subPublishers.add(subPublisher); 
      System.out.println(subPublisher.getName()); 
     } 
    } 

    @Transactional 
    public Publisher createPublisher(Publisher publisher, List<SubPublisher> subPublishers) { 

     publisher = publisherRepository.save(publisher); 
     createSubPublisher(publisher, subPublishers);  

     return publisher; 
    } 

    private void createSubPublisher(Publisher publisher, List<SubPublisher> subPublishers) { 
     populateSubPublishers(subPublishers); 

     for(SubPublisher subPublisher : subPublishers){ 
      subPublisher.setPublisher(publisher); 
      subPublisher.setName(subPublisher.getName()); 
     } 
    } 

    @Transactional 
    public Publisher updatePublisher(Publisher publisher, List<SubPublisher> subPublishers) { 

     publisher = publisherRepository.save(publisher); 
     createSubPublishers(publisher, subPublishers); 
     return publisher; 
    } 

    private void createSubPublishers(Publisher publisher, List<SubPublisher> subPublishers) { 

     subPublisherRepository.deleteByPublisher(publisher); 

     for (SubPublisher sp : subPublishers) { 
      sp.setPublisher(publisher); 
      sp = subPublisherRepository.save(sp); 
     } 
    } 

    @Transactional 
    public void updateStatus(int publisherId) { 
     Publisher publisher = publisherRepository.findOne(publisherId); 
     if(publisher != null && publisher.isStatus() != false){ 
      publisher.setStatus(false); 
      publisherRepository.save(publisher); 
     } 
     else if(publisher != null && publisher.isStatus() != true){ 
      publisher.setStatus(true); 
      publisherRepository.save(publisher); 
     } 
    } 

    @Transactional 
    public void deletePublisher(int publisherId) { 
     Publisher publisher = publisherRepository.findOne(publisherId); 
     if (publisher != null) { 
      publisherRepository.delete(publisher); 
     } 
    } 

    public List<SubPublisher> getSubPublishers(Publisher publisher){ 
     return subPublisherRepository.findByPublisher(publisher); 
    } 
} 

SubPublisherConverter

@Component 
public class SubPublisherConverter implements ResourceConverter<SubPublisher, SubPublisherResource> { 

    @Override 
    public SubPublisherResource convert(SubPublisher subPublisher) { 

     SubPublisherResource resource = new SubPublisherResource(); 
     resource.setName(subPublisher.getName()); 

     return resource; 
    } 
} 

錯誤

java.util.ConcurrentModificationException: null 
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source) 
    at java.util.ArrayList$Itr.next(Unknown Source) 
    at publishers.PublisherService.populateSubPublishers(PublisherService.java:58) 
    at publishers.PublisherService.createSubPublisher(PublisherService.java:74) 
    at publishers.PublisherService.createPublisher(PublisherService.java:68) 
+0

如果數組列表是空的沒有輸入,將產生由於'個:each'不執行0次(意味着從不)。所以'th:each'循環中的所有內容都不會被包含在內。你只需要將''移出'th:each'。每個就像一個java foreach循環。如果你用foreach循環一個空集合,循環也不會被執行。 –

+0

@TommySchmidt Thx爲您的回覆,我試着移動出來的每一個,當我去添加新的發佈者它顯示我+按鈕,但當我點擊它,它反應像保存按鈕和保存表格,而不添加字段爲子公司 – alonso05

+0

從你張貼我不知道爲什麼。請在你的問題中加入你的'

'標籤。 –

回答

0

因此,這裏的例子。 Ofc您需要將控制器(/test/test)的映射替換爲/publishers/publishers-edit。控制器:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.validation.BindingResult; 
import org.springframework.validation.annotation.Validated; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.ModelAttribute; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.PostMapping; 
import org.springframework.web.bind.annotation.RequestMapping; 

import javax.servlet.http.HttpServletRequest; 
import java.util.Collections; 
import java.util.Date; 
import java.util.List; 
import java.util.stream.Collectors; 

@Controller 
@RequestMapping("/test/test") 
public class PublisherController { 
    private PublisherService publisherService; 
    private PublisherConverter publisherConverter; 
    private SubPublisherConverter subPublisherConverter; 

    @Autowired 
    public PublisherController(PublisherService publisherService, PublisherConverter publisherConverter, SubPublisherConverter subPublisherConverter) { 
     this.publisherService = publisherService; 
     this.publisherConverter = publisherConverter; 
     this.subPublisherConverter = subPublisherConverter; 
    } 

    @GetMapping 
    public String newPublisher(Model model) { 
     PublisherResource publisher = new PublisherResource(); 
     publisher.setStatus(true); 
     return showPage(publisher, model); 
    } 

    protected String showPage(PublisherResource publisher, Model model) { 
     model.addAttribute("publisherForm", publisher); 
     return "test/test"; 
    } 

    @PostMapping 
    public String createPublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result, Model model) { 
     if(result.hasErrors()) { 
      return showPage(resource, model); 
     } 
     return savePublisher(resource); 
    } 

    @GetMapping("/{id}") 
    public String editPublisher(@PathVariable("id") Integer id, Model model) { 
     Publisher publisher = publisherService.getPublisher(id); 
     PublisherResource res = publisherConverter.convert(publisher); 
     res.setSubPublishers(publisherService.getSubPublishers(publisher).stream().map(s->subPublisherConverter.convert(s)).collect(Collectors.toList())); 
     return showPage(res, model); 
    } 

    protected String savePublisher(PublisherResource resource) { 
     Publisher publisher = populatePublisher(resource); 
     List<SubPublisher> subPublishers = populateSubPublishers(resource); 
     if(resource.getId() == 0) { 
      publisherService.createPublisher(publisher, subPublishers); 
     } else { 
      publisherService.updatePublisher(publisher, subPublishers); 
     } 
     return "redirect:/publishers"; 
    } 

    protected Publisher populatePublisher(PublisherResource resource) { 
     Publisher publisher; 
     if(resource.getId() == 0) { 
      publisher = new Publisher(); 
      publisher.setTimeAdded(new Date()); 
     } else { 
      publisher = publisherService.getPublisher(resource.getId()); 
     } 
     publisher.setPublisherName(resource.getPublisherName()); 
     publisher.setDescription(resource.getDescription()); 
     publisher.setStatus(resource.isStatus()); 
     publisher.setWebsiteURL(resource.getWebsiteURL()); 
     return publisher; 
    } 

    protected List<SubPublisher> populateSubPublishers(PublisherResource resource) { 
     if(resource.getSubPublishers() != null) { 
      return resource.getSubPublishers().stream().map(s->{ 
       SubPublisher subPublisher = new SubPublisher(); 
       subPublisher.setName(s.getName()); 
       return subPublisher; 
      }).collect(Collectors.toList()); 
     } 
     return Collections.emptyList(); 
    } 

    @PostMapping(params = { "addRow" }) 
    public String addRow(@ModelAttribute("publisherForm") final PublisherResource publisher, Model model) { 
     publisher.getSubPublishers().add(new SubPublisher()); 
     return showPage(publisher, model); 
    } 

    @PostMapping(params = { "removeRow" }) 
    public String removeRow(@ModelAttribute("publisherForm") final PublisherResource publisher, final HttpServletRequest req, Model model) { 
     final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); 
     publisher.getSubPublishers().remove(rowId.intValue()); 
     return showPage(publisher, model); 
    } 
} 

更新

我清理你的PublisherService並分裂成PublisherService和SubPublisherService。這些服務是可能的。可選,但我更傾向於在大部分時間在存儲庫和我的程序之間另有一層。

我也清理了PublisherController。 savePublisher變了很多。這是記錄的。

發佈者現在還有一個包含發佈者的所有子發佈者的列表。上一頁。你是通過代碼獲取的。不過JPA可以爲您做到這一點。

PublisherController:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.validation.BindingResult; 
import org.springframework.validation.annotation.Validated; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.ModelAttribute; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.PostMapping; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.servlet.ModelAndView; 

import javax.servlet.http.HttpServletRequest; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 

@Controller 
@RequestMapping("/test/test") 
public class PublisherController { 
    private PublisherService publisherService; 
    private SubPublisherService subPublisherService; 

    @Autowired 
    public PublisherController(PublisherService publisherService, SubPublisherService subPublisherService) { 
     this.publisherService = publisherService; 
     this.subPublisherService = subPublisherService; 
    } 

    private ModelAndView showPage(PublisherResource publisher) { 
     final ModelAndView modelAndView = new ModelAndView("test/test"); 
     modelAndView.addObject("publisherForm", publisher); 
     return modelAndView; 
    } 

    @GetMapping 
    public ModelAndView createPublisher() { 
     PublisherResource publisher = new PublisherResource(); 
     publisher.setStatus(true); 
     return showPage(publisher); 
    } 

    @GetMapping("/{id}") 
    public ModelAndView editPublisher(@PathVariable("id") Integer id) { 
     Publisher publisher = publisherService.getPublisher(id); 
     return showPage(PublisherConverter.convert(publisher)); 
    } 

    @PostMapping 
    public ModelAndView savePublisher(@ModelAttribute("publisherForm") @Validated PublisherResource resource, BindingResult result) { 
     if(result.hasErrors()) { 
      return showPage(resource); 
     } 
     return savePublisher(resource); 
    } 

    private ModelAndView savePublisher(PublisherResource resource) { 
     // create the publisher 
     Publisher publisher; 
     if(resource.getId() == 0) { 
      publisher = new Publisher(); 
      publisher.setTimeAdded(new Date()); 
      publisher = publisherService.save(publisher); 
     } else { 
      publisher = publisherService.getPublisher(resource.getId()); 
     } 

     /* -- this will update the SubPublishers -- */ 
     final List<SubPublisher> toDelete = publisher.getSubPublishers(); 
     final List<SubPublisher> toSave = new ArrayList<>(); 
     final Publisher forLambda = publisher; 
     // first we will iterate over all the SubPublishers that where specified by the user (in the form) 
     resource.getSubPublishers().forEach(name->{ 
      // we will then try to find any existing SubPublisher for the given name and publisher (to avoid duplicated database entries) 
      final SubPublisher subPublisher = subPublisherService.getOrCreateSubPublisher(forLambda, name); 
      // we will also save the SubPublisher reference for later 
      toSave.add(subPublisher); 
      // and then we will remove the SubPublisher that we just found from the List of SubPublishers from the original Publisher (that was stored in the db) 
      toDelete.removeIf(s->subPublisher.getId() == s.getId()); 
     }); 
     // effectively it will leave us with a list (toDelete) that will include all SubPublishers that have to be deleted 
     for(SubPublisher subPublisher : toDelete) { 
      // and this is what we will to here 
      subPublisherService.delete(subPublisher); 
     } 
     // after we cleaned up all unused references 
     publisher.getSubPublishers().clear(); 
     // update the subPublisher list to contain all SubPublishers that where specified by the user input (the parsed ones) 
     publisher.getSubPublishers().addAll(toSave); 
     /* -- end -- */ 

     // update all remaining fields 
     publisher.setPublisherName(resource.getPublisherName()); 
     publisher.setDescription(resource.getDescription()); 
     publisher.setStatus(resource.isStatus()); 
     publisher.setWebsiteURL(resource.getWebsiteURL()); 
     publisherService.save(publisher); 
     return new ModelAndView("redirect:/test/list"); 
    } 

    @PostMapping(params = { "addRow" }) 
    public ModelAndView addRow(@ModelAttribute("publisherForm") final PublisherResource publisher) { 
     publisher.getSubPublishers().add(""); 
     return showPage(publisher); 
    } 

    @PostMapping(params = { "removeRow" }) 
    public ModelAndView removeRow(@ModelAttribute("publisherForm") final PublisherResource publisher, final HttpServletRequest req) { 
     final Integer rowId = Integer.valueOf(req.getParameter("removeRow")); 
     publisher.getSubPublishers().remove(rowId.intValue()); 
     return showPage(publisher); 
    } 
} 

出版商:

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.OneToMany; 
import javax.persistence.Table; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 

@Entity 
@Table 
public class Publisher { 
    private int id; 
    private String publisherName; 
    private String description; 
    private boolean status; 
    private String websiteURL; 
    private Date timeAdded; 
    private List<SubPublisher> subPublishers = new ArrayList<>(); 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column 
    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    @Column 
    public String getPublisherName() { 
     return publisherName; 
    } 

    public void setPublisherName(String publisherName) { 
     this.publisherName = publisherName; 
    } 

    @Column 
    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    @Column 
    public boolean isStatus() { 
     return status; 
    } 

    public void setStatus(boolean status) { 
     this.status = status; 
    } 

    @Column 
    public String getWebsiteURL() { 
     return websiteURL; 
    } 

    public void setWebsiteURL(String websiteURL) { 
     this.websiteURL = websiteURL; 
    } 

    @Column 
    public Date getTimeAdded() { 
     return timeAdded; 
    } 

    public void setTimeAdded(Date timeAdded) { 
     this.timeAdded = timeAdded; 
    } 


    @OneToMany(mappedBy = "publisher") 
    public List<SubPublisher> getSubPublishers() { 
     return subPublishers; 
    } 

    public void setSubPublishers(List<SubPublisher> subPublishers) { 
     this.subPublishers = subPublishers; 
    } 

    @Override 
    public String toString() { 
     return "Publisher{" + "id=" + id + ", publisherName='" + publisherName + '\'' + ", description='" + description + '\'' + ", status=" + status + ", websiteURL='" + websiteURL + '\'' + ", timeAdded=" + timeAdded + ", subPublishers=" + subPublishers + '}'; 
    } 
} 

PublisherResource:

import java.util.ArrayList; 
import java.util.List; 

public class PublisherResource { 
    private int id; 
    private String publisherName; 
    private String description; 
    private boolean status; 
    private String websiteURL; 
    private List<String> subPublishers = new ArrayList<>(); 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getPublisherName() { 
     return publisherName; 
    } 

    public void setPublisherName(String publisherName) { 
     this.publisherName = publisherName; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public boolean isStatus() { 
     return status; 
    } 

    public void setStatus(boolean status) { 
     this.status = status; 
    } 

    public String getWebsiteURL() { 
     return websiteURL; 
    } 

    public void setWebsiteURL(String websiteURL) { 
     this.websiteURL = websiteURL; 
    } 

    public List<String> getSubPublishers() { 
     return subPublishers; 
    } 

    public void setSubPublishers(List<String> subPublishers) { 
     this.subPublishers = subPublishers; 
    } 
} 

PublisherService:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 

@Service 
public class PublisherService { 
    private PublisherRepository publisherRepository; 

    @Autowired 
    public void setPublisherRepository(PublisherRepository publisherRepository) { 
     this.publisherRepository = publisherRepository; 
    } 

    public Publisher save(Publisher toSave) { 
     return publisherRepository.save(toSave); 
    } 

    public void delete(Publisher toDelete) { 
     publisherRepository.delete(toDelete); 
    } 

    public Publisher getPublisher(Integer id) { 
     return publisherRepository.findOne(id); 
    } 

    public Iterable<Publisher> getAll() { 
     return publisherRepository.findAll(); 
    } 
} 

PublisherRepository:

import org.springframework.data.repository.CrudRepository; 

public interface PublisherRepository extends CrudRepository<Publisher, Integer> {} 

PublisherConverter:

import java.util.stream.Collectors; 

public class PublisherConverter { 
    public static PublisherResource convert(Publisher publisher) { 
     PublisherResource resource = new PublisherResource(); 
     resource.setId(publisher.getId()); 
     resource.setPublisherName(publisher.getPublisherName()); 
     resource.setDescription(publisher.getDescription()); 
     resource.setStatus(publisher.isStatus()); 
     resource.setWebsiteURL(publisher.getWebsiteURL()); 
     resource.getSubPublishers().addAll(publisher.getSubPublishers().stream().map(SubPublisher::getName).collect(Collectors.toList())); 
     return resource; 
    } 
} 

SubPublisher:

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.OneToOne; 
import javax.persistence.Table; 

@Entity 
@Table 
public class SubPublisher { 
    private int id; 
    private Publisher publisher; 
    private String name; 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column 
    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    @OneToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "publisherId") 
    public Publisher getPublisher() { 
     return publisher; 
    } 

    public void setPublisher(Publisher publisher) { 
     this.publisher = publisher; 
    } 

    @Column 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

SubPublisherRepository:

import org.springframework.data.repository.CrudRepository; 

public interface SubPublisherRepository extends CrudRepository<SubPublisher, Integer> { 
    SubPublisher findByPublisherAndAndName(Publisher publisher, String name); 
} 

SubPublisher服務:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 

@Service 
public class SubPublisherService { 
    private SubPublisherRepository subPublisherRepository; 

    @Autowired 
    public void setSubPublisherRepository(SubPublisherRepository subPublisherRepository) { 
     this.subPublisherRepository = subPublisherRepository; 
    } 

    public SubPublisher save(SubPublisher toSave) { 
     return subPublisherRepository.save(toSave); 
    } 

    public void delete(SubPublisher toDelete) { 
     subPublisherRepository.delete(toDelete); 
    } 

    /** 
    * This method will either find any existing SubPublisher by the Name and the Publisher or create one if none existed. 
    */ 
    public SubPublisher getOrCreateSubPublisher(Publisher publisher, String name) { 
     SubPublisher subPublisher = subPublisherRepository.findByPublisherAndAndName(publisher, name); 
     if(subPublisher == null) { 
      subPublisher = new SubPublisher(); 
      subPublisher.setPublisher(publisher); 
      subPublisher.setName(name); 
      subPublisher = save(subPublisher); 
     } 
     return subPublisher; 
    } 

    public Iterable<SubPublisher> getAll() { 
     return subPublisherRepository.findAll(); 
    } 
} 

在HTML我改變<input type="text" class="form-control" th:field="*{subPublishers[__${stat.index}__].name}" /><input type="text" class="form-control" th:field="*{subPublishers[__${stat.index}__].}" />

+0

Thx例如。我試過這個,但我仍然得到這個錯誤Whitelabel錯誤頁面 - 此應用程序沒有明確的映射/錯誤,所以你看到這是一個後備。我已經嘗試了新版發佈商頁面上的+按鈕,編輯頁面上的+/-按鈕,但是我在每個頁面上都收到了此錯誤。我已將映射替換爲/ publishers/publishers-edit。我會把我的代碼的其餘部分,以便你可以看到一切正常,因爲它有點奇怪的代碼設計,但我需要與所有這些文件 – alonso05

+0

@ alonso05你可以顯示你到目前爲止你的問題有更新嗎? –

+0

我編輯了我的問題,並把所有代碼,我有 – alonso05