Java 文件上传下载

本贴最后更新于 3324 天前,其中的信息可能已经东海扬尘

在 Web 应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下 JavaWeb 中的文件上传和下载功能的实现。

  对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 Servlet 获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用 apache 的开源工具 common-fileupload 这个文件上传组件。这个 common-fileupload 上传组件的 jar 包可以去 apache 官网上面下载,也可以在 struts 的 lib 文件夹下面找到,struts 上传的功能就是基于这个实现的。common-fileupload 是依赖于 common-io 这个包的,所以还需要下载这个包。

一、开发环境搭建

  创建一个 FileUploadAndDownLoad 项目,加入 Apache 的 commons-fileupload 文件上传组件的相关 Jar 包,如下图所示:

  

二、实现文件上传

2.1、文件上传页面和消息提示页面

upload.jsp 页面的代码如下:

?

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

|

<%@ page language=``"java" pageEncoding=``"UTF-8"``%>

``

``

``

文件上传

``

``

``

上传用户:

上传文件1:

上传文件2:

``

``

``

``

|

message.jsp 的代码如下:

?

|

1

2

3

4

5

6

7

8

9

10

11

|

<%@ page language=``"java" pageEncoding=``"UTF-8"``%>

``

``

``

消息提示

``

``

${message}

``

``

|

2.2、处理文件上传的 Servlet

UploadHandleServlet 的代码如下:

?

|

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

|

package me.gacl.web.controller;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadHandleServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全

String savePath = this``.getServletContext().getRealPath(``"/WEB-INF/upload"``);

File file = new File(savePath);

//判断上传文件的保存目录是否存在

if (!file.exists() && !file.isDirectory()) {

System.out.println(savePath+``"目录不存在,需要创建"``);

//创建目录

file.mkdir();

}

//消息提示

String message = ""``;

try``{

//使用Apache文件上传组件处理文件上传步骤:

//1、创建一个DiskFileItemFactory工厂

DiskFileItemFactory factory = new DiskFileItemFactory();

//2、创建一个文件上传解析器

ServletFileUpload upload = new ServletFileUpload(factory);

//解决上传文件名的中文乱码

upload.setHeaderEncoding(``"UTF-8"``);

//3、判断提交上来的数据是否是上传表单的数据

if``(!ServletFileUpload.isMultipartContent(request)){

//按照传统方式获取数据

return``;

}

//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List集合,每一个FileItem对应一个Form表单的输入项

List list = upload.parseRequest(request);

for``(FileItem item : list){

//如果fileitem中封装的是普通输入项的数据

if``(item.isFormField()){

String name = item.getFieldName();

//解决普通输入项的数据的中文乱码问题

String value = item.getString(``"UTF-8"``);

//value = new String(value.getBytes("iso8859-1"),"UTF-8");

System.out.println(name + "=" + value);

}``else``{``//如果fileitem中封装的是上传文件

//得到上传的文件名称,

String filename = item.getName();

System.out.println(filename);

if``(filename==``null || filename.trim().equals(``""``)){

continue``;

}

//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt

//处理获取到的上传文件的文件名的路径部分,只保留文件名部分

filename = filename.substring(filename.lastIndexOf(``"\\"``)+``1``);

//获取item中的上传文件的输入流

InputStream in = item.getInputStream();

//创建一个文件输出流

FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);

//创建一个缓冲区

byte buffer[] = new byte``[``1024``];

//判断输入流中的数据是否已经读完的标识

int len = 0``;

//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据

while``((len=in.read(buffer))>``0``){

//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中

out.write(buffer, 0``, len);

}

//关闭输入流

in.close();

//关闭输出流

out.close();

//删除处理文件上传时生成的临时文件

item.delete();

message = "文件上传成功!"``;

}

}

}``catch (Exception e) {

message= "文件上传失败!"``;

e.printStackTrace();

}

request.setAttribute(``"message"``,message);

request.getRequestDispatcher(``"/message.jsp"``).forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

|

在 Web.xml 文件中注册 UploadHandleServlet

?

|

1

2

3

4

5

6

7

8

9

|

<``servlet``>

<``servlet-name``>UploadHandleServlet

<``servlet-class``>me.gacl.web.controller.UploadHandleServlet

``

<``servlet-mapping``>

<``servlet-name``>UploadHandleServlet

<``url-pattern``>/servlet/UploadHandleServlet

``

|

运行效果如下:

  

文件上传成功之后,上传的文件保存在了 WEB-INF 目录下的 upload 目录,如下图所示:

  

2.3、文件上传的细节

  上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的

  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于 WEB-INF 目录下。

  2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  3、为防止一个目录下面出现太多文件,要使用 hash 算法打散存储。

  4、要限制上传文件的最大值。

  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

  针对上述提出的 5 点细节问题,我们来改进一下 UploadHandleServlet,改进后的代码如下:

