起步软件技术论坛
搜索
 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2006|回复: 8

[结贴] 关于文档上传时对文件进行加密

[复制链接]

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
发表于 2017-1-9 11:30:53 | 显示全部楼层 |阅读模式
平台版本5.2.7,现在要实现如下功能:
1、某业务功能中需要使用附件attachmentEditor2进行文档上传,在上传时对文件进行加密并保存在文档服务器上。
2、在该功能查询并下载附件时下载我们自行加密的文件(起步的加密只是保存在服务器上的时候加密了,下载到本地后不需要解密就可以直接查看,不符合客户要求),然后再用其他方式对加密的文件进行解密。

现在存在的问题如下:
1、开始的想法是想要在组件选择文件时获取到本地文件的路径,按照路径对文件加密后后台java代码上传文档。但是由于input file现在不能直接获取文件的实际路径了,所以拿不到。
2、如果不能拿到路径,那么我的想法是可不可以在执行form提交上传的时候把inputsteam拿到,然后把文件先保存在固定的临时文件夹内,然后加密再将文件上传,现在想按这个方法做,但是没找到表单提交时的相关代码,求告知。

91

主题

13万

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
35942
发表于 2017-1-9 14:20:20 | 显示全部楼层
远程的联系方法QQ1392416607,添加好友时,需在备注里注明其论坛名字及ID,公司等信息
发远程时同时也发一下帖子地址,方便了解要解决的问题  WeX5教程  WeX5下载



如按照该方法解决,请及时跟帖,便于版主结贴
回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 08:13:29 | 显示全部楼层
jishuang 发表于 2017-1-9 14:20
可以参考http://bbs.wex5.com/forum.php?mod=redirect&goto=findpost&ptid=76124&pid=165165322

<form method="post" action="UploadServlet" enctype="multipart/form-data">
    选择一个文件:
    <input type="file" name="uploadFile" />
    <br/><br/>
    <input type="submit" value="上传" />
</form>

我在本地MyEclipse中测试用这种上传方式拿到的InputStream是下面这样的:

--9HhjRQHYv1MaAnlDd0_nJ3qDmKlu2OrndmiDs46B
Content-Disposition: form-data; name="myfile"; filename="a.txt"
Content-Type: application/octet-stream; charset=ISO-8859-1

束带结发了看见圣诞快乐附件为了困扰剑灵开涉及到服了空间为了看人家凉快圣诞节f
凉快圣诞节弗兰克束带结发来看时间段分凉快圣诞节飞

--9HhjRQHYv1MaAnlDd0_nJ3qDmKlu2OrndmiDs46B--

但是在X5.2.7中测试拿到的是这样的:
--9HhjRQHYv1MaAnlDd0_nJ3qDmKlu2OrndmiDs46B
Content-Disposition: form-data; name="myfile"; filename="a.txt"
Content-Type: application/octet-stream; charset=ISO-8859-1


Content-Transfer-Encoding: binary


ntent-Transfer-Encoding: binary

束带结发了看见圣诞快乐附件为了困扰剑灵开涉及到服了空间为了看人家凉快圣诞节f
凉快圣诞节弗兰克束带结发来看时间段分凉快圣诞节飞

--9HhjRQHYv1MaAnlDd0_nJ3qDmKlu2OrndmiDs46B--

多了红色的部分,想问下,平台用的上传和我这个有什么区别么?在MyEclipse和平台来回调代码实在是费劲。

回复 支持 反对

使用道具 举报

91

主题

13万

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
35942
发表于 2017-1-12 10:06:26 | 显示全部楼层
确认servlet-api等相关的jar版本号都一致吗?

可以参考平台的excel导入文件上传的实现
/UI2/system/components/justep/excel/server/upload.j
远程的联系方法QQ1392416607,添加好友时,需在备注里注明其论坛名字及ID,公司等信息
发远程时同时也发一下帖子地址,方便了解要解决的问题  WeX5教程  WeX5下载



