简体   繁体   English

发布请求不起作用:无法解析请求参数是 Spring controller class

[英]Post request does not work: cannot resolve request parameters is Spring controller class

I am building a Spring application and I have a controller that has two methods for Get and Post request.我正在构建一个 Spring 应用程序,我有一个 controller 有两种获取和发布请求的方法。 The task of the controller is to show a html form and to get the params that the user has entered. controller 的任务是显示 html 表单并获取用户输入的参数。 The Get request works fine but Post request does not resolves the params from the html form. Get 请求工作正常,但 Post 请求无法解析 html 表单中的参数。

Here is my htmml file with thymeleaf:这是我的带有 thymeleaf 的 htmml 文件:

    <html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="text/html">
    <meta name="author" content="">
    <title>Budget Forecast Report</title>
    <link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h2 class="form-signin-heading" align="center">Forecast Report</h2>
        <div th:if="${param.error}" class="alert alert-danger">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}" class="alert alert-success">
            You have been logged out.
        </div>
        <form action="#" th:action="@{/forecast/saveInput}" class="form-input" method="post" align="center">
            <label for="username" class="sr-only">Username</label>
            <input type="text"  id="username" name="username" class="form-control"
                   placeholder="Username" required autofocus>
            <p>
                <label for="password" class="sr-only">Password</label>
                <input type="password" id="password" name="password" class="form-control"
                       placeholder="Password" required>
            </p>
            <p>
                <label for="startDate" class="sr-only">Start date</label>
                <input type="text" id="startDate" name="startDate" class="form-control"
                       placeholder="StartDate" required>
            </p>
            <p>
                <label for="endDate" class="sr-only">End date</label>
                <input type="text" id="endDate" name="endDate" class="form-control"
                       placeholder="EndDate" required>
            </p>
            <button class="btn btn-lg btn-primary btn-block" type="submit">Submit</button>
        </form>
    </div>
</body>
</html>

Here is my Controller:这是我的 Controller:

@Controller
public class InputFormController {

    private ForecastReportService forecastReportService;

    @Autowired
    public InputFormController(ForecastReportService forecastReportService) {
        this.forecastReportService = forecastReportService;
    }

    @GetMapping(value = "/")
    @ResponseBody
    public ModelAndView showForm(Model model) {
        System.out.println("here showForm");
        System.out.println("here showForm");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("index");
        model.addAttribute("inputBean", new InputBean());
        modelAndView.addAllObjects(model.asMap());
        return modelAndView;
    }

    @RequestMapping(method = RequestMethod.POST, value = "/saveInput", consumes = "application/json", produces = "application/json")
    public ModelAndView processInput(
//            @RequestParam("username") String username,
//            @RequestParam("password") String password,
//            @RequestParam("startDate") String startDate,
//            @RequestParam("endDate") String endDate,
                               ModelAndView modelAndView) {
        System.out.println("here processInput");
        System.out.println("here processInput");
        ModelMap modelMap = modelAndView.getModelMap();
        String username = (String) modelMap.getAttribute("username");
        String password = (String) modelMap.getAttribute("password");
        String startDate = (String) modelMap.getAttribute("startDate");
        String endDate = (String) modelMap.getAttribute("endDate");
        modelAndView.setViewName("forecast-success");
        modelAndView.addAllObjects(modelMap);
        try {
            forecastReportService.execute(new InputBean(username, password, startDate, endDate));
        } catch(IOException ioe)  {
            ioe.printStackTrace();
        } catch (ParseException pe) {
            pe.printStackTrace();
        }
        return modelAndView;
    }
}

If I have only @RequestParam arguments i the code does not enter the post method at all and I get exception that says the four parameters: username, password and the two dates are not resolved successfully:如果我只有@RequestParam arguments i,则代码根本没有进入 post 方法,并且出现异常,显示四个参数:用户名、密码和两个日期未成功解析:

