腳手架開發-Common封裝基礎通用工具類<基礎工具類>

書接上文

java一個腳手架搭建_redission java腳手架-CSDN博客

以微服務為基礎搭建一套腳手架開始前的介紹-CSDN博客

腳手架開發-準備配置-進行數據初始化-配置文件的準備-CSDN博客

腳手架開發-準備配置-配置文件的準備項目的一些中間件-CSDN博客

腳手架開發-Nacos集成-CSDN博客

腳手架開發-網關集成-CSDN博客


Common包

????????在項?開發過程中,常常會進?諸如操作JSON、操作字符串、操作時間等?具類。在不同的項? ?,這些操作往往是相同的。因此,在這個項?中,我們可以將這部分操作封裝為基礎通?的部 分。

  • 了解封裝基礎?具類;
  • 公共模塊及基礎通?包創建;
  • 基礎通??具類封裝完成;
  • 基礎通??具類功能驗證測試通過。

公共模塊及基礎通用包創建

? ? ? ? 相信有的朋友已經注意到了,在這個腳手架開發中是有一個公共模塊的,它獨立出來就是未來存放所有其他模塊公共使用的類,而common包下有一個具體的層次common-core就是專門用來存放我們的基礎通用工具類。

commoncommon-core都是用module創建出來的,到了后面的包則是package

? ? ? ? 廢話不多說,如圖

  • 1. 創建公共模塊 rs-common
  • 2.創建公共模塊的??程基礎通?包( rs-common-core)
  • 3. 在 rs-common-core ?程中創建 com.renting.rscommoncore 包。
  • 4. 在 com.renting.rscommoncore 包下創建 utils 包?于存放基礎通??具類。

封裝JSON基礎?具類

????????JSON(JavaScript Object Notation)是?種輕量級的數據交換格式。數據交換指的是客?端和服務 器之間業務數據的傳輸格式。 JSON 是?種完全獨?于語?的?本格式,開發者很容易閱讀和編寫, 機器很容易解析和?成,能有效地提升?絡傳輸效率。這些優點也使 JSON 成為?種理想的獨?語??本格式。

????????需要所有?具類的理由都是?樣的,就是項?開發中使?的頻率?。

????????在?絡傳輸場景中,JSON?格式的數據量相對較?。與其他格式(如 XML)相?,JSON 沒有過多的標簽和冗余信息,這使得它在帶寬有限的?絡環境下能夠更?效地傳輸數據。所以在?絡傳輸中我們? 般選擇JSON作為數據傳輸格式。

????????在項?開發中我們經常會涉及到要將對象數據進?存儲。?如說要將對象存儲到Redis等存儲機制中。 描述同樣的消息,json相?xml占?更少的空間。

????????我們可以看一個直觀的例子。

XML

<?xml version="1.0" encoding="UTF-8" ?>
<user><id>1</id><name>張三</name><age>30</age>
</user>

Json

{"id": 1,"name": "張三","age": 30}

那么我們應該做的,是什么?

  • 提供對象轉json(對象序列化)
    • 提供對象轉json格式化
  • 提供json轉對象(對象反序列化)

怎么封裝?

1.創建JsonUtil類

2.引入依賴

rs-common中的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>renting</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>rs-common</artifactId><packaging>pom</packaging><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>16</source><target>16</target></configuration></plugin></plugins></build><modules><module>rs-common-core</module></modules><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>

3.JsonUtil中的代碼

