I am following along with a chapter exercise in Spring in Action the chapter goes through validation but even when I POST the forms with empty input it does not return any form of validation errors! No matter what I do I cannot trigger a validation error response, the form is just accepted as it is completely empty.
Full project # https://github.com/AdrianLarssonGit/tacoworld/tree/master/tacoworld
Below is what I assume is the relevant code:
OrderController.java:
package com.tacoworld;
import lombok.extern.slf4j.Slf4j;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.tacoworld.TacoOrder;
#Slf4j
#Controller
#Validated
#RequestMapping("/orders")
public class OrderController {
#GetMapping("/current")
public String orderForm(Model model) {
model.addAttribute("tacoOrder", new TacoOrder());
return "orderForm";
}
#PostMapping
public String processOrder(#Valid TacoOrder tacoOrder, Errors errors) {
if(errors.hasErrors()) {
return "orderForm";
}
else {
log.info("Order submitted: " + tacoOrder);
return "redirect:/";
}
}
}
orderForm.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>
Taco Cloud
</title>
<link th:href="#{style.css}" rel="stylesheet" />
</head>
<body>
<form method="POST" th:action="#{/orders}" th:object="${tacoOrder}">
<h1>Order your taco creation</h1>
<img th:src="#{/images/startSplash.jpg}" />
<br>
<a th:href="#{/design}" id="another">Design another taco!</a><br/>
<h3>Deliver my taco to...</h3>
<label for="deliveryName">Name: </label>
<input type="text" th:field="*{deliveryName}" />
<span class="validationError" th:if="${#fields.hasErrors('deliveryName')}" th:errors="*{deliveryName}">TEST Error</span>
<br/>
<label for="deliveryStreet">Street address: </label>
<input type="text" th:field="*{deliveryStreet}"/>
<br/>
<label for="deliveryCity">City: </label>
<input type="text" th:field="*{deliveryCity}"/>
<br/>
<label for="deliveryState">State: </label>
<input type="text" th:field="*{deliveryState}"/>
<br/>
<label for="deliveryZip">Zip code: </label>
<input type="text" th:field="*{deliveryZip}"/>
<br/>
<h3>Here's how I'll pay...</h3>
<label for="ccNumber">Credit Card #: </label>
<input type="text" th:field="*{ccNumber}"/>
<br/>
<label for="ccExpiration">Expiration: </label>
<input type="text" th:field="*{ccExpiration}"/>
<br/>
<label for="ccCVV">CVV: </label>
<input type="text" th:field="*{ccCVV}"/>
<br/>
<input type="submit" value="Submit order" />
</form>
</body>
TacoOrder.java:
package com.tacoworld;
import java.util.List;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import java.util.ArrayList;
import lombok.Data;
#Data
public class TacoOrder {
#NotBlank(message="Delivery name is required")
private String deliveryName;
#NotBlank(message="Name must be at least 5 char long")
private String deliveryStreet;
#NotBlank(message="Name must be at least 5 char long")
private String deliveryCity;
#NotBlank(message="Name must be at least 5 char long")
private String deliveryState;
#NotBlank(message="Name must be at least 5 char long")
private String deliveryZip;
#CreditCardNumber(message="Name must be at least 5 char long")
private String ccNumber;
#Pattern(regexp="^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",message="Wrong pattern MM/YY is needed")
private String ccExpiration;
#Digits(integer=3, fraction=0,message="Invalid CCV")
private String ccCVV;
private List<Taco> tacos = new ArrayList<>();
public void addTaco(Taco taco) {
this.tacos.add(taco);
}
}
I am using Spring Boot so have not done much of POM editing except for trying to solve this particular problem, I attach it here anyway for reference:
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tacoworld</groupId>
<artifactId>tacoworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tacoworld</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>16</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Removing the whole POM, shutting down Eclipse then regenerate the POM through Spring Boot seems to have solved the problem.
Do not know if it was the POM or Eclipse who acted up but now it does indeed work.
Related
I am currently learning Spring/Spring Boot and I am trying to code a forgot password function. All my other functions, like login etc. are working as intended, but redirecting to an reset-password page does not work for some reason and gives me the following error, in which it looks for the jsp with a weird prefix.
There was an unexpected error (type=Not Found, status=404).
JSP file [/reset-password/WEB-INF/jsp/reset-password.jsp] not found
My folder structure
I generate links that look like so: http://localhost:8080/reset-password/{a-random-uuid}
reset-password.jsp
<%# include file="includes/header.jsp" %>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Reset your password</h3>
</div>
<div class="panel-body">
<form:form modelAttribute="resetPasswordForm" role="form">
<form:errors cssClass="error" />
<div class="form-group">
<form:label path="password">Type new password</form:label>
<form:password path="password" class="form-control"
placeholder="Password" />
<form:errors cssClass="error" path="password" />
</div>
<div class="form-group">
<form:label path="retypePassword">Retype new password</form:label>
<form:password path="retypePassword" class="form-control"
placeholder="Retype password" />
<form:errors cssClass="error" path="retypePassword" />
</div>
<button type="submit" class="btn btn-primary">Reset password</button>
</form:form>
</div>
</div>
<%#include file="includes/footer.jsp"%>
My reset-controller:
[imports]
#Controller
#RequestMapping("/reset-password/{resetPasswordCode}")
public class ResetPasswordController {
private final UserCommandService userCommandService;
public ResetPasswordController(UserCommandService userCommandService) {
this.userCommandService = userCommandService;
}
#GetMapping
public String forgotPassword(Model model){
model.addAttribute(new ResetPasswordForm());
return "reset-password";
}
#PostMapping
public String resetPassword(#PathVariable String resetPasswordCode, #Validated ResetPasswordForm resetPasswordForm, BindingResult result, RedirectAttributes redirectAttributes){
if (result.hasErrors()) {
return "reset-password";
}
try{
userCommandService.resetPassword(resetPasswordCode, resetPasswordForm.getPassword());
MyUtils.flash(redirectAttributes, "success", "Password was changed");
return "redirect:/login";
} catch (NoSuchElementException e) {
result.reject("Url is invalid");
return "reset-password";
}
}
}
The Resetpasswordform
package com.learningspring.springdiproject.dto;
import constraints.Password;
import constraints.RetypePassword;
#RetypePassword
public class ResetPasswordForm {
#Password
private String password;
#Password
private String retypePassword;
public String getRetypePassword() {
return retypePassword;
}
public void setRetypePassword(String retypePassword) {
this.retypePassword = retypePassword;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
properties file
spring.mvc.view.prefix= WEB-INF/jsp/
spring.mvc.view.suffix= .jsp
spring.datasource.url=jdbc:h2:~/test;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE
spring.datasource.username= spring
spring.datasource.password= spring
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.javax.persistence.validation.mode= none
Finally my pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.learningspring</groupId>
<artifactId>springdiproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springdiproject</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.4.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
I am pretty sure my pom and controller are right, since I can't see a difference between this controller and my other controllers.
Note: Password and Retype password are just custom constraints, that check, the size of the password and if the two passwords of the form math an such.
I think somewhere, the Viewcontroller messes up and puts the prefix in there. But I could not find out where that may come from. Others with the same problem didnt have jasper in their pom or the wrong folder structure, but I double checked those errors.
Try to change the following property to start with a /
spring.mvc.view.prefix= /WEB-INF/jsp/
This will allow spring to search into subfolders of your webapp/WEB-INF/jsp path.
EDIT : Below is the LatherupApplication Application class:
package latherup.com.latherup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication(scanBasePackages = "latherup.com")
public class LatherupApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(LatherupApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(LatherupApplication.class, args);
}
}
Below is my home controller :
package latherup.com.latherup;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("/home")
public class HomeController {
#GetMapping("/home")
public String navigateToHomePage() {
return "home.jsp";
}
}
Below is the pom.xml file :
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>latherup.com</groupId>
<artifactId>latherup</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>latherup</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>13</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap-datepicker</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jasper -->
</dependencies>
<build>
<!--plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins-->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Below is the home.jsp :
<html>
<head>
<title>Welcome</title>
<link href="webjars/bootstrap/3.3.6/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
<div class="container">
<table class="table table-striped">
<caption>Your todos are</caption>
<thead>
<tr>
<th>Description</th>
<th>Target Date</th>
<th>Is it Done?</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td>Todo 1</td>
<td>10/12/2017</td>
<td>No</td>
<td><a class="btn btn-warning" href="/edit-todo">Edit Todo</a></td>
<td><a class="btn btn-warning" href="/delete-todo">Delete Todo</a></td>
</tr>
</tbody>
</table>
<div>
<a class="btn btn-default" href="/add-todo">Add a Todo</a>
</div>
<script src="webjars/jquery/1.9.1/jquery.min.js"></script>
<script src="webjars/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</div>
</body>
</html>
The controller is returning String "home.jsp" instead of the page. I have added all the dependencies but not sure what is the problem. Is the problem with the versions of dependencies? If Yes, how can I decide on how to choose the versions that are compatible with each other. I keep facing this problem. Sometimes it works and sometimes it doesn't. Please guide me on this as I am a beginner.
EDIT :
Below is the image of project structure :
Application.properties :
spring.mvc.view.prefix=/LATHER-UP/jsp/
spring.mvc.view.suffix=.jsp
logging.level.org.springframework.web=INFO
You have defined spring.mvc.view.suffix = .jsp
So your controller should return home not home.jsp
#Controller
#RequestMapping("/home")
public class HomeController {
#GetMapping("/home")
public String navigateToHomePage() {
return "home";
}
}
You are using RestController for returning the JSP. Use Controller annotations for working on view part.
Read more about it here Controllers
I think you deploy in a web container, to do this you should use SpringBootServletInitializer in your main class, This binds your application's Servlet, Filter, and ServletContextInitializer to the runtime server, which is necessary for our application to run:
#SpringBootApplication(scanBasePackages = "com.baeldung.boot.jsp")
public class SpringBootJspApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringBootJspApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringBootJspApplication.class);
}
}
And you should not use #RestController in the controller for jsp view, It should be #Controller, like this:
#Controller
#RequestMapping("/book")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
#GetMapping("/viewBooks")
public String viewBooks(Model model) {
model.addAttribute("books", bookService.getBooks());
return "view-books";
}
}
Please see this spring boot with jsp section here
try this out
#RestController
public class HomeController {
#RequestMapping("/home")
public ModelAndView navigateToHomePage() {
ModelAndView mv = new ModelAndView("home.jsp");
return mv;
}
}
and while using this remove the suffix and prefix from application.properties
I wrote a simple HELLOWORLD Springboot/thymeleaf project in eclipse and I can run it.
Then I tried to create a single executable war (or jar) file, but it is not possible. What I need is a single executable Jar or war file that I use as a executable (runnable) file on my computer without using eclipse.
Export as a War
Export as a Jar
application class:
package com.example.handlingformsubmission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class HandlingFormSubmissionApplication {
public static void main(String[] args) {
SpringApplication.run(HandlingFormSubmissionApplication.class, args);
}
}
The Controller ->
package com.example.handlingformsubmission;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute Greeting greeting, Model model) {
model.addAttribute("greeting", greeting);
return "result";
}
}
Pom.xml:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>handling-form-submission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>handling-form-submission</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
http file:
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/greeting}" th:object="${greeting}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Message: <input type="text" th:field="*{content}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
I found the solution:
1- Add this code in pom file:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2- Then run the project as a MAVEN BUILD.
3- write "package" in goals field.
4- click run.
When using Spring Boot and Thymeleaf, when trying to accessing the /home URL I am getting the following:
ServletException: Circular view path [home]: would dispatch back to the current handler URL [/home] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
pom.xml:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>watchlist</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>watchlist</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
main/java/com.demo.WatchlistApplication.java:
package com.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class WatchlistApplication {
public static void main(String[] args) {
SpringApplication.run(WatchlistApplication.class, args);
}
}
main/java/com.demo.controller.HomeController.java:
package com.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class HomeController {
#GetMapping("/home")
public ModelAndView home() {
return new ModelAndView("home");
}
}
main/resources/templates/home.html:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="viewport" content="width = device-width, initial-scale = 1, shrink-to-fit = no">
<title>Web app</title>
</head>
<body>
<p th:text="'Hello world'"></p>
</body>
</html>
Annotate you controller class "HomeController" with annotation #RestController instead #Controller.
Seems duplicate of Circular View path error Spring boot
For springboot 2.6.0, Try controller:
#Controller
public class HomeController {
#GetMapping("/home")
public String home() {
return "home"; // be same as the template file name (without suffix)
}
}
You should have resources/templates/home.html.
Make sure the spring-boot-starter-thymeleaf has been downloaded successfully.
Good morning people!
I’m trying to make the Thymeleaf part of template and fragments work, but nothing happens on the page...
I already tested several configurations, but I could not do anything that would make this part of th:block work or get the layout.html correctly.
Can someone help me please? See code below:
new.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layout">
<th:block layout:fragment="content">
<ul>
<li th:each="name : ${list}">
<p th:text="${name}"></p>
</li>
</ul>
</th:block>
</html>
layout.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="ISO-8859-1" />
<title>Insert title here</title>
<link rel="stylesheet" th:href="#{/css/bootstrap.min.css}" />
</head>
<body>
<th:block layout:replace="fragments/header"></th:block>
<div class="container-fluid">
<div class="row">
<th:block layout:fragment="content"></th:block>
</div>
</div>
<script th:src="#{/js/jquery-3.3.1.min.js}"></script>
<script th:src="#{/js/bootstrap.min.js}"></script>
</body>
</html>
header.html:
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#nav">
<span class="navbar-toggler-icon"></span>
</button>
Spring App
<div class="collapse navbar-collapse" id="nav">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
Home
</li>
<li class="nav-item active">
About
</li>
</ul>
</div>
</nav>
InicioController:
package com.example.teste.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("/")
public class InicioController {
#GetMapping("/new")
public String newPath(Model model) {
List<String> list = new ArrayList<String>();
list.add("Teste 1");
list.add("Teste 2");
list.add("Teste 3");
list.add("Teste 4");
list.add("Teste 5");
model.addAttribute("list", list);
return "new";
}
}
I find it strange that Thymeleaf xmlns does not appear... Is this normal?
pom.xml:
<?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>
<groupId>com.example</groupId>
<artifactId>teste</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>teste</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I inserted another image that shows the empty part and also does not appear the xmlns: th = "http://www.thymeleaf.org" I do not know how far this is normal.
new.html:
UPDATE
The issue is caused by a dependency issue, when you add the following to your pom.xml it works:
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.0.5</version>
</dependency>
OLD ANSWER
You are probably missing the fragment declaration in your header.html, it should be like this:
<div th:fragment="header">
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#nav">
<span class="navbar-toggler-icon"></span>
</button>
Spring App
<div class="collapse navbar-collapse" id="nav">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
Home
</li>
<li class="nav-item active">
About
</li>
</ul>
</div>
</nav>
</div>
I also noticed you have in your layout.html the same fragment declaration as in new.html. I suppose one of these needs to be a replace tag?