引入七牛云 js 上传

本贴最后更新于 2774 天前,其中的信息可能已经沧海桑田

云存储有很多种方式,这里介绍前端页面直接通过 js 上传的方式,应为这种方式页面友好,对浏览器压力也小

云存储也有很多好处:

1、释放服务器磁盘空间

2、减轻服务器磁盘 IO 压力

3、减轻服务器带宽压力

4、服务器故障无影响

遇到的坑:

1、bad uptoken

2、error:incorrect zone, please use up-z2.qiniu.com

3、怎样获取文件名

4、怎样设置上传路径

5、怎样获取外部链接

6、怎样获取上传进度

bad uptoken:

在官方文档里面,七牛要求服务器返回 uptoken 格式为

|

1

2

3

|

{

"uptoken"``: ``"0MLvWPnyya1WtPnXFy9KLyGHyFPNdZceomL..."

}

|

但是这很模糊,试了几次都提示 bad token,最终在 uploader 的 uptoken 里应该直接写入字符串格式,如果是服务器返回的的 uptoken 请去掉两端的双引号,否则报错

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

|

function getTokenMessage() {

var token;

$.ajax({

url:``"http://localhost:8080/LRVideo/appservice/basic/getJSUpToken"``,

async:``false``,

success:``function (data) {

token = data;

}

})

return token;

}

var token = getTokenMessage();

uptoken = token.substring(token.indexOf(``"\""``)+1,token.lastIndexOf(``"\""``));

|

error:incorrect zone, please use up-z2.qiniu.com:

七牛官方 js 默认上传地区为华东地区,如果不是华东的则需要修改官方 js

怎样获取文件名

|

1

2

3

4

5

6

7

8

|

'Key'``: ``function``(up, file) {

// 若想在前端对每个文件的key进行个性化处理,可以配置该函数

// 该配置必须要在unique_names: false,save_key: false时才生效

var Date = getNowFormatDate();

var fileName = file.name;

console.log(``"filename" + file.name);

return key

}

|

怎样设置上传路径:

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

|

function getNowFormatDate() {

var myDate = ``new Date();

var year = myDate.getFullYear();

var month = myDate.getMonth() + 1;

var day = myDate.getDate();

var hour = myDate.getHours();

var min = myDate.getMinutes();

var second = myDate.getSeconds();

if (month >= 0 && month <= 9) {

month = ``"0" + month;

}

if (day >= 0 && day <= 9) {

day = ``"0" + day;

}

if (hour >= 0 && hour <= 9) {

hour = ``"0" + hour;

}

if (min >= 0 && min <= 9) {

min = ``"0" + min;

}

if (second >= 0 && second <= 9) {

second = ``"0" + second;

}

var currentdate = year + ``"/" + month + ``"/" + day + ``"/" + hour + ``"/" + min + ``"/" + second;

return currentdate;

}

'Key'``: ``function``(up, file) {

// 若想在前端对每个文件的key进行个性化处理,可以配置该函数

// 该配置必须要在unique_names: false,save_key: false时才生效

var Date = getNowFormatDate();

var fileName = file.name;

var key = getNowFormatDate() + ``"/" + file.name;

// do something with key here

return key

}

|

怎样获取外部链接:

这里首先需要将 uploader 的 domain 设置一下:

|

1

|

domain: ``'http://onsoxm2o9.bkt.clouddn.com'``, // bucket域名,下载资源时用到,必需

|

请参照该存储空间的外链默认域名,可自行修改

|

1

2

3

4

5

6

7

8

9

10

11

12

13

|

'FileUploaded'``: ``function``(up, file, info) {

// 每个文件上传成功后,处理相关的事情

// 其中info是文件上传成功后,服务端返回的json,形式如:

// {

// "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",

// "key": "gogopher.jpg"

// }

// 查看简单反馈

var domain = up.getOption(``'domain'``);

var res = JSON.parse(info);

sourceLink = domain +``"/"``+ res.key; ``//获取上传成功后的文件的Url

console.log(``"sourceLink:" + sourceLink);

},