package com.renting.rscommoncore.utils;import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** JSON?具類*/@Slf4jpublic class JsonUtil {/*** 對象轉換器*/private static ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER =JsonMapper.builder().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false).configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false).configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false).configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false).configure(MapperFeature.USE_ANNOTATIONS, false).addModule(new JavaTimeModule()).defaultDateFormat(new SimpleDateFormat(CommonConstants.S)).serializationInclusion(JsonInclude.Include.NON_NULL).build();}/*** 禁?構造*/private JsonUtil() {}/*** 對象轉Json格式字符串* @param obj 對象* @return Json格式字符串* @param <T> 對象類型*/public static <T> String obj2String(T obj) {if (obj == null) {return null;}try {return obj instanceof String ? (String) obj :OBJECT_MAPPER.writeValueAsString(obj);} catch (JsonProcessingException e) {log.warn("Parse Object to String error : {}", e.getMessage());return null;}}/*** 對象轉Json格式字符串(格式化的Json字符串)* @param obj 對象* @return 美化的Json格式字符串* @param <T> 對象類型*/public static <T> String obj2StringPretty(T obj) {if (obj == null) {return null;}try {return obj instanceof String ? (String) obj :OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);} catch (JsonProcessingException e) {log.warn("Parse Object to String error : {}", e.getMessage());return null;}}/*** 字符串轉換為?定義對象* @param str 要轉換的字符串* @param clazz ?定義對象的class對象* @return ?定義對象* @param <T> 對象類型*/public static <T> T string2Obj(String str, Class<T> clazz) {if (str == null || str.isEmpty()|| clazz == null) {return null;}try {return clazz.equals(String.class) ? (T) str :OBJECT_MAPPER.readValue(str, clazz);} catch (Exception e) {log.warn("Parse String to Object error : {}", e.getMessage());return null;}}/*** 字符串轉換為?定義對象,?持復雜的泛型嵌套* @param str json字符串* @param valueTypeRef 對象模板信息* @return 對象類對應的對象* @param <T> 對象類*/public static <T> T string2Obj(String str, TypeReference<T> valueTypeRef){if (str == null || str.isEmpty() || valueTypeRef == null) {return null;}try {return OBJECT_MAPPER.readValue(str,valueTypeRef);} catch (Exception e) {log.warn("Parse String to Object error : {}", e.getMessage());return null;}}/*** 字符串轉換為?定義字段轉為list,?持List嵌套簡單對象* @param str json字符串* @param clazz 對象類* @return 對象列表* @param <T> 對象類型*/public static <T> List<T> string2List(String str, Class<T> clazz) {if (str == null || str.isEmpty()|| clazz == null) {return null;}JavaType javaType =OBJECT_MAPPER.getTypeFactory().constructParametricType(List.class, clazz);try {return OBJECT_MAPPER.readValue(str, javaType);} catch (IOException e) {log.error("Parse String to Object error : {}" + e.getMessage());return null;}}/*** 字符串轉換為?定義字段轉為map,?持Map嵌套簡單對象* @param str str 字符串信息* @param valueClass valueClass value的類別* @return map對象* @param <T> value 的類型*/public static <T> Map<String, T> string2Map(String str, Class<T>valueClass){if (str == null || str.isEmpty() || valueClass == null) {return null;}JavaType javaType =OBJECT_MAPPER.getTypeFactory().constructMapType(LinkedHashMap.class,String.class, valueClass);try {return OBJECT_MAPPER.readValue(str, javaType);} catch (JsonProcessingException e) {log.warn("Parse String to Object error : {}", e.getMessage());return null;}}
}

解釋:

1.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

在反序列化時,當遇到JSON數據中存在Java對象對應類中沒有定義的屬性時,默認情況下?Jackson會拋出異常。通過將這個配置項設置為false,表?允許在反序列化時忽略那些未知的屬性,不會因為出現額外的屬性?導致反序列化失敗,增強了對不同來源JSON數據的兼容性。

2. .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,?false)在序列化時,如果Java對象中包含?期類型默認情況下Jackson可能會將?期轉換為時間戳(?個表?從某個特定時間點開始到當前時間的毫秒數等形式的數值來表?。將此配置設置為false,意味著不采?時間戳的?式來表??期,?是會按照后續配置的其他?期相關格式進?序列 化,以便?成更具可讀性的?期格式表?在JSON數據中。

3. .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false)在序列化時,Java對象中沒有任何屬性值(為空),默認情況下Jackson可能會拋出異常。設置 此項為false后,允許對這樣的空對象進?序列化,即便對象沒有實質內容也能?成對應的JSON?表?(通常可能是?個空的JSON對象{}),避免了因對象為空導致序列化失敗的情況。

4. .configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)在反序列化時,如果JSON數據中指定的類型信息與期望的Java類型層次結構不匹配(例如類型 標識錯誤等情況),默認會拋出異常。將這個配置設為false,可以放寬這種限制,使得在遇到類 型不太準確但仍有可能處理的情況下,嘗試繼續進?反序列化?不是直接失敗,提?對可能存在錯誤類型標識的JSON數據的容錯性。

