搜索词>>FormData 耗时0.1520
  • FormData 使用详解

    如何创建FormData创建FormData对象有两种方式,一个是通过已有得form表单进行创建,另一个就是直接创建如何创建FormData创建FormData对象有两种方式,一个是通过已有得form表单进行创建,另一个就是直接创建。直接创建FormData并赋值var formData=new FormData(); formData.append("name","左搜"); console.log(formData.get("name"));输出结果为:>左搜通过已有from表单进行创建FormData对象//var form=$('#formId')[0];// var form=document.querySelector("#formId"); var fromData=new FormData(form); console.log(formData.get("name"))注意:jQuery方式获取得form默认是个数组,需要对其选择第一个数据。FormData如何取值输出FormData对象取值需要只用它得get("filedName")方法。方法参数为FormData对象里面得字段名称。注意:直接对FormData对象进行console.log(formData)是看不到值得,应该使用get方法来测试值是否设置成功。!!!
  • Uncaught TypeError: Illegal invocation JQuery_ajax formData 上传文件报错

    问题描述JQuery_ajax formData 上传文件报错:Uncaught TypeError: Illegal invocationJquery 版本2.1.4$.ajax({ type: 'POST', url: url,问题描述JQuery_ajax formData 上传文件报错:Uncaught TypeError: Illegal invocationJquery 版本2.1.4$.ajax({ type: 'POST', url: url, data: formData, success: function(res){ } });解决办法设置processData与contentType参数为false$.ajax({ type: 'POST', url: url, data: formData, processData: false, // jQuery不要去处理发送的数据 contentType: false, // jQuery不要去设置Content-Type请求头 success: function(res){ } });正确使用参考:HTML5+ajax上传图片/文件以及FormData使用简单讲解
  • HTML5+ajax上传图片/文件以及FormData使用简单讲解

    HTML5+ajax上传图片/文件以及FormData使用简单讲解,HTML5,ajax上传文件,ajaxHTML5+ajax上传图片/文件以及FormData使用简单讲解<br /> <br /> HTML5中FormData的使用,解决ajax上传文件/图片难题<br /> <strong>1.FormData的创建和使用方式一</strong><br /> 创建一个空的 FormData <pre> <code class="language-javascript">var fd= new FormData();</code></pre> <br /> 使用 append() 方法向该对象里添加字段 <pre> <code class="language-javascript">fd.append("username", "Groucho"); fd.append("userfile", fileInputElement.files[0]);</code></pre> <br /> <strong>2.FormData的创建和使用方式二</strong><br /> 使用HTML表单来初始化一个FormData对象 <pre> <code class="language-html"><form id="test-form"> <input type="text" name="name"/> <input type="password" name="pwd"/> </form></code></pre>   <pre> <code class="language-javascript">var formElement = document.getElementById("test-form"); var newFormData = new FormData(formElement);</code></pre> <br /> 在有了FormData对象之后使用ajax(这里简单引用的jQuery的ajax)<br />   <pre> <code class="language-javascript">$.ajax({     url:'Your Post Url',     type:'POST',//上传文件必须为POST,查看解释一     data:newFormData,//FormData对象     processData:false,//不转换请求数据     contentType:false,//contentType 设置为 false 是为了避免 JQuery 对其操作,从而失去分界符     success:function(data){         //成功回调     },     error:function(ex){         //错误回调     } });</code></pre> <br /> <em>解释一:这里我们就要先说说在 http 中传输文件的问题。起初,http 协议中没有上传文件方面的功能,直到 rfc1867 为 http 协议添加了这个功能。当然在 rfc1867 中限定 form 的 method 必须为 POST , enctype = “multipart/form-data” 以及<input type = "file">.</em>
  • Form 获取JSON参数和URL参数

    Form前置准备首先我们有一个表单<form id="params">l; <input name="userName" value="123">l; <input name="userSex" value="男">l; </form>l;方式Form前置准备首先我们有一个表单<form id="params"> <input name="userName" value="123"> <input name="userSex" value="男"> </form>方式一:获取URL参数,用问号连接let params=$('#params').serialize(); //使用参数 let reqUrl='xxx.com/xxx.do?'+params实际得params内容格式为:userName=123&userSex=男方式二:获取JSON参数首先需要一个工具方法function getFormToJson(formObj){ let formData=$(formObj).serializeArray(); var obj={} for (var i in formData) { obj[formData[i].name]=formData[i]['value']; } return obj; }具体使用:let params=getFormJSON($('#params'));上述params参数实际为:{ "userName":"123", "userSex":"男" }
  • summernote 粘贴板图片上传到服务器

    summernote 粘贴图片上传到服务器以下为关键代码//初始化富文本 $('#description').summernote('destroy'); $('#description').summernote 粘贴图片上传到服务器以下为关键代码//初始化富文本 $('#description').summernote('destroy'); $('#description').summernote({ width:'100%', height:250, lang: 'zh-CN', focus: true, toolbar: [ ['style', ['bold', 'italic', 'underline', 'clear']], ['fontsize', ['fontsize']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['height', ['height']], ['insert', ['picture']] ], callbacks: { onImageUpload:function(files){ sendFile(files,'#description'); }, onPaste: function(event) { console.log(event); if ( event.clipboardData || event.originalEvent ) { var bufferText = ((event.originalEvent || event).clipboardData || window.clipboardData).getData('Text/plain'); if(bufferText.length>0) { ; }else event.preventDefault(); } } } });  文件上传细节:function sendFile(files, editor) { var formData = new FormData(); formData.append('file',files[0]); $.ajax({ url : '/file/upload',//后台文件上传接口 type : 'POST', data : formData, processData : false, contentType : false, success : function(res) { if(res.result==1) { var path='/file/download'+"?fileId="+res.detail;//后台展示图片地址 $(editor).summernote('insertImage', path, function ($image) { $image.css('width', 'auto'); }); }else layer.msg(res.message, {shift: 5}); },error:function(){ alert("上传失败"); } }); }​​​​​​​代码段 小部件
  • IE9 jQuery ajax文件上传兼容问题解决

    IE9 jQuery ajax文件上传兼容问题解决。主要通过jQuery的jquery.form插件解决的IE9不支持formData的文件上传问题。<h2>1.准备</h2> 下载jQuery1.x版本(测试用v1.12.4)<br /> 下载jQuery的form插件(<a href="http://plugins.jquery.com/form/" rel="external nofollow" target="_blank">下载地址</a>)<br /> 本例子是通过Java后端进行测试的,后端为spring boot框架 <h2>2.后端代码</h2> 1测试的controller代码 <pre> <code class="language-java">package com.example; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; @Controller public class TestController { @GetMapping(value = { "/", "/index.html" }) public Object index() { return new ModelAndView("index"); } @PostMapping(value = { "/fileupload.do" }, produces = { "text/html;charset=UTF-8" }) @ResponseBody public Object fileUpload(String name, MultipartFile file) { try { if (file.getBytes().length > 0) { return "{\"message\":\"success\",\"name\":\"" + name + "\"}"; } else { return "{\"message\":\"fail\"}"; } } catch (Exception e) { throw new RuntimeException("文件上传异常"); } } @PostMapping(value = { "/fileupload2.do" }/*, produces = { "text/html;charset=UTF-8" }*/) public void fileUpload2(String name, MultipartFile file,HttpServletResponse response) { try { if (file.getBytes().length > 0) { response.setContentType(""); response.setHeader("Content-Type", "text/html;charset=UTF-8"); response.getWriter().write("{\"message\":\"success\",\"name\":\"" + name + "\"}"); } else { response.setHeader("Content-Type", "text/html;charset=UTF-8"); response.getWriter().write("{\"message\":\"fail\"}"); } } catch (Exception e) { throw new RuntimeException("文件上传异常"); } } } </code></pre> <span style="color:#e74c3c">注意:上面的第一种写法<strong>produces = { "text/html;charset=UTF-8" }</strong>必须这样写,其他写法则会出现各种问题</span> <p> </p> <h2>3.后端代码</h2> 1HTML页面代码 <pre> <code class="language-html"><!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>测试</title> </head> <body> <form method="post" enctype="multipart/form-data" id="upload-form"> <input type="text" name="name" /> <input type="file" name="file"/> </form> <button type="button" id="btn-upload">上传测试</button> <script type="text/javascript" src="/libs/jquery.min.js"></script> <script type="text/javascript" src="/libs/jquery.form.js"></script> <script type="text/javascript" src="/libs/index.js"></script> </body> </html></code></pre> <br /> 2.index.js文件代码 <pre> <code class="language-javascript">/** * */ $(function() { $('#btn-upload').click(function(){ var options = { url : "/fileupload.do", success : function(data) { var returnData = JSON.parse(data); alert(data); }, resetForm : true, }; $("#upload-form").ajaxSubmit(options); }) })</code></pre> <h2>4jQuery form控件API</h2> <h2>Options</h2> <p><strong>Note:</strong> All standard <a href="http://api.jquery.com/jQuery.ajax" rel="external nofollow" target="_blank">$.ajax</a> options can be used.</p> <h3>beforeSerialize</h3> <p>Callback function invoked prior to form serialization. Provides an opportunity to manipulate the form before its values are retrieved. Returning <code>false</code> from the callback will prevent the form from being submitted. The callback is invoked with two arguments: the jQuery wrapped form object and the options object.</p> <pre> <code class="language-javascript">beforeSerialize: function($form, options) { // return false to cancel submit }</code></pre> <h3>beforeSubmit</h3> <p>Callback function invoked prior to form submission. Returning <code>false</code> from the callback will prevent the form from being submitted. The callback is invoked with three arguments: the form data in array format, the jQuery wrapped form object, and the options object.</p> <pre> <code class="language-javascript">beforeSubmit: function(arr, $form, options) { // form data array is an array of objects with name and value properties // [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] // return false to cancel submit }</code></pre> <h3>filtering</h3> <p>Callback function invoked before processing fields. This provides a way to filter elements.</p> <pre> <code class="language-javascript">filtering: function(el, index) { if ( !$(el).hasClass('ignore') ) { return el; } }</code></pre> <h3>clearForm</h3> <p>Boolean flag indicating whether the form should be cleared if the submit is successful</p> <h3>data</h3> <p>An object containing extra data that should be submitted along with the form.</p> <pre> <code>data: { key1: 'value1', key2: 'value2' } </code></pre> <h3>dataType</h3> <p>Expected data type of the response. One of: null, 'xml', 'script', or 'json'. The dataType option provides a means for specifying how the server response should be handled. This maps directly to jQuery's dataType method. The following values are supported:</p> <ul> <li>'xml': server response is treated as XML and the 'success' callback method, if specified, will be passed the responseXML value</li> <li>'json': server response will be evaluted and passed to the 'success' callback, if specified</li> <li>'script': server response is evaluated in the global context</li> </ul> <h3>delegation</h3> <p>true to enable support for event delegation <em>requires jQuery v1.7+</em></p> <pre> <code class="language-javascript">// prepare all existing and future forms for ajax submission $('form').ajaxForm({ delegation: true });</code></pre> <h3>error</h3> <p>Callback function to be invoked upon error.</p> <h3>forceSync</h3> <p>Only applicable when explicity using the iframe option or when uploading files on browses that don't support XHR2. Set to <code>true</code> to remove the short delay before posting form when uploading files. The delay is used to allow the browser to render DOM updates prior to performing a native form submit. This improves usability when displaying notifications to the user, such as "Please Wait..."</p> <h3>iframe</h3> <p>Boolean flag indicating whether the form should <em>always</em> target the server response to an iframe instead of leveraging XHR when possible.</p> <h3>iframeSrc</h3> <p>String value that should be used for the iframe's src attribute when an iframe is used.</p> <h3>iframeTarget</h3> <p>Identifies the iframe element to be used as the response target for file uploads. By default, the plugin will create a temporary iframe element to capture the response when uploading files. This options allows you to use an existing iframe if you wish. When using this option the plugin will make no attempt at handling the response from the server.</p> <h3>method</h3> <p>The HTTP method to use for the request (e.g. 'POST', 'GET', 'PUT').</p> <h3>replaceTarget</h3> <p>Optionally used along with the the target option. Set to true if the target should be replaced or false if only the target contents should be replaced.</p> <h3>resetForm</h3> <p>Boolean flag indicating whether the form should be reset if the submit is successful</p> <h3>semantic</h3> <p>Boolean flag indicating whether data must be submitted in strict semantic order (slower). Note that the normal form serialization is done in semantic order with the exception of input elements of <code>type="image"</code>. You should only set the semantic option to true if your server has strict semantic requirements and your form contains an input element of <code>type="image"</code>.</p> <h3>success</h3> <p>Callback function to be invoked after the form has been submitted. If a 'success' callback function is provided it is invoked after the response has been returned from the server. It is passed the following standard jQuery arguments:</p> <ol> <li><code>data</code>, formatted according to the dataType parameter or the dataFilter callback function, if specified</li> <li><code>textStatus</code>, string</li> <li><code>jqXHR</code>, object</li> <li><code>$form</code> jQuery object containing form element</li> </ol> <h3>target</h3> <p>Identifies the element(s) in the page to be updated with the server response. This value may be specified as a jQuery selection string, a jQuery object, or a DOM element.</p> <h3>type</h3> <p>The HTTP method to use for the request (e.g. 'POST', 'GET', 'PUT').<br /> An alias for <code>method</code> option. Overridden by the <code>method</code> value if both are present.</p> <h3>uploadProgress</h3> <p>Callback function to be invoked with upload progress information (if supported by the browser). The callback is passed the following arguments:</p> <ol> <li>event; the browser event</li> <li>position (integer)</li> <li>total (integer)</li> <li>percentComplete (integer)</li> </ol> <h3>url</h3> <p>URL to which the form data will be submitted.</p> <hr /> <h2>Utility Methods</h2> <h3>formSerialize</h3> <p>Serializes the form into a query string. This method will return a string in the format: <code>name1=value1&name2=value2</code></p> <pre> <code>var queryString = $('#myFormId').formSerialize();</code></pre> <h3>fieldSerialize</h3> <p>Serializes field elements into a query string. This is handy when you need to serialize only part of a form. This method will return a string in the format: <code>name1=value1&name2=value2</code></p> <pre> <code>var queryString = $('#myFormId .specialFields').fieldSerialize();</code></pre> <h3>fieldValue</h3> <p>Returns the value(s) of the element(s) in the matched set in an array. This method always returns an array. If no valid value can be determined the array will be empty, otherwise it will contain one or more values.</p> <h3>resetForm</h3> <p>Resets the form to its original state by invoking the form element's native DOM method.</p> <h3>clearForm</h3> <p>Clears the form elements. This method emptys all of the text inputs, password inputs and textarea elements, clears the selection in any select elements, and unchecks all radio and checkbox inputs. It does <em>not</em> clear hidden field values.</p> <h3>clearFields</h3> <p>Clears selected field elements. This is handy when you need to clear only a part of the form.</p> <hr /> <h2>File Uploads</h2> <p>The Form Plugin supports use of XMLHttpRequest Level 2 and <a href="https://developer.mozilla.org/en/XMLHttpRequest/FormData" rel="external nofollow" target="_blank">FormData</a> objects on browsers that support these features. As of today (March 2012) that includes Chrome, Safari, and Firefox. On these browsers (and future Opera and IE10) files uploads will occur seamlessly through the XHR object and progress updates are available as the upload proceeds. For older browsers, a fallback technology is used which involves iframes. <a href="http://malsup.com/jquery/form/#file-upload" rel="external nofollow" target="_blank">More Info</a></p>
  • spring boot 文件上传 REST风格API ajax方式-Java编程

    Java编程之Spring Boot 文件上传 REST风格API ajax方式<h2>一、摘要说明</h2>   这篇文章将告诉你在spring boot(REST 风格)WEB项目中如何用ajax请求上传文件。<br /> <br />   本文章中需要使用的工具: <ol> <li>Spring Boot 1.4.3.RELEASE</li> <li>Spring 4.3.5.RELEASE</li> <li>Thymeleaf</li> <li>jQuery (webjars)</li> <li>Maven</li> <li>Embedded Tomcat 8.5.6</li> <li>Google Chrome 浏览器(Network Inspect)</li> </ol> <h2>二、项目结构</h2> 一个标准的maven项目结构<br /> <img alt="项目结构" class="img-thumbnail" src="/assist/images/blog/811600c9be364e56b3c68ebbe78e0b07.png" /> <h2>三、项目依赖</h2> 声明一个外部的jQuery webjar依赖项,用于HTML表单中的Ajax请求。<br /> <br /> <strong>pom.xml</strong> <pre> <code class="language-xml"><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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mkyong</groupId> <artifactId>spring-boot-file-upload</artifactId> <packaging>jar</packaging> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- hot swapping, disable cache for template, enable live reload --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>2.2.4</version> </dependency> </dependencies> <build> <plugins> <!-- Package as an executable jar/war --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project></code></pre> <h2>四、文件上传</h2> 为了支持AJAX请求和响应, 最简单的方式是返回<code>ResponseEntity</code>. <h2>4.1下面的例子演示了上传文件的三种可能方式:</h2> <ol> <li>单个文件上传 – <code>MultipartFile</code></li> <li>多个文件上传– <code>MultipartFile[]</code></li> <li>Map file upload to a Model – <code>@ModelAttribute</code></li> </ol> <strong>RestUploadController.java</strong> <pre> <code class="language-java">import com.mkyong.model.UploadModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RestController public class RestUploadController { private final Logger logger = LoggerFactory.getLogger(RestUploadController.class); //Save the uploaded file to this folder private static String UPLOADED_FOLDER = "F://temp//"; // 3.1.1 Single file upload @PostMapping("/api/upload") // If not @RestController, uncomment this //@ResponseBody public ResponseEntity<?> uploadFile( @RequestParam("file") MultipartFile uploadfile) { logger.debug("Single file upload!"); if (uploadfile.isEmpty()) { return new ResponseEntity("please select a file!", HttpStatus.OK); } try { saveUploadedFiles(Arrays.asList(uploadfile)); } catch (IOException e) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } return new ResponseEntity("Successfully uploaded - " + uploadfile.getOriginalFilename(), new HttpHeaders(), HttpStatus.OK); } // 3.1.2 Multiple file upload @PostMapping("/api/upload/multi") public ResponseEntity<?> uploadFileMulti( @RequestParam("extraField") String extraField, @RequestParam("files") MultipartFile[] uploadfiles) { logger.debug("Multiple file upload!"); // Get file name String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename()) .filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , ")); if (StringUtils.isEmpty(uploadedFileName)) { return new ResponseEntity("please select a file!", HttpStatus.OK); } try { saveUploadedFiles(Arrays.asList(uploadfiles)); } catch (IOException e) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } return new ResponseEntity("Successfully uploaded - " + uploadedFileName, HttpStatus.OK); } // 3.1.3 maps html form to a Model @PostMapping("/api/upload/multi/model") public ResponseEntity<?> multiUploadFileModel(@ModelAttribute UploadModel model) { logger.debug("Multiple file upload! With UploadModel"); try { saveUploadedFiles(Arrays.asList(model.getFiles())); } catch (IOException e) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } return new ResponseEntity("Successfully uploaded!", HttpStatus.OK); } //save file private void saveUploadedFiles(List<MultipartFile> files) throws IOException { for (MultipartFile file : files) { if (file.isEmpty()) { continue; //next pls } byte[] bytes = file.getBytes(); Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename()); Files.write(path, bytes); } } }</code></pre> <h2>4.2选择4.1中的第三种方式上传文件并且使用注解@ModelAttribute</h2> <strong>UploadModel.java</strong> <pre> <code class="language-java">import org.springframework.web.multipart.MultipartFile; public class UploadModel { private String extraField; private MultipartFile[] files; //getters and setters }</code></pre> <h2>五、视图文件的编写</h2> HTML form for multiple file uploads.<br /> <strong>upload.html</strong> <pre> <code class="language-html"><!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <body> <h1>Spring Boot - Multiple file upload example - AJAX</h1> <form method="POST" enctype="multipart/form-data" id="fileUploadForm"> <input type="text" name="extraField"/><br/><br/> <input type="file" name="files"/><br/><br/> <input type="file" name="files"/><br/><br/> <input type="submit" value="Submit" id="btnSubmit"/> </form> <h1>Ajax Post Result</h1> <pre> <span id="result"></span> </pre> <script type="text/javascript" src="webjars/jquery/2.2.4/jquery.min.js"></script> <script type="text/javascript" src="js/main.js"></script> </body> </html></code></pre> <h2>六、jQuery – Ajax Request</h2> jQuery通过f<code>#id获取form</code>,并且发送multipart form 数据通过ajax请求.<br /> <strong>resources/static/js/main.js</strong> <pre> <code class="language-javascript">$(document).ready(function () { $("#btnSubmit").click(function (event) { //stop submit the form, we will post it manually. event.preventDefault(); fire_ajax_submit(); }); }); function fire_ajax_submit() { // Get form var form = $('#fileUploadForm')[0]; var data = new FormData(form); data.append("CustomField", "This is some extra data, testing"); $("#btnSubmit").prop("disabled", true); $.ajax({ type: "POST", enctype: 'multipart/form-data', url: "/api/upload/multi", data: data, //http://api.jquery.com/jQuery.ajax/ //https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects processData: false, //prevent jQuery from automatically transforming the data into a query string contentType: false, cache: false, timeout: 600000, success: function (data) { $("#result").text(data); console.log("SUCCESS : ", data); $("#btnSubmit").prop("disabled", false); }, error: function (e) { $("#result").text(e.responseText); console.log("ERROR : ", e); $("#btnSubmit").prop("disabled", false); } }); }</code></pre> <h2>七、Exception Handler异常拦截</h2> 拦截来自 Ajax请求的异常, 只需要继承 <code>ResponseEntityExceptionHandler</code> 并且返回 <code>ResponseEntity</code>.<br /> <strong>RestGlobalExceptionHandler.java</strong> <pre> <code class="language-java">import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import javax.servlet.http.HttpServletRequest; //http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling @ControllerAdvice public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler { // Catch file size exceeded exception! @ExceptionHandler(MultipartException.class) @ResponseBody ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) { HttpStatus status = getStatus(request); return new ResponseEntity(ex.getMessage(), status); // example //return new ResponseEntity("success", responseHeaders, HttpStatus.OK); } private HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } return HttpStatus.valueOf(statusCode); } }</code></pre> <h2>八、演示</h2> 使用默认的嵌入式Tomcat启动Spring启动<code>mvn spring-boot:run</code>.<br /> 8.1访问http://localhost:8080/,选择几个文件并单击submit以触发ajax请求。<br /> <img alt="访问并上传" class="img-thumbnail" src="/assist/images/blog/19d6d8c691d04a079fd5a18adc7560fa.png" /><br /> 8.2 Google Chrome浏览器,检查“网络检查”中的请求和响应<br /> <img alt="观察请求" class="img-thumbnail" src="/assist/images/blog/ae51363c32cf415b943dbdc57d659470.png" /><br /> 8.4 Google Chrome, “Request Payload”<br /> <img alt="上传内容" class="img-thumbnail" src="/assist/images/blog/7f1ff5d5dde64d89ae7afd664c5df0f5.png" /> <h2>9.curl工具测试</h2> More testing with <code>cURL</code> command.<br /> 9.1测试单个文件上传 <pre> <code>$ curl -F file=@"f:\\data.txt" http://localhost:8080/api/upload/ Successfully uploaded - data.txt</code></pre> <br /> 9.2.测试多个文件上传 <pre> <code>$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt" http://localhost:8080/api/upload/multi/ Successfully uploaded - data.txt , data2.txt</code></pre> 9.3测试多个文件上传使用maps to Model模式 <pre> <code>$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt" http://localhost:8080/api/upload/multi/model Successfully uploaded! </code></pre> <br /> 9.4测试一个大文件(超过100MB),将会提示下面的错误信息 <pre> <code>$ curl -F file=@"F://movies//300//Sample.mkv" http://localhost:8080/api/upload/ Attachment size exceeds the allowable limit! (10MB)</code></pre> <h2>十、curl测试加自定义错误对象测试</h2> 10.1创建一个自定义对象去存放异常信息<br /> <strong>CustomError.java</strong> <pre> <code class="language-java">public class CustomError { String errCode; String errDesc; public CustomError(String errCode, String errDesc) { this.errCode = errCode; this.errDesc = errDesc; } //getters and setters }</code></pre> 10.2更新全局的异常拦截支持自定义异常信息<br /> <strong>RestGlobalExceptionHandler.java</strong> <pre> <code class="language-java">import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import javax.servlet.http.HttpServletRequest; @ControllerAdvice public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(MultipartException.class) @ResponseBody ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) { HttpStatus status = getStatus(request); return new ResponseEntity(new CustomError("0x000123", "Attachment size exceeds the allowable limit! (10MB)"), status); //return new ResponseEntity("Attachment size exceeds the allowable limit! (10MB)", status); } private HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } return HttpStatus.valueOf(statusCode); } }</code></pre> <br /> 10.3再次上传一个大文件 <pre> <code>$ curl -F file=@"F://movies//300//Sample.mkv" http://localhost:8080/api/upload/ {"errCode":"0x000123","errDesc":"Attachment size exceeds the allowable limit! (10MB)"}</code></pre> <br /> <a href="http://www.mkyong.com/wp-content/uploads/2017/01/spring-boot-file-upload-ajax-rest.zip" rel="external nofollow" target="_blank">demo项目下载</a>
  • Spring 5 WebClient和WebTestClient使用教程

    1.引言Spring开发人员,您是否曾经觉得需要一个易于使用且高效的流畅功能样式 API 的异步/非阻塞 HTTP客户端?如果是,那么我欢迎您阅读关于WebClient的文章,WebClient是Spring 5中引入的新的被动HTTP客户1.引言Spring开发人员,您是否曾经觉得需要一个易于使用且高效的流畅功能样式 API 的异步/非阻塞 HTTP客户端?如果是,那么我欢迎您阅读关于WebClient的文章,WebClient是Spring 5中引入的新的被动HTTP客户端。2.如何使用WebClientWebClient是Spring 5的反应性Web框架Spring WebFlux的一部分。要使用WebClient,您需要将spring-webflux模块包含在您的项目中。在现有的Spring Boot项目中添加依赖项如果您有一个现有的Spring Boot项目,则可以spring-webflux通过在该pom.xml文件中添加以下依赖项来添加该模块-<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>请注意,您需要Spring Boot 2.xx版本才能使用Spring WebFlux模块。从Scratch创建一个新项目如果您从头开始创建项目,那么您可以使用Spring Initializr网站的spring-webflux模块生成初始项目-转到http://start.spring.io。选择弹簧引导版本2.xx的。在依赖项部分添加反应性Web依赖项。如果需要,请更改组和工件的详细信息,然后单击生成工程下载项目。3.使用WebClient消费远程API让我们做一些有趣的事情,并使用WebClient来使用Real World API。在本文中,我们将使用WebClient来使用Github的API。我们将使用WebClient在用户的Github存储库上执行CRUD操作。创建WebClient的一个实例1.使用该create()方法创建WebClient您可以使用create()工厂方法创建WebClient的实例-WebClient webClient = WebClient.create();如果您只使用特定服务的API,那么您可以使用该服务的baseUrl来初始化WebClientWebClient webClient = WebClient.create("https://api.github.com");2.使用WebClient构建器创建WebClientWebClient还附带了一个构建器,它为您提供了一些自定义选项,包括过滤器,默认标题,cookie,客户端连接器等 -WebClient webClient = WebClient.builder() .baseUrl("https://api.github.com") .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.github.v3+json") .defaultHeader(HttpHeaders.USER_AGENT, "Spring 5 WebClient") .build();使用WebClient发出请求并检索响应以下是如何使用WebClient GET向Github的List Repositories API发出请求-public Flux<GithubRepo> listGithubRepositories(String username, String token) { return webClient.get() .uri("/user/repos") .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToFlux(GithubRepo.class); }了解API调用的简单性和简洁性!假设我们有一个名为类GithubRepo,确认到GitHub的API响应,上面的函数会返回一个Flux的GithubRepo对象。请注意,我使用Github的基本认证机制来调用API。它需要您的github用户名和个人访问令牌,您可以从https://github.com/settings/tokens中生成该令牌。使用exchange()方法来检索响应该retrieve()方法是获取响应主体的最简单方法。但是,如果您希望对响应拥有更多的控制权,那么您可以使用可exchange()访问整个ClientResponse标题和正文的方法 -public Flux<GithubRepo> listGithubRepositories(String username, String token) { return webClient.get() .uri("/user/repos") .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .exchange() .flatMapMany(clientResponse -> clientResponse.bodyToFlux(GithubRepo.class)); }在请求URI中使用参数您可以在请求URI中使用参数,并在uri()函数中分别传递它们的值。所有参数都被花括号包围。在提出请求之前,这些参数将被WebClient自动替换 -public Flux<GithubRepo> listGithubRepositories(String username, String token) { return webClient.get() .uri("/user/repos?sort={sortField}&direction={sortDirection}", "updated", "desc") .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToFlux(GithubRepo.class); }使用URIBuilder构造请求URI您也可以使用UriBuilder类似的方法获取对请求URI的完全程序控制,public Flux<GithubRepo> listGithubRepositories(String username, String token) { return webClient.get() .uri(uriBuilder -> uriBuilder.path("/user/repos") .queryParam("sort", "updated") .queryParam("direction", "desc") .build()) .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToFlux(GithubRepo.class); }在WebClient请求中传递Request Body如果你有一个Mono或一个形式的请求体Flux,那么你可以直接将它传递给body()WebClient中的方法,否则你可以从一个对象中创建一个单声道/通量并像这样传递 -public Mono<GithubRepo> createGithubRepository(String username, String token, RepoRequest createRepoRequest) { return webClient.post() .uri("/user/repos") .body(Mono.just(createRepoRequest), RepoRequest.class) .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToMono(GithubRepo.class); }如果您具有实际值而不是Publisher(Flux/ Mono),则可以使用syncBody()快捷方式传递请求正文 -public Mono<GithubRepo> createGithubRepository(String username, String token, RepoRequest createRepoRequest) { return webClient.post() .uri("/user/repos") .syncBody(createRepoRequest) .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToMono(GithubRepo.class); } 最后,你可以使用BodyInserters类提供的各种工厂方法来构造一个BodyInserter对象并将其传递给该body()方法。本BodyInserters类包含的方法来创建一个BodyInserter从Object,Publisher,Resource,FormData,MultipartData等-public Mono<GithubRepo> createGithubRepository(String username, String token, RepoRequest createRepoRequest) { return webClient.post() .uri("/user/repos") .body(BodyInserters.fromObject(createRepoRequest)) .header("Authorization", "Basic " + Base64Utils .encodeToString((username + ":" + token).getBytes(UTF_8))) .retrieve() .bodyToMono(GithubRepo.class); }添加过滤器功能WebClient支持使用ExchangeFilterFunction。您可以使用过滤器函数以任何方式拦截和修改请求。例如,您可以使用过滤器函数为Authorization每个请求添加一个标头,或记录每个请求的详细信息。这ExchangeFilterFunction需要两个参数 -在ClientRequest与ExchangeFilterFunction过滤器链中的下一个。它可以修改ClientRequest并调用ExchangeFilterFucntion过滤器链中的下一个来继续下一个过滤器或ClientRequest直接返回修改以阻止过滤器链。1.使用过滤器功能添加基本认证在上面的所有示例中,我们都包含一个Authorization用于使用Github API进行基本身份验证的标头。由于这是所有请求共有的内容,因此您可以在创建过滤器函数时将此逻辑添加到过滤器函数中WebClient。该ExchaneFilterFunctionsAPI已经为基本认证提供了一个过滤器。你可以像这样使用它 -WebClient webClient = WebClient.builder() .baseUrl(GITHUB_API_BASE_URL) .defaultHeader(HttpHeaders.CONTENT_TYPE, GITHUB_V3_MIME_TYPE) .filter(ExchangeFilterFunctions .basicAuthentication(username, token)) .build();现在,您不需要Authorization在每个请求中添加标题。过滤器函数将拦截每个WebClient请求添加此标头。2.使用过滤器功能记录所有请求我们来看一个习惯的例子ExchangeFilterFunction。我们将编写一个过滤器函数来拦截并记录每个请求 -WebClient webClient = WebClient.builder() .baseUrl(GITHUB_API_BASE_URL) .defaultHeader(HttpHeaders.CONTENT_TYPE, GITHUB_V3_MIME_TYPE) .filter(ExchangeFilterFunctions .basicAuthentication(username, token)) .filter(logRequest()) .build(); 这里是logRequest()过滤器功能的实现-private ExchangeFilterFunction logRequest() { return (clientRequest, next) -> { logger.info("Request: {} {}", clientRequest.method(), clientRequest.url()); clientRequest.headers() .forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value))); return next.exchange(clientRequest); }; }3.使用ofRequestProcessor()和ofResponseProcessor()工厂方法来创建过滤器ExchangeFilterFunction API提供两个名为工厂方法ofRequestProcessor()和ofResponseProcessor()用于创建分别截获该请求和响应滤波器的功能。logRequest()我们在前一节中创建的过滤器函数可以使用ofRequestProcessor()这种工厂方法创建-private ExchangeFilterFunction logRequest() { ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { logger.info("Request: {} {}", clientRequest.method(), clientRequest.url()); clientRequest.headers() .forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value))); return Mono.just(clientRequest); }); } 如果您想拦截WebClient响应,则可以使用该ofResponseProcessor()方法创建像这样的过滤器功能 -private ExchangeFilterFunction logResposneStatus() { return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> { logger.info("Response Status {}", clientResponse.statusCode()); return Mono.just(clientResponse); }); }处理WebClient错误只要接收到状态码为4xx或5xx的响应retrieve(),WebClient中的方法WebClientResponseException就会抛出一个。您可以使用onStatus()像这样的方法来自定义,public Flux<GithubRepo> listGithubRepositories() { return webClient.get() .uri("/user/repos?sort={sortField}&direction={sortDirection}", "updated", "desc") .retrieve() .onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new MyCustomClientException()) ) .onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new MyCustomServerException()) ) .bodyToFlux(GithubRepo.class); }请注意,与retrieve()方法不同,该exchange()方法在4xx或5xx响应的情况下不会引发异常。您需要自己检查状态代码,并以您想要的方式处理它们。使用@ExceptionHandler控制器内部的WebClientResponseExceptions处理您可以@ExceptionHandler在控制器内部使用这种方式来处理WebClientResponseException并返回适当的响应给客户端 -@ExceptionHandler(WebClientResponseException.class) public ResponseEntity<String> handleWebClientResponseException(WebClientResponseException ex) { logger.error("Error from WebClient - Status {}, Body {}", ex.getRawStatusCode(), ex.getResponseBodyAsString(), ex); return ResponseEntity.status(ex.getRawStatusCode()).body(ex.getResponseBodyAsString()); }使用Spring 5 WebTestClient测试Rest APIWebTestClient包含类似于WebClient的请求方法。另外,它还包含检查响应状态,标题和正文的方法。您也可以像AssertJ使用WebTestClient 一样使用断言库。查看以下示例以了解如何使用WebTestClient执行其他API测试 -提示:项目源码下载spring-webclient-webtestclient-demo-master.zip