手写MyBatis

手写MyBatis简单查询的实现, 上代码!
1. 注解

package com.zhangqi.java.mybatis.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 处理dao层
 *
 * @author: zhangqi
 * @create 2021/11/24 19:23
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Mapper {
}

package com.zhangqi.java.mybatis.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * sql 参数解析
 *
 * @author: zhangqi
 * @create 2021/11/24 19:17
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
    /**
     * 参数名 #{}
     *
     * @return 参数名
     */
    String value();
}

package com.zhangqi.java.mybatis.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 查询sql
 *
 * @author: zhangqi
 * @create 2021/11/24 19:18
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
    /**
     * sql
     *
     * @return sql
     */
    String[] value();
}

package com.zhangqi.java.mybatis.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * JavaBean 转 Map 字段别名
 * Map 转 JavaBean字段别名
 *
 * @author: zhangqi
 * @create 2021/11/24 16:57
 */
@SuppressWarnings("unused")
@Documented
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BeanToMapAlias {
    /**
     * 别名
     *
     * @return 别名
     */
    String value() default "";
}

2. 工具类

package com.zhangqi.java.mybatis.utils;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Map;

/**
 * 断言
 *
 * @author Qz1997
 */
@SuppressWarnings("unused")
public final class Assert {

    private Assert() {
    }

    /**
     * 断言 boolean 为 true
     * <p>为 false 则抛出异常</p>
     *
     * @param expression {@link Boolean} boolean 值
     * @param message    {@link String}消息
     * @param params     {@link String}    参数
     */
    public static void isTrue(boolean expression, String message, Object... params) {
        if (!expression) {
            throw new RuntimeException(message);
        }
    }

    /**
     * 断言 boolean 为 false
     * <p>为 true 则抛出异常</p>
     *
     * @param expression {@link Boolean}  boolean 值
     * @param message    {@link String}   消息
     * @param params     {@link Object}
     */
    public static void isFalse(boolean expression, String message, Object... params) {
        isTrue(!expression, message, params);
    }

    /**
     * 断言 object 为 null
     * <p>不为 null 则抛异常</p>
     *
     * @param object  {@link String}  对象
     * @param message {@link String}消息
     * @param params  {@link String}    参数
     */
    public static void isNull(Object object, String message, Object... params) {
        isTrue(object == null, message, params);
    }

    /**
     * 断言 object 不为 null
     * <p>为 null 则抛异常</p>
     *
     * @param object  {@link String}  对象
     * @param message {@link String}消息
     * @param params  {@link String}    参数
     */
    public static void notNull(Object object, String message, Object... params) {
        isTrue(object != null, message, params);
    }

    /**
     * 断言 value 不为 empty
     * <p>为 empty 则抛异常</p>
     *
     * @param value   {@link String} 字符串
     * @param message {@link String}消息
     * @param params  {@link String}    参数
     */
    public static void notEmpty(String value, String message, Object... params) {
        isTrue(StringUtils.isNotBlank(value), message, params);
    }

    /**
     * 断言 collection 不为 empty
     * <p>为 empty 则抛异常</p>
     *
     * @param collection {@link Collection} 集合
     * @param message    {@link String}消息
     * @param params     {@link String}    参数
     */
    public static void notEmpty(Collection<?> collection, String message, Object... params) {
        isTrue(CollectionUtils.isNotEmpty(collection), message, params);
    }

    /**
     * 断言 map 不为 empty
     * <p>为 empty 则抛异常</p>
     *
     * @param map     {@link Map} 集合
     * @param message {@link String}消息
     * @param params  {@link String}    参数
     */
    public static void notEmpty(Map<?, ?> map, String message, Object... params) {
        isTrue(MapUtils.isNotEmpty(map), message, params);
    }

    /**
     * 断言 数组 不为 empty
     * <p>为 empty 则抛异常</p>
     *
     * @param array   {@link Object}  数组
     * @param message {@link String}消息
     * @param params  {@link String}    参数
     */
    public static void notEmpty(Object[] array, String message, Object... params) {
        isTrue(ArrayUtils.isNotEmpty(array), message, params);
    }
}

