呆萌的猿


  • 首页

  • 分类

  • 归档

  • 标签

  • 消遣

  • 书籍

  • 游戏

JavaScript 高级程序设计读书笔记 第 2 章 在HTML中使用 JavaScript

发表于 2018-12-27 | 分类于 读书笔记 | 阅读次数

第 2 章 在HTML中使用 JavaScript

2.1 <script> 元素

在页面插入 JavaScript 主要方法,就是使用 <script> 元素。 <script> 常用有下面几个属性:

  • async(html5) 该布尔属性指示浏览器是否在允许的情况下异步执行该脚本。该属性对于内联脚本无作用 (即没有src属性的脚本)。
  • defer 这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。如果缺少 src 属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用。对动态嵌入的脚本使用 async=false 来达到类似的效果。
  • src 这个属性定义引用外部脚本的URI,这可以用来代替直接在文档中嵌入脚本。指定了 src 属性的script元素标签内不应该再有嵌入的脚本
  • type 该属性定义script元素包含或src引用的脚本语言。属性的值为MIME类型; 支持的MIME类型包括text/javascript, text/ecmascript, application/javascript, 和application/ecmascript。如果没有定义这个属性,脚本会被视作JavaScript。如果type属性为 module,代码会被当作 JavaScript 模块 。请参见 ES6 In Depth: Modules

代码出现 </script> 会导致错误。

1
2
3
4
5
<script type="text/javascript*> 
function sayScript (){
alert("</script>")
}
</script>

因为按照解析嵌入式代码的规则,当浏览器遇到字符串</script>时,就会认为那是结束的 <script>标签。可以通过把这个字符串分隔为两部分可以解决这个问题。

1
2
3
4
5
<script type="text/javascript*> 
function sayScript (){
alert("<\/script>")
}
</script>

无论如何包含代码,只要不存在 defer和 async 属性,浏览器都会按照<script>元素在页面中 出现的先后顺序对它们依次进行解析。换句话说,在第一个 <script>元素包含的代码解析完成后,第 二个 <script>包含的代码才会被解析,然后才是第三个、第四个…..

2.1.1 标签的位置

如果把 <script> 标签放在 <head> 中,则必须等全部的 JavaScript 代码执行完成以后,才能呈现页面的内容。此时浏览器窗口将是一片空白。所以现代应用程序一般把 JavaScript 引用放在 <body> 元素中页面内容的后面。如下显示:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<!-- 这里放内容 -->
<script src="example1.js"></script>
</body>
</html>

2.1.2 延迟脚本 defer

如果 <script> 标签添加了 defer 属性,那么脚本会延迟到整个页面都解析完毕再运行。相当于告诉浏览器立刻下载,但是延迟执行。

1
2
<script defer="defer" src="example1.js">
<script defer="defer" src="example2.js">

在上面的例子中,脚本将延迟到浏览器遇到 </html> 标签后再按照它们出现的顺序依次执行。这两个脚本会先于 DOMContentLoaded 事件触发前执行。
注意 defer 只适用于外部脚本。

2.1.3 异步脚本

HTML5 之中为 <script> 元素定义了 async 属性。和 defer 属性类似,async 同样只适用于外部脚本。但是和 defer 不同的是标记为 async 的脚本不保证先后顺序执行。
就拿下面的例子来说,脚本2可能在脚本1之前执行。

1
2
<script async src="example1.js">
<script async src="example2.js">

异步脚本一定会在页面的 load 事件之前执行,但是可能在 DOMContentLoaded 事件触发之前或触发之后执行。

2.4 <noscript> 元素

包含在< noscript>元素中的内容只有在下列情况下才会显示出来

  • 浏览器不支持脚本;
  • 浏览器支持脚本,但脚本被禁用。
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<noscript>
<p>本页面需要浏览器支持(启用) JavaScript</p>
</noscript>
</body>
</html>

就像上面那个例子。这个页面会在脚本无效的情况下向用户展示一条消息。

2.5 小结

