Jone Sun's Blog

用心发现,这个星球很美!

0%

前言

抽象工厂模式(Abstract Factory)是为了让创建工厂和一组产品与使用相分离,并可以随时切换到另一个工厂以及另一组产品;

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。
此时,我们可以考虑将一些相关的产品组成一个”产品族”,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想

抽象工厂模式实现的关键点是定义工厂接口和产品接口,但如何实现工厂与产品本身需要留给具体的子类实现,客户端只和抽象工厂与抽象产品打交道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                                ┌────────┐
─ >│ProductA│
┌────────┐ ┌─────────┐ │ └────────┘
│ Client │─ ─>│ Factory │─ ─
└────────┘ └─────────┘ │ ┌────────┐
▲ ─ >│ProductB│
┌───────┴───────┐ └────────┘
│ │
┌─────────┐ ┌─────────┐
│Factory1 │ │Factory2 │
└─────────┘ └─────────┘
│ ┌─────────┐ │ ┌─────────┐
─ >│ProductA1│ ─ >│ProductA2│
│ └─────────┘ │ └─────────┘
┌─────────┐ ┌─────────┐
└ ─>│ProductB1│ └ ─>│ProductB2│
└─────────┘ └─────────┘

这种模式有点类似于多个供应商负责提供一系列类型的产品

阅读全文 »

前言

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

工厂方法(Factory Method)是指定义工厂接口和产品接口,但如何创建实际工厂和实际产品被推迟到子类实现,从而使调用方只和抽象工厂与抽象产品打交道, 目的是使得创建对象和使用对象是分离的,并且客户端总是引用抽象工厂和抽象产品

阅读全文 »

前言

日常开发中必不可少要与时间打交道,而关于时间的处理网上有很多文章,下面基于大神的文章和我自己的理解对时间做一个整理

开始之前我们得先明确下一些概念,有助于后面程序代码得理解

  • 时间:类似于08:002020年10月1日12:00,这个叫做时间,时间是一个相对得概念。在国内我们说得时间和国外得时间表示得就不一样,比如现在是2020年10月1日10:00,在美国芝加哥得话现在就是2020年09月30日21:00,所以一般需要说当地时间(本地时间)

  • 时刻:时刻就是一个准确得时间,如现在我们和国外同时做了一个事情,如果以上帝得视角来看,那这个时间点就是可以确定得哪个时刻(程序里就是时间戳)

  • 时区: 但我们不是上帝,我们对应得如果要准确得表示一个事情得时间,就得加上时区了。全球一共分为24个时区,伦敦所在的时区称为标准时区,其他时区按东/西偏移的小时区分,北京所在的时区是东八区

总结一下,如果要表示准确得时间,得这样说: 北京时间(东八区) 2020年10月1日12:00

下面我们就看下在Java中对于时间得处理

我们都知道Java8加入了LocalDateTime等基础类,改进了时间得运算处理,所以如果是新项目想都不要想,直接上java8+,如果是旧项目或者有引用库还是java7及以下得也有方法可以解决,但不管怎样,放弃Date或者Calendar从现在开始

阅读全文 »

InputStream代表输入字节流,OutputStream代表输出字节流

如果读写的是文本文件则可使用 Reader和Writer表示字符流,字符流传输的最小数据单位是char

字符类型char表示一个字符。Java的char类型除了可表示标准的ASCII外,还可以表示一个Unicode字符

IO

阅读全文 »

简介

Java的java.util包主要提供了以下四种类型的集合:

  • List:一种有序列表的集合

  • Set:一种保证没有重复元素的集合

  • Map:一种通过键值(key-value)查找的映射表集合

  • Queue: 先进先出(FIFO:First In First Out)的有序表

    阅读全文 »

简介

Swagger 是一个规范和完整的文档框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务文档

集成

swagger3.0.0简化了配置,故推荐直接使用最新版, 如果有还在用2.x版本的请参考时注意区分

pom.xml

1
2
3
4
5
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

这样就可以了,不用像2.x版本需要引入springfox-swagger和springfox-swagger-ui

Swagger3Config

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
@Configuration
public class Swagger3Config {

@Bean
public Docket createRestApi() {
//返回文档摘要信息
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(Operation.class))
.paths(PathSelectors.any())
.build();
}

