JAVA EMAIL发送邮件 参数可配置,模板可配置

**发送邮件实现的代码和配置文件的加载,统一将邮件相关的配置置于配置文件中,增强工具类的适应性。
闲来无事,自己写了一个工具类,发送邮件使用自定义的模板,配置文件采用了 xml 和 properties 文件,并且采用 JSSE 的 SSL socketfactory 来取代默认的 socketfactory。**

相关 jar 包:

*①:commons-lang-2.4.jar
②:jdom.jar
③:mail.jar
*整个的参数处理,配置文件加载,详见代码即其中的注释:
邮件模板:xxx.model**

[lqs-##] [lqs-##],此为注释 --- 此为实例模板,图片 logo 替换规则 cid:logo , 正文替换格式${xxx},在调用的时候自定义替换其中的内容 2017年3月28日18:27:07
<div id="mainmail" style="margin-bottom: 12px; position: relative; z-index: 1;">
                <div class="body" id="contentDiv" style="padding: 15px 15px 10px; height: auto; line-height: 1.7; font-size: 14px; position: relative; z-index: 1; -ms-zoom: 1;">
                    <div id="qm_con_body">
                        <div class="emailbox" style="height: auto;min-height: 100px;word-wrap: break-word;font-size: 14px;font-family: "lucida Grande", Verdana, "Microsoft YaHei";" id="mailContentContainer"> <br><br>
                            <table align="center" border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td align="left" valign="top">
                                        <table width="500" border="0" cellspacing="0" cellpadding="0">
                                            <tr>
                                                <td align="left" valign="top"><img width="127" height="28" src="cid:taizi_logo.png" border="0"></td>
                                                <td align="right" valign="top">it52luo@163.com</td>
                                                [lqs-##]<td align="right" valign="top"><img width="328" height="44" src="cid:right_logo" border="0"></td>
                                                <td align="right" valign="top">&nbsp;</td>
                                            </tr>
                                            <tr>
                                                <td colspan="2"><img width="500" height="1" src="cid:email_line" border="0"></td>
                                            </tr>
                                            <tr height="24">
                                                <td height="24" colspan="2">
                                            </tr>
                                            <tr>
                                                <td style="color: rgb(51, 51, 51); font-family: Geneva,Verdana,Arial,Helvetica; font-size: 10px; font-weight: normal;" colspan="2">
                                                    ${content}
                                                </td>
                                            </tr>
                                            <tr height="24">
                                                <td height="24" colspan="2">
                                            </tr>
                                            <tr>
                                                <td colspan="2"><img width="500" height="1" src="cid:email_line" border="0"></td>
                                            </tr>
                                            <tr height="36">
                                                <td height="24" colspan="2">
                                            </tr>
                                            <tr>
                                                <td class="message" style="color: rgb(0, 0, 0); font-family: Geneva,Verdana,Arial,Helvetica; font-size: 9px;" colspan="2"> <b>T̶a̶i̶z̶i̶ Inc.</b><br>Organization:T̶a̶i̶z̶i̶
                                                    <a href="https://user.qzone.qq.com/1194895584" target="_blank">T̶a̶i̶z̶i̶</a><br><br> 获取常见问题的解答,请咨询T̶a̶i̶z̶i̶
                                                    <a href="https://user.qzone.qq.com/1194895584" target="_blank">https://user.qzone.qq.com/1194895584</a>
                                                </td>
                                            </tr>
                                        </table>
                                        </td>
                                </tr>
                                <tr height="75">
                                    <td height="75">
                                </tr>
                                <tr>
                                    <td>
                                        <table align="center">
                                            <tr>
                                                <td width="500" align="center" class="message" style="color: rgb(51, 51, 51); font-family: Geneva,Verdana,Arial,Helvetica; font-size: 9px;">
                                                    <a href="https://user.qzone.qq.com/1194895584" target="_blank">T̶a̶i̶z̶i̶</a> <br><br></td>
                                            </tr>
                                            <tr>
                                                <td width="500" align="center" class="message" style="color: rgb(51, 51, 51); font-family: Geneva,Verdana,Arial,Helvetica; font-size: 9px;"> T̶a̶i̶z̶i̶尊重你的隐私权。<br>与您个人信息有关的规定见
                                                    <a href="https://user.qzone.qq.com/1194895584" target="_blank">https://user.qzone.qq.com/1194895584</a> <br><br></td>
                                            </tr>
                                            <tr>
                                                <td width="500" align="center" class="disclaimer" style="color: rgb(110, 110, 110); font-family: Geneva,Verdana,Arial,Helvetica; font-size: 9px;"> Copyright©2017LUO YuCheng.
                                                    <a href="https://user.qzone.qq.com/1194895584" target="_blank">保留所有权利</a>
                                                </td>
                                            </tr>
                                        </table>
                                    </td>
                                </tr>
                            </table><br><br> <img src="cid:email_spacer"></div>
                    </div>
                </div>
            </div>

使用 email.properties 配置:

## 尝试使用AUTH命令认证用户
mail.smtp.auth=true
## 服务协议
mail.transport.protocol=smtp
## 邮件服务器
mail.smtp.host=smtp.163.com
## 使用 JSSE 的 SSL socketfactory 来取代默认的 socketfactory
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
## false:只处理 SSL 的连接,对于非 SSL 的连接不做处理. true:处理 SSL 和非 SSL 的连接
mail.smtp.socketFactory.fallback=false
## 端口号
## mail.smtp.port=25
mail.smtp.port=465
## 服务邮箱
username=xxx
## 邮箱密码
password=xxx
## 发送人名称
senderNick=T̶a̶i̶z̶i̶
## logUrl 请以逗号分隔,且除去后缀后的名称和模板中的名称一致,不一致则不会替换,
## 会出现 tcmime.9162.9263.10034.bin 此类型的附件,凡是有图片参数的,请在模板设置对应的替换字段 cid:name
logoUrl=taizi_logo.png,email_line.gif,email_spacer.gif

其中读取文件代码及加载到 JAVA MAIL 的 session 中:

public EmailUtils(){
        pro = new Properties();
        try {
            if(!fileIsTrue(filePath)){
                System.out.println("配置文件不存在");
                return;
            }
            in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
            if(in == null) return;
            pro.load(in);//加载配置文件
            in.close();//关闭流
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在:"+e.toString());
        } catch (IOException e) {
            System.out.println("IO 流关闭异常:"+e.toString());
        } finally {
            if(in != null){
                try {
                    in.close();//关闭流
                } catch (IOException e) {
                    System.out.println("IO 流关闭异常:"+e.toString());
                }
            }
        }
        /*MailSSLSocketFactory msf = null;//SSL 加密
        try {
            msf = new MailSSLSocketFactory();
            msf.setTrustAllHosts(true);
        } catch (GeneralSecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        pro.put("mail.smtp.ssl.socketFactory",msf);*/
        //尝试使用AUTH命令认证用户
        auth = pro.getProperty("mail.smtp.auth").toString();
        //装载服务协议、服务器
        protocol = pro.getProperty("mail.transport.protocol").toString();
        host = pro.getProperty("mail.smtp.host").toString();
        //装载发件人昵称
        senderNick = pro.getProperty("senderNick").toString();
        //装载服务邮箱和密码
        username = pro.getProperty("username").toString();
        password = pro.getProperty("password").toString();
        //装载 logo 图标路径
        logoUrl = pro.getProperty("logoUrl").toString();
        //建立会话
        session = Session.getDefaultInstance(pro);
        session.setDebug(true);
    }

使用 XML 配置:

<?xml version="1.0" encoding="UTF-8"?>
<Email>
      <!--
        ## 尝试使用AUTH命令认证用户
        mail.smtp.auth=true
        ## 服务协议
        mail.transport.protocol=smtp
        ## 邮件服务器
        mail.smtp.host=smtp.163.com
        ## 使用 JSSE 的 SSL socketfactory 来取代默认的 socketfactory
        mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
        ## false:只处理 SSL 的连接,对于非 SSL 的连接不做处理. true:处理 SSL 和非 SSL 的连接
        mail.smtp.socketFactory.fallback=true
        ## 端口号
        ## mail.smtp.port=25 非加密
        mail.smtp.port=465 加密
        ## 服务邮箱
        username=xxx
        ## 邮箱密码
        password=xxx
        ## 发送人名称
        senderNick=T̶a̶i̶z̶i̶
        ## logUrl 请以逗号分隔,且除去后缀后的名称和模板中的名称一致,不一致则不会替换,
        ## 会出现 tcmime.9162.9263.10034.bin 此类型的附件,凡是有图片参数的,请在模板设置对应的替换字段 cid:name
        logoUrl=logo_apple.png,right_logo.gif,email_line.gif,email_spacer.gif
      -->
       <package mail.smtp.auth="true" mail.transport.protocol="smtp"
     mail.smtp.host="smtp.163.com" mail.smtp.port="465" mail.smtp.socketFactory.class="javax.net.ssl.SSLSocketFactory"
     mail.smtp.socketFactory.fallback="false" username="xxx" password="xxx" senderNick="T̶a̶i̶z̶i̶"
       logoUrl="taizi_logo.png,email_line.gif,email_spacer.gif"></package>
</Email>

加载 XML 中的配置进 Session:

public EmailUtils(){
        pro = new Properties();
        SAXBuilder builder = new SAXBuilder(false);
        Document doc = new Document();//解析XML配置文件
        try {
            doc = builder.build(filePath);
            //获取根元素<package>
            root = (Element)doc.getRootElement().getChildren().get(0);
            //尝试使用AUTH命令认证用户
            auth = root.getAttributeValue("mail.smtp.auth");
            //装载服务协议、服务器
            protocol = root.getAttributeValue("mail.transport.protocol");
            host = root.getAttributeValue("mail.smtp.host");
            //装载端口
            port = root.getAttributeValue("mail.smtp.port");
            //使用 JSSE 的 SSL socketfactory 来取代默认的 socketfactory
            socketFactoryclass = root.getAttributeValue("mail.smtp.socketFactory.class");
            //false:只处理 SSL 的连接,对于非 SSL 的连接不做处理. true:处理 SSL 和非 SSL 的连接
            socketFactoryfallback = root.getAttributeValue("mail.smtp.socketFactory.fallback");
            //装载服务邮箱和密码
            username = root.getAttributeValue("username");
            password = root.getAttributeValue("password");
            //装载发件人昵称
            senderNick = root.getAttributeValue("senderNick");
            //装载 logo 图标
            logoUrl = root.getAttributeValue("logoUrl");
        } catch (JDOMException e) {
            System.out.println("JDOMException 异常:"+e.toString());
        } catch (IOException e) {
            System.out.println("IO 异常:"+e.toString());
        }
        /*~采用JSSE SSL 加密代替 SSL 加密~*/
        /*MailSSLSocketFactory msf = null;//SSL 加密
        try {
            msf = new MailSSLSocketFactory();
            msf.setTrustAllHosts(true);
        } catch (GeneralSecurityException e) {
            System.out.println("GeneralSecurityException 异常:"+e.toString());
        }
        pro.put("mail.smtp.ssl.socketFactory",msf);*/
        pro.put("mail.smtp.auth", auth);//auth 认证
        pro.put("mail.transport.protocol", protocol);//协议
        pro.put("mail.smtp.host", host);//服务器
        pro.put("mail.smtp.port", port);//端口
        pro.put("mail.smtp.socketFactory.class", socketFactoryclass);//加密方式 JSSE SSL
        pro.put("mail.smtp.socketFactory.fallback", socketFactoryfallback);//是否同时处理非加密连接
        pro.put("username", username);//发送邮箱
        pro.put("password", password);//密码
        //建立会话
        session = Session.getDefaultInstance(pro);
        session.setDebug(false);
    }

配置文件加载进 Session 中之后,就可以开始发送邮件了,可以直接在main 方法中测试,前提是先配置好邮箱服务器,配制方法详见百度,x相关的变量,请自行增加或者下载附件

详见代码:

static{
        rpath = getRealPath();//src 目录
        filePath = rpath+PROPERTIESNAME;//配置文件路径
    }
/**
     * 
     * @Title: getInstance
     * @Description: TODO 单列
     * @return
     * @return: EmailUtils
     */
    public static EmailUtils getInstance() {
        if (instance == null) {
            instance = new EmailUtils();
        }
        return instance; 
    }

    /**
     * 
     * @Title: sendMail
     * @Description: TODO 邮件发送
     * @param to 收件人
     * @param copyto 抄送人[可为空数组或者null]
     * @param subject 主题
     * @param content 正文
     * @param logoarr html 邮件中的图片,名称需要和模板中的名称相同,
     *          如模板中为 cid:top_logo,那么图片名称就应该是 top_logo.xxx
     * @param fileList 附件列表
     * @return
     * @return: boolean
     */
    private boolean sendMail(String[] to, String[] copyto, String subject, String content, String[] logoarr, String[] fileList) {
        boolean success = true;
        try {
            mimeMsg = new MimeMessage(session);
            mp = new MimeMultipart();
            String nick = "";//自定义发件人昵称
            try {
                nick = MimeUtility.encodeText(senderNick);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            mimeMsg.setFrom(new InternetAddress(username, nick));//设置发件人
            //设置收件人
            if (to != null && to.length > 0) {
                String toListStr = getMailList(to);
                System.out.println("收件人:"+toListStr);
                mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toListStr));
            }
            //设置抄送人
            if (copyto != null && copyto.length > 0) {
                String ccListStr = getMailList(copyto);
                System.out.println("抄送人:"+ccListStr);
                mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccListStr)); 
            }
            mimeMsg.setSubject(subject);//设置主题
            MimeBodyPart bp = new MimeBodyPart();//设置正文
            String body = content;
            bp.setContent(body, "text/html;charset=utf-8");
            mp.addBodyPart(bp);

            for (int i = 0; i < logoarr.length; i++) {
                String sUrl = rpath+File.separator+logoarr[i];
                String str = logoarr[i].substring(0, logoarr[i].lastIndexOf("."));
                boolean flag = fileIsTrue(sUrl);
                if(flag){
                    //正文的图片部分
                    MimeBodyPart jpgBody = new MimeBodyPart();
                    FileDataSource fds = new FileDataSource(sUrl);
                    jpgBody.setDataHandler(new DataHandler(fds));
                    jpgBody.setContentID(str);
                    mp.addBodyPart(jpgBody);
                }else{
                    System.out.println("logo 不存在:"+logoarr[i]);
                }
            }

            //设置附件
            if (fileList != null && fileList.length > 0) {
                for (int i = 0; i < fileList.length; i++) {
                    boolean flag = fileIsTrue(fileList[i]);
                    if(!flag){
                        System.out.println("此附件不存在:"+fileList[i]);
                        continue;
                    }
                    bp = new MimeBodyPart();
                    FileDataSource fds_file = new FileDataSource(fileList[i]);
                    bp.setDataHandler(new DataHandler(fds_file));
                    String filename = MimeUtility.encodeText(fds_file.getName(), "UTF-8", "B");
                    filename = filename.replaceAll("\r","").replaceAll("\n","");
                    bp.setFileName(filename);
                    mp.addBodyPart(bp);
                }
            }
            mimeMsg.setContent(mp);
            mimeMsg.saveChanges();
            //发送邮件
            if (auth.equals("true")) {
                Transport transport = session.getTransport(protocol);
                transport.connect(host, username, password);
                transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
                transport.close();
            } else {
                Transport.send(mimeMsg);
            }
            System.out.println("邮件发送成功");
        } catch (MessagingException e) {
            System.out.println("邮件发送异常:"+e.toString());
            success = false;
        } catch (UnsupportedEncodingException e) {
            System.out.println("编码异常:"+e.toString());
            success = false;
        }
        return success;
    }

    /**
     * 
     * @Title: readEamilModel
     * @Description: TODO 读取模板,路径存在返回,不存在返回 null
     * @param modelPath 模板路径
     * @return
     * @return: String
     */
    private static String readEamilModel(String modelPath){
        sbf = new StringBuffer();
        String modelFilePath = rpath+modelPath;
        boolean flag = fileIsTrue(modelFilePath);
        if(!flag){
            System.out.println("路径不正确:"+rpath+",或模板不存在:"+modelPath);
            return null;
        }
        InputStreamReader in = null;
        BufferedReader br = null;
        try {
            in = new InputStreamReader(new FileInputStream(modelFilePath));
            br = new BufferedReader(in);
            String line=null;
            while((line=br.readLine()) != null){
                int index = line.indexOf("[lqs-##]");
                if(index != -1){
                    System.out.println("过滤注释行:"+line);
                    line = line.substring(0, index);
                    if("".equals(line))continue;
                }
                sbf.append(line).append("\n");
            }
        } catch (FileNotFoundException e) {
            System.out.println("IO 异常:模板不存在!"+e.toString());
        } catch (IOException e) {
            System.out.println("IO 异常:获取模板流出现异常!"+e.toString());
        } finally {
            try {
                if(br != null){
                    br.close();
                }
                if(in != null){
                    in.close();
                }
            } catch (IOException e) {
                System.out.println("IO 异常:关闭流出现异常!"+e.toString());
            }
        }
        return sbf.toString();
    }

    /**
     * 
     * @Title: getMailList
     * @Description: TODO 收件人地址处理
     * @param mailArray
     * @return
     * @return: String
     */
    private String getMailList(String[] mailArray){
        sbf = new StringBuffer();
        int length = mailArray.length;
        if(mailArray != null && length < 2){
            sbf.append(mailArray[0]);
        }else{
            for(int i = 0; i < length; i++){
                sbf.append(mailArray[i]);
                if(i != (length - 1)){
                    sbf.append(",");
                }
            }
        }
        return sbf.toString();
    }

    /**
     * 
     * @Title: fileIsTrue
     * @Description: TODO 判断文件路径是否存在
     * @param filePath 文件路径
     * @return
     * @return: boolean
     */
    public static boolean fileIsTrue(String filePath){
        File file = new File(filePath);
        if(file.exists())return true;
        return false;
    }

    /**
     * 
     * @Title: sendEmailCase
     * @Description: TODO 邮件参数处理
     * @param emailmodel 模板全名+后缀
     * @param copyto 抄送人
     * @param subject 主题
     * @param content 正文
     * @param fileList 附件列表
     * @param to 收件人
     * @return
     * @return: boolean
     */
    public boolean sendEmailCase(String emailmodel, String[] copyto, String subject, String content, String[] fileList, String... to){
        /*******************************模板处理*******************************/
        if(emailmodel != null){//测试模板是否存在,不存在的话直接使用正文作为邮件发送内容
            int indexof = emailmodel.lastIndexOf(".");
            if(indexof == -1){
                System.out.println("邮件模板异常:["+emailmodel+"],将不使用模板!");
            }else{
                if(!"model".equals(emailmodel.substring(indexof+1, emailmodel.length()))){//拿到模板后缀
                    System.out.println("邮件模板后缀异常:["+emailmodel+"],将不使用模板!");
                }else{
                    emailmodel = readEamilModel(emailmodel);//获取模板
                    if(emailmodel == null){
                        System.out.println("邮件模板为空,将不使用模板!");
                    }else{
                        content = StringUtils.replace(emailmodel, "${content}", content);//替换模板中的正文
                    }
                }
            }
        }else{
            System.out.println("邮件模板异常:[NULL],将不使用模板!");
        }
        /*******************************收件人处理*******************************/
        List<String> toFrom = null;//用于接收处理过的收件人
        int k=0;
        do{//k==1 处理收件人,k>1 处理转送人
            k++;
            String[] stri;
            toFrom = new ArrayList<String>();
            if(k==1){
                stri = to;
            }else{
                stri = copyto;
            }
            for (int i = 0; i < stri.length; i++) {
                String str = stri[i];
                str = str.replaceAll(REGEX, "");//去除空格
                Pattern r = Pattern.compile(PATTERN);//匹配邮箱
                Matcher m = r.matcher(str);
                if(m.matches()){
                    toFrom.add(str);
                }
            }
            int size = toFrom.size();
            if(size<1 && k==1){
                System.out.println("无收件人,邮件发送失败");
                return false;
            }else if(size<1 && k>1){
                System.out.println("此邮件无需转送他人");
                copyto = null;
            }else{
                if(k==1){
                    to = (String[])toFrom.toArray(new String[size]);
                }else if(k>1){
                    copyto = (String[])toFrom.toArray(new String[size]);
                }
            }
        }while(k<2);
        /*******************************正文图片处理*******************************/
        String[] logoarr = logoUrl.split(",");//配置文件的图片路径
        if(logoarr.length > 0){
            List<String> logolist = new ArrayList<String>(Arrays.asList(logoarr));
            Iterator<String> it = logolist.iterator();
            while(it.hasNext()){
                String str = it.next();
                int num = str.indexOf(".");//判断文件是否有 . 存在
                if(num == -1){
                    it.remove();
                }
            }
            logoarr = logolist.toArray(new String[logolist.size()]);
        }
        return sendMail(to, copyto, subject, content, logoarr, fileList);
    }


    /**
     * 
     * @Title: getRealPath
     * @Description: TODO 获取项目 src 路径
     * @return
     * @return: String
     */
    private static String getRealPath(){
        rpath = EmailUtils.class.getResource("/").getPath().toString();
        rpath = rpath.substring(1, rpath.length());
        rpath = rpath.replace("\\","");
        rpath = rpath.replace("/","\\");
        /*realPath = realPath.replace("file:","");
        realPath = realPath.replace("classes\\","");
        String path = Thread.currentThread().getContextClassLoader().getResource("").toString();
        path = path.replace("/","\\");
        path = path.replace("file:","");
        path = path.replace("classes\\","");
        path = path.substring(1);
        */
        return rpath;
    }

    /**
     * @Title: getRealPath
     * @Description: TODO 获取项目真实路径+后缀
     * @param fileName
     * @return
     * @return: String
     */
    public static String getRealPath(String fileName){
        return getRealPath()+fileName;
    }

    /**
     * 
     * @Title: main
     * @Description: TODO 测试
     * @param args
     * @return: void
     */
    public static void main(String[] args) {
        EmailUtils eu = EmailUtils.getInstance();
        eu.configurationFile();//测试配置文件
        String[] to = {"xxx@qq.com","xxx@163.com","xxx@xxx.com"};//收件人
        String[] copyto = {"xxx@qq.com"};//转送人
        String subject = "T̶a̶i̶z̶i̶";//主题
        sbf = new StringBuffer();
        sbf.append("您好:<p class=\"body\" style=\"margin: 1em 0px; color: rgb(51, 51, 51); font-size: 10px;\">如果有一天:<br><br><br>你不再寻找爱情,只是去爱;<br><br><br>你不再渴望成功,只是去做;<br><br><br>你不再追求空泛的成长,只是开始修养自己的性情;<br><br><br>你人生的一切,才真正开始。");
        sbf.append("<a href=\"mailto:it52luo@163.com\" target=\"_blank\">Tai<wbr>zi</a> 长情。</p>");
        sbf.append("<p class=\"body\" style=\"margin: 1em 0px; color: rgb(51, 51, 51); font-size: 10px;\">Luoyc</p>");
        sbf.append("<p class=\"body salutation\" style=\"margin: 1em 0px; color: rgb(51, 51, 51); font-size: 10px;\">此致<br>Luoyc</p>");
        String content = sbf.toString();//正文
        String emailmodel = "email.model";//模板名称.后缀
        List<String> list = new ArrayList<String>();//附件地址
        list.add(getRealPath()+"TaiziLuoyc.gif");
        int size = list.size();
        String[] fileList = (String[])list.toArray(new String[size]);
        eu.sendEmailCase(emailmodel, copyto, subject, content, fileList, to);
    }

    /**
     * 
     * @Title: configurationFile
     * @Description: TODO 测试配置文件
     * @return: void
     */
    private void configurationFile(){
        System.out.println("当前路径:"+rpath);
        System.out.println("配置文件路径:"+filePath);
        Set<String> spn = pro.stringPropertyNames();
        if(spn.size() == 0){
            System.out.println("无数据");
            return;
        }
        Iterator<String> it = spn.iterator();
        System.out.println("打印配置文件参数:");
        while(it.hasNext()){
            String key = it.next();
            System.out.println(key+":"+pro.getProperty(key));
        }
    }

至此,邮件发送结束,代码块的逻辑很简单,就不赘述了。

资源地址:http://download.csdn.net/detail/qq_29689487/9798886

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值