把 JavaScript 插入到 HTML 页面中要使用 <script> 元素。使用这个元素可以把 JavaScript 嵌入到 HTML 页面中,让脚本与标记混合在一起;也可以包含外部的JavaScript文件。而我们需要注意的地方有:

  • 在包含外部 JavaScript文件时,必须将src属性设置为指向相应文件的URL。而这个文件既可 以是与包含它的页面位于同一个服务器上的文件,也可以是其他任何域中的文件。
  • 所有 <script> 元素都会按照它们在页面中出现的先后顺序依次被解析。在不使用 defer 和 async 属性的情况下,只有在解析完前面 <script>元素中的代码之后,才会开始解析后面 <script> 元素中的代码
  • 由于浏览器会先解析完不使用 defer属性的 <script>元素中的代码,然后再解析后面的内容, 所以一般应该把 <script> 元素放在页面最后,即主要内容后面,</body>标签前面。
  • 使用 defer属性可以让脚本在文档完全呈现之后再执行延迟脚本总是按照指定它们的顺序执行。
  • 使用 async属性可以表示当前脚本不必等待其他脚本,也不必阻塞文档呈现。不能保证异步脚本按照它们在页面中出现的顺序执行。
    另外,使用< noscrip>元素可以指定在不支持脚本的浏览器中显示的替代内容。但在启用了脚本的情况下,浏览器不会显示< noscript>元素中的任何内容。

JavaScript 高级程序设计读书笔记 第 1 章 JavaScript 简介

发表于 2018-12-27 | 分类于 读书笔记 | 阅读次数

第 1 章 JavaScript 简介

完整的 Javascript 实现应该由三部分组成 ECMAScript DOM BOM。

1.2.1 ECMAScript

ECMAScript 和浏览器没有依赖关系,浏览器只是 ECMAScript 可能的宿主环境之一。宿主环境不仅提供基本的 ECMAScript 实现,同时也会提供该语言的扩展,以便语言与环境之间对接交互。而这些扩展——如 DOM,则利用 ECMAScript 的核心类型和语法提供更多具体功能。
ECMAScript 则大致规定了这门语言的下列组成部分。

  • 语法
  • 类型
  • 语句
  • 关键字
  • 保留字
  • 操作符
  • 对象

1.2.2 文档对象模型 (DOM)

1.2.2文档对象模型(DOM)
文档对象模型(DOM, Document Object Model )是针对XML但经过扩展用于HTML的 API。
利用 DOM API,开发人员就可以轻松自如地删除、添加、替换或修改任何节点。

1.2.3 浏览器对象模型(BOM)

BOM 是支持访问和操作浏览器窗口的浏览器对象模型(BOM, Browser Object Model) 的 API,开发人员使用BOM可以控制浏览器显示的页面以外的部分。但人们习惯上也把所有针对浏览器的 JavaScript扩展算作BOM的一部分。

1.3 JavaScript 版本

不同的浏览器支持不同的 JavaScript,有一些高级的 API 就无法在古老的浏览器中使用。

1.4 小结

JavaScript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成

  • ECMAScript,由ECMA-262定义,提供核心语言功能;
  • 文档对象模型(DOM),提供访问和操作网页内容的方法和接口;
  • 浏览器对象模型(BOM),提供与浏览器交互的方法和接口。

Leetcode 215 数组中的第K个最大元素

发表于 2018-03-28 | 分类于 LeetCode/LintCode 刷题 | 阅读次数

Leetcode 215 数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,它是数组有序排列后的第 k 个最大元素,而不是第 k 个不同元素。

例如,
给出 [3,2,1,5,6,4] 和 k = 2,返回 5。

注意事项:

你可以假设 k 总是有效的,1 ≤ k ≤ 数组的长度。

思路 1 堆

