java jxl实现通用导入excel

jdk1.8

包:jxl-2.6.12.jar、commons-beanutils-1.9.3.jar

1、定义属性模型AttributeModel.java

public class AttributeModel {

    /**
     * @param attribute 属性 eg:age
     * @param name 名称 eg:年龄
     * @param hasWarn 标红提醒 eg:true
     * */
    public AttributeModel(String attribute, String name, Boolean hasWarn){
        this.attribute = attribute;
        this.name = name;
        if(hasWarn){
            this.hasWarn = hasWarn;
        }
    }
    // excel表头
    private String name;
    // 实体类属性名
    private String attribute;
    // 是否提醒必填
    private Boolean hasWarn = false;

    public String getName() {
        return name;
    }

    public String getAttribute() {
        return attribute;
    }

    public Boolean isHasWarn() {
        return hasWarn;
    }

}

2、定义attributeList,也就是需要导入的字段和中文名,为提供导入的模板做准备

/**
	 * @doc会员导入
     * 数据第三个字符串是为了设置导出excel是单元格样式,true就标红提醒必填,没这需求可以不加
	 **/
	public static List getMemberImportConstant() {
		List attributeList = new ArrayList<>();
		attributeList.add(new AttributeModel("memberName","会员名", true));
		attributeList.add(new AttributeModel("idCar", "身份证号", true));
		attributeList.add(new AttributeModel("birthday", "生日", false));
		attributeList.add(new AttributeModel("sex", "性别", true));
		attributeList.add(new AttributeModel("phone", "手机号", true));
		return attributeList;
	}

 3、定义一个示例数据,方便用户参考,这一步非必须

/**
	 * @doc 会员信息导入 案例
	 **/
	public static List getMemberImportExample() {
		Memberexample = new Member();
		List exampleList = new ArrayList();
		example.setMemberName("张三");
		example.setIdCar("410*****0012");
		example.setSex("男");
        example.setPhone("1388888888");
        example.setBirthday("1999-8-8");
		exampleList.add(example);
		return exampleList;
	}

4、导出模板只需传入第二部准备好的示例数据(Listllist)和定义好的导出字段(ListattributeList)和 response

/**
	 * 用于表头导出用
	 * @param response
	 * @parm list 数据集合
     * @parm attributeList 属性模型集合
	 */
	public  void writeHeadToFile(List list, List attributeList, HttpServletResponse response) {

		if (CollectionUtils.isEmpty(attributeList)) {
			return;
		}
		try {
			WritableWorkbook book = Workbook.createWorkbook(response.getOutputStream());
			// 创建一个工作区。
			WritableSheet sheet = book.createSheet("第一页", 0);
			// 在工作区上面添加内容
			try {
				// 处理第一行,标题
				Label newLabel = null;// new Label(j, i, String.valueOf(j));
				for (int i = 0; i < attributeList.size(); i++) {
					Boolean hasRed = attributeList.get(i).getHasWarn();
					newLabel = new Label(i, FIRST_ROW, attributeList.get(i).getName(),getHeaderCellStyle(hasRed));
					sheet.addCell(newLabel);
				}
				if (!CollectionUtils.isEmpty(list)) {
					Object param = null;
					for (int i = FIRST_ROW + 1; i <= list.size(); i++) {
						T t = list.get(i - 1);
						Map properties = conversionToMapByTool(t);
						for (int j = 0; j < attributeList.size(); j++) {
							param = properties.get(attributeList.get(j).getAttribute());
							newLabel = new Label(j, i, objToString(param));
							sheet.addCell(newLabel);
						}
					}
				}
			} catch (RowsExceededException e) {
				logger.error("行或列参数错误!{}", e);
			} catch (WriteException e) {
				logger.error("写入失败!{}", e);
			} catch (Exception e) {
				logger.error("写入失败!{}", e);
			} finally {
				if (book != null) {
					book.write();
					try {
						book.close();
					} catch (WriteException e) {
						logger.error("文件关闭失败!{}", e);
					}
				}
			}
		} catch (IOException e) {
			logger.error("创建文件失败!{}", e);
		}
	}

private  Map conversionToMapByTool(T bean) throws Exception {
		Map map = new HashMap();
		PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
		PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(bean);

		for (PropertyDescriptor d : descriptors) {
			String fieldName = d.getName();
			Object value = propertyUtilsBean.getNestedProperty(bean, fieldName);
			if (!"class".equals(fieldName))
				map.put(fieldName, value);
		}
		return map;
	}

