JoyLau's Blog

JoyLau 的技术学习与思考

配置

  1. 端口: port: 7890 ; socks-port: 7891
  2. 运行局域网访问: allow-lan: true
  3. 对外提供 rest 接口: external-controller: 0.0.0.0:8080
  4. dashboard 路径: external-ui: /ui
  5. 配置文件 yaml, 挂载到: /root/.config/clash/config.yaml

运行

1
docker run -d --name clash-client --restart always -p 7890:7890 -p 7891:7891 -p 8080:8080 -v /path/config.yaml:/root/.config/clash/config.yaml -v /path/ui:/ui dreamacro/clash

Dashboard

  1. 使用官方的 Dashboard : https://github.com/Dreamacro/clash-dashboard/tree/gh-pages
  2. 使用另一个第三方看起来很炫酷的 Dashboard: https://github.com/haishanh/yacd/tree/gh-pages

配置文件

既然对外提供服务, 最好加密, 包括 Dashboard 加密和 http, socks 代理加用户名密码认证

1
2
3
4
5
6
7
8
9
10
11
12
13
port: 7890
socks-port: 7891
allow-lan: true
mode: Rule
log-level: info
external-controller: '0.0.0.0:9090'
secret: 'passwd'
external-ui: /ui
authentication:
- "user:passwd"
Proxy:
Proxy Group:
Rule:

启动之后,便可以使用 Dashboard 来操作 Clash 了.

规则解释

  • DOMAIN-SUFFIX:域名后缀匹配
  • DOMAIN:域名匹配
  • DOMAIN-KEYWORD:域名关键字匹配
  • IP-CIDR:IP段匹配
  • SRC-IP-CIDR:源IP段匹配
  • GEOIP:GEOIP数据库(国家代码)匹配
  • DST-PORT:目标端口匹配
  • SRC-PORT:源端口匹配
  • MATCH:全匹配(一般放在最后)

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
port: 7890
socks-port: 7891
allow-lan: false
mode: Rule
log-level: info
external-controller: 127.0.0.1:9090

Proxy:

Proxy Group:

Rule:
- DOMAIN-SUFFIX,google.com,DIRECT
- DOMAIN-KEYWORD,google,DIRECT
- DOMAIN,google.com,DIRECT
- DOMAIN-SUFFIX,ad.com,REJECT
- GEOIP,CN,DIRECT
- MATCH,DIRECT

额外支持特定的字段:

  • cfw-latency-timeout:延迟测试超时时间(毫秒),默认3000
  • cfw-latency-url:延迟测试URL,默认http://www.gstatic.com/generate_204
  • cfw-bypass:系统代理绕过域名或地址,参考 绕过系统代理
  • cfw-conn-break-strategy: 切换节点后或切换配置文件后打断连接
  • cfw-profiles-path: 自定义 profiles 目录路径 (beta)

这些配置关乎Clash核心是否能正常启动,如非必要,请勿更改

完全配置记录

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#---------------------------------------------------#
## 配置文件需要放置在 $HOME/.config/clash/config.yml
##
## 如果您不知道如何操作,请参阅 SS-Rule-Snippet 的 Wiki:
## https://github.com/Hackl0us/SS-Rule-Snippet/wiki/clash(X)
#---------------------------------------------------#

# HTTP 代理端口
port: 7890

# SOCKS5 代理端口
socks-port: 7891

# Linux 和 macOS 的 redir 代理端口 (如需使用此功能,请取消注释)
# redir-port: 7892

# 允许局域网的连接(可用来共享代理)
allow-lan: false
# bind-address: "*"
# 此功能仅在 allow-lan 设置为 true 时生效,支持三种参数:
# "*" 绑定所有的 IP 地址
# 192.168.122.11 绑定一个的 IPv4 地址
# "[aaaa::a8aa:ff:fe09:57d8]" 绑定一个 IPv6 地址

# 规则模式:Rule(规则) / Global(全局代理)/ Direct(全局直连)
mode: Rule

# 设置日志输出级别 (默认级别:silent,即不输出任何内容,以避免因日志内容过大而导致程序内存溢出)。
# 5 个级别:silent / info / warning / error / debug。级别越高日志输出量越大,越倾向于调试,若需要请自行开启。
log-level: silent