可以先取k个元素,放到一个数组中,然后把数组转换成最小堆。之后遍历剩下的全部元素,和最小堆的根进行比较。如果比根要大,则替换根,之后把数组重新转换成最小堆。遍历完成后,最小堆堆根即为第 k 大的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {

public static int findKthLargest(int[] nums, int k) {
int[] heap = new int[k];
//首先取k个元素
System.arraycopy(nums, 0, heap, 0, k);
//从倒数k个节点开始 调整数组成为最小堆
for (int i = k / 2 - 1; i >= 0; i--) {
adjest(heap, i);
}
//如果元素小于最小堆 跳过。
//如果元素大于最小堆 把元素放在堆顶 然后调整堆
for (int i = k; i < nums.length; i++) {
if (heap[0] < nums[i]) {
heap[0] = nums[i];
adjest(heap, 0);
}
}
//返回堆顶堆元素
return heap[0];
}


/**
* 调整最小堆
* @param heap 堆
* @param i 从哪个 index 开始
*/
private static void adjest(int[] heap, int i) {
int temp = heap[i];
int length = heap.length;
for (int k = i * 2 + 1; k < length; k = 2 * k + 1) {
if (k + 1 < length && heap[k + 1] < heap[k]) {
k++;
}
if (temp <= heap[k]) {
break;
} else {
heap[i] = heap[k];
i = k;
}
}
heap[i] = temp;
}
}

题目链接

Leetcode-cn
Leetcode

Elasticsearch 入门教程(1) 安装 Elasticsearch 与 Kibana

发表于 2018-03-26 | 阅读次数

本文基于版本 6.1.1

Elasticsearch 是基于 Lucene 的开源搜索引擎。封装了底层 Lucene 的接口并且提供了 REST API 的接口。开箱即用。

使用 docker 安装

用 docker-compose 部署最为方便。把下面的内容保存到 docker-compose.yaml 中,然后执行 docker-compose up -d 就可以启动容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
version: '2'
services:
elasticsearch:
image: registry.cn-hongkong.aliyuncs.com/yfd-ci/es-docker-image:v2018037
container_name: elasticsearch
hostname: elasticsearch
restart: always
networks:
- elk
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata1:/usr/share/elasticsearch/data
ports:
- 9200:9200
- 9300:9300
kibana:
image: registry.cn-hongkong.aliyuncs.com/yfd-ci/kibana-docker-image:v20180327-2
container_name: kibana
networks:
- elk
depends_on:
- elasticsearch
environment:
SERVER_NAME: kibana
ELASTICSEARCH_URL: http://elasticsearch:9200
ports:
- 5601:5601
volumes:
esdata1:
driver: local
networks:
elk:
driver: bridge

构建镜像的 Dockerfile 分别 如下

1
FROM docker.elastic.co/kibana/kibana-oss:6.1.1
1
2
3
4
5
6
FROM docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.1

RUN cd /usr/share/elasticsearch/ && \
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v6.1.1/elasticsearch-analysis-pinyin-6.1.1.zip && \
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.1.1/elasticsearch-analysis-ik-6.1.1.zip \
&& mv /usr/share/elasticsearch/plugins/analysis-ik/ /usr/share/elasticsearch/plugins/ik/

