情景:
有个项目需要和其他公司对接接口,他们并不是直接使用httpClient模拟http协议的方式交互数据,而是使用它们提供的jar包,当然没有功夫去看他们提供的jar包里面是通过什么方式交互数据,不过提供的方法使用也挺方便,但是方法返回的是一个对象,困难的是这个对象结构有点复杂,也没有结构文档,和他们沟通也是有一句没一句的回复。没有办法只能自己慢慢看,但是效率太低。这时候想如何能将一个java对象的每个元素打印处理来看着也方便,通过一天的琢磨和改进,实现一版类似windows的dos命令中tree命令的展示方式的工具类。
展示:
1.遍历对象
2.遍历文件夹
工具类:DataFormat
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class DataFormat {
private PrintPattern pattern;
public DataFormat(){
initDefPattern();
}
public DataFormat(PrintPattern pattern){
if(null != pattern){
this.pattern = pattern;
}else{
initDefPattern();
}
}
private void initDefPattern(){
this.pattern = new PrintPattern() {
public void printTarget(String str) {
System.out.print(str);
}
public void newLine() {
System.out.println("");
}
public void end() {
}
};
}
public static interface TreeNode{
public boolean isMap();
public boolean isCollection();
public boolean isBasic();
public Map<String,TreeNode> getMap();
public Collection<TreeNode> getCollection();
public Object getBasic();
public TreeNode toMapNode();
}
public static interface PrintPattern{
public void newLine();
public void printTarget(String str);
public void end();
}
public static class FileTreeNode implements TreeNode{
File file = null;
public FileTreeNode(File file) {
this.file = file;
}
public boolean isMap() {
return this.file.isDirectory();
}
public boolean isCollection() {
return false;
}
public boolean isBasic() {
return this.file.isFile();
}
public Map<String, TreeNode> getMap() {
Map<String,TreeNode> mapContainer = new TreeMap<String, TreeNode>();
File[] listFiles = this.file.listFiles();
for (int i = 0; i < listFiles.length; i++) {
mapContainer.put(listFiles[i].getName(),new FileTreeNode(listFiles[i]));
}
return mapContainer;
}
public Collection<TreeNode> getCollection() {
return null;
}
public Object getBasic() {
return this.file.getName();
}
public TreeNode toMapNode() {
return null ;
}
}
static class ObjectTreeNode implements TreeNode{
private Object obj;
public ObjectTreeNode(Object obj){
this.obj = obj;
}
//将自定义的对象作为一个map
public boolean isMap() {
boolean isMap = isRealMap() || (!isBasic() && ! isCollection()) ;
return isMap;
}
private boolean isRealMap(){
Class<? extends Object> type = this.obj.getClass();
return Map.class.isAssignableFrom(type);
}
public boolean isCollection() {
return Collection.class.isAssignableFrom(this.obj.getClass());
}
public boolean isBasic() {
Class<? extends Object> type = this.obj.getClass();
boolean isBasic = type.isPrimitive()
|| Integer.class.equals(type)
|| String.class.equals(type)
|| Byte.class.equals(type)
|| Character.class.equals(type)
|| Short.class.equals(type)
|| Long.class.equals(type)
|| Float.class.equals(type)
|| Double.class.equals(type)
|| Boolean.class.equals(type);
return isBasic;
}
public Map<String, TreeNode> getMap() {
if(isRealMap()){
Map<String, Object> mapValues = (Map<String,Object>)this.obj;
Set<Entry<String, Object>> nodeSet = mapValues.entrySet();
Map<String,TreeNode> mapContainer = new TreeMap<String, TreeNode>();
for (Entry<String, Object> entry : nodeSet) {
mapContainer.put(entry.getKey(), new ObjectTreeNode(entry.getValue()));
}
return mapContainer;
}else{ //自定义对象对象
Class<? extends Object> type = this.obj.getClass();
Map<String,TreeNode> mapContainer = new TreeMap<String, TreeNode>();
Field[] declaredFields = type.getDeclaredFields();
for (Field field : declaredFields) {
try {
field.setAccessible(true);
mapContainer.put(field.getName(), new ObjectTreeNode(field.get(this.obj)));
} catch (Exception e) {
e.printStackTrace();
}
}
return mapContainer;
}
}
public Collection<TreeNode> getCollection() {
Collection<Object> listValues = (Collection<Object>)this.obj;
ArrayList<TreeNode> treeNods = new ArrayList<TreeNode>();
Map<String,Object> map = null;
for (Object object : listValues) {
treeNods.add(new ObjectTreeNode(object));
}
return treeNods;
}
public Object getBasic() {
return this.obj;
}
public TreeNode toMapNode() {
Map<String,Object> mapContainer = new TreeMap<String, Object>();
mapContainer.put(this.obj.getClass().getName(), this.obj);
return new ObjectTreeNode(mapContainer) ;
}
}
private void printKey(Object key,boolean[] last){
for(int i=0,length = last.length -1 ; i < length ; i++ ){
if(last[i]){
printTarget(" ");
}else{
printTarget("│ ");
}
}
if(last[last.length-1]){
printTarget("└─");
}else{
printTarget("├─");
}
printTarget(key.toString());
}
private void printValue(Object value,boolean[] last){
printTarget("=["+value+"]");
}
public void newLine(){
this.pattern.newLine();
}
public void printTarget(String str){
this.pattern.printTarget(str);
}
public void tree(TreeNode node){
tree(node,new boolean[]{true});
this.pattern.end();
}
//map的value可以是 map,list,基本类型
//list的value只能是map,基本类型
private void tree(TreeNode node,boolean[] last){
if(node.isCollection()){
Collection<TreeNode> collection = node.getCollection();
int index = 1;
for (TreeNode value : collection) {
if(collection.size() == index){
last[last.length - 1] = true;
}else{
last[last.length - 1] = false;
}
index ++ ;
if(value.isBasic()){
printKey("["+value.getBasic()+"]",last);
newLine();
}else if(value.isMap()){
value = value.toMapNode();
Set<Entry<String, TreeNode>> entrySet = value.getMap().entrySet();
for (Entry<String, TreeNode> entry : entrySet) {
printKey(entry.getKey(), last);
newLine();
boolean[] nextLast = getNextLast(last);
notCollection(entry.getValue(),nextLast);
}
}
}
}else{
notCollection(node,last);
}
}
//map
private void notCollection(TreeNode node,boolean[] last){
if(node.isMap()){
Set<Entry<String, TreeNode>> nodeSet = node.getMap().entrySet();
int index = 1;
for (Entry<String, TreeNode> entry : nodeSet) {
if(nodeSet.size() == index){
last[last.length - 1] = true;
}else{
last[last.length - 1] = false;
}
index ++ ;
printKey(entry.getKey(),last);
if(entry.getValue().isBasic()){
printValue(entry.getValue().getBasic(),last);
newLine();
}else{
boolean[] nextLast = getNextLast(last);
newLine();
tree(entry.getValue(),nextLast);
}
}
}else{
printKey(node,last);
newLine();
}
}
private boolean isBasicType(Class<?> type){
return !Map.class.isAssignableFrom(type) && !Collection.class.isAssignableFrom(type);
}
private boolean[] getNextLast(boolean[] last){
boolean[] nextLast = new boolean[last.length+1];
System.arraycopy(last, 0, nextLast, 0, last.length);
return nextLast;
}
}
使用示例:
1.遍历文件夹打印在控制台,并输出到文件中
public class TreeTest {
@Test
public void test1(){
try {
DataFormat df = new DataFormat(new DataFormat.PrintPattern() {
StringBuffer sb = new StringBuffer(500);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\nginx.txt",true));
public void printTarget(String str) {
System.out.print(str);
sb.append(str);
}
public void newLine() {
System.out.println("");
sb.append("\r\n");
try {
bos.write(sb.toString().getBytes("UTF-8"));
sb.setLength(0);
} catch (IOException e) {
e.printStackTrace();
}
}
public void end() {
try {
bos.flush();
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
df.tree(new DataFormat.FileTreeNode(new File("D:\\source\\nginx")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.遍历元素打印在控制台
public static void main(String[] args) {
DataFormat df = new DataFormat();
ClassRoom ynj = new ClassRoom();
ynj.setGrade("向日葵奋进班");
ArrayList<Student> students = new ArrayList<Student>();
Student xm = new Student();
xm.setId(1);
xm.setName("小明");
xm.setAge(8);
students.add(xm);
Student xh = new Student();
xh.setId(2);
xh.setName("小花");
xh.setAge(7);
students.add(xh);
Student xg = new Student();
xg.setId(3);
xg.setName("小刚");
xg.setAge(10);
students.add(xg);
ynj.setStudents(students);
df.tree(new ObjectTreeNode(ynj), new boolean[]{true});
}
其他说明:
问题:
1.没有过滤功能,可以扩展
2.ObjectTreeNode中基本上没有判断null值,也就说如果元素中有null值则会报错,需要修改
扩展:
1.TreeNode接口:定义树中节点的类型,DataFormat内提供两个TreeNode实现类FileTreeNode用于遍历文件夹、ObjectTreeNode用于遍历java对象。如果需要遍历其它则需要实现TreeNode接口 map:key value的列表 collection:一个key对应多个value basic:最小的不可再拆分的
2.PrintPattern接口:定义输出的类型。DataFormat内提供一个默认的控制台输出方式,如果需要自定义则实现该接口,在实例化DataFormat对象时通过构造函数传入