冬天温泉的小庭院

记录开发生活中的点点滴滴

稍微介绍一下 java 处理 log 的东西

特别是 slf4j 的种类太多,或许也没有人能很好的说明各自用处。产生混乱的原因有七成是由 slf4j 造成的。这种混乱的局面进行了简单整理。主要分为三个类型的 jar。

1、 接口(Interface)

主要有这些

  • commons-logging
  • slf4j

他们也就只提供了接口的功能,并没实现 log 的输出功能。
接口要是太老的话,自己提供的功能也会有不足的地方。这些 jar 虽然含有有 log 输出的功能,但只是简单的实现。

2、 适配器(Adapter)

主要有这些

  • jcl-over-slf4j.XXX.jar(把 commons-logging 的处理交给 slf4j 来处理)
  • jul-to-slf4j.XXX.jar(把 java.util.logging 的处理交给 slf4j 来处理)
  • log4j-over-slf4j.XXX.jar(把 log4j 的处理交给 slf4j 来处理)

适配器的作用是,代理各接口与实际处理 logger 的任务。从外部看起来都是相同的方法,但是内部却是各自来实现自己的功能。除了处理 log 之外,也有『slf4j-jdk14』这样的兼容不同 JDK 版本来处理的适配器。正因为有了适配器,即使在 commons-logging、log4j 中追加了 slf4j 的时候也能进行工作。

适配器通过设置文件来进行适配,log4j.jar 不存在的时候会读取 log4j.xml 文件。适配器是很认真的来工作的。但是因为有了适配器来进行各种处理,这也是造成了 jar 文件混乱而使得 log 的输出复杂的原因。

另外,「jul」是「java.util.logging」の简称,「jcl」是「Jakarta Commons Logging」的简称而不是「Java Class Library」的简称。这些简称的理解困难也是造成 log 的输出复杂的原因之一。

阅读全文 »

JAVA 8 开始对 time 添加了不少东西,最常见的就是 LocalDate 这样的东西,其实还是多了点其他好玩的东西,比如说 java.time.format.FormatStyle 这个类。下面的代码中让我们来用 Local(语言, 国家) 之后格式化时间看看输出内容都有些什么。

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
public class FormatStyleTest {
public static void main(String[] args) {
LocalDate ld = LocalDate.now();
Arrays.asList(FormatStyle.FULL, FormatStyle.LONG, FormatStyle.MEDIUM, FormatStyle.SHORT)
.forEach(formatStyle -> {
System.out.println(String.format("--- FormatStyle.%s ---",
formatStyle.toString()));
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(formatStyle);
Arrays.asList(new String[]{"zh", "CN"},
new String[]{"zh", "HK"},
new String[]{"zh", "TW"},
new String[]{"en", "US"},
new String[]{"en", "UK"},
new String[]{"ja", "JP"})
.forEach(strs -> {
Locale locale = new Locale(strs[0], strs[1]);
System.out.println(String.format("%s %s -> %s",
strs[0],
strs[1],
ld.format(dtf.withLocale(locale))));
});
});

}
}
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
--- FormatStyle.FULL ---
zh CN -> 2018年7月23日 星期一
zh HK -> 2018年07月23日 星期一
zh TW -> 2018年7月23日 星期一
en US -> Monday, July 23, 2018
en UK -> Monday, July 23, 2018
ja JP -> 2018年7月23日
--- FormatStyle.LONG ---
zh CN -> 2018年7月23日
zh HK -> 2018年07月23日 星期一
zh TW -> 2018年7月23日
en US -> July 23, 2018
en UK -> July 23, 2018
ja JP -> 2018/07/23
--- FormatStyle.MEDIUM ---
zh CN -> 2018-7-23
zh HK -> 2018年7月23日
zh TW -> 2018/7/23
en US -> Jul 23, 2018
en UK -> Jul 23, 2018
ja JP -> 2018/07/23
--- FormatStyle.SHORT ---
zh CN -> 18-7-23
zh HK -> 18年7月23日
zh TW -> 2018/7/23
en US -> 7/23/18
en UK -> 7/23/18
ja JP -> 18/07/23

即使是华语圈,出来的结果基本来说都不一样的,而 en US 跟 en UK 都是一样的。

顺便说一句,java 中格式化时间还是有点麻烦。

via java.time.format.FormatStyle を確認

在甲骨文的官网上,java 10 已经没有运行在 Linux ARM 的版本了,而要想在树莓派中运行最新的 java 的话只能下载 java 8。本想从 openjdk 看看有没有可用的版本,结果迷失在各种连接中找不到下载的地址,这。。。