# clash 的 RESTful API
external-controller: 127.0.0.1:9090

# 您可以将静态网页资源(如 clash-dashboard)放置在一个目录中,clash 将会服务于 `${API}/ui`
# 参数应填写配置目录的相对路径或绝对路径。
# external-ui: folder

# RESTful API 的口令 (可选)
# secret: ""

# 实验性功能
experimental:
ignore-resolve-fail: true # 忽略 DNS 解析失败,默认值为 true

# 本地 SOCKS5 / HTTP(S) 服务认证
# authentication:
# - "user1:pass1"
# - "user2:pass2"

# # 实验性功能 hosts, 支持通配符 (例如 *.clash.dev 甚至 *.foo.*.example.com)
# # 静态的域名 比 通配域名 具有更高的优先级 (foo.example.com 优先于 *.example.com)
# # 注意: hosts 在 fake-ip 模式下不生效
# hosts:
# '*.clash.dev': 127.0.0.1
# 'alpha.clash.dev': '::1'

dns:
enable: true
ipv6: false
# listen: 0.0.0.0:53
# enhanced-mode: redir-host # 或 fake-ip
# # fake-ip-range: 198.18.0.1/16 # 如果你不知道这个参数的作用,请勿修改
# fake-ip-filter: # fake-ip 白名单列表
# - '*.lan'
# - localhost.ptlogin2.qq.com

nameserver:
- 1.2.4.8
- 114.114.114.114
- 223.5.5.5
- tls://13800000000.rubyfish.cn:853
#- https://13800000000.rubyfish.cn/

fallback: # 与 nameserver 内的服务器列表同时发起请求,当规则符合 GEOIP 在 CN 以外时,fallback 列表内的域名服务器生效。
- tls://13800000000.rubyfish.cn:853
- tls://1.0.0.1:853
- tls://dns.google:853

#- https://13800000000.rubyfish.cn/
#- https://cloudflare-dns.com/dns-query
#- https://dns.google/dns-query

fallback-filter:
geoip: true # 默认
ipcidr: # 在这个网段内的 IP 地址会被考虑为被污染的 IP
- 240.0.0.0/4

# 1. clash DNS 请求逻辑:
# (1) 当访问一个域名时, nameserver 与 fallback 列表内的所有服务器并发请求,得到域名对应的 IP 地址。
# (2) clash 将选取 nameserver 列表内,解析最快的结果。
# (3) 若解析结果中,IP 地址属于 国外,那么 clash 将选择 fallback 列表内,解析最快的结果。
#
# 因此,我在 nameserver 和 fallback 内都放置了无污染、解析速度较快的国内 DNS 服务器,以达到最快的解析速度。
# 但是 fallback 列表内服务器会用在解析境外网站,为了结果绝对无污染,我仅保留了支持 DoT/DoH 的两个服务器。
#
# 2. clash DNS 配置注意事项:
# (1) 如果您为了确保 DNS 解析结果无污染,请仅保留列表内以 tls:// 或 https:// 开头的 DNS 服务器,但是通常对于国内域名没有必要。
# (2) 如果您不在乎可能解析到污染的结果,更加追求速度。请将 nameserver 列表的服务器插入至 fallback 列表内,并移除重复项。
#
# 3. 关于 DNS over HTTPS (DoH) 和 DNS over TLS (DoT) 的选择:
# 对于两项技术双方各执一词,而且会无休止的争论,各有利弊。各位请根据具体需求自行选择,但是配置文件内默认启用 DoT,因为目前国内没有封锁或管制。
# DoH: 以 https:// 开头的 DNS 服务器。拥有更好的伪装性,且几乎不可能被运营商或网络管理封锁,但查询效率和安全性可能略低。
# DoT: 以 tls:// 开头的 DNS 服务器。拥有更高的安全性和查询效率,但端口有可能被管制或封锁。
# 若要了解更多关于 DoH/DoT 相关技术,请自行查阅规范文档。


