老男将的叨叨

生命不息 折腾不止


  • 首页

  • 标签

  • 分类

  • 归档

Windows中使用WinMerge作为git默认merge工具

发表于 2019-11-18 | 阅读次数:
字数统计: 1.5k | 阅读时长 ≈ 0:02

安装WinMerge

下载

  • 工具主页https://winmerge.org/
  • 下载地址https://winmerge.org/downloads/?lang=en

    配置git

    编辑配置文件

1
git config --global -e

或是使用你常用的文本工具打开%USER%/.gitconfig文件,%USER%在windows中一般是C:\Users\下的当前登录系统的用户名目录

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
[user]
name = liuyi
email = liuyi03@sinochem.com
[alias]
st = status
ci = commit
br = branch
co = checkout
df = diff
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset' --abbrev-commit --date=relative
[core]
autocrlf = true
editor = 'd:\\software\\Microsoft VS Code\\Code.exe' --wait
[gui]
recentrepo = E:/projects/smart_front
[difftool]
tool = winmerge
prompt = false
[difftool "winmerge"]
cmd = \"D:/software/WinMerge/WinMergeU.exe\" -e -u -dl \"Old $BASE\" -dr \"New $BASE\" \"$LOCAL\" \"$REMOTE\"
trustExitCode = true
[commit]
template = C:\\Users\\liuyi03\\git_commit_template.txt
[merge]
tool = winmerge
[mergetool "winmerge"]
cmd = \"D:/software/WinMerge/WinMergeU.exe\" -e -u -fm -wl -wr -dl \"Local\" -dm \"Base\" -dr \"Remote\" \"$LOCAL\" \"$BASE\" \"$REMOTE\" -o \"$MERGED\"
[mergetool]
trustExitCode = true
keepBackup = false

主要的配置都在mergetool里,需要自己替换WinMerge的安装路径配置

看效果

有一个a.txt文件在同一行中进行了修改,当从远端fetch后进行rebase时发生了冲突
image.png

1
git mergetool

命令行输入如上命令,出现如下界面
image.png
点工具栏中的自动合并图标或使用快捷键Ctrl+Alt+M,出来如下界面
image.png
提示自动合并两处,一处有冲突,选中左边的有冲突的行点工具栏中的复制到右侧(Alt+Right)以左边的修改准,如果想以右边的修改为准备则选中右国的有冲突的行点工具栏中的复制到左侧(Alt+Left)。
image.png
如果都不对,那么直接在中间进行修改。完成后保存并关闭winmerge。完成冲突解决,如果你的冲突文件同级目录下出现了*.bak的文件,那么需要在winmerge中配置关闭自动备份功能。
菜单 编辑->选项 中的备份文件如下图,两个复选框都去掉
image.png

Mac 终端环境配置

发表于 2019-11-18 | 阅读次数:
字数统计: 1.7k | 阅读时长 ≈ 0:02

基础工具安装

homebrew

官网https://brew.sh/
安装

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

替换清华源

1
2
3
4
5
6
7
git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git

git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git

git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git

brew update

还原回官方源(如果镜像无法使用)

1
2
3
4
5
6
7
git -C "$(brew --repo)" remote set-url origin https://github.com/Homebrew/brew.git

git -C "$(brew --repo homebrew/core)" remote set-url origin https://github.com/Homebrew/homebrew-core.git

git -C "$(brew --repo homebrew/cask)" remote set-url origin https://github.com/Homebrew/homebrew-cask.git

brew update

替换Bottles源

1
2
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc

zsh

使用brew安装zsh

1
brew install zsh

iTerm2

下载安装https://iterm2.com
配置item2的shell为zsh
image.png

oh-my-zsh

安装 https://ohmyz.sh

1
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

安装powerline字体

1
brew install powerlevel9k

powerline配置

在~/.zshrc中配置ZSH_THEME

1
ZSH_THEME="powerlevel9k/powerlevel9k"

oh-my-zsh插件

