Apache POI实现Excel文件上传、导出,工具类分享
在开发一个积分商城的项目中,客户需求是可以通过excel文件导入防伪码信息。以便用户在前台输入商品上的防伪码兑换积分,所以花一点时间研究了JAVA对Excel的处理方式,这里作出记录,以便诸位学习和日后自己再次使用。
一. API概述
本次使用的对Excel的操作的API是Apache的POI项目,其Maven依赖如下:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-examples</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.9</version>
</dependency>
1. 其中POI的相关包我寻找资料时网上说版本必须一样,但后期总结时发现,不一样也没有出现错误,大家可以自行实验一下。
2.项目中log4j基本都有,所以没什么可说的
3.commons-io是Apace的IO处理包,本身针对于IO操作有很大的优化,POI对其有依赖,打上即可。
4.我后期新搭建SSM后,目前出现的依赖只有如上所属,如果大家在自己的项目中发现有什么问题,自行解决即可。
二.工具类(ExcelUtil.java)
public class ExcelUtil {
private static final Logger logger = Logger.getLogger(ExcelUtil.class);
/**
* @Title: importDataFromExcel
* @Description: 将sheet中的数据保存到list中,
* 1、调用此方法时,vo的属性个数必须和excel文件每行数据的列数相同且一一对应,vo的所有属性都为String
* 2、在action调用此方法时,需声明
* private File excelFile;上传的文件
* private String contentType;原始文件的类型
* 3、页面的file控件name需对应File的文件名
* @param @param vo javaBean
* @param @param is 输入流
* @param @param contentType
* @param @return
* @return List<Object>
* @throws
*/
public List importDataFromExcel(Class voClass, InputStream is, String contentType){
List list = new ArrayList();
try {
//创建工作簿
Workbook workbook = this.createWorkbook(is, contentType);
//创建工作表sheet
Sheet sheet = this.getSheet(workbook, 0);
//获取sheet中数据的行数
int rows = sheet.getPhysicalNumberOfRows();
//获取表头单元格个数
int cells = sheet.getRow(0).getPhysicalNumberOfCells();
//利用反射,给JavaBean的属性进行赋值
Field[] fields = voClass.getDeclaredFields();
for (int i = 1; i < rows; i++) {//第一行为标题栏,从第二行开始取数据
//利用反射生成一个新的对象
Object obj = voClass.newInstance();
Row row = sheet.getRow(i);
int index = 0;
while (index < cells) {
Cell cell = row.getCell(index);
if (null == cell) {
cell = row.createCell(index);
}
cell.setCellType(Cell.CELL_TYPE_STRING);
String value = null == cell.getStringCellValue()?"":cell.getStringCellValue();
Field field = fields[index];
String fieldName = field.getName();
String methodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
Method setMethod = obj.getClass().getMethod(methodName, new Class[]{String.class});
setMethod.invoke(obj, new Object[]{value});
index++;
}
if (isHasValues(obj)) {//判断对象属性是否有值
list.add(obj);
}
}
} catch (Exception e) {
logger.error(e);
}finally{
try {
is.close();//关闭流
} catch (Exception e2) {
logger.error(e2);
}
}
return list;
}
/**
* 将list集合对象导出至Excel表中
* @param list 放置数据的VO类集合,一定要设置泛型!
* @param headers
* @param title
* @param os
* @param <T>
*/
public <T> void exportDataToExcel(List<T> list,String[] headers,String title,OutputStream os){
HSSFWorkbook workbook = new HSSFWorkbook();
//生成一个表格
HSSFSheet sheet = workbook.createSheet(title);
//设置表格默认列宽15个字节
sheet.setDefaultColumnWidth(15);
//生成一个样式
HSSFCellStyle style = this.getCellStyle(workbook);
//生成一个字体
HSSFFont font = this.getFont(workbook);
//把字体应用到当前样式
style.setFont(font);
//生成表格标题
HSSFRow row = sheet.createRow(0);
row.setHeight((short)300);
HSSFCell cell = null;
for (int i = 0; i < headers.length; i++) {
cell = row.createCell(i);
cell.setCellStyle(style);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
//将数据放入sheet中
for (int i = 0; i < list.size(); i++) {
row = sheet.createRow(i+1);
T t = list.get(i);
//利用反射,根据JavaBean属性的先后顺序,动态调用get方法得到属性的值。
// 原工具类中使用getFields()无法获取私有属性,修改为getDeclaredFields()即可。
//Field[] fields = t.getClass().getFields();
Field[] fields = t.getClass().getDeclaredFields();
try {
for (int j = 0; j < fields.length; j++) {
cell = row.createCell(j);
Field field = fields[j];
String fieldName = field.getName();
String methodName = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
Method getMethod = t.getClass().getMethod(methodName,new Class[]{});
Object value = getMethod.invoke(t, new Object[]{});
if(null == value)
value ="";
cell.setCellValue(value.toString());
}
} catch (Exception e) {
logger.error(e);
}
}
try {
workbook.write(os);
} catch (Exception e) {
logger.error(e);
}finally{
try {
os.flush();
os.close();
} catch (IOException e) {
logger.error(e);
}
}
}
/**
* @Title: createWorkbook
* @Description: 判断excel文件后缀名,生成不同的workbook
* @param @param is 文件输入流
* @param @param excelFileName 文件拓展名
* @param @return
* @param @throws IOException
* @return Workbook
* @throws
*/
public Workbook createWorkbook(InputStream is,String fileContentType) throws IOException{
if ("application/vnd.ms-excel".equals(fileContentType)) {
return new HSSFWorkbook(is);
}else if ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(fileContentType)) {
return new XSSFWorkbook(is);
}
return null;
}
/**
* @Title: getSheet
* @Description: 根据sheet索引号获取对应的sheet
* @param @param workbook
* @param @param sheetIndex
* @param @return
* @return Sheet
* @throws
*/
public Sheet getSheet(Workbook workbook,int sheetIndex){
return workbook.getSheetAt(0);
}
/**
* @Title: isHasValues
* @Description: 判断一个对象所有属性是否有值,如果一个属性有值(分空),则返回true
* @param @param object
* @param @return
* @return boolean
* @throws
*/
public boolean isHasValues(Object object){
Field[] fields = object.getClass().getDeclaredFields();
boolean flag = true;
for (int i = 0; i < fields.length; i++) {
String fieldName = fields[i].getName();
String methodName = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
Method getMethod;
try {
getMethod = object.getClass().getMethod(methodName);
Object obj = getMethod.invoke(object);
if (null != obj && !"".equals(obj)) {
flag = true;
break;
}
} catch (Exception e) {
logger.error(e);
}
}
return flag;
}
/**
* @Title: getCellStyle
* @Description: 获取单元格格式
* @param @param workbook
* @param @return
* @return HSSFCellStyle
* @throws
*/
public HSSFCellStyle getCellStyle(HSSFWorkbook workbook){
HSSFCellStyle style = workbook.createCellStyle();
style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setLeftBorderColor(HSSFCellStyle.BORDER_THIN);
style.setRightBorderColor(HSSFCellStyle.BORDER_THIN);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
return style;
}
/**
* @Title: getFont
* @Description: 生成字体样式
* @param @param workbook
* @param @return
* @return HSSFFont
* @throws
*/
public HSSFFont getFont(HSSFWorkbook workbook){
HSSFFont font = workbook.createFont();
font.setColor(HSSFColor.WHITE.index);
font.setFontHeightInPoints((short)12);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
return font;
}
public boolean isIE(HttpServletRequest request){
return request.getHeader("USER-AGENT").toLowerCase().indexOf("msie")>0?true:false;
}
}
工具类有两个核心方法:
导入:importDataFromExcel (Class voClass, InputStream is, String contentType){};
导出:exportDataToExcel(List list,String[] headers,String title,OutputStream os){};
详情可见工具类中注释,其中需要着重说的是:
1. 导入方法:
voClass:需要与Excel数据对应的专用的VO类Class,其中VO类对象中的属性必须与Excel数据一一对应,且都为String。
is:Excel文件输入流
contentType:传入文件的类型(即xls、xlsx两种文件的兼容问题)
2. 导出方法:
list:要导出的数据VO类集合,必须包含相应VO类对象的泛型,因为工具类需要依靠此泛型进行反射操作。
headers:导入Excel文件的头部数据集合,其必须与VO类属性对象一一对应。
os:文件输出流。
三.使用演示(FileUploadController.java)
@RequestMapping("/upload")
@Controller
public class FileUploadController {
@RequestMapping("/img")
public void uploadImg(@RequestParam(value = "myfile") MultipartFile myfile)throws Exception{
//通过获取的文件读取相应的数据到指定VO(SecurityCodeVo.class)的List集合中
List list = new ExcelUtil().importDataFromExcel(SecurityCodeVo.class,myfile.getInputStream(),myfile.getContentType());
//导出Excel时,需要通过list集合中的泛型来进行反射操作
List<SecurityCodeVo> newList = list;
//创建文件,实际中这里应该由用户前台选择路径、填写文件名。
File file = new File("D:\\exportDataToExcel.xls");
file.createNewFile();
OutputStream out = new FileOutputStream(file);
//手动设置excel的头标题,必须与VO类中储存的属性值相匹配。
String header[] = {"code","score"};
new ExcelUtil().exportDataToExcel(newList,header,"导出",out);
}
}
demo中依靠SSM上传接收Excel,并直接将此集合输出到D盘中,流程很简单,大家在自己的项目中,灵活运用即可。
最后:新手程序员上路,稚嫩年轻,有所错误,敬请提出,不胜感激。
上一篇: Java Web 登录页面的实现
下一篇: Vue前后端分离完成文件上传