Skip to content

用户设置 v3.3.0+

用户在使用软件系统时,时常会按自己的需要更改系统设置,例如:系统主题、字体大小、表格显示列等。 为了满足用户的个性化设置需求,同时减少开发成本,框架提供了用户设置的存取功能。

简介

用户设置功能简单说就是配置数据的保存和读取——保存用户提交的数据,然后在需要时读取。

在实际开发中,我们会将配置数据按照相关性合并归类,例如:基础信息、排版设置、数据设置等。 除了逻辑上更加清晰,在读取时也可以避免一次加载过多数据,减少无效内容。 框架使用“分类(Category)”标记一组相关的配置项。

配置数据存取基于强类型,即每一类配置必须定义对应的模型类,内部据此进行序列化和反序列化。 这样不仅可以避免保存恶意传入的非预期的配置项,也可以更方便地基于类属性访问配置项。

配置定义 v3.3.3+

从 v3.3.3 起,我们对配置定义进行了简化。创建表示配置的模型类,然后添加UserSetting特性声明类别即可。 无需实现接口,也无需注册到服务容器。

示例如下:

csharp
[UserSetting("locale")]
public class UserCultureSetting
{
    [Required]
    [JsonPropertyName("lang")]
    public string Language { get; set; } = "zh-CN";

    [JsonPropertyName("date")]
    public string DateFormat { get; set; } = "Ymd";
}

上例定义了一个分类为“locale”的用户设置,可以接收两个配置项,Language 为必填项,同时还提供了默认值。

提示

模型类可以正常使用验证特性,也可以根据需要设置配置项的默认值。

因为内部使用 System.Text.Json 序列化数据,因此可以使用相关 JSON 特性控制序列化结果。

有时不同类别的配置会使用相同的数据结构,这时可以在特性中声明多个类别。

csharp
[UserSetting("page_10220341", "page_10220352")]
public class UserColumnSetting
{
    // 省略属性
}

更进一步地,如果这些类别命名相似,可以使用通配符*简化声明。

csharp
[UserSetting("page_*")]
public class UserColumnSetting
{
    // 省略属性
}

注意

使用通配符可以在未来新增相似分类时,自动适配而无需修改配置定义。 不过在获取配置时存在一些限制,请查看服务方法

配置定义(旧) v3.3.3 移除

首先需要创建表示一组配置的模型类。 模型类必须实现特定接口,按照接口约定提供分类标识。

IUserSetting

一般情况下,一个模型类对应唯一一个分类标识,表示属于该分类的相关配置项。 此时模型类需要实现 IUserSetting 接口,为 Category 属性提供值。

示例如下:

csharp
public class UserCultureSetting : IUserSetting
{
    [JsonIgnore]
    public string Category => "culture";

    [Required]
    public string Language { get; set; }
}

提示

模型类可以正常使用验证特性,也可以根据需要设置配置项的默认值。

因为内部使用 System.Text.Json 序列化数据,因此可以使用相关 JSON 特性控制序列化结果。

IUserSharedSetting

如果不同类别的配置使用相同的数据结构,例如多个系统页面中数据表格的配置,可配置的内容完全一致,但会按照页面来拆分。 这时可以共用一个模型类,实现 IUserSharedSetting 接口即可。

示例如下:

csharp
public class UserPageSetting : IUserSharedSetting
{
    [JsonIgnore]
    public List<string> Categories => ["page1201", "page1202"];

    [Required]
    public List<string> Columns { get; set; }

    public bool CardStyle { get; set; } = true;
}

通配符

在上例中,如果模型类对应的配置类别较少,声明起来还是比较方便的;反之,如果有大量配置类别要声明, 或者暂时无法预见未来可能的类别,那么操作起来就有些麻烦了。此时,可以尝试使用通配符声明配置类别。

示例如下:

csharp
public class UserPageSetting : IUserSetting
{
    [JsonIgnore]
    public string Category => "page*";

    [Required]
    public List<string> Columns { get; set; }

    public bool CardStyle { get; set; } = true;
}

通过使用通配符*,可以匹配任意数量的满足特定格式的内容。这样既可以减轻声明的麻烦,也可以兼容未来新增的类别。

配置类注册

用户设置功能仅允许操作已知的类别,因此需要提前将模型类注册到系统中。

csharp
services.AddTransient<IUserSharedSetting, UserPageSetting>();
services.AddTransient<IUserSetting, UserCultureSetting>();

提示

服务注册信息仅用来建立分类与模型类映射关系,因此使用 Transient 作用域即可。

API

保存配置

POST /api/user-settings/{category}

  • 说明:为当前登录用户保存配置,重复保存则覆盖。
  • 参数:
    • category {string} 类别,必须在后端注册。
    • body {string} 配置内容,必须为 JSON 字符串
  • 返回:主键id
js
Post('/api/user-settings/locale', JSON.stringify({ lang: 'zh-Hans' });

获取配置

GET /api/user-settings/{categories}

  • 说明:获取当前登录用户的指定配置。
  • 参数:
    • categories {string} 类别,多个以逗号分隔
  • 返回:配置数据,以 category 为对象键。
js
Get('/api/user-settings/locale,page1201');
// 返回结果
{
  "body": {
    "locale": {
      "lang": "zh-Hans"
    },
    "page1201": {
      "columns": [
        "name",
        "sex",
        "age"
      ],
      "cardStyle": false
    },
  },
  "code": 0,
  "msg": "操作成功"
}

服务方法

用户设置服务提供了读取配置的方法,方便在后端使用。

获取用户配置

T Get<T>(string userId)

  • 说明:获取配置。适用于配置类 T 仅对应一个类别的场景。如果对应多个类别,则结果无法保证与预期一致。
  • 参数:
    • userId {string} 用户编号
  • 返回:配置对象
csharp
[Autowired]
IUserSettingService settingService;

var setting = settingService.Get<UserCultureSetting>("1046200001");
Console.WriteLine(setting.Language);

获取用户配置

T Get<T>(string userId, string category)

  • 说明:获取配置。适用于配置类 T 对应多个类别,或类别包含通配符的场景。
  • 参数:
    • userId {string} 用户编号
    • category {string} 类别
  • 返回:配置对象
csharp
var setting = settingService.Get<UserPageSetting>("1046200001", "page1021");
Console.WriteLine(setting.Columns);