├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── thymeleafexamples │ └── select │ ├── config │ ├── SpringWebInitializer.java │ └── WebMvcConfig.java │ ├── dao │ ├── HobbyDao.java │ └── UserDao.java │ ├── domain │ ├── Hobby.java │ └── User.java │ └── web │ ├── HobbyFormatter.java │ └── IndexController.java └── webapp └── WEB-INF ├── templates ├── editCheckbox.html ├── editSelect.html └── index.html └── web.xml /README.md: -------------------------------------------------------------------------------- 1 | thymeleafexamples-selectmultiple 2 | ================================ 3 | 4 | Example application to illustrate one forum question (problem with select multiple). 5 | 6 | This example uses: 7 | * Spring 4 with Java config 8 | * Thymeleaf 2.1 9 | * Spring conversion service 10 | 11 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.thymeleafexamples 6 | select 7 | 1.0-SNAPSHOT 8 | war 9 | 10 | Thymeleaf select multiple example 11 | 12 | 13 | UTF-8 14 | UTF-8 15 | 2.1.2.RELEASE 16 | 4.0.2.RELEASE 17 | 1.7 18 | 1.7 19 | 20 | 21 | 22 | 23 | 24 | javax 25 | javaee-web-api 26 | 7.0 27 | provided 28 | 29 | 30 | 31 | org.springframework 32 | spring-context-support 33 | ${spring.version} 34 | 35 | 36 | org.springframework 37 | spring-webmvc 38 | ${spring.version} 39 | 40 | 41 | org.thymeleaf 42 | thymeleaf 43 | ${thymeleaf.version} 44 | 45 | 46 | org.thymeleaf 47 | thymeleaf-spring4 48 | ${thymeleaf.version} 49 | 50 | 51 | 52 | 53 | select 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/config/SpringWebInitializer.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.config; 2 | 3 | import javax.servlet.ServletContext; 4 | import javax.servlet.ServletException; 5 | import javax.servlet.ServletRegistration.Dynamic; 6 | import org.springframework.web.WebApplicationInitializer; 7 | import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; 8 | import org.springframework.web.servlet.DispatcherServlet; 9 | 10 | /** 11 | * Spring configuration and Spring MVC bootstrapping. 12 | */ 13 | public class SpringWebInitializer implements WebApplicationInitializer { 14 | 15 | @Override 16 | public void onStartup(ServletContext servletContext) throws ServletException { 17 | AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 18 | context.register(WebMvcConfig.class); 19 | context.setServletContext(servletContext); 20 | // Spring MVC front controller 21 | Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context)); 22 | servlet.addMapping("/"); 23 | servlet.setLoadOnStartup(1); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.config; 2 | 3 | import com.thymeleafexamples.select.web.HobbyFormatter; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.format.FormatterRegistry; 8 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 10 | import org.thymeleaf.spring4.SpringTemplateEngine; 11 | import org.thymeleaf.spring4.view.ThymeleafViewResolver; 12 | import org.thymeleaf.templateresolver.ServletContextTemplateResolver; 13 | 14 | /** 15 | * Spring MVC configuration. 16 | */ 17 | @Configuration 18 | @EnableWebMvc 19 | @ComponentScan("com.thymeleafexamples.select") 20 | public class WebMvcConfig extends WebMvcConfigurerAdapter { 21 | 22 | private static final String ENCODING = "UTF-8"; 23 | 24 | @Bean 25 | public ServletContextTemplateResolver templateResolver() { 26 | ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(); 27 | resolver.setPrefix("/WEB-INF/templates/"); 28 | resolver.setSuffix(".html"); 29 | resolver.setTemplateMode("HTML5"); 30 | resolver.setCacheable(false); 31 | return resolver; 32 | } 33 | 34 | @Bean 35 | public SpringTemplateEngine templateEngine() { 36 | SpringTemplateEngine engine = new SpringTemplateEngine(); 37 | engine.setTemplateResolver(templateResolver()); 38 | return engine; 39 | } 40 | 41 | @Bean 42 | public ThymeleafViewResolver thymeleafViewResolver() { 43 | ThymeleafViewResolver resolver = new ThymeleafViewResolver(); 44 | resolver.setCharacterEncoding(ENCODING); 45 | resolver.setTemplateEngine(templateEngine()); 46 | return resolver; 47 | } 48 | 49 | @Override 50 | public void addFormatters(FormatterRegistry formatterRegistry) { 51 | formatterRegistry.addFormatter(new HobbyFormatter()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/dao/HobbyDao.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.dao; 2 | 3 | import com.thymeleafexamples.select.domain.Hobby; 4 | import java.util.Collection; 5 | import java.util.HashMap; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class HobbyDao { 10 | 11 | private HashMap ALL_HOBBIES = new HashMap(){{ 12 | put("CNM", new Hobby("CNM", "Cinema")); 13 | put("FTB", new Hobby("FTB", "Football")); 14 | put("PAI", new Hobby("PAI", "Painting")); 15 | put("PKR", new Hobby("PKR", "Poker")); 16 | put("DRT", new Hobby("DRT", "Darts")); 17 | put("POL", new Hobby("POL", "Pool")); 18 | put("SWI", new Hobby("SWI", "Swimming")); 19 | put("OPR", new Hobby("OPR", "Opera")); 20 | }}; 21 | 22 | public Collection findAll() { 23 | return ALL_HOBBIES.values(); 24 | } 25 | 26 | public Hobby findOne(String id) { 27 | return ALL_HOBBIES.get(id); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.dao; 2 | 3 | import com.thymeleafexamples.select.domain.Hobby; 4 | import com.thymeleafexamples.select.domain.User; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class UserDao { 12 | 13 | @Autowired HobbyDao hobbyDao; 14 | 15 | private final List DEFAULT_HOBBIES = new ArrayList(){{ 16 | add(new Hobby("CNM", "Cinema")); 17 | add(new Hobby("PKR", "Poker")); 18 | add(new Hobby("SWI", "Swimming")); 19 | }}; 20 | 21 | private final User MEMORY_USER = new User("USR101", DEFAULT_HOBBIES); 22 | 23 | public User findOne() { 24 | return MEMORY_USER; 25 | } 26 | 27 | public void save(User user) { 28 | List newHobbies = new ArrayList<>(); 29 | if (user.getHobbies() != null) { 30 | for (Hobby hobby : user.getHobbies()) { 31 | newHobbies.add(hobbyDao.findOne(hobby.getId())); 32 | } 33 | } 34 | MEMORY_USER.setHobbies(newHobbies); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/domain/Hobby.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.domain; 2 | 3 | import java.util.Objects; 4 | 5 | public class Hobby { 6 | 7 | private String id; 8 | 9 | private String description; 10 | 11 | public Hobby() { 12 | } 13 | 14 | public Hobby(String id, String description) { 15 | this.id = id; 16 | this.description = description; 17 | } 18 | 19 | public String getId() { 20 | return id; 21 | } 22 | 23 | public void setId(String id) { 24 | this.id = id; 25 | } 26 | 27 | public String getDescription() { 28 | return description; 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | int hash = 5; 34 | hash = 83 * hash + Objects.hashCode(this.id); 35 | return hash; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (obj == null) { 41 | return false; 42 | } 43 | if (getClass() != obj.getClass()) { 44 | return false; 45 | } 46 | final Hobby other = (Hobby) obj; 47 | if (!Objects.equals(this.id, other.id)) { 48 | return false; 49 | } 50 | return true; 51 | } 52 | 53 | public void setDescription(String description) { 54 | this.description = description; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.domain; 2 | 3 | import java.util.List; 4 | 5 | public class User { 6 | 7 | private String id; 8 | 9 | private List hobbies; 10 | 11 | public User() { 12 | } 13 | 14 | public User(String id, List hobbies) { 15 | this.id = id; 16 | this.hobbies = hobbies; 17 | } 18 | 19 | public String getId() { 20 | return id; 21 | } 22 | 23 | public void setId(String id) { 24 | this.id = id; 25 | } 26 | 27 | public List getHobbies() { 28 | return hobbies; 29 | } 30 | 31 | public void setHobbies(List hobbies) { 32 | this.hobbies = hobbies; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/web/HobbyFormatter.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.web; 2 | 3 | import com.thymeleafexamples.select.domain.Hobby; 4 | import java.text.ParseException; 5 | import java.util.Locale; 6 | import org.springframework.format.Formatter; 7 | 8 | public class HobbyFormatter implements Formatter { 9 | 10 | @Override 11 | public String print(Hobby hobby, Locale locale) { 12 | return hobby.getId(); 13 | } 14 | 15 | @Override 16 | public Hobby parse(String id, Locale locale) throws ParseException { 17 | Hobby hobby = new Hobby(); 18 | hobby.setId(id); 19 | return hobby; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/thymeleafexamples/select/web/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.thymeleafexamples.select.web; 2 | 3 | import com.thymeleafexamples.select.dao.HobbyDao; 4 | import com.thymeleafexamples.select.dao.UserDao; 5 | import com.thymeleafexamples.select.domain.User; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | 12 | @Controller 13 | public class IndexController { 14 | 15 | @Autowired UserDao userDao; 16 | @Autowired HobbyDao hobbyDao; 17 | 18 | @RequestMapping(value = "/", method = RequestMethod.GET) 19 | public String index(Model model) { 20 | model.addAttribute("user", userDao.findOne()); 21 | return "index"; 22 | } 23 | 24 | @RequestMapping(value = "/editSelect", method = RequestMethod.GET) 25 | public String editSelect(Model model) { 26 | model.addAttribute("user", userDao.findOne()); 27 | model.addAttribute("allHobbies", hobbyDao.findAll()); 28 | return "editSelect"; 29 | } 30 | 31 | @RequestMapping(value = "/editCheckbox", method = RequestMethod.GET) 32 | public String editCheckbox(Model model) { 33 | model.addAttribute("user", userDao.findOne()); 34 | model.addAttribute("allHobbies", hobbyDao.findAll()); 35 | return "editCheckbox"; 36 | } 37 | 38 | @RequestMapping(value = "/save", method = RequestMethod.POST) 39 | public String save(User user) { 40 | userDao.save(user); 41 | return "redirect:/"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/editCheckbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Edit user hobbies 5 | 6 | 7 |

Edit user hobbies

8 |
9 | 10 | User hobbies (checkboxes): 11 |
12 | 13 | 14 |
15 |
16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/editSelect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Edit user hobbies 5 | 6 | 7 |

Edit user hobbies

8 |
9 | 10 | 11 |
12 | 19 |
20 | 21 |
22 | 23 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | User hobbies 5 | 6 | 7 |

User hobbies

8 |
    9 |
  • 11 | Cinema 12 |
  • 13 |
14 | Edit user hobbies with a multiple select 15 | Edit user hobbies with checkboxes 16 | 17 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | --------------------------------------------------------------------------------