我正在开发我的 Java
的登录模块, Springboot
, React
和Thymeleaf
应用程序,我遇到org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported
当我提交 HTML 登录表单时。不知道如何继续。我看过类似的帖子,但它并没有帮助我解决问题。
项目结构
login.html
<!--<div th:if="${param.error}">Invalid username and/or password.</div>-->
<form action="#" th:action="@{/validateLogin}" method="post" th:object="${userInfo}" class="row g-4">
<div class="col-12">
<label>Username<span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-text"><i class="bi bi-person-fill"></i></div>
<label>
<input type="text" class="form-control" placeholder="Enter Username" th:field="*{username}">
</label>
</div>
</div>
<div class="col-12">
<label>Password<span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-text"><i class="bi bi-lock-fill"></i></div>
<label>
<input type="text" class="form-control" placeholder="Enter Password" th:field="*{password}">
</label>
</div>
</div>
<div class="col-sm-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="inlineFormCheck">
<label class="form-check-label" for="inlineFormCheck">Remember me</label>
</div>
</div>
<div class="col-sm-6">
<a href="#" class="float-end text-primary">Forgot Password?</a>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary px-4 float-end mt-4">login</button>
</div>
</form>
身份验证 Controller
import in.sandeep.campusconvene.model.Users;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class AuthenticationController {
@RequestMapping(path = "/validateLogin", method = RequestMethod.POST)
public String validateLogin(@ModelAttribute Users userInfo){
return userInfo.getUsername ();
}
}
异常堆栈跟踪
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Oct 13 09:15:25 IST 2023
There was an unexpected error (type=Method Not Allowed, status=405).
Method 'POST' is not supported.
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported
at org.springframework.web.servlet.support.WebContentGenerator.checkRequest(WebContentGenerator.java:381)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:164)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
我期待检索 username
和password
来自login.html
并对用户进行身份验证并将其路由到适当的登陆页面。
编辑1:
我已更新代码如下,删除了 AuthenticationController
类并创建了一个 RoutingController
实现 org.springframework.boot.web.servlet.error.ErrorController
的类和org.springframework.web.servlet.config.annotation.WebMvcConfigurer
.
import in.sandeep.campusconvene.model.Users;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@RestController
public class RoutingController implements ErrorController, WebMvcConfigurer {
private static final String MAIN_APPLICATION_PATH = "/";
private static final String LOGIN_VALIDATOR_PATH = "/validateLogin";
private static final String ERROR_PATH = "/error";
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(MAIN_APPLICATION_PATH)
.setViewName("forward:/login.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
@RequestMapping(value = ERROR_PATH)
public String handleError(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
return String.format("<html><body><h2>Error Page</h2><div>Status code: <b>%s</b></div>" +
"<div>Exception Message: <b>%s</b></div><body></html>",
statusCode, exception == null ? "N/A" : exception.getMessage());
}
@RequestMapping(value = LOGIN_VALIDATOR_PATH, method = RequestMethod.POST)
@ResponseStatus(value= HttpStatus.OK)
public String validateLogin(@RequestBody Users users, Model model){
System.out.println ("INSIDE validateLogin.....");
return "LET'S AUTHENTICATE";
}
}
现在,当我尝试提交表单时,这就是我分别在浏览器和控制台上遇到的情况。它甚至没有达到validateLogin
方法。
需要有关如何排序的帮助。
2023-10-14T12:17:15.890+05:30 DEBUG 10130 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : POST "/", parameters={masked}
2023-10-14T12:17:15.891+05:30 DEBUG 10130 --- [nio-8080-exec-3] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ParameterizableViewController [view="forward:/login.html"]
2023-10-14T12:17:15.901+05:30 WARN 10130 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]
2023-10-14T12:17:15.901+05:30 DEBUG 10130 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed 405 METHOD_NOT_ALLOWED
2023-10-14T12:17:15.902+05:30 DEBUG 10130 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for POST "/error", parameters={masked}
2023-10-14T12:17:15.904+05:30 DEBUG 10130 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to in.sandeep.campusconvene.controller.RoutingController#handleError(HttpServletRequest)
2023-10-14T12:17:15.927+05:30 DEBUG 10130 --- [nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8, application/signed-exchange;v=b3;q=0.7] and supported [text/plain, */*, application/json, application/*+json]
2023-10-14T12:17:15.928+05:30 DEBUG 10130 --- [nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing ["<html><body><h2>Error Page</h2><div>Status code: <b>null</b></div><div>Exception Message: <b>N/A</b> (truncated)..."]
2023-10-14T12:17:15.930+05:30 DEBUG 10130 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 405
编辑2:
当前版本为validateLogin
方法
@RequestMapping(value = LOGIN_VALIDATOR_PATH, method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public String validateLogin(HttpServletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
return username + password;
}
我现在在 API 测试器以及控制台上收到了预期的响应,如下所示
2023-10-14T23:24:50.091+05:30 DEBUG 7663 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : POST "/validateLogin", parameters={masked}
2023-10-14T23:24:50.091+05:30 DEBUG 7663 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to in.sandeep.campusconvene.controller.RoutingController#validateLogin(HttpServletRequest)
2023-10-14T23:24:50.093+05:30 DEBUG 7663 --- [nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/plain', given [*/*] and supported [text/plain, */*, application/json, application/*+json]
2023-10-14T23:24:50.093+05:30 DEBUG 7663 --- [nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing ["user1 foo"]
2023-10-14T23:24:50.094+05:30 DEBUG 7663 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
但是当我尝试通过浏览器提交表单时,我仍然遇到 405 METHOD_NOT_ALLOWED
2023-10-14T23:28:30.723+05:30 DEBUG 7663 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : POST "/", parameters={masked}
2023-10-14T23:28:30.724+05:30 DEBUG 7663 --- [io-8080-exec-10] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ParameterizableViewController [view="forward:/login.html"]
2023-10-14T23:28:30.724+05:30 WARN 7663 --- [io-8080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]
2023-10-14T23:28:30.724+05:30 DEBUG 7663 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : Completed 405 METHOD_NOT_ALLOWED
2023-10-14T23:28:30.725+05:30 DEBUG 7663 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for POST "/error", parameters={masked}
2023-10-14T23:28:30.725+05:30 DEBUG 7663 --- [io-8080-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to in.sandeep.campusconvene.controller.RoutingController#handleError(HttpServletRequest)
2023-10-14T23:28:30.727+05:30 DEBUG 7663 --- [io-8080-exec-10] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8, application/signed-exchange;v=b3;q=0.7] and supported [text/plain, */*, application/json, application/*+json]
2023-10-14T23:28:30.728+05:30 DEBUG 7663 --- [io-8080-exec-10] m.m.a.RequestResponseBodyMethodProcessor : Writing ["<html><body><h2>Error Page</h2><div>Status code: <b>null</b></div><div>Exception Message: <b>N/A</b> (truncated)..."]
2023-10-14T23:28:30.729+05:30 DEBUG 7663 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 405
最佳答案
我发现了这个问题。我看到了多个问题。
不要直接访问logic.html,将其保留在 /static
中。那样的话是行不通的。
注意: 默认情况下,Thymeleaf 检查 .html
文件在 /templates
仅目录。
首先,您的 logic.html 应该位于 /templates
中目录而不是 /static
中目录。
另一方面,您试图告诉 thymeleaf 您将在对象 userInfo
中填充/绑定(bind)值在 logic.html 中,但是你从哪里得到这个对象的。您没有创建该对象并将其传递到任何地方。
因此,您需要创建 Users ( userInfo
) 对象并将其从 Controller 传递到该页面。
项目结构:
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>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-thymleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-thymleaf</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我已经修复了您的login.html:
<!--<div th:if="${param.error}">Invalid username and/or password.</div>-->
<form th:action="@{/validateLogin}" method="post" th:object="${userInfo}" class="row g-4">
<div class="col-12">
<label>Username<span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-text"><i class="bi bi-person-fill"></i></div>
<label>
<input type="text" class="form-control" placeholder="Enter Username" th:field="*{username}">
</label>
</div>
</div>
<div class="col-12">
<label>Password<span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-text"><i class="bi bi-lock-fill"></i></div>
<label>
<input type="text" class="form-control" placeholder="Enter Password" th:field="*{password}">
</label>
</div>
</div>
<div class="col-sm-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="inlineFormCheck">
<label class="form-check-label" for="inlineFormCheck">Remember me</label>
</div>
</div>
<div class="col-sm-6">
<a href="#" class="float-end text-primary">Forgot Password?</a>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary px-4 float-end mt-4">login</button>
</div>
</form>
删除不必要的action=#
来自<form>
标签。
我根据您提供的测试信息准备了一个 Users 类。
public class Users {
private String username;
private String password;
// constructor, getter and setters
}
显示/validateLogin
的成功,我也创建了一个success.html。
<body>
<p>User Name: <strong th:text="${userInfo.username}"></strong></p>
<p>Password: <strong th:text="${userInfo.password}"></strong></p>
</body>
将 Controller 更新为如下所示:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class AuthenticationController {
@GetMapping("login-page")
public ModelAndView loginPage(){
ModelAndView view = new ModelAndView();
view.setViewName("login");
view.addObject("userInfo", new Users());
return view;
}
@PostMapping("validateLogin")
public ModelAndView validateLogin(@ModelAttribute Users userInfo){
ModelAndView view = new ModelAndView();
view.setViewName("success");
view.addObject("userInfo", userInfo);
return view;
}
}
注意:您必须创建并传递 Users
没有数据的模型对象/bean 通过 ModelAndView
到相应的login.html
在解析/打开页面之前通过 thymeleaf 文件。
基本上,它期望您通过th:object
使用的bean名称有一个普通的目标模型对象/bean。在请求属性中。
By definition, the
th:object
attribute is used for binding the fields of the form to a model object.
简而言之, thymeleaf 不知道从哪里来 userInfo
将会出现,因为当您声明 th:object="${userInfo}"
时,不存在具有该名称的模型 bean/对象。 .
当您从登录页面传递字段值时,th:object
试图在 spring 容器中查找具有绑定(bind)值名称的 bean,但找不到,因为您没有传递任何内容。
因此,这就是您收到此错误的原因(您可能没有看到该错误)。
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'userInfo' available as request attribute
要解决此问题,您必须首先提供一个 bean。仅此而已,我可以解释。
输出:
http://localhost:8080/login-page
单击“提交”按钮。它将调用http://localhost:8080/validateLogin
这会起作用。
您无需触摸application.properties
对于 thymeleaf ,除非你想覆盖默认行为。
更新:
通过查看您的 Controller 代码 here ,这需要完全修正:
将 Controller 代码更改为:
import in.sandeep.campusconvene.model.Users;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import java.io.IOException;
/**
* The type RoutingController.
*
* @author sandeep
* @version 1.0
*/
@RestController
public class RoutingController implements ErrorController {
private static final String MAIN_APPLICATION_PATH = "/";
private static final String LOGIN_VALIDATOR_PATH = "/validateLogin";
private static final String ERROR_PATH = "/error";
private ModelAndView modelAndView = new ModelAndView();
/**
* Gets Login Page.
*
* @return the Login Page
*/
@RequestMapping(value = MAIN_APPLICATION_PATH, method = RequestMethod.GET)
public ModelAndView getLoginPage() {
modelAndView.setViewName("login");
modelAndView.addObject("userInfo", new Users());
return modelAndView;
}
/**
* Handle Any Errors
*
* @return the Error Page
*/
@RequestMapping(value = ERROR_PATH)
public ModelAndView handleError() {
modelAndView.setViewName("error_page");
return modelAndView;
}
/**
* Validate Login.
*
* @param request the request
* @return the Home Page, if login is successful, else redirect to Login Page
*/
@RequestMapping(value = LOGIN_VALIDATOR_PATH, method = RequestMethod.POST)
@ResponseStatus(value= HttpStatus.OK)
public ModelAndView validateLogin(@ModelAttribute Users userInfo){
modelAndView.setViewName("welcomePage"); // REDIRECT TO USER HOME.
modelAndView.addObject ("userInfo",userInfo);
System.out.println ("ENTERED USERNAME => " + userInfo.getUsername ());
System.out.println ("ENTERED PASSWORD => " + userInfo.getPassword ());
return modelAndView;
}
}
修复:
我已删除所有
.html
来自所有人的消息setViewName
使用的方法。仅使用modelAndView.setViewName()
中的 html 文件的名称。例如:如果你想显示index.html,那么输入modelAndView.setViewName("index");
设置
modelAndView.addObject("userInfo", new Users())
在/
获取端点;
注意:也请创建error_page.html。您的应用程序显示错误,表明它丢失了。
屏幕截图:
欢迎返回页面:
登录页面:
关于java - org.springframework.web.HttpRequestMethodNotSupportedException : Request method 'POST' is not supported,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77285015/