欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java處理字節(jié)類型數據的實現步驟

 更新時間:2024年07月15日 08:28:30   作者:趙俠客  
字節(jié)(Byte)是計算機信息技術用于計量存儲容量的一種基本單位,通常簡寫為B,在ASCII編碼中1Byte可以表示一個標準的英文字符,包括大寫字母、小寫字母、數字、標點符號和控制字符等,本文給大家介紹了Java如何優(yōu)雅的處理字節(jié)類型數據,需要的朋友可以參考下

前言

字節(jié)(Byte)是計算機信息技術用于計量存儲容量的一種基本單位,通常簡寫為B,1Byte=8bit,在ASCII編碼中1Byte可以表示一個標準的英文字符,包括大寫字母、小寫字母、數字、標點符號和控制字符等,共128個不同的字符,如1、2、3、a、b、c都占用一個Byte,所以1Byte其實是非常小的單位,比Byte大的單位就是KB,一般一篇博客文字的大小應該在幾十KB,比KB大的單位是MB,目前手機拍攝一張照片的大小大概是幾MB,比MB大的還有GB、TB、PB、EB、ZB、YB,以下是各單位間的轉換。

名稱簡寫換算 
比特(Byte)B1B=8bit
千字節(jié)(KiloByte)KB1KB=2^10 B =1024B
兆字節(jié)(Mega Byte)MB1MB=2^10 KB =2^20 B
吉字節(jié)(GigaByte)GB1GB=2^10 MB =2^30 B
太字節(jié)(TeraByte)TB1TB=2^10 GB =2^40 B
拍字節(jié)(PetaByte)PB1PB=2^10 TB =2^50 B
艾字節(jié)(EXAByte)EB1EB=2^10 PB =2^60 B
澤字節(jié)(Zetta Byte)ZB1ZB=2^10 EB =2^70 B
堯字節(jié)(Yotta Byte)YB1YB=2^10 ZB =2^80 B

從字節(jié)有這么多單位可以看出選擇合適的單位可以讓人很直觀有個大小概念,比如你可以說我買了最新款的IPhone15 128GB版本,別人一看就知道是最低配版本了,可能覺得你是買了丐版的來裝逼一下,但是你說我買最新款的IPhone15Pro 134217728KB版本,別人第一感肯定不知道你買的是一個丐版,但是會覺得你是個SB。為了精度我一般在數據庫中會存儲Byte類型,另外也方便我們在代碼中作計算和比較,返回給用戶時則會轉成對用戶友好的單位,例如我們記錄用戶空間使用量在數據庫中會存儲最小單位Byte

用戶ID空間用量
183142212058073480
167652085350264853
151381439009188728
91521319605924042
240801259223266116
33251139222905087
94011128752330535
38381125023100502

返回給用戶顯示時會轉成對用戶友好的單位

由于字節(jié)的單位比較多,所以代碼中會經常出現手動單位轉換,這樣代碼就不太優(yōu)雅,本文介紹一種優(yōu)雅處理這些字節(jié)轉換的方法,接下來我們以用戶空間使用量為為例,說明如何優(yōu)雅的處理這種數據格式轉換。

應用場景

比如我們現在有一個類似百度云盤的系統,需要記錄用戶云盤空間使用量,并且后臺可以設置用戶云盤的最大容量。那么我們至少有兩個接口,一個是返回用戶當前云盤空間使用量,另一個是設置云盤最大容量

  • 獲取用戶當前空間使用量接口
GET http://localhost:80/userSize/1

返回結果
{
  "id": 1,
  "size": "1.5M"
}

需要解決的問題:將數據庫存的1572864格式化成1.5M

  • 設置用戶最大容量接口
POST http://localhost:80/userSize  
Content-Type: application/json  
  
{  
    "id":1,  
    "maxSize":"10.5G"  
}

需要解決的問題:將前端傳的10.5G轉成11274289152存入數據庫

解決思路

目前大部分開發(fā)框架都使用SpringBoot,SpringBootJAVA對象序列化成JSON和將JSON反序列化成JAVA對象默認使用Jackson,那么我們可以自定義Jackson序列化器和反序列器來達到此效果。最終效果是:我們在想要格式化的字段中增加 @ByteFormat(scale = 1)返回時自動將1572864格式化成1.5M,接收時自動將10.5G轉成11274289152,這樣是不是很優(yōu)雅?而且項目中所有地方只要增加這個注解,就自動處理這個格式轉換,下次再遇到字節(jié)類型再也不需要去做一大堆的格式轉換了。

@Data
public class UserDTO {
    private Long id;
    @ByteFormat(scale = 3)
    private Long size;
    @ByteFormat(scale = 1)
    private Long maxSize;
}

實現步驟

