logback过滤日志

问题

logback通过配置日志level可以关闭指定class或者package输出的日志。那么,有没有办法只过滤满足某些特征的部分日志,而不是全关呢?

方法

Logback用户手册 Chapter 7: Filters

  • 普通类型的Filter都通过添加到Appender来对日志进行过滤。
  • TurboFilter绑定到logging context,所以可以对所有的log事件进行过滤,它的处理范围更广。

本文主要介绍普通类型的Filter使用。

按日志级别过滤

1
2
3
4
5
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>

按内容进行过滤

dubbo的ZookeeperRegistry会info输出订阅provider的更新信息,若想过滤掉这个日志不输出,可以这么配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<appender name="RF" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<!-- defaults to type JaninoEventEvaluator -->
<evaluator>
<expression><![CDATA[return level>=INFO
&& logger.startsWith("org.apache.dubbo.registry.zookeeper.ZookeeperRegistry")
&& message.contains("[DUBBO] Notify urls for subscribe url");
]]>
</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
</appender>

按marker进行过滤

日志输出方式:

1
2
3
4
5
6
7
8
public class LogDemo {
static final Marker CF = MarkerFactory.getMarker("cf");
static final Logger logger = LoggerFactory.getLogger(LogDemo.class);

public void doSmth(){
logger.info(CF, "hello logback");
}
}

对所有符合 marker=cf 的日志,在appender=RFbyCF 中统一输出:

1
2
3
4
5
6
7
8
9
10
<appender name="RFbyCF" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<!-- defaults to type JaninoEventEvaluator -->
<evaluator>
<expression><![CDATA[return marker.contains("cf");]]></expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
</appender>

通过marker可以对日志进行分类,然后统一输出到一个文件,方便使用处理。例如:进行统计分析。

mvn如何发布SNAPSHOT项目

问题

项目开发过程中,版本号是 x.y.x-SNAPSHOT,如何能够自动以release版本号发布项目,并自动更新成新的SNAPSHOT版本号?

步骤

使用插件:Maven Release Plugin

配置pom.xml

需要同时配置scm(本文用git)和distributionManagement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<scm>
<connection>scm:git:http://git.crazy1984.com/sale_java/sale-boot.git</connection>
<tag>HEAD</tag>
</scm>
<distributionManagement>
<repository>
<id>releases</id>
<url>http://repo.crazy1984.com/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>http://repo.crazy1984.com/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>

mvn release:prepare

发布前准备:变更pom.xml中的版本为release版本号,并打scm tag。

会顺序执行以下步骤:

  • Check that there are no uncommitted changes in the sources
  • Check that there are no SNAPSHOT dependencies
  • Change the version in the POMs from x-SNAPSHOT to a new version (you will be prompted for the versions to use)
  • Transform the SCM information in the POM to include the final destination of the tag
  • Run the project tests against the modified POMs to confirm everything is in working order
  • Commit the modified POMs (git commit)
  • Tag the code in the SCM with a version name (this will be prompted for)
  • Bump the version in the POMs to a new value y-SNAPSHOT (these values will also be prompted for)
  • Commit the modified POMs (git commit)

mvn release:perform

发布:scm检出最新release版本的tag,执行mvn deploy。

