持续更新
一:内部系统页面响应慢
环境背景:jsp+springmvc+java+http接口+vue
应用场景:页面点开,一直转圈空白
优化:1、页面数据优先静态加载(vue前后端分离就不会有这问题),部分数据异步请求
2、后台分析调用对方接口,使用多线程调用,加快接口请求速度
3、分享对方接口响应时效,帮助对方修改
1、数据请求异步
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>首页 - 个人选股系统 V5.87</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<script src="/js/jquery-1.12.4.min.js"></script>
<!-- <script>
$(function(){
$.ajax({
// 配置ajax的参数
// url:'请求数据的接口地址'
url:'/index_data',
// type:请求方式
type:'get',
// dataType:返回的数据格式 html xml ***json text
dataType: 'json',
// data:{} 发送的数据
// success:请求成功之后要执行的命令 -- 回调函数
success: function(dat){
// 接收数据,显示数据
console.log(dat)
var str = '<tr><th>序号</th><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th>前期高点日期</th><th>添加自选</th></tr>';
// alert(dat)
// 遍历dat 一个表头 + 94个tr数据 -- 将这95个tr放到表格里面
for(var i=0;i<dat.length;i++)
{
// -1-- 字典对象里面的id值 00007 -- 字典里面的code值
str += '<tr><td>'+ dat[i].id +'</td><td>'+ dat[i].code+'</td><td>'+ dat[i].sname+'</td><td>10.01%</td><td>4.40%</td><td>全新好</td><td>16.05</td><td>2017-07-18</td><td><input type="button" value="添加" name="toAdd"></td></tr>';
}
$('.table').html( str )
},
// error 请求失败之后要执行的命令 -- 回调函数
error: function(){
alert('请求超时')
}
})
})
</script> -->
<!-- ajax函数内部工作中只配置基本参数,success拿到ajax函数的外面变成done(),error拿到ajax函数的外面变成fail() -->
<!-- <script>
$(function(){
$.ajax({
url:'/index_data',
type:'get',
dataType:'json'
})
.done(function(dat){
// 成功
var str = '<tr><th>序号</th><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th>前期高点日期</th><th>添加自选</th></tr>';
// alert(dat)
// 遍历dat 一个表头 + 94个tr数据 -- 将这95个tr放到表格里面
for(var i=0;i<dat.length;i++)
{
// -1-- 字典对象里面的id值 00007 -- 字典里面的code值
str += '<tr><td>'+ dat[i].id +'</td><td>'+ dat[i].code+'</td><td>'+ dat[i].sname+'</td><td>10.01%</td><td>4.40%</td><td>全新好</td><td>16.05</td><td>2017-07-18</td><td><input type="button" value="添加" name="toAdd"></td></tr>';
}
$('.table').html( str )
})
.fail(function(){
alert('请求失败')
})
})
</script> -->
<script>
$(function(){
$.get('/index_data', function(dat){
var str = '<tr><th>序号</th><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th>前期高点日期</th><th>添加自选</th></tr>';
// alert(dat)
// 遍历dat 一个表头 + 94个tr数据 -- 将这95个tr放到表格里面
for(var i=0;i<dat.length;i++)
{
// -1-- 字典对象里面的id值 00007 -- 字典里面的code值
str += '<tr><td>'+ dat[i].id +'</td><td>'+ dat[i].code+'</td><td>'+ dat[i].sname+'</td><td>10.01%</td><td>4.40%</td><td>全新好</td><td>16.05</td><td>2017-07-18</td><td><input type="button" value="添加" name="toAdd" data-code="'+dat[i].code+'"></td></tr>';
}
$('.table').html( str )
}, 'json')
// 增加关注
// 添加按钮 单击,把股票code值发送到接口 -- 接口返回不要重复添加或关注成功文字
// $('input').click(function(){
// alert(1)
// })
$('.table').delegate('input', 'click', function(){
// alert(2)
// k="v" 自定义html属性的形式获取code值
// 访问自己这个input标签的data-code属性值即可
// prop只能访问控制w3c定义的html属性,自定义的用attr函数访问和控制,attr和prop的用法完全相同
// alert($(this).prop('data-code'))
// alert($(this).attr('data-code'))
var myCode = $(this).attr('data-code')
$.ajax({
url:'/add_data',
type:'get',
dataType:'text',
data:{code: myCode}
})
.done(function(dat){
alert(dat)
})
.fail(function(){
alert('请求超时')
})
})
})
</script>
</head>
<body>
<div class="navbar navbar-inverse navbar-static-top ">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#" class="navbar-brand">选股系统</a>
</div>
<div class="collapse navbar-collapse" id="mymenu">
<ul class="nav navbar-nav">
<li class="active"><a href="">股票信息</a></li>
<li><a href="/center.html">个人中心</a></li>
</ul>
</div>
</div>
</div>
<div class="container" id="container">
<div class="container-fluid">
<table class="table table-hover">
<!-- <tr><th>序号</th><th>股票代码</th><th>股票简称</th><th>涨跌幅</th><th>换手率</th><th>最新价(元)</th><th>前期高点</th><th>前期高点日期</th><th>添加自选</th></tr>
<tr><td>1</td><td>000007</td><td>全新好</td><td>10.01%</td><td>4.40%</td><td>全新好</td><td>16.05</td><td>2017-07-18</td><td><input type="button" value="添加" name="toAdd"></td></tr> -->
</table>
</div>
</div>
</body>
</html>
2、线程池,开启多线程
2.1 自定义线程池
private ThreadPoolExecutor poolExecutor;
/**
* 利用@service和@postConstruct初始化线程池
* @postConstruct无法注入,启动error(待解决)
**/
@PostConstruct
private void init(){
poolExecutor = new ThreadPoolExecutor(5,5,60L, TimeUnit.SECONDS,
new SynchronousQueue<>(), (ThreadFactory) new LinkedBlockingQueue<Runnable>(),new ThreadPoolExecutor.CallerRunsPolicy());
}
/**
* 开启线程调用
**/
public ResultMsg getMethod1(String mUrl, List<NameValuePair> nameValuePairList){
// String mUrl =mNetwork+"queryOrderList";
// MapCastNameValuePairUtil mapCastNameValuePairUtil=new MapCastNameValuePairUtil();
// List<NameValuePair> nameValuePairList =mapCastNameValuePairUtil.mapcastNameValue(map1);
//异步请求对方接口返回数据
ResultMsg resultMsg= (ResultMsg) poolExecutor.submit(()->HttpClientTools.SendPost(mUrl,nameValuePairList,new NetPlatModel<PrizeOrder>()));
return resultMsg;
}
2.2 使用内置线程,固定线程池
整理
// Creates a thread pool that reuses a fixed number of threads
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
CompletableFuture<ResultMsg> fl1 = CompletableFuture.supplyAsync(new Supplier<ResultMsg>() {
@Override
public ResultMsg get() {
return recordService.getPrize(mUrl,nameValuePairList);
}
}, fixedThreadPool
);
CompletableFuture<ResultMsg> fl2 = CompletableFuture.supplyAsync(new Supplier<ResultMsg>() {
@Override
public ResultMsg get() {
return recordService.getHMCPrize(hUrl,hnameValuePairList);
}
}, fixedThreadPool
);
ResultMsg resultMsg = null;
ResultMsg resultMsg1 = null;
try {
resultMsg = fl1.get();
} catch (InterruptedException e) {
logger.error(e);
} catch (ExecutionException e) {
logger.error(e);
} catch (Exception e) {
logger.error(e);
}
try {
resultMsg1 = fl2.get();
} catch (InterruptedException e) {
logger.error(e);
} catch (ExecutionException e) {
logger.error(e);
} catch (Exception e) {
logger.error(e);
}
调用第三方接口(开启多线程请求,数据没有一致性。如果有,采用返回结果确定Future接受确定结果,再做请求)
public ResultMsg getPrize(String Url, List<NameValuePair> nameValuePairList){
LocalDateTime time1 =LocalDateTime.now();
logger.info("会员中心活动及奖品兑换接口,开始时间:"+time1);
ResultMsg resultMsg= HttpClientTools.SendPost(Url,nameValuePairList,new NetPlatModel<PrizeOrder>());
LocalDateTime time2 =LocalDateTime.now();
logger.info("会员中心活动及奖品兑换接口,结束时间:"+time2+",耗时:"+(time2.toInstant(ZoneOffset.of("+8")).toEpochMilli()-time1.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
return resultMsg;
}
public ResultMsg getHMCPrize(String Url, List<NameValuePair> nameValuePairList){
LocalDateTime time1 =LocalDateTime.now();
logger.info("HMC活动及奖品兑换接口,开始时间:"+time1);
ResultMsg resultMsg= HttpClientTools.SendPost(Url,nameValuePairList,new NetPlatModel<HMCPrizeOrder>());
LocalDateTime time2 =LocalDateTime.now();
logger.info("HMC活动及奖品兑换接口,结束时间:"+time2+",耗时:"+(time2.toInstant(ZoneOffset.of("+8")).toEpochMilli()-time1.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
return resultMsg;
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
@RequestMapping("prize")
public ModelAndView queryPrize(HttpServletRequest request){
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
IResponse responseData = new IResponse("/record/prizeList");
ModelAndView view = request(responseData);
String mobilephone=request.getParameter("mobilephone");
String startDate=request.getParameter("startDate");
String endDate=request.getParameter("endDate");
String mStartDate =startDate+" 00:00";
String hStartDate =startDate+" 00:00:00";
String mEndDate =endDate+" 23:59";
String hEndDate =endDate+" 23:59:59";
HashMap map=new HashMap<String,String>(5);
map.put("mobileCode",mobilephone);
map.put("startDate",mStartDate);
map.put("endDate",mEndDate);
HashMap sysparam =new HashMap<String,String>(3);
sysparam.put("channelSrc","CSS");
String busiparamS= JSONUtils.toJSONString(map);
String sysparamS=JSONUtils.toJSONString(sysparam);
HashMap<String, String> map1 = new HashMap<>(5);
map1.put("sysparam",sysparamS);
map1.put("busiparam", busiparamS);
map1.put("ifAcceptCacheData", "N");
String mNetwork =Global.getProperty("hyzx_incrementService");
String mUrl =mNetwork+"queryOrderList";
MapCastNameValuePairUtil mapCastNameValuePairUtil=new MapCastNameValuePairUtil();
List<NameValuePair> nameValuePairList =mapCastNameValuePairUtil.mapcastNameValue(map1);
HashMap hMap =new HashMap<String,String>(5);
hMap.put("mobileCode",mobilephone);
hMap.put("orderStartDate",hStartDate);
hMap.put("orderEndDate",hEndDate);
String hbusiparamS= JSONUtils.toJSONString(hMap);
HashMap<String, String> map2 = new HashMap<>(5);
map2.put("sysparam",sysparamS);
map2.put("busiparam", hbusiparamS);
map2.put("ifAcceptCacheData", "N");
String hNetwork =Global.getProperty("hyzx_HMC_MallService");
String hUrl =hNetwork+"queryHmcOrderList";
List<NameValuePair> hnameValuePairList =mapCastNameValuePairUtil.mapcastNameValue(map2);
CompletableFuture<ResultMsg> fl1 = CompletableFuture.supplyAsync(new Supplier<ResultMsg>() {
@Override
public ResultMsg get() {
return recordService.getPrize(mUrl,nameValuePairList);
}
}, fixedThreadPool
);
CompletableFuture<ResultMsg> fl2 = CompletableFuture.supplyAsync(new Supplier<ResultMsg>() {
@Override
public ResultMsg get() {
return recordService.getHMCPrize(hUrl,hnameValuePairList);
}
}, fixedThreadPool
);
ResultMsg resultMsg = null;
ResultMsg resultMsg1 = null;
try {
resultMsg = fl1.get();
} catch (InterruptedException e) {
logger.error(e);
} catch (ExecutionException e) {
logger.error(e);
} catch (Exception e) {
logger.error(e);
}
try {
resultMsg1 = fl2.get();
} catch (InterruptedException e) {
logger.error(e);
} catch (ExecutionException e) {
logger.error(e);
} catch (Exception e) {
logger.error(e);
}
/*
* 會員中心處理
* */
ArrayList<PrizeOrder> PrizeOrderList=new ArrayList<PrizeOrder>();
Map<Integer,String> PrizeOrderListhidden = new HashMap<Integer,String>();
Map<String,String> addresshidden = new HashMap<String,String>();
PrizeOrderListhidden.clear();
if (null==resultMsg||null==resultMsg1){
// view.addObject("prizeOrderMsg",new ResultMsg());
view.addObject("Msg","N");
}else{
view.addObject("Msg","Y");
if (resultMsg.isFlag()) {
NetPlatModel result = (NetPlatModel) resultMsg.getResult();
ArrayList<JSONObject> jsonObjects =result.getRespData();
for(int i=0;i<jsonObjects.size();i++) {
PrizeOrder prizeOrder=jsonObjects.get(i).toJavaObject(PrizeOrder.class);
String moblie = prizeOrder.getReceiveCall();
PrizeOrderListhidden.put(PrizeOrderListhidden.size()+1,moblie);
moblie =DesensitizeUtil.mobile(moblie);
prizeOrder.setReceiveCall(moblie);
String address =prizeOrder.getShippingAddress();
addresshidden.put(prizeOrder.getOrderCode(),address);
if(StringUtil.isNotNull(address)) {
prizeOrder.setShippingAddress(DesensitizeUtil.address(address));
}
PrizeOrderList.add(prizeOrder);
}
}else {
view.addObject("prizeOrderMsg",resultMsg);
}
/*
* HMC處理
* */
if (resultMsg1.isFlag()) {
NetPlatModel result1 = (NetPlatModel) resultMsg1.getResult();
ArrayList<JSONObject> jsonList= result1.getRespData();
if(jsonList!=null&&jsonList.size()>0){
for (int i=0;i<jsonList.size();i++) {
HMCPrizeOrder hmcPrizeOrder=jsonList.get(i).toJavaObject(HMCPrizeOrder.class);
PrizeOrder prizeOrder =new PrizeOrder(hmcPrizeOrder);
PrizeOrderList.add(prizeOrder);
}
}
for(int t=0; t<PrizeOrderList.size();t++){
PrizeOrderListhidden.put(PrizeOrderListhidden.size()+1,PrizeOrderList.get(t).getReceiveCall());
//手机号 脱敏
String moblie=PrizeOrderList.get(t).getReceiveCall();
String str =DesensitizeUtil.mobile(moblie);
PrizeOrderList.get(t).setReceiveCall(str);
//地址脱敏
String address =PrizeOrderList.get(t).getShippingAddress();
if(!addresshidden.containsKey(PrizeOrderList.get(t).getOrderCode())) {
addresshidden.put(PrizeOrderList.get(t).getOrderCode(),address);
}
if(address!=null){
logger.info("未脱敏"+address);
String add =DesensitizeUtil.address(address);
logger.info("已脱敏"+add);
PrizeOrderList.get(t).setShippingAddress(add);
}
}
}else {
view.addObject("prizeOrderMsg",resultMsg1);
}
}
fixedThreadPool.shutdown();
view.addObject("prizeOrderList",PrizeOrderList);
Global.setRemoteCache("PrizeOrderListhidden"+Global.getThreadUser().getUserCode(), PrizeOrderListhidden);
Global.setRemoteCache("PrizeOrderaddresshidden"+Global.getThreadUser().getUserCode(), addresshidden);
return view;
}
3、对各个接口调用,打印时间。针对性的优化处理