不过现在已经有人给树莓派可用的 java 10 的版本,是一个叫 bellsoft 的给编译的,下载地址在https://github.com/bell-sw/Liberica/releases 这上面。

在树莓派中运行如下命令即可食用

1
2
wget https://github.com/bell-sw/Liberica/releases/download/10.0.1/bellsoft-jdk10.0.1-linux-arm32-vfp-hflt.tar.gz
tar -zxvf bellsoft-jdk10.0.1-linux-arm32-vfp-hflt.tar.gz

别忘了把 java 命令加到 path 中

1
export PATH="jdk-10/bin:$PATH"

使用 java.time.LocalDate 计算从生日起到现在年龄的方法。

1
2
3
4
5
6
7
8
9
10
11
12
public int getAge(int year, int month, int day) {

// 生日
LocalDate birthday = LocalDate.of(year, month, day);

// 当前日期
LocalDate today = LocalDate.now();

long duration = ChronoUnit.YEARS.between(birthday, today);

return (int)duration;
}

提问:在 solr 中进行非查询的 query 是写作 -field:value,或查询的 query 是写作 field:value1 OR field:value2,那么,对同一字段进行多次非或的查询应该如何写呢?

……

从直觉上来说应该是写作 -field:value1 OR -field:value2 ,这么是没问题并且也是可以检索出数据的,但是如果加上其他的条件比如 (-field:value1 OR -field:value2) AND other_or_some_field:value3 这样的话,这样是检索不出来数据的,why??

原因请看 Negative Query Problems 这个 solr 官方的 wiki,上面说这是『Solr Magic』哦,而不是个 bug 哦,好吧。。。

解决方法:多查询条件下,在非查询的前面添加全量查询即可,即 ((*:* AND -field:value1) OR (*:* AND -field:value2)) AND other_field:value3。而 (-field:value1 OR -field:value2) 这个条件跟 -(field:value1 AND field:value2) 其实是等效的逻辑,所以进一步可改写成 (*:* AND -(field:value1 AND field:value2)) AND other_field:value3。也就是说,多条件的情况下,非或条件要写成 (*:* AND -field:value) 这样的形式,并且如果可以的话尽量把非或条件写到最后以避免出现这个 magic。

如果情况允许的话,可以把查询条件用 fq 来进行查询。

……

然后就是,如果用到了 spring-data-solr 来进行 solr 查询的话,(*:* AND -field:value) 的写法如下

1
2
Criteria criteria = Criteria.where(field).is(value);
criteria = Criteria.where(Criteria.WILDCARD).expression(Criteria.WILDCARD).and(criteria.notOperator()).connect();

也就是说,先用 notOperator() 方法给 criteria 用 -() 给包起来,然后跟 *:* 与结合之后,用 connect() 方法把该次查询加上括号。最后加上括号是为了跟其他条件进行拼接,这对括号的本身并不影响查询。

然后就是多个条件的非或查询比如 (*:* AND -(field:value1 AND field:value2)) 的写法如下

1
2
3
Criteria criteria = Criteria.where(field).is(value1);
criteria = criteria.and(Criteria.where(field).is(value2));
criteria = Criteria.where(Criteria.WILDCARD).expression(Criteria.WILDCARD).and(criteria.notOperator()).connect();

This’s “Solr Magic” with negative queries。

0x00 安装系统

Raspbian官方地址 下载镜像,基本上 lite 版的就足够了反正也是用 SSH 来链接到机器上用不到桌面,然后弄到 sd 卡上。

0x01 修改系统设置
  1. 运行 sudo dpkg-reconfigure tzdata 修改机器的 timezone。
  2. 如果有多台树莓派的话建议还是修改一下 hostname 的免得等下找机器麻烦。
    1. 运行 sudo vi /etc/hostname,直接修改
    2. 运行 sudo vi /etc/hosts,修改最后一行
    3. 运行 sudo reboot,重启
0x02 更改源地址
  1. 运行 sudo vi /etc/apt/sources.list
  2. 删除里面内容,直接变成国内源,其中的 jessie 记得替换成当时 Raspbian 的版本。
    1
    2
    3
    4
    # 中国科学技术大学源
    deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ jessie main contrib non-free
    # 大连东软信息学院源
    deb http://mirrors.neusoft.edu.cn/raspbian/raspbian/ jessie main contrib non-free
  3. 运行 sudo vi /etc/apt/sources.list.d/raspi.list,把第一行中的 ui 给删除掉让它变成如下内容
    1
    deb http://archive.raspberrypi.org/debian/ jessie main
    不然没法更新 raspberrypi-kernel 之类的内容(国内源压根就没把这些给同步回来)。
  4. 运行 sudo apt-get update
