├── springboot-core
├── helloworld
│ ├── src
│ │ ├── main
│ │ │ ├── resources
│ │ │ │ └── application.properties
│ │ │ └── java
│ │ │ │ └── grokwich
│ │ │ │ └── springbootcore
│ │ │ │ └── helloworld
│ │ │ │ └── HelloworldApplication.java
│ │ └── test
│ │ │ └── java
│ │ │ └── grokwich
│ │ │ └── springbootcore
│ │ │ └── helloworld
│ │ │ └── HelloworldApplicationTests.java
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradlew.bat
│ └── gradlew
└── groovy-joint
│ ├── src
│ └── main
│ │ ├── resources
│ │ └── application.properties
│ │ └── groovy
│ │ └── grokwich
│ │ └── springbootcore
│ │ └── groovyjoint
│ │ ├── beans
│ │ ├── JointBean.groovy
│ │ ├── JavaBeanA.java
│ │ ├── GroovyBeanB.groovy
│ │ ├── GroovyBeanD.groovy
│ │ └── JavaBeanC.java
│ │ └── GroovyJointApplication.groovy
│ ├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradlew.bat
│ └── gradlew
└── springboot-web
├── web-thymeleaf-forms
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── ValidationMessages.properties
│ │ │ ├── templates
│ │ │ │ ├── fooResult.html
│ │ │ │ └── fooForm.html
│ │ │ └── messages.properties
│ │ └── groovy
│ │ │ └── grokwich
│ │ │ └── springboot
│ │ │ └── web
│ │ │ └── thymeleaf
│ │ │ └── forms
│ │ │ ├── WebThymeleafFormsApplication.java
│ │ │ ├── command
│ │ │ └── FormCommand.java
│ │ │ └── controller
│ │ │ └── FormController.java
│ └── test
│ │ └── groovy
│ │ └── grokwich
│ │ └── springboot
│ │ └── web
│ │ └── thymeleaf
│ │ └── forms
│ │ └── WebThymeleafFormsApplicationTests.java
├── .gitignore
├── build.gradle
├── README.md
├── gradlew.bat
└── gradlew
└── web-thymeleaf-JSR303-validation
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
├── main
│ ├── resources
│ │ ├── application.properties
│ │ ├── templates
│ │ │ ├── fooResult.html
│ │ │ └── fooForm.html
│ │ ├── ValidationMessages.properties
│ │ └── messages.properties
│ └── groovy
│ │ └── grokwich
│ │ └── springboot
│ │ └── web
│ │ └── thymeleaf
│ │ └── validation
│ │ ├── command
│ │ └── FormCommand.java
│ │ ├── WebThymeleafValidationApplication.java
│ │ └── controller
│ │ └── FormController.java
└── test
│ └── groovy
│ └── grokwich
│ └── springboot
│ └── web
│ └── thymeleaf
│ └── validation
│ └── WebThymeleafFormsApplicationTests.java
├── .gitignore
├── README.md
├── build.gradle
├── gradlew.bat
└── gradlew
/springboot-core/helloworld/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/springboot-core/helloworld/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grokwich/spring-snacks/HEAD/springboot-core/helloworld/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grokwich/spring-snacks/HEAD/springboot-core/groovy-joint/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grokwich/spring-snacks/HEAD/springboot-web/web-thymeleaf-forms/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/beans/JointBean.groovy:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint.beans
2 |
3 | interface JointBean {
4 | String msg()
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grokwich/spring-snacks/HEAD/springboot-web/web-thymeleaf-JSR303-validation/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | logging.level.root=WARN
2 | #logging.level.org.springframework.web=DEBUG
3 | logging.level.grokwich.springboot.web.thymeleaf.forms=DEBUG
4 |
5 | spring.thymeleaf.cache=false
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | logging.level.root=WARN
2 | #logging.level.org.springframework.web=DEBUG
3 | logging.level.grokwich.springboot.web.thymeleaf.forms=DEBUG
4 |
5 | spring.thymeleaf.cache=false
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/beans/JavaBeanA.java:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint.beans;
2 |
3 | class JavaBeanA implements JointBean {
4 | public String msg() {
5 | return "JavaBeanA";
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/beans/GroovyBeanB.groovy:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint.beans;
2 |
3 | class GroovyBeanB extends JavaBeanA {
4 | String msg() {
5 | "${super.msg()} > GroovyBeanB"
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/beans/GroovyBeanD.groovy:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint.beans;
2 |
3 | class GroovyBeanD extends JavaBeanC {
4 | String msg() {
5 | "${super.msg()} > GroovyBeanD"
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
6 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/beans/JavaBeanC.java:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint.beans;
2 |
3 | class JavaBeanC extends GroovyBeanB {
4 | public String msg() {
5 | return super.msg() + " > JavaBeanC";
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/springboot-core/helloworld/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
6 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
6 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
6 |
--------------------------------------------------------------------------------
/springboot-core/helloworld/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | bin/
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | nbproject/private/
22 | build/
23 | nbbuild/
24 | dist/
25 | nbdist/
26 | .nb-gradle/
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | bin/
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | nbproject/private/
22 | build/
23 | nbbuild/
24 | dist/
25 | nbdist/
26 | .nb-gradle/
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | bin/
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | nbproject/private/
22 | build/
23 | nbbuild/
24 | dist/
25 | nbdist/
26 | .nb-gradle/
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | bin/
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | nbproject/private/
22 | build/
23 | nbbuild/
24 | dist/
25 | nbdist/
26 | .nb-gradle/
--------------------------------------------------------------------------------
/springboot-core/helloworld/src/test/java/grokwich/springbootcore/helloworld/HelloworldApplicationTests.java:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.helloworld;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class HelloworldApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/groovy/grokwich/springboot/web/thymeleaf/forms/WebThymeleafFormsApplication.java:
--------------------------------------------------------------------------------
1 | package grokwich.springboot.web.thymeleaf.forms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 |
7 | @SpringBootApplication
8 | public class WebThymeleafFormsApplication {
9 |
10 | public static void main(String[] args) {
11 | SpringApplication.run( WebThymeleafFormsApplication.class, args );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/resources/templates/fooResult.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Thymeleaf Form Result
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | resubmit form
14 |
15 |
16 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/groovy/grokwich/springboot/web/thymeleaf/forms/command/FormCommand.java:
--------------------------------------------------------------------------------
1 | package grokwich.springboot.web.thymeleaf.forms.command;
2 |
3 |
4 | import lombok.Data;
5 |
6 | @Data
7 | public class FormCommand {
8 |
9 | String textField;
10 |
11 | String textareaField;
12 |
13 | String datetimeField;
14 |
15 | String colorField;
16 |
17 | boolean singleCheckboxField;
18 |
19 | String[] multiCheckboxSelectedValues;
20 |
21 | String radioButtonSelectedValue;
22 |
23 | String dropdownSelectedValue;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/springboot-core/helloworld/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.7.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'java'
14 | apply plugin: 'eclipse'
15 | apply plugin: 'org.springframework.boot'
16 |
17 | group = 'grokwich.springboot-core'
18 | version = '0.0.1-SNAPSHOT'
19 | sourceCompatibility = 1.8
20 |
21 | repositories {
22 | mavenCentral()
23 | }
24 |
25 |
26 | dependencies {
27 | compile('org.springframework.boot:spring-boot-starter')
28 | runtime('org.springframework.boot:spring-boot-devtools')
29 | testCompile('org.springframework.boot:spring-boot-starter-test')
30 | }
31 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/src/main/groovy/grokwich/springbootcore/groovyjoint/GroovyJointApplication.groovy:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.groovyjoint;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean
6 |
7 | import grokwich.springbootcore.groovyjoint.beans.GroovyBeanD
8 |
9 |
10 | @SpringBootApplication
11 | public class GroovyJointApplication {
12 |
13 | public static void main(String[] args) {
14 | def context = SpringApplication.run(GroovyJointApplication.class, args)
15 |
16 | def bean = context.getBean("beanX")
17 |
18 | println bean.msg()
19 | }
20 |
21 |
22 | @Bean
23 | def beanX() {
24 | return new GroovyBeanD()
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/springboot-core/groovy-joint/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.7.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'java'
14 | apply plugin: 'eclipse'
15 | apply plugin: 'org.springframework.boot'
16 | apply plugin: 'groovy'
17 |
18 | group = 'grokwich.springboot-core'
19 | version = '0.0.1-SNAPSHOT'
20 | sourceCompatibility = 1.8
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 |
26 |
27 | dependencies {
28 | compile('org.springframework.boot:spring-boot-starter')
29 | compile('org.codehaus.groovy:groovy')
30 |
31 | runtime('org.springframework.boot:spring-boot-devtools')
32 |
33 | testCompile('org.springframework.boot:spring-boot-starter-test')
34 | }
35 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/groovy/grokwich/springboot/web/thymeleaf/validation/command/FormCommand.java:
--------------------------------------------------------------------------------
1 | package grokwich.springboot.web.thymeleaf.validation.command;
2 |
3 | import javax.validation.constraints.Size;
4 | import org.hibernate.validator.constraints.Email;
5 |
6 | import lombok.Data;
7 |
8 | @Data
9 | public class FormCommand {
10 |
11 | // textField messages are configured/handled by ValidationMessages.
12 | @Size.List({
13 | @Size(min = 5, message = "{fooCommand.textField.min.message}"),
14 | @Size(max = 20, message = "{fooCommand.textField.max.message}")
15 | })
16 | @Email(message = "{fooCommand.textField.email.message}")
17 | String textField;
18 |
19 |
20 | // textareaField messages are configured/handled by messages.properties.
21 | @Size(min=3, max=50)
22 | String textareaField;
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/README.md:
--------------------------------------------------------------------------------
1 | # web-thymeleaf-JSR303-validation (Part #2)
2 |
3 | Snack-sample that demonstrates JSR303-validation (bean validation annotations).
4 |
5 | The Command pattern is used and most form elements have been demonstrated.
6 |
7 | ## Blog Discussion
8 | https://medium.com/@grokwich/spring-boot-thymeleaf-html-form-handling-part-2-b4c9e83a189c
9 |
10 | ## Validation error messages.
11 |
12 | The code demonstrates Validation message configuration options:
13 | * messages.properties vs. validationMessages.properties
14 |
15 | Recommendation is to use validationMessages.properties (JSR-303 native).
16 | Using (default) messages.properties will only provide simple localization message
17 | configuration for validation messages (only numeric param interpolation).
18 |
19 | ## Unit Tests
20 | MockMVC tests that demonstrate happy-case and expected validation errors.
21 |
22 |
--------------------------------------------------------------------------------
/springboot-core/helloworld/src/main/java/grokwich/springbootcore/helloworld/HelloworldApplication.java:
--------------------------------------------------------------------------------
1 | package grokwich.springbootcore.helloworld;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.ApplicationContext;
6 | import org.springframework.context.annotation.Bean;
7 |
8 | @SpringBootApplication
9 | public class HelloworldApplication {
10 |
11 | public static void main(String[] args) {
12 | ApplicationContext context = SpringApplication.run(HelloworldApplication.class, args);
13 |
14 | TestBean bean = context.getBean(TestBean.class);
15 |
16 | System.out.println( bean.getMessage() );
17 | }
18 |
19 | static class TestBean {
20 | String getMessage() {
21 | return "Hello World!";
22 | }
23 | }
24 |
25 | @Bean
26 | TestBean getBean() {
27 | return new TestBean();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.7.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'groovy'
14 | apply plugin: 'eclipse'
15 | apply plugin: 'org.springframework.boot'
16 |
17 | group = 'grokwich.springboot-web'
18 | version = '0.0.1-SNAPSHOT'
19 | sourceCompatibility = 1.8
20 |
21 | repositories {
22 | mavenCentral()
23 | }
24 |
25 |
26 | dependencies {
27 | compile('org.springframework.boot:spring-boot-starter-thymeleaf')
28 | compile('org.springframework.boot:spring-boot-starter-web')
29 | compile('org.codehaus.groovy:groovy')
30 | runtime('org.springframework.boot:spring-boot-devtools')
31 | compileOnly('org.projectlombok:lombok')
32 | testCompile('org.springframework.boot:spring-boot-starter-test')
33 | }
34 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.7.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'groovy'
14 | apply plugin: 'eclipse'
15 | apply plugin: 'org.springframework.boot'
16 |
17 | group = 'grokwich.springboot-web'
18 | version = '0.0.1-SNAPSHOT'
19 | sourceCompatibility = 1.8
20 |
21 | repositories {
22 | mavenCentral()
23 | }
24 |
25 |
26 | dependencies {
27 | compile('org.springframework.boot:spring-boot-starter-thymeleaf')
28 | compile('org.springframework.boot:spring-boot-starter-web')
29 | compile('org.codehaus.groovy:groovy')
30 | runtime('org.springframework.boot:spring-boot-devtools')
31 | compileOnly('org.projectlombok:lombok')
32 | testCompile('org.springframework.boot:spring-boot-starter-test')
33 | }
34 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/resources/ValidationMessages.properties:
--------------------------------------------------------------------------------
1 | # ValidationMessages.properties is the SpringBoot default message bundle for the JSR-303 specification.
2 | # RECOMMENDATION:
3 | # Use the full power of JSR-303 by maintaining all Validation messages here (ValidationMessages.properties).
4 | # ie. do not maintain Validation messages in messages.properties.
5 | #
6 | # http://beanvalidation.org/1.0/spec/#default-resolution-algorithm
7 |
8 | fooCommand.textField.min.message=The Text Field ${validatedValue.length() < 1 ? 'is empty': 'has only ' + validatedValue.length() + 'characters'}, but the length must be at least {min} characters.
9 | fooCommand.textField.max.message=The Text Field value has ${validatedValue.length()}, but the length cannot exceed {max}.
10 |
11 | # NOTE: For demo purposes the validation message for textareaField configured in (@see) messages.properties.
12 |
13 | fooCommand.textField.email.message=The Text Field requires an email address.
14 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/resources/ValidationMessages.properties:
--------------------------------------------------------------------------------
1 | # ValidationMessages.properties is the SpringBoot default message bundle for the JSR-303 specification.
2 | # RECOMMENDATION:
3 | # Use the full power of JSR-303 by maintaining all Validation messages here (ValidationMessages.properties).
4 | # ie. do not maintain Validation messages in messages.properties.
5 | #
6 | # http://beanvalidation.org/1.0/spec/#default-resolution-algorithm
7 |
8 | fooCommand.textField.min.message=The Text Field ${validatedValue.length() < 1 ? 'is empty': 'has only ' + validatedValue.length() + 'characters'}, but the length must be at least {min} characters.
9 | fooCommand.textField.max.message=The Text Field value has ${validatedValue.length()}, but the length cannot exceed {max}.
10 |
11 | # NOTE: For demo purposes the validation message for textareaField configured in (@see) messages.properties.
12 |
13 | fooCommand.textField.email.message=The Text Field requires an email address.
14 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/resources/templates/fooResult.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Thymeleaf Form Result
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | resubmit form
20 |
21 |
22 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/resources/templates/fooForm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Thymeleaf Form Validation
5 |
6 |
9 |
10 |
11 |
12 |
13 |
26 |
27 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/main/resources/messages.properties:
--------------------------------------------------------------------------------
1 | # The Validation framework will use messages.properties by default if present,
2 | # but the Validation msg integration is adapted to the i18n message bundle api.
3 | # So just simple interpolation of parameters by number.
4 | # One nice behavior of the simple message api is auto-key generation.
5 | # By default, you do not need to be explicit about the constraint annotation specifying a message key.
6 | # The default key convention is ..
7 | # Normally the command-name is the Command Class Name.
8 | # WARN!
9 | # But if the command-name is aliased by a @ModelAttribute("command-name-alias"),
10 | # then the alias must be used as the command-name.
11 | # example:
12 | # // @Valid @ModelAttribute("command") FormCommand command,
13 | # In this example command-name -> "command" (rather than 'formCommand').
14 | # The default key in this case is demonstrated below by the @Size validation message.
15 | #
16 |
17 | Size.command.textareaField=The Textarea Field must have at least {2} characters, but no mare than {1}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/resources/messages.properties:
--------------------------------------------------------------------------------
1 | # The Validation framework will use messages.properties by default if present,
2 | # but the Validation msg integration is adapted to the i18n message bundle api.
3 | # So just simple interpolation of parameters by number.
4 | # One nice behavior of the simple message api is auto-key generation.
5 | # By default, you do not need to be explicit about the constraint annotation specifying a message key.
6 | # The default key convention is ..
7 | # Normally the command-name is the Command Class Name.
8 | # WARN!
9 | # But if the command-name is aliased by a @ModelAttribute("command-name-alias"),
10 | # then the alias must be used as the command-name.
11 | # example:
12 | # // @Valid @ModelAttribute("command") FormCommand command,
13 | # In this example command-name -> "command" (rather than 'formCommand').
14 | # The default key in this case is demonstrated below by the @Size validation message.
15 | #
16 |
17 | Size.command.textareaField=The Textarea Field must have at least {2} characters, but no mare than {1}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-JSR303-validation/src/main/groovy/grokwich/springboot/web/thymeleaf/validation/WebThymeleafValidationApplication.java:
--------------------------------------------------------------------------------
1 | package grokwich.springboot.web.thymeleaf.validation;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | import grokwich.springboot.web.thymeleaf.validation.WebThymeleafValidationApplication;
7 |
8 |
9 | @SpringBootApplication
10 | public class WebThymeleafValidationApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run( WebThymeleafValidationApplication.class, args );
14 | }
15 |
16 |
17 | /*
18 | If it was really important to you that JSR-303 validation messages be stored in messages.properties
19 | (rather that the default ValidationMessages.properties),
20 | then you could do the following...
21 |
22 | @Autowired
23 | private MessageSource messageSource;
24 |
25 | @Override
26 | public Validator getValidator() {
27 | LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
28 | factory.setValidationMessageSource(messageSource);
29 | return factory;
30 | }
31 | */
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/src/test/groovy/grokwich/springboot/web/thymeleaf/forms/WebThymeleafFormsApplicationTests.java:
--------------------------------------------------------------------------------
1 | package grokwich.springboot.web.thymeleaf.forms;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7 | import org.springframework.http.MediaType;
8 | import org.springframework.test.context.junit4.SpringRunner;
9 | import org.springframework.test.web.servlet.MockMvc;
10 |
11 | import grokwich.springboot.web.thymeleaf.forms.command.FormCommand;
12 |
13 | import static org.hamcrest.Matchers.*;
14 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
15 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
16 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
17 |
18 |
19 |
20 | @RunWith(SpringRunner.class)
21 | @WebMvcTest
22 | public class WebThymeleafFormsApplicationTests {
23 |
24 | @Autowired
25 | private MockMvc mockMvc;
26 |
27 | @Test
28 | public void fooFormTest() throws Exception {
29 | mockMvc.perform(get("/fooform"))
30 | .andExpect(model().attribute("command", any(FormCommand.class)))
31 | .andExpect(view().name("fooForm"))
32 | .andExpect(status().isOk());
33 | }
34 |
35 |
36 | @Test
37 | public void fooFormPostTest() throws Exception {
38 | this.mockMvc
39 | .perform(post("/fooform")
40 | .param("textField", "foobar")
41 | .contentType(MediaType.APPLICATION_FORM_URLENCODED))
42 | .andExpect(status().is3xxRedirection())
43 | .andExpect(flash().attribute("command", hasProperty("textField", equalTo("foobar"))));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/springboot-web/web-thymeleaf-forms/README.md:
--------------------------------------------------------------------------------
1 | # web-thymeleaf-forms
2 | Snack-sample that demonstrates integration of HTML Form workflow between Spring Boot and Thymeleaf.
3 |
4 | ## Blog Discussion
5 | https://medium.com/@grokwich/spring-boot-thymeleaf-html-form-handling-762ef0d51327
6 |
7 | ## HTML Form Elements
8 |
9 | Most form elements have been demonstrated.
10 | * `