示例

  • 原开发版本:1.1.0-SNAPSHOT
  • 发布版本:1.1.0
  • 新开发版本:1.2.0-SNAPSHOT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ mvn release:prepare
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.crazy1984:xfund-archetype >-------------------
[INFO] Building xfund-archetype 1.1.0-SNAPSHOT
[INFO] --------------------------[ maven-archetype ]---------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:prepare (default-cli) @ xfund-archetype ---
[INFO] Verifying that there are no local modifications...
[INFO] ignoring changes on: **/pom.xml.releaseBackup, **/pom.xml.next, **/pom.xml.tag, **/pom.xml.branch, **/release.properties, **/pom.xml.backup
[INFO] Executing: /bin/sh -c cd /Users/zhangjy/git/git.crazy1984.com/sale_java/sale-boot/archetype && git rev-parse --show-toplevel
[INFO] Working directory: /Users/zhangjy/git/git.crazy1984.com/sale_java/sale-boot/archetype
[INFO] Executing: /bin/sh -c cd /Users/zhangjy/git/git.crazy1984.com/sale_java/sale-boot/archetype && git status --porcelain .
[INFO] Working directory: /Users/zhangjy/git/git.crazy1984.com/sale_java/sale-boot/archetype
[WARNING] Ignoring unrecognized line: ?? archetype/release.properties
[INFO] Checking dependencies and plugins for snapshots ...
What is the release version for "xfund-archetype"? (com.crazy1984.sale:xfund-archetype) 1.1.0: :
What is SCM release tag or label for "xfund-archetype"? (com.crazy1984.sale:xfund-archetype) xfund-archetype-1.1.0: :
What is the new development version for "xfund-archetype"? (com.crazy1984.sale:xfund-archetype) 1.1.1-SNAPSHOT: : 1.2.0-SNAPSHOT
...

$ mvn release:perform
$ mvn release:clean

依依成长记录2019

01/17

晚上吃饭,依依下了饭桌自己玩,妈妈和奶奶还在吃饭。突然依依跑过来,拉着妈妈说:“救命呀,救命呀,那里有一个宝宝”。依依指着去卧室的过道,过道和卧室的灯都没开。

妈妈怕👻,都不敢过去看。妈妈被依依牵着手,在客厅从过道望过去,什么也没有看见。依依手指着过道尽头,边说“那里有一个宝宝”,妈妈被吓坏了。

然后妈妈又仔细观察了下,发现主卧内的卫生间玻璃门上有人影。主卧门开着,灯都没开,卫生间的玻璃门正对着过道,所以像镜子一样会反光。搞清楚原因之后,妈妈和奶奶都乐坏了。

爸爸还没到家,依依妈妈通过微信讲述了刚刚发生的这个趣事。

01/22

前几天家里安装了百度AI音响,奶奶说,白天在家让百度AI播放《世上只有妈妈好》。
依依听了说:“爸爸也好,唱!爸爸也好,唱!”。

谢谢我的宝。

2019夏

夏天时,某个周末骑电动车带依依去永辉超市,有几周没来了。
超市门口有个麦当劳,卖冰淇淋第二份半价,我们经常进超市前会买2个,依依自己一个。

我在停车,宝妈抱依依先去门口拉购物车,依依看见麦当劳了,作手扇舌头状,边说:“好热好热呀,宝宝是不是应该吃冰淇淋啊”。

11/05

依依2周零9个月。

今天二姑陪依依玩煮菜游戏的时候,依依突然跟二姑说:二姑今天不要煮菜,二姑煮太多菜了,晚上爸爸煮菜,二姑陪我玩,妈妈玩手机。
因为晚上经常的情况是:二姑在煮菜,我在玩手机,妈妈在陪依依。小不点怎么突然会做安排了。。

Checked vs Unchecked Exceptions

区别

检测异常和非检测异常的主要区别,是在编译时是否会进行检查
检测异常必须进行捕获处理或者抛出,否则编译时会报错无法通过。

用法

检测异常也是interface的一部分,是对接口方法的描述:接口调用时可能发生哪些异常,调用方需要关注如何处理这些异常,可以是try catch捕获后处理,也可以往外再抛出由上层调用方处理。检测异常在编程过程中就给出相应的提示,让调用方能够预见和安排如何处理相应的异常

非检测异常主要包括的是编程问题,无法在程序运行过程中恢复或者处理的(因为编程时预见不到)。例如:空制针、内存溢出等,是需要通过修改代码或者调整环境配置来解决的。

