课程目标:了解重要的Java API 和 一些必备框架的使用,这些都是系统开发的标配需要掌握 Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。 在旧版的 Java 中,日期时间 API 存在诸多问题,其中有: Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API: 新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。 因为之前的日期时间API比较糟糕,一般都会自己写DateTimeUtil工具类,后来也有Joda-Time开源项目,确实帮广大程序员解决了大问题(所以程序员为什么不止要会用框架和java API,就是需要知其然也知其所以然,如果底层本身有缺陷或实现不好,最差我们知道,当然我们也可以增强或自己实现) LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。代码如下: 如果我们需要考虑到时区,就可以使用时区的日期时间API: https://projectlombok.org/ 现在很多的java工程里都有Lombok的应用,可见它有多实用(也有反对的文章,可以参见:https://zhuanlan.zhihu.com/p/146659383)。 lombok可以通过简单的注解的形式来帮助我们简化和消除一些必须有但显得很臃肿的Java代码,比如常见的Getter&Setter、toString()、构造函数等等。lombok不仅方便编写,同时也让我们的代码更简洁。 lombok提供了一个功能完整的jar包,可以很方便的与我们的项目进行集成。 引入依赖: 常见注解: 完整注解参见: https://blog.csdn.net/afreon/article/details/109733866 最新的IDEA已经内置了Lombok插件,可以如丝滑般实用。 Lombok只是帮我们简化了代码,但背后java语言的基本规范,我们是需要知道的,这个需要大家必须掌握,请自检。 Lombok实现浅析: 在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢? 核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。 运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解。java.lang.reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。 编译时解析有两种机制,分别简单描述下: 1)Annotation Processing Tool apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因: 2)Pluggable Annotation Processing API JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强。 Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下: 通过读Lombok源码,发现对应注解的实现都在HandleXXX中,比如@Getter注解的实现在HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google Auto、Dagger等等。 前面讲Spring AOP时有提及动态代理实现,底层都是字节码增强和这里的Lombok底层原理一致。(这和元数据理念如出一辙,在元数据、元元数据每一层抽象描述层增强都能使前一层的动态化能力成为现实) 关于字节码增强,感兴趣的同学自行baidu(https://www.cnblogs.com/luxiaoxun/p/15075778.html) https://swagger.io/ Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。通俗的来讲,Swagger 就是将项目中所有(想要暴露的)接口展现在页面上,并且可以进行接口调用和测试的服务。 PS:Swagger 遵循了 OpenAPI 规范,OpenAPI 是 Linux 基金会的一个项目,试图通过定义一种用来描述 API 格式或 API 定义的语言,来规范 RESTful 服务开发过程。 Swagger 有以下 3 个重要的作用: 为什么需要swagger? 前面我们讲过,随着技术的发展,前后端分离架构越来越普及,我们知道以前在jvm内部调用别人的库要看javadoc,后来基于RPC的分布式调用使用java同种语言也是看javadoc(非同种语言调用就需要其他的调用描述),同理,前后端工程师需要一个统一沟通的接口描述方式,swagger就是解决这个问题的。对于服务提供方,我们主流的方式是基于RESTful规范,接口描述也有规范就是OpenAPI 规范,这也是后来面向API编程的一个基础设施。 常用注解: 表示标识这个类是swagger的资源 表示一个http请求的操作 表示对参数的添加元数据(说明或是否必填等) 表示对类进行说明,用于参数用实体类接收 表示对model属性的说明或者数据操作更改 表示这个方法或者类被忽略 表示单独的请求参数 看几个示例: SpringBoot集成Swagger3 出现如上错误,配置增加: spring.mvc.pathmatch.matching-strategy=ant_path_matcher SpringBoot集成Knife4j Knife4j可以参考这篇文章: https://www.jianshu.com/p/7838842cb45e 掌握了swagger的基本用法后,其实它还是不足以支撑真实的项目运转的,简单点就是不够工程化(请再一次记住工程化这个概念,没有工程化的思想是不可能进一步提升的),现在五花八门的解决方案都有一些,这里罗列下(感兴趣的同学可以先自行学习) yapi:https://hellosean1025.github.io/yapi/ yapi和swagger集成:https://www.jianshu.com/p/b6bcf95ddbfe日期时间API
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8tester = new Java8Tester();
java8tester.testLocalDateTime();
}
public void testLocalDateTime(){
// 获取当前的日期时间
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("date1: " + date1);
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date2: " + date2);
// 12 december 2014
LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
System.out.println("date3: " + date3);
// 22 小时 15 分钟
LocalTime date4 = LocalTime.of(22, 15);
System.out.println("date4: " + date4);
// 解析字符串
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date5: " + date5);
}
}
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8tester = new Java8Tester();
java8tester.testZonedDateTime();
}
public void testZonedDateTime(){
// 获取当前时间日期
ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
System.out.println("date1: " + date1);
ZoneId id = ZoneId.of("Europe/Paris");
System.out.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当期时区: " + currentZone);
}
}
Lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
Swagger
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("用户基本信息")
public class SysUser {
/**
* 用户名
*/
@ApiModelProperty("用户名")
private String userName;
/**
* 用户昵称
*/
@ApiModelProperty("用户昵称")
private String nickName;
/**
* 邮件
*/
@ApiModelProperty("邮件")
private String email;
/**
* 手机号
*/
@ApiModelProperty("手机号")
private String mobile;
}
@Api(tags = "用户管理")
@RestController
@RequestMapping("/sysUser")
public class SysUserController {
/**
* 保存用户信息
* @param sysUser
* @return ResultT<java.lang.String>
* @author missye
* @since 2020/7/21
*/
@ApiOperation("保存用户信息")
@PostMapping("/saveSysUser")
public ResultT<String> saveSysUser(@RequestBody SysUser sysUser) {
//保存用户信息
return ResultT.ok("用户保存成功!");
}
}
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- swagger3 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
@EnableOpenApi
@Configuration
public class SwaggerConfig {
@Bean
public Docket docket() {
Docket docket = new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo()).enable(true)
.select()
//apis: 添加swagger接口提取范围
.apis(RequestHandlerSelectors.basePackage("com.easycloud.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Java系统开发从入门到精通 演示 API")
.description("ruyicloud")
.contact(new Contact("小刀神", "https://ruyicloud.cn", "[email protected]"))
.version("1.0")
.build();
}
}
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
spring.mvc.pathmatch.matching-strategy=ant_path_matcher