//生成接口信息,包括标题、联系人等
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Swagger3接口文档")
.description("如有疑问,请联系开发工程师")
.contact(new Contact("JoneSun", "https://jonesun.github.io/", "sunr922@163.com"))
.version("1.0")
.build();
}

}

注意只有controller层中标注@Operation注解的才会显示,同样可以@ApiOperation或者其他注解

阅读全文 »

简介

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

阅读全文 »

设计模式是为了可扩展性,不要为了使用设计模式而使用

概念

责任链模式(Chain of Responsibility): 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

像我们日常使用的spring框架中的拦截器和过滤器都是使用了该模式,每次请求都会经过一系列的拦截,只有当前面的拦截通过后才会进入下一步

责任链模式包含如下角色:

  • Handler: 抽象处理者,处理请求的接口类包含抽象处理方法和一个后继连接
  • Concrete Handler: 实现抽象处理者的处理类,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者
  • Client: 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程

抽象的处理者实现三个职责:

  • 一是定义一个请求的处理方法handleMessage,唯一对外开放的方法;
  • 二是定义一个链的编排方法setNext,设置下一个处理者;
  • 三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务echo。

注意事项:

链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能

JavaEE的Servlet规范定义的Filter就是一种责任链模式,它不但允许每个Filter都有机会处理请求,还允许每个Filter决定是否将请求“放行”给下一个Filter,这种模式不但允许一个Filter自行决定处理ServletRequest和ServletResponse,还可以“伪造”ServletRequest和ServletResponse以便让下一个Filter处理,能实现非常复杂的功能

使用场景

审批流程、多轮面试等需要多级处理的场景都适合使用责任链模式来实现,可解决大量的分支判断造成难维护、灵活性差的问题

阅读全文 »

前言

HTTP 协议有一个缺陷:通信只能由客户端发起

HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。可以替代长轮询,用于对实时性要求比较高的场景:

  • 聊天室

  • 服务端消息实时推送

  • ……

使用

服务端

SpringBoot中使用WebSocket非常简单:

  1. pom.xml中加入引用
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  1. 新建WebSocketConfig配置类
阅读全文 »

前言

平常我们在开发过程中经常会遇到将某个对象的一些属性赋值给另一个对象,常见的是将前端传输的from或者DTO赋值给DO

DO/DTO/VO/FORM的区别

  • DO 就是entity ,对应表实体,和数据库的字段一一对应
  • DTO 数据传输对象,DTO本身不是业务对象
  • VO 用于封装传递到前端需要展示的字段,数据库表不需要展示的,不要包含
  • form 用于封装前端传入的字段, 可以配合@Valid注解,对前端传入数据,进行验证,比如必填字段

使用

一般我们会这么写:

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
public class UserInputDTO {

@NotNull
private String username;

@NotNull
private Integer age;

private Boolean sex;

@NotNull
private String desc;

private LocalDate birthday;
}

public class User {
private String userId;

private String username;

private String password;

private Integer age;

private Boolean sex;

private String desc;

private LocalDate birthday;
}

//使用
UserInputDTO userInputDTO = new UserInputDTO();
userInputDTO.setUsername("username");
userInputDTO.setAge(20);
userInputDTO.setBirthday(LocalDate.of(2000, 1, 1));
userInputDTO.setSex(Boolean.TRUE);
userInputDTO.setDesc("this is my desc");

User user = new User();
user.setUsername(userInputDTO.getUsername());
user.setAge(userInputDTO.getAge());
user.setBirthday(userInputDTO.getBirthday());
user.setSex(userInputDTO.getSex());
user.setDesc(userInputDTO.getDesc());

而实际上,Spring框架自带一个工具类,可以实现上面的功能,避免编写重复的样板代码:

1
2
3
4
5
6
7
8
9
UserInputDTO userInputDTO = new UserInputDTO();
userInputDTO.setUsername("username");
userInputDTO.setAge(20);
userInputDTO.setBirthday(LocalDate.of(2000, 1, 1));
userInputDTO.setSex(Boolean.TRUE);
userInputDTO.setDesc("this is my desc");

User user = new User();
BeanUtils.copyProperties(userInputDTO, user);

BeanUtils提供对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理

阅读全文 »