java + jdbc 讀取SQL Server數據庫中郵件相關的數據,並根據文件id生成文件夾(數據遷移)

這個代碼同之前寫過的一篇文章:使用java + jdbc連接數據庫,並解析成XML格式的文件。。另外有對流文件的操作。。

這裏不再詳述,補充一點的是:java命令行執行帶依賴jar包的main函數 

import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;

import java.util.Date;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

/**
 * 讀取SQL Server數據庫中郵件相關的數據
 *
 * @date 2019/08/08
 * @author linrui
 *
 * */
public class SelectSQLServerEmailToXml {
    public static final String NEW_FILE_PATH = "D:\\email\\";
    public static Map contentMap;
    /**
     *  程序入口
     * */
    public static void main(String[] args) throws Exception{
        System.out.println("程序正在執行中,請稍後……");
        System.out.println();
        long beginTime = System.currentTimeMillis();

        Connection connection = getConnection();
        Statement statement = null;
        ResultSet rs = null;
        try {
            statement = connection.createStatement();
            String sql = getSelectSQL();
            rs = statement.executeQuery(sql);
        } catch (SQLException e) {
            System.out.println("操作數據庫異常!");
            e.printStackTrace();
        }

        long count = 0;
        long filed = 0;

        //得到所有的主題
        List<String> subjectList = new ArrayList<>();
//        try {
            while (rs.next()) {
                subjectList.add(rs.getString("ZT"));
            }
//        } catch (SQLException e) {
//            throw new RuntimeException("解析所有主題時錯誤!");
//        }

        //關閉數據庫連接相關的資源
        closeAll(connection, statement, null, rs);

        //生成xml,並返回生成的條數(有多少個主題,就生成多少條記錄)
        for (String subject : subjectList) {
            contentMap = new HashMap(1);
            //附件中的所有文件名(包括辦理單)
            StringBuilder fileNames = new StringBuilder();

            //根據主題獲取一條郵件(獲取到發件人即可)
            Map<String,Object> mailMap = getResultBySubject(subject, fileNames);
            try {
                //生成xml,並返回生成的條數(有多少個主題,就生成多少條記錄)
                createXml(mailMap, fileNames);
                count++;
            } catch (Exception e) {
                filed++;
//                System.out.println("==========>失敗的mailMap爲:" + mailMap);
            }
        }

        System.out.println();
        System.out.println("程序執行完成。");
        System.out.println("生成了" + count + "條xml數據!");
        System.out.println("失敗了" + filed + "條xml數據!");
        System.out.println();

        long endTime = System.currentTimeMillis();
        System.out.println("總耗時:" + (endTime - beginTime)/1000 + "秒");

    }

    /**
     * 根據主題 去解析每個郵件
     *
     * @param subject
     * @param fileNames 附件名稱,用於拼接
     * */
    private static Map<String, Object> getResultBySubject(String subject, StringBuilder fileNames) {
        String filePath = "D:\\botongsoft\\OA\\tomcat5.0\\webapps\\ROOT\\mail";
        Map<String, Object> mailMap = new HashMap<>(4);

        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
        String sql = "select * from dbo.MAIL_MESSAGE where ZT = ?";
        try{
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, subject);
            rs = preparedStatement.executeQuery();

            boolean flag = true;
            while (rs.next() && flag) {
                //解析發件人,得到對應的eml文件所在位置的父文件夾名稱
                String fjr = rs.getString("FJR");
                String fjrName = "";
                if (fjr != null) {
                    if (!fjr.equals("")) {
                        String[] tempArr = fjr.split("<");
                        String[] tempArr2 = tempArr[1].split("@");
                        fjrName = tempArr2[0];
                    }
                }

                //這裏是按主題去遍歷郵件,所以一個主題對應多份郵件,這裏只需要找到發送人即可。
                // 即如果拋異常,則不是發送人,直接循環下一個
                try {
                    //解析eml文件
                    mailMap = getEmlContent(filePath + "\\" + fjrName + "\\" + rs.getString("FILENAME") + ".eml", fileNames, rs.getInt(1));
                    //同理,如果沒有拋異常,則就是這份文,記錄id、生成目錄、並直接退出循環
                    int sourceIDInt = rs.getInt(1);
                    mailMap.put("sourceId", sourceIDInt);
//                    break;//break沒有用,無法退出循環!
                    flag = false;
                } catch (Exception e) {
                    //什麼也不做
                    System.out.println("出異常了,我什麼都沒做。異常的id爲:【" + rs.getInt("MESSAGE_ID") + "】");

                }
            }
        }catch (SQLException e) {
            System.out.println("==============》解析主題爲:【" + subject + "】的郵件時異常!跳過處理");
        } finally {
            closeAll(connection, null, preparedStatement, rs);
        }

