Skip to content

Commit db6e1e7

Browse files
authored
Merge pull request #18 from VonChange/develop
Develop
2 parents 4ae793f + 91b304e commit db6e1e7

File tree

150 files changed

+3478
-3661
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+3478
-3661
lines changed

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,19 @@ SELECT [@id column] FROM user_base
2626
</where>
2727
```
2828
## see [easy-dynamic-sql.md](easy-dynamic-sql.md)
29+
30+
* extend findByExample,findByBeanProperties [UserExample.java](spring-data-jdbc-mybatis-demo%2Fsrc%2Ftest%2Fjava%2Fcom%2Fvonchange%2Fnine%2Fdemo%2Fdao%2FUserExample.java)
31+
```
32+
userInfoMethodDao.findAll(UserExample.builder()
33+
.userCodeIn(Arrays.asList("u001","u002"))
34+
.userNameLike("ch%")
35+
.createTimeDesc(true).build());
36+
```
37+
2938
## Features
3039
* method name query [method-name-query.md](method-name-query.md)
3140
* @Id @Table @Column
32-
* extend CrudJdbcRepository not CrudRepository,because [curd-repository.md](curd-repository.md)
41+
* recommend CrudExtendRepository not CrudRepository,because [curd-repository.md](curd-repository.md)
3342
* not support @Query or QueryDSL, sql must be written in markdown
3443
* batch update [bach-update.md](bach-update.md)
3544
* [multi-datasource.md](multi-datasource.md)
@@ -38,7 +47,7 @@ SELECT [@id column] FROM user_base
3847

3948
[UserInfoRepository.java](spring-data-jdbc-mybatis-demo%2Fsrc%2Fmain%2Fjava%2Fcom%2Fvonchange%2Fnine%2Fdemo%2Fdao%2FUserInfoRepository.java)
4049
```java
41-
public interface UserInfoRepository extends CrudJdbcRepository<UserInfoDO, Long> {
50+
public interface UserInfoRepository extends CrudExtendRepository<UserInfoDO, Long> {
4251
List<UserInfoDO> findByUserCodes(@Param("userCodes") List<String> userCodes);
4352
List<UserInfoDO> findUserBySearchParam(@Param("param") SearchParam searchParam);
4453
}

README.zh-CN.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99

1010
**spring data jdbc 扩展 mybatis 动态sql能力**
1111
## What Is This?
12+
* 底层 jdbcTemplate 复杂SQL才需要mybatis动态模板能力 无QueryDSL 提供crudClient 和jdbcClient
13+
1214
* 和spring data jdbc一样的追求简单,使用jdbcTemplate,调用jdbc。不提供缓存、延迟加载、QueryDSL等JPA或mybatis的许多特性。一个简单、有限、固执己见的ORM
1315

14-
* 扩展mybatis动态sql能力(不依赖mybatis!提取了动态sql代码),可以应对复杂sql,如果换其他模板引擎或自己实现也是可以的,但有一定的学习成本,使用mybatis动态sql已比较成熟
16+
* 扩展mybatis动态sql能力(不依赖mybatis!提取了动态sql代码),可以应对复杂sql,如果换其他模板引擎也是可以的,但有学习成本
1517

16-
* SQL统一写在Markdown里,不提供@Query或QueryDSL
18+
* 复杂的SQL写在Markdown的代码片段中,不提供@Query和QueryDSL写法,但按方法名查找和扩展的findByExample可以应付大部分单表查询需求
1719

18-
* 扩展简易动态sql写法 [easy-dynamic-sql.md](easy-dynamic-sql.md)
20+
* 简化mybatis动态sql写法 [easy-dynamic-sql.md](easy-dynamic-sql.md)
1921

2022
[UserInfoRepository.md](spring-data-jdbc-mybatis-demo%2Fsrc%2Fmain%2Fresources%2Fsql%2FUserInfoRepository.md)
2123

@@ -29,18 +31,26 @@ SELECT [@id column] FROM user_info
2931
<if test="null!=createTime"> and create_time < #{createTime} </if>
3032
</where>
3133
```
34+
* 扩展findByExample 按实体属性名查询扩展 入参是任意符合规范的实体 但请慎用 传入实体不可过多字段
35+
```
36+
userInfoMethodDao.findAll(UserExample.builder()
37+
.userCodeIn(Arrays.asList("u001","u002"))
38+
.userNameLike("ch%")
39+
.createTimeDesc(true).build());
40+
```
41+
3242
## 特性
33-
* 支持按方法名查询 但不推荐过度使用 [method-name-query.md](method-name-query.md)
34-
* @Id @Table @Column 极少的注解
35-
* crud 继成 CrudJdbcRepository 不是CrudRepository 因为需要新增和去掉部分方法
43+
* 支持按方法名查询 [method-name-query.md](method-name-query.md) 以及扩展版findByExample
44+
* @Id @Table @Column @Version @Transient极少的注解
45+
* 请使用CrudExtendRepository 新增insert update insertBatch updateBatch 扩展版findByExample
3646
* 不提供@Query或QueryDSL,sql统一写在markdown文件里面
3747
* 批量更新 [bach-update.md](bach-update.md)
3848
* [多数据源.md](multi-datasource.md)
3949

4050
## Getting Started with JDBC mybatis
4151

4252
```java
43-
public interface UserInfoRepository extends CrudJdbcRepository<UserInfoDO, Long> {
53+
public interface UserInfoRepository extends CrudExtendRepository<UserInfoDO, Long> {
4454
List<UserInfoDO> findByUserCodes(@Param("userCodes") List<String> userCodes);
4555
List<UserInfoDO> findUserBySearchParam(@Param("param") SearchParam searchParam);
4656
}

common-util/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<modelVersion>4.0.0</modelVersion>
1111

1212
<artifactId>common-util</artifactId>
13-
<version>2.5.0</version>
13+
<version>2.5.0.1</version>
1414

1515
<dependencies>
1616

common-util/src/main/java/com/vonchange/common/util/ClazzUtils.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import com.vonchange.common.util.bean.convert.Converter;
44

5+
import java.net.URI;
6+
import java.net.URL;
7+
import java.util.Collection;
8+
import java.util.Locale;
9+
510
public class ClazzUtils {
611
private ClazzUtils() {
712
throw new IllegalStateException("Utility class");
@@ -12,7 +17,16 @@ private ClazzUtils() {
1217
*/
1318
public static boolean isBaseType(Class<?> clazz) {
1419
// ||clazz== Time.class||clazz == Timestamp.class
15-
return Converter.hasConvertKey(clazz) || clazz.isPrimitive() || clazz.isEnum();
20+
return Converter.hasConvertKey(clazz) || clazz.isPrimitive() ||
21+
Enum.class.isAssignableFrom(clazz) ||
22+
URI.class == clazz || URL.class == clazz ||
23+
Locale.class == clazz || Class.class == clazz;
24+
}
25+
public static boolean isBaseTypeWithArray(Class<?> clazz) {
26+
return isBaseType(clazz)||(clazz.isArray()&& isBaseType(clazz.getComponentType()))|| Collection.class.isAssignableFrom(clazz) ;
27+
}
28+
public static boolean isVersionType(Class<?> clazz) {
29+
return Integer.class==clazz||Long.class==clazz;
1630
}
1731

1832
@SuppressWarnings("unchecked")
@@ -21,6 +35,15 @@ public static <T> T cast(Class<?> clazz, Object obj) {
2135
throw new ClassCastException(cannotCastMsg(clazz, obj));
2236
return (T) obj;
2337
}
38+
public static boolean isClassExists(String className) {
39+
try {
40+
Class.forName(className);
41+
return true;
42+
} catch (ClassNotFoundException e) {
43+
return false;
44+
}
45+
}
46+
2447

2548
@SuppressWarnings("unchecked")
2649
public static <T> T cast(Object obj) {

common-util/src/main/java/com/vonchange/common/util/ConvertUtil.java

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
package com.vonchange.common.util;
22

3+
import com.vonchange.common.util.bean.BeanUtil;
4+
import com.vonchange.common.util.bean.MethodAccessData;
35
import com.vonchange.common.util.bean.convert.Converter;
6+
import com.vonchange.common.util.model.BaseField;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
49

10+
import java.lang.reflect.Field;
511
import java.math.BigDecimal;
612
import java.math.BigInteger;
713
import java.nio.charset.Charset;
814
import java.time.LocalDate;
915
import java.time.LocalDateTime;
1016
import java.time.LocalTime;
17+
import java.util.ArrayList;
18+
import java.util.Arrays;
1119
import java.util.Date;
20+
import java.util.HashMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
import java.util.concurrent.ConcurrentHashMap;
1224

1325
/**
1426
* 简单方式(效率高)实现类型转换,细节部分会不如ConvertUtils :ConvertUtils一次类型转换需要69ms 有点代价过高
@@ -17,15 +29,78 @@
1729
* @author vonchange@163.com
1830
*/
1931
public class ConvertUtil {
20-
private static final String NULLSTR = "NULL";
32+
private static Logger log = LoggerFactory.getLogger(ConvertUtil.class);
33+
private static final String NULL_STR = "NULL";
34+
private static final Map<String, List<BaseField>> fieldMap = new ConcurrentHashMap<>();
35+
36+
@SuppressWarnings("unchecked")
37+
public static <T> Map<String, Object> toMap(T entity) {
38+
if (entity instanceof Map) {
39+
return (Map<String, Object>) entity;
40+
}
41+
List<BaseField> baseFields =getBeanInfo(entity.getClass());
42+
MethodAccessData methodAccessData = BeanUtil.methodAccessData(entity.getClass());
43+
Map<String, Object> map = new HashMap<>();
44+
for (BaseField baseField : baseFields) {
45+
Integer index =BeanUtil.getPropertyIndex(methodAccessData,baseField.getFieldName());
46+
if(null!=index){
47+
Object value=methodAccessData.getMethodAccess().invoke(entity,index);
48+
map.put(baseField.getFieldName(),value);
49+
}
50+
}
51+
return map;
52+
}
53+
public static List<BaseField> getBeanInfo(Class<?> clazz){
54+
String entityName = clazz.getName();
55+
if(!fieldMap.containsKey(entityName)){
56+
initField(clazz);
57+
}
58+
return fieldMap.get(entityName);
59+
}
60+
private static void getFieldList(Class<?> clazz, List<Field> fieldList) {
61+
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
62+
if(null!=clazz.getSuperclass()){
63+
getFieldList(clazz.getSuperclass(), fieldList);
64+
}
65+
}
66+
67+
private static synchronized void initField(Class<?> clazz) {
68+
if(ClazzUtils.isBaseType(clazz)){
69+
return;
70+
}
71+
String entityName=clazz.getName();
72+
log.debug("initField {}",entityName);
73+
List<Field> fieldList = new ArrayList<>();
74+
getFieldList(clazz,fieldList);
75+
List<BaseField> entityFieldList = new ArrayList<>();
76+
Map<String,Integer> fieldHasMap = new HashMap<>();
77+
MethodAccessData methodAccessData = BeanUtil.methodAccessData(clazz);
78+
int i=0;
79+
for (Field field : fieldList) {
80+
Class<?> type = field.getType();
81+
boolean isNormalField =BeanUtil.containsProperty(methodAccessData,field.getName(),"set")
82+
&&ClazzUtils.isBaseType(type);
83+
String fieldName = field.getName();
84+
if(!isNormalField||fieldHasMap.containsKey(fieldName)){
85+
continue;
86+
}
87+
BaseField entityField = new BaseField();
88+
entityField.setFieldName(fieldName);
89+
entityField.setType(type);
90+
entityFieldList.add(entityField);
91+
fieldHasMap.put(fieldName, i);
92+
i++;
93+
}
94+
fieldMap.put(clazz.getName(), entityFieldList);
95+
}
2196

2297
private static Object toNull(Object value) {
2398
if (null == value) {
2499
return null;
25100
}
26101
if (value instanceof String) {
27102
value = value.toString().trim();
28-
if (NULLSTR.equals(value)) {
103+
if (NULL_STR.equals(value)) {
29104
return null;
30105
}
31106
if ("".equals(value)) {

common-util/src/main/java/com/vonchange/common/util/JsonUtil.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,44 @@
44
import com.fasterxml.jackson.core.JsonProcessingException;
55
import com.fasterxml.jackson.core.type.TypeReference;
66
import com.fasterxml.jackson.databind.DeserializationFeature;
7+
import com.fasterxml.jackson.databind.Module;
78
import com.fasterxml.jackson.databind.ObjectMapper;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

1112
import java.io.IOException;
13+
import java.util.ArrayList;
14+
import java.util.List;
1215

1316
public class JsonUtil {
14-
private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);
17+
private static Logger log = LoggerFactory.getLogger(JsonUtil.class);
1518
private JsonUtil() {
1619
throw new IllegalStateException("Utility class");
1720
}
21+
static ObjectMapper objectMapper;
22+
static List<String> moduleList=new ArrayList<>();
23+
static {
24+
objectMapper=new ObjectMapper();
25+
moduleList.add("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule");
26+
moduleList.add("com.fasterxml.jackson.module.paramnames.ParameterNamesModule");
27+
moduleList.add("com.fasterxml.jackson.datatype.jdk8.Jdk8Module");
28+
for (String module : moduleList) {
29+
if(ClazzUtils.isClassExists(module)){
30+
try {
31+
objectMapper.registerModule((Module) Class.forName(module).newInstance());
32+
} catch (Exception e) {
33+
log.info("registerModule {} {}",module,e.getMessage());
34+
}
35+
}
36+
}
37+
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
38+
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
39+
}
1840
public static String toJson(Object object) {
19-
ObjectMapper objectMapper = new ObjectMapper();
2041
try {
2142
return objectMapper.writeValueAsString(object);
2243
} catch (JsonProcessingException e) {
23-
logger.error("序列化对象失败{}",e);
44+
log.error("toJson",e);
2445
}
2546
return null;
2647
}
@@ -35,33 +56,22 @@ public static <T> T evalJson(String json, Class<T> clazz) throws IOException {
3556
return evalJson(json,clazz,null);
3657
}
3758
public static <T> T evalJson(String json, Class<T> clazz,TypeReference<T> type) throws IOException {
38-
ObjectMapper mapper = new ObjectMapper();
39-
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
40-
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
4159
T t =null;
4260
if(null!=clazz){
43-
t = mapper.readValue(json, clazz);
61+
t = objectMapper.readValue(json, clazz);
4462
}
4563
if(null!=type){
46-
t = mapper.readValue(json, type);
64+
t = objectMapper.readValue(json, type);
4765
}
4866
return t;
4967
}
5068

5169
private static <T> T fromJson(String json, Class<T> clazz,TypeReference<T> type) {
52-
ObjectMapper mapper = new ObjectMapper();
53-
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
54-
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
5570
T t =null;
5671
try {
57-
if(null!=clazz){
58-
t = mapper.readValue(json, clazz);
59-
}
60-
if(null!=type){
61-
t = mapper.readValue(json, type);
62-
}
72+
t=evalJson(json,clazz,type);
6373
} catch (IOException e) {
64-
logger.error("反序列化对象失败{}",e);
74+
log.error("fromJson",e);
6575
}
6676
return t;
6777
}

common-util/src/main/java/com/vonchange/common/util/MarkdownUtil.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import com.vonchange.common.util.exception.EnumUtilErrorCode;
5+
import com.vonchange.common.util.exception.ErrorMsg;
56
import com.vonchange.common.util.exception.UtilException;
67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
@@ -32,7 +33,8 @@ public static synchronized Map<String,String> readMarkdownFile(String id,b
3233
if(!notFoundError){
3334
return null;
3435
}
35-
throw new UtilException(path+" not Find");
36+
throw new UtilException(EnumUtilErrorCode.MarkdownPathNotFound,
37+
ErrorMsg.builder().message(path+" not found"));
3638
}
3739
String content=null;
3840
try {
@@ -151,7 +153,8 @@ public static String getContent(String id,boolean notFoundThrowError) {
151153
if(!notFoundThrowError){
152154
return null;
153155
}
154-
throw new UtilException(EnumUtilErrorCode.MarkdownIdNotFound,id+" not found");
156+
throw new UtilException(EnumUtilErrorCode.MarkdownIdNotFound,
157+
ErrorMsg.builder().message(id+" not found"));
155158
}
156159
String filePath= UtilAll.UString.substringBeforeLast(id, StringPool.DOT);
157160
String codeId= id.substring(filePath.length()+1);
@@ -160,7 +163,8 @@ public static String getContent(String id,boolean notFoundThrowError) {
160163
if(!notFoundThrowError){
161164
return null;
162165
}
163-
throw new UtilException(EnumUtilErrorCode.MarkdownIdNotFound,id+" not found");
166+
throw new UtilException(EnumUtilErrorCode.MarkdownIdNotFound,
167+
ErrorMsg.builder().message(id+" not found"));
164168
}
165169
String content= extendContent(contentMap,codeId);
166170
if(UtilAll.UString.isNotBlank(content)){
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.vonchange.common.util;
2+
3+
public class Three<A,B,C>{
4+
private final A first;
5+
private final B second;
6+
7+
private final C third;
8+
9+
private Three(A first, B second, C third) {
10+
this.first = first;
11+
this.second = second;
12+
this.third=third;
13+
}
14+
15+
public static <A, B,C> Three<A, B,C> of(A first, B second, C third) {
16+
return new Three<>(first, second,third);
17+
}
18+
19+
20+
public A getFirst() {
21+
return first;
22+
}
23+
24+
public B getSecond() {
25+
return second;
26+
}
27+
public C getThird() {
28+
return third;
29+
}
30+
31+
}

0 commit comments

Comments
 (0)