Java TimeUnit的使用

简易的日期工具类,位于java.util.concurrent包下。

1
2
3
4
5
6
7
8
9
10
11
// 一些用法
TimeUnit.SECONDS.toMillis(1) 1秒转换为毫秒数
TimeUnit.SECONDS.toMinutes(60) 60秒转换为分钟数
TimeUnit.SECONDS.sleep(5) 线程休眠5秒
TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES) 1分钟转换为秒数
//TimeUnit.DAYS 日的工具类
//TimeUnit.HOURS 时的工具类
//TimeUnit.MINUTES 分的工具类
//TimeUnit.SECONDS 秒的工具类
//TimeUnit.MILLISECONDS 毫秒的工具类

TimeUnit提供了更优雅的线程sleep、timeJoin操作,通常用来替换Thread.sleep(),Thread.join()。
例子:

1
2
3
4
5
// 使用Thread sleep:
Thread.sleep(4 * 60 * 1000);
// 使用TimeUnit
TimeUnit.MINUTES.sleep(4);

TimeUnit中的sleep方法内部调用的也是Thread.sleep(..), timeJoin同理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void sleep(long timeout) throws InterruptedException {
if (timeout > 0) {
long ms = toMillis(timeout);
int ns = excessNanos(timeout, ms);
Thread.sleep(ms, ns);
}
}
public void timedJoin(Thread thread, long timeout)
throws InterruptedException {
if (timeout > 0) {
long ms = toMillis(timeout);
int ns = excessNanos(timeout, ms);
thread.join(ms, ns);
}
}

常用用户认证方式简介

Http Basic Auth

简单,每次请求都需要提供用户username、password,暴露的风险大不安全,生产环境不要使用。

基于Cookie认证

一次登录请求中在服务器端创建Session对象,保存用户相关信息并返回唯一sessionId,客户端浏览器会创建一个Cookie对象存放sessionId,以后的请求会携带sessionId用于认证。存在CSRF风险,可通过设置Refer来避免。

Token认证

和基于Cookie认证相比的好处:

  • 支持跨域访问
    Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
  • 无状态
    在服务器端无需存储Session信息,因为Token本身包含了所有登录用户的信息,只需在客户端的cookie或local storage、 session storage中存储即可。
  • 更适用于移动应用
    原生应用不支持Cookie,需进行特殊处理。
  • CSRF
    因为不再依赖于Cookie,所以就不需要考虑对CSRF(跨站请求伪造)的防范。
  • 性能
    使用Token认证仅需要对Token进行验证和解析。基于Cookie则需要服务器存储Session信息,甚至认证还需要去查询数据库。
  • 基于标准化
    API可以采用标准化的JSON Web Token (JWT)。这个标准已经有多个后端库(.NET, Ruby, Java, Python, PHP)的支持。

OAuth认证

是一种开放授权标准,允许让第三方应用访问该用户在某web服务上存储的资源,不需将用户名密码提供给第三方应用。

CDN源站与搜索引擎收录

问题

在Google上进行搜索时发现除了正常的域名blog.gelu.me,CDN源站cdn-blog.gelu.me也被收录进去。

使用的是阿里云CDN,当时的配置是

  • 源站类型为源站域名,cdn-blog.gelu.me
  • 回源host也是该值
  • 源站服务器上nginx配置了server_name: cdn-blog.gelu.me

解决

进行了如下修改

  • 源站类型改为IP,值为服务器IP地址
  • 回源host改为blog.gelu.me,即加速的域名,不填即为加速域名(未测试)
  • 源站服务器上nginx配置修改为 server_name: blog.gelu.me

配置完成后问题解决。

总结

CDN配置的关键流程

  • 域名解析绑定CDN的CNAME
  • 配置源站类型为IP,填写服务器的IP地址
  • 如果服务器上部署了多个网站(仅通过IP无法定位数据)时,配置回源Host为要加速域名,当然加速域名在源站服务器要能访问才行(如nginx配置server_name之类的)

此时请求到CDN且需回源时,CDN会根据IP找到源站服务器,源站服务器会根据携带来的回源host定位到对应网站,从而返回数据。

Spring Boot使用Gson替换Jackson

参考网上的一些测评,得知Gson对小文件处理比较快,Jackson处理大文件比较好,而系统主要处理小文件请求,因此打算使用Gson替换默认的Jackson。
注意项目使用Maven进行项目管理,依赖的版本号均在parent POM或import POM中维护,因此下面的Maven配置无版本号。

通常情况(排除jackson依赖)

在依赖中排除所有jackson相关依赖, 如:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>

注意所有jackson-core,jackson-databind依赖均需要排除,可使用 mvn dependency:tree查看项目依赖。
依赖排除完成的同时加入gson依赖。

1
2
3
4
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>