package com.zhangqi.java.mybatis.utils;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import com.zhangqi.java.mybatis.annotation.BeanToMapAlias;
import com.zhangqi.java.mybatis.proxy.DaoProxy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 实体相关工具类
 *
 * @author: Qz1997
 * @create 2021/6/22 9:53
 */
@Slf4j
@SuppressWarnings("unused")
public final class BeanUtils {

    /**
     * 寻找该类的父类和其祖宗十八代的属性
     *
     * @param clazz 类
     * @return 属性数组
     */
    public static Field[] getAllFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    /**
     * 将Java Bean 转成 Map
     *
     * @param obj Java Bean
     * @return Map
     */
    @SuppressWarnings({"unchecked", "DuplicatedCode"})
    public static Map<String, Object> javaBeanToMap(Object obj) {
        if (ObjectUtils.isEmpty(obj)) {
            return null;
        }
        if (obj instanceof Map) {
            return (Map<String, Object>) obj;
        }
        Class<?> clazz = obj.getClass();
        Field[] allFields = getAllFields(clazz);
        Map<String, Object> map = new HashMap<>(ArrayUtils.getLength(allFields) << 2);
        try {
            for (Field field : allFields) {
                if (Modifier.isFinal(field.getModifiers())) {
                    continue;
                }
                BeanToMapAlias annotation = field.getAnnotation(BeanToMapAlias.class);
                String alias = field.getName();
                if (ObjectUtils.isNotEmpty(annotation)) {
                    alias = annotation.value();
                    alias = StringUtils.isBlank(alias) ? field.getName() : alias;
                }
                Object fieldValue = BeanUtil.getFieldValue(obj, field.getName());
                map.put(alias, fieldValue);
            }
        } catch (Exception e) {
            /// log.error("获取Bean字段值异常,{}", obj, e);
            return null;
        }
        return map;
    }


    /**
     * Map转化为JavaBean
     *
     * @param map   map
     * @param clazz JavaBean.class
     * @param <T>   JavaBean类型
     * @return JavaBean
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        try {
            Field[] allFields = getAllFields(clazz);
            Map<String, String> mapField = new HashMap<>(ArrayUtils.getLength(allFields) << 2);
            Arrays.stream(allFields).forEach(item -> {
                String key = item.getName();
                BeanToMapAlias annotation = item.getAnnotation(BeanToMapAlias.class);
                if (ObjectUtils.isNotEmpty(annotation) && StringUtils.isNotBlank(annotation.value())) {
                    key = annotation.value();
                }
                mapField.put(key, item.getName());
            });
            T t = clazz.newInstance();
            BeanDesc desc = BeanUtil.getBeanDesc(clazz);
            map.forEach((key, value) -> {
                String fieldName = mapField.get(key);
                if (StringUtils.isNotBlank(fieldName)) {
                    desc.getProp(fieldName).setValue(t, value);
                }
            });
            return t;
        } catch (Exception e) {
            /// log.error("Map转换JavaBean异常", e);
            throw new RuntimeException("Map转换JavaBean异常");
        }
    }

    /**
     * Map转化为JavaBean
     *
     * @param map   map
     * @param clazz JavaBean.class
     * @param <T>   JavaBean类型
     * @return JavaBean
     */
    public static <T> T mapToBeanUnderscore(Map<String, Object> map, Class<T> clazz) {
        try {
            T t = clazz.newInstance();
            Field[] allFields = getAllFields(clazz);
            Map<String, Field> fieldMap = Arrays.stream(allFields).collect(Collectors.toMap(Field::getName, Function.identity()));
            BeanDesc desc = BeanUtil.getBeanDesc(clazz);
            map.forEach((key, value) -> {
                String fieldName = DaoProxy.lowerFirst(DaoProxy.replaceUnderLineAndUpperCase(key));
                Field field = fieldMap.get(fieldName);
                if (ObjectUtils.isNotEmpty(field)) {
                    desc.getProp(fieldName).setValue(t, value);
                }
            });
            return t;
        } catch (Exception e) {
            /// log.error("Map转换JavaBean异常", e);
            throw new RuntimeException("Map转换JavaBean异常");
        }
    }


}

