文件使用 JAX-RS 上传

2022-09-01 13:37:27

我尝试将文件从 JavaScript 客户机上载到 JAX-RS Java 服务器。

我在服务器上使用以下 REST 上传功能:

@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

从我使用的 JavaScript 发送文件 blob,其中包含正文中的 blob 和一些查询参数。XMLHttpRequest

如何使 JAX-RS 文件上载正常工作?如何通过 POST 请求接收一些其他查询参数?


答案 1

在服务器端,您可以使用类似这样的东西

@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>

要获取查询参数,请检查@QueryParam或标头参数使用@HeaderParam

@QueryParam示例

@HeaderParam示例

试试这个,希望这对你解决问题有所帮助。


答案 2

没有 Jax-RS 方法可以做到这一点。每个服务器都有自己的扩展,全部使用多部分表单提交。例如,在 CXF 中,以下内容将允许您通过多部分表单上传。(附件是 CXF 特定的扩展名)

@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@Multipart(value = "vendor") String vendor,
        @Multipart(value = "uploadedFile") Attachment attr) {

而以下内容与泽西岛相同(FormDataParam是泽西岛的扩展名):

 @Consumes(MediaType.MULTIPART_FORM_DATA_TYPE)
 public String postForm(
         @DefaultValue("true") @FormDataParam("enabled") boolean enabled,
         @FormDataParam("data") FileData bean,
         @FormDataParam("file") InputStream file,
         @FormDataParam("file") FormDataContentDisposition fileDisposition) {

(我忽略了@Path,@POST和@Produces以及其他不相关的注释。