Markdown介绍

Markdown是一种轻量级标记语言,排版语法简洁,让人们更多地关注内容本身而非排版。它使用易读易写的纯文本格式编写文档,可与HTML混编,可导出 HTML、PDF 以及本身的 .md 格式的文件。因简洁、高效、易读、易写,Markdown被大量使用,如Github、Wikipedia、各种笔记类App等。

语法简介

来自markdown 语法说明

基本语法

元素 Markdown 语法
标题(Heading) # H1
## H2
### H3
粗体(Bold) **bold text**
斜体(Italic) *italicized text*
引用块(Blockquote) > blockquote
有序列表(Ordered List) 1. First item
2. Second item
3. Third item
无序列表(Unordered List) - First item
- Second item
- Third item
行内代码(Code) code
链接(Link) [title](https://www.lendo.site)
图片(Image) ![alt text](image.jpg)

Markdown

Plantuml

背景

  • 很多金融机构需要输入地址,并且要复合规范
  • 省|市|县|街道及单元及门牌号,省、市、县”填写每年12月民政部发布的最新“中华人民共和国县以上行政区划代码”(六位数字)的省级、地市级、县级行政区区划代码

省级、地市级、县级行政区区划代码

  • github开源数据源
  • 地址

解析代码

  • 正则解析摘抄于网络
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public final static List<String> CITIES = Arrays.asList("北京市", "上海市", "天津市", "重庆市");
public final static String ADDRESS = "address";
public final static String PROVINCE = "province";
public final static String CITY = "city";
public final static String COUNTY = "county";
public final static String VILLAGE = "village";
public final static String STYLE = "style";
public final static String SP_CITY = "市辖区";

public static void initData() throws IOException {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:data/divisions.json");
ObjectMapper objectMapper = new ObjectMapper();
List<ChildrenCode> divisions = objectMapper.readValue(resource.getInputStream(), new TypeReference<>() {
});
Divisions.pca = divisions;
for (ChildrenCode division : divisions) {
Divisions.provinces.add(new Divisions.Province(division.getCode() + "0000", division.getName()));
Divisions.provinceMap.put(division.getName(), division.getCode() + "0000");
if (!division.getChildren().isEmpty()) {
for (ChildrenCode child1 : division.getChildren()) {
if (SP_CITY.equals(child1.getName())) {
child1.setName(division.getName() + child1.getName());
Divisions.cityMap.put(division.getName(), division.getCode() + "0000");
}
Divisions.cities.add(new Divisions.City(child1.getCode() + "00", child1.getName()));
Divisions.cityMap.put(child1.getName(), child1.getCode() + "00");
if (!child1.getChildren().isEmpty()) {
for (ChildrenCode child2 : child1.getChildren()) {
Divisions.areas.add(new Divisions.Area(child2.getCode(), child2.getName()));
if ((division.getName() + SP_CITY).equals(child1.getName())) {
Divisions.areaMap.put(division.getName() + child2.getName(), child2.getCode());
} else {
Divisions.areaMap.put(child1.getName() + child2.getName(), child2.getCode());
}
}
}
}
}
}
}

public static Map<String, String> addressResolution(String address) {
String temp;
for (String city : CITIES) {
if (address.indexOf(city) == 0 && !address.contains(SP_CITY)) {
temp = StrUtil.removePrefix(address, city);
if (temp.indexOf(city) != 0) {
address = city + address;
break;
}
}
}
String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
Matcher m = Pattern.compile(regex).matcher(address);
String province, city, county, town, village;
Map<String, String> row = new LinkedHashMap<>();
while (m.find()) {
province = m.group(PROVINCE);
row.put(PROVINCE, province == null ? "" : province.trim());
city = m.group(CITY);
row.put(CITY, city == null ? "" : city.trim());
county = m.group(COUNTY);
row.put(COUNTY, county == null ? "" : county.trim());
town = m.group("town");
row.put("town", town == null ? "" : town.trim());
village = m.group(VILLAGE);
row.put(VILLAGE, village == null ? "" : village.trim());
}
return row;
}

public static Map<String, String> addressCodeResolution(String address) {
if (ADDRESS.equals(checkChinesAddress(address))) {
Map<String, String> map = addressResolution(address);
String province = map.get(PROVINCE);
String city = map.get(CITY);
map.put(PROVINCE, getCode(PROVINCE, map.get(PROVINCE)));
map.put(CITY, getCode(CITY, map.get(CITY)));
if (SP_CITY.equals(city)) {
map.put(CITY, getCode(CITY, province + city));
city = province;
}
map.put(COUNTY, getCode(COUNTY, city + map.get(COUNTY)));
return map;
}
return null;
}

public static String getCode(String type, String name) {
return switch (type) {
case PROVINCE -> Divisions.provinceMap.get(name);
case CITY -> Divisions.cityMap.get(name);
case COUNTY -> Divisions.areaMap.get(name);
default -> name;
};
}

public static String checkChinesAddress(String address) {
Map<String, String> map = addressResolution(address);
if (map.size() == 0) {
return STYLE;
}
if (StrUtil.isBlank(map.get(PROVINCE))) {
return PROVINCE;
}
if (StrUtil.isBlank(map.get(CITY))) {
return CITY;
}
if (StrUtil.isBlank(map.get(COUNTY))) {
return COUNTY;
}
if (StrUtil.isBlank(map.get(VILLAGE))) {
return VILLAGE;
}
return ADDRESS;
}

单元测试

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
@Test
void test() {
log.debug("{}", ChineseAddress.addressResolution("湖北省武汉市洪山区xx路"));
log.debug("{}", ChineseAddress.addressResolution("湖北省恩施土家族苗族自治州恩施市xx路"));
log.debug("{}", ChineseAddress.addressResolution("北京市市辖区朝阳区xx路"));
log.debug("{}", ChineseAddress.addressResolution("北京市北京市朝阳区xx路"));
log.debug("{}", ChineseAddress.addressResolution("北京市朝阳区xx路"));
log.debug("{}", ChineseAddress.addressResolution("内蒙古自治区兴安盟科尔沁右翼前旗xx路"));
log.debug("{}", ChineseAddress.addressResolution("西藏自治区日喀则地区日喀则市xx路"));
log.debug("{}", ChineseAddress.addressResolution("海南省省直辖县级行政单位中沙群岛的岛礁及其海域xx路"));
log.debug("{}", ChineseAddress.addressResolution("广东省深南大道100号"));
assertEquals(ChineseAddress.ADDRESS, ChineseAddress.checkChinesAddress("北京市朝阳区xx路"));
assertEquals(ChineseAddress.VILLAGE, ChineseAddress.checkChinesAddress("北京市朝阳区"));
assertEquals(ChineseAddress.ADDRESS, ChineseAddress.checkChinesAddress("北京市北京市朝阳区xx路"));
assertEquals(ChineseAddress.VILLAGE, ChineseAddress.checkChinesAddress("北京市北京市朝阳区"));
assertEquals(ChineseAddress.PROVINCE, ChineseAddress.checkChinesAddress("朝阳区xx路"));
assertEquals(ChineseAddress.PROVINCE, ChineseAddress.checkChinesAddress("xx路"));
assertEquals(ChineseAddress.COUNTY, ChineseAddress.checkChinesAddress("北京市xx路"));
assertEquals(ChineseAddress.PROVINCE, ChineseAddress.checkChinesAddress("深圳市xx路"));
assertEquals(ChineseAddress.COUNTY, ChineseAddress.checkChinesAddress("广东省深圳市xx路"));
assertEquals(ChineseAddress.STYLE, ChineseAddress.checkChinesAddress("广东省xx路"));
assertEquals(ChineseAddress.VILLAGE, ChineseAddress.checkChinesAddress("广东省深圳市南山区"));
assertEquals(ChineseAddress.ADDRESS, ChineseAddress.checkChinesAddress("广东省深圳市南山区xx路"));
assertEquals(ChineseAddress.ADDRESS, ChineseAddress.checkChinesAddress("上海市浦江镇xx路"));
log.debug("{}", ChineseAddress.addressResolution("广东省深南大道100号"));
log.debug("{}", ChineseAddress.addressResolution("广东省深圳市南山区深南大道100号"));
log.debug("{}", ChineseAddress.addressCodeResolution("广东省深圳市南山区深南大道100号"));
log.debug("{}", ChineseAddress.addressResolution("北京市朝阳区xx路"));
log.debug("{}", ChineseAddress.addressCodeResolution("北京市朝阳区xx路"));
log.debug("{}", ChineseAddress.addressResolution("北京市市辖区朝阳区xx路"));
log.debug("{}", ChineseAddress.addressCodeResolution("北京市市辖区朝阳区xx路"));
log.debug("{}", ChineseAddress.addressCodeResolution("上海市虹口区**路8号"));
log.debug("{}", ChineseAddress.addressCodeResolution("上海市市辖区虹口区**路8号"));
}

说明

  • PlantUML是一个可以快速编写的组件
  • 代码画图,方便管理,专注逻辑,不用关心格式,格式自动完成
  • 支持的图有
    • 时序图
    • 架构图
    • 流程图
    • 对象图
    • 脑图
    • 甘特图

时序图

1
2
3
4
5
6
7
8
9
10

scale max 800 width
scale max 800 height

客户 -> H5: 微信
H5 -> 后台: 登录

后台 -> H5: 登录成功
H5 -> 客户: 进入系统

架构图 - C4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
!include <C4/C4_Container>

HIDE_STEREOTYPE()

scale max 800 width
scale max 800 height

Person(customer, "客户")

System(h5, "H5")
System(system, "后台")

ContainerDb(db, "数据库", "user")

Rel(customer, h5, "https", "443")
Rel(h5, system, "https", "443")
Rel(system, db, "tcp", "3306")

架构图 - Native

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

' left to right direction

<style>
componentDiagram {
BackGroundColor #f9f8ed
LineThickness 2
LineColor #283644
}
</style>

scale max 800 width
scale max 800 height

component "客户" as customer #2eb872

node "H5" as h5 #2eb872

node "后台" as system #2eb872

database oracle as oracle #2eb872 {
label "user" as user
}