package com.zhangqi.java.mybatis.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Objects;
import java.util.Properties;

/**
 * 数据库操作工具类
 *
 * @author: zhangqi
 * @create 2021/11/23 10:14
 */
@SuppressWarnings("unused")
@Slf4j
public class JdbcUtils {
    /**
     * 数据源信息
     */
    private static DataSource ds;

    static {
        try {
            Properties pro = new Properties();
            pro.load(JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 获取连接池方法
     */
    public static DataSource getDataSource() {
        return ds;
    }

    /**
     * 释放资源
     *
     * @param close 资源
     */
    public static void close(AutoCloseable... close) {
        Arrays.stream(close).forEach(autoCloseable -> {
            if (Objects.isNull(autoCloseable)) {
                return;
            }
            try {
                autoCloseable.close();
            } catch (Exception e) {
                System.err.println("数据库释放资源异常");
            }
        });
    }

}

package com.zhangqi.java.mybatis.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 扫包工具
 *
 * @author: Qz1997
 * @create 2019/11/7 10:59
 */
@SuppressWarnings("unused")
@Slf4j
public final class ScanPackageUtils {

    /**
     * 从包package中获取所有的Class
     *
     * @param pack 包
     * @return Class
     */
    public static Set<Class<?>> getClasses(String pack) {
        // 第一个class类的集合
        Set<Class<?>> classes = new LinkedHashSet<>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageName = pack;
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findAndAddClassesInPackageByFile(packageName, filePath, true, classes);
                } else if ("jar".equals(protocol)) {
                    // 如果是jar包文件
                    // 定义一个JarFile
                    JarFile jar;
                    try {
                        // 获取jar
                        jar = ((JarURLConnection) url.openConnection()).getJarFile();
                        // 从此jar包 得到一个枚举类
                        Enumeration<JarEntry> entries = jar.entries();
                        // 同样的进行循环迭代
                        while (entries.hasMoreElements()) {
                            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
                            JarEntry entry = entries.nextElement();
                            String name = entry.getName();
                            // 如果是以/开头的
                            if (name.charAt(0) == '/') {
                                // 获取后面的字符串
                                name = name.substring(1);
                            }
                            // 如果前半部分和定义的包名相同
                            if (name.startsWith(packageDirName)) {
                                int idx = name.lastIndexOf('/');
                                // 如果以"/"结尾 是一个包
                                if (idx != -1) {
                                    // 获取包名 把"/"替换成"."
                                    packageName = name.substring(0, idx).replace('/', '.');
                                }
                                // 如果可以迭代下去 并且是一个包
                                // 如果是一个.class文件 而且不是目录
                                if (name.endsWith(".class") && !entry.isDirectory()) {
                                    // 去掉后面的".class" 获取真正的类名
                                    String className = name.substring(packageName.length() + 1, name.length() - 6);
                                    try {
                                        // 添加到classes
                                        classes.add(Class.forName(packageName + '.' + className));
                                    } catch (ClassNotFoundException e) {
                                        System.err.println("添加用户自定义视图类错误 找不到此类的.class文件");
                                    }
                                }
                            }
                        }
                    } catch (IOException e) {
                        System.err.println("在扫描用户定义视图时从jar包获取文件出错");
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("扫描包出现异常");
        }
        return classes;
    }

    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param packageName 包名
     * @param packagePath 包路径
     * @param recursive   递归标识
     * @param classes     类集合
     */
    public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
        File[] dirFiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(".class")));
        if (ArrayUtils.isEmpty(dirFiles)) {
            return;
        }
        // 循环所有文件
        for (File file : Objects.requireNonNull(dirFiles)) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    System.err.println("添加用户自定义视图类错误 找不到此类的.class文件");
                }
            }
        }
    }

}

3. 代理

