【问题标题】:Spring Data MVC + Thymeleaf: update entitySpring Data MVC + Thymeleaf:更新实体
【发布时间】:2023-03-07 12:12:01
【问题描述】:

我正在尝试使用百里香形式更新实体的某些属性。

我制作了一个向模型添加 DTO 的控制器。这样我就不必将不必要的员工属性发送到视图。

此设置在尝试编辑 Employee 的属性时出现错误(单击表单上的编辑按钮):

There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='employeeDTO'. Error count: 2

显然我的设置不起作用,因为我的 DTO 中有 Date 和 List 对象。

我该如何解决这个问题?我需要写一些转换器吗?我该怎么做?

难道没有更简单的方法来编辑实体的属性吗?我的意思是比@SessionAttributes("employee")、DTO's、Mapper、Converter 更简单的方法......这看起来很简单的功能,但我无法让它工作,我感觉我正在添加很多东西(DTO's、mapper、转换器?,...)只是为了能够编辑实体的属性。

实体:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private Date birthDate;
    @OneToMany(fetch = FetchType.EAGER)
    private List<Car> carHistory = new ArrayList<Car>();

    // constructors

    // getters and setters
}

@Entity
public class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Enumerated(EnumType.STRING)
    private CarStatus status;
    private String plate;

    // constructors
    // getters & setters

    public enum CarStatus {
        FREE, ORDERED, IN_USE, INACTIVE
    }

}

存储库:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

服务:

@Service
public class EmployeeService {
    private EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public void updateEmployee(Employee employee){
        employeeRepository.saveAndFlush(employee);
    }
}

员工 DTO:

public class EmployeeDTO implements Serializable{

    private String firstName;
    private String lastName;
    private Date birthDate;
    private List<Car> carHistory;

    // getters & setters
}

DTO 映射器:

public class EmployeeMapper {

    public static Employee mapEmployeeDTOToEmployeeObject(EmployeeDTO dto, Employee employee){
        employee.setFirstName(dto.getFirstName());
        employee.setLastName(dto.getLastName());
        employee.setBirthDate(dto.getBirthDate());
        employee.setCarHistory(dto.getCarHistory());
        return employee;
    }

    public static EmployeeDTO mapEmployeeToEmployeeObject(Employee employee){
        EmployeeDTO dto = new EmployeeDTO();
        dto.setFirstName(employee.getFirstName());
        dto.setLastName(employee.getLastName());
        dto.setBirthDate(employee.getBirthDate());
        dto.setCarHistory(employee.getCarHistory());
        return dto;
    }
}

控制者:

@Controller
@RequestMapping("/manage")
@SessionAttributes("employee")
public class ManageEmployeesController {

    @Autowired
    EmployeeService employeeService;

    @RequestMapping("/employees")
    public String manageEmployee(Model model){
        model.addAttribute("employees", employeeService.getAllEmployees());
        return "manage-employee";
    }

    @RequestMapping(value = "/employee/{employeeId}", method = RequestMethod.GET)
    public String employeeDetails(@PathVariable("employeeId") Long id, Model model){
        Employee emp = employeeService.getEmployeeById(id);
        model.addAttribute("employee", EmployeeMapper.mapEmployeeToEmployeeObject(emp));
        return "manage-employee-details";
    }

    @RequestMapping(value = "/employee/{employeeId}", method = RequestMethod.POST)
    public String updateEmployeeDetails(@PathVariable("employeeId") Long id, EmployeeDTO employeeWithNewValues){
        Employee currentEmployee = employeeService.getEmployeeById(id);
        employeeService.updateEmployee(EmployeeMapper.mapEmployeeDTOToEmployeeObject(employeeWithNewValues, currentEmployee));
        return "redirect:/fleetmanager/employees";
    }
}

百里香叶形式:

<form role="form" method="post" th:object="${employee}">
    <h2>Personal details</h2>
    <table>
        <tr>
            <td>First name:</td>
            <td>
                <input type="text" th:readonly="true" th:value="*{firstName}" th:field="*{firstName}"/>
            </td>
        </tr>
        <tr>
            <td>Last name:</td>
            <td>
                <input type="text" th:value="*{lastName}" th:field="*{lastName}"/>
            </td>
        </tr>
        <tr>
            <td>Birthdate:</td>
            <td>
                <input type="text" th:value="*{birthDate}" th:field="*{birthDate}"/>
            </td>
        </tr>
        <tr th:each="car : *{carHistory}">
            <td th:text="${car.plate}">Plate</td>
        </tr>
    </table>
    <input type="submit" value="Edit"/>
</form>

【问题讨论】:

    标签: java spring-mvc spring-boot spring-data-jpa thymeleaf


    【解决方案1】:

    在绑定到表单字段的模型对象中使用日期时,您需要指定在 HTTP 请求中提交日期的格式。您需要为此定义一个PropertyEditor

    class DateEditor extends PropertyEditorSupport {
      private static final String FORMAT = "MMMMM dd, yyyy"; // Or any valid date format.
    
      public String getAsText() {
        return getValue() != null
                 ? new SimpleDateFormat(FORMAT).format(getValue())
                 : null;
      }
    
      public void setAsText(final String value) {
        try {
          setValue(new SimpleDateFormat(FORMAT).parse(value));
        }
        catch (final ParseException e) {
          // Log error.
        }
      }
    }
    

    然后,配置您的控制器以使用此编辑器。

    public class ManageEmployeesController {
      @InitBinder
      public void initBinder(final WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, new DateEditor());
      }
    }
    

    现在,当 Spring MVC 遇到 Date 类型的表单绑定字段时,它将使用此 PropertyEditorString 进行转换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-16
      • 2019-12-21
      • 1970-01-01
      • 2020-05-20
      • 2016-03-31
      • 1970-01-01
      • 2017-03-15
      相关资源
      最近更新 更多