吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8468|回复: 27
收起左侧

[Java 转载] Spring-boot+Mybatis自动代码生成器-其实是API自动生成,只能放一部分

  [复制链接]
荼蘼熊 发表于 2019-3-13 17:43
本帖最后由 荼蘼熊 于 2019-3-22 10:55 编辑

ps:刚来这个网站。总算是注册成功了。放出我的代码,嗯自己写自动代码生成器的。其实是API的阉割版,但是涉及合同。
**回归主题了

# 功能
获取数据库的单表。自动生成 mybatis 需要的映射文件和实体类。此源码不涉及前端、及 service 层和 controller 层

# 思路
按照架构分层,生成顺序为 实体类(model)层 -->> 映射文件(dao)层 -->> 使用映射文件(service)层 -->> 控制器(controller)层
//当前页 mysql 数据库为例
* 获取当前数据库的所有的单表名、字段、字段类型。
* 生成 model 层 .java 文件,将表名字当做类名,字段名当做成员变量,编译 .java 文件 生成 .class 文件。
* 生成 dao 层 .java 文件,将(表名字加 Mapper) 当做类名,生成通用查询方法和语句,编译 .java 文件 生成 .class 文件。
* 通过 spring-boot 的热加载,即可操作生成的 .class

# 实现及源码

### 配置数据库连接、及获取数据库表的映射文件
因为用的是 spring-boot 框架,直接在 .yml 文件配置就可以了。

# Mysql
spring:
  datasource:
    name: testDatasource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/XXX?useUnicode=true&characterEncoding=utf8
    username: root
    password: *

mysql 数据库获取当前库所有表和所有表的属性

[Java] 纯文本查看 复制代码
package top.xiong.snark.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

/**
 * 获取当前数据库的表和字段
 */
@Mapper
public interface TableMapper {
    /**
     * 获取当前数据库的表
     * [url=home.php?mod=space&uid=155549]@Return[/url] {"TABLE_NAME":"commodity"}
     */
    @Select("select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=(select database())")
    List<Map> getAllTable();

    /**
     * 获取当前数据库的表的字段
     * [url=home.php?mod=space&uid=952169]@Param[/url] tableName
     * @return {"TABLE_NAME":"commodity","COLUMN_NAME":"id","DATA_TYPE":"bigint"}
     */
    @Select("select TABLE_NAME,COLUMN_NAME,DATA_TYPE from information_schema.columns  where TABLE_SCHEMA=(select database()) and TABLE_NAME=#{tableName}")
    List<Map<String, String>> getTableColumns(@Param("tableName") String tableName);
}



###service层调用关系
[Java] 纯文本查看 复制代码
package top.xiong.snark.service;

import org.springframework.stereotype.Service;
import top.xiong.snark.dao.TableMapper;
import top.xiong.snark.helper.FileGenerateHelper;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;


@Service
public class UserService implements IUserService {
    
    @Resource
    private TableMapper tableMapper;

    /**
     * 获取当前数据库的表
     * @return table
     */
    @Override
    public void getAllTable() {
        //获取的所有的表
        List<Map> mapList= tableMapper.getAllTable();
        //文件自动生成帮助类
        FileGenerateHelper helper = new FileGenerateHelper();
        for (int i = 0; i < mapList.size(); i++) {
            Object tableName= mapList.get(i).get("TABLE_NAME");
            //获取当前表的属性
            List<Map<String, String>> mapsColumns=getAllTableColumns(tableName.toString());
            //开始生成文件
            helper.writeToJava(mapsColumns);

        }
    }

    /**
     * 获取当前数据库的表的字段
     * @return tableColumn
     */
    @Override
    public List<Map<String, String>> getAllTableColumns(String tableName) {
        return tableMapper.getTableColumns(tableName);

    }
}


### 构建类和sql语句,很简单,但是你可以自己扩展
package top.xiong.snark.helper;