package com.zhangqi.java.mybatis.proxy;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import com.zhangqi.java.mybatis.annotation.Mapper;
import com.zhangqi.java.mybatis.annotation.Param;
import com.zhangqi.java.mybatis.annotation.Select;
import com.zhangqi.java.mybatis.utils.Assert;
import com.zhangqi.java.mybatis.utils.BeanUtils;
import com.zhangqi.java.mybatis.utils.JdbcUtils;
import com.zhangqi.java.mybatis.utils.ScanPackageUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 简单Mybatis查询实现
 *
 * @author: zhangqi
 * @create 2021/11/24 19:25
 */
@Slf4j
public class DaoProxy {
    /**
     * dao 层 基础包 todo 抽取配置文件
     */
    private final static String DAO_PATH = "com.zhangqi.dao";

    /**
     * 类名和Mapper的 map
     */
    private static Map<String, Object> MAPPER_MAP = new HashMap<>();

    /*
     * 用于初始化Mapper 使用JDK 代理
     */
    static {
        Set<Class<?>> classes = ScanPackageUtils.getClasses(DAO_PATH);
        classes = classes.stream().filter(item -> Objects.nonNull(item.getAnnotation(Mapper.class))).collect(Collectors.toSet());
        for (Class<?> aClass : classes) {
            String simpleName = aClass.getSimpleName();
            Object objectMapper = Proxy.newProxyInstance(DaoProxy.class.getClassLoader(), new Class[]{aClass},
                    (proxy, method, args1) -> {
                        Map<String, Object> paramMap = bangDingParam(method, args1);
                        Select annotation = method.getAnnotation(Select.class);
                        String originalSql;
                        if (annotation == null) {
                            return null;
                        }
                        originalSql = annotation.value()[0];
                        originalSql = bangDingParam(paramMap, originalSql);
                        /// log.info("解析后的SQL:  " + originalSql);
                        Object o = null;
                        try {
                            o = operateDatabase(originalSql, method);
                        } catch (Exception e) {
                            /// log.error("执行数据库SQL异常", e);
                        }
                        return o;
                    });
            MAPPER_MAP.put(simpleName, objectMapper);
        }
    }

    /**
     * 获取操作dao层的Mapper
     *
     * @param t   MapperClass 信息
     * @param <T> MapperClass 信息
     * @return Mapper
     */
    @SuppressWarnings({"unchecked", "unused"})
    public static <T> T getMapper(Class<T> t) {
        Assert.isTrue(Objects.nonNull(t), "获取Mapper类信息不能为空");
        Object o = MAPPER_MAP.get(t.getSimpleName());
        if (ObjectUtils.isEmpty(o)) {
            throw new RuntimeException(String.format("没有找到对应的Mapper, 请检查类是否在[%s]包下! ", DAO_PATH));
        }
        return (T) o;
    }