customer -> h5
h5 -> system
system -> oracle

流程图

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

' 固定宽度
scale max 800 width
scale max 800 height

start
:注册页面;
:输入密码;
if (是否注册?) is (是) then
:登录;
end
else (否)
:获取手机验证码;
:注册;
note right
注释
end note
end
endif

脑图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@startmindmap
scale max 800 width
scale max 800 height
* Debian
** Ubuntu
*** Linux Mint
*** Kubuntu
*** Lubuntu
*** KDE Neon
** LMDE
** SolydXK
** SteamOS
** Raspbian with a very long name
*** <s>Raspmbc</s> => OSMC
*** <s>Raspyfi</s> => Volumio
@endmindmap

甘特图

1
2
3
4
5
6
7
8
9
10
11
12
13
@startuml
saturday are closed
sunday are closed

Project starts 2022-01-01
[Prototype design end] as [TASK1] lasts 19 days
[TASK1] is colored in Lavender/LightBlue
[Testing] lasts 14 days
[TASK1]->[Testing]

2022-01-18 to 2022-01-22 are colored in salmon
@enduml

Json

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
@startjson
#highlight "lastName"
#highlight "address" / "city"
#highlight "phoneNumbers" / "0" / "number"
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 28,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null
}
@endjson

obsidian 说明

  • obsidian是基于本地目录的知识管理软件
  • 完美支持markdown
  • 双链
  • 可以用云盘同步
  • 可以跨平台使用
  • 下载地址

