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
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.
Advertisement
Answer
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.