查看spring-webmvc.jar中WebMvcConfigurationSupport.java源码

1
2
private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", WebMvcConfigurationSupport.class.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", WebMvcConfigurationSupport.class.getClassLoader());
private static final boolean gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", WebMvcConfigurationSupport.class.getClassLoader());

1
2
3
4
5
6
7
8
9
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
...
if(jackson2Present) {
objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
} else if(gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
}

因此系统找不到jackson依赖时,Spring MVC便会使用GsonHttpMessageConverter而不是MappingJackson2HttpMessageConverter。

特殊情况(无法排除jackson依赖)

若无法排除jackson依赖(如其他依赖需要jackson),参考上面的源码得知Spring MVC在jackson和gson依赖都存在的情况下优先使用MappingJackson2HttpMessageConverter,因此需要代码中进行调整。

1
2
3
4
5
6
7
8
9
10
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(httpMessageConverter -> httpMessageConverter instanceof MappingJackson2HttpMessageConverter); // 删除MappingJackson2HttpMessageConverter
converters.add(new GsonHttpMessageConverter()); // 添加GsonHttpMessageConverter
}
...
}

总结

以上便是我在Spring Boot中使用Gson替换Jackson的相关配置,同样的仅使用Spring MVC而未使用Spring Boot配置也类似。

Restful接口定义

CRUD分别对应于HTTP方法:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

即:

GET:从服务器取出资源(一项或多项)。

POST:在服务器新建一个资源。

PUT:在服务器更新资源(客户端提供完整资源数据)。

PATCH:在服务器更新资源(客户端提供需要修改的资源数据)。

DELETE:从服务器删除资源。

其中GET,PUT,DELETE为幂等

1
2
3
4
5
6
7
8
9
10
11
12
GET /movie 获取电影列表,返回电影列表
GET /movie/1 获取标志为1的电影,返回单个电影
POST /movie 添加电影,返回新生成的电影
PUT /movie/1 提供完整电影数据,更新后会返回完整的电影
PATCH /movie/1 提供部分要修改的数据,更新后会返回完整的电影
DELETE /movie/1 删除标志为1的电影,返回空文档

postgresql常用命令与查询

配置

修改最大连接数(Ubuntu, postgresql版本9.5)
postgresql配置文件 /etc/postgresql/9.5/main/postgresql.conf

1
max_connections = 100(默认100, 修改后需重启postgres)

常用命令

1
2
-- 重启
sudo service postgresql restart

常用查询

1
2
3
4
5
6
7
8
- 查看postgresql的连接数
select * from pg_stat_activity;
- 查看最大连接数限制
show max_connections;
- 查看为超级用户保留的连接数
show superuser_reserved_connections;

firewalld常用命令

添加开放的端口

1
firewall-cmd --permanent --add-port=5000/tcp

删除开放的端口

1
firewall-cmd --permanent --remove-port=5000/tcp

刷新

1
firewall-cmd --reload

查看

1
firewall-cmd --list-all

工作小记1

就上次的问题消息系统顺序问题,考虑到修改消息系统模块风险大,太多其他模块使用了该模块(由于系统技术债务,系统并没提供扩展写法,对该模块也没有足够的单元测试),最后没有就该思路走下去。
原来的业务问题是APP端有两次请求(一先一后),后台要求有顺序,否则可能执行不成功。至于为什么原系统是这样我就不知道了…两次请求会执行一些简单的逻辑,然后第二次请求会通过消息系统调用后面的服务,此时若第一次请求没有执行完,后面的服务就报错。
最后采取的方案是将操作2(包含参数)存入数据库,然后写定时任务再去调用,从而保证操作2在后面执行。
解决方案不优雅,但也算能解决当前的业务问题。重构好像要提上进程,希望能还些债务。

我的2016

始于一个微信电商项目的快速开发上线。
然后随公司一位老板换了个办公场所专心于一个项目。
7月去上海发展,公司是做Saas类型的企业服务,我也从在小公司要承担各种事务过渡到了只要专心开发,一下轻松了很多。
又经历了从开始的一个轻松的项目组被带到更要费心的另一个组。
工作技能方面也有了进一步的提升。
生活方面没什么值得说的,长进的怕是只有年龄。

设计模式总结

创建类模式

结构型模式

  • 适配器模式
  • 装饰器模式
  • 代理模式
  • 外观模式
  • 桥接模式
  • 组合模式
  • 享元模式

行为型模式

  • 模板方法模式
    模板方法模式
  • 策略模式
  • 观察者模式
  • 责任链模式
  • 迭代子模式
  • 命令模式
  • 备忘录模式
  • 状态模式
  • 访问者模式
  • 中介者模式
  • 解释器模式

其它

  • 并发型模式
  • 线程池模式