obsidian icloud 同步

1. 同步软件 comfile

comfile

2. 同步方法

method

3. obsidian 插件

plugin

制作Windows 10的U盘启动镜像

设置bios

  • 先按住音量+,该按键和电源键都有特殊标记
  • 设置USB启动
  • 安全启动模式:disabled

安装Windows 10

  • 直接安装
  • 可能出现触摸板无法使用的情况
  • 请用USB-HUB,连接安装U盘和USB的鼠标或者键盘

升级操作系统

  • 下载补丁
  • 累积更新地址
  • 搜索关键词:2020 03 累积更新 Windows 10
  • 下载自己对应版本Windows10的更新包
  • 安装更新包

安装Surface驱动

驱动安装不上的情况

  • 解压驱动包
    1
    msiexec /a "D:\SurfaceLaptop3_Win10_17763_20.020.4371.0.msi" /qb TARGETDIR="D:\Drivers"
  • 再解压的文件夹逐个安装驱动程序即可

1
2
3
4
5
6
7
8
9
10
server {
listen 80;
server_name test.com www.test.com;
return 301 https://test.com$request_uri;
}

server {
listen 443 ssl http2;
server_name www.test.com;
}

grep单关键字查看日志

1
grep 'key' server.log

grep双关键字查看日志

1
grep 'key.*key' server.log

grep查看行号

1
2
3
4
5
6
# 出现key1******key2
grep -n 'key1.*key2' server.log
# 出现key1或者key2
grep -E 'key1|key2' server.log
# 出现key1或者key2
grep 'key1' server.log|grep 'key2'

grep查看前后多少行

1
2
3
grep -n 'key.*key' server.log
-A 10 后10行,A=After
-B 10 前10行,B=Before

head&tail

1
2
3
4
5
head 查看日志头部
tail 查看日志尾部

