首页 文章 精选 留言 我的

精选列表

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

docker 入门应用

1、docker介绍Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 2、docker的使用docker主要是应用在集成环境的开发,例如后端php开发,可以集成php、nginx、mysql、redis等,docker可以选用contos X 、ubutun等操作系统,个人习惯于ubutun 14.0.4 系统较稳定。docker搭建的环境可以实现远程复制,对于开发者来说,是极其方便的,可以保证开发、测试、线上的环境一致。同时docker各环境之间是互不影响的,可以实现独立开发、运行。 3、docker的优劣势简单来说docker就是一个虚拟机,跟VMWare一样搭建虚拟环境 特性 docker 虚拟机启动速度 秒级 分钟级性能 接近原生 较弱内存代价 很小 较多硬盘使用 一般为MB 一般为GB运行密度 单机支持上千个容器 一般几十个隔离性 安全隔离 完全隔离迁移性 优秀 一般4、docker内部构造Docker 镜像 - Docker imagesDocker 仓库 - Docker registeriesDocker 容器 - Docker containers 1.Docker 镜像Docker 镜像是 Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新 的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。 2.Docker 仓库Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker 仓库是 Docker 的分发部分。 3.Docker 容器 Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。

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

Spring Boot入门

Spring官方网站本身使用Spring框架开发,随着功能以及业务逻辑的日益复杂,应用伴随着大量的XML配置文件以及复杂的Bean依赖关系。随着Spring 3.0的发布,Spring IO团队逐渐开始摆脱XML配置文件,并且在开发过程中大量使用“约定优先配置”(convention over configuration)的思想来摆脱Spring框架中各类繁复纷杂的配置(即时是Java Config)。 Spring Boot正是在这样的一个背景下被抽象出来的开发框架,它本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。 Hello World 传统基于Spring的Java Web应用,需要配置web.xml,applicationContext.xml,将应用打成war包放入应用服务器(Tomcat, Jetty等)中并运行。如果基于Spring Boot,这一切都将变得简单: 以Maven项目为例,首先引入Spring Boot的开发依赖: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> 编写一个类包含处理HTTP请求的方法以及一个main()函数: @Controller@EnableAutoConfigurationpublicclassSampleController{@RequestMapping("/")@ResponseBody Stringhome(){ return"HelloWorld!"; } publicstaticvoidmain(String[]args)throwsException{ SpringApplication.run(SampleController.class,args); } } 启动main函数后,在控制台中可以发现启动了一个Tomcat容器,一个基于Spring MVC的应用也同时启动起来,这时访问http://localhost:8080就可以看到Hello World!出现在浏览器中了。 Spring Boot初探 在Maven依赖中引入了spring-boot-starter-web,它包含了Spring Boot预定义的一些Web开发的常用依赖: spring-web,spring-webmvcSpring WebMvc框架 tomcat-embed-*内嵌Tomcat容器 jackson处理json数据 spring-*Spring框架 spring-boot-autoconfigureSpring Boot提供的自动配置功能 Java代码中没有任何配置,和传统的Spring应用相比,多了两个我们不认识的符号: @EnableAutoConfiguration SpringApplication 它们都是由Spring Boot框架提供。在SpringApplication.run()方法执行后,Spring Boot的autoconfigure发现这是一个Web应用(根据类路径上的依赖确定),于是在内嵌的Tomcat容器中启动了一个Spring的应用上下文,并且监听默认的tcp端口8080(默认约定)。同时在Spring Context中根据默认的约定配置了Spring WebMvc: Servlet容器默认的Context路径是/ DispatherServlet匹配的路径(servlet-mapping中的url-patterns)是/* @ComponentScan路径被默认设置为SampleController的同名package,也就是该package下的所有@Controller,@Service,@Component,@Repository都会被实例化后并加入Spring Context中。 没有一行配置代码、也没有web.xml。基于Spring Boot的应用在大多数情况下都不需要我们去显式地声明各类配置,而是将最常用的默认配置作为约定,在不声明的情况下也能适应大多数的开发场景。 实例:数据库访问 除了最基本的Web框架,另一种非常普遍的开发场景是访问数据库。在传统的Spring应用中,访问数据库我们需要配置: 类路径上添加数据库访问驱动 实例化DataSource对象,指定数据库url,username,password等信息 注入JdbcTemplate对象,如果使用Hibernate,Mybatis等框架,还需要进一步配置框架信息 在Spring Boot中,上述过程会被简化。首先在Maven项目依赖中定义: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-jdbc</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> spring-boot-starter-web-jdbc引入了spring-jdbc依赖,h2是一个内存关系型数据库。在引入了这些依赖并启动Spring Boot应用程序后,autoconfigure发现spring-jdbc位于类路径中,于是: 根据类路径上的JDBC驱动类型(这里是h2,预定义了derby,sqlite,mysql,oracle,sqlserver等等),创建一个DataSource连接池对象,本例中的h2是内存数据库,无需任何配置,如果是mysql,oracle等类型的数据库需要开发者配置相关信息。 在Spring Context中创建一个JdbcTemplate对象(使用DataSource初始化) 接下来开发者的工作就非常简单了,在业务逻辑中直接引入JdbcTemplate即可: @ServicepublicclassMyService{@Autowired JdbcTemplatejdbcTemplate; } 除了spring-jdbc,Spring Boot还能够支持JPA,以及各种NoSQL数据库——包括MongoDB,Redis,全文索引工具elasticsearch,solr等等。 配置 Spring Boot最大的特色是“约定优先配置”,大量的默认配置对开发者十分的友好。但是在实际的应用开发过程中,默认配置不可能满足所有场景,同时用户也需要配置一些必须的配置项——例如数据库连接信息。Spring Boot的配置系统能够让开发者快速的覆盖默认约定,同时支持Properties配置文件和YAML配置文件两种格式,默认情况下Spring Boot加载类路径上的application.properties或application.yml文件,例如: spring.datasource.url=jdbc:mysql://localhost/testspring.datasource.username=dbuser spring.datasource.password=dbpass spring.datasource.driver-class-name=com.mysql.jdbc.Driver YAML格式更加简洁: spring:datasource: url:jdbc:mysql://localhost/test username:dbuser password:dbpass driver-class:com.mysql.jdbc.Driver 一旦发现这些信息,Spring Boot就会根据它们创建DataSource对象。另一个常见的配置场景是Web应用服务器: #Serversettings(ServerProperties) server: port:8080 address:127.0.0.1 sessionTimeout:30 contextPath:/ #Tomcatspecifics tomcat: accessLogEnabled:false protocolHeader:x-forwarded-proto remoteIpHeader:x-forwarded-for basedir: backgroundProcessorDelay:30#secs 通过port和address可以修改服务器监听的地址和端口,sessionTimeout配置session过期时间(再也不用修改web.xml了,因为它根本不存在)。同时如果在生产环境中使用内嵌Tomcat,当然希望能够配置它的日志、线程池等信息,这些现在都可以通过Spring Boot的属性文件配置,而不再需要再对生产环境中的Tomcat实例进行单独的配置管理了。 @EnableAutoCongiguration 从Spring 3.0开始,为了替代繁琐的XML配置,引入了@Enable...注解对@Configuration类进行修饰以达到和XML配置相同的效果。想必不少开发者已经使用过类似注解: @EnableTransactionManagement开启Spring事务管理,相当于XMl中的<tx:*> @EnableWebMvc使用Spring MVC框架的一些默认配置 @EnableScheduling会初始化一个Scheduler用于执行定时任务和异步任务 Spring Boot提供的@EnableAutoCongiguration似乎功能更加强大,一旦加上,上述所有的配置似乎都被包含进来而无需开发者显式声明。它究竟是如何做到的呢,先看看它的定义: @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({EnableAutoConfigurationImportSelector.class, AutoConfigurationPackages.Registrar.class}) public@interfaceEnableAutoConfiguration{/** *Excludespecificauto-configurationclassessuchthattheywillneverbeapplied. */ Class<?>[]exclude()default{}; } EnableAutoConfigurationImportSelector使用的是spring-core模块中的SpringFactoriesLoader#loadFactoryNames()方法,它的作用是在类路径上扫描META-INF/spring.factories文件中定义的类: #Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer #AutoConfigure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration 实际上这就是Spring Boot会自动配置的一些对象,例如前面提到的Web框架由EmbeddedServletContainerAutoConfiguration,DispatcherServletAutoConfiguration,ServerPropertiesAutoConfiguration等配置完成,而DataSource的自动配置则是由DataSourceAutoConfiguration完成。现在我们以Mongo的配置MongoAutoConfiguration为例,来探索Spring Boot是如何完成这些配置的: @Configuration@ConditionalOnClass(Mongo.class)@EnableConfigurationProperties(MongoProperties.class) publicclassMongoAutoConfiguration{ @Autowired privateMongoPropertiesproperties; privateMongomongo; @PreDestroy publicvoidclose()throwsUnknownHostException{ if(this.mongo!=null){ this.mongo.close(); } } @Bean @ConditionalOnMissingBean publicMongomongo()throwsUnknownHostException{ this.mongo=this.properties.createMongoClient(); returnthis.mongo; } } 首先这是一个Spring的配置@Configuration,它定义了我们访问Mongo需要的@Bean,如果这个@Configuration被Spring Context扫描到,那么Context中自然也就有两个一个Mongo对象能够直接为开发者所用。 但是注意到其它几个Spring注解: @ConditionOnClass表明该@Configuration仅仅在一定条件下才会被加载,这里的条件是Mongo.class位于类路径上 @EnableConfigurationProperties将Spring Boot的配置文件(application.properties)中的spring.data.mongodb.*属性映射为MongoProperties并注入到MongoAutoConfiguration中。 @ConditionalOnMissingBean说明Spring Boot仅仅在当前上下文中不存在Mongo对象时,才会实例化一个Bean。这个逻辑也体现了Spring Boot的另外一个特性——自定义的Bean优先于框架的默认配置,我们如果显式的在业务代码中定义了一个Mongo对象,那么Spring Boot就不再创建。 接下来看一看MongoProperties: @ConfigurationProperties(prefix="spring.data.mongodb") publicclassMongoProperties{ privateStringhost; privateintport=DBPort.PORT; privateStringuri="mongodb://localhost/test"; privateStringdatabase; //...getters/settersomitted } 显然,它就是以spring.data.mongodb作为前缀的属性,然后通过名字直接映射为对象的属性,同时还包含了一些默认值。如果不配置,那么mongo.uri就是mongodb://localhost/test。 Production特性 从前面的例子可以看出,Spring Boot能够非常快速的做出一些原型应用,但是它同样可以被用于生产环境。为了添加生产环境特性支持,需要在Maven依赖中引入: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 加入actuator依赖后,应用启动后会创建一些基于Web的Endpoint: /autoconfig,用来查看Spring Boot的框架自动配置信息,哪些被自动配置,哪些没有,原因是什么。 /beans,显示应用上下文的Bean列表 /dump,显示线程dump信息 /health,应用健康状况检查 /metrics /shutdown, 默认没有打开 /trace 总结 Spring Boot是新一代Spring应用的开发框架,它能够快速的进行应用开发,让人忘记传统的繁琐配置,更加专注于业务逻辑。现在Spring官方文档中所有的Guide中的例子都是使用Spring Boot进行构建,这也是一个学习Spring, Spring Boot非常好的地方。

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

ActiveMQ入门实例

