Compare commits
2 Commits
master
...
dev-featur
Author | SHA1 | Date |
---|---|---|
|
6bd0b2f0e0 | |
|
b62b7c75f5 |
51
.drone.yml
51
.drone.yml
|
@ -1,51 +0,0 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: ${serverName} # 服务名成,可与jar包名保持一致
|
||||
|
||||
steps:
|
||||
- name: build-jar # 流水线名称
|
||||
image: maven:3.8.5-openjdk-17 # 定义创建容器的Docker镜像,基线项目使用jdk17
|
||||
volumes: # 将容器内目录挂载到宿主机,仓库需要开启Trusted设置
|
||||
- name: maven-cache
|
||||
path: /root/.m2 # 将maven下载依赖的目录挂载出来,防止重复下载
|
||||
- name: maven-build
|
||||
path: /home/app/build # 将应用打包好的Jar和执行脚本挂载出来
|
||||
commands: # 定义在Docker容器中执行的shell命令
|
||||
- mvn clean package -DskipTests=true # 应用打包命
|
||||
- cp ${executePath} /home/app/build/${serverName}.jar # 需要修改提取的jar包位置,默认当前在根项目的target目录下,jar包名与后续执行需保持一致
|
||||
- cp start.sh /home/app/build/
|
||||
- cp Dockerfile /home/app/build/
|
||||
# - cp .dockerignore /home/app/build/
|
||||
- cp docker.sh /home/app/build/
|
||||
|
||||
- name: build-docker
|
||||
image: docker
|
||||
volumes: # 将容器内目录挂载到宿主机,仓库需要开启Trusted设置
|
||||
- name: maven-build
|
||||
path: /home/app/build # 将应用打包好的Jar和执行脚本挂载出来
|
||||
- name: docker
|
||||
path: /var/run/docker.sock # 挂载宿主机的docker
|
||||
settings:
|
||||
dockerfile: /home/app/build/Dockerfile
|
||||
commands: # 定义在Docker容器中执行的shell命令
|
||||
- cd /home/app/build
|
||||
- chmod +x docker.sh
|
||||
- sh docker.sh
|
||||
- docker ps
|
||||
|
||||
volumes: # 定义流水线挂载目录,用于共享数据
|
||||
- name: maven-build
|
||||
host:
|
||||
path: /home/data/maven/build # 从宿主机中挂载的目录
|
||||
- name: maven-cache
|
||||
host:
|
||||
path: /home/data/maven/cache
|
||||
- name: docker
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
|
||||
#trigger:
|
||||
# event:
|
||||
# - custom
|
||||
# ref:
|
||||
# - refs/tags/version1.1
|
18
Dockerfile
18
Dockerfile
|
@ -1,18 +0,0 @@
|
|||
# 目前制作docker镜像依赖的jdk,基线项目使用jdk17
|
||||
FROM openjdk:17.0.2-oraclelinux8
|
||||
|
||||
ENV SERVICE_PORTS=${innerPort}
|
||||
|
||||
RUN mkdir -p /home/app/
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY ./start.sh /home/app/
|
||||
# COPY ./.dockerignore /home/app/
|
||||
# jar包名,建议与docker.sh和drone配置文件的服务名一致
|
||||
COPY ./${serverName}.jar /home/app/
|
||||
|
||||
RUN chmod 755 -R /home/app/
|
||||
|
||||
|
||||
ENTRYPOINT ["/home/app/start.sh"]
|
22
docker.sh
22
docker.sh
|
@ -1,22 +0,0 @@
|
|||
#!/bin/sh
|
||||
# 定义应用组名
|
||||
group_name='${serverGroup}'
|
||||
# 定义应用名称,建议与drone中服务名和jar包名保持一致
|
||||
app_name='${serverName}'
|
||||
# 定义应用版本
|
||||
app_version='1.0'
|
||||
echo '----copy jar----'
|
||||
docker stop ${app_name}
|
||||
echo '----stop container----'
|
||||
docker rm ${app_name}
|
||||
echo '----rm container----'
|
||||
docker rmi ${group_name}/${app_name}:${app_version}
|
||||
echo '----rm image----'
|
||||
# 打包编译docker镜像
|
||||
docker build -t ${group_name}/${app_name}:${app_version} .
|
||||
echo '----build image----'
|
||||
docker run -p ${outerPort}:${innerPort} --name ${app_name} \
|
||||
-e TZ="Asia/Shanghai" \
|
||||
-v /etc/localtime:/etc/localtime \
|
||||
-d ${group_name}/${app_name}:${app_version}
|
||||
echo '----start container----'
|
8
start.sh
8
start.sh
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
## jar包名,与之前服务名保持一致
|
||||
java -Xms128m -Xmx128m -jar /home/app/${serverName}.jar --spring.profiles.active=dev
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
echo Failed to start java >&2
|
||||
exit 1
|
||||
fi
|
|
@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
@ -13,6 +14,8 @@ import javax.servlet.ServletRequest;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -59,6 +62,28 @@ public class ServletUtils {
|
|||
return ua != null ? ua : "";
|
||||
}
|
||||
|
||||
public static String getHeader(HttpServletRequest request, String name){
|
||||
String value = request.getHeader(name);
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return urlDecode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容解码
|
||||
*
|
||||
* @param str 内容
|
||||
* @return 解码后的内容
|
||||
*/
|
||||
public static String urlDecode(String str) {
|
||||
try {
|
||||
return URLDecoder.decode(str,"UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求
|
||||
*
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Entity基类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
@JsonIgnore
|
||||
@TableField(exist = false)
|
||||
private String searchValue;
|
||||
|
||||
// /**
|
||||
// * 创建部门
|
||||
// */
|
||||
// @TableField(fill = FieldFill.INSERT)
|
||||
// private Long deptId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
@TableField(exist = false)
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.handler;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseEntity;
|
||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
@ -41,6 +42,28 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
|||
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
|
||||
baseDO.setUpdater(userId.toString());
|
||||
}
|
||||
}else if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) {
|
||||
BaseEntity baseEntity = (BaseEntity) metaObject.getOriginalObject();
|
||||
|
||||
LocalDateTime current = LocalDateTime.now();
|
||||
// 创建时间为空,则以当前时间为插入时间
|
||||
if (Objects.isNull(baseEntity.getCreateTime())) {
|
||||
baseEntity.setCreateTime(current);
|
||||
}
|
||||
// 更新时间为空,则以当前时间为更新时间
|
||||
if (Objects.isNull(baseEntity.getUpdateTime())) {
|
||||
baseEntity.setUpdateTime(current);
|
||||
}
|
||||
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
|
||||
if (Objects.nonNull(userId) && Objects.isNull(baseEntity.getCreateBy())) {
|
||||
baseEntity.setCreateBy(userId);
|
||||
}
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
if (Objects.nonNull(userId) && Objects.isNull(baseEntity.getUpdateBy())) {
|
||||
baseEntity.setUpdateBy(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,12 +74,20 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
|||
if (Objects.isNull(modifyTime)) {
|
||||
setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
|
||||
}
|
||||
|
||||
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
Object modifier = getFieldValByName("updater", metaObject);
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
|
||||
setFieldValByName("updater", userId.toString(), metaObject);
|
||||
}
|
||||
}else if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity) {
|
||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||
Object modifier = getFieldValByName("updateBy", metaObject);
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
|
||||
setFieldValByName("updateBy", userId, metaObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.page;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页查询实体类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
public class PageQuery implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 当前页数
|
||||
*/
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
private String orderByColumn;
|
||||
|
||||
/**
|
||||
* 排序的方向desc或者asc
|
||||
*/
|
||||
private String isAsc;
|
||||
|
||||
/**
|
||||
* 当前记录起始索引 默认值
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_NUM = 1;
|
||||
|
||||
/**
|
||||
* 每页显示记录数 默认值 默认查全部
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
|
||||
*/
|
||||
public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
|
||||
|
||||
public static final String SEPARATOR = ",";
|
||||
|
||||
/**
|
||||
* 构建分页对象
|
||||
*/
|
||||
public <T> Page<T> build() {
|
||||
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
|
||||
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
|
||||
if (pageNum <= 0) {
|
||||
pageNum = DEFAULT_PAGE_NUM;
|
||||
}
|
||||
Page<T> page = new Page<>(pageNum, pageSize);
|
||||
List<OrderItem> orderItems = buildOrderItem();
|
||||
if (CollUtil.isNotEmpty(orderItems)) {
|
||||
page.addOrder(orderItems);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建排序
|
||||
*
|
||||
* 支持的用法如下:
|
||||
* {isAsc:"asc",orderByColumn:"id"} order by id asc
|
||||
* {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
|
||||
* {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
|
||||
* {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
|
||||
*/
|
||||
private List<OrderItem> buildOrderItem() {
|
||||
if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
|
||||
return null;
|
||||
}
|
||||
String orderBy = escapeOrderBySql(orderByColumn);
|
||||
orderBy = StrUtil.toUnderlineCase(orderBy);
|
||||
|
||||
// 兼容前端排序类型
|
||||
isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
|
||||
|
||||
String[] orderByArr = orderBy.split(SEPARATOR);
|
||||
String[] isAscArr = isAsc.split(SEPARATOR);
|
||||
if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
|
||||
throw new ServiceException(500,"排序参数有误");
|
||||
}
|
||||
|
||||
List<OrderItem> list = new ArrayList<>();
|
||||
// 每个字段各自排序
|
||||
for (int i = 0; i < orderByArr.length; i++) {
|
||||
String orderByStr = orderByArr[i];
|
||||
String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
|
||||
if ("asc".equals(isAscStr)) {
|
||||
list.add(OrderItem.asc(orderByStr));
|
||||
} else if ("desc".equals(isAscStr)) {
|
||||
list.add(OrderItem.desc(orderByStr));
|
||||
} else {
|
||||
throw new ServiceException(500,"排序参数有误");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Integer getFirstNum() {
|
||||
return (pageNum - 1) * pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符,防止注入绕过
|
||||
*/
|
||||
public static String escapeOrderBySql(String value) {
|
||||
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
|
||||
throw new IllegalArgumentException("参数不符合规范,不能进行查询");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 order by 语法是否符合规范
|
||||
*/
|
||||
public static boolean isValidOrderBySql(String value) {
|
||||
return value.matches(SQL_PATTERN);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.page;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表格分页数据对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TableDataInfo<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private long total;
|
||||
|
||||
/**
|
||||
* 列表数据
|
||||
*/
|
||||
private List<T> list;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*
|
||||
* @param list 列表数据
|
||||
* @param total 总记录数
|
||||
*/
|
||||
public TableDataInfo(List<T> list, long total) {
|
||||
this.list = list;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分页对象构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build(IPage<T> page) {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
rspData.setList(page.getRecords());
|
||||
rspData.setTotal(page.getTotal());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据列表构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build(List<T> list) {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
rspData.setList(list);
|
||||
rspData.setTotal(list.size());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建表格分页数据对象
|
||||
*/
|
||||
public static <T> TableDataInfo<T> build() {
|
||||
TableDataInfo<T> rspData = new TableDataInfo<>();
|
||||
return rspData;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package cn.iocoder.yudao.framework.mybatis.core.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AutoQueryUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AutoQueryUtil.class);
|
||||
|
||||
/**
|
||||
* 根据实体类的属性值是否为空自动创建LambdaQueryWrapper。
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @param <T> 实体类型
|
||||
* @return LambdaQueryWrapper
|
||||
*/
|
||||
public static <T> QueryWrapper<T> autoQuery(T entity) {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
if (entity == null) {
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
Class<?> clazz = entity.getClass();
|
||||
// 遍历当前类和所有父类的字段
|
||||
while (clazz != null) {
|
||||
Map<String, Method> getterMethods = new HashMap<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
String fieldName = field.getName();
|
||||
Class<?> finalClazz = clazz;
|
||||
Method getterMethod = getterMethods.computeIfAbsent(
|
||||
"get" + capitalize(fieldName),
|
||||
k -> {
|
||||
try {
|
||||
return MethodUtils.getAccessibleMethod(finalClazz, k, (Class<?>[]) null);
|
||||
} catch (Exception e) {
|
||||
log.error("No such getter method: {}", k, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (getterMethod != null) {
|
||||
try {
|
||||
Object value = getterMethod.invoke(entity);
|
||||
if (value != null && !"".equals(value)) {
|
||||
handleFieldValue(queryWrapper, field, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error invoking getter method: {}", getterMethod.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取父类,继续遍历父类的字段
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
public static String getTenantId(){
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
if (null != request) {
|
||||
// 获取request的header中的x-tenant-id
|
||||
String tenantId = ServletUtils.getHeader(request, "x-tenant-id");
|
||||
if (StringUtils.isNotBlank(tenantId)) {
|
||||
return tenantId;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void handleFieldValue(QueryWrapper<?> queryWrapper, Field field, Object value) {
|
||||
String fieldName = field.getName();
|
||||
|
||||
if (String.class.isAssignableFrom(field.getType())) {
|
||||
queryWrapper.like(StrUtil.toUnderlineCase(fieldName), value);
|
||||
} else if (Integer.class.isAssignableFrom(field.getType()) ||
|
||||
Long.class.isAssignableFrom(field.getType()) ||
|
||||
Double.class.isAssignableFrom(field.getType()) ||
|
||||
Float.class.isAssignableFrom(field.getType()) ||
|
||||
Boolean.class.isAssignableFrom(field.getType()) ||
|
||||
Short.class.isAssignableFrom(field.getType()) ||
|
||||
Byte.class.isAssignableFrom(field.getType()) ||
|
||||
Character.class.isAssignableFrom(field.getType()) ||
|
||||
Date.class.isAssignableFrom(field.getType()) ||
|
||||
LocalDateTime.class.isAssignableFrom(field.getType()) ||
|
||||
LocalDate.class.isAssignableFrom(field.getType()) ||
|
||||
LocalTime.class.isAssignableFrom(field.getType()) ||
|
||||
ZonedDateTime.class.isAssignableFrom(field.getType()) ||
|
||||
Instant.class.isAssignableFrom(field.getType())) {
|
||||
queryWrapper.eq(StrUtil.toUnderlineCase(fieldName), String.valueOf(value));
|
||||
} else {
|
||||
// 如果是其他类型,可以添加更多条件,或者忽略
|
||||
log.warn("Unsupported field type: {}", field.getType().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 pageReqVO 中所有 LocalDate[]、LocalDateTime[] 和 Date[] 类型字段的名称
|
||||
*/
|
||||
public static String[] getDateRangeFieldNames(Object pageReqVO) {
|
||||
return Arrays.stream(pageReqVO.getClass().getDeclaredFields())
|
||||
.filter(field -> field.getType().equals(LocalDate[].class)
|
||||
|| field.getType().equals(LocalDateTime[].class)
|
||||
|| field.getType().equals(Date[].class))
|
||||
.map(Field::getName)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态处理 pageReqVO 中所有 LocalDate[]、LocalDateTime[] 和 Date[] 类型字段,设置时间段查询条件
|
||||
*/
|
||||
public static void handleDateRangeFields(Object pageReqVO, QueryWrapper<?> queryWrapper) {
|
||||
for (Field field : pageReqVO.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
Object fieldValue = field.get(pageReqVO);
|
||||
if (fieldValue == null) {
|
||||
continue; // 跳过值为 null 的字段
|
||||
}
|
||||
|
||||
if (field.getType().equals(LocalDate[].class)) {
|
||||
LocalDate[] dateRange = (LocalDate[]) fieldValue;
|
||||
if (dateRange.length == 2) {
|
||||
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
|
||||
queryWrapper.between(columnName, dateRange[0], dateRange[1]);
|
||||
}
|
||||
} else if (field.getType().equals(LocalDateTime[].class)) {
|
||||
LocalDateTime[] dateTimeRange = (LocalDateTime[]) fieldValue;
|
||||
if (dateTimeRange.length == 2) {
|
||||
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
|
||||
queryWrapper.between(columnName, dateTimeRange[0], dateTimeRange[1]);
|
||||
}
|
||||
} else if (field.getType().equals(Date[].class)) {
|
||||
Date[] range = (Date[]) fieldValue;
|
||||
if (range.length == 2) {
|
||||
String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
|
||||
queryWrapper.between(columnName, range[0], range[1]);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ServiceException(500,"Failed to access field " + field.getName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String capitalize(String str) {
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
||||
}
|
||||
}
|
|
@ -25,11 +25,13 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -148,4 +150,21 @@ public class CodegenController {
|
|||
writeAttachment(response, "codegen.zip", outputStream.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用程序前后端代码生成,并解压到配置的路径
|
||||
*
|
||||
* @param tableIdStr 表ID串
|
||||
*/
|
||||
@Operation(summary = "应用程序前后端代码生成")
|
||||
@Parameters({
|
||||
@Parameter(name = "tableIdStr", description = "表编号", required = true, example = "1024,1025"),
|
||||
@Parameter(name = "appName", description = "应用名称", required = true, example = "testApp")
|
||||
})
|
||||
@GetMapping("/genAppCode")
|
||||
@PermitAll
|
||||
// @PreAuthorize("@ss.hasPermission('infra:codegen:genappcode')")
|
||||
public CommonResult<String> genAppCode( String tableIdStr, String appName){
|
||||
return success(codegenService.genAppCode(tableIdStr, appName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -98,4 +98,12 @@ public interface CodegenService {
|
|||
*/
|
||||
List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment);
|
||||
|
||||
/**
|
||||
* 应用程序前后端代码生成,并解压到配置的路径
|
||||
* @param tableIdStr
|
||||
* @param appName
|
||||
* @return
|
||||
*/
|
||||
String genAppCode(String tableIdStr, String appName);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
package cn.iocoder.yudao.module.infra.service.codegen;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.ZipUtil;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
|
||||
|
@ -18,29 +23,51 @@ import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
|
|||
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
|
||||
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
|
||||
import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
|
||||
import cn.iocoder.yudao.module.infra.util.DistributedLock;
|
||||
import cn.iocoder.yudao.module.infra.util.InputStreamConverter;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import com.alibaba.excel.util.DateUtils;
|
||||
import com.baomidou.mybatisplus.generator.config.po.TableField;
|
||||
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
|
||||
|
||||
/**
|
||||
* 代码生成 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CodegenServiceImpl implements CodegenService {
|
||||
|
||||
|
@ -63,6 +90,31 @@ public class CodegenServiceImpl implements CodegenService {
|
|||
@Resource
|
||||
private CodegenProperties codegenProperties;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Value("${runsystem.project.basedir.unzip}")
|
||||
private String unzipPath;
|
||||
|
||||
|
||||
@Value("${runsystem.project.basedir.menusql}")
|
||||
private String menuSqlPath;
|
||||
|
||||
@Value("${runsystem.project.basedir.shell}")
|
||||
private String shellPath;
|
||||
|
||||
@Value("${runsystem.project.basedir.config}")
|
||||
private String configPath;
|
||||
|
||||
@Value("${runsystem.project.basedir.nginx}")
|
||||
private String nginxPath;
|
||||
|
||||
@Autowired
|
||||
private DistributedLock distributedLock;
|
||||
|
||||
@Value("${runsystem.project.host}")
|
||||
private String host;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Long> createCodegenList(Long userId, CodegenCreateListReqVO reqVO) {
|
||||
|
@ -293,4 +345,243 @@ public class CodegenServiceImpl implements CodegenService {
|
|||
return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用程序前后端代码生成,并解压到配置的路径
|
||||
*/
|
||||
@Override
|
||||
public String genAppCode(String tableIdStr, String appName) {
|
||||
appName = appName.toLowerCase().replaceAll("[^a-zA-Z0-9]", "");
|
||||
log.info("应用程序前后端代码生成开始,tableIdStr:{},appName:{}", tableIdStr, appName);
|
||||
|
||||
String lockKey = "genAppCode:" + ":" + appName;
|
||||
if (!distributedLock.lock(lockKey, 10, TimeUnit.MINUTES)) {
|
||||
log.error("Failed to acquire lock for appName: {}", appName);
|
||||
throw new ServiceException(500,appName + " Failed to acquire lock");
|
||||
}
|
||||
Long[] tableIds = Convert.toLongArray(tableIdStr);
|
||||
try {
|
||||
|
||||
String appDir = "/" + appName + "-" + DateUtils.DATE_FORMAT_10;
|
||||
String savePath = unzipPath + appDir;
|
||||
String url = "";
|
||||
|
||||
Map<String,String> codeResult=new HashMap<String, String>();
|
||||
// 生成代码
|
||||
for (Long tableId : tableIds) {
|
||||
Map<String, String> codes = this.generationCodes(tableId);
|
||||
codeResult.putAll(codes);
|
||||
}
|
||||
|
||||
// 构建 zip 包
|
||||
String[] paths = codeResult.keySet().toArray(new String[0]);
|
||||
ByteArrayInputStream[] ins = codeResult.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
|
||||
|
||||
// 解压ZIP文件内容到目标文件夹
|
||||
File targetFolder = new File(savePath);
|
||||
if (!targetFolder.exists()) {
|
||||
targetFolder.mkdirs();
|
||||
} else {
|
||||
FileUtils.deleteDirectory(targetFolder);
|
||||
}
|
||||
|
||||
InputStream bais = InputStreamConverter.convertByteArrayInputStreamArrayToInputStream(ins);
|
||||
ZipInputStream zis = new ZipInputStream(bais);
|
||||
ZipUtil.unzip(zis, targetFolder);
|
||||
|
||||
//运行系统-执行菜单文件夹中的SQL脚本
|
||||
Connection connection = dataSource.getConnection();
|
||||
String menuScriptsDir = savePath + menuSqlPath;
|
||||
if (null != connection) {
|
||||
executeMenuScripts(menuScriptsDir, savePath);
|
||||
}
|
||||
|
||||
//运行系统
|
||||
executeRunSystemShell(appName, savePath);
|
||||
|
||||
//构建nginx配置文件
|
||||
url = buildNginxConf(appName, savePath);
|
||||
|
||||
// 返回成功信息
|
||||
log.info("代码生成成功,已保存到: " + savePath, "运行系统url地址:" + url);
|
||||
return StringUtils.isNotBlank(url) ? url : "应用容器启动失败";
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to generate app code: {}", e.getMessage());
|
||||
return "应用容器启动失败:" + e.getMessage();
|
||||
} finally {
|
||||
distributedLock.unlock(lockKey);
|
||||
log.info("Lock released for tableIdStr: {}, appName: {}", tableIdStr, appName);
|
||||
//删除gen_table和gen_table_column中table_id相关的数据
|
||||
codegenTableMapper.deleteByIds(Arrays.asList(tableIds));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行菜单脚本并合并为一个文件
|
||||
*/
|
||||
private static void executeMenuScripts(String menuScriptsDir, String targetDir) throws IOException {
|
||||
File dir = new File(menuScriptsDir);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalArgumentException("指定的目录不存在或不是一个文件夹: " + menuScriptsDir);
|
||||
}
|
||||
|
||||
File[] sqlFiles = dir.listFiles((dir1, name) -> name.toLowerCase().endsWith(".sql"));
|
||||
if (sqlFiles == null || sqlFiles.length == 0) {
|
||||
System.out.println("没有找到 SQL 脚本文件");
|
||||
return;
|
||||
}
|
||||
|
||||
Arrays.sort(sqlFiles); // 按文件名排序
|
||||
|
||||
StringBuilder combinedSql = new StringBuilder();
|
||||
|
||||
for (File sqlFile : sqlFiles) {
|
||||
String sqlContent = readFile(sqlFile);
|
||||
combinedSql.append(sqlContent).append(";\n");
|
||||
}
|
||||
|
||||
// 将合并后的 SQL 内容写入目标文件
|
||||
String targetFilePath = targetDir + File.separator + "menu.sql";
|
||||
Path targetPath = Paths.get(targetFilePath);
|
||||
Files.createDirectories(targetPath.getParent());
|
||||
Files.write(targetPath, combinedSql.toString().getBytes());
|
||||
|
||||
System.out.println("合并后的menu SQL脚本已保存到: " + targetFilePath);
|
||||
}
|
||||
|
||||
private static String readFile(File file) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
return reader.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行运行系统shell脚本
|
||||
*
|
||||
* @param appName
|
||||
* @return
|
||||
*/
|
||||
private String executeRunSystemShell(String appName, String savePath) {
|
||||
String result = "";
|
||||
try {
|
||||
// 组合命令和参数
|
||||
// String[] command = {"/bin/sh", "bash "+savePath + shellPath + "/runSystem.sh", appName};
|
||||
|
||||
|
||||
// 执行Shell脚本
|
||||
Process process = Runtime.getRuntime().exec("sh " + savePath + shellPath + "/runSystem.sh " + appName);
|
||||
|
||||
// 读取脚本的输出
|
||||
|
||||
BufferedReader reader = new BufferedReader(new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("ls").getInputStream())));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
|
||||
// 等待脚本执行完成
|
||||
// process.waitFor();
|
||||
int exitCode = process.waitFor();
|
||||
log.info("Script runSystem executed with exit code: " + exitCode);
|
||||
|
||||
// Thread.sleep(15000);
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String buildNginxConf(String appName, String savePath) {
|
||||
String url = "";
|
||||
// 读取nginx.conf文件内容并替换{port}和{host_ip}
|
||||
// 读取文件内容
|
||||
StringBuilder contentBuilder = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(savePath + configPath + "/nginx.conf"))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
contentBuilder.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String hostIp = executeSelectIpShell(appName, savePath);
|
||||
String port = getPortSequence().toString();
|
||||
|
||||
if (ObjectUtil.isAllNotEmpty(hostIp, port)) {
|
||||
String content = contentBuilder.toString();
|
||||
content = content.replace("{port}", port);
|
||||
content = content.replace("{host_ip}", hostIp);
|
||||
|
||||
// 构建输出文件路径
|
||||
File outputDir = new File(nginxPath);
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs(); // 如果目录不存在,则创建目录
|
||||
}
|
||||
File outputFile = new File(outputDir, appName + ".conf");
|
||||
|
||||
// 写入替换后的内容到新文件
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
|
||||
writer.write(content);
|
||||
}
|
||||
log.info("文件内容已成功替换并保存到: " + outputFile.getAbsolutePath());
|
||||
url = host + ":" + port;
|
||||
}
|
||||
// 替换 {port} 和 {host_ip}
|
||||
|
||||
|
||||
Runtime.getRuntime().exec("nginx -s reload");
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查找ip shell脚本
|
||||
*
|
||||
* @param appName
|
||||
* @return
|
||||
*/
|
||||
private String executeSelectIpShell(String appName, String savePath) {
|
||||
String result = "";
|
||||
try {
|
||||
// 执行Shell脚本
|
||||
Process process = Runtime.getRuntime().exec("sh " + savePath + shellPath + "/selectIp.sh " + appName);
|
||||
|
||||
// 读取脚本的输出
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
|
||||
// 等待脚本执行完成
|
||||
int exitCode = process.waitFor();
|
||||
log.info("Script selectIp executed with exit code: " + exitCode);
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取端口号序列值
|
||||
*
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
private Long getPortSequence() throws SQLException {
|
||||
Long port = 10000L;
|
||||
Connection connection = dataSource.getConnection();
|
||||
CallableStatement callableStatement = connection.prepareCall("{call get_next_sequence()}");
|
||||
boolean hasResult = callableStatement.execute();
|
||||
if (hasResult) {
|
||||
ResultSet resultSet = callableStatement.getResultSet();
|
||||
if (resultSet.next()) {
|
||||
port = resultSet.getLong(1);
|
||||
log.info("Next sequence value: " + port);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.infra.util;
|
||||
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class DistributedLock {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
public boolean lock(String key, long timeout, TimeUnit unit) {
|
||||
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(key, "locked", timeout, unit);
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
public void unlock(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cn.iocoder.yudao.module.infra.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
public class InputStreamConverter {
|
||||
public static InputStream convertByteArrayInputStreamArrayToInputStream(ByteArrayInputStream[] ins) {
|
||||
Vector<InputStream> inputStreams = new Vector<>();
|
||||
for (ByteArrayInputStream byteArrayInputStream : ins) {
|
||||
inputStreams.add(byteArrayInputStream);
|
||||
}
|
||||
return new SequenceInputStream(new Enumeration<InputStream>() {
|
||||
private final Enumeration<InputStream> enumeration = inputStreams.elements();
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return enumeration.hasMoreElements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream nextElement() {
|
||||
return enumeration.nextElement();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -179,3 +179,27 @@ yudao:
|
|||
- infra_data_source_config
|
||||
|
||||
debug: false
|
||||
#应用运行系统基线项目文件地址
|
||||
runsystem:
|
||||
project:
|
||||
host: 10.31.0.172
|
||||
basedir:
|
||||
# 基线项目根目录 服务器路径:/root/RunSystemBaseLineProject
|
||||
# source: D:/RunSystemBaseLineProject
|
||||
source: /root/RunSystemBaseLineProject
|
||||
# java源文件路径
|
||||
java: /app/icss-xm-app/ruoyi-modules/ruoyi-system/src/
|
||||
# web源文件路径
|
||||
web: /web/icss-xm-app-web/src/
|
||||
# 运行系统解压路径 服务器路径:/root/dockerTest
|
||||
# unzip: D:/RunSystemSavePath
|
||||
unzip: /root/dockerTest
|
||||
# 菜单sql文件路径
|
||||
menusql: /app/icss-xm-app/ruoyi-modules/ruoyi-system/src/main/resources/menusql
|
||||
# shell脚本路径
|
||||
shell:
|
||||
# config文件路径
|
||||
config: /app/icss-xm-app/script/config
|
||||
# nginx配置文件路径 服务器路径:/etc/nginx/conf.d
|
||||
# nginx: D:/code/icss-xm-app/script/nginx
|
||||
nginx: /etc/nginx/conf.d
|
|
@ -163,7 +163,7 @@ yudao:
|
|||
description: 提供管理员管理的所有功能
|
||||
version: ${yudao.info.version}
|
||||
tenant: # 多租户相关配置项
|
||||
enable: true
|
||||
enable: false
|
||||
ignore-urls:
|
||||
- /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号
|
||||
- /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号
|
||||
|
|
Loading…
Reference in New Issue