|

怎样获取上传进度:

|

1

2

3

4

5

6

|

'UploadProgress'``: ``function``(up, file) {

var progress = ``new FileProgress(file, ``'fsUploadProgress'``);

var chunk_size = plupload.parseSize(``this``.getOption(``'chunk_size'``));

progress.setProgress(file.percent + ``"%"``, file.speed, chunk_size);

console.log(``"Progress:" + file.percent + ``"%"``);

},

|

这里用到了 new FileProgress 函数,需要引入官方文档 demo 里的 ui.js 文件

QiniuUtils

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

|

package com.utils.qiniu;

import java.io.IOException;

import com.qiniu.common.QiniuException;

import com.qiniu.common.Zone;

import com.qiniu.http.Response;

import com.qiniu.storage.Configuration;

import com.qiniu.storage.UploadManager;

import com.qiniu.util.Auth;

import com.qiniu.util.StringMap;

/**

* 七牛上传工具

*

*/

public class QiniuUtils {

//设置好账号的ACCESS_KEY和SECRET_KEY

String ACCESS_KEY = ``"EybSUWG7TpxDnHze3FeYG5Dk9YzceUnITeAUIkQH"``;

String SECRET_KEY = ``"IcyUqBR2Jm5oAoeAkeMNN_hG4IRclDkRL0TMYGdv"``;

//要上传的空间

String bucketname = ``"cczb"``;

String bucketname2 = ``"cczb-video"``;

//密钥配置

Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);

///////////////////////指定上传的Zone的信息//////////////////

//第一种方式: 指定具体的要上传的zone

//注:该具体指定的方式和以下自动识别的方式选择其一即可

//要上传的空间(bucket)的存储区域为华东时

// Zone z = Zone.zone0();

//要上传的空间(bucket)的存储区域为华北时

// Zone z = Zone.zone1();

//要上传的空间(bucket)的存储区域为华南时

//Zone z = Zone.zone2();

//第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。

Zone z = Zone.autoZone();

Configuration c = ``new Configuration(z);

//创建上传对象

UploadManager uploadManager = ``new UploadManager(c);

//简单上传,使用默认策略,只需要设置上传的空间名就可以了

public String getUpToken() {

return auth.uploadToken(bucketname);

}

//js上传

//scope通过 bucket、key间接设置,deadline 通过 expires 间接设置

public String getJSUpToken() {

return auth.uploadToken(bucketname2);

}

public static void main(String[] args) {

StringMap policy = ``new StringMap().put(``"deadline"``, ``1491159381``).put(``"saveKey"``, ``"qiangge.jpg"``);

Auth auth = Auth.create(``"EybSUWG7TpxDnHze3FeYG5Dk9YzceUnITeAUIkQH"``, ``"IcyUqBR2Jm5oAoeAkeMNN_hG4IRclDkRL0TMYGdv"``);

System.err.println(auth.uploadToken(``"cczb-video:aaaaaaaa.jpg"``, ``"qiange2.jpg"``, ``3600``, policy));

}

/**

* 上传文件

* @author WangQiang 2017年2月10日 下午1:09:00

* @version 出彩V直播2.0

* @param FilePath 上传文件的真实路径

* @param key 上传到七牛后保存的文件名(可以包含路径),如 /test/test.png

* @return

*/

public boolean uploadFIle(String FilePath ,String key){

boolean flag = ``false``;

try {

//调用put方法上传

Response res = uploadManager.put(FilePath, key, getUpToken());

//上传成功

if``(res.statusCode == ``200``){

flag = ``true``;

System.out.println(``"七牛上传文件成功:" + res.bodyString());

}``else``{

flag = ``false``;

System.out.println(``"七牛上传文件失败(七牛原因或者七牛的配置原因):" + res.bodyString());

}

} ``catch (QiniuException e) {

Response r = e.response;

// 请求失败时打印的异常的信息

System.out.println(``"七牛上传文件失败(自己原因):" + r.toString());

try {

//响应的文本信息

System.out.println(r.bodyString());

} ``catch (QiniuException e1) {

//ignore

}

}

return flag;

}

