首先看下前端wangEditor的配置:
//wangEditor的配置
var E = window.wangEditor
var editor = new E('#editor')
//开启wangEditor的调试模式
/*editor.customConfig.debug = true;*/
//上传地址
editor.customConfig.uploadImgServer = 'http://***';
editor.customConfig.uploadFileName = 'file';
editor.customConfig.uploadImgParams = {
project: 'xxx' // 需要传递的参数
};
//将传递的参数拼接到上传地址后面
editor.customConfig.uploadImgParamsWithUrl = true;
editor.create();
后端jfinal 接收,直接看代码:
private final int MAXSize = 1 * 1024 * 1024; // 1M
private String webPath = "/statics/upload/" ;
//图片上传目录
private String filedir = PathKit.getWebRootPath() + webPath;
//线上图片地址
private String host = "http://xxx";
public void commUpload(){
//允许任何请求访问
getResponse().setHeader("Access-Control-Allow-Origin", "*");
getResponse().setHeader("Access-Control-Allow-Headers", "Content-Length,X-Requested-With,content-type");
getResponse().setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
//是否跨域的验证请求
if(getRequest().getMethod().equals("OPTIONS")){
valueNull();
return;
}
//此参数用来指定存储在哪个文件夹; 比如商品就存储goods ; 目录不存在将自动创建
if(!StrKit.notBlank(getPara("path"),getPara("project"))){
valueNull();
return;
}
//所有图片按年月分类
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMM");
String date = formatter.format(new Date());
//最终需要存储的目录
String path = getPara("project") + "/" + getPara("path") + "/" + date;
//接收图片并上传
UploadFile uf = getFile("file", path,MAXSize);
if(uf != null){
//重命名图片
File oldFile = new File(filedir + path + "/" + uf.getOriginalFileName());
if (oldFile.exists()) {
//获取原文件的后缀名
String fileName = oldFile.getName();
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
//生成新文件的文件名 -- 项目文件夹 + 三个‘_’下划线 + 自动生成的 . ***
String newFileName = getPara("project") + "___" + StrKit.getRandomUUID() + "." + suffix ;
//重命名
if(uf.getFile().renameTo(new File(filedir + path + "/" + newFileName))){
setAttr("errno", 0);
JSONArray jsonarray = new JSONArray();
jsonarray.add(host + webPath + path + "/" + newFileName);
setAttr("data", jsonarray);
}
else{
setAttr("errno", 1);
}
}
else{
setAttr("errno", 2);
}
}
else{
//不存在图片
setAttr("errno", 3);
}
renderJson();
}
解惑开始:
getResponse().setHeader("Access-Control-Allow-Origin", "*");
这段就是告诉浏览器支持所有跨域请求; 当然,你可以将 * 号修改为指定的域名用来限制;
对于跨域请求,浏览器会首先发送一个 OPTIONS 请求,来验证请求地址是否支持跨域:
如果验证成功,将会再次发送一个 post 请求来上传图片;
所以跨域一般都会执行两次请求;
另外,jfinal的 getFile() 方法支持post请求,且提交的编码方式为 multipart/form-data,
但是,千万不要在 wangEditor的配置中去特意注明:
editor.customConfig.uploadImgHeaders = { 'Content-Type' : 'multipart/form-data' };
否则 getFile() 会给你一段错误,如下:
java.lang.RuntimeException: java.io.IOException: Separation boundary was not specified
at com.jfinal.upload.MultipartRequest.wrapMultipartRequest(MultipartRequest.java:126)
at com.jfinal.upload.MultipartRequest.<init>(MultipartRequest.java:58)
at com.jfinal.core.Controller.getFiles(Controller.java:789)
at com.jfinal.core.Controller.getFile(Controller.java:794)
at controller.UploadPic.start(UploadPic.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.jfinal.aop.Invocation.invoke(Invocation.java:73)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:91)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:73)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Separation boundary was not specified
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:182)
at com.oreilly.servlet.MultipartRequest.<init>(MultipartRequest.java:224)
at com.jfinal.upload.MultipartRequest.wrapMultipartRequest(MultipartRequest.java:107)
... 27 more
这段错误大致意思是 Content-Type 没有指定边界;因为 multipart/form-data 这种编码方式提交是分段提交,每一段得有个boundary(边界)去隔开; 所以在google 浏览器 F12 中可以看到 ,Content-Type 必须是这种格式的。