首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

JDK 1.8新特性Lambda入门

网上关于java lambda的例子很多,但是这些五花八门的例子很不常见不常用,最后导致初学者望而却步,其实我们抓住lambda的本质之后,会发现lambda还是很好理解的。毕竟,java8设计lambda的初衷是给开发者提供便利,而不是制造障碍。 lambda表达式本质是匿名方法,下面是一些lambda表达式: (int x, int y) -> x + y () -> 42 (String s) -> { System.out.println(s); } 第一个lambda表达式接收x和y这两个整形参数并返回它们的和; 第二个lambda表达式不接收参数,返回整数42; 第三个lambda表达式接收一个字符串并把它打印到控制台,不返回值。 lambda表达式的语法由参数列表、箭头符号->和函数体组成。函数体既可以是一个表达式,也可以是一个语句块: 表达式:表达式会被执行然后返回执行结果。 语句块:语句块中的语句会被依次执行,就像方法中的语句一样。 return语句会把控制权交给匿名方法的调用者 break和continue只能在循环中使用 如果函数体有返回值,那么函数体内部的每一条路径都必须返回值 java8的安装 工欲善其器必先利其器,首先安装JDK8。过程省略,大家应该都可以自己搞定。但是有一点这里强调一下(Windows系统):目前我们工作的版本一般是java 6或者java 7,所以很多人安装java8基本都是学习为主。这样就在自己的机器上会存在多版本的JDK。而且大家一般是希望在命令行中执行java命令是基于老版本的jdk。但是在安装完jdk8并且没有设置path的情况下,你如果在命令行中输入:java -version,屏幕上会显示是jdk 8。这是因为jdk8安装的时候,会默认在C:/Windows/System32中增加java.exe,这个调用的优先级比path设置要高。所以即使path里指定是老版本的jdk,但是执行java命令显示的依然是新版本的jdk。这里我们要做的就是删除C:/Windows/System32中的java.exe文件(不要手抖!)。 下面转自:http://blog.csdn.net/renfufei/article/details/24600507 Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda表达式还增强了集合库。 Java SE 8添加了2个对集合数据进行批量操作的包:java.util.function包以及java.util.stream包。 流(stream)就如同迭代器(iterator),但附加了许多额外的功能。 总的来说,lambda表达式和 stream 是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。 在本文中,我们将从简单到复杂的示例中见认识lambda表达式和stream的强悍。 环境准备 如果还没有安装Java 8,那么你应该先安装才能使用lambda和stream(译者建议在虚拟机中安装,测试使用)。 像NetBeans 和IntelliJ IDEA 一类的工具和IDE就支持Java 8特性,包括lambda表达式,可重复的注解,紧凑的概要文件和其他特性。 下面是Java SE 8和NetBeans IDE 8的下载链接:Java Platform (JDK 8): 从Oracle下载Java 8,也可以和NetBeans IDE一起下载NetBeans IDE 8: 从NetBeans官网下载NetBeans IDE Lambda表达式的语法 基本语法: (parameters) -> expression 或 (parameters) ->{ statements; } 下面是Java lambda表达式的简单例子: [java]view plaincopy //1.不需要参数,返回值为5 ()->5 //2.接收一个参数(数字类型),返回其2倍的值 x->2*x //3.接受2个参数(数字),并返回他们的差值 (x,y)->x–y //4.接收2个int型整数,返回他们的和 (intx,inty)->x+y //5.接受一个string对象,并在控制台打印,不返回任何值(看起来像是返回void) (Strings)->System.out.print(s) 基本的Lambda例子 现在,我们已经知道什么是lambda表达式,让我们先从一些基本的例子开始。 在本节中,我们将看到lambda表达式如何影响我们编码的方式。 假设有一个玩家List ,程序员可以使用 for 语句 ("for 循环")来遍历,在Java SE 8中可以转换为另一种形式: [java]view plaincopy String[]atp={"RafaelNadal","NovakDjokovic", "StanislasWawrinka", "DavidFerrer","RogerFederer", "AndyMurray","TomasBerdych", "JuanMartinDelPotro"}; List<String>players=Arrays.asList(atp); //以前的循环方式 for(Stringplayer:players){ System.out.print(player+";"); } //使用lambda表达式以及函数操作(functionaloperation) players.forEach((player)->System.out.print(player+";")); //在Java8中使用双冒号操作符(doublecolonoperator) players.forEach(System.out::println); 正如您看到的,lambda表达式可以将我们的代码缩减到一行。 另一个例子是在图形用户界面程序中,匿名类可以使用lambda表达式来代替。 同样,在实现Runnable接口时也可以这样使用: [java]view plaincopy //使用匿名内部类 btn.setOnAction(newEventHandler<ActionEvent>(){ @Override publicvoidhandle(ActionEventevent){ System.out.println("HelloWorld!"); } }); //或者使用lambdaexpression btn.setOnAction(event->System.out.println("HelloWorld!")); 下面是使用lambdas 来实现 Runnable接口 的示例: [java]view plaincopy //1.1使用匿名内部类 newThread(newRunnable(){ @Override publicvoidrun(){ System.out.println("Helloworld!"); } }).start(); //1.2使用lambdaexpression newThread(()->System.out.println("Helloworld!")).start(); //2.1使用匿名内部类 Runnablerace1=newRunnable(){ @Override publicvoidrun(){ System.out.println("Helloworld!"); } }; //2.2使用lambdaexpression Runnablerace2=()->System.out.println("Helloworld!"); //直接调用run方法(没开新线程哦!) race1.run(); race2.run(); Runnable 的 lambda表达式,使用块格式,将五行代码转换成单行语句。 接下来,在下一节中我们将使用lambdas对集合进行排序。 使用Lambdas排序集合 在Java中,Comparator 类被用来排序集合。 在下面的例子中,我们将根据球员的 name, surname, name 长度 以及最后一个字母。 和前面的示例一样,先使用匿名内部类来排序,然后再使用lambda表达式精简我们的代码。 在第一个例子中,我们将根据name来排序list。 使用旧的方式,代码如下所示: [java]view plaincopy String[]players={"RafaelNadal","NovakDjokovic", "StanislasWawrinka","DavidFerrer", "RogerFederer","AndyMurray", "TomasBerdych","JuanMartinDelPotro", "RichardGasquet","JohnIsner"}; //1.1使用匿名内部类根据name排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.compareTo(s2)); } }); 使用lambdas,可以通过下面的代码实现同样的功能: [java]view plaincopy //1.2使用lambdaexpression排序players Comparator<String>sortByName=(Strings1,Strings2)->(s1.compareTo(s2)); Arrays.sort(players,sortByName); //1.3也可以采用如下形式: Arrays.sort(players,(Strings1,Strings2)->(s1.compareTo(s2))); 其他的排序如下所示。 和上面的示例一样,代码分别通过匿名内部类和一些lambda表达式来实现Comparator : [java]view plaincopy //1.1使用匿名内部类根据surname排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))); } }); //1.2使用lambdaexpression排序,根据surname Comparator<String>sortBySurname=(Strings1,Strings2)-> (s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))); Arrays.sort(players,sortBySurname); //1.3或者这样,怀疑原作者是不是想错了,括号好多... Arrays.sort(players,(Strings1,Strings2)-> (s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))) ); //2.1使用匿名内部类根据namelenght排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.length()-s2.length()); } }); //2.2使用lambdaexpression排序,根据namelenght Comparator<String>sortByNameLenght=(Strings1,Strings2)->(s1.length()-s2.length()); Arrays.sort(players,sortByNameLenght); //2.3orthis Arrays.sort(players,(Strings1,Strings2)->(s1.length()-s2.length())); //3.1使用匿名内部类排序players,根据最后一个字母 Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1)); } }); //3.2使用lambdaexpression排序,根据最后一个字母 Comparator<String>sortByLastLetter= (Strings1,Strings2)-> (s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1)); Arrays.sort(players,sortByLastLetter); //3.3orthis Arrays.sort(players,(Strings1,Strings2)->(s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1))); 就是这样,简洁又直观。 在下一节中我们将探索更多lambdas的能力,并将其与 stream 结合起来使用。 使用Lambdas和Streams Stream是对集合的包装,通常和lambda一起使用。 使用lambdas可以支持许多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。 同样,Stream使用懒运算,他们并不会真正地读取所有数据,遇到像getFirst()这样的方法就会结束链式语法。 在接下来的例子中,我们将探索lambdas和streams 能做什么。 我们创建了一个Person类并使用这个类来添加一些数据到list中,将用于进一步流操作。 Person 只是一个简单的POJO类: [java]view plaincopy publicclassPerson{ privateStringfirstName,lastName,job,gender; privateintsalary,age; publicPerson(StringfirstName,StringlastName,Stringjob, Stringgender,intage,intsalary){ this.firstName=firstName; this.lastName=lastName; this.gender=gender; this.age=age; this.job=job; this.salary=salary; } //GetterandSetter //..... } 接下来,我们将创建两个list,都用来存放Person对象: [java]view plaincopy List<Person>javaProgrammers=newArrayList<Person>(){ { add(newPerson("Elsdon","Jaycob","Javaprogrammer","male",43,2000)); add(newPerson("Tamsen","Brittany","Javaprogrammer","female",23,1500)); add(newPerson("Floyd","Donny","Javaprogrammer","male",33,1800)); add(newPerson("Sindy","Jonie","Javaprogrammer","female",32,1600)); add(newPerson("Vere","Hervey","Javaprogrammer","male",22,1200)); add(newPerson("Maude","Jaimie","Javaprogrammer","female",27,1900)); add(newPerson("Shawn","Randall","Javaprogrammer","male",30,2300)); add(newPerson("Jayden","Corrina","Javaprogrammer","female",35,1700)); add(newPerson("Palmer","Dene","Javaprogrammer","male",33,2000)); add(newPerson("Addison","Pam","Javaprogrammer","female",34,1300)); } }; List<Person>phpProgrammers=newArrayList<Person>(){ { add(newPerson("Jarrod","Pace","PHPprogrammer","male",34,1550)); add(newPerson("Clarette","Cicely","PHPprogrammer","female",23,1200)); add(newPerson("Victor","Channing","PHPprogrammer","male",32,1600)); add(newPerson("Tori","Sheryl","PHPprogrammer","female",21,1000)); add(newPerson("Osborne","Shad","PHPprogrammer","male",32,1100)); add(newPerson("Rosalind","Layla","PHPprogrammer","female",25,1300)); add(newPerson("Fraser","Hewie","PHPprogrammer","male",36,1100)); add(newPerson("Quinn","Tamara","PHPprogrammer","female",21,1000)); add(newPerson("Alvin","Lance","PHPprogrammer","male",38,1600)); add(newPerson("Evonne","Shari","PHPprogrammer","female",40,1800)); } }; 现在我们使用forEach方法来迭代输出上述列表: [java]view plaincopy System.out.println("所有程序员的姓名:"); javaProgrammers.forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); phpProgrammers.forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); 我们同样使用forEach方法,增加程序员的工资5%: [java]view plaincopy System.out.println("给程序员加薪5%:"); Consumer<Person>giveRaise=e->e.setSalary(e.getSalary()/100*5+e.getSalary()); javaProgrammers.forEach(giveRaise); phpProgrammers.forEach(giveRaise); 另一个有用的方法是过滤器filter() ,让我们显示月薪超过1400美元的PHP程序员: [java]view plaincopy System.out.println("下面是月薪超过$1,400的PHP程序员:") phpProgrammers.stream() .filter((p)->(p.getSalary()>1400)) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); 我们也可以定义过滤器,然后重用它们来执行其他操作: [java]view plaincopy //定义filters Predicate<Person>ageFilter=(p)->(p.getAge()>25); Predicate<Person>salaryFilter=(p)->(p.getSalary()>1400); Predicate<Person>genderFilter=(p)->("female".equals(p.getGender())); System.out.println("下面是年龄大于24岁且月薪在$1,400以上的女PHP程序员:"); phpProgrammers.stream() .filter(ageFilter) .filter(salaryFilter) .filter(genderFilter) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); //重用filters System.out.println("年龄大于24岁的女性Javaprogrammers:"); javaProgrammers.stream() .filter(ageFilter) .filter(genderFilter) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); 使用limit方法,可以限制结果集的个数: [java]view plaincopy System.out.println("最前面的3个Javaprogrammers:"); javaProgrammers.stream() .limit(3) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); System.out.println("最前面的3个女性Javaprogrammers:"); javaProgrammers.stream() .filter(genderFilter) .limit(3) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); 排序呢? 我们在stream中能处理吗? 答案是肯定的。 在下面的例子中,我们将根据名字和薪水排序Java程序员,放到一个list中,然后显示列表: [java]view plaincopy System.out.println("根据name排序,并显示前5个Javaprogrammers:"); List<Person>sortedJavaProgrammers=javaProgrammers .stream() .sorted((p,p2)->(p.getFirstName().compareTo(p2.getFirstName()))) .limit(5) .collect(toList()); sortedJavaProgrammers.forEach((p)->System.out.printf("%s%s;%n",p.getFirstName(),p.getLastName())); System.out.println("根据salary排序Javaprogrammers:"); sortedJavaProgrammers=javaProgrammers .stream() .sorted((p,p2)->(p.getSalary()-p2.getSalary())) .collect(toList()); sortedJavaProgrammers.forEach((p)->System.out.printf("%s%s;%n",p.getFirstName(),p.getLastName())); 如果我们只对最低和最高的薪水感兴趣,比排序后选择第一个/最后一个 更快的是min和max方法: [plain]view plaincopy System.out.println("工资最低的Javaprogrammer:"); Personpers=javaProgrammers .stream() .min((p1,p2)->(p1.getSalary()-p2.getSalary())) .get() System.out.printf("Name:%s%s;Salary:$%,d.",pers.getFirstName(),pers.getLastName(),pers.getSalary()) System.out.println("工资最高的Javaprogrammer:"); Personperson=javaProgrammers .stream() .max((p,p2)->(p.getSalary()-p2.getSalary())) .get() System.out.printf("Name:%s%s;Salary:$%,d.",person.getFirstName(),person.getLastName(),person.getSalary()) 上面的例子中我们已经看到 collect 方法是如何工作的。 结合 map 方法,我们可以使用 collect 方法来将我们的结果集放到一个字符串,一个 Set 或一个TreeSet中: [java]view plaincopy System.out.println("将PHPprogrammers的firstname拼接成字符串:"); StringphpDevelopers=phpProgrammers .stream() .map(Person::getFirstName) .collect(joining(";"));//在进一步的操作中可以作为标记(token) System.out.println("将Javaprogrammers的firstname存放到Set:"); Set<String>javaDevFirstName=javaProgrammers .stream() .map(Person::getFirstName) .collect(toSet()); System.out.println("将Javaprogrammers的firstname存放到TreeSet:"); TreeSet<String>javaDevLastName=javaProgrammers .stream() .map(Person::getLastName) .collect(toCollection(TreeSet::new)); Streams 还可以是并行的(parallel)。 示例如下: [java]view plaincopy System.out.println("计算付给Javaprogrammers的所有money:"); inttotalSalary=javaProgrammers .parallelStream() .mapToInt(p->p.getSalary()) .sum(); 我们可以使用summaryStatistics方法获得stream 中元素的各种汇总数据。 接下来,我们可以访问这些方法,比如getMax, getMin, getSum或getAverage: [java]view plaincopy //计算count,min,max,sum,andaveragefornumbers List<Integer>numbers=Arrays.asList(1,2,3,4,5,6,7,8,9,10); IntSummaryStatisticsstats=numbers .stream() .mapToInt((x)->x) .summaryStatistics(); System.out.println("List中最大的数字:"+stats.getMax()); System.out.println("List中最小的数字:"+stats.getMin()); System.out.println("所有数字的总和:"+stats.getSum()); System.out.println("所有数字的平均值:"+stats.getAverage()); OK,就这样,希望你喜欢它! 总结 在本文中,我们学会了使用lambda表达式的不同方式,从基本的示例,到使用lambdas和streams的复杂示例。 此外,我们还学习了如何使用lambda表达式与Comparator 类来对Java集合进行排序。