import com.squareup.javapoet.*;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import top.xiong.snark.annotation.Column;
import top.xiong.snark.annotation.TbName;
import top.xiong.snark.util.StringUtil;
import top.xiong.snark.util.TypeCastUtil;

import javax.lang.model.element.Modifier;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
* 生成 .java 文件
*
* @AuThor bj
* @version 1.0
*/
public class FileGenerateHelper {
    //生成文件的路径 top.xiong.snark.dao
    private String dao_Path;
    //生成文件的路径 top.xiong.snark.model
    private String model_Path;
    //表名
    private String tableName;
    //表、字段
    private List<Map<String,String>> mapList = new ArrayList<>();
    //项目路径
    private File file;
   
    /**
     * 自动,路径 包含在 启动类 包路径下
     */
    public FileGenerateHelper() {
        dao_Path = "top.xiong.snark.dao";
        model_Path= "top.xiong.snark.model";
        this.file=new File(System.getProperty("user.dir") + "/src/main/java");

    }
    /**
     * 手动,需要设置 model 和 dao 路径
     */
    public FileGenerateHelper(String dao_Path,String model_Path) {
        this.dao_Path=dao_Path;
        this.model_Path=model_Path;
        this.file=new File(System.getProperty("user.dir") + "/src/main/java");
    }


    /**
     * 如若不传 .java 文件的绝对路径
     */
    public void writeToJava(List<Map<String,String>> mapList) {
        this.mapList=mapList;
        //表名称
        this.tableName=StringUtil.toUpperCase(mapList.get(0).get("TABLE_NAME").toString());
        //生成 model
        this.writeToJavaModel();
        //生成 dao
        this.writeToJavaDao();

    }

