我在使用@InitBinder注释实现两个验证器时遇到问题。
控制器代码:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window1" Height="250" Width="400">
<Window.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<Style TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border BorderThickness="0,0,0,0"
CornerRadius="5" Margin="0,6,0,-5" AllowDrop="True">
<Border.Background>
<RadialGradientBrush SpreadMethod="Reflect">
<GradientStop Color="#FFA8A8A8" Offset="0.923"/>
<GradientStop Color="White"/>
<GradientStop Color="#FFE0E0E0" Offset="0.391"/>
</RadialGradientBrush>
</Border.Background>
</Border>
<Border x:Name="Shadowborder" BorderBrush="Black" BorderThickness="0,0,0,10"
CornerRadius="5">
<Border.Effect>
<DropShadowEffect Direction="270" Opacity="0.5"/>
</Border.Effect>
</Border>
<Border CornerRadius="5" x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
<Setter Property="Margin" TargetName="border" Value="0,5,0,-5"/>
<Setter Property="Margin" TargetName="Shadowborder" Value="0,5,0,-5"/>
<Setter Property="Effect" TargetName="Shadowborder">
<Setter.Value>
<DropShadowEffect Direction="270" Opacity="0.3" BlurRadius="1" ShadowDepth="1"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Padding="20" Content="Hello!"/>
</Grid>
</Window>
会话验证器:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/fragment_video_appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="200dp"
android:orientation="vertical"
app:layout_collapseMode="parallax">
<TextView
android:id="@+id/fragment_video_title_textview"
style="@style/TextAppearance.AppCompat.Light.SearchResult.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textStyle="bold"
tools:text="funny videos" />
<TextView
android:id="@+id/fragment_video_plays_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textSize="12sp"
tools:text="1.7k plays ⋅ 4 years ago" />
<TextView
android:id="@+id/fragment_video_description_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="10dp"
android:textColor="@color/colorPrimaryText"
android:textSize="13sp"
tools:text="funny videos compilation"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="8dp"
android:background="@color/mediumLightGray"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<include layout="@layout/item_user" />
</FrameLayout>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:contentInsetStart="0dp">
<android.support.constraint.ConstraintLayout
android:id="@+id/fragment_video_info_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/fragment_video_imageview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:color/darker_gray" />
<TextView
android:id="@+id/fragment_video_timelength_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textSize="12sp"
android:textColor="@color/white"
android:background="@color/dimfilter"
app:layout_constraintBottom_toBottomOf="@+id/fragment_video_imageview"
app:layout_constraintEnd_toEndOf="parent"
tools:text="03:45"/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/fragment_video_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.design.widget.TabLayout
android:id="@+id/fragment_video_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/mediumLightGray"
app:tabIndicatorColor="@color/colorPrimary"
app:tabTextColor="@color/darkMediumGray"
app:tabSelectedTextColor="@color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:layout_collapseMode="pin"/>
</android.support.v4.view.ViewPager>
<include layout="@layout/layout_content_progress" />
<include layout="@layout/layout_message" />
</android.support.design.widget.CoordinatorLayout>
频道验证器:
@Autowired
private SessionValidator sessionValidator;
@Autowired
private ChannelValidator channelValidator;
@InitBinder
public void initBinder(WebDataBinder binder){
binder.addValidators(sessionValidator, channelValidator);
}
@RequestMapping(method = RequestMethod.GET)
public UserInfo findBySession(
@Valid @ModelAttribute Session session,
@Valid @ModelAttribute Channel channel){
//...
}
我在调用控制器时收到以下异常:
@Component
public class SessionValidator implements Validator {
@Override
public boolean supports(Class<?> aClass){
return Session.class.equals(aClass);
}
@Override
public void validate(Object o, Errors errors){
//...
}
}
有人知道如何解决吗?预先感谢!
答案 0 :(得分:1)
您绑定了两个验证器,但是对于每个要验证的参数,将仅支持其中一个。
SessionValidator
支持Session
参数,但不支持Channel
参数,反之,ChannelValidator
支持Channel
参数,但不支持{{1} }参数。
例外。
作为第一种选择,您可以在每个Spring Validator子类中支持两种参数类型。有点笨拙,但应该可以使用:
Session
您当然应该检查@Override
public boolean supports(Class<?> aClass){
return Channel.class.equals(aClass) || Session.class.equals(aClass);
}
中的类型,并仅在与验证器类匹配时执行验证。
作为第二种选择,通过为每个类实现validate()
来进行验证并通过在控制器中显式验证参数来使用标准验证API。
作为第三种选择,如果可以的话,您可以直接注释javax.validation.ConstraintValidator
和Session
类上的约束。因此,您仍然可以在参数声明中使用Channel
来保持自动验证。
答案 1 :(得分:1)
您只能添加支持的验证器:
@InitBinder
protected void initBinder(WebDataBinder binder) {
if (binder.getTarget() == null) return;
final ImmutableList<Validator> validatorsList = ImmutableList.of(
new CunsomValidator1(),
new CunsomValidator2()
);
for (Validator validator : validatorsList) {
if (validator.supports(binder.getTarget().getClass())) {
binder.addValidators(validator);
}
}
}