openresty做静态资源服务器(接收图片上传),


分布式部署多服务部署,往往需要把图片单独分离出来,于是便想到了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

 

相关内容

    暂无相关文章