如按照该方法解决,请及时跟帖,便于版主结贴
回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 15:47:41 | 显示全部楼层
本帖最后由 Sunner 于 2017-1-12 15:56 编辑

完成了,总结如下:
1、过滤器:
  1. package com.cn;

  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.util.Enumeration;

  6. import javax.servlet.Filter;
  7. import javax.servlet.FilterChain;
  8. import javax.servlet.FilterConfig;
  9. import javax.servlet.ServletException;
  10. import javax.servlet.ServletRequest;
  11. import javax.servlet.ServletResponse;
  12. import javax.servlet.http.HttpServletRequest;
  13. import javax.servlet.http.HttpServletResponse;

  14. public class LWUploadFilter implements Filter {
  15.         public void destroy() {
  16.                 // TODO Auto-generated method stub

  17.         }

  18.         public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws IOException,
  19.                         ServletException {
  20.                 // TODO Auto-generated method stub
  21.                 HttpServletRequest req = (HttpServletRequest) servletrequest;
  22.                 HttpServletResponse res = (HttpServletResponse) servletresponse;
  23.                 Boolean actionIsUpload = false;
  24.                 Enumeration e = req.getHeaderNames();
  25.                 while (e.hasMoreElements()) {
  26.                         String name = (String) e.nextElement();
  27.                         if ("content-type".equals(name)) {
  28.                                 if ("multipart/form-data".equals(req.getHeader(name).split(";")[0])) {
  29.                                         actionIsUpload = true;
  30.                                 }
  31.                         }
  32.                 }
  33.                 if (actionIsUpload == true) {
  34.                         //如果是上传请求,则对request中文件流进行加密处理并包装
  35.                         req = new GetHttpServletRequestWrapper(req, res);
  36.                 }
  37.                 filterchain.doFilter(req, servletresponse);
  38.         }

  39.         public void init(FilterConfig arg0) throws ServletException {
  40.                 // TODO Auto-generated method stub
  41.         }

  42. }
复制代码



