web-dev-qa-db-ja.com

オブジェクト付きタグの選択-ThymeleafおよびSpringMVC

この例のコードを変更しようとしています thymeleafexamples-stsm なので、クラスタイプの列挙型を変更しました:

Type.Java

public class Type { 

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

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

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

したがって、Seedスターターを追加できません。

私の出力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>

エラーは

タイプJava.lang.Stringのプロパティ値をプロパティタイプに必要なタイプthymeleafexamples.stsm.business.entities.Typeに変換できませんでした。ネストされた例外はJava.lang.IllegalStateExceptionです:タイプ[Java.lang.String]の値をプロパティタイプに必要なタイプ[thymeleafexamples.stsm.business.entities.Type]に変換できません:一致するエディターまたは変換戦略が見つかりません

タイプに正しくマッピングするにはどうすればよいですか?あなたが私を助けてくれることを願っています。ありがとうございました。

7
JohnPortella

そのエラーメッセージは基本的に、Springが文字列_thymeleafexamples.stsm.business.entities.Type@2c08cec0_をTypeのインスタンスに変換する方法を知らないことを示しています。これはコードのバグです。そうしようとしても意味がないからです。

ObjectのtoString()値をフォームのドロップダウン識別子として使用することは想定されていません。ユーザーが選択したタイプを識別するためのコードには、(はるかに)優れた戦略が必要です。

一般的なアプローチは、id属性を使用することです。

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

フォームが送信されたら、コントローラーのID名に基づいてTypeのインスタンスを廃止する必要があります。

12
gerrytan

私はこの質問が古いことを知っていますが、私はそれを簡単に見つけることができなかったので、以下の答えは誰かを助けるかもしれません。

この問題を解決するために、Thymeleafはフォーマッターを使用してオブジェクトと文字列を変換します。

  • 表示フェーズ(GET)で、フォーマッターサービスはオブジェクトを文字列に変換します。
  • 送信フェーズ(POST)で、フォーマッターサービスは文字列をに変換し直します

    オブジェクト。

最初に、タグで使用するクラスの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
    }
}

これは、2つのメソッドを持つ非常に単純なクラスです。

  • print:オブジェクトを文字列に変換します。
  • parse:文字列をオブジェクトに変換します。

さて、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);
    }
}

これで、ソリューションを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}"は、デフォルトで登録済みのフォーマッターサービスを適用しています。タイプを文字列に変換します(ここでは、文字列はタイプIDになります)
  • th:value = "$ {{type}}"も型を文字列に変換しています。
  • 送信時に、SpringはFormatterサービスを使用してIDをオブジェクトに変換し直します。

最後に、デフォルトの選択を防ぎ、ユーザーに説明するために、「----- SelectType -----」のようなヘッダーをドロップダウンリストに追加したい場合があります。この場合、変換エラーが発生しない限り、th:value = "NULL"を設定する必要があります。

14
Ayman Al-Absi