-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 115 KB
/
content.json
1
{"meta":{"title":"eastFu","subtitle":"","description":"","author":"eastFu","url":"http://xiaodongzi.cn","root":"/"},"pages":[{"title":"关于","date":"2020-12-06T10:39:24.714Z","updated":"2020-12-06T10:39:24.714Z","comments":false,"path":"about/index.html","permalink":"http://xiaodongzi.cn/about/index.html","excerpt":"","text":"90后 2013年毕业 码农一枚 中年大叔 30而立 北漂 devops、linux、java、mysql、c#、golang、易语言、python、vue、hadoop、scrum、pmp"},{"title":"分类","date":"2020-12-06T09:12:15.395Z","updated":"2020-12-06T08:25:51.631Z","comments":false,"path":"categories/index.html","permalink":"http://xiaodongzi.cn/categories/index.html","excerpt":"","text":""},{"title":"友情链接","date":"2020-12-06T09:31:48.486Z","updated":"2020-12-06T08:25:51.632Z","comments":true,"path":"links/index.html","permalink":"http://xiaodongzi.cn/links/index.html","excerpt":"","text":""},{"title":"404 Not Found:该页无法显示","date":"2020-12-06T09:32:34.677Z","updated":"2020-12-06T08:25:51.622Z","comments":false,"path":"/404.html","permalink":"http://xiaodongzi.cn/404.html","excerpt":"","text":""},{"title":"标签","date":"2020-12-06T08:25:51.636Z","updated":"2020-12-06T08:25:51.636Z","comments":false,"path":"tags/index.html","permalink":"http://xiaodongzi.cn/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"storm 安装部署","slug":"storm安装","date":"2019-02-26T10:24:57.000Z","updated":"2020-12-19T04:04:04.518Z","comments":true,"path":"2019/02/26/storm安装/","link":"","permalink":"http://xiaodongzi.cn/2019/02/26/storm%E5%AE%89%E8%A3%85/","excerpt":"","text":"storm 安装部署1.关于Storm Storm是Twitter开源的分布式实时大数据处理框架,被业界称为实时版Hadoop。随着越来越多的场景对Hadoop的MapReduce高延迟无法容忍,比如网站统计、推荐系统、预警系统、金融系统(高频交易、股票)等等,大数据实时处理解决方案(流计算)的应用日趋广泛,目前已是分布式技术领域最新爆发点,而Storm更是流计算技术中的佼佼者和主流。 按照storm作者的说法,Storm对于实时计算的意义类似于Hadoop对于批处理的意义。Hadoop提供了map、reduce原语,使我们的批处理程序变得简单和高效。同样,Storm也为实时计算提供了一些简单高效的原语,而且Storm的Trident是基于Storm原语更高级的抽象框架,类似于基于Hadoop的Pig框架,让开发更加便利和高效。 Storm 目前版本更新到2.x,这里我们选用经典版本1.1.0进行安装部署,storm+kafka+zookeeper 实现流式计算。 官方下载地址: 1https://archive.apache.org/dist/storm/ 2.单节点安装部署修改配置文件conf/storm.yaml1234567891011storm.zookeeper.servers: - "zk001.test.com"nimbus.seeds: ["storm001.test.com"]storm.log.dir: "/data/storm/logs"storm.local.dir: "/data/storm/db"storm.zookeeper.root: "/storm-1.1.0"ui.port: 18888supervisor.slots.ports: - 19527 - 19528 - 19529 启动storm123nohup bin/storm nimbus >/data/storm/logs/storm_start.log 2>&1 &nohup bin/storm supervisor >/data/storm/logs/storm_supervisor.log 2>&1 &nohup bin/storm ui >/data/storm/logs/storm_ui.log 2>&1 & 访问UI web12http://ip:18888 3.集群部署4.应用程序编写和打包发布","categories":[{"name":"storm","slug":"storm","permalink":"http://xiaodongzi.cn/categories/storm/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"kafka的安装","slug":"kafka安装","date":"2018-10-20T11:26:08.000Z","updated":"2020-12-19T04:04:52.704Z","comments":true,"path":"2018/10/20/kafka安装/","link":"","permalink":"http://xiaodongzi.cn/2018/10/20/kafka%E5%AE%89%E8%A3%85/","excerpt":"","text":"kafka的安装1.下载安装 kafka的安装需要依赖zookeeper,虽然kafka自带了zookeeper,但是为了方便维护,推荐自己安装zookeeper 1234567891011121314151617181920212223242526272829303132333435363738394041#zookeeper下载地址:https://zookeeper.apache.org/releases.html#解压缩zookeepertar -zxvf apache-zookeeper-3.6.2-bin.tar.gz##修改配置 conf/zoo.cfgdataDir=/data/zk/node1/dataclientPort=2181server.1=localhost:2287:3387server.2=localhost:2288:3388server.3=localhost:2289:3389echo 1 >> /data/zk/node1/data/myidecho 2 >> /data/zk/node2/data/myidecho 3 >> /data/zk/node3/data/myid##启动zookeeper./zkServer.sh start ../conf/zoo1.cfg./zkServer.sh start ../conf/zoo2.cfg./zkServer.sh start ../conf/zoo3.cfg#kafka下载地址:http://kafka.apache.org/downloads# 解压缩tar -zxvf kafka_2.11-2.2.2.tgz#修改 conf/server.propertiesbroker.id=0listeners=PLAINTEXT://hostname:9092log.dirs=/data/kafka-logs/kafka3zookeeper.connect=zk1:2181,zk3:2181,zk3:2181#启动./kafka-server-start.sh -daemon ../config/server.properties 2.配置文件修改12345678910111213141516171819202122232425262728293031323334353637broker.id=0 #当前机器在集群中的唯一标识,和zookeeper的myid性质一样port=19092 #当前kafka对外提供服务的端口默认是9092host.name=192.168.7.100 #这个参数默认是关闭的,在0.8.1有个bug,DNS解析问题,失败率的问题。num.network.threads=3 #这个是borker进行网络处理的线程数num.io.threads=8 #这个是borker进行I/O处理的线程数log.dirs=/opt/kafka/kafkalogs/ #消息存放的目录,这个目录可以配置为“,”逗号分割的表达式,上面的num.io.threads要大于这个目录的个数这个目录,如果配置多个目录,新创建的topic他把消息持久化的地方是,当前以逗号分割的目录中,那个分区数最少就放那一个socket.send.buffer.bytes=102400 #发送缓冲区buffer大小,数据不是一下子就发送的,先回存储到缓冲区了到达一定的大小后在发送,能提高性能socket.receive.buffer.bytes=102400 #kafka接收缓冲区大小,当数据到达一定大小后在序列化到磁盘socket.request.max.bytes=104857600 #这个参数是向kafka请求消息或者向kafka发送消息的请请求的最大数,这个值不能超过java的堆栈大小num.partitions=1 #默认的分区数,一个topic默认1个分区数log.retention.hours=168 #默认消息的最大持久化时间,168小时,7天message.max.byte=5242880 #消息保存的最大值5Mdefault.replication.factor=2 #kafka保存消息的副本数,如果一个副本失效了,另一个还可以继续提供服务replica.fetch.max.bytes=5242880 #取消息的最大直接数log.segment.bytes=1073741824 #这个参数是:因为kafka的消息是以追加的形式落地到文件,当超过这个值的时候,kafka会新起一个文件log.retention.check.interval.ms=300000 #每隔300000毫秒去检查上面配置的log失效时间(log.retention.hours=168 ),到目录查看是否有过期的消息如果有,删除log.cleaner.enable=false #是否启用log压缩,一般不用启用,启用的话可以提高性能zookeeper.connect=192.168.7.100:12181,192.168.7.101:12181,192.168.7.107:1218 #设置zookeeper的连接端口 3.启动命令1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768#启动./kafka-server-start.sh -daemon ../config/server.propertieskafka1/bin/kafka-server-start.sh -daemon kafka1/config/server.propertieskafka2/bin/kafka-server-start.sh -daemon kafka2/config/server.propertieskafka3/bin/kafka-server-start.sh -daemon kafka3/config/server.properties#暂停kafka1/bin/kafka-server-stop.shkafka2/bin/kafka-server-stop.shkafka3/bin/kafka-server-stop.sh#创建Topic./kafka-topics.sh --create --zookeeper 192.168.7.100:12181 --replication-factor 2 --partitions 1 --topic shuaige#解释--replication-factor 2 #复制两份--partitions 1 #创建1个分区--topic #主题为shuaige'''在一台服务器上创建一个发布者'''#创建一个broker,发布者./kafka-console-producer.sh --broker-list 192.168.7.100:19092 --topic shuaige#在一台服务器上创建一个订阅者./kafka-console-consumer.sh --zookeeper localhost:12181 --topic shuaige --from-beginning#查看topic./kafka-topics.sh --list --zookeeper localhost:12181#查看topic状态/kafka-topics.sh --describe --zookeeper localhost:12181 --topic shuaige#下面是显示信息Topic:ssports PartitionCount:1 ReplicationFactor:2 Configs: Topic: shuaige Partition: 0 Leader: 1 Replicas: 0,1 Isr: 1#分区为为1 复制因子为2 他的 shuaige的分区为0 #Replicas: 0,1 复制的为0,1 4.kafka日志 可以通过配置server.properties文件中配置log.dirs参数来指定kafka的日志地址 123456789server.log #kafka的运行日志state-change.log #kafka他是用zookeeper来保存状态,所以他可能会进行切换,切换的日志就保存在这里controller.log #kafka选择一个节点作为“controller”,当发现有节点down掉的时候它负责在游泳分区的所有节点中选择新的leader,这使得Kafka可以批量的高效的管理所有分区节点的主从关系。如果controller down掉了,活着的节点中的一个会备切换为新的controller. 5.kafka的一些基本概念 consumer 消费者:从消息队列中请求消息的客户端应用程序 producer 生产者:向broker发布消息的应用程序 broker AMQP服务端:用来接收生产者发送的消息并将这些消息路由给服务器中的队列,便于kfafka将生产者发送的消息,动态的添加到磁盘并给每一条消息一个偏移量,所以对于kafka一个broker就是一个应用程序的实例,即一个kafka节点。 partition 分区:一个Topic中的消息数据按照多个分区组织,分区是kafka消息队列组织的最小单位,一个分区可以看作是一个FIFO( First Input First Output的缩写,先入先出队列)的队列。 topic 主题:一个主题类似新闻中的体育、娱乐、教育等分类概念,在实际工程中通常一个业务一个主题 replication factor 副本因子:推送到kafka的消息都进行了持久化,集群模式为了防止数据丢失,需要将消息数据进行复制,副本因子即为消息数据的复制个数,类比hadoop。 controller 控制器:类似于hadoop的hdfs中的namenode,负责消息副本和分区leader的管理,一套kafka集群启动后选举出一个broker节点作为controller。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"kafka","slug":"编程/kafka","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/kafka/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"正则表达式的那些事儿","slug":"正则表达式的那些事儿","date":"2018-10-15T14:10:55.000Z","updated":"2020-12-05T08:55:25.552Z","comments":true,"path":"2018/10/15/正则表达式的那些事儿/","link":"","permalink":"http://xiaodongzi.cn/2018/10/15/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/","excerpt":"","text":"正则表达式引擎正则表达式是一个很方便的匹配符号,但要实现这么复杂,功能如此强大的匹配语法,就必须要有一套算法来实现,而实现这套算法的东西就叫做正则表达式引擎。简单地说,实现正则表达式引擎的有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)。 对于这两种自动机,他们有各自的区别,这里并不打算深入将它们的原理。简单地说,DFA 自动机的时间复杂度是线性的,更加稳定,但是功能有限。而 NFA 的时间复杂度比较不稳定,有时候很好,有时候不怎么好,好不好取决于你写的正则表达式。但是胜在 NFA 的功能更加强大,所以包括 Java 、.NET、Perl、Python、Ruby、PHP 等语言都使用了 NFA 去实现其正则表达式。 NFA自动机的回溯了解了 NFA 是如何进行字符串匹配的,接下来我们就可以讲讲这篇文章的重点了:回溯。为了更好地解释回溯,我们同样以下面的例子来讲解。 1text="abbc"regex="ab{1,3}c" 上面的这个例子的目的比较简单,匹配以 a 开头,以 c 结尾,中间有 1-3 个 b 字符的字符串。NFA 对其解析的过程是这样子的: 首先,读取正则表达式第一个匹配符 a 和 字符串第一个字符 a 比较,匹配了。于是读取正则表达式第二个字符。 读取正则表达式第二个匹配符 b{1,3} 和字符串的第二个字符 b 比较,匹配了。但因为 b{1,3} 表示 1-3 个 b 字符串,以及 NFA 自动机的贪婪特性(也就是说要尽可能多地匹配),所以此时并不会再去读取下一个正则表达式的匹配符,而是依旧使用 b{1,3} 和字符串的第三个字符 b 比较,发现还是匹配。于是继续使用 b{1,3} 和字符串的第四个字符 c 比较,发现不匹配了。此时就会发生回溯。 发生回溯是怎么操作呢?发生回溯后,我们已经读取的字符串第四个字符 c 将被吐出去,指针回到第三个字符串的位置。之后,程序读取正则表达式的下一个操作符 c,读取当前指针的下一个字符 c 进行对比,发现匹配。于是读取下一个操作符,但这里已经结束了。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"正则表达式","slug":"编程/正则表达式","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"深入浅出Http和WebSocket","slug":"深入浅出HTTP和WebSocket","date":"2018-10-12T14:46:19.000Z","updated":"2020-12-05T08:55:25.556Z","comments":true,"path":"2018/10/12/深入浅出HTTP和WebSocket/","link":"","permalink":"http://xiaodongzi.cn/2018/10/12/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BAHTTP%E5%92%8CWebSocket/","excerpt":"","text":"关于http协议 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议[1]。HTTP是万维网的数据通信的基础。 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识 HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)。我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)。 尽管TCP/IP协议是互联网上最流行的应用,HTTP协议中,并没有规定必须使用它或它支持的层。事实上,HTTP可以在任何互联网协议上,或其他网络上实现。HTTP假定其下层协议提供可靠的传输。因此,任何能够提供这种保证的协议都可以被其使用。因此也就是其在TCP/IP协议族使用TCP作为其传输层。 通常,由HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如”HTTP/1.1 200 OK”,以及返回的内容,如请求的文件、错误消息、或者其它信息。 http协议的弊端 http协议是半双开工协议。半双开工协议指数据可以在客户端和服务端两个方向上传输,但是不能同时传输。它意味着在同一时刻,只有一个方向上的数据传送; http消息冗长而繁琐。http消息包含消息头、消息体、换行符等,通常情况下采用文本方式传送,相比于其他的二进制通讯协议,冗长而繁琐; 针对服务器推送的黑客攻击。 例如长时间轮询; 关于websocket websocket 是 html5 开始提供的一种浏览器和服务器间进行全双工通讯的网络技术,websocket通讯协议于2011年被IETF定为标准 RFC6455,websocket API 被W3C 定为标准。 websocket的特点 单一的TCP连接,采用全双工模式通讯 对代理、防火墙和路由器透明 无头部信息、cookie和身份验证 无安全开销 通过“ping/pong” 帧保持链路激活 服务器可以主动传递消息给客户端,不再需要客户端轮询。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"网络","slug":"编程/网络","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E7%BD%91%E7%BB%9C/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"初识RabbitMQ","slug":"初识RabbitMQ","date":"2018-10-10T11:33:24.000Z","updated":"2020-12-05T08:55:25.554Z","comments":true,"path":"2018/10/10/初识RabbitMQ/","link":"","permalink":"http://xiaodongzi.cn/2018/10/10/%E5%88%9D%E8%AF%86RabbitMQ/","excerpt":"","text":"参考资料","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"RabbitMQ","slug":"编程/RabbitMQ","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/RabbitMQ/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"聊一聊常用的登录认证方式","slug":"聊一聊常用的登录认证方式","date":"2018-09-30T11:26:08.000Z","updated":"2020-12-05T08:55:25.559Z","comments":true,"path":"2018/09/30/聊一聊常用的登录认证方式/","link":"","permalink":"http://xiaodongzi.cn/2018/09/30/%E8%81%8A%E4%B8%80%E8%81%8A%E5%B8%B8%E7%94%A8%E7%9A%84%E7%99%BB%E5%BD%95%E8%AE%A4%E8%AF%81%E6%96%B9%E5%BC%8F/","excerpt":"","text":"介绍 登录认证几乎是任何一个系统的标配,web 系统、APP、PC 客户端等,好多都需要注册、登录、授权认证。 以一个电商系统,假设淘宝为例,如果我们想要下单,首先需要注册一个账号。拥有了账号之后,我们需要输入用户名(比如手机号或邮箱)、密码完成登录过程。之后如果你在一段时间内再次进入系统,是不需要输入用户名和密码的,只有在连续长时间不登录的情况下(例如一个月没登录过)访问系统,再次需要输入用户名和密码。如果使用频率很频繁,通常是一年都不用再输一次密码,所以经常在换了一台电脑或者一部手机之后,一些经常使用的网站或 APP 不记得密码了。 提炼出来整个过程大概就是如下几步: 首次使用,需要通过邮箱或手机号注册;注册完成后,需要提供用户名和密码完成登录;下次再使用,通常不会再次输入用户名和密码即可直接进入系统并使用其功能(除非连续长时间未使用); 常用的认证方式OAuth 认证OAuth 认证比较常见的就是微信登录、微博登录、qq登录等,简单来说就是利用这些比较权威的网站或应用开放的 API 来实现用户登录,用户可以不用在你的网站或应用上注册账号,直接用已有的微信、微博、qq 等账号登录。 这一样一来,即省了用户注册的时间,又简化了你的系统的账号体系。从而既可以提高用户注册率可以节省开发时间,同时,安全性也有了保障。 维基百科对它的解释摘要如下: OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌>授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。 假设我们开发了一个电商平台,并集成了微信登录,以这个场景为例,说一下 OAuth 的工作原理。 讲之前需要了解其中涉及到的几个角色: 用户:即使用我们平台的用户 用户终端:即最终用户使用的 APP 端或 web 端 应用服务器端:即我们的服务器端 授权服务器端:这里就是微信处理授权请求的服务器 好的,接下来开始在我们的电商平台web端实现微信登录功能。微信网页授权是授权码模式(authorization code)的 OAuth 授权模式。 我们电商平台的用户过来登录,常用场景是点击“微信登录”按钮; 接下来,用户终端将用户引导到微信授权页面; 用户同意授权,应用服务器重定向到之前设置好的 redirect_uri (应用服务器所在的地址),并附带上授权码(code); 应用服务器用上一步获取的 code 向微信授权服务器发送请求,获取 access_token,也就是上面说的令牌; 之后应用服务器用上一步获取的 access_token 去请求微信授权服务器获取用户的基本信息,例如头像、昵称等; Cookie-Session认证早期互联网以 web 为主,客户端是浏览器,所以 Cookie-Session 方式最那时候最常用的方式,直到现在,一些 web 网站依然用这种方式做认证。 认证过程大致如下: 用户输入用户名、密码或者用短信验证码方式登录系统; 服务端验证后,创建一个 Session 信息,并且将 SessionID 存到 cookie,发送回浏览器; 下次客户端再发起请求,自动带上 cookie 信息,服务端通过 cookie 获取 Session 信息进行校验; 弊端: 只能在 web 场景下使用,如果是 APP 中,不能使用 cookie 的情况下就不能用了; 即使能在 web 场景下使用,也要考虑跨域问题,因为 cookie 不能跨域; cookie 存在 CSRF(跨站请求伪造)的风险; 如果是分布式服务,需要考虑 Session 同步问题; Cookie-Session改造版由于传统的 Cookie-Session 认证存在诸多问题,可以把上面的方案改造一下。改动的地方如下: 不用 cookie 做客户端存储,改用其他方式,web 下使用 local storage,APP 中使用客户端数据库,这样就实现了跨域,并且避免了 CSRF ; 服务端也不存 Session 了,把 Session 信息拿出来存到 Redis 等内存数据库中,这样即提高了速度,又避免了 Session 同步问题;经过改造之后变成了如下的认证过程: 用户输入用户名、密码或者用短信验证码方式登录系统; 服务端经过验证,将认证信息构造好的数据结构存储到 Redis 中,并将 key 值返回给客户端; 客户端拿到返回的 key,存储到 local storage 或本地数据库; 下次客户端再次请求,把 key 值附加到 header 或者 请求体中; 服务端根据获取的 key,到 Redis 中获取认证信息; 基于JWT的Token认证上面的方案虽然经过了改版,但还是需要客户端和服务器端维持一个状态信息,比如用 cookie 换 session ,或者用 key 换 Redis 的 value 信息,基于 JWT 的 Token 认证方案可以省去这个过程。 JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。 认证过程 依然是用户登录系统; 服务端验证,将认证信息通过指定的算法(例如HS256)进行加密,例如对用户名和用户所属角色进行加密,加密私钥是保存在服务器端的,将加密后的结果发送给客户端,加密的字符串格式为三个”.” 分隔的字符串 Token,分别对应头部、载荷与签名,头部和载荷都可以通过 base64 解码出来,签名部分不可以; 客户端拿到返回的 Token,存储到 local storage 或本地数据库; 下次客户端再次发起请求,将 Token 附加到 header 中; 服务端获取 header 中的 Token ,通过相同的算法对 Token 中的用户名和所属角色进行相同的加密验证,如果验证结果相同,则说明这个请求是正常的,没有被篡改。这个过程可以完全不涉及到查询 Redis 或其他存储; 优点: 使用 json 作为数据传输,有广泛的通用型,并且体积小,便于传输; 不需要在服务器端保存相关信息; jwt 载荷部分可以存储业务相关的信息(非敏感的),例如用户信息、角色等; 总结综上所述,JWT 可以作为首选的认证方案。当然,具体的情况具体分析,还要看是不是适合真实的应用场景。除了上述的这些,涉及到信息安全的,建议全部采用 https 方式部署,采用 https 方式,信息很难被嗅探破解,对应用的安全性很重要。 参考资料 OAuth - http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html JWT- [https://jwt.io/introduction/ http://blog.leapoahead.com/2015/09/06/understanding-jwt](https://jwt.io/introduction/ http://blog.leapoahead.com/2015/09/06/understanding-jwt) JWT Java 库- https://github.com/jwtk/jjwt","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"安全","slug":"编程/安全","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E5%AE%89%E5%85%A8/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"OAuth 2.0介绍[转]","slug":"OAuth-2-0介绍-转","date":"2018-09-26T12:55:51.000Z","updated":"2020-12-07T05:38:44.387Z","comments":true,"path":"2018/09/26/OAuth-2-0介绍-转/","link":"","permalink":"http://xiaodongzi.cn/2018/09/26/OAuth-2-0%E4%BB%8B%E7%BB%8D-%E8%BD%AC/","excerpt":"","text":"OAuth OAuth 是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为 RFC 6749。 应用场景为了理解OAuth的适用场合,让我举一个假设的例子。 有一个”云冲印”的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让”云冲印”读取自己储存在Google上的照片。 问题是只有得到用户的授权,Google才会同意”云冲印”读取这些照片。那么,”云冲印”怎样获得用户的授权呢? 传统方法是,用户将自己的Google用户名和密码,告诉”云冲印”,后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。 ”云冲印”为了后续的服务,会保存用户的密码,这样很不安全。 Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。 ”云冲印”拥有了获取用户储存在Google所有资料的权力,用户没法限制”云冲印”获得授权的范围和有效期。 用户只有修改密码,才能收回赋予”云冲印”的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。 只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。 OAuth就是为了解决上面这些问题而诞生的。 名词定义在详细讲解OAuth 2.0之前,需要了解几个专用名词。它们对读懂后面的讲解,尤其是几张图,至关重要。 Third-party application:第三方应用程序,本文中又称”客户端”(client),即上一节例子中的”云冲印”。 HTTP service:HTTP服务提供商,本文中简称”服务提供商”,即上一节例子中的Google。 Resource Owner:资源所有者,本文中又称”用户”(user)。 User Agent:用户代理,本文中就是指浏览器。 Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。 Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。 知道了上面这些名词,就不难理解,OAuth的作用就是让”客户端”安全可控地获取”用户”的授权,与”服务商提供商”进行互动。 OAuth的思路OAuth在”客户端”与”服务提供商”之间,设置了一个授权层(authorization layer)。”客户端”不能直接登录”服务提供商”,只能登录授权层,以此将用户与客户端区分开来。”客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。 “客户端”登录授权层以后,”服务提供商”根据令牌的权限范围和有效期,向”客户端”开放用户储存的资料。 运行流程OAuth 2.0的运行流程如下图,摘自RFC 6749。 OAuth运行流程 用户打开客户端以后,客户端要求用户给予授权。 用户同意给予客户端授权。 客户端使用上一步获得的授权,向认证服务器申请令牌。 认证服务器对客户端进行认证以后,确认无误,同意发放令牌。 客户端使用令牌,向资源服务器申请获取资源。 资源服务器确认令牌无误,同意向客户端开放资源。 不难看出来,上面六个步骤之中,B是关键,即用户怎样才能给于客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。 下面一一讲解客户端获取授权的四种模式。 客户端的授权模式客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。 授权码模式(authorization code) 简化模式(implicit) 密码模式(resource owner password credentials) 客户端模式(client credentials) 授权码模式授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与”服务提供商”的认证服务器进行互动。 授权码模式 它的步骤如下: 用户访问客户端,后者将前者导向认证服务器。 用户选择是否给予客户端授权。 假设用户给予授权,认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个授权码。 客户端收到授权码,附上早先的”重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。 认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。 下面是上面这些步骤所需要的参数。 1步骤中,客户端申请认证的URI,包含以下参数: 12345response_type:表示授权类型,必选项,此处的值固定为"code"client_id:表示客户端的ID,必选项redirect_uri:表示重定向URI,可选项scope:表示申请的权限范围,可选项state:表示 客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。 下面是一个例子。 123GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1Host: server.example.com 3步骤中,服务器回应客户端的URI,包含以下参数: code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。下面是一个例子。 123HTTP/1.1 302 FoundLocation: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA &state=xyz 4步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数: grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。code:表示上一步获得的授权码,必选项。redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。client_id:表示客户端ID,必选项。下面是一个例子。 1234567POST /token HTTP/1.1Host: server.example.comAuthorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedgrant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 5步骤中,认证服务器发送的HTTP回复,包含以下参数: 12345access_token:表示访问令牌,必选项。token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。 下面是一个例子。 123456789101112HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" } 从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。 简化模式简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了”授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。 简化模式 它的步骤如下: 客户端将用户导向认证服务器。 用户决定是否给于客户端授权。 假设用户给予授权,认证服务器将用户导向客户端指定的”重定向URI”,并在URI的Hash部分包含了访问令牌。 浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。 资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。 浏览器执行上一步获得的脚本,提取出令牌。 浏览器将令牌发给客户端。 下面是上面这些步骤所需要的参数。 1步骤中,客户端发出的HTTP请求,包含以下参数: 12345response_type:表示授权类型,此处的值固定为"token",必选项。client_id:表示客户端的ID,必选项。redirect_uri:表示重定向的URI,可选项。scope:表示权限范围,可选项。state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。 下面是一个例子。 123GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1Host: server.example.com 3步骤中,认证服务器回应客户端的URI,包含以下参数: 12345access_token:表示访问令牌,必选项。token_type:表示令牌类型,该值大小写不敏感,必选项。expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。 下面是一个例子。 123HTTP/1.1 302 Found Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA &state=xyz&token_type=example&expires_in=3600 在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。 根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。 密码模式密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向”服务商提供商”索要授权。 在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。 密码模式 它的步骤如下: 用户向客户端提供用户名和密码。 客户端将用户名和密码发给认证服务器,向后者请求令牌。 认证服务器确认无误后,向客户端提供访问令牌。 2步骤中,客户端发出的HTTP请求,包含以下参数: 1234grant_type:表示授权类型,此处的值固定为"password",必选项。username:表示用户名,必选项。password:表示用户的密码,必选项。scope:表示权限范围,可选项。 下面是一个例子。 123456POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w 3步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。 123456789101112HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" } 上面代码中,各个参数的含义参见《授权码模式》一节。 整个过程中,客户端不得保存用户的密码。 客户端模式客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向”服务提供商”进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求”服务提供商”提供服务,其实不存在授权问题。 客户端模式 它的步骤如下: 客户端向认证服务器进行身份认证,并要求一个访问令牌。 认证服务器确认无误后,向客户端提供访问令牌。 1步骤中,客户端发出的HTTP请求,包含以下参数: granttype:表示授权类型,此处的值固定为”clientcredentials”,必选项。scope:表示权限范围,可选项。 123456POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials 认证服务器必须以某种方式,验证客户端身份。 2步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。 1234567891011HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "example_parameter":"example_value" } 上面代码中,各个参数的含义参见《授权码模式》一节。 更新令牌如果用户访问的时候,客户端的”访问令牌”已经过期,则需要使用”更新令牌”申请一个新的访问令牌。 客户端发出更新令牌的HTTP请求,包含以下参数: 123granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。refresh_token:表示早前收到的更新令牌,必选项。scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。 下面是一个例子。 123456POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA (完) 原文转载地址: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"OAuth","slug":"编程/OAuth","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/OAuth/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"spring boot中的banner.txt","slug":"Spring-Boot中的banner-txt","date":"2018-09-25T11:19:25.000Z","updated":"2020-12-05T08:55:25.561Z","comments":true,"path":"2018/09/25/Spring-Boot中的banner-txt/","link":"","permalink":"http://xiaodongzi.cn/2018/09/25/Spring-Boot%E4%B8%AD%E7%9A%84banner-txt/","excerpt":"","text":"关于banneerbanner是spring boot 应用启动时打印在控制台的彩蛋信息,默认是这样的 1234567. ____ _ __ _ _ /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\ \\\\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.4.3.RELEASE) DIY想要修改这个文本的话,只需要在resources下新建banner.txt即可。这里可以自定义banner: http://patorjk.com/software/taag 看这里闲来无事收集了一些有趣的注释,各式各样的都有,程序员真是一群有趣的人,喜欢哪一款拿走不谢,还可以用到bannner文件中 第一款:佛祖保佑,永无BUG123456789101112131415161718192021// _ooOoo_// o8888888o// 88" . "88// (| -_- |)// O\\ = /O// ____/`---'\\____// . ' \\\\| |// `.// / \\\\||| : |||// \\// / _||||| -:- |||||- \\// | | \\\\\\ - /// | |// | \\_| ''\\---/'' | |// \\ .-\\__ `-` ___/-. /// ___`. .' /--.--\\ `. . __// ."" '< `.___\\_<|>_/___.' >'"".// | | : `- \\`.;`\\ _ /`;.`/ - ` : | |// \\ \\ `-. \\_ __\\ /__ _/ .-` / /// ======`-.____`-.___\\_____/___.-`____.-'======// `=---='//// .............................................// 佛祖保佑 永无BUG 第二款:神兽护体,永无BUG12345678910111213141516171819202122232425262728293031323334353637383940// ┏┓ ┏┓// ┏┛┻━━━┛┻┓// ┃ ┃// ┃ ━ ┃// ┃ ┳┛ ┗┳ ┃// ┃ ┃// ┃ ┻ ┃// ┃ ┃// ┗━┓ ┏━┛// ┃ ┃ Code is far away from bug with the animal protecting// ┃ ┃ 神兽保护,永无BUG!// ┃ ┗━━━┓// ┃ ┣┓// ┃ ┏┛// ┗┓┓┏━┳┓┏┛// ┃┫┫ ┃┫┫// ┗┻┛ ┗┻┛/** * ┏┓ ┏┓+ + * ┏┛┻━━━┛┻┓ + + * ┃ ┃ * ┃ ━ ┃ ++ + + + * ████━████ ┃+ * ┃ ┃ + * ┃ ┻ ┃ * ┃ ┃ + + * ┗━┓ ┏━┛ * ┃ ┃ * ┃ ┃ + + + + * ┃ ┃ Code is far away from bug with the animal protecting * ┃ ┃ + 神兽保佑,永无bug * ┃ ┃ * ┃ ┃ + * ┃ ┗━━━┓ + + * ┃ ┣┓ * ┃ ┏┛ * ┗┓┓┏━┳┓┏┛ + + + + * ┃┫┫ ┃┫┫ * ┗┻┛ ┗┻┛+ + + + */ 第三款:来首程序员打油诗,笑123456789101112131415161718192021/** * 江城子 . 程序员之歌 * * 十年生死两茫茫,写程序,到天亮。 * 千行代码,Bug何处藏。 * 纵使上线又怎样,朝令改,夕断肠。 * * 领导每天新想法,天天改,日日忙。 * 相顾无言,惟有泪千行。 * 每晚灯火阑珊处,夜难寐,加班狂。*//** * 写字楼里写字间,写字间里程序员; * 程序人员写程序,又拿程序换酒钱。 * 酒醒只在网上坐,酒醉还来网下眠; * 酒醉酒醒日复日,网上网下年复年。 * 但愿老死电脑间,不愿鞠躬老板前; * 奔驰宝马贵者趣,公交自行程序员。 * 别人笑我忒疯癫,我笑自己命太贱; * 不见满街漂亮妹,哪个归得程序员? */ 第四款:无尽诱惑12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849//// .::::.// .::::::::.// :::::::::::// ..:::::::::::'// '::::::::::::'// .::::::::::// '::::::::::::::..// ..::::::::::::.// ``::::::::::::::::// ::::``:::::::::' .:::.// ::::' ':::::' .::::::::.// .::::' :::: .:::::::'::::.// .:::' ::::: .:::::::::' ':::::.// .::' :::::.:::::::::' ':::::.// .::' ::::::::::::::' ``::::.// ...::: ::::::::::::' ``::.// ```` ':. ':::::::::' ::::..// '.:::::' ':'````../** * _.._ ,------------. * ,' `. ( We want you! ) * / __) __` \\ `-,----------' * ( (`-`(-') ) _.-' * /) \\ = / ( * /' |--' . \\ * ( ,---| `-.)__` * )( `-.,--' _`-. * '/,' ( Uu", * (_ , `/,-' ) * `.__, : `-'/ /`--' * | `--' | * ` `-._ / * \\ ( * /\\ . \\. * / |` \\ ,-\\ * / \\| .) / \\ * ( ,'|\\ ,' : * | \\,`.`--"/ } * `,' \\ |,' / * / "-._ `-/ | * "-. "-.,'| ; * / _/["---'""] * : / |"- ' * ' | / * ` | */ 第五款:单身狗专用1234567891011121314151617181920212223242526272829303132333435<!-- :: :;J7, :, ::;7: ,ivYi, , ;LLLFS: :iv7Yi :7ri;j5PL ,:ivYLvr ,ivrrirrY2X, :;[email protected]: :ivu@kexianli. :iL7::,:::iiirii:ii;::::,,irvF7rvvLujL7ur ri::,:,::i:iiiiiii:i:irrv177JX7rYXqZEkvv17 ;i:, , ::::iirrririi:i:::iiir2XXvii;L8OGJr71i :,, ,,: ,::[email protected]:i:::j1jri7ZBOS7ivv, ,::, ::rv77iiiriii:iii:i::,[email protected] ,, ,, ,:ir7ir::,:::i;ir:::i:i::rSGGYri712: ::: ,v7r:: ::rrv77:, ,, ,:i7rrii:::::, ir7ri7Lri , 2OBBOi,iiir;r:: ,irriiii::,, ,iv7Luur: ,, i78MBBi,:,:::,:, :7FSL: ,iriii:::i::,,:rLqXv:: : iuMMP: :,:::,:ii;2GY7OBB0viiii:i:iii:i:::iJqL;:: , ::::i ,,,,, ::LuBBu BBBBBErii:i:i:i:i:i:i:r77ii , : , ,,:::rruBZ1MBBqi, :,,,:::,::::::iiriri: , ,,,,::::i: @arqiao. ,:,, ,:::ii;i7: :, rjujLYLi ,,:::::,:::::::::,, ,:i,:,,,,,::i:iii :: BBBBBBBBB0, ,,::: , ,:::::: , ,,,, ,,::::::: i, , ,8BMMBBBBBBi ,,:,, ,,, , , , , , :,::ii::i:: : iZMOMOMBBM2::::::::::,,,, ,,,,,,:,,,::::i:irr:i:::, i ,,:;u0MBMOG1L:::i:::::: ,,,::, ,,, ::::::i:i:iirii:i:i: : ,iuUuuXUkFu7i:iii:i:::, :,:,: ::::::::i:i:::::iirr7iiri:: : :[email protected]:::::, ,:ii:::::::i:::::i::,::::iirrriiiri::, : 5BMBBBBBBSr:,::rv2kuii:::iii::,:i:,, , ,,:,:i@petermu., , :r50EZ8MBBBBGOBBBZP7::::i::,:::::,: :,:,::i;rrririiii:: :jujYY7LS0ujJL7r::,::i::,::::::::::::::iirirrrrrrr:ii: ,: :@kevensun.:,:,,,::::i:i:::::,,::::::iir;ii;7v77;ii;i, ,,, ,,:,::::::i:iiiii:i::::,, ::::[email protected];7:i, , , ,,,:,,::::::::iiiiiiiiii:,:,:::::::::iiir;ri7vL77rrirri:: :,, , ::::::::i:::i:::i:i::,,,,,:,::i:i:::iir;@Secbone.ii:::--> 第六款:骷髅头123456789101112131415161718192021222324/** ************************************************************** * * * .=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-. * * | ______ | * * | .-" "-. | * * | / \\ | * * | _ | | _ | * * | ( \\ |, .-. .-. ,| / ) | * * | > "=._ | )(__/ \\__)( | _.=" < | * * | (_/"=._"=._ |/ /\\ \\| _.="_.="\\_) | * * | "=._"(_ ^^ _)"_.=" | * * | "=\\__|IIIIII|__/=" | * * | _.="| \\IIIIII/ |"=._ | * * | _ _.="_.="\\ /"=._"=._ _ | * * | ( \\_.="_.=" `--------` "=._"=._/ ) | * * | > _.=" "=._ < | * * | (_/ \\_) | * * | | * * '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=' * * * * LASCIATE OGNI SPERANZA, VOI CH'ENTRATE * ************************************************************** */ 第七款:标准键盘12345678910111213141516/** * ┌───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐ * │Esc│ │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│ ┌┐ ┌┐ ┌┐ * └───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘ └┘ └┘ └┘ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐ * │~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤ * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \\ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │ │ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │ * │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter │ │ 4 │ 5 │ 6 │ │ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ ┌───┐ ├───┼───┼───┼───┤ * │ Shift │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│ Shift │ │ ↑ │ │ 1 │ 2 │ 3 │ │ * ├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││ * │ Ctrl│ │Alt │ Space │ Alt│ │ │Ctrl│ │ ← │ ↓ │ → │ │ 0 │ . │←─┘│ * └─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘ */ 第八款:顶123456789101112131415/** * 頂頂頂頂頂頂頂頂頂 頂頂頂頂頂頂頂頂頂 * 頂頂頂頂頂頂頂 頂頂 * 頂頂 頂頂頂頂頂頂頂頂頂頂頂 * 頂頂 頂頂頂頂頂頂頂頂頂頂頂 * 頂頂 頂頂 頂頂 * 頂頂 頂頂 頂頂頂 頂頂 * 頂頂 頂頂 頂頂頂 頂頂 * 頂頂 頂頂 頂頂頂 頂頂 * 頂頂 頂頂 頂頂頂 頂頂 * 頂頂 頂頂頂 * 頂頂 頂頂 頂頂 頂頂 * 頂頂頂頂 頂頂頂頂頂 頂頂頂頂頂 * 頂頂頂頂 頂頂頂頂 頂頂頂頂 */ 还有一些其他有趣搞怪的注释1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556/** * _ooOoo_ * o8888888o * 88" . "88 * (| -_- |) * O\\ = /O * ___/`---'\\____ * . ' \\\\| |// `. * / \\\\||| : |||// \\ * / _||||| -:- |||||- \\ * | | \\\\\\ - /// | | * | \\_| ''\\---/'' | | * \\ .-\\__ `-` ___/-. / * ___`. .' /--.--\\ `. . __ * ."" '< `.___\\_<|>_/___.' >'"". * | | : `- \\`.;`\\ _ /`;.`/ - ` : | | * \\ \\ `-. \\_ __\\ /__ _/ .-` / / * ======`-.____`-.___\\_____/___.-`____.-'====== * `=---=' * ............................................. * 佛曰:bug泛滥,我已瘫痪! *//** * ,s555SB@@& * :9H####@@@@@Xi * 1@@@@@@@@@@@@@@8 * ,8@@@@@@@@@B@@@@@@8 * :B@@@@X3hi8Bs;B@@@@@Ah, * ,8i r@@@B: 1S ,M@@@@@@#8; * 1AB35.i: X@@8 . SGhr ,A@@@@@@@@S * 1@h31MX8 18Hhh3i .i3r ,A@@@@@@@@@5 * ;@&i,58r5 rGSS: :B@@@@@@@@@@A * 1#i . 9i hX. .: .5@@@@@@@@@@@1 * sG1, ,G53s. 9#Xi;hS5 3B@@@@@@@B1 * .h8h.,A@@@MXSs, #@H1: 3ssSSX@1 * s ,@@@@@@@@@@@@Xhi, r#@@X1s9M8 .GA981 * ,. rS8H#@@@@@@@@@@#HG51;. .h31i;9@r .8@@@@BS;i; * .19AXXXAB@@@@@@@@@@@@@@#MHXG893hrX#XGGXM@@@@@@@@@@MS * s@@MM@@@hsX#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&, * :GB@#3G@@Brs ,1GM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B, * .hM@@@#@@#MX 51 r;iSGAM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@8 * :3B@@@@@@@@@@@&9@h :Gs .;sSXH@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@: * s&HA#@@@@@@@@@@@@@@M89A;.8S. ,r3@@@@@@@@@@@@@@@@@@@@@@@@@@@r * ,13B@@@@@@@@@@@@@@@@@@@5 5B3 ;. ;@@@@@@@@@@@@@@@@@@@@@@@@@@@i * 5#@@#&@@@@@@@@@@@@@@@@@@9 .39: ;@@@@@@@@@@@@@@@@@@@@@@@@@@@; * 9@@@X:MM@@@@@@@@@@@@@@@#; ;31. H@@@@@@@@@@@@@@@@@@@@@@@@@@: * SH#@B9.rM@@@@@@@@@@@@@B :. 3@@@@@@@@@@@@@@@@@@@@@@@@@@5 * ,:. 9@@@@@@@@@@@#HB5 .M@@@@@@@@@@@@@@@@@@@@@@@@@B * ,ssirhSM@&1;i19911i,. s@@@@@@@@@@@@@@@@@@@@@@@@@@S * ,,,rHAri1h1rh&@#353Sh: 8@@@@@@@@@@@@@@@@@@@@@@@@@#: * .A3hH@#5S553&@@#h i:i9S #@@@@@@@@@@@@@@@@@@@@@@@@@A. * * * */ 注意什么?上面这些都不能满足你,想要找更多的ascii图在这里 : http://www.asciiworld.com/","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"spring","slug":"编程/spring","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/spring/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"markdown编辑器:Haroopad","slug":"markdown编辑器-Haroopad","date":"2018-09-02T10:19:53.000Z","updated":"2020-12-07T05:38:03.940Z","comments":true,"path":"2018/09/02/markdown编辑器-Haroopad/","link":"","permalink":"http://xiaodongzi.cn/2018/09/02/markdown%E7%BC%96%E8%BE%91%E5%99%A8-Haroopad/","excerpt":"","text":"haroopad经常写Markdown 文件,需要一款趁手的“兵器”,用的的编辑器很多: StackEdit、EpicEditor、Markable、Dillinger、Markdown Pad等。但都或多或少有点不舒服,尤其最近用Markdown在预览界面一直出不来,果断卸载,这里推荐一款很简单安装和操作简单的markdown编辑器: haroopad 。 操作界面: 功能:可以快捷插入标题、图标、超链接等等,而且很方便的切换主题。你值得拥有! 官网地址:http://http://pad.haroopress.com/ 注意事项因为这款软件比较小众,所以坐着应该很久没有维护了,官网放出的下载连接是v0.13.1 , 但是这款软件有bug ,中文不现实的问题,如图: 所以请下载v0.13 之前的版本,下面是下载地址: https://bitbucket.org/rhiokim/haroopad-download/downloads/?tab=downloads","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"IDE","slug":"编程/IDE","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/IDE/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"踩坑:python base64","slug":"踩坑-python-base64","date":"2018-04-11T13:46:08.000Z","updated":"2020-12-05T08:55:25.560Z","comments":true,"path":"2018/04/11/踩坑-python-base64/","link":"","permalink":"http://xiaodongzi.cn/2018/04/11/%E8%B8%A9%E5%9D%91-python-base64/","excerpt":"","text":"需求读取文本内容,对字符串进行base64加密 1234>>> str = 'aaaaaaaaaaaaaaaaaaa\\nbbbbbbbbbbbbbbbbbbbbbbbbbbb\\ncccccccccccccccccccccccccc'>>> encodeStr = base64.encodestring(str)>>> encodeStr 'YWFhYWFhYWFhYWFhYWFhYWFhYQpiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmIKY2NjY2NjY2Nj\\nY2NjY2NjY2NjY2NjY2NjY2M=\\n' 使用到了 base64 模块的 base64.encodestring() 采坑返回的字符串默认结尾带”\\n”,而且产生的base64编码字符串每76个字符就会用”\\n”隔开 解决使用replace() 替换吊所有的\\n base64.ecodestring每76字符就换行,这个是mime协议的规定,用于email发送,感兴趣的话自己去了解一下mime协议","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Python","slug":"编程/Python","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Python/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"解决npm安装速度慢的问题","slug":"解决npm安装速度慢的问题","date":"2017-11-30T11:42:34.000Z","updated":"2020-12-05T08:55:25.557Z","comments":true,"path":"2017/11/30/解决npm安装速度慢的问题/","link":"","permalink":"http://xiaodongzi.cn/2017/11/30/%E8%A7%A3%E5%86%B3npm%E5%AE%89%E8%A3%85%E9%80%9F%E5%BA%A6%E6%85%A2%E7%9A%84%E9%97%AE%E9%A2%98/","excerpt":"","text":"问题不知道各位是否遇到这种情况,使用NPM(Node.js包管理工具)安装依赖时速度特别慢,为了安装Express,执行命令后两个多小时都没安装成功,最后只能取消安装,笔者20M带宽,应该不是我网络的原因,后来在网上找了好久才找到一种最佳解决办法,在安装时可以手动指定从哪个镜像服务器获取资源,我们可以使用阿里巴巴在国内的镜像服务器。 方法命令如下: 1npm install -gd express --registry=http://registry.npm.taobao.org 只需要使用–registry参数指定镜像服务器地址,为了避免每次安装都需要–registry参数,可以使用如下命令进行永久设置: 1npm config set registry http://registry.npm.taobao.org 换了国内镜像,安装速度就很快了,特写篇博客分享这种方法,希望对大家有帮助","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Node.js","slug":"编程/Node-js","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Node-js/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"cmd命令右键菜单","slug":"cmd命令右键菜单","date":"2017-11-26T10:40:07.000Z","updated":"2020-12-06T09:21:44.442Z","comments":true,"path":"2017/11/26/cmd命令右键菜单/","link":"","permalink":"http://xiaodongzi.cn/2017/11/26/cmd%E5%91%BD%E4%BB%A4%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95/","excerpt":"","text":"使用方法新建一个xx.reg,将下面的命令粘贴进去,直接双击运行即可 添加cmd12345678910111213141516171819Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\\*\\shell\\mycmd]@="在此处打开CMD"[HKEY_CLASSES_ROOT\\*\\shell\\mycmd\\command]@="cmd.exe /k pushd \\"%L\\\\..\\""[HKEY_CLASSES_ROOT\\Folder\\shell\\mycmd]@="在此处打开CMD"[HKEY_CLASSES_ROOT\\Folder\\shell\\mycmd\\command]@="cmd.exe /k pushd \\"%L\\""[HKEY_CLASSES_ROOT\\DesktopBackground\\shell\\mycmd]@="在此处打开CMD"[HKEY_CLASSES_ROOT\\DesktopBackground\\shell\\mycmd\\command]@="cmd.exe /k pushd \\"%V\\""[HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\mycmd]@="在此处打开CMD"[HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\mycmd\\command]@="cmd.exe /k pushd \\"%V\\"" 删除cmd123456Windows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\\*\\shell\\mycmd][-HKEY_CLASSES_ROOT\\Folder\\shell\\mycmd][-HKEY_CLASSES_ROOT\\DesktopBackground\\shell\\mycmd][-HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\mycmd]","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"其它","slug":"编程/其它","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E5%85%B6%E5%AE%83/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"精简JRE","slug":"精简JRE","date":"2016-07-18T12:34:23.000Z","updated":"2020-12-05T08:55:25.555Z","comments":true,"path":"2016/07/18/精简JRE/","link":"","permalink":"http://xiaodongzi.cn/2016/07/18/%E7%B2%BE%E7%AE%80JRE/","excerpt":"","text":"需求场景最近手头上的有个项目发布是以jar包来发布运行的,由于部署的服务器很多,不能保证每台机器上都安装同一版本的Java环境。 需要 发布包中内置jre,但是原始的jre太大,所以进行了手动的精简(这个精简包有可能会不能通用你们的项目,原因是不同的项目使用到jre中的class不同 ,精简包主要是将一些没有用到的class删除)。 下面我们看一下jre的目录结构: 123456789101112131415161718192021222324252627282930313233jre7 ├─bin │ ├─dtplugin │ ├─plugin2 │ └─server └─lib ├─amd64 ├─applet ├─cmm ├─deploy ├─ext ├─fonts ├─images │ └─cursors ├─management ├─security ├─servicetag └─zi ├─Africa ├─America │ ├─Argentina │ ├─Indiana │ ├─Kentucky │ └─North_Dakota ├─Antarctica ├─Asia ├─Atlantic ├─Australia ├─Etc ├─Europe ├─Indian ├─Pacific └─SystemV 瘦身jre bin目录下 我们要保留的 是 jvm 虚拟机的配置文件。 之后就是精简lib包, lib包中我们仅仅需要三个jar包:charsets.jar,resources.jar,rt.jar (32位的系统会多几个jar包)我们使用最核心的jar包是 rt.jar ,需要根据自己的需求删除其中没用的class文件。 最后附上,jre7 Linux和Windows ,32和 64 位 的精简包,希望可以解决你们的问题。 地址:https://pan.baidu.com/s/1c1RfxxY","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"zookeeper的断线重连实现","slug":"zookeeper的断线重连实现","date":"2016-06-18T02:31:48.000Z","updated":"2020-12-05T08:55:25.543Z","comments":true,"path":"2016/06/18/zookeeper的断线重连实现/","link":"","permalink":"http://xiaodongzi.cn/2016/06/18/zookeeper%E7%9A%84%E6%96%AD%E7%BA%BF%E9%87%8D%E8%BF%9E%E5%AE%9E%E7%8E%B0/","excerpt":"","text":"zookeeper简介ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。我们可以使用zookeeper做程序的健康监测(EPHEMERAL 临时节点)、公共配置文件、集群管理(leader 选举)等等。但是zookeeper并没有提供断线重连的功能,必须我们手动实现,这里使用 Curator来实现了zookeeper的断线重连功能,代码如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115import java.io.UnsupportedEncodingException;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.listen.ListenerContainer;import org.apache.curator.framework.state.ConnectionState;import org.apache.curator.framework.state.ConnectionStateListener;import org.apache.curator.retry.ExponentialBackoffRetry;import org.apache.zookeeper.CreateMode;/** * @ClassName: ZookeeperExcutor * @Description: zookeeper连接处理器 */public class ZookeeperExcutor { private CuratorFramework client; public ZookeeperExcutor(String zklist,int sessionTimeout,int connectTimeout){ client = CuratorFrameworkFactory.builder() .connectString(zklist).sessionTimeoutMs(sessionTimeout) .connectionTimeoutMs(connectTimeout) .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build(); client.start(); } public CuratorFramework getClient() { return client; } /** * @Title: createNodeAddListener * @Description: 添加node节点 * @param nodePath * @param nodeData 设定文件 * @return void 返回类型 */ public String createNode(String nodePath,String nodeData){ if(client!=null){ try { String nodeName=client.create().creatingParentsIfNeeded() .withMode(CreateMode.EPHEMERAL_SEQUENTIAL) .forPath(nodePath, nodeData.getBytes("UTF-8")); return nodeName; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } } return null; } /** * @Title: getListener * @Description: 为节点添加 connectState 监听器,实现断线重连,然后添加上节点 * @param nodePath 节点路径 * @param nodeData 节点数据 * @return void 返回类型 */ public ConnectionStateListener getListener(final String nodePath,final String nodeData){ if(null!=client){ ConnectionStateListener connectListener = new ConnectionStateListener() { @Override public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) { if (connectionState == ConnectionState.LOST) { while (true) { try { //手动重连 boolean flag=curatorFramework.getZookeeperClient().blockUntilConnectedOrTimedOut(); if (flag){ //重新添加节点 clearListener(); createNode(nodePath, nodeData); client.getConnectionStateListenable().addListener(getListener(nodePath, nodeData)); break; } } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }else if(connectionState==ConnectionState.RECONNECTED){ //重新连接成功 }else if(connectionState==ConnectionState.SUSPENDED){ //自动重连,自动新建 schedular的临时节点 } } }; return connectListener; } return null; } public void clearListener(){ ListenerContainer<ConnectionStateListener> list=(ListenerContainer<ConnectionStateListener>) client.getConnectionStateListenable(); list.clear(); } public void addListener(String nodePath,String nodeData){ client.getConnectionStateListenable().addListener(getListener(nodePath, nodeData)); } public static void main(String[] args) { ZookeeperExcutor zke=new ZookeeperExcutor("127.0.0.1:2181",10000, 10000); String nodeName=zke.createNode("/Test", "test"); if(null!=nodeName){ zke.addListener("/Test", "test"); } }} 关于curatorCurator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量,原生的zookeeper实现起来稍微麻烦一点。下面是Curator的maven配置: 123456789101112131415<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.4.2</version></dependency><dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-client</artifactId> <version>2.4.2</version></dependency><dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.4.2</version></dependency>","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Zookeeper","slug":"编程/Zookeeper","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Zookeeper/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"IDEA版本: Ultimate、Community、EAP","slug":"IDEA版本-Ultimate、Community、EAP","date":"2016-04-11T13:11:17.000Z","updated":"2020-12-05T08:55:25.526Z","comments":true,"path":"2016/04/11/IDEA版本-Ultimate、Community、EAP/","link":"","permalink":"http://xiaodongzi.cn/2016/04/11/IDEA%E7%89%88%E6%9C%AC-Ultimate%E3%80%81Community%E3%80%81EAP/","excerpt":"","text":"Community社区版,免费,但是功能有限制,Android Studio就是基于这个版本定制的。 1http://idea-intellij.com/intellij-community/ Ultimate终极版,收费,功能无限制。 1http://idea-intellij.com/intellij-ultimate/ EAP终极版的免费版,免费,功能无限制,但是每隔30天要重装一次。 1http://idea-intellij.com/intellij-eap/","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"IDE","slug":"编程/IDE","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/IDE/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"关于spring mvc请求乱码问题分析","slug":"关于spring-mvc请求乱码问题分析","date":"2015-04-26T11:46:07.000Z","updated":"2020-12-05T08:55:25.548Z","comments":true,"path":"2015/04/26/关于spring-mvc请求乱码问题分析/","link":"","permalink":"http://xiaodongzi.cn/2015/04/26/%E5%85%B3%E4%BA%8Espring-mvc%E8%AF%B7%E6%B1%82%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/","excerpt":"","text":"spring乱码spring mvc 在请求参数乱码的时候可以使用 CharacterEncodingFilter来做处理,配置如下: 12345678910111213141516<filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param></filter><filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping> 原理很简单,就是拦截所有/*的请求,并将request和response的编码设置为UTF-8,关键的源代码如下: 12345678910111213@Overrideprotected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) { request.setCharacterEncoding(this.encoding); if (this.forceEncoding) { response.setCharacterEncoding(this.encoding); } } filterChain.doFilter(request, response);} get请求但是这只能解决post的请求,对于get请求传递的参数,这种方法是不起作用的。最简单的办法就是修改tomcat的配置文件,新增配置项: useBodyEncodingForURI=”true” 1<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/> 原因1tomcat 默认按ISO-8859-1进行URL解码,如果请求方式为get,参数包含中文字符,则会出现乱码的问题,按ISO-8859-1进行URL解码,useBodyEncodingForURI的作用是根据响应该请求的页面的request.setCharacterEncoding参数对数据进行的重新编码,不同的页面可以有不同的重新编码的编码,默认:false 不启用,设置为 true,那么我们上面配置的filter就生效了。 其它方式tomcat还有一个URIEncoding的配置项,它的作用是对所有GET方式的请求的数据进行统一的重新编码,简单暴力,如果尝试过多次还未解决乱码问题,可以添加这样一个配置项: 1<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8"/>","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"hibernate插入mysql中文乱码问题","slug":"hibernate插入mysql中文乱码问题","date":"2014-08-26T01:41:23.000Z","updated":"2020-12-05T08:55:25.535Z","comments":true,"path":"2014/08/26/hibernate插入mysql中文乱码问题/","link":"","permalink":"http://xiaodongzi.cn/2014/08/26/hibernate%E6%8F%92%E5%85%A5mysql%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/","excerpt":"","text":"mysql配置问题首先需要修改mysql数据库的配置文件my.ini,此文件放在mysql根目录下。在此文件下查找default-character-set属性,并将其值更改为utf8(注意:不是utf-8,也要注意大小写),这里需要将default-character-set属性全部属性的值修改为utf8。示例: 1default-character-set= utf8 提示:default-character-set属性有两个,一个在[mysql]下面,另外一个在[mysqld]下面。 sql问题同时创建hibernate数据库时需要显示设置数据库的编码方式为utf8。示例: 1create database daycode default charset=utf8; hibernate配置问题做完这两步还是不行,需要修改hibernate的配置文件hibernate.cfg.xml,在配置文件配置hibernate.connection.url属性。示例: 1234<property name="hibernate.connection.url"> <![CDATA[jdbc:mysql://localhost:3306/daycode?useUnicode=true&characterEncoding=utf8]]></property>设置这些之后乱码问题就解决了。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"入门(三)详解redis配置文件","slug":"入门-三-详解redis配置文件","date":"2014-06-08T05:15:34.000Z","updated":"2020-12-05T08:55:25.547Z","comments":true,"path":"2014/06/08/入门-三-详解redis配置文件/","link":"","permalink":"http://xiaodongzi.cn/2014/06/08/%E5%85%A5%E9%97%A8-%E4%B8%89-%E8%AF%A6%E8%A7%A3redis%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/","excerpt":"","text":"redis脚本简介在我们介绍redis的配置文件之前,我们先来说一下Redis安装完成后生成的几个可执行文件: redis-server 、redis-cli 、redis-benchmark 、redis-stat 、redis-check-dump、redis-check-aof : 1234567891011redis-server:Redis 服务器的daemon启动程序。redis-cli:Redis 命令行执行工具。当然,你也可以用telnet根据其纯文本协议来操作。redis-benchmark:Redis 性能检测工具,测试Redis在你的系统及你的配置下的读写性能。redis-stat:Redis 状态检测工具,可以检测 Redis 当前状态参数及延迟状况(高版本的Redis将没有这个脚本)。redis-check-dump:Redis dump 数据文件的修复工具。redis-check-aof:Redis aof 日志文件修复工具。 redis配置详解redis 的配置 定义在 redis.conf 文件中,下面我们介绍一下各个配置项的含义: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定 pidfile /var/run/redis.pid3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字 port 63794. 绑定的主机地址 bind 127.0.0.15.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能 timeout 3006. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose loglevel verbose7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null logfile stdout8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id databases 169. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 save <seconds> <changes> Redis默认配置文件中提供了三个条件: save 900 1 save 300 10 save 60 10000 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大 rdbcompression yes11. 指定本地数据库文件名,默认值为dump.rdb dbfilename dump.rdb12. 指定本地数据库存放目录 dir ./13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步 slaveof <masterip> <masterport>14. 当master服务设置了密码保护时,slav服务连接master的密码 masterauth <master-password>15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭 requirepass foobared16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息 maxclients 12817. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区 maxmemory <bytes>18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no appendonly no19. 指定更新日志文件名,默认为appendonly.aof appendfilename appendonly.aof20. 指定更新日志条件,共有3个可选值: no:表示等操作系统进行数据缓存同步到磁盘(快) always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) everysec:表示每秒同步一次(折衷,默认值) appendfsync everysec21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制) vm-enabled no22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享 vm-swap-file /tmp/redis.swap23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0 vm-max-memory 024. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值 vm-page-size 3225. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。 vm-pages 13421772826. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 vm-max-threads 427. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 glueoutputbuf yes28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 hash-max-zipmap-entries 64 hash-max-zipmap-value 51229. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍) activerehashing yes30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 include /path/to/local.conf<<<<<<< HEAD ======= >>>>>>> origin/master","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Redis","slug":"编程/Redis","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Redis/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"入门(二)Windows环境下redis的安装","slug":"入门-二-Windows环境下redis的安装","date":"2014-06-07T11:05:10.000Z","updated":"2020-12-07T05:41:13.939Z","comments":true,"path":"2014/06/07/入门-二-Windows环境下redis的安装/","link":"","permalink":"http://xiaodongzi.cn/2014/06/07/%E5%85%A5%E9%97%A8-%E4%BA%8C-Windows%E7%8E%AF%E5%A2%83%E4%B8%8Bredis%E7%9A%84%E5%AE%89%E8%A3%85/","excerpt":"","text":"说明之前介绍了Linux环境下Redis的安装,这次介绍一下Windows环境下Redis的安装,首先要讲的是,Redis官方只支持Linux,还好 Microsoft Open Tech group 开发了windows版本的Redis,github地址: https://github.com/MicrosoftArchive/redis 已经发布了很多个release版本,截至目前已经发布到了 v-3.2.100 。 官网截图: github截图: 下载与安装截至到目前最新版本是3.2.100 ,这里就使用这个版本来进行安装,下载 Redis-x64-3.2.100.msi ,双击开始安装: 安装完毕,我们看一下目录文件: redis启动1redis-server redis.windows.conf redis-cli的使用双击打开 redis-cli.exe,我们可以在命令行使用redis命令来进行操作:","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Redis","slug":"编程/Redis","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Redis/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"入门(一)Linux环境下redis的安装","slug":"入门-一-Linux环境下redis的安装","date":"2014-06-06T08:52:03.000Z","updated":"2020-12-07T05:41:52.097Z","comments":true,"path":"2014/06/06/入门-一-Linux环境下redis的安装/","link":"","permalink":"http://xiaodongzi.cn/2014/06/06/%E5%85%A5%E9%97%A8-%E4%B8%80-Linux%E7%8E%AF%E5%A2%83%E4%B8%8Bredis%E7%9A%84%E5%AE%89%E8%A3%85/","excerpt":"","text":"关于redis Redis最为一款开源的key-value存储系统,自推出到现在一直受到编程人员的喜爱。它支持存储多种value类型,String 、List 、Set 、Zset 、Hash。这些数据类型都支持push/pop、add/remove 及取交集、并集、差集等操作,这些操作都是原子性的,而且Redis还有各种不同的排序方式。 Redis 的数据都是缓存在内存中,这样做是为了保证效率,而且也支持数据的磁盘持久化,目前Redis 不仅可以部署Linux 而且Windows 同样可以进行部署。 下载与安装Redis的下载地址:http://download.redis.io/releases/ 版本很多,请自己下载想要安装的版本,这里 介绍 3.2.8的安装过程: 12345$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz$ tar xzf redis-3.2.8.tar.gz$ cd redis-3.2.8$ make$ make install 启动安装完成之后,进入src文件夹,你会发现脚本文件很多,为了操作方便我们将我们一会要使用到的脚本文件拷贝到一个目录同一进行管理: 123456789101112131415# 1. 创建两个文件夹 bin 、etc$ mkdir -p /usr/local/redis/bin$ mkdir -p /usr/local/redis/ect# 2. copy 脚本和配置文件$ mv /lamp/redis-3.2.8/redis.conf /usr/local/redis/etc$ cd /lamp/redis-3.2.8/src$ mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server /usr/local/redis/bin#3. 启动Redis$ cd /usr/local/redis/bin$ ./redis-server 下面是启动后的截图(redis 默认端口 6379): 问题分析如上图所示,redis已经成功启动,但是这里有三个WARNING 警告项,请不要忽略,下面介绍一下解决方法: 第一个错误大概是说somaxconn的值128设置过小,从/proc/sys/net/core/somaxconn这个路径也可大概知道这个值的设置是关于网络连接中某个最大值的限定设置,此值表示网络连接的队列大小,在配置文件redis.conf中的“tcp-backlog 511”就配置在高并发环境下的最大队列大小,此值受限于系统的somaxconn与tcp_max_syn_backlog这两个值,所以应该把这两个内核参数值调大,具体解决方法如下: 1234$ vim /etc/sysctl.conf$ net.core.somaxconn = 20480 #最大队列长度,应付突发的大并发连接请求,默认为128$ net.ipv4.tcp_max_syn_backlog = 20480 #半连接队列长度,此值受限于内存大小,默认为1024$ sysctl -p #使参数生效 报错解释 12345678910111213141516警告:过量使用内存设置为0!在低内存环境下,后台保存可能失败。为了修正这个问题,请在/etc/sysctl.conf 添加一项 'vm.overcommit_memory = 1' ,然后重启(或者运行命令'sysctl vm.overcommit_memory=1' )使其生效。vm.overcommit_memory不同的值说明:0 表示检查是否有足够的内存可用,如果是,允许分配;如果内存不够,拒绝该请求,并返回一个错误给应用程序。1 允许分配超出物理内存加上交换内存的请求2 内核总是返回trueredis的数据回写机制分为两种同步回写即SAVE命令。redis主进程直接写数据到磁盘。当数据量大时,这个命令将阻塞,响应时间长异步回写即BGSAVE命令。redis 主进程fork一个子进程,复制主进程的内存并通过子进程回写数据到磁盘。由于RDB文件写的时候fork一个子进程。相当于复制了一个内存镜像。当时系统的内存是4G,而redis占用了近3G的内存,因此肯定会报内存无法分配。如果 「vm.overcommit_memory」设置为0,在可用内存不足的情况下,就无法分配新的内存。如果 「vm.overcommit_memory」设置为1。 那么redis将使用交换内存。 解决方法: 1234$ vim /etc/sysctl.conf$ vm.overcommit_memory = 1 #末尾追加$ sysctl -p #参数生效注:使用交换内存并不是一个完美的方案。最好的办法是扩大物理内存。 关闭THP透明内存 1234567891011121314`Transparent Huge Pages (THP)`告警,这是一个关于透明内存巨页的话题。简单来说内存可管理的最小单位是page,一个page通常是4kb,那1M内存就会有256个page,CPU通过内置的内存管理单元管理page表记录。Huge Pages就是表示page的大小已超过4kb了,一般是2M到1G,它的出现主要是为了管理超大内存。个人理解上TB的内存。而THP就是管理Huge Pages的一个抽象层次,根据一些资料显示THP会导致内存锁影响性能,所以一般建议关闭此功能。"/sys/kernel/mm/transparent_hugepage/enabled”有三个值,如下:$ cat /sys/kernel/mm/transparent_hugepage/enabledalways [madvise] never##### always 尽量使用透明内存,扫描内存,有512个 4k页面可以整合,就整合成一个2M的页面# never 关闭,不使用透明内存# madvise 避免改变内存占用 解决方法: 123456# 临时解决$ echo never > /sys/kernel/mm/transparent_hugepage/enabled# 永久解决$ vim /etc/rc.local$ echo never > /sys/kernel/mm/transparent_hugepage/enabled #在开机脚本里追加此命令 redis的启动和暂停刚刚我们使用 ./redis-server 来启动了Redis ,但是Redis默认是前台启动的,后台启动Redis设置: 123456789101112131415161718# 修改配置文件,将 daemonize 设置为 yes$ cd /usr/local/redis/etc$ vim redis.conf$ daemonize yes# 调用启动脚本$ cd /usr/local/redis/bin$ ./redis-server /usr/local/redis/etc/redis.conf复制代码停止Redis 两种方式:$ cd /usr/local/redis/bin$ ./redis-cli shutdown# 或者关闭端口为 6379 的 redis-server$ ./redis-cli -p 6379 shutdown 到此我们对Redis有了初步的了解,后面我们将继续了解Redis的其他内容。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Redis","slug":"编程/Redis","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Redis/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"java对xml文件的操作","slug":"java对xml文件的操作","date":"2013-12-26T03:05:05.000Z","updated":"2020-12-05T08:55:25.537Z","comments":true,"path":"2013/12/26/java对xml文件的操作/","link":"","permalink":"http://xiaodongzi.cn/2013/12/26/java%E5%AF%B9xml%E6%96%87%E4%BB%B6%E7%9A%84%E6%93%8D%E4%BD%9C/","excerpt":"","text":"##介绍 利用org.w3c.dom来操作xml文件相当的简单,今天自己简单的练习了一下。 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.Writer;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.transform.OutputKeys;import javax.xml.transform.Result;import javax.xml.transform.Source;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerConfigurationException;import javax.xml.transform.TransformerException;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;public class DomXml { //读取 XML 文件 private static void readXMLFile(String path){ try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(path); // 获取到xml文件 // 下面开始读取 Element root = doc.getDocumentElement(); // 获取根元素 NodeList nodeList = root.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = (Node) nodeList.item(i); if (node instanceof Element){ Element ss = (Element) node; System.out.println(ss.getAttribute("username")); System.out.println(ss.getAttribute("password")); } } } catch (Exception e) { e.printStackTrace(); } } // 写入xml文件 public static void callWriteXmlFile(Document doc, Writer w, String encoding) { try { Source source = new DOMSource(doc); Result result = new StreamResult(w); Transformer xformer = TransformerFactory.newInstance() .newTransformer(); xformer.setOutputProperty(OutputKeys.ENCODING, encoding); xformer.transform(source, result); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } } private static void writeXMLFile(String path,List<User> list) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = dbf.newDocumentBuilder(); } catch (Exception e) { } Document doc = builder.newDocument(); System.out.println(list.size()); Element root = doc.createElement("osee"); doc.appendChild(root); // 将根元素添加到文档上 for (User u : list) { Element stu = doc.createElement("user"); stu.setAttribute("password", u.getPassword()); stu.setAttribute("username", u.getUsername()); root.appendChild(stu);// 添加属性 } try { FileOutputStream fos = new FileOutputStream(path); OutputStreamWriter outwriter = new OutputStreamWriter(fos); callWriteXmlFile(doc, outwriter, "utf-8"); outwriter.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } }}","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"使用jxl导出excel","slug":"使用jxl导出excel","date":"2013-12-12T06:36:13.000Z","updated":"2020-12-05T08:55:25.544Z","comments":true,"path":"2013/12/12/使用jxl导出excel/","link":"","permalink":"http://xiaodongzi.cn/2013/12/12/%E4%BD%BF%E7%94%A8jxl%E5%AF%BC%E5%87%BAexcel/","excerpt":"","text":"介绍简单的实现了,将查询结果导出为一个excel文件,这里 使用的传进来的Table 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687package com.osee.alarm.common;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import javax.swing.JTable;import javax.swing.table.JTableHeader;import javax.swing.table.TableModel;import jxl.Workbook;import jxl.format.Alignment;import jxl.format.Colour;import jxl.format.UnderlineStyle;import jxl.format.VerticalAlignment;import jxl.write.Label;import jxl.write.WritableCellFormat;import jxl.write.WritableFont;import jxl.write.WritableSheet;import jxl.write.WritableWorkbook;import jxl.write.WriteException;import jxl.write.biff.RowsExceededException;/** * 导出报警查询信息工具类 * @author fudongfang * */public class WriteExcel { /** * 将table中的数据 导出EXCEL * @param fileName * @return */ public static boolean writeXls(String fileName,JTable table) { boolean flag=false; WritableWorkbook wwb; FileOutputStream fos; try { fos = new FileOutputStream(fileName); wwb = Workbook.createWorkbook(fos); WritableSheet ws = wwb.createSheet("报警信息", 10); // 创建一个工作表 // 设置单元格的文字格式 WritableFont wf = new WritableFont(WritableFont.ARIAL, 12, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,Colour.BLUE); WritableCellFormat wcf = new WritableCellFormat(wf); wcf.setVerticalAlignment(VerticalAlignment.CENTRE); wcf.setAlignment(Alignment.CENTRE);// ws.setRowView(1, 500); // 填充数据的内容 ws.addCell(new Label(0, 0,"id", wcf)); ws.addCell(new Label(1, 0,"报警时间", wcf)); ws.addCell(new Label(2, 0,"设备", wcf)); ws.addCell(new Label(3, 0,"画面", wcf)); ws.addCell(new Label(4, 0,"故障", wcf)); ws.addCell(new Label(5, 0,"恢复时间", wcf)); ws.addCell(new Label(6, 0,"时长", wcf)); wcf = new WritableCellFormat(); TableModel model=table.getModel(); int columnCount=model.getColumnCount(); int rowCoutnt=model.getRowCount(); System.out.println(columnCount+":"+rowCoutnt); for(int i=0;i<rowCoutnt;i++){ for(int y=0;y<columnCount;y++){ String data=model.getValueAt(i,y).toString(); ws.addCell(new Label(y, i+1,data, wcf)); } } wwb.write(); wwb.close(); fos.close(); //导出成功 flag=true; } catch (Exception e) { //删除文件 File file=new File(fileName); file.delete(); return false; } return flag; }}","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"swing实现横向滚动窗口","slug":"swing实现横向滚动窗口","date":"2013-02-26T02:24:57.000Z","updated":"2020-12-07T05:39:03.412Z","comments":true,"path":"2013/02/26/swing实现横向滚动窗口/","link":"","permalink":"http://xiaodongzi.cn/2013/02/26/swing%E5%AE%9E%E7%8E%B0%E6%A8%AA%E5%90%91%E6%BB%9A%E5%8A%A8%E7%AA%97%E5%8F%A3/","excerpt":"","text":"介绍上网看视频的时候都看见过,一个视频滚动的窗体,通过点击按钮视频可以产生横向滚动效果,下面自己用swing写了一个类似的功能窗口。 效果图: 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.List;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.ScrollPaneConstants;import javax.swing.Timer;public class RollingFrame extends JFrame{ private static final int LIST_CELL_WIDTH = 120;// 每次滚一次的 刻度 private static int y = 0;// 滚动轴滑动的刻度 private JScrollPane sp; private static int index = 0; // 用来 计数,算的开始滚动到最后滚动的y private int currentResolution = 20; // 动画效果,50毫秒 private Timer timer1 = null, timer2 = null;// 两个timer 用于 操作两个监听事件 private int moveMinX;// 每次滚动的开始刻度 private int moveMaxX;// 每次滚动的结束刻度 private static int max;// 计算滚动面板的滚动轴的最大滑动刻度 private JPanel j,centerPanel,statusPanel,scollPanel; // 定义一个面板。用于将节点添加到面板上,并将j天津到滚动面板上 private JButton leftButton,rightButton; public RollingFrame() { // TODO Auto-generated constructor stub setBackground(Color.WHITE); initGui(); setTitle("横向滚动"); setBounds(100, 100, 365, 80); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } private void initGui() { // 初始化操作,将各个组件和节点添加到面板中 setLayout(new BorderLayout(0, 0)); add(getLeftButton(), BorderLayout.WEST); add(getRightButton(), BorderLayout.EAST); add(getSp(), BorderLayout.CENTER); } // 定义滚动面板,将j 和滚动条添加进去 private JScrollPane getSp(){ if(j==null){ j = new JPanel(); j.setBackground(Color.WHITE); j.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5)); for(int i=0;i<15;i++){ j.add(new JButton("按钮:"+i)); } sp = new JScrollPane(j, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); sp.setBackground(Color.WHITE); } return sp; } // 得到向左滑动按钮 public JButton getLeftButton() { if (leftButton == null) { leftButton = new JButton("<<"); leftButton.setBorder(null); leftButton.setContentAreaFilled(false); leftButton.setFocusPainted(false); } leftButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { max = sp.getHorizontalScrollBar().getMaximum() - sp.getHorizontalScrollBar().getModel().getExtent();// 得到滚动轴 // 最大滑动刻度 moveMinX = (index - 1) * LIST_CELL_WIDTH > max ? max : (index - 1) * LIST_CELL_WIDTH; moveMaxX = index * LIST_CELL_WIDTH > max ? max : index * LIST_CELL_WIDTH; if (moveMaxX > 0) { if (timer1 == null) { timer1 = new Timer(currentResolution, action1); } if (!timer1.isRunning()) { timer1.start(); } } } }); leftButton.setPreferredSize(new Dimension(48, 50)); return leftButton; } // 得到向右滑动按钮 public JButton getRightButton() { if (rightButton == null) { rightButton = new JButton(">>"); rightButton.setBorder(null); rightButton.setContentAreaFilled(false); rightButton.setFocusPainted(false); } rightButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { max = sp.getHorizontalScrollBar().getMaximum() - sp.getHorizontalScrollBar().getModel().getExtent();// 得到滚动轴 // 最大滑动刻度 moveMinX = index * LIST_CELL_WIDTH > 0 ? index * LIST_CELL_WIDTH : 0; moveMaxX = moveMinX + LIST_CELL_WIDTH > max ? max : moveMinX + LIST_CELL_WIDTH; if (moveMinX < max) { if (timer2 == null) { timer2 = new Timer(currentResolution, action2); } if (!timer2.isRunning()) { timer2.start(); } } } }); rightButton.setPreferredSize(new Dimension(48, 50)); return rightButton; } private ActionListener action1 = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { y -= 8; if (y <= moveMinX) { y = moveMinX; timer1.stop(); if (index > 0) { index--; } } sp.getHorizontalScrollBar().setValue(y); } }; private ActionListener action2 = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { y += 8; if (y >= moveMaxX) { y = moveMaxX; timer2.stop(); index++; } sp.getHorizontalScrollBar().setValue(y); } }; public static void main(String[] args) { new RollingFrame(); }}","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]},{"title":"java正则表达式","slug":"java正则表达式","date":"2011-04-12T08:22:38.000Z","updated":"2020-12-05T08:55:25.538Z","comments":true,"path":"2011/04/12/java正则表达式/","link":"","permalink":"http://xiaodongzi.cn/2011/04/12/java%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/","excerpt":"","text":"简介正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串 正则表 字符 说明 \\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,”n”匹配字符”n”。”\\n”匹配换行符。序列”\\”匹配”\\”,”(“匹配”(“。 ^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\\n”或”\\r”之后的位置匹配。 $ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\\n”或”\\r”之前的位置匹配。 * 零次或多次匹配前面的字符或子表达式。例如,zo 匹配”z”和”zoo”。 等效于 {0,}。 + 一次或多次匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于 {1,}。 ? 零次或一次匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于 {0,1}。 {n} n 是非负整数。正好匹配 n 次。例如,”o{2}”与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配。 {n,} n 是非负整数。至少匹配 n 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效于”o+”。”o{0,}”等效于”o*”。 {n,m} M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,”o{1,3}”匹配”fooooood”中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。 ? 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。 . 匹配除”\\r\\n”之外的任何单个字符。若要匹配包括”\\r\\n”在内的任意字符,请使用诸如”[\\s\\S]”之类的模式。 (pattern) 匹配 pattern 并捕获该匹配的子表达式。可以使用 9 属性从结果”匹配”集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用”(“或者”)”。 (?:pattern) 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符 ( (?=pattern) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?=95 (?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?!95 x y [xyz] 字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。 [^xyz] 反向字符集。匹配未包含的任何字符。例如,”[^abc]”匹配”plain”中”p”,”l”,”i”,”n”。 [a-z] 字符范围。匹配指定范围内的任何字符。例如,”[a-z]”匹配”a”到”z”范围内的任何小写字母。 [^a-z] 反向范围字符。匹配不在指定的范围内的任何字符。例如,”[^a-z]”匹配任何不在”a”到”z”范围内的任何字符。 \\b 匹配一个字边界,即字与空格间的位置。例如,”er\\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。 \\B 非字边界匹配。”er\\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。 \\cx 匹配 x 指示的控制字符。例如,\\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是”c”字符本身。 \\d 数字字符匹配。等效于 [0-9]。 \\D 非数字字符匹配。等效于 [^0-9]。 \\f 换页符匹配。等效于 \\x0c 和 \\cL。 \\n 换行符匹配。等效于 \\x0a 和 \\cJ。 \\r 匹配一个回车符。等效于 \\x0d 和 \\cM。 \\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \\f\\n\\r\\t\\v] 等效。 \\S 匹配任何非空白字符。与 [^ \\f\\n\\r\\t\\v] 等效。 \\t 制表符匹配。与 \\x09 和 \\cI 等效。 \\v 垂直制表符匹配。与 \\x0b 和 \\cK 等效。 \\w 匹配任何字类字符,包括下划线。与”[A-Za-z0-9_]”等效。 \\W 与任何非单词字符匹配。与”[^A-Za-z0-9_]”等效。 \\xn 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\\x41”匹配”A”。”\\x041”与”\\x04”&”1”等效。允许在正则表达式中使用 ASCII 代码。 \\num 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,”(.)\\1”匹配两个连续的相同字符。 \\n 标识一个八进制转义码或反向引用。如果 \\n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。 \\nm 标识一个八进制转义码或反向引用。如果 \\nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \\nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \\nm 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7) \\nml 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。 \\un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\\u00A9 匹配版权符号 (©)。","categories":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]}],"categories":[{"name":"storm","slug":"storm","permalink":"http://xiaodongzi.cn/categories/storm/"},{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/"},{"name":"kafka","slug":"编程/kafka","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/kafka/"},{"name":"正则表达式","slug":"编程/正则表达式","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"},{"name":"网络","slug":"编程/网络","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E7%BD%91%E7%BB%9C/"},{"name":"RabbitMQ","slug":"编程/RabbitMQ","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/RabbitMQ/"},{"name":"安全","slug":"编程/安全","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E5%AE%89%E5%85%A8/"},{"name":"OAuth","slug":"编程/OAuth","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/OAuth/"},{"name":"spring","slug":"编程/spring","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/spring/"},{"name":"IDE","slug":"编程/IDE","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/IDE/"},{"name":"Python","slug":"编程/Python","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Python/"},{"name":"Node.js","slug":"编程/Node-js","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Node-js/"},{"name":"其它","slug":"编程/其它","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/%E5%85%B6%E5%AE%83/"},{"name":"Java","slug":"编程/Java","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Java/"},{"name":"Zookeeper","slug":"编程/Zookeeper","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Zookeeper/"},{"name":"Redis","slug":"编程/Redis","permalink":"http://xiaodongzi.cn/categories/%E7%BC%96%E7%A8%8B/Redis/"}],"tags":[{"name":"编程","slug":"编程","permalink":"http://xiaodongzi.cn/tags/%E7%BC%96%E7%A8%8B/"}]}