java POI 读写 excel(项目实际需求)

本贴最后更新于 3880 天前,其中的信息可能已经时过境迁

这几天由于工作需要,需要做一个报表比对工具(找出两张报表的差异)。需求如下

1、做一个客户端工具,采用java,可以不用GUI(考虑到,我目前只懂j2ee相关的技术,其实这个需求用python(python版本)来做是最合适的,可是我目前不会,当然后面我会学习下这们语言)

2、两张报表的比队列需要灵活配置,通过配置文件来控制需要比对的列(可以是一列,可以是多列)

3、需要找出表A中有的一条数据,但是表B中没有的。或者表B中有的,表A中没有的。或者表A和表B同时都存在的一条数据,但是里面的某一些字段不一样。

4、两张报表的格式可能不一样,有可能为csv,xls,xlsx。两张报表的列数也是不固定的(这两张报表可以是任意的两张报表)

5、将比对结果再汇总到一张excel中(格式没有要求,我这里默认的是xls)

6、主键可能为复合主键,比对的报表,可能需要一次比对多组报表(由于这个需求,是今天才加上的,所以目前代码还处理这个问题,当然会很快加上)

思路一:

POI1-1

1、采用二维数组为主要的数据结构。因为,报表的列数不确定,所以不能构造对象,采用下标来控制每一列

2、将A表中的第一行的主键,然后搜索表B的主键,如果没搜到记下来,如果搜到了,比较所配置的列看是否相同,如果不同记下来,再反搜,表B中的主键来搜素表A,如果表B中有的,表A中没有的,记下来。

将记下来的数据重组,再导出excel。

效率:两张表都是30多列,52行,大概一秒左右比对完导出到excel中。

思路二

 POI1-2

1、主要采用了循环加map的方式,再比较是否有相等行的时候,直接用,表A的mapA.get(mapB.get("key"))如果数据不为空,说明在表A中有数据和表B匹配,这里的get有效的减少了一次循环。利用了map.get的方法速度更快。其他的。但是主要逻辑,还是如思路相同

接下来贴出,处理这个需求的主要代码。贴出代码的目的,主要是希望各位网友看到后,能够给指点一二,我这代码,肯定还需要优化,重构。或者说换思路。当然你有什么想法,通过评论,或者邮件告诉我。谢谢

ReadCSVExcel方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import au.com.bytecode.opencsv.CSVReader;

import com.qly.report.operate.facade.IReadExcel;

