这个代码同之前写过的一篇文章:使用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);
            }
        }
    }
}