非检测异常虽然可以让接口调用起来更干净和方便,不需要麻烦的try catch处理,但这样会使调用方疏于处理应处理的异常。一般来说,不要为了避免麻烦而使用RuntimeException。

Java官方的建议是

  • If a client can reasonably be expected to recover from an exception, make it a checked exception.
    • 如果调用方可以从异常中恢复进行后续处理,那么使用检测异常。
  • If a client cannot do anything to recover from the exception, make it an unchecked exception.
    • 如果调用方不能够从异常中恢复,那么使用非检测异常。

简单概括:需要调用方在运行时关注并处理的异常,声明为检测性异常。

其他参考

https://stackoverflow.com/questions/499437/in-java-when-should-i-create-a-checked-exception-and-when-should-it-be-a-runti

At my last job, we ran into some real issues with Runtime exceptions being forgotten until they showed up in production (on agedwards.com), so we resolved to use checked exceptions exclusively.

在我的上一份工作中,我们遇到了一些真实案例,因为运行时异常被忽略而导致问题在生产环境才出现,所以后来我们只使用检测异常。

https://stackoverflow.com/questions/27578/when-to-choose-checked-and-unchecked-exceptions

Checked Exceptions should be used for predictable, but unpreventable errors that are reasonable to recover from.

Unchecked Exceptions should be used for everything else.

工利其器:shell使用(1)

0. 环境要求

  • shell环境:mac 或 linux 或 cygwin

1. 按目录结构拷贝部分文件

想结合着通配符(ls命令支持的那种),将指定目录下的部分文件带着目录结构筛选出来,拷贝到另一个目录下。

例如:一个多module到mvn项目,将所有子项目src/main/resources目录下的yml文件拷贝出来备份。

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
$ ls -1 */src/main/resources/*.yml
crm-collector-xxx/src/main/resources/application.yml
crm-collector-yyy/src/main/resources/application.yml
crm-main/src/main/resources/application.yml
crm-service/src/main/resources/application-service.yml
$ ls -1 */src/main/resources/*.yml |cpio -pdmuv copy2zjy
copy2zjy/crm-collector-xxx/src/main/resources/application.yml
copy2zjy/crm-collector-yyy/src/main/resources/application.yml
copy2zjy/crm-main/src/main/resources/application.yml
copy2zjy/crm-service/src/main/resources/application-service.yml
20 blocks
$ tree copy2zjy
copy2zjy
├── crm-collector-xxx
│   └── src
│   └── main
│   └── resources
│   └── application.yml
├── crm-collector-yyy
│   └── src
│   └── main
│   └── resources
│   └── application.yml
├── crm-main
│   └── src
│   └── main
│   └── resources
│   └── application.yml
└── crm-service
└── src
└── main
└── resources
└── application-service.yml

16 directories, 4 files

相关命令

  • ls – list directory contents
  • cpio – copy files to and from archives
  • tree - list contents of directories in a tree-like format

2. 生成批量操作脚本

对于给定的参数列表,生成批量操作脚本。例如:给定一个文件或目录列表,批量删除

1
2
3
4
5
6
7
$ ls -d1 *service*/target
crm-service-api/target
crm-service/target

$ ls -d1 *service*/target | awk '{print "rm -rfv "$1}'
rm -rfv crm-service-api/target
rm -rfv crm-service/target

对于生成的批量脚本,可以拷贝粘贴执行,也可以直接执行:

1
$ ls -d1 *service*/target | awk '{print "rm -rfv "$1}' | sh

docker 批量删除镜像

1
$ docker images |grep {your-image-name} | awk '{print "docker rmi "$3}'

3. shell下的时间转换

时间转epoch seconds

1
2
3
4
5
6
$ date "+%s"
1567568345
$ date -v-3m "+%s" #3个月前
1559620329
$ date -v-3m -v-3d -v0H -v0M -v0S "+%s" #3个月3天前,时分秒设置为0
1559318400

epoch seconds 转时间

