33 changed files with 3016 additions and 0 deletions
@ -0,0 +1,62 @@ |
|||
# 作者 |
|||
AUTHOR = "snail" |
|||
# 微信公众号 |
|||
WECHAT = "ot_bus" |
|||
# 子项目默认项目包名 |
|||
BASE_PACKAGE = "com.xr.api" |
|||
# 默认模块名称,控制controller的URL的前缀 |
|||
DEFAULT_PREFIX_URL = "models" |
|||
# 项目主目录 |
|||
# health-ai 主项目; |
|||
MAIN_MODULE = "health-ai" |
|||
#health-user-api 模块(子项目) |
|||
MODULE_NAME = "health-user-api" |
|||
# 项目根目录 |
|||
BASE_DIR = "./" |
|||
# 输出目录 |
|||
# 是否生成REST风格 |
|||
REST_CONTROLLER_STYLE = True |
|||
# 默认的GROUP_ID |
|||
GROUP_ID = "com.xr.health" |
|||
OUTPUT_DIR = f"./{MAIN_MODULE}/{MODULE_NAME}/src/main" |
|||
|
|||
DB = { |
|||
"host": "192.168.1.80", |
|||
"user": "root", |
|||
"password": "Khq#P9hZ4L@EwCZw", |
|||
"database": "health_ai_b", |
|||
"port": 3728 |
|||
} |
|||
|
|||
APPLICATION = { |
|||
"name": MODULE_NAME, |
|||
"version": "1.0.0", |
|||
"author": AUTHOR, |
|||
"package": {"base": BASE_PACKAGE}, |
|||
"redis": { |
|||
"host": "192.168.1.87", |
|||
"port": 6379, |
|||
"password": "redis_Hkhtz7", |
|||
"database": 4 |
|||
}, |
|||
"minio": { |
|||
"host": "192.168.1.88", |
|||
"port": "9001", |
|||
"accessKey": "BHB4X5zgZXuzQE6ku31e", |
|||
"secretKey": "NZgHX5LhtAVD1KdaucL0EVWy6IQk4owdZLA2A7wi", |
|||
"bucketName": "health-bucket", |
|||
"downloadDir": "/data/excel" |
|||
}, |
|||
"xxlJob":{ |
|||
"addresses": "http://192.168.1.88:8800/xxl-job-admin", |
|||
"accessToken": "xxljobTokenQ", |
|||
"address": "192.168.1.88:9999", |
|||
"ip": "192.168.1.88", |
|||
"port": "9998", |
|||
}, |
|||
"eureka":{ |
|||
"host": "92.168.1.87", |
|||
"port": "8761" |
|||
}, |
|||
"db": DB |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
# =============================== |
|||
# 基础项目信息 |
|||
# =============================== |
|||
mainModule: test-ai |
|||
moduleName: test-user-api |
|||
groupId: com.test.ai |
|||
author: snail |
|||
wechat: ot_bus |
|||
baseDir: "./" |
|||
outputDir: /${mainModule}/${moduleName}/src/main |
|||
# 是否启用 Lombok |
|||
entityLombokModel: true |
|||
|
|||
# 是否生成 REST 风格 Controller |
|||
restControllerStyle: true |
|||
|
|||
# =============================== |
|||
# 包路径配置 |
|||
# =============================== |
|||
package: |
|||
Models: models |
|||
Base: com.test.api |
|||
Common: ${package.Base}.${package.Models}.common |
|||
Entity: ${package.Base}.${package.Models}.entity |
|||
Service: ${package.Base}.${package.Models}.service |
|||
ServiceImpl: ${package.Base}.${package.Models}.service.impl |
|||
Controller: ${package.Base}.${package.Models}.controller |
|||
Mapper: ${package.Base}.${package.Models}.mapper |
|||
|
|||
# =============================== |
|||
# 数据库配置 |
|||
# =============================== |
|||
db: |
|||
host: 192.168.1.80 |
|||
port: 3728 |
|||
user: root |
|||
password: Khq#P9hZ4L@EwCZw |
|||
database: health_ai_b |
|||
|
|||
# =============================== |
|||
# 应用级配置 |
|||
# =============================== |
|||
application: |
|||
name: ${moduleName} |
|||
version: 1.0.0 |
|||
author: snail |
|||
|
|||
package: |
|||
base: ${package.Base} |
|||
|
|||
# ---------- Redis ---------- |
|||
redis: |
|||
host: 192.168.1.1 |
|||
port: 6379 |
|||
password: redis_Hkhtz7 |
|||
database: 4 |
|||
|
|||
# ---------- MinIO ---------- |
|||
minio: |
|||
host: 192.168.1.1 |
|||
port: 9001 |
|||
accessKey: BHB4X5zgZXuzQE6ku31e |
|||
secretKey: NZgHX5LhtAVD1KdaucL0EVWy6IQk4owdZLA2A7wi |
|||
bucketName: health-bucket |
|||
downloadDir: /data/excel |
|||
|
|||
# ---------- XXL-JOB ---------- |
|||
xxlJob: |
|||
addresses: http://192.168.1.88:8800/xxl-job-admin |
|||
accessToken: xxljobTokenQ |
|||
address: 192.168.1.1:9999 |
|||
ip: 192.168.1.1 |
|||
port: 9998 |
|||
|
|||
# ---------- Eureka ---------- |
|||
eureka: |
|||
host: 192.168.1.1 |
|||
port: 8761 |
|||
|
|||
# ---------- DB(应用内复用) ---------- |
|||
db: |
|||
host: 192.168.1.80 |
|||
port: 3728 |
|||
user: root |
|||
password: Khq#P9hZ4L@EwCZw |
|||
database: health_ai_b |
|||
@ -0,0 +1,41 @@ |
|||
import pymysql |
|||
from config import DB |
|||
|
|||
def get_conn(): |
|||
return pymysql.connect( |
|||
**DB, |
|||
cursorclass=pymysql.cursors.DictCursor |
|||
) |
|||
|
|||
def get_table(table_name): |
|||
sql = """ |
|||
SELECT table_name, table_comment |
|||
FROM information_schema.tables |
|||
WHERE table_schema=%s AND table_name=%s |
|||
""" |
|||
with get_conn() as conn: |
|||
with conn.cursor() as cur: |
|||
cur.execute(sql, (DB["database"], table_name)) |
|||
return cur.fetchone() |
|||
|
|||
def get_columns(table_name): |
|||
sql = """ |
|||
SELECT column_name, data_type, column_comment |
|||
FROM information_schema.columns |
|||
WHERE table_schema=%s AND table_name=%s |
|||
ORDER BY ordinal_position |
|||
""" |
|||
with get_conn() as conn: |
|||
with conn.cursor() as cur: |
|||
cur.execute(sql, (DB["database"], table_name)) |
|||
return cur.fetchall() |
|||
|
|||
def mysql_to_java(mysql_type): |
|||
mapping = { |
|||
"bigint": "Long", |
|||
"int": "Integer", |
|||
"varchar": "String", |
|||
"datetime": "LocalDateTime", |
|||
"decimal": "BigDecimal" |
|||
} |
|||
return mapping.get(mysql_type, "String") |
|||
@ -0,0 +1,312 @@ |
|||
import logging |
|||
import os |
|||
from datetime import datetime |
|||
from jinja2 import Environment, FileSystemLoader |
|||
# from config import * |
|||
from db import get_table, get_columns |
|||
from utils import * |
|||
import argparse |
|||
import yaml |
|||
|
|||
env = Environment(loader=FileSystemLoader("templates")) |
|||
|
|||
def build_fields(table_name): |
|||
columns = get_columns(table_name) |
|||
fields = [] |
|||
for c in columns: |
|||
fields.append({ |
|||
"java_name": to_camel(c["column_name"]), |
|||
"tab_name": c["column_name"], |
|||
"tab_type": c["data_type"], |
|||
"java_get_name": to_m_camel(c["column_name"]), |
|||
"java_type": mysql_to_java(c["data_type"]), |
|||
"comment": c["column_comment"] |
|||
}) |
|||
return fields |
|||
|
|||
def render(template_name, out_path, context, overwrite=False): |
|||
""" |
|||
:param template_name: 模板文件名 |
|||
:param out_path: 输出文件路径 |
|||
:param context: 渲染上下文 |
|||
:param overwrite: 是否覆盖已存在文件,默认 False |
|||
""" |
|||
# 文件存在且不允许覆盖 → 直接跳过 |
|||
if os.path.exists(out_path) and not overwrite: |
|||
logging.info("Skip exists file: %s", out_path) |
|||
return |
|||
|
|||
tpl = env.get_template(template_name) |
|||
content = tpl.render(**context) |
|||
|
|||
os.makedirs(os.path.dirname(out_path), exist_ok=True) |
|||
with open(out_path, "w", encoding="utf-8") as f: |
|||
f.write(content) |
|||
|
|||
logging.info("Generated file: %s", out_path) |
|||
|
|||
def generate(table_names: list[str], model_names: list[str], conf_name: str, over_write: bool): |
|||
|
|||
# context = { |
|||
# "mainModule": MAIN_MODULE, |
|||
# "moduleName": MODULE_NAME, |
|||
# "groupId": GROUP_ID, |
|||
# "author": AUTHOR, |
|||
# "wechat": WECHAT, |
|||
# "date": datetime.now().strftime("%Y-%m-%d"), |
|||
# "entityLombokModel": True, |
|||
# "package": { |
|||
# "Base": BASE_PACKAGE, |
|||
# "Common": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.common", |
|||
# "Entity": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.entity", |
|||
# "Service": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.service", |
|||
# "Controller": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.controller", |
|||
# "ServiceImpl": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.service.impl", |
|||
# "Mapper": f"{BASE_PACKAGE}.{DEFAULT_PREFIX_URL}.mapper" |
|||
# }, |
|||
# "db": DB, |
|||
# "application": APPLICATION, |
|||
# "restControllerStyle": REST_CONTROLLER_STYLE |
|||
# } |
|||
|
|||
with open(conf_name, "r", encoding="utf-8") as f: |
|||
cfg = yaml.safe_load(f) |
|||
cfg = resolve_config(cfg) |
|||
|
|||
context = { |
|||
"mainModule": cfg["mainModule"], |
|||
"moduleName": cfg["moduleName"], |
|||
"groupId": cfg["groupId"], |
|||
"author": cfg["author"], |
|||
"wechat": cfg["wechat"], |
|||
"date": datetime.now().strftime("%Y-%m-%d"), |
|||
"entityLombokModel": cfg["entityLombokModel"], |
|||
"package": cfg["package"], |
|||
"db": cfg["db"], |
|||
"application": cfg["application"], |
|||
"restControllerStyle": cfg["restControllerStyle"] |
|||
} |
|||
# MAIN_BASE_PACKAGE_DIR = f"{OUTPUT_DIR}/java/{to_path(BASE_PACKAGE)}" |
|||
# MAIN_OUTPUT_DIR = f"{MAIN_BASE_PACKAGE_DIR}/{DEFAULT_PREFIX_URL}" |
|||
|
|||
BASE_DIR = cfg["baseDir"] |
|||
BASE_PACKAGE = cfg["package"]["Base"] |
|||
OUTPUT_DIR = cfg["outputDir"] |
|||
MAIN_MODULE = cfg["mainModule"] |
|||
MODULE_NAME = cfg["moduleName"] |
|||
MAIN_BASE_PACKAGE_DIR = f"{cfg['outputDir']}/java/{to_path(BASE_PACKAGE)}" |
|||
MAIN_OUTPUT_DIR = f"{MAIN_BASE_PACKAGE_DIR}/{cfg['package']['Models']}" |
|||
|
|||
|
|||
# ========= 按表循环 ========= |
|||
for table_name in table_names: |
|||
table = get_table(table_name) |
|||
entity = to_class(table_name) |
|||
|
|||
context = dict(context) |
|||
context.update({ |
|||
"fields": build_fields(table_name), |
|||
"table": { |
|||
"entity": entity, |
|||
"lowerEntity": lower_first(entity), |
|||
"name": table_name, |
|||
"comment": table["table_comment"] |
|||
} |
|||
}) |
|||
|
|||
# ========= 需要循环生成的模板 ========= |
|||
render( |
|||
"entity.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/entity/{entity}.java", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
render( |
|||
"controller.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/controller/{entity}Controller.java", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
render( |
|||
"service.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/service/{entity}Service.java", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
render( |
|||
"serviceImpl.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/service/impl/{entity}MPJBaseServiceImpl.java", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
render( |
|||
"mapper.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/mapper/{entity}Mapper.java", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
render( |
|||
"mapper.xml.j2", |
|||
f"{MAIN_MODULE}/{MODULE_NAME}/src/main/resources/mappers/{entity}Mapper.xml", |
|||
context, |
|||
over_write |
|||
) |
|||
|
|||
# ========= 生成固定模板 ========= |
|||
# BaseEntity |
|||
render( |
|||
"baseEntity.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/entity/BaseEntity.java", |
|||
context |
|||
) |
|||
|
|||
# common MybatisPlusConfig |
|||
render( |
|||
"mybatisPlusConfig.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/MybatisPlusConfig.java", |
|||
context |
|||
) |
|||
|
|||
# common MybatisPlusConfig |
|||
render( |
|||
"webLogAspect.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/WebLogAspect.java", |
|||
context |
|||
) |
|||
|
|||
# common 基础输出result |
|||
render( |
|||
"result.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/vo/Result.java", |
|||
context |
|||
) |
|||
|
|||
#Util 公共功能 |
|||
for file in ["Md5HashUtil.java.j2","FilesUtil.java.j2"]: |
|||
render( |
|||
file, |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/unit/{file.replace('.j2', '')}", |
|||
context |
|||
) |
|||
|
|||
# application 启动的方法 |
|||
render( |
|||
"application.java.j2", |
|||
f"{BASE_DIR}{MAIN_BASE_PACKAGE_DIR}/Application.java", |
|||
context |
|||
) |
|||
|
|||
# test 测试类 |
|||
render( |
|||
"applicationTests.java.j2", |
|||
f"{BASE_DIR}{OUTPUT_DIR}/test/{to_path(BASE_PACKAGE)}/ApplicationTests.java", |
|||
context |
|||
) |
|||
|
|||
# 主pom文件 |
|||
render( |
|||
"main.pom.xml.j2", |
|||
f"{BASE_DIR}{MAIN_MODULE}/pom.xml", |
|||
context |
|||
) |
|||
|
|||
# 子项目pom文件 |
|||
render( |
|||
"project.pom.xml.j2", |
|||
f"{BASE_DIR}{MAIN_MODULE}/{MODULE_NAME}/pom.xml", |
|||
context |
|||
) |
|||
|
|||
#项目的yml配置文件 resources 生成环境配置为了最低限度能将项目跑起来 |
|||
render( |
|||
"application.yml.j2", |
|||
f"{MAIN_MODULE}/{MODULE_NAME}/src/main/resources/application.yml", |
|||
context |
|||
) |
|||
|
|||
#项目开发环境的yml配置文件 resources yml 只生成dev环境配置为了最低限度能将项目跑起来 |
|||
render( |
|||
"application-dev.yml.j2", |
|||
f"{MAIN_MODULE}/{MODULE_NAME}/src/main/resources/application-dev.yml", |
|||
context |
|||
) |
|||
|
|||
#项目开发环境的yml配置文件 resources yml 只生成dev环境配置为了最低限度能将项目跑起来 |
|||
render( |
|||
"logback.xml.j2", |
|||
f"{MAIN_MODULE}/{MODULE_NAME}/src/main/resources/logback.xml", |
|||
context |
|||
) |
|||
|
|||
# ========= 功能模块 ========= |
|||
for model_name in model_names: |
|||
match model_name: |
|||
case "swagger": |
|||
# common Swagger2 |
|||
render( |
|||
"swagger2.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/Swagger2.java", |
|||
context |
|||
) |
|||
case "saToken": |
|||
# common GlobalException soToken 报错自定义 |
|||
render( |
|||
"globalException.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/GlobalException.java", |
|||
context |
|||
) |
|||
render( |
|||
"saTokenConfigure.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/SaTokenConfig.java", |
|||
context |
|||
) |
|||
case "minio": |
|||
#MinioConfig |
|||
render( |
|||
"MinioConfig.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/MinioConfig.java", |
|||
context |
|||
) |
|||
render( |
|||
"MinioUpController.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/controller/MinioUpController.java", |
|||
context |
|||
) |
|||
render( |
|||
"MinioUpComponent.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/unit/MinioUpComponent.java", |
|||
context |
|||
) |
|||
case "xxlJob": |
|||
# common XxlJobConfig |
|||
render( |
|||
"xxlJobConfig.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/config/XxlJobConfig.java", |
|||
context |
|||
) |
|||
# common xxjob的测试类 |
|||
render( |
|||
"testJob.java.j2", |
|||
f"{BASE_DIR}{MAIN_OUTPUT_DIR}/common/job/TestJob.java", |
|||
context |
|||
) |
|||
|
|||
if __name__ == "__main__": |
|||
args = parse_args() |
|||
|
|||
tables = [t.strip() for t in args.tab.split(",") if t.strip()] |
|||
models = [m.strip() for m in args.model.split(",") if m.strip()] |
|||
conf = args.conf |
|||
re = args.re |
|||
|
|||
generate( |
|||
table_names=tables, |
|||
model_names=models, |
|||
conf_name=conf, |
|||
over_write=re |
|||
) |
|||
@ -0,0 +1,142 @@ |
|||
package {{ package.Common }}.unit; |
|||
|
|||
import org.apache.commons.io.FileUtils; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
import sun.misc.BASE64Encoder; |
|||
|
|||
import java.io.*; |
|||
import java.util.Base64; |
|||
|
|||
public class FilesUtil { |
|||
|
|||
/** |
|||
* 根据文件路径获取文件字节流 |
|||
* @return |
|||
* filePath 文件路径 |
|||
* @throws IOException |
|||
*/ |
|||
public static byte[] toByteArray(String filePath) throws IOException { |
|||
File f = new File(filePath); |
|||
if (!f.exists()) { |
|||
throw new FileNotFoundException("文件不存在"); |
|||
} |
|||
|
|||
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length()); |
|||
BufferedInputStream in = null; |
|||
try { |
|||
in = new BufferedInputStream(new FileInputStream(f)); |
|||
int buf_size = 1024; |
|||
byte[] buffer = new byte[buf_size]; |
|||
int len = 0; |
|||
while (-1 != (len = in.read(buffer, 0, buf_size))) { |
|||
bos.write(buffer, 0, len); |
|||
} |
|||
return bos.toByteArray(); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
throw e; |
|||
} finally { |
|||
try { |
|||
in.close(); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
bos.close(); |
|||
} |
|||
} |
|||
public static File multipartFileToFile(MultipartFile file) throws Exception { |
|||
File toFile = null; |
|||
if (file.equals("") || file.getSize() <= 0) { |
|||
file = null; |
|||
} else { |
|||
InputStream ins = null; |
|||
ins = file.getInputStream(); |
|||
toFile = new File(file.getOriginalFilename()); |
|||
inputStreamToFile(ins, toFile); |
|||
ins.close(); |
|||
} |
|||
return toFile; |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
private static void inputStreamToFile(InputStream ins, File file) { |
|||
try { |
|||
OutputStream os = new FileOutputStream(file); |
|||
int bytesRead = 0; |
|||
byte[] buffer = new byte[8192]; |
|||
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { |
|||
os.write(buffer, 0, bytesRead); |
|||
} |
|||
os.close(); |
|||
ins.close(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
public static String TransformPhotoToBase64Data(String path){ |
|||
Base64.Encoder encoder= Base64.getEncoder(); //获取Base64编码器 |
|||
byte [] ImgContainer = null ; //数据集缓存器 |
|||
FileInputStream fileInputStream = null; //文件输入流 |
|||
try { |
|||
System.out.println(path); |
|||
File file=new File(path); |
|||
fileInputStream = new FileInputStream(file); //到指定路径寻找文件 |
|||
ImgContainer = new byte[fileInputStream.available()]; //设置图片字节数据缓冲区大小 |
|||
fileInputStream.read(ImgContainer); //将数据流中的图片数据读进缓冲区 |
|||
String Base64ImgData =encoder.encodeToString(ImgContainer); //将图片编码转换成Base64格式的数据集 |
|||
fileInputStream.close(); //关闭数据流 |
|||
return Base64ImgData; //将缓冲区数据转换成字符数据返回 |
|||
} catch (FileNotFoundException e) { |
|||
return "找不到指定文件!"; |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return "null"; |
|||
} |
|||
|
|||
public static String getBase64String(MultipartFile multiPartFile) throws IOException { |
|||
String baseStr = null; |
|||
|
|||
//把MultipartFile转化为File |
|||
File file = new File(multiPartFile.getOriginalFilename()); |
|||
FileUtils.copyInputStreamToFile(multiPartFile.getInputStream(), file); |
|||
|
|||
try {//file转base64 |
|||
FileInputStream inputStream = new FileInputStream(file); |
|||
byte[] buffer = new byte[(int) file.length()]; |
|||
inputStream.read(buffer); |
|||
inputStream.close(); |
|||
baseStr = new BASE64Encoder().encode(buffer); |
|||
|
|||
} catch (FileNotFoundException e) { |
|||
e.printStackTrace(); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
//删除临时文件 |
|||
if (file.exists()) { |
|||
file.delete(); |
|||
} |
|||
baseStr = baseStr.replaceAll("\r\n", ""); |
|||
return baseStr; |
|||
} |
|||
|
|||
/** |
|||
* 返回文件扩展名,带。 |
|||
* @param file |
|||
* @return |
|||
*/ |
|||
public static String getFileExtension(MultipartFile file) { |
|||
String fileName = file.getOriginalFilename(); |
|||
int dotIndex = fileName.lastIndexOf("."); |
|||
if (dotIndex == -1) { |
|||
return ""; |
|||
} else { |
|||
return "."+fileName.substring(dotIndex + 1); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package {{ package.Common }}.unit; |
|||
|
|||
import java.security.MessageDigest; |
|||
import java.security.NoSuchAlgorithmException; |
|||
|
|||
public class Md5HashUtil { |
|||
|
|||
public static String getMD5Hash(byte[] input) { |
|||
try { |
|||
MessageDigest md = MessageDigest.getInstance("MD5"); |
|||
byte[] digest = md.digest(input); |
|||
StringBuilder sb = new StringBuilder(); |
|||
for (byte b : digest) { |
|||
sb.append(String.format("%02x", b)); |
|||
} |
|||
return sb.toString(); |
|||
} catch (NoSuchAlgorithmException e) { |
|||
throw new RuntimeException("Could not find MD5 algorithm", e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
package {{ package.Common }}.config; |
|||
import {{ package.Common }}.unit.MinioUpComponent; |
|||
|
|||
|
|||
import io.minio.MinioClient; |
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @Description: minio配置类 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
@Component |
|||
@Data |
|||
@ConditionalOnClass(MinioUpComponent.class) |
|||
public class MinioConfig implements Serializable { |
|||
|
|||
|
|||
/** |
|||
* API调用地址ip |
|||
*/ |
|||
@Value("${minio.config.ip}") |
|||
private String ip; |
|||
|
|||
/** |
|||
* API调用地址端口 |
|||
*/ |
|||
@Value("${minio.config.port}") |
|||
private String port; |
|||
|
|||
/** |
|||
* 连接账号 |
|||
*/ |
|||
@Value("${minio.config.accessKey}") |
|||
private String accessKey; |
|||
|
|||
/** |
|||
* 连接秘钥 |
|||
*/ |
|||
@Value("${minio.config.secretKey}") |
|||
private String secretKey; |
|||
|
|||
/** |
|||
* minio存储桶的名称 |
|||
*/ |
|||
@Value("${minio.config.bucketName}") |
|||
private String bucketName; |
|||
|
|||
/** |
|||
* 文件下载到本地的路径 |
|||
*/ |
|||
@Value("${minio.config.downloadDir}") |
|||
private String downloadDir; |
|||
|
|||
/** |
|||
* #如果是true,则用的是https而不是http,默认值是true |
|||
*/ |
|||
@Value("${minio.config.secure}") |
|||
private Boolean secure; |
|||
|
|||
@Value("${minio.config.readPath}") |
|||
private String readPath; |
|||
|
|||
@Value("${minio.config.endpoint}") |
|||
private String endpoint; |
|||
|
|||
@Bean |
|||
public MinioClient buildClient() { |
|||
//1.创建minio链接客户端 |
|||
return MinioClient |
|||
.builder() |
|||
.credentials(accessKey, secretKey) |
|||
.endpoint(endpoint) |
|||
.build(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,191 @@ |
|||
package {{ package.Common }}.unit; |
|||
import {{ package.Common }}.config.MinioConfig; |
|||
|
|||
import io.minio.*; |
|||
import io.minio.http.Method; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.io.ByteArrayOutputStream; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.text.SimpleDateFormat; |
|||
import java.util.Date; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
|
|||
/**** |
|||
* @Description: 上传 文件组件 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class MinioUpComponent { |
|||
|
|||
private final static String separator = "/"; |
|||
@Autowired |
|||
private MinioConfig minioConfig; |
|||
@Autowired |
|||
private MinioClient minioClient; |
|||
|
|||
/** |
|||
* @param dirPath |
|||
* @param filename yyyy/mm/dd/file.jpg |
|||
* @return |
|||
*/ |
|||
public static String builderFilePath(String dirPath, String filename) { |
|||
StringBuilder stringBuilder = new StringBuilder(50); |
|||
if (!StringUtils.isEmpty(dirPath)) { |
|||
stringBuilder.append(dirPath).append(separator); |
|||
} |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); |
|||
String todayStr = sdf.format(new Date()); |
|||
stringBuilder.append(todayStr).append(separator); |
|||
stringBuilder.append(filename); |
|||
return stringBuilder.toString(); |
|||
} |
|||
|
|||
/** |
|||
* 上传图片文件 |
|||
* |
|||
* @param prefix 文件前缀 |
|||
* @param filename 文件名 |
|||
* @param inputStream 文件流 |
|||
* @return 文件全路径 |
|||
*/ |
|||
public String uploadImg(String prefix, String filename, InputStream inputStream) { |
|||
String filePath = builderFilePath(prefix, filename); |
|||
try { |
|||
PutObjectArgs putObjectArgs = PutObjectArgs.builder() |
|||
.object(filePath) |
|||
.contentType("image/jpg") |
|||
.bucket(minioConfig.getBucketName()).stream(inputStream, inputStream.available(), -1) |
|||
.build(); |
|||
minioClient.putObject(putObjectArgs); |
|||
StringBuilder urlPath = new StringBuilder(minioConfig.getReadPath()); |
|||
urlPath.append(separator + minioConfig.getBucketName()); |
|||
urlPath.append(separator); |
|||
urlPath.append(filePath); |
|||
return urlPath.toString(); |
|||
} catch (Exception ex) { |
|||
log.error("minio put file error.", ex); |
|||
throw new RuntimeException("上传文件失败"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 上传html文件 |
|||
* |
|||
* @param prefix 文件前缀 |
|||
* @param filename 文件名 |
|||
* @param inputStream 文件流 |
|||
* @return 文件全路径 |
|||
*/ |
|||
public String uploadHtml(String prefix, String filename, InputStream inputStream) { |
|||
String filePath = builderFilePath(prefix, filename); |
|||
try { |
|||
PutObjectArgs putObjectArgs = PutObjectArgs.builder() |
|||
.object(filePath) |
|||
.contentType("text/html") |
|||
.bucket(minioConfig.getBucketName()) |
|||
.stream(inputStream, inputStream.available(), -1) |
|||
.build(); |
|||
minioClient.putObject(putObjectArgs); |
|||
StringBuilder urlPath = new StringBuilder(minioConfig.getReadPath()); |
|||
urlPath.append(separator + minioConfig.getBucketName()); |
|||
urlPath.append(separator); |
|||
urlPath.append(filePath); |
|||
return urlPath.toString(); |
|||
} catch (Exception ex) { |
|||
log.error("minio put file error.", ex); |
|||
ex.printStackTrace(); |
|||
throw new RuntimeException("上传文件失败"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 防盗链接有效期按分钟 |
|||
* |
|||
* @param filePath 文件前缀 |
|||
* @param expiry 超时分钟 |
|||
* @return 文件全路径 |
|||
*/ |
|||
public String getPresignObjectUrl(String filePath, Integer expiry) { |
|||
try { |
|||
filePath = filePath.replace("http://health.reglory.com.cn:9001/health-bucket/", ""); |
|||
GetPresignedObjectUrlArgs putObjectArgs = GetPresignedObjectUrlArgs.builder() |
|||
.object(filePath) |
|||
.bucket(minioConfig.getBucketName()) |
|||
.method(Method.GET) |
|||
// .region("health.reglory.com.cn:9001") |
|||
.expiry(expiry, TimeUnit.MINUTES) |
|||
.build(); |
|||
return minioClient.getPresignedObjectUrl(putObjectArgs); |
|||
} catch (Exception ex) { |
|||
log.error("minio put file error.", ex); |
|||
ex.printStackTrace(); |
|||
throw new RuntimeException("上传文件失败"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 删除文件 |
|||
* |
|||
* @param pathUrl 文件全路径 |
|||
*/ |
|||
public void delete(String pathUrl) { |
|||
String key = pathUrl.replace(minioConfig.getEndpoint() + "/", ""); |
|||
int index = key.indexOf(separator); |
|||
String bucket = key.substring(0, index); |
|||
String filePath = key.substring(index + 1); |
|||
// 删除Objects |
|||
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build(); |
|||
try { |
|||
minioClient.removeObject(removeObjectArgs); |
|||
} catch (Exception e) { |
|||
log.error("minio remove file error. pathUrl:{}", pathUrl); |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 下载文件 |
|||
* |
|||
* @param pathUrl 文件全路径 |
|||
* @return 文件流 |
|||
*/ |
|||
public byte[] downLoadFile(String pathUrl) { |
|||
String key = pathUrl.replace(minioConfig.getEndpoint() + "/", ""); |
|||
int index = key.indexOf(separator); |
|||
//String bucket = key.substring(0, index); |
|||
String filePath = key.substring(index + 1); |
|||
InputStream inputStream = null; |
|||
try { |
|||
inputStream = minioClient.getObject( |
|||
GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build() |
|||
); |
|||
} catch (Exception e) { |
|||
log.error("minio down file error. pathUrl:{}", pathUrl); |
|||
e.printStackTrace(); |
|||
} |
|||
|
|||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
|||
byte[] buff = new byte[100]; |
|||
int rc = 0; |
|||
while (true) { |
|||
try { |
|||
if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break; |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
byteArrayOutputStream.write(buff, 0, rc); |
|||
} |
|||
return byteArrayOutputStream.toByteArray(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,53 @@ |
|||
package {{ package.Controller }}; |
|||
import {{ package.Common }}.unit.FilesUtil; |
|||
import {{ package.Common }}.unit.Md5HashUtil; |
|||
import {{ package.Common }}.unit.MinioUpComponent; |
|||
import {{ package.Common }}.vo.Result; |
|||
|
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* <p> |
|||
* 上传控制器 |
|||
* </p> |
|||
* |
|||
* @author tiger |
|||
* @since 2024-06-04 |
|||
*/ |
|||
@Api(tags = "文件上传") |
|||
@RestController |
|||
@CrossOrigin(origins = "*") |
|||
@RequestMapping("/models/file") |
|||
public class MinioUpController { |
|||
|
|||
@Autowired |
|||
private MinioUpComponent minioUpComponent; |
|||
|
|||
@ApiOperation(value = "图片上传") |
|||
@CrossOrigin(origins = "*") |
|||
@PostMapping(value = "/upImg") |
|||
public Result<?> up(@RequestParam("file") MultipartFile file) { |
|||
if (file.isEmpty()) { |
|||
return Result.error("请选择一个文件上传"); |
|||
} |
|||
// 文件上传路径 可以为空 默认 bucketName: "health-bucket" 桶的名字为根目录 |
|||
// String path = "/tmp/user"; |
|||
String path = ""; |
|||
String url = ""; |
|||
try { |
|||
url = minioUpComponent.uploadImg(path,Md5HashUtil.getMD5Hash(file.getBytes()) + |
|||
FilesUtil.getFileExtension(file), file.getInputStream()); |
|||
} catch (IOException e) { |
|||
return Result.error("上传失败"); |
|||
} |
|||
return Result.OK(url); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,137 @@ |
|||
server: |
|||
port: 8060 |
|||
servlet: |
|||
context-path: /api |
|||
|
|||
spring: |
|||
############## datasource 相关 |
|||
datasource: |
|||
type: com.zaxxer.hikari.HikariDataSource |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
url: jdbc:mysql://{{ application.db.host }}:{{ application.db.port }}/{{ application.db.database }}?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false |
|||
username: {{ application.db.user }} |
|||
password: {{ application.db.password }} |
|||
#Hikari连接池配置 |
|||
hikari: |
|||
#池中维护的最小空闲连接数 |
|||
minimum-idle: 5 |
|||
#池中最大连接数,包括闲置和使用中的连接 |
|||
maximum-pool-size: 15 |
|||
#自动提交从池中返回的连接 |
|||
auto-commit: true |
|||
#连接允许在池中闲置的最长时间 |
|||
idle-timeout: 30000 |
|||
#连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置 |
|||
pool-name: DatebookHikariCP |
|||
#池中连接最长生命周期 |
|||
max-lifetime: 18000000 |
|||
#等待来自池的连接的最大毫秒数 |
|||
connection-timeout: 30000 |
|||
#验证该连接是否是有效的查询语句 |
|||
connection-test-query: select 1 from dual |
|||
cloud: |
|||
inetutils: |
|||
timeout-seconds: 10 |
|||
config: |
|||
enabled: false |
|||
############## redis 相关 |
|||
redis: |
|||
host: {{ application.redis.host }} |
|||
port: {{ application.redis.port }} |
|||
password: {{ application.redis.password }} |
|||
timeout: 10000 |
|||
jedis: |
|||
pool: |
|||
max-active: 1000 |
|||
max-wait: -1ms |
|||
max-idle: 10 |
|||
min-idle: 5 |
|||
database: {{application.redis.database}} |
|||
############## eureka 相关 |
|||
eureka: |
|||
instance: |
|||
instance-id: ${spring.cloud.client.ip-address}:${server.port} |
|||
prefer-ip-address: true |
|||
client: |
|||
healthcheck: |
|||
enabled: true |
|||
service-url: |
|||
defaultZone: http://{{ application.eureka.host }}:{{ application.eureka.port }}/eureka |
|||
|
|||
############## mybatis-plus配置 |
|||
mybatis-plus: |
|||
# 启动检查MyBatis配置文件 |
|||
check-config-location: false |
|||
# MyBatis配置文件位置 |
|||
config-location: |
|||
# MyBaits别名包扫描路径 |
|||
type-aliases-package: com.qiangesoft.mybatisplusjoin.entity |
|||
# Mapper所对应的XML文件位置 默认【classpath*:/mapper/**/*.xml】 |
|||
mapper-locations: classpath*:/mapper/*Mapper.xml |
|||
# TypeHandler扫描路径 |
|||
type-handlers-package: |
|||
configuration: |
|||
# 日志打印 |
|||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
|||
# 是否开启自动驼峰命名规则 |
|||
map-underscore-to-camel-case: true |
|||
# 开启Mybatis二级缓存,默认为true |
|||
cache-enabled: true |
|||
global-config: |
|||
# 控制台mybatis-plus的logo |
|||
banner: true |
|||
db-config: |
|||
# 全局默认主键类型 |
|||
id-type: auto |
|||
# 逻辑删除配置 |
|||
logic-delete-field: deleted |
|||
logic-delete-value: 1 |
|||
logic-not-delete-value: 0 |
|||
|
|||
############## Sa-Token 配置 (文档: https://sa-token.cc) ############## |
|||
sa-token: |
|||
# token 名称(同时也是 cookie 名称) |
|||
token-name: Token |
|||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效 |
|||
timeout: 2592000 |
|||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 |
|||
active-timeout: -1 |
|||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) |
|||
is-concurrent: true |
|||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) |
|||
is-share: true |
|||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) |
|||
token-style: uuid |
|||
# 是否输出操作日志 |
|||
is-log: true |
|||
|
|||
############## swagger |
|||
swagger: |
|||
show: true |
|||
|
|||
############## minio |
|||
minio: |
|||
config: |
|||
ip: {{ application.minio.host }} #ip地址 |
|||
port: {{ application.minio.port }} # 端口号 |
|||
accessKey: {{ application.minio.accessKey }} # 账号 |
|||
secretKey: {{ application.minio.secretKey }} # 密码 |
|||
secure: false #如果是true,则用的是https而不是http,默认值是true |
|||
bucketName: "{{ application.minio.bucketName }}" # 桶的名字 |
|||
downloadDir: "{{ application.minio.downloadDir }}" #保存到本地的路径 |
|||
readPath: "http://{{ application.minio.host }}:{{ application.minio.port }}" #保存到本地的路径 |
|||
endpoint: "http://{{ application.minio.host }}:{{ application.minio.port }}" #保存到本地的路径 |
|||
|
|||
############## xxl-job |
|||
xxl: |
|||
job: |
|||
admin: |
|||
addresses: {{ application.xxlJob.addresses }} # 调度中心部署根地址 |
|||
accessToken: "{{ application.xxlJob.accessToken }}" # 执行器通讯TOKEN,非空时启用 |
|||
executor: |
|||
appname: xxl-{{ application.name }} # 执行器AppName |
|||
address: {{ application.xxlJob.address }} # 执行器注册地址,为空时使用内嵌服务IP:PORT |
|||
ip: {{ application.xxlJob.ip }} # 执行器IP,默认为空自动获取 |
|||
port: {{ application.xxlJob.port }} # 执行器端口号 |
|||
logpath: /data/applogs/xxl-job/jobhandler # 执行器运行日志文件存储磁盘路径 |
|||
logretentiondays: 30 # 执行器日志文件保存天数 |
|||
@ -0,0 +1,48 @@ |
|||
package {{ package.Base }}; |
|||
|
|||
//-- 固定引入 --// |
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
import org.springframework.cache.annotation.EnableCaching; |
|||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
|||
import org.springframework.cloud.openfeign.EnableFeignClients; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.web.cors.CorsConfiguration; |
|||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|||
import org.springframework.web.filter.CorsFilter; |
|||
//-- 固定引入 --// |
|||
|
|||
/** |
|||
* @Description: 启动类 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@SpringBootApplication |
|||
@EnableDiscoveryClient |
|||
@EnableFeignClients |
|||
@EnableCaching |
|||
public class Application { |
|||
|
|||
public static void main(String[] args) throws JsonProcessingException { |
|||
SpringApplication.run(Application.class, args); |
|||
} |
|||
|
|||
|
|||
|
|||
@Bean |
|||
public CorsFilter corsFilter() { |
|||
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
|||
final CorsConfiguration config = new CorsConfiguration(); |
|||
config.setAllowCredentials(true); // 允许cookies跨域 |
|||
config.addAllowedOrigin("*");// 允许向该服务器提交请求的URI,*表示全部允许。。这里尽量限制来源域,比如http://xxxx:8080 ,以降低安全风险。。 |
|||
config.addAllowedHeader("*");// 允许访问的头信息,*表示全部 |
|||
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 |
|||
config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许,也可以单独设置GET、PUT等 |
|||
source.registerCorsConfiguration("/**", config); |
|||
return new CorsFilter(source); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
spring: |
|||
profiles: |
|||
active: dev #开发环境 |
|||
#active: test #测试环境 |
|||
#active: pro #生产环境 |
|||
application: |
|||
name: {{ application.name }} |
|||
devtools: |
|||
restart: |
|||
log-condition-evaluation-delta: false |
|||
security: |
|||
user: |
|||
name: admin |
|||
password: admin |
|||
servlet: |
|||
multipart: |
|||
max-file-size: 30MB |
|||
max-request-size: 30MB |
|||
logging: |
|||
level: |
|||
root: info |
|||
{{ application.package.base }}: debug |
|||
org: |
|||
springframework: |
|||
boot: |
|||
autoconfigure: error |
|||
@ -0,0 +1,23 @@ |
|||
package {{ package.Base }}; |
|||
|
|||
/*** |
|||
* @description {{ projectName }} |
|||
* @version 1.0.0 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
import org.junit.jupiter.api.Test; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import java.io.IOException; |
|||
|
|||
@SpringBootTest |
|||
class ApplicationTests { |
|||
|
|||
@Test |
|||
void contextLoads() throws IOException { |
|||
System.out.println("test start"); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
package {{ package.Entity }}; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* 基础Entity类 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
@ApiModel("基础Entity类") |
|||
@Setter |
|||
@Getter |
|||
public class BaseEntity implements Serializable { |
|||
|
|||
@ApiModelProperty(value = "主键id") |
|||
@TableId(value = "id", type = IdType.AUTO) |
|||
private Integer id; |
|||
|
|||
@ApiModelProperty(value = "创建者", hidden = true) |
|||
protected Integer createdBy; |
|||
|
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
@ApiModelProperty(value = "创建日期", hidden = true, example = "yyyy-MM-dd HH:mm:ss") |
|||
@TableField(value = "created_at", fill = FieldFill.INSERT) |
|||
protected Date createdAt; |
|||
|
|||
@ApiModelProperty(value = "更新者", hidden = true) |
|||
protected Integer updatedBy; |
|||
|
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
|||
@ApiModelProperty(value = "更新日期", hidden = true, example = "yyyy-MM-dd HH:mm:ss") |
|||
@TableField(value = "updated_at", fill = FieldFill.INSERT, update = "NOW()") |
|||
protected Date updatedAt; |
|||
|
|||
@ApiModelProperty(value = "删除标记", hidden = true) |
|||
@TableField(value = "deleted_flag") |
|||
@TableLogic(value = "0", delval = "1") |
|||
protected Integer deletedFlag; |
|||
|
|||
@ApiModelProperty(value = "页码", required = false) |
|||
@TableField(exist = false) |
|||
private Integer pageNum; //页码 |
|||
|
|||
@ApiModelProperty(value = "每页条数", required = false) |
|||
@TableField(exist = false) |
|||
private Integer pageSize;//每页条数 |
|||
|
|||
@ApiModelProperty(value = "排序方式排序[true:正序; false:倒序]", required = false) |
|||
@TableField(exist = false) |
|||
private Boolean sort; |
|||
|
|||
@ApiModelProperty(value = "排序字段,参照返回字段", required = false) |
|||
@TableField(exist = false) |
|||
private String sortName; |
|||
|
|||
@ApiModelProperty(value = "用户ID") |
|||
@TableField(value = "user_id") |
|||
private Integer userId; |
|||
|
|||
@ApiModelProperty(value = "创建者用户名") |
|||
@TableField(exist = false) |
|||
private String createdByName; |
|||
|
|||
@ApiModelProperty(value = "更新者用户名") |
|||
@TableField(exist = false) |
|||
private String updatedByName; |
|||
|
|||
public BaseEntity() { |
|||
if (this.pageSize == null) { |
|||
this.setPageSize(10); |
|||
} |
|||
if (this.pageNum == null) { |
|||
this.setPageNum(1); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,107 @@ |
|||
package {{ package.Controller }}; |
|||
import {{ package.Entity }}.{{ table.entity }}; |
|||
import {{ package.Service }}.{{ table.entity }}Service; |
|||
import {{ package.Common }}.vo.Result; |
|||
|
|||
//--- import 固定引入 ---// |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import javax.annotation.Resource; |
|||
import javax.validation.Valid; |
|||
import java.util.List; |
|||
//--- import 固定引入 ---// |
|||
|
|||
/** |
|||
* <p> |
|||
* {{ table.comment }} 前端控制器 |
|||
* </p> |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Api(tags = "{{ table.comment }}") |
|||
{% if restControllerStyle %} |
|||
@RestController |
|||
{% else %} |
|||
@Controller |
|||
{% endif %} |
|||
@RequestMapping("{{ table.name }}") |
|||
public class {{ table.entity }}Controller { |
|||
|
|||
@Resource |
|||
private {{ table.entity }}Service {{table.lowerEntity}}Service; |
|||
|
|||
@ApiOperation(value = "{{ table.comment }}分页列表查询", response = {{ table.entity }}.class) |
|||
@PostMapping(value = "/page") |
|||
public Result<Page<{{ table.entity }}>> page(@Valid @RequestBody {{ table.entity }} param,@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
Page<{{ table.entity }}> page = {{table.lowerEntity}}Service.page(param); |
|||
return Result.OK(page); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "{{ table.comment }}根据条件查询") |
|||
@PostMapping(value = "/info") |
|||
public Result<Object> info(@Valid @RequestBody {{ table.entity }} param, |
|||
@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
if (token ==null) { |
|||
return Result.error("token不能为空"); |
|||
} |
|||
{{ table.entity }} data = {{table.lowerEntity}}Service.info(param); |
|||
return Result.OK(data); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "{{ table.comment }}新增") |
|||
@PostMapping(value = "/add") |
|||
public Result add(@Valid @RequestBody {{ table.entity }} param, |
|||
@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
if (token ==null) { |
|||
return Result.error("token不能为空"); |
|||
} |
|||
{{table.lowerEntity}}Service.add(param); |
|||
return Result.OK(); |
|||
} |
|||
|
|||
@ApiOperation(value = "{{ table.comment }}修改") |
|||
@PostMapping(value = "/modify") |
|||
public Result modify(@Valid @RequestBody {{ table.entity }} param, |
|||
@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
if (token ==null) { |
|||
return Result.error("token不能为空"); |
|||
} |
|||
{{table.entity}} info = {{table.lowerEntity}}Service.info(Integer.valueOf(param.getId())); |
|||
if (info ==null) { |
|||
return Result.error(String.format("[%s]记录不存在", info)); |
|||
} |
|||
{{table.lowerEntity}}Service.modify(param); |
|||
return Result.OK(); |
|||
} |
|||
|
|||
@ApiOperation(value = "{{ table.comment }}删除(单个条目)") |
|||
@GetMapping(value = "/remove/{id}") |
|||
public Result remove(@PathVariable Integer id, |
|||
@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
|
|||
{{table.lowerEntity}}Service.remove(id); |
|||
return Result.OK(); |
|||
} |
|||
|
|||
@ApiOperation(value = "{{ table.comment }}删除(多个条目)") |
|||
@PostMapping(value = "/removes") |
|||
public Result removes(@Valid @RequestBody List<Integer> ids, |
|||
@RequestHeader("token") String token, |
|||
@RequestHeader(value = "version", defaultValue = "1.0") String version) { |
|||
{{table.lowerEntity}}Service.removes(ids); |
|||
return Result.OK(); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
package {{ package.Entity }}; |
|||
import {{ package.Entity }}.BaseEntity; |
|||
|
|||
//--- import 固定引入 ---// |
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }} |
|||
* |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
{% if entityLombokModel %} |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@TableName("{{ table.name }}") |
|||
@ApiModel(value = "{{ table.name }}对象", description = "{{ table.comment }}"){% endif %} |
|||
public class {{ table.entity }} extends BaseEntity { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
{% for field in fields %} |
|||
{% if field.java_type == 'Date' and field.tab_type == 'date' %}@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8"){% endif %} |
|||
{% if field.java_type == 'Date' and field.tab_type == 'datetime' %}@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8"){% endif %} |
|||
@TableField("{{ field.tab_name }}") |
|||
@ApiModelProperty("{{ field.comment }}") |
|||
private {{ field.java_type }} {{ field.java_name }}; |
|||
{% endfor %} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
package {{ package.Common }}.config; |
|||
import {{ package.Common }}.vo.Result; |
|||
|
|||
//--- 固定引入 ---// |
|||
import cn.dev33.satoken.exception.*; |
|||
import org.springframework.web.bind.annotation.ExceptionHandler; |
|||
import org.springframework.web.bind.annotation.RestControllerAdvice; |
|||
//--- 固定引入 ---// |
|||
|
|||
/** |
|||
* 全局异常处理 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
|
|||
@RestControllerAdvice |
|||
public class GlobalException { |
|||
|
|||
// 拦截:未登录异常 |
|||
@ExceptionHandler(NotLoginException.class) |
|||
public Result handlerException(NotLoginException e) { |
|||
|
|||
// 打印堆栈,以供调试 |
|||
e.printStackTrace(); |
|||
|
|||
// 返回给前端 |
|||
return Result.error(1000,e.getMessage()); |
|||
} |
|||
|
|||
// 拦截:缺少权限异常 |
|||
@ExceptionHandler(NotPermissionException.class) |
|||
public Result handlerException(NotPermissionException e) { |
|||
e.printStackTrace(); |
|||
return Result.error("缺少权限:" + e.getPermission()); |
|||
} |
|||
|
|||
// 拦截:缺少角色异常 |
|||
@ExceptionHandler(NotRoleException.class) |
|||
public Result handlerException(NotRoleException e) { |
|||
e.printStackTrace(); |
|||
return Result.error("缺少角色:" + e.getRole()); |
|||
} |
|||
|
|||
// 拦截:二级认证校验失败异常 |
|||
@ExceptionHandler(NotSafeException.class) |
|||
public Result handlerException(NotSafeException e) { |
|||
e.printStackTrace(); |
|||
return Result.error("二级认证校验失败:" + e.getService()); |
|||
} |
|||
|
|||
// 拦截:服务封禁异常 |
|||
@ExceptionHandler(DisableServiceException.class) |
|||
public Result handlerException(DisableServiceException e) { |
|||
e.printStackTrace(); |
|||
return Result.error("当前账号 " + e.getService() + " 服务已被封禁 (level=" + e.getLevel() + "):" + e.getDisableTime() + "秒后解封"); |
|||
} |
|||
|
|||
// 拦截:Http Basic 校验失败异常 |
|||
@ExceptionHandler(NotBasicAuthException.class) |
|||
public Result handlerException(NotBasicAuthException e) { |
|||
e.printStackTrace(); |
|||
return Result.error(1003,e.getMessage()); |
|||
} |
|||
|
|||
// 拦截:其它所有异常 |
|||
@ExceptionHandler(Exception.class) |
|||
public Result handlerException(Exception e) { |
|||
e.printStackTrace(); |
|||
return Result.error(1002,e.getMessage()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration debug="false"> |
|||
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> |
|||
<property name="LOG_HOME" value="/home" /> |
|||
<!--控制台日志, 控制台输出 --> |
|||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
<!--文件日志, 按照每天生成日志文件 --> |
|||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<!--日志文件输出的文件名--> |
|||
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern> |
|||
<!--日志文件保留天数--> |
|||
<MaxHistory>30</MaxHistory> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
|||
</encoder> |
|||
<!--日志文件最大的大小--> |
|||
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> |
|||
<MaxFileSize>10MB</MaxFileSize> |
|||
</triggeringPolicy> |
|||
</appender> |
|||
|
|||
<!-- show parameters for hibernate sql 专为 Hibernate 定制 --> |
|||
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" /> |
|||
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" /> |
|||
<logger name="org.hibernate.SQL" level="DEBUG" /> |
|||
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" /> |
|||
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" /> |
|||
|
|||
<!--myibatis log configure--> |
|||
<logger name="com.apache.mybatis" level="TRACE"/> |
|||
<logger name="java.sql.Connection" level="DEBUG"/> |
|||
<logger name="java.sql.Statement" level="DEBUG"/> |
|||
<logger name="java.sql.PreparedStatement" level="DEBUG"/> |
|||
|
|||
<!-- 日志输出级别 --> |
|||
<root level="DEBUG"> |
|||
<appender-ref ref="STDOUT" /> |
|||
<appender-ref ref="FILE"/> |
|||
</root> |
|||
</configuration> |
|||
@ -0,0 +1,229 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<groupId>{{ groupId }}</groupId> |
|||
<artifactId>{{ mainModule }}</artifactId> |
|||
<version>1.0.0</version> |
|||
<name>${project.artifactId}</name> |
|||
<packaging>pom</packaging> |
|||
<modules> |
|||
<module>{{ moduleName }}</module> |
|||
</modules> |
|||
|
|||
<properties> |
|||
<spring-boot.version>2.0.8.RELEASE</spring-boot.version> |
|||
<spring-cloud.version>Finchley.SR4</spring-cloud.version> |
|||
<spring-platform.version>Cairo-SR7</spring-platform.version> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<maven.compiler.source>1.8</maven.compiler.source> |
|||
<maven.compiler.target>1.8</maven.compiler.target> |
|||
<spring-boot-admin.version>2.0.5</spring-boot-admin.version> |
|||
<hutool.version>4.5.0</hutool.version> |
|||
<oracle.version>11.2.0.4.0-atlassian-hosted</oracle.version> |
|||
<ndsjdbc.version>1.0</ndsjdbc.version> |
|||
<avtiviti.version>5.22.0</avtiviti.version> |
|||
<kaptcha.version>0.0.9</kaptcha.version> |
|||
<elastic-job.version>2.0.0</elastic-job.version> |
|||
<curator.version>2.10.0</curator.version> |
|||
<velocity.version>1.7</velocity.version> |
|||
<lcn.version>4.1.0</lcn.version> |
|||
<jasypt.version>2.1.0</jasypt.version> |
|||
<logstash.version>4.11</logstash.version> |
|||
<truelicense.version>1.33</truelicense.version> |
|||
<elastic-job-lite.version>2.1.5</elastic-job-lite.version> |
|||
<jackson.modules>2.9.8</jackson.modules> |
|||
<kafka-collector.version>2.4.1</kafka-collector.version> |
|||
<skywalking.version>6.0.0-GA</skywalking.version> |
|||
<registry.url>192.168.0.13:5000</registry.url> |
|||
<shiro.version>1.3.2</shiro.version> |
|||
<druid.version>1.1.6</druid.version> |
|||
<fastjson.version>1.2.78</fastjson.version> |
|||
<barcode4j.version>2.1</barcode4j.version> |
|||
<flying-saucer-pdf.version>9.1.5</flying-saucer-pdf.version> |
|||
<axis2.version>1.6.1</axis2.version> |
|||
<mybatisplus.version>3.5.3.2</mybatisplus.version> |
|||
</properties> |
|||
|
|||
<dependencyManagement> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-dependencies</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<type>pom</type> |
|||
<scope>import</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>io.spring.platform</groupId> |
|||
<artifactId>platform-bom</artifactId> |
|||
<version>${spring-platform.version}</version> |
|||
<type>pom</type> |
|||
<scope>import</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-dependencies</artifactId> |
|||
<version>${spring-cloud.version}</version> |
|||
<type>pom</type> |
|||
<scope>import</scope> |
|||
</dependency> |
|||
<!--jackson模块 --> |
|||
<dependency> |
|||
<groupId>com.fasterxml.jackson.module</groupId> |
|||
<artifactId>jackson-modules-java8</artifactId> |
|||
<version>${jackson.modules}</version> |
|||
<type>pom</type> |
|||
<scope>import</scope> |
|||
</dependency> |
|||
</dependencies> |
|||
</dependencyManagement> |
|||
|
|||
<dependencies> |
|||
<!-- Sleuth --> |
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-sleuth</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.aspectj</groupId> |
|||
<artifactId>aspectjweaver</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.skywalking</groupId> |
|||
<artifactId>apm-toolkit-logback-1.x</artifactId> |
|||
<version>${skywalking.version}</version> |
|||
</dependency> |
|||
<!--监控 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-actuator</artifactId> |
|||
</dependency> |
|||
<!--监控客户端 --> |
|||
<dependency> |
|||
<groupId>de.codecentric</groupId> |
|||
<artifactId>spring-boot-admin-starter-client</artifactId> |
|||
<version>${spring-boot-admin.version}</version> |
|||
</dependency> |
|||
<!--断路器依赖 --> |
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId> |
|||
</dependency> |
|||
<!-- Postgresql --> |
|||
<dependency> |
|||
<groupId>org.postgresql</groupId> |
|||
<artifactId>postgresql</artifactId> |
|||
</dependency> |
|||
<!-- logstash --> |
|||
<dependency> |
|||
<groupId>net.logstash.logback</groupId> |
|||
<artifactId>logstash-logback-encoder</artifactId> |
|||
<version>${logstash.version}</version> |
|||
</dependency> |
|||
|
|||
<!-- truelicense --> |
|||
<dependency> |
|||
<groupId>de.schlichtherle.truelicense</groupId> |
|||
<artifactId>truelicense-core</artifactId> |
|||
<version>${truelicense.version}</version> |
|||
</dependency> |
|||
<!--Lombok --> |
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>1.18.24</version> |
|||
<scope>provided</scope> |
|||
</dependency> |
|||
<!--测试依赖 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-test</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.shiro</groupId> |
|||
<artifactId>shiro-spring</artifactId> |
|||
<version>${shiro.version}</version> |
|||
</dependency> |
|||
<!-- 新增阿里 --> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>druid</artifactId> |
|||
<version>${druid.version}</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
<version>${fastjson.version}</version> |
|||
</dependency> |
|||
<!-- 新增 barcode4j--> |
|||
<dependency> |
|||
<groupId>net.sf.barcode4j</groupId> |
|||
<artifactId>barcode4j</artifactId> |
|||
<version>${barcode4j.version}</version> |
|||
</dependency> |
|||
<!--flying-saucer-pdf-9.1.5.jar--> |
|||
<dependency> |
|||
<groupId>org.xhtmlrenderer</groupId> |
|||
<artifactId>flying-saucer-pdf</artifactId> |
|||
<version>${flying-saucer-pdf.version}</version> |
|||
</dependency> |
|||
<!-- 新增axis2 --> |
|||
<dependency> |
|||
<groupId>org.apache.axis2</groupId> |
|||
<artifactId>axis2</artifactId> |
|||
<version>${axis2.version}</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
<version>${mybatisplus.version}</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.poi</groupId> |
|||
<artifactId>poi-ooxml</artifactId> |
|||
<version>3.9</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<build> |
|||
<finalName>${project.name}</finalName> |
|||
<pluginManagement> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<configuration> |
|||
<finalName>${project.build.finalName}</finalName> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</pluginManagement> |
|||
<plugins> |
|||
<plugin> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<version>3.8.0</version> |
|||
<configuration> |
|||
<target>${maven.compiler.target}</target> |
|||
<source>${maven.compiler.source}</source> |
|||
<encoding>UTF-8</encoding> |
|||
</configuration> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>pl.project13.maven</groupId> |
|||
<artifactId>git-commit-id-plugin</artifactId> |
|||
<version>2.2.5</version> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
</project> |
|||
@ -0,0 +1,20 @@ |
|||
package {{ package.Mapper }}; |
|||
|
|||
import {{package.Entity}}.{{ table.entity }}; |
|||
|
|||
//--- import 固定引入 ---// |
|||
import com.github.yulichang.base.MPJBaseMapper; |
|||
//--- import 固定引入 ---// |
|||
|
|||
/** |
|||
* <p> |
|||
* 操作记录 Mapper 接口 |
|||
* </p> |
|||
* |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
public interface {{ table.entity }}Mapper extends MPJBaseMapper<{{ table.entity }}> { |
|||
|
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?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"> |
|||
<mapper namespace="{{ package.Mapper }}.{{ table.entity }}Mapper"> |
|||
<!-- 通用查询映射结果 --> |
|||
<resultMap id="BaseResultMap" type="{{ package.Entity }}.{{ table.entity }}"> |
|||
{% for field in fields %} |
|||
<result column="{{ field.tab_name }}" property="{{ field.java_name }}" /> |
|||
{% endfor %} |
|||
</resultMap> |
|||
|
|||
</mapper> |
|||
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> |
|||
<configuration> |
|||
<typeAliases> |
|||
<typeAlias alias="Integer" type="java.lang.Integer" /> |
|||
<typeAlias alias="Long" type="java.lang.Long" /> |
|||
<typeAlias alias="HashMap" type="java.util.HashMap" /> |
|||
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" /> |
|||
<typeAlias alias="ArrayList" type="java.util.ArrayList" /> |
|||
<typeAlias alias="LinkedList" type="java.util.LinkedList" /> |
|||
</typeAliases> |
|||
</configuration> |
|||
@ -0,0 +1,37 @@ |
|||
package {{ package.Common }}.config; |
|||
|
|||
//--- 固定引入 ---// |
|||
import com.baomidou.mybatisplus.annotation.DbType; |
|||
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; |
|||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
|||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
|||
import org.mybatis.spring.annotation.MapperScan; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
//--- 固定引入 ---// |
|||
|
|||
/** |
|||
* MybatisPlus 配置 |
|||
* |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
@Configuration |
|||
@MapperScan(basePackages = {"{{package.Mapper}}"}) |
|||
public class MybatisPlusConfig { |
|||
@Bean |
|||
public MybatisPlusInterceptor mybatisPlusInterceptor() { |
|||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
|||
//向Mybatis过滤器链中添加分页拦截器 |
|||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); |
|||
//还可以添加i他的拦截器 |
|||
return interceptor; |
|||
} |
|||
|
|||
@Bean |
|||
public ConfigurationCustomizer configurationCustomizer() { |
|||
return configuration -> configuration.setUseGeneratedShortKey(false); |
|||
} |
|||
} |
|||
@ -0,0 +1,310 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>{{ groupId }}</groupId> |
|||
<artifactId>{{ mainModule }}</artifactId> |
|||
<version>1.0.0</version> |
|||
</parent> |
|||
<artifactId>{{ moduleName }}</artifactId> |
|||
<name>{{ moduleName }}</name> |
|||
<properties> |
|||
<java.version>1.8</java.version> |
|||
</properties> |
|||
<dependencies> |
|||
|
|||
<!-- netty tcp 客户端和服务端 --> |
|||
<dependency> |
|||
<groupId>io.netty</groupId> |
|||
<artifactId>netty-all</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- mysql 8.0.27--> |
|||
<dependency> |
|||
<groupId>mysql</groupId> |
|||
<artifactId>mysql-connector-java</artifactId> |
|||
<version>8.0.27</version> |
|||
</dependency> |
|||
|
|||
<!--web 模块 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
</dependency> |
|||
|
|||
<!--tomcat容器 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-tomcat</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-jdbc</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- mybatis-plus --> |
|||
<dependency> |
|||
<groupId>com.github.yulichang</groupId> |
|||
<artifactId>mybatis-plus-join-boot-starter</artifactId> |
|||
<version>1.4.11</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.yulichang</groupId> |
|||
<artifactId>mybatis-plus-join-core</artifactId> |
|||
<version>1.4.11</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>io.minio</groupId> |
|||
<artifactId>minio</artifactId> |
|||
<version>7.1.0</version> |
|||
</dependency> |
|||
|
|||
<!-- Others --> |
|||
<dependency> |
|||
<groupId>com.jcraft</groupId> |
|||
<artifactId>jsch</artifactId> |
|||
</dependency> |
|||
|
|||
<!--freemarker-2.3.19.jar --> |
|||
<dependency> |
|||
<groupId>org.freemarker</groupId> |
|||
<artifactId>freemarker</artifactId> |
|||
<version>2.3.28</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-data-redis</artifactId> |
|||
</dependency> |
|||
|
|||
<!--spring2.X集成redis所需common-pool2--> |
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-pool2</artifactId> |
|||
<version>2.10.0</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
<version>1.2.78</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.axis</groupId> |
|||
<artifactId>axis</artifactId> |
|||
<version>1.4</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.axis</groupId> |
|||
<artifactId>axis-jaxrpc</artifactId> |
|||
<version>1.4</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.sap.cloud.db.jdbc</groupId> |
|||
<artifactId>ngdbc</artifactId> |
|||
<version>2.5.49</version> |
|||
<type>pom</type> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>commons-discovery</groupId> |
|||
<artifactId>commons-discovery</artifactId> |
|||
<version>0.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>wsdl4j</groupId> |
|||
<artifactId>wsdl4j</artifactId> |
|||
<version>1.6.3</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.junit.jupiter</groupId> |
|||
<artifactId>junit-jupiter-api</artifactId> |
|||
<version>5.5.0</version> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>cn.hutool</groupId> |
|||
<artifactId>hutool-all</artifactId> |
|||
<version>5.3.8</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>transmittable-thread-local</artifactId> |
|||
<version>2.12.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.jeecgframework</groupId> |
|||
<artifactId>autopoi</artifactId> |
|||
<version>1.3.6</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>io.springfox</groupId> |
|||
<artifactId>springfox-swagger2</artifactId> |
|||
<version>2.9.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>io.springfox</groupId> |
|||
<artifactId>springfox-swagger-ui</artifactId> |
|||
<version>2.9.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.xiaoymin</groupId> |
|||
<artifactId>swagger-bootstrap-ui</artifactId> |
|||
<version>1.8.7</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-openfeign</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- 热部署模块 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-devtools</artifactId> |
|||
<version>2.0.4.RELEASE</version> |
|||
<optional>true</optional> <!-- 这个需要为 true 热部署才有效 --> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>commons-net</groupId> |
|||
<artifactId>commons-net</artifactId> |
|||
<version>3.6</version> |
|||
</dependency> |
|||
|
|||
<!-- 新增poi 3.9版本 --> |
|||
<dependency> |
|||
<groupId>org.apache.poi</groupId> |
|||
<artifactId>poi</artifactId> |
|||
<version>3.9</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.poi</groupId> |
|||
<artifactId>poi-ooxml</artifactId> |
|||
<version>3.9</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-websocket</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.penggle</groupId> |
|||
<artifactId>kaptcha</artifactId> |
|||
<version>2.3.2</version> |
|||
</dependency> |
|||
|
|||
<!-- aliyun下达指令的两个依赖 --> |
|||
<dependency> |
|||
<groupId>com.aliyun</groupId> |
|||
<artifactId>aliyun-java-sdk-core</artifactId> |
|||
<version>4.5.17</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.aliyun</groupId> |
|||
<artifactId>aliyun-java-sdk-iot</artifactId> |
|||
<version>7.1.0</version> |
|||
</dependency> |
|||
|
|||
|
|||
|
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-generator</artifactId> |
|||
<version>3.5.3.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
<version>3.5.3.2</version> |
|||
</dependency> |
|||
|
|||
<!-- 对象映射的库 --> |
|||
<dependency> |
|||
<groupId>org.modelmapper</groupId> |
|||
<artifactId>modelmapper</artifactId> |
|||
<version>2.3.9</version> |
|||
</dependency> |
|||
|
|||
<!-- swagger --> |
|||
<dependency> |
|||
<groupId>com.github.xiaoymin</groupId> |
|||
<artifactId>swagger-bootstrap-ui</artifactId> |
|||
<version>1.8.7</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
|
|||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) --> |
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-redis-jackson</artifactId> |
|||
<version>1.38.0</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-spring-boot-starter</artifactId> |
|||
<version>1.38.0</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
|
|||
<!-- xxl-job --> |
|||
<dependency> |
|||
<groupId>com.xuxueli</groupId> |
|||
<artifactId>xxl-job-core</artifactId> |
|||
<version>2.4.0</version> |
|||
</dependency> |
|||
|
|||
<!-- 验证码 --> |
|||
<dependency> |
|||
<groupId>com.github.whvcse</groupId> |
|||
<artifactId>easy-captcha</artifactId> |
|||
<version>1.6.2</version> |
|||
</dependency> |
|||
|
|||
<!-- websocket --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-websocket</artifactId> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
|
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
|||
@ -0,0 +1,172 @@ |
|||
package {{ package.Common }}.vo; |
|||
|
|||
//---固定引入---// |
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
import java.io.Serializable; |
|||
//---固定引入---// |
|||
|
|||
|
|||
/** |
|||
* 接口返回数据格式 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
|
|||
@Data |
|||
@ApiModel(value="接口返回对象", description="接口返回对象") |
|||
public class Result<T> implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 成功标志 |
|||
*/ |
|||
@ApiModelProperty(value = "成功标志") |
|||
private boolean success = true; |
|||
|
|||
/** |
|||
* 返回处理消息 |
|||
*/ |
|||
@ApiModelProperty(value = "返回处理消息") |
|||
private String message = ""; |
|||
|
|||
/** |
|||
* 返回代码 |
|||
*/ |
|||
@ApiModelProperty(value = "返回代码") |
|||
private Integer code = 0; |
|||
|
|||
/** |
|||
* 返回数据对象 data |
|||
*/ |
|||
@ApiModelProperty(value = "返回数据对象") |
|||
private T result; |
|||
|
|||
/** |
|||
* 时间戳 |
|||
*/ |
|||
@ApiModelProperty(value = "时间戳") |
|||
private long timestamp = System.currentTimeMillis(); |
|||
|
|||
public Result() { |
|||
} |
|||
|
|||
/** |
|||
* 兼容VUE3版token失效不跳转登录页面 |
|||
* @param code |
|||
* @param message |
|||
*/ |
|||
public Result(Integer code, String message) { |
|||
this.code = code; |
|||
this.message = message; |
|||
} |
|||
|
|||
public Result<T> success(String message) { |
|||
this.message = message; |
|||
this.code = 200; |
|||
this.success = true; |
|||
return this; |
|||
} |
|||
|
|||
@Deprecated |
|||
public static Result<Object> ok() { |
|||
Result<Object> r = new Result<Object>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
return r; |
|||
} |
|||
|
|||
@Deprecated |
|||
public static Result<Object> ok(String msg) { |
|||
Result<Object> r = new Result<Object>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
r.setMessage(msg); |
|||
return r; |
|||
} |
|||
|
|||
@Deprecated |
|||
public static Result<Object> ok(Object data) { |
|||
Result<Object> r = new Result<Object>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
r.setResult(data); |
|||
return r; |
|||
} |
|||
|
|||
public static<T> Result<T> OK() { |
|||
Result<T> r = new Result<T>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
return r; |
|||
} |
|||
|
|||
public static<T> Result<T> OK(String msg) { |
|||
Result<T> r = new Result<T>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
r.setMessage(msg); |
|||
//Result OK(String msg)方法会造成兼容性问题 issues/I4IP3D |
|||
r.setResult((T) msg); |
|||
return r; |
|||
} |
|||
|
|||
public static<T> Result<T> OK(T data) { |
|||
Result<T> r = new Result<T>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
r.setResult(data); |
|||
return r; |
|||
} |
|||
|
|||
public static<T> Result<T> OK(String msg, T data) { |
|||
Result<T> r = new Result<T>(); |
|||
r.setSuccess(true); |
|||
r.setCode(200); |
|||
r.setMessage(msg); |
|||
r.setResult(data); |
|||
return r; |
|||
} |
|||
|
|||
public static<T> Result<T> error(String msg, T data) { |
|||
Result<T> r = new Result<T>(); |
|||
r.setSuccess(false); |
|||
r.setCode(500); |
|||
r.setMessage(msg); |
|||
r.setResult(data); |
|||
return r; |
|||
} |
|||
|
|||
public static Result<Object> error(String msg) { |
|||
return error(500, msg); |
|||
} |
|||
|
|||
public static Result<Object> error(int code, String msg) { |
|||
Result<Object> r = new Result<Object>(); |
|||
r.setCode(code); |
|||
r.setMessage(msg); |
|||
r.setSuccess(false); |
|||
return r; |
|||
} |
|||
|
|||
public Result<T> error500(String message) { |
|||
this.message = message; |
|||
this.code = 500; |
|||
this.success = false; |
|||
return this; |
|||
} |
|||
/** |
|||
* 无权限访问返回结果 |
|||
*/ |
|||
public static Result<Object> noauth(String msg) { |
|||
return error(210, msg); |
|||
} |
|||
|
|||
@JsonIgnore |
|||
private String onlTable; |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
package {{ package.Common }}.config; |
|||
|
|||
import cn.dev33.satoken.interceptor.SaInterceptor; |
|||
import cn.dev33.satoken.router.SaRouter; |
|||
import cn.dev33.satoken.stp.StpUtil; |
|||
import com.alibaba.fastjson.JSONArray; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* SaToken配置 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
* 解决@RequestAttribute、@RequestParam和@RequestBody三种类型的时间类型参数接收与转换问题 |
|||
*/ |
|||
@Configuration |
|||
public class SaTokenConfig implements WebMvcConfigurer { |
|||
|
|||
@Override |
|||
public void addInterceptors(InterceptorRegistry registry) { |
|||
|
|||
// 注册 Sa-Token 拦截器,定义详细认证规则 |
|||
registry.addInterceptor(new SaInterceptor(handler -> { |
|||
// 指定一条 match 规则 |
|||
SaRouter |
|||
.match("/models/**") // 拦截的 path 列表,可以写多个 */ |
|||
// .notMatch("/models/health-user/login") // 排除掉的 path 列表,可以写多个 |
|||
.check(r -> StpUtil.checkLogin()); // 要执行的校验动作,可以写完整的 lambda 表达式 |
|||
|
|||
//拦截并写操作日志 |
|||
// SaRouter.match(r).check(t->{ |
|||
// SaLog.info("操作日志:{}", SaLog.getParamJson()); |
|||
// SaLog.info("操作日志:{}", SaLog.getRequestBody()); |
|||
// ); |
|||
|
|||
})).addPathPatterns("/**"); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
package {{ package.Service }}; |
|||
import {{ package.Entity }}.{{ table.entity }}; |
|||
|
|||
//--- import 固定引入 ---// |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import java.util.List; |
|||
//--- import 固定引入 ---// |
|||
|
|||
/** |
|||
* {{ table.comment }}服务接口 |
|||
* |
|||
* @author {{ author }} |
|||
* @date {{ date }} |
|||
*/ |
|||
|
|||
public interface {{ table.entity }}Service extends IService<{{ table.entity }}> { |
|||
|
|||
/** |
|||
* {{ table.comment }}分页列表 |
|||
* |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
Page<{{ table.entity }}> page({{ table.entity }} param); |
|||
|
|||
/** |
|||
* {{ table.comment }}详情 |
|||
* |
|||
* @param param |
|||
* @return |
|||
*/ |
|||
{{ table.entity }} info({{ table.entity }} param); |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}详情 |
|||
* |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
{{ table.entity }} info(Integer id); |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}列表 |
|||
* |
|||
* @param param |
|||
* @return |
|||
*/ |
|||
List<{{ table.entity }}> list({{ table.entity }} param); |
|||
|
|||
/** |
|||
* {{ table.comment }}新增 |
|||
* |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
void add({{ table.entity }} param); |
|||
|
|||
/** |
|||
* {{ table.comment }}修改 |
|||
* |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
void modify({{ table.entity }} param); |
|||
|
|||
/** |
|||
* {{ table.comment }}删除(单个条目) |
|||
* |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
void remove(Integer id); |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}删除(多个条目) |
|||
* |
|||
* @param ids |
|||
* @return |
|||
*/ |
|||
void removes(List<Integer> ids); |
|||
} |
|||
@ -0,0 +1,154 @@ |
|||
package {{ package.ServiceImpl }}; |
|||
|
|||
import {{ package.Entity }}.{{ table.entity }}; |
|||
import {{ package.Mapper }}.{{ table.entity }}Mapper; |
|||
import {{ package.Service }}.{{ table.entity }}Service; |
|||
|
|||
//--- import 固定引入 ---// |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|||
import com.github.yulichang.base.MPJBaseServiceImpl; |
|||
import com.github.yulichang.wrapper.MPJLambdaWrapper; |
|||
import org.springframework.stereotype.Service; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
//--- import 固定引入 ---// |
|||
|
|||
/** |
|||
* <p> |
|||
* {{ table.comment }} 服务实现类 |
|||
* </p> |
|||
* |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Service |
|||
public class {{ table.entity }}MPJBaseServiceImpl extends MPJBaseServiceImpl<{{ table.entity }}Mapper, {{ table.entity }}> implements {{ table.entity }}Service { |
|||
|
|||
/** |
|||
* {{ table.comment }}分页列表 |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public Page<{{ table.entity }}> page({{ table.entity }} param) { |
|||
MPJLambdaWrapper<{{ table.entity }}> queryWrapper = new MPJLambdaWrapper<>(); |
|||
queryWrapper.selectAll({{ table.entity }}.class) |
|||
{% for field in fields %}{% if not entityLombokModel %}{% if field.java_type == "Boolean" %}{% set get_pre_fix = "is" %}{% else %}{% set get_pre_fix = "get" %}{% endif %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.{{ get_pre_fix }}{{ field.java_get_name }}()), {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.{{ get_pre_fix }}{{ field.java_get_name }}() != null, {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% endif %}{% else %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.get{{ field.java_get_name }}()), {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.get{{ field.java_get_name }}() != null, {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% endif %}{% endif %}{% endfor %}; |
|||
return selectJoinListPage( new Page<>(param.getPageNum(), param.getPageSize()), {{ table.entity }}.class, queryWrapper); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}详情 |
|||
* @param param |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public {{ table.entity }} info({{ table.entity }} param) { |
|||
MPJLambdaWrapper<{{ table.entity }}> queryWrapper = new MPJLambdaWrapper<>(); |
|||
queryWrapper.selectAll({{ table.entity }}.class) |
|||
{% for field in fields %}{% if not entityLombokModel %}{% if field.java_type == "Boolean" %}{% set get_pre_fix = "is" %}{% else %}{% set get_pre_fix = "get" %}{% endif %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.{{ get_pre_fix }}{{ field.java_get_name }}()), {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.{{ get_pre_fix }}{{ field.java_get_name }}() != null, {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% endif %}{% else %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.get{{ field.java_get_name }}()), {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.get{{ field.java_get_name }}() != null, {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% endif %}{% endif %}{% endfor %}; |
|||
return selectJoinOne( {{ table.entity }}.class, queryWrapper ); |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}详情 |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public {{ table.entity }} info(Integer id) { |
|||
return getById(id); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}列表 |
|||
* @param param |
|||
*/ |
|||
@Override |
|||
public List<{{ table.entity }}> list({{ table.entity }} param) { |
|||
MPJLambdaWrapper<{{ table.entity }}> queryWrapper = new MPJLambdaWrapper<>(); |
|||
queryWrapper.selectAll({{ table.entity }}.class) |
|||
{% for field in fields %}{% if not entityLombokModel %}{% if field.java_type == "Boolean" %}{% set get_pre_fix = "is" %}{% else %}{% set get_pre_fix = "get" %}{% endif %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.{{ get_pre_fix }}{{ field.java_get_name }}()), {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.{{ get_pre_fix }}{{ field.java_get_name }}() != null, {{ table.entity }}::{{ get_pre_fix }}{{ field.capital_name }}, param.{{ get_pre_fix }}{{ field.java_get_name }}()) |
|||
{% endif %}{% else %}{% if field.java_type == "String" %} |
|||
.eq(StringUtils.isNotBlank(param.get{{ field.java_get_name }}()), {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% else %} |
|||
.eq(param.get{{ field.java_get_name }}() != null, {{ table.entity }}::get{{ field.java_get_name }}, param.get{{ field.java_get_name }}()) |
|||
{% endif %}{% endif %}{% endfor %}; |
|||
return selectJoinList( {{ table.entity }}.class, queryWrapper); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* {{ table.comment }}新增 |
|||
* |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public void add({{ table.entity }} param) { |
|||
param.setCreatedAt(new Date()); |
|||
param.setCreatedBy(param.getUserId()); |
|||
save(param); |
|||
} |
|||
|
|||
/** |
|||
* {{ table.comment }}修改 |
|||
* |
|||
* @param param 根据需要进行传值 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public void modify({{ table.entity }} param) { |
|||
param.setUpdatedAt(new Date()); |
|||
param.setUpdatedBy(param.getUserId()); |
|||
updateById(param); |
|||
} |
|||
|
|||
/** |
|||
* {{ table.comment }}删除(单个条目) |
|||
* |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public void remove(Integer id) { |
|||
removeById(id); |
|||
} |
|||
|
|||
/** |
|||
* {{ table.comment }}删除(多个条目) |
|||
* |
|||
* @param ids |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public void removes(List<Integer> ids) { |
|||
removeByIds(ids); |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
package {{ package.Common }}.config; |
|||
|
|||
//--- 固定引入 ---// |
|||
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; |
|||
import com.google.common.base.Predicates; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import springfox.documentation.builders.ApiInfoBuilder; |
|||
import springfox.documentation.builders.PathSelectors; |
|||
import springfox.documentation.builders.RequestHandlerSelectors; |
|||
import springfox.documentation.service.ApiInfo; |
|||
import springfox.documentation.service.Contact; |
|||
import springfox.documentation.spi.DocumentationType; |
|||
import springfox.documentation.spring.web.plugins.Docket; |
|||
import springfox.documentation.swagger2.annotations.EnableSwagger2; |
|||
//--- 固定引入 ---// |
|||
|
|||
|
|||
/** |
|||
* Swagger2配置类 |
|||
* 在与spring boot集成时,放在与Application.java同级的目录下。 |
|||
* 通过@Configuration注解,让Spring来加载该类配置。 |
|||
* 再通过@EnableSwagger2注解来启用Swagger2。 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
* 访问地址:http://localhost:port/api/doc.html |
|||
*/ |
|||
@Configuration |
|||
@EnableSwagger2 |
|||
@EnableSwaggerBootstrapUI |
|||
public class Swagger2 { |
|||
|
|||
@Value("${swagger.show}") |
|||
private boolean swaggerShow; |
|||
|
|||
@Bean |
|||
public Docket createRestApi() { |
|||
|
|||
return new Docket(DocumentationType.SWAGGER_2) |
|||
.apiInfo(apiInfo()) |
|||
.enable(swaggerShow)// 设置正式环境不显示Swagger2 |
|||
.select() |
|||
// 配置多个扫描路径 |
|||
.apis( |
|||
Predicates.or( |
|||
RequestHandlerSelectors.basePackage("{{package.Controller}}") |
|||
) |
|||
) |
|||
.paths(PathSelectors.any()) |
|||
.build(); |
|||
} |
|||
|
|||
private ApiInfo apiInfo() { |
|||
// name:作者,url:通常项目地址,email:邮箱 |
|||
Contact contact=new Contact("{{author}}","https://blog.csdn.net/Extraordinarylife"," "); |
|||
return new ApiInfoBuilder() |
|||
.title("数据中心接口文档")//标题 |
|||
.description("数据中心相关接口文档")// 描述 |
|||
.contact(contact) |
|||
.version("1.0")//版本 |
|||
.build(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,26 @@ |
|||
package {{ package.Common }}.job; |
|||
|
|||
import com.xxl.job.core.handler.annotation.XxlJob; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
|
|||
/** |
|||
* @Description: |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Component |
|||
public class TestJob { |
|||
private static Logger logger = LoggerFactory.getLogger(TestJob.class); |
|||
|
|||
@XxlJob("testJobHand") |
|||
public void testJobHand() { |
|||
logger.info(">>>>>>>>>>> testJobHand"); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,85 @@ |
|||
package {{ package.Common }}.config; |
|||
|
|||
//--- 固定引入 ---// |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.aspectj.lang.ProceedingJoinPoint; |
|||
import org.aspectj.lang.annotation.Around; |
|||
import org.aspectj.lang.annotation.Aspect; |
|||
import org.aspectj.lang.reflect.MethodSignature; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import org.springframework.web.context.request.RequestContextHolder; |
|||
import org.springframework.web.context.request.ServletRequestAttributes; |
|||
//--- 固定引入 ---// |
|||
|
|||
|
|||
/*** |
|||
* @Description: 日志切面 |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Slf4j |
|||
@Aspect |
|||
@Component |
|||
public class WebLogAspect { |
|||
|
|||
private final ObjectMapper objectMapper = new ObjectMapper(); |
|||
|
|||
/** 拦截所有 Controller 方法 */ |
|||
@Around("within(@org.springframework.web.bind.annotation.RestController *)") |
|||
public Object logWebRequest(ProceedingJoinPoint joinPoint) throws Throwable { |
|||
long start = System.currentTimeMillis(); |
|||
|
|||
ServletRequestAttributes attributes = |
|||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
|||
HttpServletRequest request = attributes != null ? attributes.getRequest() : null; |
|||
|
|||
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); |
|||
String methodName = signature.toShortString(); |
|||
|
|||
// ========== 读取请求入参 ========== |
|||
String paramsJson = ""; |
|||
try { |
|||
paramsJson = objectMapper.writeValueAsString(joinPoint.getArgs()); |
|||
} catch (Exception ignored) {} |
|||
|
|||
// ----------- 打印入参 ------- |
|||
if (request != null) { |
|||
log.info("\n================= 请求开始 =================\n" + |
|||
"URL : {}\n" + |
|||
"Method : {}\n" + |
|||
"Controller : {}\n" + |
|||
"IP : {}\n" + |
|||
"Request : {}\n" + |
|||
"============================================", |
|||
request.getRequestURI(), |
|||
request.getMethod(), |
|||
methodName, |
|||
request.getRemoteAddr(), |
|||
paramsJson); |
|||
} |
|||
|
|||
// ========== 执行方法 ========== |
|||
Object result = joinPoint.proceed(); |
|||
|
|||
// ========== 打印返回结果 ========== |
|||
String resultJson = ""; |
|||
try { |
|||
resultJson = objectMapper.writeValueAsString(result); |
|||
} catch (Exception ignored) {} |
|||
|
|||
log.info("\n================= 请求结束 =================\n" + |
|||
"URL : {}\n" + |
|||
"耗时 : {} ms\n" + |
|||
"返回值 : {}\n" + |
|||
"============================================", |
|||
request != null ? request.getRequestURI() : methodName, |
|||
(System.currentTimeMillis() - start), |
|||
resultJson); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
package {{ package.Common }}.config; |
|||
|
|||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|||
|
|||
/**** |
|||
* xxl-job config |
|||
* @Author: {{author}} |
|||
* @Date: {{date}} |
|||
* @Wechat: {{ wechat }} |
|||
*/ |
|||
@Configuration |
|||
public class XxlJobConfig implements WebMvcConfigurer { |
|||
|
|||
@Value("${xxl.job.admin.addresses}") |
|||
private String adminAddresses; |
|||
|
|||
@Value("${xxl.job.executor.appname}") |
|||
private String appName; |
|||
|
|||
@Value("${xxl.job.executor.ip}") |
|||
private String ip; |
|||
|
|||
@Value("${xxl.job.executor.port}") |
|||
private int port; |
|||
|
|||
@Value("${xxl.job.accessToken}") |
|||
private String accessToken; |
|||
|
|||
@Value("${xxl.job.executor.logpath}") |
|||
private String logPath; |
|||
|
|||
@Value("${xxl.job.executor.logretentiondays}") |
|||
private int logRetentionDays; |
|||
|
|||
@Bean |
|||
public XxlJobSpringExecutor xxlJobExecutor() { |
|||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); |
|||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses); |
|||
xxlJobSpringExecutor.setAppname(appName); |
|||
xxlJobSpringExecutor.setIp(ip); |
|||
xxlJobSpringExecutor.setPort(port); |
|||
xxlJobSpringExecutor.setAccessToken(accessToken); |
|||
xxlJobSpringExecutor.setLogPath(logPath); |
|||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); |
|||
return xxlJobSpringExecutor; |
|||
} |
|||
} |
|||
@ -0,0 +1,131 @@ |
|||
import argparse |
|||
import re |
|||
from copy import deepcopy |
|||
|
|||
def to_camel(name): |
|||
parts = name.split("_") |
|||
return parts[0] + "".join(p.capitalize() for p in parts[1:]) |
|||
|
|||
def to_m_camel(name): |
|||
return "".join(p.capitalize() for p in name.split("_")) |
|||
|
|||
def to_class(name): |
|||
return "".join(p.capitalize() for p in name.split("_")) |
|||
|
|||
def lower_first(s: str) -> str: |
|||
if not s: |
|||
return s |
|||
return s[0].lower() + s[1:] |
|||
|
|||
def to_path(name): |
|||
parts = name.split(".") |
|||
if len(parts) < 2: # 如果没有".",parts长度就是1 |
|||
return "" |
|||
return parts[0] + "/" + "/".join(p for p in parts[1:]) |
|||
|
|||
|
|||
def get_first_part(name, default=""): |
|||
delimiter="_" |
|||
if delimiter not in name: |
|||
return default |
|||
|
|||
parts = name.split(delimiter) |
|||
if not parts or not parts[0]: |
|||
return default |
|||
|
|||
return parts[0].capitalize() |
|||
|
|||
def parse_args(): |
|||
parser = argparse.ArgumentParser(description="Java Code Generator") |
|||
|
|||
parser.add_argument( |
|||
"--tab", |
|||
default="", |
|||
help="表名,多个用逗号分隔,例如: tab,tab2" |
|||
) |
|||
|
|||
parser.add_argument( |
|||
"--model", |
|||
default="", |
|||
help="可选模块 xxlJob,minio,saToken,swagger" |
|||
) |
|||
|
|||
parser.add_argument( |
|||
"--re", |
|||
action="store_true", |
|||
help="是否覆盖已存在文件(默认不覆盖)" |
|||
) |
|||
|
|||
parser.add_argument( |
|||
"--conf", |
|||
required=True, |
|||
default="", |
|||
help="配置文件路径" |
|||
) |
|||
|
|||
return parser.parse_args() |
|||
|
|||
|
|||
VAR_PATTERN = re.compile(r"\$\{([^}]+)\}") |
|||
def get_by_path(data: dict, path: str): |
|||
""" |
|||
从 dict 中通过 a.b.c 取值 |
|||
""" |
|||
cur = data |
|||
for key in path.split("."): |
|||
if not isinstance(cur, dict) or key not in cur: |
|||
return None |
|||
cur = cur[key] |
|||
return cur |
|||
|
|||
def resolve_string(value: str, data: dict) -> str: |
|||
def replacer(match): |
|||
expr = match.group(1) |
|||
v = get_by_path(data, expr) |
|||
return str(v) if v is not None else match.group(0) |
|||
|
|||
return VAR_PATTERN.sub(replacer, value) |
|||
|
|||
def resolve_config(config: dict, max_rounds=5) -> dict: |
|||
""" |
|||
递归解析配置中的 ${xxx} |
|||
""" |
|||
result = deepcopy(config) |
|||
|
|||
for _ in range(max_rounds): |
|||
changed = False |
|||
|
|||
def walk(obj): |
|||
nonlocal changed |
|||
if isinstance(obj, dict): |
|||
for k, v in obj.items(): |
|||
obj[k] = walk(v) |
|||
elif isinstance(obj, list): |
|||
return [walk(i) for i in obj] |
|||
elif isinstance(obj, str): |
|||
new = resolve_string(obj, result) |
|||
if new != obj: |
|||
changed = True |
|||
return new |
|||
return obj |
|||
|
|||
walk(result) |
|||
|
|||
if not changed: |
|||
break |
|||
|
|||
return result |
|||
|
|||
|
|||
def mysql_to_java(mysql_type): |
|||
mapping = { |
|||
"bigint": "Long", |
|||
"int": "Integer", |
|||
"tinyint": "Integer", |
|||
"varchar": "String", |
|||
"mediumtext": "String", |
|||
"datetime": "Date", |
|||
"date": "Date", |
|||
"decimal": "BigDecimal" |
|||
} |
|||
return mapping.get(mysql_type, "String") |
|||
Loading…
Reference in new issue