Proxy:
# shadowsocks
# 所支持的加密方式与 go-shadowsocks2 保持一致
# 支持加密方式:
# aes-128-gcm aes-192-gcm aes-256-gcm
# aes-128-cfb aes-192-cfb aes-256-cfb
# aes-128-ctr aes-192-ctr aes-256-ctr
# rc4-md5 chacha20 chacha20-ietf xchacha20
# chacha20-ietf-poly1305 xchacha20-ietf-poly1305

- name: "ss1"
type: ss
server: server
port: 443
cipher: chacha20-ietf-poly1305
password: "password"
# udp: true

- name: "ss2"
type: ss
server: server
port: 443
cipher: AEAD_CHACHA20_POLY1305
password: "password"
plugin: obfs
plugin-opts:
mode: tls # 混淆模式,可以选择 http 或 tls
host: bing.com # 混淆域名,需要和服务器配置保持一致

- name: "ss3"
type: ss
server: server
port: 443
cipher: AEAD_CHACHA20_POLY1305
password: "password"
plugin: v2ray-plugin
plugin-opts:
mode: websocket # 暂时不支持 QUIC 协议
# tls: true # wss
# skip-cert-verify: true
# host: bing.com
# path: "/"
# headers:
# custom: value

# vmess
# 支持加密方式:auto / aes-128-gcm / chacha20-poly1305 / none
- name: "vmess"
type: vmess
server: server
port: 443
uuid: uuid
alterId: 32
cipher: auto
# udp: true
# tls: true
# skip-cert-verify: true
# network: ws
# ws-path: /path
# ws-headers:
# Host: v2ray.com

# socks5
- name: "socks"
type: socks5
server: server
port: 443
# username: username
# password: password
# tls: true
# skip-cert-verify: true
# udp: true

# http
- name: "http"
type: http
server: server
port: 443
# username: username
# password: password
# tls: true # https
# skip-cert-verify: true

# snell
- name: "snell"
type: snell
server: server
port: 44046
psk: yourpsk
# obfs-opts:
# mode: http # 或 tls
# host: bing.com

Proxy Group:
# url-test 可以自动选择与指定 URL 测速后,延迟最短的服务器
- name: "auto"
type: url-test
proxies:
- ss1
- ss2
- vmess1
url: 'http://www.gstatic.com/generate_204'
interval: 300

# fallback 可以尽量按照用户书写的服务器顺序,在确保服务器可用的情况下,自动选择服务器
- name: "fallback-auto"
type: fallback
proxies:
- ss1
- ss2
- vmess1
url: 'http://www.gstatic.com/generate_204'
interval: 300

# load-balance 可以使相同 eTLD 请求在同一条代理线路上
- name: "load-balance"
type: load-balance
proxies:
- ss1
- ss2
- vmess1
url: 'http://www.gstatic.com/generate_204'
interval: 300

# select 用来允许用户手动选择 代理服务器 或 服务器组
# 您也可以使用 RESTful API 去切换服务器,这种方式推荐在 GUI 中使用
- name: Proxy
type: select
proxies:
- ss1
- ss2
- vmess1
- auto

Rule:
# 抗 DNS 污染
- DOMAIN-KEYWORD,amazon,Proxy
- DOMAIN-KEYWORD,google,Proxy
- DOMAIN-KEYWORD,gmail,Proxy
- DOMAIN-KEYWORD,youtube,Proxy
- DOMAIN-KEYWORD,facebook,Proxy
- DOMAIN-SUFFIX,fb.me,Proxy
- DOMAIN-SUFFIX,fbcdn.net,Proxy
- DOMAIN-KEYWORD,twitter,Proxy
- DOMAIN-KEYWORD,instagram,Proxy
- DOMAIN-KEYWORD,dropbox,Proxy
- DOMAIN-SUFFIX,twimg.com,Proxy
- DOMAIN-KEYWORD,blogspot,Proxy
- DOMAIN-SUFFIX,youtu.be,Proxy
- DOMAIN-KEYWORD,whatsapp,Proxy

