界面中的验证

ScreenValidation bean 可以用来运行界面中的验证逻辑,有如下方法:

  • validateUiComponents()StandardEditorInputDialogMasterDetailScreen 提交改动时默认使用。该方法接收一组界面组件或者一个组件容器作为参数,返回这些组件中的验证错误 - ValidationErrors 对象。validateUiComponents() 方法还可以用在其他任意的界面中。示例:

    @UiController("sample_DemoScreen")
    @UiDescriptor("demo-screen.xml")
    public class DemoScreen extends Screen {
    
        @Autowired
        private ScreenValidation screenValidation;
    
        @Autowired
        private Form demoForm;
    
        @Subscribe("validateBtn")
        public void onValidateBtnClick(Button.ClickEvent event) {
            ValidationErrors errors = screenValidation.validateUiComponents(demoForm);
            if (!errors.isEmpty()) {
                screenValidation.showValidationErrors(this, errors);
                return;
            }
        }
    }
  • showValidationErrors() - 显示所有的错误和有问题的组件。该方法接收界面和 ValidationErrors 对象作为参数。默认在 StandardEditorInputDialogMasterDetailScreen 中使用。

  • validateCrossFieldRules() - 接收界面和实体作为参数,返回 ValidationErrors 对象。默认情况下,在 StandardEditorMasterDetailScreen 以及 DataGrid 的编辑界面使用。该方法可进行跨字段验证。

    如果编辑界面的约束中包含 UiCrossFieldChecks 并且所有的属性级别验证通过,则会在提交时,进行类级别约束的验证。可以使用控制器的 setCrossFieldValidate() 方法禁用此类验证。另外,validateCrossFieldRules() 方法也可以用在任意界面中。

    举个例子,对于 Event 实体,我们可以定义类级别注解 @EventDate 来检查 Start date 必须小于 End date

    @JmixEntity
    @Table(name = "SAMPLE_EVENT")
    @Entity(name = "sample_Event")
    @EventDate(groups = {Default.class, UiCrossFieldChecks.class})
    public class Event {
        @JmixGeneratedValue
        @Column(name = "ID", nullable = false)
        @Id
        private UUID id;
    
        @Column(name = "NAME")
        @InstanceName
        private String name;
    
        @Column(name = "START_DATE")
        @Temporal(TemporalType.TIMESTAMP)
        private Date startDate;
    
        @Column(name = "END_DATE")
        @Temporal(TemporalType.TIMESTAMP)
        private Date endDate;
    
        // ...

    注解定义如下:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = EventDateValidator.class)
    public @interface EventDate {
    
        String message() default "Start date must be earlier than the end date";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }

    EventDateValidator 类:

    public class EventDateValidator implements ConstraintValidator<EventDate, Event> {
    
        @Override
        public boolean isValid(Event event, ConstraintValidatorContext context) {
            if (event == null) {
                return false;
            }
    
            if (event.getStartDate() == null || event.getEndDate() == null) {
                return false;
            }
    
            return event.getStartDate().before(event.getEndDate());
        }
    }

    然后可以在任意界面中使用 validateCrossFieldRules() 方法。

    @UiController("sample_DemoScreen")
    @UiDescriptor("demo-screen.xml")
    public class DemoScreen extends Screen {
    
        @Autowired
        private ScreenValidation screenValidation;
    
        @Autowired
        protected Metadata metadata;
    
        @Autowired
        protected TimeSource timeSource;
    
        @Subscribe("validateDateBtn")
        public void onValidateDateBtnClick(Button.ClickEvent event) {
            Event demoEvent = metadata.create(Event.class);
            demoEvent.setName("Demo event");
            demoEvent.setStartDate(timeSource.currentTimestamp());
            demoEvent.setEndDate(DateUtils.addDays(demoEvent.getStartDate(), -1));
            ValidationErrors errors = screenValidation.validateCrossFieldRules(this, demoEvent);
            if (!errors.isEmpty()) {
                screenValidation.showValidationErrors(this, errors);
            }
        }
    }
  • showUnsavedChangesDialog()showSaveConfirmationDialog() 方法为没保存的数据显示对话框,对话框中带有 YesNo 按钮或 SaveDo not saveCancel 按钮。这些方法用于 StandardEditorpreventUnsavedChanges() 方法。可以用 jmix.ui.screen.use-save-confirmation 应用程序属性选择对话框类型。