首页 文章 精选 留言 我的

精选列表

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

不学无数——SpringBoot入门IV

SpringBoot 1.Profiles Spring Profiles能够在不同的环境中使不同的应用配置生效。@Component和@Configuration两个注解都能够通过@Profiles来标记。下面是例子: @Configuration @Profile("buxuewushu") public class ProductionConfiguration { // ... } 在配置文件中可以通过spring.profiles.active这个变量来控制哪个Profiles生效。例如,可以在application.properties配置文件中配置如下: spring.profiles.active=buxuewushu1,buxuewushu --即通过@Profiles注解标记的名为buxuewushu和buxuewushu1的文件生效 当然也可以通过命令行的形式进行配置:--spring.profiles.active= buxuewushu1, buxuewushu 1.1在代码中配置 在启动文件运行之前可以通过SpringApplication设置需要使哪一个配置生效,SpringApplication.setAdditionalProfiles(…​),也可以通过Spring的ConfigurableEnvironment接口来配置。 2.日志 SpringBoot使用 Commons Logging作为内部的日志门面,但是也提供了一系列的接口来实现扩展。默认的日志配置有,Java Util Logging,Log4J2和[Logback] (https://commons.apache.org/proper/commons-logging/),在这每一种的实现下,都能通过配置来实现针对于哪一些日志的输出。 2.1日志的格式 SpringBoot默认的日志输出格式如下所示,默认输出级别是INFO。默认使用的是Logback进行记录日志的。 2018-07-20 19:11:40.046 INFO 21758 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@db57326: startup date [Fri Jul 20 19:11:38 CST 2018]; root of context hierarchy 2018-07-20 19:11:40.093 INFO 21758 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String com.example.FirstSpringBoot.FirstSpringBootApplication.home() 2018-07-20 19:11:40.097 INFO 21758 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2018-07-20 19:11:40.097 INFO 21758 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 时间:非常精确的时间,并且是根据时间进行排序的输出顺序。 日志级别:ERROR,WARN,INFO,DEBUG,TRANCE 进程ID 通过---进行分割,右边为实际的日志输出内容 线程名 日志名称:通常是源类的名称 日志的内容 2.2调整日志级别 SpringBoot默认的日志级别是INFO,如果想打印其他级别的日志的话可以通过配置。日志级别的顺序是ERROR>WARN>INFO>DEBUG>TRANCE.第一种办法是通过在启动的时候进行参数的配置--debug。 $ java -jar myapp.jar --debug 当然也可以通过配置文件的形式进行调整级别。debug=true,即输出为DEBUG级别的日志信息。 2.3在文件中记录日志 默认情况下,SpringBoot仅仅在控制台中打印日志,不会将日志记录在文件中。如果想将日志输出在文件中的话,那么可以在配置文件中配置文件的路径。logging.file或者logging.path.下面介绍logging.file和logging.path的区别。 logging.file logging.path 例子 描述 none none none 仅仅在控制台中输出日志 文件名 none buxuewushu.log 会在项目的根目录下生成一个buxuewushu.log来记录日志 none 文件夹的名字 ./logs 会在项目的根目录中生成一个logs文件夹,logs文件下会生成默认的spring.log来记录日志 当日志文件记录的数据达到一定量时,SpringBoot会将此文件进行压缩为.gz的压缩文件。SpringBoot默认的大小为10M。当然这个大小也可以通过logging.file.max-size进行配置,但是必须得带单位。 2.4自定义日志配置 许多的日志系统能够被相应的配置文件所配置,或者通过在application.properties中配置Spring的环境变量进行配置logging.config。 可以通过org.springframework.boot.logging.LoggingSystem的系统变量的设置从而使用特定的日志系统,系统日志的value值应该是日志实现的全路径名。 由于日志的加载是在ApplicationContext创建之前的,所以不能通过@PropertySources和@Configuration进行配置。唯一的配置方式就是在系统的环境变量中。 不同的日志系统所对应的配置文件如下: 日志名 文件名 Logback logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy Log4j2 log4j2-spring.xml or log4j2.xml JDK (Java Util Logging) logging.properties Java Util Logging在可执行jar包运行时,可能会造成类加载的问题,所以尽可能避免在jar包执行时使用Java Util Logging 为了更好配置化,一些在properties中的配置被转化为了配置在系统中的变量。对应关系如下: Spring配置变量 系统变量 描述 logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 记录异常时使用的转换字 logging.file LOG_FILE 用于默认日志配置在哪个文件中 logging.path LOG_PATH 用于默认日志配置文件夹下 logging.file.max-size LOG_FILE_MAX_SIZE 日志文件中支持的最大容量 logging.file.max-history LOG_FILE_MAX_HISTORY 最大的已经被压缩的文件的数量 logging.pattern.console CONSOLE_LOG_PATTERN 在控制台上使用的日志模式 PID PID 当前的进程ID(如果可能,还没有被定义为OS环境变量时发现) 2.5 Logback的扩展 SpringBoot为Logback的可扩展性提供了许多的帮助。能够在logback-spring.xml文件中进行配置想要扩展的内容。 由于logback.xml文件的加载时间太早了,所以不能将扩展的内容配置在logback.xml中。 通常在开发过程中,我们根据不同的环境进行配置不同的日志级别。所以在配置文件中可以通过<springProfile>标签进行有选择的使具体哪一步分生效。例子如下,在logback-spring.xml进行配置 --想要的配置的具体内容在<springProfile>标签中进行编写 <springProfile name="staging"> <!-- 配置staging生效 --> </springProfile> <springProfile name="dev | staging"> <!-- 配置dev或者staging生效 --> </springProfile> <springProfile name="!production"> <!-- 配置除了production之外的生效 --> </springProfile>

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

Java入门(一)---面向对象

二狗子.jpeg 面向对象: 关注现实存在的事物的各个方面的信息,从对象的角度出发,根据事物的特征进行程序设计。 类 类,是抽象的概念,可以理解为一个模型,用来确定对象将会拥有的特征(属性)和行为(方法) 对象,是类的实例表现形式,一个实体。 类的属性:对象具有的各种静态特征 (对象有什么) 类的方法:对象具有的各种动态行为 (对象能做什么) 实例化 定义一个Dog类,有两个属性name和age,还有两个方法,run()和eat() 新建文件Dog.java public class Dog { //成员属性:name age String name; int age; //成员方法: run eat public void run(){ System.out.println("跑"); } public void eat(){ System.out.println("吃"); } } 接着,再定义一个用来测试的类, TestDog.java 1 public class TestDog { 2 public static void main(String[] args){ 3 Dog dog = new Dog(); 4 dog.name = "灰灰"; 5 dog.age = 2; 6 System.out.println(dog.name); 7 System.out.println(dog.age); 8 dog.eat(); 9 dog.run(); } } 下边来看下TestDog.java做了些什么: 第一行第二行的基础部分这里不再赘述,直接看第三行,实例化对象 Dog dog = new Dog(); 实例化对象的过程可以分为两部分: 声明对象 Dog dog :在内存的栈空间开辟一块空间, 此时对象是空的, 无法使用 实例化对象 new Dog() : 在内存的堆空间开辟一块空间,完成具体对象初始化操作 image.png 通过赋值操作,把堆空间的内存地址存放到了 dog中: Dog dog = new Dog(); 关于对象的实例化操作,是通过new + 构造方法的形式来完成的。 构造方法 构造方法也称为构造函数、构造器: 1.构造方法与类同名且没有返回值 2.只能在对象实例化的时候调用(配合 new调用) 3.当没有指定构造方法时,系统会自动添加无参的构造方法 4.当指定了构造方法,无论有参数还是无参数的构造方法,都不会自动添加无参数的构造方法 5.一个类中可以有多个构造方法,---构造方法重载,java会根据参数去自动选择。 上边的Dog.java没有定义构造方法,在调用时系统自动帮我们添加无参数的构造方法,下边我们添加上有参数的构造方法: public class Dog { String name; int age; //带参数的构造方法 public Dog(String name, int age){ } public void run(){ System.out.println("跑"); } public void eat(){ System.out.println("吃"); } } 当我们使用带参数的构造函数来进行初始化的时候,为了避免产生赋值错误的情况,可以使用this关键字 this关键字 this代表当前对象的默认引用,上述代码,dog就是当前对象 更改Dog.java public class Dog { String name; int age; //带参数的构造方法 public Dog(String name, int age){ //把传入的 name 赋值给局部变量 name this.name = name; //把传入的 age 赋值给局部变量 age this.age = age; } public void run(){ //调用成员方法eat,(这里只是演示this的使用 不关心逻辑) this.eat(); System.out.println("跑"); } public void eat(){ //也可以不用this 直接调用成员方法run run(); System.out.println("吃"); } } 补充知识 我们在类中定义变量后,其实变量是有初始值的,代码说明: 新建Demo.java和TestDemo.java public class Demo { String name; int age; double d; boolean n; } public class TestDemo { public static void main(String[] args){ Demo de = new Demo(); System.out.println(de.name); System.out.println(de.age); System.out.println(de.d); System.out.println(de.n); } } 运行结果: null 0 0.0 false 上边Demo.java中定义了四个不同类型的变量,直接在TestDemo.java中调用并打印,可看到变量的默认值。 下图展示了变量定以后的初始值: image.png

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

Java 基础 之 入门HelloWorld

http://www.verejava.com/?id=1699251664916 import java.lang.*; /** @author : 胡杨 @version : 1.0 1. //双斜杠代表注释, 是给人看的, 机器忽略不计 2. public 公有的, 是java 的关键字 3. class 叫 类, 每一个java文件里必须包含一个类 4. HelloWord 叫 类名, 类名可以跟文件名不一样, 但是规范一般写成一样 5. static 叫 静态的, main方法必须写static java 虚拟机才能找到 6. void 空 也就是没有返回值 7. main 叫主方法, 是java程序的入口, 必须这么写固定的, 否则程序不能运行. 8. String 字符串 是用双引号括起来的数字字符的一连串的组合 9. String[] 字符串数组 10. args 叫 main 方法的参数 11. System: 系统, out : 输出 println : 打印 12. 类名 后面{}部分叫做 类体 括号必须成对出现 13. 主方法main 后面 {} 部分叫做方法体 括号必须成对出现 14. import java.lang.*; 叫做 导入 java.lang下面的所有类, 但是java 默认 java.lang 下面的类已经导入, 所有 java.lang这个包也是java唯一可以省略不用导入的包. 编码规范: 1. 类名 第一个单词首字母大写, 如果有多个单词组成, 每个单词的首字母大写 2. java 是区分大小写的语言 3. 书写类体时{} 括号要成对出现 4. 书写方法体时{}括号要成对出现 5. 方法写在类体中 每个方法前面留一个 Tab 键空格 6. 方法中的执行语句 写作方法体中 每条执行语句 相对于方法前面留一个Tab 键空格, 并且每条执行语句后面都要写一个分号; 表示该条语句执行结束 */ public class HelloWorld { public static void main(String[] args) { //向控制台打印输出 Hello Word信息 然后换一行 System.out.println("Hello Word"); //向控制台打印输入信息, 但不换行 System.out.print("aaaa\t"); System.out.print("bbb"); } } http://www.verejava.com/?id=1699251664916

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

react新手入门(序)

之前在软件园使用的是react,当时为了做个集光推送,自己去搭过react,这次项目中继续使用react,于是又重新操作了遍,恰巧公司买了本react的书籍,这本书写的非常好,看着并不觉得拗口,很容易理解,于是我又搭了遍react,然后对比之前写的我的第一个react,感觉这次对react更加深入理解了。先把这本书推荐给大家。 react深入浅出 react安装步骤: 1.通过官网https://nodejs.org/安装node.js和npm, node装好,npm就出来了 2.查看是否安装成功npm -v, node -v 3.npm install --global create-react-app 4.create-react-app first_react_app 5.cd first_react_app 6.npm start 7.进入项目中运行npm install,然后npm start,由于前端数据绑定层是react,UI框架是阿里的Ant Design,这框架不支持ie,所以只能在谷歌等浏览器上操作 image.png image.png 也可以用淘宝的镜像下载淘宝镜像 下载完以后可以直接用cnpm install安装即可,淘宝镜像服务器都在国内速度相对快些。 image.png image.png image.png 我看了TypeError不支持startsWith想到了可能跟浏览器有关 react的背景:facebook出品,目前最为流行的前端框架之一,相比vue和angular来说,vue相对react要容易上手,但是性能和功能都略差,angular更新太快,从angular1到angular4,可以说是面目全非,并且后期有点抄袭react的趋势,react不仅功能强度,性能好,有单元测试,热部署等优势,目前更新也很快,很多大厂都在使用react。 个人看法:目前比较流行的技术栈是,前端(深度)react+Ant Design,广度(小程序,app,公众号等等),后端springboot+springcloud+mysql+hadop+docker+spark+elasticsearch,技术这东西真是学之不尽。这也是我个人看法,不一定全面。

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

Protocol Buffers入门教程

什么是Protocol Buffers 先看官网定义: protocol buffers – a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more. Protocol Buffers 是一种结构化数据的存储格式,可以用于结构化数据的序列化和反序列化。它很适合做数据存储、 RPC 数据交换格式。 Protocol Buffers的作用可以类比JSON、XML。 对于传输双方,如果约定好使用Protocol Buffer为数据传输的格式,那么这将是一种比JSON和XML都高效轻便的途径。 Protocol Buffers支持多种编程语言,包括C++、Java、Python、Go、C#等。 安装Protocol Buffers 1、官网下载压缩包 2、解压 tar -zxvf protobuf-all-3.6.0.tar.gz 3、protobuf的包需要自己编译 cd protobuf-3.6.0 ./configure make make install 4、在protobuf-3.6.0目录下有对应着各种语言的文件夹,每个文件夹下都有README.md,里面有相应的安装步骤。对于python: cd protobuf-3.6.0/python python setup.py build python setup.py test python setup.py install 5、到此为止,protobuf的python版本已经安装完成,可在命令行键入protoc试试。 Demo 1、创建addressbook.proto文件。.proto文件定义了要序列化的数据结构。 syntax = "proto2"; package tutorial; message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; } 2、编译addressbook.proto protoc --python_out=/Users/ya/developer/protoc-test addressbook.proto 这一条命令执行完后会在你指定的目录下生成addressbook_pb2.py文件。 addressbook_pb2.py会提供关于所定义的数据结构的操作方法。 3、编写writer.py,负责序列化数据并保存到文件 # See README.txt for information and build instructions. import addressbook_pb2 import sys try: raw_input # Python 2 except NameError: raw_input = input # Python 3 # This function fills in a Person message based on user input. def PromptForAddress(person): person.id = int(raw_input("Enter person ID number: ")) person.name = raw_input("Enter name: ") email = raw_input("Enter email address (blank for none): ") if email != "": person.email = email while True: number = raw_input("Enter a phone number (or leave blank to finish): ") if number == "": break phone_number = person.phones.add() phone_number.number = number type = raw_input("Is this a mobile, home, or work phone? ") if type == "mobile": phone_number.type = addressbook_pb2.Person.MOBILE elif type == "home": phone_number.type = addressbook_pb2.Person.HOME elif type == "work": phone_number.type = addressbook_pb2.Person.WORK else: print("Unknown phone type; leaving as default value.") # Main procedure: Reads the entire address book from a file, # adds one person based on user input, then writes it back out to the same # file. if len(sys.argv) != 2: print("Usage:", sys.argv[0], "ADDRESS_BOOK_FILE") sys.exit(-1) address_book = addressbook_pb2.AddressBook() # Read the existing address book. try: with open(sys.argv[1], "rb") as f: address_book.ParseFromString(f.read()) except IOError: print(sys.argv[1] + ": File not found. Creating a new file.") # Add an address. PromptForAddress(address_book.people.add()) # Write the new address book back to disk. with open(sys.argv[1], "wb") as f: f.write(address_book.SerializeToString()) 5、执行writer.py python writer.py addressbook.data 执行完脚本后数据将会序列化并存储到addressbook.data中。 6、编写reader.py,负责读取文件并反序列化数据 import addressbook_pb2 import sys # Iterates though all people in the AddressBook and prints info about them. def ListPeople(address_book): for person in address_book.people: print "Person ID:", person.id print "Name:", person.name if person.email != "": print "E-mail address:", person.email for phone_number in person.phones: if phone_number.type == addressbook_pb2.Person.MOBILE: print "Mobile phone :", elif phone_number.type == addressbook_pb2.Person.HOME: print "Home phone :", elif phone_number.type == addressbook_pb2.Person.WORK: print "Work phone :", print(phone_number.number) # Main procedure: Reads the entire address book from a file and prints all # the information inside. if len(sys.argv) != 2: print("Usage:", sys.argv[0], "ADDRESS_BOOK_FILE") sys.exit(-1) address_book = addressbook_pb2.AddressBook() # Read the existing address book. with open(sys.argv[1], "rb") as f: address_book.ParseFromString(f.read()) ListPeople(address_book) 7、执行reader.py python reader.py addressbook.data 输出结果示例: Person ID: 1 Name: kanon E-mail address: 540004716@qq.com Mobile phone : 123456 两个很重要的方法 SerializeToString( ):serializes the message and returns it as a string. ParseFromString( data ):parses a message from the given string. Protocol Buffers 相比 XML are simpler are 3 to 10 times smaller are 20 to 100 times faster are less ambiguous generate data access classes that are easier to use programmatically 在ODPS(MaxCompute)中的应用 ODPS的Tunnel HTTP Server采用了Protobuf作为其序列化机制。客户端在上传数据时,需要先对结构化数据进行序列化(生成二进制流),Tunnel服务端接收到数据后,(对二进制流)执行反序列化,还原出结构化数据,写到ODPS表中。

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

代码审计入门总结

参考文献:http://www.vuln.cn/6701 通用思路 通读全文代码,从功能函数代码开始阅读,例如include文件夹下的common_fun.php,或者有类似关键字的文件。 看配置文件,带有config关键字的文件,找到mysql.class.php文件的connect()函数,查看在数据库连接时是否出现漏洞。 继续跟读首页文件index.php了解程序运作时调用了哪些函数和文件,以index.php文件作为标线,一层一层去扩展阅读所包含的文件,了解其功能,之后进入其功能文件夹的首页文件,进行扩展阅读。 漏洞总结: 1.文件操作漏洞 ①.文件包含漏洞:(详细可看:https://www.jianshu.com/p/41bb503abe61) (1) 本地文件包含: 一般存在于模块加载,模板加载,cache调用 包括函数:include()/include_once(),require()/require_once()寻找可控变量 (2)* 远程文件包含:* 前提条件:allow_url_include = on (3) 文件包含截断: %00截断(php版本小于5.3) 问号截断(问号后面相当于请求的参数,伪截断) 英文(.) 反斜杠(/) 截断 ②.文件读取(下载)漏洞: 搜索关键函数: file_get_contents() highlight_file() fopen() read file() fread() fgetss() fgets() parse_ini_file() show_source() file() ...... ③.文件上传漏洞: 搜索关键函数:move_uploaded_file()接着看调用这个函数的代码是否存在为限制上传格式或者可以绕过。 (1) 未过滤或本地过滤: 服务器端未过滤,直接上传PHP格式的文件即可利用。 (2) 黑名单扩展名过滤: 限制不够全面:IIS默认支持解析.asp,.cdx, .asa,.cer等。 (3) 文件头 content-type验证绕过: getimagesize()函数:验证文件头只要为GIF89a,就会返回真。 限制$_FILES["file"]["type"]的值 就是人为限制content-type为可控变量。 ④.文件删除漏洞: 搜索关键函数:unlink()利用回溯变量的方式 老版本下的session_destroy(),可以删除文件,现已基本被修复。 2.代码执行漏洞 ①代码执行函数: 搜索关键函数: eval(), assert(), preg_replace(), call_user_func(), call_user_func_array(), array_map() (1) preg_replace()函数: mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) 当$pattern处存在e修饰符时,$replacement 会被当做php代码执行。 (2)call_user_func()函数 mixed call_user_func( callable $callbank [ , mixed $parameter [ , mixed $…): 第一个参数为回调函数,第二个参数是回调函数的参数 (3)eval()和assert(): 当assert()的参数为字符串时 可执行PHP代码 eval(" phpinfo(); ");【√】 eval(" phpinfo() ");【X】 assert(" phpinfo(); ");【√】 assert(" phpinfo() ");【√】 ②.动态函数执行: 动态函数后门: <?php $_GET['a']($_GET['b']); ?> 1.png ③.命令执行函数: 搜索关键函数: system(), exec(), shell_exec(), passthru() ,pcntl_exec(), popen(),proc_open() (1) popen()和proc_open(): <?php popen( 'whoami >> 1.txt', 'r' ); ?> 所在路径就会出现一个1.txt ,里面的内容为命令执行后的结果 (2) 反引号命令执行: <?php echo `whoami`; ?> //直接就可以执行命令 双引号和单引号的区别: <?php $a = 1; echo " $a " ; //1 echo ' $a ' ;//$a ?> //双引号时,可以直接解析变量,造成代码执行漏洞。 3.变量覆盖漏洞 ①.函数使用不当: int extract( array &$var_array , int $extract_type = EXTR_OVERWRITE , string $prefix = null ) void parse_str( string $str , array &$arr ) bool import_request_variables( string $type , string $prefix ) ②.$$变量覆盖: <?php include "flag.php"; if ($_SERVER["REQUEST_METHOD"] != "POST") die("flag is here"); if (!isset($_POST["flag"]) ) die($_403); foreach ($_GET as $k => $v){ $$k = $$v; } foreach ($_POST as $k => $v){ $$k = $v; } if ( $_POST["flag"] !== $flag ) die($_403); echo "flag: ". $flag . "\n"; die($_200); ?> 使用了两个foreach并且也使用了$$.两个foreach中对 $$key的处理是不一样的,满足条件后会将$flag里面的值打印出来。 但是由于后两个if语句及foreach代码会将$flag的值给覆盖掉了,所以需要先将$flag的值赋给$_200或$_403变量,然后利用die($_200)或 die($_403)将flag打印出来。 解题方法: 利用第一个foreach先将$flag的值赋给$_200,然后利用die($_200)将原本的flag值打印出来。 最终PAYLOAD: GET DATA:?_200=flag POST DATA:flag=aaaaaaaaaaaaaaaaaaaaa 4.逻辑漏洞 需要思考的问题: 程序是否可以重复安装 修改密码是否存在越权,修改其他用户密码 找回密码验证码是否可以暴力破解 cookie是否可以预测 验证存在绕过 ①.账户体系中的越权问题: 水平越权:A用户能够以B用户的身份,进行B用户的全部权限操作。前提A用户和B用户拥有相同的权限。 垂直越权:A用户能够以C用户的身份,进行C用户的全部权限操作,前提C用户比A用户拥有更高的权限。 (1) 未exit/return/die: <?php if(file_exists('install.lock)){ header("Location:xxx.com"); } echo "test"; ?> test 依旧会被输出,替换成安装流程,PHP依旧会进行。 (2) 支付漏洞: 客户端修改单价 客户端修改总价和购买数量 服务端未校验严格 重复发包利用时间差: <?php if (check_money($price)){ //Do something //花费几秒 $money = $money - $price; } ?> 可能导致漏洞函数: str_replace() <?php $a = addslashes($_GET['a']); $b = addslashes($_GET['b']); echo "$a<br>$b<br>"; $c = str_replace($a,'',$b); echo trim($c); ?> 1.png 5.会话认证漏洞 COOKIE验证:没有使用SESSION验证,将信息直接保存在COOKIE中 找到传入sql语句的参数的传递过程,回溯变量到最原始的函数,看它保存在cookie的算法是否可逆 审计代码时,查看登录处代码

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

Terraform alicloud provider开发入门

Terraform和AliCloud Terraform provider简介 Terraform是一家名叫HashCorp的洛杉矶公司推出的,HashCorp名称来源于它的创始人Mitchell Hashimoto姓氏的一部分。Terraform宣称可以“为任意的应用部署任意的基础设施资源”,这得益于丰富的Terraform provider,目前全球顶级云计算玩家和热门的云计算架构(OpenStack/Kubernetes/Docker)都为Terraform贡献了provider。阿里云也不例外,AliCloud Terraform provider作为支持Terraform的providers之一,目前支持ECS, Block Storage, SLB, VPC, Nat Gateway, RDS, ESS, OSS等云产品

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

Docker 从入门到精通

1、yum安装 2、获取镜像 docker pull IP/iamjingxiang 3、运行镜像 docker run -t -i iamjingxiang /bin/bash 4、列出本地镜像 docker images 5、保存更改后的镜像 docker commit -m "Added json gem" -a "Docker Newbee" 0b2616b0e5a8 ouruser/sinatra:v2 6、Dockerfile文件来创建镜像 image.png 生成镜像:docker build ,其中.为dockerfile的路径 image.png 7、add复制文件,expose开放端口,CMD容器启动后的执行的东西 image.png 8、Docker push上传镜像 9、docker save/load 保存与载入压缩后的镜像 10、docker rm 删除镜像 11、docker run -d 后台启动容器 12、查看 docker ps -a 13、挂载本地磁盘到容器中 image.png 14、数据卷容器 image.png 15、本机与容器端口映射 image.png 16、查看端口映射与多端口映射 image.png 17、--LINK 容器互联

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

Elastic Stack学习--logstash入门

logstash是基于实时管道的数据收集引擎。它像一根处理数据的管道,收集分散的数据,进行汇总处理后输出给下游进行数据分析和展现。 logstash可以配合Beats组件或者其它第三方组件进行数据收集,数据经过处理后存放到elasticsearch中进行检索和分析。 除了对接beats以外,logstash有着丰富的组件,能够支持各种数据源接入。包括jdbc、kafka、http等。 logstash是基于pipeline方式进行数据处理的,pipeline可以理解为数据处理流程的抽象。在一条pipeline数据经过上游数据源汇总到消息队列中,然后由多个工作线程进行数据的转换处理,最后输出到下游组件。一个logstash中可以包含多个pipeline。 基本概念 pipeline:一条数据处理流程的逻辑抽象,类似于一条管道,数据从一端流入,经过处理后,从另一端流出;一个pipeline包括输入、过滤、输出3个部分,其中输入和输出部分是必选组件,过滤是可选组件; instance:一个logstash实例,可以包含多条数据处理流程,即多个pipeline; inputs:数据输入组件,用于对接各种数据源,接入数据,支持解码器,允许对数据进行编码解码操作;必选组件; filters:数据过滤组件,负责对输入数据进行加工处理;可选组件; outputs:数据输出组件,用于对接下游组件,发送处理后的数据,支持解码器,允许对数据进行编码解码操作;必选组件; event:pipeline中的数据都是基于事件的,一个event可以看作是数据流中的一条数据或者一条消息; 安装logstash 1)依赖java8,且不支持java9:检查java版本并配置JAVA_HOME环境变量。logstash基于jruby开发,logstash 6.x版本要求运行在java8环境,且目前不支持java9;2)下载并解压:下载logstash,解压文件;注意logstash所在路径中不可以包含冒号; tar -zxvf logstash-6.2.2.tar.gz cd logstash-6.2.2 3)启动logstash,发布第一个事件:通过-e指定一个pipeline的处理流程,指定从stdin中读取event,然后在stdout输出; bin/logstash -e 'input { stdin { } } output { stdout {} }' 可以看到类似如下日志: Sending Logstash's logs to /home/work/zion_package/elastic/logstash/logstash-6.2.2/logs which is now configured via log4j2.properties h[2018-03-14T14:48:00,053][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"fb_apache", :directory=>"/home/work/zion_package/elastic/logstash/logstash-6.2.2/modules/fb_apache/configuration"} [2018-03-14T14:48:00,074][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"netflow", :directory=>"/home/work/zion_package/elastic/logstash/logstash-6.2.2/modules/netflow/configuration"} [2018-03-14T14:48:00,172][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.queue", :path=>"/home/work/zion_package/elastic/logstash/logstash-6.2.2/data/queue"} [2018-03-14T14:48:00,178][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.dead_letter_queue", :path=>"/home/work/zion_package/elastic/logstash/logstash-6.2.2/data/dead_letter_queue"} [2018-03-14T14:48:00,631][WARN ][logstash.config.source.multilocal] Ignoring the 'pipelines.yml' file because modules or command line options are specified [2018-03-14T14:48:00,672][INFO ][logstash.agent ] No persistent UUID file found. Generating new UUID {:uuid=>"5901ab9f-fdc9-43dc-a88d-c5c636cf8224", :path=>"/home/work/zion_package/elastic/logstash/logstash-6.2.2/data/uuid"} [2018-03-14T14:48:01,337][INFO ][logstash.runner ] Starting Logstash {"logstash.version"=>"6.2.2"} [2018-03-14T14:48:01,733][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600} [2018-03-14T14:48:03,264][INFO ][logstash.pipeline ] Starting pipeline {:pipeline_id=>"main", "pipeline.workers"=>12, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>50} [2018-03-14T14:48:03,453][INFO ][logstash.pipeline ] Pipeline started succesfully {:pipeline_id=>"main", :thread=>"#<Thread:0x128244e5 run>"} The stdin plugin is now waiting for input: [2018-03-14T14:48:03,546][INFO ][logstash.agent ] Pipelines running {:count=>1, :pipelines=>["main"]} 在控制台随便输入字符串按回车后,发现消息会立刻在控制台输出,此时pipeline的处理过程是从stdin接收我们的输入,然后再在stdout输出: Hello, this is my first event to logstash ! 2018-03-14T06:50:26.261Z yf-beidou-dmp00.yf01.baidu.com Hello, this is my first event to logstash ! logstash会给消息添加ip和时间戳,要退出logstash,输入ctrl+d; 通过Filebeat发送日志到logstash 配置Filebeat Filebeat用于追踪服务器上的文件数据,它的设计以可靠和低资源占用为初衷,和业务系统部署在一起时,能够避免因为资源消耗影响到业务系统的正常运行。logstash安装后默认包含Beats input组件,用于接收各种beat组件上报事件。Filebeat也可以直接上报事件给elasticsearch,而不用经过logstash。 1)下载文件样例logstash-tutorial.log.gz,上传至Filebeat将要部署的服务器并解压;该样例为官方文档提供的apache的web日志样例。2)下载Filebeat,上传服务器并解压;此处下载LINUX 64-BIT的安装包; tar -zxvf filebeat-6.2.2-linux-x86_64.tar.gz cd filebeat-6.2.2-linux-x86_64 3)配置Filebeat,修改filebeat.yml,设置监控日志文件路径和上报logstash地址; filebeat.prospectors: - type: log # 监控日志文件路径 paths: - /path/to/file/logstash-tutorial.log output.logstash: # 上报logstash地址 hosts: ["localhost:5044"] 注:设置监控日志文件的路径一定是绝对路径,支持通配符; 4)启动Filebeat;其中-e参数指定输出日志到stderr,而非输出到日志文件;-c参数指定配置文件路径;-d参数debug选择器; ./filebeat -e -c filebeat.yml -d "publish" 配置logstash 1)创建pipeline配置文件;pipeline配置格式如下: # The # character at the beginning of a line indicates a comment. Use # comments to describe your configuration. input { } # The filter part of this file is commented out to indicate that it is # optional. # filter { # # } output { } 创建一个名为first-pipeline.conf的文件,配置如下: input { beats { # 设置beats上报端口 port => "5044" } } # The filter part of this file is commented out to indicate that it is # optional. # filter { # # } output { # 输出到stdout,同时指定日志解码器为rubydebug stdout { codec => rubydebug } } 2)校验配置是否正确,命令如下。--config.test_and_exit选项会校验配置文件,并输出错误; bin/logstash -f first-pipeline.conf --config.test_and_exit 输出类似如下日志,说明配置文件格式校验通过: Configuration OK [2018-03-14T16:23:08,919][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash 3)启动logstash,命令如下。--config.reload.automatic选项能够使得配置文件修改后被自动加载,从而避免重新启动logstash; bin/logstash -f first-pipeline.conf --config.reload.automatic 如果配置正确,可以看到logstash命令行有类似如下输出: { "host" => "yf-beidou-dmp00.yf01.baidu.com", "offset" => 22310, "tags" => [ [0] "beats_input_codec_plain_applied" ], "message" => "218.30.103.62 - - [04/Jan/2015:05:28:43 +0000] \"GET /blog/geekery/xvfb-firefox.html HTTP/1.1\" 200 10975 \"-\" \"Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)\"", "prospector" => { "type" => "log" }, "beat" => { "name" => "yf-beidou-dmp00.yf01.baidu.com", "version" => "6.2.2", "hostname" => "yf-beidou-dmp00.yf01.baidu.com" }, "@timestamp" => 2018-03-14T08:43:52.564Z, "source" => "/home/work/zion_package/elastic/filebeat/logstash-tutorial.log", "@version" => "1" } 通过Grok过滤组件解析日志 通过上面的例子,我们可以将filebeat上报的日志经由logstash输出,接下来将添加filter组件,对日志进行处理。grok组件是logstash的filter组件之一,它可以将非结构化的数据按照一定规则整理成结构化数据,从而便于检索。这些规则需要根据日志格式事先设定好,因此需要了解采集日志的格式。因为我们的样例日志是apache的web日志,因而可以直接使用grok提供的%{COMBINEDAPACHELOG}格式进行日志的过滤,过滤后的日志格式如下: 修改first-pipeline.conf文件,增加filter,如下: input { beats { port => "5044" } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} } } output { stdout { codec => rubydebug } } 因为启动logstash时添加了--config.reload.automatic选项,logstash能够自动加载修改后的配置文件,因而不需要重启;修改保存后可以看到重新加载配置,重启pipeline的日志: [2018-03-14T17:04:57,325][INFO ][logstash.pipelineaction.reload] Reloading pipeline {"pipeline.id"=>:main} [2018-03-14T17:05:01,758][INFO ][logstash.pipeline ] Pipeline has terminated {:pipeline_id=>"main", :thread=>"#<Thread:0x58f295b9 run>"} [2018-03-14T17:05:02,048][INFO ][logstash.pipeline ] Starting pipeline {:pipeline_id=>"main", "pipeline.workers"=>12, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>50} [2018-03-14T17:05:02,362][INFO ][logstash.inputs.beats ] Beats inputs: Starting input listener {:address=>"0.0.0.0:5044"} [2018-03-14T17:05:02,422][INFO ][logstash.pipeline ] Pipeline started succesfully {:pipeline_id=>"main", :thread=>"#<Thread:0x5506295b sleep>"} [2018-03-14T17:05:02,429][INFO ][org.logstash.beats.Server] Starting server on port: 5044 [2018-03-14T17:05:02,453][INFO ][logstash.agent ] Pipelines running {:count=>1, :pipelines=>["main"]} 为了能够使filebeat重新读取文件,需要停止filebeat,删除读取文件的保存点记录,并重启filebeat: cd filebeat-6.2.2-linux-x86_64 rm data/registry 添加filter后,输出的日志格式如下,发现不仅输出了日志原文,同时对日志进行解析切割,存放到相应的字段中。 { "host" => "yf-beidou-dmp00.yf01.baidu.com", "clientip" => "121.107.188.202", "verb" => "GET", "tags" => [ [0] "beats_input_codec_plain_applied" ], "message" => "121.107.188.202 - - [04/Jan/2015:05:27:57 +0000] \"GET /presentations/logstash-monitorama-2013/images/kibana-dashboard3.png HTTP/1.1\" 200 171717 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36\"", "beat" => { "name" => "yf-beidou-dmp00.yf01.baidu.com", "version" => "6.2.2", "hostname" => "yf-beidou-dmp00.yf01.baidu.com" }, "httpversion" => "1.1", "auth" => "-", "response" => "200", "bytes" => "171717", "ident" => "-", "@version" => "1", "request" => "/presentations/logstash-monitorama-2013/images/kibana-dashboard3.png", "offset" => 21927, "prospector" => { "type" => "log" }, "@timestamp" => 2018-03-14T09:06:47.927Z, "source" => "/home/work/zion_package/elastic/filebeat/logstash-tutorial.log", "timestamp" => "04/Jan/2015:05:27:57 +0000", "agent" => "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36\"", "referrer" => "\"-\"" } 使用Geoip过滤器组件增强数据处理 geoip也是filter组件的一种,用于从ip地址中解析出位置信息,并添加到输出日志中;geoip需要配置需要指定存放ip地址的字段,在本例中,我们使用通过gork解析后clientip字段;因为过滤器是按顺序过滤,所以需要确保geoip的过滤器在之前配置的gork过滤器之后,配置文件如下: input { beats { port => "5044" } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} } geoip { # 指定要进行ip解析的字段 source => "clientip" } } output { stdout { codec => rubydebug } } 停止filebeat,删除data/registry文件,重启filebeats后再次查看日志,发现新增了地理位置信息: { "host" => "yf-beidou-dmp00.yf01.baidu.com", "clientip" => "218.30.103.62", "verb" => "GET", "tags" => [ [0] "beats_input_codec_plain_applied" ], "message" => "218.30.103.62 - - [04/Jan/2015:05:28:43 +0000] \"GET /blog/geekery/xvfb-firefox.html HTTP/1.1\" 200 10975 \"-\" \"Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)\"", "beat" => { "name" => "yf-beidou-dmp00.yf01.baidu.com", "version" => "6.2.2", "hostname" => "yf-beidou-dmp00.yf01.baidu.com" }, "httpversion" => "1.1", "auth" => "-", "response" => "200", "bytes" => "10975", "ident" => "-", "@version" => "1", "request" => "/blog/geekery/xvfb-firefox.html", "geoip" => { "location" => { "lat" => 39.9289, "lon" => 116.3883 }, "latitude" => 39.9289, "continent_code" => "AS", "region_code" => "11", "country_code3" => "CN", "country_code2" => "CN", "longitude" => 116.3883, "city_name" => "Beijing", "country_name" => "China", "ip" => "218.30.103.62", "region_name" => "Beijing", "timezone" => "Asia/Shanghai" }, "offset" => 22310, "prospector" => { "type" => "log" }, "@timestamp" => 2018-03-14T09:22:31.299Z, "source" => "/home/work/zion_package/elastic/filebeat/logstash-tutorial.log", "timestamp" => "04/Jan/2015:05:28:43 +0000", "agent" => "\"Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)\"", "referrer" => "\"-\"" } 将logstash数据输出到elasticsearch 1)修改output,写入数据到elasticsearch:修改first-pipeline.conf文件,配置elasticsearch访问地址; input { beats { port => "5044" } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} } geoip { source => "clientip" } } output { elasticsearch { # 指定elasticsearch地址,指定多个地址,logstash会自动负载均衡 hosts => [ "ip1:port1", "ip2,port2" ] # 如果设置用户名和密码,则需要指定如下两个字段; # 用户必须具有对index的CRUD权限; user => "username" password => "password" } } 2)重新发送消息:停止filebeat,删除data/registry文件,重启filebeats;3)检索日志:执行如下语句,查询是否有日志写入elasticsearch,ip和端口是elasticsearch实例的ip和端口;因为first-pipeline.conf中未指定创建index的名称格式,默认为:logstash-yyyy.MM.dd(日期部分需要替换);如果未指定用户名/密码,则不需要-u参数; curl -XGET 'ip:port/logstash-2018.03.14/_search?pretty&q=response=200' -u username:password 检索结果类似如下json串: { "took" : 20, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 98, "max_score" : 2.3988724, "hits" : [ { "_index" : "logstash-2018.03.14", "_type" : "doc", "_id" : "t76VJGIBe9U4s2F_OL_W", "_score" : 2.3988724, "_source" : { "verb" : "GET", "@timestamp" : "2018-03-14T12:56:19.779Z", "response" : "200", "agent" : "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"", "source" : "/home/work/zion_package/elastic/filebeat/logstash-tutorial.log", "host" : "yf-beidou-dmp00.yf01.baidu.com", "auth" : "-", "clientip" : "83.149.9.216", "geoip" : { "country_code3" : "RU", "continent_code" : "EU", "ip" : "83.149.9.216", ... ... 4)在kibana上配置index-pattern,通过Discover检索日志:点击菜单:Management -> Index Pattern; 点击 Create Index Pattern,创建index pattern; 点击菜单:Discover,检索日志; 参考 官方视频:Getting Started with Logstash官方文档:Getting Started with Logstash

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