5. .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)在序列化時,如果Java對象中有以?期類型作為鍵(?如在Map中,鍵是Date類型等情況的結構,如果設置為true會將?期鍵轉換為時間戳形式。設置為false則按照其他?期相關配置來處 理,保證?期鍵也以期望的格式進?序列化,使得整個JSON結構中?期相關內容都能保持統?的 格式呈現。(默認值為false)

6. .configure(MapperFeature.USE_ANNOTATIONS, false)?Jackson?持通過在Java類的屬性或?法上添加各種注解來定制序列化和反序列化?為。將此配 置設為false,表?不依賴這些注解來進?相關操作,?是更多地依據全局配置(如上述其他配置 項)來控制序列化和反序列化過程,適?于希望統?管理JSON處理規則,減少因注解使?不當或 過多導致的復雜性的場景。

7. addModule(newJavaTimeModule())?這是序列化LocalDateTIme和LocalDate的必要配置,由Jackson-data-JSR310實現。

8. .defaultDateFormat(new SimpleDateFormat(CommonConstants.STANDARD_FORMAT))?所有的?期格式都統?為以下的樣式,即yyyy-MM-dd HH:mm:ss

4.泛型擦除<理解>

我們給出這樣一段代碼

@Test2    
public void string2ListObjTest(){
//        TestRegion testRegion = new TestRegion();
//        testRegion.setId(1L);
//        testRegion.setName("北京");
//        testRegion.setFullName("北京市");
//        testRegion.setCode("110000");
//        List<TestRegion> regionList = new ArrayList<>();
//        regionList.add(testRegion);
//        System.out.println(JsonUtil.obj2String(regionList));
//        [{"id":1,"name":"北京","fullName":"北京市","code":"110000"}]
List list = JsonUtil.string2Obj("[{\"id\":1,\"name\":\"北京\",\"fullName\":\"北京市\",\"code\":\"110000\"}]", List.class);System.out.println(list);

我們單步調試可以看到list和我們定義的類型不?致

????????這是因為java的泛型擦除導致的,如果后?代碼我們基于List繼續定義,那么會報類型不匹配。

什么是泛型擦除?

????????Java中的泛型擦除(Type Erasure)是指Java編譯器在編譯泛型代碼時,會移除泛型類型參數的相關信息,使得?成的字節碼中不包含泛型類型信息。這使得Java泛型在運?時(Runtime)表現為原始類型(Raw Type)。

為什么出現泛型擦除:

? ? ? ? 向后兼容:新舊代碼兼容,在編譯時泛型信息就擦除了,所以舊版本jvm可以運載新代碼

? ? ? ? 類型安全:盡管泛型信息在編譯時被擦除,但在編譯時會進?類型檢查,確保泛型的使用是安全的。這意味著你可以在編譯時發現類型錯誤,而不是在運行時

? ? ? ? 避免性能開銷:所有的類型信息在編譯時就已經確定,泛型擦除避免了如果JVM需要在運?時維護泛型類型信息引入的額外開銷。

解決方法:

????????常見的Collection如 List、Map 中包含泛型,需要先反序列化Collection類型為泛型的CollectionType。

????????如果是ArrayList那么使?ObjectMapper的 getTypeFactory().constructParametricType(collectionClass,YourBean.class)。

????????HashMap那么 ObjectMapper 的 getTypeFactory().constructMapType(HashMap.class,String.class, YourBean.class)。


封裝Bean拷貝基礎工具類

????????Bean拷?(BeanCopy)是指在?向對象編程中,將?個Java對象(通常稱為源Bean)的屬性值復制到另?個Java對象(目標Bean)中的操作。

示例:

@Testpublic void beanCopyTest() {//源bean : TestUser {"name" : "張三","sex" : "男","age" : 29}//?標bean: TestUserVO  TestUserVO userVO = new TestUserVO();userVO.setName(testUser.getName());userVO.setAge(testUser.getAge());
}

????????Web項目中有控制器(Controller)層、業務邏輯(service)層、數據訪問 (DAO)層。不同層之間通常會使用不同的數據模型,這就意味著項目中往往不止一種數據模型,經常需要將數據從一種數據模型轉換成另外一種 數據模型,正因如此,才需要Bean拷貝。

具體來說分為這

幾種常見的數據模型:

DO(Data Object)是?個與數據庫表結構對應的對象,也叫持久化對象。DO通常?來在DAO層 (數據訪問層)和數據庫進?交互。

BO(Business Object)是?個封裝業務邏輯的對象,主要存在于業務邏輯層。它封裝了業務邏輯 相關的數據和操作。BO不僅僅是簡單的數據容器,還包含了業務規則和業務流程相關的?法。?

DTO(Data Transfer Object)是?個?來傳輸數據的對象。DTO?來在不同層或不同系統之間傳 遞數據,?如從Service層傳遞到Controller層或者Controller層傳遞到service層等。DTO可以避免 在層與層之間傳遞過多的不必要的數據,同時也可以隱藏內部的數據結構和實現細節。

VO(View Object)是?個?來展?數據的對象(返回給前端的數據)。它是根據具體的視圖(如?Web??、桌?應?的界?等)的要求,將數據以?種合適的形式進?組織和封裝,以便于在視圖中進進行展示。

POJO(Plain Ordinary Java Object)是?個普通的Java對象,它沒有任何特殊的要求或約束,可 以?來表?任何類型的數據。


拷貝

????????手動拷貝
private String QQ;...............public TestUserVO convertToVO() {TestUserVO userVO = new TestUserVO();userVO.setName(this.name);userVO.setAge(this.age);............return userVO ;
? ? ? ? 拷貝工具

BeanUtils.copyProperties() 是 Spring 框架提供的?個?具?法,它可以簡化對象屬性的拷貝操作

TestUserVO userVO = new TestUserVO();
BeanUtils.copyProperties(user, userVO);

? ? ? ? 但如果源bean和?標bean之間的屬性名稱不?致,或者源bean向?標bean拷?時需要對源bean 中的屬性值進?處理后再進?拷?。此時使??具類就?法準確的完成拷??作了

????????拷貝工具類+手動拷貝

使?spring提供的?具類,針對具體的對象提供專?的bean拷??法,就是拷貝工具類+手動拷貝

例如

@Getter
@Setter
@ToStringpublic class TestUserVO {private String nickName;private int age;private String school;private String contactInfo;
}
public class TestUser {private String name;private int age;private String sex;private String school;private String weChat;private String QQ;...............public TestUserVO convertToVO() {TestUserVO userVO = new TestUserVO();BeanUtils.copyProperties(user, userVO);userVO.setNickName(this.name);userVO.setContactInfo(this.weChat + "--" + this.QQ);return userVO ;}
}
????????內置拷??具類+拷??具類+?動拷?

單個對象普通拷?:直接使?spring提供的?具類。

列表對象普通拷?:由于拷?spring框架提供的bean拷??具類?法?持對列表對象的拷??作,所 以我們需要??封裝內置Bean拷??具類提供對列表對象的拷??法。

特殊拷?(包括列表對象和單個對象):需要?動拷?。針對具體的對象提供專?的bean拷??法。

Bean拷貝工具類

1.創建BeanCopyUtil工具類

BeanUtils.copyProperties 不?持列表拷?,默認只?持java bean,我們擴展下該?法?持 列表拷?

package com.renting.rscommoncore.utils;import org.springframework.beans.BeanUtils;import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;public class BeanCopyUtil extends BeanUtils {/*** 集合數據的拷?* @param sources 數據源類* @param target ?標類::new(eg: UserVO::new)* @return 拷?結果* @param <S> 源?標類型* @param <T> ?標對象類型*/public static <S, T> List<T> copyListProperties(List<S> sources,Supplier<T> target) {List<T> list = new ArrayList<>(sources.size());for (S source : sources) {T t = target.get();copyProperties(source, t);list.add(t);}return list;}
}

2.Spring框架提供的Bean拷??具類問題

?屬性類型不?致導致拷?失敗

實際開發中,很可能會出現同?字段在不同的類中定義的類型不?致,例如ID,可能在A類中 定義的類型為Long,在B類中定義的類型為String,此時如果使?BeanUtils.copyProperties進?拷?,就會出現拷?失敗的現象,導致對應的字段為null

@Data
@AllArgsConstructor
@NoArgsConstructorclass SourcePoJo{private String username;private Long id;
}@Data class TargetPoJo{private String username;private String id;
}@Testvoid copyfail1() {SourcePoJo sourcePoJo = new SourcePoJo("bite", (long) 1000000);TargetPoJo targetPoJo = new TargetPoJo();BeanUtils.copyProperties(sourcePoJo,targetPoJo);System.out.println(targetPoJo);
}輸出結果會變成
BeanUtilsTests.TargetPoJo(username=bite, id=null)

在實際開發中,很可能會出現同?字段在不同的類中定義的類型不?致,例如ID,可能在A類中 定義的類型為Long,在B類中定義的類型為long,此時如果使BeanUtils.copyProperties進?拷?,就會出現拷?失敗的現象,會拋出FatalBeanException。

@Data
@AllArgsConstructor
@NoArgsConstructorclass SourcePoJo{private String username;private Long id;
}@Dataclass TargetPoJo2{private String username;private long id;
}@Testvoid copyfail2() {SourcePoJo sourcePoJo = new SourcePoJo();sourcePoJo.setUsername("bite");TargetPoJo2 targetPoJo2 = new TargetPoJo2();BeanUtils.copyProperties(sourcePoJo,targetPoJo2);System.out.println(targetPoJo2);
}輸出結果:
org.springframework.beans.FatalBeanException: Could not copy property 'id' 
from source to targetat 
org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java...(報錯信息)
底層實現為反射拷?效率低

BeanUtils.copyProperties底層是通過反射獲取到對象的set和get?法,然后通過get、set完成數據的 拷?,整體拷?效率較低。

????????使?BeanUtils.copyProperties拷?數據和直接set的?式賦值效率對?,為了便于直觀的看出 效果,這?以拷?1萬次為例:

@Testvoid copyslow(){long copyStartTime = System.currentTimeMillis();SourcePoJo source = new SourcePoJo("bite",1000000L);TargetPoJo2 target = new TargetPoJo2();for(int i = 0; i < 10000; i++) {BeanUtils.copyProperties(source, target);}System.out.println("copy?式:"+(System.currentTimeMillis()-
copyStartTime));long setStartTime = System.currentTimeMillis();for(int i = 0; i < 10000; i++) {target.setUsername(source.getUsername());target.setId(source.getId());}System.out.println("set?式:"+(System.currentTimeMillis()-setStartTime));
}結果:
copy?式:127
set?式:0
BeanUtils.copyProperties是淺拷?
? ? ? ? 淺拷貝是說在創建?個新對象(?標對象),?標對象的屬性值與原始對象相同,但對于引?類型的屬性,仍然共享相同的引?。也就是說在淺拷?下,當源對象的引?屬性的值發?變化時,?標對象的引?屬性值也會隨之發?變化

我們可以舉一個簡單的例子

@Data
@NoArgsConstructor
@AllArgsConstructorclass Card {private String num;
}@NoArgsConstructor
@AllArgsConstructor
@Dataclass Person {private String name;private Card card;
}@Testvoid copylight(){Person sourcePerson = new Person("bite",new Card("123456"));Person targetPerson = new Person();BeanUtils.copyProperties(sourcePerson, targetPerson);System.out.println(targetPerson);sourcePerson.getCard().setNum("654321");System.out.println(targetPerson);//修改后代碼: 
Person sourcePerson = new Person("bite",new Card("123456"));Person targetPerson = new Person();BeanUtils.copyProperties(sourcePerson, targetPerson);Card targetCard = new Card();BeanUtils.copyProperties(sourcePerson.getCard(), targetCard);targetPerson.setCard(targetCard);System.out.println(targetPerson);sourcePerson.getCard().setNum("654321");System.out.println(targetPerson);
}結果如下:
BeanCopyUtilTests.Person(name=bite, card=BeanCopyUtilTests.Card(num=123456))
BeanCopyUtilTests.Person(name=bite, card=BeanCopyUtilTests.Card(num=654321))
內部類數據無法成功拷貝

Spring 的?BeanUtils.copyProperties?在處理內部類屬性時會遇到拷貝失敗的問題,這是由其設計機制決定的。

  1. 訪問權限限制

    • 內部類的字段默認是?private?訪問級別

    • BeanUtils?使用反射訪問字段時,無法突破 Java 的訪問控制規則

    • 示例:內部類?Inner?的字段?innerValue?無法被外部訪問

  2. Getter/Setter 缺失

    • 內部類的字段通常沒有公共的 getter/setter 方法

    • BeanUtils?依賴標準的 JavaBean 規范(通過 getter/setter 訪問屬性)

    • 當缺少這些方法時,屬性拷貝會靜默失敗


其它的一些公共工具類

時間戳工具類

  • 獲取當前時間戳
  • 獲取未來x秒的時間戳
  • 獲取未來x天的時間戳
  • 獲取未來x?的時間戳
  • 獲取未來x年的時間戳
  • 計算兩個時間戳之間的差異
  • 所有?法均提供返回秒級時間和毫秒級時間兩種實現

package com.renting.rscommoncore.utils;import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;public class TimeStampUtil {/*** 獲取當前時間戳(秒級)* @return 當前時間戳(秒級)*/public static long getCurrentSeconds() {return Instant.now().getEpochSecond();}/*** 獲取當前時間戳(毫秒級)* @return 當前時間戳(毫秒級)*/public static long getCurrentMillis() {return Instant.now().toEpochMilli();}/*** 獲取未來x秒的時間戳(秒級)* @param seconds 秒* @return 時間戳*/public static long getSecondsLaterSeconds(long seconds) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime secondsLater = now.plusSeconds(seconds);return secondsLater.toEpochSecond();}/*** 獲取未來x秒的時間戳(毫秒級)* @param seconds 秒* @return 時間戳*/public static long getSecondsLaterMillis(long seconds) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime secondsLater = now.plusSeconds(seconds);return secondsLater.toInstant().toEpochMilli();}/*** 獲取未來x天的時間戳(秒級)* @param days 天* @return 時間戳*/public static long getDaysLaterSeconds(long days) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime secondsLater = now.plusDays(days);return secondsLater.toEpochSecond();}/*** 獲取未來x天的時間戳(毫秒級)* @param days 天* @return 時間戳*/public static long getDaysLaterMillis(long days) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime monthsLater = now.plusDays(days);return monthsLater.toInstant().toEpochMilli();}/*** 獲取未來x?的時間戳(秒級)* @param months ?* @return 時間戳*/public static long getMonthsLaterSeconds(long months) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime monthsLater = now.plusMonths(months);return monthsLater.toEpochSecond();}/*** 獲取未來x?的時間戳(毫秒級)* @param months ?* @return 時間戳*/public static long getMonthsLaterMillis(long months) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime monthsLater = now.plusMonths(months);return monthsLater.toInstant().toEpochMilli();}/*** 獲取未來x年的時間戳(秒級)* @param years 年* @return 時間戳*/public static long getYearLaterSeconds(long years) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime yearLater = now.plusMonths(years);return yearLater.toEpochSecond();}/*** 獲取未來x年的時間戳(毫秒級)* @param years 年* @return 時間戳*/public static long getYearLaterMillis(long years) {ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC"));ZonedDateTime yearLater = now.plusMonths(years);return yearLater.toInstant().toEpochMilli();}/*** 計算兩個時間戳之間的差異(毫秒)* @param timestamp1 時間戳1* @param timestamp2 時間戳2* @return 時間戳差異(毫秒)*/public static long calculateDifferenceMillis(long timestamp1, longtimestamp2) {return ChronoUnit.MILLIS.between(Instant.ofEpochMilli(timestamp1),Instant.ofEpochMilli(timestamp2));}/*** 計算兩個時間戳之間的差異(秒)* @param timestamp1 時間戳1* @param timestamp2 時間戳2* @return 時間戳差異(秒)*/public static long calculateDifferenceSeconds(long timestamp1, longtimestamp2) {return ChronoUnit.SECONDS.between(Instant.ofEpochSecond(timestamp1),Instant.ofEpochSecond(timestamp2));}
}

