文章目录
前言
有时候,我们需要将一堆的数据打印到控制台,方便观察,或者做一些监控功能的时候,希望以表格的形式输出到控制台,方便进行观察。
例如下图,显示服务器列表的状态。
如何实现数据格式化打印
- 导入依赖(如果已经包含可以忽略)
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- 定义打印工具类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* 数据打印工具,支持控制台和日志打印,支持数据左对齐,居中和右对齐,默认右对齐。小标题自动居中(不支持设置)
* <br>备注:大标题可以使用中文,小标题和内容不建议包含中文
*/
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DataPrinter {
/**
* 日志输出模式(默认控制台输出)
*/
private LogOutputModel logOutputModel = LogOutputModel.CONSOLE;
/**
* 数据对齐模式(默认右对齐)
*/
private DataAlignModel dataAlignModel = DataAlignModel.RIGHT;
/**
* 是否显示行数
*/
private boolean showRows = true;
/**
* 日志输出模式
*/
public enum LogOutputModel {
LOG, CONSOLE;
}
/**
* 数据对齐模式
*/
public enum DataAlignModel {
LEFT, CENTER, RIGHT;
}
/**
* 数据格式化输出
* @param topTitle 大标题
* @param titles 小标题
* @param data 数据集合
*/
public void printListMap(String topTitle, String[] titles, List<Map<String, Object>> data) {
List<Object[]> objsList = new ArrayList<>();
if (null != data) {
for (Map<String, Object> map : data) {
Object[] objs = new Object[titles.length];
for (int i = 0; i < titles.length; i++) {
Object obj = map.get(titles[i]);
objs[i] = obj;
}
objsList.add(objs);
}
}
print(topTitle,titles,objsList);
}
/**
* 数据格式化输出
* @param topTitle 大标题
* @param titles 小标题
* @param data 数据集合
*/
public void print(String topTitle, String[] titles, List<Object[]> data) {
topTitle = null == topTitle ? "Not Defined" : topTitle;
/**
* 控制日志输出
*/
Function<String, Integer> outputLog_fun = (string) -> {
if (this.getLogOutputModel() == LogOutputModel.CONSOLE) {
System.out.println(string);
} else if (this.getLogOutputModel() == LogOutputModel.LOG) {
log.info(string);
}
return 1;
};
/**
* 1. 根据标题和内容计算每一列需要的最大宽度
*/
Integer[] lineWidths = new Integer[titles.length];
int totalWidth = 0;//最大长度
for (int i = 0; i < lineWidths.length; i++) {
int maxWidth = 0; // 默认最小长度
String title = titles[i];
if (null != title) {
maxWidth = Math.max(maxWidth, title.length());
} else {
titles[i] = "";
}
if (null != data) {
for (Object[] array : data) {
Object obj = array[i];
if (null != obj) {
maxWidth = Math.max(maxWidth, obj.toString().length());
}
}
}
if (maxWidth + 4 < 10) {
maxWidth = 10;
} else {
maxWidth = maxWidth + 4; //避免数据左右顶到表格
}
lineWidths[i] = maxWidth;
totalWidth = totalWidth + maxWidth;
}
/**
* 2. 输出大标题
*/
if (isShowRows()) {
int dataSize = null != data ? data.size() : 0;
outputLog_fun.apply(StringUtils.leftPad(topTitle + "(rows:" + dataSize + ")", (int) (totalWidth * 0.5)));
} else {
outputLog_fun.apply(StringUtils.leftPad(topTitle, (int) (totalWidth * 0.5)));
}
/**
* 3. 输出标题头
*/
StringBuffer head_sb = new StringBuffer("+");
for (int i = 0; i < titles.length; i++) {
String title = titles[i];
String str = StringUtils.center(title, lineWidths[i], "-");
head_sb.append(str).append("+");
}
outputLog_fun.apply(head_sb.toString());
/**
* 4. 输出数据
*/
if (null != data) {
for (int i = 0; i < data.size(); i++) {
Object[] array = data.get(i);
StringBuffer data_sb = new StringBuffer("|");
for (int j = 0; j < array.length; j++) {
Object obj = array[j];
String str = null;
if (this.getDataAlignModel() == DataAlignModel.RIGHT) {
str = String.format("%" + (lineWidths[j] - 2) + "s ", obj);
} else if (this.getDataAlignModel() == DataAlignModel.CENTER) {
str = StringUtils.center(obj + "", lineWidths[j]);
} else if (this.getDataAlignModel() == DataAlignModel.LEFT) {
str = String.format(" %-" + (lineWidths[j] - 2) + "s", obj);
}
data_sb.append(str).append("|");
}
outputLog_fun.apply(data_sb.toString());
}
}
/**
* 5.输出结尾
*/
StringBuffer foot_sb = new StringBuffer("+");
for (int i = 0; i < titles.length; i++) {
String str = StringUtils.center("", lineWidths[i], "-");
foot_sb.append(str).append("+");
}
outputLog_fun.apply(foot_sb.toString());
}
}
- 编写测试用例,执行测试代码
@Test
void testDataPrinter() {
String topTitle = "服务器的运行状态表";
String[] titles = {"IP", "PORT", "SERVICE NAME", "QPS",null};
List<Object[]> objs = new ArrayList<>();
objs.add(new Object[]{"1.2.3.4", 65121, "order", 600000,"UP"});
objs.add(new Object[]{"192.82.9.247", 85, "game", 7788,"DOWN"});
objs.add(new Object[]{"114.114.115.115", 65121, "financial", 2,"UP"});
objs.add(new Object[]{"88.2.3.4", 65121, "game99", 989,"UP"});
objs.add(new Object[]{"199.77.35.4", 65121, "pay", 333,"UP"});
objs.add(new Object[]{null, "", null, 133,"UP"});
DataPrinter dataPrinter= new DataPrinter();//默认数据是右对齐,控制台打印
dataPrinter.setLogOutputModel(DataPrinter.LogOutputModel.CONSOLE);//控制台输出
dataPrinter.print(topTitle, titles, objs);
dataPrinter.setDataAlignModel(DataPrinter.DataAlignModel.LEFT);//左对齐
dataPrinter.print(topTitle, titles, objs);
dataPrinter.setDataAlignModel(DataPrinter.DataAlignModel.CENTER);//居中
dataPrinter.print(topTitle, titles, objs);
/**
* 自定义参数日志输出
*/
DataPrinter dataPrinter2=new DataPrinter(DataPrinter.LogOutputModel.LOG,DataPrinter.DataAlignModel.RIGHT,true);
dataPrinter2.print(topTitle, titles, objs);
/**
* ListMap的打印
*/
String[] titles2={"ip","port"};
List<Map<String,Object>> objsList=new ArrayList<>();
Map<String,Object> m1=new HashMap<>();
m1.put("ip","1.1.2.3");
m1.put("port",9898);
objsList.add(m1);
Map<String,Object> m2=new HashMap<>();
m2.put("ip","1.190.22.3");
m2.put("port",18908);
objsList.add(m2);
dataPrinter.setDataAlignModel(DataPrinter.DataAlignModel.RIGHT);//居中
dataPrinter.printListMap("服务器列表", titles2, objsList);
}
控制台内容解释