appWidget 简单入门学习笔记

1,让桌面能够添加你的appWidget 1,一个类,和2个xml //一个实现AppWidgetProvider的类 publicclassTomAppWidgetProviderextends AppWidgetProvider{} <!--放在res/xml文件夹中命名为tom_appwidget_info.xml--> <appwidget-providerxmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="86400000" android:initialLayout="@layout/tom_appwidget" android:configure="kg.tom.AppWidgetConfigure"></appwidget-provider> <!--android:initialLayout:初始化你的appWidget布局--> <!--放置在res/layout/tom_appwidget_provider.xml--> <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="294dp" android:layout_height="72dp" android:orientation="vertical"><TextView android:id="@+id/appwidget_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff000000"/><Button android:id="@+id/appwidget_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@android:string/ok"/> </LinearLayout> 在AndroidManifest.xml中声明你的appWidget <receiverandroid:name="TomAppWidgetProvider"> <intent-filter> <!--让系统能够设别到你的appWidgetProvider的动作--><actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <!--设置你的appWidget的布局--> <meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/tom_appwidget_info"/> </receiver> 长按你的Home 界面,你就会看到你的widget已经在列表当中 但是,现在点击是会出错的,这时候我们需要设置我们的AppWidgetConfigure 在activity中增加一个Intent-filter <intent-filter> <!--让系统能够设别到你的appWidgetProvider的动作--> <actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> publicclassAppWidgetConfigureextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置widgetId intmAppWidgetId=AppWidgetManager.INVALID_APPWIDGET_ID; //1,将setResult设置为取消,用于取消widgethostsetResult(RESULT_CANCELED); //2,从Intent中找到widget的id Intentintent=getIntent(); Bundleextras=intent.getExtras(); if(extras!=null){ mAppWidgetId=extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);} //3,如果获取不到appWidgetid我们就结束 if(mAppWidgetId==AppWidgetManager.INVALID_APPWIDGET_ID){ Log.d("app","获取失败退出!!!"); finish();} finalContextcontext=AppWidgetConfigure.this; //4,实例化你的appWidget AppWidgetManagerappWidgetManager=AppWidgetManager.getInstance(context); //5,更新widget IntentresultValue=newIntent();resultValue.putExtra(appWidgetManager.EXTRA_APPWIDGET_ID,mAppWidgetId); setResult(RESULT_OK,resultValue); finish();}} 2,然后写provider的代码 publicclassTomAppWidgetProviderextendsAppWidgetProvider{ @Override publicvoidonUpdate(Contextcontext,AppWidgetManagerappWidgetManager, int[]appWidgetIds){ //TODOAuto-generatedmethodstub super.onUpdate(context,appWidgetManager,appWidgetIds); finalintN=appWidgetIds.length; Log.d("app","onUpdate--->Ids==="+String.valueOf(N)); for(inti=0;i<N;i++){ intappWidgetId=appWidgetIds[i]; updateAppWidget(context,appWidgetManager,appWidgetId);}} staticvoidupdateAppWidget(Contextcontext,AppWidgetManagerappWidgetManager,intappWidgetId){ Log.d("app","update---->id"+appWidgetId); //1,widget中的的标题 CharSequencetext="这是我第一个widget"; //2,widget显示用布局,并设置text显示的值 RemoteViewsviews=newRemoteViews(context.getPackageName(),R.layout.tom_appwidget_provider);views.setTextViewText(R.id.appwidget_text,text); //3,通知widgetmanager更新appWidgetManager.updateAppWidget(appWidgetId,views);} @Override publicvoidonDeleted(Contextcontext,int[]appWidgetIds){ //TODOAuto-generatedmethodstubsuper.onDeleted(context,appWidgetIds); //删除的时候调用的方法 intappids=appWidgetIds.length; Log.d("app","onDelete--->"+appids);}} 然后就可以运行了: 顺便附上一张简单原理图:.. 2,小小的进阶为widget实现运行activity 只要在加上几行代码的appwidget 就能实现挑战到Activity的功能 1,新建一个HelloAppWidget的activity staticvoidupdateAppWidget(Contextcontext,AppWidgetManagerappWidgetManager,intappWidgetId){ Log.d("app","update---->id"+appWidgetId); //1,设置显示用标题 CharSequencetext="这是我第一个widget"; //1.1,增加跳转用activity相关intent Intentintent=newIntent(context,HelloAppWidget.class); PendingIntentpendingIntent=PendingIntent.getActivity(context,0,intent,0); //2,如果,没有在xml中声明RemoteViews布局,这里就必须要让其他布局基于RemoteViews RemoteViewsviews=newRemoteViews(context.getPackageName(),R.layout.tom_appwidget_provider);views.setTextViewText(R.id.appwidget_text,text); //2.1将需要跳转的intent绑定到appWidgetbutton中views.setOnClickPendingIntent(R.id.appwidget_button,pendingIntent); //3,通知widgetmanager更新appWidgetManager.updateAppWidget(appWidgetId,views);} 跳转到特定activity…ps:使用activity记得在AndroidManifest.xml中注册

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册