百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

Java系统开发从入门到精通第四讲(文字版)

liuian 2025-02-26 12:45 10 浏览


课程目标:了解重要的Java API 和 一些必备框架的使用,这些都是系统开发的标配需要掌握

日期时间API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:

  • 非线程安全 ? java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 ? Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理麻烦 ? 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。

Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:

  • Local(本地) ? 简化了日期时间的处理,没有时区的问题。
  • Zoned(时区) ? 通过制定的时区处理日期时间。

新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。

因为之前的日期时间API比较糟糕,一般都会自己写DateTimeUtil工具类,后来也有Joda-Time开源项目,确实帮广大程序员解决了大问题(所以程序员为什么不止要会用框架和java API,就是需要知其然也知其所以然,如果底层本身有缺陷或实现不好,最差我们知道,当然我们也可以增强或自己实现)

LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。代码如下:


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);
   }
}

如果我们需要考虑到时区,就可以使用时区的日期时间API:


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

https://projectlombok.org/

现在很多的java工程里都有Lombok的应用,可见它有多实用(也有反对的文章,可以参见:
https://zhuanlan.zhihu.com/p/146659383)。

lombok可以通过简单的注解的形式来帮助我们简化和消除一些必须有但显得很臃肿的Java代码,比如常见的Getter&Setter、toString()、构造函数等等。lombok不仅方便编写,同时也让我们的代码更简洁。 lombok提供了一个功能完整的jar包,可以很方便的与我们的项目进行集成。

引入依赖:


    org.projectlombok
    lombok
    1.18.22
    provided

常见注解:

  • @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
  • @Getter 使用方法同上,区别在于生成的是getter方法。
  • @ToString 注解在类,添加toString方法。
  • @EqualsAndHashCode 注解在类,生成hashCode和equals方法。
  • @NoArgsConstructor 注解在类,生成无参的构造方法。
  • @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
  • @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
  • @Data 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
  • @Slf4j 注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

完整注解参见:
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点原因:

  • api都在com.sun.mirror非标准包下
  • 没有集成到javac中,需要额外运行

2)Pluggable Annotation Processing API

JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强。

Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:

  1. javac对源代码进行分析,生成了一棵抽象语法树(AST)
  2. 运行过程中调用实现了“JSR 269 API”的Lombok程序
  3. 此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
  4. javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)

通过读Lombok源码,发现对应注解的实现都在HandleXXX中,比如@Getter注解的实现在HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google Auto、Dagger等等。

前面讲Spring AOP时有提及动态代理实现,底层都是字节码增强和这里的Lombok底层原理一致。(这和元数据理念如出一辙,在元数据、元元数据每一层抽象描述层增强都能使前一层的动态化能力成为现实)

关于字节码增强,感兴趣的同学自行baidu(
https://www.cnblogs.com/luxiaoxun/p/15075778.html)

Swagger

https://swagger.io/

Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。通俗的来讲,Swagger 就是将项目中所有(想要暴露的)接口展现在页面上,并且可以进行接口调用和测试的服务。

PS:Swagger 遵循了 OpenAPI 规范,OpenAPI 是 Linux 基金会的一个项目,试图通过定义一种用来描述 API 格式或 API 定义的语言,来规范 RESTful 服务开发过程。

Swagger 有以下 3 个重要的作用:

  • 将项目中所有的接口展现在页面上,这样后端程序员就不需要专门为前端使用者编写专门的接口文档;
  • 当接口更新之后,只需要修改代码中的 Swagger 描述就可以实时生成新的接口文档了,从而规避了接口文档老旧不能使用的问题
  • 通过 Swagger 页面,我们可以直接进行接口调用,降低了项目开发阶段的调试成本

为什么需要swagger?

前面我们讲过,随着技术的发展,前后端分离架构越来越普及,我们知道以前在jvm内部调用别人的库要看javadoc,后来基于RPC的分布式调用使用java同种语言也是看javadoc(非同种语言调用就需要其他的调用描述),同理,前后端工程师需要一个统一沟通的接口描述方式,swagger就是解决这个问题的。对于服务提供方,我们主流的方式是基于RESTful规范,接口描述也有规范就是OpenAPI 规范,这也是后来面向API编程的一个基础设施。

常用注解:

  • @Api()用于类;

表示标识这个类是swagger的资源

  • @ApiOperation()用于方法;

表示一个http请求的操作

  • @ApiParam()用于方法,参数,字段说明;

表示对参数的添加元数据(说明或是否必填等)

  • @ApiModel()用于类

表示对类进行说明,用于参数用实体类接收

  • @ApiModelProperty()用于方法,字段

表示对model属性的说明或者数据操作更改

  • @ApiIgnore()用于类,方法,方法参数

表示这个方法或者类被忽略

  • @ApiImplicitParam() 用于方法

表示单独的请求参数

  • @ApiImplicitParams() 用于方法,包含多个 @ApiImplicitParam

看几个示例:

@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
     * @author missye
     * @since 2020/7/21
     */
    @ApiOperation("保存用户信息")
    @PostMapping("/saveSysUser")
    public ResultT saveSysUser(@RequestBody SysUser sysUser) {
        //保存用户信息
        return ResultT.ok("用户保存成功!");
    }
}

SpringBoot集成Swagger3

  • 增加依赖


    org.springframework.boot
    spring-boot-starter-web




    io.springfox
    springfox-boot-starter
    3.0.0
  • 增加SpringBoot配置
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

出现如上错误,配置增加:
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

  • 设置Configuration
