大多数手机不支持文件上传控件,无法直接像电脑客户端一样上传文件到服务器。这里考虑通过邮件发送文件到服务器的方式来实现上传。
大概步骤如下:
step 1. 打开上传文件的页面时,生成uuid作为临时文件的名称
step 2. 页面里显示发送邮件的tag,通过邮件标题传递uuid,用户通过发送带附件的邮件来上传文件
step 3. 这一步是重点和难点。
首先,是配置邮件服务器,在接收到包含了附件的邮件时(某个指定邮件账户test@test.com接收到邮件时),触发脚本(test1.sh)。
然后,在脚本里面调用Java(Test2.java),传入的参数是接收到的邮件文件路径。
最后,Java里从邮件文件里读取出附件,然后访问Web服务器,把附件上传到Web服务器,保存为文件名包含uuid的临时文件。
step 4. 在页面点击更新按钮后,根据uuid从临时文件里找到匹配的上传文件,做对应业务处理。
基本思路就是这样子,当然真正去实现肯定要花费一发功夫的。这里写一下大概的实现代码
1. 使用java的java.util.UUID类生成uuid
String s = UUID.randomUUID().toString();
2. 页面的发送邮件tag和保持uuid的hidden tag
<a href="mailto:test@test.com?subject=7bcffff4-0f54-442e-8111-d698b88008ed">上传文件</a>
<input type="hidden" name="uuid" value="7bcffff4-0f54-442e-8111-d698b88008ed" />
3.配置邮件服务器,这里以postfix做例子
1) 在/etc/aliases里添加一行脚本来调用新建的脚本 test1.sh。test就是用于接收邮件的邮件账户。
添加完后需要执行newaliases命令重新载入。
test: "| /usr/local/etc/script/test1.sh"
2)脚本test1.sh,调用java程序Test2,传入的参数TMP_FILE是接收到的邮件文件。
#!/bin/sh
TMP_PATH=/tmp/
LOG_FILE=/tmp/test.log
read -rd '' s;
EXTENTION='_mail.tmp'
TMP_FILE=$TMP_PATH$RANDOM$EXTENTION
echo "$s" >> $TMP_FILE
cd /usr/local/etc/script
/usr/local/jdk6/bin/java -Djava.awt.headless=true -classpath ./:./lib/commons-logging-1.1.1.jar:./lib/httpclient-4.1.2.jar:./lib/httpcore-4.1.2.jar:./lib/httpmime-4.1.2.jar:./lib/mail.jar Test2 $TMP_FILE >> $LOG_FILE
rm -f $TMP_FILE
3)Test2.java的代码主要包含几个部分
a. 从邮件中抽取出附件的文件流、UUID等
String mimeType;
String attachmentOriginalFileName;
InputStream isMailAttachmentFile;
String uuid;
InputStream in = null;
try {
in = new FileInputStream(mailFilePath);
MimeMessage message = new MimeMessage(null, in);
Object obj = message.getContent();
// 取得uuid
uuid = message.getSubject();
// 取得附件
if ((obj instanceof MimeMultipart)) {
int count = ((MimeMultipart) obj).getCount();
for (int i = 0; i < count; i++) {
BodyPart bodyPart = ((MimeMultipart) obj).getBodyPart(i);
String disposition = bodyPart.getDisposition();
if (disposition != null && (disposition.equals(Part.ATTACHMENT)
|| disposition.equals(Part.INLINE))) {
mimeType = bodyPart.getContentType();
attachmentOriginalFileName = bodyPart.getFileName();
isMailAttachmentFile = bodyPart.getInputStream();
break;
}
}
} else {
if (message.getEncoding().equalsIgnoreCase("base64")) {
mimeType = message.getContentType();
attachmentOriginalFileName = message.getFileName();
isMailAttachmentFile = (BASE64DecoderStream) message.getContent();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
b.将附件的文件流保存为临时文件
File mailAttachmentTmpFile = null;
BufferedInputStream fileIn = null;
FileOutputStream fileOut = null;
try {
mailAttachmentTmpFile = File.createTempFile(tmpFileUUID, ".tmp");
fileIn = new BufferedInputStream(isMailAttachmentFile);
fileOut = new FileOutputStream(mailAttachmentTmpFile);
int data = -1;
while ((data = fileIn.read()) != -1) {
fileOut.write(data);
}
mailAttachmentTmpFile.deleteOnExit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fileOut != null) {
fileOut.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (fileIn != null) {
fileIn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
c. 访问Web服务器,将附件上传到Web服务器。使用apache的HttpClient。这里因为Web服务器的接收端是https,所以代码比较复杂。如果是http的话,会简单很多,具体的可以自己去google。
SSLContext sslContext = null;
HttpPost httpPost = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
} }, new SecureRandom());
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme httpsScheme = new Scheme("https", 443, socketFactory);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm);
HttpsURLConnection.setDefaultHostnameVerifier(SSLSocketFactory
.ALLOW_ALL_HOSTNAME_VERIFIER);
httpPost = new HttpPost("https://www.test.com/receive");
// post data
MultipartEntity multipart = new MultipartEntity();
FileBody fileBody = new FileBody(mailAttachmentTmpFile,
attachmentOriginalFileName, mimeType, charset);
multipart.addPart("answerFile", fileBody);
StringBody uuidBody = new StringBody(key);
multipart.addPart("uuid", uuidBody);
StringBody fileNameBody = new StringBody(URLEncoder
.encode(attachmentOriginalFileName, charset));
multipart.addPart("fileName", fileNameBody);
httpPost.setEntity(multipart);
// request
HttpResponse response = httpClient.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpPost != null) {
httpPost.abort();
}
}
这是我们公司做手机网站时,上传文件的实现方案。有什么不妥的地方,欢迎指正。也欢迎大家把自己好的方案共享出来,万分感谢。