使用JAX-RS的FileUpload

我尝试从JavaScript客户端上传文件到JAX-RS Java服务器。

我在我的服务器上使用以下REST上传function:

@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 Controller中使用代码时,它运行良好,但是当我在REST资源中使用它时,我总是得到:请求不是MultipartHttpServletRequest或SecurityContextHolderAwareRequestWrapper

日志输出是

 request: com.sun.proxy.$Proxy58 

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

如何使JAX-RS文件上传工作? 如何通过POST请求收到一些额外的查询参数?

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

 @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,您只需使用此代码进行检查即可

   

Upload File with RESTFul WebService

Choose a file :

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

@QueryParam的示例

@HeaderParam的示例

试试这个,希望这可以帮助您解决问题。

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

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

而Jersey的以下内容是相同的(FormDataParam是Jersey扩展名):

  @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以及其他不相关的注释。)

在表单提交代码中添加enctype="multipart/form-data" ,在@POST方法中添加@Consumes(MediaType.MULTIPART_FORM_DATA_TYPE) ,这样我们就知道我们正在提交一个多部分文件,其余的api可以使用它。 你的restapi方法可能看起来像

 @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 @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> uploadForm = input.getFormDataMap(); //The file name String fileName; String pathFileName = ""; //Get file data to save List inputParts = uploadForm.get("attachment"); try { for (InputPart inputPart : inputParts) { //Use this header for extra processing if required MultivaluedMap 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(); } 

对于客户端,我们使用由另一个团队编码的AngularJS。 我将无法解释它,但这里是代码:

  $scope.setPicture = function (element) { var t = new Date(); console.log(t + ' - ' + t.getMilliseconds()); // Only process image files. if (!element[0].type.match('image.*')) { console.log('File is not an image'); Error.current.element = $document[0].getElementById('comet-project-upload'); Error.current.message = 'Please select a picture.'; $scope.$apply(); } else if (element[0].size > 10 * 1024 * 1024) { console.log('File is too big'); Error.current.element = $document[0].getElementById('comet-project-upload'); Error.current.message = 'File is too big. Please select another file.'; $scope.$apply(); } else { self.animSpinner = true; var fd = new FormData(); //Take the first file fd.append('attachment', element[0]); //Note : attachment is the compulsory name ? Project.uploadImage(fd).then( function (data) { self.animSpinner = false; // self.$apply not needed because $digest already in progress self.projectPicture = data; }, function () { self.animSpinner = false; Error.current.element = $document[0].getElementById('comet-project-upload'); Error.current.message = 'Error with the server when uploading the image'; console.error('Picture Upload failed! ' + status + ' ' + headers + ' ' + config); } ); } }; 

而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; }; 

希望它能帮到你……