@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", "yq76034150@163.com"))
                .version("1.0")
                .build();
    }
}

SpringBoot集成Knife4j

  • 增加依赖
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            com.github.xiaoymin
            knife4j-spring-boot-starter
            3.0.3
        
  • application.properties
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
  • 设置Configuration(同上)
  • 效果如下图


Knife4j可以参考这篇文章:
https://www.jianshu.com/p/7838842cb45e

掌握了swagger的基本用法后,其实它还是不足以支撑真实的项目运转的,简单点就是不够工程化(请再一次记住工程化这个概念,没有工程化的思想是不可能进一步提升的),现在五花八门的解决方案都有一些,这里罗列下(感兴趣的同学可以先自行学习)


yapi:https://hellosean1025.github.io/yapi/

yapi和swagger集成:
https://www.jianshu.com/p/b6bcf95ddbfe

相关推荐

HR必备Excel函数:4个与日期相关的计算函数。

提到日期函数,很多人首先会想到“today”,它可以显示当天的日期,并且每次打开表格时都会自动更新。但是,对于前天、昨天、明天和后天的日期,就不能用yesterday或者tomorrow等这些英文了,...

这篇文章有点长,但可以让你十分钟玩转Excel的时间函数

日期与时间函数——TODAY、NOW、YEAR、MONTH、DAY!如何用WORKDAY函数查询距离某天的第20个工作日是哪一天?如何用NETWORKDAYS函数查询员工工作了多少个工作日?如何用WE...

Excel2020年日历套装,表格设计,农历显示,查阅套打轻松应用

Hello大家好,我是帮帮。今天跟大家分享一组Excel2020年日历套装,表格设计,自带农历控件,查阅套打轻松应用。有个好消息!为了方便大家更快的掌握技巧,寻找捷径。请大家点击文章末尾的“了解更多”...

巧用NETWORKDAYS函数计算两个日期之间工作日的天数

带有日期的单元格是我们日常使用EXCEL的时候经常见到的,有的时候我们需要求出两个日期之间间隔的天数,可以直接用结束日期减去开始日期即可,这是个非常简单的减法公式。不过这个单纯的减法公式会默认去掉开始...

Excel按工作日、休息日进行汇总

1、按周六日/其它时间汇总为了区分一周的周六日和其它时间,可以使用WEEKDAY函数,把WEEKDAY函数的第2个参数指定为2,如WEEKDAY(A3,2),则周一返回1,周二返回2,…,周六返回...

如何计算每月应出勤天数,如有法定假期和调休,如何计算

本文介绍如何计算每月的应出勤天数。第一部分介绍正常双休制下计算应出勤天数;第二部份介绍当月有法定假期和调休的情况下计算应出勤天数。一、计算正常双休制的应出勤天数如下图所示,要求计算各员工2021年3月...

《Excel一键生成工作日历:让会议排期更轻松!》

每当需要安排会议时,总要翻看日历确认工作日,再逐个标注会议时间,既耗时又容易出错。今天教大家用Excel快速生成工作日历表,让会议排期变得简单高效!一、快速生成日历框架创建基础日期:在A1单元格输入月...

如何计算指定日期区间内,有多少工作日和休息日?

大家好,今天咱们要解决的问题是如何计算给定的一段日期内,正常工作日有多少天,放假时间有多少天?比如咱们要计算2025年3月份工作日一共有多少天,又有多少天放假,如下图所示:通过肉眼我们可以数清楚,20...

如何如何在表格中自动突出显示双休日?

现在不少人喜欢用Excel来制作备忘录或安排工作事项。在表格中输入日期后,可以使用条件格式突出显示双休日,避免在休息日安排了工作。具体方法是这样的:第1步:选择要设置条件格式的日期单元格区域;在“开始...

excel函数技巧:networkdays.intl判断节假日

如图,想知道6月的每一天是否是节假日,公式如下:=NETWORKDAYS.INTL(A2,A2,1,$E$2:$E$28)这个函数既可以判断当前日期(一参=二参)是否是周末及工作日(三参、四参)还可得...

仅需3步,让考勤表根据实际休息日,自动地填充颜色

Hello,大家好,之前跟大家分享了我们如何让考勤表根据单休与双休自动的填充颜色,最近有粉丝问到:能不能让考勤表根据实际的休息日自动的填充颜色呢?可以是可以,只不过因为牵扯到假期调休,我们每年的休息日...

5步搞定动态考勤表!标记节假日、调休日?Excel自动变色!

今天教你用「动态考勤表」一招解决所有问题!只需输入月份,自动变色、自动更新节假日,从此告别加班,效率翻倍!动态考勤表的优势:自动变色:节假日、双休日一键标记,颜色分明。一表多用:修改月份即可...

一起用python做个炫酷音乐播放器,想听啥随便搜

前言前段时间写的Python自制一款炫酷音乐播放器,有不少小伙伴私信我,对播放器提了不少改进建议,让我完善播放器的功能。今天音乐播放器2.0版本完成了,大家一起来看看是如何用python自制一款炫酷的...

用Python做个“冰墩墩雪容融”桌面部件(好玩又有趣)

桌面太单调?今天就带大家,一起用Python的PyQt5开发一个有趣的自定义桌面动画挂件,看看实现的动画挂件效果!下面,我们开始介绍这个自定义桌面动画挂件的制作过程。一、核心功能设计实现将动态图gif...

Python串口调试助手源码分享

以下是一个基于Python和PyQt5实现的串口调试助手示例,包含核心功能实现代码:pythonimportsysimportserialfromPyQt5.QtCoreimportQTim...