CNode

Nodejs 里Excel开发实践

分享
Ii5ting发布于11 年前最后回复7 年前19 回复10746 浏览0 收藏

excel的导入导出在一般业务系统里是非常常见的,但是nodejs里并没有成熟的处理excel的库,导入问题不大,稍微复杂的导出就搞不定了

那么,只剩下曲线救国一条路了

excel的导入导出在一般业务系统里是非常常见的,但是nodejs里并没有成熟的处理excel的库,导入问题不大,稍微复杂的导出就搞不定了

  • exceljs
  • excel.js
  • node-xlsx

都太简单了...

那么,只剩下曲线救国一条路了

合理架构

node的优点就不说了,它虽好,但毕竟才出来几年,很多东西都不够完善的,所以在使用这种比较新比较潮的技术的时候,一定要学会扬长避短,不然会很难受

apache的poi是一个不错的库,非常成熟,我从07年就开始用它,

下面是百科的简介

Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。

Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案(适用于Excel97-2008)。

http://poi.apache.org/

我们需要考虑以下问题:

  • 多语言是否合适?
  • 分拆功能是否合适?

思考

系统小的时候肯定会尽量统一的,系统大了就会有各种鸟了

比如创业初期,可能是rails or express写的东西,但随着业务的壮大,会发现瓶颈的,这个时候你需要扩容

你多加台机器,然后部署一次

可是这样真的好么?

理想的做法是拆分成小模块,就像处理redis缓存一样,业务量大了,就立马多起几个docker实例,非常好运维

而且从职责上看,它也是小而美的代表

既然小了,那么你用什么语言开发还重要么?

比如我的核心系统是expressjs写的,我的下载就用的java写的,我部署了2个,然后nginx处理一下,谁又能看出来差别呢?

而且我的express一定要多起几个实例,而java的可能并发比较少,我没有去浪费资源。

分享一个简单的工具类

package im.xbm.dlcenter.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelUtils {
	// 对外提供读取excel文件的接口
	public static List<List<Object>> readExcel(File file) throws IOException {
		String fName = file.getName();
		String extension = fName.lastIndexOf(".") == -1 ? "" : fName
				.substring(fName.lastIndexOf(".") + 1);
		if ("xls".equals(extension)) {// 2003
			System.err.println("读取excel2003文件内容");
			return read2003Excel(file);
		} else if ("xlsx".equals(extension)) {// 2007
			System.err.println("读取excel2007文件内容");
			return read2007Excel(file);
		} else {
			throw new IOException("不支持的文件类型:" + extension);
		}
	}

	/**
	 * 读取2003excel
	 * 
	 * @param file
	 * @return
	 */
	private static List<List<Object>> read2003Excel(File file)
			throws IOException {
		List<List<Object>> dataList = new ArrayList();
		HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(file));
		HSSFSheet sheet = wb.getSheetAt(0);
		HSSFRow row = null;
		HSSFCell cell = null;
		Object val = null;
		DecimalFormat df = new DecimalFormat("0");// 格式化数字
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 格式化日期字符串
		for (int i = sheet.getFirstRowNum(); i < sheet
				.getPhysicalNumberOfRows(); i++) {
			row = sheet.getRow(i);
			if (row == null) {
				continue;
			}
			List<Object> objList = new ArrayList<Object>();
			for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
				cell = row.getCell(j);
				if (cell == null) {
					val = null;
					objList.add(val);
					continue;
				}
				switch (cell.getCellType()) {
				case HSSFCell.CELL_TYPE_STRING:
					val = cell.getStringCellValue();
					break;
				case HSSFCell.CELL_TYPE_NUMERIC:
					if ("@".equals(cell.getCellStyle().getDataFormatString())) {
						val = df.format(cell.getNumericCellValue());
					} else if ("General".equals(cell.getCellStyle()
							.getDataFormatString())) {
						val = df.format(cell.getNumericCellValue());
					} else {
						val = sdf.format(HSSFDateUtil.getJavaDate(cell
								.getNumericCellValue()));
					}
					break;
				case HSSFCell.CELL_TYPE_BOOLEAN:
					val = cell.getBooleanCellValue();
					break;
				case HSSFCell.CELL_TYPE_BLANK:
					val = "";
					break;
				default:
					val = cell.toString();
					break;
				}
				objList.add(val);
			}
			dataList.add(objList);
		}
		return dataList;
	}

	/**
	 * 读取excel表头
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String[] readExcelHead(File file) throws IOException {
		HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(file));
		HSSFSheet sheet = wb.getSheetAt(0);
		HSSFRow row = null;
		HSSFCell cell = null;
		row = sheet.getRow(0);
		String[] buff = new String[row.getLastCellNum()];
		for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
			cell = row.getCell(i);
			buff[i] = cell.getStringCellValue();
		}
		return buff;
	}

	/**
	 * 读取2007excel
	 * 
	 * @param file
	 * @return
	 */

	private static List<List<Object>> read2007Excel(File file)
			throws IOException {
		List<List<Object>> dataList = new ArrayList<List<Object>>();
		XSSFWorkbook xwb = new XSSFWorkbook(new FileInputStream(file));
		XSSFSheet sheet = xwb.getSheetAt(0);
		XSSFRow row = null;
		XSSFCell cell = null;
		Object val = null;
		DecimalFormat df = new DecimalFormat("0");// 格式化数字
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 格式化日期字符串
		for (int i = sheet.getFirstRowNum(); i < sheet
				.getPhysicalNumberOfRows(); i++) {
			row = sheet.getRow(i);
			if (row == null) {
				continue;
			}
			List<Object> objList = new ArrayList<Object>();
			for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
				cell = row.getCell(j);
				if (cell == null) {
					val = null;
					objList.add(val);
					continue;
				}
				switch (cell.getCellType()) {
				case XSSFCell.CELL_TYPE_STRING:
					val = cell.getStringCellValue();
					break;
				case XSSFCell.CELL_TYPE_NUMERIC:
					if ("@".equals(cell.getCellStyle().getDataFormatString())) {
						val = df.format(cell.getNumericCellValue());
					} else if ("General".equals(cell.getCellStyle()
							.getDataFormatString())) {
						val = df.format(cell.getNumericCellValue());
					} else {
						val = sdf.format(HSSFDateUtil.getJavaDate(cell
								.getNumericCellValue()));
					}
					break;
				case XSSFCell.CELL_TYPE_BOOLEAN:
					val = cell.getBooleanCellValue();
					break;
				case XSSFCell.CELL_TYPE_BLANK:
					val = "";
					break;
				default:
					val = cell.toString();
					break;
				}
				objList.add(val);
			}
			dataList.add(objList);
		}
		return dataList;
	}
}