1
2
3
4
5
6
$ date -r 1567568345
Wed Sep 4 11:39:05 CST 2019
$ date -j -r 1567568345 "+%Y-%m-%d %H:%M:%S"
2019-09-04 11:39:05
$ date -j -r 1559318400 "+%Y-%m-%d %H:%M:%S"
2019-06-01 00:00:00

工利其器:mac篇

0. 基础安装

  • java >= 1.8
  • xcode
1
$ xcode-select --install

1. Homebrew https://brew.sh/

The missing package manager for macOS (or Linux)

1
2
3
4
5
6
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew install calc curl fd fzf httpie imagemagick jq rename tree wget zsh \
git-extras git-flow-avh pandoc snappy unar xz z zplug \
ant etcd maven go grpc protobuf pyenv \
mysql redis sqlite libressl openssl
$ brew upgrade libressl openssl

brew install 安装的程序:

  • calc 命令行下的计算器
  • curl http网页内容请求
  • wget The non-interactive network downloader. 支持续传
  • rename renames multiple files
  • unar 命令行下解压缩。可指定字符集解压zip内文件名带中文。

关闭brew的自动更新,设置环境变量

1
HOMEBREW_NO_AUTO_UPDATE=1

这样可以避免每次brew install时都执行update,太慢。
需要自己定期执行brew update获得最新的程序列表及版本。

2. iTerm2 https://www.iterm2.com/

iTerm2 is a replacement for Terminal and the successor to iTerm. It works on Macs with macOS 10.12 or newer. iTerm2 brings the terminal into the modern age with features you never knew you always wanted.

自定义设置

  • Preferences -> Profiles -> Keys
    • Load Preset…
    • 选择:Nextural Text Editing
    • 这样就可以支持用 CTRL + <CTRL + >跳转字符串了
  • Preferences -> Keys -> Hotkey
    • Show/hide iTerm2 with a system-wide hotkey 快捷键设置为:”command+.”

3. zsh

zsh可以作为bash的替代品。相比mac默认的bash,zsh有很多更强大更方便的功能。

1
2
3
4
$ brew install zsh zplug zsh-completions
$ vi /etc/shells
#设置zsh为默认,在文件末尾添加:/usr/local/bin/zsh
$ chsh -s /usr/local/bin/zsh

oh-my-zsh https://github.com/robbyrussell/oh-my-zsh

Oh My Zsh is an open source, community-driven framework for managing your zsh configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ sh -c "$(wget -O- https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
$ git clone git@github.com:igoradamenko/jira.plugin.zsh.git ~/.oh-my-zsh/custom/plugins/jira
$ git clone git@github.com:changyuheng/fz.git ~/.oh-my-zsh/custom/plugins/fz
$ vi ~/.zshrc
#修改plguins配置
plugins=(adb brew copydir copyfile cp dotenv docker docker-machine fd fzf osx urltools
git git-extras git-flow-avh golang httpie history jira mvn npm nvm spring
pip pyenv rsync vscode web-search xcode z zsh_reload)

# config by cf
export GOPATH=$(go env GOPATH)
PATH=$PATH:$GOPATH/bin

export JAVA_HOME=$(/usr/libexec/java_home)
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
PATH=$JAVA_HOME/bin:$PATH

export JIRA_URL=http://jira.crazy1984.com
export JIRA_NAME=zhangjy
# extract JIRA issue name [ZNKFN-1234] from: feature/ZNKFN-1234_xyz
export JIRA_BRANCH_REGEX="s/[a-zA-Z]+\/([A-Z]+-[0-9]+)([^0-9].*)?/\1/p"

上边启用了一些非常有用的插件:

  • adb、brew、docker、mvn 命令的提示与补全(按TAB TAB)
  • git、git-flow-avh、jira(git与jira的自动关联) 命令的提示与补全
  • jira:注意要修改上述的JIRA_NAME配置,改成你的账号

