@@ -41,7 +41,7 @@ public class FileDownloadController { | |||
@RequestParam(value = "absolutePath", required = false) Boolean absolutePath, | |||
HttpServletRequest request | |||
) throws FileNotFoundException { | |||
String filePath = request.getRequestURI().substring(10); | |||
String filePath = request.getServletPath().substring(10); | |||
return download(filePath, name, noCache,absolutePath, request); | |||
} | |||
@@ -91,7 +91,7 @@ public class FileDownloadController { | |||
@RequestParam(value = "noCache", required = false) Boolean noCache, | |||
@RequestHeader(value = "If-Modified-Since", required = false) String ifModifiedSince, | |||
HttpServletRequest request) throws FileNotFoundException { | |||
String filePath = request.getRequestURI().substring(11); | |||
String filePath = request.getServletPath().substring(11); | |||
HttpHeaders headers = new HttpHeaders(); | |||
@@ -12,5 +12,9 @@ public interface BpmConst { | |||
interface DataRight { | |||
public final static Long CUR_VALUE = 999L;//本机构,本部门 | |||
public final static Long ALL_DEPT = 998L;//全部门权限 | |||
public final static int V_SELF = 0;//本级 | |||
public final static int V_INCLUDE_CHILDREN = 1;//含下级 | |||
public final static int V_INCLUDE = 0;//包含 | |||
public final static int V_EXCEPT = 1;//排除 | |||
} | |||
} |
@@ -29,6 +29,8 @@ public interface BpmEnum { | |||
public static MenuFuncRight instance = new MenuFuncRight(); | |||
public static StrEnumBean READ = instance.addEnum("read", "查看"); | |||
public static StrEnumBean WRITE = instance.addEnum("write", "修改"); | |||
public static StrEnumBean EXPORT = instance.addEnum("export", "导出"); | |||
public static StrEnumBean AUDIT = instance.addEnum("audit", "审核"); | |||
} | |||
class UserStatu extends IntEnum { | |||
@@ -12,11 +12,17 @@ import cc.smtweb.framework.core.db.vo.ModelTable; | |||
import cc.smtweb.framework.core.exception.BizException; | |||
import cc.smtweb.framework.core.exception.SwException; | |||
import cc.smtweb.framework.core.mvc.service.SqlNamedPara; | |||
import cc.smtweb.framework.core.mvc.service.TreeHelper; | |||
import cc.smtweb.framework.core.util.MapUtil; | |||
import cc.smtweb.framework.core.util.NumberUtil; | |||
import cc.smtweb.framework.core.util.SqlUtil; | |||
import cc.smtweb.framework.core.util.StringUtil; | |||
import cc.smtweb.system.bpm.web.design.form.define.*; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRight.DataRightDefine; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRight.DataRightDefineCache; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.IDataRightHandler; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.IDataRightTreeFactory; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.springframework.lang.NonNull; | |||
@@ -31,6 +37,7 @@ import static cc.smtweb.framework.core.common.SwConsts.TOTAL_KEY; | |||
* Created by Akmm at 2022/4/23 10:01 | |||
* 动态页面辅助类 | |||
*/ | |||
@Slf4j | |||
public class DynPageHelper { | |||
/** | |||
* 新建bean | |||
@@ -137,29 +144,50 @@ public class DynPageHelper { | |||
buildSelectSql(dataSet, params, sqlNamedPara, null); | |||
return sqlNamedPara; | |||
} | |||
private static Map<String, IBuilderExpr> mapBuilder; | |||
private static IBuilderExpr baseBuilder; | |||
static { | |||
baseBuilder = (opt, field, name, value, args, filter) -> { | |||
args.put(name, value); | |||
return field + " " + opt + " :" + name; | |||
}; | |||
mapBuilder = new HashMap<>(); | |||
mapBuilder.put(SwEnum.OptType.LIKE.value, (opt, field, name, value, args, filter) -> { | |||
args.put(name, "%" + value + "%"); | |||
return field + " like :" + name; | |||
}); | |||
/** | |||
* 构建合计栏sql | |||
* | |||
* @param dataSet | |||
* @param params | |||
* @return | |||
*/ | |||
public static SqlNamedPara buildSumSql(PageDataset dataSet, @NonNull SqlNamedPara sqlNamedPara) { | |||
StringBuilder sql = new StringBuilder(256); | |||
sql.append("select count(1) " + TOTAL_KEY); | |||
for (PageDatasetField field : dataSet.fields) { | |||
if (StringUtils.isEmpty(field.summary)) continue; | |||
if (field.fieldIsCalc()) continue; | |||
sql.append(","); | |||
if (!SwEnum.SummaryType.instance.isText(field.summary)) { | |||
sql.append(field.summary).append("(").append(field.name).append(") ").append(field.name); | |||
} else { | |||
sql.append("'").append(field.summary).append("' ").append(field.name); | |||
mapBuilder.put(SwEnum.OptType.PLIKE.value, (opt, field, name, value, args, filter) -> { | |||
args.put(name, value + "%"); | |||
return field + " like :" + name; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.BT.value, (opt, field, name, value, args, filter) -> { | |||
String[] ss = value.toString().split(","); | |||
if (ss.length != 2) throw new BizException("介于条件,参数值个数错误!"); | |||
args.put(name + "_1", ss[0]); | |||
args.put(name + "_2", ss[1]); | |||
return "(" + field + ">=:" + name + "_1 and " + field + "<=:" + name + "_2)"; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.IN.value, (opt, field, name, value, args, filter) -> { | |||
if (StringUtil.isEmpty(value.toString())) return ""; | |||
args.put(name, value); | |||
return field + " in (:" + name + ") "; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.NOT_IN.value, (opt, field, name, value, args, filter) -> { | |||
if (StringUtil.isEmpty(value.toString())) return ""; | |||
args.put(name, value); | |||
return field + " not in (:" + name + ") "; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.IN_CHILD.value, (opt, field, name, value, args, filter) -> { | |||
ModelTable table = ModelTableCache.getInstance().get(filter.link); | |||
if(table==null){ | |||
return ""; | |||
} | |||
} | |||
sqlNamedPara.sql = sql.toString() + " from (" + sqlNamedPara.sql + ") xxxxa"; | |||
return sqlNamedPara; | |||
return TreeHelper.getTreeHelper(table.getName()).buildLikeFrSql(Long.parseLong(value.toString()),field); | |||
}); | |||
} | |||
private static String buildSelFieldsSql(PageDataset dataSet, SqlNamedPara sqlNamedPara, IBuildSqlListener listener) { | |||
@@ -189,6 +217,30 @@ public class DynPageHelper { | |||
} | |||
/** | |||
* 构建合计栏sql | |||
* | |||
* @param dataSet | |||
* @param sqlNamedPara | |||
* @return | |||
*/ | |||
public static SqlNamedPara buildSumSql(PageDataset dataSet, @NonNull SqlNamedPara sqlNamedPara) { | |||
StringBuilder sql = new StringBuilder(256); | |||
sql.append("select count(1) " + TOTAL_KEY); | |||
for (PageDatasetField field : dataSet.fields) { | |||
if (StringUtils.isEmpty(field.summary)) continue; | |||
if (field.fieldIsCalc()) continue; | |||
sql.append(","); | |||
if (!SwEnum.SummaryType.instance.isText(field.summary)) { | |||
sql.append(field.summary).append("(").append(field.name).append(") ").append(field.name); | |||
} else { | |||
sql.append("'").append(field.summary).append("' ").append(field.name); | |||
} | |||
} | |||
sqlNamedPara.sql = sql.toString() + " from (" + sqlNamedPara.sql + ") xxxxa"; | |||
return sqlNamedPara; | |||
} | |||
/** | |||
* 构建where条件:组合固定和动态条件 | |||
* | |||
* @param dataSet | |||
@@ -218,6 +270,12 @@ public class DynPageHelper { | |||
args.put(s, MapUtil.readString(params, s, "")); | |||
} | |||
if (listener != null) listener.buildWhere(dataSet, sql, args); | |||
// 设置固定条件数据权限 | |||
for (PageDatasetFilter filter : dataSet.filters) { | |||
if(!setFixedFilter.contains(filter.name))break; | |||
if(filter.dataRightType<=0L)break; | |||
buildDataRight(filter.dataRightType,filter.sqlName,MapUtil.readString(params, filter.name, ""),sql,args); | |||
} | |||
return new SqlNamedPara(sql.toString(), args); | |||
} | |||
@@ -265,6 +323,11 @@ public class DynPageHelper { | |||
value = params.get(filter.name); | |||
} | |||
if (value == null || StringUtils.isEmpty(value.toString())) { | |||
if(filter.dataRightType>0L){ | |||
StringBuilder frSql = new StringBuilder(); | |||
buildDataRight(filter.dataRightType,filter.sqlName,value.toString(),frSql,args); | |||
return frSql.toString(); | |||
} | |||
if (filter.required) { | |||
throw new BizException("过滤条件不能为空(" + filter.name + ")!"); | |||
} | |||
@@ -272,9 +335,21 @@ public class DynPageHelper { | |||
} | |||
IBuilderExpr builder = getBuilder(dynCond.opt); | |||
String ns = isNameSelf ? filter.name: filter.name + "_" + dynCond.hashCode(); | |||
return builder.build(dynCond.opt, filter.sqlName, ns, value, args); | |||
String optWhere = builder.build(dynCond.opt, filter.sqlName, ns, value, args,filter); | |||
// 添加数据权限 | |||
if(filter.dataRightType>0L){ | |||
StringBuilder frSql = new StringBuilder(); | |||
buildDataRight(filter.dataRightType,filter.sqlName,value.toString(),frSql,args); | |||
if(frSql.length()>0){ | |||
if(StringUtil.isEmpty(optWhere)){ | |||
optWhere = frSql.toString(); | |||
}else { | |||
optWhere+= " and "+ frSql.toString(); | |||
} | |||
} | |||
} | |||
return optWhere; | |||
} | |||
/** | |||
* 处理计算字段 | |||
* | |||
@@ -289,44 +364,24 @@ public class DynPageHelper { | |||
} | |||
} | |||
private static Map<String, IBuilderExpr> mapBuilder; | |||
private static IBuilderExpr baseBuilder; | |||
static { | |||
baseBuilder = (opt, field, name, value, args) -> { | |||
args.put(name, value); | |||
return field + " " + opt + " :" + name; | |||
}; | |||
mapBuilder = new HashMap<>(); | |||
mapBuilder.put(SwEnum.OptType.LIKE.value, (opt, field, name, value, args) -> { | |||
args.put(name, "%" + value + "%"); | |||
return field + " like :" + name; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.PLIKE.value, (opt, field, name, value, args) -> { | |||
args.put(name, value + "%"); | |||
return field + " like :" + name; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.BT.value, (opt, field, name, value, args) -> { | |||
String[] ss = value.toString().split(","); | |||
if (ss.length != 2) throw new BizException("介于条件,参数值个数错误!"); | |||
args.put(name + "_1", ss[0]); | |||
args.put(name + "_2", ss[1]); | |||
return "(" + field + ">=:" + name + "_1 and " + field + "<=:" + name + "_2)"; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.IN.value, (opt, field, name, value, args) -> { | |||
if (StringUtil.isEmpty(value.toString())) return ""; | |||
args.put(name, value); | |||
return field + " in (:" + name + ") "; | |||
}); | |||
mapBuilder.put(SwEnum.OptType.NOT_IN.value, (opt, field, name, value, args) -> { | |||
if (StringUtil.isEmpty(value.toString())) return ""; | |||
args.put(name, value); | |||
return field + " not in (:" + name + ") "; | |||
}); | |||
/** | |||
* 构建数据权限 | |||
* @param dsType 数据权限定义ID | |||
* @param sqlField sql字段名 | |||
* @param value 值 | |||
* @param sql sql语句 | |||
* @param args 参数 | |||
*/ | |||
private static void buildDataRight(long dsType,String sqlField,String value,StringBuilder sql,SwMap args){ | |||
DataRightDefine drd = DataRightDefineCache.getInstance().get(dsType); | |||
if(drd==null){return;} | |||
try{ | |||
IDataRightHandler dataRightHandler = IDataRightTreeFactory.getInstance().getHandler(drd.getCode()); | |||
dataRightHandler.buildSqlWhere(true,sqlField,value,sql,args); | |||
}catch (Exception e){ | |||
log.error("加载数据权限失败:",e); | |||
throw new SwException(e); | |||
} | |||
} | |||
private static IBuilderExpr getBuilder(String opt) { | |||
@@ -335,7 +390,7 @@ public class DynPageHelper { | |||
} | |||
interface IBuilderExpr { | |||
String build(String opt, String field, String name, Object value, Map<String, Object> args); | |||
String build(String opt, String field, String name, Object value, Map<String, Object> args,PageDatasetFilter filter); | |||
} | |||
} |
@@ -28,6 +28,8 @@ public class FlowModelService extends LCSingleService { | |||
return new FlowModelSaveHandler<>(); | |||
case TYPE_MODEL_DEL: | |||
return new FlowModelDelHandler(); | |||
case TYPE_FLOW: | |||
return new FlowTransHandler(); | |||
} | |||
return super.createHandler(type); | |||
} | |||
@@ -25,6 +25,7 @@ public class FlowLcLc1Service extends FlowModelService { | |||
case TYPE_MODEL_LOAD: | |||
case TYPE_MODEL_SAVE: | |||
case TYPE_MODEL_DEL: | |||
case TYPE_FLOW: | |||
return super.createHandler(type); | |||
} | |||
return worker.createHandler(type); | |||
@@ -22,6 +22,7 @@ public class FlowLcMsService extends FlowModelService { | |||
switch (type) { | |||
case TYPE_MODEL_LIST: | |||
case TYPE_MODEL_LOAD: | |||
case TYPE_FLOW: | |||
return super.createHandler(type); | |||
case TYPE_MODEL_SAVE: | |||
return new FlowLcMsSaveHandler(); | |||
@@ -61,6 +61,7 @@ public class AuthService { | |||
User user = UserCache.getInstance().get(mappingUserRet.getUserId()); | |||
if(user==null){ | |||
data.put("isOk", false); | |||
data.put("extra", mappingUserRet.getExtra()); | |||
data.put("msg", "映射登录失败!"); | |||
return R.success(data); | |||
} | |||
@@ -1,5 +1,6 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.dataRightGroup; | |||
import cc.smtweb.framework.core.common.SwConsts; | |||
import cc.smtweb.framework.core.common.SwMap; | |||
import cc.smtweb.framework.core.session.UserSession; | |||
import cc.smtweb.framework.core.util.StringUtil; | |||
@@ -12,7 +13,7 @@ import java.util.Map; | |||
* 数据权限计算处理抽象类 | |||
*/ | |||
public abstract class AbsTreeDataRightHandler implements IDataRightHandler{ | |||
protected final static String menuIdKey = "_menuId"; | |||
protected final static String KEY_HEADER_MENU = "hmk"; | |||
//权限查找结果常量定义 | |||
protected final static int RIGHT_RET_NONE = 0; //未找到 | |||
protected final static int RIGHT_RET_IN_CHILD = 1;//找到,包含,且含下级 | |||
@@ -35,11 +36,16 @@ public abstract class AbsTreeDataRightHandler implements IDataRightHandler{ | |||
} | |||
@Override | |||
public void init(UserSession us,SwMap params) { | |||
this.isByRight = true; | |||
this.us = us; | |||
this.params = params; | |||
String menuId = params.readString("_menuId"); | |||
// 获取header中的菜单ID | |||
SwMap header = params.readMap(SwConsts.PARAMS_HEADER_KEY); | |||
long menuId = 0L; | |||
if(header!=null){ | |||
menuId = header.readLong(KEY_HEADER_MENU); | |||
} | |||
if (us == null) return; | |||
this.isByRight = true; | |||
mapRight = DataRightHelper.getDataRightItemMap(getDataRightType(), menuId, us); | |||
if (mapRight == null) return; | |||
//将本单位处理下 | |||
@@ -2,6 +2,12 @@ package cc.smtweb.system.bpm.web.sys.user.dataRightGroup; | |||
import cc.smtweb.framework.core.annotation.SwTable; | |||
import cc.smtweb.framework.core.db.impl.DefaultEntity; | |||
import cc.smtweb.framework.core.util.CommUtil; | |||
import cc.smtweb.framework.core.util.JsonUtil; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
/** | |||
* Created by 1 at 2022-08-04 17:45:35 | |||
@@ -98,4 +104,18 @@ public class DataRightGroup extends DefaultEntity { | |||
public void setSdrdId(long sdrg_sdrd_id) { | |||
put("sdrg_sdrd_id", sdrg_sdrd_id); | |||
} | |||
// 获取权限明细集合 | |||
public List<DataRightGroupItem> getDataRightItemList(){ | |||
List<DataRightGroupItem> rtList = new ArrayList<>(); | |||
List<Map<String, Object>> listItem = data.readListMap("sdrg_content"); | |||
if(!CommUtil.isEmpty(listItem)){ | |||
listItem.forEach(map-> { | |||
DataRightGroupItem item = JsonUtil.parse(map,DataRightGroupItem.class); | |||
if(item!=null){ | |||
rtList.add(item); | |||
} | |||
}); | |||
} | |||
return rtList; | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.dataRightGroup; | |||
import cc.smtweb.framework.core.db.impl.BaseBean; | |||
import cc.smtweb.system.bpm.web.common.BpmConst; | |||
/** | |||
* @Author: tanghp | |||
@@ -31,4 +32,8 @@ public class DataRightGroupItem extends BaseBean { | |||
public void setType(int type) { | |||
put("type",type); | |||
} | |||
// 包含 | |||
public boolean isInclude(){ | |||
return getKind() == BpmConst.DataRight.V_INCLUDE; | |||
} | |||
} |
@@ -1,8 +1,13 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.dataRightGroup; | |||
import cc.smtweb.framework.core.session.UserSession; | |||
import cc.smtweb.system.bpm.web.common.BpmConst; | |||
import cc.smtweb.system.bpm.web.sys.user.role.RoleHelper; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
/** | |||
* @Author: tanghp | |||
@@ -18,7 +23,30 @@ public class DataRightHelper { | |||
* @param us 用户session | |||
* @return | |||
*/ | |||
public static Map<String,DataRightGroupItem> getDataRightItemMap(String dType, String menuId, UserSession us ){ | |||
return null; | |||
public static Map<String,DataRightGroupItem> getDataRightItemMap(String dType, long menuId, UserSession us ){ | |||
Set<DataRightGroup> setGroup = RoleHelper.getDataRightGroup(us.getUserId(), us.getPartyId(), menuId,dType); | |||
//以value作为key | |||
Map<String, DataRightGroupItem> map = new HashMap<>(); | |||
for (DataRightGroup group : setGroup) { | |||
List<DataRightGroupItem> items = group.getDataRightItemList(); | |||
for (DataRightGroupItem item : items) { | |||
if (!map.containsKey(item.getValue())) { | |||
map.put(item.getValue(), item); | |||
} | |||
DataRightGroupItem i = map.get(item.getValue()); | |||
if ((!i.isInclude() && item.isInclude()) || (i.isInclude() == item.isInclude() && item.getType() == BpmConst.DataRight.V_INCLUDE_CHILDREN)) { | |||
map.put(item.getValue(), item); | |||
} | |||
} | |||
} | |||
// 如果没有配置数据权限,默认设置个本级及下级 | |||
if(map.size()==0){ | |||
DataRightGroupItem drgi = new DataRightGroupItem(); | |||
drgi.setKind(BpmConst.DataRight.V_INCLUDE); | |||
drgi.setType(BpmConst.DataRight.V_INCLUDE_CHILDREN); | |||
drgi.setValue(BpmConst.DataRight.CUR_VALUE.toString()); | |||
map.put(drgi.getValue(),drgi); | |||
} | |||
return map; | |||
} | |||
} |
@@ -12,5 +12,5 @@ import java.util.List; | |||
public interface IDataRightHandler { | |||
void init(UserSession us,SwMap params); | |||
//构建sql | |||
boolean buildSqlWhere(boolean where, String sqlField, String value, StringBuilder sql, List<Object> args); | |||
boolean buildSqlWhere(boolean where, String sqlField, String value, StringBuilder sql, SwMap args); | |||
} |
@@ -3,6 +3,7 @@ package cc.smtweb.system.bpm.web.sys.user.dataRightGroup; | |||
import cc.smtweb.framework.core.exception.SwException; | |||
import cc.smtweb.system.bpm.web.common.BpmEnum; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.impl.DeptDataRightTreeWork; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.impl.PartyDataRightHandler; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.impl.PartyDataRightTreeWork; | |||
import java.util.HashMap; | |||
@@ -27,11 +28,13 @@ public class IDataRightTreeFactory { | |||
} | |||
private Map<String, Class<? extends IDataRightTreeWorker>> mapWorks; | |||
private Map<String, Class<? extends IDataRightHandler>> mapHandlers; | |||
private IDataRightTreeFactory() { | |||
mapWorks = new HashMap<>(); | |||
mapHandlers = new HashMap<>(); | |||
mapWorks.put(BpmEnum.DataRightType.PARTY.value, PartyDataRightTreeWork.class); | |||
mapHandlers.put(BpmEnum.DataRightType.PARTY.value, PartyDataRightHandler.class); | |||
mapWorks.put(BpmEnum.DataRightType.DEPT.value, DeptDataRightTreeWork.class); | |||
} | |||
@@ -40,4 +43,9 @@ public class IDataRightTreeFactory { | |||
if (cls == null) throw new SwException("暂不支持[" + key + "]类型权限!"); | |||
return cls.newInstance(); | |||
} | |||
public IDataRightHandler getHandler(String key) throws Exception { | |||
Class<? extends IDataRightHandler> cls = mapHandlers.get(key); | |||
if (cls == null) throw new SwException("暂不支持[" + key + "]类型权限!"); | |||
return cls.newInstance(); | |||
} | |||
} |
@@ -1,13 +1,24 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.dataRightGroup.impl; | |||
import cc.smtweb.framework.core.common.SwConsts; | |||
import cc.smtweb.framework.core.common.SwMap; | |||
import cc.smtweb.framework.core.db.EntityHelper; | |||
import cc.smtweb.framework.core.util.CommUtil; | |||
import cc.smtweb.system.bpm.web.common.BpmConst; | |||
import cc.smtweb.system.bpm.web.common.BpmEnum; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.AbsTreeDataRightHandler; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.DataRightGroupItem; | |||
import cc.smtweb.system.bpm.web.sys.user.party.Party; | |||
import cc.smtweb.system.bpm.web.sys.user.party.PartyCache; | |||
import java.util.*; | |||
import java.util.HashSet; | |||
import java.util.Random; | |||
import java.util.Set; | |||
/** | |||
* @Author: tanghp | |||
* @Date: 2022-09-22 15:17 | |||
* @Desc: | |||
* @Desc: 单位数据权限 | |||
*/ | |||
public class PartyDataRightHandler extends AbsTreeDataRightHandler { | |||
@Override | |||
@@ -18,11 +29,225 @@ public class PartyDataRightHandler extends AbsTreeDataRightHandler { | |||
@Override | |||
protected String getDataRightType() { | |||
return "partyId"; | |||
return BpmEnum.DataRightType.PARTY.value; | |||
} | |||
@Override | |||
public boolean buildSqlWhere(boolean where, String sqlField, String value, StringBuilder sql, List<Object> args) { | |||
public boolean buildSqlWhere(boolean where, String sqlField, String value, StringBuilder sql, SwMap args) { | |||
return false; | |||
} | |||
/** | |||
* 根据菜单数据权限,找有权限的顶级机构列表 | |||
* | |||
* @return | |||
*/ | |||
public Set<Party> getTopList() { | |||
if (!isByRight || mapRight == null) { //不控制权限,直接取吧 | |||
return PartyCache.getInstance().getChildren(SwConsts.DEF_ROOT_ID_LONG); | |||
} | |||
Set<Party> list = new HashSet<>(); | |||
if (mapRight.isEmpty()) return list; | |||
Set<String> setExists = new HashSet<>(); | |||
for (DataRightGroupItem item : mapRight.values()) { | |||
if (!item.isInclude()) continue; //不包含的对象,这里是计算根节点,不管就是了 | |||
//本单位之类的已处理 | |||
Party party = PartyCache.getInstance().get(item.getValue()); | |||
if (party == null) continue; | |||
boolean isParentExists = false; | |||
//添加节点,注意:如果是已经添加了的单位的下级,则不要添加 | |||
String[] pids = party.getLevelCode().split(SwConsts.SPLIT_CHAR); | |||
for (String pid : pids) { | |||
if (setExists.contains(pid)) { | |||
isParentExists = true; | |||
break; | |||
} | |||
} | |||
if (!isParentExists) { | |||
list.add(party); | |||
setExists.add(String.valueOf(party.getEntityId())); | |||
} | |||
} | |||
return list; | |||
} | |||
/** | |||
* 获取下级节点 | |||
* | |||
* @param parentId 上级机构id | |||
* @return | |||
*/ | |||
public Set<Party> getChildren(long parentId) { | |||
Set<Party> children = PartyCache.getInstance().getChildren(parentId); | |||
if (!isByRight || mapRight == null || CommUtil.isEmpty(children)) { //不控制权限,直接取吧 | |||
return children; | |||
} | |||
if (mapRight.isEmpty()) return null; | |||
children.removeIf(party -> !hasRight(party)); | |||
return children; | |||
} | |||
/** | |||
* 是否拥有此单位权限 | |||
* | |||
* @param party | |||
* @return | |||
*/ | |||
private boolean hasRight(Party party) { | |||
int nret = hasRight(party.getEntityId()); | |||
if (nret != RIGHT_RET_NONE) return nret != RIGHT_RET_EX; | |||
String[] pids = party.getLevelCode().split(SwConsts.SPLIT_CHAR); | |||
for (String pid : pids) { | |||
nret = hasRight(Long.parseLong(pid)); | |||
if (nret == RIGHT_RET_IN_CHILD) return true; | |||
if (nret == RIGHT_RET_IN_NOCHILD || nret == RIGHT_RET_EX) return false; | |||
} | |||
return false; | |||
} | |||
private int hasRight(long id) { | |||
if (mapRight == null || !mapRight.containsKey(String.valueOf(id))) return RIGHT_RET_NONE; | |||
DataRightGroupItem item = mapRight.get(String.valueOf(id)); | |||
if (item.isInclude()) { | |||
if (item.getType()== BpmConst.DataRight.V_INCLUDE_CHILDREN) return RIGHT_RET_IN_CHILD; | |||
return RIGHT_RET_IN_NOCHILD; | |||
} | |||
if (!item.isInclude()) return RIGHT_RET_EX; | |||
return 0; | |||
} | |||
/** | |||
* 判断childId是否是parentId的子孙 | |||
* | |||
* @param childId | |||
* @param parentId | |||
* @return | |||
*/ | |||
public boolean isChild(long childId, long parentId) { | |||
if (parentId<=0L) return true; | |||
Party party = PartyCache.getInstance().get(childId); | |||
if (party == null) return false; | |||
String parentIdStr = SwConsts.SPLIT_CHAR+parentId+SwConsts.SPLIT_CHAR; | |||
return (party.getLevelCode() + SwConsts.SPLIT_CHAR).contains(parentIdStr); | |||
} | |||
/** | |||
* 获取查询语句,使用子查询的方式,数据权限越复杂,构建的语句就越复杂 | |||
* | |||
* @param where 是否带的有where了,确定是where还是and | |||
* @param sqlField 查询的表的单位字段 | |||
* @param partyId 查询条件机构的值,可以为空 | |||
* @param qnext 是否带下级 注意:此方法仅单位管理使用。 | |||
* @param includeSelf 是否包含自己 | |||
* @param sql sql | |||
* @param args 参数 | |||
*/ | |||
public boolean buildSqlWhere(boolean where, String sqlField, long partyId, boolean qnext, | |||
boolean includeSelf, StringBuilder sql, SwMap args) { | |||
if (partyId>0L) {//前端页面传入了单位id | |||
Party party = PartyCache.getInstance().get(partyId); | |||
if (isByRight&&party==null) { | |||
if (where) sql.append(" and "); | |||
else sql.append(" where "); | |||
sql.append(" 1 <> 1 "); | |||
return true; | |||
} | |||
if (party != null) {//单位不存在,则默认查所有,押后 | |||
int nret = hasRight(partyId); | |||
if (nret == RIGHT_RET_IN_NOCHILD) {//不包含下级,则直接等于即可 | |||
if (where) sql.append(" and "); | |||
else sql.append(" where "); | |||
sql.append(" ").append(sqlField).append(" =:_dr_partyId "); | |||
args.put("_dr_partyId",partyId); | |||
return true; | |||
} | |||
if (nret == RIGHT_RET_EX) {//不包含,直接用顶级单位的id来筛选,应该是无数据返回 | |||
if (where) sql.append(" and "); | |||
else sql.append(" where "); | |||
sql.append(" 1 <> 1 "); | |||
return true; | |||
} | |||
} else { | |||
partyId = SwConsts.DEF_ROOT_ID_LONG; | |||
} | |||
} | |||
StringBuilder sqlAnd = new StringBuilder(128); | |||
StringBuilder sqlOr = new StringBuilder(128); | |||
addPartySql(partyId, true, true, qnext, includeSelf, sqlAnd, sqlOr, args); | |||
if (mapRight != null) { | |||
for (DataRightGroupItem item : mapRight.values()) { | |||
long itemPartyId = Long.parseLong(item.getValue()); | |||
if (item.getValue().equalsIgnoreCase(String.valueOf(partyId))) continue; | |||
if (!isChild(itemPartyId, partyId)) continue; //非指定partyId的下级,不用搭理 | |||
addPartySql(itemPartyId, item.isInclude(), item.getType() == BpmConst.DataRight.V_INCLUDE_CHILDREN, true, true, sqlAnd, sqlOr, args); | |||
} | |||
} | |||
if (sqlAnd.length() == 0 && sqlOr.length() == 0) { | |||
return where; | |||
} | |||
if (where) sql.append(" and "); | |||
else sql.append(" where "); | |||
if (sqlOr.length() > 0) { | |||
sql.append("\nEXISTS(\n" + | |||
" SELECT pt_id FROM " + EntityHelper.getSchemaTableName(Party.ENTITY_NAME) + " r2 WHERE r2.party_id=" + sqlField); | |||
sql.append(" and (").append(sqlOr.substring(4)).append("))"); | |||
return true; | |||
} | |||
if (sqlAnd.length() > 0) { | |||
sql.append("\nand not EXISTS(\n" + | |||
" SELECT pt_id FROM " + EntityHelper.getSchemaTableName(Party.ENTITY_NAME)+ " r2 WHERE r2.party_id=" + sqlField); | |||
sql.append(" and (").append(sqlAnd.substring(4)).append("))"); | |||
return true; | |||
} | |||
return false; | |||
} | |||
private void addPartySql(long partyId, boolean isInclude, boolean hasChild, boolean qnext, boolean includeSelf, StringBuilder sqlAnd, StringBuilder sqlOr, SwMap args) { | |||
if (partyId<=0L) return; | |||
if (!hasChild && isInclude) {//不包含下级 | |||
String p = String.format("_dr_pt_id_%s", new Random().nextInt(10)); | |||
sqlOr.append(String.format(" or r2.pt_id=:%s",p)); | |||
args.put(p,partyId); | |||
return; | |||
} | |||
Party party = PartyCache.getInstance().get(partyId); | |||
if (party == null) return; | |||
if (isInclude) { | |||
localBuildSqlPara(qnext, includeSelf, sqlOr, args, party); | |||
} else { | |||
localBuildSqlPara(qnext, includeSelf, sqlAnd, args, party); | |||
} | |||
} | |||
//构建子查询语句 | |||
private void localBuildSqlPara(boolean qnext, boolean includeSelf, StringBuilder sqlOr, SwMap args, Party party) { | |||
sqlOr.append(" or ( "); | |||
if (includeSelf) { | |||
String p = String.format("_dr_pt_id_%s", new Random().nextInt(10)); | |||
sqlOr.append(String.format("(r2.pt_id=:%s or ",p)); | |||
args.put(p,party.getId()); | |||
} | |||
if (qnext) { | |||
String p = String.format("_dr_pt_level_code_%s", new Random().nextInt(10)); | |||
sqlOr.append(String.format(" r2.pt_level_code like :%s",p)); | |||
args.put(p,party.getLevelCode() + SwConsts.SPLIT_CHAR + party.getId() + "%"); | |||
} else { | |||
String p = String.format("_dr_pt_parent_id_%s", new Random().nextInt(10)); | |||
sqlOr.append(String.format(" r2.pt_parent_id = :%s",p)); | |||
args.put(p,party.getId()); | |||
} | |||
if (includeSelf) sqlOr.append("))"); | |||
else sqlOr.append(")"); | |||
} | |||
} |
@@ -14,7 +14,6 @@ import java.util.Set; | |||
public class MenuPlanCache extends AbstractEntityCache<MenuPlan> { | |||
//缓存key:按项目缓存 | |||
public final static String mk_p = "p"; | |||
public static MenuPlanCache getInstance() { | |||
return CacheManager.getIntance().getCache(MenuPlanCache.class); | |||
} | |||
@@ -0,0 +1,21 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.menuPlan; | |||
/** | |||
* @Author: tanghp | |||
* @Date: 2022-09-26 10:19 | |||
* @Desc: 菜单方案辅助类 | |||
*/ | |||
public class MenuPlanHelper { | |||
/** | |||
* 获取命中菜单方案明细ID | |||
* @param menuId 菜单方案明细ID | |||
* @param pageId 页面ID | |||
* @param fullPath 带参数的路径 | |||
* @return | |||
*/ | |||
public long findMenuId(long menuId,long pageId,String fullPath){ | |||
// | |||
return 0L; | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.menuPlan; | |||
import cc.smtweb.framework.core.cache.SessionCacheFactory; | |||
import cc.smtweb.framework.core.util.CommUtil; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* @Author: tanghp | |||
* @Date: 2022-09-26 11:12 | |||
* @Desc: 菜单明细加载类 | |||
*/ | |||
public class MenuPlanItemProvider { | |||
private volatile MenuPlanItemProvider provider; | |||
private Map<Long, MenuPlanItem> map = new HashMap<>(); | |||
private MenuPlanItemProvider() { | |||
} | |||
public MenuPlanItemProvider getInstance(){ | |||
if (provider == null) { | |||
synchronized (SessionCacheFactory.class) { | |||
if (provider == null) { | |||
provider = new MenuPlanItemProvider(); | |||
} | |||
} | |||
} | |||
return provider; | |||
} | |||
// 获取菜单方案明细ID | |||
public MenuPlanItem getMenuPlanItem(long menuId){ | |||
MenuPlanItem menuPlanItem = map.get(menuId); | |||
if(menuPlanItem!=null)return menuPlanItem; | |||
Collection<MenuPlan> plans = MenuPlanCache.getInstance().getAll(); | |||
if(CommUtil.isEmpty(plans))return null; | |||
for(MenuPlan menuPlan: plans){ | |||
menuPlanItem = MenuPlanCache.getInstance().getById(menuPlan.getEntityId(),menuId); | |||
if(menuPlanItem!=null){ | |||
map.put(menuId,menuPlanItem); | |||
return menuPlanItem; | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -1,5 +1,9 @@ | |||
package cc.smtweb.system.bpm.web.sys.user.role; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRight.DataRightDefine; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRight.DataRightDefineCache; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.DataRightGroup; | |||
import cc.smtweb.system.bpm.web.sys.user.dataRightGroup.DataRightGroupCache; | |||
import cc.smtweb.system.bpm.web.sys.user.menuPlan.MenuPlan; | |||
import cc.smtweb.system.bpm.web.sys.user.menuPlan.MenuPlanCache; | |||
import cc.smtweb.system.bpm.web.sys.user.menuPlan.MenuPlanContent; | |||
@@ -8,9 +12,7 @@ import cc.smtweb.system.bpm.web.sys.user.user.User; | |||
import cc.smtweb.system.bpm.web.sys.user.user.UserCache; | |||
import cc.smtweb.system.bpm.web.sys.user.user.UserRoleCache; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.*; | |||
/** | |||
* @Author: tanghp | |||
@@ -127,4 +129,54 @@ public final class RoleHelper { | |||
}); | |||
return mpList; | |||
} | |||
/** | |||
* 获取用户指定类型的数据权限组 | |||
* @param userId 用户ID | |||
* @param partyId 登录的单位 | |||
* @param menuId 菜单ID | |||
* @param dsType 数据权限类型编码 | |||
* @return 数据权限组集合 | |||
*/ | |||
public static Set<DataRightGroup> getDataRightGroup(long userId,long partyId,long menuId,String dsType){ | |||
Set<Long> mpIds = getMenuPlanIds(userId,partyId); | |||
if(mpIds.size()==0){ | |||
return new HashSet<>(); | |||
} | |||
// 没传菜单方案ID,随机取一个菜单方案 | |||
return getDataRightGroup(userId,partyId,menuId,dsType,mpIds.iterator().next()); | |||
} | |||
/** | |||
* 获取用户指定类型的数据权限组 | |||
* @param userId 用户ID | |||
* @param partyId 登录单位 | |||
* @param dsType 数据权限类型编码 参见 BpmEnum.DataRightType | |||
* @param menuPlanId 菜单方案id | |||
* @return 据权限组集合 | |||
*/ | |||
public static Set<DataRightGroup> getDataRightGroup(long userId,long partyId,long menuId,String dsType,long menuPlanId){ | |||
Map<Long,DataRightGroup> mapGroup = new HashMap<>(); | |||
//先看数据权限类型存在不 | |||
DataRightDefine drd = DataRightDefineCache.getInstance().getByCode(dsType); | |||
if(drd==null)return new HashSet<>(); | |||
Set<Long> roleIds = UserRoleCache.getInstance().getRoleIdByUP(userId,partyId); | |||
RoleCache roleCache = RoleCache.getInstance(); | |||
roleIds.forEach((roleId)-> { | |||
Role role = roleCache.get(roleId); | |||
if(role==null || role.getSmpId()!=menuPlanId){ | |||
return; | |||
} | |||
RoleRightContent roleRightContent = new RoleRightContent(role.getPrivilege()); | |||
long groupId =roleRightContent.getDataRightGroupId(menuId,drd.getEntityId()); | |||
if(groupId>0L){ | |||
DataRightGroup dataRightGroup = DataRightGroupCache.getInstance().get(groupId); | |||
if(dataRightGroup!=null){ | |||
mapGroup.put(groupId,dataRightGroup); | |||
} | |||
} | |||
}); | |||
return new HashSet<>(mapGroup.values()); | |||
} | |||
} |
@@ -112,4 +112,25 @@ public class RoleRightContent { | |||
}); | |||
return cache; | |||
} | |||
/** | |||
* 获取菜单的数据权限组ID | |||
* @param menuId 菜单id | |||
* @param dataRightId 数据权限定义id | |||
* @return 数据权限组ID | |||
*/ | |||
public long getDataRightGroupId(long menuId, long dataRightId){ | |||
RoleRight right = getRoleRight(menuId); | |||
List<Map<String, Object>> list = right.getRightData(); | |||
if(CommUtil.isEmpty(list))return 0L; | |||
for(Map<String,Object> map :list){ | |||
SwMap swMap = new SwMap(); | |||
swMap.putAll(map); | |||
long key = swMap.readLong("key"); | |||
if(key ==dataRightId){ | |||
return swMap.readLong("value"); | |||
} | |||
} | |||
return 0L; | |||
} | |||
} |
@@ -34,7 +34,21 @@ | |||
<#if fields.lookup??> | |||
"lookup": { | |||
<#list fields.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -25,9 +25,23 @@ | |||
"required": "${dfield.required}", | |||
<#if dfield.lookup??> | |||
"lookup": { | |||
<#list dfield.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
</#list> | |||
<#list dfield.lookup as k, v> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
<#if dfield.maxlength gt 0> | |||
@@ -33,7 +33,21 @@ | |||
<#if filter.lookup??> | |||
"lookup": { | |||
<#list filter.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -59,9 +59,23 @@ | |||
"field": "${filter.id}", | |||
<#if filter.lookup??> | |||
"lookup": { | |||
<#list filter.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
</#list> | |||
<#list filter.lookup as k, v> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
"name": "${filter.name}" | |||
@@ -184,7 +184,21 @@ | |||
<#if fields.lookup??> | |||
"lookup": { | |||
<#list fields.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -293,7 +307,21 @@ | |||
<#if fields.lookup??> | |||
"lookup": { | |||
<#list fields.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -80,7 +80,21 @@ | |||
<#if field.lookup??> | |||
"lookup": { | |||
<#list field.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -165,7 +165,21 @@ | |||
<#if field.lookup??> | |||
"lookup": { | |||
<#list field.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -168,7 +168,21 @@ | |||
<#if dfield.lookup??> | |||
"lookup": { | |||
<#list dfield.lookup as k, v> | |||
"${k}": "${v}" <#if k_has_next>,</#if> | |||
<#if v?is_enumerable> | |||
"${k}": [ | |||
<#list v as v1> | |||
{ | |||
<#list v1 as vk1, vv1> | |||
"${vk1}": "${vv1}"<#if vk1_has_next>,</#if> | |||
</#list> | |||
} | |||
<#if v1_has_next>,</#if> | |||
</#list> | |||
] | |||
<#else> | |||
"${k}": "${v}" | |||
</#if> | |||
<#if k_has_next>,</#if> | |||
</#list> | |||
}, | |||
</#if> | |||
@@ -168,6 +168,16 @@ | |||
<artifactId>spring-boot-starter-test</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.poi</groupId> | |||
<artifactId>poi</artifactId> | |||
<version>5.2.2</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.poi</groupId> | |||
<artifactId>poi-ooxml</artifactId> | |||
<version>5.2.2</version> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
@@ -62,4 +62,6 @@ public interface SwConsts { | |||
//定时任务key | |||
String REDIS_KEY_BASE_JOB = "jobexe"; | |||
// params 参数中的header key | |||
String PARAMS_HEADER_KEY ="_header"; | |||
} |
@@ -314,6 +314,7 @@ public interface SwEnum { | |||
public static StrEnumBean LIKE = instance.addEnum("like", "包含"); | |||
public static StrEnumBean IN = instance.addEnum("in", "在列表"); | |||
public static StrEnumBean NOT_IN = instance.addEnum("not in", "不在列表"); | |||
public static StrEnumBean IN_CHILD = instance.addEnum("inChild", "本级及下级"); | |||
} | |||
//合计栏类型 "summary": "COUNT/SUM/AVG/MAX/MIN/其他为文本" | |||
@@ -8,6 +8,7 @@ import cc.smtweb.framework.core.util.JsonUtil; | |||
import org.apache.commons.lang3.StringUtils; | |||
import javax.servlet.http.HttpServletRequest; | |||
import java.util.Enumeration; | |||
import java.util.Map; | |||
/** | |||
@@ -32,6 +33,10 @@ public class SwMapBodyEditor implements IEditor { | |||
private Object getGetValue(String paramName, Class<?> paramType, Map<String, Object> params, HttpServletRequest request) { | |||
SwMap result = JsonUtil.parseSimple(params, SwMap.class); | |||
if(result!=null){ | |||
SwMap header = getHeaderMap(request); | |||
result.put("_header",header); | |||
} | |||
request.setAttribute(BODY_MAP, result); | |||
return getFieldValue(result, paramName); | |||
} | |||
@@ -42,10 +47,25 @@ public class SwMapBodyEditor implements IEditor { | |||
} | |||
SwMap result = JsonUtil.parse(body, SwMap.class); | |||
if(result!=null){ | |||
SwMap header = getHeaderMap(request); | |||
result.put("_header",header); | |||
} | |||
request.setAttribute(BODY_MAP, result); | |||
return getFieldValue(result, paramName); | |||
} | |||
private SwMap getHeaderMap( HttpServletRequest request){ | |||
SwMap header = new SwMap(); | |||
Enumeration<String> headerNames = request.getHeaderNames(); | |||
if (null != headerNames) { | |||
while (headerNames.hasMoreElements()) { | |||
String headerName = headerNames.nextElement(); | |||
String headerValue = request.getHeader(headerName); | |||
header.put(headerName,headerValue); | |||
} | |||
} | |||
return header; | |||
} | |||
private Object getFieldValue(SwMap result, String paramName) { | |||
if (paramName != null) { | |||
Object value = result.get(paramName); | |||
@@ -54,6 +54,14 @@ public abstract class AbstractListHandler extends AbstractHandler { | |||
return R.success(buildListData()); | |||
} | |||
/** | |||
* 导出excel | |||
* @return R:{ file: fileName@@filePath } | |||
*/ | |||
public R exportExcel() { | |||
return R.success(buildListData()); | |||
} | |||
public SwListData buildListData() { | |||
List<SwMap> listData; | |||
SqlPara sqlPara = buildDataSql(); | |||
@@ -6,6 +6,7 @@ import cc.smtweb.framework.core.common.SwConsts; | |||
import cc.smtweb.framework.core.common.SwEnum; | |||
import cc.smtweb.framework.core.db.DbEngine; | |||
import cc.smtweb.framework.core.db.EntityDao; | |||
import cc.smtweb.framework.core.db.EntityHelper; | |||
import cc.smtweb.framework.core.db.cache.ModelTableCache; | |||
import cc.smtweb.framework.core.db.impl.DefaultEntity; | |||
import cc.smtweb.framework.core.db.vo.ModelTable; | |||
@@ -36,6 +37,7 @@ public class TreeHelper<T extends DefaultEntity> { | |||
private String fieldParent; | |||
private String fieldLevel; | |||
private String fieldLevelCode; | |||
private String fieldId; | |||
public static TreeHelper getTreeHelper(String tableName) { | |||
@@ -69,6 +71,7 @@ public class TreeHelper<T extends DefaultEntity> { | |||
fieldParent = table.findFieldNameByType(SwEnum.FieldType.PARENT_ID.value); | |||
fieldLevelCode = table.findFieldNameByType(SwEnum.FieldType.LEVEL_CODE.value); | |||
fieldLevel = table.findFieldNameByType(SwEnum.FieldType.LEVEL.value); | |||
fieldId = table.getIdField(); | |||
} | |||
public long getParentId(T bean) { | |||
@@ -125,13 +128,24 @@ public class TreeHelper<T extends DefaultEntity> { | |||
} | |||
return list; | |||
} | |||
// 拼接查询本级及下级sql片段 | |||
public String buildLikeFrSql(long id,String sqlField){ | |||
T bean = cache.get(id); | |||
if(bean==null){ | |||
return "1<>1"; | |||
} | |||
String childStr = "'"+getLevelCode(bean)+ SwConsts.SPLIT_CHAR+ bean.getEntityId()+"'"; | |||
String schemaTableName = EntityHelper.getSchemaTableName(tableName); | |||
return String.format(" exists ( select %s from %s tt where tt.%s = %s and (tt.%s=%s or tt.%s like %s))", | |||
fieldId,schemaTableName,fieldId,sqlField,fieldId,id,fieldLevelCode,childStr); | |||
} | |||
private void resetParentChildren(T bean, List<T> list) { | |||
T parent = cache.get(getParentId(bean)); | |||
if (parent != null) { | |||
bean.put(fieldLevelCode, getLevelCode(parent) + SwConsts.SPLIT_CHAR + parent.getEntityId()); | |||
bean.put(fieldLevel, getLevel(parent) + 1); | |||
dao.updateEntity(bean, fieldLevelCode, fieldLevel); | |||
dao.updateEntity(bean, fieldLevelCode+","+fieldLevel); | |||
list.add(bean); | |||
} | |||
Collection<T> children = getChildren(bean); | |||
@@ -37,7 +37,6 @@ public class SessionUtil { | |||
//url参数名 | |||
private final static String KEY_PARAM_FP_KEY = "fpk"; | |||
private final static String KEY_PARAM_FP_VAL = "fpv"; | |||
//不需要校验登录的url | |||
public static List<String> notLoginUrl = new ArrayList<>(); | |||
/*//不需要切换数据源的url,强制用主库 | |||
@@ -0,0 +1,131 @@ | |||
package cc.smtweb.framework.core.util; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
import org.apache.poi.ss.usermodel.CellType; | |||
import org.apache.poi.ss.usermodel.Row; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class ExcelUtil { | |||
private static int xy(int x, int y) { | |||
if (y == 0) return 1; | |||
if (y == 1) return x; | |||
int f = x * x; | |||
for (int i = 0; i < (y - 2); ++i) { | |||
f *= x; | |||
} | |||
return f; | |||
} | |||
// Z==> 26, AA == > 27 , AB ==> 28 | |||
public static int toColInt(String col) { | |||
col = col.toUpperCase(); | |||
int colv = 0, left = 0; | |||
for (int i = col.length(); i > 0; --i) { | |||
char c = col.charAt(i - 1); | |||
colv += (c - 'A' + 1) * xy(26, left); | |||
++left; | |||
} | |||
return colv - 1; // excel是从0开始的 | |||
} | |||
/** | |||
* 数字下标转列 | |||
* @param index | |||
* @return | |||
*/ | |||
public static String toColExcel(int index) { | |||
int shang = 0; | |||
int yu = 0; | |||
List<Integer> list = new ArrayList<Integer>(); //10进制转26进制 倒序 | |||
do { | |||
shang = index / 26; | |||
yu = index % 26; | |||
index = shang; | |||
list.add(yu); | |||
} while (shang != 0); | |||
StringBuilder sb = new StringBuilder(); | |||
for (int j = list.size() - 1; j >= 0; j--) { | |||
sb.append((char) (list.get(j) + 'A' - (Math.min(j, 1)))); //倒序拼接 序号转字符 非末位 序号减去 1 | |||
} | |||
return sb.toString(); | |||
} | |||
// 注意col要大写字母 | |||
public static String getStr(Row row, char col) { | |||
int i = col - 'A'; | |||
return getStr(row, i); | |||
} | |||
public static String getStr(Row row, int col) { | |||
if(col <0) return ""; | |||
Cell cell = row.getCell(col); | |||
if (null == cell) return ""; | |||
if (cell.getCellType() == CellType.BLANK || cell.getCellType() == CellType.ERROR) { | |||
return ""; | |||
} | |||
// AKzz : cell 是数字时,会报错误, | |||
if (cell.getCellType() == CellType.NUMERIC) { | |||
// 非日期格式 | |||
if (!org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) { | |||
double d = cell.getNumericCellValue(); | |||
// long x = (long) d; | |||
return MathUtil.getDoubleStr(d); | |||
} else { | |||
return cc.smtweb.framework.core.util.DateUtil.toStdDateString(cell.getDateCellValue()); | |||
} | |||
} | |||
if (cell.getCellType() == CellType.STRING) { | |||
return StringUtil.checkNull(cell.getStringCellValue()); | |||
} | |||
if (cell.getCellType() == CellType.FORMULA) { | |||
return getFormulaStr(cell); | |||
} | |||
return ""; | |||
} | |||
// 注意col要大写字母 | |||
public static int getInt(Row row, char col) { | |||
int i = col - 'A'; | |||
return getInt(row, i); | |||
} | |||
public static int getInt(Row row, int col) { | |||
if(col <0) return 0; | |||
Cell cell = row.getCell(col); | |||
if (null == cell) return 0; | |||
if (cell.getCellType() == CellType.NUMERIC && !org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) { | |||
double d = cell.getNumericCellValue(); | |||
return (int) d; | |||
} else if (cell.getCellType() == CellType.STRING) { | |||
return MathUtil.toint(cell.getStringCellValue(), 0); | |||
} else if (cell.getCellType() == CellType.FORMULA) { | |||
return (int) getFormulaDbl(cell); | |||
} | |||
return 0; | |||
} | |||
private static String getFormulaStr(Cell cell) { | |||
try { | |||
return StringUtil.checkNull(cell.getStringCellValue()); | |||
} catch (Exception e) { | |||
// UtilLogger.warn("读取数据出错:"+cell, e); | |||
System.err.println("读取数据出错"); | |||
String v = MathUtil.toStdNumberString(cell.getNumericCellValue()); | |||
if (v.endsWith(".00")) v = v.substring(0, v.length() - 3); | |||
return v; | |||
} | |||
} | |||
private static double getFormulaDbl(Cell cell) { | |||
try { | |||
return cell.getNumericCellValue(); | |||
} catch (Exception e) { | |||
return MathUtil.todouble(cell.getStringCellValue()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
package cc.smtweb.framework.core.util; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
public class ExportUtil { | |||
//填充变量 | |||
public static String myReplaceStr(String s, Map<String, String> map) { | |||
boolean isDouble = s.startsWith("[@exprd"); | |||
boolean isInt = s.startsWith("[@expri@]"); | |||
if (isDouble || isInt) { | |||
s = s.substring(s.indexOf("@]") + 2); | |||
String b = "[#", e = "#]", svar; | |||
int n = s.indexOf(b), lb = b.length(); | |||
Map<String, Object> mapvar = new HashMap<>(); | |||
int i = 0; | |||
while (n >= 0) { | |||
svar = "a" + (++i); | |||
String fn = s.substring(n + lb, s.indexOf(e)); | |||
s = s.replace(b + fn + e, svar); | |||
n = s.indexOf(b); | |||
mapvar.put(svar, StringUtil.getDoubleIgnoreErr(map.get(fn))); | |||
} | |||
double d; | |||
try { | |||
d = MathUtil.calcExprMapDouble(s, mapvar); | |||
} catch (Exception e1) { | |||
d = 0.0; | |||
// UtilLogger.error("计算错误:", e1); | |||
} | |||
if (isDouble) { | |||
String v = MathUtil.getAmountStr(d); | |||
v = v.replace(".00", "").replaceAll(",", ""); | |||
if (v.contains(".") && v.endsWith("0")) v = v.substring(0, v.length() - 1); | |||
return v; | |||
} | |||
return MathUtil.toStdNumberString(d, 0); | |||
} else if (s.startsWith("[@d") || s.startsWith("[@i@]")) s = s.substring(s.indexOf("@]") + 2); | |||
else if (s.startsWith("[@expfml@]")) s = s.substring(10); | |||
return myReplaceStrEx(s, "[#", "#]", map); | |||
} | |||
//填充变量 | |||
public static String myReplaceStrEx(String s, String b, String e, Map<String, String> map) { | |||
int n = s.indexOf(b), lb = b.length(); | |||
while (n >= 0) { | |||
String fn = s.substring(n + lb, s.indexOf(e)); | |||
s = s.replace(b + fn + e, StringUtil.checkNull(map.get(fn))); | |||
n = s.indexOf(b); | |||
} | |||
return s; | |||
} | |||
} |
@@ -3,6 +3,7 @@ package cc.smtweb.framework.core.util; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.codec.binary.Base64; | |||
import org.apache.commons.io.FileUtils; | |||
import sun.misc.BASE64Decoder; | |||
import sun.misc.BASE64Encoder; | |||
import javax.imageio.ImageIO; | |||
@@ -98,6 +99,24 @@ public class FileUtil { | |||
return "data:image/png;base64," + png_base64; | |||
} | |||
/** | |||
* 判断是否是图片 | |||
* | |||
* @param base64Str | |||
* @return | |||
*/ | |||
public static boolean isImageFromBase64(String base64Str) { | |||
try { | |||
BufferedImage bufImg = ImageIO.read(new ByteArrayInputStream(new BASE64Decoder().decodeBuffer(base64Str))); | |||
if (null == bufImg) { | |||
return false; | |||
} | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
public static boolean copyFile(File oldfile, String newPath, boolean isDelOld) { | |||
if (!oldfile.exists()) return true; | |||
int byteread; | |||
@@ -107,7 +107,12 @@ public class HttpUtil { | |||
public static SwMap post(String url, Map<String, String> paras) throws Exception { | |||
String json_resp = post(url, null, paras, null); | |||
if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; | |||
return (SwMap) JsonUtil.parseMap(json_resp); | |||
SwMap swMap = new SwMap(); | |||
Map map = JsonUtil.parseMap(json_resp); | |||
if(map!=null){ | |||
swMap.putAll(map); | |||
} | |||
return swMap; | |||
} | |||
/** | |||
@@ -147,7 +152,12 @@ public class HttpUtil { | |||
json_resp = new String(Base64.decodeBase64(json_resp), charset); | |||
} | |||
if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; | |||
return (SwMap) JsonUtil.parseMap(json_resp); | |||
SwMap swMap = new SwMap(); | |||
Map map = JsonUtil.parseMap(json_resp); | |||
if(map!=null){ | |||
swMap.putAll(map); | |||
} | |||
return swMap; | |||
} | |||
/** | |||
@@ -169,14 +179,24 @@ public class HttpUtil { | |||
json_resp = new String(Base64.decodeBase64(json_resp), charset); | |||
} | |||
if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; | |||
return (SwMap) JsonUtil.parseMap(json_resp); | |||
SwMap swMap = new SwMap(); | |||
Map map = JsonUtil.parseMap(json_resp); | |||
if(map!=null){ | |||
swMap.putAll(map); | |||
} | |||
return swMap; | |||
} | |||
public static SwMap post(String url, Map<String, String> header, Map<String, String> paras) throws Exception { | |||
String json_resp = post(url, header, paras, null); | |||
if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; | |||
return (SwMap) JsonUtil.parseMap(json_resp); | |||
SwMap swMap = new SwMap(); | |||
Map map = JsonUtil.parseMap(json_resp); | |||
if(map!=null){ | |||
swMap.putAll(map); | |||
} | |||
return swMap; | |||
} | |||
/** | |||
@@ -0,0 +1,507 @@ | |||
package cc.smtweb.framework.core.util; | |||
import org.apache.commons.jexl3.*; | |||
import org.apache.commons.jexl3.internal.Engine; | |||
import java.math.BigDecimal; | |||
import java.math.RoundingMode; | |||
import java.text.DecimalFormat; | |||
import java.util.Map; | |||
public class MathUtil { | |||
//整数 | |||
private static DecimalFormat dfLng = new DecimalFormat("##############0"); | |||
private static DecimalFormat dfLong = new DecimalFormat("###,###,###,###,##0"); | |||
//一位小数 | |||
private static DecimalFormat df1 = new DecimalFormat("##############0.0"); | |||
private static DecimalFormat df1Format = new DecimalFormat("###,###,###,###,##0.0"); | |||
//两位小数 | |||
private static DecimalFormat df2 = new DecimalFormat("##############0.00"); | |||
private static DecimalFormat df2Format = new DecimalFormat("###,###,###,###,##0.00"); | |||
//四位小数 | |||
private static DecimalFormat df4 = new DecimalFormat("###,###,###,###,##0.0000"); | |||
//六位小数 | |||
private static DecimalFormat df6Number = new DecimalFormat("#######################0.000000"); | |||
private static DecimalFormat df6NumberF = new DecimalFormat("#,###,###,###,###,###,##0.000000"); | |||
public final static DecimalFormat stdAmountFormat = new DecimalFormat("###,###,###,###,##0.00"); | |||
public final static DecimalFormat stdNumberFormat = new DecimalFormat("#0.00"); | |||
public final static String DEF_NUM_TEN_THOUSAND = "10000";//万 | |||
public static final double MAX_VALUE = 9999999999999.99D; | |||
public static final double MIN_VALUE = -9999999999999.99D; | |||
private final static BigDecimal ONE_BIG = new BigDecimal(1.00D); | |||
private static final String UNIT = "万仟佰拾亿仟佰拾万仟佰拾元角分"; | |||
private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖"; | |||
/** | |||
* 4舍5入double,2位小数 | |||
*/ | |||
public static double roundDouble(double src) { | |||
return roundDouble(src, 2); | |||
} | |||
/** | |||
* 4舍5入double,N 位小数 | |||
* | |||
* @param src | |||
* @param scale 小数位数 | |||
* @return | |||
*/ | |||
public static double roundDouble(Object src, int scale) { | |||
if (src == null) return 0.0; | |||
String v = src.toString(); | |||
if (StringUtil.isEmpty(v)) return 0.0; | |||
if (scale < 0) scale = 2; | |||
BigDecimal src_b = new BigDecimal(v); | |||
BigDecimal src_v = src_b.divide(ONE_BIG, scale + 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 | |||
src_v = src_v.divide(ONE_BIG, scale, BigDecimal.ROUND_HALF_UP);// 4舍5入 | |||
return src_v.doubleValue(); | |||
} | |||
/** | |||
* 舍位处理,原生floor有坑,部分浮点数记录为.99999999999形式,导致floor结果错误 | |||
* | |||
* @param d | |||
* @return | |||
*/ | |||
public static double floor(double d) { | |||
return Math.floor(MathUtil.roundDouble(d, 2)); | |||
} | |||
/** | |||
* 比较两Double是否相等,将会吧他们专程BigDecimal进行比较; | |||
* | |||
* @param src double1 | |||
* @param tag double2 | |||
* @return src > tag 返回1, src < tag 返回-1, 否则返回0 | |||
*/ | |||
public static int compare(double src, double tag) { | |||
BigDecimal src_b = new BigDecimal(src); | |||
BigDecimal src_v = src_b.divide(ONE_BIG, 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 | |||
BigDecimal tag_b = new BigDecimal(tag); | |||
BigDecimal tag_v = tag_b.divide(ONE_BIG, 2, BigDecimal.ROUND_HALF_UP);// 4舍5入 | |||
return src_v.compareTo(tag_v); | |||
} | |||
/** | |||
* 自动过滤金额中的逗号转换为double,如果出错,则返回0 | |||
* | |||
* @param s 源串,可能为带逗号的金额串; | |||
* @return double | |||
*/ | |||
public static Double toDouble(String s) { | |||
return todouble(s); | |||
} | |||
/** | |||
* 自动过滤金额中的逗号转换为double,如果出错,则返回0 | |||
* | |||
* @param s 源串,可能为带逗号的金额串; | |||
* @return double | |||
*/ | |||
public static double todouble(String s) { | |||
try { | |||
return Double.parseDouble(s.replaceAll(",", "")); | |||
} catch (Exception e) { | |||
return 0.00; | |||
} | |||
} | |||
/** | |||
* 获取double,主要过滤d为null的情况; | |||
* | |||
* @param d Double对象; | |||
* @return double | |||
*/ | |||
public static double todouble(Double d) { | |||
if (d == null) return 0.0d; | |||
return d.doubleValue(); | |||
} | |||
/** | |||
* 自动过滤金额中的逗号转换为float,如果出错,则返回0 | |||
* | |||
* @param s 源串,可能为带逗号的金额串; | |||
* @return Float | |||
*/ | |||
public static Float toFloat(String s) { | |||
return tofloat(s); | |||
} | |||
/** | |||
* 自动过滤金额中的逗号转换为float,如果出错,则返回0 | |||
* | |||
* @param s 源串,可能为带逗号的金额串; | |||
* @return Float | |||
*/ | |||
public static float tofloat(String s) { | |||
try { | |||
return Float.parseFloat(s.replaceAll(",", "")); | |||
} catch (Exception e) { | |||
return 0.0f; | |||
} | |||
} | |||
public static long tolong(String src, long defaultvalue) { | |||
try { | |||
return Long.parseLong(src); | |||
} catch (Exception e) { | |||
return defaultvalue; | |||
} | |||
} | |||
public static int toint(String src, int defaultvalue) { | |||
try { | |||
return Integer.parseInt(src); | |||
} catch (Exception e) { | |||
return defaultvalue; | |||
} | |||
} | |||
/** | |||
* 考虑使用中的精度,判断一个Value是否>0,实际是>0.00001 | |||
* | |||
* @param value double类型 | |||
* @return boolean | |||
*/ | |||
public static boolean isBigThanZero(double value) { | |||
return (value > 0.00001); | |||
} | |||
/** | |||
* 考虑使用中的精度,判断一个Value是否>0,实际是>0.00001 | |||
* | |||
* @param value String类型 | |||
* @return boolean | |||
*/ | |||
public static boolean isBigThanZero(String value) { | |||
return !StringUtil.isEmpty(value) && isBigThanZero(toDouble(value)); | |||
} | |||
/** | |||
* 考虑使用中的精度,判断一个Value是否=0,实际是给出一个值范围。 | |||
* | |||
* @param value double类型 | |||
* @return boolean | |||
*/ | |||
public static boolean isEqualsZero(double value) { | |||
return (-0.00001 < value && value < 0.00001); | |||
} | |||
/** | |||
* 考虑使用中的精度,判断一个Value是否=0,实际是给出一个值范围。 | |||
* | |||
* @param value String类型 | |||
* @return boolean | |||
*/ | |||
public static boolean isEqualsZero(String value) { | |||
return StringUtil.isEmpty(value) || isEqualsZero(toDouble(value)); | |||
} | |||
/** | |||
* 是否是负数 | |||
* | |||
* @param db_val 要判断的double | |||
* @return 负数则返回true; | |||
*/ | |||
public static boolean isNegative(double db_val) { | |||
return (compare(db_val, 0.00D) == -1); | |||
} | |||
/** | |||
* 是否是正数 | |||
* | |||
* @param db_val 要判断的double | |||
* @return 正数则返回true; | |||
*/ | |||
public static boolean isPlus(double db_val) { | |||
return (compare(db_val, 0.00D) == 1); | |||
} | |||
/** | |||
* 得到金额字符串,保持小数点2位 | |||
* | |||
* @param db 将double转换为金额字符串; | |||
* @return 金额字符串#0.00; | |||
*/ | |||
public static String toStdNumberString(double db) { | |||
try { | |||
return stdNumberFormat.format(db); | |||
} catch (Exception e) { | |||
return "0.00"; | |||
} | |||
} | |||
public static String toStdNumberStringEx(double db) { | |||
try { | |||
if (compare(db, -1d) == 0) return "-"; | |||
return stdNumberFormat.format(db); | |||
} catch (Exception e) { | |||
return "0.00"; | |||
} | |||
} | |||
/** | |||
* 将金额格式字符串,如23,333,093.01 去掉逗号 | |||
* | |||
* @param s 金额串 | |||
* @return String 去掉逗号后的串,如果amount为空,则返回0.00 | |||
*/ | |||
public static String toStdNumberString(String s) { | |||
if (StringUtil.isEmpty(s)) | |||
return "0.00"; | |||
return stdNumberFormat.format(MathUtil.todouble(s)); | |||
} | |||
/** | |||
* 将数据转换为两位小数的数字格式; | |||
* | |||
* @param d 数据 | |||
* @param isZeroToEmpty 如果未0,是否返回“”; | |||
* @return 两位小数的字符串; | |||
*/ | |||
public static String toStdNumberString(double d, boolean isZeroToEmpty) { | |||
if (isEqualsZero(d)) { | |||
return isZeroToEmpty ? "" : "0.00"; | |||
} | |||
return stdNumberFormat.format(d); | |||
} | |||
public static String toStdNumberString(String s, boolean isZeroToEmpty) { | |||
return toStdNumberString(MathUtil.todouble(s), isZeroToEmpty); | |||
} | |||
public static String toStdNumberString(double d, int scale) { | |||
DecimalFormat dfn = null; | |||
if (scale == 1) dfn = df1Format; | |||
if (scale == 2) dfn = df2Format; | |||
else if (scale == 4) dfn = df4; | |||
else if (scale == 6) dfn = df6NumberF; | |||
else if (scale <= 0) dfn = dfLong; | |||
else { | |||
StringBuilder sb = new StringBuilder("###,###,###,###,##0."); | |||
for (int i = 0; i < scale; i++) sb.append("0"); | |||
dfn = new DecimalFormat(sb.toString()); | |||
} | |||
return dfn.format(d); | |||
} | |||
/** | |||
* 将数字乘100,保留小数点后两位, 然后后面添加% | |||
* | |||
* @param d 值 | |||
* @param isZeroToEmpty,如果值为0,是否返回空; | |||
* @return 字符串; | |||
*/ | |||
public static String toStdPercentNumberStr(double d, boolean isZeroToEmpty) { | |||
if (d > -0.00000000001 && d < 0.00000000001) { | |||
return isZeroToEmpty ? "" : "0.00%"; | |||
} | |||
return toStdNumberString(d * 100) + "%"; | |||
} | |||
public static String toStdAmountString(double d) { | |||
return toStdAmountString(d, false); | |||
} | |||
/** | |||
* 将数据转换为两位小数的金额格式,带逗号; | |||
* | |||
* @param d 数据 | |||
* @param isZeroToEmpty 如果未0,是否返回“”; | |||
* @return 金额格式的字符串; | |||
*/ | |||
public static String toStdAmountString(double d, boolean isZeroToEmpty) { | |||
if (isEqualsZero(d)) { | |||
return isZeroToEmpty ? "" : "0.00"; | |||
} | |||
return stdAmountFormat.format(d); | |||
} | |||
public static String toStdAmountString(String s) { | |||
return toStdAmountString(MathUtil.todouble(s), false); | |||
} | |||
public static String toStdAmountString(String s, boolean isZeroToEmpty) { | |||
return toStdAmountString(MathUtil.todouble(s), isZeroToEmpty); | |||
} | |||
/** | |||
* 将小写金额转换为人民币大写金额 | |||
* | |||
* @param s 金额格式的串 | |||
* @return String 转换结果 | |||
*/ | |||
public static String toCapsAmountString(String s) { | |||
if (StringUtil.isEmpty(s)) return ""; | |||
return toCapsAmountString(todouble(s)); | |||
} | |||
/** | |||
* 将小写金额转换为人民币大写金额 | |||
* | |||
* @param v double | |||
* @return String 转换结果 | |||
*/ | |||
public static String toCapsAmountString(double v) { | |||
if (v < MIN_VALUE || v > MAX_VALUE) return "参数非法!"; | |||
boolean negative = isNegative(v); | |||
if (negative) v = Math.abs(v); | |||
long l = Math.round(v * 100); | |||
if (l == 0) return "零元整"; | |||
String strValue = String.valueOf(l); | |||
// i用来控制数 | |||
int i = 0; | |||
// j用来控制单位 | |||
int j = UNIT.length() - strValue.length(); | |||
StringBuilder rs = new StringBuilder(32); | |||
boolean isZero = false; | |||
for (; i < strValue.length(); i++, j++) { | |||
char ch = strValue.charAt(i); | |||
if (ch == '0') { | |||
isZero = true; | |||
if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') { | |||
rs.append(UNIT.charAt(j)); | |||
isZero = false; | |||
} | |||
} else { | |||
if (isZero) { | |||
rs.append('零'); | |||
isZero = false; | |||
} | |||
rs.append(DIGIT.charAt(ch - '0')).append(UNIT.charAt(j)); | |||
} | |||
} | |||
if (rs.charAt(rs.length() - 1) != '分') | |||
rs.append('整'); | |||
i = rs.indexOf("亿万"); | |||
if (i > 0) rs.delete(i + 1, i + 2); // i+1 ->万 | |||
if (negative) | |||
return rs.insert(0, '负').toString(); | |||
else | |||
return rs.toString(); | |||
} | |||
/** | |||
* 返回0 到 maxvalue的随机数 | |||
* | |||
* @param maxvalue 随机数的最大值 | |||
* @return int | |||
*/ | |||
public static int rnd(int maxvalue) { | |||
return (int) (Math.random() * (maxvalue + 1)); | |||
} | |||
public static double chkDbNull(Double v) { | |||
return v == null ? 0 : v; | |||
} | |||
public static double max(double d1, double d2) { | |||
return compare(d1, d2) < 0 ? d2 : d1; | |||
} | |||
public static double min(double d1, double d2) { | |||
return compare(d1, d2) < 0 ? d1 : d2; | |||
} | |||
/** | |||
* double 去尾法 | |||
* | |||
* @param src 待处理数据 | |||
* @param scale 保留小数位数 | |||
* @return | |||
*/ | |||
public static double cutDouble(double src, int scale) { | |||
String v = toStdNumberString(src, 6);//先到6位小数,再去计算,否则容易出错,如8.3成8.29999999999,舍位就成了8.29了 | |||
DecimalFormat formater = new DecimalFormat(); | |||
formater.setMaximumFractionDigits(scale); | |||
formater.setGroupingSize(0); | |||
formater.setRoundingMode(RoundingMode.FLOOR); | |||
return new BigDecimal(formater.format(toDouble(v))).doubleValue(); | |||
} | |||
public static String getAmountStr(double amount) { | |||
return df2Format.format(amount); | |||
} | |||
//数字转字符串,如无小数,则去掉.00 | |||
public static String getDoubleStr(double d) { | |||
return getAmountStr(d).replaceAll(",", "").replaceAll("\\.00", ""); | |||
} | |||
/** | |||
* double 进位法 | |||
* | |||
* @param src 待处理数据 | |||
* @param scale 保留小数位数 | |||
* @return | |||
*/ | |||
public static double upDouble(double src, int scale) { | |||
String v = toStdNumberString(src, 6);//先到6位小数,再去计算 | |||
DecimalFormat formater = new DecimalFormat(); | |||
formater.setMaximumFractionDigits(scale); | |||
formater.setGroupingSize(0); | |||
formater.setRoundingMode(RoundingMode.UP); | |||
return new BigDecimal(formater.format(toDouble(v))).doubleValue(); | |||
} | |||
/** | |||
* 计算公式 参数以Map方式传入 | |||
* | |||
* @param expr 表达式 | |||
* @param mapVar 变量 | |||
* @return 计算结果 | |||
*/ | |||
public static Object calcExprMapObject(String expr, Map<String, Object> mapVar) { | |||
if (StringUtil.isEmpty(expr)) return ""; | |||
JexlContext jc = new MapContext(); | |||
jc.set("Math", Math.class); | |||
jc.set("UtilPub", StringUtil.class); | |||
for (String k : mapVar.keySet()) jc.set(k, mapVar.get(k)); | |||
JexlExpression e = new Engine().createExpression(expr); | |||
return e.evaluate(jc); | |||
} | |||
/** | |||
* 计算公式,参数以数组方式传入,key、value交替 | |||
* | |||
* @param expr 表达式 | |||
* @param vars 变量 | |||
* @return | |||
*/ | |||
public static Object calcExprObjectEx(String expr, Object... vars) { | |||
if (StringUtil.isEmpty(expr)) return ""; | |||
JexlContext jc = new MapContext(); | |||
jc.set("Math", Math.class); | |||
jc.set("UtilPub", StringUtil.class); | |||
for (int i = 0, len = vars.length; i < len; ) { | |||
jc.set((String) vars[i++], vars[i++]); | |||
} | |||
JexlExpression e = new Engine().createExpression(expr); | |||
return e.evaluate(jc); | |||
} | |||
public static double calcExprMapDouble(String expr, Map<String, Object> mapVar) { | |||
Object o = calcExprMapObject(expr, mapVar); | |||
if (o != null) return StringUtil.getDoubleIgnoreErr(o.toString()); | |||
return 0.0; | |||
} | |||
public static double calcExprDoubleEx(String expr, Object... vars) { | |||
Object o = calcExprObjectEx(expr, vars); | |||
if (o != null) return StringUtil.getDoubleIgnoreErr(o.toString()); | |||
return 0.0; | |||
} | |||
} |
@@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; | |||
import java.nio.charset.StandardCharsets; | |||
import java.text.Collator; | |||
import java.text.DecimalFormat; | |||
import java.util.*; | |||
/** | |||
@@ -15,6 +16,8 @@ import java.util.*; | |||
*/ | |||
@SuppressWarnings("UnusedDeclaration") | |||
public class StringUtil { | |||
private static DecimalFormat df2Format = new DecimalFormat("###,###,###,###,##0.00"); | |||
private static Collator chineseCollator = Collator.getInstance(Locale.CHINA); | |||
public static boolean isEmpty(String str) { | |||
@@ -182,6 +185,52 @@ public class StringUtil { | |||
} | |||
/** | |||
* 获取浮点数(有错误默认为0),可以识别金额中的逗号格式 | |||
* | |||
* @param str 带转换的字符串 | |||
* @return 浮点数 | |||
*/ | |||
public static double getDoubleIgnoreErr(String str) { | |||
if (str == null) | |||
return 0.0; | |||
str = str.trim(); | |||
if (str.equals("")) | |||
return 0.0; | |||
str = str.replaceAll(",", "").replaceAll(",", ""); | |||
try { | |||
return Double.valueOf(str); | |||
} catch (Exception e) { | |||
return 0.0; | |||
} | |||
} | |||
/** | |||
* 得到int 获取转换的int值,有错返回0 | |||
* | |||
* @param str 带转换的字符串 | |||
* @return int | |||
*/ | |||
public static int getIntIgnoreErr(String str) { | |||
return getIntIgnoreErr(str, 0); | |||
} | |||
public static int getIntIgnoreErr(String str, int defValue) { | |||
if (str == null) | |||
return defValue; | |||
str = str.trim(); | |||
if (str.equals("")) | |||
return defValue; | |||
str = str.replaceAll(",", "").replaceAll(",", ""); | |||
if (str.contains(".")) | |||
str = str.substring(0, str.indexOf('.')); | |||
try { | |||
return Integer.valueOf(str); | |||
} catch (Exception e) { | |||
return defValue; | |||
} | |||
} | |||
/** | |||
* 取得重复字串 | |||
* | |||
* @param repeatString 重复字串 | |||