From 8cbec826817f842bd6fd1c81c470ce220df71f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Thu, 13 Apr 2023 16:29:41 +0800 Subject: [PATCH] add RowUtil.java --- docs/zh/db-row.md | 51 ++++++++- .../java/com/mybatisflex/core/row/Row.java | 14 +-- .../com/mybatisflex/core/row/RowSetter.java | 71 ------------ .../com/mybatisflex/core/row/RowUtil.java | 108 ++++++++++++++++++ 4 files changed, 161 insertions(+), 83 deletions(-) delete mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowSetter.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java diff --git a/docs/zh/db-row.md b/docs/zh/db-row.md index bbd4355c..9414e116 100644 --- a/docs/zh/db-row.md +++ b/docs/zh/db-row.md @@ -37,24 +37,58 @@ Page rowPage = Db.paginate("tb_account",3,10,query); > > 具体参考: [Db.java](./mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Db.java) 。 -## Row 转换为 Entity +## Row.toEntity() + +`Row.toEntity(Entity.class)` 方法主要是用于可以把 Row 转换为 entity 实体类。通过这个方法,可以把 Entity 里的 +`@Column()` 配置的列名和 Row 里的 key 进行自动关联。 + +代码示例: ```java -Row row = Db.selectOneById("tb_account","id",1); +Row row = Db.selectOneBySql("select * from ...."); Account entity = row.toEntity(Account.class); ``` +## Row.toObject() + +`Row.toObject(Other.class)` 和 `Row.toEntity(Entity.class)` 和相似。不一样的地方在于 `Row.toObject(Other.class)` 是通过去查找 +`Other.class` 的 `setter` 方法去匹配 Row 的 key 进行赋值的。 + +例如 `Other.class` 的代码如下: + +```java +public class Other { + private String id; + private String userName; + + //getter setter +} +``` + +那么,当我们去通过 SQL 查询得到 Row 的时候,Row 里的 `key` 为 `userName`、`UserName`、`USERNAME`、`user_name`、`USER_NAME` 等 +都能自动适配到 `Other.userName` 属性。这个方法常用于把 Row 直接转换为 VO 的场景。 + +> PS:我们可以通过调用 `RowUtil.registerMapping(clazz, columnSetterMapping)` 去让更多的 `字段` 名称和 `属性` 进行匹配。 + + +代码示例: + +```java +Row row = Db.selectOneBySql("select * from ...."); +Other other = row.toObject(Other.class); +``` + ## Row 字段转化为驼峰风格 ```java -Row row = Db.selectOneById("tb_account","id",1); +Row row = Db..selectOneBySql("select * from ...."); Map result = row.toCamelKeysMap(); ``` ## Row 字段转换为下划线风格 ```java -Row row = Db.selectOneById("tb_account","id",1); +Row row = Db..selectOneBySql("select * from ...."); Map result = row.toUnderlineKeysMap(); ``` @@ -92,3 +126,12 @@ row.set(ACCOUNT.USER_NAME,"Michael"); Db.insert("tb_account",row); ``` +## RowUtil 工具类 + +`RowUtil` 工具类是用于帮助用户快速的把 `Row` 或者 `List` 转换为 VO 的工具类。其提供的方法如下: + +- `RowUtil.toObject(row, objectClass)` +- `RowUtil.toObjectList(rows, objectClass)` +- `RowUtil.toEntity(row, entityClass)` +- `RowUtil.toEntityList(rows, entityClass)` +- `RowUtil.registerMapping(clazz, columnSetterMapping)` 用于注册数据库 `字段` 名称和 Class 属性的映射关系。 \ No newline at end of file diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java index 0e8ec379..4840894a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java @@ -17,9 +17,10 @@ package com.mybatisflex.core.row; import com.mybatisflex.core.javassist.ModifyAttrsRecord; import com.mybatisflex.core.query.QueryColumn; -import com.mybatisflex.core.table.TableInfo; -import com.mybatisflex.core.table.TableInfoFactory; -import com.mybatisflex.core.util.*; +import com.mybatisflex.core.util.ArrayUtil; +import com.mybatisflex.core.util.ConvertUtil; +import com.mybatisflex.core.util.SqlUtil; +import com.mybatisflex.core.util.StringUtil; import java.math.BigDecimal; import java.math.BigInteger; @@ -275,14 +276,11 @@ public class Row extends HashMap implements ModifyAttrsRecord { } public T toEntity(Class entityClass) { - TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); - return tableInfo.newInstanceByRow(this); + return RowUtil.toEntity(this, entityClass); } public T toObject(Class objectClass) { - Object instance = ClassUtil.newInstance(objectClass); - RowSetter.setObject(this, instance); - return (T) instance; + return RowUtil.toObject(this, objectClass); } public Map toCamelKeysMap() { diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowSetter.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowSetter.java deleted file mode 100644 index 56a0a085..00000000 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowSetter.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). - *