//上传测试

public void uploadTest(String FilePath , String key) ``throws IOException {

try {

//调用put方法上传

Response res = uploadManager.put(FilePath, key, getUpToken());

//打印返回的信息

System.out.println(res.bodyString());

System.out.println(res.statusCode);

// System.out.println(res.toString());

if``(res.statusCode == ``200``){

System.out.println(``"上传成功"``);

}``else {

System.out.println(``"上传失败:" + res.bodyString());

}

} ``catch (QiniuException e) {

Response r = e.response;

// 请求失败时打印的异常的信息

System.out.println(r.toString());

try {

//响应的文本信息

System.out.println(r.bodyString());

} ``catch (QiniuException e1) {

//ignore

}

}

}

}

|

获取 uptoken

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

|

@RequestMapping``(value = ``"/uploadFile"``)

@ResponseBody

public Object uploadFile(HttpServletRequest request, HttpServletResponse response,

@RequestParam``(value = ``"file"``, required = ``false``) MultipartFile file) ``throws IOException {

// TODO 文件上传接口

String fileName = file.getOriginalFilename();

Map m = ``new HashMap();

BufferedOutputStream outputStream = ``null``;

try {

InputStream fileInputStream = file.getInputStream();

String datefolder = ``"/" + DateUtil.dateToString(``new Date(), ``"yyyy"``) + ``"/"

+ DateUtil.dateToString(``new Date(), ``"MM"``) + ``"/"

+ DateUtil.dateToString(``new Date(), ``"dd" + ``"/" + (Integer.parseInt(DateUtil.dateToString(``new Date(), ``"hh"``))+``0``) )

+ DateUtil.dateToString(``new Date(), ``"mm" + DateUtil.dateToString(``new Date(), ``"ss"``));``// 日期命名的文件夹

String webParentPath = ``new File(request.getSession().getServletContext().getRealPath(``"/"``)).getParent()

.replace(``"\\"``, ``"/"``);``// 当前WEB环境的上层目录

String realPath = webParentPath + ``"/gcrcsUploadFile" + datefolder;``// 文件上传到服务器的真实路径

File up = ``new File(realPath);

if (!up.exists()) {

up.mkdirs();

}

String newFileName = fileName;

String filePath = ``"/gcrcsUploadFile" + datefolder + ``"/" + newFileName;

outputStream = ``new BufferedOutputStream(``new FileOutputStream(``new File(realPath, newFileName)));

IOUtils.copy(fileInputStream, outputStream);

//这两个流一定要关闭,不然接下来上传到七牛上文件会缺失

fileInputStream.close();

outputStream.close();

logger.error(``"文件在服务器的绝对路径:"``+ ``new File(realPath, newFileName).toString());

logger.error(``"文件在服务器的相对路径:" + filePath);

// ++++++++上传文件到七牛 +++++++++

boolean flag = ``new QiniuUtils().uploadFIle( ``new File(realPath, newFileName).toString().replace(``"\\"``, ``"/"``) , filePath);

Map data = ``new HashMap();

// 保存附件

data.put(``"picUrl"``, filePath);

data.put(``"videoUrl"``, filePath);

m.put(``"status"``, ``0``);

m.put(``"msg"``, ``"上传成功"``);

m.put(``"data"``, data);

if``(flag){

logger.error(``"++++++++++ 上传文件" + filePath + ``"到七牛【成功】 ++++++++++"``);

//后期上传到云 成功 后把上传到本地的删除

}``else``{

m.put(``"status"``, ``1``);

m.put(``"msg"``, ``"上传失败"``);

m.put(``"data"``, data);

logger.error(``"++++++++++ 上传文件到七牛【失败】 ++++++++++"``);

}

} ``catch (Exception e) {

logger.error(``"error on deploy process, because of file input stream"``, e);

} ``finally {

outputStream.flush();

outputStream.close();

}

return m;

}

