todo
待整合
信息整合平台参考:
https://www.oschina.net/p/o2oa?hmsr=aladdin1e1
http://www.o2oa.net/download.html
迅睿CMS
https://www.xunruicms.com/down/
演示:http://demo4.xunruicms.com/admin.php
通用权限管理设计:
https://www.cnblogs.com/ADTL/articles/3130583.html
后台管理系统的一套体系
分布式权限管理系统-架构篇
https://www.jianshu.com/p/7ee979986ab1
https://www.jianshu.com/p/4eb0d61d9a0c
权限管理系统参考:人人权限
https://gitee.com/renrenio/renren-security
后台管理系统微服务化
https://www.jianshu.com/p/7ee979986ab1#comments
多租户体系?(拦截校验)
关于企业内多系统的权限整合:
https://blog.csdn.net/yuan_ming/article/details/40687389
企业员工角色权限管理平台(SpringBoot2.0+Mybatis+Shiro+Vue)
https://www.roncoo.com/view/1159028108916490242
异常处理可自定义:MethodArgumentNotValidException(参数校验失败异常)
flowable相关
了解深研技术大佬Flowable框架使用状态,结合现有科室业务需求进行整改
[ ] 配置项概念:回归flowable最原始的状态,搭建流程监控平台、抽离公共的方法供业务侧进行调用
[ ] 业务要素配置:针对不同的业务需求,关联的表单项和筛选条件不同,需要提供业务要素配置相关,业务侧可结合自身项目实际对关联的业务表进行调整,并借助关联字段将业务数据与flowable进行绑定
目前后台管理部分实现还是过于局限,后续考虑公共系统模块完善
echart开发相关
使用进度条:虽然针对不同的统计参数,针对每个统计维度确认一个统一的标准
将进度条转化为对应维度的百分比统计,标签上额外展示真正的数据
(如果所有进度条数据统计维度不同会导致显示样式错乱,因此将统计数据全部转化为百分比的概念,随后在数据标签中展示不同的数据即可)
{
"extend": {
"dataList": {
"symbolSizeLimit": 600000,
"data": {
"nameArr":["宝安支行","福田支行","中心区支行","景苑支行","华侨城支行","龙岗支行","水贝珠宝支行","龙华支行","罗湖支行","南山支行","前海支行","上步支行","田背支行","盐田支行","分行营业部"],
"valueArr":["313","2234","355","3645","6454","7524","424","6464","6231","5","757","7686","6786","5423","2334"],
"yjlArr":["313","2234","355","3645","6454","7524","424","6464","6231","5","757","7686","6786","5423","2334"],
"sblArr":["12","434","656","865","32","545","767","32","646","5","54","32","45","76","64"],
"zjeArr":["32123","5345","7678","8908","345","234","656","567","75767","6465","6464","3131","5353","2984","42334"],
"zbsArr":["423","2121","424","45545","678","4224","42346","6456","423","5345","5354","577","477","2423","676"],
"yjlZs":"100",
"yjlRateArr":["12","32","34","1","2","32","1","32","43","1","2","3","43","32","12"],
"sblZs":"4265",
"sblRateArr":[],
"zjeZs":"191890",
"zjeRateArr":[],
"zbsZs":"117492",
"zbscalRateArr":[]
},
"dataName": "预警量",
"visualMapMax": 10000
}
},
"errCode": 0,
"errMsg": "[响应成功]"
}
前后端交互测试问题:
get方法测试
如果指定get方式,在url指定路径,则无需指定form-data,如果出现同名参数指定则会在后面拼接参数,造成参数传递出错而无法正常关联后端数据,调整测试:
[ ] 文件下载异常处理
模板文件下载异常处理:前后端交互
response.reset()?
poi-tl:指定封装模板字段参数不能为null
文件下载后不返回AjaxResult,前端无法识别json和流转化,下载失败直接抛出异常
[ ] 流程图处理
流程图:前端显示流程图数据处理:getFlowImage接口调整,将将图片数据转换成BASE64数据字符串,由前端进行解析
[ ] 结合echarts+poi-tl下载模板文件
https://blog.csdn.net/u012441594/article/details/89308576
[ ] 提供下载用户导入模板接口
https://blog.csdn.net/jiankunking/article/details/75213798
poi-tl模板
poi-tl数据导出问题:如果指定导出的模板字段为null则报错,因此要处理null异常
数据异常调试说明:
方式1:响应成功返回标识
@GetMapping("/exportLcrbdForAD")
public AjaxResult exportLcrbdForAD(HttpServletResponse response,@RequestParam String procInstId,@RequestParam String templateKey) throws Exception{
dataHandleService.exportLcrbdForAD(response,procInstId,templateKey);
return AjaxResultUtil.success();
}
2020-07-24 15:26:54.503 ERROR 20820 --- [nio-9081-exec-1] c.s.f.handler.GlobalExceptionHandler : 未知的运行时异常:
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.LinkedHashMap] with preset Content-Type 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:309) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:219) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:580) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:516) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:388) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:253) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:348) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:173) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594) [tomcat-embed-core-9.0.33.jar:9.0.33]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.33.jar:9.0.33]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.33.jar:9.0.33]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]
2020-07-24 15:26:54.507 WARN 20820 --- [nio-9081-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Failure in @ExceptionHandler com.sz.framework.handler.GlobalExceptionHandler#unKnowErr(RuntimeException)
考虑是数据导出的时候触发了异常,例如数据格式转化错误、空指针异常等,抛出异常无法被正常接收,检查问题
调整接口返回格式
@GetMapping("/exportBCN")
public void exportBCN(HttpServletResponse response,@RequestParam String procInstId,@RequestParam String templateKey) throws Exception{
dataHandleService.exportBCN(response,procInstId,templateKey);
// return AjaxResultUtil.success();
}
触发下载异常可以看到日志报错:日期空指针异常
设置断点调试:考虑可能触发异常清空掉之前的日志打印数据,一步步设置断点便可看到info信息,对导出的模板字段进行数据校验和转化,消除error信息(通过断点调试查看数据)
前端调用下载模板出错
问题1:当后台返回AjaxResult数据,后台在不触发异常的情况下能够正常导出数据,但是下载数据相应完成之后便会抛出异常,原因是响应完成之后前端无法正常解析后台返回的json数据,导致数据转化异常
将后台接口调整,只需要正常调用方法返回流数据即可,无须额外返回AjaxResult数据(消除文件下载后处理导致的异常情况,无关业务逻辑)
问题2:盲目使用response.reset()方法导致数据处理异常,前后端响应不报错,但是前端无法正常接收响应数据(postman接口请求测试不报错)
福费廷开发日记
bug调整(待测试)
删除未提交的流程实例,删除关联的附件记录:CommonController:deleteFlowByCond
取消登录退出拦截校验
持有卖出业务引用了转买业务的编号,因此在校验编号的时候需要进行去重处理,否则会出现两条相同的编号记录导致校验出错
基于Spring+SpringMVC+Mybatis分布式敏捷开发系统架构,提供整套公共微服务服务模块:集中权限管理(单点登录)、内容管理、支付中心、用户管理(支持第三方登录)、微信平台、存储系统、配置中心、日志分析、任务和通知等,支持服务治理、监控和追踪,努力为中小型企业打造全方位J2EE企业级开发解决方案。
https://gitee.com/scc/zheng
BOXING价格测算出错:
原有实现逻辑为了方便封装统计数据是根据businessType、priceType查找所有的价格参数,从这个范围去筛选最新价格生效时间。
但这种情况会导致,当不同timeLimit的生效时间不同的时候,下述语句会筛选满足条件的最新的价格生效时间,但并不是所有timeLimit限制下的生效时间都统一一致,从而导致部分数据能找出来,而部分数据缺失导致出错。
SELECT
P .price_id "priceId",
-- p.publisher "publisher",
U .user_name "publisher",
-- p.business_type "businessType",
CASE
WHEN P .business_type = '1' THEN
'初级市场'
WHEN P .business_type = '2' THEN
'二级市场'
ELSE
'其他状态'
END "businessType",
P .effect_time "effectTime",
P .price_type "priceType",
P .other_bank "otherBank",
P .time_limit "timeLimit",
P .price "price",
-- p.publish_status "publishStatus",
P .create_time "createTime",
P .modify_time "modifyTime",
CASE
WHEN P .publish_status = '0' THEN
'未发布'
WHEN P .publish_status = '1' THEN
'已发布'
ELSE
'其他状态'
END "publishStatus"
FROM
boxing_param_price P
LEFT JOIN boxing_user U ON U .user_id = P .publisher
WHERE
P .business_type = '2'
AND P .price_type = '利率下限'
AND TO_CHAR (P .effect_time, 'yyyy-MM-dd') = (
-- 根据筛选条件获取指定筛选范围内最近的日期数据
SELECT
MAX (
TO_CHAR (
pc.effect_time,
'yyyy-MM-dd'
)
)
FROM
boxing_param_price pc
WHERE
pc.business_type = '2'
AND pc.price_type = '利率下限'
AND '2020-08-01' >= TO_CHAR (
pc.effect_time,
'yyyy-MM-dd'
)
)
/**
* 方式1:未动态测算直接根据范围筛选数值(内转价格)
**/
/*
@Override
public String getInwardTransferPrice(JSONObject jsonObject) {
// 校验到期日和起息日参数
Date dueDate = jsonObject.getDate("dueDate");
Date valueDate = jsonObject.getDate("valueDate");
if(dueDate==null||valueDate==null){
throw new BoxingException("指定到期日或起息日不能为空");
}
// 根据指定参数(期限)匹配内转价格参数:期限、价格种类、生效日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
JSONObject queryCond = new JSONObject();
queryCond.put("businessType", BusinessTypeEnum.SECONDARY_MARKET.getKey());
queryCond.put("priceType", PriceTypeEnum.NZJG.getKey());
queryCond.put("effectTime",sdf.format(new Date()));
// 根据间隔日期封装期限参数
Long timeLimit = DateUtil.between(valueDate,dueDate, DateUnit.DAY);
if(timeLimit<30){
queryCond.put("timeLimit", TimeLimitEnum.LIMIT_1M.getKey());
}else if(timeLimit>30&&timeLimit<=90){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_3M.getKey());
}else if(timeLimit>90&&timeLimit<=180){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_6M.getKey());
}else if(timeLimit>180&&timeLimit<=270){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_9M.getKey());
}else if(timeLimit>270&&timeLimit<=360){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_1Y.getKey());
}else {
throw new BoxingException("到期日-起息日期限超出1Y");
}
Price price = priceMapper.getPriceByCond(queryCond);
if(price==null){
throw new BoxingException("系统未找到有效的参数,请联系相关产品经理进行处理");
}
return price.getPrice();
}
*/
private String getCalPriceByCond(String businessType, String priceType, Long timeLimit,Date valueDate) {
// 根据指定参数(期限)匹配内转价格参数:期限、价格种类、生效日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
JSONObject queryCond = new JSONObject();
queryCond.put("businessType", businessType);
queryCond.put("priceType", priceType);
// 默认指定测算生效日期默认均为当日
// queryCond.put("effectTime", sdf.format(new Date()));
// 以“最新的生效日期”为基准(以起息日作为参考,选择比起息日小且距离起息日最近的生效日期)
queryCond.put("valueDate", sdf.format(valueDate));
// 获取指定筛选条件所有价格参数(将数据从Map转化为实体Price)
Map<String, Price> priceMap = priceMapper.getPriceMapByCond(queryCond);
Price price_1M = JSONObject.parseObject(JSON.toJSONString(priceMap.get(TimeLimitEnum.LIMIT_1M.getKey())), Price.class);
Price price_3M = JSONObject.parseObject(JSON.toJSONString(priceMap.get(TimeLimitEnum.LIMIT_3M.getKey())), Price.class);
Price price_6M = JSONObject.parseObject(JSON.toJSONString(priceMap.get(TimeLimitEnum.LIMIT_6M.getKey())), Price.class);
Price price_9M = JSONObject.parseObject(JSON.toJSONString(priceMap.get(TimeLimitEnum.LIMIT_9M.getKey())), Price.class);
Price price_1Y = JSONObject.parseObject(JSON.toJSONString(priceMap.get(TimeLimitEnum.LIMIT_1Y.getKey())), Price.class);
BigDecimal res = null;
// 设置大数运算保留两位小数
DecimalFormat df = new DecimalFormat("0.00");
// 四舍五入模式df.setRoundingMode(RoundingMode.HALF_UP);
df.setRoundingMode(RoundingMode.UP);
// 计算公式:非标准期限利率=短期限标准利率+(非标准期限月或天数-短期标准期限月或天数)/相邻期限月或天数差额*(短期与长期标准利率差)
if (timeLimit < 30) {
if (price_1M == null) {
throw new BoxingException("系统未找到有效的参数-" + priceType + ":期限-'1M',请联系相关产品经理进行处理");
}
return price_1M.getPrice();
} else if (timeLimit > 30 && timeLimit <= 90) {
if (price_1M == null || price_3M == null) {
throw new BoxingException("系统未找到有效的参数-" + priceType + ":期限-'1M'或'3M',请联系相关产品经理进行处理");
}
// 动态计算数值
// res = Double.valueOf(price_3M.getPrice())+(timeLimit-90)/(180-timeLimit)*(Double.valueOf(price_6M.getPrice())-Double.valueOf(price_3M.getPrice()));
BigDecimal subVal = new BigDecimal(price_3M.getPrice()).subtract(new BigDecimal(price_1M.getPrice()));
// BigDecimal做除法需要指定精确精度否则抛异常Non-terminating decimal expansion; no exact representable decimal result
BigDecimal addVal = new BigDecimal((timeLimit - 30)).divide(new BigDecimal(90 - timeLimit), 2, BigDecimal.ROUND_HALF_UP).multiply(subVal);
res = new BigDecimal(price_1M.getPrice()).add(addVal);
} else if (timeLimit > 90 && timeLimit <= 180) {
if (price_3M == null || price_6M == null) {
throw new BoxingException("系统未找到有效的参数-" + priceType + ":期限-'3M'或'6M',请联系相关产品经理进行处理");
}
// 动态计算数值
// res = Double.valueOf(price_3M.getPrice())+(timeLimit-90)/(180-timeLimit)*(Double.valueOf(price_6M.getPrice())-Double.valueOf(price_3M.getPrice()));
BigDecimal subVal = new BigDecimal(price_6M.getPrice()).subtract(new BigDecimal(price_3M.getPrice()));
BigDecimal addVal = new BigDecimal((timeLimit - 90)).divide(new BigDecimal(180 - timeLimit), 2, BigDecimal.ROUND_HALF_UP).multiply(subVal);
res = new BigDecimal(price_3M.getPrice()).add(addVal);
} else if (timeLimit > 180 && timeLimit <= 270) {
if (price_6M == null || price_9M == null) {
throw new BoxingException("系统未找到有效的参数-" + priceType + ":期限-'6M'或'9M',请联系相关产品经理进行处理");
}
// 动态计算数值
// res = Double.valueOf(price_6M.getPrice())+(timeLimit-180)/(270-timeLimit)*(Double.valueOf(price_9M.getPrice())-Double.valueOf(price_6M.getPrice()));
BigDecimal subVal = new BigDecimal(price_9M.getPrice()).subtract(new BigDecimal(price_6M.getPrice()));
BigDecimal addVal = new BigDecimal((timeLimit - 180)).divide(new BigDecimal(270 - timeLimit), 2, BigDecimal.ROUND_HALF_UP).multiply(subVal);
res = new BigDecimal(price_6M.getPrice()).add(addVal);
} else if (timeLimit > 270 && timeLimit <= 360) {
if (price_9M == null || price_1Y == null) {
throw new BoxingException("系统未找到有效的参数-" + priceType + ":期限-'9M'或'1Y',请联系相关产品经理进行处理");
}
// 动态计算数值
// res = Double.valueOf(price_9M.getPrice())+(timeLimit-270)/(360-timeLimit)*(Double.valueOf(price_1Y.getPrice())-Double.valueOf(price_9M.getPrice()));
BigDecimal subVal = new BigDecimal(price_1Y.getPrice()).subtract(new BigDecimal(price_9M.getPrice()));
BigDecimal addVal = new BigDecimal((timeLimit - 270)).divide(new BigDecimal(360 - timeLimit), 2, BigDecimal.ROUND_HALF_UP).multiply(subVal);
res = new BigDecimal(price_9M.getPrice()).add(addVal);
} else {
throw new BoxingException("期限超出1Y统计");
}
// 参数转化保留两位小数(默认数值无%单位)
return df.format(res);
}
/**
* 方式2:动态测算-结合期限范围测算(内转价格)
**/
@Override
public String getInwardTransferPrice(JSONObject jsonObject) {
// 校验到期日和起息日参数
Date dueDate = jsonObject.getDate("dueDate");
Date valueDate = jsonObject.getDate("valueDate");
if (dueDate == null || valueDate == null) {
throw new BoxingException("指定到期日或起息日不能为空");
}
// 根据指定参数(期限)匹配内转价格参数:业务类型、期限、价格种类、生效日期调用公有方法获取动态计算的数据
return getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.NZJG.getKey(), DateUtil.between(valueDate, dueDate, DateUnit.DAY),valueDate);
}
/** 方式1:未动态测算直接根据范围筛选数值(利率下限) **/
/*
@Override
public String getRateLowerLimit(JSONObject jsonObject) {
Date dueDate = jsonObject.getDate("dueDate");
Date valueDate = jsonObject.getDate("valueDate");
if(dueDate==null||valueDate==null){
throw new BoxingException("指定到期日或起息日不能为空");
}
// 根据指定参数(期限)匹配利率下限参数:期限、价格种类、生效日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
JSONObject queryCond = new JSONObject();
queryCond.put("businessType", BusinessTypeEnum.SECONDARY_MARKET.getKey());
queryCond.put("priceType", PriceTypeEnum.LLXX.getKey());
queryCond.put("effectTime",sdf.format(new Date()));
// 根据间隔日期封装期限参数
Long timeLimit = DateUtil.between(valueDate,dueDate, DateUnit.DAY);
if(timeLimit<30){
queryCond.put("timeLimit", TimeLimitEnum.LIMIT_1M.getKey());
}else if(timeLimit>30&&timeLimit<=90){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_3M.getKey());
}else if(timeLimit>90&&timeLimit<=180){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_6M.getKey());
}else if(timeLimit>180&&timeLimit<=270){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_9M.getKey());
}else if(timeLimit>270&&timeLimit<=360){
queryCond.put("timeLimit",TimeLimitEnum.LIMIT_1Y.getKey());
}
Price price = priceMapper.getPriceByCond(queryCond);
if(price==null){
throw new BoxingException("系统未找到有效的参数,请联系相关产品经理进行处理");
}
return price.getPrice();
}
*/
/**
* 方式2:动态测算-结合期限范围测算(利率下限)
**/
@Override
public String getRateLowerLimit(JSONObject jsonObject) {
Date dueDate = jsonObject.getDate("dueDate");
Date valueDate = jsonObject.getDate("valueDate");
if (dueDate == null || valueDate == null) {
throw new BoxingException("指定到期日或起息日不能为空");
}
// 根据指定参数(期限)匹配内转价格参数:期限、价格种类、生效日期调用公有方法获取动态计算的数据
return getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.LLXX.getKey(), DateUtil.between(valueDate, dueDate, DateUnit.DAY),valueDate);
}
@Override
public Map<String, String> getCalPrice(JSONObject jsonObject) {
JSONArray dateRange = jsonObject.getJSONArray("dateRange");
Date startDate = null;
Date endDate = null;
if (dateRange != null) {
startDate = dateRange.getDate(0);
endDate = dateRange.getDate(1);
}
if (startDate == null || endDate == null) {
throw new BoxingException("指定筛选日期范围数值不能为空");
}
// 动态计算非标准期限参数
Long timeLimit = DateUtil.between(startDate, endDate, DateUnit.DAY);
// 获取不同种类的价格参数(默认生效日期为当日):利率下限、内转价格、指导价格和跨境联动价格
String llxx = getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.LLXX.getKey(), timeLimit,startDate);
String nzjg = getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.NZJG.getKey(), timeLimit,startDate);
String zdjg = getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.ZDJG.getKey(), timeLimit,startDate);
String kjldjg = getCalPriceByCond(BusinessTypeEnum.SECONDARY_MARKET.getKey(), PriceTypeEnum.KJLDJG.getKey(), timeLimit,startDate);
Map<String, String> resultMap = new HashMap<>();
resultMap.put(PriceTypeEnum.LLXX.getKey(), llxx);
resultMap.put(PriceTypeEnum.NZJG.getKey(), nzjg);
resultMap.put(PriceTypeEnum.ZDJG.getKey(), zdjg);
resultMap.put(PriceTypeEnum.KJLDJG.getKey(), kjldjg);
return resultMap;
}
解决方式:调整后台代码逻辑
先根据指定的筛选条件获取相应的timeLimit,随后根据businessType、priceType、timeLimit这三个条件去约束获取最新的价格生效时间,然后再在这个基础上筛选出最新的价格生效时间并获取参数
where p.business_type = #{queryCond.businessType}
and p.price_type = #{queryCond.priceType}
and p.time_limit = #{queryCond.timeLimit}
and to_char(p.effect_time,'yyyy-MM-dd') = (
-- 根据筛选条件获取指定筛选范围内最近的日期数据
select max(to_char(pc.effect_time,'yyyy-MM-dd'))
from boxing_param_price pc
where pc.business_type = #{queryCond.businessType}
and pc.price_type = #{queryCond.priceType}
and pc.time_limit = #{queryCond.timeLimit}
and #{queryCond.valueDate} >= to_char(pc.effect_time,'yyyy-MM-dd')
)
设置iframe高度自适应屏幕高度
https://blog.csdn.net/weixin_30505225/article/details/94981803
在引用他人的框架的时候,清理无关代码需要注意相关的css、js的联动影响
例如:清理了echarts相关的html代码,但是在页面初始化的时候引用了相关的js,js找不到指定的引用对象便会报相关的js错误,导致影响整个框架的展示
POST请求JSON数据格式规范
var submitData = {
"roleId": modifyForm.roleId.value,
"roleKey": addForm.roleKey.value,
"roleName": addForm.roleName.value,
"remark": addForm.remark.value
};
$.ajax({
url: '../../../../resources/json-data/system/role/getByPage.json',
// url: contextPath + '/aps/user/findAllUser',
// type: 'POST',
// contentType: 'application/json; charset=UTF-8',
async: true,
dataType: 'json', // json正常请求
// 跨域请求数据
// dataType: 'jsonp',
// jsonp: "jsoncallback",
data: JSON.stringify(submitData),
success: function(responseData) {
// console.log(responseData);
var errCode = responseData.errCode;
if(errCode == "0") {
// 执行操作
} else {
alert('服务器反馈^_^:从后台获取数据失败,请联系管理员!');
}
}
});
# url拼接参数请求ajax格式
$.ajax({
url: '../../../../resources/json-data/system/role/getById.json',
// url: contextPath + '/system/role/getById?roleId='+roleId,
// type: 'POST',
// contentType: 'application/json; charset=UTF-8',
async: true,
success: function(responseData) {
var errCode = responseData.errCode;
if(errCode == "0" || errCode == 0) {
// 返回状态码为0,数据正常响应,执行操作
} else {
alert('服务器反馈^_^:' + responseData.errMsg);
}
}
});
js失效:效果失效(将自定义js放在最后错误消失?)js引用顺序问题??
注意ajax请求的同步、异步问题(如果请求为异步请求,可能出现当页面加载完成数据还没有填充的情况)
动态菜单节点
此前使用bootstrap模板,动态菜单节点生成时js样式失效,后查找原因发现模板自定义引用的theme.js中使用的点击事件js定义
调整为监听模式的onclick方法,此时动态生成节点的js效果生效
引用模板:
此处引用模板使用的是jquery.metisMenu.js插件:
在不变动原生JS代码的基础上调整,则需要在初始化加载的js中调用相应的方法进行动态加载
根据模板相应找到了对应的custom-scripts.js文件,去除一些无关的js方法定义,在初始化加载菜单前先采用同步方式加载菜单数据后调用方法加载数据
通过调用$('#main-menu').metisMenu();方法实现菜单加载(可以在引入ajax请求成功后后调用)
问题分析:
直接在html引用发现还是无效,后检查html引用的js文件发现在custom-scripts.js中已经定义了$(document).ready(function () {});方法,然后在html中又重复定义初始化方法导致后面加载的节点js渲染失效
一个页面中重复定义$(document).ready方法触发的问题
$(document).ready(function () {
// 加载菜单数据
getAuthMenu01();
});
custom-scripts.js:(主页面引入相关自定义JS)
flowable维护:
数据库清理:
清理关联的Flowable数据表,随后在SYS账号下查看指定用户Flowable关联的序列,如果存在未清理干净的序列则相应在指定用户账号下之执行删除操作,
--查看当前用户的所有序列
SELECT
SEQUENCE_OWNER,
SEQUENCE_NAME
FROM
dba_sequences
WHERE
sequence_owner = 'CCB-WORK';
# 删除操作需要在相应的账号下执行(CCB-WORK)
DROP SEQUENCE ACT_HI_TASK_EVT_LOG_SEQ;
--查询当前用户的序列总数
SELECT
COUNT (*)
FROM
dba_sequences
WHERE
sequence_owner = 'CCB-WORK';
flowable清理参考说明:
https://blog.csdn.net/zhongzk69/article/details/90953578
参考链接:
https://www.cnblogs.com/wcnwcn/p/9998964.html
https://blog.csdn.net/qq_43679849/article/details/86996329
如果多次尝试启动失败,则注意查看后台报错,追踪错误原因
有可能多次启动生成了不同的序列?在oracle的sys账号中查看相应的序列,并清理相应的序列定义后重启尝试。DROP SEQUENCE ACT_HI_TASK_EVT_LOG_SEQ;报错
压缩文件:
https://www.cnblogs.com/Animation-programmer/p/8124463.html
BigDecimal数字转化异常:
注意处理空指针和空字符串数据
Object接受Double数据防止数据库数据精度丢失
/**
* Object对象转化为BigDecimal数据,处理空指针异常
**/
public static BigDecimal transferObjToBigDecimal(Object amount) {
if(StringUtils.isEmpty(String.valueOf(amount))){
// 获取的数据为nul或空字符串,则返回0
return new BigDecimal("0.00");
}
// 正常返回转化后的BigDecimal数据
return new BigDecimal(String.valueOf(amount));
}
springboot+vue前后端整合:将vue导出的静态资源文件放在后台工程的resources资源文件夹下随后创建static文件夹存放:
springboot:shiro拦截配置过滤静态资源
vue:配置相应的导出路径
文件压缩
https://www.cnblogs.com/jpfss/p/9830594.html
批量操作空指针异常:
考虑是实体类没有建立映射的问题,或者是新增指定的实体属性配置没有对应通过set("field_key",xxx)赋值
echache.xml配置参考:
https://www.cnblogs.com/yudar/p/4949486.html
F11全屏切换,内置Frame需要重新刷新方能自适应相应的高度,否则其高度无法自动刷新
bootstrap模态框添加滚动条:style="height:800px; overflow:scroll;
http://localhost:8081/report/pageJump?url=WEB-INF/view/show1.html
flowable单人节点跳转参考:
https://blog.csdn.net/qq_36760953/article/details/91456688
https://www.cnblogs.com/liuwenjun/p/10173004.html
flowable节点
网上提示关闭tomcat的reload属性即可,经常报异常但不影响系统使用
14.flowable 已办任务列表查询:
https://blog.csdn.net/liuwenjun05101/article/details/103420120?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-9-103420120.nonecase&utm_term=flowable%E4%BB%A3%E5%8A%9E
springboot集成druid配置多数据源连接:
https://cloud.tencent.com/developer/article/1413966
flowable參考:
http://dazhuanlan.com/2020/01/06/5e128b27059e9/?cf_chl_jschl_tk=c045173e035b54a4bfe8ea98f9539738e735eed3-1599920125-0-ASxV7lpfc3z3sprcF1y6SA4Dmw_cCdi5w3l1mFaJHhZ51TnC2GHJyTvPD8KOMKbBw5RxGq9DxZBJqBkrTbKieb7ZN-BsZXZHltROiAhrKxn-q2IZlhyo8HduTE3UAZYRedLKmR8EY8Pt4kp2_yX1x-rwh5BbFRe-L64BKhbp0zxHeY-Qd4N191xqxJt22BntGk6L2342yoCcWU3CqiLdam7oskaNdHRehTO3fCvFaTZkSCkdORMAbSfyyYy5XSUnYqItrbLZl7dNamhTzqJZxI8uCjHrFUYk97-1a-z7NWf6FQIr-Xe0Lr2_0gtOgWH98g
https://blog.csdn.net/qq_35098526/article/details/87818988
2020-09-02 前端待整理
单元格样式调整
报价表导出加入单元格边框样式
excel台账数据导出限定格式统一:日期格式统一、数值格式统一(调整为可供计算的数值型)
poi导出设置金额对应单元格格式为数值:如果单个单元格设置代码累赘,指定某列的单元格格式即可
通过设置指定列单元格样式(设定金额相关列单元格格式(默认四舍五入,保留两位小数))
# 设置指定列单元格格式
CellStyle amountStyle = workbook.createCellStyle();
DataFormat amountDataFormat = workbook.createDataFormat();
amountStyle.setDataFormat(amountDataFormat.getFormat("#,##0.00"));
sheet.setDefaultColumnStyle(5, amountStyle);
# 设置指定单元格值
tempRow.createCell(cellIndex++).setCellValue(CommonUtil.transferDouble(historyTrade.getBusinessAmt()));//原参考:CommonUtil.formatAmt(historyTrade.getBusinessAmt())
参考链接:https://blog.csdn.net/huyuyang6688/article/details/49786227
shiro实现用户多角色切换
参考:
https://bbs.csdn.net/topics/394578738
不同类型用户登录处理:shiro参考
https://blog.csdn.net/weixin_42803027/article/details/84836084
实现思路:
将当前指定用户角色存入指定用户session中,每次权限缓存刷新的时候从当前的session中获取当前指定的用户角色信息后刷新用户权限
即登录时指定一个默认角色,这个默认角色可以没有任何功能访问权限,随后用户切换相应的角色ID调用后台接口更新数据缓存(页面重新刷新)
https://blog.csdn.net/jizhunboss/article/details/53606808
将当前指定的用户角色数据存入登录用户信息缓存中,从当前登录用户中获取关联的用户数据
在线用户监听
AOP:实时同步session数据,登录、退出操作触发
针对由于登录过期导致下线的用户,定时器触发操作