主要参考另外两篇博文,这里表示感谢
参考一(mybatisplus3.x分页) : https://www.jianshu.com/p/2ec9337dc2b0
参考二(mybatisplus2.x升级3.x) : https://my.oschina.net/u/241218/blog/1838534
mybatisplus2.x 和 mybatisplus3.x 变化比较大, 资料查询的时候注意版本, 可以避依赖冲突.
0.新建springboot web项目(打包模式一定要用war包 ,否则报错找不到模版,目前还不知道原因)
1. demo项目环境 springboot-2.1.1 + mybatisplus3.0.6 + velocity2.0 + jdk1.8 + idea
2. application.yml
server: port: 8080 servlet: context-path: /maven #项目名称 spring: profiles: active: local #@spring.active@ #默认使用本地配置文件 mvc: static-path-pattern: /static/** view: prefix: /WEB-INF/view devtools: restart: enabled: false additional-paths: src/main/java exclude: static/**,WEB-INF/view/** servlet: multipart: max-request-size: 100MB max-file-size: 100MB freemarker: allow-request-override: false cache: false check-template-location: true charset: utf-8 content-type: text/html expose-request-attributes: false expose-session-attributes: false expose-spring-macro-helpers: true suffix: .ftl settings: auto_import: /spring.ftl as spring template_update_delay: 0 mybatis-plus: mapper-locations: classpath*:/mapper/**Mapper.xml #实体扫描,多个package用逗号或者分号分隔 typeAliasesPackage: com.dofun.code.entity global-config: #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; id-type: 0 #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" field-strategy: 2 #驼峰下划线转换 db-column-underline: true #刷新mapper 调试神器 refresh-mapper: true #逻辑删除配置(下面3个配置) logic-delete-value: 0 logic-not-delete-value: 1 configuration: map-underscore-to-camel-case: true cache-enabled: false #logging logging: path: maven-logs level: com.dofun: debug #这个改成自己项目路径,不然可能报错 --- spring: profiles: local datasource: url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useServerPrepStmts=false&serverTimezone=Hongkong username: root password: root db-name: test filters: wall,mergeStat
3. pom 工程依赖
<dependencies> <!--springboot依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>1.0.5</version> </dependency>
<!-- 内部集成mybatis和mybatis-spring, 不需要在引入, 避免版本冲突 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.0.6</version> </dependency> <!-- druid连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> <scope>runtime</scope> </dependency> <!-- 模版引擎 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- java编译插件,maven默认1.5版本过低,指定为1.8 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <!--编译打包时,忽略测试类--> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build>
4. MpGenerator 代码生成器
package com.dofun.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; 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.TableFill; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.DbColumnType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MpGenerator { /** * <p> * MySQL 生成演示 * </p> */ public static void main(String[] args) { // 自定义需要填充的字段 List<TableFill> tableFillList = new ArrayList<>(); tableFillList.add(new TableFill("ASDD_SS", FieldFill.INSERT_UPDATE)); AutoGenerator mpg = new AutoGenerator(); // 选择 freemarker 引擎,默认 Veloctiy // mpg.setTemplateEngine(new FreemarkerTemplateEngine()); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir("F:\idea-maven\maven\src\main\java"); gc.setFileOverride(true); gc.setActiveRecord(true);// 不需要ActiveRecord特性的请改为false gc.setEnableCache(false);// XML 二级缓存 gc.setBaseResultMap(true);// XML ResultMap gc.setBaseColumnList(true);// XML columList //gc.setKotlin(true);//是否生成 kotlin 代码 gc.setAuthor("Hcl"); // 自定义文件命名,注意 %s 会自动填充表实体属性! gc.setMapperName("%sMapper"); gc.setXmlName("%sMapper"); gc.setServiceName("%sService"); gc.setServiceImplName("%sServiceImpl"); gc.setControllerName("%sController"); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); /*dsc.setTypeConvert(new MySqlTypeConvert(){ // 自定义数据库表字段类型转换【可选】 public DbColumnType processTypeConvert(String fieldType) { System.out.println("转换类型:" + fieldType); // 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。 return super.processTypeConvert(fieldType); } });*/ dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&serverTimezone=Hongkong"); mpg.setDataSource(dsc); // 策略配置 StrategyConfig strategy = new StrategyConfig(); // strategy.setCapitalMode(true);// 全局大写命名 ORACLE 注意 //strategy.setTablePrefix(new String[] { "tlog_", "tsys_" });// 此处可以修改为您的表前缀 strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略 //strategy.setInclude(new String[]{"app_certificate"}); // 需要生成的表,注释掉生成全部表 // strategy.setExclude(new String[]{"test"}); // 排除生成的表 // 自定义实体父类 // strategy.setSuperEntityClass("com.baomidou.demo.TestEntity"); // 自定义实体,公共字段 // strategy.setSuperEntityColumns(new String[] { "test_id", "age" }); // 自定义 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); strategy.setTableFillList(tableFillList); mpg.setStrategy(strategy); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent("com.dofun"); pc.setController("controller"); pc.setXml("mapper"); mpg.setPackageInfo(pc); // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】 ${cfg.abc} InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { Map<String, Object> map = new HashMap<String, Object>(); map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp"); this.setMap(map); } }; // 自定义 xxListIndex.html 生成 List<FileOutConfig> focList = new ArrayList<FileOutConfig>(); focList.add(new FileOutConfig("/templates/list.html.vm") { @Override public String outputFile(TableInfo tableInfo) { // 自定义输入文件名称 return "F:/idea-maven/maven/src/main/resources/static/" + tableInfo.getEntityName() + "ListIndex.html"; } }); cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 关闭默认 xml 生成,调整生成 至 根目录 /*TemplateConfig tc = new TemplateConfig(); tc.setXml(null); mpg.setTemplate(tc);*/ // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改, // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称 TemplateConfig tc = new TemplateConfig(); tc.setController("/templates/controller.java.vm"); tc.setService("/templates/service.java.vm"); tc.setServiceImpl("/templates/serviceImpl.java.vm"); tc.setEntity("/templates/entity.java.vm"); tc.setMapper("/templates/mapper.java.vm"); tc.setXml("/templates/mapper.xml.vm"); // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。 mpg.setTemplate(tc); // 执行生成 mpg.execute(); // 打印注入设置【可无】 System.err.println(mpg.getCfg().getMap().get("abc")); } }
package com.dofun.common; import java.io.Serializable; import java.util.List; public class DatatablesJSON<T> implements Serializable { //当前页面 private int draw; //总页数 private long recordsTotal; private long recordsFiltered; // 响应状态 默认false private Boolean success = false; // 响应消息 private String error; public List<T> getData() { return data; } public void setData(List<T> data) { this.data = data; } // 存放的数据 private List<T> data; public int getDraw() { return draw; } public void setDraw(int draw) { this.draw = draw; } public long getRecordsTotal() { return recordsTotal; } public void setRecordsTotal(long recordsTotal) { this.recordsTotal = recordsTotal; } public long getRecordsFiltered() { return recordsFiltered; } public void setRecordsFiltered(long recordsFiltered) { this.recordsFiltered = recordsFiltered; } public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } public String getError() { return error; } public void setError(String error) { this.error = error; } }
package com.dofun.common; import java.io.Serializable; /** * ajax 传参返回值 */ public class JSONResult<T> implements Serializable { // 响应状态 默认false private Boolean success = false; // 响应消息 private String message; // 存放的数据 private T data; public JSONResult() { super(); } public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
5. controller 模版 controller.java.vm
package ${package.Controller}; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestMethod; #if(${restControllerStyle}) import org.springframework.web.bind.annotation.RestController; #else import org.springframework.stereotype.Controller; #end #if(${superControllerClassPackage}) import ${superControllerClassPackage}; #end import org.springframework.beans.factory.annotation.Autowired; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import ${package.Service}.${table.serviceName}; import com.dofun.common.DatatablesJSON; import com.dofun.common.JSONResult; import ${package.Entity}.${entity}; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @description : ${entity} 控制器 * @author ${author} * @since ${date} */ #if(${restControllerStyle}) @RestController #else @Controller #end @RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end") #if(${superControllerClass}) public class ${table.controllerName} extends ${superControllerClass} { #else public class ${table.controllerName} { #end private final Logger logger=LoggerFactory.getLogger(${table.controllerName}.class); @Autowired public ${table.serviceName} ${table.entityPath}Service; /** * @description : 获取分页列表 * --------------------------------- * @author : ${author} * @since : Create in ${date} */ @RequestMapping(value = "/get${entity}List", method = RequestMethod.POST) public Object get${entity}List(${entity} param,@RequestParam(value = "draw", defaultValue = "0") Integer draw, @RequestParam(value = "length") Integer length, @RequestParam(value = "start") Integer start){ DatatablesJSON<${entity}> resJson=new DatatablesJSON<>(); try{ ## Integer pageNo=getPageNo(start,length); Integer pageNo=1; Page<${entity}> page=new Page<${entity}>(pageNo,length); ${table.entityPath}Service.page(page,new QueryWrapper<${entity}>(param)); resJson.setDraw(draw++); resJson.setRecordsTotal(page.getTotal()); resJson.setRecordsFiltered(page.getTotal()); resJson.setData(page.getRecords()); resJson.setSuccess(true); }catch(Exception e){ resJson.setSuccess(false); resJson.setError("异常信息:{"+e.getClass().getName()+"}"); logger.info("异常信息:{}"+e.getMessage()); } return resJson; } /** * @description : 通过id获取${entity} * --------------------------------- * @author : ${author} * @since : Create in ${date} */ @RequestMapping(value = "/get${entity}ById", method = RequestMethod.GET) public Object get${entity}ById(String id){ JSONResult<${entity}> resJson=new JSONResult<>(); try{ ${entity} param= ${table.entityPath}Service.getById(id); resJson.setData(param); resJson.setSuccess(true); }catch(Exception e){ resJson.setSuccess(false); resJson.setMessage("异常信息:{"+e.getClass().getName()+"}"); logger.info("异常信息:{}"+e.getMessage()); } return resJson; } /** * @description : 通过id删除${entity} * --------------------------------- * @author : ${author} * @since : Create in ${date} */ @RequestMapping(value = "/delete${entity}ById", method = RequestMethod.GET) public Object delete${entity}ById(String id){ JSONResult<${entity}> resJson=new JSONResult<>(); try{ resJson.setSuccess(${table.entityPath}Service.removeById(id)); }catch(Exception e){ resJson.setSuccess(false); resJson.setMessage("异常信息:{"+e.getClass().getName()+"}"); logger.info("异常信息:{}"+e.getMessage()); } return resJson; } /** * @description : 通过id更新${entity} * --------------------------------- * @author : ${author} * @since : Create in ${date} */ @RequestMapping(value = "/update${entity}ById", method = RequestMethod.POST) public Object update${entity}ById(${entity} param){ JSONResult<${entity}> resJson=new JSONResult<>(); try{ resJson.setSuccess(${table.entityPath}Service.updateById(param)); }catch(Exception e){ resJson.setSuccess(false); resJson.setMessage("异常信息:{"+e.getClass().getName()+"}"); logger.info("异常信息:{}"+e.getMessage()); } return resJson; } /** * @description : 添加${entity} * --------------------------------- * @author : ${author} * @since : Create in ${date} */ @RequestMapping(value = "/add${entity}", method = RequestMethod.POST) public Object add${entity}(${entity} param){ JSONResult<${entity}> resJson=new JSONResult<>(); try{ resJson.setSuccess(${table.entityPath}Service.save(param)); }catch(Exception e){ resJson.setSuccess(false); resJson.setMessage("异常信息:{"+e.getClass().getName()+"}"); logger.info("异常信息:{}"+e.getMessage()); } return resJson; } }
6. html页面模版 list.html.vm (这个目前生成的页面和项目并不配套,先预留位置, 后续结合自己项目慢慢研究~)
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head th:replace="common/common_header :: common_header(~{::title},~{},~{})"> <title>首页</title> </head> <body> <section class="content"> <div class="row"> <!-- BEGIN SAMPLE TABLE PORTLET--> <div class="col-md-12"> <!-- BEGIN SAMPLE TABLE PORTLET--> <div class="box-body" style="padding-bottom:0px;"> <div class="panel panel-default"> <div class="panel-heading">高级检索</div> <div class="panel-body"> <form class="form-inline" method="post" id="searchForm" > <div class="form-group"> <label for="name">角色名</label> <input type="text" class="form-control" id="name" name="name" placeholder="用户名"/> <input id="hiddenText" type="text" style="display:none" /><!-- 隐藏的 控制回车提交表单--> </div> <button shiro:hasPermission="sys:user:search" type="button" id="btn_query" class="btn btn-success"><i class="fa fa-search"></i> 查询</button> <button shiro:hasPermission="sys:user:search" type="button" id="btn_reset" class="btn btn-primary"><i class="fa fa-undo"></i> 重置</button> </form> </div> </div> <div id="toolbar" class="btn-group"> <button shiro:hasPermission="sys:user:add" id="btn_add" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增 </button> <button shiro:hasPermission="sys:user:delete" id="btn_delete" type="button" class="btn btn-default" disabled="disabled"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>批量删除 </button> </div> <div class="table-scrollable"> <table class="table-striped table-hover table-bordered" id="empUserList"> </table> </div> </div> <!-- END SAMPLE TABLE PORTLET--> </div> </div> </section> </body> <script th:inline="javascript"> var permissionButton = [];//权限按钮 </script> <script th:inline="javascript" shiro:hasPermission="sys:user:update"> permissionButton.push('<a class="btn btn-icon-only" data-type="edit" href="javascript:void(0)" title="修改"><i class="glyphicon glyphicon-edit"></i></a>'); </script> <script th:inline="javascript" shiro:hasPermission="sys:user:delete"> permissionButton.push('<a class="btn btn-icon-only" data-type="delete" href="javascript:void(0)" title="删除"><i class="glyphicon glyphicon-remove"></i></a>'); </script> <div th:replace="common/common_foot :: foot"></div> <script th:src="@{/content/plugins/bootstrap-table/bootstrap-table.js}"></script> <script th:src="@{/content/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.js}"></script> <script th:src="@{/content/common/common.server.js}"></script> <script th:inline="javascript">#macro(dian).#end #set($bootstrapTable = '$table') #macro(tanh)!#end #set($query = '$query') #set($reset = '$reset') #set($remove = '$remove') #set($add = '$add') var $bootstrapTable = $('#empUserList'), $query = $('#btn_query'), $reset = $('#btn_reset'), $remove = $('#btn_delete'), $add = $('#btn_add'), selections = [];//权限按钮 $(function () { $(".select2").select2(); $bootstrapTable#dian()bootstrapTable({ url: getRootPath()+'/a/${table.entityPath}/get${entity}PageList', queryParams : queryParams, classes: "table-striped table-hover table-bordered", buttonsAlign: "right", //按钮位置 toolbar: "#toolbar",// 指定工具栏 uniqueId: "id", // 每一行的唯一标识 columns: [ {checkbox : true}, #foreach($field in ${table.fields}) #if(!${field.keyFlag})##生成普通字段 {title: '${field.comment}', field: '${field.propertyName}', align: 'center', valign: 'middle', sortable: true}, #end #end { title: '操作', field: 'id', align: 'center', valign: 'middle', formatter: function (value, row, index) { return permissionButton.join(''); }, events: { 'click [data-type="edit"]': function (e, value, row) { layer_show("修改", getRootPath() + "/a/${table.entityPath}/${table.entityPath}Update?id=" + value, "800", "600"); }, 'click [data-type="delete"]': function (e, value, row) { $.fn.modalConfirm('确定要删除所选数据?', function () { $.ajax({ url: getRootPath() + '/a/${table.entityPath}/${table.entityPath}Delete', type: "Post", data: {id: value}, dataType: "json", success: function (result) { if (result > 0) { $.fn.modalMsg("操作成功", "success"); } else { $.fn.modalMsg("操作失败", "error"); } $remove#dian()prop('disabled', true); $bootstrapTable#dian()bootstrapTable('refresh'); //从新加载数据 } }); }); } } } ], onLoadSuccess: function(){ //加载成功时执行 //layer.msg("加载成功"); }, onLoadError: function(){ //加载失败时执行 layer.msg("加载数据失败", {time : 1500, icon : 2}); } }); // sometimes footer render error. setTimeout(function () { $bootstrapTable#dian()bootstrapTable('resetView', { height:getHeight() }); }, 300); $(window).resize(function () { $bootstrapTable#dian()bootstrapTable('resetView', { height:getHeight() }); }); //点击行中的checkbox 和全选的checkbox事件 $bootstrapTable#dian()on('check.bs.table uncheck.bs.table ' + 'check-all.bs.table uncheck-all.bs.table', function () { $remove#dian()prop('disabled', #tanh()$bootstrapTable#dian()bootstrapTable('getSelections').length); selections = getIdSelections(); }); $query#dian()click(function () { $bootstrapTable#dian()bootstrapTable('refresh'); //从新加载数据 }); $reset#dian()click(function () { $(".form-inline .form-control").val(""); $bootstrapTable#dian()bootstrapTable('refresh'); //从新加载数据 }); $add#dian()click(function () { layer_show("添加", getRootPath()+"/a/${table.entityPath}/${table.entityPath}Add","800","600"); }); $remove#dian()click(function () { if (selections.length < 1) { $.fn.modalAlert('请选择一条或多条数据进行删除!','error'); } else { //询问框 $.fn.modalConfirm ('确定要删除所选数据?', function () { $.ajax({ url: getRootPath()+'/a/${table.entityPath}/${table.entityPath}BatchDelete', type: "Post", data:{item:JSON.stringify(selections)}, dataType : "json", success:function(result){ if(result > 0){ $.fn.modalMsg("操作成功","success"); }else { $.fn.modalMsg("操作失败","error"); } $remove#dian()prop('disabled', true); $bootstrapTable#dian()bootstrapTable('refresh'); //从新加载数据 } }); }); } }); /* input 获取焦点 才能触发 刷新事件*/ $("input").keydown(function() { if (event.keyCode == "13") {//keyCode=13是回车键 if ($query#dian()length > 0){ $bootstrapTable#dian()bootstrapTable('refresh'); //从新加载数据 } } }); }); /** * 返回所有的checked选中的值 */ function getIdSelections() { return $.map($bootstrapTable#dian()bootstrapTable('getSelections'), function (row) { return row.id }); } /** * 查询条件与分页数据 * @param params * @returns {{limit: (*|number), offset, sort, order}} */ function queryParams(params) { var temp = { //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的 limit: params.limit, //页面大小 offset: params.offset, //页码 sort: params.sort, //排序列名 order:params.order //排序方式 //search:params.search, //搜索框参数 }; getSearchFormData($("#searchForm"),temp); return temp; } </script> </html>