实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了

前言

在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一。MyBatis-Plus 代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块及前端页面的代码,极大的提升了开发效率。

项目介绍

本项目将以springboot用演示,前端使用freemaker,数据库持久层用mybatis(考虑到mybatis的使用还是最普遍的,就没有用jpa和mybatisplus),通过Velocity模板引擎配置各模块的文件模板,通过mybatis-plus代码生成器连接mysql,用商品表为例生成各模块的代码和前端页面。(本项目只演示分页查询和导出功能)。

本项目所有代码和脚本都能都文末找到地址。

实战

数据库脚本

创建一张商品表test_goods

CREATE TABLE `test_goods` (
  `id` bigint(20) DEFAULT NULL COMMENT 'id',
  `goods_sn` varchar(45) DEFAULT NULL COMMENT '商品编码',
  `name` varchar(255) DEFAULT NULL COMMENT '商品名称',
  `title` varchar(80) DEFAULT NULL COMMENT '标题',
  `price` decimal(10,2) DEFAULT NULL COMMENT '售价',
  `status` int(2) DEFAULT NULL COMMENT '商品状态',
  `sale_count` int(11) DEFAULT NULL COMMENT '销量',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_date` datetime DEFAULT NULL COMMENT '修改时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

maven依赖

  
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.2
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        
            com.baomidou
            mybatis-plus
            2.1.4
        

        
        
            org.aspectj
            aspectjweaver
            provided
        
        

        
        
            org.projectlombok
            lombok
            1.16.10
            provided
        

        
            org.apache.velocity
            velocity-engine-core
            2.0
        
        
            mysql
            mysql-connector-java
            runtime
        
  
        
            com.opencsv
            opencsv
            3.8
        
  
        
            org.springframework.boot
            spring-boot-starter-freemarker
        
    

配置文件

mybatis:
  mapper-locations: classpath:mybatis/*Mapper.xml
  type-aliases-package: com.lzn.mybatisplus.codegenerator.entity

spring:
  datasource:
    username: root
    password: 123qwe
    url: jdbc:mysql://192.168.0.1:3306/myProject?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
  redis:
    host: 192.168.0.1
    password: 1234qwer
    port: 6379
  freemarker:
    template-loader-path: classpath:/templates/pages/
    cache: false
    charset: UTF-8
    check-template-location: true
    content-type: text/html
    expose-request-attributes: true
    expose-session-attributes: true
    suffix: .ftl

模板文件

本项目中,所有模块的文件都是用Velocity模板引擎生成,这里简单介绍下Velocity的语法,在Velocity中用 表示变量,例如: {table.entityName} 表示实体名,{author}、 {date} 表示作者,日期等。在Velocity中用#表示语法,例如 #foreach( field in ${table.fields})  #end遍历表字段。下面演示几个类、前端文件、xml文件的模板文件

实体类模板(entity.java.vm)

package ${package.Entity};

import java.math.BigDecimal;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * 数据库表名 ${table.name}
 *
 * @author ${author}
 * @date ${date}
 */
@Getter
@Setter
@ToString
public class ${table.entityName}  {

    #foreach($field in ${table.fields})
    /**
     * 数据库字段名 ${field.name} 类型 ${field.type}
     */
    private ${field.propertyType}  ${field.propertyName};

    #end

}

Controller模板(controller.java.vm)

package ${package.Controller};

import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
import com.lzn.mybatisplus.codegenerator.export.${table.entityName}VO;
import com.lzn.mybatisplus.codegenerator.export.${table.entityName}ExportService;
import com.lzn.mybatisplus.codegenerator.utils.entity.*;
import com.lzn.mybatisplus.codegenerator.utils.export.*;
import org.apache.commons.beanutils.ConvertUtils;
import com.lzn.mybatisplus.codegenerator.utils.ParameterUtil;
import com.lzn.mybatisplus.codegenerator.utils.entity.GridDataModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 

 * ${tablecomment}  前端控制器  * 

 *  * @author ${author}  * @since ${date}  */ @Controller @RequestMapping(value="/admin/${table.entityPath}") public class ${table.controllerName}{     private static Logger logger = LoggerFactory.getLogger(${table.controllerName}.class);     @Resource     private ${entity}Service ${table.entityPath}Service;     @RequestMapping(value = "list", method = RequestMethod.GET)     public String list(Model model){         return "/admin/${cfg.pageDirName}/list";     }     @RequestMapping(value = "searchList", method = RequestMethod.POST)     @ResponseBody     @ExportMethod(serviceClass = ${entity}ExportService.class, memo = "明细导出")     public String searchList(ServletRequest request,@ModelAttribute("page")  OmuiPage page){         try {             Map searchParam =    ParameterUtil.getParametersStartingWith(request, "filter_");             GridDataModel<${entity}VO> gd =${table.entityPath}Service.findByPage(searchParam, page);             return JsonMapper.nonDefaultMapper().toJson(gd);         } catch (Exception e) {             logger.error("查询出错了",e);             return JsonMapper.nonDefaultMapper().toJson(new Resp("false", e.getMessage()));         }     } }

Service类模板(service.java.vm)

package ${package.Service};



import org.springframework.stereotype.Service;
import com.lzn.mybatisplus.codegenerator.dao.${table.mapperName};
import com.lzn.mybatisplus.codegenerator.utils.entity.GridDataModel;
import com.lzn.mybatisplus.codegenerator.utils.entity.OmuiPage;
import com.lzn.mybatisplus.codegenerator.export.${table.entityName}VO;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 

 * $!{tablecomment} 服务类  * 

 *  * @author ${author}  * @since ${date}  */ @Service public class ${table.serviceName} {     @Resource     private ${table.mapperName} ${table.entityPath}Dao;     /**      * 分页查询      * */     public GridDataModel<${table.entityName}VO>  findByPage(Map searchParams, OmuiPage page){         GridDataModel<${table.entityName}VO> gm = new GridDataModel<${table.entityName}VO>();         searchParams.put("start", page.getStart());         searchParams.put("limit", page.getLimit());         long count = ${table.entityPath}Dao.countForPage(searchParams);         List<${table.entityName}VO> list = ${table.entityPath}Dao.listForPage(searchParams);         gm.setTotal(count);         gm.setRows(list);         return gm;     } }

Dao类模板(dao.java.vm)

package ${package.Mapper};

import com.lzn.mybatisplus.codegenerator.entity.${table.entityName};
import com.lzn.mybatisplus.codegenerator.export.${table.entityName}VO;
import java.util.List;
import java.util.Map;

public interface ${table.mapperName}  {
    /**
     *  根据主键删除数据库的记录, ${table.name}
     */
    int deleteByPrimaryKey(Long id);

    /**
     *  新写入数据库记录, ${table.name}
     */
    int insert(${table.entityName} record);

    /**
     *  根据指定主键获取一条数据库记录, ${table.name}
     */
    ${table.entityName} selectByPrimaryKey(Long id);

    /**
     *  根据主键来更新符合条件的数据库记录, ${table.name}
     */
    int updateByPrimaryKey(${table.entityName} record);

    /**
     *  根据条件分页查询
     * */
    List<${table.entityName}VO> listForPage(Map searchMap);

    /**
     *  根据条件分页查询(计数)
     * */
    long countForPage(Map searchMap);
    
}

Mapper.xml模板(mapper.xml.vm)




    #if(${baseResultMap})
        
        
            #foreach($field in ${table.fields})
                #if(${field.keyFlag})##生成主键排在第一位
                    
                #end
            #end
            #foreach($field in ${table.commonFields})##生成公共字段
                
            #end
            #foreach($field in ${table.fields})
                #if(!${field.keyFlag})##生成普通字段
                    
                #end
            #end
        
    #end

    #if(${baseColumnList})
        
        
        #foreach($field in ${table.commonFields})
            #if(${field.name} == ${field.propertyName})${field.name}#else${field.name} AS ${field.propertyName}#end,
        #end
        ${table.fieldNames}
        
    #end

    
        
        delete from ${table.name}
        where
        #foreach($field in ${table.fields})
            #if(${field.keyFlag})## 主键
                ${field.name} = #{ ${field.propertyName} }
            #end
        #end
    

    
        
        
            SELECT LAST_INSERT_ID()
        
        insert into ${table.name} (
        #foreach($field in ${table.fields})
            #if(!${field.keyFlag})##生成普通字段
                ${field.name}#if($foreach.hasNext),#end
            #end
        #end
        )
        values (
        #foreach($field in ${table.fields})
            #if(!${field.keyFlag})##生成普通字段
                #{ ${field.propertyName}}#if($foreach.hasNext),#end
            #end
        #end
        )
    

    
        
        update ${table.name}
        set
        #foreach($field in ${table.fields})
            #if(!${field.keyFlag})##生成普通字段
               ${field.name} = #{ ${field.propertyName}} #if($foreach.hasNext),#end
            #end
        #end
        where
        #foreach($field in ${table.fields})
            #if(${field.keyFlag})
              id = #{ ${field.name} }
            #end
        #end
    


    
        
        select
        
        from ${table.name}
        where id = #{ id }
    

    
        
        select
         count(*)
        from
        ${table.name}
        where 1=1
        
            and create_date =]]>  #{beginDate}
        
        
            and  create_date  #{endDate}
        
    

    
        
        select
        
        from
        ${table.name}
        where 1=1
        
            and create_date =]]>  #{beginDate}
        
        
            and  create_date  #{endDate}
        
        limit #{start}, #{limit}
    

前端页面list.ftl模板(list.ftl.vm)


 <#assign base=request.contextPath>



$!{tablecomment}














   $().ready(function(){

      //初始化控件
      $("#search-panel").omPanel({
         title : "条件搜索",collapsible:false
      });

      //搜索
      $('#searchButton').bind('click', function(e) {
           var data = $("#listForm").HForm('form2json');
           $('#listGrid').omGrid({extraData:data});
      });

      $("#start-time").omCalendar();
      $("#time-end").omCalendar();

       $('#searchButton').omButton({
         icons : {left : '${base}/static/omui/images/search.png'},width : 70
       });

        $(".input-select").change(function(){
            $('#searchButton').click();
        });

      $('#buttonbar').omButtonbar({
         btns : [{label:"导出Excel",
                  id:"addbutton" ,
                  icons : {left : '${base}/static/omui/images/export.png'},
                  onClick:function()
                     {
                        exportUtil({
                           title : "列表导出",
                           exportUrl : "${base}/admin/${table.entityPath}/searchList",
                           extraParam : $("#listForm").HForm('form2json')
                        });
                     }
                  }
               ]
      });


      //初始化列表
      var  height=$(document).height() -$('#search-panel').outerHeight()-$('#buttonbar').outerHeight()-40;
      $('#listGrid').omGrid({
         height:height,
         limit:20,
         method:'post',
         singleSelect:false,
         extraData:$("#listForm").HForm('form2json'),
         dataSource : '${base}/admin/${table.entityPath}/searchList',
         colModel : [
                     {header : 'ID', name : 'id', width : 30, align : 'left',sort:'serverSide'},
                  {header : '创建时间', name : 'createDate', width : 150, align : 'left',sort:'serverSide',renderer :dataFormat1},
                  {header : '修改时间', name : 'modifyDate', width : 150, align : 'left',sort:'serverSide',renderer :dataFormat1},
#foreach($field in ${table.fields})

#set($comment = "")
#set($type = "")
#set($isNullAble = true)
#set($defaultValue = false)
#set($listIsShow = true)
#set($listIsSearch = false)

#foreach( $e in $field.comment.split(","))
    #if( $foreach.count == 1 )
    #set($comment = $e)
    #elseif( $foreach.count == 2 )
    #set($type = $e)
    #elseif( $foreach.count == 3)
    #if($e == "YES")
    #set($isNullAble = true)
    #else
    #set($isNullAble = false)
    #end
    #elseif( $foreach.count == 4)
    #if($e == "true")
    #set($defaultValue = true)
    #else
    #set($defaultValue = false)
    #end
    #elseif( $foreach.count == 5)
    #if($e == "true")
    #set($listIsShow = true)
    #else
    #set($listIsShow = false)
    #end
    #elseif( $foreach.count == 6)
    #if($e == "true")
    #set($listIsSearch = true)
    #else
    #set($listIsSearch = false)
    #end
    #end
#end
         {header : '#if("$!comment" != "")${comment}#end', name : '${field.propertyName}',width : 90, align : 'left',sort:'serverSide'#if($type == "timer"),renderer :dataFormat1 #end},
#end
         ],
         rowDetailsProvider:function(rowData){
         }
      });

      //初始化控件  end
      function getIds(datas) {
         var str = "";
         for (var i = 0; i < datas.length; i++) {
            str += datas[i].id + ",";
         }
         //去掉最后一个逗号(如果不需要去掉,就不用写)
         if (str.length > 0) {
            str = str.substr(0, str.length - 1);
         }
         return str;
      }

      $('#searchButton').click();
   });








    
   
      状态:                 待处理          已处理          全部              手机号:              联系人:              创建时间:              -              查询    
   
 

代码生成器

package com.lzn.mybatisplus.codegenerator;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 辅助生产后台开发相关代码  开发时只在自己本地代码修改,不要提交
 * 生成ddao service controller entity java代码 和前端 flt文件。
 * 只演示list场景
 */
public class MpGenerator {

    //注意:开发时只在自己本地代码修改,不要提交、不要提交 不要提交
    //第一步修改 javaSrcDir 修改成自己项目存放java源代码的根路径
    static String javaSrcDir = "D:/Git_space/lunzijihua/codegenerator/src/main/java";
    static String resourceDir = "D:/Git_space/lunzijihua/codegenerator/src/main/resources";
    //第二步修改 pageRootDir 修改成你要开发的模块的名称 存放ftl文件的文件夹的根路径
    static String pageRootDir ="D:/Git_space/lunzijihua/codegenerator/src/main/resources/templates/pages/";


    //第三步修改 packageName 修改成你要开发的模块的名称 包名 要小写 生产的entity service dao action文件夹和java代码会在下面
    static String packageName = "user";//模块文件夹包名称
    //第四步修改 pageDirName 修改成你要开发的模块的名称 存放ftl文件的文件夹 要小写
    static String pageDirName = "user";//模块页面文件夹名
    //第五步骤 表的前缀 填写了 生成文件时会去除掉
    static String tablePrefix="test_";
    //第六步 数据库里面对应的表的全名
    static String tableName="test_goods";

    /**
     * 

     * 代码自动生成      * 

     */     public static void main(String[] args) {         AutoGenerator mpg = new AutoGenerator();         // 全局配置         GlobalConfig gc = new GlobalConfig();         gc.setOutputDir(javaSrcDir);         gc.setFileOverride(true);         gc.setActiveRecord(true);// 不需要ActiveRecord特性的请改为false         gc.setEnableCache(false);// XML 二级缓存         gc.setBaseResultMap(true);// XML ResultMap         gc.setBaseColumnList(true);// XML columList         // .setKotlin(true) 是否生成 kotlin 代码         gc.setAuthor("liuzhinan");         // 自定义文件命名,注意 %s 会自动填充表实体属性!         gc.setMapperName("%sMybatisDao");         // gc.setXmlName("%sDao");         gc.setServiceName("%sService"); //         gc.setServiceImplName("%sService");         // gc.setControllerName("%sAction");         mpg.setGlobalConfig(gc);         // 数据源配置         DataSourceConfig dsc = new DataSourceConfig();         dsc.setDbType(DbType.MYSQL);         dsc.setTypeConvert(new MySqlTypeConvert(){             // 自定义数据库表字段类型转换【可选】             @Override             public DbColumnType processTypeConvert(String fieldType) {                 System.out.println("转换类型:" + fieldType);                 // 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。                 return super.processTypeConvert(fieldType);             }         });         dsc.setDriverName("com.mysql.jdbc.Driver");         dsc.setUsername("test");         dsc.setPassword("123456");         dsc.setUrl("jdbc:mysql://192.168.0.1:3306/myProject?useSSL=false");         mpg.setDataSource(dsc);         // 策略配置         StrategyConfig strategy = new StrategyConfig();         // strategy.setCapitalMode(true);// 全局大写命名 ORACLE 注意         strategy.setTablePrefix(new String[] { tablePrefix });// 此处可以修改为您的表前缀         strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略         strategy.setInclude(new String[] { tableName }); // 需要生成的表         // strategy.setExclude(new String[]{"test"}); // 排除生成的表         // 自定义实体父类         strategy.setSuperEntityClass("com.lzn.mybatisplus.codegenerator.entity.IdEntity");         // 自定义实体,公共字段         //  strategy.setSuperEntityColumns(new String[] { "id", "create_date","modify_date" });         // 自定义 mapper 父类         // strategy.setSuperMapperClass("com.baomidou.demo.TestMapper");         // 自定义 service 父类         // strategy.setSuperServiceClass("com.baomidou.demo.TestService");         // 自定义 service 实现类父类         // strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl");         // 自定义 controller 父类         // strategy.setSuperControllerClass("com.baomidou.demo.TestController");         // 【实体】是否生成字段常量(默认 false)         // public static final String ID = "test_id";         // strategy.setEntityColumnConstant(true);         // 【实体】是否为构建者模型(默认 false)         // public User setName(String name) {this.name = name; return this;}         // strategy.setEntityBuilderModel(true);         mpg.setStrategy(strategy);         // 包配置         PackageConfig pc = new PackageConfig();         pc.setParent("com.lzn.mybatisplus.codegenerator");         pc.setModuleName(null);         pc.setMapper("dao");         pc.setEntity("entity");         pc.setService("service");         pc.setServiceImpl("service.impl");         pc.setController("controller");         mpg.setPackageInfo(pc);         // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】         InjectionConfig cfg = new InjectionConfig() {             @Override             public void initMap() {                 Map map = new HashMap();                 map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");                 map.put("pageDirName",pageDirName);                 map.put("packageName",packageName);                 this.setMap(map);             }         };         List focList = new ArrayList(); //        cfg.setFileOutConfigList(focList); //        mpg.setCfg(cfg);         //生成导出视图对象         focList.add(new FileOutConfig("/templates/vm/vo.java.vm") {             @Override             public String outputFile(TableInfo tableInfo) {                 return javaSrcDir+"/com/lzn/mybatisplus/codegenerator/export/"+tableInfo.getEntityName()+"VO.java";             }         });         //生成excel导出的服务类,         focList.add(new FileOutConfig("/templates/vm/exportservice.java.vm") {             @Override             public String outputFile(TableInfo tableInfo) {                 return javaSrcDir+"/com/lzn/mybatisplus/codegenerator/export/"+tableInfo.getEntityName()+"ExportService.java";             }         });         //生成mybatisDao文件到指定目录         focList.add(new FileOutConfig("/templates/vm/mybatisdao.java.vm") {             @Override             public String outputFile(TableInfo tableInfo) {                 return  javaSrcDir+"/com/lzn/mybatisplus/codegenerator/dao/"+tableInfo.getEntityName()+"MybatisDao.java";             }         });         //生成mapper文件到指定目录         focList.add(new FileOutConfig("/templates/vm/mapper.xml.vm") {             @Override             public String outputFile(TableInfo tableInfo) {                 return resourceDir+"/mybatis/"+tableInfo.getEntityName()+"Mapper.xml";             }         });         // 自定义 xxList.ftl 生成         focList.add(new FileOutConfig("/templates/vm/list.ftl.vm") {             @Override             public String outputFile(TableInfo tableInfo) {                 // 自定义输入文件名称                 return pageRootDir+pageDirName+"/list.ftl";             }         });         cfg.setFileOutConfigList(focList);         mpg.setCfg(cfg);         // 关闭默认 xml 生成,调整生成 至 根目录         TemplateConfig tc = new TemplateConfig();         tc.setEntity("/templates/vm/entity.java.vm");         tc.setService("/templates/vm/service.java.vm");         tc.setServiceImpl(null);//设成null才会不生产         tc.setController("/templates/vm/controller.java.vm");         tc.setMapper(null);         tc.setXml(null);         mpg.setTemplate(tc);         // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,         // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称         // TemplateConfig tc = new TemplateConfig();         // tc.setController("...");         // tc.setEntity("...");         // tc.setMapper("...");         // tc.setXml("...");         // tc.setService("...");         // tc.setServiceImpl("...");         // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。         // mpg.setTemplate(tc);         // 执行生成         mpg.execute();         // 打印注入设置【可无】         System.err.println(mpg.getCfg().getMap().get("abc"));     } }

执行代码生成器的Main方法

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第1张图片

执行代码后,在对应的目录自动生成了文件

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第2张图片

启动项目

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第3张图片

并访问列表页路径 http://localhost:8080/admin/goods/list

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第4张图片 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第5张图片

点击导出按钮(由于篇幅有限,导出的视图对象,导出service类和aop切面实现本文没有阐述,各位可自行下载代码查看)

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第6张图片 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第7张图片

总结

本文为项目自动生成前后端代码提供了思路:我们可以为项目的增删改查业务编写一套规范的代码,以此编写代码模板,后续通过代码生成器,通过数据库的一张表可快速生成前后端代码,提高项目组的开发效率。

代码

https://github.com/pengziliu/GitHub-code-practice

这个项目包含很多轮子实例,每个实例都配有技术文章。

觉得不错可以给个Star哦~

实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了_第8张图片

推荐实战文章

  • Java实现图片水印+压缩So easy!

  • 分布式定时任务xxJob的常用姿势都集齐了,So Easy!

  • 这个轮子让SpringBoot实现api加密So Easy!

  • 实战:SpringBoot集成xxl-sso实现单点登录

  • 神奇!不需要服务器,搭建免费个人Blog,so easy!

  • 没想到啊,Java操作Excel竟然这么简单!

  • 实战:Shardingsphere分库分表

  • 实战:十分钟实现基于JWT前后端分离的权限框架

  • 实战:SpringBoot集成rabbitmq并实现延时队列

  • 实战:SpringBoot分布式验证码登录方案

原创不易,觉得有点用的话,请为本文点个在看,因为这将是我肝轮子的最强动力。

写了几十篇原创在这个小号,并行更新,关注回复“资料”有惊喜哦

你可能感兴趣的:(数据库,glassfish,entity,ado.net,javabean)