openresty 이미지(파일)서버 구현
38953 단어 짜임새
앞 순서
이 기능 은 openresty 의 lua 스 크 립 트 를 이용 하여 이 루어 진 그림(파일)저장 기능 으로 파일 업로드 에 자바 코드 를 사용 하여 개발 한 것 입 니 다.
데이터 정의
업로드 데이터 와 파일 정 보 는 앞 뒤 를 가리 지 않 지만 시스템 은 마지막 한 쌍 의 정보 만 저장 합 니 다.
{"fileDir":" ","fileName":" "}
{"status":" ","result":" ","msg":" "}
enum status:["success","failed"]
Nginx 설정
다음 과 같다.
server {
listen 80;
server_name localhost;
#
set $prefix "/data";
location /uploadimage {
# lua ,
# lua_code_cache off;
# lua
content_by_lua_file /openresty-web/luascript/luascript;
}
# nginx
location /uploadtest{
# lua_code_cache off;
content_by_lua_file /openresty-web/luascript/luauploadtest;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
lua 스 크 립 트
luascript:
package.path = '/openresty-web/lualib/resty/?.lua;'
local upload = require "upload"
local cjson = require("cjson")
Result={status="success",result="",msg=""}
Result.__index=Result
function Result.conSuccess(ret)
ret["status"]="success"
ret["result"]="upload success"
return ret
end
function Result.conFailed(ret,err)
ret["status"]="failed"
ret["msg"]=err
ret["result"]="upload failed"
return ret
end
function Result:new()
local ret={}
setmetatable({},Result)
return ret
end
-- lua-resty-upload
local chunk_size = 4096
local form = upload:new(chunk_size)
if not form then
ngx.say(cjson.encode(Result.conFailed(Result:new(),"plase upload right info")))
return
end
local file
local filelen=0
form:set_timeout(0) -- 1 sec
local filename
local prefix=ngx.var.prefix
-- ,
function get_filename(res)
local filename = ngx.re.match(res,'(.+)filename="(.+)"(.*)')
if filename then
return filename[2]
end
end
-- ,
function openstream(fileinfo,opt)
local file,err=io.open(prefix..fileinfo["fileDir"],"r")
if not file then
local start=string.find(err,"No such file or directory")
if start then
local exeret=os.execute("mkdir -p "..prefix..fileinfo["fileDir"])
if exeret ~= 0 then
return nil,"Make directory failed"
end
else
return nil,err
end
end
file,err=io.open(prefix..fileinfo["fileDir"]..fileinfo["fileName"],opt)
return file,err
end
local osfilepath
local tmpfiletbl
local hasFile=false
local loopfile=false
local fileinfostr
local fileinfo
local result=Result:new()
--
while true do
local typ, res, err = form:read()
if not typ then
break
end
if typ == "header" then
if res[1] ~= "Content-Type" then
filename = get_filename(res[2])
if filename then
loopfile=true
hasFile=true
--
--
if fileinfo then
file,err=openstream(fileinfo,"w")
if not file then
break
end
else
tmpfiletbl={}
end
else
loopfile = false
fileinfostr = ""
end
end
end
if loopfile then
if typ == "body" then
if file then
filelen= filelen + tonumber(string.len(res))
file:write(res)
else
table.insert(tmpfiletbl,res)
end
elseif typ == "part_end" then
if file then
file:close()
file = nil
end
end
else
if typ == "body" then
fileinfostr=fileinfostr .. res
elseif typ == "part_end" then
fileinfo = cjson.decode(fileinfostr)
end
end
if typ == "eof" then
break
end
end
if not hasFile then
err="plase upload file"
elseif not fileinfo or not fileinfo["fileDir"] or not fileinfo["fileName"] then
err="plase offer file info"
end
if err then
ngx.log(ngx.ERR,err)
Result.conFailed(result,err)
ngx.say(cjson.encode(result))
return
end
--
--
if tmpfiletbl and table.getn(tmpfiletbl) > 0 then
file,err=openstream(fileinfo,"w")
if not file then
ngx.log(ngx.ERR,err)
Result.conFailed(result,err)
ngx.say(cjson.encode(result))
return
else
for index,value in ipairs(tmpfiletbl)
do
filelen= filelen + tonumber(string.len(value))
file:write(value)
end
file:close()
file=nil
end
end
Result.conSuccess(result)
ngx.say(cjson.encode(result))
luauploadtest:
local upload = require "resty.upload"
local cjson = require "cjson"
local chunk_size = 5 -- should be set to 4096 or 8192
-- for real-world settings
local form, err = upload:new(chunk_size)
if not form then
ngx.log(ngx.ERR, "failed to new upload: ", err)
ngx.exit(500)
end
form:set_timeout(1000) -- 1 sec
while true do
local typ, res, err = form:read()
if not typ then
ngx.say("failed to read: ", err)
return
end
ngx.say("read: ", cjson.encode({typ, res}))
if typ == "eof" then
break
end
end
local typ, res, err = form:read()
ngx.say("read: ", cjson.encode({typ, res}))
luauploadtest 코드 는 공식 제공 코드 입 니 다.
Java
ImageServer:
package cn.com.cgbchina.image;
import cn.com.cgbchina.image.exception.ImageDeleteException;
import cn.com.cgbchina.image.exception.ImageUploadException;
import org.springframework.web.multipart.MultipartFile;
/**
* Created by 11140721050130 on 16-3-22.
*/
public interface ImageServer {
/**
*
*
* @param fileName
* @return
*/
boolean delete(String fileName) throws ImageDeleteException;
/**
*
* @param originalName
* @param file
* @return
*/
String upload(String originalName, MultipartFile file) throws ImageUploadException;
}
LuaResult:
package cn.com.cgbchina.image.nginx;
import lombok.Getter;
import lombok.Setter;
/**
* Comment: ,
* LuaImageServiceImpl ,
* Jackson ,
* Created by ldaokun2006 on 2017/10/24.
*/
@Setter
@Getter
public class LuaResult{
private LuaResultStatus status;
private String result;
private String msg;
private String httpUrl;
public LuaResult(){}
public void setStatus(String result){
status=LuaResultStatus.valueOf(result.toUpperCase());
}
public enum LuaResultStatus{
SUCCESS,FAILED;
}
}
ImageServerImpl:
package cn.com.cgbchina.image.nginx;
import cn.com.cgbchina.common.utils.DateHelper;
import cn.com.cgbchina.image.ImageServer;
import cn.com.cgbchina.image.exception.ImageDeleteException;
import cn.com.cgbchina.image.exception.ImageUploadException;
import com.github.kevinsawicki.http.HttpRequest;
import com.google.common.base.Splitter;
import com.spirit.util.JsonMapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Comment:
* Created by ldaokun2006 on 2017/10/16.
*/
@Service
@Slf4j
public class LuaImageServiceImpl implements ImageServer{
// nginx url ,
private List httpUrls;
private ExecutorService fixedThreadPool ;
private Integer timeout;
private int threadSize=50;
public LuaImageServiceImpl(String httpUrls){
this(httpUrls,30000);
}
/**
*
* @param httpUrls nginx url
* @param timeout http
*/
public LuaImageServiceImpl(String httpUrls,int timeout){
this.httpUrls=Splitter.on(";").splitToList(httpUrls);
// ,
this.fixedThreadPool= new ThreadPoolExecutor(threadSize, threadSize,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),new ThreadFactory(){
private final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
{
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "LuaUploadPool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
});
this.timeout=timeout;
}
/**
* Comment:
* @param fileName
* @return
* @throws ImageDeleteException
*/
@Override
public boolean delete(String fileName) throws ImageDeleteException {
return true;
}
/**
* Commont: SpringMVC
* @param originalName
* @param file
* @return
* @throws ImageUploadException
*/
@Override
public String upload(String originalName, MultipartFile file) throws ImageUploadException {
try {
return this.upload(originalName,file.getInputStream());
} catch (IOException e) {
log.error("upload fail : " + e.getMessage(), e);
throw new ImageUploadException("upload fail : "+e.getMessage(),e);
}
}
/**
* Commont:
* @param originalName
* @param inputStream
* @return
* @throws ImageUploadException
*/
private String upload(String originalName,InputStream inputStream) throws ImageUploadException {
ByteArrayOutputStream byteOutStream = null;
try {
//
byte[] tmpData=new byte[1024];
byte[] inputData;
byteOutStream = new ByteArrayOutputStream();
int len=0;
while((len=inputStream.read(tmpData,0,tmpData.length))!=-1){
byteOutStream.write(tmpData,0,len);
}
inputData=byteOutStream.toByteArray();
LuaSend sendInfo = new LuaSend(generateFileDir(),generateFileName(originalName));
List> resultList=new ArrayList<>(httpUrls.size());
//
for(String httpUrl:httpUrls) {
SendImg sendImg = new SendImg(httpUrl,sendInfo, inputData,this.timeout);
resultList.add(fixedThreadPool.submit(sendImg));
}
for(Future future:resultList) {
//
LuaResult resultLuaResult = future.get();
if (LuaResult.LuaResultStatus.SUCCESS != resultLuaResult.getStatus()) {
throw new ImageUploadException("lua result url:"+resultLuaResult.getHttpUrl()+" msg : " + resultLuaResult.getMsg());
}
}
return sendInfo.toString();
}catch (Exception e){
log.error("upload fail : "+e.getMessage(),e);
throw new ImageUploadException("upload fail : "+e.getMessage(),e);
}finally {
try {
if(byteOutStream!=null) {
byteOutStream.close();
}
if(inputStream!=null) {
inputStream.close();
}
} catch (IOException e) {
throw new ImageUploadException("upload fail : "+e.getMessage(),e);
}
}
}
String separator=File.separator;
String dateFormat=separator+"yyyy"+separator+"MM"+separator+"dd"+ separator;
/**
* Comment: ,
* @return
*/
private String generateFileDir(){
return DateHelper.date2string(new Date(),dateFormat);
}
/**
* Comment: UUID
* @param originalName
* @return
*/
private String generateFileName(String originalName){
return UUID.randomUUID().toString();
}
/**
* Comment:
*/
@AllArgsConstructor
class SendImg implements Callable{
private String httpUrl;
private LuaSend sendInfo;
private byte[] inputStream;
private Integer timeout;
@Override
public LuaResult call() throws Exception {
try {
String resultStr = HttpRequest
.post(httpUrl, false)
.part("fileInfo", JsonMapper.JSON_NON_EMPTY_MAPPER.toJson(sendInfo))
// ,part ,
// Content-Type fileName
.part("file", sendInfo.getFileName(), "multipart/form-data; boundary=00content0boundary00", new ByteArrayInputStream(inputStream))
.connectTimeout(timeout).body();
log.info("result:"+resultStr);
LuaResult result = JsonMapper.JSON_NON_DEFAULT_MAPPER.fromJson(resultStr, LuaResult.class);
result.setHttpUrl(httpUrl);
return result;
}catch(Exception e){
throw new ImageUploadException("upload failed url:"+httpUrl+" info:"+sendInfo.toString(),e);
}
}
}
/**
* Comment:
*/
@Setter
@Getter
@AllArgsConstructor
class LuaSend {
//
private String fileDir;
//
private String fileName;
@Override
public String toString(){
return fileDir+fileName;
}
}
/**
* Comment:
* @param args
* @throws ImageUploadException
* @throws FileNotFoundException
*/
public static void main(String[] args) throws ImageUploadException, FileNotFoundException {
LuaImageServiceImpl service=new LuaImageServiceImpl("http://192.168.99.102/uploadimage");
try {
System.out.println(service.upload("qqqqq", new FileInputStream("D:\\shsh.txt")));
}finally {
service.fixedThreadPool.shutdown();
}
}
}
총결산
이 가능 하 다,~할 수 있다,...
client_max_body_size 100M;
multipart/form-data;
boundary=00content0boundary00
.boundary 는 존재 해 야 합 니 다.그렇지 않 으 면 사용 하기 어렵 습 니 다nil
Content-type:multipart/form-data;
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
OpenResty 관련 nginx 및 lua 함수루 아 코드 를 어떻게 사용 하 는 지 소개 한다.두 가지 방법 이 있 습 니 다.첫 번 째, server 의 location 에 직접 삽입 합 니 다. Nginx subrequest 를 통 해 다른 location...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.