# 常见广告域名屏蔽
- DOMAIN-KEYWORD,admarvel,REJECT
- DOMAIN-KEYWORD,admaster,REJECT
- DOMAIN-KEYWORD,adsage,REJECT
- DOMAIN-KEYWORD,adsmogo,REJECT
- DOMAIN-KEYWORD,adsrvmedia,REJECT
- DOMAIN-KEYWORD,adwords,REJECT
- DOMAIN-KEYWORD,adservice,REJECT
- DOMAIN-KEYWORD,domob,REJECT
- DOMAIN-KEYWORD,duomeng,REJECT
- DOMAIN-KEYWORD,dwtrack,REJECT
- DOMAIN-KEYWORD,guanggao,REJECT
- DOMAIN-KEYWORD,lianmeng,REJECT
- DOMAIN-SUFFIX,mmstat.com,REJECT
- DOMAIN-KEYWORD,omgmta,REJECT
- DOMAIN-KEYWORD,openx,REJECT
- DOMAIN-KEYWORD,partnerad,REJECT
- DOMAIN-KEYWORD,pingfore,REJECT
- DOMAIN-KEYWORD,supersonicads,REJECT
- DOMAIN-KEYWORD,uedas,REJECT
- DOMAIN-KEYWORD,umeng,REJECT
- DOMAIN-KEYWORD,usage,REJECT
- DOMAIN-KEYWORD,wlmonitor,REJECT
- DOMAIN-KEYWORD,zjtoolbar,REJECT

# LAN
- DOMAIN-SUFFIX,local,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT

# 最终规则
- GEOIP,CN,DIRECT
- MATCH,Proxy

绕过系统代理

Clash for Windows在v 0.4.5 版本后可以自定义系统代理需要绕过的域名或IP

部分应用检测到系统代理会拒绝响应(例如网易云音乐uwp),此功能用于解决此类问题

设置方式
config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
port: 8888
socks-port: 8889
redir-port: 0
allow-lan: true
mode: Rule
log-level: info
external-controller: '0.0.0.0:6170'
secret: ''
Proxy:
...
Proxy Group:
...
Rule:
...
cfw-bypass:
... # 原有字段不用删除
- 'music.163.com' # 网易云域名1
- '*.music.126.net' # 网易云域名2

cfw-bypass类型为数组,item为需要绕过的域名或节点,支持通配符*

最后一行对应系统中“请勿将代理服务器用于本地(Intranet)地址”选项,请确保此项在最底部

版本环境

  1. Elasticsearch 6.4.3
  2. SpringBoot 2.1.2.RELEASE

引入依赖

1
compile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version: '6.4.3'

配置

其实引入这依赖后, spring-boot-autoconfigure-2.1.2.RELEASE.jar 这个依赖你会为你自动配置 RestHighLevelClient, 而不需要手动创建 RestHighLevelClient

代码具体位置:

org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration

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
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.autoconfigure.elasticsearch.rest;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch REST clients.
*
* @author Brian Clozel
* @since 2.1.0
*/
@Configuration
@ConditionalOnClass(RestClient.class)
@EnableConfigurationProperties(RestClientProperties.class)
public class RestClientAutoConfiguration {

private final RestClientProperties properties;

private final ObjectProvider<RestClientBuilderCustomizer> builderCustomizers;

public RestClientAutoConfiguration(RestClientProperties properties,
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
this.properties = properties;
this.builderCustomizers = builderCustomizers;
}

@Bean
@ConditionalOnMissingBean
public RestClient restClient(RestClientBuilder builder) {
return builder.build();
}

@Bean
@ConditionalOnMissingBean
public RestClientBuilder restClientBuilder() {
HttpHost[] hosts = this.properties.getUris().stream().map(HttpHost::create)
.toArray(HttpHost[]::new);
RestClientBuilder builder = RestClient.builder(hosts);
PropertyMapper map = PropertyMapper.get();
map.from(this.properties::getUsername).whenHasText().to((username) -> {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
Credentials credentials = new UsernamePasswordCredentials(
this.properties.getUsername(), this.properties.getPassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider));
});
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
return builder;
}

@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
public static class RestHighLevelClientConfiguration {

@Bean
@ConditionalOnMissingBean
public RestHighLevelClient restHighLevelClient(
RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}

}

}