4. git

修改 ~/.gitconfig 配置:一些UI颜色的设置,一些别名的配置。

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
[user]
name = "Your Name Here"
email = "your.email@crazy1984.com"
[color]
ui = auto
branch = auto
diff = auto
status = auto
[color "branch"]
current = green
local = yellow
remote = red
[color "diff"]
meta = yellow bold
frag = magenta bold
old = red bold
new = green bold
[color "status"]
added = yellow
changed = green
untracked = cyan
[alias]
st = status
di = diff
ci = commit
co = checkout
br = branch
hist = log --graph --pretty=format:'%Cred%h%Creset %s%C(yellow)%d%Creset %Cgreen(%cr)%Creset [%an]' --abbrev-commit --date=relative
[core]
autocrlf = input
# display unicode file names
quotePath = false
[credential "https://git.yours.com"]
username = zhangjy
[http "https://git.yours.com"]
sslVerify = false

配置git的SSH Key

1
2
$ ssh-keygen -t rsa -C "your.email@crazy1984.com" -b 4096
$ pbcopy < ~/.ssh/id_rsa.pub

打开git web控制台:

  • 个人设置 => SSH Keys ,添加SSH Key,粘贴、保存。
  • 配置好SSH Key后,git clone使用ssh地址,pull和push的时候就不需要输入账户密码了

5. SDKMAN https://sdkman.io

SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems. It provides a convenient Command Line Interface (CLI) and API for installing, switching, removing and listing Candidates. Formerly known as GVM the Groovy enVironment Manager, it was inspired by the very useful RVM and rbenv tools, used at large by the Ruby community.

https://sdkman.io/install

1
2
3
$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk version

openjdk-alpine容器中的jvm如何dump

openjdk-alpine容器中的jvm如何dump

微服务架构之后,应用的jvm运行在容器之内,如果系统出现问题,如何对jvm进行dump?

有两种方法:

  1. 开启jmx,使用jvisualvm通过jmx连接jvm,生成dump。
  2. 使用docker命令,进入容器的shell环境,使用jmap命令生成dump。

本文主要介绍第二种方法。在之前的文章中说过,我们的项目使用Google的jib打包成镜像,使用的基础镜像是8-jdk-alpine。容器启动时第一个进程就是java:

1
2
3
4
5
6
[root@VM_16_16_centos pp]# docker exec -it pp_eureka_1 sh
/ # ps
PID USER TIME COMMAND
1 root 0:50 java -Xms256m -Xmx512m ......
94 root 0:00 sh
99 root 0:00 ps

使用alpine镜像会有个问题,如果java进程的pid=1,那么无法执行jdk的各种连接java进程的命令,会报如下错误:

Unable to get pid of LinuxThreads manager thread

其他os镜像未验证,相关issue:https://github.com/docker-library/openjdk/issues/76

解决的方法是:启动一个init进程(pid=1)来接收docker stop and docker kill的信号,它会转发信号给其他进程,负责关闭僵尸进程。java进程由init进程启动。

具体有以下两种做法。

docker run –init

在docker 1.13 之后的版本,可以在docker run时加上 --init 参数来实现。

1
2
3
4
5
6
7
$ docker run --rm -it --init openjdk:8-jdk-alpine
/ # ps
PID USER TIME COMMAND
1 root 0:00 /dev/init -- /bin/sh
7 root 0:00 /bin/sh
8 root 0:00 ps
/ #

如果是docker compse,可以在docker-compose中配置上init参数。

1
2
3
4
5
6
7
8
9
10
11
12
version: '2.2'
services:
web:
image: alpine:latest
init: true


version: '2.2'
services:
web:
image: alpine:latest
init: /usr/libexec/docker-init

需要注意的是,init参数对docker-compose.yml的文件格式版本有要求:

  1. v2版本,version必须配置为2.2或以上版本。
  2. v3版本,version必须配置为3.7或以上版本。
  3. 不同版本的compose文件,有docker版本兼容性要求

