【问题标题】:Cannot read strings from form无法从表单中读取字符串
【发布时间】:2018-05-12 03:09:36
【问题描述】:

我正在编写允许用户更改密码的表单。我没有将User 对象传递给form,而是传递了3 个空字符串。一切都很好,但是当我通过 Submit 时,字符串返回为空。有没有什么方法可以从 Spring 中的表单中获取字符串,而无需将它们打包成带有 3 个字符串字段的 changePasswordForm 之类的对象?

我的代码:

更改密码视图:

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
    <div class="container">
        <div th:replace="/fragments/header"> </div>

        <div class="jumbotron">
            <h1 class="display-4">Changing password</h1>
            <form action="#" th:action="@{/user/changePassword/} + ${user.id}" method="post">
                <div class="form-group">
                    <label>Current password</label>
                    <input type="password" th:field="${currentPassword}" class="form-control" placeholder="Your current password"/>
                </div>
                <div class="form-group">
                    <label>New password</label>
                    <input type="password" th:field="${newPassword}" class="form-control" placeholder="Your new password"/>
                </div>
                <div class="form-group">
                    <label>New password confirmation</label>
                    <input type="password" th:field="${newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
                </div>
                <button class="btn btn-primary">Submit</button>
                <button class="btn btn-secondary">Reset</button>
            </form>
        </div>

        <div th:replace="/fragments/footer"> </div>
    </div>
</body>
</html>

用户控制器:

package io.gromo13.personalBlog.controller;

import io.gromo13.personalBlog.service.RoleService;
import io.gromo13.personalBlog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import io.gromo13.personalBlog.model.User;
import javax.validation.Valid;

@Controller

@RequestMapping("/user")
@SessionAttributes("user")
public class UserController {

@Autowired
UserService userService;

@Autowired
RoleService roleService;

public void setUserService(UserService userService) {
    this.userService = userService;
}

public void setRoleService(RoleService roleService) {
    this.roleService = roleService;
}

@GetMapping("/{id}")
public String profile(@PathVariable Long id, Model model) {
    User user = userService.get(id);
    model.addAttribute("user", user);
    return "/user/profile";
}

@GetMapping("/register")
public String register(Model model) {
    model.addAttribute("roles", roleService.getAll());
    model.addAttribute("user", new User());
    return "/user/register";
}

@PostMapping("/register")
public String registerSubmit(@Valid User user, BindingResult bindingResult) {
    if (bindingResult.hasErrors())
        return "/user/register";
    userService.add(user);

    return "redirect:/admin/users";
}

@GetMapping("/edit/{id}")
public String edit(@PathVariable Long id, Model model) {
    User user = userService.get(id);
    model.addAttribute("user", user);
    model.addAttribute("password", "");

    return "/user/edit";
}

@PostMapping("/edit/{id}")
public String editSubmit(@ModelAttribute("user") @Valid User user, BindingResult bindingResult) {
    if (bindingResult.hasErrors())
        return "/user/edit";
    userService.edit(user);

    return "redirect:/admin/users";
}

@GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
    model.addAttribute("currentPassword", "");
    model.addAttribute("newPassword", "");
    model.addAttribute("newPasswordConfirmation", "");

    return "/user/changePassword";
}

@PostMapping("/changePassword/{id}")
public String changePasswordSubmit(@PathVariable Long id,
                                   @ModelAttribute("currentPassword") String currentPassword,
                                   @ModelAttribute("newPassword") String newPassword,
                                   @ModelAttribute("newPasswordConfirmation") String newPasswordConfirmation,
                                   BindingResult bindingResult) {
    if (bindingResult.hasErrors())
        return "/user/changePassword";

    User user = userService.get(id);
    if (newPassword.equals(newPasswordConfirmation) && user.getPassword().equals(currentPassword)) {
        user.setPassword(newPassword);
        userService.edit(user);
    }

    return "redirect:/admin/users";
}

@GetMapping("/delete/{id}")
public String delete(@PathVariable Long id) {
    userService.delete(id);

    return "redirect:/admin/users";
}

}

实际上我的整个页面工作正常,我只是无法读取传递给表单的单个字符串而不包装到对象。

我发现的每个关于 Spring 表单的教程都在传递像 xFormUser 这样的对象来查看和阅读它们。它也适用于我,但我认为只为单一形式创建特殊对象没有意义。

【问题讨论】:

  • 您可以将字符串作为request.getParameter("paramName") 并在控制器方法中添加参数HttpServletRequest request

