这次的修改内容
1.为了将一些可复用的方法统一使用,修改源码MapperAnnotationBuilder
2.MapperAnnotationBuilder中使用到的内容,包括CrudMapper/CrudProvider/CrudSqlProvider/CrudSqlSource
3.当使用缓存的时候,需要实现Serializable,添加基类Entity
4.dao实现CrudMapper,实体类实现Entity
5.xml文件中添加实体类的基类<property name="typeAliasesSuperType" value="com.lizhaoblog.base.mybatis.Entity"></property>
6.TestFirstHandler中添加测试方法
项目变化如图所示
使用一些现有比较完善的mybatis小工具,可以不用再写一些通用的方法(增删改查)
通过修改org.apache.ibatis.builder.annotation.MapperAnnotationBuilder中的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27在getSqlSourceFromAnnotations中修改 else { CrudProvider crudAnnotation = method .getAnnotation(CrudProvider.class); if (crudAnnotation != null) { Type[] genericInterfaces = this.type.getGenericInterfaces(); if (genericInterfaces.length > 0) { ParameterizedType parameterizedType = (ParameterizedType) genericInterfaces[0]; Class<?> entityType = (Class<?>) parameterizedType .getActualTypeArguments()[0]; return new CrudSqlSource(assistant.getConfiguration(), crudAnnotation, entityType, method); } } } 在getSqlCommandType中修改 Class<? extends Annotation> type = getSqlAnnotationType(method); if (type == null) { type = getSqlProviderAnnotationType(method); if (type == null) { if (method.isAnnotationPresent(CrudProvider.class)) { String sqlType = method.getAnnotation(CrudProvider.class).sqlType(); return SqlCommandType.valueOf(sqlType.toUpperCase()); } return SqlCommandType.UNKNOWN;
在方法中需要用到2个类(CrudProvider/CrudSqlSource),这个通过我们自己去实现,下面都是工具类,可以直接使用
CrudMapper 封装dao层通用的增删改查方法
CrudProvider 对数据库的操作类型,注解
CrudSqlProvider 写的通用方法的sql提供者,@see CrudMapper
CrudSqlSource 从XML文件或注释读取的映射语句的内容,创建sql
Entity 实体类对应的接口
EntityUtils 实体类操作工具
具体代码
CrudMapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88/* * Copyright (C), 2015-2018 * FileName: CrudMapper * Author: zhao * Date: 2018/7/4 10:33 * Description: 封装dao层通用的增删改查方法 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.ResultType; import java.io.Serializable; import java.util.List; /** * 〈一句话功能简述〉<br> * 〈封装dao层通用的增删改查方法〉 * * @author zhao * @date 2018/7/4 10:33 * @since 1.0.0 */ public interface CrudMapper<T, ID extends Serializable> { @CrudProvider @ResultMap("resultMap") T findOne(ID id); @CrudProvider @ResultType(Boolean.class) @Options(useCache = false) boolean exists(ID id); @CrudProvider @ResultMap("resultMap") @Options(useCache = false) List<T> listAll(); @CrudProvider @ResultType(Long.class) @Options(useCache = false) Long count(); @CrudProvider @ResultMap("resultMap") @Options(useCache = false) List<T> listByExample(T example); @CrudProvider @ResultType(Long.class) @Options(useCache = false) Long countByExample(T example); @CrudProvider(sqlType = "delete") @Options(flushCache = true) void deleteById(ID id); @CrudProvider(sqlType = "delete") @Options(flushCache = true) void deleteByIds(List<ID> ids); @CrudProvider(sqlType = "delete") @Options(flushCache = true) void deleteByIdArray(ID[] ids); @CrudProvider(sqlType = "delete") @Options(flushCache = true) void delete(T entity); @CrudProvider(sqlType = "delete") @Options(flushCache = true) void deleteEntities(List<T> entities); @CrudProvider(sqlType = "insert") @Options(flushCache = true) void insert(T entity); @CrudProvider(sqlType = "update") @Options(flushCache = true) void update(T entity); }
CrudProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39/* * Copyright (C), 2015-2018 * FileName: CrudProvider * Author: zhao * Date: 2018/7/4 10:38 * Description: 对数据库的操作类型,注解 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 〈一句话功能简述〉<br> * 〈对数据库的操作类型,注解〉 * * @author zhao * @date 2018/7/4 10:38 * @since 1.0.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CrudProvider { Class<?> type() default CrudSqlProvider.class; String sqlType() default "select"; String method() default ""; boolean isJpaStyle() default false; }
CrudSqlProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281/* * Copyright (C), 2015-2018 * FileName: CrudSqlProvider * Author: zhao * Date: 2018/7/4 10:39 * Description: 提供生成sql语句 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.jdbc.SQL; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; /** * 〈一句话功能简述〉<br> * 〈写的通用方法的sql提供者,@see CrudMapper〉 * * @author zhao * @date 2018/7/4 10:39 * @since 1.0.0 */ public class CrudSqlProvider { private Class<?> entityType; private String tableName; private String idColumnName; private String idPropertyName; public CrudSqlProvider(Class<?> entityType) { this.entityType = entityType; initTableName(); initIdColumnName(); initIdPropertyName(); } public String findOne() { return selectFrom().WHERE(eqId()).toString(); } public String exists() { return countFrom().WHERE(eqId()).toString(); } public String listAll() { return selectFrom().toString(); } public String count() { return countFrom().toString(); } public String listByExample(Object example) throws IllegalAccessException { SQL sql = selectFrom(); appendConditionByExample(sql, example); return sql.toString(); } public String countByExample(Object example) throws IllegalAccessException { SQL sql = countFrom(); appendConditionByExample(sql, example); return sql.toString(); } public String deleteById() { return deleteFrom().WHERE(eqId()).toString(); } public String deleteByIds(List<Object> ids) { SQL sql = deleteFrom(); if (CollectionUtils.isEmpty(ids)) { throw new BuilderException("参数ids不能为空"); } StringBuilder sb = new StringBuilder(idColumnName).append(" in ("); for (Object id : ids) { if (id instanceof String) { sb.append("'").append(id).append("'"); } else { sb.append(id); } sb.append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); sql.WHERE(sb.toString()); return sql.toString(); } public String deleteByIdArray(Object[] ids) { return deleteByIds(Arrays.asList(ids)); } public String delete() { return deleteFrom().WHERE(eqId()).toString(); } public String deleteEntities(List<Object> entities) throws NoSuchFieldException, SecurityException, IllegalAccessException { if (CollectionUtils.isEmpty(entities)) { throw new BuilderException("参数entities不能为空"); } List<Object> ids = new ArrayList<Object>(); for (Object entity : entities) { Field idField = entityType.getDeclaredField(idPropertyName); idField.setAccessible(true); ids.add(idField.get(entity)); } return deleteByIds(ids); } public String deleteAll() { return deleteFrom().toString(); } public String insert(Object entity) throws IllegalAccessException { SQL sql = new SQL().INSERT_INTO(tableName); Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Id.class) && field.isAnnotationPresent(GeneratedValue.class)) { continue; } field.setAccessible(true); Object fieldVal = field.get(entity); Column colomnAnnotation = field.getAnnotation(Column.class); boolean bool = StringUtils.isEmpty(Objects.toString(fieldVal, "")) && (colomnAnnotation != null || field .isAnnotationPresent(Id.class)); if (!bool) { String propertyName = field.getName(); String columnName = propertyName; if (colomnAnnotation != null) { columnName = colomnAnnotation.name(); if (StringUtils.isEmpty(columnName)) { columnName = propertyName; } } sql.VALUES(columnName, wrapParameter(propertyName)); } } return sql.toString(); } public String update(Object entity) throws IllegalAccessException { SQL sql = new SQL().UPDATE(tableName); Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Id.class)) { continue; } field.setAccessible(true); Object fieldVal = field.get(entity); Column colomnAnnotation = field.getAnnotation(Column.class); if (!StringUtils.isEmpty(Objects.toString(fieldVal, "")) && colomnAnnotation != null) { String propertyName = field.getName(); String columnName = colomnAnnotation.name(); if (StringUtils.isEmpty(columnName)) { columnName = propertyName; } sql.SET(assign(columnName, propertyName)); } } return sql.WHERE(eqId()).toString(); } private SQL deleteFrom() { return new SQL().DELETE_FROM(tableName); } public String findWithJpaStyle(String methodName) { // TODO support jpastyle SQL sql = selectFrom(); return sql.toString(); } private SQL selectFrom() { return new SQL().SELECT("*").FROM(tableName); } public String countWithJpaStyle(String methodName) { // TODO support jpastyle SQL sql = countFrom(); return sql.toString(); } private SQL countFrom() { return new SQL().SELECT("count(*)").FROM(tableName); } private void appendConditionByExample(SQL sql, Object example) throws IllegalAccessException { Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object fieldVal = field.get(example); Column colomnAnnotation = field.getAnnotation(Column.class); if (!StringUtils.isEmpty(Objects.toString(fieldVal, "")) && colomnAnnotation != null) { String propertyName = field.getName(); String columnName = colomnAnnotation.name(); if (StringUtils.isEmpty(columnName)) { columnName = propertyName; } sql.WHERE(eq(columnName, propertyName)); } } } private String eqId() { return eq(idColumnName, idPropertyName); } private String eq(String columnName, String propertyName) { return String.format("%s = #{%s}", columnName, propertyName); } private String assign(String columnName, String propertyName) { return String.format("%s = #{%s}", columnName, propertyName); } private String wrapParameter(String propertyName) { return String.format("#{%s}", propertyName); } private void initIdColumnName() { Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Id.class) && field.isAnnotationPresent(Column.class)) { idColumnName = field.getAnnotation(Column.class).name(); if (StringUtils.isEmpty(idColumnName)) { idColumnName = field.getName(); } } else if (field.isAnnotationPresent(Id.class)) { idColumnName = field.getName(); } } if (StringUtils.isEmpty(idColumnName)) { throw new IllegalArgumentException("实体未注解Id"); } } private void initIdPropertyName() { Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Id.class)) { idPropertyName = field.getName(); } } if (StringUtils.isEmpty(idPropertyName)) { throw new IllegalArgumentException("实体未注解Id"); } } private void initTableName() { Table tableAnno = entityType.getAnnotation(Table.class); if (tableAnno == null) { throw new IllegalArgumentException("实体未注解Table"); } tableName = tableAnno.name(); if (StringUtils.isEmpty(tableName)) { tableName = getTableNameFromClass(entityType); } } private String getTableNameFromClass(Class<?> clazz) { String simpleName = clazz.getSimpleName(); String first = simpleName.substring(0, 1); String remains = clazz.getSimpleName().substring(1); return first + remains; } }
CrudSqlSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117/* * Copyright (C), 2015-2018 * FileName: CrudSqlSource * Author: zhao * Date: 2018/7/4 10:46 * Description: sql * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.builder.SqlSourceBuilder; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.defaults.DefaultSqlSession; import org.springframework.util.StringUtils; import java.lang.reflect.Method; import java.util.HashMap; /** * 〈一句话功能简述〉<br> * 〈SqlSource:从XML文件或注释读取的映射语句的内容。 * 创建将从用户接收的输入参数中传递到数据库的SQL。〉 * * @author zhao * @date 2018/7/4 10:46 * @since 1.0.0 */ public class CrudSqlSource implements SqlSource { private SqlSourceBuilder sqlSourceParser; private Class<?> providerType; private Method providerMethod; private boolean providerTakesParameterObject; private Class<?> entityType; private boolean isJpaStyle = false; private Method mapperInterfaceMethod; public CrudSqlSource(Configuration config, CrudProvider provider, Class<?> entityType, Method mapperInterfaceMethod) { String providerMethodName = null; try { this.entityType = entityType; this.mapperInterfaceMethod = mapperInterfaceMethod; this.sqlSourceParser = new SqlSourceBuilder(config); this.providerType = provider.type(); isJpaStyle = provider.isJpaStyle(); providerMethodName = provider.method(); if (StringUtils.isEmpty(providerMethodName)) { providerMethodName = mapperInterfaceMethod.getName(); } if (isJpaStyle) { if (providerMethodName.startsWith("find")) { providerMethodName = "findWithJpaStyle"; } else if (providerMethodName.startsWith("count")) { providerMethodName = "countWithJpaStyle"; } else if (providerMethodName.startsWith("delete")) { providerMethodName = "deleteWithJpaStyle"; } else { throw new BuilderException("only method startwith find/count/delete support jpa style"); } } for (Method m : this.providerType.getMethods()) { if (providerMethodName.equals(m.getName())) { if (m.getParameterTypes().length < 2 && m.getReturnType() == String.class) { this.providerMethod = m; this.providerTakesParameterObject = m.getParameterTypes().length == 1; } } } } catch (Exception e) { throw new BuilderException("Error creating SqlSource for SqlProvider. Cause: " + e, e); } if (this.providerMethod == null) { throw new BuilderException( "Error creating SqlSource for SqlProvider. Method '" + providerMethodName + "' not found in SqlProvider '" + this.providerType.getName() + "'."); } } @Override public BoundSql getBoundSql(Object parameterObject) { SqlSource sqlSource = createSqlSource(parameterObject); return sqlSource.getBoundSql(parameterObject); } private SqlSource createSqlSource(Object parameterObject) { try { String sql; Object providerInstance = providerType.getConstructor(Class.class).newInstance(entityType); if (isJpaStyle) { sql = (String) providerMethod.invoke(providerInstance, mapperInterfaceMethod.getName()); } else { if (providerTakesParameterObject) { if (parameterObject instanceof DefaultSqlSession.StrictMap) { DefaultSqlSession.StrictMap strictMap = (DefaultSqlSession.StrictMap) parameterObject; parameterObject = strictMap.get(strictMap.keySet().iterator().next()); } sql = (String) providerMethod.invoke(providerInstance, parameterObject); } else { sql = (String) providerMethod.invoke(providerInstance); } } Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); return sqlSourceParser.parse(sql, parameterType, new HashMap<String, Object>()); } catch (Exception e) { throw new BuilderException( "Error invoking SqlProvider method (" + providerType.getName() + "." + providerMethod.getName() + "). Cause: " + e, e); } } }
Entity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25/* * Copyright (C), 2015-2018 * FileName: Entity * Author: zhao * Date: 2018/7/4 10:52 * Description: 实体类对应的接口 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import java.io.Serializable; /** * 〈一句话功能简述〉<br> * 〈实体类对应的接口〉 * * @author zhao * @date 2018/7/4 10:52 * @since 1.0.0 */ public interface Entity extends Serializable { }
EntityUtils
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51/* * Copyright (C), 2015-2018 * FileName: EntityUtils * Author: zhao * Date: 2018/7/4 10:53 * Description: 实体类操作工具 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.lizhaoblog.base.mybatis; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import javax.persistence.Column; import javax.persistence.Id; /** * 〈一句话功能简述〉<br> * 〈实体类操作工具〉 * * @author zhao * @date 2018/7/4 10:53 * @since 1.0.0 */ public final class EntityUtils { public static String getColumnName(Class<?> entityClass, String fieldName) throws NoSuchFieldException, SecurityException { String columnName = null; Field field = entityClass.getDeclaredField(fieldName); if (field.isAnnotationPresent(Column.class)) { columnName = field.getAnnotation(Column.class).name(); if (StringUtils.isEmpty(columnName)) { columnName = fieldName; } } else if (field.isAnnotationPresent(Id.class)) { columnName = fieldName; } if (StringUtils.isEmpty(columnName)) { throw new IllegalArgumentException("实体未注解"); } return columnName; } private EntityUtils() { } }
这几个变化也没什么好贴代码的了
4.然后修改dao实现CrudMapper,实体类实现Entity
5.xml文件中添加实体类的基类<property name="typeAliasesSuperType" value="com.lizhaoblog.base.mybatis.Entity"></property>
6.TestFirstHandler中添加测试方法
1
2
3
4
5
6
7
8
9
10
11List<User> all = userDao.listAll(); logger.info(all.toString()); User user = new User(); user.setName("a"); user.setAccount("aa"); user.setPassword("aaa"); userDao.insert(user); all = userDao.listAll(); logger.info(all.toString());
上面的代码在码云上 https://gitee.com/lizhaoandroid/JgServer
可以加qq群一起探讨Java游戏服务器开发的相关知识 676231564
最后
以上就是冷傲导师最近收集整理的关于Java游戏服务器开发之十三--整合MyBatis通用语句工具的全部内容,更多相关Java游戏服务器开发之十三--整合MyBatis通用语句工具内容请搜索靠谱客的其他文章。
发表评论 取消回复