选择带有对象的标签 - Thymeleaf 和 Spring MVC

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25234357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:58:04  来源:igfitidea点击:

Select Tag with Object - Thymeleaf and Spring MVC

springspring-mvcthymeleaf

提问by JohnPortella

I'm trying to change the code of this example thymeleafexamples-stsm, so I changed enum type for class type:

我正在尝试更改此示例thymeleafexamples-stsm的代码,因此我更改了类类型的枚举类型:

Type.java

类型.java

public class Type { 

    private Integer id; 
    private String type; 
   ...getters and setters 
}

SeedStarterMngController.java

SeedStarterMngController.java

@ModelAttribute("allTypes") 
    public List<Type> populateTypes() { 
        Type type1 = new Type(); 
        type1.setId(1); 
        type1.setType("OUTDOOR"); 

        Type type2 = new Type(); 
        type2.setId(2); 
        type2.setType("INDOOR"); 

        List<Type> tipos = new ArrayList<Type>(); 
        tipos.add(type1); 
        tipos.add(type2); 
        return tipos; 
    } 

seedstartermng.html

种子启动器.html

<select th:field="*{type}">
    <option th:each="type : ${allTypes}" th:value="${type}" th:text="${type.type}">Wireframe</option>
</select>

So, I can't Add Seed Starter.

所以,我不能添加种子启动器。

My Output html is

我的输出 html 是

<select id="type" name="type">
    <option value="thymeleafexamples.stsm.business.entities.Type@2c08cec0">OUTDOOR</option>
    <option value="thymeleafexamples.stsm.business.entities.Type@26cf024">INDOOR</option>
</select>

and the error is

错误是

Failed to convert property value of type java.lang.String to required type thymeleafexamples.stsm.business.entities.Type for property type; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [thymeleafexamples.stsm.business.entities.Type] for property type: no matching editors or conversion strategy found

无法将 java.lang.String 类型的属性值转换为属性类型所需的类型 thymeleafexamples.stsm.business.entities.Type;嵌套异常是 java.lang.IllegalStateException:无法将类型 [java.lang.String] 的值转换为属性类型所需的类型 [thymeleafexamples.stsm.business.entities.Type]:找不到匹配的编辑器或转换策略

How I can do to be mapped to type correctly? I hope you can help me. Thank you.

我该怎么做才能正确映射到类型?我希望你能帮助我。谢谢你。

回答by Ayman Al-Absi

I know this question is old but below answer may help someone as I could not find it easily.

我知道这个问题很老,但下面的答案可能对某人有所帮助,因为我找不到它。

To solve this issue, Thymeleaf uses Formatters to convert between Object and String.

为了解决这个问题,Thymeleaf 使用 Formatters 在 Object 和 String 之间进行转换。

  • In display phase (GET), Formatter Service will convert Object to String.
  • In submitting phase (POST), Formatter Service will convert String back to

    object.

  • 在显示阶段(GET),Formatter Service 会将 Object 转换为 String。
  • 在提交阶段 (POST),Formatter Service 会将 String 转换回

    目的。

First implement Formatter service for your Class to be used in tag:

首先为要在标签中使用的 Class 实现 Formatter 服务:

@Service
public class TypeFormatter implements Formatter<Type> {

    @Autowired
    TypeService typeService;//Service -> DB

    @Override
    public String print(Type object, Locale locale) {
        return (object != null ? object.getId().toString() : "");
    }

    @Override
    public Type parse(String text, Locale locale) throws ParseException {
        Integer id = Integer.valueOf(text);
        return this.typeService.get(id);//return Type object form DB
    }
}

It is very simple class with two methods:

这是一个非常简单的类,有两种方法:

  • print: converts object to string.
  • parse: converts string to object.
  • 打印:将对象转换为字符串。
  • parse: 将字符串转换为对象。

Now, we've to tell Spring-Thymeleaf abbout our formatter or we may call it converter. To do that we've to register this formatter in our WebConfig (Configuration class whic extends WebMvcConfigurerAdapter):

现在,我们必须告诉 Spring-Thymeleaf 关于我们的格式化程序,或者我们可以称之为转换器。为此,我们必须在我们的 WebConfig(扩展 WebMvcConfigurerAdapter 的配置类)中注册此格式化程序:

@Configuration
@EnableWebMvc
@ComponentScan(value = { "your package" })
public class WebConfig extends WebMvcConfigurerAdapter {

....
    //Formatters

    @Autowired //Without autowire, this solution may not work
    private TypeFormatter typeFormatter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(typeFormatter);
    }
}

Now our solution is ready to be implemented in html file but how to tell Thymeleaf to apply conversion? Answer is by using th:field="*{type}"attribute and using Double-bracket syntax th:value="${{type}}":

现在我们的解决方案已准备好在 html 文件中实现,但如何告诉 Thymeleaf 应用转换?答案是使用th:field="*{type}"属性并使用双括号语法th:value="${{type}}"

<select th:field="*{type}">
    <option th:value="NULL" th:text="---Select Type---"></option>
    <option th:each="type : ${allTypes}" th:value="${{type}}" th:text="${type.type}">Wireframe</option>
</select>
  • th:field="*{type}"is applying registered Formatter service by default. It will convert type to String (here the string will be Type Id)
  • th:value="${{type}}"is converting type to string as well.
  • In submit, Spring will use the Formatter service to convert Id back to object.
  • th:field="*{type}"默认应用注册的 Formatter 服务。它将类型转换为字符串(这里的字符串将是类型 ID)
  • th:value="${{type}}"也将类型转换为字符串。
  • 在提交时,Spring 将使用 Formatter 服务将 Id 转换回对象。

Last thing to tell, sometimes we want to add a header to the dropdown list like "-----Select Type-----" in order to prevent default selection as well as explain to user. In this case you must set th:value="NULL"unless you'll get conversion error.

最后要说的是,有时我们想在下拉列表中添加一个标题,例如“-----选择类型-----”,以防止默认选择以及向用户解释。在这种情况下,您必须设置th:value="NULL"除非您会收到转换错误。

回答by gerrytan

That error message basically says Spring don't know how to convert the string thymeleafexamples.stsm.business.entities.Type@2c08cec0into an instance of Type. This is a bug on your code because it doesn't make any sense trying to do so.

该错误消息基本上是说 Spring 不知道如何将字符串thymeleafexamples.stsm.business.entities.Type@2c08cec0转换为 Type 的实例。这是您代码中的一个错误,因为尝试这样做没有任何意义。

You're not supposed to use the toString()value of Object as a form dropdown identifier. You need to have a (much) better strategy for the code to identify the Type selected by user.

您不应该使用toString()Object的值作为表单下拉标识符。您需要有一个(更好)的代码策略来识别用户选择的类型。

Common approach is to use the idattribute:

常用的方法是使用id属性:

<option th:each="type : ${allTypes}" th:value="${type.id}" th:text="${type.type}">Wireframe</option>

When the form is submitted, you then need to retireve an instance of Type based on its id name on your controller

提交表单后,您需要根据控制器上的 id 名称停用 Type 的实例