定義注解ByteFormat

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = ByteFormatSerializer.class)
@JsonDeserialize(using = ByteFormatDeserializer.class)
@JacksonAnnotationsInside
public @interface ByteFormat {
    // 保留精度
    int scale() default 2;
}

Jackson是可以支持自定義序列化器和反序列化器的, 所以基于此我們可以擴展實現一些自定義序列化注解, 就像 @JsonFormat注解對時間格式處理一樣。 那我們擴展自定義注解原理也很簡單,主要是利用 @JsonSerialize、@JsonDeserialize@JacksonAnnotationsInside注解去實現, @JacksonAnnotationsInside是一個組合注解,主要標記在用戶的自定義注解上,那么這個用戶自定義注解上標記的所有其他注解也會生效。

定義序列化器ByteFormatSerializer

ByteFormatSerializer類的作用是當Jackson序列化遇到Number類型時會調用createContextual()方法,在該方法中判斷字段上是否有ByteFormat注解,如果有則告訴Jackson來調用ByteFormatSerializerserialize來序列化,在serialize()方法中完成了數據格式的轉換。

public class ByteFormatSerializer extends JsonSerializer<Number> implements ContextualSerializer {
    protected ByteFormat byteFormat;
    
    public ByteFormatSerializer(){
    }

    public ByteFormatSerializer(ByteFormat byteFormat){
        this.byteFormat=byteFormat;
    }

    @Override
    public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null){
            return;
        }
        int scale = byteFormat.scale();
        BigDecimal bigValue = new BigDecimal(value.toString());
        String result = ByteConvert.convertValue(bigValue,  scale);
        gen.writeString(result );
    }
    

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass().getGenericSuperclass(), Number.class) ) {
                ByteFormat t = beanProperty.getAnnotation(ByteFormat.class);
                if (t != null) {
                    return  new ByteFormatSerializer(t);
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(beanProperty);
    }

}

定義反序列化器ByteFormatDeserializer

ByteFormatDeserializer類的作用是Jackson反序列化遇到Number類型時會調用createContextual()方法,在該方法中判斷如果字段上有ByteFormat注解則告訴Jackson來調用ByteFormatDeserializerdeserialize方法,在deserialize()方法中完成了數據的轉換。

public class ByteFormatDeserializer extends JsonDeserializer<Number> implements ContextualDeserializer  {
    protected ByteFormat byteFormat;

    public ByteFormatDeserializer(){
    }

    public ByteFormatDeserializer(ByteFormat byteFormat){
        this.byteFormat=byteFormat;
    }


    @Override
    public Number deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (!StringUtils.hasText(p.getText())) {
            return null;
        }
        if(byteFormat!=null){
            String value = p.getText();
            return ByteConvert.convertNumber(value);
        }
        return null;
    }


    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass().getGenericSuperclass(), Number.class) ) {
                ByteFormat t = beanProperty.getAnnotation(ByteFormat.class);
                if (t != null) {
                    return  new ByteFormatDeserializer(t);
                }
            }
            return serializerProvider.findContextualValueDeserializer(beanProperty.getType(), beanProperty);
        }
        return this;
    }
}


格式轉換工具類ByteConvert

public class ByteConvert {
    public static final Long KB=1L<<10;
    public static final Long MB=KB<<10;
    public static final Long GB=MB<<10;
    public static final Long TB=GB<<10;
    
    public static String convertValue(BigDecimal bigValue, int scale) {
        if(bigValue.compareTo(BigDecimal.valueOf(TB))>=0){
            return String.format("%sT",bigValue.divide(BigDecimal.valueOf(TB), scale, RoundingMode.HALF_UP));
        }
        if(bigValue.compareTo(BigDecimal.valueOf(GB))>=0){
            return String.format("%sG",bigValue.divide(BigDecimal.valueOf(GB), scale, RoundingMode.HALF_UP));
        }
        if(bigValue.compareTo(BigDecimal.valueOf(MB))>=0){
            return String.format("%sM",bigValue.divide(BigDecimal.valueOf(MB), scale, RoundingMode.HALF_UP));
        }
        if(bigValue.compareTo(BigDecimal.valueOf(KB))>=0){
            return String.format("%sK",bigValue.divide(BigDecimal.valueOf(KB), scale, RoundingMode.HALF_UP));
        }
        return String.format("%sB",bigValue);
    }

    public static Number convertNumber(String stringValue) {
        if (stringValue.endsWith("T")) {
            Double value = Double.parseDouble(stringValue.replaceAll("T", "")) * TB;
            return value.longValue();
        }
        if (stringValue.endsWith("G")) {
            Double value = Double.parseDouble(stringValue.replaceAll("G", "")) * GB;
            return value.longValue();
        }
        if (stringValue.endsWith("M")) {
            Double value = Double.parseDouble(stringValue.replaceAll("M", "")) * MB;
            return value.longValue();
        }
        if (stringValue.endsWith("K")) {
            Double value = Double.parseDouble(stringValue.replaceAll("K", "")) * KB;
            return value.longValue();
        }
        return Double.valueOf(stringValue).longValue();
    }
}