/**

* 七牛云上传获得uptoken

* @author wanningxi

* @return

*/

@ResponseBody

@RequestMapping``(``"/getJSUpToken"``)

public Object getJSUpToken() {

logger.error(``"获取七牛UpToken"``);

Map map = ``new HashMap();

try {

return new QiniuUtils().getJSUpToken();

} ``catch (Exception e) {

e.printStackTrace();

logger.error(``"Exception : " + e);

return ResultMapUtils.systemError(e);

}

}

|

qiniuTest.jsp

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

|

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">`

<``html``>

<``head``>

<``meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<``title``>七牛云测试

<%-- 引入qiniu扩展 --%>

<``script src="${pageContext.request.contextPath}/resources/js/qiniu/jquery.min.js" type="text/javascript" charset="utf-8">

<%-- <``script src="${pageContext.request.contextPath}/resources/js/qiniu/moxie.js" type="text/javascript" charset="utf-8"> --%>

<%-- <``script src="${pageContext.request.contextPath}/resources/js/qiniu/plupload.full.min.js" type="text/javascript" charset="utf-8"> --%>

<%-- <``script src="${pageContext.request.contextPath}/resources/js/qiniu/qiniu.js" type="text/javascript" charset="utf-8"> --%>

<``script type="text/javascript" src="https://cdn.staticfile.org/plupload/2.1.8/plupload.full.min.js">

<``script type="text/javascript" src="https://cdn.staticfile.org/plupload/2.1.9/moxie.min.js">

<``script type="text/javascript" src="https://cdn.staticfile.org/qiniu-js-sdk/1.0.14-beta/qiniu.min.js">

<``script src="${pageContext.request.contextPath}/resources/js/qiniu/ui.js" type="text/javascript" charset="utf-8">

``

<``body``>

<``p class="tip1">本demo实现的图片预览功能需要浏览器支持data URL,IE8+以及其他标准浏览器都是支持的

<``div id="container">

<``a class="btn btn-default btn-lg " id="pickfiles" style="width:160px" href="#" >

<``i class="glyphicon glyphicon-plus">

<``span``>选择文件

``

``

``

``

<``script type="text/javascript">

var time = getNowFormatDate();

var token = getTokenMessage();

uptoken = token.substring(token.indexOf("\"")+1,token.lastIndexOf("\""));