?

|

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

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

|

package me.gacl.web.controller;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.List;

import java.util.UUID;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.FileUploadBase;

import org.apache.commons.fileupload.ProgressListener;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**

* @ClassName: UploadHandleServlet

* @Description: TODO(这里用一句话描述这个类的作用)

* @author: 孤傲苍狼

* @date: 2015-1-3 下午11:35:50

*

*/

public class UploadHandleServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全

String savePath = this``.getServletContext().getRealPath(``"/WEB-INF/upload"``);

//上传时生成的临时文件保存目录

String tempPath = this``.getServletContext().getRealPath(``"/WEB-INF/temp"``);

File tmpFile = new File(tempPath);

if (!tmpFile.exists()) {

//创建临时目录

tmpFile.mkdir();

}

//消息提示

String message = ""``;

try``{

//使用Apache文件上传组件处理文件上传步骤:

//1、创建一个DiskFileItemFactory工厂

DiskFileItemFactory factory = new DiskFileItemFactory();

//设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。

factory.setSizeThreshold(``1024``*``100``);``//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB

//设置上传时生成的临时文件的保存目录

factory.setRepository(tmpFile);

//2、创建一个文件上传解析器

ServletFileUpload upload = new ServletFileUpload(factory);

//监听文件上传进度

upload.setProgressListener(``new ProgressListener(){

public void update(``long pBytesRead, long pContentLength, int arg2) {

System.out.println(``"文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);

/**

* 文件大小为:14608,当前已处理:4096

文件大小为:14608,当前已处理:7367

文件大小为:14608,当前已处理:11419

文件大小为:14608,当前已处理:14608

*/

}

});

//解决上传文件名的中文乱码

upload.setHeaderEncoding(``"UTF-8"``);

//3、判断提交上来的数据是否是上传表单的数据

if``(!ServletFileUpload.isMultipartContent(request)){

//按照传统方式获取数据

return``;

}

//设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB

upload.setFileSizeMax(``1024``*``1024``);

//设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB

upload.setSizeMax(``1024``*``1024``*``10``);

//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List集合,每一个FileItem对应一个Form表单的输入项

List list = upload.parseRequest(request);

for``(FileItem item : list){

//如果fileitem中封装的是普通输入项的数据

if``(item.isFormField()){

String name = item.getFieldName();

//解决普通输入项的数据的中文乱码问题

String value = item.getString(``"UTF-8"``);

//value = new String(value.getBytes("iso8859-1"),"UTF-8");

System.out.println(name + "=" + value);

}``else``{``//如果fileitem中封装的是上传文件

//得到上传的文件名称,

String filename = item.getName();

System.out.println(filename);

if``(filename==``null || filename.trim().equals(``""``)){

continue``;

}

//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt

//处理获取到的上传文件的文件名的路径部分,只保留文件名部分

filename = filename.substring(filename.lastIndexOf(``"\\"``)+``1``);

//得到上传文件的扩展名

String fileExtName = filename.substring(filename.lastIndexOf(``"."``)+``1``);

//如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法

System.out.println(``"上传的文件的扩展名是:"``+fileExtName);

//获取item中的上传文件的输入流

InputStream in = item.getInputStream();

//得到文件保存的名称

String saveFilename = makeFileName(filename);

//得到文件的保存目录

String realSavePath = makePath(saveFilename, savePath);

//创建一个文件输出流

FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);

//创建一个缓冲区

byte buffer[] = new byte``[``1024``];

//判断输入流中的数据是否已经读完的标识 int len = 0;

//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据

while``((len=in.read(buffer))>``0``){

//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中

out.write(buffer, 0``, len);

}

//关闭输入流

in.close();

//关闭输出流

out.close(); //删除处理文件上传时生成的临时文件 //item.delete(); message = "文件上传成功!";

}

}

}``catch (FileUploadBase.FileSizeLimitExceededException e) {

e.printStackTrace();

request.setAttribute(``"message"``, "单个文件超出最大值!!!"``);

request.getRequestDispatcher(``"/message.jsp"``).forward(request, response);

return``;

}``catch (FileUploadBase.SizeLimitExceededException e) {

e.printStackTrace();

request.setAttribute(``"message"``, "上传文件的总的大小超出限制的最大值!!!"``);

request.getRequestDispatcher(``"/message.jsp"``).forward(request, response);

return``;

}``catch (Exception e) {

message= "文件上传失败!"``;

e.printStackTrace();

}

request.setAttribute(``"message"``,message);

request.getRequestDispatcher(``"/message.jsp"``).forward(request, response);

}

/**

* @Method: makeFileName

* @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称

* @Anthor:孤傲苍狼

* @param filename 文件的原始名称

* @return uuid+"_"+文件的原始名称

*/

