0%

最近比较空,就抽时间看了《Efffectice Java》这本书,虽然这本书的第二版和现在的Java版本有点老了,但是看了一遍后,感觉,其中的一些思想,平时写代码的时候需要注意的地方,还是讲的不错的。

用静态工厂方法代替构造器

对于Map的new,在Java的后面的版本中,已经修改了,不需要如书上说的创建一个newMap的静态工厂类,可以如下进行创建一个新的Map:

1
Map<Integer,String> map = new HashMap<>();

遇到多个构造器参数时要考虑用构建器

重叠构造器模式

这种模式就是利用重载,不断调用构造函数,生成需要的bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyClass{
//必要的参数
private final int one;
private final int two;
//可选的参数
private final int three;
private final int four;
public MyClass1(int one,int two){
this(one,two,0);
}
public MyClass(int one,int two,int three){
this(one,two,three,0);
}
public MyClass(int one,int two,int three,int four){
this.one=one;
this.two=two;
this.three=three;
this.four=four;
}
@Override
public String toString(){
return " one="+this.one+" two="+this.two+" three="+this.three+" four="+this.four;
}
}

从这代代码可以看出,这种写法有点复杂,个人觉得实际开发中,不会去使用

JavaB ean

使用创建对象,通过set来设置参数,这种也是在实际开发中,使用最多的。但是如果存在很多歌参数需要set,那就有点麻烦了,所以推荐builder模式。

1
user.setNation("China");

使用builder模式

在编辑器idea中,提供了丰富的插件,其中有一款Builder Generator的插件,提供了builder模式。这种生成的对象,可以选择参数。如果类的构造器或者静态工厂中具有多个参数,设计这种类时, Builder模式就是种不错的选择,特别是当大多数参数都是可选的时候。这种模式结合了重叠和JavaBeans的模式,在开发中可以使用。

使用builder模式的时候,只要如下代码使用就可以:

1
2
3
4
SimpleDTO builder = SimpleDTO.SimpleDTOBuilder.aSimpleDTO()
.withId(1)
.withName("金华市")
.build();

用私有构造器或者枚举类型强化Singleton属性

Singleton在设计模式中,指的是单例模式。只需要初始化一次,之后就不需要再创建对象了。

通过私有构造器强化不可实例化的能力

避免创建不必要的对象

String

在项目中,对于String的属性,若改变量存在频繁的操作,就选择StringBuilder或者StringBuffer这两个。因为String定义的变量是不可变的,在执行+来修改变量的时候,String变量重新new一个String对象实例。详情

使用静态工厂方法

对于同时提供了静态工厂方法(见第1条)和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。例如,静态工厂方法 Boolean. valueof( String)几乎总是优先于构造器 Boolean( String)。构造器在每次被调用的时候都会创建一个新的对象,而静态工厂方法则从来不要求这样做,实际上也不会这样做。

自动装箱

要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。类型对象需要不断的创建。

消除过期的对象引用

避免使用终结方法