不过需要先配置 spring.elasticsearch.rest 配置

1
2
3
4
5
6
spring:
elasticsearch:
rest:
uris:
username:
password:

默认只配置了 hosts 和 username password, 如果要加更多配置的话, 建议重新添加 RestClientBuilder 的配置

当然也可以全部手动配置, 我这里给一个参考:

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
package cn.joylau.code.config.elasticsearch.highLevelClient;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
* Created by joylau on 2020/4/27.
* cn.joylau.code.config.elasticsearch.highLevelClient
* 2587038142.liu@gmail.com
*/
@Configuration
public class ElasticSearchClient {
/** 协议 */
@Value("${elasticsearch.schema:http}")
private String schema;

/** 集群地址,如果有多个用“,”隔开 */
@Value("${elasticsearch.address}")
private String address;

/** 连接超时时间 */
@Value("${elasticsearch.connectTimeout:5000}")
private int connectTimeout;

/** Socket 连接超时时间 */
@Value("${elasticsearch.socketTimeout:10000}")
private int socketTimeout;

/** 获取连接的超时时间 */
@Value("${elasticsearch.connectionRequestTimeout:5000}")
private int connectionRequestTimeout;

/** 最大连接数 */
@Value("${elasticsearch.maxConnectNum:100}")
private int maxConnectNum;

/** 最大路由连接数 */
@Value("${elasticsearch.maxConnectPerRoute:100}")
private int maxConnectPerRoute;

@Bean
public RestHighLevelClient restHighLevelClient() {
// 拆分地址
List<HttpHost> hostLists = new ArrayList<>();
String[] hostList = address.split(",");
for (String addr : hostList) {
String host = addr.split(":")[0];
String port = addr.split(":")[1];
hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
}
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
// 异步连接延时配置
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(connectTimeout);
requestConfigBuilder.setSocketTimeout(socketTimeout);
requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
return requestConfigBuilder;
});
// 异步连接数配置
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(maxConnectNum);
httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
return httpClientBuilder;
});
return new RestHighLevelClient(builder);
}
}

背景

在网络上搜索关于 ClashX 的教程, 看到的截图都是中文的界面, 而我安装后的界面语言却是英文的, 就想着怎么能够切换下
在软件的设置里, 没有找到设置语言的选项

操作

去作者的 Github 去看了下代码, 发现是有中英文的配置的
那么既然作者做了语言环境适配, 那么在安装包里肯定有语言文件

  1. Applications 右键 ClashX ,显示包内容
  2. 进入 Resources 目录, 看到 en.lprojzh-Hans.lproj
  3. zh-Hans.lproj 目录里的文件拷贝并覆盖掉 en.lproj 里的文件
  4. 重启软件即可

工具

  1. PowerDesigner 16.5

注意

使用 PowerDesigner 的原生方式连接各种数据库我遇到很多问题, 于是,这里我都是使用的 JDBC 的方式连接

使用 JDBC 方式连接需要注意一下几点

  1. JDK 的版本必须是 32 位的
  2. 需要 JDBC 的驱动 jar 包
  3. 需要新建 CLASSPATH 环境变量, 并且将驱动 jar 包的路径配置到 CLASSPATH 中, 否则的话会导致无法加载驱动类

步骤

  1. File -> New Module, 选择 Physical Diagram, DBMS 选择实际的数据库类型
  2. 选择 Database -> Configure Connections… -> Connection Profiles , 选择 第二个图标, add data source
  3. Connections Type 现在 JDBC, 然后根据实际情况填写, 注意最后一项的 JDBC driver jar files 的文件需要配置的 CLASSPATH 环境变量中去, 如果已经配置了, 则此项都可以不用选择,亲测
  4. 点击测试,没有问题,保存即可
  5. 选择 Database -> Update Model from Database , 选择需要的表
  6. 此时双击表,可能没有注释, 需要双击表,弹出表属性对话框,切到 ColumnTab ,默认是没显示 Comment 的,此时点击漏斗状的按钮 Customize Columns and Filter, 勾选 Comment

