JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本

This commit is contained in:
zhangdaiscott
2021-06-02 15:51:19 +08:00
parent f15855049c
commit a18ffa6b40
120 changed files with 4734 additions and 239599 deletions

View File

@ -0,0 +1,47 @@
package org.jeecg.common.api.desform;
import org.jeecg.common.system.vo.DictModel;
import java.util.List;
import java.util.Map;
/**
* 表单设计器【System】翻译API接口
*
* @author sunjianlei
*/
public interface ISysTranslateAPI {
/**
* 查询分类字典翻译
*/
List<String> categoryLoadDictItem(String ids);
/**
* 根据字典code加载字典text
*
* @param dictCode 顺序tableName,text,code
* @param keys 要查询的key
* @return
*/
List<String> dictLoadDictItem(String dictCode, String keys);
/**
* 获取字典数据
*
* @param dictCode 顺序tableName,text,code
* @param dictCode 要查询的key
* @return
*/
List<DictModel> dictGetDictItems(String dictCode);
/**
* 【JSearchSelectTag下拉搜索组件专用接口】
* 大数据量的字典表 走异步加载 即前端输入内容过滤数据
*
* @param dictCode 字典code格式table,text,code
* @return
*/
List<DictModel> dictLoadDict(String dictCode, String keyword, Integer pageSize);
}

View File

@ -23,6 +23,11 @@ public class MessageDTO implements Serializable {
*/
protected String toUser;
/**
* 发送给所有人
*/
protected boolean toAll;
/**
* 消息主题
*/

View File

@ -1,12 +1,12 @@
package org.jeecg.common.api.vo;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.jeecg.common.constant.CommonConstant;
import lombok.Data;
import org.jeecg.common.constant.CommonConstant;
import java.io.Serializable;
/**
* 接口返回数据格式
@ -112,7 +112,16 @@ public class Result<T> implements Serializable {
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(CommonConstant.SC_INTERNAL_SERVER_ERROR_500);
r.setMessage(msg);
r.setResult(data);
return r;
}
public static Result<Object> error(String msg) {
return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);
}

View File

@ -14,16 +14,15 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.ModuleType;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.IPUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

View File

@ -17,6 +17,7 @@ import org.jeecg.common.constant.CommonConstant;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
@ -38,6 +39,8 @@ public class DictAspect {
@Autowired
private CommonAPI commonAPI;
@Autowired
public RedisTemplate redisTemplate;
// 定义切点Pointcut
@Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..))")
@ -144,12 +147,33 @@ public class DictAspect {
if (k.trim().length() == 0) {
continue; //跳过循环
}
//update-begin--Author:scott -- Date:20210531 ----for !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
if (!StringUtils.isEmpty(table)){
log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
tmpValue= commonAPI.translateDictFromTable(table,text,code,k.trim());
log.info("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim());
if (redisTemplate.hasKey(keyString)){
try {
tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
} catch (Exception e) {
log.warn(e.getMessage());
}
}else {
tmpValue= commonAPI.translateDictFromTable(table,text,code,k.trim());
}
}else {
tmpValue = commonAPI.translateDict(code, k.trim());
String keyString = String.format("sys:cache:dict::%s:%s",code,k.trim());
if (redisTemplate.hasKey(keyString)){
try {
tmpValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
} catch (Exception e) {
log.warn(e.getMessage());
}
}else {
tmpValue = commonAPI.translateDict(code, k.trim());
}
}
//update-end--Author:scott -- Date:20210531 ----for !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
if (tmpValue != null) {
if (!"".equals(textValue.toString())) {
textValue.append(",");

View File

@ -305,4 +305,21 @@ public interface CommonConstant {
* 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用
*/
public final static String THIRD_LOGIN_CODE = "third_login_code";
/**
* 第三方APP同步方向本地 --> 第三方APP
*/
String THIRD_SYNC_TO_APP = "SYNC_TO_APP";
/**
* 第三方APP同步方向第三方APP --> 本地
*/
String THIRD_SYNC_TO_LOCAL = "SYNC_TO_LOCAL";
/** 系统通告消息状态0=未发布 */
String ANNOUNCEMENT_SEND_STATUS_0 = "0";
/** 系统通告消息状态1=已发布 */
String ANNOUNCEMENT_SEND_STATUS_1 = "1";
/** 系统通告消息状态2=已撤销 */
String ANNOUNCEMENT_SEND_STATUS_2 = "2";
}