终结方法( finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。使用终结方法会导致行为不稳定、降低性能,以及可移植性问题。当然,终结方法也有其可用之处,但是根据经验,应该避免使用终结方法。

覆盖 equals时请遵守通用约定

覆盖 equals时总要覆盖 hashCode

始终要覆盖 toString

在实体类的创建的时候,记得覆盖 toString,这样在打印日志什么的时候,就可以在日志中看到实体类中的具体数据了,而不是出现“实体类@163b91”这种日志了。

谨慎地覆盖clone

这个clone还没使用过,这几天详细的去看下。

考虑实现Comparable接口

在Java8中的Stream中,新增了一些排序的功能,详情

声明:本文使用JDK1.8

Java8提供了丰富的lambda的API。今天我们来讲讲关于其中的stream(流的操作)。对于List集合,有了stream的流操作,感觉如虎添翼。

生成一个List

1
2
3
4
5
6
7
String str = "1,2,3,4,10,11,9,66,222,12";
List<Integer> list = Stream.of(str.split(","))
.map(Integer::valueOf)
.filter(x-> !Objects.equals(x,3))
.sorted(Comparator.reverseOrder())
.limit(4)
.collect(Collectors.toList());

上面的代码Stream.of 为我们生成了一个List,但是我们需要的Integer,所以我们还需要使用map来转换类型。然后对于生成的列表,我们不想要其中的3,于是我们使用filter来过滤掉列表中的3。对于现在列表我们又想是倒序后的列表的前四条数据,于是我们在使用sorted来对列表来进行倒序后,再使用limit取前四条。顺便说一句,对于比较,推荐使用Objects.equals(a,b).
下面来简单的介绍下stream。

map

map:对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素
map方法是对列表里面的对象的转换,比如上面的map的功能是吧String转换成Integer。除了这样的转换,你也可以对对象进行你需要的操作。比如现在有一个对象ListDTO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ListDTO{
public Integer id;
public String name;
public ListDTO() {
}
public ListDTO(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

现在这么一个List,你现在只想得到这个列表中ListDTO对象里面的id,现在你就可以这样操作:

1
List<Integer> idList = beans.stream().map(ListDTO::getId).collect(Collectors.toList());

如果你想要得到name的列表,也可以进行上面类似的操作。
下面对List列表的元素先转换成大写,在用逗号把元素拼接起来

1
2
3
4
// 将字符串换成大写并用逗号拼接起来
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

输出:

1
USA, JAPAN, FRANCE, GERMANY, ITALY, U.K., CANADA

flatMap

类似于map,但是flatMap是对Stream之间的转换。

1
2
3
String[][] data = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};
Stream<String[]> temp = Arrays.stream(data);
Stream<String[]> stream = temp.filter(x -> "a".equals(x.toString()));

count

count()是对列表的聚合,统计列表的数量。

1
Long count = list.stream().count();

filter

对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素

distinct

distinct是对stream里面的元素进行去重,有点类似于SQL里面的distinct去重

limit

对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素

stream 生成 map

上面我们介绍了stream里面的toList(),下面我们来介绍下如何使用stream直接生成map,而不是像以前一样,需要循环后再一个一个的put进map。虽然我们也可以第三方的jar生成Map,比如Google的某些jar,使用里面的Maps.uniqueIndex()也可以直接把List转换成Map。

toMap

利用Collectors里面的toMap对List列表转换Map。

1
2
Map<Integer,String> beanMap = beans.stream()
.collect(Collectors.toMap(x->x.getId(), m->m.getName()));

groupingBy

利用Collectors里面的groupingBy,可以对列表进行分组,总和和排序。

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public static void main(String[] args) {

List<String> items = Arrays.asList("Apple", "Apple", "orange",
"Apple", "orange", "banana", "papaya");

Map<String, Long> result = items
.stream()
.collect(Collectors
.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(result);

//数据统计
BeanData beanData = new BeanData();
List<SimpleDTO> beans = beanData.getBeanDataList();
Map<Integer, Long> countMap = beans
.stream().collect(
Collectors.groupingBy(SimpleDTO::getId, Collectors.counting()));
System.out.println(countMap);

Map<Integer, List<SimpleDTO>> listMap = beans.stream().collect(
Collectors.groupingBy(SimpleDTO::getId));
System.out.println(listMap);

//Map 的value重新聚合单个元素的List
Map<Integer, Set<String>> setMap = beans.stream().collect(
Collectors.groupingBy(SimpleDTO::getId, Collectors.mapping(SimpleDTO::getName, Collectors.toSet()))
);
System.out.println(setMap);

//Map的value重新聚合一个新的对象
Map<Integer, List<UserDTO>> collectMap = beans.stream()
.collect(Collectors.groupingBy(SimpleDTO::getId,
Collectors.collectingAndThen(Collectors.toList(), input -> input.stream()
.map(m -> {
UserDTO user = new UserDTO();
user.setId(m.getId());
user.setUsername(m.getName());
return user;
}).collect(Collectors.toList())
)));
System.out.println(JSON.toJSON(collectMap));

//多个属性封装成唯一的Key
SimpleDTO dto1 = new SimpleDTO(1, "Jack","1");
SimpleDTO dto2 = new SimpleDTO(2,"James","2");
SimpleDTO dto3 = new SimpleDTO(3, "Hangzhou","3");
SimpleDTO dto4 = new SimpleDTO(3, "Hangzhou","4");
List<SimpleDTO> list = new ArrayList<>();
list.add(dto1);
list.add(dto2);
list.add(dto3);
list.add(dto4);

Map<String, List<SimpleDTO>> collect = list.stream().collect(Collectors.groupingBy(e -> fetchGroupKey(e)));
System.out.println(collect);
}


private static String fetchGroupKey(SimpleDTO dto){
return dto.getId() +"_"+ dto.getName();
}

总和

1
2
3
4
5
List<String> items = Arrays.asList("Apple", "Apple", "orange",
"Apple", "orange", "banana", "papaya");
Map<String,Long> result = items.stream()
.collect(Collectors
.groupingBy(Function.identity(),Collectors.counting()));

输出结果:

1
{papaya=1, banana=1, orange=2, Apple=3}

排序

1
2
3
4
5
6
Map<String, Long> finalMap = new LinkedHashMap<>();
//Sort a map and add to finalMap
result.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed()).forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
System.out.println(finalMap);

分组

现在有数据

1
2
3
4
5
6
7
public static List<ListDTO> getBeanDataList(){
List<ListDTO> listDTOS = Arrays.asList(
new ListDTO(1,"孙博"), new ListDTO(1,"二代"),new ListDTO(1,"孙博"),
new ListDTO(2,"戴硕"),new ListDTO(2,"戴硕"),new ListDTO(2,"赛克"),
new ListDTO(3,"二代"),new ListDTO(3,"路痴"),new ListDTO(3,"路痴"),
new ListDTO(4,"赛克"),new ListDTO(4,"二代"),new ListDTO(4,"路痴")
);

下面更加其中的ID作为Map的key,对上面的List进行Map.

1
2
Map<Integer,List<ListDTO>> listMap = beans.stream().collect(
Collectors.groupingBy(ListDTO::getId));

把对象中的name取出并塞到一个Set中

1
2
3
Map<Integer,Set<String>> setMap = beans.stream().collect(
Collectors.groupingBy(ListDTO::getId,Collectors.mapping(ListDTO::getName,Collectors.toSet()))
);

其他

现在需要对上面的集合,根据ID,对数据进行统计。

1
2
3
4
Map<Integer,Long> countMap = beans
.stream().collect(
Collectors.groupingBy(ListDTO::getId,Collectors.counting())
);

Stream 和 parallelStream

Stream 是普通的对流操作,而 parallelStream 是对集合进行并发操作,看下面的对两者的简单比较:

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
public static void main(String[] args) {
List<SimpleDTO> list = new ArrayList<>();
for (int i = 1; i < 100000; i++) {
SimpleDTO dto = new SimpleDTO();
dto.setId(i);
dto.setName("测试员" + i + "号");
dto.setContent("Stream 测试普通和并行的效率");
list.add(dto);
}

List<SimpleDTO> testList = list;

Long stattTime = System.currentTimeMillis();
List<String> list1 = list.stream()
.filter(x -> x.getId() > 1000)
.map(SimpleDTO::getName)
.collect(Collectors.toList());
Long endTime = System.currentTimeMillis();

System.out.println("stream 耗时:" + (endTime - stattTime) + "ms");

List<String> list2 = testList.parallelStream()
.filter(x -> x.getId() > 1000)
.map(SimpleDTO::getName)
.collect(Collectors.toList());
Long endTime1 = System.currentTimeMillis();

System.out.println("parallelStream 耗时:" + (endTime1 - endTime) + "ms");
}

结果:

1
2
stream 耗时:77ms
parallelStream 耗时:19ms

从最终的耗时可以看出,对于 parallelStream 处理大量数据的时候,效率还是有很大的提升的。

之前Mac上面使用Python都是使用系统自带的Python,哈哈。。。使用Mac的知道,Mac上面已经安装了Python2.7,这个是Mac系统需要的。现在Python有两个版本,2.x和3.x。Python2.7支持延迟时间是到2020年,2.7是2.x系列的最后一个版本,之后将不再更新了。虽然这两个版本很相似,只是语法上面有点差别。所有,如果现在学Python的话,还是下载Python3来学习吧。

Homebrew

在Mac上面安装一些软件,还是在Homebrew下面安装吧,像Git,mysql,node.js等,都可以在homebrew里面安装,这样安装卸载都方便,只需要brew install/uninstall <软件名字>

安装Xcode

安装Homebrew之前,需要安装Xcode,这个可以到APP Store里面去下载。

安装Homebrew

1.到Homebrew官网去下载
2.在命令终端里面下载

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装Python3

homebrew的一些基本命令:

1
2
3
4
5
6
7
8
9
$ brew search <pkg_name> #查找软件包
$ brew install <pkg_name> #安装软件包
$ brew list #列出软件包
$ brew uninstall <pkg_name> #卸载软件包
$ brew info <pkg_name> #查看软件包的基本资料
$ brew update # 更新 Homebrew 的信息
$ brew outdated # 看一下哪些软件可以升级
$ brew upgrade <xxx> # 如果不是所有的都要升级,那就这样升级指定的
$ brew upgrade; brew cleanup # 如果都要升级,直接升级完然后清理干净

查询homebrew下的Python

1
brew search Python

安装Python

1
brew install Python3

安装后的Python3在/usr/local/Cellar/python3/3.6.3

安装Python3时碰到的问题

我在安装的时候碰到了 Error: Permission denied @ dir_s_mkdir - /usr/local/Frameworks 的问题。看着好像是在安装Python3的时候,因为权限问题,不能创建Frameworks文件夹。于是我去GitHub上面的HomeBrew上面去找问题。网址上面有类似的答案。

1
2
sudo mkdir -p /usr/local/Frameworks
sudo chown -R $(whoami) /usr/local/*

然后在使用 brew install python3 安装。然后使用which python3 查看是否安装。
如果使用PyCharm的话,需要自己去找你安装Python3目录下的python3文件。

相比较于之前的版本之前的版本,增加了很大新特性,其中关于时间多了很多功能:LocalDateTime,LocalDate,LocalTime。

时间介绍

LocalDate是年月日;LocalTime是时分秒;LocalDateTime则是两者的合并,可以通过下面得到:

1
2
3
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);

1
LocalDateTime localDateTime = LocalDateTime.now();

Java8对这几个时间提供了丰富的时间计算接口。
关于Date和String之间的转化,我这里就不多说了

String –> LocalDate/LocalTime/LocalDateTime

String类型转化新特性时间可以使用 DateTimeFormatter 功能。

1
2
DateTimeFormatter dateformatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate ld = LocalDate.parse("2017-08-01", dateformatter);
1
2
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse("2017-09-22 11:30:10", df);
1
2
3
String time = "11:30:10";
DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm:ss");
LocalTime lt = LocalTime.parse(time,df);

但是在转化的时候要注意了,你不能把“2017-08-01”的String转化成LocalDateTime/LocalTime,不然会报错,需要他们代表时间的范围。

Date –> LocalDate/LocalTime/LocalDateTime

1
2
3
4
5
6
Date date = new Date();
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);//转化成LocalDateTime
LocalDate localDate = localDateTime.toLocalDate();//转化成LocalDate
LocalTime localTime = localDateTime.toLocalTime();//转化成LocalTime

LocalDate/LocalTime/LocalDateTime –> Date

1
2
3
4
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant();
Date date = Date.from(instant);
1
2
3
4
LocalDate localDate = LocalDate.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
Date date = Date.from(instant);
1
2
3
4
5
6
7
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
LocalDateTime localDateTime1 = LocalDateTime.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant();
Date date = Date.from(instant);

计算两个时间差

1
2
3
4
LocalDateTime now = LocalDateTime.now();
LocalDateTime start = now.minusDays(5);
Duration duration = Duration.between(start,now);
System.out.println(duration.toDays());

Instant

Instant代表某个时间,类似于java.util.Date,它是精确到纳秒的(而不是象旧版本的Date精确到毫秒)。如果使用Long去表示,其中的存储空间是不够的,不能像data那样直接使用一个long类型表示时间戳。其实在Instant中,它的源码就是分成两部分组成的。

1
2
3
4
5
private Instant(long epochSecond, int nanos) {
super();
this.seconds = epochSecond;
this.nanos = nanos;
}

Instant和上面介绍的时间类一样,提供了很多的方法。简单的介绍点。

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Instant instant = Instant.now();
System.out.println(instant);
//将java.util.Date转换为Instant
Instant time = Instant.ofEpochMilli(new Date().getTime());
//从字符串类型中创建Instant类型的时间
instant = Instant.parse("1995-10-23T10:12:35Z");
//将现在的时间加上5个小时4分钟
instant.plus(Duration.ofHours(5).plusMinutes(4));
}

参考

最近想自己搭建一个个人博客,就去网上去看下有没有开源的代码可以拿来使用,在比较了网上一些开源的博客后,选择了Hexo。主要自己想在平时学习积累的时候,有个地方记录下自己的学习,嗯,还有一个和重要的的因素,那就是顺便装个B。

什么是 Hexo?

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

安装

安装

安装hexo之前先安装 Node.js 和 Git,之后使用npm下载hexo

1
$ npm install -g hexo-cli

建站

安装 Hexo 完成后,请执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件。

1
2
3
$ hexo init <folder>
$ cd <folder>
$ npm install

部署

参考官网Hexo的技术文档。服务器可以选择 coding 和 GitHub Page,他们都有免费的静态博客服务器提供,基本上满足了自己的需求。

域名的绑定

本人实在阿里云上面买的域名。

1
2
cd source
touch CNAME
  • 并在文件中写上你的域名,比如:example.com。如果想在国内走coding,国外走GitHub,那些在阿里云上面设置域名解析。

并在coding page上,进行域名绑定,可以开启HTTPS。GitHub上面现在不支持自定义域名绑定的HTTPS。

  • 不过GitHub page已经支持HTTPS认证了,直接在域名解析中,如下图使用就OK了,顺便再GitHub上面勾选Enforce Https:

部署服务器

Hexo提供了很多种部署,可以如前面一样选择部署到coding page或者GitHub page上面,也可以部署到服务器上面,部署详情

本人选择的喜欢捣鼓,就想把hexo部署到阿里云服务器上面,参考资料1参考资料2
部署完成,发现Nginx访问403,看了下日志,好像是文件权限问题,于是就使用ll命令查看了下文件,发现hexo文件是git用户的,Nginx是root用户在访问这个文件夹,使用chown -R root:root <文件夹名>,把hexo文件夹权限改为root的,再次访问就可以了。

基本命令

启动本地服务

1
$ hexo s

部署到GitHub

1
$ hexo g -d

主题的选择

一开始使用的主题是indigo,但是在使用的过程中,虽然自己是一只程序猿,但是对前端的内容只能看个基本的,所以对于自己的一些前端修改,很怕。最近,在逛hexo主题的时候,发现了一款非常不错的主题next。反正我在使用之后,发现是个不错的主题,它对很多第三方插件,有了很好的集成,你是要改下配置,基本上就满足你的需求。详情可以查看它的next主题官网,上面有很多的介绍,可以自己进行定制,而且页面也比较简洁。

开启版权声明

把其中的enable设置为true:

1
2
3
4
5
# Declare license on posts
post_copyright:
enable: true
license: CC BY-NC-SA 3.0
license_url: https://creativecommons.org/licenses/by-nc-sa/3.0/

修改文章底部的那个带#号的标签

打开 themes/next/layout/_macro/post.swig 文件,搜索 rel=”tag”># ,将 # 换成

1
2
3
4
5
6

<div class="post-tags">
{% for tag in post.tags %}
<a href="{{ url_for(tag.path) }}" rel="tag"><i class="fa fa-tag"></i> {{ tag.name }}</a>
{% endfor %}
</div>

撰写博客

先使用下面命令生成博客模板

1
$ hexo new post <title>

之后就可以使用编译器进行编写了。Hexo博客的编写是使用Markdown的。查看Markdown的详细语言。

发布

可以现在本地看下自己的编写情况:

1
hexo s

可以边修改便查看。好了之后就可以发布到自己的Coding page和GitHub page上面了。

1
hexo g -d

图床

在编写博客的时候,我们难免会使用到图片,那是把图片放在hexo本地呢?还是放在服务器上呢?为什么删除七牛云,因为七牛云因为有人使用它的域名,进行非法事件,域名被查封了,于是出现了测试域名回收事件,域名只有30天有效时间,除非你自己绑定域名,而且需要备案过的。对于自己简单的博客,不想搞了,于是去找别家的对象存储,发现腾讯云和网易云的对象存储有免费的,对于一个网站图床来说感觉够用了。本人最后选择的是腾讯云,因为我之前在活动期间买了服务器,不想东一家西一家了。

这个时候我就推荐七牛云了,这个在我之前的工作中也在使用,发现还挺方便的。免费用户有每月10GB流量+总空间10GB+PUT/DELETE 10万次请求+GET 100万次请求,这个对于个人来说已经够用了,如果你想使用七牛云,可以走这个通道,这样,我就可以每个月多得5G的下载流量了。

七牛云+Alfred+插件组合

本人图床使用的是七牛云+Alfred+插件组合使用的,使用快捷键,就可以直接上传到七牛云,返回一个MarkDown的图片路径,插件源码,上面有比较详细的安装过程,声明一点Alfed这款软件只在Mac有。

PicGo

上面只能再Mac上使用,发现了另外一款图床软件PicGo,支持Mac和Windows,在他的介绍上,除了七牛云、GitHub图床、腾讯云等。

live2

今天看到别人关于介绍给博客添加个萌娘,给自己的博客增彩。效果如下:

live2 完美兼容 Hexo,对Hexo 的支持非常友好。

安装

使用 npm 在 hexo 下安装 hexo-helper-live2d,它将 live2d-widget.js 与 hexo 进行了整合,使得我们只需要通过简单的配置,即可生效:

1
2
3
4
# 安装 live2 插件
npm install --save hexo-helper-live2d
# 安装人物模型 https://github.com/xiazeyu/live2d-widget-models
npm install live2d-widget-model-z16

配置

在Hexo 的 _config.yml 文件中添加配置,同时在根目录下添加 1live2dw` 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
live2d:
enable: true
scriptFrom: local # 默认
pluginRootPath: live2dw/ # 插件在站点上的根目录(相对路径)
pluginJsPath: lib/ # 脚本文件相对与插件根目录路径
pluginModelPath: assets/ # 模型文件相对与插件根目录路径
tagMode: false # 标签模式, 是否仅替换 live2d tag标签而非插入到所有页面中
debug: false # 调试, 是否在控制台输出日志
model:
use: live2d-widget-model-wanko # npm-module package name
display:
position: right
width: 150
height: 300
mobile:
show: true
react:
opacity: 0.7