分布式部署多服务部署,往往需要把图片单独分离出来,于是便想到了nginx的增强版openresty。nginx虽然可以作为静态资源服务器,接收图片上传、下载,但openresty作为nginx的升级版,提供了大量精良lua、第三方库,为广大开发者所喜爱,比nginx是更胜一筹。
一、openresty安装
1、安装依赖
$ yum install pcre-devel openssl-devel gcc curl postgresql-devel
2、下载解压
去http://openresty.org/cn/download.html下载最新源码包,如openresty-1.13.6.2.tar.gz
解压$ tar -zxvf openresty-1.13.6.2.tar.gz
进入解压目录$ cd openresty-1.13.6.2 配置安装
3、编译安装
配置 $ ./configure(不配置默认安装在/usr/local/openresty)
还可以指定路径选项配置
$./configure --prefix=/usr/local/openresty \
--with-luajit \
--without-http_redis2_module \
--with-http_iconv_module \
--with-http_postgres_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-http_gzip_static_module
编译 $ make
安装 $ make install
二、openresty配置
nginx.conf中的server配置文件如下
server {
listen 8086;
server_name localhost;
charset utf-8;
#图片读取路径
location ^~ /images {
default_type ""; #默认类型,给浏览器解释
root /opt/project/resource;
autoindex on;#开启目录访问,默认off,不允许访问
autoindex_exact_size off;#关闭具体大小,显示kb或mb或gb;
autoindex_localtime on;#显示服务器的文件修改时间,默认off,不显示
}
#图片上传路径
location ^~ /uploadfile {
#lua脚本路径,脚本需要编写
content_by_lua_file '/usr/local/openresty/lua/file/uploadfile.lua';
}
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
三、lua脚本接收上传
把uploadfile.lua脚本放到/usr/local/openresty/lua/file,uploadfile.lua脚本如下
package.path = '/usr/local/openresty/lualib/resty/?.lua;'
local upload = require "upload"
local chunk_size = 4096
local form = upload:new(chunk_size)
local file
local filelen=0
form:set_timeout(0) -- 1 sec
local filename
-- 设置上传的根路径
local osfilepath = "/opt/project/resource/images/"
-- 获取文件名字
function get_filename(res)
local filename = ngx.re.match(res,'(.+)filename="(.+)"(.*)')
if filename then
return filename[2]
end
end
-- relname是相对路径文件名,创建不存在路径
function file_exists(relname)
local path = osfilepath .. relname
local abspath=string.match(path, "(.+)/[^/]*%.%w+$")
testfile,errs = io.open(abspath,"rb")
if not testfile then
ngx.log(ngx.ERR,errs)
local md="mkdir -p "
local mdpath=md .. abspath
ngx.log(ngx.ERR,"not exist! start mkdir "..abspath)
os.execute(mdpath)
else
testfile:close()
end
end
local i=0
-- 循环true 一直接收上传
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("failed to read: ", err)
return
end
if typ == "header" then
if res[1] ~= "Content-Type" then
filename = get_filename(res[2])
file_exists(filename) -- 判断子文件夹是否存在,不存在创建
if filename then
i=i+1
filepath = osfilepath .. filename
-- 已只写方式打开
file,err = io.open(filepath,"w")
if not file then
ngx.say("failed to open file ")
ngx.log(ngx.ERR,err)
return
end
else
end
end
elseif typ == "body" then
if file then
filelen= filelen + tonumber(string.len(res))
file:write(res)
else
end
elseif typ == "part_end" then
if file then
file:close()
file = nil
-- 上传成功,客户端判断是否成功
ngx.say("upload-success")
end
elseif typ == "eof" then
break
else
end
end
if i==0 then
ngx.say("please upload at least one file!")
return
end
四、启动openresty
(1)指定配置文件启动
/usr/local/openresty/nginx/sbin/nginx -c /usr/local/openresty/nginx/conf/nginx.conf
(2)访问http://192.168.1.72:8086/images查看,可以看到创建的文件夹
五、Java中转上传
以下提供了本地文件上传和中转文件上传方法:
1、本地文件上传测试
(1)测试代码入下
public static void main(String[] args) {
String url="http://192.168.1.72:8086/uploadfile";//nginx上传请求地址
// /opt/resource/images/是根路径,上传到/opt/resource/images/user/head/下
String uploadPath="user/head/";//相对子路径
String filePath="C:/Users/line/Desktop/20180525181332442.png";//本地window路径
FileUploadUtil.localFileUpload(url, uploadPath, filePath);
}
(2)浏览器访看到图片已经上传
2、接收前端中转测试
(1)控制层接收前端上传
@PostMapping("/admin/upload")
public String upload(@RequestParam("file")MultipartFile file) throws IOException {
String url = "http://192.168.1.72:8086/uploadfile";//nginx文件上传地址
String path = "user/head/";//上传服务器相对子路径,不设置默认上传nginx中设置的路径
String originalFilename=file.getOriginalFilename();//原始文件名,要判断浏览器兼容性
String fileName = path+originalFilename;//新文件名
byte[] fileBytes = file.getBytes();//文件字节流
String result = FileUploadUtil.deliverFileUpload(url,fileName,fileBytes);
return result;
}
(2) 浏览器表单上传文件
html上传代码
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="/front/upload" enctype="multipart/form-data" method="post">
<p>上传文件: <input type="file" name="file"/></p>
<input type="submit" value="上传" >
</form>
</body>
</html>
选择图片进行上传
(3) 浏览器访看到图片已经上传
3、 文件上传工具类
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class FileUploadUtil {
/**
* 本地文件上传
* @param url nginx上传地址
* @param uploadPath 服务器文件存储相对路径,如:user/head/。若此参数为null默认上传到nginx中设置的根路径下
* @param filePath 本地文件全路径名
* @return
*/
public static String localFileUpload(String url,String uploadPath,String filePath) {
//构建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String result="";
try {
File file = new File(filePath);//要上传的文件
String fullPathFileName=uploadPath+file.getName();//存储路径拼接文件名
FileBody fileBody = new FileBody(file,ContentType.MULTIPART_FORM_DATA,fullPathFileName); //构建文件体
HttpPost httpPost = new HttpPost(url);//构建POST请求
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式
builder.addPart("uploadFile", fileBody);//相当于表单name
HttpEntity httpEntity = builder.build();
httpPost.setEntity(httpEntity);
HttpResponse response = httpClient.execute(httpPost); //发送请求
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
EntityUtils.consume(responseEntity);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(httpClient != null){
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
/**
* 接收前端的文件,进行中转上传
* @param url nginx的上传地址
* @param fileName 文件名
* @param fileByte 文件转化后的字节流
* <p>example: {@code (MultipartFile file) byte[] fileBytes = file.getBytes();}</p>
* @return
*/
public static String deliverFileUpload(String url,String fileName, byte[] fileByte) {
CloseableHttpClient httpClient = HttpClients.createDefault();
String result = "";
try {
HttpPost httpPost = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//默认上传到nginx设置的根目录,若上传到指定子路径,可拼接路径名 。如:fileName=user/head/20190501.png
builder.addBinaryBody("uploadFile", fileByte, ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
builder.addTextBody("filename", fileName);// 类似浏览器表单提交,对应input的name和value
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);// 执行提交
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
EntityUtils.consume(responseEntity);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (httpClient!=null) {
httpClient.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
参考:https://github.com/openresty/lua-resty-upload
参考:http://moguhu.com/article/detail?articleId=19