add RowUtil.java

This commit is contained in:
开源海哥 2023-04-13 16:29:41 +08:00
parent 59a3cb1d7a
commit 8cbec82681
4 changed files with 161 additions and 83 deletions

View File

@ -37,24 +37,58 @@ Page<Row> 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<Row>` 转换为 VO 的工具类。其提供的方法如下:
- `RowUtil.toObject(row, objectClass)`
- `RowUtil.toObjectList(rows, objectClass)`
- `RowUtil.toEntity(row, entityClass)`
- `RowUtil.toEntityList(rows, entityClass)`
- `RowUtil.registerMapping(clazz, columnSetterMapping)` 用于注册数据库 `字段` 名称和 Class 属性的映射关系。

View File

@ -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<String, Object> implements ModifyAttrsRecord {
}
public <T> T toEntity(Class<T> entityClass) {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
return tableInfo.newInstanceByRow(this);
return RowUtil.toEntity(this, entityClass);
}
public <T> T toObject(Class<T> objectClass) {
Object instance = ClassUtil.newInstance(objectClass);
RowSetter.setObject(this, instance);
return (T) instance;
return RowUtil.toObject(this, objectClass);
}
public Map<String, Object> toCamelKeysMap() {

View File

@ -1,71 +0,0 @@
/**
* 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.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<Class<?>, Map<String, Method>> getterMethods = new ConcurrentHashMap<>();
static void setObject(Row row, Object toObject) {
Map<String, Method> 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<String, Method> getSetterMethods(Class<?> aClass) {
return MapUtil.computeIfAbsent(getterMethods, aClass, aClass1 -> {
Map<String, Method> getterMethodsMapping = new HashMap<>();
List<Method> 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;
});
}
}

View File

@ -0,0 +1,108 @@
/**
* 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.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<Class<?>, Map<String, Method>> classGettersMapping = new ConcurrentHashMap<>();
public static <T> T toObject(Row row, Class<T> objectClass) {
T instance = ClassUtil.newInstance(objectClass);
Map<String, Method> 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 <T> List<T> toObjectList(List<Row> rows, Class<T> objectClass) {
if (rows == null || rows.isEmpty()) {
return Collections.emptyList();
} else {
List<T> objectList = new ArrayList<>();
for (Row row : rows) {
objectList.add(toObject(row, objectClass));
}
return objectList;
}
}
public static <T> T toEntity(Row row, Class<T> entityClass) {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
return tableInfo.newInstanceByRow(row);
}
public static <T> List<T> toEntityList(List<Row> rows, Class<T> entityClass) {
if (rows == null || rows.isEmpty()) {
return Collections.emptyList();
} else {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
List<T> entityList = new ArrayList<>();
for (Row row : rows) {
T entity = tableInfo.newInstanceByRow(row);
entityList.add(entity);
}
return entityList;
}
}
public static void registerMapping(Class<?> clazz, Map<String, Method> columnSetterMapping) {
classGettersMapping.put(clazz, columnSetterMapping);
}
private static Map<String, Method> getSetterMethods(Class<?> aClass) {
return MapUtil.computeIfAbsent(classGettersMapping, aClass, aClass1 -> {
Map<String, Method> columnSetterMapping = new HashMap<>();
List<Method> 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;
});
}
}