    /**
     * 生成 .java model 层
     */
    private void writeToJavaModel() {
        List<FieldSpec> fieldSpecIterable=new LinkedList<>();
        List<MethodSpec> methodSpecs = new LinkedList<>();
        int size =mapList.size();
                //初始化 @override toString
        MethodSpec toStringSpec= MethodSpec.methodBuilder("toString")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addCode("return \"$N { \" + \"",tableName)
                .build();
        for (Map map : mapList) {
            //构建 field
            FieldSpec fieldSpec = FieldSpec
                    .builder(TypeCastUtil.getJavaType(map.get("DATA_TYPE").toString()), map.get("COLUMN_NAME").toString(),Modifier.PRIVATE)
                    .addAnnotation(AnnotationSpec.builder(Column.class).addMember("value", "$S",map.get("COLUMN_NAME").toString()).build())
                    .build();
            fieldSpecIterable.add(fieldSpec);
            //构建 get method
            MethodSpec getMethod= MethodSpec.methodBuilder("get"+ StringUtil.toUpperCase(map.get("COLUMN_NAME").toString()))
                    .addModifiers(Modifier.PUBLIC)
                    .returns(TypeCastUtil.getJavaType(map.get("DATA_TYPE").toString()))
                    .addStatement("return this.$N",map.get("COLUMN_NAME").toString())
                    .build();
            methodSpecs.add(getMethod);
            //构建 set method
            MethodSpec setMethod= MethodSpec.methodBuilder("set"+ StringUtil.toUpperCase(map.get("COLUMN_NAME").toString()))
                    .addModifiers(Modifier.PUBLIC)
                    .returns(void.class)
                    .addParameter(TypeCastUtil.getJavaType(map.get("DATA_TYPE").toString()), map.get("COLUMN_NAME").toString())
                    .addStatement("this.$N = $N",map.get("COLUMN_NAME").toString(),map.get("COLUMN_NAME").toString())
                    .build();
            methodSpecs.add(setMethod);
            if (size < mapList.size()) {
                toStringSpec= toStringSpec.toBuilder().addCode("\", ")
                        .build();
            }
            //构建 toString()
            toStringSpec= toStringSpec.toBuilder().addCode("$N =\" + $N +", map.get("COLUMN_NAME").toString(),map.get("COLUMN_NAME").toString())
                    .build();
            size--;
        }
        //构建 toString()
        toStringSpec=toStringSpec.toBuilder().addStatement("'}'")
                .build();
        //构建 构造函数
        MethodSpec methodSpec= MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .build();
        //构建 类
        TypeSpec typeSpec = TypeSpec.classBuilder(tableName)
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(AnnotationSpec.builder(TbName.class).addMember("name","$S", tableName).build())
                .addMethod(methodSpec)
                .addFields(fieldSpecIterable)
                .addMethods(methodSpecs)
                .addMethod(toStringSpec)
                .build();

        //生成文件
        JavaFile javaFile= JavaFile.builder(model_Path,typeSpec).build();
        try {
            javaFile.writeTo(file);
            JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
            String matchPath=model_Path;
            compiler.run(null, null, null, "-d", System.getProperty("user.dir")+"/target/classes", System.getProperty("user.dir") + "/src/main/java/"+matchPath.replace(".", "/")+"/"+tableName+".java");

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 生成 .java dao 层
     */
    public void writeToJavaDao() {
        CoreProviderHelper coreHelper= new CoreProviderHelper();
        try {
            TypeName list = ParameterizedTypeName.get(ClassName.get("java.util", "List"), ClassName.get(model_Path.replace("/", "."),tableName));

            //加载类
            Class cls=Class.forName(model_Path+"."+tableName);

            //构建查全表的方法
            TypeSpec typeSpec= TypeSpec.interfaceBuilder(tableName+"Mapper")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(MethodSpec.methodBuilder("select"+tableName+"All")
                            .addModifiers(Modifier.PUBLIC,Modifier.ABSTRACT)
                            .returns(list)
                            .addAnnotation(AnnotationSpec.builder(Select.class)
                                    .addMember("value", "$S",coreHelper.getSelectAllCore(cls.newInstance()))
                                    .build())
                            .build())
                    .addAnnotation(Mapper.class)
                    .build();
            JavaFile javaFile= JavaFile.builder(dao_Path,typeSpec).build();
            javaFile.writeTo(file);
            String matchPath=dao_Path;
            JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
            compiler.run(null, null, null, "-d", System.getProperty("user.dir")+"/target/classes", System.getProperty("user.dir") + "/src/main/java/"+matchPath.replace(".", "/")+"/"+tableName+"Mapper.java");

        }catch (Exception e){
            e.printStackTrace();
        }

    }





    public void setDao_Path(String dao_Path) {
        this.dao_Path = dao_Path;
    }

    public void setModel_Path(String model_Path) {
        this.model_Path = model_Path;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }
}


###生成sql的帮助类
[Java] 纯文本查看 复制代码
package top.xiong.snark.helper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.xiong.snark.annotation.Column;
import top.xiong.snark.annotation.TbName;
import top.xiong.snark.util.CollectionUtil;
import top.xiong.snark.util.StringUtil;

import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.Map;

/**
 * 代码提供
 *
 * @author bj
 * @version 2.0
 */
public class CoreProviderHelper {
    private static final Logger LOG = LoggerFactory.getLogger(CoreProviderHelper.class);

    public static String ClassName = "clz";

    /**
     * 获取表名称
     *
     * @param obj
     * @return tableName
     */
    protected String getTableName(@org.jetbrains.annotations.NotNull Object obj) {
        Class clz = obj.getClass();
        if (clz.isAnnotationPresent(TbName.class)) {
            TbName tableName = obj.getClass().getAnnotation(TbName.class);
            return tableName.name();
        } else {
            return obj.getClass().getName();
        }

    }

    /**
     * sql 条件字符串化
     *
     * @param map
     * @return
     */
    private StringBuilder mapToStringBuilder(Map<String, String> map) {
        int size = map.size();
        if (CollectionUtil.isEmpty(map)) {
            return new StringBuilder(" 1=1 ");
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            // key = #{className.value}
            sb.append(entry.getKey()).append(" = ")
                    .append("#{").append(ClassName).append(".").append(entry.getValue()).append("}");
            if (size > 1) {
                sb.append(" and ");
                size--;
            }
        }
        return sb;
    }

    /**
     * 生成 insert all sql
     *
     * @param obj
     * @param size
     * @param mysql
     * @return
     */
    protected String getInsertAllCore(Object obj, int size, boolean mysql) {
        Class clz = obj.getClass();
        Field[] fields = clz.getDeclaredFields();
        StringBuilder classField = new StringBuilder(" ( ");
        StringBuilder tbColumn = new StringBuilder(" ( ");
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                if (field.isAnnotationPresent(Column.class) && field.get(obj) != null) {
                    Column fieldAnnotation = field.getAnnotation(Column.class);
                    //输出注解属性
                    String columnTemp = StringUtil.isEmpty(fieldAnnotation.value()) ? field.getName() : fieldAnnotation.value();
                    //mysql 格式:`user`, ; 其余 user,
                    tbColumn.append(mysql ? "`" + columnTemp + "`," : columnTemp + ",");
                    classField.append("#'{'").append("list[{0}]").append(".").append(field.getName()).append("'}'")
                            .append(",");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        tbColumn.setCharAt(tbColumn.length() - 1, ')');
        StringBuilder sb = new StringBuilder("insert into ");
        sb.append(getTableName(obj));
        sb.append(tbColumn).append(" values ");
        classField.setCharAt(classField.length() - 1, ')');
        MessageFormat messageFormat = new MessageFormat(classField.toString());
        StringBuilder temp = new StringBuilder();
        for (int i = 0; i < size; i++) {
            temp.append(messageFormat.format(new Integer[]{i}));
            temp.append(",");
        }
        temp.deleteCharAt(temp.length() - 1);
        classField = temp;
        sb.append(classField);
        return sb.toString();
    }

    /**
     * 单条 insert sql
     *
     * @param obj
     * @param mysql
     * @return sql
     */
    protected String getInsertCore(Object obj, boolean mysql) {
        Field[] fields = obj.getClass().getDeclaredFields();
        StringBuilder tbColumn = new StringBuilder(" ( ");
        StringBuilder classField = new StringBuilder(" ( ");
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                String columnName = StringUtil.isEmpty(column.value()) ? field.getName() : column.value();
                tbColumn.append(mysql ? "`" + columnName + "`" : columnName + ",");
                classField.append("#{").append(ClassName).append(".").append(columnName).append("}").append(",");
            }

        }
        tbColumn.setCharAt(tbColumn.length() - 1, ')');
        classField.setCharAt(classField.length() - 1, ')');

        StringBuilder sb = new StringBuilder("insert into ");
        sb.append(getTableName(obj)).append(tbColumn).append(" values ").append(classField);

        return sb.toString();
    }

    /**
     * 生成查询全表的 sql
     * @param obj
     * @return select
     */
    public String getSelectAllCore(Object obj) {
        StringBuilder classField = new StringBuilder();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                String value = StringUtil.isEmpty(column.value()) ? field.getName() : column.value();
                classField.append(value).append(",");
            }

        }
        classField.deleteCharAt(classField.length()-1);
        StringBuilder sb= new StringBuilder("select ");
        sb.append(classField);
        sb.append(" from " ).append(getTableName(obj));
        return sb.toString();
    }


}