    /**
     * 操作查询数据库
     *
     * @param sql    sql
     * @param method 执行的方法
     * @return 结果
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private static Object operateDatabase(String sql, Method method) throws Exception {
        Class<?> returnType = method.getReturnType();
        boolean flag = false;
        if (Objects.equals(returnType, List.class)) {
            Type genericReturnType = method.getGenericReturnType();
            String typeName = ((ParameterizedTypeImpl) genericReturnType).getActualTypeArguments()[0].getTypeName();
            returnType = Class.forName(typeName);
            flag = true;
        }
        Object o;
        if (!flag) {
            o = returnType.newInstance();
        } else {
            o = new ArrayList<>();
        }

        Field[] allFields = BeanUtils.getAllFields(returnType);
        Map<String, Field> map = Arrays.stream(allFields).filter(item -> !Modifier.isFinal(item.getModifiers())).collect(Collectors.toMap(Field::getName, Function.identity()));
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            //获得连接
            conn = JdbcUtils.getConnection();
            //获取pstmt对象
            pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            while (rs.next()) {
                Object xu = null;
                if (flag) {
                    xu = returnType.newInstance();
                }
                int columnCount = metaData.getColumnCount();
                for (int i = 1; i < columnCount + 1; i++) {
                    String columnName = metaData.getColumnName(i);
                    String javaFieldName = lowerFirst(replaceUnderLineAndUpperCase(columnName));
                    Field field = map.get(javaFieldName);
                    if (ObjectUtils.isNotEmpty(field)) {
                        Object columnValue;
                        if (field.getType().isEnum()) {
                            String enumValue = rs.getString(columnName);
                            columnValue = Enum.valueOf(field.getType().asSubclass(field.getType()), enumValue);
                        } else {
                            columnValue = rs.getObject(columnName);
                        }
                        // 赋值
                        BeanDesc desc = BeanUtil.getBeanDesc(returnType);
                        if (flag) {
                            desc.getProp(javaFieldName).setValue(xu, columnValue);
                        } else {
                            desc.getProp(javaFieldName).setValue(o, columnValue);
                        }
                    }
                }
                if (flag) {
                    ((List) o).add(xu);
                }
            }
            return o;
        } catch (Exception e) {
            ///  log.error("操作数据库异常", e);
            return null;
        } finally {
            JdbcUtils.close(pstmt, conn);
        }
    }


    /**
     * 替换原sql 参数
     *
     * @param map         解析的参数
     * @param originalSql 原来的sql
     * @return 新sql
     */
    private static String bangDingParam(Map<String, Object> map, String originalSql) {
        StringBuilder sb = new StringBuilder();
        int length = originalSql.length();
        for (int i = 0; i < length; i++) {
            char indexChar = originalSql.charAt(i);
            if (indexChar == '#') {
                if (i + 1 >= length) {
                    throw new RuntimeException(String.format("格式错讹误 原sql: %s index: %s", originalSql, i));
                }
                if (originalSql.charAt(i + 1) != '{') {
                    throw new RuntimeException(String.format("格式错讹误 没有 [{]   原sql: %s index: %s", originalSql, i));
                }
                StringBuilder name = new StringBuilder();
                i = parseSqlParam(originalSql, i + 1, name);
                if (name.toString().isEmpty()) {
                    throw new RuntimeException("参数名错误");
                }
                Object paramValue = map.get(name.toString());
                sb.append(paramValue);
                continue;
            }
            sb.append(indexChar);

        }
        return sb.toString();
    }

    /**
     * 解析参数名
     *
     * @param originalSql 原sql
     * @param index       参数名开始的 `{`  下标
     * @param paramName   参数名称
     * @return 解析参数名结束下标
     */
    private static int parseSqlParam(String originalSql, int index, StringBuilder paramName) {
        int length = originalSql.length();
        int newIndex = index;
        index++;
        for (; newIndex < length; newIndex++) {
            char indexChar = originalSql.charAt(newIndex);
            if (indexChar == '}') {
                paramName.append(originalSql, index, newIndex);
                return newIndex;
            }
        }
        throw new RuntimeException(String.format("格式错讹误 没有 [{]   原sql: %s ", originalSql));
    }

    /**
     * 解析参数
     *
     * @param method 执行的方法
     * @param arg    传入的参数
     * @return key参数名  value参数值
     */
    public static Map<String, Object> bangDingParam(Method method, Object[] arg) {
        Map<String, Object> map = new HashMap<>(16);
        int[] index = {0};
        Arrays.stream(method.getParameters()).forEach(parameter -> {
            String name = parameter.getAnnotation(Param.class).value();
            map.put(name, "'" + arg[index[0]] + "'");
            index[0]++;
        });
        return map;
    }

    /**
     * 下划线转驼峰
     *
     * @param str 下划线字符串
     * @return 驼峰字符串
     */
    public static String replaceUnderLineAndUpperCase(String str) {
        StringBuilder sb = new StringBuilder();
        sb.append(str);
        int count = sb.indexOf("_");
        while (count != 0) {
            int num = sb.indexOf("_", count);
            count = num + 1;
            if (num != -1) {
                char ss = sb.charAt(count);
                char ia = (char) (ss - 32);
                sb.replace(count, count + 1, String.valueOf(ia));
            }
        }
        String result = sb.toString().replaceAll("_", "");
        return StringUtils.capitalize(result);
    }

    /**
     * 实现首字母小写
     *
     * @param name 首字母小写前字符串
     * @return 首字母小写后字符串
     */
    public static String lowerFirst(String name) {
        char[] chars = name.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值