当前位置: 首页 > news >正文

第四章 表单(3)- 表单验证

在Blazor中,表单的验证可以通过两种方式实现,一种是使用Blazor所提供表单验证特性,另一种是使用ValidationMessageStore进行验证。

表单验证的基础使用(内置特性)

一、内置特性表单验证的开启

Blazor中,使用表单组件<EditForm>时,如果希望开启表单的验证功能,需要在表单中使用<DataAnnotationsValidator/><ValidationSummary/><ValidationMessage>组件。

1、开启特性验证系统

在表单中使用<DataAnnotationsValidator>组件可以将数据特性验证附加到关联的EditContext,从而开启特性验证系统(根据表单模型属性的特性声明或IValidatableObject接口的Validate方法进行验证)。

Blazor执行验证有两个节点:

  • 当用户从某个字段中失焦时,将执行字段验证。 在字段验证期间,DataAnnotationsValidator组件将报告的所有验证结果与该字段相关联。
  • 当用户提交表单时,将执行模型验证, 在模型验证期间,DataAnnotationsValidator组件尝试根据验证结果报告的成员名称来确定字段,与单个成员无关的验证结果将与模型而不是字段相关联。

2、验证信息展示组件

特定验证信息的展示组件

如果要展示指定字段的验证失败信息,可以使用<ValidationMessage>组件,并通过For组件参数设置要进行信息展示的对应属性。

综合验证信息的展示组件

如果想要展示表单中所有的验证失败信息,可以直接使用<ValidationSummary>组件,如果有需要,也可以通过其Model组件参数来设置对特定的模型。

需要注意的是,这两个组件都依赖于 ValidationMessageStore 类来获取表单字段的验证错误消息,当ValidationMessageStore对象中存在验证失败消息时,就可以通过上面的两个组件进行展示。

样式

<ValidationMessage><ValidationSummary>组件支持任意属性,验证失败的信息将添加到生成的 <div><ul> 元素中。

验证信息的CSS样式则通过wwwroot/css/app.csswwwroot/css/site.css进行设置,如:

.validation-message {color: red;
}
  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<EditForm Model="Model" OnValidSubmit="Submit" FormName="Form1"><DataAnnotationsValidator /><ValidationSummary /><div class="mb-3 w-25"><InputText @bind-Value="Model!.Name" /><ValidationMessage For="() => Model!.Name" /></div><div class="mb-3 w-25"><InputNumber @bind-Value="Model!.Age" /><ValidationMessage For="() => Model!.Age" /></div><div class="mb-3"><button type="submit">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student? Model { get; set; }protected override void OnInitialized(){Model ??= new();}void Submit(){Console.WriteLine(Model!.Name);}public class Student{[Required(ErrorMessage = "名字必须填写")]public string Name { get; set; } = null!;[Range(23, 30, ErrorMessage = "岁数只能是23~30")]public int Age { get; set; } = 23;}
    }
    

在这里插入图片描述

二、内置验证特性

ASP.NET Core 框架中提供了一批验证特性,通过验证特性可以为模型属性指定验证规则,这样使用验证特性可对模型类提供数据注解,好处是在没有运行应用程序的情况下,就能一目了然看到模型中每个属性应该处理什么样的数据,从而对模型对进行验证。

ASP.NET Core 中内置的验证特性

[Display]:设置属性名称,一般用于验证信息,若没有使用[Display]特性,则使用的是属性名

  • Name:设置的属性名

[Required]:验证属性不可为 null

[StringLength]:验证字符串属性值是否未超过指定长度限制

[MaxLength]:验证设定的最大长度

[MinLength]:验证设定的最小长度

[Range]:验证属性值是否在指定范围内

[Compare]:验证模型中的两个属性是否匹配

[CreditCard]:验证属性是否为信用卡格式

[EmailAddress]:验证属性是否为电子邮件格式

[Phone]:验证属性是否为电话号码格式

[Url]:验证属性是否为 URL 格式

[RegularExpression]:验证属性值是否与指定的正则表达式匹配

[FileExtensions]:验证文件扩展名

[CustomValidation]:用于自定义验证逻辑,可以进行个性化验证

1、非空验证

[Required]:用于验证属性不可为 null

  • ErrorMessage:验证失败时,显式的异常信息,可以使用{n}占位符,其中{0}表示Display设置的名或默认属性名

  • AllowEmptyStrings:是否允许空字符串,默认为false

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator/><div class="mb-3 w-25"><label>姓名:<InputText @bind-Value="Model.Name"/><ValidationMessage For="()=> Model.Name"/></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){Console.WriteLine(Model?.Name);}public class Student{[Required(ErrorMessage = "{0}不可为空!")][Display(Name = "姓名")]public string Name { get; set; } = null!;}
    }
    

2、长度验证

[StringLength]:用于验证字符串属性值是否未超过指定长度限制

  • MaximumLength:最大长度
  • MinimumLength:最小长度
  • ErrorMessage:验证失败时显式的异常信息,可以使用{n}占位符,其中{0}表示Display设置的名或默认属性名,{1}表示[StringLength]特性第一个属性值,即MaximumLength的值,{2}表示第二个属性值,即MinimumLength的值

[MaxLength]:验证设定的最大长度

[MinLength]:验证设定的最小长度

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator/><div class="mb-3 w-25"><label>地址:<InputText @bind-Value="Model.Address" /><ValidationMessage For="()=> Model.Address" /></label></div><div class="mb-3 w-25"><label>最大长度:<InputText @bind-Value="Model.MaxLength" /><ValidationMessage For="()=> Model.MaxLength" /></label></div><div class="mb-3 w-25"><label>最小长度:<InputText @bind-Value="Model.MinLength" /><ValidationMessage For="()=> Model.MinLength" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){//提交时的业务处理}public class Student{[Display(Name = "地址")][StringLength(5,MinimumLength=2,ErrorMessage="{0}的长度要在{2}~{1}之间")]public string? Address { get; set; }[Display(Name = "最大长度")][MaxLength(5, ErrorMessage = "{0}的最大长度为{1}")]public string? MaxLength { get; set; }[Display(Name = "最小长度")][MinLength(2, ErrorMessage = "{0}的最小长度为{1}")]public string? MinLength { get; set; }}
    }
    