private String makeFileName(String filename){ //2.jpg

//为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名

return UUID.randomUUID().toString() + "_" + filename;

}

/**

* 为防止一个目录下面出现太多文件,要使用hash算法打散存储

* @Method: makePath

* @Description:

* @Anthor:孤傲苍狼

*

* @param filename 文件名,要根据文件名生成存储目录

* @param savePath 文件存储路径

* @return 新的存储目录

*/

private String makePath(String filename,String savePath){

//得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址

int hashcode = filename.hashCode();

int dir1 = hashcode&``0xf``; //0--15

int dir2 = (hashcode&``0xf0``)>>``4``; //0-15

//构造新的保存目录

String dir = savePath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5

//File既可以代表文件也可以代表目录 File file = new File(dir);

//如果目录不存在

if``(!file.exists()){

//创建目录

file.mkdirs();

}

return dir;

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

|

针对上述提出的 5 点小细节问题进行改进之后,我们的文件上传功能就算是做得比较完善了。

三、文件下载

3.1、列出提供下载的文件资源

  我们要将 Web 应用系统中的文件资源提供给用户进行下载,首先我们要有一个页面列出上传文件目录下的所有文件,当用户点击文件下载超链接时就进行下载操作,编写一个 ListFileServlet,用于列出 Web 应用系统中所有下载文件。

ListFileServlet 的代码如下:

?

|

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

|

package me.gacl.web.controller;

import java.io.File;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

/**

* @ClassName: ListFileServlet

* @Description: 列出Web系统中所有下载文件

* @author: 孤傲苍狼

* @date: 2015-1-4 下午9:54:40

*

*/

public class ListFileServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//获取上传文件的目录

String uploadFilePath = this``.getServletContext().getRealPath(``"/WEB-INF/upload"``);

//存储要下载的文件名

Map fileNameMap = new HashMap();

//递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中

listfile(``new File(uploadFilePath),fileNameMap);``//File既可以代表一个文件也可以代表一个目录

//将Map集合发送到listfile.jsp页面进行显示

request.setAttribute(``"fileNameMap"``, fileNameMap);

request.getRequestDispatcher(``"/listfile.jsp"``).forward(request, response);

}

/**

* @Method: listfile

* @Description: 递归遍历指定目录下的所有文件

* @Anthor:孤傲苍狼

* @param file 即代表一个文件,也代表一个文件目录

* @param map 存储文件名的Map集合

*/

public void listfile(File file,Map map){

//如果file代表的不是一个文件,而是一个目录

if``(!file.isFile()){

//列出该目录下的所有文件和目录

File files[] = file.listFiles();

//遍历files[]数组

for``(File f : files){

//递归

listfile(f,map);

}

}``else``{

/**

* 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分

file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:9349249849-88343-8344_阿_凡_达.avi

那么file.getName().substring(file.getName().indexOf("_")+1)处理之后就可以得到阿_凡_达.avi部分

*/

String realName = file.getName().substring(file.getName().indexOf(``"_"``)+``1``);

//file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复

map.put(file.getName(), realName);

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

|

这里简单说一下 ListFileServlet 中 listfile 方法,listfile 方法是用来列出目录下的所有文件的,listfile 方法内部用到了递归,在实际开发当中,我们肯定会在数据库创建一张表,里面会存储上传的文件名以及文件的具体存放目录,我们通过查询表就可以知道文件的具体存放目录,是不需要用到递归操作的,这个例子是因为没有使用数据库存储上传的文件名和文件的具体存放位置,而上传文件的存放位置又使用了散列算法打散存放,所以需要用到递归,在递归时,将获取到的文件名存放到从外面传递到 listfile 方法里面的 Map 集合当中,这样就可以保证所有的文件都存放在同一个 Map 集合当中。

在 Web.xml 文件中配置 ListFileServlet

?

|

1

2

3

4

5

6

7

8

9

|

<``servlet``>

<``servlet-name``>ListFileServlet

<``servlet-class``>me.gacl.web.controller.ListFileServlet

``

<``servlet-mapping``>

<``servlet-name``>ListFileServlet

<``url-pattern``>/servlet/ListFileServlet

``

|

展示下载文件的 listfile.jsp 页面如下:

?

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

|

<%@ page language=``"java" import=``"java.util.*" pageEncoding=``"UTF-8"``%>

<%@taglib prefix=``"c" uri=``"[http://java.sun.com/jsp/jstl/core](http://java.sun.com/jsp/jstl/core)" %>

``

``

``

下载文件显示页面

``

``

``

``

``

``

``

${me.value}下载

``

``

``

``

|

访问 ListFileServlet,就可以在 listfile.jsp 页面中显示提供给用户下载的文件资源,如下图所示:

  

3.2、实现文件下载

编写一个用于处理文件下载的 Servlet,DownLoadServlet 的代码如下:

?

|

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

|

package me.gacl.web.controller;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.net.URLEncoder;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class DownLoadServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//得到要下载的文件名

String fileName = request.getParameter(``"filename"``); //23239283-92489-阿凡达.avi

fileName = new String(fileName.getBytes(``"iso8859-1"``),``"UTF-8"``);

//上传的文件都是保存在/WEB-INF/upload目录下的子目录当中

String fileSaveRootPath=``this``.getServletContext().getRealPath(``"/WEB-INF/upload"``);

//通过文件名找出文件的所在目录

String path = findFileSavePathByFileName(fileName,fileSaveRootPath);

//得到要下载的文件

File file = new File(path + "\\" + fileName);

//如果文件不存在

if``(!file.exists()){

request.setAttribute(``"message"``, "您要下载的资源已被删除!!"``);

request.getRequestDispatcher(``"/message.jsp"``).forward(request, response);

return``;

}

//处理文件名

String realname = fileName.substring(fileName.indexOf(``"_"``)+``1``);

//设置响应头,控制浏览器下载该文件

response.setHeader(``"content-disposition"``, "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"``));

//读取要下载的文件,保存到文件输入流

FileInputStream in = new FileInputStream(path + "\\" + fileName);

//创建输出流

OutputStream out = response.getOutputStream();

//创建缓冲区

byte buffer[] = new byte``[``1024``];

int len = 0``;

//循环将输入流中的内容读取到缓冲区当中

while``((len=in.read(buffer))>``0``){

//输出缓冲区的内容到浏览器,实现文件下载

out.write(buffer, 0``, len);

}

//关闭文件输入流

in.close();

//关闭输出流

out.close();

}