tail -f 从尾部滚动日志
tail -f -n 100 从尾部100行开始滚动日志

sed查看多少行到多少行的日志

1
2
# 查看server.log的100行到110行的日志
sed -n '100,110p' server.log

git子模块

就是git子项目
git的一个目录打开还是git项目

父项目

git clone 一个已有的项目

子项目

得先有一个已经存在的项目
git submodule add git子项目地址 新的目录名
完成后目录出现.gitmodules文件

1
2
3
[submodule "submodule"]
path = submodule
url = https://github.com/submodule.git

官方文档

1
2
3
git clone https://github.com/parent.git project
cd project
git submodule add https://github.com/submodule.git submodule
1
2
3
git clone https://github.com/parent.git project
git submodule init
git submodule update

spring-boot-maven-plugin

1
2
3
4
5
6
7
8
9
10
11
12
<properties>
<start-class>com.cifm.ds.account.AccountApp</start-class>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
  1. 打包可执行的jar包
  2. 不要放在不是运行jar的pom.xml文件中,否则出现👇错误

Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.2.0.M1:repackage failed: Unable to find main class

dubbo的序列化与spring

1
2
3
4
5
# dubbo的序列化的序列化有问题
# 主要是类型的定义,比如int类型,序列化后值都为0
# 还有其他的未知原因
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

自定义spring boot jpa Repository

1
2
3
4
5
6
@NoRepositoryBean
public interface BaseRepository<T extends Serializable, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
}

# 此处很重要,不加,spring boot jpa 会把BaseRepository定义的方法当做T的属性去解析
@EnableJpaRepositories(repositoryBaseClass = BaseRepositoryImpl.class)

spring boot test

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
public interface AutoTest {
}
public interface SelfTest {
}

@Category(AutoTest.class)
public class OutTest {
@Test
public void out1() {
log.info("hello");
}
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApp.class)
@Category(SelfTest.class)
public class AccountTest {
}

/**
* 执行此测试类,只会执行OutTest的测试类,AccountTest的测试类不会执行
*/
@RunWith(Categories.class)
@IncludeCategory(AutoTest.class)
@ExcludeCategory(SelfTest.class)
@SuiteClasses({OutTest.class, AccountTest.class})
public class AccountTestSuite {
}

mvn 排除部分测试类不进入自动测试

1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>com/lendo/test/account/self/**</exclude>
</excludes>
</configuration>
</plugin>

openssl 新建RSA公钥私钥

1
2
3
4
5
6
7
8
# 私钥
openssl genrsa -out key.pem 1024
# 公钥
openssl rsa -in key.pem -pubout -out pubkey.pem
# 转换为pkcs8格式的私钥,Java读取的就是这个格式
openssl pkcs8 -topk8 -inform PEM -in key.pem -outform pem -nocrypt -out pkcs8.pem
# 转换rsa私钥,参考
openssl rsa -in pkcs8.pem -out pkcs1.pem

私钥的区别

1
2
3
4
# rsa私钥的头部
-----BEGIN RSA PRIVATE KEY-----
# pkcs8格式的私钥的头部
-----BEGIN PRIVATE KEY-----

jasypt maven

1
2
3
4
5
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>

jasypt的用法

1
2
3
4
5
6
7
8
9
10
# jasypt配置,本地采用PEM的RSA私钥解密
jasypt:
encryptor:
privateKeyFormat: PEM
privateKeyLocation: classpath:key.pem

# 配置密码的部分用ENC(******)
spring:
mail:
password: ENC(******)

jasypt生成密文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.ulisesbocchio.jasyptspringboot.encryptor.SimpleAsymmetricConfig;
import com.ulisesbocchio.jasyptspringboot.encryptor.SimpleAsymmetricStringEncryptor;
import org.jasypt.encryption.StringEncryptor;

SimpleAsymmetricConfig config = new SimpleAsymmetricConfig();
config.setKeyFormat(PEM);
config.setPublicKey("-----BEGIN PUBLIC KEY-----\n"
+ "******\n"
+ "-----END PUBLIC KEY-----\n");
config.setPrivateKey("-----BEGIN PRIVATE KEY-----\n"
+ "******\n"
+ "-----END PRIVATE KEY-----\n");
StringEncryptor encryptor = new SimpleAsymmetricStringEncryptor(config);
String message = "passord";
String encrypted = encryptor.encrypt(message);
System.out.printf("Encrypted message %s\n", encrypted);
System.out.printf("Decrypted message %s\n", encryptor.decrypt(encrypted));