设置物理模型显示注释

  1. Tools>Display Perferences..
  2. 进入 Table, 先勾选 Comment
  3. 再点击 Advanced -> Columns , 点击 List columns 右边的按钮 select , 选择上 code, 并将位置调的最上方, 点击确定
  4. Tools>Execute Commands>Edit/Run Script.., 执行下面的脚本, 脚本的作用是将 NAME 替换成 COMMENT
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
Option   Explicit   
ValidationMode = True
InteractiveMode = im_Batch
Dim blankStr
blankStr = Space(1)
Dim mdl ' the current model

' get the current active model
Set mdl = ActiveModel
If (mdl Is Nothing) Then
MsgBox "There is no current Model "
ElseIf Not mdl.IsKindOf(PdPDM.cls_Model) Then
MsgBox "The current model is not an Physical Data model. "
Else
ProcessFolder mdl
End If

Private sub ProcessFolder(folder)
On Error Resume Next
Dim Tab 'running table
for each Tab in folder.tables
if not tab.isShortcut then
tab.name = tab.comment
Dim col ' running column
for each col in tab.columns
if col.comment = "" or replace(col.comment," ", "")="" Then
col.name = blankStr
blankStr = blankStr & Space(1)
else
col.name = col.comment
end if
next
end if
next

Dim view 'running view
for each view in folder.Views
if not view.isShortcut then
view.name = view.comment
end if
next

' go into the sub-packages
Dim f ' running folder
For Each f In folder.Packages
if not f.IsShortcut then
ProcessFolder f
end if
Next
end sub

背景

之前看到一个像素时钟 LaMeetric Time, 感觉很漂亮, 但是太贵,淘宝上要卖到 2000 块左右
后来又看到一个项目 AWTRIX : https://awtrixdocs.blueforcer.de/#/en-en/
作者在他的网站上介绍了如何制作一个像素时钟
于是,我就跟着他的文档后面做了起来

这玩意是什么??

  1. 首先它是一个时钟
  2. 其次,他能够通过 WIFI 连接到一个服务端, 服务端有 AppStore 能装很多 app 实现很多效果
  3. 我想用它来实时显示我博客的访客数, 当然,这需要我后期自己编码
  4. 好玩

材料

必须材料

  1. WS2812B 可编程像素软屏
  2. Wemos D1 mini ESP 8266 mini WIFI 开发板
  3. 杜邦连接线,公对母

如何你想要制作成我的这种效果, 你还需要

  1. 10V 1000uF 电容
  2. 电烙铁家用一套
  3. 5v 4A 2.5mm 电源
  4. 2.5mm 直流电源插头
  5. 手动修改官方 3D 打印图纸, 这是我修改好的图纸,其中前面板的高度调高了 3 mm : //s3.joylau.cn:9000//blog/awtrix2/3d打印图纸.zip
  6. 手摇自喷漆一罐
  7. 定制黑色半透明亚克力板一块,尺寸 335mm * 95mm * 3mm
  8. 通用超 520 粘胶一小瓶

服务端部署

这里最方便的莫过于 docker 部署

1
docker run -d --name awtrix2 -p 7000:7000 -p 7001:7001 --restart always -e TZ=Asia/Shanghai -v /path:/data whyet/awtrix2:latest

注意: 这里需要挂载容器里的目录 data, 否则重启后,安装的软件会丢失不见

客户端烧录

最简单的方式是使用 Windows 机器

  1. 下载烧录工具: https://blueforcer.de/downloads/ESP8266Flasher.exe
  2. 下载最新固件: https://blueforcer.de/awtrix/stable/firmware.bin
  3. 启动 ESP8266Flasher.exe 并在 “ Config” 选项卡中打开固件(单击齿轮选择固件)
  4. 返回到 “操作” 选项卡,如果未自动检测到正确的串口,则需要手动设置它
  5. 单击“ Flash”,然后等待该过程完成,在左下角会显示一个绿色的复选标记。
  6. 重新启动控制器

