集群模式是为了满足分布式环境下多用户并发需求,分担单个服务器的压力,预防因单个服务器超载导致宕机引起的风险,所以集群模式开发软件是当下的一种趋势。集群部署如下图:
系统中最初考虑将图片以二进制形式保存在顶层数据库中,这样在每台客户端都能够预览图片,但是这样会给数据库带来很大的负担,不是一个好的方案,针对性的我们提出将图片保存在服务器上,数据库中创建一张材料清单与图片路径的映射表,每次预览时现根据映射表查出图片路径,然后将图片以二进制流的形式回写到页面实现预览。但是这里有一个问题,就是用户上传的图片只能上传到自己配置的那台服务器上,对于连接其他服务器的用户来说,数据库中虽然有了映射表,但是服务器指定路径下没有这些图片,从而造成数据不一致问题。如何解决这一问题呢?我们经过思考讨论提出了进行文件同步分发,这样每个服务器上都有一份一模一样的文件,路径也相同,从而实现了集群环境下的数据同步。
还有一个问题就是怎样一个性上传多个具有图片和材料清单映射关系的图片呢,我们知道多图片上传插件uploadify可以同时上传多个文件,他的上传原理是先把你选取的文件放入到待上传队列中,然后再从队列中逐个出队列上传,这种方式很好,但是缺乏我们需要的映射关系,所以我们没有采取这种上传方式。我们的思路是:
1)每次选取完单个图片的时候都立即将其上传到服务器上的一个临时文件夹下面,并且将文件名改写成我们需要的文件名,上传完后将该文件名回写到页面。
2)选择完所有的图片后,点击确认按钮时,将材料清单编码和图片名拼成一个长字符串,如:arrClqdAndImg=01@01.jpg;02@02.png;03@03.jpeg;提交到后台。
3)后台对arrClqdAndImg进行拆分,在临时路径下找图片,然后将该图片从临时文件夹temp下面复制到真正的文件夹ImgSrc下面,并且往映射表里插入一条映射记录。
4)配置其他服务器的配置文件,如
<?xml version="1.0" encoding="UTF-8"?>
<server>
<item>http://127.0.0.1:8090/xxx/xxx/xxx!xxx.do</item>
</server>
在同步分发的时候先解析这个xml,获得路径,遍历本地的资源文件夹ImgSrc,利用HttpClient将文件同步分发到其他服务器上,
/**
* 解析分发路径Xml,通过httpClient调用分发函数
* @return
*/
public static String uploadingRemoteImgFile(String folder_name){
try {
UploadingAction ua=new UploadingAction();
String realpath = ServletActionContext.getServletContext()
.getRealPath("/")+"\\sourceImg\\"+folder_name;//获取服务器路径
//同步其他服务器
String url = "";
if (ua.getClass().getClassLoader().getResource("/") == null) {
url = System.getProperty("user.dir") + "\\etc\\" + "file_distribute.xml";
} else {
url = URLDecoder.decode(ua.getClass().getClassLoader().getResource("/").getPath(), "utf-8")
+ "file_distribute.xml";
}
SAXBuilder builder = new SAXBuilder();
FileInputStream file = new FileInputStream(url);//xml文件
Document document = builder.build(file);
Element root = document.getRootElement();
List<Element> ls_scheme = root.getChildren();
for (Element item : ls_scheme) {
String uploaurl=item.getText();//得到上传路径
//遍历文件夹
File folder= new File(realpath);
if(folder.exists()){//文件夹存在
File[] array = folder.listFiles();
for(int i=0;i<array.length;i++){
if(array[i].isFile()){
String newFileName=array[i].getName();
HttpClientFactory.fileupLoad(uploaurl,newFileName,realpath,folder_name);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "uploadingRemoteImgFile";
}
/*
* uri 要上传的服务器连接 http://ip:port/studentMgt/uploading!distributeFile.do
* fileName :文件名称
* path:本地文件绝对路径
*
* */
public static String fileupLoad(String uri,String fileName,String path,String folderName) throws ClientProtocolException, IOException{
System.out.println("源文件:"+path +"\\"+ fileName);
HttpPost httppost = new HttpPost(uri);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(3000).build();
httppost.setConfig(requestConfig);
FileBody bin = new FileBody(new File(path +"\\"+ fileName));
StringBody file_name = new StringBody(
fileName, ContentType.create(
"text/plain", Consts.UTF_8));
StringBody folder_name = new StringBody(
folderName, ContentType.create(
"text/plain", Consts.UTF_8));
//以浏览器兼容模式运行,防止文件名乱码。
HttpEntity reqEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addPart("multipartFile", bin)
.addPart("folderName", folder_name).setCharset(CharsetUtils.get("UTF-8"))
.addPart("fileName", file_name).setCharset(CharsetUtils.get("UTF-8")).build();
httppost.setEntity(reqEntity);
ResponseHandler<String> rh = new ResponseHandler<String>() {
@Override
public String handleResponse(
final HttpResponse response) throws IOException {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300) {
System.out.println("$$$statuscode="+statusLine.getStatusCode());
throw new HttpResponseException(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
if (entity == null) {
throw new ClientProtocolException("Response contains no content");
}
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
//System.out.println("entity length:"+entity.getContentLength());
InputStream instream = entity.getContent();
try {
//instream.available() 网络如果阻塞的话,instream.available()只是阻塞之前的长度,因此在网络环境下该函数不靠谱
StringBuffer out = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = instream.read(b)) != -1;) {
out.append(new String(b, 0, n,charset));
}
out.toString();
return out.toString();
}catch(Exception ex){
ex.printStackTrace();
}
return null;
}
};
try{
return httpClient.execute(httppost, rh).trim();
}catch(ConnectTimeoutException e){
return "timeout";
}catch(SocketTimeoutException e){
return "timeout";
}catch(Exception e){
return e.toString();
}
}
分发函数
public String distributeFile(){
try {
System.out.println("distributeFile()开始-----------------");
//绝多路径
String realpath = ServletActionContext.getServletContext().getRealPath("/");
String targetDirectory = realpath+"\\sourceImg\\"+folderName;//真实保存绝对路径
if (null!=multipartFile){
File saveFile=new File(targetDirectory+"\\"+fileName);
if(saveFile.exists()){//如果该文件已存在就删除
saveFile.delete();
}
System.out.println("multipartFile="+multipartFile.getAbsolutePath());
System.out.println("saveFile="+saveFile.getAbsolutePath());
FileUtils.copyFile(multipartFile, saveFile);
// copyFile(multipartFile,saveFile);
}else{
System.err.println("参数为空!");
mess="1";
return mess;
}
//交给 处理线程
mess="0";
} catch (Exception e) {
mess="1";
e.printStackTrace();
}
return "mess";
}