4

spring 3.2 mvcで複雑なオブジェクトを受け取る方法は?

以下の単純な例では、多対 1 の関係を持つ 2 つのモデル クラスがあります。新しい Employee オブジェクトを追加するとき、html select を使用して部門を選択したいと思います。

新しい従業員を追加するために投稿すると、次のエラーが表示されます。

タイプ java.lang.String のプロパティ値をプロパティ department の必要なタイプ hu.pikk.model.Department に変換できませんでした。ネストされた例外は java.lang.IllegalStateException です: タイプ [java.lang.String] の値をプロパティ部門の必要なタイプ [hu.pikk.model.Department] に変換できません: 一致するエディターまたは変換戦略が見つかりません

エディターまたは変換戦略をどのように実装すればよいですか? 注意すべきベストプラクティスや落とし穴はありますか?

spring mvc のドキュメント、いくつかの記事、stackoverflow の質問を読んだことがありますが、正直なところ、それらは少し混乱し、多くの場合短すぎて手に負えません。

モデル:

@Entity
public class Employee {
    @Id
    @GeneratedValue
    private int employeeId;
    @NotEmpty
    private String name;

    @ManyToOne
    @JoinColumn(name="department_id")
    private Department department;
    //getters,setters
}

@Entity
public class Department {
    @Id
    @GeneratedValue
    private int departmentId;
    @Column
    private String departmentName;

    @OneToMany
    @JoinColumn(name = "department_id")
    private List<Employee> employees;
    //getters,setters
}

私のコントローラークラスでは:

@RequestMapping(value = "/add", method = RequestMethod.GET)
private String addNew(ModelMap model) {
    Employee newEmployee = new Employee();
    model.addAttribute("employee", newEmployee);
    model.addAttribute("departments", departmentDao.getAllDepartments());
    return "employee/add";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
private String addNewHandle(@Valid Employee employee, BindingResult bindingResult, ModelMap model, RedirectAttributes redirectAttributes) {
    if (bindingResult.hasErrors()) {
        model.addAttribute("departments", departmentDao.getAllDepartments());
        return "employee/add";
    }
    employeeDao.persist(employee);
    redirectAttributes.addFlashAttribute("added_employee", employee.getName());
    redirectAttributes.addFlashAttribute("message", "employee added...");
    return "redirect:list";     
}

add.jsp:

<f:form commandName="employee" action="${pageContext.request.contextPath}/employee/add" method="POST">
    <table>
        <tr>
            <td><f:label path="name">Name:</f:label></td>
            <td><f:input path="name" /></td>
            <td><f:errors path="name" class="error" /></td>
        </tr>
        <tr>
            <td><f:label path="department">Department:</f:label></td>
        <td><f:select path="department">
                <f:option value="${null}" label="NO DEPARTMENT" />
                <f:options items="${departments}" itemLabel="departmentName" itemValue="departmentId" />
            </f:select></td>
            <td><f:errors path="department" class="error" /></td>
        </tr>
    </table>
    <input type="submit" value="Add Employee">
</f:form>
4

2 に答える 2

3

問題は、コントローラが POST を受信したときに、id 文字列を Department オブジェクトに変換する方法がわからないことです。この問題を解決するには、基本的に 3 つの方法があることがわかりました。

  1. スプリングフォームjstlを使用するのではなく、カスタム名を持つ単純なhtml選択を使用し、コントローラーで@RequestParamでそれを読み取り、データベースにアクセスしてデータを入力します。
  2. Converter インターフェースを実装し、それを Bean として登録します。
  3. PropertyEditor インターフェイスの実装。これは、PropertyEditorSupport クラスを拡張することで簡単に実行できます。

私は3番目のオプションを使用していました。(後で時間ができたら、最初の2つのオプションを検討してこの回答を編集します。)

2. Converter<String, Department> インターフェースの実装

@Component 
public class DepartmentConverter implements Converter<String,Department>{
    @Autowired
    private DepartmentDao departmentDao;
    @Override
    public Department convert(String id){
        Department department = null;
        try {
            Integer id = Integer.parseInt(text);
            department = departmentDao.getById(id);
            System.out.println("Department name:" + department.getDepartmentName());
        } catch (NumberFormatException ex) {
            System.out.println("Department will be null");
        }
        return department;
    }
}

Spring Bean 構成ファイル内:

<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
  class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="package.DepartmentConverter"/>
        </list>
    </property>
</bean>

3. PropertyEditorSupport クラスの拡張

public class SimpleDepartmentEditor extends PropertyEditorSupport {

    private DepartmentDao departmentDao;

    public SimpleDepartmentEditor(DepartmentDao departmentDao){
        this.departmentDao = departmentDao;
    }
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        Department department = null;
        try {
            Integer id = Integer.parseInt(text);
            department = departmentDao.getById(id);
            System.out.println("Department name:" + department.getDepartmentName());
        } catch (NumberFormatException ex) {
            System.out.println("Department will be null");
        }
        setValue(department);
    }
}

コントローラー内に @InitBinder を追加する必要がありました。

    @InitBinder
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
        binder.registerCustomEditor(Department.class, new SimpleDepartmentEditor(departmentDao));
    }
于 2013-11-19T01:02:32.310 に答える
0

私の意見では、ここで次の状況に遭遇しました。EmployeeSpringが受信したエンティティをデシリアライズしようとして、文字列型のaddNewHandleプロパティdepartmentが見つかりましたが、ターゲット エンティティにDepartment型がある場合、そのような種類の変換用の変換登録がないため、失敗します。したがって、この問題を解決するには、文字列を取得して返し、登録する独自のコンバーター ( Converter ) を実装するか、 Jackson JsonDeserializerをオーバーライドしてプロパティに注釈を付けることで、独自の JSON デシリアライズ戦略を実装できます。お役に立てれば。DepartmentconversionServicedepartment@JsonDeserialize(using=<your Jacson custom deserializer>.class)

于 2013-11-13T16:21:04.003 に答える