使用Apache POI进行Excel操作
首先
我使用Apache POI将CSV导出为Excel。顺便还生成了柱状图。就是这样。
由于初学者的原因,可能存在一些不足之处,如果能收到您的意见和建议我将不胜感激。
GitHub
https://github.com/y012/POI_Sample.git
目录
1. 关于Apache POI
2. 使用环境
3. 准备工作
4. 实现
5. 总结
关于Apache POI
起初我是从”Apache POI是什么?”开始探索的。
经过调查,似乎可以操作Microsoft Office格式的文件。(不只限于Excel,还有Word、PowerPoint等)
维基百科
https://ja.wikipedia.org/wiki/Apache_POI
API文档
https://poi.apache.org/apidocs/dev/overview-summary.html
听起来有很多功能并且很方便,但它看起来也很复杂…
这次我们将依照标题进行Excel操作!
2. 环境的应用
-
- Windows 7
-
- Java 8
-
- Apache POI 4.1.1
- Microsoft Excel 2010
3. 准备前
下载Apache POI。
Apache POI 是一个用于操作 Microsoft Office 文档的开源 Java 库。您可以通过访问 https://poi.apache.org/index.html 来获取更多详细信息。
从链接中下载→poi-bin-~.zip→通过赤框内的可获取链接进行下载。这次下载了第二个选项。
在想要添加的项目上点击右键→新建→文件夹,创建一个名为lib的文件夹,并把下载的zip文件解压到lib文件夹中。
然后,将解压后的文件夹中的所有jar文件都添加到了构建路径中!
这次的输入数据是从下面的网站准备的!
它其实只是一些虚假的个人信息。
http://kazina.com/dummy/
吃咖喱的方式听起来很有趣,但这次我选择克制。
由于POI要从头开始设置字体和样式非常麻烦,因此我会先制作一个模板!
4. 实施
前期准备已经结束,现在开始实施。在使用Apache POI操作Excel时,可以使用XSSF或者HSSF。大致有以下区别,这次我们将使用XSSF。
暂时先加载模板文件并输出。
FileInputStream fis = null;
FileOutputStream fos = null;
Workbook wb = null;
try{
// テンプレートファイルを取得
fis = new FileInputStream("テンプレートのファイルパス");
wb = (XSSFWorkbook)WorkbookFactory.create(fis);
// デフォルトのフォント設定
wb.createFont().setFontName("フォント名");
// (1)start
// テンプレートからシートを複製し、シート名を設定する
// 複製はワークブック内の最後のシートに追加される
Sheet sheet = wb.cloneSheet(wb.getSheetIndex("テンプレートシート名"));
wb.setSheetName(wb.getSheetIndex(sheet), "アウトプットシート名");
// 行、セルを取得(列単位での取得不可)
// 行やセルがデフォルト状態だとnullになるためcreateする
int rowIndex = 0;
Row row = sheet.getRow(rowIndex);
if(row == null){
row = sheet.createRow(rowIndex);
}
int columnIndex = 0;
Cell cell = row.getCell(columnIndex);
if(cell == null){
cell = row.createCell(columnIndex);
}
// A1に設定
cell.setCellValue("Hello World!!");
// (1)end
// アウトプットファイルに出力
fos = new FileOutputStream("アウトプットファイルパス");
wb.write(fos);
}catch(Exception e) {
e.printStackTrace();
}finally {
if(fis != null) {
try {
fis.close();
}catch(IOException e) {
}
}
if(fos != null) {
try {
fos.close();
}catch(IOException e) {
}
}
if(wb != null) {
try {
wb.close();
}catch(IOException e) {
}
}
}
在不更改模板文件的情况下,可以通过设置单元格的值来进行输出,但由于需要在(1)范围内多次重复此操作。因此,我们创建了一个包含移动和输入操作的Manager类。
创建Manager类
package poi.common.util;
import static poi.common.constant.ExcelConstants.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBoolean;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLegend;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTScaling;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTSerTx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
import org.openxmlformats.schemas.drawingml.x2006.chart.STAxPos;
import org.openxmlformats.schemas.drawingml.x2006.chart.STBarDir;
import org.openxmlformats.schemas.drawingml.x2006.chart.STLegendPos;
import org.openxmlformats.schemas.drawingml.x2006.chart.STOrientation;
import org.openxmlformats.schemas.drawingml.x2006.chart.STTickLblPos;
public class ExcelManager {
private Sheet sheet = null;
private Row row = null;
private Cell cell = null;
private int offset;
private int rowIndex;
private int columnIndex;
private Map<Integer,CellStyle> styleMap;
// 設定処理
/**
* シートを設定し、参照するセル位置を「A1」に設定する
* @param sheet
*/
public void setSheet(Sheet sheet) {
this.sheet = sheet;
setPosition();
this.styleMap = new HashMap<>();
this.offset = 1;
this.rowIndex = 0;
this.columnIndex = 0;
}
/**
* テンプレートの印刷設定をコピーする
* @param printSetup
*/
public void setPrintSetup(PrintSetup printSetup) {
PrintSetup newSetup = this.sheet.getPrintSetup();
// コピー枚数
newSetup.setCopies(printSetup.getCopies());
// 下書きモード
//newSetup.setDraft(printSetup.getDraft());
// シートに収まる高さのページ数
newSetup.setFitHeight(printSetup.getFitHeight());
// シートが収まる幅のページ数
newSetup.setFitWidth(printSetup.getFitWidth());
// フッター余白
//newSetup.setFooterMargin(printSetup.getFooterMargin());
// ヘッダー余白
//newSetup.setHeaderMargin(printSetup.getHeaderMargin());
// 水平解像度
//newSetup.setHResolution(printSetup.getHResolution());
// 横向きモード
newSetup.setLandscape(printSetup.getLandscape());
// 左から右への印刷順序
//newSetup.setLeftToRight(printSetup.getLeftToRight());
// 白黒
newSetup.setNoColor(printSetup.getNoColor());
// 向き
newSetup.setNoOrientation(printSetup.getNoOrientation());
// 印刷メモ
//newSetup.setNotes(printSetup.getNotes());
// ページの開始
//newSetup.setPageStart(printSetup.getPageStart());
// 用紙サイズ
newSetup.setPaperSize(printSetup.getPaperSize());
// スケール
newSetup.setScale(printSetup.getScale());
// 使用ページ番号
//newSetup.setUsePage(printSetup.getUsePage());
// 有効な設定
//newSetup.setValidSettings(printSetup.getValidSettings());
// 垂直解像度
//newSetup.setVResolution(printSetup.getVResolution());
}
/**
* 印刷範囲取得
* @return
*/
public String getPrintArea() {
int firstRow = this.sheet.getFirstRowNum();
int lastRow = this.rowIndex;
int firstColumn = this.sheet.getRow(firstRow).getFirstCellNum();
int lastColumn = this.sheet.getRow(lastRow).getLastCellNum()-1;
String printArea = "$" + getColumnAlphabet(firstColumn)
+ "$" + String.valueOf(firstRow+1)
+ ":$" + getColumnAlphabet(lastColumn)
+ "$" + String.valueOf(lastRow);
return printArea;
}
// 設定処理はここまで
// 移動処理
/**
* 参照する行位置を設定する
*/
private void setRow() {
if((this.row = sheet.getRow(this.rowIndex)) == null) {
this.row = sheet.createRow(this.rowIndex);
}
}
/**
* 参照するセル位置を設定する
*/
private void setCell() {
if((this.cell = row.getCell(this.columnIndex)) == null) {
this.cell = row.createCell(this.columnIndex);
}
}
/**
* オフセット(移動量)を設定する
* ※デフォルトは「1」
* @param offset
*/
public void setOffset(int offset) {
this.offset = offset;
}
/**
* 参照する行位置、セル位置を設定する
*/
private void setPosition() {
setRow();
setCell();
}
/**
* 行と列を指定して参照するセル位置を設定する
* @param rowIndex
* 行位置(0ベース)
* @param columnIndex
* 列位置(0ベース)
*/
public void setPosition(int rowIndex, int columnIndex) {
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
setPosition();
}
/**
* 設定してあるオフセットに従って参照するセル位置を移動する
* 現在列位置+オフセット
*/
public void nextCell() {
moveCell(this.offset);
}
/**
* 指定したオフセットに従って参照するセル位置を移動する
* 現在列位置+オフセット
* @param columnOffset
*/
public void moveCell(int columnOffset) {
move(0, columnOffset);
}
/**
* 設定してあるオフセットに従って参照する行位置を移動する
* 現在行位置+オフセット
* ※列位置は0(A)列になる
*/
public void nextRow() {
nextRow(0);
}
/**
* 設定してあるオフセットに従って参照する行位置を移動し、指定した列位置に移動する
* 現在行位置+オフセット
* @param columnIndex
*/
public void nextRow(int columnIndex) {
this.columnIndex = columnIndex;
moveRow(this.offset);
}
/**
* 指定したオフセットに従って参照する行位置を移動する
* 現在行位置+オフセット
* ※列位置は変わらない
* @param rowOffset
*/
public void moveRow(int rowOffset) {
move(rowOffset, 0);
}
/**
* 指定した行オフセット、列オフセットに従って参照する行位置、列位置を移動する
* 現在行位置+行オフセット
* 現在列位置+列オフセット
* @param rowOffset
* @param columnOffset
*/
public void move(int rowOffset, int columnOffset) {
this.rowIndex += rowOffset;
this.columnIndex += columnOffset;
setPosition();
}
/**
* 現在行位置から以降の行を1行下へシフトする(行の挿入)
* ※上の行のスタイル、高さを引き継ぐ
*/
public void shiftRows() {
int lastRowNum = this.sheet.getLastRowNum();
int lastCellNum = this.sheet.getRow(this.rowIndex-1).getLastCellNum();
this.sheet.shiftRows(this.rowIndex, lastRowNum+1, 1);
Row newRow = this.sheet.getRow(this.rowIndex);
if(newRow == null) {
newRow = this.sheet.createRow(this.rowIndex);
}
Row oldRow = this.sheet.getRow(this.rowIndex-1);
for(int i = 0; i < lastCellNum-1; i++) {
Cell newCell = newRow.createCell(i);
Cell oldCell = oldRow.getCell(i);
// oldCellがnullでなければスタイル設定
// wrokbookに作成出来るcellstyleには上限があるのでmapに詰める
if(oldCell != null) {
if(!styleMap.containsKey(i)) {
CellStyle newStyle = this.sheet.getWorkbook().createCellStyle();
newStyle.cloneStyleFrom(oldCell.getCellStyle());
newStyle.setBorderTop(BorderStyle.DOTTED);
styleMap.put(i, newStyle);
}
newCell.setCellStyle(styleMap.get(i));
}
}
newRow.setHeightInPoints(oldRow.getHeightInPoints());
setPosition();
}
// 移動処理はここまで
// 入力処理
/**
* char型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
* @param columnOffset
*/
public void setCellValue(char value, int columnOffset) {
setCellValue(String.valueOf(value), columnOffset);
}
/**
* char型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
*/
public void setCellValue(char value) {
setCellValue(value, this.offset);
}
/**
* String型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
* @param columnOffset
*/
public void setCellValue(String value, int columnOffset) {
if(value.trim().length() == 0) {
this.cell.setBlank();
}else {
this.cell.setCellValue(value);
}
moveCell(columnOffset);
}
/**
* String型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
*/
public void setCellValue(String value) {
setCellValue(value, this.offset);
}
/**
* RichTextString型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
* @param columnOffset
*/
public void setCellValue(RichTextString value, int columnOffset) {
if(value.getString().trim().length() == 0) {
this.cell.setBlank();
}else {
this.cell.setCellValue(value);
}
moveCell(columnOffset);
}
/**
* RichTextString型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* 値がなければBLANKを設定する
* @param value
*/
public void setCellValue(RichTextString value) {
setCellValue(value, this.offset);
}
/**
* byte型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(byte value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* byte型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(byte value) {
setCellValue(value, this.offset);
}
/**
* short型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(short value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* short型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(short value) {
setCellValue(value, this.offset);
}
/**
* int型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(int value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* int型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(int value) {
setCellValue(value, this.offset);
}
/**
* long型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(long value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* long型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(long value) {
setCellValue(value, this.offset);
}
/**
* double型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(double value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* double型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(double value) {
setCellValue(value, this.offset);
}
/**
* float型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(float value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* float型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(float value) {
setCellValue(value, this.offset);
}
/**
* boolean型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(boolean value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* boolean型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(boolean value) {
setCellValue(value, this.offset);
}
/**
* Calendar型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(Calendar value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* Calendar型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(Calendar value) {
setCellValue(value, this.offset);
}
/**
* Date型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(Date value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* Date型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(Date value) {
setCellValue(value, this.offset);
}
/**
* LocalDate型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(LocalDate value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* LocalDate型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(LocalDate value) {
setCellValue(value, this.offset);
}
/**
* LocalDateTime型の値をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellValue(LocalDateTime value, int columnOffset) {
this.cell.setCellValue(value);
moveCell(columnOffset);
}
/**
* LocalDateTime型の値をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellValue(LocalDateTime value) {
setCellValue(value, this.offset);
}
/**
* String型の計算式("="は要らない)をセルに設定し、指定したオフセットに従って参照する列位置を移動する
* @param value
* @param columnOffset
*/
public void setCellFormula(String value, int columnOffset) {
this.cell.setCellFormula(value);
moveCell(columnOffset);
}
/**
* String型の計算式("="は要らない)をセルに設定し、設定してあるオフセットに従って参照する列位置を移動する
* @param value
*/
public void setCellFormula(String value) {
setCellFormula(value, this.offset);
}
/**
* String型のコメントをセルに設定する(表示領域は固定値)
* ※列位置は移動しない
* @param commentStr
*/
public void setCellComment(String commentStr) {
CreationHelper helper = sheet.getWorkbook().getCreationHelper();
XSSFDrawing drawing = (XSSFDrawing)sheet.createDrawingPatriarch();
// row1の位置からずらす値(ピクセル単位)
int dx1 = 0;
// col1の位置からずらす値(ピクセル単位)
int dy1 = 0;
// row2の位置からずらす値(ピクセル単位)
int dx2 = 0;
// col2の位置からずらす値(ピクセル単位)
int dy2 = 0;
// コメント表示領域の左上の列位置(セル単位)
int col1 = this.columnIndex + 1;
// コメント表示領域の左上の行位置(セル単位)
int row1 = this.rowIndex;
// コメント表示領域の右下の列位置(セル単位)
int col2 = this.columnIndex + 4;
// コメント表示領域の右下の行位置(セル単位)
int row2 = this.rowIndex + 3;
ClientAnchor anchor = drawing.createAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
Comment comment = drawing.createCellComment(anchor);
//comment.setAuthor("master");
comment.setString(helper.createRichTextString(commentStr));
this.cell.setCellComment(comment);
}
/**
* 現在のセル位置から棒グラフを挿入(大きさは固定値)
*/
public void setBarChart() {
XSSFDrawing drawing = (XSSFDrawing)sheet.createDrawingPatriarch();
int dx1 = 0;
int dy1 = 0;
int dx2 = 0;
int dy2 = 0;
int col1 = this.columnIndex;
int row1 = this.rowIndex;
move(16, 10);
int col2 = this.columnIndex;
int row2 = this.rowIndex;
ClientAnchor anchor = drawing.createAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
XDDFChart chart = (XDDFChart)drawing.createChart(anchor);
CTChart ctChart = ((XSSFChart)chart).getCTChart();
CTPlotArea ctPlotArea = ctChart.getPlotArea();
CTBarChart ctBarChart = ctPlotArea.addNewBarChart();
CTBoolean ctBoolean = ctBarChart.addNewVaryColors();
ctBoolean.setVal(true);
ctBarChart.addNewBarDir().setVal(STBarDir.COL);
for (int r = 4; r < 8; r++) {
CTBarSer ctBarSer = ctBarChart.addNewSer();
CTSerTx ctSerTx = ctBarSer.addNewTx();
CTStrRef ctStrRef = ctSerTx.addNewStrRef();
// 凡例
ctStrRef.setF("集計!$B$" + r);
ctBarSer.addNewIdx().setVal(r-4);
CTAxDataSource cttAxDataSource = ctBarSer.addNewCat();
ctStrRef = cttAxDataSource.addNewStrRef();
// 項目
ctStrRef.setF("集計!$C$3:$I$3");
CTNumDataSource ctNumDataSource = ctBarSer.addNewVal();
CTNumRef ctNumRef = ctNumDataSource.addNewNumRef();
// データエリア
ctNumRef.setF("集計!$C$" + r + ":$I$" + r);
ctBarSer.addNewSpPr().addNewLn().addNewSolidFill()
.addNewSrgbClr().setVal(new byte[] {0,0,0});
}
int catId = 100;
int valId = 200;
ctBarChart.addNewAxId().setVal(catId);
ctBarChart.addNewAxId().setVal(valId);
CTCatAx ctCatAx = ctPlotArea.addNewCatAx();
ctCatAx.addNewAxId().setVal(catId);
CTScaling ctScaling = ctCatAx.addNewScaling();
ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
ctCatAx.addNewDelete().setVal(false);
ctCatAx.addNewAxPos().setVal(STAxPos.B);
ctCatAx.addNewCrossAx().setVal(valId);
ctCatAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);
CTValAx ctValAx = ctPlotArea.addNewValAx();
ctValAx.addNewAxId().setVal(valId);
ctScaling = ctValAx.addNewScaling();
ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
ctValAx.addNewDelete().setVal(false);
ctValAx.addNewAxPos().setVal(STAxPos.L);
ctValAx.addNewCrossAx().setVal(catId);
ctValAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);
CTLegend ctLegend = ctChart.addNewLegend();
ctLegend.addNewLegendPos().setVal(STLegendPos.B);
ctLegend.addNewOverlay().setVal(false);
}
// 入力処理はここまで
// 変換処理
/**
* 指定した列番号をA1表記に変換する
* @param ascii
* @return
*/
public String getColumnAlphabet(int ascii) {
String alphabet = "";
if(ascii < 26) {
alphabet = String.valueOf((char)(ASCII+ascii));
}else {
int div = ascii / 26;
int mod = ascii % 26;
alphabet = getColumnAlphabet(div-1) + getColumnAlphabet(mod);
}
return alphabet;
}
/**
* 現在の列番号をA1表記に変更する
* @return
*/
public String getColumnAlphabet() {
return getColumnAlphabet(this.columnIndex);
}
// 変換処理はここまで
}
简而言之,使用nextCell()函数可以将光标移动到下一个单元格,使用nextRow()函数可以将光标移动到下一行,而单元格会在第0列(A列)上。使用setCellValue()函数可以为单元格设置值,并移动到下一个单元格。由于setBarChart()函数已经为模板中的单元格设置了值,所以范围设置是固定的。我现在正努力将所有内容都放入一个神级类中,但也知道需要进行分割。暂时就先这样吧(笑)。
完成版的Main类
package poi.main;
import static poi.common.constant.ExcelConstants.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import poi.common.dao.CSVInputDao;
import poi.common.dto.CSVDto;
import poi.common.util.ExcelManager;
public class PoiSample {
public static void main(String[] args) {
System.out.println("開始");
FileInputStream fis = null;
FileOutputStream fos = null;
Workbook wb = null;
ExcelManager manager = new ExcelManager();
int rowIndex = 0;
CSVInputDao csvInDao = new CSVInputDao();
CSVDto csvDto = new CSVDto();
Map<Integer, List<CSVDto>> agesMap = new TreeMap<>();
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy/MM/dd");
csvInDao.setFile(FILE_PATH_INPUT);
try {
fis = new FileInputStream(FILE_PATH_TEMPLATE);
wb = (XSSFWorkbook)WorkbookFactory.create(fis);
wb.createFont().setFontName(FONT);
// シート名を指定して取得
Sheet sheet = wb.cloneSheet(wb.getSheetIndex(SHEET_NAME_TEMPLATE));
// シート名の設定
wb.setSheetName(wb.getSheetIndex(sheet), SHEET_NAME_ALL_DATA);
System.out.println("createSheet:" + sheet.getSheetName());
manager.setSheet(sheet);
csvInDao.open();
// 全データ出力
while((csvDto = csvInDao.read()) != null) {
if(rowIndex != 0){
if(rowIndex >= 2) {
manager.shiftRows();
}
int age = Integer.parseInt(csvDto.getAge());
String comment = "電話:" + csvDto.getTelephone() + LINE_SEPARATOR
+ "携帯:" + csvDto.getMobile() + LINE_SEPARATOR
+ "メール:" + csvDto.getMail();
manager.setCellComment(comment);
manager.setCellValue(csvDto.getName());
manager.setCellValue(csvDto.getFurigana());
manager.setCellValue(csvDto.getSex());
manager.setCellValue(age);
manager.setCellValue(sdFormat.parse(csvDto.getBirthDay()));
manager.setCellValue(csvDto.getMarriage());
manager.setCellValue(csvDto.getBloodType());
manager.setCellValue(csvDto.getBirthPlace());
manager.setCellValue(csvDto.getCareer());
// 年代取得 ex)23→20
age = (int)(age / 10) * 10;
if(agesMap.containsKey(age)) {
agesMap.get(age).add(csvDto);
}else {
List<CSVDto> dtoList = new ArrayList<>();
dtoList.add(csvDto);
agesMap.put(age, dtoList);
}
}
rowIndex++;
manager.nextRow();
}
// 印刷設定、印刷範囲
manager.setPrintSetup(wb.getSheetAt(wb.getSheetIndex(SHEET_NAME_TEMPLATE)).getPrintSetup());
wb.setPrintArea(wb.getSheetIndex(sheet), manager.getPrintArea());
// 年代毎にシート分けして出力
List<String> sheetNames = new ArrayList<>();
for(Map.Entry<Integer, List<CSVDto>> ageMap : agesMap.entrySet()) {
String sheetName = String.valueOf(ageMap.getKey()) + "代";
if((sheet = wb.getSheet(sheetName)) == null) {
sheet = wb.cloneSheet(wb.getSheetIndex(SHEET_NAME_TEMPLATE));
wb.setSheetName(wb.getSheetIndex(sheet), sheetName);
}
sheetNames.add(sheet.getSheetName());
System.out.println("createSheet:" + sheet.getSheetName());
manager.setSheet(sheet);
rowIndex = 1;
manager.nextRow();
for(CSVDto nextDto: ageMap.getValue()) {
if(rowIndex >= 2) {
manager.shiftRows();
}
String comment = "電話:" + nextDto.getTelephone() + LINE_SEPARATOR
+ "携帯:" + nextDto.getMobile() + LINE_SEPARATOR
+ "メール:" + nextDto.getMail();
manager.setCellComment(comment);
manager.setCellValue(nextDto.getName());
manager.setCellValue(nextDto.getFurigana());
manager.setCellValue(nextDto.getSex());
manager.setCellValue(Integer.parseInt(nextDto.getAge()));
manager.setCellValue(sdFormat.parse(nextDto.getBirthDay()));
manager.setCellValue(nextDto.getMarriage());
manager.setCellValue(nextDto.getBloodType());
manager.setCellValue(nextDto.getBirthPlace());
manager.setCellValue(nextDto.getCareer());
rowIndex++;
manager.nextRow();
}
// 印刷設定、印刷範囲
manager.setPrintSetup(wb.getSheetAt(wb.getSheetIndex(SHEET_NAME_TEMPLATE)).getPrintSetup());
wb.setPrintArea(wb.getSheetIndex(sheet), manager.getPrintArea());
}
// 集計出力
sheet = wb.cloneSheet(wb.getSheetIndex(SHEET_NAME_GRAPH_TEMPLATE));
wb.setSheetName(wb.getSheetIndex(sheet), SHEET_NAME_AGGREGATED);
System.out.println("createSheet:" + sheet.getSheetName());
manager.setSheet(sheet);
String formula = "";
for(rowIndex = 3; 7 >= rowIndex; rowIndex++) {
manager.setPosition(rowIndex, 2);
for(String sheetName: sheetNames) {
if(rowIndex == 7) {
formula = "SUM($" + manager.getColumnAlphabet() + "$4:$"
+ manager.getColumnAlphabet() +"$7)";
}else {
formula = "COUNTIF(\'" + sheetName + "\'!$I:$I,$B$" + String.valueOf(rowIndex+1) + ")";
}
manager.setCellFormula(formula);
}
}
// 数式は設定しただけでは計算されないので、再計算
wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
rowIndex++;
manager.setPosition(rowIndex, 1);
// 棒グラフ設定
manager.setBarChart();
// 印刷設定、印刷範囲
manager.setPrintSetup(wb.getSheetAt(wb.getSheetIndex(SHEET_NAME_GRAPH_TEMPLATE)).getPrintSetup());
wb.setPrintArea(wb.getSheetIndex(sheet), manager.getPrintArea());
// 不要なテンプレートを削除
wb.removeSheetAt(wb.getSheetIndex(SHEET_NAME_TEMPLATE));
wb.removeSheetAt(wb.getSheetIndex(SHEET_NAME_GRAPH_TEMPLATE));
// ファイル出力
fos = new FileOutputStream(FILE_PATH_OUTPUT);
wb.write(fos);
System.out.println("終了");
}catch(Exception e) {
e.printStackTrace();
}finally {
if(fis != null) {
try {
fis.close();
}catch(IOException e) {
}
}
if(fos != null) {
try {
fos.close();
}catch(IOException e) {
}
}
if(wb != null) {
try {
wb.close();
}catch(IOException e) {
}
}
}
}
}
5. 总结
有很多事情我不太了解,所以进行了很多试错。
但是,我终于成功读取了csv文件,并输出了全部数据,并且还按照年龄分组进行了输出和汇总!
个人感觉得益于我创建了一个Manager类,使得实现变得容易了一些,但由于我太过于堆砌了内容,所以应该按照处理内容将类进行划分并使用继承的方式进行。我觉得我应该学习一下继承,因为我不擅长它。
感谢您一直以来的观看!最后再次公开github的链接给大家!
github
https://github.com/y012/POI_Sample.gitGitHub
https://github.com/y012/POI_Sample.git