krallin/tini

安装Tini,使用tini作为入口进程,配置启动java进程。

1
2
3
RUN apk add --no-cache tini
# Tini is now available at /sbin/tini
ENTRYPOINT ["/sbin/tini", "--", "java", "-Xms256m", "-Xmx512m", ......]

实际上,docker的--init参数也是通过集成Tini实现的。

其他事项

上述两种方式,那种更好?关于这个问题,github上有相关的讨论。个人觉得,各有利弊:

  1. 使用docker --init 参数简单,但是需要运维人员注意,部署时存在人为操作遗漏的风险。
  2. 使用 Tini 不用担心人为失误,但用jib打包镜像会增加配置工作,需要为每个项目配置entrypoint参数。

另外需要注意的是,在centos下,docker必须是docker-1.13.1-88.git07f3374.el7.centos.x86_64之后的发行版本,之前版本有bug。这个问题耽误了我一天时间,在本地windows下都好使,部署到docker不好使,试了好久,最后发现是centos下docker版本bug,更新后就好了。

依依成长日记201812

依依本月1周零10个月

20181211

依依早上半夜醒来,黑暗中挥着小手,闭着眼睛在那喊着“不要,不要”。心理琢磨着这是做噩梦了吧,不要什么呢?“不要爸爸,不要爸爸”,爸爸心理崩溃。依依妈妈把这小事讲给同事听,大家笑死了。

最近一段时间忙着写论文,陪依依时间比较少,被嫌弃了啊。

20181220

今天下班后要去办事,回家比平时早了一点,比依依妈妈更早到家。最近一个多月时间,经常都是依依妈妈先到家。

依依刚睡醒没多久,奶奶刚热好奶正要喂依依吃。我钥匙开门,依依听见了开门声,奶都不喝欢快的从沙发那跳到门口,边走边说“妈妈回来”。然后门打开,依依看见是爸爸回来了,而不是期待的妈妈,突然就崩溃了,边哭边说“爱妈妈,爱妈妈”。可能依依满怀期待的要迎接妈妈,突然希望落空,失落的哭了。

爸爸赶紧去哄她,说“爸爸也爱依依”,同时蹲下来张开双手,要去抱她。依依说“不要,不要爸爸,爱妈妈”,边哭边躲,跑到了窗户边上,趴在窗台在那继续哭着,嘴上还在说着“爱妈妈”,特别可怜的样子。

就在这时,妈妈开门进来了,依依看见妈妈马上止哭,跑过去抱妈妈了。爸爸跟妈妈描述刚才的事情,还学依依哭的样子,依依听了还会跟着咔咔大笑。

20181223

今天周日,晚饭洗澡后,陪依依玩了一会捉迷藏。

卧室和走廊的灯关着,爸爸一会躲在门后,一会躲在衣柜边,一会又藏到了被窝里,依依有时候能找到,有时候又找不到。每一轮开始,依依都是先去上一轮找到爸爸的地方看看,小孩子的逻辑简单直接。找不到的时候,依依会说“哦?爸爸。哦?爸爸”,意思是爸爸在哪呢。

有一次爸爸藏在窗帘后,窗帘未落地,小腿以下露出来了,以为依依发现不了,然而却被她看见了。然后又一次,爸爸坐在床右侧地上,用被子盖着头,身后是窗户,边上就是刚才躲过的窗帘。依依走到窗帘边,掀了几次窗帘发现没有人,爸爸坐在边上看着她也不做声。依依检查完窗帘,左转身的时候突然发现了爸爸,咔咔咔笑的很开心。

依依玩的很高兴,跟她说玩最后一次,然后还想玩,说“还要玩一次”,实际又玩了5次以上。

微信小程序开发问题总结(1)

微信小程序开发问题总结(1)

