Mybitis根据工具类反射数据库生成映射+整合springboot

一 反向生成数据库mapper的工具类:

  添加依赖

<dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <scope>test</scope>
            <version>1.3.2</version>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>


        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
        </dependency>

   工具类

package org.mybatis.generator.plugins;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

import java.util.List;

public class AddLimitOffsetPlugin extends PluginAdapter {

    public boolean validate(List<String> warnings) {
        return true;
    }

    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
            IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType offsetType = new FullyQualifiedJavaType(
                "javax.annotation.Generated");
        topLevelClass.addImportedType(offsetType);
        topLevelClass.addAnnotation("@Generated(\"" + introspectedTable.getTableConfiguration().getTableName() + "\")");
         PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();
         
        Field limit = new Field();
        limit.setName("limit");
        limit.setVisibility(JavaVisibility.PRIVATE);
        limit.setType(integerWrapper);
        topLevelClass.addField(limit);

        Method limitSet = new Method();
        limitSet.setVisibility(JavaVisibility.PUBLIC);
        limitSet.setName("setLimit");
        limitSet.addParameter(new Parameter(integerWrapper, "limit"));
        limitSet.addBodyLine("this.limit = limit;");
        topLevelClass.addMethod(limitSet);

        Method limitGet = new Method();
        limitGet.setVisibility(JavaVisibility.PUBLIC);
        limitGet.setReturnType(integerWrapper);
        limitGet.setName("getLimit");
        limitGet.addBodyLine("return limit;");
        topLevelClass.addMethod(limitGet);

        Field offset = new Field();
        offset.setName("offset");
        offset.setVisibility(JavaVisibility.PRIVATE);
        offset.setType(integerWrapper);
        topLevelClass.addField(offset);

        Method offsetSet = new Method();
        offsetSet.setVisibility(JavaVisibility.PUBLIC);
        offsetSet.setName("setOffset");
        offsetSet.addParameter(new Parameter(integerWrapper, "offset"));
        offsetSet.addBodyLine("this.offset = offset;");
        topLevelClass.addMethod(offsetSet);

        Method offsetGet = new Method();
        offsetGet.setVisibility(JavaVisibility.PUBLIC);
        offsetGet.setReturnType(integerWrapper);
        offsetGet.setName("getOffset");
        offsetGet.addBodyLine("return offset;");
        topLevelClass.addMethod(offsetGet);

        return true;
    }

    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
            XmlElement element, IntrospectedTable introspectedTable) {
        XmlElement isNotNullElement = new XmlElement("if");
        isNotNullElement.addAttribute(new Attribute("test", "limit > 0"));
        isNotNullElement.addElement(new TextElement("limit ${limit}"));
        element.getElements().add(isNotNullElement);

        isNotNullElement = new XmlElement("if");
        isNotNullElement.addAttribute(new Attribute("test", "offset > 0"));
        isNotNullElement.addElement(new TextElement("offset ${offset}"));
        element.getElements().add(isNotNullElement);
        return true;
    }

}
package org.mybatis.generator.plugins;

import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ProgressCallback;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * mybatis代码生成插件调用者.
 */
public class Generator {

    @Test
    public void generate() throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;

        InputStream stream = Generator.class.getClassLoader().getResourceAsStream("generatorConfig.xml");

        ConfigurationParser cp = new ConfigurationParser(warnings);
        InputStreamReader reader = new InputStreamReader(stream, "utf-8");
        BufferedReader bufferedReader = new BufferedReader(reader);

        String line = bufferedReader.readLine();
        StringBuffer buffer = new StringBuffer();
        while (line != null) {
            buffer.append(line + "\n");
            line = bufferedReader.readLine();
        }
        String xmlWithParam = buffer.toString();
        
        System.out.println("------- xml config begin -------");
        System.out.println(xmlWithParam);
        System.out.println("------- xml config end -------");