String?具類

  • 提供字符串常?操作
  • 判斷url是否與規則匹配(url:特殊的字符串)
    • 判斷指定字符串(url)是否與指定匹配規則鏈表中的任意?個匹配規則匹配

引入依賴

<dependencies><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId></dependency>
</dependencies>

package com.renting.rscommoncore.utils;import org.apache.commons.lang3.StringUtils;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;import java.util.List;/*** 字符串?具類*/
public class StringUtil {/*** 判斷指定字符串是否與指定匹配規則鏈表中的任意?個匹配規則匹配* @param str 指定字符串* @param patternList 匹配規則鏈表* @return 是否匹配*/public static boolean matches(String str, List<String> patternList){if (StringUtils.isEmpty(str) || CollectionUtils.isEmpty(patternList)){return false;}for (String pattern : patternList){if (isMatch(pattern, str)){return true;}}return false;}/*** 判斷url是否與規則匹配* 匹配規則:* 精確匹配* 匹配規則中包含 ? 表?任意單個字符;* 匹配規則中包含 * 表??層路徑內的任意字符串,不可跨層級;* 匹配規則中包含 ** 表?任意層路徑的任意字符,可跨層級* @param pattern 匹配規則* @param url 需要匹配的url* @return 是否匹配*/public static boolean isMatch(String pattern, String url){if (StringUtils.isEmpty(url) || StringUtils.isEmpty(pattern)) {return false;}AntPathMatcher matcher = new AntPathMatcher();return matcher.match(pattern, url);}
}

