本文主要记录几种提升基于深度学习的图像语义分割精度的方法,以防忘记!
By zhengzibing2011, 2017年10月21日-星期六
1
1.图像语义分割面临的挑战
(1).特征分辨率减小:主要是由神经网络中的重复最大池化和降采样(stride跨越)操作造成的,而采用此种操作的原因是
A.降维,以免参数过多难以优化;
B.基于DL的语义分割是从用于分类任务的CNN转化而来,而在分类任务中,分类器要求对输入的空间变换具有不变性,池化恰能满足这样的要求。
(2).不同scale下的目标存在的状况:主要是目标在multi-scale图像中的状态造成的,因为在同一种尺度下,不同目标的特征往往响应并不相同。如需要在较大的尺度下才能较好地提取图像中比较小的目标,而较大的目标为了获取全局性信息也必须在较小的尺度下才能实现。
(3). CNN的空间不变性造成定位精度的下降:对于分割任务而言,由于pooling操作引起的分类器对输入的空间变换具有不变性丢失空间信息,内在的限制了分割的空间精度。
2.潜在的解决方法
FCN作为将CNN应用于semantic segmentation的forerunner,贡献巨大。但不可回避,其提出的方法具有一些不足。为保证却终的feature map不至于过小,FCN的conv1引入pad=100,引入了较大的噪声;
32倍upsample(deconvolution)非常粗糙,而且deconvolution的filter不可学习; skip architecture虽能有效提高精度,但需要3次训练即FCN-32s->FCN-16s->FCN-8s。除skip architecture外。随着研究的深入,针对以上挑战,有以下几种方法解决:
(1). Encoder-Decoder结构
采用此种思想的代表为DeconvNet,SegNet,其基本思想是采用一种对称结构将由于pooling操作而减小的feature map通过逐步的upsample逐渐恢复到原图像大小,同时在upsample阶段,融合了subsample中pooling index,具体细节可参见原文。
(2). Atrous convolution
feature map的减小是由于pooling造成的,为确保一定精度的feature map,能否不使用或减少使用pooling呢?理论上是可行的,但如果这样做会使得需要优化的参数过多,重要的是难以基于以前的model进行fine-tuning,atrous convolution解决了这个问题。
在DeepLab中令pool4,pool5的stride=1,再加上1 padding,这样经过pooling后feature map大小不变,但后层的感受野发生了变化,为使感受野不变,后面的卷积层使用atrous convolution,其作用是在不增加参数的前提下,增加感受野。因此,解决了feature map空间分辨率下降的问题。
(3). ASPP
针对不同scale下的目标存在的状况问题,可通过两种方法解决:
A.标准的多尺度处理方法,用共享相同参数的并行CNN的分支,从不同尺度的Input image中提取score map,然后进行双线性差值,最终对它们进行融合,在不同尺度上获得每个位置的最大响应。训练和测试时均这样处理,比较繁琐的是需要计算输入图像的每个尺度在各layer上的特征响应。
B.基于任意尺度上的区域都可以用在这个单一尺度上重采样卷积特征进行有效地分类的思想,使用多个不同采样率上的多个并行多空卷积,每个采样率上提取的特征再用单独的分支处理,融合生成最后的结果。
(4). FC-CRF
CRF几乎可以用于所有的分割任务中图像精度的提高。CNN可用于对图像中的目标进行分类并预测出目标的大致位置,但并不能真正描绘他们的边界。因此,将DCNN的识别能力和全连接CRF优化定位精度耦合在一起,能成功的处理定位挑战问题,生成了的语义分割结果。全连接CRF理论较为复杂,在此不作阐述。类似的概率图模型(PGM)还有MRF,G-CRF(高斯-条件随机场)。
3.总结
目前,暂且先记录以上4种提高分割精度的方法。后续若有新的方法,予以追加!
————————————————
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
JS的作用域一共有三个范围,分别是:
全局作用域
定义在所有函数之外的变量,其作用范围是在整个脚本中
局部作用域(函数作用域)
使用var定义在函数内部的变量,其作用范围是整个函数结构,超出函数 {} 花括号的范围则不能使用。
块级作用域
ES6声明变量的方式:let / const
let 变量名 = 变量值;
const 变量名 = 变量值;
PS:注意: 使用const修饰的变量,赋值确定后,不允许再重新赋值。(一般修饰常量或者数组对象之类的)
而且必须给予初始值。
const修饰数组对象后虽然不可以再对变量进行等号赋值了,但是还是可以用数组和对象的方法去改变它的内部结构。
IIFE(立即调用函数表达式 - - 自执行匿名函数):
英文全名:(Immediately Invoked Function Expression)
语法:
//这三种都属于IIFE写法
(function () {})();
(function () {}());
+function () {}();
//作用与ES6当中的let是一样的,只不过用这个语法是为了解决个别浏览器的兼容问题。
1
2
3
4
5
声名提升:
将使用var定义的变量声名提升到对应作用域的最顶部,赋值部分位置不变。
使用ES6的let与const没有声名提升。
函数的定义也存在声名提升:
如果是声名的方式定义的函数,将整个函数(声名及函数主体)都提升到作用域的最顶部。
如果是表达式的方式定义的函数,只提升声名,不提升赋值(函数主体部分)
示例:
//在声名函数前面输出它。输出的结果就是整个声名函数的内容
console.log(testArg)
function testArg(a, b, c){
console.log(arguments)
}
1
2
3
4
5
输出结果:
//在函数表达式之前输出函数
console.log(testArg)
var testArg = function(a, b, c) {
console.log(arguments)
}
1
2
3
4
5
输出结果:
这就是声名提升的特点,只提升声名部分,不提升赋值部分。大家一定要牢牢记住哦~
————————————————
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
很多朋友在开发的过程中要把ECharts图标做成自适应浏览器宽高的效果。于是去翻看ECharts官网发现了resize方法,结果用了之后发现没用,而且根本不知道什么原因。
解决办法:
不能给ECharts的容器设置固定的宽高。
宽度要写百分比
高度要写vh
然后再搭配resize方法才可以实现根据浏览器大小而改变大小的功能
示例代码:
let ECharts = echarts.init(document.getElementById('wrapBox'));
//ECharts的配置项和数据
let option = {
title: {
text: 'demo'
},
tooltip: {},
legend: {
data: ['dataSource']
},
xAxis: {
data: ['aa', 'bb', 'cc']
},
yAxis: {},
series: [{
name: 'dataSource',
type: 'bar',
data: [2, 5, 6],
}]
};
//配置图表数据及配置项
ECharts.setOption(option);
//根据浏览器大小改变大小
window.onresize = () => {
ECarts.resize();
//如果有多个表变动在下方依次写下去就可以了
}
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
推荐使用 vue-wechat-title
vue-wechat-title作用
Vuejs 单页应用在iOS系统下部分APP的webview中 标题不能通过 document.title = xxx 的方式修改 该插件只为解决该问题而生(兼容安卓)
已测试APP
微信
QQ
支付宝
淘宝
安装
npm install vue-wechat-title --save
1
用法
1,在 main.js 中引入
import VueWechatTitle from 'vue-wechat-title'
Vue.use(VueWechatTitle)
1
2
2,在路由文件 index.js 中给每个路由添加 title
// 挂载路由
const router = new Router({
mode: 'history',
routes:[
{
path: '/',
name: 'Index',
component: Index,
meta: {
title: '首页' // 标题设置
}
},
{
path: '/lists',
name: 'Lists',
component: Lists,
meta: {
title: '列表' // 标题设置
}
}
]
});
3,在 app.vue 中修改 router-view 组件
<router-view v-wechat-title='$route.meta.title'></router-view>
1
自定义加载的图片地址 默认是 ./favicon.ico 可以是相对或者绝对的
<div v-wechat-title="$route.meta.title" img-set="/static/logo.png"></div>
1
ok !重启看看
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
在 C 语言中
1、char a[10] = {"China"} 中,这个 a 占用多少字节?
答:占用 10 个字节。
解析:上面代码对 a 做了赋值的操作,
a[0]='C' ,a[1]='h' ,a[2]='i' ,a[3]='n' ,a[4]='a' ,a[5]='\0',a[6]='\0',a[7]='\0',a[8]='\0',a[9]='\0'
所以,它占用的是 10 个字节。
2、如果单指 ”China“ ?
答:共 6 个字节。China 占 5 个字节,最后以 '\0' 结束,占 1 个字节。
在 Java 语言中
1、String s = "China"; 占多少字节?
答:占 5 个字节。
System.out.println(Charset.defaultCharset());//获取ide默认编码类型
String s = new String("China".getBytes());
byte[] b = s.getBytes();
System.out.println("" + b.length);
以上代码,可以输出 "China" 所占的字节长度为 5
2、String s = "中国"; 占多少字节?
答:如果是 汉字 的情况需要考虑编码。
(1)GBK 编码(ide默认)时,每一个汉字占用 2 个字节,那么中国占 4 个字节。
(2)UTF-8 编码时,每一个汉字占用 3 个字节,那么中国占用 6 个字节。
3、转码问题,GBK 转 UTF-8 时,字节占用会变大吗?反过来呢?
//获取的是 UTF-8编码
System.out.println(Charset.defaultCharset());
String s;
try {
s = new String("中国".getBytes(),"GBK");
byte[] b = s.getBytes();
System.out.println("" + b.length);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
如上代码是:UTF-8 转 GBK 编码格式,s 长度从 6 字节变为 9 字节。
s 内容变化:中国 —> 涓浗
因为当前编码是 UTF-8,转码之后变成了 3 个文字,占用 9 个字节。然而,反过来的情况是这样的:
中国 (gbk) —> ?й? (utf-8)
s 长度从 4字节 变成了 4字节,虽然长度没发生改变,但是文字已经改变。这里的 ? 占用 1 个字节。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
如果说 npm 的大新闻,莫过于之前的 left-pad 撤包事件,event-stream 投毒事件,Ant Design 彩蛋事件。使得很多前端开发者又开始重新思考 npm 生态时候真的存在问题?
今天我们文章的主角是 memwatch,一个用来帮助我们检查 Node.js 是否存在内存泄漏的库,和这个库传奇的一生。
2012 年 02 月 06 日,一位 Mozilla 的工程师 lloyd 创建了这个库,并写了一篇博文“Is My NodeJS Program Leaking?”(我的 Node.js 程序是否存在内存泄漏?)。这个包最初被命名为 gcstats,代码上传到了 github。
6 月 27 日,npm 包改名为 memwatch,发布 0.1.1 版。
7 月 4 日,lloyd 为这个库添加了开源许可协议:WTFPL,发布 0.1.2 版。很多人对这个开源许可协议可能比较陌生,WTFPL 的全称是 Do What The Fuck You Want To Public License,中文译名:你他妈的想干嘛就干嘛公共许可证。也许就是这份协议开启了 memwatch 库不寻常的一生。
2013 年 3 月 14 日,作者 lloyd 提交了最后一次代码,发布了 0.2.2 版本。支持的 Node.js 版本为 0.6.0。随后这个库再也没有更新过。
从作者的博文和推文可以看到,作者在 2014 年离开了 Mozilla。而从作者的 github 动态更可以看出,作者应该是转入了 golang 阵营。
2014 年 6 月 28 日,作者的一位前同事 deepak1556 fork 了这个库,增加了对 Node.js 0.11 的支持,并发起了合并请求。但是作者并没有回复,也没有合并此次请求。此时距离原作者放弃这个库也已经过去一年多了。
2015 年 2 月 7 日,marcominetti 又 fork 了 deepak1556 的库,增加了对 Node.js 0.12 的支持,并向原库发起了合并请求,同样没有得到作者的任何回复。于是 marcominetti 决定自立门户,于是将 memwatch 改名为 memwatch-next 发布到了 npm。
2017 年 1 月 27 日,如同前两位维护者一样,marcominetti 也最终放弃了继续更新这个库。到此时,此库支持的 Node.js 版本为 4、5、6。
2018 年 5 月 6 日,eduardbcom 又 fork 了 marcominetti 的库,增加了 Node.js 9 的支持,并且放弃了对 Node.js 9 以下所有版本的支持。改名为 node-memwatch 并发布到了 npm。随后再也没有更新过代码。
2018 年 7 月 17 日,一位开发者 dyatko 又 fork 了 eduardbcom 的库,增加了对 Node.js 8 的支持,并向原库发起了合并请求,同样没有得到作者的任何回复。
但在此次 pr 的评论中,另一位开发者说,airbnb 也 fork 了 marcominetti 的库,并改名为 @airbnb/node-memwatch 发布到了 npm。
有了大厂接手,也算是这个库最终的归宿吧。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
把项目放在wampserver的www目录下,启动wampserver,并且浏览器打开后手动修改url为localhost
index.js=》getData():
ajax.js以及index。js对它的调用:
ajax的参数:method、data、url都是字符串
index.js =》getData()=》调用ajax
ajax('GET', 'http://localhost/web/ajax/waterfall2/src/js/getPics.php', addDom, 'cpage=' + num, true)
并且url是localhost下——localhost/web/ajax/waterfall2/src/js/getPics.php
不是直接图片资源地址
图片资源地址写在php中,只管调用就行
data:
ajax调用是data是这样的=》'cpage=' + num
测试用的data.txt:
一个数组里有很多对象,每个对象都是一张图片的全部信息,每条信息都是json.stringify格式
所以测试用ajax的callback这样写:
function addDom(data) {
console.log(JSON.parse(data));
}
这个data不是自己定义的,是xhr.responseText,是接口的数据
这个data是callback的参数
回调函数的data参数和使用方法:
xhr.onreadystatechange = function() {
////////状态改变
if(xhr.readyState == 4) {
if(xhr.status == 200) {
callback(xhr.responseText);
////////满足两个条件时,callback才获取数据成功,才能用数据做些什么
}else {
console.log('error');
}
}
}
ajax()中callback是参数,而callback的定义和对数据的操作通常在ajax()调用之后
例如:
(1)
ajax('GET', 'http://localhost/web/ajax/waterfall2/src/js/data.txt', addDom, 'cpage=2', true);
function addDom(data) {
console.log(JSON.parse(data));
}
如此简单明了
(2)
function getData() {
// if(!flag) {
// flag = true;
// ajax('GET', 'http://localhost/web/ajax/waterfall2/src/js/getPics.php', addDom, 'cpage=' + num, true)
// num++;
// }
// }
// getData();
// function addDom(data) {
……
}
回来…………
ajax中的data在本例中是字符串'cpage=' + num 或者 'cpage=2'这种
get中作用:
xhr.open(method, url + '?' + data + '&timer=' + timer, flag);
post中作用:
xhr.send(data);
话说回来…………
都是获取数据,data.txt和getPics.php区别:
一个只有第2页的地址,一个是动态获取很多页数据
反正就那么传吧
而ajax
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
前面介绍了Vue中组件的创建方式和data及methods属性,本文我们来做一个Vue组件的切换案例,效果如下:
这个效果相信大家都能搞定,本文希望通过这个案例来加深下组件的使用,
Vue 组件切换案例
基础页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
},
methods: {
}
})
</script>
</body>
</html>
一、通过v-if控制实现
首先我们通过前面介绍的v-if标签来实现下这种效果
1.创建组件
创建我们需要的两个全局组件,并通过标签使用。
<div id="app">
<login></login>
<register ></register>
</div>
<script>
// 创建登录的组件
Vue.component("login",{
template: "<h3>这是一个登录LOGIN组件</h3>"
})
// 创建注册的组件
Vue.component("register",{
template: "<h3>这是一个注册组件</h3>"
})
var vm = new Vue({
el: "#app",
data: {
},
methods: {
}
})
</script>
2.控制显示
添加链接标签,通过 v-if 和 v-else 标签来控制显示和隐藏,如下
效果
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<a href="" @click.prevent="flag=true">登录</a>
<a href="" @click.prevent="flag=false">注册</a>
<!--注意: v-if v-else-if v-else 使用^_^ -->
<login v-if="flag"></login>
<register v-else></register>
</div>
<script>
// 创建登录的组件
Vue.component("login",{
template: "<h3>这是一个登录LOGIN组件</h3>"
})
// 创建注册的组件
Vue.component("register",{
template: "<h3>这是一个注册组件</h3>"
})
var vm = new Vue({
el: "#app",
data: {
flag: false
},
methods: {}
})
</script>
</body>
</html>
二、通过component标签来实现
除了上面介绍的这种方式以外我们还可以通过Vue组件中给我们提供的一个component标签来实现
Vue提供了 component 来展示对应名称的组件,component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称
效果
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<component :is="comName"></component>
</div>
<script>
// 创建登录的组件
Vue.component("login",{
template: "<h3>这是一个登录LOGIN组件</h3>"
})
// 创建注册的组件
Vue.component("register",{
template: "<h3>这是一个注册组件</h3>"
})
var vm = new Vue({
el: "#app",
data: {
comName: "login"
},
methods: {
}
})
</script>
</body>
</html>
35
36
37
38
39
组件切换-动画
前面我们介绍了 动画 的使用,那么刚好我们可以在切换的时候把动画效果给加上。
添加动画样式:
<style>
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(150px) ;
}
.v-enter-active,
.v-leave-active{
transition: all 1s ease;
}
</style>
组件包裹 标签
效果
我们发现动画切换的时候两个是一块执行的,这时我们可以在 transition 标签添加一个 mode属性 来设置动画的模式
搞定~
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
第一种情况
新增框内既有各类保险金额,也有保险总费用。当输入一类保险金额时,保险总费用自动累加显示,点击保存之后将所有数据插入数据库。然后查询查询显示在结果列表即可。如下图:
第一种情况可以在前端js中写一个计费方法。获取每个不同类的保险金额,值取到之后在点击保存之前将变量中的值赋值给保险总费用,然后点击保存。代码如下(js中计费的方法写在代码一开始中的method{}中,也就是新增,查询,删除,修改下方即可):
//计费方法
Vehicle_sum:function(){
var sum = /^[0-9]\d{0,5}$/;
var trafficCompulsoryInsuranceCost=$("#vehicleInsurance_add_trafficCompulsoryInsuranceCost").textbox('getValue');
trafficCompulsoryInsuranceCost=parseInt(trafficCompulsoryInsuranceCost);
if(!trafficCompulsoryInsuranceCost == ''){
if(!sum.test(trafficCompulsoryInsuranceCost)){
Message.error("请输入正确的保险!");
return;
}
}
var commercialInsuranceCost=$("#vehicleInsurance_add_commercialInsuranceCost").textbox('getValue');
commercialInsuranceCost=parseInt(commercialInsuranceCost);
if(!commercialInsuranceCost == ''){
if(!sum.test(commercialInsuranceCost)){
Message.error("请输入正确的保险!");
return;
}
}
var carrierInsuranceCost=$("#vehicleInsurance_add_carrierInsuranceCost").textbox('getValue');
carrierInsuranceCost=parseInt(carrierInsuranceCost);
if(!carrierInsuranceCost == ''){
if(!sum.test(carrierInsuranceCost)){
Message.error("请输入正确的保险!");
return;
}
}
var vehicleAndVesselTaxCost=$("#vehicleInsurance_add_vehicleAndVesselTaxCost").textbox('getValue');
vehicleAndVesselTaxCost=parseInt(vehicleAndVesselTaxCost);
if(!vehicleAndVesselTaxCost == ''){
if(!sum.test(vehicleAndVesselTaxCost)){
Message.error("请输入正确的保险!");
return;
}
}
var total = trafficCompulsoryInsuranceCost+commercialInsuranceCost+carrierInsuranceCost+vehicleAndVesselTaxCost;
$("#vehicleInsurance_add_totalCost").textbox("setValue",total);
},
第二种情况
新增的表单中只有各种类别的保险费用,并没有保险费用合计的字段。意思是在新增时只输入各种类别的保险金额,后台拿到各种类型的保险金额之后,在后台将各类保险金额累加,用set方法给totalcost(保险总费用)赋值,插入数据库中。查询是从数据库查询显示在结果列表即可。如下图
第二种情况可以在后台中写一个计费的累加方法。用BigDecimal的add方法进行累加。首先实例化一个BigDecimal的对象totalCost,赋一个初始值为0,然后用保险的对象insurance的get方法获取各种保险的金额,然后用totalCost.add方法将获取每个不同类的保险金额一次加到totalCost中,然后将totalCost用insurance的set方法set到保险总费用的字段中,然后进行插入操作。代码如下(后台中计费的方法写在Service中的新增方法中):
/**
* 车辆保险新增
* 陈通
* @param insurance
* @param request
* @return
* @throws IOException
*/
public Result insertVehicleInsurance(VehicleInsurance insurance,HttpServletRequest request) throws IOException{
Result result = Result.getInstance();
insurance.setKeyID(IDGenerator.uuid());
//计费方法开始
BigDecimal totalCost = new BigDecimal("0");
if(insurance.getTrafficCompulsoryInsuranceCost()!=null){
totalCost=totalCost.add(insurance.getTrafficCompulsoryInsuranceCost());
}
if(insurance.getCommercialInsuranceCost()!=null){
totalCost=totalCost.add(insurance.getCommercialInsuranceCost());
}
if(insurance.getCarrierInsuranceCost()!=null){
totalCost=totalCost.add(insurance.getCarrierInsuranceCost());
}
if(insurance.getVehicleAndVesselTaxCost()!=null){
totalCost=totalCost.add(insurance.getVehicleAndVesselTaxCost());
}
insurance.setTotalCost(totalCost);
//计费方法结束
//插入车辆保险信息,返回受影响的行数
int count=vehicleInsuranceDao.insertVehicleInsurance(insurance);
//插入附件
sysFileService.saveFile(insurance.getKeyID(), Enums.FILE_CATALOG.INSURANCEFILE.getValue(), request);
if (count>0) {
result.setFlag(true);
result.setMessage("车辆保险新增成功!");
}else{
result.setFlag(false);
result.setMessage("车辆保险新增失败!");
}
return result;
}
以上是两种计费方法(前台和后台)。
---------------------
作者:ct_??
来源:CSDN
原文:https://blog.csdn.net/weixin_40418595/article/details/94736305
版权声明:本文为博主原创文章,转载请附上博文链接!
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
多参数柯里
原生bind
实现promise
防抖节流函数
多参数柯里化
参数fn可以是function(a,b,c){},也可以是function(a,b,c,d,f){}
// 支持多参数传递
function progressCurrying(fn, args) {
var _this = this
var len = fn.length;
var args = args || [];
return function() {
var _args = Array.prototype.slice.call(arguments).concat(args);
// 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
if (_args.length < len) {
return progressCurrying.call(_this, fn, _args);
}
// 参数收集完毕,则执行fn
return fn.apply(this, _args);
}
}
原生js实现bind
Function.prototype.myBind = function(Othis){
if(typeof this !== "function"){
return new TypeError("not a function");
}
let _this = this;
let args = [...arguments].slice(1);
let func = function(){};
let fBound = function () {
return _this.apply(this instanceof func ?this:Othis,[...arguments].concat(args));
}
func.prototype = _this.prototype;
fBound.prototype = new func();
return fBound;
}
防抖函数
//每wait时间内执行一次,若期间被触发,则重新执行
function debounce(func,wait) {
var timeout ;
return function(){
let args = [...arguments];
let _this = this;
if(timeout){
clearTimeout(timeout);
}
timeout = setTimeout(function() {
func.apply(_this,args);
}, wait);
}
}
节流函数
//每wait时间执行一次
function throttle(func,wait){
var timeStart = 0 ;
return function(){
let _this = this;
let args = [...arguments];
let now = Date().now();
if(now - timeStart >wait){
func.apply(_this,args);
timeStart = now;
}
}
}
实现一个promise
function _Promise(func){
this.status = 'pending'
this.result = '' ;
func(this.resolve.bind(this),this.reject.bind(this));
}
_Promise.prototype.resolve = function(result){
if(this.status == 'pending'){
this.status = 'fullfilled';
this.result = result;
}
}
_Promise.prototype.reject = function(error){
if(this.status == 'pending'){
this.status = 'rejected';
this.result = error;
}
}
_Promise.prototype.then = function(preResolve,preReject){
let _isPromise ;
if(this.status == 'fullfilled'){
_isPromise = preResolve(this.result);
}else if(this.status == 'rejected' && arguments[1]){
_isPromise = preReject(this.result);
}
return _isPromise instanceof _Promise ? _isPromise:this;
}
实现一个promise.all()
function promiseAll(promiseArray){
//首先参数一定是一个数组
//然后此函数返回的是一个promise,如果全部成功,则返回结果的数组,只要有一个失败,则返回失败的结果
return new Promise(function (resolve,reject){
if(!Array.isArray(promiseArray)){
return reject(new TypeError("not a function"));
}
let resolveNum = 0;
let arrNum = promiseArray.length;
let resolveResult = [];
for(let i=0; i<arrNum ;i++){
(function (i){
Promise.resolve(promiseArray[i]).then(function(result){
resolveNum ++;
resolveResult.push(result);
if(resolveNum == arrNum){
return resolve(resolveResult);
}
},function(error){
return reject(error);
})
})(i);
}
}) //返回的promise结束
}
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、网站建设 、平面设计服务。
蓝蓝设计的小编 http://www.lanlanwork.com