/**
	 * 表头单元格样式的设定
	 */
	public WritableCellFormat getHeaderCellStyle(Boolean hasRed){

		/*
		 * WritableFont.createFont("宋体"):设置字体为宋体
		 * 10:设置字体大小
		 * WritableFont.BOLD:设置字体加粗(BOLD:加粗     NO_BOLD:不加粗)
		 * false:设置非斜体
		 * UnderlineStyle.NO_UNDERLINE:没有下划线
		 */
		WritableFont font = null;
		if(hasRed){
			font = new WritableFont(WritableFont.ARIAL,10,WritableFont.BOLD,false, UnderlineStyle.NO_UNDERLINE,Colour.RED);
		}else{
			font = new WritableFont(WritableFont.ARIAL,10,WritableFont.NO_BOLD,false,UnderlineStyle.NO_UNDERLINE,Colour.BLACK);
		}

		WritableCellFormat headerFormat = new WritableCellFormat();
		try {
			//添加字体设置
			headerFormat.setFont(font);
			//设置单元格背景色:表头为黄色
			//headerFormat.setBackground(Colour.YELLOW);
			//设置表头表格边框样式
			//整个表格线为粗线、黑色
			//headerFormat.setBorder(Border.ALL, BorderLineStyle.THICK, Colour.BLACK);
			//表头内容水平居中显示
			headerFormat.setAlignment(Alignment.LEFT);
		} catch (WriteException e) {
			System.out.println("表头单元格样式设置失败!");
		}
		return headerFormat;
	}

5、用户填好导出的excel后,上传文件处理方法

