feat(code-gen): 添加JPA

This commit is contained in:
15858193327
2020-10-22 02:48:47 +08:00
parent 7ead16f2f3
commit 5ae1fb63dd
18 changed files with 198 additions and 56 deletions

View File

@@ -1 +1,17 @@
maven 多环境打包 配置信息自动切换 ## `Maven` 多环境打包
配置信息自动切换
## 安全 - 敏感配置项加密
配置文件中包含了中间件密码、第三方应用密钥等敏感信息,直接以明文方式存储并不安全,故需要加密。
由于我们使用了配置中心,故只需要保证系统与配置中心的通信安全即可,我们采用了 `Nacos`,有以下几种方案可供参考:
* 将 `Nacos-Server` 与应用部署在同一个局域网中,不暴露于互联网。
* `Nacos-Server` 可以支持 `https` 对数据进行加密的,对 `Nacos-Server` 进行改造,使其支持 `https`。
* 通过 `nginx` 间接访问保护,`nginx` 不仅仅可以提供 `https`,还可以提供 `Basic Authentication`、`IP白名单` 等安全方式。
如果不使用注册中心,可以使用 `jasypt` 等方式来将敏感信息脱敏处理。

View File

@@ -43,7 +43,7 @@ public class GeneratorController {
/** /**
* 生成代码 * 生成代码
* web 中不需要主动关闭流 * web 中不需要主动关闭流
* http://localhost:8080/generator/code?tables=tb_shop * http://localhost:8080/generator/code?tables=*
*/ */
@RequestMapping("/code") @RequestMapping("/code")
public void code(String tables, HttpServletResponse response) throws IOException { public void code(String tables, HttpServletResponse response) throws IOException {
@@ -51,9 +51,8 @@ public class GeneratorController {
if (StringUtils.isEmpty(tables)) { if (StringUtils.isEmpty(tables)) {
throw new IllegalArgumentException("tableName can't be empty"); throw new IllegalArgumentException("tableName can't be empty");
} }
response.reset(); response.reset();
byte[] data = sysGeneratorService.generatorCode(tables.split(","), response.getOutputStream()); byte[] data = "*".equals(tables) ? sysGeneratorService.generatorCode(response.getOutputStream()) :sysGeneratorService.generatorCode(tables.split(","), response.getOutputStream());
if (data != null && data.length > 0) { if (data != null && data.length > 0) {
/* /*
// file out put stream 必须及时关闭 // file out put stream 必须及时关闭

View File

@@ -1,6 +1,7 @@
package cn.itlym.shoulder.generator.dao; package cn.itlym.shoulder.generator.dao;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
@@ -21,4 +22,9 @@ public interface SysGeneratorDao {
List<Map<String, String>> queryColumns(String tableName); List<Map<String, String>> queryColumns(String tableName);
@Select("select * from information_schema.TABLES where TABLE_SCHEMA=(select database())")
List<Map<String, String>> listTable();
@Select("select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=(select database())")
List<String> listTableNames();
} }

View File

@@ -19,6 +19,10 @@
</if> </if>
</select> </select>
<select id="queryNameLike" resultType="list">
SELECT table_name FROM information_schema.tables WHERE table_schema='库名'
</select>
<select id="queryTable" resultType="map"> <select id="queryTable" resultType="map">
select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables
where table_schema = (select database()) and table_name = #{tableName} where table_schema = (select database()) and table_name = #{tableName}

View File

@@ -21,6 +21,7 @@ public class TableEntity {
//类名(第一个字母大写)sys_user => SysUser //类名(第一个字母大写)sys_user => SysUser
private String className; private String className;
//类名(第一个字母小写)sys_user => sysUser //类名(第一个字母小写)sys_user => sysUser
private String lowClassName; private String lowClassName;

View File

@@ -23,4 +23,5 @@ public interface SysGeneratorService {
byte[] generatorCode(String[] tableNames, OutputStream out); byte[] generatorCode(String[] tableNames, OutputStream out);
byte[] generatorCode(OutputStream out);
} }

View File

@@ -71,8 +71,29 @@ public class SysGeneratorServiceImpl implements SysGeneratorService {
} }
//生成代码 //生成代码
GenUtils.generatorCode(table, columns, zip); GenUtils.generatorCode(table, columns, zip);
IOUtils.closeQuietly(zip);
} }
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
@Override
public byte[] generatorCode(OutputStream out) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
// 查询所有表信息
List<Map<String, String>> tables = sysGeneratorDao.listTable();
for (Map<String, String> table : tables) {
String tableName = table.get("TABLE_NAME");
//查询列信息
List<Map<String, String>> columns = queryColumns(tableName);
if (MapUtils.isEmpty(table) || CollectionUtils.isEmpty(columns)) {
log.warn("table {} not exist or without any columns", table);
continue;
}
//生成代码
GenUtils.generatorCode(table, columns, zip);
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray(); return outputStream.toByteArray();
} }

View File

@@ -2,6 +2,7 @@ package cn.itlym.shoulder.generator.utils;
import cn.itlym.shoulder.generator.model.ColumnEntity; import cn.itlym.shoulder.generator.model.ColumnEntity;
import cn.itlym.shoulder.generator.model.TableEntity; import cn.itlym.shoulder.generator.model.TableEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.configuration.PropertiesConfiguration;
@@ -24,13 +25,17 @@ import java.util.zip.ZipOutputStream;
* *
* @author lym * @author lym
*/ */
@Slf4j
public class GenUtils { public class GenUtils {
public static List<String> getTemplates() { public static List<String> getTemplates() {
List<String> templates = new ArrayList<String>(); List<String> templates = new ArrayList<String>();
templates.add("template/JpaEntity.java.vm");
templates.add("template/JpaRepository.java.vm");
templates.add("template/Entity.java.vm"); templates.add("template/Entity.java.vm");
templates.add("template/Dao.java.vm"); templates.add("template/Mapper.java.vm");
templates.add("template/Dao.xml.vm"); templates.add("template/Mapper.xml.vm");
templates.add("template/Service.java.vm"); templates.add("template/Service.java.vm");
templates.add("template/ServiceImpl.java.vm"); templates.add("template/ServiceImpl.java.vm");
templates.add("template/Controller.java.vm"); templates.add("template/Controller.java.vm");
@@ -50,8 +55,8 @@ public class GenUtils {
boolean hasBigDecimal = false; boolean hasBigDecimal = false;
//表信息 //表信息
TableEntity tableEntity = new TableEntity(); TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName")); tableEntity.setTableName(table.computeIfAbsent("tableName", k -> table.get("TABLE_NAME")));
tableEntity.setComments(table.get("tableComment")); tableEntity.setComments(table.computeIfAbsent("tableComment", k -> table.get("TABLE_COMMENT")));
//表名转换成Java类名 //表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), config.getString("tablePrefix")); String className = tableToJava(tableEntity.getTableName(), config.getString("tablePrefix"));
tableEntity.setClassName(className); tableEntity.setClassName(className);
@@ -78,7 +83,7 @@ public class GenUtils {
map.put("comments", tableEntity.getComments()); map.put("comments", tableEntity.getComments());
map.put("pk", tableEntity.getPk()); map.put("pk", tableEntity.getPk());
map.put("className", tableEntity.getClassName()); map.put("className", tableEntity.getClassName());
map.put("classname", tableEntity.getLowClassName()); map.put("lowClassName", tableEntity.getLowClassName());
map.put("pathName", tableEntity.getLowClassName().toLowerCase()); map.put("pathName", tableEntity.getLowClassName().toLowerCase());
map.put("columns", tableEntity.getColumns()); map.put("columns", tableEntity.getColumns());
map.put("hasBigDecimal", hasBigDecimal); map.put("hasBigDecimal", hasBigDecimal);
@@ -99,13 +104,15 @@ public class GenUtils {
tpl.merge(context, sw); tpl.merge(context, sw);
try { try {
//添加到zip //添加到zip todo 包名通过 sw 第一行获取
String fileName = getFileName(template, tableEntity.getClassName(), config.getString("package"), tableEntity.getTableName()); String fileName = getFileName(template, tableEntity.getClassName(), config.getString("package"), tableEntity.getTableName());
assert fileName != null;
zip.putNextEntry(new ZipEntry(fileName)); zip.putNextEntry(new ZipEntry(fileName));
IOUtils.write(sw.toString(), zip, "UTF-8"); IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw); IOUtils.closeQuietly(sw);
zip.closeEntry(); zip.closeEntry();
} catch (IOException e) { } catch (IOException e) {
log.error("渲染模板失败," + tableEntity.getTableName(), e);
throw new RuntimeException("渲染模板失败,表名:" + tableEntity.getTableName(), e); throw new RuntimeException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
} }
} }
@@ -127,9 +134,9 @@ public class GenUtils {
columnEntity.setAttributeName(StringUtils.uncapitalize(attrName)); columnEntity.setAttributeName(StringUtils.uncapitalize(attrName));
//列的数据类型转换成Java类型 //列的数据类型转换成Java类型
String attrType = config.getString(columnEntity.getDataType(), "unknowType"); String attrType = config.getString(columnEntity.getDataType(), "unknown");
columnEntity.setAttrType(attrType); columnEntity.setAttrType(attrType);
if (attrType.equals("BigDecimal")) { if ("BigDecimal".equals(attrType)) {
hasBigDecimal = true; hasBigDecimal = true;
} }
//是否主键 //是否主键
@@ -182,12 +189,20 @@ public class GenUtils {
packagePath += packageName.replace(".", File.separator) + File.separator + tableName + File.separator; packagePath += packageName.replace(".", File.separator) + File.separator + tableName + File.separator;
} }
if (template.contains("JpaEntity.java.vm")) {
return packagePath + "entity" + File.separator + className + "Entity.java";
}
if (template.contains("Entity.java.vm")) { if (template.contains("Entity.java.vm")) {
return packagePath + "entity" + File.separator + className + ".java"; return packagePath + "entity" + File.separator + className + ".java";
} }
if (template.contains("Dao.java.vm")) { if (template.contains("Mapper.java.vm")) {
return packagePath + "dao" + File.separator + className + "Dao.java"; return packagePath + "dao" + File.separator + className + "Mapper.java";
}
if (template.contains("JpaRepository.java.vm")) {
return packagePath + "repository" + File.separator + className + "Repository.java";
} }
if (template.contains("Service.java.vm")) { if (template.contains("Service.java.vm")) {
@@ -202,8 +217,8 @@ public class GenUtils {
return packagePath + "controller" + File.separator + className + "Controller.java"; return packagePath + "controller" + File.separator + className + "Controller.java";
} }
if (template.contains("Dao.xml.vm")) { if (template.contains("Mapper.xml.vm")) {
return packagePath + "dao" + File.separator + className + "Dao.xml"; return packagePath + "dao" + File.separator + className + "Mapper.xml";
} }
if (template.contains("menu.sql.vm")) { if (template.contains("menu.sql.vm")) {

View File

@@ -8,7 +8,7 @@ author=lym
#Email #Email
email= email=
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00) #\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
tablePrefix=tb_ #tablePrefix=tb_
#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F #\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F
tinyint=Integer tinyint=Integer
smallint=Integer smallint=Integer

View File

@@ -31,46 +31,54 @@ public class ${className}Controller {
private ${className}Service ${lowClassName}Service; private ${className}Service ${lowClassName}Service;
/** /**
* 列表 * 条件查询,分页
* @param condition 查询条件
* @return 分页结果
*/ */
@RequestMapping("/list") @RequestMapping("/list")
@PreAuthorize("hasAnyAuthority('${tableName}:${pathName}:list')") @PreAuthorize("hasAnyAuthority('${tableName}:${pathName}:list')")
public PageResult list(@RequestParam Map<String, Object> params){ public PageResult list(@RequestParam Map<String, Object> condition){
PageResult pageResult = ${lowClassName}Service.findAll(params); PageResult pageResult = ${lowClassName}Service.findAll(condition);
return pageResult; return pageResult;
} }
/** /**
* 保存 * 保存单个
* @param ${lowClassName} 新增数据
* @return 保存成功
*/ */
@RequestMapping("/save") @RequestMapping("/save")
@PreAuthorize("hasAnyAuthority('generator:sysroleuser:save')") @PreAuthorize("hasAnyAuthority('resource:sysroleuser:save')")
public Result save(@RequestBody ${className} ${lowClassName}){ public RestResult save(@RequestBody ${className} ${lowClassName}){
${lowClassName}Service.save(${lowClassName}); ${lowClassName}Service.save(${lowClassName});
return Result.succeed("保存成功"); return RestResult.succeed();
} }
/** /**
* 修改 * 单个修改
* @param ${lowClassName} 修改属性
* @return 修改成功
*/ */
@RequestMapping("/update") @RequestMapping("/update")
@PreAuthorize("hasAnyAuthority('generator:sysroleuser:update')") @PreAuthorize("hasAnyAuthority('resource:sysroleuser:update')")
public Result update(@RequestBody ${className} ${lowClassName}){ public RestResult update(@RequestBody ${className} ${lowClassName}){
${lowClassName}Service.update(${lowClassName}); ${lowClassName}Service.update(${lowClassName});
return Result.succeed("修改成功"); return RestResult.succeed();
} }
/** /**
* 删除 * 根据 id 删除单个
* @param ${pk.attributeName} id
* @return 删除成功
*/ */
@RequestMapping("/delete/{id}") @RequestMapping("/delete/{id}")
@PreAuthorize("hasAnyAuthority('generator:sysroleuser:delete')") @PreAuthorize("hasAnyAuthority('resource:sysroleuser:delete')")
public Result delete(@PathVariable Long ${pk.attrname}){ public RestResult delete(@PathVariable Long ${pk.attributeName}){
${lowClassName}Service.delete(${pk.attrname}); ${lowClassName}Service.delete(${pk.attributeName});
return Result.succeed("删除成功"); return RestResult.succeed();
} }
} }

View File

@@ -1,4 +1,4 @@
package ${package}.${pkgName}.entity; package ${package}.${pkgName}.po;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -25,7 +25,7 @@ public class ${className} implements Serializable {
#if($column.columnName == $pk.columnName) #if($column.columnName == $pk.columnName)
#end #end
private $column.attrType $column.attrname; private $column.attrType $column.attributeName;
#end #end
} }

View File

@@ -0,0 +1,38 @@
package ${package}.${pkgName}.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
import java.io.Serializable;
import java.util.Date;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
@Data
@Entity
@NoArgsConstructor
@Table// 唯一索引 (uniqueConstraints = {@UniqueConstraint(name = "uk_$pk.columnName", columnNames = {"$pk.columnName"})})
public class ${className}Entity implements Serializable {
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if($column.columnName == $pk.columnName)
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
#end
private $column.attrType $column.attributeName;
#end
}

View File

@@ -0,0 +1,35 @@
package ${package}.${pkgName}.repository;
import ${package}.${pkgName}.entity.${className};
import com.github.kfcfans.powerjob.server.persistence.core.model.OmsLockDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Map;
/**
* ${comments}
*
* @author ${author}
* @date ${datetime}
*/
public interface ${className}Repository extends JpaRepository<${className}, Long> {
/**
* 根据名称查询
* @param name 名称
* @return 查询结果
*/
Optional<${className}> findByName(String name);
/**
* 根据名称模糊查询
* @param name 名称
* @return 查询结果
*/
Page<${className}> findByNameLike(String name, Pageable pageable);
}

View File

@@ -12,9 +12,9 @@ import java.util.Map;
* @date ${datetime} * @date ${datetime}
*/ */
@Mapper @Mapper
public interface ${className}Dao { public interface ${className}Mapper {
int save(${className} ${lowClassName}); int insert(${className} ${lowClassName});
int update(${className} ${lowClassName}); int update(${className} ${lowClassName});
@@ -22,6 +22,4 @@ public interface ${className}Dao {
List<${className}> findAll(Map<String, Object> params); List<${className}> findAll(Map<String, Object> params);
} }

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package}.${pkgName}.dao.${className}Dao"> <mapper namespace="${package}.${pkgName}.dao.${className}Mapper">
<!-- 可根据自己的需求,是否要使用 --> <!-- 可根据自己的需求,是否要使用 -->
<resultMap type="${package}.${pkgName}.entity.${className}" id="${lowClassName}Map"> <resultMap type="${package}.${pkgName}.entity.${className}" id="${lowClassName}Map">
#foreach($column in $columns) #foreach($column in $columns)
<result property="${column.attrname}" column="${column.columnName}"/> <result property="${column.attributeName}" column="${column.columnName}"/>
#end #end
</resultMap> </resultMap>

View File

@@ -11,7 +11,7 @@ import java.util.Map;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
import ${package}.${pkgName}.entity.${className}; import ${package}.${pkgName}.entity.${className};
import ${package}.${pkgName}.dao.${className}Dao; import ${package}.${pkgName}.dao.${className}Mapper;
import ${package}.${pkgName}.service.${className}Service; import ${package}.${pkgName}.service.${className}Service;
@@ -19,14 +19,14 @@ import ${package}.${pkgName}.service.${className}Service;
public class ${className}ServiceImpl implements ${className}Service { public class ${className}ServiceImpl implements ${className}Service {
@Autowired @Autowired
private ${className}Dao ${lowClassName}Dao; private ${className}Mapper ${lowClassName}Mapper;
/** /**
* 添加 * 添加
* @param ${lowClassName} * @param ${lowClassName}
*/ */
public int save(${className} ${lowClassName}){ public int save(${className} ${lowClassName}){
return ${lowClassName}Dao.save(${lowClassName}); return ${lowClassName}Mapper.insert(${lowClassName});
} }
/** /**
@@ -34,16 +34,16 @@ public class ${className}ServiceImpl implements ${className}Service {
* @param ${lowClassName} * @param ${lowClassName}
*/ */
public int update(${className} ${lowClassName}){ public int update(${className} ${lowClassName}){
return ${lowClassName}Dao.update(${lowClassName}); return ${lowClassName}Mapper.update(${lowClassName});
} }
/** /**
* 删除 * 删除
* @param id * @param id 主键
*/ */
public int delete(Long id){ public int delete(Long id){
return ${lowClassName}Dao.delete(id); return ${lowClassName}Mapper.delete(id);
} }
@@ -53,11 +53,11 @@ public class ${className}ServiceImpl implements ${className}Service {
* @return * @return
*/ */
public PageResult<${className}> findAll(Map<String, Object> params){ public PageResult<${className}> findAll(Map<String, Object> params){
//设置分页信息,分别是当前页数和每页显示的总记录数【记住必须在mapper接口中的方法执行之前设置该分页信息】 //设置分页信息,分别是当前页数和每页显示的总记录数
if (MapUtils.getInteger(params, "page")!=null && MapUtils.getInteger(params, "limit")!=null) if (MapUtils.getInteger(params, "page")!=null && MapUtils.getInteger(params, "limit")!=null) {
PageHelper.startPage(MapUtils.getInteger(params, "page"),MapUtils.getInteger(params, "limit"),true); PageHelper.startPage(MapUtils.getInteger(params, "page"), MapUtils.getInteger(params, "limit"), true);
}
List<${className}> list = ${lowClassName}Dao.findAll(params); List<${className}> list = ${lowClassName}Mapper.findAll(params);
PageInfo<${className}> pageInfo = new PageInfo(list); PageInfo<${className}> pageInfo = new PageInfo(list);
return PageResult.<${className}>builder().data(pageInfo.getList()).code(0).count(pageInfo.getTotal()).build(); return PageResult.<${className}>builder().data(pageInfo.getList()).code(0).count(pageInfo.getTotal()).build();

View File

@@ -1,10 +1,10 @@
# shoulder-platform-common # shoulder-platform-common
Shoulder 平台各个工程的`基础设施层`统一实现 Shoulder 平台各个工程的`基础设施层`统一实现(为了简化使用者调试、该工程的模块需要发布至`maven`仓库)
一般的工程模块图如下 一般的工程模块图如下
![projectAndModule.png](../img/projectAndModule.png) ![工程结构.png](../img/archetype/projectAndModule.png)
* 本模块提供了基础中间件的选型与集成,目的:统一技术栈选型。 * 本模块提供了基础中间件的选型与集成,目的:统一技术栈选型。
* 本项目中一般不应引入本模块以外的能力,以保证平台的安全与易维护。 * 本项目中一般不应引入本模块以外的能力,以保证平台的安全与易维护。

View File

@@ -13,7 +13,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>system-config</module> <!--<module>system-config</module>--> <!--系统配置使用 nacos 管理-->
<module>system-dictionary</module> <module>system-dictionary</module>
<module>system-error-code</module> <module>system-error-code</module>
</modules> </modules>