如果运行成功,那么 es 会在本地的9200端口运行。用 curl 请求9200端口,可以获取当前集群的名称,版本等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
curl localhost:9200
{
"name" : "OFyyM08",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "tEBFzeLWT5uuCas17Z0Waw",
"version" : {
"number" : "6.1.1",
"build_hash" : "bd92e7f",
"build_date" : "2017-12-17T20:23:25.338Z",
"build_snapshot" : false,
"lucene_version" : "7.1.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}

访问 localhost:5601 就可以看到 Kibana 的页面了

注意点

max virtual memory areas vm.maxmapcount [65530] is too low

如果执行失败 出现 max virtual memory areas vm.max*map*count [65530] is too low 的错误。需要执行下面的命令。

1
sudo sysctl -w vm.max_map_count=262144

Java Object 方法简析

发表于 2018-03-23 | 分类于 Java 基础 | 阅读次数

Java Object 方法简析

Object 类位于java.lang ,我们可以看到源码中写到 Every class has {@code Object} as a superclass. All objects 即 Object 类是所有类的父类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public final native Class<?> getClass();

public native int hashCode();
public boolean equals(Object obj);

protected native Object clone() throws CloneNotSupportedException;

public String toString();

public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
public final void wait() throws InterruptedException;

protected void finalize() throws Throwable { }

getClass方法

1
2
3
 * @return The {@code Class} object that represents the runtime
* class of this object.
public final native Class<?> getClass();

从源码中可以看到 getClass 是 final 方法,无法被继承。同时是 native 方法。即其他语言例如 C 与 C++ 实现的方法。结果为对象的运行时 Class 对象。

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package im.yfd.demo;
class A {
}

class B extends A {
}

class Test{
public static void main(String[] args) {
A a = new A();
A b = new B();
System.out.println(a.getClass());
System.out.println(b.getClass());
a = b;
System.out.println(a.getClass());
}
}

返回结果

1
2
3
class im.yfd.demo.A
class im.yfd.demo.B
class im.yfd.demo.B

hashCode 方法与 equals 方法

equals

equals主要用于判断两个对象是否相等。约定 equals 有下列几个性质。

当object object1 object2 均为非空时。

  • 自反性:object.equals(object) 永远为 true
  • 对称性:object1.equals(object) == object.equals(object1) 永远为 true
  • 传递性:object.equals(object1) 为 true且object1.equals(object2) 为 true 时,object.equals(object2) 为 true。
  • 一致性:当 object 与 object1 均未修改时候。object.equals(object1) 结果永远保持不变。
  • 对于非空对象 object。那个 object.equals(null) 永远返回 false。

Object类中的默认实现为比较两个地址是否相同。等价于 ==

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

hashCode

hashCode也是一个native方法。该方法返回对象的哈希码,通常用在哈希表中。例如常用的 HashMap。

对于hashCode,我们 应该 遵循如下规则:

  • 在一个应用程序执行期间,任何时间对同一个对象调用 hashCode 方法。都必须返回用一个整数。这个整数在两次对同一个应用程序的执行在不需要保持一致。
  • 如果两个对象通过 equals 比较相等,那么 hashCode 方法必须产生同样的结果。
  • 如果两个对象通过 equals 比较不相等,那么 hashCode 方法产生的结果 不需要 向灯。但是如果不同对象产生不同的结果。那么有助于提高哈希表的效率

当重写 equals 时候 必须也要重写 hashcode 。否则在 HashMap 中就会出错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Person {
Person(String name) {
this.name = name;
}
private String name;
@Override
public boolean equals(Object object) {
if (this == object) {
return false;
}
if (object == null || object.getClass() != this.getClass()) {
return false;
}
Person p = (Person) object;
if (p.name == null) {
return this.name == null;
}
return p.name.equals(this.name);
}
}


class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person a = new Person("name");
Person b = new Person("name");
Map<Person, String> map = new HashMap<>();
map.put(a, "a");
System.out.println(a.equals(b));
System.out.println(map.get(a));
System.out.println(map.get(b));
}
}

例如上面的代码的返回结果就是

1
2
3
true
a
null

因为 HashMap 会先根据 hashcode 来决定对象在哪个桶中。再在同一个桶中根据 equals 判断 key 是否相同。

clone方法

clone 会返回对象的拷贝。如果直接调用

1
2
3
4
5
6
class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Test test = new Test();
Test testClone = (Test) test.clone();
}
}

会报错 Exception in thread "main" java.lang.CloneNotSupportedException。

finalize方法

finalize 方法会在对象被回收时候调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Test {

String name;

@Override
public void finalize() {
System.out.println("GC: " + name);
}

public static void main(String[] args) throws CloneNotSupportedException {
Test test = new Test();
test.name = "1";
System.out.println("test 1");
System.gc();
test = new Test();
System.gc();
System.out.println("test 2");
}
}

例如上面的代码返回结果

1
2
3
test 1
test 2
GC: 1

阿里云折腾记

发表于 2017-09-25 | 分类于 技术与折腾 | 阅读次数

起源