项目外包研发小伙伴开发的小程序,遇到2个问题解决不了:

  1. 某同事Z的小米6手机,打开小程序,在选择法院界面,搜索输入任何内容都没有搜索结果。周围其他同事手机上没遇到问题。
  2. 某同事C的华为mate手机,进入法院选择页面,选择法院后跳转回首页,选择的结果未刷新。周围其他同事手机上能正常。

问题1

同样的程序,周围其他人手机上正常,说明可能跟环境有关。

远程调试,跟踪代码的时候发现,代码写法不严格,很多语句结尾没有加封号。相关的js文件里,把代码的结尾封号都加上,再远程调试,就好了。

原因推测:微信针对不同的Android手机平台,编译了不同版本的js引擎。

总结:虽然js语法宽松,但是为了避免出现莫名其妙的问题,代码写法需要保持严格。这是个低级错误。

问题2

首页(/homepage/homepage)相关代码:

1
2
3
4
5
onLoad: function(options) {
// ...
var courtName = wx.getStorageSync('courtName');
// 更新首页中已选择法院输入框的值
}

法院选择页(/court/court)相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bindcourt: function (e) {
var courtName = e.currentTarget.dataset.court; //选中的法院名称
var courtId = e.currentTarget.dataset.cid; //选中的法院ID
wx.setStorageSync('courtName', courtName);
wx.setStorageSync('courtId', courtId);
wx.switchTab({
url: '../homepage/homepage',
success: function (e) {
var page = getCurrentPages().pop();
if (page == undefined || page == null) return;
page.onLoad();
}
});
}

代码说明:在法院选择页,选中了法院之后,将选择结果保存到本地存储(小程序即使退出,下次进入也要默认使用最后一次的选择结果,所以存储)。然后调用switchTab返回首页,switchTab的success回调中,调用getCurrentPages()获取当前页,然后调用onLoad进行主动刷新。

上述代码有几个问题:

  1. 在switchTab的回调中去调用getCurrentPages(),可能会有同步问题,不能保证得到的页面就是目标页面。
  2. getCurrentPages().pop() 修改了页面栈,可能引发未知问题。
  3. 首页的onLoad是事件函数,一个页面只会调用一次。

解决方法:

  1. 首页在onShow事件中进行页面的刷新处理。
  2. 移出swtichTab中的回调处理代码。

感悟

编程习惯也是非常重要的技能,不好的编程习惯,误用的方法会引入莫名其妙的问题。

依依成长日记201810

依依本月1周零8个月

20181020

今天带依依去新奥购物中心和奥森玩,妈妈带着依依走到了儿童服装区,依依看见鞋架上鞋子就拿下来,然后快速的踢踢踢把鞋子脱了,去试穿新鞋,动作利索。

吃完饭去给依依取儿童滑板车,路过小火车,妈妈说依依一路跟着,想要做。然后妈妈带着坐了一圈,到站了还不下来,嚎啕大哭,大嗓门引得路人侧目。

带依依取奥森,想去看雨看秋菊,依依一路自己带着滑板车,有时推有时踩,不让人帮忙。往回走的时候已经比较熟练了。

20181022

今天周一,早上楼上邻居彤彤奶奶带彤彤来家里玩,依依不高兴,彤彤进门就开始一直叫“走、走、走”。彤彤在客厅,穿了依依一只凉鞋,依依穿着另一只,两人争执不下,依依生气的推着自己的小椅子,进到了厨房里,边哭边叫走走走,还抖椅子撞击地板,发出嗒嗒嗒的声音。

依依最近跟彤彤玩,老被欺负,彤彤总拍她脑袋,所以依依不喜欢彤彤。小小年纪已经有了爱恨。

20181023

半夜依依在睡眠中,爸爸憋不住放了个响屁,把依依都给震醒了。依依半睡半醒中反复说着“依依放屁屁,奶奶,依依放屁屁”。妈妈把依依搂过去,又给奶睡了。