SpringBoot的官方文档中关于Jersey的介绍并非很全面: 27.3 JAX-RS and Jersey,SpringBoot-Sample项目里面也只有很是基础的代码,对于一些复杂的经常使用需求,这个文档给不了任何帮助。html
为了使用Jersey提供的Restful API完成文件上传功能,今天我花了很多时间查阅文档资料,遇到了一些问题,而后不断地踩坑尝试,其中一些坑仍是参照Stack Overflow的解决方案,甚至是框架官方文档的说明而碰到的。主要问题就是,SpringBoot和Jersey的官方文档没有给出更详细的内容,Stack Overflow针对的问题很片面,不能适用于全部的状况,因此我打算将搭建项目的过程从头至尾写下来,以便有一个方便参照的教程。java
我使用了Spring发布的Spring Tool Suit(STS)来建立项目,由于这个IDE使用SpringBoot十分方便,能够在建立项目时引入一些技术栈。spring
我使用的Java版本是JDK 8,后面会用到CURL这个命令行工具来测试相关的接口,你们能够先准备好,以便学习过程连贯。apache
这个项目命名为demo-app
,默认包为org.demo
,我在建立时仅添加了Jersey的支持,SpringBoot版本是1.5.10。api
若是没有STS,也能够用Eclipse建立一个Maven项目,Pom文件配置以下:tomcat
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.demo</groupId> <artifactId>demo-app</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
项目建立完成后,须要添加一个jersey-media-multipart
的依赖,在pom中dependencies
标签中添加:restful
<dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-multipart</artifactId> </dependency>
这个依赖不须要版本号,由于在spring-boot-starter-parent
中已经定义了版本,咱们只须要添加一个dependency在具体项目中便可。app
项目建立好时,已经存在一个带有main方法的入口类DemoAppApplication
,咱们不须要改动它。框架
Jersey的官方文档中将Restful API调用的入口称做Resources
,而在SpringBoot的示例代码中将其命名为Endpoint
,其实指的是同一个东西。由于使用了SpringBoot,为了风格统一我使用了Endpoint
的命名规则,这不是强制的,你们也能够自定义命名规则。但建议从这二者中选择一种,以便你们方便理解。curl
首先增长一个HelloEndpoint
类:
package org.demo; import java.io.IOException; import java.io.InputStream; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; import org.apache.tomcat.util.http.fileupload.IOUtils; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; import org.springframework.stereotype.Component; @Component @Path("/file") public class FileUploadEndpoint { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public String upload(@FormDataParam("file") InputStream fis, @FormDataParam("file") FormDataContentDisposition fileDisposition) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { IOUtils.copy(fis, baos); String content = new String(baos.toByteArray()); return content; } catch (IOException e) { e.printStackTrace(); } return null; } }
它十分相似于SpringMVC的Controller
,可是拥有更规范更严格的REST风格,并且它不能像SpringMVC同样经过返回一个视图名称指向某个视图。
其次是JerseyConfig
类:
package org.demo; import javax.ws.rs.ApplicationPath; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.server.ResourceConfig; import org.springframework.stereotype.Component; @Component @ApplicationPath("/rest/demo") public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(MultiPartFeature.class); register(FileUploadEndpoint.class); } }
至此,一个文件上传的服务端接口已经编写完成。关于表单页面这里很少作说明,由于这个项目不是一个Web项目,而是Web Service的服务端,不能在项目中直接访问静态Web资源。也不建议使用特殊方法知足这种须要,咱们应当保持项目的纯净。
须要注意@ApplicationPath
这个注解,它决定了全部Endpoint
的基础路径。
下面咱们来测试一下这个Restful API是否能正常工做,运行DemoAppApplication
,等待项目部署。
接下来准备使用CURL测试,CURL能够到官网下载操做系统对应的版本。建立一个demo.txt
文件保存到任意目录,文件内容写入Test my restful api with curl.
,使用英文是为了不CMD命令行中的中文出现乱码的状况,这里不用过多在乎,咱们只要关注结果。
进入demo.txt
文件所在的目录,按住Shift
打开CMD或者PowerShell(Linux系统下打开终端定位到该目录),执行:curl -X POST -F "file=@demo.txt" http://localhost:8080/rest/demo/file
若是获得Test my restful api with curl.
的回显,说明Restful API部署成功,而且可以接收上传的文件。
在实现利用Jersey完成文件上传的过程当中,我遇到的一些问题须要你们特别关注:
jersey-media-multipart
依赖,仅预先定义了须要的版本,若是未引入这个包,将没法使用@FormDataParam
注解和Multipart相关的类,没法对Multipart内容进行解析;JerseyConfig
中须要注册MultiPartFeature.class
,不然会出现报错,没法正确注入文件输入流对象。报错的时机根据是否延迟加载决定,若是application.properties定义了spring.jersey.servlet.load-on-startup=1
,会在项目启动时报错;不然会在首次上传文件,初始化FileUploadEndpoint
时报错。FileUploadEndpoint.upload()
方法,有些文档和教程中,fileDisposition
对象使用了ContentDisposition
类来定义,尽管它是FormDataContentDisposition
的父类,但仍然会报错,缘由未知。建议直接使用FormDataContentDisposition