- 续Java:SpringBoot+Jwt+Shiro+MybatisPlus+Swagger集成
在上文中描述了项目中各框架的集成,本文主要讲述MybatisPlus的代码生成环节。下文讲述时环境均以第一篇相同。
- Generator 生成器
package com.huafeng.cams.common.generator;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Author JinXing _让世界看到我
* On 2019/12/31
* Note mybatis plus 代码生成器
*
* 生成代码时请注意各配置项的内容,比如数据库连接等
*/
public class Generator {
private static Logger logger=LoggerFactory.getLogger(Generator.class);
public static final String dbDeviceName= "com.mysql.jdbc.Driver";
public static final String dbUrl= "jdbc:mysql://localhost:3306/cams_server_hf?useSSL=true";
public static final String dbUsername= "jinxing";
public static final String dbPassword= "19910414";
public static final String author = "jxx";
public static final String parentPackage= "com.huafeng.cams.module";
public static void main(String[] args) {
generatorAllTable();
}
/**
* 生成数据库中所有表的代码
* 谨慎使用,如果把原来的代码覆盖掉就麻烦了
*/
private static void generatorAllTable() {
List tableNames = DBUtil.getMysqlTableNames(dbDeviceName, dbUrl, dbUsername, dbPassword);
logger.info("数据库中的表名称:"+new Gson().toJson(tableNames));
for (String tableName : tableNames) {
generatorTable(tableName);
}
}
/**
* 生成一个表的代码
* @param tableName
*/
private static void generatorTable(String tableName) {
AutoGenerator mpg = new AutoGenerator();
//全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor(author);
gc.setOpen(false);
gc.setSwagger2(true); //实体属性 swagger2 注解
mpg.setGlobalConfig(gc);
//数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setDbType(DbType.MYSQL);
dsc.setDriverName(dbDeviceName);
dsc.setUrl(dbUrl);
dsc.setUsername(dbUsername);
dsc.setPassword(dbPassword);
mpg.setDataSource(dsc);
//包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(tableName);
pc.setParent(parentPackage);
pc.setXml(pc.getMapper());
mpg.setPackageInfo(pc);
//自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
//
}
};
//自定义输出配置
//使用过程中好像没什么用,mapper.xml文件生成在模块中mapper目录中了,这里生成了一个空目录
List fos = new ArrayList<>();
fos.add(new FileOutConfig() {
@Override
public String outputFile(TableInfo tableInfo) {
String xmlPath = projectPath+"/src/main/java/"+pc.getParent()+"/"+tableInfo.getEntityName()+"Mapper"+ StringPool.DOT_XML;
System.out.println("自定义输出配置:"+xmlPath);
return xmlPath;
}
});
mpg.setCfg(cfg);
//配置模板引擎,如果不配置默认使用velocity,并且各模块代码中都是空
TemplateConfig tc = new TemplateConfig();
//tc.setEntity("template/Entity.java.vm");
tc.setController("template/Controller.java.vm");
//tc.setService("template/Service.java.vm");
tc.setServiceImpl("template/ServiceImpl.java.vm");
//tc.setMapper("template/Mapper.java.vm");
//tc.setXml(null);
mpg.setTemplate(tc);
//策略配置
StrategyConfig sc = new StrategyConfig();
sc.setNaming(NamingStrategy.underline_to_camel);
sc.setColumnNaming(NamingStrategy.underline_to_camel);
//sc.setSuperEntityClass("");//自定义实体的父类
//sc.setEntityLombokModel(true);
sc.setRestControllerStyle(true);
//sc.setSuperControllerClass("");//自定义父类controller
//sc.setSuperEntityColumns("");//自定义父类中的公共字段
sc.setInclude(new String[]{tableName});//需要生成的表名
sc.setControllerMappingHyphenStyle(true);
//sc.setTablePrefix(pc.getModuleName()+"_");
mpg.setStrategy(sc);
mpg.execute();
}
}
- DBUtil 自定义
package com.huafeng.cams.common.generator;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* Author JinXing _让世界看到我
* On 2020/1/2
* Note TODO
*/
public class DBUtil {
/**
* 获取MySQL数据库中的所有表名
*
* @param driveName
* @param url
* @param username
* @param password
* @return
*/
public static List getMysqlTableNames(String driveName, String url, String username, String password) {
List list = new ArrayList<>();
Connection conn = getConn(driveName, url, username, password);
if (conn != null) {
try {
DatabaseMetaData db = conn.getMetaData();
ResultSet tables = db.getTables(null, null, null, null);
while (tables.next()) {
list.add(tables.getString(3));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
closeConn(conn);
return list;
}
private static void closeConn(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static Connection getConn(String driveName, String url, String username, String password) {
Connection conn = null;
try {
Class.forName(driveName);
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
-
代码生成器中就是根据数据库表结构和自定义某些规则,生成对应的controller、entity、mapper、service代码:
在编写代码生成器时值得注意的几点:
- 可以通过数据库连接获取到数据库中的所有表一次生成所有的代码
- 可以只针对单表的代码生成
- 可以指定代码生成的位置(包),比如:
public static final String parentPackage= "com.huafeng.cams.module";
pc.setParent(parentPackage);
- 可以指定生成代码的名称的规则比如实体类名称已数据库表名称命名或者加前缀/后缀
- 实体中属性的命名和表中字段的规则,一般以小驼峰形式
- mapper.xml文件的位置
- 代码生成使用的模板定义
- 代码生成模板
//配置模板引擎,如果不配置默认使用velocity,并且各模块代码中都是空
TemplateConfig tc = new TemplateConfig();
//tc.setEntity("template/Entity.java.vm");
tc.setController("template/Controller.java.vm");
//tc.setService("template/Service.java.vm");
tc.setServiceImpl("template/ServiceImpl.java.vm");
//tc.setMapper("template/Mapper.java.vm");
//tc.setXml(null);
mpg.setTemplate(tc);
如果不适用模板的话,默认也是能生成代码的,不过都是空的。为了让代码生成器更加健壮,我们可以自定义模板,让代码生成按照我们的规则,生成尽可能多的适合我们的代码,根据实际业务,笔者编写了controller和serviceImpl的模板:
- controller
package ${package.Controller};
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.*;
#else
import org.springframework.stereotype.Controller;
#end
#if(${supperControllerClassPackage})
import ${supperControllerClassPackage};
#end
import com.huafeng.cams.common.R;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
*
* @author ${author}
* @since ${date}
*
* @motto 让世界看到我
*
* TODO
*/
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping(value = "/${table.entityPath}")
@Api(tags = "${entity}接口文档")
#if (${supperControllerClass})
public class ${table.controllerName} extends ${supperControllerClass} {
#else
public class ${table.controllerName} {
#end
@Autowired
private ${table.serviceName} mService;
@GetMapping(value = "getList")
@ApiOperation(value = "获取${entity}列表")
public R getList(){
List<${entity}> list = mService.list();
return R.RESULT_SUCCESS_DATA(list);
}
@GetMapping(value = "get${entity}ById")
@ApiOperation(value = "根据id查询${entity}信息")
public R get${entity}ById(long id){
${entity} object = mService.getById(id);
return R.RESULT_SUCCESS_DATA(object);
}
@PostMapping(value = "update${entity}ById")
@ApiOperation(value = "根据id修改${entity}信息")
public R update${entity}ById(${entity} object) {
boolean update = mService.updateById(object);
return R.RESULT_SUCCESS_DATA(update);
}
@PostMapping(value = "delete${entity}ById")
@ApiOperation(value = "根据id删除${entity}信息")
public R delete${entity}ById(long id){
boolean delete = mService.removeById(id);
return R.RESULT_SUCCESS_DATA(delete);
}
@PostMapping(value = "insert${entity}")
@ApiOperation(value = "新增一条${entity}信息")
public R insert${entity}(${entity} object) {
boolean save = mService.save(object);
return R.RESULT_SUCCESS_DATA(save);
}
}
- serviceImpl
package ${package.ServiceImpl};
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
/**
*
* 服务实现类
*
*
* @author ${author}
* @since ${date}
*/
@Service
@Primary
public class ${table.serviceImplName} extends ServiceImpl<${table.mapperName}, ${entity}> implements I${entity}Service {
@Autowired
${table.mapperName} mMapper;
}
其中controller中添加了对实体最基础的增删改查。serviceImpl中其实什么也没加,笔者编写的原因是默认生成的serviceImpl文件会有错误,需要添加@Primary注解才行,每一个添加肯定麻烦,因此编写了一个模板,从这种小事情可以看出模板定义的重要性。这也说明在多框架整合时,不同的版本还是有差异的,因此发现问题需要寻找解决方案。
-
在代码生成完毕后启动项目,可以通过swagger看到各模块的调试接口,供前端人员调试。