public class ReadCsvImpl implements IReadExcel{
static String qlyStringArr[][] = new String[1000][1000];
static String otherStringArr[][] = new String[1000][1000];
static Map<String,Integer > qlycontent = new HashMap<String,Integer >();
static Map<String,Integer > othercontent = new HashMap<String,Integer >();

@Override
public Map&lt;String, Object&gt; readExcel(String path, String flag) {
	CSVReader reader = null;
	// 取特定列放到集合
	try {
		InputStream ins = new FileInputStream(new File(path));
		InputStreamReader in = new InputStreamReader(ins, &quot;gbk&quot;);
		reader = new CSVReader(in);
		int len = reader.readNext().length;
		String nextline[];
		int counter = 0;
		// 将不同的来源的csv文件分别存放到不同的二维数组中
		if (&quot;qly&quot;.equals(flag)) {
			Map&lt;String, Object&gt; qlyMap = new HashMap&lt;String, Object&gt;();
			while ((nextline = reader.readNext()) != null) {
				for (int i = 0; i &lt; len; i++) {
					qlyStringArr[counter][i] = nextline[i];
				}
				counter++;
			}
			qlycontent.put(&quot;colNum&quot;, len);
			qlycontent.put(&quot;rowNum&quot;, counter);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return qlyMap;
		}

		if (&quot;other&quot;.equals(flag)) {
			Map&lt;String, Object&gt; otherMap = new HashMap&lt;String, Object&gt;();
			while ((nextline = reader.readNext()) != null) {
				for (int i = 0; i &lt; len; i++) {
					otherStringArr[counter][i] = nextline[i];
				}
				counter++;
			}
			othercontent.put(&quot;colNum&quot;, len);
			othercontent.put(&quot;rowNum&quot;, counter);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}

	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		try {
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	return null;
}

}

ReadXlsExcel 方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFCell;
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.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.qly.report.operate.facade.IReadExcel;
import com.qly.report.util.ReportUtil;

public class ReadXlsImpl implements IReadExcel{

public static HSSFWorkbook wb = null;
public static HSSFSheet hssfSheet =null;
public static HSSFRow hssfRow = null;
public static XSSFWorkbook xb = null;
public static XSSFSheet xssfSheet =null;
public static XSSFRow xssfRow =null;
public static String qlyStringArr[][] = new String[1000][1000];
public 	static String otherStringArr[][] = new String[1000][1000];
static Map&lt;String,Integer &gt; qlycontent = new HashMap&lt;String,Integer &gt;();
static Map&lt;String,Integer &gt; othercontent = new HashMap&lt;String,Integer &gt;();
@SuppressWarnings({ &quot;deprecation&quot; })
@Override
public Map&lt;String ,Object&gt; readExcel(String path, String flag) {
	int counter = 0;
	try {
		InputStream is = new FileInputStream(new File(path));

		wb = new HSSFWorkbook(is);
		hssfSheet = wb.getSheetAt(0);
		// 得到总行数
		int rowNum = hssfSheet.getLastRowNum();
		hssfRow = hssfSheet.getRow(1);

		int colNum = hssfRow.getPhysicalNumberOfCells();
		// 正文内容应该从第二行开始,第一行为表头内容
		if(&quot;qly&quot;.equals(flag)){
			Map&lt;String,Object&gt;qlyMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				hssfRow = hssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					qlyStringArr[i][counter] = get2003StringCellValue(
							hssfRow.getCell((short)counter)).trim();
					counter++;
				}
			}
			qlycontent.put(&quot;colNum&quot;, counter);
			qlycontent.put(&quot;rowNum&quot;, rowNum);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return  qlyMap;
		}
		if(&quot;other&quot;.equals(flag)){
			Map&lt;String,Object&gt;otherMap = new HashMap&lt;String, Object&gt;();
			for (int i =1; i &lt; rowNum; i++) {
				hssfRow = hssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					otherStringArr[i][counter] = get2003StringCellValue(hssfRow.getCell((short) counter)).trim();
					
					counter++;
				}
			}
			othercontent.put(&quot;colNum&quot;, counter);
			othercontent.put(&quot;rowNum&quot;, rowNum);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}


	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}	
	return null;
}
private static String get2003StringCellValue(HSSFCell cell) {
	String strCell = &quot;&quot;;
	
	if (null == cell) {
		return &quot;&quot;;
	}
	switch (cell.getCellType()) {
	case HSSFCell.CELL_TYPE_STRING:
		strCell = cell.getStringCellValue();
		break;
	case HSSFCell.CELL_TYPE_NUMERIC:
		//使用DecimalFormat类对科学计数法格式的数字进行格式化
		DecimalFormat df = new DecimalFormat(&quot;#&quot;);
		String str = String.valueOf(cell.getNumericCellValue());
		if(ReportUtil.isNumber(str)){
			strCell =  df.format(cell.getNumericCellValue());
		}else{
			strCell = str;
		}
		
		break;
	case HSSFCell.CELL_TYPE_BOOLEAN:
		
		strCell = String.valueOf(cell.getBooleanCellValue());
		break;
	case HSSFCell.CELL_TYPE_BLANK:
		strCell = &quot;&quot;;
		break;
	default:
		strCell = &quot;&quot;;
		break;
	}
	if (strCell.equals(&quot;&quot;) || null == strCell) {
		return &quot;&quot;;
	}
	return strCell;

}

}

ReadXlsxExcel方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

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;

import com.qly.report.operate.facade.IReadExcel;
import com.qly.report.util.ReportUtil;