- * 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 - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * 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.row; - -import com.mybatisflex.core.util.ClassUtil; -import com.mybatisflex.core.util.ConvertUtil; -import com.mybatisflex.core.util.StringUtil; -import org.apache.ibatis.util.MapUtil; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -class RowSetter { - - static Map, Map> getterMethods = new ConcurrentHashMap<>(); - - static void setObject(Row row, Object toObject) { - Map setterMethods = getSetterMethods(toObject.getClass()); - row.forEach((column, columnValue) -> { - Method setter = setterMethods.get(column); - try { - if (setter != null) { - Object value = ConvertUtil.convert(columnValue, setter.getParameterTypes()[0]); - setter.invoke(toObject, value); - } - } catch (Exception e) { - throw new RuntimeException("Can not invoke method: " + setter); - } - }); - } - - - private static Map getSetterMethods(Class aClass) { - return MapUtil.computeIfAbsent(getterMethods, aClass, aClass1 -> { - Map getterMethodsMapping = new HashMap<>(); - List setters = ClassUtil.getAllMethods(aClass1, - method -> method.getName().startsWith("set") - && method.getParameterCount() == 1 - && Modifier.isPublic(method.getModifiers()) - ); - for (Method setter : setters) { - String column = setter.getName().substring(3); - getterMethodsMapping.put(column, setter); - getterMethodsMapping.put(column.toLowerCase(), setter); - getterMethodsMapping.put(column.toUpperCase(), setter); - getterMethodsMapping.put(StringUtil.firstCharToLowerCase(column), setter); - getterMethodsMapping.put(StringUtil.camelToUnderline(column), setter); - getterMethodsMapping.put(StringUtil.camelToUnderline(column).toUpperCase(), setter); - getterMethodsMapping.put(StringUtil.underlineToCamel(column), setter); - } - return getterMethodsMapping; - }); - } -} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java new file mode 100644 index 00000000..a55152e6 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * 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 + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.row; + +import com.mybatisflex.core.table.TableInfo; +import com.mybatisflex.core.table.TableInfoFactory; +import com.mybatisflex.core.util.ClassUtil; +import com.mybatisflex.core.util.ConvertUtil; +import com.mybatisflex.core.util.StringUtil; +import org.apache.ibatis.util.MapUtil; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class RowUtil { + + private static final Map, Map> classGettersMapping = new ConcurrentHashMap<>(); + + public static T toObject(Row row, Class objectClass) { + T instance = ClassUtil.newInstance(objectClass); + Map setterMethods = getSetterMethods(objectClass); + row.forEach((column, columnValue) -> { + Method setter = setterMethods.get(column.toLowerCase()); + try { + if (setter != null) { + Object value = ConvertUtil.convert(columnValue, setter.getParameterTypes()[0]); + setter.invoke(instance, value); + } + } catch (Exception e) { + throw new RuntimeException("Can not invoke method: " + setter); + } + }); + return instance; + } + + + public static List toObjectList(List rows, Class objectClass) { + if (rows == null || rows.isEmpty()) { + return Collections.emptyList(); + } else { + List objectList = new ArrayList<>(); + for (Row row : rows) { + objectList.add(toObject(row, objectClass)); + } + return objectList; + } + } + + + public static T toEntity(Row row, Class entityClass) { + TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); + return tableInfo.newInstanceByRow(row); + } + + + public static List toEntityList(List rows, Class entityClass) { + if (rows == null || rows.isEmpty()) { + return Collections.emptyList(); + } else { + TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); + List entityList = new ArrayList<>(); + for (Row row : rows) { + T entity = tableInfo.newInstanceByRow(row); + entityList.add(entity); + } + return entityList; + } + } + + + public static void registerMapping(Class clazz, Map columnSetterMapping) { + classGettersMapping.put(clazz, columnSetterMapping); + } + + + private static Map getSetterMethods(Class aClass) { + return MapUtil.computeIfAbsent(classGettersMapping, aClass, aClass1 -> { + Map columnSetterMapping = new HashMap<>(); + List setters = ClassUtil.getAllMethods(aClass1, + method -> method.getName().startsWith("set") + && method.getParameterCount() == 1 + && Modifier.isPublic(method.getModifiers()) + ); + for (Method setter : setters) { + String column = setter.getName().substring(3); + columnSetterMapping.put(column.toLowerCase(), setter); + columnSetterMapping.put(StringUtil.camelToUnderline(column).toLowerCase(), setter); + columnSetterMapping.put(StringUtil.underlineToCamel(column).toUpperCase(), setter); + } + return columnSetterMapping; + }); + } +}