Java 使用JAX-RS上传文件
我尝试将文件从JavaScript客户端上传到JAX-RS Java服务器 我在服务器上使用以下REST上载功能:Java 使用JAX-RS上传文件,java,rest,grails,jersey,jax-rs,Java,Rest,Grails,Jersey,Jax Rs,我尝试将文件从JavaScript客户端上传到JAX-RS Java服务器 我在服务器上使用以下REST上载功能: @POST @Produces('application/json') UploadDto upload( @Context HttpServletRequest request, @QueryParam("cookie") String cookie) { def contentType byte [] fileBytes
@POST
@Produces('application/json')
UploadDto upload(
@Context HttpServletRequest request,
@QueryParam("cookie") String cookie) {
def contentType
byte [] fileBytes
log.debug "upload - cookie: "+cookie
try{
if (request instanceof MultipartHttpServletRequest) {
log.debug "request instanceof MultipartHttpServletRequest"
MultipartHttpServletRequest myrequest = request
CommonsMultipartFile file = (CommonsMultipartFile) myrequest.getFile('file')
fileBytes = file.bytes
contentType = file.contentType
log.debug ">>>>> upload size of the file in byte: "+ file.size
}
else if (request instanceof SecurityContextHolderAwareRequestWrapper) {
log.debug "request instanceof SecurityContextHolderAwareRequestWrapper"
SecurityContextHolderAwareRequestWrapper myrequest = request
//get uploaded file's inputStream
InputStream inputStream = myrequest.inputStream
fileBytes = IOUtils.toByteArray(inputStream);
contentType = myrequest.getHeader("Content-Type")
log.debug ">>>>> upload size of the file in byte: "+ fileBytes.size()
}
else {
log.error "request is not a MultipartHttpServletRequest or SecurityContextHolderAwareRequestWrapper"
println "request: "+request.class
}
}
catch (IOException e) {
log.error("upload() failed to save file error: ", e)
}
}
在客户端,我按如下方式发送文件:
var str2ab_blobreader = function(str, callback) {
var blob;
BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder
|| window.BlobBuilder;
if (typeof (BlobBuilder) !== 'undefined') {
var bb = new BlobBuilder();
bb.append(str);
blob = bb.getBlob();
} else {
blob = new Blob([ str ]);
}
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result)
}
f.readAsArrayBuffer(blob);
}
var fileName = "fileName.jpg";
var contentType = "image/jpeg";
if (file.type.toString().toLowerCase().indexOf("png") > -1) {
fileName = "fileName.png";
contentType = "image/png";
}
var xhrNativeObject = new XMLHttpRequest();
var urlParams = ?test=123;
xhrNativeObject.open("post", url + urlParams, true);
xhrNativeObject.setRequestHeader("Content-Type", contentType);
xhrNativeObject.onload = function(event) {
var targetResponse = event.currentTarget;
if ((targetResponse.readyState == 4)
&& (targetResponse.status == 200)) {
var obj = JSON.parse(targetResponse.responseText);
console.log(obj.uploadImageId);
} else {
console.log("fail");
}
}
var buffer = str2ab_blobreader(file, function(buf) {
xhrNativeObject.send(buf);
});
当我在Grails控制器中使用代码时,它工作得很好,但当我在REST资源中使用它时,我总是得到:请求不是MultipartHttpServletRequest或SecurityContextHolderAwareRequestWrapper
日志输出为
request: com.sun.proxy.$Proxy58
我使用XMLHttpRequest
从JavaScript发送一个文件blob,其中包含body中的blob和一些查询参数
如何使JAX-RS文件上传工作正常?如何通过POST请求接收一些额外的查询参数?没有Jax-RS方法可以做到这一点。每个服务器都有自己的扩展,都使用多部分表单提交。例如,在CXF中,以下内容将允许您通过多部分表单上载。(附件是CXF特定的扩展) 鉴于以下内容与Jersey相同(FormDataParam是Jersey的扩展):
(我忽略了@Path、@POST和@products以及其他不相关的注释。)在服务器端,您可以使用类似的注释
@POST
@Path("/fileupload") //Your Path or URL to call this service
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
@DefaultValue("true") @FormDataParam("enabled") boolean enabled,
@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
//Your local disk path where you want to store the file
String uploadedFileLocation = "D://uploadedFiles/" + fileDetail.getFileName();
System.out.println(uploadedFileLocation);
// save it
File objFile=new File(uploadedFileLocation);
if(objFile.exists())
{
objFile.delete();
}
saveToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded via Jersey based RESTFul Webservice to: " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
private void saveToFile(InputStream uploadedInputStream,
String uploadedFileLocation) {
try {
OutputStream out = null;
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
同样,这可以通过java中的客户端代码进行检查
public class TryFile {
public static void main(String[] ar)
throws HttpException, IOException, URISyntaxException {
TryFile t = new TryFile();
t.method();
}
public void method() throws HttpException, IOException, URISyntaxException {
String url = "http://localhost:8080/...../fileupload"; //Your service URL
String fileName = ""; //file name to be uploaded
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
FileBody fileContent = new FiSystem.out.println("hello");
StringBody comment = new StringBody("Filename: " + fileName);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("file", fileContent);
httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
}
}
使用HTML,您只需检查以下代码
<html>
<body>
<h1>Upload File with RESTFul WebService</h1>
<form action="<Your service URL (htp://localhost:8080/.../fileupload)" method="post" enctype="multipart/form-data">
<p>
Choose a file : <input type="file" name="file" />
</p>
<input type="submit" value="Upload" />
</form>
使用RESTfulWebService上载文件
选择一个文件:
要获取QueryParam,请选中@QueryParam或使用@HeaderParam获取标题参数
试试这个,希望它能帮你解决问题。下面是我们上传文件的步骤(在我们的例子中是图像):
服务器端
@POST
@RolesAllowed("USER")
@Path("/upload")
@Consumes("multipart/form-data")
public Response uploadFile(MultipartFormDataInput input) throws IOException
{
File local;
final String UPLOADED_FILE_PATH = filesRoot; // Check applicationContext-Server.properties file
//Get API input data
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
//The file name
String fileName;
String pathFileName = "";
//Get file data to save
List<InputPart> inputParts = uploadForm.get("attachment");
try
{
for (InputPart inputPart : inputParts)
{
//Use this header for extra processing if required
MultivaluedMap<String, String> header = inputPart.getHeaders();
fileName = getFileName(header);
String tmp = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
pathFileName = "images/upload/" + tmp + '_' + fileName + ".png";
fileName = UPLOADED_FILE_PATH + pathFileName;
// convert the uploaded file to input stream
InputStream inputStream = inputPart.getBody(InputStream.class, null);
byte[] bytes = IOUtils.toByteArray(inputStream);
// constructs upload file path
writeFile(bytes, fileName);
// NOTE : The Target picture boundary is 800x600. Should be specified somewhere else ?
BufferedImage scaledP = getScaledPicture(fileName, 800, 600, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(scaledP, "png", os);
local = new File(fileName);
ImageIO.write(scaledP, "png", local);
}
}
catch (Exception e)
{
e.printStackTrace();
return Response.serverError().build();
}
return Response.status(201).entity(pathFileName).build();
}
以及uploadImage功能:
this.uploadImage = function (imageData)
{
var deferred = $q.defer();
$http.post('/comet/api/image/upload', imageData,
{
headers: { 'Content-Type': undefined, Authorization: User.hash },
//This method will allow us to change how the data is sent up to the server
// for which we'll need to encapsulate the model data in 'FormData'
transformRequest: angular.identity
//The cool part is the undefined content-type and the transformRequest: angular.identity
// that give at the $http the ability to choose the right "content-type" and manage
// the boundary needed when handling multipart data.
})
.success(function (data/*, status, headers, config*/)
{
deferred.resolve(data);
})
.error(function (data, status, headers, config)
{
console.error('Picture Upload failed! ' + status + ' ' + headers + ' ' + config);
deferred.reject();
});
return deferred.promise;
};
希望它能帮助您……在表单提交者代码中添加enctype=“multipart/form data”
,并在@POST方法中使用@Consumes(MediaType.multipart\u form\u data\u TYPE)
,这样我们就知道我们正在提交一个多部分文件,rest api可以使用它。
您的RESTAPI方法可能如下所示
@POST
@Path("/uploadfile")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(
@FormDataParam("file") InputStream fileInputStream,
@FormDataParam("file") FormDataContentDisposition disposition) {
//...
}
或
这将在服务器上创建一个临时文件。它从网络读取数据并保存到临时文件中
为了防御性地编程,我将使用纯JAX-RS检查正在上载的文件的内容类型元数据,假设您不需要文件名,上载方法如下所示:
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void upload(InputStream file, @QueryParam("foo") String foo) {
// Read file contents from the InputStream and do whatever you need
}
这仅适用于文件
@POST
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response upload(Map<String, InputStream> files) {
return Response.ok().build();
}
@POST
@使用({MediaType.MULTIPART\u FORM\u DATA})
公共响应上载(地图文件){
返回Response.ok().build();
}
但我仍然希望在请求中添加json
也许,JAX-RS规范中的4.2.1章节是实现实践中最纯粹方法的途径。这将实现一个提供者:MessageBodyReader专门化。我没有得到它。你可以发布一个完整的例子来说明我是如何获取文件字节的吗?在Jersey,你可以得到一个Inputstream。从这一点到字节[]应该比较简单。不过,我不知道答案。如何获取字节[]?对此有很多答案。Apache commons io、Google guava或straight Java。在特定于cxf的情况下,这可能是@confile question
DataHandler=attr.getDataHandler()的答案;InputStream instream=handler.getInputStream()代码>什么是MultipartFormDataInput。它是哪一个导入?它是由library org.jboss.resteasy:resteasy多部分提供程序:3.0.8.Final提供的。但这不是Jersey?不是。也许我在写答案时漏掉了“Jersey”标签:)你有Jersey的答案吗?通过这个链接。希望你能澄清你的问题。如何使用apache wink实现这一点?值得一提的是,这种依赖于FormDataContentDisposition
和@FormDataParam
的方法签名不能在客户端用于生成动态代理(WebResourceFactory.newResource(…)
)。因此,在客户端,如果您希望从服务器界面动态生成一个动态代理,您最好使用@PathParam
来指定文件名,例如:@POST@Path(/test/{fileName}”)@Consumes(APPLICATION_OCTET_STREAM)void upload(@PathParam(“fileName”)String fileName,InputStream in)
这不是JAX-RS的一部分。它不适用于所有服务器。例如,使用Jersey实现的Tomcat就可以实现这一点。使用这一点,pdf文件可以完美地上传,当上传jpg文件时,它会被上传,但文件已损坏。有什么建议吗?我想我要放弃了。entityStream太难处理了。我几乎没有时间处理它。需要选择两个选项之一:用于处理多部分/表单数据有效负载的第三方LIB或基于JAX-RS的容器实现实现资源类。在第二个选项中,最好将它与其他资源实现分开,并且与其他资源实现非常不同,这样就更容易更改任何基于容器的实现。
@POST
@Path("/uploadfile")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(
@FormDataParam("file") InputStream fileInputStream,
@FormDataParam("file") FormDataContentDisposition disposition) {
//...
}
@POST
@Path("/uploadfile")
public void post(File file) {
Reader reader = new Reader(new FileInputStream(file));
// ...
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void upload(InputStream file, @QueryParam("foo") String foo) {
// Read file contents from the InputStream and do whatever you need
}
@POST
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response upload(Map<String, InputStream> files) {
return Response.ok().build();
}