首页 > 代码库 > 剖析固定長度欄位的訊息字串

剖析固定長度欄位的訊息字串

在進行系統整合時,系統間不管是透過網路、檔案傳送訊息資料,常會遇到訊息字串的各個欄位是固定長度的,這種情況下程式怎麼寫會比較簡潔易懂? 這裡是我提供的一個方法,使用 annotation 將訊息字串欄位的設定值直接寫在程式上,而不是寫在設定檔裡,這樣應該會比較直覺。

假設有個程式,要顯示中華民國總統的任期和歷史評價,其訊息格式如下:

首先,我們定義一個 annotation,可以設定欄位的開始位置和長度,如下:

 1 package idv.steven; 2  3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7  8 @Retention(RetentionPolicy.RUNTIME) 9 @Target(ElementType.FIELD)10 public @interface MsgField {11     public int start();12     public int length();13 }

接著定義一個 POJO,並且於類別裡的各個欄位上設定開始位置、長度,因為訊息有四個欄位,當然這個類別也有相對應的四個欄位。

 1 package idv.steven.pojo; 2  3 import idv.steven.MsgField; 4  5 public class Message { 6     @MsgField(start=0,length=4) 7     private String startYear; 8     @MsgField(start=4,length=4) 9     private String endYear;10     @MsgField(start=8,length=10)11     private String name;12     @MsgField(start=18,length=30)13     private String evaluate;14     15     /**16      * @return 任期開始的年份17      */18     public String getStartYear() {19         return startYear;20     }21     public void setStartYear(String startYear) {22         this.startYear = startYear;23     }24     25     /**26      * @return 任期結束的年份27      */28     public String getEndYear() {29         return endYear;30     }31     public void setEndYear(String endYear) {32         this.endYear = endYear;33     }34     35     /**36      * @return 姓名37      */38     public String getName() {39         return name;40     }41     public void setName(String name) {42         this.name = name;43     }44     45     /**46      * @return 評價47      */48     public String getEvaluate() {49         return evaluate;50     }51     public void setEvaluate(String evaluate) {52         this.evaluate = evaluate;53     }54 }

下面就是剖析訊息的程式了…

 1 package idv.steven; 2  3 import java.lang.reflect.Field; 4 import java.lang.reflect.InvocationTargetException; 5 import java.lang.reflect.Method; 6 import java.util.Arrays; 7  8 import idv.steven.pojo.Message; 9 10 /**11  * 剖析固定欄位長度的訊息12  * @author Steven13  */14 public class Parser {15     private Message parsing(byte[] msg) 16             throws IllegalArgumentException, IllegalAccessException, 17             NoSuchMethodException, SecurityException, 18             InvocationTargetException, ClassNotFoundException {19         20         Message message = new Message();21 22         Class<?> aClass = Class.forName(Message.class.getName());23         Field[] fields = aClass.getDeclaredFields();24         for(Field field:fields) {25             MsgField msgField = field.getAnnotation(MsgField.class);26             if (msgField != null) {27                 byte[] subMsg = Arrays.copyOfRange(msg, msgField.start(), msgField.start() + msgField.length());28                 29                 Method method = aClass.getMethod(getSetterName(field.getName()), String.class);30                 method.invoke(message, new String(subMsg));31                 //field.set(message, new String(subMsg));32             }33         }34         35         return message;36     }37     38     private String getSetterName(String fieldName) {39         return String.format("set%s%s", fieldName.substring(0, 1).toUpperCase(), fieldName.substring(1));40     }41     42     public void run(byte[] msg) {43         try {44             Message message = parsing(msg);45             46             System.out.println("任期: " + message.getStartYear() + " ~ " + message.getEndYear());47             System.out.println("總統姓名: " + message.getName());48             System.out.println("歷史評價: " + message.getEvaluate());49         } catch (Exception e) {50             e.printStackTrace();51         }        52     }53 54     public static void main(String[] args) {55         56         new Parser().run("20082016馬英九    一個自私的笨蛋、禍國殃民!     ".getBytes());57     }58 }

執行結果如下:

任期: 2008 ~ 2016總統姓名: 馬英九    歷史評價: 一個自私的笨蛋、禍國殃民!