【问题标题】:Passing Custom Objects from thymeleaf View to a Controller将自定义对象从 thymeleaf 视图传递到控制器
【发布时间】:2019-12-11 15:45:15
【问题描述】:

尝试将使用 th:value 的自定义对象从 View 传递到 Controller,但只能通过 th:value 传递 Java 的原始数据类型。有什么办法可以通过th:value发送复杂的对象@

我是 spring 新手,正在尝试一些随机的东西。 这是一个简单的网络应用程序。

我想要做什么:

我有一个创建团队的表格。该表单包括一个团队名称的文本字段和一堆用于选择团队成员的复选框。对于每个选中的复选框,应将相应的成员添加到团队列表中。

我尝试使用 thymeleaf 的 th:value 属性将对象从 View 传递到 Controller。但我只能使用 th:value

传递字符串值 teamCreationForm.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Create your Team</title>
</head>
<body>
    <h1>Create your dream team</h1>

    <form method="post" th:object="${team}">

        <span>Name of the team</span>
        <input type="text" th:field="*{name}">

        <div th:each="player : ${playersList}">
            <input type="checkbox" name="players" th:value="${player}" th:valueType="com.example.kkvamshee.Cricket.Player">
            <span th:text="${player.name}">Player Name</span>
        </div>

        <button type="submit">Submit your team</button>
    </form>
</body>
</html>
创建团队控制器.java
package com.example.kkvamshee.Cricket.web;

import com.example.kkvamshee.Cricket.Player;
import com.example.kkvamshee.Cricket.Team;
import com.example.kkvamshee.Cricket.data.JdbcPlayerRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

@Slf4j
@Controller
@RequestMapping("/create-your-team")
public class CreateTeamController {

    ....

    @GetMapping
    public String showSelectTeamPage(Model model) {
        List<Player> playersList = playerRepo.findAll();

        model.addAttribute("playersList", playersList);
        model.addAttribute("team", new Team());

        return "teamCreationForm";
    }

    .....

}

团队.java
package com.example.kkvamshee.Cricket;

import lombok.Data;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;

@Data
public class Team {
    @NotNull private String name;

    @Size(min = 3, max = 3, message = "You can only have 3 members on the team")
    private List<Player> players;
}

错误日志

Field error in object 'team' on field 'players': rejected value [Player(name=vamshee, age=20, exp=1),Player(name=messi, age=32, exp=18),Player(name=ronaldo, age=34, exp=18)]; codes [typeMismatch.team.players,typeMismatch.players,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [team.players,players]; arguments []; default message [players]]; default message [Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.List' for property 'players'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.kkvamshee.Cricket.Player' for property 'players[0]': no matching editors or conversion strategy found]

在这个错误日志的末尾,“没有找到匹配的编辑器或转换策略”。

我尝试将th:valueType 更改为Integer,它成功地将相应的文本转换为整数值。但是我得到这个转换错误,例如对 Team 对象或任何其他自定义对象做同样的事情。

【问题讨论】:

    标签: java html spring model-view-controller thymeleaf


    【解决方案1】:

    模板引擎必须将&lt;input ... th:value="${player}"&gt;标签转换成HTML(浏览器可以理解的东西),转换后的标签看起来像&lt;input ... value="string returned by player.toString()"&gt;

    因此,视图不知道对象Player。该值只是视图的简单字符串。 Spring 需要一些转换器来将字符串转换为适当的播放器对象。

    这可以通过实现Converter&lt;String, Player&gt;接口然后在我们的应用程序中注册转换器来完成。

    转换器接口的实现:

    package com.example.kkvamshee.cricket.config;
    
    import com.example.kkvamshee.cricket.Player;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.core.convert.converter.Converter;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    @Slf4j
    public class StringToPlayerConverter implements Converter<String, Player> {
    
        @Override
        public Player convert(String source) {
            String pattern = "Player\\(name=([a-zA-z0-9]+), age=([1-9]+), exp=([1-9]+)\\)";
    
            Matcher matcherResult = Pattern.compile(pattern).matcher(source);
    
            log.info("regex result : " + matcherResult.find());
    
            String name = matcherResult.group(1);
            int age = Integer.parseInt(matcherResult.group(2));
            int exp = Integer.parseInt(matcherResult.group(3));
    
            return new Player(name, age, exp);
        }
    }
    
    

    注册上述转换器对象:

    package com.example.kkvamshee.cricket.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.format.FormatterRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToPlayerConverter());
        }
    }
    
    

    有多种方法可以实现这种类型转换。

    更多详情请参考documentation

    【讨论】:

      【解决方案2】:

      Thymeleaf 可以知道您正在使用哪个对象,尤其是在您正确映射并接受它的情况下。看看我用你的代码做的测试。

      请注意表单中是如何引入动作的。

      【讨论】:

      • 感谢您的努力,但就我而言,不知何故,错误仍然保持不变。添加 th:action 属性并没有显着改变。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 2017-03-17
      • 2019-07-06
      相关资源
      最近更新 更多