从这个可以看出poi的用法,整体还是比较简单

这是读取部分的代码,写的部分也很简单,涉及公司业务,就不放上来了

开发知识点

你需要学的是

  • 会基本的servlet,写接口(eclipse新建项目的时候,选择dynamic项目)
  • 使用eclipse调试开发
  • 使用mongodb java driver去操作mongodb
  • 使用poi去读取和生成文件
  • 使用java处理一下文件路径

这里就不科普了,javaEE的教程一搜一大堆

心态

不要排斥其他语言,用好它们的长处才是本事

现在是一个合作的时代

欢迎关注我的公众号【node全栈】 node全栈.png 原文

查看回复

回复 (19)

D
dengnan123#1·9 年前

狼叔,现在node有好的导入导出功能没 还是node-xlsx吗

H
huhuime#2·7 年前
引用 dengnan123狼叔,现在node有好的导入导出功能没 还是node xlsx吗

@dengnan123 在有office的情况下用wanx会舒服些

R
russj#3·11 年前

友情提醒大家, Java 的

I
i5ting#4·11 年前
引用 russj友情提醒大家, Java 的

@russj 求教:复杂的excel导入导出,node如何做?我没有找到更好的办法

I
i5ting#5·11 年前

exceljs 和 excel.js 复杂的就不行了。。。。

R
russj#6·11 年前

我用的这个 https://www.npmjs.com/package/node-xlsx 可能我的还不够复杂

I
i5ting#9·11 年前
C
coolicer#10·11 年前

你为什么不用C#版的

G
gotolnc#12·11 年前

不如c#方便好用

I
i5ting#13·11 年前
引用 gotolnc不如c 方便好用

@gotolnc 考虑部署么?

1
151263#14·11 年前
引用 i5ting@151263 你确定你试过了么?

@i5ting 1年前,做了系统,里面有30多张复杂的报表,赚了几十万了,你说呢

1
151263#15·11 年前
引用 i5ting@151263 你确定你试过了么?

@i5ting 你提出的这些办法,我想问,假如要做非常复杂的财务报表,里面还有动态公式,还需要宏,还要柱状图,Excel本身还要只读状态,还要密码,等等等等,怎么搞?
然后客户还告诉你,这需求不是最终版的, 你先做, 做出来之后,他给老板看了才能确定对不对,可能还要再改多次, 我想说,用这种写代码来导出Excel,只能导出简单的, 在很多场合,远远不够

I
i5ting#16·11 年前
引用 coolicer你为什么不用C 版的

@coolicer 恩,NPOI也可以,不过部署服务器会比较麻烦

等C#跨平台了再考虑吧

1
151263#18·11 年前

https://cnodejs.org/topic/54afa85cce87bace2444ce44 这个复杂的更好用 模板+数据=导出

参与回复
登录后即可参与回复。登录