前置条件

要求版本 2.1.0.0 及以上

<parent>
    <groupId>cn.flyrise</groupId>
    <artifactId>pai</artifactId>
    <version>2.1.0.0</version>
    <relativePath/>
</parent>

引用依赖

<parent>
    <groupId>cn.flyrise</groupId>
    <artifactId>pai-common-i18nkit</artifactId>
</parent>

定义 i18n 资源

储存目录:src\main\resources\i18n

文件夹里包含多个资源文件:

  • messages.properties
  • messages_en_US.properties
  • messages_zh_CN.properties
  • messages_zh_TW.properties

注意事项
1.其中 messages.properties 是个默认文件,即使为空也要有,否则MessageSource加会变成[Empty MessageSource]
2.切记切记所有文件编码必需是 UTF-8 格式

配置application.yaml

spring:
  messages:
    #相对路径 开头请勿添加斜杠, 注意要放一个messages.properties 否则会加载失败,建议直接把这个当成中文来用
    basename: i18n/messages
    encoding: UTF-8

定义错误常量类

src\main\java\cn\flyrise\pai\demo\exception\BusinessErrors.java

划重点:
示例1:public static final Message ERR_1001 = Message.create(“walking”, “1001”, “{}数据已存在”)
示例2:public static final Message ERR_1001 = Message.create(“1001”, “{}数据已存在”)

  • 1001 :错误代码,取值范围 1001-2999 (与 VO的InvalidCode 3001-9999校验区分开,如业务特别复杂可以考虑升至5位各自独立编码范围段)
  • 解析到资源文件,
    • 示例1:message.walking.1001={}数据已存在
    • 示例2:message.code.1001={}数据已存在
  • {}数据已存在 :即是描述信息也是默认信息,当 message.walking.1001 在相应的资源文件中找不到时使用
  • biz.data.exist :对比应 messages.properties 中定义的Key
import cn.flyrise.common.core.domain.Message;

/**
 * 业务错误代码定义枚举类,错误代码 1001-2999
 *
 * @author Joe
 * @date 2020/5/8 星期五 16:30
 */
public class BusinessErrors  {

    private BusinessErrors() {
    }

    private static final String WALKING = "walking";
    private static final String EXCEL = "excel";

    // 通用编码示例(取值全局1001~2999)
    // message.code.1001
    public static final Message ERR_1001 = Message.create("1001", "{}数据不存在");
    // message.walking.1002
    public static final Message ERR_1002 = Message.create(WALKING, "1002", "车牌号格式不符");

    // 按模块编码(取值全局1001~2999)
    // message.walking.1001...2999
    public static final Message ERR_WALKING_1001 = Message.create(WALKING, "1001", "{}数据已存在");
    public static final Message ERR_WALKING_1002 = Message.create(WALKING, "1002", "车牌号格式不符");
    // message.excel.1001...2999
    public static final Message ERR_WALKING_1001 = Message.create(EXCEL, "1001", "{}数据已存在");
    public static final Message ERR_WALKING_1002 = Message.create(EXCEL, "1002", "格式不符");

    //... 其他错误码的定义
}

定义业务异常类

要求每个业务工程有一个独立的业务异常类,继承于BizException

主要用于Feign调用时返回异常信息有助于开发人员识别错误来源

/**
 * 演示模块异常类
 *
 * @author Joe
 * @date 2020/5/8 星期五 16:30
 */
public class DemoBizException extends BizException {

    public DemoBizException(Message error, Object... params) {
        super(error.getCode(), error.format(params));
    }
}

业务逻辑中使用常量

@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserPO, UserVO> implements IUserService {
    @Autowired
    UserMapper userMapper;

    @Override
    public boolean insert(UserPO userPO) {
        if (StrUtil.isNotEmpty(userPO.getId()) && userMapper.selectById(userPO.getId()) != null) {
            // 使用常量抛异常
            new DemoBizException(BusinessErrors.ERR_1001, userPO.getId());
        }

        return SqlHelper.retBool(userMapper.insert(userPO));
    }
}

数据对象(VO)中使用

划重点:
通过注解 @InvalidCode 实现错误消息使用

  • value: 错误编码,取值范围 3001-9999 (建议取3001-9999开始,与 常量类1001-2999 区分开)

  • message: 错误消息表达式,用 {} 包起来,Key为 messages.properties 定义(弃用)

    更新说明:
    2021/01/04 为了简化编Key的过程,message 默认为空,即得默认值为 invalid.code.xxxx(xxxx为value的数值型错误代码), properties中对应的配置为 invalid.code.xxxx=内容

  • desc: 错误消息的描述,当没有在messages.properties中定义时,会作为默认消息

UserVO.java

@ApiModel
public class UserVO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty("主键")
    private String id;

    @ApiModelProperty("账号")
    @Mapping("name")
    @NotBlank
    @InvalidCode(value = "3001", message = "{view.user.3001}", desc = "账号")
    public String name;

    @ApiModelProperty("密码")
    @NotNull
    @Size(min = 6, max = 16)
    @InvalidCode(value = "3002", desc = "密码")
    protected String password;

}

解释一下
@InvalidCode(value = “3001”, message = “{view.user.3001}”, desc = “账号”)
@InvalidCode(value = “3002”, desc = “密码”)

对应的分别是:
view.user.3001=账号
invalid.code.3002=密码

意思就是:开发者定义了message属性就以定义的为准,没有则默认为 invalid.code.编号

控制层(Controller)

   @ApiOperation("修改用户信息")
   @PostMapping("/user/info/update")
   public Reply<?> updateUserInfo(@RequestBody @Valid UserVO userVO)

开发工具包 I18nKit

  String packageName = "cn.flyrise.pai.xxx";
  // 1.针对所有使用了@ApiModelProperty 或 @InvalidCode 且有使用@NotNull等验证规则的源码类按全路径名称升序排序后按指定的起始编号(不含)重新编码
  I18nKit.renewAllWithAnnotation(ApiModelProperty.class, "cn.flyrise.xxx.model.vo");
  I18nKit.renewAllWithAnnotation(ApiModelProperty.class, "cn.flyrise.xxx.model.vo", 3000);
  I18nKit.renewAllWithAnnotation(InvalidCode.class, "cn.flyrise.xxx.model.vo");
  I18nKit.renewAllWithAnnotation(InvalidCode.class, "cn.flyrise.xxx.model.vo", 3000);

  // 2.针对所有使用了@ApiModelProperty 或 @InvalidCode 且有使用@NotNull等验证规则的源码类按全路径名称升序排序后按最大的编号(不含)编码
  I18nKit.fixAddWithAnnotation(ApiModelProperty.class, "cn.flyrise.xxx.model.vo");
  I18nKit.fixAddWithAnnotation(InvalidCode.class, "cn.flyrise.xxx.model.vo");

  // 3. 扫描生成国际化配置(使用了@InvalidCode的源代码生成配置)
  for (String s : genI18nForInvalidCode(packageName)) {
     System.out.println(s);
  }

  // 4. 扫描生成国际化配置(常量类的源代码生成配置,如: BusinessErrors.class)
  for (String s : genI18nForConstants(BusinessErrors.class)) {
     System.out.println(s);
  }

注: 以上示例中 3 不能与 1或2 同时执行,同时要求VP和常量类按以上文规则方可实现扫描生成

文档更新时间: 2023-12-29 18:43   作者:姚连洲