插件列表

  1. https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins
  2. https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins

在~/.zshrc中增加如下配置安装插件

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
plugins=(
git
brew
node
nvm
kubectl
helm
z
vi-mode
zsh-syntax-highlighting
zsh-autosuggestions
osx
colored-man-pages
catimg
web-search
vscode
docker
docker-compose
copydir
copyfile
npm
yarn
extract
fzf
)

团队协作规范

发表于 2019-10-25 | 阅读次数:
字数统计: 2.9k | 阅读时长 ≈ 0:03

Git使用

分支管理与发布策略

一个仓库只允许一个长期的分支:

  • master 开发分支

所有的开发人员基于master分支进行开发。

临时分支:

  • 发布分支 - release/{date} (例:release/**20190823**)
  • 线上紧急热修复分支 - hotfix/{date} (例:hotfix/**20190823**)
  • 开发人员临时功能分支 - feature/{feature name} (例:feature/fileupload)

开发模式如下:

  1. 获取最新的代码

    1
    2
    3
    git checkout master
    git fetch
    git rebase origin/master
  2. 本地开发,然后提交

    1
    2
    git add .
    git commit
  3. 推送到仓库

    1
    2
    3
    git fetch
    git rebase origin/master
    git push

rebase的时候如果有冲突先解决冲突然后再执行

1
2
git add .
git commit

完成后再重复3

注意:

这里只能使用rebase,禁止使用merge

建议:

  1. 如果功能较大,一次代码提交不合适,可多次commit最后再一次性push到主仓
  2. 如果多人协同一个功能,尽量使用代码原子性、API版本、提前定义接口等方法,把功能拆小后尽快push到主仓,以免影响协作开发的同事

部署

  1. 从master拉出一个发布分支

    1
    2
    3
    4
    git checkout master
    git checkout -b release/20190309
    # 推到远端库
    git push
  2. 在发布分支上进行测试与验证

  3. 如果验证发现问题,开发人员提交代码到master并cherry-pick到发布分支,回到2继续

    1
    git cherry-pick <fix-shal>
  4. 完成发布打tag

tag命名规则: release-{date}、hotfix-{release_date}-{seq} (例如:release-20190319、hotfix-20190319-1)

热修复过程

  1. 从指定tag checkout 一个hotfix分支(该分支一直存在到下一次release版本发布)。
  2. 开发人员在master分支上进行修复,然后cherry pick到hotfix分支。
  3. 进行测试与验证,如果发现问题回到2继续
  4. 发布hotfix分支,并打tag

注意:

hotfix分支的生命周期应与每一次迭代的生命周期保持一致,上一次发布的热修复会一直在这个分支上进行

commit 规范

1
2
3
<type>: <subject>
<BLANK LINE>
<body>

Type(必要)

描述本次提交的类型。
高频:

  • feat: 一个新的功能
  • fix: 修复 Bug
  • perf: 提高性能的代码
  • refactor: 代码重构
  • style: 编码规范、风格上的修改,不影响功能
  • test: 测试用例修改

低频:

  • docs: 仅改变项目文档
  • build: 改变项目构建流程或包依赖

    Subject(必要)

    用于描述本次 commit 的简要说明

    Body(可选)

    往往用来描述本次 Commit 的动机、需同步给团队的信息等

参考:https://www.conventionalcommits.org/en/v1.0.0/

配置git提交模板

创建文件 .git_commit_template

1
2
3
<type>: <subject>

<body>

设置为git提交模板

1
git config --global commit.template $HOME/.git_commit_template

API接口文档

为什么我们要使用API接口文档?当前大部分的项目都是前后端分离的开发模式,前端与后台开发必须基于约定进行开发,这样才能并行开发。接口的变化及版本也需要记录并标记下来。对于测试人员也可以提前针对接口编写自动化的测试脚本,可以更早的发现问题。

API接口文档我们选用去哪网前端团队开发的YApi,具体的使用手册请参考这里。
其功能包括:

  • 可视化接口管理
  • 数据mock
  • 自动化接口测试
  • 数据导入(各种,包括swagger、har、postman、json、命令行)
  • 权限管理
  • 支持本地化部署
  • 支持插件
  • 支持二次开发

对于后台开发人员编写API接口文档有以下两种推荐方式:

  1. swagger导入
  2. har导入

Swagger导入,可以在项目中集成Swagger,并使用Swagger maven plugin在每次打包时生成swagger的json格式api,可直接导入YApi。
HAR导入,har是HTTP Archive format的简称,我们写好代码,在开发自测调试时可以在chrome中访问我们的接口,chrome可以自动记录并将所有的请求保存为har格式的文件并导入YApi,如下图所示。
Snipaste_2019-10-31_13-09-48.png

代码评审 - CodeReview

代码评审在不管任何项目或产品的开发过程中都是不可或缺的一步。一般项目都不会由一个人开发完成,都是由团队中的多人共同合作完成,但团队中的人员级别不一素质不同,因此代码评审可以帮助团队生产出的代码质量更均一,初级的开发人员可以更快速的提升自己能力,一些bug可以尽早发现。除此外还为什么我们强调代码评审是一个不可或缺的一步?如果不这样做为有什么问题?

  • 没有人可以完全了解一个项目所包含的所有代码,因为这些代码是由不同的人编写的。
  • 项目中的某些代码都只有作者自己才能看到。
  • 质量差的代码很可能会长期存在。
  • 没有人应对他人的代码负责,甚至不为自己的代码负责。
  • 团队成员发现很难获得经验并提高编码技能。
  • 糟糕的代码在测试阶段将会引起许多小问题。
  • 糟糕的代码会在开发人员修复bug时造成很大的困难(改出更多的bug)。
  • 当新开发人员加入项目时,他们的代码可能是风险最高的代码。
  • 对三个月前的代码进行重构将会非常复杂。

因此我们需要通过代码评审来解决上面这些问题。

对于一个新的功能或业务的开发(已有功能的修改和bugfix不算在内,除非这个改动影响比较大),其代码入库前需要进行代码评审,我们这里采用基于GitLab的Merge Request进行Code Review,步骤如下:

  1. 获取最新的代码

    1
    2
    3
    git checkout master
    git fetch
    git rebase origin/master
  2. 签出到功能分支

    1
    git checkout -b feature/***
  3. 本地开发并提交

    1
    2
    git add .
    git commit
  4. push到远端

    1
    git push
  5. 发起merge request

  1. 评审并批注,如果不通过回到3
  2. 评审人进行merge,如有冲突先解决冲突

Guava学习记录

发表于 2019-09-29 | 阅读次数:
字数统计: 11k | 阅读时长 ≈ 0:11

Guava简介

The Guava project contains several of Google’s core libraries that we rely on in our Java-based projects: collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, and so forth. Each of these tools really do get used every day by Googlers, in production services.

But trawling through Javadoc isn’t always the most effective way to learn how to make best use of a library. Here, we try to provide readable and pleasant explanations of some of the most popular and most powerful features of Guava.

Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。


基本工具

避免null

  • 返回的集合类型不要使用null
    • 是不是没有记录??比较含糊
  • set中不要使用null
    • 如果有多个null放到set无法区分,如果是一个变量放入set,你不知道他是不是null
  • map中的key不要使用null
    • 多个null的key被覆盖,如果是变量作为key,你不知道他是不是null

示例:

1
2
3
4
5
6
7
8
Optional<Object> opt = Optional.fromNullable(null);
assertFalse("不应该有", opt.isPresent());
assertEquals("null", opt.or("null"));
opt = Optional.absent();
assertFalse("不应该有", opt.isPresent());
opt = Optional.of("null");
assertEquals("null", opt.get());
Optional.of(null);

对于jdk1.8来说可以使用java.util.Optional来代替

前置条件

参数检查

1
2
3
int i = -1, j = -32;
assertThrows(IllegalArgumentException.class, () -> checkArgument(i >= 0, "参数是%s,预期是一个正数", i));
assertThrows(IllegalArgumentException.class, () -> checkArgument(i < j, "需要i < j,但是 %s >= %s", i, j));

这些可以帮助方法快速失败

通用Object方法

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
assertTrue(Objects.equal("a", "a")); // returns true
assertFalse(Objects.equal(null, "a")); // returns false
assertFalse(Objects.equal("a", null)); // returns false
assertTrue(Objects.equal(null, null)); // returns true

public class TestPojo implements Comparable<TestPojo> {

...

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("desc", desc)
.add("user", user)
.add("price", price)
.add("title", title)
.add("buyCount", buyCount)
.add("viewCount", viewCount)
.add("contentSize", contentSize)
.add("img", img)
.add("category", category)
.add("createdAt", createdAt)
.add("updatedAt", updatedAt)
.add("finishedAt", finishedAt)
.add("isFinished", isFinished)
.add("isDeleted", isDeleted)
.add("isHot", isHot)
.add("isPublish", isPublish)
.add("isShow", isShow)
.add("profile", profile)
.add("lastSectionCount", lastSectionCount)
.add("pv", pv)
.add("timeLimitDiscountFirstDay", timeLimitDiscountFirstDay)
.add("timeLimitDiscount", timeLimitDiscount)
.add("wechatSignal", wechatSignal)
.add("wechatImg", wechatImg)
.add("wechatImgDesc", wechatImgDesc)
.add("url", url)
.add("section", section)
.add("tags", tags)
.toString();
}

@Override
public int compareTo(TestPojo that) {
return ComparisonChain.start()
.compare(this.buyCount, that.buyCount)
.compare(this.contentSize, that.contentSize)
.result();
}
}

对Objects来说如果使用的是jdk1.7,那么可以使用java.util.Object来代替

排序器

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
String[] array = {"1", "2", null, "3", "12", null, "14"};
assertThrows(NullPointerException.class, () -> Arrays.sort(array, Ordering.natural()));
logger.info(Arrays.toString(array)); // [1, 2, null, 3, 12, null, 14]

Arrays.sort(array, Ordering.natural().nullsFirst());
assertArrayEquals(new String[]{null, null, "1", "12", "14", "2", "3"}, array);
logger.info(Arrays.toString(array)); // [null, null, 1, 12, 14, 2, 3]

Arrays.sort(array, Ordering.natural().nullsLast());
assertArrayEquals(new String[]{"1", "12", "14", "2", "3", null, null}, array);
logger.info(Arrays.toString(array)); // [1, 12, 14, 2, 3, null, null]

Arrays.sort(array, Ordering.natural().reverse().nullsLast());
assertArrayEquals(new String[]{"3", "2", "14", "12", "1", null, null}, array);
logger.info(Arrays.toString(array)); // [3, 2, 14, 12, 1, null, null]

Arrays.sort(array, Ordering.natural().nullsLast().reverse());
assertArrayEquals(new String[]{null, null, "3", "2", "14", "12", "1"}, array);
logger.info(Arrays.toString(array)); // [null, null, 3, 2, 14, 12, 1]

Arrays.sort(array, Ordering.natural().onResultOf(new Function<String, Integer>() {
@Nullable
@Override
public Integer apply(@Nullable String input) {
return Integer.valueOf(Optional.fromNullable(input).or("-1"));
}
}));
assertArrayEquals(new String[]{null, null, "1", "2", "3", "12", "14"}, array);
logger.info(Arrays.toString(array)); // [null, null, 1, 2, 3, 12, 14]

异常处理

好像也没有什么可说的

集合

不可变集合

不可变对象有以下优点:

  1. 被第三方库使用时是安全的(不会被修改了还不知道 )
  2. 线程安全:多线程使用时没有条件竞争风险
  3. 无需支持变化,能节约时间与空间。所有的不可变集合比可变集合的实现在内存上效率更好
  4. 可用作常量

构造对象的不可变拷贝是一个好的防御性编程技巧。
JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式,但这些方法有以下问题:

  1. 使用不便
  2. 不安全,不一定是真正的不可变
  3. 低效,数据结构仍是在可变集合基础上实现的

注意:所有的Guava的不可变集合都不支持null值元素,如果发现null值会快速失败

使用方式

1
2
3
4
5
6
7
8
ImmutableSet.copyOf(set);
ImmutableSet.of("a", "b", "c");
ImmutableMap.of("a", 1, "b", 2);
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();

新的集合类型

multisets, multimaps, tables, bidirectional maps

Multiset

继承于collection,这里的set是数学中集合的意思,并不是java不是Set接口。(把Multiset当成List一样用就可以了)
用于计数

1
2
3
4
5
6
7
8
9
Map<String, Integer> counts = new HashMap<String, Integer>();
for (String word : words) {
Integer count = counts.get(word);
if (count == null) {
counts.put(word, 1);
} else {
counts.put(word, count + 1);
}
}

使用Multset

1
2
3
4
5
6
List<String> list = Lists.newArrayList("hello", "guava", "hello", "world");
HashMultiset<String> multiset = HashMultiset.create();
multiset.addAll(list);
assertEquals(2, multiset.count("hello"));
assertEquals(1, multiset.count("guava"));
assertEquals(0, multiset.count("guave"));

Multiset的实现有

Map Corresponding Multiset Supports null elements
HashMap HashMultiset Yes
TreeMap TreeMultiset Yes
LinkedHashMap LinkedHashMultiset Yes
ConcurrentHashMap ConcurrentHashMultiset No
ImmutableMap ImmutableMultiset No

SortedMultiset

它是Multiset的一个变种,能按给定的范围高效的获取子集

Multimap

每个有经验的Java程序员都在某处实现过Map<K, List>或Map<K, Set>,比如,我要做一个归类操作,把复合某种特征的数据放归到一起,就可以使用这个接口,Multimap是把键映射到任意多个值的一般方式。
不会有任何键映射到空集合:一个键要么至少到一个值,要么根本就不在Multimap中。
很少会直接使用Multimap接口,更多时候你会用ListMultimap或SetMultimap接口,它们分别把键映射到List或Set。

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
List<String> list = Lists.newArrayList("hello", "guava", "hello", "world");
HashMultiset<String> multiset = HashMultiset.create();
multiset.addAll(list);
assertEquals(2, multiset.count("hello"));
assertEquals(1, multiset.count("guava"));
assertEquals(0, multiset.count("guave"));

Multimap<Integer, Integer> listMultimap = MultimapBuilder.treeKeys().arrayListValues().build();
Multimap<Integer, Integer> setMultimap = MultimapBuilder.hashKeys().hashSetValues().build();

listMultimap.put(1, 2);
listMultimap.put(1, 2);
listMultimap.put(1, 3);
listMultimap.put(1, 4);
listMultimap.put(2, 3);
listMultimap.put(3, 3);
listMultimap.put(4, 3);
listMultimap.put(5, 3);

setMultimap.put(1, 2);
setMultimap.put(1, 2);
setMultimap.put(1, 3);
setMultimap.put(1, 4);
setMultimap.put(2, 3);
setMultimap.put(3, 3);
setMultimap.put(4, 3);
setMultimap.put(5, 3);

assertEquals(4, listMultimap.get(1).size());
assertEquals(0, listMultimap.get(6).size());
assertNull(listMultimap.asMap().get(6));

assertEquals(3, setMultimap.get(1).size());
// 对值视图集合进行的修改最终都会反映到底层的Multimap
setMultimap.get(1).remove(2);
assertEquals(2, setMultimap.get(1).size());

assertTrue(listMultimap.containsKey(1));
assertFalse(listMultimap.containsKey(6));

BiMap

传统上,实现键值对的双向映射需要维护两个单独的map,并保持它们间的同步。但这种方式很容易出错,而且对于值已经在map中的情况,会变得非常混乱。例如:

1
2
3
4
5
6
7
Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();

nameToId.put("Bob", 42);
idToName.put(42, "Bob");
// what happens if "Bob" or 42 are already present?
// weird bugs can arise if we forget to keep these in sync...

BiMap<K, V>是特殊的Map:

  • 允许你使用inverse()方法去反转BiMap<V, K>的键值
  • 保证值是唯一的,values()返回一个Set

使用BiMap.put(key, value)方法去添加一个已存在的key将会引起IllegalArgumentException异常,如果你想强制替换就要使用BiMap.forcePut(key, value)

Table

通常来说,当你想使用多个键做索引的时候,你可能会用类似Map<FirstName, Map<LastName, Person>>的实现,这种方式很丑陋,使用上也不友好。Guava为此提供了新集合类型Table,它有两个支持所有类型的键:”行”和”列”。Table提供多种视图,以便你从各种角度使用它:

  • rowMap():用Map<R, Map<C, V>>表现Table<R, C, V>。同样的, rowKeySet()返回“行”的集合Set。
  • row(r) :用Map<C, V>返回给定“行”的所有列,对这个map进行的写操作也将写入Table中。
  • 类似的列访问方法:columnMap()、columnKeySet()、column(c)。(基于列的访问会比基于的行访问稍微低效点)
  • cellSet():用元素类型为Table.Cell<R, C, V>的Set表现Table<R, C, V>。Cell类似于Map.Entry,但它是用行和列两个键区分的。

给出一个学生-课程-成绩表:

a javase 80
b javaee 90
c javame 100
d guava 60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Table<String, String, Integer> tables = HashBasedTable.create();
tables.put("a", "javase", 80);
tables.put("b", "javaee", 90);
tables.put("c", "javame", 100);
tables.put("c", "javaee", 80);
tables.put("d", "guava", 70);

// 所有学生
Set<String> students = tables.rowKeySet();
assertEquals(Sets.newHashSet("a", "b", "c", "d"), students);

// 找到对应学生和科目的成绩
assertEquals(100, tables.get("c", "javame").intValue());
assertEquals(80, tables.get("c", "javaee").intValue());

// 所有课程
Set<String> courses = tables.columnKeySet();
assertEquals(Sets.newHashSet("javase", "javaee", "javame", "guava"), courses);

// 所有分数
Collection<Integer> scores = tables.values();
assertArrayEquals(Lists.newArrayList(80, 90, 100, 80, 70).toArray(new Integer[]{}), scores.toArray(new Integer[]{}));

RangeSet

RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。例如:

1
2
3
4
5
6
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15));//不相连区间:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); //相连区间; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0)); //空区间; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; {[1,5], [10,10], [11,20)}

RangeMap

RangeMap描述了”不相交的、非空的区间”到特定值的映射。和RangeSet不同,RangeMap不会合并相邻的映射,即便相邻的区间映射到相同的值。例如:

1
2
3
4
5
RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); //{[1,10] => "foo"}
rangeMap.put(Range.open(3, 6), "bar"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo"}
rangeMap.put(Range.open(10, 20), "foo"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo", (10,20) => "foo"}
rangeMap.remove(Range.closed(5, 11)); //{[1,3] => "foo", (3,5) => "bar", (11,20) => "foo"}

字符工具

  • Joiner
  • Splitter
  • CharMatcher
  • Charsets
  • CaseFormat

CaseFormat在做代码生成器的时候是非常有用的,比如:

1
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME"));

springboot集成docker

发表于 2019-09-15 | 阅读次数:
字数统计: 1.9k | 阅读时长 ≈ 0:02

maven添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.12</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<useMavenSettingsForAuth>true</useMavenSettingsForAuth>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>

使用aliyun镜像私库

  1. maven配置私库账号密码
    配置setting.xml文件 ${user.home}/.m2/settings.xml, 这里的${user.home}就是用户主目录,windows里在C:\Users\下你的用户名目录,mac在/Home/下你的用户名目录
1
2
3
4
5
6
7
8
9
10
...
<server>
<id>registry.cn-beijing.aliyuncs.com</id>
<username>topcatii@126.com</username>
<password>********</password>
<configuration>
<email>topcatii@126.com</email>
</configuration>
</server>
...

这里的密码用明文是比较危险的,所以还要加密

  1. 创建master password
1
mvn --encrypt-master-password <password>

这个命令会生成一条类似{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}的字符串
将这个生成的字符串存储在${user.home}/.m2/settings-security.xml文件里

1
2
3
<settingsSecurity>
<master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}</master>
</settingsSecurity>
  1. 生成服务器密码
1
mvn --encrypt-password <password>

得到类似{COQLCE6DU6GtcS5P=}的字符串,替换到上面的setting.xml文件中

1
2
3
4
5
6
7
8
9
10
...
<server>
<id>registry.cn-beijing.aliyuncs.com</id>
<username>topcatii@126.com</username>
<password>{COQLCE6DU6GtcS5P=}</password>
<configuration>
<email>topcatii@126.com</email>
</configuration>
</server>
...

使用maven命令打包发布

1
mvn package dockerfile:build dockerfile:push

参考:

  • http://maven.apache.org/guides/mini/guide-encryption.html

springboot使用maven打包docker

发表于 2019-03-05 | 阅读次数:
字数统计: 3.1k | 阅读时长 ≈ 0:03

Springboot项目配置Maven插件打包Docker镜像

  1. 创建Dockerfile配置文件
  2. 在pom.xml中添加插件
  3. 需要注意的地方
    阅读全文 »

系统数据容量获取

发表于 2019-01-14 | 阅读次数:
字数统计: 2.8k | 阅读时长 ≈ 0:03

统计系统数据容量

MySQL数据库

  • 查看所有数据库容量大小
    1
    2
    3
    4
    5
    6
    7
    select table_schema                                 as '数据库',
    sum(table_rows) as '记录数',
    sum(truncate(data_length / 1024 / 1024, 2)) as '数据容量(MB)',
    sum(truncate(index_length / 1024 / 1024, 2)) as '索引容量(MB)'
    from information_schema.tables
    group by table_schema
    order by sum(data_length) desc, sum(index_length) desc;
阅读全文 »

将vs code配置到zsh中命令行启动

发表于 2018-02-14 | 分类于 mac | 阅读次数:
字数统计: 511 | 阅读时长 ≈ 0:01

我们在mac上使用Visual Studio Code时希望在zsh中通过命令快速打开一个文件或文件夹如何做到?

阅读全文 »

Sublime Text3配置BracketHighlighter插件

发表于 2016-03-20 | 阅读次数:
字数统计: 4.1k | 阅读时长 ≈ 0:04

BracketHighlighter是一款括号匹配高亮显示的sublime插件
下面是官网上的一个截图
BracketHighlighter

今天就介绍一下这个插件在mac下如何安装到Sublime Text3下

阅读全文 »

我的MacBook系统及开发环境配置

发表于 2016-01-23 | 分类于 mac | 阅读次数:
字数统计: 1.5k | 阅读时长 ≈ 0:01

MacBookPro已入手多时,现在也已用的比较熟练了,这里记录一下我的Mac的开发环境配置。下面将从几个方面记录一下板沙的成果。

  1. 基础软件HomeBrew、iterm2、ohmyzsh
  2. 美化powerline
  3. 系统工具Mackup
  4. 开发工具MacVim或Vim、Sublime Text 3
阅读全文 »
12
刘易(Roy Liu)

刘易(Roy Liu)

20 日志
7 分类
24 标签
GitHub E-Mail Google Weibo
Creative Commons
© 2019 刘易(Roy Liu) | 站点总字数: 43k | 站点总阅读时长: 0:43
由 Hexo 强力驱动
|
主题 — NexT.Muse v6.0.4
0%