3、正则验证

[RegularExpression]:验证属性值是否与指定的正则表达式匹配

  • Pattern:正则校验规则

  • ErrorMessage:验证失败时显式的异常信息,可以使用{n}占位符,其中{0}表示Display设置的名或默认属性名,{1}表示[RegularExpression]特性第一个属性值,即Pattern的值

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator/><div class="mb-3 w-25"><label>正则:<InputText @bind-Value="Model.Regex" /><ValidationMessage For="()=> Model.Regex" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){Console.WriteLine(Model?.Regex);}public class Student{[Display(Name = "正则数据")][RegularExpression("^[0-9]*[1-9][0-9]*$",ErrorMessage = "{0}不符合正则规则")] //正则public string? Regex { get; set; }}
    }
    

4、范围校验

[Range(minimum,maximum[,ErrorMessage])]:用于指定数值类型的最小值和最大值之间的范围

  • minimum:数值最小值

  • maximum:数值最大值

  • ErrorMessage:验证失败时显式的异常信息,可以使用{n}占位符,其中{0}表示Display设置的名或默认属性名,{1}表示[Range]特性第一个属性值,即minimum的值,{2}表示第二个属性值,即maximum的值

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator/><div class="mb-3 w-25"><label>范围校验:<InputNumber @bind-Value="Model.Range"/><ValidationMessage For="()=> Model.Range"/></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){}public class Student{[Range(1, 5, ErrorMessage = "{0}最小值为{1},最大值为{2}")]public int Range { get; set; }}
    }
    

5、对比校验

[Compare(otherProperty[,ErrorMessage])]:用于验证模型对象中的两个属性值是否相同,例如创建账号时的两次密码输入验证。

  • otherProperty:要进行对比的属性名,可以借助nameof()方法来获取

  • ErrorMessage:验证失败时显式的异常信息

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator/><div class="mb-3 w-25"><label>密码:<InputText @bind-Value="Model.Password" /></label></div><div class="mb-3 w-25"><label>密码校验:<InputText @bind-Value="Model.ConfirmPassword" /><ValidationMessage For="()=> Model.ConfirmPassword" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){Console.WriteLine(Model?.Password);}public class Student{public string? Password { get; set; }[Compare(nameof(Password), ErrorMessage = "密码不一致")]public string? ConfirmPassword { get; set; }}
    }
    

在这里插入图片描述

6、格式校验

[EmailAddress]:验证<InputText>组件中输入的内容是否为正确的电子邮箱地址格式

[Phone]:用于验证国际标准手机号格式的正确性,如果要检验中国的11位手机号码,可以使用[RegularExpression]特性进行验证

[CreditCard]:用于验证信用卡号码的正确性

[Url]:用于验证 URL 地址格式的正确性

  • ErrorMessage:验证失败时,显式的异常信息,可以使用{0}表示Display设置的名或默认属性名

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator /><div class="mb-3 w-25"><label>邮箱:<InputText @bind-Value="Model.Email" /><ValidationMessage For="()=> Model.Email" /></label></div><div class="mb-3 w-25"><label>手机号:<InputText @bind-Value="Model.Phone" /><ValidationMessage For="()=> Model.Phone" /></label></div><div class="mb-3 w-25"><label>信用卡:<InputText @bind-Value="Model.CreditCard" /><ValidationMessage For="()=> Model.CreditCard" /></label></div><div class="mb-3 w-25"><label>URL:<InputText @bind-Value="Model.URL" /><ValidationMessage For="()=> Model.URL" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public Student Model { get; set; } = new();void Submit(){Console.WriteLine(Model.Phone);}public class Student{//邮箱地址[Display(Name = "邮箱")][EmailAddress(ErrorMessage = "请输入正确的邮箱")]public string? Email { get; set; }[Display(Name = "手机号")][Phone(ErrorMessage = "请输入正确的手机号码")]public string? Phone { get; set; }[Display(Name = "信用卡")][CreditCard(ErrorMessage = "请输入正确的信用卡号")]public string? CreditCard { get; set; }[Url(ErrorMessage = "请输入正确的URL地址")]public string? URL { get; set; }}
    }
    

在这里插入图片描述

7、文件扩展名校验

[FileExtensions]:用于验证文件的扩展名。

  • Extensions:设置要校验的文件扩展名,如果允许多个扩展名,可以使用逗号,隔开

  • ErrorMessage:验证失败时,显式的异常信息,可以使用{0}表示Display设置的名或默认属性名

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator /><div class="mb-3 w-25"><label>文件名:<InputText @bind-Value="Model.FileName" /><ValidationMessage For="()=> Model.FileName" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public FileModel Model { get; set; } = new();void Submit(){Console.WriteLine(Model.FileName);}public class FileModel{[FileExtensions(Extensions = "jpg,doc",ErrorMessage = "必须为jpg或doc文件")]public string? FileName { get; set; }}
    }
    

在这里插入图片描述

8、自定义校验

[CustomValidation(validatorType,methodName)]:用于自定义验证逻辑,可以进行个性化验证

  • validatorTypeType类型,用于指定自定义校验方法所在的类型
  • methodNamestring类型,用于指定自定义的验证方法的名称

