Merge pull request #11595 from chaos2418/JAVA-8281

JAVA-8281: split or move spring-thymeleaf module
This commit is contained in:
kwoyke 2021-12-20 09:27:19 +01:00 committed by GitHub
commit 3a2adcdb8e
28 changed files with 518 additions and 44 deletions

View File

@ -44,6 +44,7 @@
<module>spring-thymeleaf</module>
<module>spring-thymeleaf-2</module>
<module>spring-thymeleaf-3</module>
<module>spring-thymeleaf-4</module>
<module>spring-boot-jsp</module>
<module>spring-web-url</module>
</modules>

View File

@ -11,3 +11,4 @@ This module contains articles about Spring with Thymeleaf
- [Using Hidden Inputs with Spring and Thymeleaf](https://www.baeldung.com/spring-thymeleaf-hidden-inputs)
- [Thymeleaf Variables](https://www.baeldung.com/thymeleaf-variables)
- [Displaying Error Messages with Thymeleaf in Spring](https://www.baeldung.com/spring-thymeleaf-error-messages)
- [[next -->]](/spring-thymeleaf-4)

View File

@ -0,0 +1,26 @@
## Spring Thymeleaf
This module contains articles about Spring with Thymeleaf
### Relevant Articles:
- [Conditionals in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-conditionals)
- [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration)
- [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination)
### Build the Project
mvn clean install
### Run the Project
mvn cargo:run
- **note**: starts on port '8082'
Access the pages using the URLs:
- http://localhost:8082/spring-thymeleaf-4/
- http://localhost:8082/spring-thymeleaf-4/addStudent/
- http://localhost:8082/spring-thymeleaf-4/listStudents/
The first URL is the home page of the application. The home page has links to the second and third pages.

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-thymeleaf-4</artifactId>
<name>spring-thymeleaf-4</name>
<packaging>war</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-spring-5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-spring-5</relativePath>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${spring-data.version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax.validation-version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${org.thymeleaf-version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${org.thymeleaf-version}</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>${thymeleaf-layout-dialect.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>${org.thymeleaf.extras-version}</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>${cargo-maven2-plugin.version}</version>
<configuration>
<wait>true</wait>
<container>
<containerId>jetty9x</containerId>
<type>embedded</type>
<systemProperties>
</systemProperties>
</container>
<configuration>
<properties>
<cargo.servlet.port>8082</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<spring-data.version>2.3.2.RELEASE</spring-data.version>
<org.thymeleaf-version>3.0.11.RELEASE</org.thymeleaf-version>
<org.thymeleaf.extras-version>3.0.4.RELEASE</org.thymeleaf.extras-version>
<thymeleaf-layout-dialect.version>2.4.1</thymeleaf-layout-dialect.version>
<javax.validation-version>2.0.1.Final</javax.validation-version>
<hibernate-validator.version>6.0.11.Final</hibernate-validator.version>
<!-- Maven plugins -->
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
</properties>
</project>

View File

@ -0,0 +1,36 @@
package com.baeldung.thymeleaf.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.ServletRegistration.Dynamic;
/**
* Java configuration file that is used for web application initialization
*/
public class WebApp extends AbstractAnnotationConfigDispatcherServletInitializer {
public WebApp() {
super();
}
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebMVCConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected void customizeRegistration(final Dynamic registration) {
super.customizeRegistration(registration);
}
}

View File

@ -0,0 +1,115 @@
package com.baeldung.thymeleaf.config;
import com.baeldung.thymeleaf.formatter.NameFormatter;
import com.baeldung.thymeleaf.utils.ArrayUtil;
import nz.net.ultraq.thymeleaf.LayoutDialect;
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect;
import org.thymeleaf.spring5.ISpringTemplateEngine;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import java.util.Locale;
@Configuration
@EnableWebMvc
@ComponentScan({ "com.baeldung.thymeleaf" })
/*
Java configuration file that is used for Spring MVC and Thymeleaf
configurations
*/
public class WebMVCConfig implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public ViewResolver htmlViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
resolver.setContentType("text/html");
resolver.setCharacterEncoding("UTF-8");
resolver.setViewNames(ArrayUtil.array("*.html"));
return resolver;
}
private ISpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addDialect(new LayoutDialect(new GroupingStrategy()));
engine.addDialect(new Java8TimeDialect());
engine.setTemplateResolver(templateResolver);
engine.setTemplateEngineMessageSource(messageSource());
return engine;
}
private ITemplateResolver htmlTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/views/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
@Bean
@Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(new Locale("en"));
return localeResolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**", "/css/**")
.addResourceLocations("/WEB-INF/resources/", "/WEB-INF/css/");
}
@Override
@Description("Custom Conversion Service")
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new NameFormatter());
}
}

View File

@ -1,22 +1,20 @@
package com.baeldung.thymeleaf.controller;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.baeldung.thymeleaf.model.Book;
import com.baeldung.thymeleaf.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
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 org.springframework.web.bind.annotation.RequestParam;
import com.baeldung.thymeleaf.model.Book;
import com.baeldung.thymeleaf.service.BookService;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Controller
public class BookController {

View File

@ -1,14 +1,14 @@
package com.baeldung.thymeleaf.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
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.text.DateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Handles requests for the application home page.
*

View File

@ -1,9 +1,7 @@
package com.baeldung.thymeleaf.controller;
import java.util.List;
import javax.validation.Valid;
import com.baeldung.thymeleaf.model.Student;
import com.baeldung.thymeleaf.utils.StudentUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
@ -11,8 +9,8 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.baeldung.thymeleaf.model.Student;
import com.baeldung.thymeleaf.utils.StudentUtils;
import javax.validation.Valid;
import java.util.List;
/**
* Handles requests for the student model.

View File

@ -1,12 +1,11 @@
package com.baeldung.thymeleaf.controller;
import com.baeldung.thymeleaf.utils.TeacherUtils;
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 com.baeldung.thymeleaf.utils.TeacherUtils;
@Controller
public class TeacherController {

View File

@ -0,0 +1,30 @@
package com.baeldung.thymeleaf.formatter;
import org.springframework.format.Formatter;
import org.thymeleaf.util.StringUtils;
import java.text.ParseException;
import java.util.Locale;
/**
*
* Name formatter class that implements the Spring Formatter interface.
* Formats a name(String) and return the value with spaces replaced by commas.
*
*/
public class NameFormatter implements Formatter<String> {
@Override
public String print(String input, Locale locale) {
return formatName(input, locale);
}
@Override
public String parse(String input, Locale locale) throws ParseException {
return formatName(input, locale);
}
private String formatName(String input, Locale locale) {
return StringUtils.replace(input, " ", ",");
}
}

View File

@ -0,0 +1,59 @@
package com.baeldung.thymeleaf.model;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
*
* Simple student POJO with few fields
*
*/
public class Student implements Serializable {
private static final long serialVersionUID = -8582553475226281591L;
@NotNull(message = "Student ID is required.")
@Min(value = 1000, message = "Student ID must be at least 4 digits.")
private Integer id;
@NotNull(message = "Student name is required.")
private String name;
@NotNull(message = "Student gender is required.")
private Character gender;
private Float percentage;
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;
}
public Character getGender() {
return gender;
}
public void setGender(Character gender) {
this.gender = gender;
}
public Float getPercentage() {
return percentage;
}
public void setPercentage(Float percentage) {
this.percentage = percentage;
}
}

View File

@ -1,11 +1,10 @@
package com.baeldung.thymeleaf.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Teacher implements Serializable {

View File

@ -1,16 +1,15 @@
package com.baeldung.thymeleaf.service;
import java.util.Collections;
import java.util.List;
import com.baeldung.thymeleaf.model.Book;
import com.baeldung.thymeleaf.utils.BookUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.baeldung.thymeleaf.model.Book;
import com.baeldung.thymeleaf.utils.BookUtils;
import java.util.Collections;
import java.util.List;
@Service
public class BookService {

View File

@ -0,0 +1,8 @@
package com.baeldung.thymeleaf.utils;
public class ArrayUtil {
public static String[] array(String... args) {
return args;
}
}

View File

@ -1,11 +1,11 @@
package com.baeldung.thymeleaf.utils;
import com.baeldung.thymeleaf.model.Book;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import com.baeldung.thymeleaf.model.Book;
public class BookUtils {
private static List<Book> books = new ArrayList<Book>();

View File

@ -0,0 +1,34 @@
package com.baeldung.thymeleaf.utils;
import com.baeldung.thymeleaf.model.Student;
import java.util.ArrayList;
import java.util.List;
public class StudentUtils {
private static List<Student> students = new ArrayList<Student>();
public static List<Student> buildStudents() {
if (students.isEmpty()) {
Student student1 = new Student();
student1.setId(1001);
student1.setName("John Smith");
student1.setGender('M');
student1.setPercentage(Float.valueOf("80.45"));
students.add(student1);
Student student2 = new Student();
student2.setId(1002);
student2.setName("Jane Williams");
student2.setGender('F');
student2.setPercentage(Float.valueOf("60.25"));
students.add(student2);
}
return students;
}
}

View File

@ -1,10 +1,10 @@
package com.baeldung.thymeleaf.utils;
import com.baeldung.thymeleaf.model.Teacher;
import java.util.ArrayList;
import java.util.List;
import com.baeldung.thymeleaf.model.Teacher;
public class TeacherUtils {
private static List<Teacher> teachers = new ArrayList<Teacher>();

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,13 @@
msg.id=ID
msg.name=Name
msg.gender=Gender
msg.percent=Percentage
welcome.message=Welcome Student !!!
msg.AddStudent=Add Student
msg.ListStudents=List Students
msg.Home=Home
msg.ListTeachers=List Teachers
msg.ListBooks=List Books with paging
msg.courses=Courses
msg.skills=Skills
msg.active=Active

View File

@ -0,0 +1,19 @@
package com.baeldung.thymeleaf;
import com.baeldung.thymeleaf.config.WebApp;
import com.baeldung.thymeleaf.config.WebMVCConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { WebApp.class, WebMVCConfig.class })
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}

View File

@ -10,9 +10,6 @@ This module contains articles about Spring with Thymeleaf
- [Spring MVC + Thymeleaf 3.0: New Features](https://www.baeldung.com/spring-thymeleaf-3)
- [How to Work with Dates in Thymeleaf](https://www.baeldung.com/dates-in-thymeleaf)
- [Working with Fragments in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-fragments)
- [Conditionals in Thymeleaf](https://www.baeldung.com/spring-thymeleaf-conditionals)
- [Iteration in Thymeleaf](https://www.baeldung.com/thymeleaf-iteration)
- [Spring with Thymeleaf Pagination for a List](https://www.baeldung.com/spring-thymeleaf-pagination)
- [[next -->]](/spring-thymeleaf-2)
### Build the Project
@ -24,13 +21,5 @@ mvn clean install
mvn cargo:run
- **note**: starts on port '8082'
Access the pages using the URLs:
- http://localhost:8082/spring-thymeleaf/
- http://localhost:8082/spring-thymeleaf/addStudent/
- http://localhost:8082/spring-thymeleaf/listStudents/
The first URL is the home page of the application. The home page has links to the second and third pages.
### Security
The user/password required is: user1/user1Pass