first commit

This commit is contained in:
2025-06-18 19:14:40 +08:00
commit 343db0669c
368 changed files with 31132 additions and 0 deletions

View File

@ -0,0 +1,77 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
/**
* 列的数据信息
* @author Zheng Jie
* @date 2019-01-02
*/
@Getter
@Setter
@NoArgsConstructor
@TableName("code_column")
public class ColumnInfo implements Serializable {
@ApiModelProperty(value = "ID", hidden = true)
@TableId(value = "column_id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "表名")
private String tableName;
@ApiModelProperty(value = "数据库字段名称")
private String columnName;
@ApiModelProperty(value = "数据库字段类型")
private String columnType;
@ApiModelProperty(value = "数据库字段键类型")
private String keyType;
@ApiModelProperty(value = "字段额外的参数")
private String extra;
@ApiModelProperty(value = "数据库字段描述")
private String remark;
@ApiModelProperty(value = "是否必填")
private Boolean notNull;
@ApiModelProperty(value = "是否在列表显示")
private Boolean listShow = true;
@ApiModelProperty(value = "是否表单显示")
private Boolean formShow = true;
@ApiModelProperty(value = "表单类型")
private String formType;
@ApiModelProperty(value = "查询 1:模糊 2精确")
private String queryType;
@ApiModelProperty(value = "字典名称")
private String dictName;
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 代码生成配置
* @author Zheng Jie
* @date 2019-01-03
*/
@Getter
@Setter
@NoArgsConstructor
@TableName("code_config")
public class GenConfig implements Serializable {
public GenConfig(String tableName) {
this.tableName = tableName;
}
@ApiModelProperty(value = "ID", hidden = true)
@TableId(value = "config_id", type = IdType.AUTO)
private Long id;
@NotBlank
@ApiModelProperty(value = "表名")
private String tableName;
@ApiModelProperty(value = "接口名称")
private String apiAlias;
@NotBlank
@ApiModelProperty(value = "包路径")
private String pack;
@NotBlank
@ApiModelProperty(value = "模块名")
private String moduleName;
@NotBlank
@ApiModelProperty(value = "前端文件路径")
private String path;
@ApiModelProperty(value = "前端文件路径")
private String apiPath;
@ApiModelProperty(value = "作者")
private String author;
@ApiModelProperty(value = "表前缀")
private String prefix;
@ApiModelProperty(value = "是否覆盖")
private Boolean cover = false;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.domain.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 表的数据信息
* @author Zheng Jie
* @date 2019-01-02
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TableInfo {
@ApiModelProperty(value = "表名称")
private Object tableName;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建日期yyyy-MM-dd HH:mm:ss")
private Object createTime;
@ApiModelProperty(value = "数据库引擎")
private Object engine;
@ApiModelProperty(value = "编码集")
private Object coding;
@ApiModelProperty(value = "备注")
private Object remark;
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.domain.ColumnInfo;
import com.fuyuanshen.domain.dto.TableInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author Zheng Jie
* @date 2023-06-26
*/
@Mapper
public interface ColumnInfoMapper extends BaseMapper<ColumnInfo> {
IPage<TableInfo> getTables(@Param("tableName") String tableName, Page<Object> page);
List<ColumnInfo> findByTableNameOrderByIdAsc(@Param("tableName") String tableName);
List<ColumnInfo> getColumns(@Param("tableName") String tableName);
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fuyuanshen.domain.GenConfig;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @author Zheng Jie
* @date 2023-06-26
*/
@Mapper
public interface GenConfigMapper extends BaseMapper<GenConfig> {
GenConfig findByTableName(@Param("tableName") String tableName);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.fuyuanshen.domain.GenConfig;
import com.fuyuanshen.service.GenConfigService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/genConfig")
@Api(tags = "系统:代码生成器配置管理")
public class GenConfigController {
private final GenConfigService genConfigService;
@ApiOperation("查询")
@GetMapping(value = "/{tableName}")
public ResponseEntity<GenConfig> queryGenConfig(@PathVariable String tableName){
return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK);
}
@PutMapping
@ApiOperation("修改")
public ResponseEntity<GenConfig> updateGenConfig(@Validated @RequestBody GenConfig genConfig){
return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig),HttpStatus.OK);
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.rest;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.fuyuanshen.domain.ColumnInfo;
import com.fuyuanshen.domain.dto.TableInfo;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.service.GenConfigService;
import com.fuyuanshen.service.GeneratorService;
import com.fuyuanshen.utils.PageResult;
import com.fuyuanshen.utils.PageUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/generator")
@Api(tags = "系统:代码生成管理")
public class GeneratorController {
private final GeneratorService generatorService;
private final GenConfigService genConfigService;
@Value("${generator.enabled}")
private Boolean generatorEnabled;
@ApiOperation("查询数据库数据")
@GetMapping(value = "/tables")
public ResponseEntity<PageResult<TableInfo>> queryTables(@RequestParam(defaultValue = "") String name, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size){
return new ResponseEntity<>(generatorService.getTables(name, new Page<>(page, size)), HttpStatus.OK);
}
@ApiOperation("查询字段数据")
@GetMapping(value = "/columns")
public ResponseEntity<PageResult<ColumnInfo>> queryColumns(@RequestParam String tableName){
List<ColumnInfo> columnInfos = generatorService.getColumns(tableName);
return new ResponseEntity<>(PageUtil.toPage(columnInfos), HttpStatus.OK);
}
@ApiOperation("保存字段数据")
@PutMapping
public ResponseEntity<HttpStatus> saveColumn(@RequestBody List<ColumnInfo> columnInfos){
generatorService.save(columnInfos);
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("同步字段数据")
@PostMapping(value = "sync")
public ResponseEntity<HttpStatus> syncColumn(@RequestBody List<String> tables){
for (String table : tables) {
generatorService.sync(generatorService.getColumns(table), generatorService.query(table));
}
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("生成代码")
@PostMapping(value = "/{tableName}/{type}")
public ResponseEntity<Object> generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){
if(!generatorEnabled && type == 0){
throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!");
}
switch (type){
// 生成代码
case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
break;
// 预览
case 1: return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
// 打包
case 2: generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
break;
default: throw new BadRequestException("没有这个选项");
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.domain.GenConfig;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
public interface GenConfigService extends IService<GenConfig> {
/**
* 查询表配置
* @param tableName 表名
* @return 表配置
*/
GenConfig find(String tableName);
/**
* 更新表配置
* @param tableName 表名
* @param genConfig 表配置
* @return 表配置
*/
GenConfig update(String tableName, GenConfig genConfig);
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.domain.GenConfig;
import com.fuyuanshen.domain.ColumnInfo;
import com.fuyuanshen.domain.dto.TableInfo;
import com.fuyuanshen.utils.PageResult;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
public interface GeneratorService extends IService<ColumnInfo> {
/**
* 查询数据库元数据
*
* @param name 表名
* @param page 分页参数
* @return /
*/
PageResult<TableInfo> getTables(String name, Page<Object> page);
/**
* 得到数据表的元数据
* @param name 表名
* @return /
*/
List<ColumnInfo> getColumns(String name);
/**
* 同步表数据
* @param columnInfos /
* @param columnInfoList /
*/
void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList);
/**
* 保持数据
* @param columnInfos /
*/
void save(List<ColumnInfo> columnInfos);
/**
* 代码生成
* @param genConfig 配置信息
* @param columns 字段信息
*/
void generator(GenConfig genConfig, List<ColumnInfo> columns);
/**
* 预览
* @param genConfig 配置信息
* @param columns 字段信息
* @return /
*/
ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns);
/**
* 打包下载
* @param genConfig 配置信息
* @param columns 字段信息
* @param request /
* @param response /
*/
void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response);
/**
* 查询数据库的表字段数据数据
* @param table /
* @return /
*/
List<ColumnInfo> query(String table);
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import com.fuyuanshen.domain.GenConfig;
import com.fuyuanshen.mapper.GenConfigMapper;
import com.fuyuanshen.service.GenConfigService;
import org.springframework.stereotype.Service;
import java.io.File;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
@Service
@RequiredArgsConstructor
@SuppressWarnings({"unchecked","all"})
public class GenConfigServiceImpl extends ServiceImpl<GenConfigMapper, GenConfig> implements GenConfigService {
private final GenConfigMapper genConfigMapper;
@Override
public GenConfig find(String tableName) {
GenConfig genConfig = genConfigMapper.findByTableName(tableName);
if(genConfig == null){
return new GenConfig(tableName);
}
return genConfig;
}
@Override
public GenConfig update(String tableName, GenConfig genConfig) {
String separator = File.separator;
String[] paths;
String symbol = "\\";
if (symbol.equals(separator)) {
paths = genConfig.getPath().split("\\\\");
} else {
paths = genConfig.getPath().split(File.separator);
}
StringBuilder api = new StringBuilder();
for (String path : paths) {
api.append(path);
api.append(separator);
if ("src".equals(path)) {
api.append("api");
break;
}
}
genConfig.setApiPath(api.toString());
saveOrUpdate(genConfig);
return genConfig;
}
}

View File

@ -0,0 +1,161 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.fuyuanshen.domain.GenConfig;
import com.fuyuanshen.domain.ColumnInfo;
import com.fuyuanshen.domain.dto.TableInfo;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.mapper.ColumnInfoMapper;
import com.fuyuanshen.service.GeneratorService;
import com.fuyuanshen.utils.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class GeneratorServiceImpl extends ServiceImpl<ColumnInfoMapper, ColumnInfo> implements GeneratorService {
private final ColumnInfoMapper columnInfoMapper;
private final String CONFIG_MESSAGE = "请先配置生成器";
@Override
public PageResult<TableInfo> getTables(String name, Page<Object> page) {
return PageUtil.toPage(columnInfoMapper.getTables(name, page));
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<ColumnInfo> getColumns(String tableName) {
List<ColumnInfo> columnInfos = columnInfoMapper.findByTableNameOrderByIdAsc(tableName);
if (CollectionUtil.isNotEmpty(columnInfos)) {
return columnInfos;
} else {
columnInfos = query(tableName);
saveBatch(columnInfos);
return columnInfos;
}
}
@Override
public List<ColumnInfo> query(String tableName) {
List<ColumnInfo> columnInfos = columnInfoMapper.getColumns(tableName);
for (ColumnInfo columnInfo : columnInfos) {
columnInfo.setTableName(tableName);
if(GenUtil.PK.equalsIgnoreCase(columnInfo.getKeyType())
&& GenUtil.EXTRA.equalsIgnoreCase(columnInfo.getExtra())){
columnInfo.setNotNull(false);
}
}
return columnInfos;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList) {
// 第一种情况,数据库类字段改变或者新增字段
for (ColumnInfo columnInfo : columnInfoList) {
// 根据字段名称查找
List<ColumnInfo> columns = columnInfos.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
// 如果能找到,就修改部分可能被字段
if (CollectionUtil.isNotEmpty(columns)) {
ColumnInfo column = columns.get(0);
column.setColumnType(columnInfo.getColumnType());
column.setExtra(columnInfo.getExtra());
column.setKeyType(columnInfo.getKeyType());
if (StringUtils.isBlank(column.getRemark())) {
column.setRemark(columnInfo.getRemark());
}
saveOrUpdate(column);
} else {
// 如果找不到,则保存新字段信息
save(columnInfo);
}
}
// 第二种情况,数据库字段删除了
for (ColumnInfo columnInfo : columnInfos) {
// 根据字段名称查找
List<ColumnInfo> columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
// 如果找不到,就代表字段被删除了,则需要删除该字段
if (CollectionUtil.isEmpty(columns)) {
removeById(columnInfo);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void save(List<ColumnInfo> columnInfos) {
saveOrUpdateBatch(columnInfos);
}
@Override
public void generator(GenConfig genConfig, List<ColumnInfo> columns) {
if (genConfig.getId() == null) {
throw new BadRequestException(CONFIG_MESSAGE);
}
try {
GenUtil.generatorCode(columns, genConfig);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new BadRequestException("生成失败,请手动处理已生成的文件");
}
}
@Override
public ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns) {
if (genConfig.getId() == null) {
throw new BadRequestException(CONFIG_MESSAGE);
}
List<Map<String, Object>> genList = GenUtil.preview(columns, genConfig);
return new ResponseEntity<>(genList, HttpStatus.OK);
}
@Override
public void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response) {
if (genConfig.getId() == null) {
throw new BadRequestException(CONFIG_MESSAGE);
}
try {
File file = new File(GenUtil.download(columns, genConfig));
String zipPath = file.getPath() + ".zip";
ZipUtil.zip(file.getPath(), zipPath);
FileUtil.downloadFile(request, response, new File(zipPath), true);
} catch (IOException e) {
throw new BadRequestException("打包失败");
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.utils;
import org.apache.commons.configuration.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* sql字段转java
*
* @author Zheng Jie
* @date 2019-01-03
*/
public class ColUtil {
private static final Logger log = LoggerFactory.getLogger(ColUtil.class);
/**
* 转换mysql数据类型为java数据类型
*
* @param type 数据库字段类型
* @return String
*/
static String cloToJava(String type) {
Configuration config = getConfig();
assert config != null;
return config.getString(type, "unknowType");
}
/**
* 获取配置信息
*/
public static PropertiesConfiguration getConfig() {
try {
return new PropertiesConfiguration("gen.properties");
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
return null;
}
}

View File

@ -0,0 +1,417 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.utils;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.*;
import lombok.extern.slf4j.Slf4j;
import com.fuyuanshen.domain.GenConfig;
import com.fuyuanshen.domain.ColumnInfo;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.time.LocalDate;
import java.util.*;
import static com.fuyuanshen.utils.FileUtil.SYS_TEM_DIR;
/**
* 代码生成
*
* @author Zheng Jie
* @date 2019-01-02
*/
@Slf4j
@SuppressWarnings({"unchecked", "all"})
public class GenUtil {
private static final String TIMESTAMP = "Timestamp";
private static final String BIGDECIMAL = "BigDecimal";
public static final String PK = "PRI";
public static final String EXTRA = "auto_increment";
/**
* 获取后端代码模板名称
*
* @return List
*/
private static List<String> getAdminTemplateNames() {
List<String> templateNames = new ArrayList<>();
templateNames.add("Entity");
templateNames.add("Controller");
templateNames.add("QueryCriteria");
templateNames.add("Service");
templateNames.add("ServiceImpl");
templateNames.add("Mapper");
templateNames.add("Mapper-xml");
return templateNames;
}
/**
* 获取前端代码模板名称
*
* @return List
*/
private static List<String> getFrontTemplateNames() {
List<String> templateNames = new ArrayList<>();
templateNames.add("index");
templateNames.add("api");
return templateNames;
}
public static List<Map<String, Object>> preview(List<ColumnInfo> columns, GenConfig genConfig) {
Map<String, Object> genMap = getGenMap(columns, genConfig);
List<Map<String, Object>> genList = new ArrayList<>();
// 获取后端模版
List<String> templates = getAdminTemplateNames();
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
for (String templateName : templates) {
Map<String, Object> map = new HashMap<>(1);
Template template = engine.getTemplate("admin/" + templateName + ".ftl");
map.put("content", template.render(genMap));
map.put("name", templateName.replace("-xml", ".xml"));
genList.add(map);
}
// 获取前端模版
templates = getFrontTemplateNames();
for (String templateName : templates) {
Map<String, Object> map = new HashMap<>(1);
Template template = engine.getTemplate("front/" + templateName + ".ftl");
map.put(templateName, template.render(genMap));
map.put("content", template.render(genMap));
map.put("name", templateName);
genList.add(map);
}
return genList;
}
public static String download(List<ColumnInfo> columns, GenConfig genConfig) throws IOException {
// 拼接的路径:/tmpeladmin-gen-temp/这个路径在Linux下需要root用户才有权限创建,非root用户会权限错误而失败更改为 /tmp/eladmin-gen-temp/
// String tempPath =SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
String tempPath = SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
Map<String, Object> genMap = getGenMap(columns, genConfig);
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
// 生成后端代码
List<String> templates = getAdminTemplateNames();
for (String templateName : templates) {
Template template = engine.getTemplate("admin/" + templateName + ".ftl");
String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), tempPath + "eladmin" + File.separator);
assert filePath != null;
File file = new File(filePath);
// 如果非覆盖生成
if (!genConfig.getCover() && FileUtil.exist(file)) {
continue;
}
// 生成代码
genFile(file, template, genMap);
}
// 生成前端代码
templates = getFrontTemplateNames();
for (String templateName : templates) {
Template template = engine.getTemplate("front/" + templateName + ".ftl");
String path = tempPath + "eladmin-web" + File.separator;
String apiPath = path + "src" + File.separator + "api" + File.separator;
String srcPath = path + "src" + File.separator + "views" + File.separator + genMap.get("changeClassName").toString() + File.separator;
String filePath = getFrontFilePath(templateName, apiPath, srcPath, genMap.get("changeClassName").toString());
assert filePath != null;
File file = new File(filePath);
// 如果非覆盖生成
if (!genConfig.getCover() && FileUtil.exist(file)) {
continue;
}
// 生成代码
genFile(file, template, genMap);
}
return tempPath;
}
public static void generatorCode(List<ColumnInfo> columnInfos, GenConfig genConfig) throws IOException {
Map<String, Object> genMap = getGenMap(columnInfos, genConfig);
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
// 生成后端代码
List<String> templates = getAdminTemplateNames();
for (String templateName : templates) {
Template template = engine.getTemplate("admin/" + templateName + ".ftl");
String rootPath = System.getProperty("user.dir");
String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), rootPath);
assert filePath != null;
File file = new File(filePath);
// 如果非覆盖生成
if (!genConfig.getCover() && FileUtil.exist(file)) {
continue;
}
// 生成代码
genFile(file, template, genMap);
}
// 生成前端代码
templates = getFrontTemplateNames();
for (String templateName : templates) {
Template template = engine.getTemplate("front/" + templateName + ".ftl");
String filePath = getFrontFilePath(templateName, genConfig.getApiPath(), genConfig.getPath(), genMap.get("changeClassName").toString());
assert filePath != null;
File file = new File(filePath);
// 如果非覆盖生成
if (!genConfig.getCover() && FileUtil.exist(file)) {
continue;
}
// 生成代码
genFile(file, template, genMap);
}
}
// 获取模版数据
private static Map<String, Object> getGenMap(List<ColumnInfo> columnInfos, GenConfig genConfig) {
// 存储模版字段数据
Map<String, Object> genMap = new HashMap<>(16);
// 接口别名
genMap.put("apiAlias", genConfig.getApiAlias());
// 包名称
genMap.put("package", genConfig.getPack());
// 模块名称
genMap.put("moduleName", genConfig.getModuleName());
// 作者
genMap.put("author", genConfig.getAuthor());
// 创建日期
genMap.put("date", LocalDate.now().toString());
// 表名
genMap.put("tableName", genConfig.getTableName());
// 大写开头的类名
String className = StringUtils.toCapitalizeCamelCase(genConfig.getTableName());
// 小写开头的类名
String changeClassName = StringUtils.toCamelCase(genConfig.getTableName());
// 判断是否去除表前缀
if (StringUtils.isNotEmpty(genConfig.getPrefix())) {
className = StringUtils.toCapitalizeCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
changeClassName = StringUtils.toCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
changeClassName = StringUtils.uncapitalize(changeClassName);
}
// 保存类名
genMap.put("className", className);
// 保存小写开头的类名
genMap.put("changeClassName", changeClassName);
// 存在 Timestamp 字段
genMap.put("hasTimestamp", false);
// 查询类中存在 Timestamp 字段
genMap.put("queryHasTimestamp", false);
// 存在 BigDecimal 字段
genMap.put("hasBigDecimal", false);
// 查询类中存在 BigDecimal 字段
genMap.put("queryHasBigDecimal", false);
// 是否需要创建查询
genMap.put("hasQuery", false);
// 自增主键
genMap.put("auto", false);
// 存在字典
genMap.put("hasDict", false);
// 存在日期注解
genMap.put("hasDateAnnotation", false);
// 存储主键字段名
genMap.put("pkIdName", "none");
// 存储符号
genMap.put("symbol", "#");
// 保存字段信息
List<Map<String, Object>> columns = new ArrayList<>();
// 保存查询字段的信息
List<Map<String, Object>> queryColumns = new ArrayList<>();
// 存储字典信息
List<String> dicts = new ArrayList<>();
// 存储 between 信息
List<Map<String, Object>> betweens = new ArrayList<>();
// 存储不为空的字段信息
List<Map<String, Object>> isNotNullColumns = new ArrayList<>();
for (ColumnInfo column : columnInfos) {
Map<String, Object> listMap = new HashMap<>(16);
// 字段描述
listMap.put("remark", column.getRemark());
// 字段类型
listMap.put("columnKey", column.getKeyType());
// 主键类型
String colType = ColUtil.cloToJava(column.getColumnType());
// 小写开头的字段名
String changeColumnName = StringUtils.toCamelCase(column.getColumnName());
// 大写开头的字段名
String capitalColumnName = StringUtils.toCapitalizeCamelCase(column.getColumnName());
if (PK.equals(column.getKeyType())) {
// 存储主键类型
genMap.put("pkColumnType", colType);
// 存储小写开头的字段名
genMap.put("pkChangeColName", changeColumnName);
// 存储大写开头的字段名
genMap.put("pkCapitalColName", capitalColumnName);
// 存储主键字段名
genMap.put("pkIdName", column.getColumnName());
}
// 是否存在 Timestamp 类型的字段
if (TIMESTAMP.equals(colType)) {
genMap.put("hasTimestamp", true);
}
// 是否存在 BigDecimal 类型的字段
if (BIGDECIMAL.equals(colType)) {
genMap.put("hasBigDecimal", true);
}
// 主键是否自增
if (EXTRA.equals(column.getExtra())) {
genMap.put("auto", true);
}
// 主键存在字典
if (StringUtils.isNotBlank(column.getDictName())) {
genMap.put("hasDict", true);
if(!dicts.contains(column.getDictName()))
dicts.add(column.getDictName());
}
// 存储字段类型
listMap.put("columnType", colType);
// 存储字原始段名称
listMap.put("columnName", column.getColumnName());
// 不为空
listMap.put("istNotNull", column.getNotNull());
// 字段列表显示
listMap.put("columnShow", column.getListShow());
// 表单显示
listMap.put("formShow", column.getFormShow());
// 表单组件类型
listMap.put("formType", StringUtils.isNotBlank(column.getFormType()) ? column.getFormType() : "Input");
// 小写开头的字段名称
listMap.put("changeColumnName", changeColumnName);
//大写开头的字段名称
listMap.put("capitalColumnName", capitalColumnName);
// 字典名称
listMap.put("dictName", column.getDictName());
// 添加非空字段信息
if (column.getNotNull()) {
isNotNullColumns.add(listMap);
}
// 判断是否有查询如有则把查询的字段set进columnQuery
if (!StringUtils.isBlank(column.getQueryType())) {
// 查询类型
listMap.put("queryType", column.getQueryType());
// 是否存在查询
genMap.put("hasQuery", true);
if (TIMESTAMP.equals(colType)) {
// 查询中存储 Timestamp 类型
genMap.put("queryHasTimestamp", true);
}
if (BIGDECIMAL.equals(colType)) {
// 查询中存储 BigDecimal 类型
genMap.put("queryHasBigDecimal", true);
}
if ("between".equalsIgnoreCase(column.getQueryType())) {
betweens.add(listMap);
} else {
// 添加到查询列表中
queryColumns.add(listMap);
}
}
// 添加到字段列表中
columns.add(listMap);
}
// 保存字段列表
genMap.put("columns", columns);
// 保存查询列表
genMap.put("queryColumns", queryColumns);
// 保存字段列表
genMap.put("dicts", dicts);
// 保存查询列表
genMap.put("betweens", betweens);
// 保存非空字段信息
genMap.put("isNotNullColumns", isNotNullColumns);
return genMap;
}
/**
* 定义后端文件路径以及名称
*/
private static String getAdminFilePath(String templateName, GenConfig genConfig, String className, String rootPath) {
String projectPath = rootPath + File.separator + genConfig.getModuleName();
String packagePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
String mpXmlPath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;
if (!ObjectUtils.isEmpty(genConfig.getPack())) {
packagePath += genConfig.getPack().replace(".", File.separator) + File.separator;
}
if ("Entity".equals(templateName)) {
return packagePath + "domain" + File.separator + className + ".java";
}
if ("Controller".equals(templateName)) {
return packagePath + "rest" + File.separator + className + "Controller.java";
}
if ("Service".equals(templateName)) {
return packagePath + "service" + File.separator + className + "Service.java";
}
if ("ServiceImpl".equals(templateName)) {
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if ("QueryCriteria".equals(templateName)) {
return packagePath + "domain" + File.separator + "dto" + File.separator + className + "QueryCriteria.java";
}
if ("Mapper".equals(templateName)) {
return packagePath + "mapper" + File.separator + className + "Mapper.java";
}
if ("Mapper-xml".equals(templateName)) {
return mpXmlPath + "mapper" + File.separator + className + "Mapper.xml";
}
return null;
}
/**
* 定义前端文件路径以及名称
*/
private static String getFrontFilePath(String templateName, String apiPath, String path, String apiName) {
if ("api".equals(templateName)) {
return apiPath + File.separator + apiName + ".js";
}
if ("index".equals(templateName)) {
return path + File.separator + "index.vue";
}
return null;
}
private static void genFile(File file, Template template, Map<String, Object> map) throws IOException {
// 生成目标文件
Writer writer = null;
try {
FileUtil.touch(file);
writer = new FileWriter(file);
template.render(map, writer);
} catch (TemplateException | IOException e) {
throw new RuntimeException(e);
} finally {
assert writer != null;
writer.close();
}
}
}