2016-07-25 11 views
2

Ich möchte ein Project Objekt im Frühjahr generieren oder binden, indem Sie ein HTML-Formular verwenden, das von Thymeleaf verarbeitet wird. Alles funktioniert so weit, nur das rolesNeeded Listenfeld, das mit Rollen gefüllt werden soll, indem man die Kontrollkästchen ankreuzt, funktioniert noch nicht.Spring Thymeleaf wie man Werte von Checkboxen an ein Sammlungsfeld bindet

Das Projekt Klasse

package com.floriantoenjes.instateam.model; 

import javax.persistence.*; 
import java.util.List; 

@Entity 
public class Project { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id; 
    private String name; 
    private String description; 
    private String status; 

    @ManyToMany 
    private List<Role> rolesNeeded; 

    @ManyToMany 
    private List<Collaborator> collaborators; 

    public Project() { 
    } 

    public int getId() { 
     return id; 
    } 

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

    public String getName() { 
     return name; 
    } 

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

    public String getDescription() { 
     return description; 
    } 

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

    public String getStatus() { 
     return status; 
    } 

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

    public List<Role> getRolesNeeded() { 
     return rolesNeeded; 
    } 

    public void setRolesNeeded(List<Role> rolesNeeded) { 
     this.rolesNeeded = rolesNeeded; 
    } 

    public List<Collaborator> getCollaborators() { 
     return collaborators; 
    } 

    public void setCollaborators(List<Collaborator> collaborators) { 
     this.collaborators = collaborators; 
    } 
} 

Die Rolle Klasse

package com.floriantoenjes.instateam.model; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 

@Entity 
public class Role { 

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

    public Role() { 
    } 

    public Integer getId() { 
     return id; 
    } 

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

    public String getName() { 
     return name; 
    } 

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

Der Regler

package com.floriantoenjes.instateam.web.controller; 

import com.floriantoenjes.instateam.model.Project; 
import com.floriantoenjes.instateam.model.Role; 
import com.floriantoenjes.instateam.service.ProjectService; 
import com.floriantoenjes.instateam.service.RoleService; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 

import java.util.List; 

@Controller 
public class ProjectController { 
    @Autowired 
    ProjectService projectService; 

    @Autowired 
    RoleService roleService; 

    @RequestMapping("/add") 
    public String newProjectForm(Model model) { 
     List<Role> roles = roleService.findAll(); 

     model.addAttribute("project", new Project()); 
     model.addAttribute("roles", roles); 

     return "edit_project"; 
    } 

    @RequestMapping(value = "/add", method = RequestMethod.POST) 
    public String addProject(Project project) { 
     projectService.save(project); 
     return "redirect:/index"; 
    } 

} 

Die Vorlage

<!DOCTYPE html> 
<html> 
    <head th:replace="layout :: head('Edit Project')"></head> 
    <body> 
     <header> 
      <div class="container"> 
       <div class="site-header"> 
        <a class="logo" href="index.html">InstaTeam</a> 
        <a class="new-project button icon-left" href="#"><i class="material-icons">add</i> New Project</a> 
       </div> 
      </div> 
     </header> 
     <nav> 
      <ul> 
       <li class="selected"><a href="index.html">Projects</a></li> 
       <li><a href="collaborators.html">Collaborators</a></li> 
       <li><a href="roles.html">Roles</a></li> 
      </ul> 
     </nav> 
     <section> 
      <div class="container wrapper"> 
       <form th:object="${project}" action="" method="post"> 
        <div> 
         <label for="project_name"> Project Name:</label> 
         <input type="text" th:field="*{name}" name="project_name"/> 
        </div> 
        <div> 
         <label for="project_description">Project Description:</label> 
         <textarea rows="4" th:field="*{description}" name="project_description"></textarea> 
        </div> 
        <div> 
         <label for="project_status">Project Status:</label> 
         <div class="custom-select"> 
         <span class="dropdown-arrow"></span> 
          <select th:field="*{status}" name="project_status"> 
           <option value="active">Active</option> 
           <option value="archived">Archived</option> 
           <option value="not_started">Not Started</option> 
          </select> 
         </div> 
        </div> 
        <div> 
         <label for="project_roles">Project Roles:</label> 
         <ul class="checkbox-list"> 
          <li th:each="role : ${roles}"> 
           <input type="checkbox" th:field="*{rolesNeeded}" name="project_roles" th:value="${role.id}"/> 
           <span class="primary" th:text="${role.name}"></span> 
          </li> 
         </ul> 
        </div> 
        <div class="actions"> 
         <input type="submit" value="Save" class="button"/> 
         <a href="#" class="button button-secondary">Cancel</a> 
        </div> 
       </form> 
      </div> 
     </section> 
    </body> 
</html> 

Wie Sie sehen können ist rolesNeeded eine Sammlung und ich möchte in der Lage sein, Kontrollkästchen für Rollen anzukreuzen und dann beim Übermitteln des Formulars ein Projektobjekt mit den Rollen zu generieren, die der "rolesNeeded" Sammlung zugewiesen sind. Wie ich es jetzt mit *{rolesNeeded} und {role.id} richtig ausgedrückt habe funktioniert es nicht.

Im Moment habe ich gerade bin immer folgende Fehlermeldung:

There was an unexpected error (type=Bad Request, status=400). Validation failed for object='project'. Error count: 1

Hoffentlich jemand einen Vorschlag hat, wie dieses oder vielleicht zu lösen, wie ich in der Lage bin eine detailliertere Fehlermeldung zu erhalten.

Mit freundlichen Grüßen, Florian

+0

In Bezug auf den Fehler: Der hilfreichste Ansatz ist wahrscheinlich, die Registerkarte Netzwerk in Ihrem Browser-Debugger zu öffnen und die gesendeten Anforderungsdaten zu überprüfen. – chrylis

+0

Nur eine Frage bezüglich "$ {role.id}" /> und $ {role.name} ">. Könnten Sie Ihre Klasse der Role Bean (pojo) zeigen? –

+0

chrylis danke für den schnellen Kommentar. Ich habe das getan und ich kann Beachten Sie, dass die Postanforderung die Rollen-IDs der ausgewählten Rollen enthält Hey Georges Ich habe die Rollenklasse zu meiner Frage hinzugefügt: – Florian

Antwort

1

Ich hatte meinen eigenen Frühling Converter schreibe von „String“ zu „Rolle“ zu konvertieren, diese Klasse als @Component markieren und einen @Bean erstellen. Dann funktionierte es wie Charme.

@Component 
public class StringRoleConverter implements Converter<String, Role> { 