重点关注验证方法的几个要求:

  • 必须为静态方法

  • 必须返回ValidationResult类型,当验证方法验证成功时,返回ValidationResult.Success值,验证失败时,通过返回new ValidationResult(errorMessage)返回一条错误信息

  • 接收两个参数,一个为目标校验值,一个为ValidationContext对象,可以通过该对象的ObjectInstance属性获取目标校验属性的所在对象

  • 示例

    @page "/AnnotationsTest"
    @using System.ComponentModel.DataAnnotations<PageTitle>验证特性测试</PageTitle><EditForm Model="Model" OnValidSubmit="Submit"><DataAnnotationsValidator /><div class="mb-3 w-25"><label>姓名:<InputText @bind-Value="Model.Name" /><ValidationMessage For="()=> Model.Name" /></label></div><div class="mb-3 w-25"><label>岁数:<InputNumber @bind-Value="Model.Age" /><ValidationMessage For="()=> Model.Age" /></label></div><div class="w-25"><button class="btn btn-primary">提交</button></div>
    </EditForm>@code {[SupplyParameterFromForm]public CustomModel Model { get; set; } = new();void Submit(){Console.WriteLine(Model.Name);}public class CustomModel{[CustomValidation(typeof(CustomValidator), nameof(CustomValidator.ValidationName))]public string? Name { get; set; }[CustomValidation(typeof(CustomValidator), nameof(CustomValidator.ValidationAge))]public int Age { get; set; }}public class CustomValidator{public static ValidationResult? ValidationName(string data, ValidationContext validationContext){   //可以通过ValidationContext对象获取校验值,也可以直接使用第一个参数//string name = ((CustomModel)validationContext.ObjectInstance).Name!;if (data != null && data.Contains("ABC")){return ValidationResult.Success;}//返回错误信息return new ValidationResult("商品名称必须包含 ABC !");}public static ValidationResult? ValidationAge(int data, ValidationContext validationContext){//可以通过ValidationContext对象获取校验值,也可以直接使用第一个参数//int age = ((CustomModel)validationContext.ObjectInstance).Age!;  if (data > 0 && data < 100){return ValidationResult.Success;}//返回错误信息return new ValidationResult("岁数必须在0~100之间");}}
    }
    

二、模型校验

有时候需要对多个属性进行综合性的验证,比如两个人属性的大小对比、开始和结束时间的先后约束、总数限制等等,因为依赖多个属性共同完成的校验,无法通过单个特性来实现,此时就需要用到IValidatableObject 接口。

IValidatableObject 是 .NET 中的一个接口,用于实现对象级别的自定义验证逻辑。它的核心作用是允许开发者编写复杂的验证规则,尤其是那些涉及多个属性或需要动态判断的验证场景,而不仅仅依赖于单个属性的特性声明(如 [Required][Range] 等)。

1、定义模型校验

表单模型通过继承IValidatableObject接口并实现Validate方法即可定义模型校验的规则。在表单进行提交时,会自动进行模型校验。

  • 示例

    public class Order : IValidatableObject
    {public DateTime StartDate { get; set; }public DateTime EndDate { get; set; }public int Quantity { get; set; }public IEnumerable<ValidationResult> Validate(ValidationContext validationContext){// 规则1:结束时间必须晚于开始时间if (EndDate < StartDate){yield return new ValidationResult("结束时间必须晚于开始时间");}// 规则2:数量不能超过 100(假设需要动态判断)if (Quantity > 100){yield return new ValidationResult("数量不能超过 100", new[] { nameof(Quantity) });}}
    }
    

2、模型校验

模型校验的错误信息可以通过<ValidationSummary/>组件展示,如果只希望展示模型校验的异常信息,只需要通过Model属性绑定到指定的表单模型对象上即可。

  • 示例

    <EditForm Model="Input" method="post" OnValidSubmit="LoginUser" Enhance FormName="Login"><DataAnnotationsValidator /><ValidationSummary Model="@Input"/>......
    </EditForm >
    

自定义表单验证(ValidationMessageStore)

一、表单验证的过程控制

Blazor中,使用EditForm组件时,可以使用EditContextValidationMessageStore对象来控制表单的验证过程。

1、ValidationMessageStore

在 Blazor 中,ValidationMessageStore是一个用于管理和存储验证错误消息的服务。它提供了一种集中管理和显示验证错误消息的机制,可以方便地在整个应用程序中使用。

构造方法

ValidationMessageStore(EditContext):设置对应编辑上下文对象的ValidationMessageStore实例。

常用属性

this[Expression<Func<Object>>]:索引器,获取指定字段在此ValidationMessageStore中的验证消息。

常用方法

Add(Expression<Func<Object>>, String):为指定字段添加验证信息。

  • 第一个参数中,是一个返回需要设置验证信息的字段的Lamda表达式

Add(Expression<Func<Object>>, IEnumerable<String>):为指定字段添加多条验证信息。

Clear():清除所有的消息。

Clear(Expression<Func<Object>>):消除指定字段的消息。

2、EditContext

在表单的验证过程中,EditContext作为上下文对象,起到了承上启下的作用。

常用属性

Modelobject属性,获取当前EditContext对象所关联的表单模型对象。

ShouldUseFieldIdentifiers:是否对表单模型字段使用唯一标识,可以确保在验证错误消息中能够准确地指示出错的字段,特别是在处理复杂表单时非常有用,默认情况下为true。如果希望简化验证错误消息,可以将该属性设置为false

常用方法

bool Validate():表单验证是否通过。

FieldIdentifier Field(string fieldName):获取对应字段的可编辑唯一标识对象。

IEnumerable<string> GetValidationMessages([Expression<Func<object>> accessor/FieldIdentifier fieldIdentifier]):获取全部或指定字段的验证错误信息,当表单字段验证失败时,Blazor会将相应的错误消息存储在EditContext对象中,可以通过此方法获取,以便在UI中进行自定义展示。

bool IsModified([Expression<Func<object>> accessor/FieldIdentifier fieldIdentifier]):任意字段或指定字段是否已被改变。

bool IsValid(Expression<Func<object>> accessor/FieldIdentifier fieldIdentifier):指定字段是否验证通过。

NotifyValidationStateChanged():当字段的验证状态发生变化时,可以调用此方法来通知Blazor组件进行重新渲染。

常用事件

OnValidationRequested(object? sender,ValidationRequestedEventArgs args):在EditForm表单发起验证时会触发,可以在事件处理函数中进行验证处理。

OnFieldChanged(object? sender, FieldChangedEventArgs args):当字段内容发生变化时触发。

OnValidationStateChanged(object? sender, TEventArgs e):在表单验证状态发生变化时触发,例如字段的验证结果从有效变为无效或从无效变为有效时触发。

3、综合示例

  • 示例

    @page "/starship-8"
    @rendermode InteractiveServer
    @implements IDisposable
    @inject ILogger<Starship8> Logger<h2>Holodeck Configuration</h2><EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship8"><div><label><InputCheckbox @bind-Value="Model!.Subsystem1" />Safety Subsystem</label></div><div><label><InputCheckbox @bind-Value="Model!.Subsystem2" />Emergency Shutdown Subsystem</label></div><div><ValidationMessage For="() => Model!.Options"/></div><div><button type="submit">Update</button></div>
    </EditForm>@code {private EditContext? editContext;[SupplyParameterFromForm]public Holodeck? Model { get; set; }private ValidationMessageStore? messageStore;protected override void OnInitialized(){Model ??= new();editContext = new(Model);editContext.OnValidationRequested += HandleValidationRequested;messageStore = new(editContext);}private void HandleValidationRequested(object? sender,ValidationRequestedEventArgs args){//清除上一次遗留的验证结果信息messageStore?.Clear();//自定义验证逻辑if (!Model!.Options){messageStore?.Add(() => Model.Options, "Select at least one.");}}private void Submit(){Logger.LogInformation("Submit called: Processing the form");}public class Holodeck{public bool Subsystem1 { get; set; }public bool Subsystem2 { get; set; }public bool Options => Subsystem1 || Subsystem2;}public void Dispose(){if (editContext is not null){editContext.OnValidationRequested -= HandleValidationRequested;}}
    }
    

二、自定义验证器组件

Blazor 框架提供了 DataAnnotationsValidator 验证器组件,用于在EditForm表单中开启特性验证。

如果对表单中的验证逻辑、顺序有自定义的需求,可以通过继承ComponentBase来创建自定义的验证器组件。

  • 大多数情况下,可以使用自定义的验证特性来代替自定义验证器组件。

继承ComponentBase创建自定义验证器组件时,可以尝试实现如下内容:

  • 表单的EditContext是组件的级联参数,可以在自定义验证器组件中接收该对象

  • 初始化验证器组件时,创建一个基于EditContext对象的新的ValidationMessageStore来维护当前表单的错误列表

  • 定义DisplayErrors(Dictionary<string, List<string>> errors)方法,当开发人员调用此方法时,将验证信息设置到ValidationMessageStore对象中。

  • 发生以下任一情况时,将清除消息:

    • 引发 EditContextOnValidationRequested 事件时,将ValidationMessageStore对象的所有异常消息清除
    • 引发 OnFieldChanged 事件时,将验证失败的字段清除
    • ClearErrors 方法由开发人员代码调用。 所有错误都将被清除。
  • CustomValidation.cs

    public class CustomValidation : ComponentBase
    {private ValidationMessageStore? messageStore;[CascadingParameter]private EditContext? CurrentEditContext { get; set; }protected override void OnInitialized(){if (CurrentEditContext is null){throw new InvalidOperationException($"{nameof(CustomValidation)} requires a cascading " +$"parameter of type {nameof(EditContext)}. " +$"For example, you can use {nameof(CustomValidation)} " +$"inside an {nameof(EditForm)}.");}messageStore = new(CurrentEditContext);CurrentEditContext.OnValidationRequested += (s, e) => messageStore?.Clear();CurrentEditContext.OnFieldChanged += (s, e) => messageStore?.Clear(e.FieldIdentifier);}public void DisplayErrors(Dictionary<string, List<string>> errors){if (CurrentEditContext is not null){foreach (var err in errors){messageStore?.Add(CurrentEditContext.Field(err.Key), err.Value);}CurrentEditContext.NotifyValidationStateChanged();}}public void ClearErrors(){messageStore?.Clear();CurrentEditContext?.NotifyValidationStateChanged();}
    }
    
  • Starship9.razor

    @page "/starship-9"
    @inject ILogger<Starship9> Logger<h1>Starfleet Starship Database</h1><h2>New Ship Entry Form</h2><EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9"><CustomValidation @ref="customValidation"/><ValidationSummary/><div><label>Primary Classification:<InputSelect @bind-Value="Model!.Classification"><option value="">Select classification ...</option><option checked="@(Model!.Classification == "Exploration")" value="Exploration">Exploration</option><option checked="@(Model!.Classification == "Diplomacy")" value="Diplomacy">Diplomacy</option><option checked="@(Model!.Classification == "Defense")"  value="Defense">Defense</option></InputSelect></label></div><div><label>Description (optional):<InputTextArea @bind-Value="Model!.Description"/></label></div><div><button type="submit">Submit</button></div>
    </EditForm>@code {private CustomValidation? customValidation;[SupplyParameterFromForm]public Starship? Model { get; set; }protected override void OnInitialized() =>Model ??= new() { ProductionDate = DateTime.UtcNow };private void Submit(){customValidation?.ClearErrors();var errors = new Dictionary<string, List<string>>();if (Model!.Classification == "Defense" && string.IsNullOrEmpty(Model.Description)){errors.Add(nameof(Model.Description),new() { "For a 'Defense' ship classification, " + "'Description' is required." });}if (errors.Any()){customValidation?.DisplayErrors(errors);}else{Logger.LogInformation("Submit called: Processing the form");}}
    }
    

三、自定义验证特性

在实际项目开发过程中,大多数情况下,使用自定义验证特性就可以满足表单上的验证需求,并且自定义验证特性的复用性更强一些,其实现过程具体如下:

  • 继承ValidationAttribute

  • 重写IsValid方法,返回验证结果

  • 示例

    public class ClassicMovieAttribute : ValidationAttribute
    {public ClassicMovieAttribute(int year)=> Year = year;public int Year { get; }//返回验证信息public string GetErrorMessage() =>$"Classic movies must have a release year no later than {Year}.";protected override ValidationResult? IsValid(object? value, ValidationContext validationContext){var movie = (Movie)validationContext.ObjectInstance;var releaseYear = ((DateTime)value!).Year;if (movie.Genre == Genre.Classic && releaseYear > Year){return new ValidationResult(GetErrorMessage());}return ValidationResult.Success;}
    }
    

IsValid方法可以接收字段值以及一个ValidationContext参数。ValidationContext为验证的上下文对象,可以从中取得一些验证相关的信息。此外还可以通过ValidationContext对象获取IOC容器中服务。

  • 示例

    public class SaladChefValidatorAttribute : ValidationAttribute
    {protected override ValidationResult? IsValid(object? value,ValidationContext validationContext){//这里假定SaladChef已经在Program.cs中注册了服务,其SaladToppers属性为一个字符串数组var saladChef = validationContext.GetRequiredService<SaladChef>();if (saladChef.SaladToppers.Contains(value?.ToString())){return ValidationResult.Success;}return new ValidationResult("Is that a Vulcan salad topper?! " +"The following toppers are available for a Ten Forward salad: " +string.Join(", ", saladChef.SaladToppers));}
    }
    

四、自定义CSS

默认情况下,Blazor框架在wwwroot/css/app.csswwwroot/css/site.css中设置了表单验证失败信息的基本样式

在这里插入图片描述

实现步骤

wwwroot/css/app.csswwwroot/css/site.css中添加自定义的验证失败样式

  • 示例

    .validField {border-color: lawngreen;
    }.invalidField {background-color: tomato;
    }
    

创建自定义的样式提供类

  • 继承FieldCssClassProvider

  • 重写GetFieldCssClass方法,返回对应CSS的class名称

  • CustomFieldClassProvider.cs

    using Microsoft.AspNetCore.Components.Forms;public class CustomFieldClassProvider : FieldCssClassProvider
    {public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier){var isValid = editContext.IsValid(fieldIdentifier);return isValid ? "validField" : "invalidField";}
    }
    

设置表单的验证演示提供对象

  • 调用表单的EditContext实例的SetFieldCssClassProvider方法,将CustomFieldClassProvider设置为表单的验证样式提供对象

  • Starship13.razor

    @page "/starship-13"
    @using System.ComponentModel.DataAnnotations
    @inject ILogger<Starship13> Logger<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship13"><DataAnnotationsValidator /><ValidationSummary /><div><label>Identifier: <InputText @bind-Value="Model!.Id" /></label></div><div><button type="submit">Submit</button></div>
    </EditForm>@code {private EditContext? editContext;[SupplyParameterFromForm]public Starship? Model { get; set; }protected override void OnInitialized(){Model ??= new();editContext = new(Model);editContext.SetFieldCssClassProvider(new CustomFieldClassProvider());}private void Submit(){Logger.LogInformation("Submit called: Processing the form");}public class Starship{[Required][StringLength(10, ErrorMessage = "Id is too long.")]public string? Id { get; set; }}
    }
    

上面的示例中,是对表单模型的所有字段都生效的,如果只希望对指定的一些字段使用自定义样式,其他字段继续使用默认样式的话,就需要在GetFieldCssClass方法中,根据需求返回对应的CSS类名

  • CustomFieldClassProvider.cs

    using Microsoft.AspNetCore.Components.Forms;public class CustomFieldClassProvider : FieldCssClassProvider
    {public override string GetFieldCssClass(EditContext editContext,in FieldIdentifier fieldIdentifier){var isValid = editContext.IsValid(fieldIdentifier);if (fieldIdentifier.FieldName == "Name"){return isValid ? "validField" : "invalidField";}else{if (editContext.IsModified(fieldIdentifier)){return isValid ? "modified valid" : "modified invalid";}else{return isValid ? "valid" : "invalid";}}}
    }
    

表单模型的嵌套验证

虽然Blazor框架提供了DataAnnotationsValidator来验证表单,但是DataAnnotationsValidator仅验证绑定到表单的模型的基础类型的直接成员,并不能验证表单模型中的复杂类型(引用类型)属性。

如果想要验证绑定模型的整个对象图(包括模型中的复杂类型),可以尝试使用Microsoft.AspNetCore.Components.DataAnnotations.Validation 包提供的 ObjectGraphDataAnnotationsValidator组件

  • Microsoft.AspNetCore.Components.DataAnnotations.Validation可以从Nuget中下载
  • Microsoft.AspNetCore.Components.DataAnnotations.Validation包据官方介绍,处于试验阶段,不知道有啥坑等着,能不用就先别用。

实现步骤

先创建一个表单模型类

  • 示例

    public class ShipDescription
    {[Required][StringLength(40, ErrorMessage = "Description too long (40 char).")]public string? ShortDescription { get; set; }[Required][StringLength(240, ErrorMessage = "Description too long (240 char).")]public string? LongDescription { get; set; }
    }
    

在模型中的复杂类型属性上,使用[ValidateComplexType]特性

  • 示例

    public class Starship
    {...[ValidateComplexType]public ShipDescription ShipDescription { get; set; } = new();...
    }
    

EditForm表单中,使用<ObjectGraphDataAnnotationsValidator>组件

  • 示例

    <EditForm ...><ObjectGraphDataAnnotationsValidator />...
    </EditForm>
    

相关文章:

第四章 表单(3)- 表单验证

在Blazor中&#xff0c;表单的验证可以通过两种方式实现&#xff0c;一种是使用Blazor所提供表单验证特性&#xff0c;另一种是使用ValidationMessageStore进行验证。 表单验证的基础使用(内置特性) 一、内置特性表单验证的开启 Blazor中&#xff0c;使用表单组件<EditFo…...

手撕AVL树

引入&#xff1a;为何要有AVL树&#xff0c;二次搜索树有什么不足&#xff1f; 二叉搜索树有其自身的缺陷&#xff0c;假如往树中插入的元素有序或者接近有序&#xff0c;二叉搜索树就会退化成单支树&#xff0c;时间复杂度会退化成O(N)&#xff0c;因此产生了AVL树&#xff0c…...

Linux驱动开发练习案例

1 开发目标 1.1 架构图 操作系统&#xff1a;基于Linux5.10.10源码和STM32MP157开发板&#xff0c;完成tf-a(FSBL)、u-boot(SSBL)、uImage、dtbs的裁剪&#xff1b; 驱动层&#xff1a;为每个外设配置DTS并且单独封装外设驱动模块。其中电压ADC测试&#xff0c;采用linux内核…...

Redis 下载 — Ubuntu22.04稳定版,配置

官方文档 &#xff1a; https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/ Nano学习 &#xff1a; 【Linux环境下最先应该掌握的文本编辑器nano】https://www.bilibili.com/video/BV1p8411z7dJ?vd_source5ce003da2a16f44ea73ec9bbc30389e4 Redis配置…...

有没有可以帮助理解高数的视频或者书籍资料?

高数的学习是一个入门很高&#xff0c;但是一旦入门之后&#xff0c;就会变得比较简单的科目。 可是&#xff0c;我们应该怎么入门高数呢&#xff1f;在当年刚开始学习高数的时候&#xff0c;我也有过这样的困惑。 但是&#xff0c;后来我发现&#xff0c;我总是可以在经历一…...

了解拦截器

目录 什么是拦截器 拦截器的基本使用 拦截器的使用步骤 拦截器路径设置 拦截器执行流程 一、什么是拦截器 拦截器是Spring框架提供的核心功能之一&#xff0c;主要用来拦截用户的请求&#xff0c;在指定方法前后&#xff0c;根据业务需要执行预先设定的代码。 开发人员可以…...

Linux / Windows 下 Mamba / Vim / Vmamba 安装教程及安装包索引

目录 背景0. 前期环境查询/需求分析1. Linux 平台1.1 Mamba1.2 Vim1.3 Vmamba 2. Windows 平台2.1 Mamba2.1.1 Mamba 12.1.2 Mamba 2- 治标不治本- 终极版- 高算力版 2.2 Vim- 治标不治本- 终极版- 高算力版 2.3 Vmamba- 治标不治本- 终极版- 高算力版 3. Linux / Windows 双平…...

prism WPF 对话框

项目结构 1.创建对话框 用户控件 Views \ DialogView.xaml <UserControl x:Class"PrismWpfApp.Views.DialogView"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"…...

eventEmitter实现

没有做任何异常处理,简单模拟实现 事件对象的每一个事件都对应一个数组 /*__events {"事件1":[cb1,cb2],"事件2":[cb3,cb4],"事件3":[...],"事件4":[...],};*/class E{__events {};constructor(){}//注册监听回调on(type , callbac…...

Koordinator-NodeInfoCollector

Run 每秒执行一次 func (n *nodeInfoCollector) Run(stopCh <-chan struct{}) {go wait.Until(n.collectNodeInfo, n.collectInterval, stopCh) }collectNodeInfo() 采集node cpu信息采集node numa信息func (n *nodeInfoCollector) collectNodeInfo() {started := time.No…...

洛谷题单3-P5724 【深基4.习5】求极差 最大跨度值 最大值和最小值的差-python-流程图重构

题目描述 给出 n n n 和 n n n 个整数 a i a_i ai​&#xff0c;求这 n n n 个整数中的极差是什么。极差的意思是一组数中的最大值减去最小值的差。 输入格式 第一行输入一个正整数 n n n&#xff0c;表示整数个数。 第二行输入 n n n 个整数 a 1 , a 2 … a n a_1,…...

SignalR给特定User发送消息

1、背景 官网上SignalR的demo很详细&#xff0c;但是有个特别的问题&#xff0c;就是没有详细阐述如何给指定的用户发送消息。 2、解决思路 网上整体解决思路有三个&#xff1a; 1、最简单的方案&#xff0c;客户端连接SignalR的Hub时&#xff0c;只是简单的连接&#xff0c…...

新浪财经股票每天10点自动爬取

老规矩还是先分好三步&#xff0c;获取数据&#xff0c;解析数据&#xff0c;存储数据 因为股票是实时的&#xff0c;所以要加个cookie值&#xff0c;最好分线程或者爬取数据时等待爬取&#xff0c;不然会封ip 废话不多数&#xff0c;直接上代码 import matplotlib import r…...

【CSP】202403-1词频统计

文章目录 算法思路1. 数据结构选择2. 输入处理3. 统计出现的文章数4. 输出结果 代码示例代码优化 样例输入 4 3 5 1 2 3 2 1 1 1 3 2 2 2 2 3 2样例输出 2 3 3 6 2 2算法思路 1. 数据结构选择 vector<int>&#xff1a;用于存储每篇文章的单词列表&#xff08;可能包含…...

CentOs系统部署DNS服务

1. 安装 Bind 软件包 首先需要安装bind以及相关的工具包&#xff0c;在终端中执行以下命令&#xff1a; bash sudo yum install bind bind-utils -y2. 配置主配置文件 Bind 的主配置文件是/etc/named.conf&#xff0c;你可以使用文本编辑器&#xff08;如vim&#xff09;打开…...

LintCode第974题-求矩阵各节点的最短路径(以0为标准)

描述 给定一个由0和1组成的矩阵&#xff0c;求每个单元格最近的0的距离。 两个相邻细胞之间的距离是1。 给定矩阵的元素数不超过10,000。 在给定的矩阵中至少有一个0。 单元格在四个方向上相邻:上&#xff0c;下&#xff0c;左和右。 样例 例1: 输入: [[0,0,0],[0,0,0],[0…...

吴恩达深度学习复盘(6)神经网络的矢量化原理

矢量化基础是线性运算&#xff0c;这里先简单复习一下。线性基本运算基本没什么&#xff0c;大量使用的有点乘和叉乘。 基本例子 1. 矩阵的基本概念 - 矩阵可以看作是一个块或者二维数组&#xff0c;这是对矩阵的一个在计算机计算的直观描述。 2. 向量的点积&#xff08;内积…...

ISIS多区域配置

一、什么是ISIS多区域 ISIS&#xff08;Intermediate System to Intermediate System&#xff09;多区域是指网络被划分为多个逻辑区域&#xff08;Areas&#xff09;&#xff0c;不同区域之间通过特定的ISIS路由器&#xff08;Level-1-2&#xff09;进行路由交互。多区域设计提…...

The emulator process for AVD xxx has terminated

问题描述 离线环境下部署Android虚拟机&#xff0c;启动时报错The emulator process for AVD xxx has terminated&#xff0c;其中xxx为虚拟机名称。 解决过程 可先在C:\Users\admin\AppData\Local\Google\AndroidStudio2024.3\log目录下找到idea.log文件&#xff0c;其中记录…...

Haskell语言的区块链扩展性

Haskell语言的区块链扩展性研究 引言 区块链技术近年来在金融、供应链、物联网等多个领域取得了显著的进展。作为一种分布式账本技术&#xff0c;区块链的核心在于其去中心化、不可篡改和透明性。然而&#xff0c;随着应用的不断深入&#xff0c;区块链面临着可扩展性、性能、…...

第11/100节:三点估算

第11/100节&#xff1a;三点估算 三、完成某信息系统集成项目中的一个最基本的工作单元 A 所需的时间&#xff0c;乐观的估计需 8 天&#xff0c;悲观的估计需 38天&#xff0c;最可能的估计需 20 天&#xff0c;按照三点估算方法进行估算&#xff0c;项目的工期应该为&#xf…...

Tourists

一道圆方树恶心题&#xff0c;*3200&#xff0c;不知道为什么不评黑。 这道题很容易直接想到圆方树&#xff1a;因为两个操作如果在树上&#xff0c;都需要树链剖分 线段树维护。而将这么一个普通图转化为一棵树&#xff0c;也就只有圆方树这种形式了。 于是就可以综合使用圆…...

【动态规划】深入动态规划:连续子结构的算法剖析

文章目录 前言例题一、最大子数组和二、环形子数组的最大和三、 乘积最大子数组四、乘积为正数的最长子数组五、等差数列划分六、最长湍流子数组七、单词拆分八、环绕字符串中唯一的子字符串 结语 前言 什么是是动态规划连续子数组、子串系列算法问题? 连续子数组问题通常聚焦…...

结肠镜3D视频数据集-C3VD论文中文版

文章目录 标题作者摘要一、介绍1.1. 相关工作1.1.1. 内镜重建数据集1.1.2. 注册真实和虚拟内窥镜图像1.1.3. 2D-3D注册1.2. 贡献 二、方法2.1. 幻影模型生产2.2. 数据采集2.3. 注册流程概述2.3.1. 数据预处理2.3.2. 目标深度估计2.3.3. 渲染深度帧2.3.4. 边缘损失和优化 2.4. 模…...

封装自己的api签名sdk

api平台接口调用&#xff0c;需要通过签名去核对是不是有效的用户&#xff0c;&#xff0c;一般会给两个key&#xff0c;acceeKey 和 secretKey,第一个相当于用户名&#xff0c;第二个相当于密钥&#xff0c;&#xff0c;&#xff0c;前端通过一定的算法&#xff0c;&#xff0…...

ASP.NET Core Web API 中 HTTP状态码的分类及对应的返回方法

文章目录 前言一、HTTP状态码分类及常用方法二、具体返回方法示例1&#xff09; 2xx 成功类2&#xff09;4xx 客户端错误3&#xff09;5xx 服务器错误4&#xff09;其他特殊状态码 三、高级返回方式1&#xff09;使用 IActionResult 与 ActionResult<T>2&#xff09;统一…...

函数和模式化——python

一、模块和包 将一段代码保存为应该扩展名为.py 的文件&#xff0c;该文件就是模块。Python中的模块分为三种&#xff0c;分别为&#xff1a;内置模块、第三方模块和自定义模块。 内置模块和第三方模块又称为库内置模块&#xff0c;有 python 解释器自带&#xff0c;不用单独安…...

LeetCode 1817 查找用户活跃分钟数

深入剖析 LeetCode 用户活跃分钟数统计问题 一、题目详情 给定用户在 LeetCode 的操作日志&#xff0c;日志以二维整数数组logs表示&#xff0c;其中每个logs[i][IDi, timei]&#xff0c;意味着 ID 为IDi的用户在timei分钟时执行了某个操作。多个用户能够同时执行操作&#x…...

matlab从pytorch中导入LeNet-5网络框架

文章目录 一、Pytorch的LeNet-5网络准备二、保存用于导入matlab的model三、导入matlab四、用matlab训练这个导入的网络 这里演示从pytorch的LeNet-5网络导入到matlab中进行训练用。 一、Pytorch的LeNet-5网络准备 根据LeNet-5的结构图&#xff0c;我们可以写如下结构 import…...

网络:华为HCIA学习笔记:ICMP协议

ICMP&#xff08;Internet Control Message Protocol&#xff09;Internet控制消息协议 前言ICMPICMP重定向ICMP差错监测ICMP错误报告ICMP数据包格式ICMP消息类型和编码类型ICMP应用-PingICMP应用-Tracert 总结 前言 Internet控制消息协议ICMP (Internet Control Message Prot…...

Visio | 将(.vsdx)导出为更清楚/高质量的图片(.png) | 在Word里面的visio图

此时大家在用Visio画完图直接复制到word里面后&#xff0c;如果后期需要重新保存高清图片&#xff0c;但是此时图片在word&#xff0c;是不是很多人会选择直接crtlA截图复制&#xff0c;这样出来的图又不清晰又小&#xff0c;完全不符合你导的审美&#xff0c;接下来跟着我&…...

算法设计学习8

实验目的及要求&#xff1a; 通过深入学习树&#xff08;Tree&#xff09;和二叉树&#xff08;Binary Tree&#xff09;这两种重要的数据结构&#xff0c;掌握它们的基本概念、性质和操作&#xff0c;提高对树形结构的理解和应用能力。通过本实验&#xff0c;学生将深化对树和…...

Dive into Deep Learning - 2.4. Calculus (微积分)

Dive into Deep Learning - 2.4. Calculus {微积分} 1. Derivatives and Differentiation (导数和微分)1.1. Visualization Utilities 2. Chain Rule (链式法则)3. DiscussionReferences 2.4. Calculus https://d2l.ai/chapter_preliminaries/calculus.html For a long time, …...

kotlin中const 和val的区别

在 Kotlin 中&#xff0c;const 和 val 都是用来声明常量的&#xff0c;但它们的使用场景和功能有所不同&#xff1a; 1. val: val 用于声明只读变量&#xff0c;也就是不可修改的变量&#xff08;类似于 Java 中的 final 变量&#xff09;。它可以是任何类型&#xff0c;包括…...

Webpack中loader的作用。

文章目录 前言1. 处理样式文件2. 处理 JavaScript 文件3. 处理其他文件总结 前言 在 Webpack 中&#xff0c;Loader 是用于对模块的源代码进行转换的工具&#xff0c;它能够将不同类型的文件&#xff08;如 CSS、图片、字体、TypeScript 等&#xff09;转换为有效的 JavaScrip…...

C++ 极简常用内容

C 极简常用内容 1. 类与对象 定义&#xff1a;封装数据&#xff08;成员变量&#xff09;和行为&#xff08;成员函数&#xff09;的自定义类型。 Demo&#xff1a; class Car { public:string brand;void drive() { cout << brand << " is moving." …...

如何在windows 环境、且没有显卡的情况下用python跑通从ModelScope下载的大模型的调用

文章目录 背景介绍源代码&#xff1a;安装调试过程1.设置第三方镜像源2.预先安装&#xff1a;3.在python中创建代码&#xff1a;4.最终修改程序,将device_map从“cuda”改成“auto”&#xff0c;大模型调用1.5B&#xff08;1___5B)的5.最终跑出结果解释&#xff1a;示例&#x…...

MINIQMT学习课程Day10

开始获取股票数据课程的学习&#xff1a; 获取qmt账号的持仓情况后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的委托状况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件 导入包&#xff1a…...

如何彻底关闭Windows 10中的Xbox游戏栏

一、打工人的困扰&#xff1a;不速之客“Game Bar” 在日常工作中&#xff0c;许多使用Windows 10的用户常常被一个不起眼却频频打扰的系统功能困扰&#xff0c;那就是“Xbox游戏栏”&#xff08;Game Bar&#xff09;。当你正在专注处理紧急的Excel表格或准备PPT汇报&#xf…...

26考研资料分享考研资料合集 百度网盘(仅供参考学习)

考研资料分享考研资料合集 百度网盘&#xff08;仅供参考学习&#xff09; 通过网盘分享的文件&#xff1a;2026考研英语数学政治最新等3个文件 链接1: https://pan.baidu.com/s/1JXBI9ROng4KAWHoaUHpkug?pwdjydb 提取码: jydb 链接2:https://pan.baidu.com/s/1a…...

59.基于ssm和vue学生考试成绩管理系统

目录 1.系统的受众说明 2.系统关键技术 2.1 java技术 2.2 MYSQL数据库 2.3 B/S结构 3.系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2经济可行性 3.2 系统性能分析 3.3 系统功能分析 3.5系统流程分析 3.5.1登录流程 3.5.2注册流程 3.5.3添加信息流程 3.5.4删…...

常见的ETL工具分类整理

一、开源ETL工具 ‌Kettle&#xff08;Pentaho Data Integration&#xff09;--Spoon‌ 设计及架构&#xff1a;面向数据仓库建模的传统ETL工具。使用方式&#xff1a;C/S客户端模式&#xff0c;开发和生产环境需要独立部署&#xff0c;任务编写、调试、修改都在本地。底层架构…...

【leetcode100】数组中的第K个最大元素

1、题目描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2,…...

markdown语法学习

三化markdown语法 研究对象系统化全局化结构化markdown语法富文本字体样式*斜体*&#xff0c;主题样式#&#xff0c;表格样式||&#xff0c;代码块样式&#xff0c;待办样式- [ ]样式之间互相协作&#xff0c;互不冲突 待办 斜体 加粗 标题 删除线 public class{ //代码块 …...

Linux_4

开始学习ssh工具 在做开发的时候,肯定不止一台服务器,那么假设每台服务器都是Linux服务器,要在服务器上操作就需要登入终端,即Terminal。ssh的作用就是可以通过一个服务器登陆上其他的服务器。 登陆到哪个服务器看到的就是哪个服务器的终端terminal。 ssh登陆 ssh user@…...

Netty——连接超时 与 断开重连

文章目录 1. 处理连接超时和断开重连的原因2. 处理连接超时和断开重连的方法2.1 处理连接超时2.1.1 步骤一&#xff1a;配置连接超时时间2.1.2 步骤二&#xff1a;监听连接结果 2.2 处理断开重连2.2.1 步骤一&#xff1a;监听连接断开事件2.2.2 步骤二&#xff1a;实现重连逻辑…...

linux 进程/线程设置核亲和性

1&#xff0c;线程绑定内核 #include <pthread.h> #include <stdio.h> #include <stdlib.h> // 定义一个函数&#xff0c;用于设置线程的CPU亲和性 void set_thread_affinity(pthread_t thread, int cpu_id) { cpu_set_t cpuset; int s; // 清空CPU集…...

前端页面鼠标移动监控(鼠标运动、鼠标监控)鼠标节流处理、throttle、限制触发频率(setTimeout、clearInterval)

文章目录 使用lodashjs库手动实现节流&#xff08;通过判断之前设定的定时器setTimeout是否存在&#xff09; 使用lodashjs库 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Com…...

【MySQL基础-21】MySQL事务机制详解:原理、实现与最佳实践

在现代数据库系统中&#xff0c;事务机制是确保数据一致性和完整性的核心技术。MySQL作为最流行的开源关系型数据库之一&#xff0c;其事务实现机制对于开发者而言至关重要。本文将深入探讨MySQL的事务机制&#xff0c;包括核心概念、实现原理、隔离级别以及实际应用中的最佳实…...

Transformer+BO-SVM时间序列预测(Matlab)

TransformerBO-SVM时间序列预测&#xff08;Matlab&#xff09; 目录 TransformerBO-SVM时间序列预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 普通的单变量时序已经用腻了&#xff0c;审稿人也看烦了&#xff0c;本期推出一期高创…...