阅读全文 »

之前用 Octopress 来部署本站点来着,但是依赖的 ruby 版本实在是太古老,heroku 也发过几次邮件说将不支持 ruby 1.9.2 需要升级,但是一直都没管它(原因还是懒癌发作),结果在某一天网站彻底就打不开了。。。

虽然是免费给部署不过好歹咱也是写过技术文档的人,本着折腾的原则这次打算换其他的框架来弄,所以就这次就用了(凭借着记忆)在推上看到的了基于 nodejs 来开发的 Hexo

按照文档来搭建基本环境很是方便,而且也不存在依赖的 package 不支持 windows 环境的说法,很快的就把之前的环境给在本地配置起来了,而且之前写的 markdown 文档也能直接的就拿过来用(不过话说 categories 跟 tags 不是一个意思的啊。。。)。重要的是这货感觉速度很快的说,本地打开网站也就分分钟的事情,而且部署也方便只要在站点的 _config.yml 文件中配置好了的话一个命令就部署到 heroku 上了。

需要多说一句的是,因为之前的 heroku 项目中已经存在了 ruby 的项目,所以需要先把之前的项目删除掉之后才能把新的给部署上去。(或许也可以直接用 git push -f 命令强推过去不过已经无法实验了)

ほかの言語も勉強しようかな

1)一句话启动http server

1
ruby -rwebrick -e "WEBrick::HTTPServer.new(:DocumentRoot => './', :Port => 8080).start"

2)解决maven下,运行mvn test时出现乱码的问题

1
2
3
4
5
6
7
8
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>once</forkMode>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>

3)禁止#to_json方法对中文的escape

1
something.to_json.gsub(/\\u([0-9a-z]{4})/){|s| [$1.to_i(16)].pack("U")}

4)在windows下使用vundle

1
2
3
4
5
6
7
if has("win16") || has("win32") || has("win64")
set rtp+=$VIM\vimfiles\bundle\vundle
call vundle#rc('$VIM\vimfiles\bundle')
else
set rtp+=~/.vim/bundle/vundle/
call vundle#rc()
endif

4)一个比较好看的bash的显示方式

bash中路径太长的话看起来实在是很不舒服,把下面这段代码添加到.bashrc里面试试

1
2
export PS1='%{$fg[magenta]%}%(?..%?%1v )%n%{$reset_color%}@%{$fg[green]%}%m%{$reset_color%} %{$fg[cyan]%}%c%{$reset_color%} ${vcs_info_msg_0_}%# 
$ '

5)一个小知识

  • 日本企业的职称顺序(参考):(会長>)(副会長>)社長>専務>常務>部長>(次長>)課長>係長>平社員。(括号表示并非所有公司都有同样职位)
  • 台湾企业的职称次序(参考):董事长(>执行长)>总经理>副总经理>协理(>襄理)>经理>副经理>课长>副课长>组长>副组长。

###Befor work

1)在Gemfile中添加如下代码

1
2
3
4
group :test do
gem 'rspec'
gem 'capybara'
end

2)在Rakefile中添加如下代码

1
2
3
4
5
6
7
require 'rspec/core/rake_task'
desc "Run specs"
task :spec do
RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = './spec/**/*_spec.rb'
end
end

3)在/ROOT/spec文件夹下的spec_helper.rb文件中添加如下代码

1
2
3
require 'rspec'
require 'capybara/rspec'
require 'rack/test'

做完以上步骤后就可以进行测试代码了

###Test

1)测试功能

在/ROOT/spec文件夹中添加lib_helper.rb文件,里面中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require File.dirname(__FILE__) + '/spec_helper'
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
require 'lib'

describe Lib do
before(:each) do
@lib = Lib.new
end

it "test name" do
@lib.name = "test name"
@lib.name.should == 'test name'
end
end

2)测试页面动作

在/ROOT/spec文件夹中添加root_helper.rb文件,里面中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require File.dirname(__FILE__) + '/spec_helper'
# 加载sinatra app
require File.join(File.dirname(__FILE__), '..', 'app.rb')

# 采用模块化的方式
Capybara.app = App.new

# 采用传统的方式
Capybara.app = Sinatra::Application.new

feature Root do
context 'login' do
it 'success' do
visit '/login'
within("#login") do
fill_in 'name', :with => 'admin'
fill_in 'password', :with => 'password'
end
click_button 'Login'
current_path.should == '/'
page.should have_content 'Login success'
end
end
end

3)在命令行中运行rake spec

####Read more

0%