var uploader = Qiniu.uploader({

runtimes: 'html5,flash,html4', // 上传模式,依次退化

browse_button: 'pickfiles', // 上传选择的点选按钮,必需

// 在初始化时,uptoken,uptoken_url,uptoken_func三个参数中必须有一个被设置

// 切如果提供了多个,其优先级为uptoken > uptoken_url > uptoken_func

// 其中uptoken是直接提供上传凭证,uptoken_url是提供了获取上传凭证的地址,如果需要定制获取uptoken的过程则可以设置uptoken_func

uptoken : uptoken, // uptoken是上传凭证,由其他程序生成

// uptoken_url: 'http://localhost:8080/LRVideo/appservice/basic/getJSUpToken', // Ajax请求uptoken的Url,强烈建议设置(服务端提供)

// uptoken_func: function(file){ // 在需要获取uptoken时,该方法会被调用

// // do something

// return uptoken;

// },

get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的uptoken

// downtoken_url: '/downtoken',

// Ajax请求downToken的Url,私有空间时使用,JS-SDK将向该地址POST文件的key和domain,服务端返回的JSON必须包含url字段,url值为该文件的下载地址

// unique_names: true, // 默认false,key为文件名。若开启该选项,JS-SDK会为每个文件自动生成key(文件名)

// save_key: true, // 默认false。若在服务端生成uptoken的上传策略中指定了sava_key,则开启,SDK在前端将不对key进行任何处理

domain: 'http://onsoxm2o9.bkt.clouddn.com', // bucket域名,下载资源时用到,必需

container: 'container', // 上传区域DOM ID,默认是browser_button的父元素

max_file_size: '100000mb', // 最大文件体积限制

flash_swf_url: 'path/of/plupload/Moxie.swf', //引入flash,相对路径

max_retries: 3, // 上传失败最大重试次数

dragdrop: true, // 开启可拖曳上传

drop_element: 'container', // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传

chunk_size: '0mb', // 分块上传时,每块的体积

auto_start: true, // 选择文件后自动上传,若关闭需要自己绑定事件触发上传

//x_vars : {

// 查看自定义变量

// 'time' : function(up,file) {

// var time = (new Date()).getTime();

// do something with 'time'

// return time;

// },

// 'size' : function(up,file) {

// var size = file.size;

// do something with 'size'

// return size;

// }

//},

init: {

'FilesAdded': function(up, files) {

plupload.each(files, function(file) {

// 文件添加进队列后,处理相关的事情

});

},

'BeforeUpload': function(up, file) {

// 每个文件上传前,处理相关的事情

},

'UploadProgress': function(up, file) {

var progress = new FileProgress(file, 'fsUploadProgress');

var chunk_size = plupload.parseSize(this.getOption('chunk_size'));

progress.setProgress(file.percent + "%", file.speed, chunk_size);

console.log("Progress:" + file.percent + "%");

},

'FileUploaded': function(up, file, info) {

// 每个文件上传成功后,处理相关的事情

// 其中info是文件上传成功后,服务端返回的json,形式如:

// {

// "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",

// "key": "gogopher.jpg"

// }

// 查看简单反馈

var domain = up.getOption('domain');

var res = JSON.parse(info);

sourceLink = domain +"/"+ res.key; //获取上传成功后的文件的Url

console.log("sourceLink:" + sourceLink);

},

'Error': function(up, err, errTip) {

//上传出错时,处理相关的事情

},

'UploadComplete': function() {

//队列文件处理完毕后,处理相关的事情

},

'Key': function(up, file) {

// 若想在前端对每个文件的key进行个性化处理,可以配置该函数

// 该配置必须要在unique_names: false,save_key: false时才生效

var Date = getNowFormatDate();

var fileName = file.name;

var key = getNowFormatDate() + "/" + file.name;

// do something with key here

return key

}

}

});

// domain为七牛空间对应的域名,选择某个空间后,可通过 空间设置->基本设置->域名设置 查看获取

// uploader为一个plupload对象,继承了所有plupload的方法

function getTokenMessage() {

var token;

$.ajax({

url:"http://localhost:8080/LRVideo/appservice/basic/getJSUpToken",

async:false,

success:function (data) {

token = data;

}

})

return token;

}

function getNowFormatDate() {

var myDate = new Date();

var year = myDate.getFullYear();

var month = myDate.getMonth() + 1;

var day = myDate.getDate();

var hour = myDate.getHours();

var min = myDate.getMinutes();

var second = myDate.getSeconds();

if (month >= 0 && month <= 9) {

month = "0" + month;

}

if (day >= 0 && day <= 9) {

day = "0" + day;

}

if (hour >= 0 && hour <= 9) {

hour = "0" + hour;

}

if (min >= 0 && min <= 9) {

min = "0" + min;

}

if (second >= 0 && second <= 9) {

second = "0" + second;

}

var currentdate = year + "/" + month + "/" + day + "/" + hour + "/" + min + "/" + second;

return currentdate;

}

``

|

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1327 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 22 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 742 关注
  • Java

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

    3187 引用 • 8213 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 232 回帖 • 2 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 62 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    190 引用 • 1057 回帖
  • 安全

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

    199 引用 • 816 回帖 • 1 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 1 关注
  • 电影

    这是一个不能说的秘密。

    120 引用 • 599 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 531 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    47 引用 • 25 回帖 • 1 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 99 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 362 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 471 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 18 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖 • 1 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    17 引用 • 236 回帖 • 328 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    107 引用 • 295 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 384 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    32 引用 • 130 回帖 • 2 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    12 引用 • 54 回帖 • 63 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