        return mailMap;
    }

    /**
     * 生成xml,並返回生成的條數
     *
     * @param mailMap 數據庫查詢結果集
     * @return int 返回生成xml的條數
     * */
    private static void createXml(Map<String, Object> mailMap, StringBuilder fileNames) throws Exception {
        // 創建解析器工廠
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = factory.newDocumentBuilder();

        //文件id要多次使用,故直接賦值出來
        int sourceIDInt = (int)mailMap.get("sourceId");
//        String sourceID = (String)mailMap.get("sourceId");
        String sourceID = String.valueOf(sourceIDInt);


        Document document = db.newDocument();
        document.setXmlVersion("1.0");
        document.setXmlStandalone(true);

        Element docs = document.createElement("docs");
        // 向docs根節點中添加子節點doc
        Element doc = document.createElement("doc");

        //創建一個新的目錄
//        File file = new File(getNewFilePath());
//        file.mkdir();
//        file = new File(getNewFilePath() + sourceID);
//        file.mkdir();

        //每個字段信息
        //原文ID
        Element item = document.createElement("item");
        item.setAttribute("name", "uuid");
        CDATASection cdataSection = document.createCDATASection(sourceID);
        item.appendChild(cdataSection);
        doc.appendChild(item);
        //發件人
        String fjrAddress = (String)mailMap.get("fjrAddress");
        String fjrShortName = fjrAddress.split("@")[0];
        String fjrName = getUserName(fjrShortName);
        item = getItem(fjrName, "fromAddress", document, cdataSection);
        doc.appendChild(item);
        //收件人
        String sjrAddressList = (String)mailMap.get("sjrAddressList");
        String[] sjrMailArr = sjrAddressList.split("。");
        StringBuilder toAddressSB = new StringBuilder();
        for (String sjrMail: sjrMailArr) {
//            System.out.println("收件人郵箱=====》" + sjrMail);
            String sjrShortName = sjrMail.split("@")[0];
//            System.out.println("收件人簡稱=====》" + sjrShortName);
            String sjrName = getUserName(sjrShortName);
            toAddressSB.append(sjrName);
            toAddressSB.append(";;");
        }
        if (toAddressSB.length() > 1) {
            toAddressSB.deleteCharAt(toAddressSB.length()-1);
            toAddressSB.deleteCharAt(toAddressSB.length()-1);
        }
        item = getItem(toAddressSB.toString(), "toAddress", document, cdataSection);
        doc.appendChild(item);
        //郵件主題
        String subject = (String)mailMap.get("subject");
        item = getItem(subject, "subject", document, cdataSection);
        doc.appendChild(item);
        //發送日期
        Date sendDate = (Date)mailMap.get("sentDate");
        String sendDateToString = "";
        if(sendDate != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sendDateToString = format.format(sendDate);
        }
        item = getItem(sendDateToString, "sendDate", document, cdataSection);
        doc.appendChild(item);
        //郵件內容
        try {
            if (contentMap.size() > 0) {
                String htmlContent = (String)contentMap.get("htmlContent");
                item = getItem(htmlContent, "htmlContent", document, cdataSection);
                doc.appendChild(item);
            }
        } catch (Exception e) {
            System.out.println("沒有郵件內容");
        }

        //附件
        if (fileNames.length() > 1) {
            fileNames.deleteCharAt(fileNames.length()-1);
            fileNames.deleteCharAt(fileNames.length()-1);
            fileNames.deleteCharAt(fileNames.length()-1);
            fileNames.deleteCharAt(fileNames.length()-1);
            fileNames.deleteCharAt(fileNames.length()-1);
        }
        item = getItem(fileNames.toString(), "附件", document, cdataSection);
        doc.appendChild(item);

        // 將doc節點添加到docs根節點中
        docs.appendChild(doc);
        // 將docs節點(已包含doc)添加到dom樹中
        document.appendChild(docs);

        // 創建TransformerFactory對象
        TransformerFactory tff = TransformerFactory.newInstance();
        // 創建 Transformer對象
        Transformer tf = tff.newTransformer();

        // 輸出內容是否使用換行
        tf.setOutputProperty(OutputKeys.INDENT, "yes");
        // 創建xml文件並寫入內容
        tf.transform(new DOMSource(document), new StreamResult(new File(getNewFilePath() + sourceID + "\\basicInfo" +".xml")));
    }

    /**
     * 獲取item
     *
     * @param source 源字段
     * @param target 目標字段
     * @param document
     * @param cdataSection CDATA區
     * */
    private static Element getItem(String source, String target, Document document, CDATASection cdataSection){
        Element item;
        item = document.createElement("item");
        item.setAttribute("name", target);
        cdataSection = document.createCDATASection(source.trim());
        item.appendChild(cdataSection);

        return item;
    }

    /**
     * 根據擬稿人編號到數據庫中查詢其名字
     *
     * @param login_id 登錄編號(唯一的)
     *
     * @return String 用戶名稱
     * */
    private static String getUserName(String login_id) {
        String userName = "";
        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
        try {
            String sql = "select * from dbo.TS_USER where login_id=?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, login_id);
            rs = preparedStatement.executeQuery();

            while (rs.next()) {
                userName = rs.getString("NAME");
            }
        } catch (SQLException e) {
            System.out.println("根據用戶編號獲取用戶名是出現了未知的異常!");
            e.printStackTrace();
        } finally {
            //關閉數據庫連接相關的資源
            closeAll(connection, null, preparedStatement, rs);
        }

        return userName;
    }


    /**
     * 獲取Connection連接
     *
     * @return connection
     * */
    private static Connection getConnection () {
        //獲取指定的數據庫連接信息
        Map<String, String> databaseMap =  getDatabaseMap();

        //聲明Connection對象
        Connection con = null;
        //驅動程序名
        String driver = databaseMap.get("driverName");
        //URL指向要訪問的數據庫名
        String url = databaseMap.get("url");
        //MySQL配置時的用戶名
        String userName = databaseMap.get("userName");
        //MySQL配置時的密碼
        String password = databaseMap.get("password");

        try {
            //加載驅動程序
            Class.forName(driver);
            con = DriverManager.getConnection(url, userName, password);
        } catch(ClassNotFoundException e) {
            //數據庫驅動類異常處理
            System.out.println("沒有找到驅動!");
            e.printStackTrace();
            throw new RuntimeException();
        } catch(SQLException e) {
            //數據庫連接失敗異常處理
            System.out.println("連接失敗!");
            e.printStackTrace();
            throw new RuntimeException();
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return con;
    }

    /**
     * 獲取數據庫連接信息
     *
     * @return Map
     * */
    private static Map<String, String> getDatabaseMap() {
        Map<String, String> databaseMap = new HashMap<>(4);
        //讀取屬性文件
        Properties properties = readProperties();
        databaseMap.put("driverName", properties.getProperty("driverName"));
        databaseMap.put("url", properties.getProperty("url"));
        databaseMap.put("userName", properties.getProperty("userName"));
        databaseMap.put("password", properties.getProperty("password"));

        return databaseMap;
    }

    /**
     * 獲取SQL語句
     *
     * @return String
     * */
    private static String getSelectSQL() {
        Properties properties = readProperties();
        return properties.getProperty("selectSQL");
    }

    /**
     * 獲取存放文件的路徑
     *
     * @return String
     * */
    private static String getNewFilePath() {
        return NEW_FILE_PATH;
//        Properties properties = readProperties();
//        return properties.getProperty("newFilePath");
    }

    /**
     * 讀取屬性文件
     *
     * @return Properties
     * */
    private static Properties readProperties() {
        InputStream inputStream = null;
        Properties properties = null;

        try {
            //用流讀入properties配置文件
            inputStream = new FileInputStream("D:\\database.properties");
            properties = new Properties();
            //從輸入字節流讀取屬性列表(鍵和元素對)
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (properties == null) {
            System.out.println("讀取屬性文件失敗,值爲null");
            throw new RuntimeException();
        }

        //關閉流
        closeToIO(inputStream, null);

        return properties;
    }

    /**
     * 關閉數據庫連接及操作相關的資源
     *
     * @param conn 數據庫連接
     * @param statement 執行數據庫操作的對象
     * */
    private static void closeAll(Connection conn, Statement statement, PreparedStatement preparedStatement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                System.out.println("關閉resultSet資源失敗");
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                System.out.println("關閉statement資源失敗");
                e.printStackTrace();
            }
        }
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                System.out.println("關閉preparedStatement資源失敗");
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                System.out.println("關閉數據庫連接connection失敗");
                e.printStackTrace();
            }
        }
    }

    /**
     * 關閉流的資源
     * */
    private static void closeToIO (InputStream inputStream, OutputStream outputStream) {
        try {
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            System.out.println("關閉輸入流inputStream流異常!");
            e.printStackTrace();
        }

        try {
            if (outputStream != null) {
                outputStream.close();
            }
        } catch (IOException e) {
            System.out.println("關閉輸出流outputStream流異常!");
            e.printStackTrace();
        }
    }

    /*************************************************************************************
     * **********************下面是解析 .eml 郵件格式的文件的代碼 ************************
     *************************************************************************************/
    /**
     * 獲取郵件中的內容
     * @param filePath 文件路徑
     *
     * @return map
     * */
    private static Map<String, Object> getEmlContent(String filePath, StringBuilder fileNames, int sourceId) throws Exception{
        Map<String, Object> map;

        map = parserFile(filePath, fileNames, sourceId);

        //System.out.println("============>" + map);
        return map;
    }
    /**
     * 解析文件
     *
     * @param emlPath 文件路徑
     * */
    public static Map<String, Object> parserFile(String emlPath, StringBuilder fileNames, int sourceId) throws Exception {
        Map<String, Object> map;
        //System.out.println(emlPath);
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        InputStream inMsg;
        inMsg = new FileInputStream(emlPath);
        Message msg = new MimeMessage(session, inMsg);
        map = parseEml(msg, fileNames, sourceId);

        return map;
    }

    private static Map<String, Object> parseEml(Message msg, StringBuilder fileNames, int sourceIDInt) throws Exception {

        String sourceIdToString = String.valueOf(sourceIDInt);
        //創建目錄
        File file = new File(getNewFilePath());
        file.mkdir();
        file = new File(getNewFilePath() + sourceIdToString);
        file.mkdir();

        Map<String, Object> map = new HashMap<>(10);
        // 發件人信息
        Address[] froms = msg.getFrom();
        if (froms != null) {
            InternetAddress addr = (InternetAddress) froms[0];
//            System.out.println("發件人地址:" + addr.getAddress());
            map.put("fjrAddress",addr.getAddress());
            //System.out.println("發件人顯示名:" + addr.getPersonal());
            map.put("fjrName", addr.getPersonal());

        }
        //收件人信息
        Address[] tos = msg.getAllRecipients();
//        List<String> sjrAddressList = new ArrayList<>();
        StringBuilder sjrAddressStringBuilder = new StringBuilder();
        for (Address a : tos) {
            InternetAddress addr = (InternetAddress)a;
            //System.out.println("====>收件人地址:" + addr.getAddress());
//            sjrAddressList.add(addr.getAddress());
            sjrAddressStringBuilder.append(addr.getAddress());
            sjrAddressStringBuilder.append("。");
        }
        map.put("sjrAddressList", sjrAddressStringBuilder.toString());

        //System.out.println("郵件主題:" + msg.getSubject());
        map.put("subject", msg.getSubject());
        //發件日期
        //System.out.println("===>發件日期:" + msg.getSentDate());
        map.put("sentDate", msg.getSentDate());
        // getContent() 是獲取包裹內容, Part相當於外包裝
        Object o = msg.getContent();
        if (o instanceof Multipart) {
            Multipart multipart = (Multipart) o;
            reMultipart(multipart, fileNames, sourceIdToString);
        } else if (o instanceof Part) {
            Part part = (Part) o;
            rePart(part, fileNames, sourceIdToString);
        } else {
            // System.out.println("類型" + msg.getContentType());
            map.put("type", msg.getContentType());
            //System.out.println("內容" + msg.getContent());
            map.put("content", msg.getContent().toString());
        }

        return map;
    }


    /**
     * 解析內容
     *
     * @param part
     * @throws Exception
     */
    private static void rePart(Part part, StringBuilder fileNames, String sourceIdToString) throws Exception {
        if (part.getDisposition() != null) {
            String strFileNmae = part.getFileName();
            if(strFileNmae != null) {
                // MimeUtility.decodeText解決附件名亂碼問題
                strFileNmae=MimeUtility.decodeText(strFileNmae);
                // System.out.println("發現附件: "+ strFileNmae);

                // 打開附件的輸入流
                InputStream in = part.getInputStream();

                //取文件明的hash值
                String strFileNameHash = String.valueOf(strFileNmae.hashCode());
                //保存文件名
                fileNames.append(strFileNameHash + ";;" + strFileNmae);
                fileNames.append("#####");

//                String strFile = "C:\\Users\\lin\\Desktop\\test\\" + strFileNmae;
                String strFile = getNewFilePath() + sourceIdToString + "\\" + strFileNameHash;
                FileOutputStream out = new FileOutputStream(strFile);
                byte[] bytes = new byte[1024];
                while(in.read(bytes,0,1024) != -1){
                    out.write(bytes);
                }

                in.close();
                out.close();

            }

            //System.out.println("內容類型: "+ MimeUtility.decodeText(part.getContentType()));
            //System.out.println("附件內容:" + part.getContent());


        } else {
            if (part.getContentType().startsWith("text/plain")) {
//                System.out.println("文本內容:" + part.getContent());
                if (part.getContent() != null  && !part.getContent().equals("") ) {
                    contentMap.put("htmlContent", part.getContent());
                }
            } else {
//                 System.out.println("HTML內容:" + part.getContent());
                if (part.getContent() != null  && !part.getContent().equals("") ) {
                    contentMap.put("htmlContent", part.getContent());
                }
            }
        }
    }

    /**
     * 接卸包裹(含所有郵件內容(包裹+正文+附件))
     * @param multipart
     * @throws Exception
     */
    private static void reMultipart(Multipart multipart, StringBuilder fileNames, String sourceIdToString) throws Exception {
        // System.out.println("郵件共有" + multipart.getCount() + "部分組成");
        // 依次處理各個部分
        for (int j = 0, n = multipart.getCount(); j < n; j++) {
            // System.out.println("處理第" + j + "部分");
            Part part = multipart.getBodyPart(j);// 解包, 取出 MultiPart的各個部分,
            // 每部分可能是郵件內容,
            // 也可能是另一個小包裹(MultipPart)
            // 判斷此包裹內容是不是一個小包裹, 一般這一部分是 正文 Content-Type: multipart/alternative
            if (part.getContent() instanceof Multipart) {
                Multipart p = (Multipart) part.getContent();// 轉成小包裹
                // 遞歸迭代
                reMultipart(p, fileNames, sourceIdToString);
            } else {
                rePart(part, fileNames, sourceIdToString);
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章