标签: java html spring spring-mvc thymeleaf


【解决方案1】:

如果你想使用验证,你需要创建一个 POJO 并添加约束。

1)

public class ChangePass {

    @Size(min = 8,max = 13, message = "error current password between {min} to {max}")
    private String currentPassword;

    @Size(min = 8,max = 13,message = "error new password between {min} to {max}")
    private String newPassword;

    //validate later
    private String newPasswordConfirmation;
}

2)

那么你需要在视图中添加这个 POJO 的实例。

 @GetMapping("/changePassword/{id}")
    public String changePasword(Model model) {
        model.addAttribute("userPass", new ChangePass()); // adding model

        return "/user/changePassword";
    }

3)

在您的表单中,您需要修复 2 件事添加

th:object="${userPass}" 和添加th:field="*{currentPassword}" 而不是th:field="${currenctPassword}" 区别是" * "

<form th:action="@{/user/changePassword/} + ${user.id}" method="post" th:object="${userPass}">
            <div class="form-group">
                <label>Current password</label>
                <input type="password" th:field="*{currentPassword}" class="form-control" placeholder="Your current password"/>
            </div>
            <div class="form-group">
                <label>New password</label>
                <input type="password" th:field="*{newPassword}" class="form-control" placeholder="Your new password"/>
            </div>
            <div class="form-group">
                <label>New password confirmation</label>
                <input type="password" th:field="*{newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
            </div>
            <button class="btn btn-primary">Submit</button>
            <button class="btn btn-secondary">Reset</button>
        </form>

4)

Post 方法应该是……

@PostMapping("/changePassword/{id}")
    public String changePassword(@PathVariable Long id,
                                 @ModelAttribute("userPass"), 
                                 @Valid ChangePass change,
                                 BindingResult errors){

        if(errors.hasErrors()){
            return "/user/changePassword";
        }

        //your next code 

【讨论】:

    【解决方案2】:

    th:field 更改为name 标签

    <!DOCTYPE html>
    <html lang="en"
          xmlns:th="http://www.thymeleaf.org">
    <head th:replace="/fragments/head"></head>
    <body>
        <div class="container">
            <div th:replace="/fragments/header"> </div>
    
            <div class="jumbotron">
                <h1 class="display-4">Changing password</h1>
                <form action="#" th:action="@{/user/changePassword/} + ${user.id}" method="post">
                    <div class="form-group">
                        <label>Current password</label>
                        <input type="password" name="currentPassword" class="form-control" placeholder="Your current password"/>
                    </div>
                    <div class="form-group">
                        <label>New password</label>
                        <input type="password" name="newPassword" class="form-control" placeholder="Your new password"/>
                    </div>
                    <div class="form-group">
                        <label>New password confirmation</label>
                        <input type="password" name="newPasswordConfirmation" class="form-control" placeholder="Confirm your new password"/>
                    </div>
                    <button class="btn btn-primary">Submit</button>
                    <button class="btn btn-secondary">Reset</button>
                </form>
            </div>
            <div th:replace="/fragments/footer"> </div>
        </div>
    </body>
    </html>
    

    从控制器中删除它

    @GetMapping("/changePassword/{id}")
    public String changePasword(Model model) {
        model.addAttribute("currentPassword", ""); //remove
        model.addAttribute("newPassword", ""); //remove
        model.addAttribute("newPasswordConfirmation", ""); //remove
    
        return "/user/changePassword";
    }
    

    这里将 ModelAttribute 更改为 RequestParam Annotation

    @PostMapping("/changePassword/{id}")
    public String changePasswordSubmit(@PathVariable Long id,
                                       @RequestParam("currentPassword") String currentPassword,
                                       @RequestParam("newPassword") String newPassword,
                                       @RequestParam("newPasswordConfirmation") String newPasswordConfirmation) {
    

    这句话 bindingResult 不起作用,因为这使用验证注释验证 POJO

    //if (bindingResult.hasErrors())
    //    return "/user/changePassword";
    

    对于这种情况,最好的方法是使用这些字段创建一个新的 POJO,然后验证它们。

    【讨论】:

    • 谢谢。我看到我必须添加 POJO 只是为了验证。这是做到这一点的唯一方法。你能解释一下,为什么 th:object 不起作用?是否使用 setter 和 getter 来设置值,这就是它无法设置字符串值的原因?
    • 我该怎么做?
    • 检查新答案
    猜你喜欢
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 2016-01-27
    • 1970-01-01
    相关资源
    最近更新 更多