SSM+POI上传读取导出excel--------读取(二)

本文介绍了一种利用自定义注解实现Java Bean属性与Excel列对应的方法,通过创建注解并应用于Bean字段,结合反射读取Excel数据,实现自动转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接着上一篇,该如何做到bean的属性与excel的列相对应呢。。经过我一番百度学习,发现注解可以实现我的需求

附上大佬博客,基本就是跟着他写的,成功实现了功能

https://my.oschina.net/wang520/blog/894276

创建注解

package com.mqb.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * excel自定义注解,name为在实体字段excel对应的列名
 * columnIndex为该字段对应在excel的列的索引,-1时不从excel获取值
 * @author MQB
 *
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Excel {
	String name() default "";
	int columnIndex() default -1;
}

测试用的bean

package com.mqb.test.poiTest;

import java.util.Date;

import org.springframework.stereotype.Component;

import com.mqb.annotation.Excel;

@Component
public class TTT {
	@Excel(name="姓名",columnIndex=0)
	String name;
	@Excel(name="性别",columnIndex=1)
	Boolean sex;
	@Excel(name="出生日期",columnIndex=2)
	Date birthday;
	@Excel(name="数字",columnIndex=3)
	Integer num;
	
	public TTT() {}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Boolean getSex() {
		return sex;
	}
	public void setSex(Boolean sex) {
		this.sex = sex;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public Integer getNum() {
		return num;
	}
	public void setNum(Integer num) {
		this.num = num;
	}
	@Override
	public String toString() {
		return "TTT [name=" + name + ", sex=" + sex + ", birthday=" + birthday + ", num=" + num + "]";
	}
	
	
}

自定义工具类

package com.mqb.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import com.mqb.annotation.Excel;
import com.mqb.test.poiTest.TTT;

public class ExcelUtil {
	
	public static String getValueByCellStyle(Cell cell) {
		String value="";
		switch(cell.getCellTypeEnum()) {
			case STRING:
				value=cell.getStringCellValue();
				break;
			case BOOLEAN:
				value=String.valueOf(cell.getBooleanCellValue());
				break;
			case NUMERIC:
				String str=cell.getCellStyle().getDataFormatString();
				if("m/d/yy".equals(str)) {
					value=cell.getDateCellValue().toString();
				}else {
					value=String.valueOf(cell.getNumericCellValue());
				}
				break;
			default:
					break;
		}
		
		return value;
	}
	
	public static <T> List<T> readExcel(Class<T> clazz,Workbook workbook) {
		List<T> list=new ArrayList<>();
		try {
			for(int i=0;i<workbook.getNumberOfSheets();i++) {
				Sheet sheet=workbook.getSheetAt(i);
				for(int j=0;j<sheet.getPhysicalNumberOfRows();j++) {
					if(j==0)//第一行默认为列名,跳过第一行
						continue;
					Row row=sheet.getRow(j);
					T o=clazz.newInstance();//使用无参构造函数创建一个clazz类的实例
					for(Field field:clazz.getDeclaredFields()) {
						field.setAccessible(true);//可以访问私有字段
						int cellnum=field.getAnnotation(Excel.class).columnIndex();
						if(cellnum==-1)//-1表示该字段不用从excel中读取
							continue;
						System.out.println(field.getType()+"================");
						
						//有新的需要的类型在此添加
						if(field.getType().equals(String.class)) {
							String value=getValueByCellStyle(row.getCell(cellnum));
							field.set(o, value);
						}else if(field.getType().equals(Boolean.class)) {
							Boolean value=Boolean.valueOf(getValueByCellStyle(row.getCell(cellnum)));
							field.set(o, value);
						}else if(field.getType().equals(Integer.class)) {
							String s=getValueByCellStyle(row.getCell(cellnum));
							Integer value=Integer.parseInt(s.substring(0, s.indexOf(".")));
							field.set(o, value);
						}else if(field.getType().equals(Date.class)) {
							Date value=new Date(getValueByCellStyle(row.getCell(cellnum)));
							field.set(o, value);
						}else {
							System.out.println("缺少类型判断:"+field.getType());
							return null;
						}
						
					}
					list.add(o);
				}
			}
		}catch(Exception e) {
			System.out.println("出错了");
			return null;
		}
		
		return list;
	}
}

在上一篇博客中工具类的基础上添加了一个  readExcel 的方法。

具体思路就是:将workbook的每个sheet的每个row都遍历出来,每个sheet的第一个row跳过,这一行作为为列名行

当遍历到其他row时,通过反射获取到我们要封装的bean的实例

然后遍历bean的字段,读取该字段的Excel注解,获得该字段对应excel中列的索引 cellnum

通过  row.getCell()获取到对应的cell,传入getValueByCellStyle 做一些基本的处理,然后根据字段的类型将值修改然后赋值

这里我只进行了4个类型判断,有需要可以日后增加。

 

controller,这里我将  readExcel() 返回的list输出,可以看到成功封装

@RequestMapping(value="/testUpExcel",method=RequestMethod.POST)
	@ResponseBody
	public Msg uploadExcel(
			MultipartFile uploadFile,
			HttpServletRequest request) throws Exception, IOException {
		
		//上传到本地磁盘
		String realPath="E:\\upload\\temp\\excel\\";
		
		//获取原始图片的拓展名-------暂时不判断后缀名
        String originalFilename = uploadFile.getOriginalFilename();
        //封装上传文件位置的全路径,就是硬盘路径+文件名
        File targetFile = new File(realPath,originalFilename); 
        //使用MultipartFile接口中的方法,把本地文件上传到已经封装好的文件位置的全路径就是上面的targetFile
        uploadFile.transferTo(targetFile);
        
        
        FileInputStream stream=new FileInputStream(targetFile);
        HSSFWorkbook workbook=new HSSFWorkbook(stream);
        
        List<TTT> list=ExcelUtil.readExcel(TTT.class, workbook);
        System.out.println("read excel completed,start out list:");
        for(TTT t:list) {
        	System.out.println(t.toString());
        }
        return Msg.success();
	}

我上传的excel

 

如果一定要求excel每列的顺序不能变,那可以对每个sheet的row0进行判断,

取得field的excel注解的columnIndex和name

对应row(columnIndex)的值是否和name一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值