博客挂在Github上不要钱,但是总感觉访问有些慢。而且有时候会想跑一些脚本和服务,就一直考虑过买一台服务器。在大学里对Linux用的不多,唯一一次就是在阿里云上买了一个学生主机,玩了几天以后感觉没什么用不会玩,就没有再续费了。前几天逛阿里云的时候,居然看到了一个叫云上浙江的活动。西湖区的公司,没用过阿里云的话可以免费领2000无任何限制的代金券。简直是天上掉了馅饼。因为我刚好有一个杭州的公司,所以就新注册了一个账户。中间虽然有一些小波折,但是最终还是成功领到了钱。千挑万选之下选了ECS香港 2核4G 1M 带宽 100G 硬盘。虽然带宽1M有点小,不过只需要1980就能买这个配置的服务器三年。还是非常划算的。更何况也不需要我自己出钱。

SSH相关设定

为了不用输入密码和安全考虑,肯定是要用SHH key登录,阿里云控制面板的云服务器 ECS-绑定密钥对-创建密钥,输入名字例如test就可以直接生成密钥对,生成完成以后会自动下载一个test.pem的私钥,然后选择之前已经买好的ECS。绑定之后不需要重启就可以利用这个私钥登录了。用阿里云的服务生成和绑定只要是和自己写的项目FastAirport 有关。

安装docker

假如我们服务的IP是aaa.bbb.ccc.ddd SSH的接口是1234

1
ssh root@aaa.bbb.ccc.ddd -i test.pem -p 1234

部署hexo

原先的博客是放在Github pages上的。分成了blog和GeorgeYuen.github.io,虽然这样不要钱,也比较方便,不过既然搬家到了自己的服务器上,那肯定是要折腾一下的。后来用 Daocloud 做了持续部署。

其他放在另外的文章里面说吧,一下子也说不完。

如何在自己电脑上搭建一个电子书网站

发表于 2017-09-04 | 分类于 技术与折腾 | 阅读次数

搭建了一个个人的电子书网站

作为一个松鼠党,从高中逛E-INK开始就收集各类电子书,这么多年下来也积攒了一大笔积蓄。下书入流水,看书如抽丝。那么这些书的管理就成了一个问题。最后选了半天还是决定用calibre来管理自己的电子书。

calibre虽然速度有些慢,不过应该是目前为止能找到的最好的电子书管理工具了。和kindle的结合也很好。考虑数据的备份,除了在自己的Mac上存放了书库以外,还利用Resilio Sync把书库存到了群晖上。这样就算是电脑被偷数据也不会丢了。不过calibre的数据库有一个缺点,他在电脑上储存文件的目录结构是/calibre/author/books

而且会把全部的汉字转换成拼音。直接用Mac上的calibre看的话挺方便的,但是远程用手机访问群晖的话看到的都是类似于拼音文件。找书很不方便。所以就想找一下有没有calibre的web版本。

搜了一下果然有人已经早好轮子了calibre-web 一个用Python写的一个Web app。

官方介绍是这样的:Calibre Web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database.

直接利用calibre的数据库,然后支持下载,上传,在线阅读,数据修改,发送到kindle。而且手机端和web端都支持,真是完美符合我的需求。不过要吐槽一点,这个源码居然不打tag,程序更新完全是靠git拉取来更新。真的是大开眼界。

既然调研好了,那么就开始搭建吧。

网站搭建

背景说明

  • 群晖216+Ⅱ
  • Calibre
  • Resilio
  • docker

其实上面啥都不需要,只需要一台能运行docker的设备就可以了。内存大约100m 不知道树莓派能不能撑得住。 Python的效率真低呀。

首先先是电脑上安装calibre,然后同步自己的书库到群晖。这一步网上教程太多,就不详细介绍了。

同步完之后,我们的群晖上就有了数据库。例如我的目录是 /Backup/书库 里面有一个数据库文件 metadata.db

数据库有了,就开始安装程序。程序安装很简单,只需要一个python环境就可以了。

1
2
3
4
5
6
# 1.下载源码
git clone https://github.com/janeczku/calibre-web/
# 2.利用pip安装依赖
pip install --target vendor -r requirements.txt
# 3.运行程序
python cps.py