连接 WiFi

  1. 启动控制器
  2. 手机连接 SSID 为 “ AWTRIX Controller ” 的 WiFi, 密码是: awtrixxx
  3. 如果网页没有自动跳出,则可以使用任何浏览器将设置页面导航到 IP “ 172.217.28.1 ”
  4. 点击“配置WiFi”,进入实际设置页面,配置家里的 WLAN 的 SSID 和密码
  5. 主机 IP 则设置为之前 docker 部署的服务端的 IP, 注意不需要加端口号
  6. 如果你的像素屏不是 32* 8 ,则需要配置 MatrixType2, 这个不需要配置

如何重置控制器???

  1. 按住控制器的 reset 键 3-4 秒
  2. 等待重启
  3. 再按住 reset 键 3-4 秒
  4. 等待重启
  5. 此时如何屏上显示 RESET ,则重置成功

接线图

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

Siri 语音控制

28

29

前提

  1. 清楚 ENTRYPOINT 和 CMD 的 shell 和 exec 的 2 种写法
  2. 定义多个 CMD, 只有最后一个 CMD 生效
  3. 同时定义 ENTRYPOINT 和 CMD, 那么 ENTRYPOINT 会覆盖 CMD

总结的结论

  1. ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略
  2. ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数
  3. ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式
  4. Dockerfile 里至少定义一个 ENTRYPOINT 或者 CMD

下面是官方文档里 2 种组合情况

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

docker-entrypoint.sh 的使用

参照我 blog 的 Dockerfile 的 docker-entrypoint.sh

set -e

文件开头加上set -e, 这句语句告诉bash如果任何语句的执行结果不是true则应该退出

exec gosu www-data “$0” “$@”

使用 gosu 来切换身份,而不是 su
$0 代表当前的 shell 脚本名, $@ 代表 CMD 的第一个参数

exec “$@”

当在 docker-entrypoint.sh 执行了一些需要初始化的事情后,边去执行 CMD 定义的脚本

综合

1
2
3
4
5
6
7
8
9
#!/bin/bash
set -e
if [ "$1" = '/my-blog/bash/init.sh' -a "$(id -u)" = '0' ]; then
service nginx start
service fcgiwrap start
echo "☆☆☆☆☆ base service has started. ☆☆☆☆☆"
exec gosu www-data "$0" "$@"
fi
exec "$@"

解释: 如果 CMD 的第一个参数是 /my-blog/bash/init.sh,并且 当前用户是 root 的话, 那么启动 nginxfcgiwrap 服务,并切换到 www-data 的身份,带上参数 /my-blog/bash/init.sh, 再次运行 docker-entrypoint.sh

当再次执行该脚本时由于已经不是 root 用户了, 会直接执行 exec "$@", 于是直接执行带的参数,即 CMD 定义的脚本.

很多 Dockerfile 都是这样的做法,比如 MySQL , Redis

背景

有台老 iPhone 7,电池峰值只有 66%, 家人一直在用,想着买块电池换上,缝缝补补又三年….

步骤

  1. 使用 0.8mm 五角螺丝刀拆下充电口 2 边的螺丝
  2. 吹风机均匀加热手机 5 分钟, 使手机的边框的防水胶变软
  3. 使用吸盘吸住屏幕,并使用拆机片沿手机尾部慢慢切入,并沿着四周慢慢划开
  4. 注意手机的右侧,有屏幕和指纹的排线,切入右侧的时候需要小心
  5. 打开手机屏幕,将手机绑到一个瓶子上固定住

1

2

  1. 卸下下图位置的挡板,先断开电池的排线, 在断开指纹和屏幕的排线

4

3

  1. 断开电池尾部震动马达的排线和手机上面的排线接口

5

  1. 拿下屏幕,使用镊子挑开屏幕尾部的易拉胶,再慢慢抽出来, 我这里抽断了,再次使用吹风机在背部加热三分钟,然后在使用拆机片沿底部慢慢切入划开,注意不要硬撬,有风险

6

花了不少时间,电池都形变了

7

8

  1. 卸下的螺丝按位置摆放好

9

  1. 换上新电池,注意先扣上排线接口,再放入电池

  2. 依次接好之前挑开的排线,开机测试,查看电池容量, 测试电池充放电是否正常..

  3. 没有问题,再次关机, 在电池背部贴上易拉胶,上好之前卸下的螺丝,扣上屏幕

  4. 满血复活

10

0%