    @Override 
    public Role convert(String source) { 
     Role role = new Role(); 
     int id = Integer.parseInt(source); 
     role.setId(id); 
     return role; 
    } 

    @Bean 
    public ConversionService getConversionService() { 
     ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean(); 
     Set<Converter> converters = new HashSet<>(); 
     converters.add(new StringRoleConverter()); 
     bean.setConverters(converters); 
     return bean.getObject(); 
    } 
} 
0

In meinem Fall habe ich zwei Konverter erstellt:

@Component 
public class RoleStringConverter implements Converter<Role, String> { 

    @Override 
    public String convert(Role role) { 
     return role.getId().toString(); 
    } 

} 

@Component 
public class StringRoleConverter implements Converter<String, Role> { 

    @Autowired 
    private RolesRepository rolesRepository; 

    @Override 
    public Role convert(String source) { 
     return rolesRepository.findOne(Long.parseLong(source)); 
    } 

} 

Ich habe sie in meiner Web-Konfiguration hinzugefügt, um die addFormatters Methode überschrieben werden. Keine Notwendigkeit, etwas anderes zu tun.

@Configuration 
@ComponentScan(value = { "controllers", "services", "converters" }) 
@Import(value = { ThymeleafConfig.class, i18nConfig.class }) 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter{ 

    @Autowired 
    private LocaleChangeInterceptor localeChangeInterceptor; 
    @Autowired 
    private StringRoleConverter stringRoleConverter; 
    @Autowired 
    private RoleStringConverter roleStringConverter; 

    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
     registry.addViewController("/403").setViewName("403"); 
     registry.addViewController("/about").setViewName("frontend/about"); 
     registry.addViewController("/admin").setViewName("admin/index"); 
     registry.addViewController("/admin/login").setViewName("admin/login"); 
    } 

    @Override 
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
     // habilitar procesamiento de contenido estático 
     configurer.enable(); 
    } 

    @Override 
    public void addInterceptors(InterceptorRegistry registry) { 
     registry.addInterceptor(localeChangeInterceptor); 
     registry.addInterceptor(new CacheControlHandlerInterceptor()); 
    } 

    @Bean(name="multipartResolver") 
    public MultipartResolver provideMultipartResolver(){ 
     return new StandardServletMultipartResolver(); 
    } 

    @Override 
    public void addFormatters(FormatterRegistry registry) { 
     registry.addConverter(Role.class, String.class, roleStringConverter); 
     registry.addConverter(String.class, Role.class, stringRoleConverter); 
    } 
} 

Ich hoffe, das hilft jemandem :).