之前工作中遇到了表单跨域上传的问题,寻觅了挺久,才找到解决方法,在此记录。
一、使用from表单上传
工作原理:直接表单提交,访问ssc_media的对应接口
架构说明:使用的是SpringBoot微服务架构,ssc_web负责前端页面和实现对应的后台接口。 ssc_media负责把图片和文件上传到mongodb。
${temp}:使用了thymeleaf模块,是一个url路径,指向ssc_media模块的上传文件接口。
<body>
<!--直接调用media模块的接口--> <form id= "uploadForm" th:action= "${temp}" method= "post" enctype ="multipart/form-data"> <h1 >测试通过Rest接口上传文件 </h1> <p >上传文件: <input type ="file" name="file" /></p> <input type ="submit" value="上传"/> </form>
</body>
当点击“上传”按钮时,会采用“表单提交”方式上传图片,跳转到ssc_media模块的相关接口。
缺点是:“表单提交”方式上传成功后,会刷新页面。本项目要求:页面局部刷新。
二、ajax提交
工作原理:把ssc_web的后台接口当中间层,转发文件流到ssc_media的相关接口
html:
<body>
<!--直接调用media模块的接口-->
<form id= "uploadForm" enctype ="multipart/form-data">
<p >上传文件: <input type ="file" name="file"/></p>
<input type="button" value="上传" onclick="doUpload()"/>
</form>
<script language="JavaScript">
<![CDATA[
function doUpload() { var formData = new FormData($( "#uploadForm" )[0]); $.ajax({ url: "/web/retailer/lotus/outlet/014/uploadDmImg/1" , type: 'POST', data: formData, async: false, cache: false, contentType: false, processData: false, success: function (returndata) { var obj = eval('(' + returndata + ')'); alert(obj.data.image); }, error: function (returndata) { alert("no"); } }); } ]]> </script> </body>
ssc_web的DmController.java:
/** * 上传图片 * @param retailerCode * @param outletExternalId * @param dmId * @throws IOException */ @RequestMapping(value = "/{retailerCode}/outlet/{outletExternalId}/uploadDmImg/{dmId}", method = RequestMethod.POST ) @ResponseBody public String uploadDmImg(@PathVariable("retailerCode") String retailerCode, @PathVariable("outletExternalId") String outletExternalId, @PathVariable("dmId") Long dmId,@RequestParam("file") MultipartFile multipartFile) throws IOException { String url = "http://172.19.155.33:9999/media/image/uploadDm?retailerCode="+retailerCode+"&isThumbnail=false&outletExternalId="+outletExternalId+"&dmId="+dmId; return postFile(url,multipartFile); }
//拼请求头,ssc_media的接口要求接收MultipartFile类型文件 public String postFile(String urlStr,MultipartFile multipartFile) throws IOException { String end = "\r\n"; String twoHyphens = "--"; String boundary = "******"; URL url = new URL(urlStr); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestMethod("POST"); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); httpURLConnection.setConnectTimeout(30000); // 必须在Content-Type请求头中指定分界符中的任意字符串 httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); //获取输出流对象,预备上传文件 DataOutputStream dos = new DataOutputStream(httpURLConnection .getOutputStream()); //设置分界符,加end表示单独一行 dos.writeBytes(twoHyphens + boundary + end); //设置与上传文件相关的信息 String filename = multipartFile.getOriginalFilename(); dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename.substring(filename.lastIndexOf("/") + 1) + "\"" + end); //在上传文件信息与文件的内容之间必须有一个空行 dos.writeBytes(end); InputStream fis = multipartFile.getInputStream(); byte[] buffer = new byte[8192]; // 8k int count = 0; while ((count = fis.read(buffer)) != -1) { dos.write(buffer, 0, count); } fis.close(); dos.writeBytes(end); dos.writeBytes(twoHyphens + boundary + twoHyphens + end); dos.flush(); InputStream is = httpURLConnection.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); String result = br.readLine(); System.out.println("result = " + result); dos.close(); is.close(); return result; }
ssc_meida的ImageControlle.java:
@RequestMapping(value = "/uploadDm", method = RequestMethod.POST) public RspVo<DmImageInfoVo> uploadDm(String retailerCode, String outletExternalId, Long dmId, Boolean isThumbnail, @RequestParam("file") MultipartFile file) { //实现逻辑。。。。。。。。 }
额外话题:
1、若要局部刷新页面,必须是:
<input type="button" value="确定" />
若是:
<button value="确定" /> 或者 <input type="submit" value="确定" />
会刷新页面。