/**

* @Method: findFileSavePathByFileName

* @Description: 通过文件名和存储上传文件根目录找出要下载的文件的所在路径

* @Anthor:孤傲苍狼

* @param filename 要下载的文件名

* @param saveRootPath 上传文件保存的根目录,也就是/WEB-INF/upload目录

* @return 要下载的文件的存储目录

*/

public String findFileSavePathByFileName(String filename,String saveRootPath){

int hashcode = filename.hashCode();

int dir1 = hashcode&``0xf``; //0--15

int dir2 = (hashcode&``0xf0``)>>``4``; //0-15

String dir = saveRootPath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5

File file = new File(dir);

if``(!file.exists()){

//创建目录

file.mkdirs();

}

return dir;

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

|

在 Web.xml 文件中配置 DownLoadServlet

?

|

1

2

3

4

5

6

7

8

9

|

``

DownLoadServlet

me.gacl.web.controller.DownLoadServlet

``

``

DownLoadServlet

/servlet/DownLoadServlet

``

|

 点击【下载】超链接,将请求提交到 DownLoadServlet 就行处理就可以实现文件下载了,运行效果如下图所示:

  

  从运行结果可以看到,我们的文件下载功能已经可以正常下载文件了。

  • Java

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

    3206 引用 • 8217 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 686 关注
  • Sillot

    Insights(注意当前设置 master 为默认分支)

    汐洛彖夲肜矩阵(Sillot T☳Converbenk Matrix),致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点。其中汐洛绞架(Sillot-Gibbet)基于自思源笔记(siyuan-note),前身是思源笔记汐洛版(更早是思源笔记汐洛分支),是智慧新录乄终端(多端融合,移动端优先)。

    主仓库地址:Hi-Windom/Sillot

    文档地址:sillot.db.sc.cn

    注意事项:

    1. ⚠️ 汐洛仍在早期开发阶段,尚不稳定
    2. ⚠️ 汐洛并非面向普通用户设计,使用前请了解风险
    3. ⚠️ 汐洛绞架基于思源笔记,开发者尽最大努力与思源笔记保持兼容,但无法实现 100% 兼容
    29 引用 • 25 回帖 • 152 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    502 引用 • 1397 回帖 • 241 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 74 关注
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    11 引用 • 15 回帖
  • 996
    13 引用 • 200 回帖 • 6 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    4 引用 • 16 回帖 • 200 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    78 引用 • 37 回帖
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    85 引用 • 324 回帖
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    337 引用 • 324 回帖 • 4 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 799 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1062 引用 • 3456 回帖 • 124 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 1 关注
  • React

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

    192 引用 • 291 回帖 • 350 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    60 引用 • 22 回帖 • 2 关注
  • OnlyOffice
    4 引用 • 41 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    151 引用 • 257 回帖 • 1 关注
  • 大疆创新

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

    2 引用 • 14 回帖
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 623 关注
  • 以太坊

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

    34 引用 • 367 回帖 • 1 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 72 关注
  • 外包

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

    26 引用 • 234 回帖 • 1 关注
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 694 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4602 回帖 • 731 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    9 引用 • 75 回帖
  • OpenResty

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

    17 引用 • 51 关注