!188 feat:错误信息国际化支持

Merge pull request !188 from 王帅/main
This commit is contained in:
Michael Yang 2023-07-26 10:45:19 +00:00 committed by Gitee
commit d385d996b8
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
18 changed files with 293 additions and 64 deletions

View File

@ -18,6 +18,7 @@ MyBatis-Flex 使用了 APTAnnotation Processing Tool技术在项目编
| processor.enable | 全局启用apt开关 | true/false | true |
| processor.stopBubbling | 是否停止向上级合并配 | true/false | false |
| processor.genPath | APT 代码生成路径 | 合法的绝对或相对路径 | target/generated-sources/annotations |
| processor.charset | APT 代码生成文件字符集 | UTF-8 | target/generated-sources/annotations |
| processor.allInTables.enable | 是否所有的类都生成在 Tables 类里 | true/false | false |
| processor.allInTables.package | Tables 类名 | 合法的包名 | ${entityPackage}.table |
| processor.allInTables.className | Tables 类名 | 合法的类名 | Tables |

View File

@ -82,4 +82,18 @@ public final class FlexAssert {
}
}
}
/**
* 断言传入的数组内容不能为 null 或者
*/
public static <T> void assertAreNotNull(T[] elements, String msg, Object params) {
if (elements == null || elements.length == 0) {
throw FlexExceptions.wrap(msg, params);
}
for (T element : elements) {
if (element == null) {
throw FlexExceptions.wrap(msg, params);
}
}
}
}

View File

@ -15,6 +15,8 @@
*/
package com.mybatisflex.core.exception;
import com.mybatisflex.core.exception.locale.Localizable;
/**
* MybatisFlexException 异常封装类
*/
@ -61,41 +63,8 @@ public final class FlexExceptions {
return new MybatisFlexException(String.format(msg, params));
}
/**
* 断言 condition 必须为 true
*
* @param condition 条件
* @param msg 消息
* @param params 消息参数
*/
public static void assertTrue(boolean condition, String msg, Object... params) {
if (!condition) {
throw wrap(msg, params);
}
}
/**
* 断言传入的内容不能为 null
*/
public static void assertNotNull(Object object, String msg, Object params) {
assertTrue(object != null, msg, params);
}
/**
* 断言传入的数组内容不能为 null 或者
*/
public static <T> void assertAreNotNull(T[] elements, String msg, Object params) {
if (elements == null || elements.length == 0) {
throw wrap(msg, params);
}
for (T element : elements) {
if (element == null) {
throw wrap(msg, params);
}
}
public static MybatisFlexException wrap(Localizable pattern, Object... args) {
return new MybatisFlexException(pattern, args);
}
}

View File

@ -15,10 +15,23 @@
*/
package com.mybatisflex.core.exception;
import com.mybatisflex.core.exception.locale.Localizable;
import java.text.MessageFormat;
import java.util.Locale;
public class MybatisFlexException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Localizable pattern;
private Object[] arguments;
public MybatisFlexException(Localizable pattern, Object... arguments) {
this.pattern = pattern;
this.arguments = arguments;
}
public MybatisFlexException(String message) {
super(message);
}
@ -31,5 +44,19 @@ public class MybatisFlexException extends RuntimeException {
super(cause);
}
@Override
public String getMessage() {
return getMessage(Locale.CHINESE);
}
@Override
public String getLocalizedMessage() {
return getMessage(Locale.getDefault());
}
private String getMessage(Locale locale) {
String localizedString = pattern.getLocalizedString(locale);
return MessageFormat.format(localizedString, arguments);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.exception.locale;
import java.io.Serializable;
import java.util.Locale;
/**
* 可本地化字符串接口
*
* @author 王帅
* @since 2023-07-26
*/
public interface Localizable extends Serializable {
/**
* 获取源非本地化字符串
*
* @return 源字符串
*/
String getSourceString();
/**
* 获取本地化字符串
*
* @param locale 要获取字符串的区域
* @return 本地化字符串或源字符串如果没有可用的本地化版本
*/
String getLocalizedString(Locale locale);
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.exception.locale;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* 异常消息中使用的本地化消息格式的枚举
*
* @author 王帅
* @since 2023-07-26
*/
public enum LocalizedFormats implements Localizable {
OBJECT_NULL("{0} can not be null.");
private final String sourceFormat;
LocalizedFormats(String sourceFormat) {
this.sourceFormat = sourceFormat;
}
@Override
public String getSourceString() {
return this.sourceFormat;
}
@Override
public String getLocalizedString(final Locale locale) {
try {
// 本地化消息路径
String path = LocalizedFormats.class.getName().replace(".", "/");
// 获取多语言本地化消息信息文件
ResourceBundle bundle = ResourceBundle.getBundle("assets/" + path, locale);
// 获取当前语言的消息格式
if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
return bundle.getString(toString());
}
} catch (MissingResourceException mre) {
mre.printStackTrace();
// do nothing here.
}
// 如果没有该语言的本地化消息则返回源消息字符串
return sourceFormat;
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 异常信息国际化
*/
package com.mybatisflex.core.exception.locale;

View File

@ -47,20 +47,6 @@ public abstract class AbstractLogicDeleteProcessor implements LogicDeleteProcess
, getLogicNormalValue()));
}
/**
* 获取逻辑删除列未删除标记值
*
* @return 未删除标记值
*/
public abstract Object getLogicNormalValue();
/**
* 获取逻辑删除列删除时标记值
*
* @return 删除时标记值
*/
public abstract Object getLogicDeletedValue();
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.logicdelete.impl;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.dialect.IDialect;
import com.mybatisflex.core.exception.FlexAssert;
import com.mybatisflex.core.logicdelete.AbstractLogicDeleteProcessor;
import com.mybatisflex.core.table.IdInfo;
import com.mybatisflex.core.table.TableInfo;
import java.util.List;
import static com.mybatisflex.core.constant.SqlConsts.EQUALS;
/**
* 主键逻辑删除处理器
*
* @author 王帅
* @see <a href="https://gitee.com/mybatis-flex/mybatis-flex/issues/I7O1VV">I7O1VV</a>
* @since 2023-07-26
*/
public class PrimaryKeyLogicDeleteProcessor extends AbstractLogicDeleteProcessor {
@Override
public String buildLogicDeletedSet(String logicColumn, TableInfo tableInfo, IDialect dialect) {
List<IdInfo> primaryKeyList = tableInfo.getPrimaryKeyList();
FlexAssert.notEmpty(primaryKeyList, "Must have one primary key.");
String column = primaryKeyList.get(0).getColumn();
return dialect.wrap(logicColumn) + EQUALS + dialect.wrap(column);
}
/**
* 正常未删除的值为 0 或者可配置为其他值
*/
@Override
public Object getLogicNormalValue() {
Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete();
if (normalValueOfLogicDelete instanceof Number) {
return normalValueOfLogicDelete;
}
return 0;
}
/**
* 逻辑删除后则更新逻辑删除字段值为主键的值
*/
@Override
public Object getLogicDeletedValue() {
return null;
}
}