/**
     *@param file,request,response
     *@doc 会员导入
     **/
    @ResponseBody
    @RequestMapping(value = "importExcel", method = {RequestMethod.GET, RequestMethod.POST})
    public Result importExcel(@RequestParam(value="filename") MultipartFile file, HttpServletRequest request, HttpServletResponse response){
        if(file == null){
            return new ResultSupport<>(false, "此文件为空");
        }
        //获取文件名字
        String name=file.getOriginalFilename();
        //判断文件后缀是否为xls
        if(!("xls".equals(name.substring(name.lastIndexOf(".")+1)))){
            return new ResultSupport<>(false, "该文件不是xls类型,请核对文件,或者重新下载导入模板");
        }
        //进一步判断文件是否为空(即判断其大小是否为0或其名称是否为null)
        long size=file.getSize();
        if(StringUtil.isEmpty(name) || ("").equals(name) && size==0){
            return new ResultSupport<>(false, "文件内容为空/字段类型不对符合请检查");
        }
        try {
			// JxlImportExcelUtil 封装的导入导出工具类
            List values = JxlImportExcelUtil.getInstance().readLines(file);
            if(CollectionUtils.isEmpty(values)){
                return new ResultSupport<>(false, "数据过大请少于50000条");
            }
			// 判断字段和nameList是否一样多,不一样可能模板不正确
            if(!(values.get(0).length != nameList.size()){
                Result result = new ResultSupport<>(false, "所导入的模板不正确,请下载正确的模板");
                result.setData(0);
                return result;
            }
			// 第一个参数为excel里面的数据
            // 第二个需要传入实体类的路径
            // 第三个是导出模板的标题
            List memberList = JxlImportExcelUtil.getInstance().generatorTargets(values,"com.david.member.domain.Member", attributeList);
            if(CollectionUtils.isEmpty(goodsList)){
                return new ResultSupport<>(false, "excel中没有数据");
            }else{
                // 将转换好的memberList 进行批量新增
                return menberService.insertList(memberList);
            }
        } catch (Exception e) {
            logger.error("导入会员失败:"+e.getMessage(), e);
            return new ResultSupport<>(false, "导入会员失败");
        }
    } 
  

自己封装的导入导出工具类:JxlImportExcelUtil

// JxlImportExcelUtil
	
	/**
	 * @throws BiffException
	 * @throws IOException
	 * @Title: readLines
	 * @Description: TODO 读取excel
	 * @return List
	 * @throws
	 */
	public List readLines(MultipartFile mfile) throws IOException, BiffException {
		if (mfile == null) {
			return new ArrayList<>(0);
		}
		return readLinesFromstream(mfile.getInputStream());
	}
	
	// JxlImportExcelUtil
	
	/**
	* 读取数据
	**/
	private List readLinesFromstream(InputStream ins) throws BiffException, IOException {
		List list = new ArrayList();
		Workbook rwb = null;
		try {
			rwb = Workbook.getWorkbook(new BufferedInputStream(ins, 20 * 1024 * 1024));

			Sheet sheet = rwb.getSheet(0);
			// 设置导入条数限制5W
			if (sheet.getRows() > Integer.parseInt(import_Limit) + 1) {
				return null;
			}
			for (int i = 0; i < sheet.getRows(); i++) {
				String[] str = new String[sheet.getColumns()];
				Cell cell = null;
				for (int j = 0; j < sheet.getColumns(); j++) {
					cell = sheet.getCell(j, i);
					if (cell instanceof DateCell) {
						// DateUtil.formatDateYMDHMS 时间转换工具类,把日期转换为字符串格式
						str[j] = DateUtil.formatDateYMDHMS(((DateCell) cell).getDate(), "GMT");
					} else {
						str[j] = cell.getContents();
						if(!StringUtils.isEmpty(str[j])) {
							str[j].trim();
						}
					}
				}
				list.add(str);
			}
		} catch (Exception e) {
			throw e;
		} finally {
			if (rwb != null) {
				rwb.close();
			}
			ins.close();
		}
		return list;
	}
	
	/**
	 * @param valueList excel 读取的数据
	 * @param className T的classname
	 * @param strList param与中文描述的对应
	 * @Title: generatorTargets
	 * @Description: TODO
	 * @return List 将读取的excel转换成目标对象列表。
	 * @throws
	 */
	public  List generatorTargets(List valueList, String className, List strList)
			throws InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException {
		List paramCnName = Arrays.asList(valueList.get(0));// excel 表头
		List pname = new ArrayList();// 表头对应的属性名称
		Map namesMap = strList.stream().collect(Collectors.toMap(str -> str[1], str -> str[0]));
		paramCnName.forEach(o -> {
			pname.add(namesMap.get(o));
		});
		// 因为第一行为示例数据,所以删除第一行,没有示例数据可以不删
		valueList.remove(0);
		List tList = new ArrayList();
		if (CollectionUtils.isEmpty(valueList)) {
			return tList;
		}

		final int scalar = 2500;
		int size = valueList.size();
		long jobNums = 0;
		if (size % scalar == 0) {
			jobNums = size / scalar;
		} else {
			jobNums = size / scalar + 1;
		}
		List>> jobs = new ArrayList>>();
		List subList = null;
		for (int i = 0; i < jobNums; i++) {
			if (i == jobNums - 1) {
				subList = valueList.subList(i * scalar, size);
			} else {
				subList = valueList.subList(i * scalar, (i + 1) * scalar);
			}
            // JxlImportCallable 继承了Callable,下面会粘出代码
			Callable> c = new JxlImportCallable(subList, className, pname);
			jobs.add(c);
		}
        // MutiThreadJobUtil 多线程处理工具类,下面粘出代码
		tList = MultiThreadJobsUtil.doJob(jobs);
		return tList;
	}

JxlImportCallable 类

import com.david.domain.common.DateUtil;
import com.david.web.util.myConverter.MyBooleanConverter;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.collections.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class JxlImportCallable implements Callable> {
	private List dataList;
	private String clazzName;
	List pname;

	public JxlImportCallable(List dtList, String claName, List pnameList) {
		this.dataList = dtList;
		this.clazzName = claName;
		this.pname = pnameList;
	}

	@Override
	public List call() throws Exception {
		List dataList = null;
		try {
			dataList = generatorData();
		} catch (Exception e) {
			dataList = new ArrayList();
		}
		return dataList;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private  List generatorData()
			throws IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {

		if (CollectionUtils.isEmpty(dataList)) {
			return null;
		}

		/**
		 * 实现java.util.Date的cover
		 */
		ConvertUtils.register(new Converter() {
			public Object convert(Class type, Object value) {
				
				return DateUtil.parseDate(value.toString());
			}
		}, java.util.Date.class);
		// 注册自定义boolean值转换工具类
		ConvertUtils.register(new MyBooleanConverter(), java.lang.Boolean.class);

		List tList = new ArrayList();
		T t = null;
		for (int i = 0; i < dataList.size(); i++) {
			t = (T) Class.forName(clazzName).newInstance();
			for (int j = 0; j < pname.size(); j++) {
				BeanUtils.setProperty(t, pname.get(j), dataList.get(i)[j]);
			}
			tList.add(t);
		}

		return tList;
	}

}
MultiThreadJobsUtil 多线程任务通用工具
package com.david.web.util;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 多线程任务通用工具
 *
 */
public class MultiThreadJobsUtil {

	private static final Logger log = LoggerFactory.getLogger(MultiThreadJobsUtil.class);

	private static ExecutorService executor = new ThreadPoolExecutor(10, 10, 30L, TimeUnit.MINUTES,
			new LinkedBlockingQueue(), new ThreadFactory() {

				@Override
				public Thread newThread(Runnable r) {
					Thread t = new Thread(r);
					t.setName("CRM-线程-" + t.getId());
					return t;
				}
			});

	public static  List doJob(final List>> jobs) {

		List result = new ArrayList();
		try {
			if (!executor.isShutdown()) {
				List>> results = executor.invokeAll(jobs);
				for (Future> future : results)
					result.addAll(future.get());
			}
		} catch (InterruptedException e) {

			log.error("线程中断异常", e);
		} catch (ExecutionException e) {
			log.error("线程执行异常", e);

		} catch (Exception e) {

			log.error("其它错误异常", e);
		}
		return result;

	}

	public static void doJob(final Runnable r) {
		try {
			if (!executor.isShutdown()) {
				executor.submit(r);
			}
		} catch (Exception e) {
			log.error("其它错误异常", e);
		}
	}

	public static void shutdown() throws InterruptedException {
		executor.shutdown();
		executor.awaitTermination(60, TimeUnit.SECONDS);
		executor.shutdownNow();
	}

	@Override
	protected void finalize() throws Throwable {
		shutdown();
	}

}

 

你可能感兴趣的:(Java)