public class ReadXlsxImpl implements IReadExcel {
public static HSSFWorkbook wb = null;
public static HSSFSheet hssfSheet =null;
public static HSSFRow hssfRow = null;
public static XSSFWorkbook xb = null;
public static XSSFSheet xssfSheet =null;
public static XSSFRow xssfRow =null;
public static String qlyStringArr[][] = new String[1000][1000];
public static String otherStringArr[][] = new String[1000][1000];
static Map<String,Integer > qlycontent = new HashMap<String,Integer >();
static Map<String,Integer > othercontent = new HashMap<String,Integer >();
@Override
public Map<String,Object> readExcel(String path, String flag) {
int counter = 0;
try {
InputStream is = new FileInputStream(new File(path));

		xb = new XSSFWorkbook(is);
		xssfSheet = xb.getSheetAt(0);
		// 得到总行数
		int rowNum = xssfSheet.getLastRowNum();
		xssfRow = xssfSheet.getRow(1);

		int colNum = xssfRow.getPhysicalNumberOfCells();
		// 正文内容应该从第二行开始,第一行为表头内容
		if(&quot;qly&quot;.equals(flag)){
			Map&lt;String,Object&gt;qlyMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				xssfRow = xssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					qlyStringArr[i][counter] = get2007StringCellValue(
							xssfRow.getCell((short) counter)).trim();
					counter++;
				}
			}
			qlycontent.put(&quot;colNum&quot;, counter);
			qlycontent.put(&quot;rowNum&quot;, rowNum);
			qlyMap.put(&quot;qlyStringArr&quot;, qlyStringArr);
			qlyMap.put(&quot;qlycontent&quot;, qlycontent);
			return  qlyMap;
		}
		if(&quot;other&quot;.equals(flag)){
			Map&lt;String,Object&gt;otherMap = new HashMap&lt;String, Object&gt;();
			for (int i = 1; i &lt; rowNum; i++) {
				xssfRow = xssfSheet.getRow(i);
				counter = 0;
				while (counter &lt; colNum) {
					otherStringArr[i][counter] = get2007StringCellValue(
							xssfRow.getCell((short) counter)).trim();
					counter++;
				}
			}
			othercontent.put(&quot;colNum&quot;, counter);
			othercontent.put(&quot;rowNum&quot;, rowNum);
			otherMap.put(&quot;othercontent&quot;, othercontent);
			otherMap.put(&quot;otherStringArr&quot;, otherStringArr);
			return otherMap;
		}
		
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
	return null;
}
private static String get2007StringCellValue(XSSFCell cell) {
	String strCell = &quot;&quot;;
	if (null == cell) {
		return &quot;&quot;;
	}
	switch (cell.getCellType()) {
	case XSSFCell.CELL_TYPE_STRING:
		strCell = cell.getStringCellValue();
		break;
	case XSSFCell.CELL_TYPE_NUMERIC:
		//使用DecimalFormat类对科学计数法格式的数字进行格式化
		
		DecimalFormat df = new DecimalFormat(&quot;#&quot;);
		String str = String.valueOf(cell.getNumericCellValue());
		if(ReportUtil.isNumber(str)){
			strCell =  df.format(cell.getNumericCellValue());
		}else{
			strCell = str;
		}
		
		break;
	case XSSFCell.CELL_TYPE_BOOLEAN:
		strCell = String.valueOf(cell.getBooleanCellValue());
		break;
	case XSSFCell.CELL_TYPE_BLANK:
		strCell = &quot;&quot;;
		break;
	default:
		strCell = &quot;&quot;;
		break;
	}
	if (strCell.equals(&quot;&quot;) || null == strCell) {
		return &quot;&quot;;
	}
	return strCell;

}

}

 

 