优秀的个人博客,低调大师

Vue入门---事件与方法详解

一、 vue方法实现 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Vue方法与事件</title> 6 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> 7 <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> 8 </head> 9 <body> 10 <div id="test"> 11 <button @click="sayHi">点击我</button> <!--这里使用@--> 12 </div> 13 <script type="text/javascript"> 14 var myVue = new Vue({ 15 el: '#test', 16 methods: { //这里使用methods 17 sayHi: function () { 18 alert('我被点击了') 19 } 20 } 21 }) 22 </script> 23 </body> 24 </html> 二、 方法传参 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Vue方法与事件</title> 6 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> 7 <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> 8 </head> 9 <body> 10 <div id="test"> 11 <button @click="sayHi('你好')">说你好</button> <!--这里使用@--> 12 <button @click="sayHi('我被点击了')">说我被点击了</button> <!--这里使用@--> 13 </div> 14 <script type="text/javascript"> 15 var myVue = new Vue({ 16 el: '#test', 17 methods: { //这里使用methods 18 sayHi: function (message) { 19 alert(message) 20 } 21 } 22 }) 23 </script> 24 </body> 25 </html> 三 、vue访问原生 DOM 事件 注意用$event获取 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Vue方法与事件</title> 6 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> 7 <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> 8 </head> 9 <body> 10 <div id="test"> 11 <button @click="changeColor('你好',$event)">点击我</button> <!--这里使用@--> 12 <div style="height: 100px;width: 100px;background-color: red;" @mouseover="over('鼠标从我上面滑过',$event)"> 13 鼠标从我上面滑过试试 14 </div> 15 </div> 16 <script type="text/javascript"> 17 var myVue = new Vue({ 18 el: '#test', 19 methods: { //这里使用methods 20 changeColor: function (message, event) { 21 alert(message+event); //弹出我被点击了,事件是[object MouseEvent] 22 }, 23 over :function (message, event) { 24 alert(message+event); //弹出鼠标从我上面滑过,事件是[object MouseEvent] 25 } 26 } 27 }) 28 </script> 29 </body> 30 </html> 四、 事件修饰符 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue方法与事件</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="test"> <button @click.stop="sayHi('你好')">说你好</button> <!-- 阻止单击事件冒泡 --> <button @click.prevent="sayHi('你好')">说你好</button> <!-- 提交事件不再重载页面 --> <button @click.stop.prevent="sayHi('你好')">说你好</button> <!-- 阻止单击事件冒泡和提交事件不再重载页面 --> <button @click.capture="sayHi('你好')">说你好</button> <!-- 添加事件侦听器时使用 capture 模式 --> <button @click.self="sayHi('你好')">说你好</button> <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 --> <div @keyup.13="sayHi('你好')">说你好</div> <!-- 只有在 keyCode 是 13 时调用 vm.submit() --> </div> <script type="text/javascript"> var myVue = new Vue({ el: '#test', methods: { //这里使用methods sayHi: function (message) { alert(message) } } }) </script> </body> </html> 五、常用事件 v-on:click/mouseover...... 简写的: @click="" 推荐 1、事件对象: @click="show($event)" 2、事件冒泡: 阻止冒泡: a). ev.cancelBubble=true; b). @click.stop 推荐 3、默认行为(默认事件): 阻止默认行为: a). ev.preventDefault(); b). @contextmenu.prevent 推荐 4、键盘: @keydown $event ev.keyCode @keyup 常用键: 回车 a). @keyup.13 b). @keyup.enter 上、下、左、右 @keyup/keydown.left // 左 @keyup/keydown.right // 右 @keyup/keydown.up // 上 @keyup/keydown.down // 下

优秀的个人博客,低调大师

深度学习入门笔记系列 ( 三 )

本系列将分为 8 篇 。今天是第三篇 。主要讲讲感知器模型和 tensorboard 的基本使用方法 。 1. 感知器模型 因为小詹之前写过一篇感知器模型的介绍 ,这里就不赘述了 。 2. tensorboard TensorBoard 是 TensorFlow 自带的可视化结构管理和调试优化网络的工具 。在我们学习深度学习网络框架时 ,我们需要更直观的看到各层网络结构和参数 ,也可以更好的进行调试优化网络 。TensorBoard 可以实现网络结构的显示 ,也可以进行显示训练及测试过程中各层参数的变化情况 。 TensorBoard 界面如下 : 我们可以看到顶部有几个功能分类 :SCALARS 、GRAPHS 、HISTOGRAM 等 。 SCALARS 是训练参数统计显示 ,可以看到整个训练过程中 ,各个参数的变换情况 。 HISTOGRAM 是训练过程参数分布情况显示 。 GRAPHS 是网络结构显示 。 TensorBoard 基本操作介绍如下 : 下面用一个最简单的例子来实现基础启动 。定义了两个常量相加的操作 ,运行后会在 log_test 文件夹中出现目标文件 。 之后我们需要在命令窗口启动 tensorboard 。方法在上边基础语法介绍中提及 。这里就小詹自己代码存放位置 ,可在命令窗口执行如下命令 ,得到一个网址(下图标出的部分),并在浏览器中打卡即可 。 在浏览器中打开该网址即可得到上述实例程序的 graph 信息 。 举例比较简单 ,但是并不说明 TensorBoard 不重要 。事实上 ,基于 TensorBoard ,我们可以直观的看到各层网络结构和参数,也可以更好的进行调试优化网络。 原文发布时间为:2018-07-30本文作者:小詹同学本文来自云栖社区合作伙伴“小詹学Python”,了解相关信息可以关注“小詹学Python”

优秀的个人博客,低调大师

深度学习入门笔记系列 ( 一 )

本系列将分为 8 篇 。今天是第一篇 ,工欲善其事必先利其器 ,先简单讲讲当前的主流深度学习框架 TensorFlow 及其安装方法 。 我们知道 ,深度学习研究的热潮持续高涨 ,许多的开源深度学习框架也层出不穷 ,比如 TensorFlow、Caffe、Keras、Theano、Torch7……其中 ,TensorFlow 由强大的谷歌研发 ,应用也十分广泛 ,从 GitHub 上的数据统计可以看出来其有着大一统之势头 。 关于 TensorFlow 的安装 ,我们首先得知道 : Window 、MacOS 、Linux 都已支持 TensorFlow Window用户只能使用python3.5+ ,MacOS,Linux支持python2.7和python3.3+ 有GPU可以安装带GPU版本的,没有GPU就安装CPU版本的。 关于 TensorFlow 的安装 ,这里推荐使用 pip 方式安装 ,简单粗暴 !这里小詹安利一款神器 ,谁用谁说好哈哈 !Anaconda ,你可以试试 ,自带python3.5 ,也包含了很多模块 ,配置其他模块的时候也很好用 。 首先是 windows 下的 pip 安装 :(命令窗口执行) CPU 版本 :pip install tensorflow GPU 版本 :pip install tensorflow-gpu 如果要更新 ,可以选择先pip uninstall tensorflow 再执行pip install tensorflow 至于 Linux 和 MacOS 安装 Tensorflow : CPU版本:Python 2.7 用户:pip install tensorflow Python 3.3+ 用户:pip3 install tensorflow GPU版本:Python 2.7用户:pip install tensorflow-gpu Python3.3+用户:pip3 install tensorflow-gpu 磨刀不误砍柴工 ,花较少的篇幅汇总下如何安装 TensorFlow 在我看来还是很有必要的 ! 原文发布时间为:2018-07-25本文作者: 小詹学Python本文来自云栖社区合作伙伴“小詹学Python”,了解相关信息可以关注“小詹学Python”

优秀的个人博客,低调大师

webpack 从入门到放弃(一)

什么是 webpack,为什么要使用 webpack 什么是 webpack 官网给出的概念是: 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。 根据官网最直观最出名的那个图我们可以知道,webpack 可以打包/脚本/图片/样式/表 从图中我们可以看出左边有依赖关系的模块(MODULES WITH DEPENDENCIES)通过 webpack 打包成了各种静态资源(STATIC ASSETS) 为什么要使用 webpack 通过上面的概念,你是不是已经大概知道了 webpack 是干什么的,那么问题来了,为什么要使用 webpack 呢? 这就说来话长了,那就长话短说,emmmm 为什么使用 webpack,这应该是和前端的发展有关系的,我认为,webpack 是前端发展到一定阶段的必然产物(貌似是一句废话)。 因为计算机网络的飞速发展,导致 web 前端也在迅猛发展。最初的实践方案已经不能满足我们的需求,于是,越来越多的新技术新思想新框架孕育而生,比如: 前端模块化 随着前端项目的复杂度越来越高,相互之前的依赖越来越多,以及为了更好的复用代码,前端也需要用模块化的思想来组织代码。 首先我们要明白模块化解决了前端的哪些痛点: 命名冲突 文件依赖(js 加载顺序) 代码复用 我们这里说的模块和 Java 的 package 的概念是类似的。逻辑上相关的代码放在一个包中,每一个包都是相互独立的,不用担心命名冲突的问题,如果其他人想要用这部分功能,直接 import 导入包就好 所以前端代码模块化的实现,会帮我们解决命名冲突和代码复用的问题,那么文件依赖要怎么处理呢?这就用到了我们的 webpack,稍后再做介绍。 所以有了模块,我们就可以方便的复用他人的代码,那么问题来了,无规矩不成方圆,我们在使用他人代码的时候肯定是要遵循某种规范,所以就出现了 CommonJS、AMD 和 终极模块化方案 —— ES6 模块,这些都是前端模块化的规范。 我们来简单了解一下: CommonJS node.js 采用的就是 CommonJS 规范,使用 require 的方法同步加载依赖,一个文件就是一个模块,导入导出格式如下: // 导入 const moduleA = require('./moduleA'); // 导出 module.exports = moduleA.someFunc; 缺点是加载的模块是同步的,只有加载完才能执行后面的操作。因为 node.js 的模块文件一般存在于本地硬盘,所以一般不会出现这个问题,但是在浏览器环境该规范就不那么适用了。 AMD 原因如上,因为 CommonJS 不适用于浏览器环境,所以出现了 AMD 规范。该规范异步加载依赖,可以再声明的时候指定需要加载的依赖,并且需要当做参数传入,对于依赖的模块提前执行,依赖前置。 写法如下: define("module", ["dep1", "dep2"], function(d1, d2) { return someExportedValue; }); require(["module", "../file"], function(module, file) { /* ... */ }); ES6 模块化 ES6 直接在语言层面上实现了模块化。我们现在用的最多的就是 ES6 模块化的实践方式。 写法如下: // 导入 import { readFile } from 'fs'; import React from 'react'; // 导出 export function hello() {}; export default { // ... }; 样式模块化 现在越来越多人也开始使用模块化的思想写样式。比如现在大部分的 CSS 预编译器都支持 @import 的写法。将一些公用样式放在一个文件中,在其他文件中导入。 //全局安装 npm install -g webpack //安装到你的项目目录 npm install --save-dev webpack npm init 初始化之后我们还要创建几个文件来存放我们的项目文件。 创建一个 app 文件夹来存放我们打包之前的源文件 创建一个 public 文件夹来存放一个入口文件 index.hrml 和通过 webpack 打包之后浏览器可直接运行的 js 文件 比如我们在 app 文件夹下创建一个 Greeter.js 文件,里面有一个方法可以再页面显示文字信息 Hi there and greetings! module.exports = function() { var greet = document.createElement('div'); greet.textContent = "Hi there and greetings!"; return greet; }; 然后我们创建一个 main.js 来引入 Greeter.js 这个文件, 浏览器的入口 index.html 文件内容如下(其中 bundle.js 是打包之后的文件): <html lang="en"> <head> <meta charset="utf-8"> <title>Webpack Sample Project</title> </head> <body> <div id='root'> </div> <script src="bundle.js"></script> </body> </html> 此时的文件路径如下 . ├── app │ ├── Greeter.js │ └── main.js ├── package.json ├── public │ ├── bundle.js │ └── index.html 安装 webpack 初始化项目之后,要安装 webpack npm install --save-dev webpack 在安装完 webpack 之后,可以再 package.json 文件中看到增加了 webpack 的依赖。 配置 webpack 安装完 webpack 之后,我们就要配置 webpack 了,首先创建配置文件 webpack.config.js 文件内容如下: module.exports = { entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js"//打包后输出文件的文件名 } } 然后我们在该项目的终端输入 webpack 就可以看到如下信息: Hash: 4e6a6b5eb88a83b29e02 Version: webpack 4.12.0 Time: 551ms Built at: 2018-06-24 14:53:39 Asset Size Chunks Chunk Names bundle.js 6.82 KiB 0 [emitted] main [3] ./node_modules/css-loader!./app/main.css 190 bytes {0} [built] [4] ./app/main.css 1.04 KiB {0} [built] [5] ./app/Greeter.js 143 bytes {0} [built] [6] ./app/main.js 119 bytes {0} [built] + 3 hidden modules WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 看到这样的信息,那么恭喜你,你的第一个 webpack 项目就完成了! 打开 public 文件夹下面的 index.html,你就可以再浏览器上看到如下的效果。 Loader loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件! 因为 webpack 本身只能处理 JavaScript,如果要处理其他类型的文件,就需要使用 loader 进行转换,loader 本身就是一个函数,接受源文件为参数,返回转换的结果。 举个 —— css-loader 例如,我们想在刚刚的页面增加样式,使文字居中显示,那么我在 app 文件夹下面新建一个 main.css 文件。在 webpack 中,所有的文件都是模块,所以要使用这个 css 文件,就必须要先引入。 引入 css 文件 所以我就在 app 文件夹下面的 main.js 中引入该 css 文件 const greeter = require('./Greeter.js'); require ('./main.css') document.querySelector("#root").appendChild(greeter()); 重新打包 然后我重新打包一遍,蓝后,发现居然报错了! Hash: 179c18498fac6de89a96 Version: webpack 4.12.0 Time: 533ms Built at: 2018-06-24 15:00:24 1 asset [0] ./app/Greeter.js 143 bytes {0} [built] [1] ./app/main.js 119 bytes {0} [built] WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ ERROR in ./app/main.js Module not found: Error: Can't resolve 'style-loader' in '/Users/cherry/Workspace/webpack-demo' @ ./app/main.js 2:0-22 根据报错信息,我们很明显能发现是提示我们项目缺少 style-loader,这是因为 webpack 原生只支持解析 js 文件,要支持非 js 类型的文件,就需要使用 loader 安装 loader 所以我们要安装 style-loader 和 css-loader npm i -D style-loader css-loader 修改配置文件 然后修改 webpack 的配置文件 webpack.config.js module.exports = { entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js"//打包后输出文件的文件名 }, module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] } } 配置文件增加了 module.rules 数组,该数组是一些配置规则,告诉 webpack 符合 test 的文件需要使用 use 后面的 loader 处理。所以该规则就是对所有 .css 结尾的文件使用 style-loader、 css-loader 进行处理。 loader 特性 我们来看一下 loader 有哪些特性: loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。 loader 可以是同步的,也可以是异步的。 loader 运行在 Node.js 中,并且能够执行任何可能的操作。 loader 接收查询参数。用于对 loader 传递配置。 loader 也能够使用 options 对象进行配置。 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。 插件(plugin)可以为 loader 带来更多特性。 loader 能够产生额外的任意文件。 使用 webpack 的三种姿势 webpack 中使用 loader 有三种姿势 通过 CLI 命令行中运行 webpack --module-bind jade --module-bind 'css=style!css' jade,style,css后面可省略-loader,他们分别对.jade使用jade-loader,对.css使用style-loader和css-loader 通过require 可以直接在源码中指定使用什么 loader 去处理文件。 require('style-loader!css-loader?minimize!./main.css') 这样就是对 ./main.css 文件先使用 css-loader 再使用 style-loader 进行转换 使用配置文件 webpack.config.js 最常用的方式就是使用本文所使用的配置文件的方式 常见的 loader 常见的 loader 将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。 gzip-loader | 可以加载 gzip 压缩之后的资源 html-loader | 将 html 输出为字符串,也可以根据配置进行压缩 imports-loader | imports-loader 允许使用依赖于特定全局变量的模块,这对于依赖于像 $ 这样的全局变量的第三方模块非常有用 jshint-loader | 为加载的模块使用 jshint json-loader | 由于 webpack >= v2.0.0 默认支持导入 JSON 文件。如果你使用自定义文件扩展名,你可能仍然需要使用此 loader json5-loader | 将 json5 文件解析成 js 对象 less-loader | 将 less 转化为 css null-loader | 返回一个空模块 postcss-loader | 将 postcss 转化为 css raw-loader | 加载文件原始内容(utf-8格式) sass-loader | 将 SASS/SCSS 转换为 css source-map-loader | 从现有源文件(源代码源URL)中提取源映射,方便调试 style-loader | 将 CSS 放在 <style> 标签中注入到 DOM 中 script-loader | 在全局上下文中执行一次 JavaScript 文件(如在 script 标签),不需要解析 svg-inline-loader | 将 SVG 作为模块嵌入 url-loader | 将文件加载为 Base64 编码的 URL row 2 col 1 | row 2 col 2 Plugin 插件(plugin)是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上! 插件目的在于解决 loader 无法实现的其他事 Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。 通过plugin(插件)webpack可以实 loader 所不能完成的复杂功能,使用 plugin 丰富的自定义 API 以及生命周期事件,可以控制 webpack 打包流程的每个环节,实现对 webpack 的自定义功能扩展。 举个 —— ExtractTextPlugin webpack4 已经不支持用extract-text-webpack-plugin来优化 css, 需要改成optimize-css-assets-webpack-plugin和mini-css-extract-plugin 在刚刚的例子中,我们查看打包之后的 index.html 文件可以看到我们刚刚写的 css 代码放在了 head 中的 style 标签中,这是 style-loader 帮我们处理的 但是,如果你希望打包之后 css 在单独的文件中,那么你就需要 ExtractTextPlugin 这个 plugin 了。 安装 ExtractTextPlugin npm i -D ExtractTextPlugin 修改配置文件 我们需要修改配置文件: const path = require('path') const ExtractTextPlugin = require('extract-text-webpack-plugin') module.exports = { entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js",//打包后输出文件的文件名 }, module: { rules: [ { test: /\.css$/, // 转换 .css 需要的 loader loaders: ExtractTextPlugin.extract({ use: ['css-loader'], }) } ] }, plugins: [ new ExtractTextPlugin({ filename: '[name]-[contenthash:8].css' }) ] } 然后我们再重新打包,就可以发现在 public 文件夹下面多了一个 main-493a2c3c.css 文件,下面我们要在 index.html 中自动引入这个 css 文件 html-webpack-plugin html-webpack-plugin 可以根据你设置的模板,在每次运行后生成对应的模板文件,同时所依赖的 CSS/JS 也都会被引入,如果 CSS/JS 中含有 hash 值,则 html-webpack-plugin 生成的模板文件也会引入正确版本的 CSS/JS 文件。 安装 html-webpack-plugin 安装方式我们已经很熟悉了 npm i -D html-webpack-plugin 修改配置文件 const path = require('path') const ExtractTextPlugin = require('extract-text-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 output: { path: __dirname + "/public",//打包后的文件存放的地方 filename: "bundle.js",//打包后输出文件的文件名 }, module: { rules: [ { test: /\.css$/, loaders: ExtractTextPlugin.extract({ use: ['css-loader'], }) } ] }, plugins: [ new ExtractTextPlugin({ filename: '[name]-[contenthash:8].css' }), new HtmlWebpackPlugin(), ] } 蓝后我们删除之前我们在 punlic 文件夹下面 index.html 的内容,在打包一次,就会生成一个 html 模板 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> <link href="main-493a2c3c.css" rel="stylesheet"></head> <body> <script type="text/javascript" src="bundle.js"></script></body> </html> 在 new HtmlWebpackPlugin 的时候,我们可以进行一系列的配置 new HtmlWebpackPlugin({ // 生成的HTML模板的title,如果模板中有设置title的名字,则会忽略这里的设置 title: "This is the webpack config", // 生成的模板文件的名字 filename: "/index.html", // 模板来源文件 template: "index.html", // 引入模块的注入位置;取值有true/false/body/head // true 默认值,script标签位于html文件的 body 底部 // body script标签位于html文件的 body 底部 // head script标签位于html文件的 head中 // false 不插入生成的js文件,这个几乎不会用到的 inject: "body", // 指定页面图标; favicon: "", // 是html-webpack-plugin中集成的 html-minifier ,生成模板文件压缩配置 minify: { caseSensitive: false, //是否大小写敏感 collapseBooleanAttributes: true, // 省略布尔属性的值 collapseWhitespace: true //删除空格 }, // 是否生成hash添加在引入文件地址的末尾,类似于我们常用的时间戳,避免缓存带来的麻烦 hash: true, // 是否需要缓存,如果填写true,则文件只有在改变时才会重新生成 cache: true, // 是否将错误信息写在页面里,默认true,出现错误信息则会包裹在一个pre标签内添加到页面上 showErrors: true, // 引入的模块,这里指定的是entry中设置多个js时,在这里指定引入的js,如果不设置则默认全部引入 chunks: "", // 引入模块的排序方式 // 默认四个选项: none auto dependency {function} // 'dependency' 文件的依赖关系 // 'auto' 默认值,插件的内置的排序方式 // 'none' 无序 // {function} 自定义 chunksSortMode: "auto", // 排除的模块 excludeChunks: "", // 生成的模板文档中标签是否自动关闭,针对xhtml的语法,会要求标签都关闭,默认false xhtml: false }), 常见的 plugin 摘自:http://www.css88.com/doc/webpack/plugins/ 原文发布时间为:2018年06月25日 原文作者: sunshine小小倩 本文来源: 掘金 如需转载请联系原作者

优秀的个人博客,低调大师

Appium+Python3+Android入门

前言: Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用。 一、环境配置 1、安装Node.js https://nodejs.org/ 2、安装Appium http://appium.io/ 3、安装Android SDK http://tools.android-studio.org/index.php/sdk 4、安装Python-client pip3 install Appium-Python-Client 5、安装Appium-client npm install wd 最后,打开命令行,输入“appium-doctor”命令,提示Appium所需要的各项环境准备情况。 二、服务关键字 Desired Capabilities在启动session的时候是必须提供的。 Desired Capabilities本质上是以key value字典的方式存放,客户端将这些键值对发给服务端,告诉服务端我们想要怎么测试。 desired_caps = {} desired_caps['platformName'] ='Android' desired_caps['platformVersion'] ='6.0.1' desired_caps['deviceName'] ='e0bbc8b7' desired_caps['appPackage'] ='com.ximalaya.ting.android' desired_caps['appActivity'] ='com.ximalaya.ting.android.host.activity.WelComeActivity' desired_caps["unicodeKeyboard"] ="True" desired_caps["resetKeyboard"] ="True" self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) 它告诉appium Server这样一些事情: deviceName:启动哪种设备,是真机还是模拟器?iPhone Simulator,iPad Simulator,iPhone Retina 4-inch,Android Emulator,Galaxy S4… automationName:使用哪种自动化引擎。appium(默认)还是Selendroid。 platformName:使用哪种移动平台。iOS, Android, orFirefoxOS。 platformVersion:指定平台的系统版本。例如指的Android平台,版本为5.1。 appActivity:待测试的app的Activity名字。比如MainActivity、.Settings。注意,原生app的话要在activity前加个”.“。 appPackage:待测试的app的Java package。比如com.example.android.myApp, com.android.settings。 注️:aapt工具可获取appActivity,appPackage aapt dump badging <file.apk> 即可获取appActivity,appPackage等~~ 三、定位控件 1、ID定位 使用方法:driver.find_element_by_id(‘com.android.calculator2:id/formula’) image 2、name定位 使用方法:driver.find_element_by_name("9")) image 3、class name定位 使用方法:driver.find_element_by_class_name(“android.widget.Button")) image 4、XPath定位 使用方法:用class的属性来替代做标签的名字。 driver.find_element_by.xpath(“//android.view.ViewGroup/android.widget.Button”) image 当果如果出现class相同的情况下可以用控件的属性值进行区分。 driver.find_element_by_xpath("//android.widget.Button[contains(@text,'7')]").click(); driver.find_element_by_xpath(”//android.widget.Button[contains(@content-desc,’times')]").click(); driver.find_element_by_xpath("//android.widget.Button[contains(@text,'7')]").click(); driver.ffind_element_by_xpath("//android.widget.Button[contains(@content-desc,'equals')]").click(); XPath在Appium上的用法依然很强大,有时需要写更臭更长的定位语法,因为APP上元素的class命令本来就长,再加上多层级,结果可想而知。 5、Accessibility ID定位 使用方法:其实,我们的核心是要找到元素的contentDescription属性。它就是元素的content-desc。 driver.find_element_by_accessibility_id("plus").click(); image 6、android uiautomator定位 使用方法: 一个元素的任意属性都可以通过android uiautomator方法来进行定位,但要保证这种定位方式的唯一性。 driver.find_element_by_android_uiautomator("new UiSelector().text(\”8\")").click(); driver.find_element_by_android_uiautomator("new UiSelector().description(\”plus\")").click(); image 四、应用操作 1、安装应用 installApp() 安装应用到设备中去。需要apk包的路径。 2、卸载应用 removeApp() 从设备中删除一个应用。 3、关闭应用 closeApp() 关闭打开的应用,默认关闭当前打开的应用,所以不需要入参。这个方法并非真正的关闭应用,相当于按home键将应用置于后台,可以通过launchApp()再次启动。 4、启动应用 launchApp() 启动应用。你一定很迷惑,不是在初始化的配置信息已经指定了应用,脚本运行的时候就需要启动应用,为什么还要有这个方法去启动应用呢?重新启动应用也是一个测试点,该方法需要配合closeApp()使用的。 5、检查应用是否安装 isAppInstalled() 检查应用是否已经安装。需要传参应用包的名字。返回结果为Ture或False。 6、将应用置于后台 runAppInBackground() 将当前活跃的应用程序发送到后台。这个方法需要入参,需要指定应用置于后台的时长。 7、应用重置 resetApp() 重置当前被测程序到出始化状态。该方法不需要入参。 五、键盘操作 1、SendKeys()方法 driver.find_element_by_name(“Name”).send_keys("jack"); 2、PressKeyCode()方法 除此之外,Appium扩展提供了pressKeyCode()方法。该方法Android特有。 发送一个键码的操作。(键码对照表请自行百度,此处不展示了。) driver.press_keycode(3)//点击Android的HOME键 driver.press_keycode(27)//点击拍照键 3、输入法问题: 必须使用appium自带键盘,并添加: desired_caps["unicodeKeyboard"] = "True" desired_caps["resetKeyboard"] = "True" 六、TouchAction操作 Appium的辅助类,主要针对手势操作,比如滑动、长按、拖动等。 1、按压控件press() 开始按压一个元素或坐标点(x,y)。通过手指按压手机屏幕的某个位置。 press(WebElement el, int x, int y) 2、长按控件longPress() 开始按压一个元素或坐标点(x,y)。相比press()方法,longPress()多了一个入参,既然长按,得有按的时间吧。duration以毫秒为单位。1000表示按一秒钟。其用法与press()方法相同。 longPress(WebElement el, int x, int y, Duration duration) 3、点击控件tap() 对一个元素或控件执行点击操作。用法参考press()。 tap(WebElement el, int x, int y) 4、移动moveTo() 将指针(光标)从过去指向指定的元素或点。 movTo(WebElement el, int x, int y) 5、暂停wait() 暂停脚本的执行,单位为毫秒。 action.wait(1000); 七、其他操作 其它操作针对移动设备上特有的一些操作。 1、熄屏 方法:lockDevice() 点击电源键熄灭屏幕。 在iOS设备可以设置熄屏一段时间。Android上面不带参数,所以熄屏之后就不会再点亮屏幕了。 driver.lockDevice(1000);// iOS driver.lockDriice();//Android 2、收起键盘 方法:hideKeyboard() 收起键盘,这个方法很有用,当我们对一个输入框输入完成后,需要将键盘收起,再切换到一下输入框进行输入。 driver.hideKeyboard();//收起键盘 3、滑动 方法:swipe() 模拟用户滑动。将控件或元素从一个位置(x,y)拖动到另一个位置(x,y)。 swipe(int startx, int starty, int endx, int endy, int duration) * start_x:开始滑动的x坐标。* start_y:开始滑动的y坐标。 * end_x:结束滑动的x坐标。* end_y:结束滑动的y坐标。 * duration:持续时间。 例:driver.swipe(75, 500, 75, 0, 800); 4、截屏 方法:get_screenshot_as_file() 用法:driver.get_screenshot_as_file('../screenshot/foo.png'),参数为保存的图片路径和名称 5、获取控件各种属性 方法:get_attribute() 用法: driver.find_element_by_id().get_attribute(name), name即是左侧的标志(class,package,checkable,checked....), 可获取的字符串类型: name(返回content-desc或text) text(返回text) className(返回class,只有API=>18才能支持) resourceId(返回resource-id,只有API=>18才能支持) 八、unittest之断言 在unittest单元测试框架中,TestCase类提供了一些方法来检查并报告故障: assertEqual(first, second, msg=None) 判断first和second的值是否相等,如果不相等则测试失败,msg用于定义失败后所抛出的异常信息。 assertNotEqual(first, second, msg=None) 测试first和second不相等,如果相等,则测试失败。 assertTure(expr,msg=None) assertFalse(expr,msg=None) 测试expr为Ture(或为False) assertIs(first, second, msg=None) assertIsNot(first, second, msg=None) 测试的first和second是(或不是)相同的对象。 assertIsNone(expr, msg=None) assertIsNotNone(expr, msg=None) 测试expr是(或不是)为None assertIn(first, second, msg=None) assertNotIn(first, second, msg=None) 测试first是(或不是)在second中。second包含是否包含first。 九、实例代码(例子app:喜马拉雅FM) import os import unittest from appium import webdriver from time import sleep # Returns abs path relative to this file and not cwd PATH =lambdap: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) class Contacts Android Tests(unittest.TestCase): def setUp(self): desired_caps = {} desired_caps['platformName'] ='Android' desired_caps['platformVersion'] ='6.0.1' desired_caps['deviceName'] ='e0bbc8b7' desired_caps['appPackage'] ='com.ximalaya.ting.android' desired_caps['appActivity'] ='com.ximalaya.ting.android.host.activity.WelComeActivity' desired_caps["unicodeKeyboard"] ="True" desired_caps["resetKeyboard"] ="True" self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) sleep(6) def tearDown(self): self.driver.close_app() self.driver.quit() deftest_Login(self): self.driver.find_element_by_id('com.ximalaya.ting.android:id/tab_myspace').click() sleep(2) self.driver.find_element_by_accessibility_id('设置').click() sleep(2) width =self.driver.get_window_size()['width'] height =self.driver.get_window_size()['height'] self.driver.swipe(width /2, height *7/8, width /2, height *4/8,1000) # 不同的手机分辨率不同,所以一个坐标如果用另一个分辨率不同的手机可能位置就有所变化了,为了让apppium 更好的兼容不同分辨率的设备, # 在执行滑动前先获取屏幕的分辨率。 self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_tv_login').click() self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_username').send_keys('18500425217') self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_password').send_keys('wj1234') self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_login').click() sleep(4) text =self.driver.find_element_by_id('com.ximalaya.ting.android:id/tab_myspace').text self.assertEqual(text,'我的') deftest_Search(self): sleep(3) message =self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_item_finding_title').text self.assertEqual(message,'天天好书') self.driver.find_element_by_accessibility_id("搜索").click() self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_search_et').send_keys('段子') self.driver.find_element_by_id('com.ximalaya.ting.android:id/main_search_button').click() self.driver.get_screenshot_as_file('/Users/wangjuan/截图图库/1.jpg') self.driver.press_keycode(4) self.assertEqual(message,'天天好书') if__name__ =='__main__': suite = unittest.TestLoader().loadTestsFromTestCase(ContactsAndroidTests) unittest.TextTestRunner(verbosity=2).run(suite) 以上,希望对你有所帮助~~

优秀的个人博客,低调大师

Gauva的安装——入门

Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 guava类似Apache Commons工具集 一、guava的安装 1.下载guava的最新的版本,网址:https://github.com/google/guava/wiki/Release19 (ps:jar,javadoc,sources都下载下来,后面都要用到) 2.打开eclipse,在java项目右键-->Build Path-->Add External Archievs 3.选择刚才下载好的jar包(jar包其实就是一个压缩文件夹,可以解压出来的) 二、guava源代码的下载 1.还是刚刚下载guava的页面,这一次下载的是源代码 2.把源代码添加到eclipse,方便查看和以后的开发 1)在java项目右键-->Build Path-->Configure Build Path 2)java build path-->Libraries-->guava-->Source attachment:(None) -->Edit 3)选择External location-->External File ; 如果你已经把源代码的jar解压成文件夹了,选择External location-->External Folder ; 4)选择源代码的jar包,双击,确定, (如果解压成文件夹了就选择对应的最外层的文件夹,确定) 5)接下来就是一路确定,然后就可以在eclipse中看guava的源码了。

优秀的个人博客,低调大师

python3入门与实践

Day 1 语言特点,环境搭建,数据结构 python 官网:http://python.org 集成开发环境:Geany,一个字:快,各个平台都有对应版本 变量 变量名只能包含字母,数字和下划线 变量名不能包含空格 不要将Python关键字和函数名用作变量名 变量名应既简短而又具有描述性 慎用小写字母l和大写字母O,因为它们可能被人错堪称1和0 字符串 用单引号或者双引号括起来,主要是为了方便在字符串中包含引号和撇号。 比如: 'I told my friend,"python is my favorite language!"' 使用方法修改字符串的大小写 字符串可以看过为对象,所以他有很多实现好了的方法 title() :返回此字符串每个单词的首字母大写状态的字符串 upper():全部大写 lower():全部小写 拼接字符串 1.直接“+”相连 删除空白 rstrip():返回字符串末尾没有空白状态的字符串 lstrip():返回字符串开头没有空白状态的字符串 strip():返回字符串两端没有空白状态的字符串 数字 整数 在Python中,可对整数执行加(+)减(-)乘(*)除(/)运算。在终端会话中,Python直接返回运算结果。Python使用两个乘号表示乘方运算: result = 3 ** 2 print(result) 浮点数 使用str()函数避免类型错误 和非字符串类型的变量或常量与字符串拼接时应该调一下str函数确保类型一致 例子: result = 3 ** 2 message = "happy "+str(result)+" brithday!" print(message) 注释 注释用“#”标识 编码 # -*- coding: gbk -*-

优秀的个人博客,低调大师

区块链比特币入门详解

比特币和区块链技术的发展非常迅速,即使那些没有听说过加密货币或了解其工作的人也在寻求投资和探索这个领域。区块链技术和加密货币今天已经成为人们开始执行标准交易的平行平台。现在,如果一个新系统正在慢慢取代现有系统,那么目前的系统肯定存在一些问题。我们将通过了解当前银行系统的问题引出当前的比特币和区块链的概念。 目前银行体系存在的问题: 任何现有的系统都会有一些问题。让我们看看银行系统最常见的一些问题: 高交易费用 我们来看一个例子来更好地理解这个问题: 在这里,钱德勒给乔发送100美元,但在乔可以收到钱之前, 它必须通过像银行或金融服务公司这样的可信第三方。从这笔金额中扣除2%的交易费用,Joe在交易结束时仅收到98美元。现在这似乎不是一个大数目,但想象一下,如果您发送的是100000美元而不是100美元,那么交易费用也会增加到2,000美元,这是一笔很大的数额。根据SNL Financial和CNNMoney的报告, 摩根大通,美国银行和富国银行在2015年从ATM和透支费用中获得超过60亿美元的收入。 双重支出 双重支出是数字现金计划中的一个错误,其中同一单个数字代币花费两次或更多。为了帮助你更好地理解这个问题,让我举个例子: 彼得在他的账户中只有500美元。他同时向亚当发起了2笔交易,价格为400美元,玛丽为500美元。通常这笔交易不会经过,因为他的账户中没有足够的900美元余额。但是,通过复制或伪造与每个数字交易相关的数字令牌,他可以在没有所需余额的情况下完成这些交易。此操作称为双重支出。 网络欺诈和帐户黑客 在印度,2016年与信用卡/借记卡和网上银行有关的欺诈案件数量为14,824件。涉及这些欺诈案件的净金额为77.79亿卢比,其中21亿卢比来自互联网欺诈,41.64亿卢比为从ATM /借记卡相关的欺诈行为。 金融危机和崩溃 image 想象一下,把你所有的存款都交给你信任的人,只知道他们已经去了,并在别的地方失去了它。这就是2007 - 08年发生的情况,当时银行和投资机构已经大举借贷,并将其作为次级抵押贷款给那些甚至无力偿还这些贷款的人。这反过来又导致了有史以来最严重的金融危机之一,估计造成全球接近11万亿美元(11亿美元)的损失。这只是最受欢迎的例子之一,我们多久听说银行和金融服务公司因内部欺诈而崩溃?整个第三方系统是建立在对中间人盲目信任的基础之上的。 我们看到了每个人都面临的一些最常见的问题。拥有一套克服这些问题的系统并为我们提供一个这正是Blockchain Technology所做的事情,这不是一件好事。 现在让我们试着了解区块链和比特币如何解决这些问题,下面引出区块链。 区块链如何解决这些问题? 以下是区块链技术解决上述问题的一些方法: 分散系统 与被中央或联邦当局控制和管理的银行和金融组织相比,区块链系统采用分散的方式。在这里,作为系统一部分的每个人都对系统的增长和崩溃负有同样的责任。每个参与系统的人都有权力,而不是一个单独的实体拥有权力。 公共总帐 持有区块链上发生的所有交易细节的分类账是开放的,并且与系统相关的每个人都可以完全访问。一旦加入区块链网络,您就可以下载自启动以来的完整交易列表。尽管完整的分类帐可公开访问,但涉及交易的人员的详细信息仍然完全匿名。 每笔交易的验证 每一笔交易都通过交叉检查分类账 进行核实,并在几分钟后发送交易的确认信号。通过使用多种复杂的加密算法和哈希算法,消除了双重支出的问题。 低或无交易费用 交易费 通常不适用,但区块链的某些变体确实实施了某些最低交易费用。与银行和其他金融机构暗示的费用相比,这些交易费用相对较少。如果交易需要优先完成,那么用户可以添加额外的交易费用,以便优先验证交易。 现在我们已经谈到了现有系统的问题,并了解了区块链技术如何克服这些挑战,我相信您一定对区块链系统有了一些了解。 在这一点上,你可能仍然想知道区块链和比特币到底是什么。所以让我们尝试在本区块链教程的下一部分中了解这些重要概念。 什么是区块链和比特币? 在我们继续了解区块链之前,了解什么是比特币非常重要: 比特币是一个由未知程序员或一群程序员发明的加密货币和数字支付系统,其名称是Satoshi Nakamoto。这意味着它们可以像通常的货币一样使用,但不会像美元钞票那样在物理上存在。他们是可以用来购买东西的在线货币。这些与人们电脑上的“数字现金”类似。比特币只存在于云端,如Paypal,Citrus或Paytm。即使它们是虚拟的,而不是物质的,当它们通过网络在人与人之间转移时,它们就像现金一样使用。 比特币系统是基于对等网络的,并且交易直接发生在用户之间,没有中介。这些交易由网络节点验证并记录在称为区块链的公共分布式账本中。由于该系统没有中央存储库或单一管理员,因此比特币被称为第一个分散数字货币。 比特币生产使他们成为独特的货币。与普通货币不同,比特币不能根据需要创建。只有2100万比特币可以创建,其中已经创建了1700万比特币。只要包含有效交易的区块添加到区块链,就会创建比特币。这是创建比特币和通过各种数学和加密算法确保没有伪造比特币被创建或传播的唯一手段。让我们现在了解更多Blockchain。 什么是区块链? 区块链可以被称为整个加密货币系统的脊柱。区块链技术不仅有助于用户使用加密货币执行交易,还可确保所涉及用户的安全性和匿名性。它是一个不断增长的记录列表,称为块,它们使用密码技术进行链接和保护。区块链可以充当“开放和分布式账本,可以以可验证和永久的方式记录双方之间的交易”。该网络中的每个人都共享的这个账户是公开的,所有人都可以查看。这带来了透明度和信任进入系统。 一个区块是区块链的'当前'部分,它记录了一些或所有最近的交易,并且一旦完成就作为永久数据库进入Vlockchain。每次块完成时,都会生成一个新块。 区块链通常由对等网络管理,共同遵守验证新区块的协议。一旦记录,任何给定的数据块中的数据都不能追溯更改,而不会改变所有后续的数据块和网络多数的合谋。一旦存储在区块链中的交易是永久性的。他们不能被黑客攻击或操纵。一旦我们进入区块链的概念,我们将进一步了解这一点。 您可以通过这个简短的动画视频来了解什么是区块链,通过例子来了解这些主题,以帮助您更好地理解这一概念。 现在我希望你对比特币和区块链有更好的理解。在我们的Blockchain教程博客中继续前进,让我们看看Blockchain技术的功能,以帮助我们理解它为何如此受欢迎。 Blockchain的特点 以下是区块链技术的最重要特性,使其成为革命性的技术: SHA256散列函数 公钥加密 分布式总账和对等网络 工作证明 确认奖励 让我们试着逐一了解他们中的每一个。 SHA256散列函数 区块链技术中使用的核心散列算法是SHA256。使用散列的目的是因为输出不是'加密',即它不能被解密回原始文本。它是一种“单向”加密函数,对于任何大小的源文本都是固定的大小。为了更好地理解,让我们看看下面的例子: 如果你看第一个例子,我们将输入作为“Hello World”输入,并得到一个输出为“a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e”。但是,通过在最后加上“!”,输出完全变为“7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069”。如果我们将“H”改变为“h”和“W”改为“w”,则输出值变为“7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9”。 我希望通过这个例子,您已经理解了算法的复杂程度,因为即使输入中的最小变化都会导致输出的巨大变化。 公钥加密 这种密码技术通过创建一组称为公钥和私钥的密钥来帮助用户。在这里,公钥与其他人共享,而私钥作为用户保密。为了理解这些密钥的作用,让我们看看下面的例子以获得更好的理解: image 如果钱德勒给乔伊寄了一些比特币,那笔交易将会有三条信息: 乔伊的比特币地址(乔伊的公钥) Chandler送给Joey的比特币数量。 钱德勒的比特币地址(钱德勒的公钥) 现在,所有这些数据以及加密数字签名都会通过网络发送进行验证。数字签名再次是Chandler的比特币地址和他发送给joey的金额的组合实现的哈希值。该数字签名由私钥加密。一旦必须验证此交易的矿工收到这些数据,他就会同时进行2个过程: 他将Joey和Chandler的所有未加密数据(如交易金额和公钥),并将其提供给散列算法以获取散列值,我们将其称为Hash1 他采用数字签名并使用chandler的公钥解密,得到一个散列值,我们将其称为Hash2 如果Hash1和Hash2都相同,那么这意味着这是一个有效的事务。 分布式账本和P2P网络 image 网络上的每个人都拥有分类帐的副本。没有单一的集中式副本。让我通过以下示例帮助您了解账簿是什么:假设您需要将10比特币发送给您的朋友约翰,您的比特币余额为974.65,约翰在这里余额为37.您的余额将被扣除10 BTC并且记入John的账户。 区块链有一个独特的方式来实现这一点。比特币区块链账本中没有账户和余额。来自第一个交易的每笔交易都存储在一个名为Blockchain的不断增长的数据库中。有大约2050个交易的交易区块,截至目前,区块链中有484,000个交易区块,约有2.5亿笔交易。 这个分类账分布在比特币区块链的所有用户中,即分类账没有存储的中央位置。网络上的每个人都拥有分类账的副本,而真正的副本是所有分布式分类账的集合。 工作证明 您可能想知道是否每个人都拥有分块账户,谁给区块链增加了块?人们如何相信这个人? 为此,我们有工作证明的概念。这基本上就像解决一个非常大的难题。它需要大量的计算工作。这项工作是由我们称为矿工的比特币网络中的人完成的。 这些矿工的工作是验证交易并解决与创建块相关的复杂数学难题。调整问题的难度,以便在10分钟内平均可以解决问题。矿工搜索特定的随机数(数学值),它给出了 预定的期望散列。目前的难度级别是这样的,你需要尝试20.6万亿次以上的随机数来得到正确的散列。 每个块都有一个散列值,它是前一个块的最终散列值,事务数据的散列值和随机数的组合。该块的最终结果散列必须以指定数量的尾随零开始。正是这种计算才能找到满足条件的随机数,这使得采矿的计算成本很高。 因此,发现这种随机数的人是成功的矿工,他/她可以将他们的区块添加到区块链中。通过我们的P2P分布式网络,他/她广播它们的块,并且每个人都验证散列是否匹配,更新它们的区块链并立即开始解决下一个区块。 确认奖励 image 比特币交易的最后一步是给创建最新街区的矿工给予奖励。Blockchain系统提供此奖励用于验证交易和维护区块链。目前每块的奖励是12.5 比特币(3,427,850卢比/或 53,390美元)。这是比特币矿山最有趣的部分。 比特币激励是产生新货币进入系统的唯一途径,并且相信到2140年,所有2100万比特币将被开采。 有了这个,我希望你现在对Blockchain技术有更多的理解和欣赏。区块链比比特币要多得多。金融只是Blockchain旨在破坏的众多行业之一。继续阅读Blockchain教程,现在让我们看看IBM和Maersk的一个例子,了解供应链行业如何被区块链破坏。 区块链教程:用例 马士基是一家丹麦的企业集团,在运输和物流以及能源领域开展活动。自1996年以来,马士基一直是全球最大的集装箱船和供应船运营商。该公司总部位于丹麦哥本哈根,在130个国家设有分公司和办事处,员工人数约为88,000人。 IBM是一家美国跨国技术公司,主要从事自1921年以来的业务解决方案,安全解决方案和存储解决方案 业务需求: 作为极具活力的供应链行业的一部分,跟踪最轻微的变化对于客户来说是最重要的。他们需要一种解决方案,使他们能够完成装运流程,而不会延误纸质工作。这个解决方案能够将系统的所有利益相关方聚集在一起,并为货件提供实时状态。 挑战: 今天,全球贸易中90%的商品都由航运业承担。这种供应链由于点对点通信的复杂性和庞大的流量而流动。这些沟通是通过松散耦合的陆路运输提供者,货运代理,海关,经纪人,政府的港口和海运承运人处理的。 估计集装箱货物的文件和信息的成本是实际实际运输的两倍以上。 解: IBM和Maersk正在通过设计用于交换事件数据和处理文档工作流的供应链生态系统访问分布式许可平台来解决这个问题。 image 默克和IBM正在采用区块链技术,通过数字化交易工作流程和端到端追踪货物来创建全球防篡改系统。这消除了包括昂贵的点对点通信在内的摩擦。这项合作将启动,每年可追踪数百万集装箱航程,并与选定贸易航道上的海关当局进行整合。 结果: 为参与供应链系统的所有利益相关者提供了一个安全的数据交换平台。 建立防篡改存储库,以存储作为该过程一部分的所有文档。 定期航运活动有助于减少重大延误和欺诈行为,每年节省数十亿美元。 减少贸易组织之间的壁垒,从而使全球GDP增长3%。 帮助整体贸易量增加 12%。 这就是区块链技术如何帮助马士基,并一直在帮助全球许多其他公司。 上面只是区块链1.0的概念,现在区块链已经发展到了2.0了,可以将很多应用使用区块链去中心化的实现完成,保证数据的安全、公平、公正。 使用区块链可以开发去中心化应用,现在区块链2.0应用的领域: 智能合约 分布式记账使得能够在符合指定条件时执行简单合同的编码。Ethereum是一个专门为实现这一可能性而开发的开源块链项目。 尽管如此,在它的早期阶段,Ethereum有可能在真正世界变化的规模上验证区块链的可用性。 在技术当前的发展水平上,智能合同可以被编程为执行简单的功能。 例如,当金融工具符合某些基准时,衍生产品可以支付,使用区块链技术,Bitcoin可以实现自动付款。 分享经济 像Uber和滴滴这样的公司蓬勃发展,分享经济已经取得了成功。 然而,目前,想要分享履行共享服务的用户必须依靠像Uber这样的中介。 通过实现对等支付,该区块开启了双方之间直接互动的大门 - 真正地实现了去中心化的共享经济。 早期的例子,OpenBazaar使用区块链来创建一个对等eBay。 将应用程序下载到计算设备上,您可以与OpenBazzar供应商进行交易,而无需支付交易费用。 协议的无规则精神意味着个人声誉对于商业互动将比目前在eBay上更为重要。 众筹 像Kickstarter和Gofundme这样的众筹平台正在为新兴的同行经济进行先进的工作。 这些网站的普及表明人们希望在产品开发中有直接的发言权。 区块链将这个兴趣提高到一个新的水平,潜在地创造了大量的风险投资基金。 在2016年,一个这样的实验,即以爱心为基础的DAO(权力下放自治组织)在短短两个月内众筹了惊人的2亿美元。 参与者购买了“DAO令牌”,允许他们对智能合同风险投资进行投票(投票权与其持有的DAO数量成比例)。 随后的项目资金遭到破坏,证明该项目没有进行适当的尽职调查,造成灾难性的后果。 无论如何,DAO实验表明,该块有潜力开创“经济合作的新范式”。 治理 通过使结果完全透明和公开访问,分布式数据库技术可以使选举或任何其他形式的投票获得透明度。 基于Ethereum的智能合同有助于自动化流程。 应用程序,会议室,使组织化决策发生在区块上。 实际上,这意味着在管理数字资产,股权或信息时,公司治理将变得完全透明和可验证。 供应链审计 消费者越来越想知道公司对其产品的道德声明是真实的。 分布式分类帐提供了一种简单的方式来证明我们购买的东西的背景是真实的。 透明度带有日期和位置的基于块的时间戳,例如对应于产品编号的伦理钻石。 位于英国的Provenance为一系列消费品提供供应链审核。 利用Ethereum区块链,Provenance试点项目确保日本寿司餐厅销售的鱼已经在印度尼西亚的供应商可持续收获。 文件存储 在互联网上去中心化文件存储带来明显的好处。 在整个网络中分发数据可以保护文件免遭黑客入侵或丢失。 行星文件系统(IPFS)可以很容易地概括分布式网络的运行方式。 类似于Bittorrent在互联网上移动数据的方式,IPFS摆脱了对集中的客户端 - 服务器关系(即当前Web)的需求。 由完全分散网站组成的互联网有可能加快文件传输和流媒体时间。 这样的改进不仅方便。 这是网络目前重载的内容传送系统的必要升级。 预测市场 对事件概率的预测的众包被证明具有高度的准确性。 平均意见取消了歪理判断的未经审查的偏见。 根据事件结果支付的预测市场已经活跃。 区块链是一种“智慧的人群”技术,无疑将在未来几年内找到其他应用。 然而,在Beta版中,预测市场应用Augur可以为现实世界事件的结果提供分享。 参与者可以通过购买正确的预测来赚钱。 在正确结果中购买的股票越多,支付就越高。 由于资金投入少(一美元),任何人都可以提出问题,根据预测结果创造市场,并收集市场产生的所有交易费用的一半。 保护知识产权 众所周知,数字信息可以无限再生 - 由于互联网而广泛分发。 这给全球网络用户提供了免费内容的金矿。 然而,版权所有者并没有那么幸运,因此失去了对知识产权的控制和财政困境。 智能合同可以保护版权,并在线自动销售创意作品,消除文件复制和再分发的风险。 Mycelia使用块链来创建一个对等音乐分发系统。 Mycelia由英国歌手 - 创作者Imogen Heap创立,让音乐家直接向观众销售歌曲,以及向制片人发放许可证样本,并向歌曲作者和音乐家分发版税,所有这些功能都通过智能合同进行自动化。 区块分发能力以小数加密的金额支付(微支付)表明,这种用例对于块链有很大的成功机会。 物联网(IoT) 什么是物联网? 对某些类型的电子设备的网络控制管理 - 例如监视存储设备中的空气温度。 智能合同使远程系统管理的自动化成为可能。 软件,传感器和网络的组合有助于对象和机制之间的数据交换。 结果提高了系统效率,并提高了成本监控。 制造业,科技和电讯业最大的厂商正在争夺物联网的统治地位。 认为三星,IBM和AT&T。 现有基础设施的自然扩展由现任公司控制,物联网应用将从机械部件的预测性维护到数据分析以及大规模自动化系统管理等领域。 邻里微电网 块链技术能够购买和销售邻里微电网产生的可再生能源。 当太阳能电池板产生过剩的能量时,基于Ethereum的智能合约将自动重新分配。 类似类型的智能合约自动化将具有许多其他应用,因为物联网成为现实。 Consensys位于布鲁克林,是全球最重要的公司之一,正在为Ethereum开发一系列应用。 他们正在合作的一个项目是Transactive Grid,与分布式能源装备LO3合作。 目前正在运行的原型项目使用Ethereum智能合同来自动监测和重新分配微电网。 这种所谓的“智能电网”是IoT功能的早期例子。 身份管理 在网络上需要更好的身份管理。 验证您的身份的能力降低在线发生的金融交易的隐患。 但是,网络商务所带来的安全隐患的补救办法是不完美的。 分布式分类帐提供增强的方法来证明您是谁,以及将个人文档数字化的可能性。 拥有安全身份对于在线互动也是重要的,例如在共享经济中。 毕竟,良好的信誉是在线交易的最重要条件。 开发数字身份标准被证明是一个非常复杂的过程。 除了技术挑战之外,通用的在线身份解决方案需要私营机构和政府之间的合作。 此外,需要在不同的国家进行法律制度的导航,问题变得十分困难。 互联网上的电子商务目前依赖于SSL证书(小绿色锁),用于网络上的安全交易。 Netki是一个希望为区块链创建SSL标准的创业公司。 Netki最近宣布了350万美元的种子,Netki在2017年初将推出产品。 反洗钱(AML)和 充分了解你的客户(KYC) 反洗钱(AML)和充分了解您的客户(KYC)在区块链应用这块有很大的开发潜力。 目前,金融机构必须为每位新客户执行劳动密集型多步骤流程。 通过跨机构客户验证可以减少KYC成本,同时增加监控和分析的有效性。 启动Polycoin有一个涉及分析交易的AML / KYC解决方案。 被认定为可疑的交易转交给合规官。 Tradle正在开发一个名为Trust in Motion(TiM)的应用程序。 作为“KYC的Instagram”,TiM允许客户拍摄关键文件(护照,公用事业帐单等)的快照。 一旦经过银行的验证,这些数据被加密地存储在区块上。 数据管理 今天,为了交换大家的个人资料,人们可以免费使用Facebook等社交媒体平台。 将来,用户将能够管理和销售其在线活动产生的数据。 因为它可以容易地以小数量的分发,比特币(或类似的东西)很可能是用于这种类型的交易的货币。 麻省理工学院项目Enigma了解到,用户隐私是创建个人数据市场的关键前提。 Enigma使用加密技术来允许单个数据集在节点之间分割,同时在整个数据组上运行批量计算。 数据碎片也使Enigma可扩展(不像那些在每个节点上复制数据的区块链解决方案)。 土地所有权登记 作为可公开访问的分布式账本,区块链可以使各种记录更有效率。 属性标题就是一个例子。 他们往往容易受欺诈,以及管理费用高昂和劳动密集。 一些国家正在进行以封锁为基础的土地登记项目。 洪都拉斯是第一个在2015年宣布这一举措的政府,尽管该项目目前的状况不明确。 今年,格鲁吉亚共和国与Bitfury集团达成协议,开发了一个区块链产权制度。 据报道,高调的经济学家和产权倡导者Hernando de Soto将就该项目提供建议。 最近,瑞典宣布正在试验一个块式的财产申请。 股票交易 股票结算增加效率的潜力为股票交易中的区块结构提供了强有力的用例。 执行点对点时,交易确认变得几乎瞬间(而不是花三天时间清算)。 潜在地,这意味着中介机构(如结算所,审计师和监管人)被从过程中移除。 许多股票和商品交易所都是为其提供的服务提供原始形式的封锁应用程序,包括澳大利亚证券交易所(澳大利亚证券交易所),德意志交易所(德国法兰克福证券交易所)和JPX(日本交易所集团)。 纳斯达克的Linq是私人市场交易的平台(通常在IPO前创业公司和投资者之间),这是该地区公认的先行者最为高调。 与积木科技公司Chain的合作,Linq宣布在2015年完成其首次股票交易。纳斯达克近日宣布,开发一项针对爱沙尼亚股票代理投票的试用块链项目。

优秀的个人博客,低调大师

ELK入门使用-与springboot集成

前言 ELK官方的中文文档写的已经挺好了,为啥还要记录本文?因为我发现,我如果不写下来,过几天就忘记了,而再次捡起来必然还要经历资料查找筛选测试的过程。虽然这个过程很有意义,但并不总是有那么多时间去做。因此,接下来的内容仅仅是我根据查询到的资料,筛选,组装,测试后达到我的目标的一个过程。 什么是ELK K我最初还以为是Kafka,事实上,ELK平台是一个完整的日志分析解决方案,由这三个开源工具构建而成:Elasticsearch、Logstash、Kibana。 Elasticsearch用于深度搜索和数据分析,它是基于Apache Lucene的分布式开源搜索引擎,无须预先定义数据结构就能动态地对数据进行索引; Logstash用于日志集中管理,包括从多台服务器上传输和转发日志,并对日志进行丰富和解析,是一个数据管道,提供了大量插件来支持数据的输入和输出处理; 最后是Kibana,提供了强大而美观的数据可视化,Kibana完全使用HTML和Javascript编写,它利用Elasticsearch 的RESTful API来实现其强大的搜索能力,将结果显示位各种震撼的图形提供给最终的用户。 安装Elasticsearch 官网下载对应平台的安装包。 Windows用法比较简单,只要下载后双机bin/elasticsearch.bat就启动成功了. 下面关注linux上的安装使用。 ES不允许root运行,所以,最好我们创建专门的用户来运行。 解压后,运行./bin/elasticsearch就会启动成功。如果失败,应该是用root启动的,改成普通用户即可。 然后浏览器访问:http://localhost:9200/ 可以看到响应 { "name": "ZSedUub", "cluster_name": "elasticsearch", "cluster_uuid": "_pS5AOR4Rf2oGPk5uRKK-A", "version": { "number": "6.2.4", "build_hash": "ccec39f", "build_date": "2018-04-12T20:37:28.497551Z", "build_snapshot": false, "lucene_version": "7.2.1", "minimum_wire_compatibility_version": "5.6.0", "minimum_index_compatibility_version": "5.0.0" }, "tagline": "You Know, for Search" } 安装Kibana 官网下载对应平台的安装包。然后,解压。 启动: ./bin/kibana 浏览器访问: http://localhost:5601 安装logstash 官网下载对应平台的安装包。然后,解压。 这里采用压缩包的方式,当然也可以使用系统安装包,比如 //ubuntu sudo apt-get update && sudo apt-get install logstash centos rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch 在/etc/yum.repos.d/ 新建logstash.repo [logstash-6.x] name=Elastic repository for 6.x packages baseurl=https://artifacts.elastic.co/packages/6.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md sudo yum install logstash 甚至docker。 修改ruby仓库地址为中国:编辑Gemfile 修改为source "https://gems.ruby-china.org/" 启动: bin/logstash -e 'input { stdin { } } output { stdout {} }' 这是一个交互式输入,你输入的内容将被当做message收集起来。 test { "message" => "test", "@version" => "1", "@timestamp" => 2018-05-26T14:29:09.212Z, "host" => "ryan-900X5L" } 到这里就算安装成功了。 遇到的问题, Unsupported platform: x86_64-linux 原因是Java9不支持,卸载Java9即可。 安装logstash-codec-json_lines插件 ryan@ryan-900X5L:~/apps/logstash-6.2.4$ ./bin/logstash-plugin install logstash-codec-json_lines Validating logstash-codec-json_lines Installing logstash-codec-json_lines Installation successful 接下来,我们直接编写我们springboot需要的配置方案,新建config/logstash-sample.conf input { tcp { port => 4560 codec => json_lines } } output{ elasticsearch { hosts => ["localhost:9200"] index => "%{[appName]}-%{+YYYY.MM.dd}" #用一个项目名称来做索引 } stdout { codec => rubydebug } } 4560 是logstash接收数据的端口 codec => json_lines是一个json解析器,接收json的数据。这个要装 logstash-codec-json_lines 插件 ouput elasticsearch指向我们安装的地址 stdout会打印收到的消息,调试用 启动: ./bin/logstash -f config/logstash-sample.conf 新建一个springboot项目 项目地址: https://github.com/Ryan-Miao/springboot-with-elk pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>springboot-with-elk</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-with-elk</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 新建启动类 @SpringBootApplication public class SpringbootWithElkApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(SpringbootWithElkApplication.class, args); } @Override public void run(String... args) throws Exception { Logger logger = LoggerFactory.getLogger(SpringbootWithElkApplication.class); logger.info("测试log"); for (int i = 0; i < 10; i++) { logger.error("something wrong. id={}; name=Ryan-{};", i, i); } } } 在resources下新建logback-spring.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration> <configuration> <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <destination>localhost:4560</destination> <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" /> </appender> <include resource="org/springframework/boot/logging/logback/base.xml"/> <root level="INFO"> <appender-ref ref="LOGSTASH" /> <appender-ref ref="CONSOLE" /> </root> </configuration> 启动。然后就可以观察到,logsash控制台打印我们的日志 { "@version" => "1", "thread_name" => "restartedMain", "message" => "something wrong. id=9; name=Ryan-9;", "logger_name" => "com.test.springbootwithelk.SpringbootWithElkApplication", "level_value" => 40000, "@timestamp" => 2018-05-26T15:21:05.109Z, "host" => "localhost", "level" => "ERROR", "port" => 34902 } 在kibana- management - index pattern里新建一个pattern,我们就用*吧。创建好了,点击discover。就可以看到我们的日志了 到这里,hello world完成。当然还要继续高级配置和查询啥的,后面再说。 参考 logstash官网 关注我的公众号 唯有不断学习方能改变! -- Ryan Miao

优秀的个人博客,低调大师

任务调度工具Quartz入门笔记

一,导包 1)官网下载:http://www.quartz-scheduler.org/downloads/ 2)Maven <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> 二,实例 1.先定义一个作业任务类,写我们的执行代码 package cn.zyzpp.quartz.demo; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.Trigger; /** * Created by yster@foxmail.com * 2018年4月9日 下午11:00:52 */ public class HelloJob implements Job { //第(2)种获取传入的参数的方法:setter方法 属性对应key的值 private String setKey; public void execute(JobExecutionContext context) throws JobExecutionException { //获取JobDetail对象 String now = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss").format(new Date()); JobDetail detail = context.getJobDetail(); String group = detail.getKey().getGroup(); String value = detail.getJobDataMap().getString("key"); //获取Trigger对象 Trigger trigger = context.getTrigger(); value= trigger.getJobDataMap().getString("key"); //获取JobDataMap对象 //第(1)种获取传入的参数的方法 JobDataMap data = context.getMergedJobDataMap(); value = data.getString("key");//相同key 调用trigger的value //System.out.println(group + ":" + value + " at " + now + setKey); //获取Jobkey对象 JobKey jobKey = trigger.getJobKey(); String name = jobKey.getName(); group = jobKey.getGroup(); try { Thread.sleep(5000l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(now + ":" + name + " " +group); } public String getSetKey() { return setKey; } public void setSetKey(String setKey) { this.setKey = setKey; } } 2. package cn.zyzpp.quartz.demo; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; import org.quartz.SimpleScheduleBuilder; import org.quartz.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.Trigger; import org.quartz.impl.StdSchedulerFactory; /** * Created by yster@foxmail.com 2018年4月9日 下午10:57:14 */ public class QuartzTest { public static void main(String[] args) { SimpleDateFormat sf =new SimpleDateFormat("yyyy-mm-dd hh:mm:ss"); try { // Quartz 作业:定义一个JobDetail:为Job类设置属性 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) // 定义Job类为HelloQuartz类,这是真正的执行逻辑所在 .withIdentity("job1", "group1") // 定义name/group .usingJobData("key", "job-value") // 自定义参数 .usingJobData("setKey", "setValue").build(); // System.out.println(jobDetail.getKey().getName()); // System.out.println(jobDetail.getKey().getGroup()); // System.out.println(jobDetail.getJobClass()); // 定义任务开始时间以及结束时间 Date startDate = new Date(); System.out.println("scheduler开始:" + sf.format(new Date())); startDate.setTime(new Date().getTime() + 2000); Date endDate = new Date(); endDate.setTime(startDate.getTime() + 4000); // Quartz触发器:定义一个Trigger Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") // 定义name/group // .startNow()//一旦加入scheduler,立即生效 .startAt(startDate) .endAt(endDate) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) // 每隔一秒执行一次 .repeatForever()) // 一直执行,奔腾到老不停歇 .usingJobData("key", "trigger-value") .build(); //SimpleTrigger 在一个指定时间段内执行一次作业任务 或者在指定时间间隔内多次执行作业任务 SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder .newTrigger() .withIdentity("trigger1", "group1") // 定义name/group .startAt(startDate) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .withRepeatCount(3)) //执行第1次后再执行3次(SimpleTrigger.REPEAT_INDEFINITELY) .build(); //CronTrigger 基于 cron 表达式,更常用 CronTrigger cronTrigger = (CronTrigger) TriggerBuilder .newTrigger() .withIdentity("trigger1", "group1") // 定义name/group .startAt(startDate) .withSchedule( //Cron表达式:[秒][分][时][日][月][周][年] (周日1-周六7,年可不写) *每 ?不关心 -至 #第 /递增 ,和 L最后 W最近工作日 CronScheduleBuilder.cronSchedule("0/2 * * * * ? * ") ) .build(); // 调度类链接“工作”和“触发器”到一起,并执行它 // 创建scheduler StdSchedulerFactory sfact = new StdSchedulerFactory(); Scheduler scheduler = sfact.getScheduler(); // 加入这个调度 返回第一次执行时间 scheduler.scheduleJob(jobDetail, cronTrigger); //System.out.println("调度器:" + sf.format(scheduler.scheduleJob(jobDetail, cronTrigger))); // 启动之 scheduler.start(); // 运行一段时间后暂停 可再次start 当前主线程不终止 Thread.sleep(10000l); // scheduler.standby(); // System.out.println("暂停:三秒后再次开启"); // Thread.sleep(3000l); // scheduler.start(); // Thread.sleep(5000l); scheduler.shutdown(true);//true等待执行的job完成后关闭scheduler,false直接关闭 System.out.println("scheduler终止" + sf.format(new Date())); } catch (Exception e) { e.printStackTrace(); } } } 三,干货 1)Cron表达式 2)/org/quartz/quartz.properties 3)集成Spring <!-- JobDetail --> <!-- (1)simpleJobDetail : 定义任务类和任务方法--> <bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myBean" /> <property name="targetMethod" value="printMessage" /> </bean> <!--(2)继承 QuartzJobBean 传参--> <bean id="firstComplexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="com.imooc.springquartz.quartz.FirstScheduledJob" /> <property name="jobDataMap"> <map> <entry key="anotherBean" value-ref="anotherBean" /> </map> </property> <property name="durability" value="true"/> </bean> <!--Trigger--> <!-- (1)距离当前时间1秒之后执行,之后每隔两秒钟执行一次 --> <bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="simpleJobDetail"/> <property name="startDelay" value="1000"/> <property name="repeatInterval" value="2000"/> </bean> <!-- (2)每隔5秒钟执行一次 --> <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="firstComplexJobDetail"/> <property name="cronExpression" value="0/5 * * ? * *"/> </bean> <!-- (3)Scheduler --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobDetails"> <list> <ref bean="simpleJobDetail"/> <ref bean="firstComplexJobDetail"/> </list> </property> <property name="triggers"> <list> <ref bean="mySimpleTrigger"/> <ref bean="myCronTrigger"/> </list> </property> </bean> 1.MyBean.java import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.stereotype.Component; @Component("myBean") public class MyBean { public void printMessage() { // 打印当前的执行时间,格式为2017-01-01 00:00:00 Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("MyBean Executes!" + sf.format(date)); } } 2.AnotherBean.java import org.springframework.stereotype.Component; @Component("anotherBean") public class AnotherBean { public void printAnotherMessage() { System.out.println("AnotherMessage"); } } 3.FirstScheduledJob.java import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; public class FirstScheduledJob extends QuartzJobBean{ private AnotherBean anotherBean; public void setAnotherBean(AnotherBean anotherBean){ this.anotherBean = anotherBean; } @Override protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("FirstScheduledJob Executes!" + sf.format(date)); this.anotherBean.printAnotherMessage(); } }

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册