測試

編寫兩個測試接口,一個接口返回用戶當前使用容器量,然后把size大小設置成1572864,另一個是設置用戶最大使用容量,使用UserDTO直接接收。

    @GetMapping("/userSize/{id}")
    public ResponseEntity<UserDTO> userSize(@PathVariable Long id) {
        UserDTO userDTO = new UserDTO();
        userDTO.setId(id);
        userDTO.setSize(1572864L);
        return ResponseEntity.ok(userDTO);
    }

    @PostMapping("/userSize")
    public ResponseEntity<UserDTO> setUserSize(@RequestBody UserDTO userDTO) {
        log.info("user {} maxSize {}", userDTO.getId(), userDTO.getMaxSize());
        return ResponseEntity.ok(userDTO);
    }

可以接口返回用戶使用容量字段size成功格式化成1.5M,當然如里返回List<UserDTO>Map中也是能正常格式化的,完全符合預期

可以看出用戶傳maxSize:10.5G,后端成功使用Long maxSize類型接收到了String類型數據,并且將String數值轉成了11274289152,完全符合預期。

總結

本文使用Jackson自定義了ByteFormat注解,解決了字節(jié)類型數據在前端與后端之間的優(yōu)雅轉換。當然本方法不僅可以解決字節(jié)類型的數據格式轉換,還可以用于如時間格式、枚舉格式、金錢格式的轉換,再擴展一下也可以用于數據脫敏等場景。本解決方法主要有以下優(yōu)點:

  • 使用優(yōu)雅:使用者只需要在字段上增加@ByteFormat(scale = 3)即可,代碼很優(yōu)雅
  • 方法通用:該方法不僅可用于http接口參數的轉換,還可用于Jackson數據的轉換的所有場景
  • 降本增效:該方法完全可以在團隊中推廣,大家都可以使用,不用每個人寫一堆轉換
  • 前端友好:前端拿到這樣的接口使用很方便,返回數據直接顯示就好,用戶輸入數據直接傳后端

當然本方法也是有缺點的:

  • 只能用于Jackson:其它JSON序列化工具不支持如使用FastJson、Gson
  • 使用域實體對象:實體對象一旦添加了ByteFormat都會作格式轉換,如果有特殊場景不想做轉換則需要使用新實體對象

以上就是Java處理字節(jié)類型數據的實現步驟的詳細內容,更多關于Java處理字節(jié)類型數據的資料請關注腳本之家其它相關文章!

相關文章

  • java如何利用poi解析doc和docx中的數據

    java如何利用poi解析doc和docx中的數據

    這篇文章主要給大家介紹了關于java如何利用poi解析doc和docx中數據的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 深入了解SpringBoot中@ControllerAdvice的介紹及三種用法

    深入了解SpringBoot中@ControllerAdvice的介紹及三種用法

    這篇文章主要為大家詳細介紹了SpringBoot中@ControllerAdvice的介紹及三種用法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-02-02
  • json-lib將json格式的字符串,轉化為java對象的實例

    json-lib將json格式的字符串,轉化為java對象的實例

    下面小編就為大家?guī)硪黄猨son-lib將json格式的字符串,轉化為java對象的實例。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • spring boot org.junit.jupiter.api不存在的解決

    spring boot org.junit.jupiter.api不存在的解決

    這篇文章主要介紹了spring boot org.junit.jupiter.api不存在的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Eclipse使用maven搭建spring mvc圖文教程

    Eclipse使用maven搭建spring mvc圖文教程

    這篇文章主要為大家分享了Eclipse使用maven搭建spring mvc圖文教程,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Java Mybatis批量修改封裝詳解

    Java Mybatis批量修改封裝詳解

    這篇文章主要介紹了Mybatis批量修改封裝的相關內容,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 詳解Java 微服務架構

    詳解Java 微服務架構

    這篇文章主要介紹了Java 微服務架構的相關資料,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2021-02-02
  • JavaWeb文件上傳入門教程

    JavaWeb文件上傳入門教程

    這篇文章主要為大家詳細介紹了JavaWeb文件上傳入門教程,分析了文件上傳原理、介紹了第三方上傳組件,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java超詳細講解三大特性之一的多態(tài)

    Java超詳細講解三大特性之一的多態(tài)

    多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量到底會指向哪個類的實例對象,該引用變量發(fā)出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定
    2022-05-05
  • java入門概念個人理解之package與import淺析

    java入門概念個人理解之package與import淺析

    下面小編就為大家?guī)硪黄猨ava入門概念個人理解之package與import淺析。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08

最新評論