如果說還有需要添加的,不論是說你需要的還是后面加上來的,滿足下面三個原則即可

?具類封裝原則

  • 先從成熟的?商所提供的?具類當中尋找,推薦:spring和apache,具體不做限制,但是要確定安 全可靠,明確?具類的特點。
  • 如果成熟?商所提供的?具類當中沒有們想要使?的?法,再封裝內置?具類提供。
  • 公司如果對此有明確要求,以公司要求為準。(常?要求:對于?種?具類的使?盡可能統?)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93654.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93654.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93654.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

軟件系統運維常見問題

系統部署常見問題 環境配置、兼容性問題。生產與測試環境的操作系統、庫版本、中間件版本不一致&#xff0c;運行環境軟件版本不匹配。新舊版本代碼/依賴不兼容。依賴缺失或沖突問題。后端包啟動失敗&#xff0c;提示類/方法/第三方依賴庫找不到或者版本沖突。配置錯誤。系統啟…

2021 IEEE【論文精讀】用GAN讓音頻隱寫術騙過AI檢測器 - 對抗深度學習的音頻信息隱藏

使用GAN生成音頻隱寫術的隱寫載體 本文為個人閱讀GAN音頻隱寫論文&#xff0c;部分內容注解&#xff0c;由于原文篇幅較長這里就不再一一粘貼&#xff0c;僅對原文部分內容做注解&#xff0c;僅供參考詳情參考原文鏈接 原文鏈接&#xff1a;https://ieeexplore.ieee.org/abstra…

PWA技術》》漸進式Web應用 Push API 和 WebSocket 、webworker 、serviceworker

PWA # 可離線 # 高性能 # 無需安裝 # 原生體驗Manifest {"name": "天氣助手", // 應用全名"short_name": "天氣", // 短名稱&#xff08;主屏幕顯示&#xff09;"start_url": "/index.html&…

數據結構——棧和隊列oj練習

225. 用隊列實現棧 - 力扣&#xff08;LeetCode&#xff09; 這一題需要我們充分理解隊列和棧的特點。 隊列&#xff1a;隊頭出數據&#xff0c;隊尾入數據。 棧&#xff1a;棧頂出數據和入數據。 我們可以用兩個隊列實現棧&#xff0c;在這過程中&#xff0c;我們總要保持其…

Java基礎 8.19

目錄 1.局部內部類的使用 總結 1.局部內部類的使用 說明&#xff1a;局部內部類是定義在外部類的局部位置&#xff0c;比如方法中&#xff0c;并且有類名可以直接訪問外部類的所有成員&#xff0c;包含私有的不能添加訪問修飾符&#xff0c;因為它的地位就是一個局部變量。局…

從父類到子類:C++ 繼承的奇妙旅程(2)

前言&#xff1a;各位代碼航海家&#xff0c;歡迎回到C繼承宇宙&#xff01;上回我們解鎖了繼承的「基礎裝備包」&#xff0c;成功馴服了public、protected和花式成員隱藏術。但——??前方高能預警&#xff1a; 繼承世界的暗流涌動遠不止于此&#xff01;今天我們將勇闖三大神…

【圖像算法 - 16】庖丁解牛:基于YOLO12與OpenCV的車輛部件級實例分割實戰(附完整代碼)

庖丁解牛&#xff1a;基于YOLO12與OpenCV的車輛部件級實例分割實戰&#xff08;附完整代碼&#xff09; 摘要&#xff1a; 告別“只見整車不見細節”&#xff01;本文將帶您深入實戰&#xff0c;利用YOLO12-seg訓練實例分割模型&#xff0c;結合OpenCV的強大圖像處理能力&…

ubuntu22.04配置遠程桌面

文章目錄前言檢查桌面類型xorg遠程桌面(xrdp)安裝xrdpxrdp添加到ssl-certwayland遠程桌面(gnome-remote-desktop)檢查安裝開啟開啟狀況檢查自動登錄奇技淫巧前言 在windows上使用遠程桌面服務&#xff0c;連接ubuntu主機的遠程桌面 檢查桌面類型 查看桌面類型、協議 echo $…

SQL Server 中子查詢、臨時表與 CTE 的選擇與對比

在 SQL Server 的實際開發過程中&#xff0c;我們常常需要將復雜的查詢邏輯分解為多個階段進行處理。實現這一目標的常見手段有 子查詢 (Subquery)、臨時表 (Temporary Table) 和 CTE (Common Table Expression)。這三者在語法、執行效率以及可維護性方面各有優勢與局限。如何選…

肖臻《區塊鏈技術與應用》第20-22講 - 以太坊難度調整、權益證明和智能合約

以太坊的“冰河時代”:詳解難度調整算法與“難度炸彈” 摘要: 為了實現遠快于比特幣的十幾秒出塊速度,以太坊必須設計一套更為靈敏和復雜的挖礦難度調整算法。本文基于北京大學肖臻老師的公開課內容,深入剖析了以太坊獨特的逐塊難度調整機制。文章首先解釋了其維持15秒平均…

C++中內存池(Memory Pool)詳解和完整示例

1. 什么是內存池&#xff1f; 內存池&#xff08;Memory Pool / Pool Allocator&#xff09; 是一種內存管理機制&#xff0c;提前向系統申請一大塊內存&#xff0c;再在這塊內存里切分、分配和回收。 它相當于在用戶空間建立了一層 “小型堆管理器”&#xff0c;避免頻繁調用系…

測試 Next.js 應用:工具與策略

1. 引言 Next.js 作為一個基于 React 的全棧框架&#xff0c;在構建復雜 Web 應用時&#xff0c;測試是確保代碼質量、功能穩定性和用戶體驗的關鍵步驟。測試可以分為單元測試、集成測試和端到端測試三種類型&#xff0c;每種類型針對不同的層面&#xff1a;單元測試驗證單個組…

IP 分片和組裝的具體過程

IP 分片和組裝的具體過程 在這里插入圖片描述 ? 16 位標識(id): 唯一的標識主機發送的報文. 如果 IP 報文在數據鏈路層被分片了, 那么每一個片里面的這個 id 都是相同的. ? 3 位標志字段: 第一位保留(保留的意思是現在不用, 但是還沒想好說不定以后要用到). 第二位置為 1 表示…

數據倉庫OLTPOLAP維度講解

?博客主頁&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客內容》&#xff1a;大數據、Java、測試開發、Python、Android、Go、Node、Android前端小程序等相關領域知識 &#x1f4e2;博客專欄&#xff1a; https://blog.csdn.net/m0_63815035/…

OpenHarmony之編譯配置白名單機制深度解析:構建系統的安全防線

一、白名單機制概述 在OpenHarmony的構建系統中&#xff0c;compile_standard_whitelist.json是一個關鍵的安全驗證機制&#xff0c;它作為編譯過程中的"守門人"&#xff0c;確保只有經過驗證的組件和依賴關系才能被納入最終構建產物。這個機制是OpenHarmony構建系統…

backward怎么計算的是torch.tensor(2.0, requires_grad=True)變量的梯度

import torch import torch.nn as nn import torch.optim as optim# 一個參數 w 2 w torch.tensor(2.0, requires_gradTrue) # 預測值 y_pred w * 3 # 6 # 真實值 y_true torch.tensor(10.0) # 損失 (預測 - 真實)^2 loss (y_pred - y_true) ** 2 # (6-10)^2 16loss.b…

戴永紅×數圖:重構零售空間價值,讓陳列創造效益!

風雨同舟&#xff0c;智贏未來。近日&#xff0c;湖南戴永紅商業連鎖有限公司&#xff08;以下簡稱“戴永紅”&#xff09;正式攜手數圖信息科技有限公司&#xff0c;全面啟動“可視化品類空間管理”項目。以數圖可視化陳列系統為引擎&#xff0c;雙方將共同推進企業零售管理的…

排查Redis數據傾斜引發的性能瓶頸

以下是針對 Redis 數據傾斜問題的完整排查與優化方案&#xff0c;結合實戰案例說明如何提升吞吐量和響應速度&#xff1a;一、問題現象定位1. ?性能監控異常?# Redis集群節點負載差異 $ redis-cli -c cluster nodes | grep master e1d7b... 10.0.0.1:637916379 master - 0 16…

元宇宙的硬件設備:從 VR 頭顯到腦機接口

1 元宇宙的主流硬件設備1.1 VR 頭顯&#xff1a;沉浸式體驗的核心入口VR 頭顯是當前進入元宇宙最主要的硬件設備&#xff0c;通過封閉的顯示系統為用戶營造沉浸式虛擬環境。主流 VR 頭顯采用雙屏 LCD 或 OLED 顯示技術&#xff0c;單眼分辨率已從早期的 1080P 提升至 4K 級別&a…

具身智能2硬件架構(人形機器人)摘自Openloong社區

青龍人形機器人: 硬件 身體全身自由度43,手部自由度6*2,電池續航3h,運動控制算法(zmp/slip/mpc/深度學習)MPC+WBC+強化學習,54Tops(FP16),具有路徑建圖和自主導航能力,感官系統深度視覺傳感器*3全景環視*1,具備語音識別與聲源定位,可擴展嗅覺傳感器 OpenLoong通…