        final Configuration config = cp.parseConfiguration(new ByteArrayInputStream(xmlWithParam.getBytes("utf-8")));
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        System.out.println("------- generator begin -------");
        ProgressCallback cb = new ProgressCallback() {
            private Pattern SqlProviderPattern = Pattern.compile("\\w*SqlProvider\\.java");
            private List<String> taskNames = new ArrayList();

            @Override
            public void startTask(String taskName) {
                /*
                 * 输出这些信息从而知道 生成那些类了 
                * Generating Example class for table demo
                * Generating Primary Key class for table demo 
                * Generating Record class for table demo 
                * Generating Mapper Interface for table demo 
                * Generating SQL Provider for table demo 
                * Saving file DemoExample.java
                * Saving file DemoKey.java Saving file Demo.java
                * Saving file DemoMapper.java
                * Saving file DemoSqlProvider.java
                 */
                // System.out.println(taskName);
                taskNames.add( taskName);
            }

            @Override
            public void saveStarted(int arg0) {}

            @Override
            public void introspectionStarted(int arg0) {}

            @Override
            public void generationStarted(int arg0) {}

            @Override
            public void done() {
                for(String taskName : taskNames){
                Matcher matcher = SqlProviderPattern.matcher(taskName);
                    if (matcher.find()) {
                        final String SqlProviderFilename = matcher.group();
                        System.out.println("处理生成文件,selectByExample  增加mysql分页: " + SqlProviderFilename);
                        List<Context> contexts = config.getContexts();
                        FilenameFilter filter = new FilenameFilter() {
                            @Override
                            public boolean accept(File dir, String name) {
                                return SqlProviderFilename.equalsIgnoreCase(name);
                            }
                        };
                        boolean done = false;
                        for (Context ctx : contexts) {
                            if(done){
                                break;
                            }
                            String targetProject = ctx.getJavaClientGeneratorConfiguration().getTargetProject();
                            String targetPackage = ctx.getJavaClientGeneratorConfiguration().getTargetPackage();
                            String dir = targetProject.replaceAll("\\.", "\\\\") + "\\" + targetPackage.replaceAll("\\.", "\\\\");
                            System.out.println(System.getProperty("user.dir") + dir);
                            File mapperDir = new File(System.getProperty("user.dir"), dir);
                            File[] files = mapperDir.listFiles(filter);
                            if (files != null && files.length > 0) {
                                File sqlProviderFile = files[0];
                                try {
                                    Generator.addMysqlLimit(sqlProviderFile);
                                    done = true;
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        if(!done){
                             System.out.println("转换失败!!!! selectByExample  增加mysql分页: " + SqlProviderFilename);
                        } else {
                            System.out.println("转换成功!!!! selectByExample  增加mysql分页: " + SqlProviderFilename);
                        }
                    }
                }
            }

            @Override
            public void checkCancel() throws InterruptedException {}
        };
        myBatisGenerator.generate(cb);
        for (String warning : warnings) {
            System.out.println(warning);
        }
        System.out.println("------- generator end -------");
        // System.out.println(config.getClassPathEntries());
    }

    private static void addMysqlLimit(File sqlProviderFile) throws Exception {
        /*
         * 这是自动生成的selectByExample 中的代码片段
        if (example != null && example.getOrderByClause() != null) {
            ORDER_BY(example.getOrderByClause()); // 整个文件唯一
        }
        
        return SQL();
        
         * 将return SQL()改为下面片段即可:

        String sqlString = SQL();
        if (example != null && example.getLimit() != null) {
            sqlString += " limit " + example.getLimit();
        }
        if (example != null && example.getOffset() != null) {
            sqlString += " offset " + example.getOffset();
        }
        return sqlString;
         */
        BufferedReader reader = new BufferedReader( new FileReader(sqlProviderFile));
        List<String> lines = IOUtils.readLines(reader);
        reader.close();
        String limitString = "        String sqlString = SQL();\n" +
                "        if (example != null && example.getLimit() != null) {\n" +
                "            sqlString += \" limit \" + example.getLimit();\n" +
                "        }\n" +
                "        if (example != null && example.getOffset() != null) {\n" +
                "            sqlString += \" offset \" + example.getOffset();\n" +
                "        }\n" +
                "        return sqlString;";
        ArrayList<String> newLines = new ArrayList<String>();

        
        for (int i=0; i< lines.size();++i) {
            String line = lines.get(i);
            newLines.add(line );
            if(line.replaceAll(" ", "") .equalsIgnoreCase("ORDER_BY(example.getOrderByClause());")) {
                // 添加下一行大括号和空白行
                ++i;
                newLines.add(lines.get(i));
                ++i;
                newLines.add(lines.get(i));
                
                ++i; // 跳过 return SQL();
                newLines.addAll(Arrays.asList( limitString.split("\n")));
            }
        }
        
//        for (String line : newLines) {
//            System.out.println(line);
//        }
        FileOutputStream writer = new FileOutputStream(sqlProviderFile);
        IOUtils.writeLines(newLines, "\n",writer,"UTF-8");
        writer.close();
    }
    
    public static void main(String[] args) throws Exception {
       new Generator().generate();
    }
}

  映射关系配置xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>

    <context id="entmobile" targetRuntime="MyBatis3">

        <plugin type="org.mybatis.generator.plugins.AddLimitOffsetPlugin" />
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />

        <commentGenerator>
            <property name="suppressDate" value="true" />
            <!-- remove comments -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
         
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"
            userId="root" password="root" />
            
        <!-- java type resolver -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- gem entity -->
        <!-- data -->
        <javaModelGenerator targetPackage="com.自己建的实体类包.domain"
            targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>
         
        <!-- //////////////////////////////////////////////////////////////////////////////////////////////////////////////// -->
        <!-- gem annotated mapper -->
        <!-- data -->
        <javaClientGenerator type="ANNOTATEDMAPPER"
            targetPackage="com.自己建的mapper包.mapper"
            targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        
        
        <!--  
        <table tableName="material_type">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>
        -->

        <table tableName="表名">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>




    </context>
</generatorConfiguration>

另外springboot启动类中添加注解:

  @EnableAutoConfiguration 

 

二 数据库配置 application.yml:

spring:
  datasource:
      url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&connectTimeout=3000&socketTimeout=1000
      username: root           # 自己修改填写
      password: root         # 自己修改填写
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      minIdle: 5
      maxActive: 100
      initialSize: 10
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 'x'
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 50
      removeAbandoned: true
      filters: stat # ,wall,log4j # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
      useGlobalDataSourceStat: true # 合并多个DruidDataSource的监控数据
      druidLoginName: wjf # 登录druid的账号
      druidPassword: wjf # 登录druid的密码
      cachePrepStmts: true  # 开启二级缓存
  redis:
         database: 0
         host: XX.XX.XX.XX
         port: 6380
         password: 1234567
  activemq:
      broker-url: tcp://XX.XX.XX.XX:61616
      user: admin
      password: zhangjiawen
      pool:
        enabled: true
        max-connections: 100
mybatis:
   typeAliasesPackage: com.concurrent.mapper # 自己修改填写
   mapperLocations: classpath:/com/concurrent/mapper/*.xml
   mapperScanPackage: com.concurrent.mapper
   configLocation: classpath:/mybatis-config.xml

   mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration  
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
     "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 使全局的映射器启用或禁用缓存。 -->
        <setting name="cacheEnabled" value="true" />
        <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->        
         <setting name="aggressiveLazyLoading" value="true"/>        
         <!-- 是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true -->
        <setting name="multipleResultSetsEnabled" value="true" />
        <!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
        <setting name="useColumnLabel" value="true" />
        <!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false  -->
        <setting name="useGeneratedKeys" value="false" />
        <!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分  FULL:全部  -->
        <setting name="autoMappingBehavior" value="PARTIAL" />
        <!-- 这是默认的执行类型  (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)  -->
        <setting name="defaultExecutorType" value="SIMPLE" />
        
        <setting name="defaultStatementTimeout" value="25" />
        
        <setting name="defaultFetchSize" value="100" />
        
        <setting name="safeRowBoundsEnabled" value="false" />
        <!-- 使用驼峰命名法转换字段。 -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!-- 设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
        <setting name="localCacheScope" value="SESSION" />
        <!-- 默认为OTHER,为了解决oracle插入null报错的问题要设置为NULL -->
        <setting name="jdbcTypeForNull" value="NULL" />
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
    </settings>
    
</configuration>

 

 

另外还有将mapper数据映射加入spring扫描

package com.concurrent.service;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

import javax.sql.DataSource;
import java.sql.SQLException;


/**
 * Created  on 2016/10/25 0025.
 */

@Configuration
@MapperScan("com.自己建的映射包.mapper")
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 50)
public class DataSourceConfig {
    private Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);