"org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'username' for method parameter type String is not present
\r\n\tat org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValueInternal(RequestParamMethodArgumentResolver.java:218)
\r\n\tat org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)
\r\n\tat org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:114)
\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)
\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\r\n\tat 
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat
 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\r\n\tat
 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\r\n\tat
 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat
 org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n\tat 
 javax.servlet.http.HttpServlet.service(HttpServlet.java:681)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
 \r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat 
 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat 
 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat 
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat 
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat 
 org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat 
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat 
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat 
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat 
 org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal
 (WebMvcMetricsFilter.java:96)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 \r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat
 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
 \r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat 
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat 
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat 
 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat
 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat 
 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\r\n\tat 
 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat 
 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat 
 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat
 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat
 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat 
 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat
 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)\r\n\tat 
 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)\r\n\tat
 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat 
 org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat 
 org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat 
 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\n",
    "message": "Required request parameter 'username' for method parameter type String is not present",

If I comment the four params and put ModelAndView as input argument the code enters the method but the model map is with null values.如果我注释四个参数并将 ModelAndView 作为输入参数,则代码进入方法,但 model map 与 null 值。 I also have InputBean class that is a wrapper for these four strings:我还有 InputBean class ,它是这四个字符串的包装器:

    @Component
public class InputBean {

    private String username;

    private String password;

    private String startDate;

    private String endDate;

    public InputBean() {

    }


    public InputBean(String username, String password, String startDate, String endDate) {
        this.username = username;
        this.password = password;
        this.startDate = startDate;
        this.endDate = endDate;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getStartDate() {
        return startDate;
    }

    public void setStartDate(String startDate) {
        this.startDate = startDate;
    }

    public String getEndDate() {
        return endDate;
    }

    public void setEndDate(String endDate) {
        this.endDate = endDate;
    }
}

So I tried to do the following too: @PostMapping(value = "/saveInput") public String processInput(@ModelAttribute("inputBean") InputBean inputBean) {}所以我也尝试执行以下操作: @PostMapping(value = "/saveInput") public String processInput(@ModelAttribute("inputBean") InputBean inputBean) {}

but this did not worked because Intellij complained that th:field="*{username}" is an error and throws an exception for unsuccessful resolving so I removed it although in internet everywhere people use this syntax.但这并没有奏效,因为 Intellij 抱怨th:field="*{username}"是一个错误并抛出一个解析不成功的异常,所以我删除了它,尽管在互联网上到处都有人使用这种语法。

Could you help me please.请问你能帮帮我吗。 Does someone have an idea wehere is the problem?有人知道问题出在哪里吗?

Thank you in advance!先感谢您!

I fixed this by implementing the post request the following way:我通过以下方式实现发布请求来解决此问题:

@PostMapping(value = "/index")
    public ModelAndView processUserInput(@ModelAttribute("userInput") UserInput userInput) {
        try {
            validateUserInput(userInput);
            service.execute(userInput);
        } catch(IOException ioe)  {
            ioe.printStackTrace();
        } catch (ParseException pe) {
            pe.printStackTrace();
        } catch (InvalidInputException e) {
            e.printStackTrace();
        }
        ModelAndView modelAndView = new ModelAndView();
        ModelMap modelMap = new ModelMap();
        modelMap.put("username", userInput.getUsername());
        modelMap.put("password", userInput.getPassword());
        modelMap.put("startDate", userInput.getStartDate());
        modelMap.put("endDate", userInput.getEndDate());
        modelAndView.addAllObjects(modelMap);
        modelAndView.setViewName("forecast-success");

        return modelAndView;
    }

The UserInput (I renamed InputBean to UserInput ) class should be a component, it is not true it shouldn't. UserInput (我将InputBean重命名为UserInput ) class 应该是一个组件,它不应该是不正确的。 After I set the @Component again it was resolved successfully.在我再次设置@Component后,它已成功解决。

Respectively, I had to change the GET method too:分别地,我也不得不改变 GET 方法:

@GetMapping(value = "/index")
    public String showForm(Model model) {
        System.out.println("Invoking the user input form");
        model.addAttribute("userInput", new UserInput());
        return "/index";
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM