概述
这次的修改内容
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中的方法
在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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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中添加测试方法
List<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通用语句工具所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复