回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 15:57:56 | 显示全部楼层
2、解析request得到的文件流,拆分头尾,对真正的文件流进行加密,拼接头尾,然后包装返回
  1. package com.cn;
  2. import java.io.BufferedOutputStream;
  3. import java.io.BufferedReader;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.ByteArrayOutputStream;
  6. import java.io.DataInputStream;
  7. import java.io.DataOutputStream;
  8. import java.io.File;
  9. import java.io.FileInputStream;
  10. import java.io.FileNotFoundException;
  11. import java.io.FileOutputStream;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.io.InputStreamReader;
  15. import java.io.ObjectInputStream;
  16. import java.io.OutputStream;
  17. import java.io.StringReader;
  18. import java.io.UnsupportedEncodingException;
  19. import java.util.Arrays;
  20. import java.util.Enumeration;
  21. import java.util.HashMap;
  22. import java.util.Map;

  23. import javax.servlet.ServletInputStream;
  24. import javax.servlet.ServletRequest;
  25. import javax.servlet.http.HttpServletRequest;
  26. import javax.servlet.http.HttpServletRequestWrapper;
  27. import javax.servlet.http.HttpServletResponse;
  28. import javax.swing.JOptionPane;

  29. import org.apache.commons.lang.StringUtils;



  30. public final class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {
  31.         private byte[] buffer;
  32.         public GetHttpServletRequestWrapper(HttpServletRequest servletRequest,HttpServletResponse servletresponse) throws UnsupportedEncodingException {
  33.                 super(servletRequest);
  34.         }

  35.         public ServletInputStream getInputStream() {
  36.                 ServletInputStream retInStream = null;
  37.                 try {
  38.                         super.setCharacterEncoding("utf-8");
  39.                         final int NONE = 0; // 状态码,表示没有特殊操作
  40.                         final int DATAHEADER = 1; // 表示下一行要读到报头信息
  41.                         final int FILEDATA = 2; // 表示下面要读的是上传文件和二进制数据
  42.                         final int FIELDDATA = 3; // 表示下面要读到表单域的文本值
  43.                         // 请求消息实体的总长度(请求消息中除消息头之外的数据长度)
  44.                         Integer totalbytes = super.getContentLength();
  45.                         // 容纳请求消息实体的字节数组
  46.                         byte[] dataOrigin = new byte[totalbytes];
  47.                         // 对于post多个文件的表单,b作为原始数据的副本提供提取文件数据的操作
  48.                         byte[] b = new byte[totalbytes];
  49.                         // 请求消息类型
  50.                         String contentType = super.getContentType();
  51.                         String fieldname = ""; // 表单域的名称
  52.                         String fieldvalue = ""; // 表单域的值
  53.                         String fileFormName = ""; // 上传的文件再表单中的名称
  54.                         String fileRealName = ""; // 上传文件的真实名字
  55.                         String boundary = ""; // 分界符字符串
  56.                         String lastboundary = ""; // 结束分界符字符串
  57.                         String fileFullPath = ""; //文件路径
  58.                         String ecoding = "";
  59.                         String temp = "";
  60.                         String type = "";
  61.                         int fileSize = 0; // 文件长度
  62.                         File f; // 上传文件储存在服务器上
  63.                         // 容纳表单域的名称/值的哈希表
  64.                         Map<String, String> formfieldsTable = new HashMap<String, String>();
  65.                         // 容纳文件域的名称/文件名的哈希表
  66.                         Map<String, String> filenameTable = new HashMap<String, String>();
  67.                         int state = NONE; // 起始状态为NONE
  68.                         // 得到请求消息的数据输入流
  69.                         DataInputStream in = new DataInputStream(super.getInputStream());
  70.                         in.readFully(dataOrigin); // 根据长度,将消息实体的内容读入字节数组dataOrigin中
  71.                         in.close(); // 关闭数据流
  72.                         String reqcontent = new String(dataOrigin); // 从字节数组中得到表示实体的字符串
  73.                         // 从字符串中得到输出缓冲流
  74.                         BufferedReader reqbuf = new BufferedReader(new StringReader(
  75.                                         reqcontent));
  76.                         // 在消息头类型中找到分界符的定义
  77.                         int pos = contentType.indexOf("boundary=");
  78.                         int pos2; // position2
  79.                         if (pos != -1) {
  80.                                 pos += "boundary=".length();
  81.                                 boundary = "--" + contentType.substring(pos); // 解析出分界符
  82.                                 lastboundary = boundary + "--"; // 得到结束分界符
  83.                         }
  84.                         // 设置循环标志
  85.                         boolean flag = true;
  86.                         // int i = 0;
  87.                         while (flag == true) {
  88.                                 String s = reqbuf.readLine();
  89.                                 if (s == lastboundary || s == null)
  90.                                         break;
  91.                                 switch (state) {
  92.                                 case NONE:
  93.                                         if (s.startsWith(boundary)) {
  94.                                                 // 如果读到分界符,则表示下一行一个头信息
  95.                                                 state = DATAHEADER;
  96.                                                 // i += 1;
  97.                                         }
  98.                                         break;
  99.                                 case DATAHEADER:
  100.                                         pos = s.indexOf("filename=");
  101.                                         // 先判断出这是一个文本表单域的头信息,还是一个上传文件的头信息
  102.                                         if (pos == -1) {
  103.                                                 // 如果是文本表单域的头信息,解析出表单域的名称
  104.                                                 pos = s.indexOf("name=");
  105.                                                 pos += "name=".length() + 1; // 1表示后面的"的占位
  106.                                                 s = s.substring(pos);
  107.                                                 int l = s.length();
  108.                                                 s = s.substring(0, l - 1); // 应该是"
  109.                                                 fieldname = s; // 表单域的名称放入fieldname
  110.                                                 state = FIELDDATA; // 设置状态码,准备读取表单域的值
  111.                                         } else {
  112.                                                 // 如果是文件数据的头,先存储这一行,用于在字节数组中定位
  113.                                                 temp = s;
  114.                                                 // 先解析出文件名
  115.                                                 pos = s.indexOf("name=");
  116.                                                 pos += "name=".length() + 1; // 1表示后面的"的占位
  117.                                                 pos2 = s.indexOf("filename=");
  118.                                                 String s1 = s.substring(pos, pos2 - 3); // 3表示";加上一个空格
  119.                                                 fileFormName = s1;
  120.                                                 pos2 += "filename=".length() + 1; // 1表示后面的"的占位
  121.                                                 s = s.substring(pos2);
  122.                                                 int l = s.length();
  123.                                                 s = s.substring(0, l - 1);
  124.                                                 pos2 = s.lastIndexOf("\"); // 对于IE浏览器的设置
  125.                                                 s = s.substring(pos2 + 1);
  126.                                                 fileRealName = s;
  127.                                                 if (fileRealName.length() != 0) { // 确定有文件被上传
  128.                                                         ecoding = getEcoding(dataOrigin);
  129.                                                         // 下面这一部分从字节数组中取出文件的数据
  130.                                                         b = dataOrigin; // 复制原始数据以便提取文件
  131.                                                         pos = byteIndexOf(b, temp, 0); // 定位行
  132.                                                         // 定位下一行,2 表示一个回车和一个换行占两个字节
  133.                                                         b = subBytes(b, pos + temp.getBytes().length + 2,
  134.                                                                         b.length);
  135.                                                         // 再读一行信息,是这一部分数据的Content-type
  136.                                                         s = reqbuf.readLine();
  137.                                                         type = s;
  138.                                                         // 设置文件输入流,准备写文件
  139.                                                         fileFullPath = "d:" + File.separator + fileRealName;
  140.                                                         f = new File(fileFullPath);
  141. //                                                        DataOutputStream fileout = new DataOutputStream(
  142. //                                                                        new FileOutputStream(f));
  143.                                                         // 字节数组再往下一行,4表示两回车换行占4个字节,本行的回车换行2个字节,Content-type的下
  144.                                                         // 一行是回车换行表示的空行,占2个字节
  145.                                                         // 得到文件数据的起始位置
  146.                                                         b = subBytes(b, s.getBytes().length + 39, b.length);
  147.                                                         pos = byteIndexOf(b, boundary, 0); // 定位文件数据的结尾
  148.                                                         b = subBytes(b, 0, pos - 1); // 取得文件数据
  149.                                                         BufferedOutputStream bos = null;  
  150.                                                 FileOutputStream fos = null;  
  151.                                                 File file = null;  
  152.                                                 try  
  153.                                                 {          //文件加密在这里调用接口,暂无
  154.                                                     file = new File(fileFullPath);  
  155.                                                     fos = new FileOutputStream(file);  
  156.                                                     bos = new BufferedOutputStream(fos);  
  157.                                                     bos.write(b);  
  158.                                                 }  
  159.                                                 catch (Exception e)  
  160.                                                 {  
  161.                                                     e.printStackTrace();  
  162.                                                 }  
  163.                                                 finally  
  164.                                                 {  
  165.                                                     if (bos != null)  
  166.                                                     {  
  167.                                                         try  
  168.                                                         {  
  169.                                                             bos.close();  
  170.                                                         }  
  171.                                                         catch (IOException e)  
  172.                                                         {  
  173.                                                             e.printStackTrace();  
  174.                                                         }  
  175.                                                     }  
  176.                                                     if (fos != null)  
  177.                                                     {  
  178.                                                         try  
  179.                                                         {  
  180.                                                             fos.close();  
  181.                                                         }  
  182.                                                         catch (IOException e)  
  183.                                                         {  
  184.                                                             e.printStackTrace();  
  185.                                                         }  
  186.                                                     }  
  187.                                                 }  
  188. //                                                        fileout.write(b, 0, b.length - 1); // 将文件数据存盘
  189. //                                                        fileout.close();
  190.                                                         fileSize = b.length - 1; // 文件长度存入fileSize
  191.                                                         filenameTable.put(fileFormName, fileRealName);
  192.                                                         state = FILEDATA;
  193.                                                 }
  194.                                         }
  195.                                         break;
  196.                                 case FIELDDATA:
  197.                                         // 读取表单域的值
  198.                                         s = reqbuf.readLine();
  199.                                         fieldvalue = s; // 存入fieldvalue
  200.                                         formfieldsTable.put(fieldname, fieldvalue);
  201.                                         state = NONE;
  202.                                         break;
  203.                                 case FILEDATA:
  204.                                         // 如果是文件数据不进行分析,直接读过去
  205.                                         while ((!s.startsWith(boundary))
  206.                                                         && (!s.startsWith(lastboundary))) {
  207.                                                 s = reqbuf.readLine();
  208.                                                 if (s.startsWith(boundary)) {
  209.                                                         state = DATAHEADER;
  210.                                                 } else {
  211.                                                         break;
  212.                                                 }
  213.                                         }
  214.                                         break;
  215.                                 }
  216.                         }
  217.                         String title = boundary+"\r\n"+temp+"\r\n"+type+"\r\n"+ecoding+"\r\n\r\n";
  218.                         String bottom = "\n"+lastboundary+"\r\n";
  219.                         byte[] tbyte = title.getBytes();
  220.                         byte[] bbyte = bottom.getBytes();
  221.                         //加密后的文件流在这里拼接头尾完成包装
  222.                         byte[] finalbytes = this.byteMerger(tbyte,b,bbyte);
  223.                         System.out.print(reqcontent.equals(new String(finalbytes)));
  224.                         retInStream = new BufferedServletInputStream( finalbytes );
  225.                 } catch (IOException e) {
  226.                         // TODO Auto-generated catch block
  227.                         e.printStackTrace();
  228.                 }
  229.                 return retInStream;
  230.         }
复制代码



回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 15:59:02 | 显示全部楼层
3、调用到的方法(上面那层楼太长了,放不下了拆开放。。。)

  1. private String getEcoding(byte[] dataOrigin) {
  2.                 // TODO Auto-generated method stub
  3.                 String reqcontent = new String(dataOrigin);
  4.                
  5.                 return StringUtils.substringBefore(reqcontent.split("charset=ISO-8859-1\r\n")[1], "\r\n\r\n");
  6.         }

  7.         //java 合并3个byte数组
  8.         public byte[] byteMerger(byte[] byte_1, byte[] byte_2,byte[] byte_3) throws UnsupportedEncodingException{
  9.                 byte[] byte_4 = new byte[byte_1.length+byte_2.length+byte_3.length];
  10.                 System.arraycopy(byte_1, 0, byte_4, 0, byte_1.length); //原数组、原数组起始位置、目标数组、目标数组起始位置、插入数组的长度
  11.                 System.arraycopy(byte_2, 0, byte_4, byte_1.length, byte_2.length);
  12.                 System.arraycopy(byte_3, 0, byte_4, byte_1.length+byte_2.length, byte_3.length);
  13. //                String finalb = new String(byte_1)+"\r\n"+new String(byte_2,"utf-8")+"\r\n"+new String(byte_3);
  14. //                byte_4 = finalb.getBytes();
  15.                 return byte_4;
  16.         }
  17.        
  18.         private byte[] getBytes(String filePath){  
  19.         byte[] buffer1 = null;  
  20.         try {  
  21.             File file = new File(filePath);  
  22.             FileInputStream fis = new FileInputStream(file);  
  23.             ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  24.             byte[] b = new byte[1024];  
  25.             int n;  
  26.             while ((n = fis.read(b)) != -1) {  
  27.                 bos.write(b, 0, n);  
  28.             }  
  29.             fis.close();  
  30.             bos.close();  
  31.             buffer1 = bos.toByteArray();
  32.         } catch (FileNotFoundException e) {  
  33.             e.printStackTrace();  
  34.         } catch (IOException e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.         return buffer1;  
  38.     }

  39.         private static int byteIndexOf(byte[] b, String s, int start) {
  40.                 return byteIndexOf(b, s.getBytes(), start);
  41.         }

  42.         private static int byteIndexOf(byte[] b, byte[] s, int start) {
  43.                 int i;
  44.                 if (s.length == 0) {
  45.                         return 0;
  46.                 }

  47.                 int max = b.length - s.length;
  48.                 if (max < 0) {
  49.                         return -1;
  50.                 }

  51.                 if (start > max) {
  52.                         return -1;
  53.                 }

  54.                 if (start < 0) {
  55.                         start = 0;
  56.                 }

  57.                 // 在b中找到s的第一个元素

  58.                 search: for (i = start; i <= max; i++) {
  59.                         if (b[i] == s[0]) {
  60.                                 // 找到了s中的第一个元素后,比较剩余的部分是否相等
  61.                                 int k = 1;
  62.                                 while (k < s.length) {
  63.                                         if (b[k + i] != s[k]) {
  64.                                                 continue search;
  65.                                         }
  66.                                         k++;
  67.                                 }
  68.                                 return i;
  69.                         }
  70.                 }
  71.                 return -1;
  72.         }

  73.         private static byte[] subBytes(byte[] b, int from, int end) {
  74.                 byte[] result = new byte[end - from];
  75.                 System.arraycopy(b, from, result, 0, end - from);
  76.                 return result;

  77.         }

  78.         private static String subBytesString(byte[] b, int from, int end) {
  79.                 return new String(subBytes(b, from, end));
  80.         }

  81. }

  82. class BufferedServletInputStream extends ServletInputStream {
  83.     private ByteArrayInputStream inputStream;
  84.     public BufferedServletInputStream(byte[] buffer) {
  85.         this.inputStream = new ByteArrayInputStream( buffer );
  86.     }
  87.     @Override
  88.     public int available() throws IOException {
  89.         return inputStream.available();
  90.     }
  91.     @Override
  92.     public int read() throws IOException {
  93.         return inputStream.read();
  94.     }
  95.     @Override
  96.     public int read(byte[] b, int off, int len) throws IOException {
  97.         return inputStream.read( b, off, len );
  98.     }
  99. }
复制代码




回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 16:01:36 | 显示全部楼层
4、用到的jar包有:commons-fileupload-1.2.1.jar、commons-lang-2.3.jar、servlet-api.jar
5、将上面写好的项目达成jar包,放在\runtime\DocServer\WEB-INF\lib下
6、在\runtime\DocServer\WEB-INF\web.xml中配置过滤器:
  1. <filter>
  2.           <filter-name>LWUploadFilter</filter-name>
  3.           <filter-class>com.cn.LWUploadFilter</filter-class>
  4.          </filter>
  5.        
  6.          <filter-mapping>
  7.           <filter-name>LWUploadFilter</filter-name>
  8.           <url-pattern>/*</url-pattern>
  9.          </filter-mapping>
复制代码



回复 支持 反对

使用道具 举报

61

主题

265

帖子

800

积分

高级会员

Rank: 4

积分
800
QQ
 楼主| 发表于 2017-1-12 16:02:26 | 显示全部楼层
jishuang 发表于 2017-1-12 10:06
确认servlet-api等相关的jar版本号都一致吗?

可以参考平台的excel导入文件上传的实现

暂时完成了,可以结贴了,谢谢。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|X3技术论坛|Justep Inc.    

GMT+8, 2024-5-18 11:44 , Processed in 0.071270 second(s), 23 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表