我有一条信息作为字符串代码值存储在数据库表中。我定义了一个枚举以使代码易于阅读。实体类使用枚举定义字段。
当我在 Vaadin 网格中显示数据时,它会显示枚举值,这正是所需要的。但是,我也试图在表单文本字段中显示相同的数据,这表现不同。我不得不为数据绑定编写一个转换器以避免运行时错误,但结果与我预期的相反 - 它显示代码值而不是枚举。
一些代码来说明:
枚举类型:
public enum TaskType {
TASK_VIEW("00"), INTERACTIVE("01"), BATCH("02"), FOLDER("07"), URL("08"), USER_DEFINED("11");
private String codeValue;
private TaskType(String codeValue) {
this.codeValue = codeValue;
}
public String getCodeValue() {
return codeValue;
}
public static TaskType fromCodeValue(String value) {
switch (value) {
case "00":
return TASK_VIEW;
case "01":
return INTERACTIVE;
case "02":
return BATCH;
case "07":
return FOLDER;
case "08":
return URL;
case "11":
return USER_DEFINED;
default:
return null;
}
}
}
实体类:
@Entity
public class TaskMaster extends AbstractEntity {
private TaskType type;
// other fields
public TaskType getType() {
return type;
}
public void setType(TaskType type) {
this.type = type;
}
// other methods
}
数据库字段和枚举类型之间的转换器:
@Converter(autoApply = true)
public class TaskTypeConverter implements AttributeConverter<TaskType, String> {
@Override
public String convertToDatabaseColumn(TaskType type) {
if (type != null) {
return type.getCodeValue();
} else {
return null;
}
}
@Override
public TaskType convertToEntityAttribute(String dbData) {
if (dbData != null) {
return TaskType.fromCodeValue(dbData);
} else {
return null;
}
}
}
网格视图类:
public class TaskMasterListView extends VerticalLayout {
private Grid<TaskMaster> grid = new Grid<>(TaskMaster.class);
private TaskMasterService taskService;
public TaskMasterListView(TaskMasterService taskService) {
this.taskService = taskService;
...
}
@PostConstruct
public void init() {
List<TaskMaster> items = taskService.findAll();
grid.setItems(items);
}
private void configureGrid() {
grid.addClassName("tasks-grid");
grid.setColumns("internalTaskID", "taskID", "name", "type", "objectName", "version",
"formName");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
}
...
}
详细信息视图(显示错误的地方):
public class TaskDetailView extends FormLayout {
private static final Logger logger = LoggerFactory.getLogger(TaskDetailView.class);
private TextField type;
// other GUI objects
private Binder<TaskMaster> binder;
public TaskDetailView() {
configureView();
bindData();
}
public void loadTask(TaskTreeView.TaskSelectionEvent event) {
if (event.getSelected() != null) {
binder.setBean(event.getSelected());
}
}
private void bindData() {
binder = new Binder<>(TaskMaster.class);
binder.setBean(new TaskMaster());
binder.forField(type).withConverter(new TaskTypeConverter()).bind("type");
// other bindings
}
private static class TaskTypeConverter implements Converter<String, TaskType> {
@Override
public Result<TaskType> convertToModel(String value, ValueContext context) {
logger.info("convertToModel: value={}", value);
return Result.ok(TaskType.fromCodeValue(value));
}
@Override
public String convertToPresentation(TaskType value, ValueContext context) {
if (value != null) {
logger.info("convertToPresentation: value={}", value.toString());
return value.getCodeValue();
} else {
logger.info("convertToPresentation: null");
return "";
}
}
}
}
所以,举个例子,如果一个 type = 07
的实体显示在网格中,它会显示 FOLDER
,这就是我想要的。但是,当我在文本字段中显示相同类型的对象时,它会显示 07
而不是 FOLDER
。
知道这里发生了什么吗?它似乎与我需要的相反。
答案 0 :(得分:2)
您的 static class TaskTypeConverter
用于由活页夹从 TaskType.FOLDER
转换。现在让我们看看您的 convertToPresentation()
做了什么:它调用 value.getCodeValue()
所以当然您的 TextField 填充了 07
。
但是,您想要返回枚举名称,因此您需要调用固有的枚举方法 value.name()
,反之亦然,在 TaskType.valueOf(value)
中调用 convertToModel()
。调用 IllegalArgumentException
时不要忘记捕获 valueOf()
和 NPE!
最好不要使用 .name()
,而是使用友好名称 f.e.您可以在枚举中保存的“文件夹”。
但是,您可能应该使用 Select<TaskType>
或 ComboBox<TaskType>
让用户从一组预定义的值中进行选择,即从枚举而不是 TextField 中进行选择。
如果您需要自定义的不仅仅是文本,请通过 setItemLabelGenerator()
或渲染器设置友好名称。