在开始之前需要去到网上去下载一个activeMQ,(官方网站下载:http://activemq.apache.org/),然后直接解压运行bin目录下面的activemq.bat文件,启动后登陆:http://localhost:8161/admin/,创建一个Queue,命名为FirstQueue,到这里准备工作就完成了,然后就可以开始了。 第一步,创建一个普通的java项目,然后导入java包(本人导入的是activemq-all-5.9.0.jar) 第二步、添加消息发送者 publicclassSender{ //连接工厂 privatestaticConnectionFactoryconnectionFactory; static{ connectionFactory=newActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); } publicstaticvoidmain(String[]args){ //连接 Connectionconnection=null; //会话 Sessionsession=null; //目的地,消息要发往的地方 Destinationdestination; //消息发送者 MessageProducerproducer=null; try{ //获取消息连接 connection=connectionFactory.createConnection(); //开启连接 connection.start(); //通过连接创建会话 session=connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE); //创建消息队列 destination=session.createQueue("FirstQueue"); //创建发送者 producer=session.createProducer(destination); //发送消息 send(session,producer); }catch(JMSExceptione){ e.printStackTrace(); }finally{ try{ session.commit(); connection.close(); }catch(JMSExceptione){ e.printStackTrace(); } } } publicstaticvoidsend(Sessionsession,MessageProducerproducer)throwsJMSException{ for(inti=0;i<10;i++){ //创建消息 TextMessagemsg=session.createTextMessage("消息"+i); //发送消息 producer.send(msg); System.out.println("发送消息:消息"+i); } } } 最后一步,添加消息的接受者 publicclassconsumer{ privatestaticConnectionFactoryconnectionFactory; static{ connectionFactory=newActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); } publicstaticvoidmain(String[]args){ Connectionconnection=null; Sessionsession=null; Destinationdestination; MessageConsumerconsumer=null; try{ connection=connectionFactory.createConnection(); connection.start(); session=connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE); destination=session.createQueue("FirstQueue"); consumer=session.createConsumer(destination); while(true){ TextMessagemsg=(TextMessage)consumer.receive(30000); if(msg!=null){ System.out.println("接受到的消息:"+msg.getText()); }else{ break; } } }catch(JMSExceptione){ e.printStackTrace(); }finally{ try{ consumer.close(); session.commit(); connection.close(); }catch(JMSExceptione){ e.printStackTrace(); } } } } 注意:接受消息还可以通过MessageListener接收 publicclassconsumerList{ privatestaticConnectionFactoryconnectionFactory; static{ connectionFactory=newActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://localhost:61616"); } publicstaticvoidmain(String[]args){ Connectionconnection=null; Sessionsession=null; Destinationdestination; MessageConsumerconsumer=null; try{ connection=connectionFactory.createConnection(); connection.start(); session=connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE); destination=session.createQueue("FirstQueue"); consumer=session.createConsumer(destination); consumer.setMessageListener(newMessageListener(){ @Override publicvoidonMessage(Messagemessage){ TextMessagemsg=(TextMessage)message; try{ System.out.println(msg.getText()); }catch(JMSExceptione){ e.printStackTrace(); } } }); }catch(JMSExceptione){ e.printStackTrace(); }finally{ try{ consumer.close(); session.commit(); connection.close(); }catch(JMSExceptione){ e.printStackTrace(); } } } }

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

Spring MVC入门

Spring mvc架构 1.1架构图 1.2.架构流程 1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3.处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。 4.DispatcherServlet通过HandlerAdapter处理器适配器调用处理器 5.执行处理器(Controller,也叫后端控制器)。 6.Controller执行完成返回ModelAndView 7.HandlerAdapter将controller执行结果ModelAndView返回 8.DispatcherServletDispatcherServlet将ModelAndView传给ViewReslover视图解析器 9.ViewReslover解析后返回具体View 10.DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。 11.DispatcherServlet响应用户 一.前端控制器(DispatcherServlet) <servlet> <servlet-name>JdbcSqlServlet</servlet-name> <servlet-class>com.imooc.page.servlet.JdbcSqlServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JdbcSqlServlet</servlet-name> <url-pattern>/jdbcSql/JdbcSqlServlet</url-pattern> </servlet-mapping> 二.Spring MVC配置文件(同Spring配置文件) <?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> 前端控制器(DispatcherServlet)带有默认的,映射器和适配器 三.处理器映射器(HandlerMapping) 用户发起的request请求,前端控制器(DispatcherServlet) 首先会请求 处理器映射器(HandlerMapping)来查找 后端控制器(Handler) 四.处理器适配器(HandlerAdapter) 处理器映射器将查找到的Handler返回给DispatcherServlet后,DispatcherServlet会调用适配器执行Handler,通过适配器去扩展对不同Handler的执行。 五.后端控制器的编写(Handler) Controller.java 六.配置视图解析器(ViewResolver) <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean>

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

Java入门—集合

应用场景: 无法预测存储数据的数量 同时存储具有一对一关系的数据 需要进行数据的增删 数据重复问题 集合概览 image.png List(列表) List是元素有序并且可以重复的集合,称为序列。 List可以精确控制每个元素的插入位置,或者删除某个为止的元素。 List两个主要实现类是ArrayList 和 LinkedList。 ArrayList 和 LinkedList 两者的数据存储方式是不同的: ArrayList :和数组相似,但是长度可以动态增长,在内存中的一片连续存储空间进行存储 LinkedList:本身是链表 Set 无序、不重复集合。 HashSet HashSet是Set的一个重要实现类,称为哈希集。 HashSet中元素无需并且不可重复。 HashSet中只允许一个null元素。 具有良好的存取和查找性能。 HashSet底层是hashMap。 遍历HashSet需要使用迭代器方法。 Iterator(迭代器) Iterator接口可以以统一的方式对各种集合元素进行遍历 hasNext()方法检测集合中是否还有下一个元素(返回ture或false) next() 方法返回集合中的下一个元素 import java.util.HashSet; import java.util.Set; import java.util.Iterator; public class TestIterator { public static void main(String[] args){ Set s = new HashSet(); s.add("allen"); s.add("ming"); s.add("hello"); Iterator it = s.iterator(); while (it.hasNext()){ System.out.println(it.next()); } } } Map Map中的数据是以键值对(key-value)形式存储的 key-value以Entry类型的对象实例存在 通过key可以快速查找value值 不能包含重复的建(key值必须唯一) HashMap 基于哈希表的Map接口实现 允许使用null值和null键值 HashMap中Entry对象时无序排列的 总结 ArrayList 底层由数组实现 元素有序且可以重复 可以动态增长,以满足应用程序的需求 元素值可以为null HashSet 元素无序并且不可以重复 只允许一个null元素 HashMap 键不能重复 允许使用null值和null键 HashMap中的Entry对象是无序排列的 Iterator(迭代器) Iterator接口以统一的方式对各种集合元素进行遍历 image.png

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

pipenv快速入门

学过Python的同学应该都了解pip这个工具,我们用pip绝大部分的第三方库都可以用pip来安装,用起来很方便。但是如果我们要把项目部署到服务器上面的话,就稍微有些麻烦了,因为还需要在服务器上用pip安装这些包,假如项目中用到很多包的话,一个个安装会很麻烦,而且没有通用性。Java上的maven、gradle,NodeJS的npm这些工具就不存在这个问题,它们有一个或多个的专门的依赖文件来管理这些包。pipenv就是这样一个类似的工具,可以帮助我们管理Python和第三方库的版本。 安装 安装pipenv很简单,用pip命令就可以安装。 pip install pipenv 将来需要更新pipenv的时候,运行: pip install --user --upgrade pipenv 首次运行 如果是第一次在项目中运行pipenv命令的话,会在项目中创建一个名为Pipfile的文件,文件内容类似下面这样。用过maven、gradle等工具的同学对此应该熟悉,相信不用我解释其中的含义。 [[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] requests-html = "*" [dev-packages] [requires] python_version = "3.7" 如果运行过install、update等命令的话,还会创建一个Pipfile.lock文件,类似npm中的lock文件。这两个文件就是pipenv用于管理第三方库的配置文件,如果同时使用版本控制软件的话,需要将它们也加入进去。 常用命令 安装 例如,我想在项目中安装requests这个包,运行: pipenv install requests 如果需要指定具体版本号,可以这样: pipenv install requests==2.13.0 如果是第一次运行pipenv的话,会先创建Pipfile文件,否则会修改Pipfile`文件。 该命令还有一个常用参数-d或--dev,用于安装仅供开发使用的包。 卸载 相应的还有命令来卸载第三方包,该命令还有两个参数--all和--all-dev用于卸载所有包和所有开发包。 pipenv uninstall requests 更新 查看所有需要更新的包: pipenv update --outdated 更新所有包: pipenv update 更新指定的包: pipenv update <包名> 从requirements.txt导入 如果项目中有requirements.txt文件,pipenv会在安装的时候自动导入。如果需要导入其他位置的requirements.txt,可以用下面的命令: pipenv install -r path/to/requirements.txt 指定Python版本 pipenv会创建虚拟Python环境,并在其中用pip安装所有包。如果要指定Python版本,可以用下面的命令,三种版本号都支持: pipenv --python 3 pipenv --python 3.6 pipenv --python 2.7.14 如果不指定版本号,pipenv会使用系统默认的Python版本。需要注意,这里指定的Python必须是系统已经安装的、可以在环境变量中搜索到的版本号,如果指定未安装的版本,会提示错误。 运行命令 用下面的命令可以启动一个在虚拟环境中的shell: pipenv shell 如果不想启动shell,而是直接在虚拟环境中执行命令,可以使用run: pipenv run python --version 高级用法 一开始我文档没看全,然后用pipenv的时候发现有一些问题,后来我发现官方文档还有一部分高级内容也很重要,所以再来补充一下。当然如果有需要的话还是得看原文。 导出requirements.txt 用下面的命令就可以将Pipfile和Pipfile.lock文件里面的包导出为requirements.txt文件。 pipenv lock -r 如果只想导出开发用的包,可以添加--dev参数: pipenv lock -r --dev 自动安装Python pipenv只能搜索系统中已经安装的Python版本,对于未安装的版本,会提示错误。但是如果你同时安装了pyenv的话,pipenv会自动发现pyenv,然后直接询问你是否要安装。这样一来,原来的工作流程是:用pyenv安装某个Python->用virtualenv或venv创建虚拟环境->用pip从requirements.txt中安装包->将来可能还要更新包。现在完全可以用pipenv一两条命令解决,真的是非常方便。 自动加载.env文件 .env文件可以设置一些环境变量,在程序开发的时候模拟环境变量。pipenv也可以自动加载.env文件。 $ cat .env HELLO=WORLD⏎ $ pipenv run python Loading .env environment variables… Python 2.7.13 (default, Jul 18 2017, 09:17:00) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import os >>> os.environ['HELLO'] 'WORLD' 环境变量支持 在Pipfile中也可以引用环境变量的值,格式为${MY_ENVAR}或$MY_ENVAR,在Windows系统中还支持%MY_ENVAR%。 [[source]] url = "https://${PYPI_USERNAME}:${PYPI_PASSWORD}@my_private_repo.example.com/simple" verify_ssl = true name = "pypi" [dev-packages] [packages] requests = {version="*", index="home"} maya = {version="*", index="pypi"} records = "*" 自定义虚拟环境路径 很多工具遵循Linux开发习惯,将东西全存在用户目录中,在Linux中可能没啥,但是在Windows下可能有人不喜欢把这些东西放在用户目录。当然pipenv也可以自定义,只需要设置或修改WORKON_HOME环境变量的值即可。 如果设置了PIPENV_VENV_IN_PROJECT环境变量,pipenv会把虚拟环境放在项目目录的.venv目录下。 配置pipenv pipenv还有一些配置,都是使用环境变量配置的,由于配置项比较多,这里就不介绍了,直接看官方文档好了。 从setup.py安装 pipenv也可以从setup.py安装: pipenv install -e . 那么为什么不全用pipenv来安装呢?官方文档这里为我们做出了解释:项目可以分为两种,程序和库,对于程序来说应该使用pipenv,而对于库来说则是在setup.py中安装。详细解释说实话我没太看懂,大意就是抽象依赖和具体依赖,还有一个责任分配的问题,原文在这里。

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

pyenv快速入门

在开发Python程序的时候,有时候可能需要在不同版本的Python上进行测试。pyenv就是这么一个管理多版本Python的工具。由于在Windows中我们可以同时安装多个版本的Python,所以这里是在Linux下介绍该工具。 安装 首先当然是安装pyenv了,最简单的办法就是利用官方Github仓库中的安装脚本了: $ curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 安装脚本有可能会提示你手动把几行命令添加到shell的配置文件中。 如果你用的是zsh的话,别忘了替换命令中的bash。将来如果要删除的话,需要在.zshrc文件中删除。如果你用oh-my-zsh的话,不需要在.zshrc中添加那几行(加了也没用),而是在.zshrc中启用pyenv插件。 将来要进行更新的话: $ pyenv update 要卸载pyenv的话更加简单,直接删除目录即可: $ rm -fr ~/.pyenv 别忘了把.bashrc中的这几行也一并删掉: export PATH="~/.pyenv/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" 工作原理 Linux环境变量 当执行命令的时候,系统会在环境变量中从左到右依次寻找匹配的命令并执行。环境变量中是一组以冒号:分隔的路径。 环境变量 垫片(Shims) pyenv的工作原理其实很简单,将它自己管理的Python目录插到环境变量的最前面,这样一来系统在搜索Python的时候第一个找到的就是pyenv管理的Python环境。这个插到最前面的路径就叫做垫片(shims),当然这是在英文语境下,在中文环境下我老觉得怪怪的,反正理解意思就好。 选择Python版本 当执行pyenv命令的时候,它会按照以下顺序来决定要使用的Python版本: 使用PYENV_VERSION环境变量(如果存在). 你可以使用pyenv shell 命令来在当前shell环境中设置该环境变量. 当前目录中应用程序指定的.python-version文件(如果存在). 你可以用pyenv local 命令来修改当前目录的.python-version文件. 自底向上搜索各层上级目录,找到的第一个.python-version, 直到到达文件系统根目录. 全局的$(pyenv root)/version文件. 可以使用 pyenv global 命令来修改. 如果全局版本文件不存在, pyenv假设你使用系统安装的Python. (换句话说就是未安装pyenv时环境变量中找到的Python.) 常用命令 完整命令请参考官方文档。 安装 列出所有可安装的Python版本: pyenv install -l|--list 安装某个Python: pyenv install <version> 卸载 卸载某个Python,-f参数指定是否强制卸载,如果强制卸载的话不会弹出提示,而且如果版本不存在的话也不会显示错误信息: pyenv uninstall [-f|--force] <version> versions 列出所有已安装的Python,当前使用的Python会用星号标出: $ pyenv versions 2.5.6 2.6.8 * 2.7.6 (set by /home/yyuu/.pyenv/version) 3.3.3 jython-2.5.3 pypy-2.2.1 global 通过写~/.pyenv/version文件的方式设置全局Python: $ pyenv global 2.7.6 local 通过在当前目录写.python-version文件的方式设置当前目录下的Python: pyenv local 2.7.6 当不再需要本地Python的时候,用--set来清除: $ pyenv local --unset shell 指定当前shell使用的Python: $ pyenv shell pypy-2.2.1 当不再需要的时候,用--set来清除: $ pyenv shell --unset 最后展示一下pyenv install -l的输出,可以看到,pyenv可以方便的安装大部分版本的Python,省略号表示中间有一大堆: yitian@ubuntu:~ $ pyenv install -l Available versions: 2.1.3 ... 2.7.15 ... 3.6.6 3.7.0 3.7-dev 3.8-dev activepython-2.7.14 activepython-3.5.4 activepython-3.6.0 anaconda-1.4.0 ... anaconda3-5.2.0 ironpython-dev ironpython-2.7.4 ironpython-2.7.5 ironpython-2.7.6.3 ironpython-2.7.7 jython-dev jython-2.5.0 jython-2.5-dev jython-2.5.1 jython-2.5.2 jython-2.5.3 jython-2.5.4-rc1 jython-2.7.0 jython-2.7.1 micropython-dev micropython-1.9.3 micropython-1.9.4 miniconda-latest miniconda-2.2.2 ... miniconda3-4.3.30 pypy-c-jit-latest pypy-c-nojit-latest pypy-dev pypy-stm-2.3 pypy-stm-2.5.1 pypy-1.5-src pypy-1.5 ... pypy3.5-6.0.0 pyston-0.5.1 pyston-0.6.0 pyston-0.6.1 stackless-dev stackless-2.7-dev stackless-2.7.2 ... stackless-3.5.4 常见问题 用pyenv安装Python的时候可能会出现各种各样问题,例如缺少zlib、缺少ctypes模块等等。对此pyenv也有专门一个页面解决。对于我的Ubuntu 18.04虚拟机来说,安装以下一坨软件可以解决问题: sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \ libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ xz-utils tk-dev libffi-dev liblzma-dev libedit-dev 其他系统请查看pyenv的页面,如果有其它问题请自行搜索Stack Overflow。

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

【原创】nginx入门

一、简介 Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。2018年08月28日发布1.15.3版本。 其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。 二、功能概述 1、HTTP基础功能: 处理静态文件,索引文件以及自动索引; 反向代理加速(无缓存),简单的负载均衡和容错; FastCGI,简单的负载均衡和容错; 模块化的结构。过滤器包括gzipping, byte ranges, chunked responses, 以及 SSI-filter 。在SSI过滤器中,到同一个 proxy 或者 FastCGI 的多个子请求并发处理; SSL 和 TLS SNI 支持; 2、IMAP/POP3 代理服务功能: 使用外部 HTTP 认证服务器重定向用户到 IMAP/POP3 后端; 使用外部 HTTP 认证服务器认证用户后连接重定向到内部的 SMTP 后端; 认证方法: POP3: POP3 USER/PASS, APOP, AUTH LOGIN PLAIN CRAM-MD5; IMAP: IMAP LOGIN; SMTP: AUTH LOGIN PLAIN CRAM-MD5; SSL 支持; 在 IMAP 和 POP3 模式下的 STARTTLS 和 STLS 支持; 3、支持的操作系统: FreeBSD 3.x, 4.x, 5.x, 6.x i386; FreeBSD 5.x, 6.x amd64; Linux 2.2, 2.4, 2.6 i386; Linux 2.6 amd64; Solaris 8 i386; Solaris 9 i386 and sun4u; Solaris 10 i386; MacOS X (10.4) PPC; 4、结构与扩展: 一个主进程和多个工作进程。工作进程是单线程的,且不需要特殊授权即可运行; kqueue (FreeBSD 4.1+), epoll (Linux 2.6+), rt signals (Linux 2.2.19+), /dev/poll (Solaris 7 11/99+), select, 以及 poll 支持; kqueue支持的不同功能包括 EV_CLEAR, EV_DISABLE (临时禁止事件), NOTE_LOWAT, EV_EOF, 有效数据的数目,错误代码; sendfile (FreeBSD 3.1+), sendfile (Linux 2.2+), sendfile64 (Linux 2.4.21+), 和 sendfilev (Solaris 8 7/01+) 支持; 输入过滤 (FreeBSD 4.1+) 以及 TCP_DEFER_ACCEPT (Linux 2.4+) 支持; 10,000 非活动的 HTTP keep-alive 连接仅需要 2.5M 内存。 最小化的数据拷贝操作; 5、其他HTTP功能: 基于IP 和名称的虚拟主机服务; Memcached 的 GET 接口; 支持 keep-alive 和管道连接; 灵活简单的配置; 重新配置和在线升级而无须中断客户的工作进程; 可定制的访问日志,日志写入缓存,以及快捷的日志回卷; 4xx-5xx 错误代码重定向; 基于 PCRE 的 rewrite 重写模块; 基于客户端 IP 地址和 HTTP 基本认证的访问控制; PUT, DELETE, 和 MKCOL 方法; 支持 FLV (Flash 视频); 带宽限制; 三、安装与启动 命令: yum install -y gcc gcc-c++ pcre pcre-devel zlib zlib-devel # 安装依赖 cd /usr/local/src wget http://nginx.org/download/nginx-1.15.3.tar.gz # 下载源代码 tar -xvzf nginx-1.15.3.tar.gz cd nginx-1.15.3 ./configure --prefix=/usr/local/nginxmake && make install #编译、安装 启动:/usr/local/nginx/sbin/nginx 测试配置文件:/usr/local/nginx/sbin/nginx –t 重启:/usr/local/nginx/sbin/nginx -s reopen 重新载入配置文件:/usr/local/nginx/sbin/nginx -s reload 快速关闭:/usr/local/nginx/sbin/nginx -s stop 优雅关闭:/usr/local/nginx/sbin/nginx -s quit 访问: http://192.168.141.130/ 四、配置示例 1)、反向代理 正向代理-转发代理(forward proxy): 反向代理(reverse proxy): 配置: server { listen 80; server_name fxdl.test.com; location /fxdl { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.141.130:8080/fxdl; } } 2)、动静分离 配置: server { listen 80; server_name djfl.test.com; location ^~ /static/ { alias /usr/local/nginx/djfl/; break; } location /djfl { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.141.130:8080/djfl; } } 3)、负载均衡 配置: upstream fzjh { server 192.168.141.130:8080; server 192.168.141.130:9090; } server { listen 80; server_name fzjh.test.com; location ^~ /static/ { alias /usr/local/nginx/fzjh/; break; } location /fzjh { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://fzjh/fzjh; } } 负载均衡算法: Nginx的upstream目前支持以下几种方式的分配 (1)、轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 (2)、weight 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 (3)、ip_hash 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 (4)、fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。 (5)、url_hash(第三方) 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 4)、FastCGI FastCGI是一个可伸缩地、高速地在HTTP服务器和动态脚本语言间通信的接口(FastCGI接口在Linux下是socket(可以是文件socket,也可以是ip socket)),主要优点是把动态语言和HTTP服务器分离开来。多数流行的HTTP服务器都支持FastCGI,包括Apache、Nginx和lightpd。 同时,FastCGI也被许多脚本语言所支持,比较流行的脚本语言之一为PHP。FastCGI接口方式采用C/S架构,可以将HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或多个脚本解析守护进程。当HTTP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程执行,然后将得到的结构返回给浏览器。这种方式可以让HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。 FastCGI的重要特点: 1、FastCGI是HTTP服务器和动态脚本语言间通信的接口或者工具。 2、FastCGI优点是把动态语言解析和HTTP服务器分离开来。 3、Nginx、Apache、Lighttpd以及多数动态语言都支持FastCGI。 4、FastCGI接口方式采用C/S架构,分为客户端(HTTP服务器)和服务端(动态语言解析服务器)。 5、PHP动态语言服务端可以启动多个FastCGI的守护进程。 6、HTTP服务器通过FastCGI客户端和动态语言FastCGI服务端通信。 Nginx FastCGI的运行原理 Nginx不支持对外部动态程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper,这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整个运作过程。 FastCGI的主要优点是把动态语言和HTTP服务器分离开来,是Nginx专一处理静态请求和向后转发动态请求,而PHP/PHP-FPM服务器专一解析PHP动态请求。 5)、rewrite 看下面两张图: 配置: server { listen 80; server_name old.test.com; rewrite ^(.*)$ http://new.test.com$1 permanent; #return 301 http://new.test.com$request_uri; } server { listen 80; server_name new.test.com; location / { root html; index index.html index.htm; } } 五、nginx和apache httpd服务器的对比 server Apache Nginx Proxy代理 非常好 非常好 Rewriter 好 非常好 Fcgi 不好 好 热部署 不支持 支持 系统压力比较 很大 很小 稳定性 好 非常好 安全性 好 一般 技术支持 非常好 很少 静态文件处理 一般 非常好 Vhosts虚拟主机 支持 不支持 反向代理 一般 非常好 Session sticky 支持 不支持 Apache和Nginx比较 功能对比 Nginx和Apache一样,都是HTTP服务器软件,在功能实现上都采用模块化结构设计,都支持通用的语言接口,如PHP、Perl、Python等,同时还支持正向和反向代理、虚拟主机、URL重写、压缩传输、SSL加密传输等。 在功能实现上,Apache的所有模块都支持动、静态编译,而Nginx模块都是静态编译的, 对FastCGI的支持,Apache对Fcgi的支持不好,而Nginx对Fcgi的支持非常好; 在处理连接方式上,Nginx支持epoll,而Apache却不支持; 在空间使用上,Nginx安装包仅仅只有几百K,和Nginx比起来Apache绝对是庞然大物。 Nginx相对apache的优点 轻量级,同样起web 服务,比apache 占用更少的内存及资源 静态处理,Nginx 静态处理性能比 Apache 高 3倍以上 抗并发,nginx 处理请求是异步非阻塞的,而apache则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能。在Apache+PHP(prefork)模式下,如果PHP处理慢或者前端压力很大的情况下,很容易出现Apache进程数飙升,从而拒绝服务的现象。 高度模块化的设计,编写模块相对简单 社区活跃,各种高性能模块出品迅速啊 apache相对nginx的优点 rewrite,比nginx 的rewrite 强大 模块超多,基本想到的都可以找到 少bug,nginx的bug相对较多 超稳定 Apache对PHP支持比较简单,Nginx需要配合其他后端用 选择Nginx的优势所在 作为Web服务器: Nginx处理静态文件、索引文件,自动索引的效率非常高。 作为代理服务器,Nginx可以实现无缓存的反向代理加速,提高网站运行速度。 作为负载均衡服务器,Nginx既可以在内部直接支持Rails和PHP,也可以支持HTTP代理服务器对外进行服务,同时还支持简单的容错和利用算法进行负载均衡。 在性能方面,Nginx是专门为性能优化而开发的,在实现上非常注重效率。它采用内核Poll模型(epoll and kqueue ),可以支持更多的并发连接,最大可以支持对50 000个并发连接数的响应,而且只占用很低的内存资源。 在稳定性方面,Nginx采取了分阶段资源分配技术,使得CPU与内存的占用率非常低。Nginx官方表示,Nginx保持10 000个没有活动的连接,而这些连接只占用2.5MB内存,因此,类似DOS这样的攻击对Nginx来说基本上是没有任何作用的。 在高可用性方面,Nginx支持热部署,启动速度特别迅速,因此可以在不间断服务的情况下,对软件版本或者配置进行升级,即使运行数月也无需重新启动,几乎可以做到7×24小时不间断地运行。 同时使用Nginx和Apache 由于Nginx和Apache各自的优势,现在很多人选择了让两者在服务器中共存。在服务器端让Nginx在前,Apache在后。由Nginx做负载均衡和反向代理,并且处理静态文件,讲动态请求(如PHP应用)交给Apache去处理。 作者: Candyメ奶糖 出处: http://www.cnblogs.com/Candies/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 博文来源广泛,如原作者认为我侵犯知识产权,请尽快给我发邮件 359031282@qq.com联系,我将以第一时间删除相关内容。

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

Jackson快速入门

Java生态圈中有很多处理JSON和XML格式化的类库,Jackson是其中比较著名的一个。虽然JDK自带了XML处理类库,但是相对来说比较低级,使用本文介绍的Jackson等高级类库处理起来会方便很多。 引入类库 由于Jackson相关类库按照功能分为几个相对独立的,所以需要同时引入多个类库,为了方便我将版本号单独提取出来设置,相关Gradle配置如下。 ext { jacksonVersion = '2.9.5' } dependencies { compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion // 引入XML功能 compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: jacksonVersion // 比JDK自带XML实现更高效的类库 compile group: 'com.fasterxml.woodstox', name: 'woodstox-core', version: '5.1.0' // Java 8 新功能 compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: jacksonVersion compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: jacksonVersion compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: jacksonVersion compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.22' } Maven配置请去mvnrepository搜索。 Jackson注解 Jackson类库包含了很多注解,可以让我们快速建立Java类与JSON之间的关系。详细文档可以参考Jackson-Annotations。下面介绍一下常用的。 属性命名 @JsonProperty注解指定一个属性用于JSON映射,默认情况下映射的JSON属性与注解的属性名称相同,不过可以使用该注解的value值修改JSON属性名,该注解还有一个index属性指定生成JSON属性的顺序,如果有必要的话。 属性包含 还有一些注解可以管理在映射JSON的时候包含或排除某些属性,下面介绍一下常用的几个。 @JsonIgnore注解用于排除某个属性,这样该属性就不会被Jackson序列化和反序列化。 @JsonIgnoreProperties注解是类注解。在序列化为JSON的时候,@JsonIgnoreProperties({"prop1", "prop2"})会忽略pro1和pro2两个属性。在从JSON反序列化为Java类的时候,@JsonIgnoreProperties(ignoreUnknown=true)会忽略所有没有Getter和Setter的属性。该注解在Java类和JSON不完全匹配的时候很有用。 @JsonIgnoreType也是类注解,会排除所有指定类型的属性。 序列化相关 @JsonPropertyOrder和@JsonProperty的index属性类似,指定属性序列化时的顺序。 @JsonRootName注解用于指定JSON根属性的名称。 处理JSON 简单映射 我们用Lombok设置一个简单的Java类。 @Data @AllArgsConstructor @NoArgsConstructor public class Friend { private String nickname; private int age; } 然后就可以处理JSON数据了。首先需要一个ObjectMapper对象,序列化和反序列化都需要它。 ObjectMapper mapper = new ObjectMapper(); Friend friend = new Friend("yitian", 25); // 写为字符串 String text = mapper.writeValueAsString(friend); // 写为文件 mapper.writeValue(new File("friend.json"), friend); // 写为字节流 byte[] bytes = mapper.writeValueAsBytes(friend); System.out.println(text); // 从字符串中读取 Friend newFriend = mapper.readValue(text, Friend.class); // 从字节流中读取 newFriend = mapper.readValue(bytes, Friend.class); // 从文件中读取 newFriend = mapper.readValue(new File("friend.json"), Friend.class); System.out.println(newFriend); 程序结果如下。可以看到生成的JSON属性和Java类中定义的一致。 {"nickname":"yitian","age":25} Friend(nickname=yitian, age=25) 集合的映射 除了使用Java类进行映射之外,我们还可以直接使用Map和List等Java集合组织JSON数据,在需要的时候可以使用readTree方法直接读取JSON中的某个属性值。需要注意的是从JSON转换为Map对象的时候,由于Java的类型擦除,所以类型需要我们手动用new TypeReference<T>给出。 ObjectMapper mapper = new ObjectMapper(); Map<String, Object> map = new HashMap<>(); map.put("age", 25); map.put("name", "yitian"); map.put("interests", new String[]{"pc games", "music"}); String text = mapper.writeValueAsString(map); System.out.println(text); Map<String, Object> map2 = mapper.readValue(text, new TypeReference<Map<String, Object>>() { }); System.out.println(map2); JsonNode root = mapper.readTree(text); String name = root.get("name").asText(); int age = root.get("age").asInt(); System.out.println("name:" + name + " age:" + age); 程序结果如下。 {"name":"yitian","interests":["pc games","music"],"age":25} {name=yitian, interests=[pc games, music], age=25} name:yitian age:25 Jackson配置 Jackson预定义了一些配置,我们通过启用和禁用某些属性可以修改Jackson运行的某些行为。详细文档参考JacksonFeatures。下面我简单翻译一下Jackson README上列出的一些属性。 // 美化输出 mapper.enable(SerializationFeature.INDENT_OUTPUT); // 允许序列化空的POJO类 // (否则会抛出异常) mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 把java.util.Date, Calendar输出为数字(时间戳) mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 在遇到未知属性的时候不抛出异常 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 强制JSON 空字符串("")转换为null对象值: mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); // 在JSON中允许C/C++ 样式的注释(非标准,默认禁用) mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); // 允许没有引号的字段名(非标准) mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); // 允许单引号(非标准) mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); // 强制转义非ASCII字符 mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); // 将内容包裹为一个JSON属性,属性名由@JsonRootName注解指定 mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true); 这里有三个方法,configure方法接受配置名和要设置的值,Jackson 2.5版本新加的enable和disable方法则直接启用和禁用相应属性,我推荐使用后面两个方法。 用注解管理映射 前面介绍了一些Jackson注解,下面来应用一下这些注解。首先来看看使用了注解的Java类。 @Data @NoArgsConstructor @AllArgsConstructor @JsonRootName("FriendDetail") @JsonIgnoreProperties({"uselessProp1", "uselessProp3"}) public class FriendDetail { @JsonProperty("NickName") private String name; @JsonProperty("Age") private int age; private String uselessProp1; @JsonIgnore private int uselessProp2; private String uselessProp3; } 然后看看代码。需要注意的是,由于设置了排除的属性,所以生成的JSON和Java类并不是完全对应关系,所以禁用DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES是必要的。 ObjectMapper mapper = new ObjectMapper(); //mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); FriendDetail fd = new FriendDetail("yitian", 25, "", 0, ""); String text = mapper.writeValueAsString(fd); System.out.println(text); FriendDetail fd2 = mapper.readValue(text, FriendDetail.class); System.out.println(fd2); 运行结果如下。可以看到生成JSON的时候忽略了我们制定的值,而且在转换为Java类的时候对应的属性为空。 {"NickName":"yitian","Age":25} FriendDetail(name=yitian, age=25, uselessProp1=null, uselessProp2=0, uselessProp3=null) 然后取消注释代码中的那行,也就是启用WRAP_ROOT_VALUE功能,再运行一下程序,运行结果如下。可以看到生成的JSON结果发生了变化,而且由于JSON结果变化,所以Java类转换失败(所有字段值全为空)。WRAP_ROOT_VALUE这个功能在有些时候比较有用,因为有些JSON文件需要这种结构。 {"FriendDetail":{"NickName":"yitian","Age":25}} FriendDetail(name=null, age=0, uselessProp1=null, uselessProp2=0, uselessProp3=null) Java8日期时间类支持 Java8增加了一套全新的日期时间类,Jackson对此也有支持。这些支持是以Jackson模块形式提供的,所以首先就是注册这些模块。 ObjectMapper mapper = new ObjectMapper() .registerModule(new JavaTimeModule()) .registerModule(new ParameterNamesModule()) .registerModule(new Jdk8Module()); 导入类库之后,Jackson也可以自动搜索所有模块,不需要我们手动注册。 mapper.findAndRegisterModules(); 我们新建一个带有LocalDate字段的Java类。 @Data @NoArgsConstructor @AllArgsConstructor @JsonRootName("Person") public class Person { @JsonProperty("Name") private String name; @JsonProperty("NickName") private String nickname; @JsonProperty("Age") private int age; @JsonProperty("IdentityCode") private String identityCode; @JsonProperty @JsonFormat(pattern = "yyyy-MM-DD") private LocalDate birthday; } 然后来看看代码。 static void java8DateTime() throws IOException { Person p1 = new Person("yitian", "易天", 25, "10000", LocalDate.of(1994, 1, 1)); ObjectMapper mapper = new ObjectMapper() .registerModule(new JavaTimeModule()); //mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); String text = mapper.writeValueAsString(p1); System.out.println(text); Person p2 = mapper.readValue(text, Person.class); System.out.println(p2); } 运行结果如下。可以看到,生成的JSON日期变成了[1994,1,1]这样的时间戳形式,一般情况下不符合我们的要求。 {"birthday":[1994,1,1],"Name":"yitian","NickName":"易天","Age":25,"IdentityCode":"10000"} Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01) 取消注释那行代码,程序运行结果如下。这样一来就变成了我们一般使用的形式了。如果有格式需要的话,可以使用@JsonFormat(pattern = "yyyy-MM-DD")注解格式化日期显示。 {"birthday":"1994-01-01","Name":"yitian","NickName":"易天","Age":25,"IdentityCode":"10000"} Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01) 处理XML Jackson是一个处理JSON的类库,不过它也通过jackson-dataformat-xml包提供了处理XML的功能。Jackson建议我们在处理XML的时候使用woodstox-core包,它是一个XML的实现,比JDK自带XML实现更加高效,也更加安全。 这里有个注意事项,如果你正在使用Java 9以上的JDK,可能会出现java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException异常,这是因为Java 9实现了JDK的模块化,将原本和JDK打包在一起的JAXB实现分隔出来。所以这时候需要我们手动添加JAXB的实现。在Gradle中添加下面的代码即可。 compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' 注解 Jackson XML除了使用Jackson JSON和JDK JAXB的一些注解之外,自己也定义了一些注解。下面简单介绍一下几个常用注解。 @JacksonXmlProperty注解有三个属性,namespace和localname属性用于指定XML命名空间的名称,isAttribute指定该属性作为XML的属性(<a b="xxx"></a>)还是作为子标签(<a><b></b></a>). @JacksonXmlRootElement注解有两个属性,namespace和localname属性用于指定XML根元素命名空间的名称。 @JacksonXmlText注解将属性直接作为未被标签包裹的普通文本表现。 @JacksonXmlCData将属性包裹在CDATA标签中。 XML映射 新建如下一个Java类。 @Data @NoArgsConstructor @AllArgsConstructor @JsonRootName("Person") public class Person { @JsonProperty("Name") private String name; @JsonProperty("NickName") //@JacksonXmlText private String nickname; @JsonProperty("Age") private int age; @JsonProperty("IdentityCode") @JacksonXmlCData private String identityCode; @JsonProperty("Birthday") //@JacksonXmlProperty(isAttribute = true) @JsonFormat(pattern = "yyyy/MM/DD") private LocalDate birthday; } 下面是代码示例,基本上和JSON的API非常相似,XmlMapper实际上就是ObjectMapper的子类。 Person p1 = new Person("yitian", "易天", 25, "10000", LocalDate.of(1994, 1, 1)); XmlMapper mapper = new XmlMapper(); mapper.findAndRegisterModules(); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.enable(SerializationFeature.INDENT_OUTPUT); String text = mapper.writeValueAsString(p1); System.out.println(text); Person p2 = mapper.readValue(text, Person.class); System.out.println(p2); 运行结果如下。 <Person> <Name>yitian</Name> <NickName>易天</NickName> <Age>25</Age> <IdentityCode><![CDATA[10000]]></IdentityCode> <Birthday>1994/01/01</Birthday> </Person> Person(name=yitian, nickname=易天, age=25, identityCode=10000, birthday=1994-01-01) 如果取消那两行注释,那么运行结果如下。可以看到Jackson XML注解对生成的XML的控制效果。 <Person birthday="1994/01/01"> <Name>yitian</Name>易天 <Age>25</Age> <IdentityCode><![CDATA[10000]]></IdentityCode> </Person> Person(name=yitian, nickname=null, age=25, identityCode=10000, birthday=1994-01-01) Spring Boot集成 自动配置 Spring Boot对Jackson的支持非常完善,只要我们引入相应类库,Spring Boot就可以自动配置开箱即用的Bean。Spring自动配置的ObjectMapper(或者XmlMapper)作了如下配置,基本上可以适应大部分情况。 禁用了MapperFeature.DEFAULT_VIEW_INCLUSION 禁用了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 禁用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 如果需要修改自动配置的ObjectMapper属性也非常简单,Spring Boot提供了一组环境变量,直接在application.properties文件中修改即可。 Jackson枚举 Spring环境变量 com.fasterxml.jackson.databind.DeserializationFeature spring.jackson.deserialization.<feature_name>=true|false com.fasterxml.jackson.core.JsonGenerator.Feature spring.jackson.generator.<feature_name>=true|false com.fasterxml.jackson.databind.MapperFeature spring.jackson.mapper.<feature_name>=true|false com.fasterxml.jackson.core.JsonParser.Feature spring.jackson.parser.<feature_name>=true|false com.fasterxml.jackson.databind.SerializationFeature spring.jackson.serialization.<feature_name>=true|false com.fasterxml.jackson.annotation.JsonInclude.Include spring.jackson.default-property-inclusion=always|non_null|non_absent|non_default|non_empty 由于Spring会同时配置相应的HttpMessageConverters,所以我们其实要做的很简单,用Jackson注解标注好要映射的Java类,然后直接让控制器返回对象即可!下面是一个Java类。 @JsonRootName("person") public class Person { @JsonProperty private String name; @JsonProperty private int id; @JsonFormat(pattern = "yyyy-MM-DD") private LocalDate birthday; public Person(String name, int id, LocalDate birthday) { this.name = name; this.id = id; this.birthday = birthday; } } 然后是控制器代码。在整个过程中我们只需要引入Jackson类库,然后编写业务代码就好了。关于如何配置Jackson类库,我们完全不需要管,这就是Spring Boot的方便之处。 @Controller public class MainController { private Person person = new Person("yitian", 10000, LocalDate.of(1994, 1, 1)); @RequestMapping("/") public String index() { return "index"; } @RequestMapping(value = "/json", produces = "application/json") @ResponseBody public Person json() { return person; } } 进入localhost:8080/xml就可以看到对应结果了。 结果 手动配置 Spring Boot自动配置非常方便,但不是万能的。在必要的时候,我们需要手动配置Bean来替代自动配置的Bean。 @Configuration public class JacksonConfig { @Bean @Primary @Qualifier("xml") public XmlMapper xmlMapper(Jackson2ObjectMapperBuilder builder) { XmlMapper mapper = builder.createXmlMapper(true) .build(); mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } @Bean @Qualifier("json") public ObjectMapper jsonMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper mapper = builder.createXmlMapper(false) .build(); mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } } 然后在需要的地方进行依赖注入。需要注意为了区分ObjectMapper和XmlMapper,需要使用@Qualifier注解进行标记。 @Controller public class MainController { private ObjectMapper jsonMapper; private XmlMapper xmlMapper; private Person person = new Person("yitian", 10000, LocalDate.of(1994, 1, 1)); public MainController(@Autowired @Qualifier("json") ObjectMapper jsonMapper, @Autowired @Qualifier("xml") XmlMapper xmlMapper) { this.jsonMapper = jsonMapper; this.xmlMapper = xmlMapper; } 以上就是Jackson类库的一些介绍,希望对大家有所帮助。项目代码在我的Github,感兴趣的同学可以看看。

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

Jupyter Notebooks 入门

自从有了纸莎草纸以来,出版人们一直在努力以吸引读者的方式来格式化数据。尤其是在数学、科学、和编程领域,设计良好的图表、插图和方程式可以成为帮助人们理解技术信息的关键。 Jupyter Notebook 通过重新构想我们如何制作教学文本来解决这个问题。Jupyter (我在 2017 年 10 月在 All Things Open 上首次了解到)是一款开源应用程序,它使用户能够创建包含实时代码、方程式、可视化和文本的交互式共享笔记本。 Jupyter 从 IPython 项目发展而来,它是个具有交互式 shell 和基于浏览器的笔记本,支持代码、文本和数学表达式。Jupyter 支持超过 40 种编程语言,包括 Python、R 和 Julia,其代码可以导出为 HTML、LaTeX、PDF、图像和视频,或者作为 IPyhton 笔记本与其他用户共享。 一个有趣的事实是:“Jupyter” 是 “Julia、Python 和 R” 的缩写。 根据 Jupyter 项目网站介绍,它的一些用途包括“数据清理和转换,数值模拟,统计建模,数据可视化,机器学习等等”。科学机构正在使用 Jupyter Notebooks 来解释研究结果。代码可以来自实际数据,可以调整和重新调整以可视化成不同的结果和情景。通过这种方式,Jupyter Notebooks 变成了生动的文本和报告。 安装并开始 Jupyter Jupyter 软件是开源的,其授权于修改过的 BSD 许可证,它可以安装在 Linux、MacOS 或 Windows 上。有很多种方法可以安装 Jupyter;我在 Linux 和 MacOS 上试过 PIP 和 Anaconda 安装方式。PIP 安装要求你的计算机上已经安装了 Python;Jupyter 推荐 Python 3。 由于 Python 3 已经安装在我的电脑上,我通过在终端(在 Linux 或 Mac 上)运行以下命令来安装 Jupyter: $ python3 -m pip install --upgrade pip $ python3 -m pip install jupyter 在终端提示符输入以下命令立即启动应用程序: $ jupyter notebook 很快,我的浏览器打开并显示了我在 http://localhost:8888 的 Jupyter Notebook 服务器。(支持的浏览器有 Google Chrome、Firefox 和 Safari) 在右上角有一个标有 “New” 的下拉菜单,它使我能够根据自己的指示和代码快速创建新的笔记本。请注意,我的新笔记本默认为 Python 3,这是我目前的环境。 一个带有一些默认值的新笔记本,它可以被改变(包括笔记本的名字),已打开。 笔记本有两种不同的模式:“命令模式”和“编辑模式”。命令模式允许你添加或删除单元格。你可以通过按下 Escape 键进入命令模式,按 Enter 键或单击单元格进入编辑模式。 单元格周围的绿色高亮显示你处于编辑模式,蓝色高亮显示你处于命令模式。以下笔记本处于命令模式并准备好执行单元中的 Python 代码。注意,我已将笔记本的名称更改为 “First Notebook”。 使用 Jupyter Jupyter Notebooks 的强大之处在于除了能够输入代码之外,你还可以用 Markdown 添加叙述性和解释性文本。我想添加一个标题,所以我在代码上面添加了一个单元格,并以 Markdown 输入了一个标题。当我按下 Ctrl+Enter 时,我的标题转换为 HTML。(LCTT 译注:或者可以按下 Run 按钮。) 我可以通过在命令前追加 ! 来添加 Bash 命令或脚本的输出。 我也可以利用 IPython 的 line magic 和 cell magic 命令。你可以通过在代码单元内附加 % 或 %% 符号来列出魔术命令。例如,%lsmagic 将输出所有可用于 Jupyter notebooks 的魔法命令。 这些魔术命令的例子包括 %pwd——它输出当前工作目录(例如 /Users/YourName)和 %ls——它列出当前工作目录中的所有文件和子目录。另一个神奇命令显示从笔记本中的 matplotlib 生成的图表。%%html 将该单元格中的任何内容呈现为 HTML,这对嵌入视频和链接很有用,还有 JavaScript 和 Bash 的单元魔术命令。 如果你需要更多关于使用 Jupyter Notebooks 和它的特性的信息,它的帮助部分是非常完整的。 人们用许多有趣的方式使用 Jupyter Notebooks;你可以在这个展示栏目里找到一些很好的例子。你如何使用 Jupyter 笔记本?请在下面的评论中分享你的想法。 原文发布时间为:2018-05-21 本文来自云栖社区合作伙伴“Linux中国开源社区”,了解相关信息可以关注“Linux中国开源社区”。

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

Yaml入门笔记

什么是yamlYAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递归缩写,早先YAML的意思其实是:"Yet Another Markup Language"(另外一种置标语言),但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名,YAML的官方定义很简单,即一种人性化的数据格式定义语言,其主要功能用途类似于XML或JSON,YAML使用空白字符和分行来分隔数据,且巧妙避开各种封闭符号,如:引号、括号等,以避免这些符号在复杂层次结构中变得难以辨认。YAML的语法与高阶语言类似,可以很简单地表述序列(java中的list)、杂凑表(java中的map)、标量(java中的基本类型等)数据结构,它重点强调可阅读性。 本文内容 image.png YAML的设计目的 容易人类阅读 适合表示程序语言的数据结构 可用于不同程序间交换数据 支持泛型工具 支持串行处理? 丰富的表达能力和可扩展性 易于使用 xml和yaml的代码块: xml代码块: <site> <name>github</name> <url>https://github.com</url> </site> <site> <name>简书</name> <url>https://www.jianshu.com</url> </site> yaml代码块: --- site: name: github url: https://github.com --- site: name: 简书 url: https://www.jianshu.com --- #或者 --- site:{name:github,url:https://github.com} --- site:{name:简书,url:https://jianshu.com} 主要标记 注释-comment 举例: # Comment Example # Profile Of Mary Mary: - name: Mary - age : 19 # age property 文档(document) # documents example --- site: name: github url: https://github.com --- site: name: 简书 url: https://www.jianshu.com 数据结构 YAML的设计者认为在配置文件中所要表达的数据内容有三种类型:标量(Scalar,如字符串和整数等)、序列(Sequence,如数组)和Mapping(类似hash的key/value pair)。 sequence.png mapping.png 例子:我们用YAML来描述一本书: # 《单元测试之道-c#版》描述 --- # begin of document 书名 : '单元测试之道-C#版' 出版社: '电子工业出版社' 原作者: ['Andrew Hunt', 'David Thomas'] 译者 : - 陈伟柱 - 陶文 前二章节 : - 第一章: 序言 - 第二章: 你的首个单元测试计划 #end document 注意:YAML推荐使用空格作为缩进,避免了在不同编辑器中对tab的表示形式不同而可能产生误解。 YAML 与 XML 优势: YAML的可读性好 YAML和脚本语言的交互性好 YAML使用实现语言的数据类型 YAML有一个一致的信息模型 YAML易于实现 上面5条是XML不足的地方,同时,YAML也具有XML的下列优点: YAML可以基于流来处理 YAML表达能力强,扩展性好 YAML类似于XML的数据描述语言,语法比XML简单很多,YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务。 YAML 与 JSON JSON的语法其实是YAML的子集,大部分的JSON文件都可以被YAML的剖析器剖析。虽然大部分的数据分层形式也可以使用类似JSON的格式,不过YAML并不建议这样使用,除非这样编写能让文件可读性增加,更重要的是,YAML的许多扩展在JSON是找不到的,如:进阶资料形态、关系锚点、字串不需要引号、映射资料形态会储存键值的顺序等。 YAML用途 脚本语言 由于实现简单,解析成本很低,YAML特别适合在脚本语言中使用。列一下现有的语言实现:Ruby,Java,Perl,Python,PHP,OCaml,JavaScript,除了Java,其他都是脚本语言。 序列化 YAML比较适合做序列化。因为它是宿主语言数据类型直转的。 配置文件 YAML做配置文件也不错。写YAML要比写XML快得多(无需关注标签或引号),并且比ini文档功能更强。 调试 由于其很强的阅读性,用于调试过程中dump出信息供分析也是一种比较方便的做法。 YAML缺陷与不足 YAML没有自己的数据类型的定义,而是使用实现语言的数据类型。一个YAML文件,在不同语言中解析后得到的数据类型可能会不同,由于其兼容性问题,不同语言间的数据流转不建议使用YAML。 YAML语法与范例 YAML使用可打印的Unicode字符,可使用UTF-8或UTF-16 使用空白字符(不能使用<kbd>Tab</kbd>)分层,同层元素左侧对齐 单行注解由井字号(<kbd> #</kbd> )开始,可以出现在行中任何位置 每个清单成员以单行表示,并用短杠+空白(<kbd>- </kbd>)起始 每个杂凑表的成员用冒号+空白(<kbd>: </kbd>)分开键和值 杂凑表的键值可以用问号 (<kbd>?</kbd>)起始,表示多个词汇组成的键值 字串一般不使用引号,但必要的时候可以用引号框住 使用双引号表示字串时,可用倒斜线(<kbd></kbd>)进行特殊字符转义 区块的字串用缩排和修饰词(非必要)来和其他资料分隔,有新行保留(使用符号<kbd>|</kbd>)或新行折叠(使用符号<kbd>></kbd>)两种方式 在单一档案中,可用连续三个连字号(<kbd>---</kbd>)区分多个档案 可选择性的连续三个点号(<kbd>...</kbd>)用来表示档案结尾(在流式传输时非常有用,不需要关闭流即可知道到达结尾处) 重复的内容可使从参考标记星号 (<kbd>*</kbd>)复制到锚点标记(<kbd>&</kbd>) 指定格式可以使用两个惊叹号 ( !! ),后面接上名称 receipt: Oz-Ware Purchase Invoice date: 2007-08-06 customer: given: Dorothy family: Gale items: - part_no: A4786 descrip: Water Bucket (Filled) price: 1.47 quantity: 4 - part_no: E1628 descrip: High Heeled "Ruby" Slippers price: 100.27 quantity: 1 bill-to: &id001 street: | 123 Tornado Alley Suite 16 city: East Westville state: KS ship-to: *id001 specialDelivery: > Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain. ... 这个文件的的顶层由七个键值组成:其中一个键值"items",是个两个元素构成的清单,清单中的两个元素同时也是包含了四个键值的杂凑表。 文件中重复的部分处理方式:使用锚点(&)和参考(*)标签将"bill-to"杂凑表的内容复制到"ship-to"杂凑表。也可以在文件中加入选择性的空行,以增加可读性。 YAML的JAVA实现 YAML已经有了多种语言不少实现,详见YAML官网。 一般YAML文件扩展名为.yaml,比如John.yaml,其内容为: name: John Smith age: 37 children: - name: Jimmy Smith age: 15 - name: Jenny Smith age: 12 spouse: name: Jane Smith age: 25 由于yaml的超强可读性,我们了解到:John今年37岁,两个孩子Jimmy 和Jenny活泼可爱,妻子Jane年轻美貌,而且年仅25岁,一个幸福的四口之家。 对John.yaml进行java描述,抽象出一个Person类,如下: public class Person { private String name; private int age; private Person sponse; private Person[] children; // setXXX, getXXX方法略. } 现在我们使用java装配一个Jone: Person john = new Person(); john.setAge(37); john.setName("John Smith"); Person sponse = new Person(); sponse.setName("Jane Smith"); sponse.setAge(25); john.setSponse(sponse); Person[] children = {new Person(), new Person()}; children[0].setName("Jimmy Smith"); children[0].setAge(15); children[1].setName("Jenny Smith"); children[1].setAge(12); john.setChildren(children); 使用SnakeYAML实现 项目主页:http://code.google.com/p/snakeyaml/ 使用手册:https://code.google.com/p/snakeyaml/wiki/Documentation SnakeYAML是一个标准的YAML的java实现,它有以下特点: 完全支持YAML 1.1,可以跑通规范中的所有示例 支持YAML的所有类型 支持UTF-8/UTF-16的输入和输出 提供了本地java对象的序列化和反序列化的高层API 提供相对合理的错误提示信息 使用SnakeYAML将john dump出来,如果有引用相同对象,则dump出到yaml文件会自动使用<kbd>&</kbd>和<kbd></kbd>进行锚点和引用*: DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(options); //Yaml yaml = new Yaml(); String dump = yaml.dump(john); System.out.println(dump); 内容如下: !!Person age: 37 children: - age: 15 children: null name: Jimmy Smith sponse: null - age: 12 children: null name: Jenny Smith sponse: null name: John Smith sponse: age: 25 children: null name: Jane Smith sponse: null 现在用SnakeYAML把yaml load进来,如果yaml文件中使用了<kbd>&</kbd>和<kbd></kbd>,则会自动对load出来的对象赋相同的值*: Yaml yaml = new Yaml(); Object load = yaml.load(new FileInputStream(new File("jhon.yaml"))); System.out.println(load.getClass()); System.out.println(yaml.dump(load)); 或 Yaml yaml = new Yaml(options); Person person = yaml.loadAs(inputStream, Person.class); System.out.println(person.getSponse().getChildren().length); 如果一个yaml文件中有多个文档,由<kbd>---</kbd>分割,解析如下: Yaml yaml = new Yaml(); int counter = 0; for (Object data : yaml.loadAll(input)) { System.out.println(data); counter++; } 保存一个Map对象: Map<String, Object> data = new HashMap<String, Object>(); data.put("name", "Silenthand Olleander"); data.put("race", "Human"); data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" }); Yaml yaml = new Yaml(); String output = yaml.dump(data); System.out.println(output); // or StringWriter writer = new StringWriter(); yaml.dump(data, writer); System.out.println(writer.toString()); 将多个文档dump出到同一个yaml文件中去: List<Integer> docs = new LinkedList<Integer>(); for (int i = 1; i < 4; i++) { docs.add(i); } DumperOptions options = new DumperOptions(); //options.setCanonical(true); options.explicitStart(true); Yaml yaml = new Yaml(options); System.out.println(yaml.dump(docs)); System.out.println(yaml.dumpAll(docs.iterator())); --- [1, 2, 3] --- 1 --- 2 --- 3 YAML JAVA !null null !!bool Boolean !!int Integer, Long, BigInteger !!float Double !!binary String !!timestamp java.util.Date, java.sql.Date, java.sql.Timestamp !!omap, !!pairs List of Object[] !!set Set !!str String !!seq List !!map Map YAML与java类型对照表: YAML JAVA !null null !!bool Boolean !!int Integer, Long, BigInteger !!float Double !!binary String !!timestamp java.util.Date, java.sql.Date, java.sql.Timestamp !!omap, !!pairs List of Object[] !!set Set !!str String !!seq List !!map Map 集合的默认实现是: List: ArrayList Map: LinkedHashMap 使用JYaml实现 JYaml(最新版本是2007年的,可以考虑放弃了),使用JYaml把Jone “Dump” 出来: File dumpfile = new File("John_dump.yaml"); Yaml.dump(john, dumpfile); 下面我们看看John_dump.yaml是什么样子: --- !yaml.test.internal.Person age: 37 children: !yaml.test.internal.Person[] - !yaml.test.internal.Person age: 15 name: Jimmy Smith - !yaml.test.internal.Person age: 12 name: Jenny Smith name: John Smith sponse: !yaml.test.internal.Person age: 25 name: Jane Smith 其中!yaml.test.internal.Person是一些类型的信息。load的时候需要用。 现在用JYaml把Jone_dump.yaml load进来: Person john2 = (Person) Yaml.loadType(dumpfile, Person.class); 还可以用下面的代码dump出没有类型信息的John.yaml: Yaml.dump(john,dumpfile, true); 我们再来看看JYaml对流处理的支持,为简便起见,我们只是把同一个john写10次: YamlEncoder enc = new YamlEncoder(new FileOutputStream(dumpfile)); for(int i=0; i<10; i++){ john.setAge(37+i); enc.writeObject(john); enc.flush(); } enc.close(); 下面再把这十个对象一个一个读出来(注意while循环退出的方式): YamlDecoder dec = new YamlDecoder(new FileInputStream(dumpfile)); int age = 37; while(true){ try{ john = (Person) dec.readObject(); assertEquals(age, john.getAge()); age++; }catch(EOFException eofe){ break; } } 参考文档: YAML Specification YAML 数据类型说明 http://blog.csdn.net/conquer0715/article/details/42108061 http://www.cnblogs.com/chwkai/archive/2009/03/01/249924.html

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

maven入门(一)

现在基本上很多项目开始使用maven进行构建项目,已经不是直接在lib文件夹下统一放置jar包,所以还是有必要学习掌握下maven的。 针对maven。这篇文章主要介绍一下几点,大家如果都明白了,就可以参照这个思维导图,再复习下,毕竟知识长时间不用,会忘记的。 一、 maven 是什么 Maven的Apache公司开源项目,是项目构建工具,也用来依赖管理。 二、maven的好处 1、由于maven构建的项目是没有jar包的,所以项目的大小上,肯定是maven的项目比较小。 2、jar包统一交给maven管理。 3、maven同样可以进行项目构建。 maven主要就是 项目构建和依赖(jar包)管理 三、maven安装 maven程序安装前提:maven程序java开发,它的运行依赖jdk。 1、 首先去Maven官网,下载Maven的包,地址为http://maven.apache.org/download.cgi 2、下载完解压,然后配置一下环境变量,和JDK的环境变量配置类似(如图) 3、查询maven版本信息 4、 配置本地仓库 找到 解压目录下的 config/setting.xml,我的就是 E:\app\apache-maven-3.5.3\conf\setting.xml 主要修改2个地方 4.1 修改本地仓库路径 4.2 修改成阿里云镜像 <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> 4.4 复制刚刚设置好的setting.xml 到你设置的本地仓库路径 我的是E:\dev_maven 5.仓库类型有哪些 四、 使用maven构建项目 这里我是用eclipse 进行创建的 1、eclipse配置 1.1 配置maven程序 1.2 配置userSetting ,知道仓库位置 1.3 构建索引,方便查找jar包(Window->show view ->maven Repository) 2、开始创建项目 2.1 这里选择普通项目- Maven Project ,点击next 2.2 打包方式选择war ,完成。 2.3 web.xml缺失报错 此时,会报错,需要在src-main-webapp 下面创建 WEB-INF/web.xml 目录结构 web.xml 内容 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app> 同时创建一个index.xml_(src\main\webapp\index.html) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Hello maven</h1> </body> </html> 设置jdk编译版本为1.8.默认为1.5 修改pom文件 <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.zhb</groupId> <artifactId>maven_hello</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project> 更新maven 运行项目 tomcat:run 4.大功告成 五、maven 常用命令 clean:清理 将项目根目录下target目录清理掉 compile:编译 将项目中.java文件编译为.class文件 test:单元测试 单元测试类名有要求:XxxxTest.java 将项目根目录下src/test/java目录下的单元测试类都会执行。 package:打包 web project --- war包 java project --- jar 包 将项目打包,打包项目根目录下taget目录。 install:安装 本地多个项目公用一个jar包。 打包到本地仓库 这里大家自己尝试一下,进入工程目录里面 如打包 则执行 mvn package 2018年5月20日更新 我现在发现 我先在使用idea开发,大家可以在自己电脑的c盘的,m2 文件夹下将setting.xml 考到里面,这样本地仓库就是你设置的了 好了,写了好久。终于弄完了。玩的开心。 学习不是要么0分,要么100分的。80分是收获;60分是收获;20分也是收获。有收获最重要。但是因为着眼于自己的不完美,最终放弃了,那就是彻底的0分了。

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

JetCache快速入门

创建缓存实例 通过@CreateCache注解创建一个缓存实例,默认超时时间是100秒 @CreateCache(expire = 100) private Cache<Long, UserDO> userCache; 用起来就像map一样 UserDO user = userCache.get(123L); userCache.put(123L, user); userCache.remove(123L); 创建一个两级(内存+远程)的缓存,内存中的元素个数限制在50个。 @CreateCache(name = "UserService.userCache", expire = 100, cacheType = CacheType.BOTH, localLimit = 50) private Cache<Long, UserDO> userCache; name属性不是必须的,但是起个名字是个好习惯,展示统计数据的使用,会使用这个名字。如果同一个area两个@CreateCache的name配置一样,它们生成的Cache将指向同一个实例。 创建方法缓存 使用@Cached方法可以为一个方法添加上缓存。JetCache通过Spring AOP生成代理,来支持缓存功能。注解可以加在接口方法上也可以加在类方法上,但需要保证是个Spring bean。 public interface UserService { @Cached(name="UserService.getUserById", expire = 3600) User getUserById(long userId); } 基本配置(使用Spring Boot) 如果使用Spring Boot,可以按如下的方式配置。 POM <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-starter-redis</artifactId> <version>2.4.4</version> </dependency> 配置一个spring boot风格的application.yml文件,把他放到资源目录中 jetcache: statIntervalMinutes: 15 areaInCacheName: false local: default: type: linkedhashmap keyConvertor: fastjson remote: default: type: redis keyConvertor: fastjson valueEncoder: java valueDecoder: java poolConfig: minIdle: 5 maxIdle: 20 maxTotal: 50 host: 127.0.0.1 port: 6379 然后创建一个App类放在业务包的根下,EnableMethodCache,EnableCreateCacheAnnotation这两个注解分别激活Cached和CreateCache注解,其他和标准的Spring Boot程序是一样的。这个类可以直接main方法运行。 package com.company.mypackage; import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; import com.alicp.jetcache.anno.config.EnableMethodCache; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableMethodCache(basePackages = "com.company.mypackage") @EnableCreateCacheAnnotation public class MySpringBootApp { public static void main(String[] args) { SpringApplication.run(MySpringBootApp.class); } } 未使用SpringBoot的配置方式 如果没有使用spring boot,可以按下面的方式配置(这里使用jedis客户端连接redis为例)。 <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-anno</artifactId> <version>2.4.4</version> </dependency> <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-redis</artifactId> <version>2.4.4</version> </dependency> 配置了这个JetCacheConfig类以后,可以使用@CreateCache和@Cached注解。 package com.company.mypackage; import java.util.HashMap; import java.util.Map; import com.alicp.jetcache.anno.CacheConsts; import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; import com.alicp.jetcache.anno.config.EnableMethodCache; import com.alicp.jetcache.anno.support.GlobalCacheConfig; import com.alicp.jetcache.anno.support.SpringConfigProvider; import com.alicp.jetcache.embedded.EmbeddedCacheBuilder; import com.alicp.jetcache.embedded.LinkedHashMapCacheBuilder; import com.alicp.jetcache.redis.RedisCacheBuilder; import com.alicp.jetcache.support.FastjsonKeyConvertor; import com.alicp.jetcache.support.JavaValueDecoder; import com.alicp.jetcache.support.JavaValueEncoder; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.util.Pool; @Configuration @EnableMethodCache(basePackages = "com.company.mypackage") @EnableCreateCacheAnnotation public class JetCacheConfig { @Bean public Pool<Jedis> pool(){ GenericObjectPoolConfig pc = new GenericObjectPoolConfig(); pc.setMinIdle(2); pc.setMaxIdle(10); pc.setMaxTotal(10); return new JedisPool(pc, "localhost", 6379); } @Bean public SpringConfigProvider springConfigProvider() { return new SpringConfigProvider(); } @Bean public GlobalCacheConfig config(SpringConfigProvider configProvider, Pool<Jedis> pool){ Map localBuilders = new HashMap(); EmbeddedCacheBuilder localBuilder = LinkedHashMapCacheBuilder .createLinkedHashMapCacheBuilder() .keyConvertor(FastjsonKeyConvertor.INSTANCE); localBuilders.put(CacheConsts.DEFAULT_AREA, localBuilder); Map remoteBuilders = new HashMap(); RedisCacheBuilder remoteCacheBuilder = RedisCacheBuilder.createRedisCacheBuilder() .keyConvertor(FastjsonKeyConvertor.INSTANCE) .valueEncoder(JavaValueEncoder.INSTANCE) .valueDecoder(JavaValueDecoder.INSTANCE) .jedisPool(pool); remoteBuilders.put(CacheConsts.DEFAULT_AREA, remoteCacheBuilder); GlobalCacheConfig globalCacheConfig = new GlobalCacheConfig(); globalCacheConfig.setConfigProvider(configProvider); globalCacheConfig.setLocalCacheBuilders(localBuilders); globalCacheConfig.setRemoteCacheBuilders(remoteBuilders); globalCacheConfig.setStatIntervalMinutes(15); globalCacheConfig.setAreaInCacheName(false); return globalCacheConfig; } } 进一步阅读 CreateCache的详细使用说明可以看这里 使用@CacheCache创建的Cache接口实例,它的API使用可以看这里 关于方法缓存(@Cached, @CacheUpdate, @CacheInvalidate)的详细使用看这里 详细的配置说明看这里。

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

python:爬虫入门

直接上代码吧: 一、爬取某外卖平台的指定商家菜品信息 from urllib import request import json import random url = "https://www.ele.me/restapi/shopping/v2/menu?restaurant_id=1392240&terminal=web" # 多搞几个user-agent 看上去更真实点~_^ user_agents = [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0'] random_user_agent = user_agents[random.randint(0, len(user_agents) - 1)] page = request.Request(url, headers={'User-Agent': random_user_agent}) page_info = request.urlopen(page).read().decode("utf-8") # 该url正好返回的是json数组,直接解析就可以了 menu_json = json.loads(page_info) # 清理一些特殊字符串 def clean_menu_name(name): temp = ["-", "^_^", "\n", "◆"] for s in temp: name = name.replace(s, "") return name for category in menu_json: print("分类名:", clean_menu_name(category["name"])) for food in category["foods"]: print("\t", "菜名:", clean_menu_name(food["name"]), " , 菜ID:", food["item_id"], " , 分类ID:", food["category_id"]) for spec in food["specfoods"]: print("\t\t", "规格ID:", spec["sku_id"], " , 价格:", spec["price"]) 输出: 分类名: 必选品(【必选!】吃法二选一,嘛哩匠心出品) 菜名: 经典骨汤上等豚骨每日现熬 , 菜ID: 17548636051 , 分类ID: 13737658 规格ID: 20830000019 , 价格: 1 菜名: 特色干拌—麻辣拌(招牌,秘制麻酱) , 菜ID: 17548637075 , 分类ID: 13737658 规格ID: 20830001043 , 价格: 1.5 分类名: 热销 菜名: 经典骨汤上等豚骨每日现熬 , 菜ID: 17548636051 , 分类ID: 13737658 规格ID: 20830000019 , 价格: 1 菜名: 娃娃菜 , 菜ID: 17548706707 , 分类ID: 13737835 规格ID: 20830070675 , 价格: 3 菜名: 精品肥牛 , 菜ID: 17548664723 , 分类ID: 13737800 规格ID: 20830028691 , 价格: 5.5 菜名: 金针菇 , 菜ID: 17548711827 , 分类ID: 13737835 规格ID: 20830075795 , 价格: 3 菜名: 土豆 , 菜ID: 17548693395 , 分类ID: 13737835 规格ID: 20830057363 , 价格: 2.5 菜名: 特色干拌—麻辣拌(招牌,秘制麻酱) , 菜ID: 17548637075 , 分类ID: 13737658 规格ID: 20830001043 , 价格: 1.5 菜名: 精品蟹肉棒 , 菜ID: 17548654483 , 分类ID: 13737790 规格ID: 20830018451 , 价格: 4 菜名: 冬瓜 , 菜ID: 17548694419 , 分类ID: 13737835 规格ID: 20830058387 , 价格: 2.5 菜名: 梅林午餐肉 , 菜ID: 17548656531 , 分类ID: 13737790 规格ID: 20830020499 , 价格: 5.5 菜名: 【人气】秘制麻酱芝麻花生酱 , 菜ID: 17548638099 , 分类ID: 13737698 规格ID: 20830002067 , 价格: 1 分类名: 优惠 菜名: 招牌霸道~经典荤素~套餐 , 菜ID: 200000173605996435 , 分类ID: 1238754176 规格ID: 200000199013771155 , 价格: 29.4 菜名: 招牌霸道~素食主义~套餐 , 菜ID: 200000173616109459 , 分类ID: 1238754176 规格ID: 200000199009531795 , 价格: 25.2 分类名: Hi~嘛哩来袭咯~ 菜名: 有问题?找嘛哩!~ , 菜ID: 200000173483983763 , 分类ID: 1238743250 规格ID: 200000198867809171 , 价格: 0.01 分类名: 【不得不吃】秘制酱料匠心出品 菜名: 【人气】秘制麻酱芝麻花生酱 , 菜ID: 17548638099 , 分类ID: 13737698 规格ID: 20830002067 , 价格: 1 菜名: 香辣酱 , 菜ID: 17548639123 , 分类ID: 13737698 规格ID: 20830003091 , 价格: 1 菜名: 沙茶酱 , 菜ID: 17548640147 , 分类ID: 13737698 规格ID: 20830004115 , 价格: 1 菜名: 菌菇酱 , 菜ID: 17548642195 , 分类ID: 13737698 规格ID: 20830006163 , 价格: 1 分类名: 【必选】麻辣在舌尖(口味选择) 菜名: 不麻+不辣 , 菜ID: 17548643219 , 分类ID: 13737734 规格ID: 20830007187 , 价格: 0 菜名: 微麻+微辣 , 菜ID: 17548644243 , 分类ID: 13737734 规格ID: 20830008211 , 价格: 0 菜名: 中麻+中辣 , 菜ID: 17548645267 , 分类ID: 13737734 规格ID: 20830009235 , 价格: 0 菜名: 重麻+重辣 , 菜ID: 17548646291 , 分类ID: 13737734 规格ID: 20830010259 , 价格: 0 分类名: 【可选】调味小料区(放碗里,不单独打包) 菜名: 香葱 , 菜ID: 17548647315 , 分类ID: 13737756 规格ID: 20830011283 , 价格: 0.1 菜名: 蒜泥 , 菜ID: 17548648339 , 分类ID: 13737756 规格ID: 20830012307 , 价格: 0.1 菜名: 醋 , 菜ID: 17548649363 , 分类ID: 13737756 规格ID: 20830013331 , 价格: 0.1 分类名: 人气特色榜单 菜名: 冻豆腐 , 菜ID: 17548650387 , 分类ID: 13737790 规格ID: 20830014355 , 价格: 3.5 菜名: 成都酥肉 , 菜ID: 17548651411 , 分类ID: 13737790 规格ID: 20830015379 , 价格: 4.5 菜名: 芝士年糕 , 菜ID: 17548653459 , 分类ID: 13737790 规格ID: 20830017427 , 价格: 4 菜名: 精品蟹肉棒 , 菜ID: 17548654483 , 分类ID: 13737790 规格ID: 20830018451 , 价格: 4 菜名: 荠菜丸子 , 菜ID: 17548655507 , 分类ID: 13737790 规格ID: 20830019475 , 价格: 3.5 菜名: 梅林午餐肉 , 菜ID: 17548656531 , 分类ID: 13737790 规格ID: 20830020499 , 价格: 5.5 菜名: 哈尔滨红肠 , 菜ID: 17548657555 , 分类ID: 13737790 规格ID: 20830021523 , 价格: 4 菜名: 甜玉米 , 菜ID: 17548658579 , 分类ID: 13737790 规格ID: 20830022547 , 价格: 3.5 菜名: 牛百叶 , 菜ID: 17548659603 , 分类ID: 13737790 规格ID: 20830023571 , 价格: 5 分类名: 精品荤菜 菜名: 燕饺 , 菜ID: 17548690323 , 分类ID: 13737800 规格ID: 20830054291 , 价格: 4 菜名: 广味香肠 , 菜ID: 17548691347 , 分类ID: 13737800 规格ID: 20830055315 , 价格: 4 菜名: 川味香肠 , 菜ID: 17548692371 , 分类ID: 13737800 规格ID: 20830056339 , 价格: 4 菜名: 培根 , 菜ID: 17548660627 , 分类ID: 13737800 规格ID: 20830024595 , 价格: 3.5 菜名: 鸡胗 , 菜ID: 17548661651 , 分类ID: 13737800 规格ID: 20830025619 , 价格: 4 菜名: 里脊肉 , 菜ID: 17548662675 , 分类ID: 13737800 规格ID: 20830026643 , 价格: 3.5 菜名: 骨肉相连 , 菜ID: 17548663699 , 分类ID: 13737800 规格ID: 20830027667 , 价格: 4 菜名: 精品肥牛 , 菜ID: 17548664723 , 分类ID: 13737800 规格ID: 20830028691 , 价格: 5.5 菜名: 鲜腐皮虾卷 , 菜ID: 200000176127363987 , 分类ID: 13737800 规格ID: 200000202129068947 , 价格: 4.9 菜名: 蟹粉包 , 菜ID: 17548668819 , 分类ID: 13737800 规格ID: 20830032787 , 价格: 3 菜名: 海胆包 , 菜ID: 17548669843 , 分类ID: 13737800 规格ID: 20830033811 , 价格: 3 菜名: 蛋饺 , 菜ID: 17548670867 , 分类ID: 13737800 规格ID: 20830034835 , 价格: 3.5 菜名: 千叶豆腐 , 菜ID: 17548671891 , 分类ID: 13737800 规格ID: 20830035859 , 价格: 3 菜名: 鱼皮豆腐 , 菜ID: 17548672915 , 分类ID: 13737800 规格ID: 20830036883 , 价格: 3 菜名: 深海鱼蛋丸 , 菜ID: 200000176114181011 , 分类ID: 13737800 规格ID: 200000202122663827 , 价格: 4 菜名: 墨鱼丸 , 菜ID: 17548674963 , 分类ID: 13737800 规格ID: 20830038931 , 价格: 4.5 菜名: 包心贡丸 , 菜ID: 17548675987 , 分类ID: 13737800 规格ID: 20830039955 , 价格: 4.5 菜名: 撒尿牛丸 , 菜ID: 17548677011 , 分类ID: 13737800 规格ID: 20830040979 , 价格: 4.5 菜名: 龙虾丸 , 菜ID: 17548678035 , 分类ID: 13737800 规格ID: 20830042003 , 价格: 4.5 菜名: 北极翅 , 菜ID: 17548680083 , 分类ID: 13737800 规格ID: 20830044051 , 价格: 4 菜名: 玉米肠 , 菜ID: 17548682131 , 分类ID: 13737800 规格ID: 20830046099 , 价格: 4 菜名: 开花肠 , 菜ID: 17548683155 , 分类ID: 13737800 规格ID: 20830047123 , 价格: 3.5 菜名: 亲亲肠 , 菜ID: 17548684179 , 分类ID: 13737800 规格ID: 20830048147 , 价格: 3.5 菜名: 大红肠 , 菜ID: 17548686227 , 分类ID: 13737800 规格ID: 20830050195 , 价格: 4 分类名: 蔬菜菌类 菜名: 土豆 , 菜ID: 17548693395 , 分类ID: 13737835 规格ID: 20830057363 , 价格: 2.5 菜名: 冬瓜 , 菜ID: 17548694419 , 分类ID: 13737835 规格ID: 20830058387 , 价格: 2.5 菜名: 藕片 , 菜ID: 17548695443 , 分类ID: 13737835 规格ID: 20830059411 , 价格: 3 菜名: 莴笋 , 菜ID: 17548696467 , 分类ID: 13737835 规格ID: 20830060435 , 价格: 3 菜名: 白萝卜 , 菜ID: 17548697491 , 分类ID: 13737835 规格ID: 20830061459 , 价格: 2 菜名: 生菜 , 菜ID: 17548699539 , 分类ID: 13737835 规格ID: 20830063507 , 价格: 2.5 菜名: 茼蒿菜 , 菜ID: 17548700563 , 分类ID: 13737835 规格ID: 20830064531 , 价格: 3 菜名: 香菜 , 菜ID: 17548701587 , 分类ID: 13737835 规格ID: 20830065555 , 价格: 3 菜名: 菠菜 , 菜ID: 17548702611 , 分类ID: 13737835 规格ID: 20830066579 , 价格: 3 菜名: 油麦菜 , 菜ID: 17548703635 , 分类ID: 13737835 规格ID: 20830067603 , 价格: 2.5 菜名: 小青菜 , 菜ID: 17548705683 , 分类ID: 13737835 规格ID: 20830069651 , 价格: 2.5 菜名: 娃娃菜 , 菜ID: 17548706707 , 分类ID: 13737835 规格ID: 20830070675 , 价格: 3 菜名: 有机花菜 , 菜ID: 17548707731 , 分类ID: 13737835 规格ID: 20830071699 , 价格: 3.5 菜名: 西兰花 , 菜ID: 17548708755 , 分类ID: 13737835 规格ID: 20830072723 , 价格: 3.5 菜名: 西红柿 , 菜ID: 17548709779 , 分类ID: 13737835 规格ID: 20830073747 , 价格: 3 菜名: 海带结 , 菜ID: 17548710803 , 分类ID: 13737835 规格ID: 20830074771 , 价格: 2.5 菜名: 金针菇 , 菜ID: 17548711827 , 分类ID: 13737835 规格ID: 20830075795 , 价格: 3 菜名: 香菇 , 菜ID: 17548712851 , 分类ID: 13737835 规格ID: 20830076819 , 价格: 3 菜名: 秀珍菇 , 菜ID: 17548713875 , 分类ID: 13737835 规格ID: 20830077843 , 价格: 3 菜名: 海鲜菇 , 菜ID: 17548714899 , 分类ID: 13737835 规格ID: 20830078867 , 价格: 3.5 菜名: 黑木耳 , 菜ID: 17548715923 , 分类ID: 13737835 规格ID: 20830079891 , 价格: 3 菜名: 红薯 , 菜ID: 17548717971 , 分类ID: 13737835 规格ID: 20830081939 , 价格: 2.5 菜名: 特级笋尖/水笋 , 菜ID: 17548718995 , 分类ID: 13737835 规格ID: 20830082963 , 价格: 4 分类名: 豆蛋类 菜名: 油豆腐 , 菜ID: 17548716947 , 分类ID: 13737840 规格ID: 20830080915 , 价格: 3 菜名: 日本豆腐 , 菜ID: 17548721043 , 分类ID: 13737840 规格ID: 20830085011 , 价格: 3 菜名: 绿豆芽 , 菜ID: 17548722067 , 分类ID: 13737840 规格ID: 20830086035 , 价格: 2 菜名: 豆腐皮 , 菜ID: 17548723091 , 分类ID: 13737840 规格ID: 20830087059 , 价格: 2.5 菜名: 厚百叶 , 菜ID: 17548724115 , 分类ID: 13737840 规格ID: 20830088083 , 价格: 3 菜名: 腐竹 , 菜ID: 17548725139 , 分类ID: 13737840 规格ID: 20830089107 , 价格: 3 菜名: 鸭血 , 菜ID: 17548726163 , 分类ID: 13737840 规格ID: 20830090131 , 价格: 3 菜名: 鹌鹑蛋 , 菜ID: 17548727187 , 分类ID: 13737840 规格ID: 20830091155 , 价格: 2.5 菜名: 油面筋 , 菜ID: 17548728211 , 分类ID: 13737840 规格ID: 20830092179 , 价格: 2.5 菜名: 油条 , 菜ID: 17548729235 , 分类ID: 13737840 规格ID: 20830093203 , 价格: 2.5 分类名: 主食类 菜名: 锅巴 , 菜ID: 17548730259 , 分类ID: 13737847 规格ID: 20830094227 , 价格: 2.5 菜名: 方便面 , 菜ID: 17548731283 , 分类ID: 13737847 规格ID: 20830095251 , 价格: 3 菜名: 鸡蛋面 , 菜ID: 17548732307 , 分类ID: 13737847 规格ID: 20830096275 , 价格: 2.5 菜名: 红薯宽粉 , 菜ID: 17548733331 , 分类ID: 13737847 规格ID: 20830097299 , 价格: 3 菜名: 红薯细粉 , 菜ID: 17548734355 , 分类ID: 13737847 规格ID: 20830098323 , 价格: 3 菜名: 蒙古宽粉 , 菜ID: 17548735379 , 分类ID: 13737847 规格ID: 20830099347 , 价格: 3 菜名: 手工细面 , 菜ID: 17548736403 , 分类ID: 13737847 规格ID: 20830100371 , 价格: 2.5 菜名: 刀削面 , 菜ID: 17548737427 , 分类ID: 13737847 规格ID: 20830101395 , 价格: 3 菜名: 玉米面条 , 菜ID: 17548738451 , 分类ID: 13737847 规格ID: 20830102419 , 价格: 4 菜名: 魔芋丝结 , 菜ID: 17548739475 , 分类ID: 13737847 规格ID: 20830103443 , 价格: 5 菜名: 龙口粉丝 , 菜ID: 17548740499 , 分类ID: 13737847 规格ID: 20830104467 , 价格: 4 菜名: 年糕节 , 菜ID: 17548741523 , 分类ID: 13737847 规格ID: 20830105491 , 价格: 2 分类名: 饿了么送红包 菜名: 扫码领红包 , 菜ID: 260439795603 , 分类ID: 526021154 规格ID: 301159743379 , 价格: 0.01 分类名: 霸道总裁套餐 菜名: 招牌霸道~经典荤素~套餐 , 菜ID: 200000173605996435 , 分类ID: 1238754176 规格ID: 200000199013771155 , 价格: 29.4 菜名: 招牌霸道~素食主义~套餐 , 菜ID: 200000173616109459 , 分类ID: 1238754176 规格ID: 200000199009531795 , 价格: 25.2 二、抓取博客园某园友的首页文章列表 以我自己的博客为例: from urllib import request import random from bs4 import BeautifulSoup url = "http://yjmyzz.cnblogs.com/" # 多搞几个user-agent 看上去更真实点~_^ user_agents = [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0'] random_user_agent = user_agents[random.randint(0, len(user_agents) - 1)] page = request.Request(url, headers={'User-Agent': random_user_agent}) html = request.urlopen(page).read().decode("utf-8") bsObj = BeautifulSoup(html, "lxml") # 找出标题的a链接 title_links = bsObj.find_all("a", {"class": "postTitle2"}) with open("blog.csv", "a", encoding='utf-8') as f: i = 0 for link in title_links: i += 1 print(str(i), "\t", link.string, "\t", link["href"]) # 保存到csv文件中 f.write(str(i) + "\t" + link.string + "\t" + link["href"] + "\n") 注:BeautifulSoup是一个专门的解析html/xml的模块,贼好用。 输出如下: 1 [置顶]关于博客的背景音乐 http://www.cnblogs.com/yjmyzz/p/listen-to-your-heart.html 2 python: 序列化/反序列化及对象的深拷贝/浅拷贝 http://www.cnblogs.com/yjmyzz/p/python-serialization-and-object-copy.html 3 python中的zip、lambda、map操作 http://www.cnblogs.com/yjmyzz/p/python-zip-lambda-map.html 4 python面向对象笔记 http://www.cnblogs.com/yjmyzz/p/python-object-oriented-programming.html 5 RxJava2学习笔记(3) http://www.cnblogs.com/yjmyzz/p/rx-java-2-tutorial-3.html 6 RxJava2学习笔记(2) http://www.cnblogs.com/yjmyzz/p/rx-java-2-tutorial-2.html 7 RxJava2学习笔记(1) http://www.cnblogs.com/yjmyzz/p/rx-java-2-tutorial-1.html 8 Matplotlib新手上路(下) http://www.cnblogs.com/yjmyzz/p/matplotlib-tutorial-3.html 9 Matplotlib新手上路(中) http://www.cnblogs.com/yjmyzz/p/matplotlib-tutorial-2.html 10 Matplotlib新手上路(上) http://www.cnblogs.com/yjmyzz/p/matplotlib-tutorial-1.html 11 pycharm如何设置python版本、设置国内pip镜像、添加第三方类库 http://www.cnblogs.com/yjmyzz/p/pycharm-add-third-package-and-add-domestic-mirror.html 12 利用java8对设计模式的重构 http://www.cnblogs.com/yjmyzz/p/refactor-design-pattern-using-java8.html 13 机器学习笔记(6):多类逻辑回归-使用gluon http://www.cnblogs.com/yjmyzz/p/8128122.html 14 spring cloud:Edgware.RELEASE版本hystrix超时新坑 http://www.cnblogs.com/yjmyzz/p/8097713.html 15 spring cloud:Edgware.RELEASE版本中zuul回退方法的变化 http://www.cnblogs.com/yjmyzz/p/8093462.html 16 spring cloud:config-server中@RefreshScope的"陷阱" http://www.cnblogs.com/yjmyzz/p/8085530.html 17 机器学习笔记(5):多类逻辑回归-手动添加隐藏层 http://www.cnblogs.com/yjmyzz/p/8035041.html 18 机器学习笔记(4):多类逻辑回归-使用gluton http://www.cnblogs.com/yjmyzz/p/8034597.html 19 spring boot + embed tomcat + standalone jar的内存泄露问题 http://www.cnblogs.com/yjmyzz/p/the-memory-leak-problem-of-spring-boot-with-embed-tomcat.html 20 机器学习笔记(3):多类逻辑回归 http://www.cnblogs.com/yjmyzz/p/7789252.html 21 归一化(softmax)、信息熵、交叉熵 http://www.cnblogs.com/yjmyzz/p/7822990.html 22 NDArray自动求导 http://www.cnblogs.com/yjmyzz/p/7783286.html 23 机器学习笔记(2):线性回归-使用gluon http://www.cnblogs.com/yjmyzz/p/7774166.html 24 机器学习笔记(1):线性回归 http://www.cnblogs.com/yjmyzz/p/7764496.html 25 mxnet安装及NDArray初体验 http://www.cnblogs.com/yjmyzz/p/mxnet-install-and-ndarray-demo.html 26 jupyter notebook 在mac OS上的安装 http://www.cnblogs.com/yjmyzz/p/how-to-install-jupyter-notebook-on-mac.html 27 spring cloud 学习(11) - 用fastson替换jackson及用gb2312码输出 http://www.cnblogs.com/yjmyzz/p/spring-cloud-set-response-gbk-encoding.html 28 spring cloud 学习(10) - 利用springfox集成swagger http://www.cnblogs.com/yjmyzz/p/how-to-integrate-swagger-with-spring-cloud-by-springfox.html 29 spring-boot 速成(12) - 如何注入多个redis StringRedisTemplate http://www.cnblogs.com/yjmyzz/p/how-to-inject-multi-redis-instance-in-spring-boot.html 30 spring cloud 学习(9) - turbine stream无法在eureka注册的解决办法 http://www.cnblogs.com/yjmyzz/p/spring-cloud-turbine-eureka-register-problem.html 31 java:线上问题排查常用手段 http://www.cnblogs.com/yjmyzz/p/7478266.html 32 java一些常用并发工具示例 http://www.cnblogs.com/yjmyzz/p/java-concurrent-tools-sample.html 33 kafka集群部署 http://www.cnblogs.com/yjmyzz/p/kafka-cluster-deployment.html 34 spring cloud 学习(8) - sleuth & zipkin 调用链跟踪 http://www.cnblogs.com/yjmyzz/p/spring-cloud-with-zipkin.html 35 spring集成kafka http://www.cnblogs.com/yjmyzz/p/spring-integration-with-kafka.html 36 @Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法 http://www.cnblogs.com/yjmyzz/p/7390331.html 37 centos上安装elasticsearch 5.5.1 遇到的各种坑 http://www.cnblogs.com/yjmyzz/p/7372561.html 38 spring cloud 学习(7) - 生产环境如何不停机热发布? http://www.cnblogs.com/yjmyzz/p/how-to-hot-release-using-eureka-rest-operation.html 39 spring-boot 速成(11) - 单元测试 http://www.cnblogs.com/yjmyzz/p/unit-test-with-spring-boot.html 40 spring-boot 速成(10) -【个人邮箱/企业邮箱】发送邮件 http://www.cnblogs.com/yjmyzz/p/send-mail-using-spring-boot.html 41 spring cloud 学习(6) - zuul 微服务网关 http://www.cnblogs.com/yjmyzz/p/spring-cloud-zuul-demo.html csv文件打开截图: 参考文档: http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/ 作者: 菩提树下的杨过 出处: http://yjmyzz.cnblogs.com 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

资源下载

更多资源
Mario

Mario

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

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应用均可从中受益。

WebStorm

WebStorm

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

用户登录
用户注册