java反射機制-excel導入-表頭名字和順序允許互換

如下excel表格,按照表頭名字讀取數據,允許表頭增加無意義空格,允許表頭順序交換。


序號隧道左公里標隧道右公里標是否隧道
1DK2291.416DK0
2DK7389.65DK2291.416
3ZK2277ZK0
4ZK5235.68ZK2277
實現方法如下,充分利用java反射機制,巧妙運用正則表達式進行表頭名字匹配,提取配置表格文件順序,模糊動態匹配表頭名字和順序。
/**
	 * 
	 * 讀取指定sheet 頁指定行<T>數據
	 * 
	 * @param sheetIx 指定 sheet 頁,從 0 開始
	 * @param start   指定開始行,從 0 開始
	 * @param end     指定結束行,從 0 開始
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<List<T>> readGeneric(int sheetIx, int start, int end, T t) throws Exception {
		Sheet sheet = workbook.getSheetAt(sheetIx);
		List<List<T>> list = new ArrayList<List<T>>();

		if (end > getRowCount(sheetIx)) {
			end = getRowCount(sheetIx);
		}
		List<Integer> colNums = new ArrayList<Integer>();
		for (int i = start; i <= end; i++) {
			List<T> rowList = new ArrayList<T>();
			Row row = sheet.getRow(i);
			List rowdata = getRowdata(row);
			Class clazz = t.getClass();
			Object fa= clazz.newInstance();
			Method method = t.getClass().getMethod("getLdcode", new Class[]{});
			String[] ldcode = (String[])method.invoke(fa, new Object[]{});
			

			//處理從0行開始取得請求
			if(0 == start)
			{
				//處理請求的第0行,即表頭
				if(i == 0)
				{
					//通過反射獲取模板類的實例
					try {
						String simpleName = t.getClass().getSimpleName();
						String StrEnumClass = simpleName.substring(0, simpleName.length()-5) + "Enum";
						Class EnumClass = Class.forName("com.crscd.config.service.cbtc2.atp.excel.enums."+StrEnumClass);
						//Object enumInstance = EnumClass.newInstance();
						
						for(int j = 0; j < rowdata.size(); j++)
						{
							//去除表頭上空格、回車、換行符、製表符
							if(null != rowdata.get(j) && !"".equals(rowdata.get(j))) {
								Pattern p = Pattern.compile("\\s*|\t|\r|\n");
								String str = (String)rowdata.get(j);
					            Matcher m = p.matcher(str);
					            String excelData =  m.replaceAll("");
					            //獲取表頭對應的工具類中ldcode位置
					            Method met = EnumClass.getMethod("getStatus", String.class);
					            int col = (int) met.invoke(Object.class, excelData);
								colNums.add(col);
							}else
							{
								colNums.add(-1);
							}
						}
					}catch(ClassNotFoundException e) {
						//e.printStackTrace();
					}
					
				}
			}
				
			for(int j = 0; j < colNums.size(); j++) {
				int k = j;
				//如果映射表頭列和數據列不匹配,當數據列小於映射表頭列時,說明excel有無效列,則不足的列用空串補足
				if (colNums.size() > rowdata.size() ) {
					rowdata.add("");
				}
				if(0 == start && !colNums.isEmpty())
				{
					k = colNums.get(j);
				}
				if(k == -1) {
					continue;
				}else {
					try {
						method = t.getClass().getMethod("set"+ldcode[k], String.class);
						method.invoke(fa, rowdata.get(j));
					//如果映射表頭列和數據列不匹配,是excel多餘無效行列,則越界,仍保留未越界之前的全部數據。
					}catch(IndexOutOfBoundsException e) {
						continue;
					}
				}
			}
			rowList.add((T) fa);
			list.add(rowList);
		}

		return list;
	}


package com.crscd.config.service.cbtc2.atp.excel;

public class TunnelUtils<T> implements Comparable<TunnelUtils<T>>,Cloneable{

	private String[] ldcode = {
			"Id", "TunnelLeftKilo", "TunnelRightKilo", "IsTunnel"
	};
	
	private String id;
	private String tunnelLeftKilo;
	private String tunnelRightKilo;
	private String isTunnel;
	
	public String[] getLdcode() {
		return ldcode;
	}
	public void setLdcode(String[] ldcode) {
		this.ldcode = ldcode;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getTunnelLeftKilo() {
		return tunnelLeftKilo;
	}
	public void setTunnelLeftKilo(String tunnelLeftKilo) {
		this.tunnelLeftKilo = tunnelLeftKilo;
	}
	public String getTunnelRightKilo() {
		return tunnelRightKilo;
	}
	public void setTunnelRightKilo(String tunnelRightKilo) {
		this.tunnelRightKilo = tunnelRightKilo;
	}
	public String getIsTunnel() {
		return isTunnel;
	}
	public void setIsTunnel(String isTunnel) {
		this.isTunnel = isTunnel;
	}
	
	@Override
	public int compareTo(TunnelUtils<T> o) {
		if(Double.parseDouble(stringGetNum(tunnelLeftKilo))<Double.parseDouble(stringGetNum(o.getTunnelLeftKilo()))) {
			return -1;
		}
		if(Double.parseDouble(stringGetNum(tunnelLeftKilo))>Double.parseDouble(stringGetNum(o.getTunnelLeftKilo()))) {
			return 1;
		}
		return 0;
	}
	//字符串取數
		public String stringGetNum(String str) {
			String str2 = "";
			if(str != null && !"".equals(str)){
				for(int i=0;i<str.length();i++){
					if((str.charAt(i)>=48 && str.charAt(i)<=57) || str.charAt(i)==46){
						str2+=str.charAt(i);
					}
				}
				return str2;
			}
			return str;
		}
		@Override  
	    public Object clone() {  
			TunnelUtils<T> stu = null;  
	        try{  
	            stu = (TunnelUtils<T>)super.clone();  
	        }catch(CloneNotSupportedException e) {  
	            e.printStackTrace();  
	        }  
	        return stu;  
	    }  
}
package com.crscd.config.service.cbtc2.atp.excel.enums;

import java.util.regex.Pattern;

public enum TunnelEnum {
	id("序號",0),
	tunnelLeftKilo("隧道左公里標",1),
	tunnelRightKilo("隧道右公里標",2),
	isTunnel("是否隧道",3);
	
	private final String msg;
    private final int status;
	
	TunnelEnum(String msg,int status)
	{
		this.msg = msg;
        this.status = status;
	}	
	//動態匹配表頭名字,允許加空,加無意義字符
	public static int getStatus(String str)
	{
		str = str.replaceAll("\\(", "\\\\(");
		str = str.replaceAll("\\)", "\\\\)");
		String pattern = "^"+str+".*";
		for(TunnelEnum e : TunnelEnum.values())
		{
			if(Pattern.matches(pattern, e.msg))
			{
				return e.status;
			}
		}
		return -1;
	}

}

excel的數據如下:

序號隧道左公里標隧道右公里標是否隧道
1DK2291.416DK0
2DK7389.65DK2291.416
3ZK2277ZK0
4ZK5235.68ZK2277


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章