View File

@ -18,7 +18,6 @@ package com.mybatisflex.core.provider;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.dialect.DialectFactory;
import com.mybatisflex.core.exception.FlexAssert;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.query.CPI;
import com.mybatisflex.core.query.QueryTable;
import com.mybatisflex.core.query.QueryWrapper;
@ -240,7 +239,7 @@ public class EntitySqlProvider {
Object[] primaryValues = tableInfo.buildPkSqlArgs(entity);
Object[] tenantIdArgs = tableInfo.buildTenantIdArgs();
FlexExceptions.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity);
FlexAssert.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity);
ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs));

View File

@ -18,7 +18,6 @@ package com.mybatisflex.core.provider;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.dialect.DialectFactory;
import com.mybatisflex.core.exception.FlexAssert;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.query.CPI;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
@ -247,7 +246,7 @@ public class RowSqlProvider {
Object[] primaryValues = tableInfo.buildPkSqlArgs(entity);
Object[] tenantIdArgs = tableInfo.buildTenantIdArgs();
FlexExceptions.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity);
FlexAssert.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity);
ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs));

View File

@ -0,0 +1 @@
OBJECT_NULL={0} \u4E0D\u80FD\u4E3A null \u503C\u3002

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.coretest;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.exception.locale.LocalizedFormats;
import org.junit.Test;
/**
* @author 王帅
* @since 2023-07-26
*/
public class LocaleFormatTest {
@Test
public void test() {
throw FlexExceptions.wrap(LocalizedFormats.OBJECT_NULL, "primaryValues");
}
}

View File

@ -20,6 +20,8 @@ import com.mybatisflex.core.dialect.DialectFactory;
import com.mybatisflex.core.dialect.IDialect;
import com.mybatisflex.core.logicdelete.LogicDeleteProcessor;
import com.mybatisflex.core.logicdelete.impl.*;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.table.TableInfoFactory;
import org.junit.Test;
/**
@ -41,12 +43,14 @@ public class LogicDeleteTest {
print("IntegerLogicDeleteProcessor", new IntegerLogicDeleteProcessor());
print("DateTimeLogicDeleteProcessor", new DateTimeLogicDeleteProcessor());
print("TimeStampLogicDeleteProcessor", new TimeStampLogicDeleteProcessor());
print("PrimaryKeyLogicDeleteProcessor", new PrimaryKeyLogicDeleteProcessor());
}
public void print(String type, LogicDeleteProcessor processor) {
System.out.println("===== " + type + " =====");
System.out.println(processor.buildLogicDeletedSet(logicColumn, null, dialect));
System.out.println(processor.buildLogicNormalCondition(logicColumn, null, dialect));
TableInfo tableInfo = TableInfoFactory.ofEntityClass(Account.class);
System.out.println(processor.buildLogicDeletedSet(logicColumn, tableInfo, dialect));
System.out.println(processor.buildLogicNormalCondition(logicColumn, tableInfo, dialect));
}
}
}

View File

@ -45,7 +45,6 @@ import java.io.PrintWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Files;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.*;
@ -383,7 +382,7 @@ public class MybatisFlexProcessor extends AbstractProcessor {
return;
}
writer = new PrintWriter(Files.newOutputStream(genJavaFile.toPath()));
writer = new PrintWriter(genJavaFile, configuration.get(ConfigurationKey.CHARSET));
writer.write(genContent);
writer.flush();
} catch (IOException e) {

View File

@ -29,6 +29,11 @@ public enum ConfigurationKey {
*/
ENABLE("processor.enable", ""),
/**
* 生成文件的字符集
*/
CHARSET("processor.charset", "UTF-8"),
/**
* APT 代码生成路径
*/

View File

@ -198,11 +198,6 @@
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>
*.properties
</exclude>
</excludes>
</resource>
</resources>