#### pom maven 包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>top.xiong</groupId>
    <artifactId>snarkee</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>snark</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <!-- Mybatis -->
        <snark.mybatis.version>1.3.2</snark.mybatis.version>
        <!-- Mysql -->
        <snark.mysql.version>8.0.13</snark.mysql.version>
        <!-- Generate -->
        <snark.generte.version>1.11.1</snark.generte.version>
        <!--cglib-->
        <snark.cglib.version>3.2.7</snark.cglib.version>

    </properties>

    <dependencies>
        <!-- 可以不用再去关心原生配置方式里的细节,直接使用默认配置就能实现最基本的功能 -->
        <!-- 自动检查Spring Boot的数据源配置并构建DataSource对象
通过SqlSessionFactoryBean使用数据源构建并注册SqlSessionFactory对象
从SqlSessionFactory中创建并注册一个SqlSessionTemplate实例,其实就是构建一个SqlSession对象
自动扫描接口映射器,并将这些映射器与SqlSessionTemplate实例进行关联,同时将它们注册到Spring容器中 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

        <!-- 添加热部署,自动刷新 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <version>2.1.3.RELEASE</version>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>

        <!-- 外部 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${snark.mybatis.version}</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${snark.mysql.version}</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>${snark.cglib.version}</version>
        </dependency>



        <dependency>
            <groupId>com.squareup</groupId>
            <artifactId>javapoet</artifactId>
            <version>${snark.generte.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>bootstrap-test.properties</exclude>
                    <exclude>bootstrap-dev.properties</exclude>
                    <exclude>bootstrap-pro.properties</exclude>
                    <exclude>bootstrap.properties</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <!--<include>bootstrap-${env}.properties</include>-->
                    <include>bootstrap.yml</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

运行就可以的。
如若不懂,我会回复。
我会慢慢分离我自己的代码,早日放源码程序。
第一次发帖好紧张
···今儿才看见有小同志提了问题,关于数据库类型与java类型转换的问题:
*由于我使用的事mybatis自带的type转换注册器,如若您的数据库类型不在org.apache.ibatis.type.JdbcType
此枚举类下,请在我注册转换器的地方top.xiong.snark.util.TypeCastUtil
添加对应转换类型,如:
if ("datetime".equals(typeName)){
    return Date.class;
}
也可以重写我的方法或者重写type注册器,我只是提供一种简单的方式。
链接: https://pan.baidu.com/s/1o9FV9ITOKUEC-Fh-Fcm74Q 提取码: 5gst

免费评分

参与人数 5吾爱币 +3 热心值 +5 收起 理由
没伞的孩子 + 1 + 1 谢谢@Thanks!
kaka233 + 1 + 1 热心回复!
hqm2019 + 1 + 1 用心讨论,共获提升!
LLingding + 1 用心讨论,共获提升!
葬天VS晓伟 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 荼蘼熊 发表于 2019-3-14 09:08
分离完毕,运行即用
链接: https://pan.baidu.com/s/1o9FV9ITOKUEC-Fh-Fcm74Q 提取码: 5gst
 楼主| 荼蘼熊 发表于 2019-3-22 10:49
WingSky 发表于 2019-3-21 16:46
会报java.lang.IllegalArgumentException: No enum constant org.apache.ibatis.type.JdbcType.INT错误

您的数据库的类型是什么,我用的是mybatis 的枚举转换类,如若没有您的类型,你可以在路径top.xiong.snark.util.TypeCastUtil里面添加此类型的转换;只要在org.apache.ibatis.type.JdbcType枚举类虾没有的数据库参数都需要自己转换,或者自己重写TYPE转换注册类。比如if ("int".equals(typeName)){
                return Integer.class;
            };或者用别的方式
葬天VS晓伟 发表于 2019-3-13 18:09
kiritoooo 发表于 2019-3-13 18:29
楼主有springboot的学习视频吗
 楼主| 荼蘼熊 发表于 2019-3-13 18:41
kiritoooo 发表于 2019-3-13 18:29
楼主有springboot的学习视频吗

这个没有,我看的官方文档。可帮你留意一下
 楼主| 荼蘼熊 发表于 2019-3-13 18:41
葬天VS晓伟 发表于 2019-3-13 18:09
期待楼主分享最终版

正在剖离~~
nickle52 发表于 2019-3-13 19:05
期待最终版研究研究
PyScrapy 发表于 2019-3-14 07:42 来自手机
等待最终版
LLingding 发表于 2019-3-14 09:29
感谢分享,已下载,正在研究
小康康 发表于 2019-3-14 10:25
了解一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 15:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表