    @Value("${spring.datasource.url}")
    private String dbUrl;

    @Value("${spring.datasource.type}")
    private String dbType;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;

    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;

    @Value("${spring.datasource.useGlobalDataSourceStat}")
    private boolean useGlobalDataSourceStat;

    @Value("${spring.datasource.druidLoginName}")
    private String druidLoginName;

    @Value("${spring.datasource.druidPassword}")
    private String druidPassword;

    @Bean(name="dataSource",destroyMethod = "close", initMethod="init")
    @Primary //不要漏了这
    public DataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
        try {
            datasource.setUrl(this.dbUrl);
            datasource.setDbType(dbType);
            datasource.setUsername(username);
            datasource.setPassword(password);
            datasource.setDriverClassName(driverClassName);
            datasource.setInitialSize(initialSize);
            datasource.setMinIdle(minIdle);
            datasource.setMaxActive(maxActive);
            datasource.setMaxWait(maxWait);
            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            datasource.setValidationQuery(validationQuery);
            datasource.setTestWhileIdle(testWhileIdle);
            datasource.setTestOnBorrow(testOnBorrow);
            datasource.setTestOnReturn(testOnReturn);
            datasource.setPoolPreparedStatements(poolPreparedStatements);
            datasource.setFilters(filters);
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter", e);
        }
        return datasource;
    }

    /////////  下面是druid 监控访问的设置  /////////////////
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");  //url 匹配
        reg.addInitParameter("allow", "192.168.16.110,127.0.0.1"); // IP白名单 (没有配置或者为空,则允许所有访问)
        reg.addInitParameter("deny", "192.168.16.111"); //IP黑名单 (存在共同时,deny优先于allow)
        reg.addInitParameter("loginUsername", this.druidLoginName);//登录名
        reg.addInitParameter("loginPassword", this.druidPassword);//登录密码
        reg.addInitParameter("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        return reg;
    }

    @Bean(name="druidWebStatFilter")
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); //忽略资源
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
        filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
        return filterRegistrationBean;
    }
}

使用例子:

  @Resource
    private SysUserMapper sysUserMapper;

    private BloomFilter<Integer> bf;

    /***
     * PostConstruct 程序启动时候加载此方法
     */
    @PostConstruct
    public void initBloomFilter() {
        SysUserExample sysUserExample = new SysUserExample();
        List<SysUser> sysUserList = sysUserMapper.selectByExample(sysUserExample);
       
    }

 



posted @ 2019-10-10 11:59  valar-dohaeris  阅读(744)  评论(0编辑  收藏  举报