View File

@ -9,12 +9,14 @@ public interface DataBaseConstant {
public static final String DB_TYPE_DM = "DM";//达梦数据库
public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL";
public static final String DB_TYPE_SQLSERVER = "SQLSERVER";
public static final String DB_TYPE_MARIADB = "MARIADB";
// 数据库类型,对应 database_type 字典
public static final String DB_TYPE_MYSQL_NUM = "1";
public static final String DB_TYPE_ORACLE_NUM = "2";
public static final String DB_TYPE_SQLSERVER_NUM = "3";
public static final String DB_TYPE_POSTGRESQL_NUM = "4";
public static final String DB_TYPE_MARIADB_NUM = "5";
//*********系统上下文变量****************************************
/**
* 数据-所属机构编码
@ -65,6 +67,10 @@ public interface DataBaseConstant {
* 系统时间"yyyy-MM-dd HH:mm"
*/
public static final String SYS_TIME_TABLE = "sys_time";
/**
* 数据-所属机构编码
*/
public static final String SYS_BASE_PATH = "sys_base_path";
//*********系统上下文变量****************************************

View File

@ -221,20 +221,31 @@ public class QueryGenerator {
if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) {
order = parameterMap.get(ORDER_TYPE)[0];
}
log.debug("排序规则>>列:"+column+",排序方式:"+order);
log.info("排序规则>>列:" + column + ",排序方式:" + order);
if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
//字典字段,去掉字典翻译文本后缀
if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
}
//SQL注入check
SqlInjectionUtil.filterContent(column);
SqlInjectionUtil.filterContent(column);
//update-begin--Author:scott Date:20210531 for36 多条件排序无效问题修正-------
// 排序规则修改
// 将现有排序 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1,column2 desc"
// 修改为 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1 desc,column2 desc"
if (order.toUpperCase().indexOf(ORDER_TYPE_ASC)>=0) {
queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
String columnStr = oConvertUtils.camelToUnderline(column);
String[] columnArray = columnStr.split(",");
queryWrapper.orderByAsc(columnArray);
} else {
queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column));
String columnStr = oConvertUtils.camelToUnderline(column);
String[] columnArray = columnStr.split(",");
queryWrapper.orderByDesc(columnArray);
}
//update-end--Author:scott Date:20210531 for36 多条件排序无效问题修正-------
}
}
@ -1073,7 +1084,7 @@ public class QueryGenerator {
* @Return: java.lang.String
*/
private static String specialStrConvert(String value) {
if (DataBaseConstant.DB_TYPE_MYSQL.equals(getDbType())) {
if (DataBaseConstant.DB_TYPE_MYSQL.equals(getDbType()) || DataBaseConstant.DB_TYPE_MARIADB.equals(getDbType())) {
String[] special_str = QueryGenerator.LIKE_MYSQL_SPECIAL_STRS.split(",");
for (String str : special_str) {
if (value.indexOf(str) !=-1) {

View File

@ -6,6 +6,11 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.base.Joiner;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
@ -16,10 +21,6 @@ import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
/**
* @Author Scott
* @Date 2018-07-12 14:23

View File

@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
@ -74,7 +75,8 @@ public class CommonUtils {
fileName = fileName.substring(pos + 1);
}
//替换上传文件名字的特殊字符
fileName = fileName.replace("=","").replace(",","").replace("&","").replace("#", "");
fileName = fileName.replace("=","").replace(",","").replace("&","")
.replace("#", "").replace("", "").replace("", "");
//替换上传文件名字中的空格
fileName=fileName.replaceAll("\\s","");
return fileName;
@ -106,6 +108,44 @@ public class CommonUtils {
}
return url;
}
/**
* 本地文件上传
* @param mf 文件
* @param bizPath 自定义路径
* @return
*/
public static String uploadLocal(MultipartFile mf,String bizPath,String uploadpath){
try {
String fileName = null;
File file = new File(uploadpath + File.separator + bizPath + File.separator );
if (!file.exists()) {
file.mkdirs();// 创建文件根目录
}
String orgName = mf.getOriginalFilename();// 获取文件名
orgName = CommonUtils.getFileName(orgName);
if(orgName.indexOf(".")!=-1){
fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
}else{
fileName = orgName+ "_" + System.currentTimeMillis();
}
String savePath = file.getPath() + File.separator + fileName;
File savefile = new File(savePath);
FileCopyUtils.copy(mf.getBytes(), savefile);
String dbpath = null;
if(oConvertUtils.isNotEmpty(bizPath)){
dbpath = bizPath + File.separator + fileName;
}else{
dbpath = fileName;
}
if (dbpath.contains("\\")) {
dbpath = dbpath.replace("\\", "/");
}
return dbpath;
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return "";
}
/**
* 统一全局上传 带桶
@ -132,7 +172,7 @@ public class CommonUtils {
return getDatabaseTypeByDataSource(dataSource);
} catch (SQLException e) {
//e.printStackTrace();
log.warn(e.getMessage());
log.warn(e.getMessage(),e);
return "";
}
}
@ -157,8 +197,11 @@ public class CommonUtils {
DB_TYPE = DataBaseConstant.DB_TYPE_SQLSERVER;
}else if(dbType.indexOf("postgresql")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_POSTGRESQL;
}else if(dbType.indexOf("mariadb")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_MARIADB;
}else {
throw new JeecgBootException("数据库类型:["+dbType+"]不识别!");
log.error("数据库类型:[" + dbType + "]不识别!");
//throw new JeecgBootException("数据库类型:["+dbType+"]不识别!");
}
} catch (Exception e) {
log.error(e.getMessage(), e);

View File

@ -75,7 +75,11 @@ public class MinioUtil {
orgName=file.getName();
}
orgName = CommonUtils.getFileName(orgName);
String objectName = bizPath+"/"+orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
String objectName = bizPath+"/"
+( orgName.indexOf(".")==-1
?orgName + "_" + System.currentTimeMillis()
:orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."))
);
// 使用putObject上传一个本地文件到存储桶中。
if(objectName.startsWith("/")){

View File

@ -13,6 +13,7 @@ import java.util.Map;
public class SqlUtils {
public static final String DATABSE_TYPE_MYSQL = "mysql";
public static final String DATABSE_TYPE_MARIADB = "mariadb";
public static final String DATABSE_TYPE_POSTGRE = "postgresql";
public static final String DATABSE_TYPE_ORACLE = "oracle";
public static final String DATABSE_TYPE_SQLSERVER = "sqlserver";
@ -47,7 +48,7 @@ public class SqlUtils {
*/
public static boolean dbTypeIsMySQL(String dbType) {
return dbTypeIf(dbType, DATABSE_TYPE_MYSQL, DataBaseConstant.DB_TYPE_MYSQL_NUM);
return dbTypeIf(dbType, DATABSE_TYPE_MYSQL, DataBaseConstant.DB_TYPE_MYSQL_NUM) || dbTypeIf(dbType, DATABSE_TYPE_MARIADB, DataBaseConstant.DB_TYPE_MARIADB_NUM);
}
public static boolean dbTypeIsOracle(String dbType) {

View File

@ -111,7 +111,9 @@ public class OssBootUtil {
orgName=file.getName();
}
orgName = CommonUtils.getFileName(orgName);
String fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
String fileName = orgName.indexOf(".")==-1
?orgName + "_" + System.currentTimeMillis()
:orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
if (!fileDir.endsWith("/")) {
fileDir = fileDir.concat("/");
}

View File

@ -23,7 +23,7 @@ import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
import java.util.ArrayList;
import java.util.Collections;
@ -33,7 +33,7 @@ import java.util.List;
* @Author scott
*/
@Configuration
@EnableSwagger2
@EnableSwagger2WebMvc
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class Swagger2Config implements WebMvcConfigurer {

View File

@ -19,7 +19,7 @@ public class OssConfiguration {
private String accessKeySecret;
@Value("${jeecg.oss.bucketName}")
private String bucketName;
@Value("${jeecg.oss.staticDomain}")
@Value("${jeecg.oss.staticDomain:}")
private String staticDomain;

View File

@ -1,6 +1,7 @@
package org.jeecg.config.shiro;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
@ -110,6 +111,11 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
// update-begin--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP
filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon");
// update-end--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP
//积木报表排除
filterChainDefinitionMap.put("/jmreport/**", "anon");
filterChainDefinitionMap.put("/**/*.js.map", "anon");
@ -127,7 +133,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
filterChainDefinitionMap.put("/eoaSocket/**","anon");//我的聊天
//性能监控 TODO 存在安全漏洞泄露TOEKNdurid连接池也有
filterChainDefinitionMap.put("/actuator/**", "anon");
@ -241,8 +247,17 @@ public class ShiroConfig {
RedisClusterManager redisManager = new RedisClusterManager();
Set<HostAndPort> portSet = new HashSet<>();
lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort())));
JedisCluster jedisCluster = new JedisCluster(portSet);
redisManager.setJedisCluster(jedisCluster);
//update-begin--Author:scott Date:20210531 for修改集群模式下未设置redis密码的bug issues/I3QNIC
if (oConvertUtils.isNotEmpty(lettuceConnectionFactory.getPassword())) {
JedisCluster jedisCluster = new JedisCluster(portSet, 2000, 2000, 5,
lettuceConnectionFactory.getPassword(), new GenericObjectPoolConfig());
redisManager.setPassword(lettuceConnectionFactory.getPassword());
redisManager.setJedisCluster(jedisCluster);
} else {
JedisCluster jedisCluster = new JedisCluster(portSet);
redisManager.setJedisCluster(jedisCluster);
}
//update-end--Author:scott Date:20210531 for修改集群模式下未设置redis密码的bug issues/I3QNIC
manager = redisManager;
}
return manager;

View File

@ -0,0 +1,79 @@
package org.jeecg.config.thirdapp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 第三方App对接配置
*/
@Configuration
public class ThirdAppConfig {
/**
* 钉钉
*/
public final static String DINGTALK = "DINGTALK";
/**
* 企业微信
*/
public final static String WECHAT_ENTERPRISE = "WECHAT_ENTERPRISE";
/**
* 是否启用 第三方App对接
*/
@Value("${third-app.enabled:false}")
private boolean enabled;
/**
* 系统类型目前支持WECHAT_ENTERPRISE企业微信DINGTALK (钉钉)
*/
@Autowired
private ThirdAppTypeConfig type;
public boolean isEnabled() {
return enabled;
}
public ThirdAppConfig setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}
/**
* 获取企业微信配置
*/
public ThirdAppTypeItemVo getWechatEnterprise() {
return this.type.getWECHAT_ENTERPRISE();
}
/**
* 获取钉钉配置
*/
public ThirdAppTypeItemVo getDingtalk() {
return this.type.getDINGTALK();
}
/**
* 获取企业微信是否启用
*/
public boolean isWechatEnterpriseEnabled() {
try {
return this.enabled && this.getWechatEnterprise().isEnabled();
} catch (Exception e) {
return false;
}
}
/**
* 获取钉钉是否启用
*/
public boolean isDingtalkEnabled() {
try {
return this.enabled && this.getDingtalk().isEnabled();
} catch (Exception e) {
return false;
}
}
}

View File

@ -0,0 +1,26 @@
package org.jeecg.config.thirdapp;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 第三方APP配置
*
* @author sunjianlei
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "third-app.type")
public class ThirdAppTypeConfig {
/**
* 对应企业微信配置
*/
private ThirdAppTypeItemVo WECHAT_ENTERPRISE;
/**
* 对应钉钉配置
*/
private ThirdAppTypeItemVo DINGTALK;
}

View File

@ -0,0 +1,36 @@
package org.jeecg.config.thirdapp;
import lombok.Data;
/**
* 第三方App对接
*/
@Data
public class ThirdAppTypeItemVo {
/**
* 是否启用
*/
private boolean enabled;
/**
* 应用Key
*/
private String clientId;
/**
* 应用Secret
*/
private String clientSecret;
/**
* 应用ID
*/
private String agentId;
/**
* 目前仅企业微信用到自建应用Secret
*/
private String agentAppSecret;
public int getAgentIdInt() {
return Integer.parseInt(agentId);
}
}