Thymeleaf @Valid LazyInitializationException

Thymeleaf @Valid LazyInitializationException

我在 thymeleaf 中遇到验证问题。我的案例是用 Position 和 Role-s 保存 Employee。当验证有错误时,这两个 "fields" 会导致 LazyInitializationException。如果验证通过,员工将被保存到数据库,一切正常。请给我一些建议,我做错了什么或者我该如何解决。

请在下面查找我的代码:

雇员控制器:

@Controller
public class EmployeeController extends BaseCrudController {

    // (........)

    @RequestMapping(value = urlFragment + "/create", method = RequestMethod.GET)
    public String createEmployee(Model model) {
        prepareEmployeeForm(model);
        return "crud/employee/create";
    }

    @RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
    public String processNewEmployee(Model model, @ModelAttribute("employeeForm") @Valid EmployeeForm employeeForm, BindingResult result) {

        if (!result.hasErrors()) {
            User user = employeeFormService.getUserFromEmployeeForm(employeeForm);
            try {
                userService.merge(user);
                model.addAttribute("success", true);
                prepareEmployeeForm(model);
            } catch (Exception e) {
                model.addAttribute("error", true);
            }
        } else {
            initCollections(employeeForm, model);
        }

        return "crud/employee/create";
    }

    private void initCollections(EmployeeForm employeeForm, Model model)
    {
        employeeForm.setAllAvailableRoles(roleRepository.findAll());
        employeeForm.setAllAvailablePositions(positionRepository.findByEnabledTrueOrderByNameAsc());
        model.addAttribute("employeeForm", employeeForm);
    }

    private void prepareEmployeeForm(Model model) {
        EmployeeForm employee = new EmployeeForm();

        employee.setAllAvailablePositions(positionRepository.findByEnabledTrueOrderByNameAsc());
        employee.setAllAvailableRoles(roleRepository.findAll());

        model.addAttribute("employeeForm", employee);
    }
}

雇员表格:

public class EmployeeForm extends BaseForm {

    @Length(min = 2, max = 45)
    private String firstName = "";

    // (........)

    private Position position;

    private Collection<Role> roles;

    private Collection<Position> allAvailablePositions;

    private Collection<Role> allAvailableRoles;

    public EmployeeForm() {
    }

    public Position getPosition() {
        return position;
    }

    public void setPosition(Position position) {
        this.position = position;
    }

    public Collection<Role> getRoles() {
        return roles;
    }

    public void setRoles(Collection<Role> roles) {
        this.roles = roles;
    }

    public Collection<Position> getAllAvailablePositions() {
        return allAvailablePositions;
    }

    public void setAllAvailablePositions(Collection<Position> allAvailablePositions) {
        this.allAvailablePositions = allAvailablePositions;
    }

    public Collection<Role> getAllAvailableRoles() {
        return allAvailableRoles;
    }

    public void setAllAvailableRoles(Collection<Role> allAvailableRoles) {
        this.allAvailableRoles = allAvailableRoles;
    }
}

employeeForm.html

    <form action="#" th:action="@{/panel/employee/create}" th:object="${employeeForm}" method="post">

                <!--(......)-->

                <div class="row">
                    <div class="col-md-6">
                        <label th:text="#{position}">Position</label>
<!--(Line 57 cause LazyInitializationException)--><select th:field="*{position}" class="form-control">
                            <option th:each="positionQ : *{allAvailablePositions}"
                                    th:value="${{positionQ}}"
                                    th:text="${positionQ.name}">Position name
                            </option>
                        </select>
                    </div>
                    <div class="col-md-6">
                        <label th:text="#{permissions}">Permissions</label>
                        <th:block th:each="role : *{allAvailableRoles}">
                            <p>
                                <input type="checkbox" th:id="${{role}}" th:value="${{role}}" th:field="*{roles}"/>
                                <label th:for="${{role}}"
                                       th:text="#{${role.name}}">Role name</label>
                            </p>
                        </th:block>
                    </div>
                </div>
           </form>

跟踪:

HTTP Status 500 - Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringSelectFieldAttrProcessor' (crud/employee/employeeForm:57)

根本原因:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringSelectFieldAttrProcessor' (crud/employee/employeeForm:57)

根本原因

org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringSelectFieldAttrProcessor' (crud/employee/employeeForm:57)

根本原因

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

如果有任何帮助,我将非常高兴。

问题是您的休眠会话已关闭。模式 open-session-in-view 解决了这个问题。您可以使用默认的 spring-boot 或查看 fuwesta-sampe.

中的配置

更简洁的方法是确保在关闭会话之前已完成数据加载。这意味着服务层应导航到每个实体或使用预先获取。