执行命令以后你就把网站搭好了,访问http://localhost:8083就可以看到自己搭建的网站了。

不过妈妈说了,能用docker解决的问题都用docker解决。

Dockerfile如下。

1
2
3
4
5
6
7
8
9
10
11

FROM python:2.7.13
MAINTAINER FandiYuan <georgeyuan@diamondyuan.com>

RUN git clone https://github.com/janeczku/calibre-web/ && \
cd calibre-web && \
pip install --target vendor -r requirements.txt

EXPOSE 8083

CMD ["python","/calibre-web/cps.py"]

项目的主页有一个镜像了,但是我个人有点没看懂,而且镜像里面是不带项目本身的,在第一次启动镜像的时候会从git上面拉取最新的源码,然后重启。其实挺符合这个开源项目的风格的,利用git进行版本更新。写得其实比我好。有需要的小伙伴可以自己研究安装。

安装说明

说了半天废话,那么图文教大家如何安装吧。

  • 首先安装群晖的docker 点开注册表 双击选择阿里云。

    搜索calibre,找到我写好的的镜像后双击下载。因为在国内,所以挺快的。感谢阿里爸爸。

    ​

安装完双击启动容器


配置一下本地目录和装载目录。本地目录就是你电子说所在的位置。

如果你需要电子书编辑的功能,那么不要勾选只读。英文我只想浏览和下载,所以选择了只读。

设置完成以后点击确认 应用。你的个人服务器就布置好了。
举个例子
例如我群晖的路由访问页面是192.168.3.101:6001,那么192.168.3.101:8083就可以看到自己部署的网站了。

利用Daocloud完成Hexo的持续部署

发表于 2017-08-10 | 分类于 技术与折腾 | 阅读次数

本文不仅限于hexo,可以适用于任何项目。

因为买了阿里云的服务器,而且受不了Github的速度,就准备把自己的博客迁移到国内的网站。而且把网站放在docker里以后,无论在哪台服务器,只要安装了docker,都可以很快捷得部署自己的博客。之前先说一下

思路,一开始我是把blog的源码(不含node_modules)直接copy到hexo的镜像中,然后下载npm的模块,再执行generate。执行完以后把public目录下的文件全部复制到一个nginx的镜像下面。需要部署的时候,只需要拉取那个nginx镜像就可以了。

但是这样有一个缺点,每次更新博客,都要重新下载一遍node_modules。如果不换国内源的话,发布一次要等很久。于是就换了一个思路。因为博客的依赖基本上是不变的,package-lock.json与package.json基本上不更新,所以可以先把这两个文件复制到hexo里面,预先下载好,生成一个新的base镜像。每次发布的时候,都从这个镜像开始动手。只需要hexo g。然后就可以把public文件提取了。build速度从原来的7分钟提升到了40秒。等依赖或者插件更新的时候,可以手动更新一下base镜像。

思路有了,那就开始动手布置吧。详细文件可以看我的Github 希望大家喜欢的话可以star。

首先是base镜像,除非添加新的插件或者hexo更新,不然基本上不会替换。

1
2
3
4
5
6
7
FROM emitting/hexo
MAINTAINER FandiYuan <georgeyuan@diamondyuan.com>
ADD package-lock.json /temp/
ADD package.json /temp/
RUN cd /temp && \
npm install
CMD ["bash"]

构建镜像,主要基于base镜像是把博客源码复制进去,然后生成public文件。

1
2
3
4
5
6
FROM daocloud.io/diamondyuan/blog-base:latest
MAINTAINER FandiYuan <georgeyuan@diamondyuan.com>
ADD / /blog
RUN mv /temp/node_modules /blog/node_modules && \
hexo g
CMD ["bash"]

发布镜像 把博客的html文件复制到nginx镜像中。

如果是部署在github,那么可以把这个文件替换成一个有git的镜像,把代码提交到git中。