CompareExcel方法,比较算法在这里

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.qly.report.operate.facade.ICompareExcel;
import com.qly.report.util.ReportUtil;
/**

  • by guop 2013-7-12 上午 9:11:06

  • 比较 excel
    */
    public class CompareExcelImpl implements ICompareExcel{

    @Override
    public Map<String ,Object> compareExcel(String [][] qlyString, String [][] otherString,
    int[] qlycolumn, int[] othercolumn,
    Map<String,Integer> qlycontent, Map<String,Integer> othercontent,
    int qlyflag, int otherflag, int qlystartRow, int otherstartRow,
    String outReportPath) {

     // 761报表的行数
     int qlyRowNum = qlycontent.get(&quot;rowNum&quot;);
     // 761报表的列数
     int otherRowNum = othercontent.get(&quot;rowNum&quot;);
    
     List&lt;Map&lt;String, Integer&gt;&gt; listErrorStr = new ArrayList&lt;Map&lt;String, Integer&gt;&gt;();
     // 在这里比较下,用a表的标记字段扫描b表从1开始,0为表头
     for (int i = qlystartRow; i &lt; qlyRowNum; i++) {
     	boolean boolflag = false;
     	boolean boolother = true;
     	Map&lt;String, Integer&gt; errorMap = new HashMap&lt;String, Integer&gt;();
    
     	for (int j = otherstartRow; j &lt; otherRowNum; j++) {
     		// 按照配置的标记列,如761中的票号,和腾邦的票号
     		// 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0
     		if (ReportUtil.handleSpecialCharacter(qlyString[i][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[j][otherflag].trim()))) {
     			boolother = false;
     			int rowother = j;
     			// 在寻找到b表中,有相同的字段后,比较其他字段是否相同
     			for (int a1 = 0; a1 &lt; qlycolumn.length;a1++) {
     				if(null == qlyString[i][qlycolumn[a1]] || null == otherString[rowother][othercolumn[a1]]){
     					break;
     				}
    
     				// 当a表和b表中的 票面号相同,比较里面的规定的字段的值是否相同
     					if (!ReportUtil.handleSpecialCharacter(qlyString[i][qlycolumn[a1]].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[rowother][othercolumn[a1]].trim()))) {
     						errorMap.put(&quot;qlylinenumber&quot;, i);
     						errorMap.put(&quot;otherlinenumber&quot;, rowother);
     						listErrorStr.add(errorMap);
     						boolflag = true;
     						break;
     					} 
     				}
    
     			if (boolflag) {
     				break;
     			}
     		}
     	}
     	if (boolother) {
     		errorMap.put(&quot;qlylinenumber&quot;, i);
     		listErrorStr.add(errorMap);
     	}
     }
     //用b表扫描a表的某一个字段
     		// 在这里比较下,用a表的标记字段扫描b表
     for (int i = otherstartRow; i &lt; otherRowNum; i++) {
     	boolean boolother = true;
     	Map&lt;String, Integer&gt; errorMap = new HashMap&lt;String, Integer&gt;();
     	for (int j = qlystartRow; j &lt; qlyRowNum; j++) {
    
     		// 按照配置的标记列,如761中的票号,和腾邦的票号
     		// 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0
     		if (ReportUtil.handleSpecialCharacter(qlyString[j][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[i][otherflag].trim()))) {
     			boolother = false;
     			// 在寻找到b表中,有相同的字段后,比较其他字段是否相同
     		}
     	}
     	if (boolother) {
     		errorMap.put(&quot;otherlinenumber&quot;, i);
     		listErrorStr.add(errorMap);
     	}
     }
    
     Map&lt;String,Object&gt; compareMap = new HashMap&lt;String, Object&gt;();
     compareMap.put(&quot;listErrorStr&quot;, listErrorStr);
    

    return compareMap;
    }

}

全部代码在这里,github,请多多指教

  • POI
    22 引用 • 21 回帖
  • Excel
    30 引用 • 28 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3165 引用 • 8206 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone

    老船长这个不是专栏是博客吧。哈哈。专栏不是这个意思吧。

推荐标签 标签

  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖 • 1 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 6 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 124 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 618 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    16 引用 • 53 回帖 • 104 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    475 引用 • 899 回帖 • 1 关注
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 676 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    5 引用 • 26 回帖 • 489 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 39 关注
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 87 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 249 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    198 引用 • 120 回帖
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 408 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    284 引用 • 4481 回帖 • 652 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 383 回帖
  • 安全

    安全永远都不是一个小问题。

    189 引用 • 813 回帖 • 2 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 426 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    529 引用 • 3527 回帖 • 2 关注
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    25 引用 • 215 回帖 • 163 关注
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 34 关注
  • sts
    2 引用 • 2 回帖 • 142 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 405 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 339 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 41 关注