1
2
3
FROM nginx:stable-alpine
MAINTAINER FandiYuan <georgeyuan@diamondyuan.com>
copy /blog/public/ /usr/share/nginx/html/

本来这样就可以了,原本是准备自己造一套轮子的,但是后来实在是嫌麻烦,就直接用了daocloud的服务,反正也不要钱,还可以为自己服务器节约一些硬盘。如果用docker官方的hub,我不是很清楚提取文件和打包应该如何,可能需要自己在本机写一下脚本吧。其他的博客生成器使用思路都差不多,只需要改一下dockerfile的命令就好了。

窝在daocloud上建了两个项目。blog和blog-base。都关联了github。还有两个ymal文件,直接贴出来。

第一个是blog-base的流程,只有装新的插件而且打tag以后,才会触发这项目,更新base。

1
2
3
4
5
6
7
8
9
10
11
12
13
version: 3
stages:
- 构建阶段
默认构建任务:
label: release-image
stage: 构建阶段
job_type: image_build
only:
tags:
- .*
build_dir: /
cache: true
dockerfile_path: /Dockerfile/Dockerfile.base.build

第二个上blog项目,用了两个dockerfile。每次更新代码会先临时生成一个镜像,提取出public文件后复制到nginx的镜像中。这些操作都在daocloud的服务器上完成,不需要占用自己电脑的空间。我一个空的hexo博客+nginx大约是15mb。而一个node+hexo的镜像在700mb左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: 3
stages:
- build
lite-build:
stage: build
job_type: lite_image_build
only:
branches:
- ^master$
compile:
build_dir: /
dockerfile_path: /Dockerfile/Dockerfile.build
extract:
- /blog
package:
build_dir: /
dockerfile_path: /Dockerfile/Dockerfile.deploy

最后只需要拉取最终生成的镜像,就可以在任何电脑上布置自己的博客了。更新博客的话只需要往hexo/source/_posts 里添加一篇文件并且push到github,就会自动触发daocloud,构建一个新的博客镜像。基于这个镜像,窝在daocloud上发布了一个应用,并且设置为自动更新。每次有新的镜像出来就会自动拉取镜像到我的阿里云上,并且发布。

这个思路可以用在任何的项目上,比如我司的JAVA项目,就是把源码拷贝到一个gradle的镜像里,构建好以后提取jar出来,再放到一个只有jre的镜像中。可以缩小最终生成的docker镜像的大小。

为SpringBoot应用添加可以配置的拦截器

发表于 2017-07-26 | 阅读次数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@ConditionalOnExpression("${cache.response.enabled:false}")
public class FilterRegistrationBeanConfigration {
@Bean
public FilterRegistrationBean filterRegistrationBean() {
return new FilterRegistrationBean() {{
setFilter(new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletResponse responseToUse = new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, responseToUse);
((ContentCachingResponseWrapper) responseToUse).copyBodyToResponse();
}
});
}};
}
}
1
cache.response.enabled=true

git的各种常用操作

发表于 2017-06-23 | 阅读次数

远程分支删除后,本地依旧可以看到的解决方法

使用命令 git branch -a,可以看到很多本地和远程都删除了的分支。

使用命令 git remote show origin,可以查看remote地址,远程分支,还有本地分支与之相对应关系等信息。

使用命令 git remote prune origin,可以删除远程仓库已经不存在的分支。

Fix 线上bug的git流程

假如我们现在在develop分支开发,平时都是合并到dev。然后发布的时候合并到master发布。那么我们现在就有三个分支 dev develop master。这个时候线上出现了bug,需要紧急修复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git satash --先保存自己现在在写的代码
git checkout master
git checkout -b fix
--然后修改代码之后合并到master发布。
git commit
git push

--发布后先切到master拉取最新代码
git checkout master
git pull

--然后切回之前开发的develop分支,把修改的代码合并到develop
git checkout develop
git stash pop
git merge master
git checkout -d fix

--develop开发完成后合并到dev就可以完成一次开发流程
123
Diamond Yuan

Diamond Yuan

27 日志
6 分类
22 标签
© 2016 - 2018 Diamond Yuan