前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何将offcie 2003文档(.doc、.xls、.ppt)转换成mht文档

如何将offcie 2003文档(.doc、.xls、.ppt)转换成mht文档

作者头像
张善友
发布于 2022-03-28 02:40:53
发布于 2022-03-28 02:40:53
1.5K00
代码可运行
举报
文章被收录于专栏:张善友的专栏张善友的专栏
运行总次数:0
代码可运行

要实现office文档转换成MHTML文档,首先会将office文档转换成HTML格式的文档,然后将HTML文档转换成MHTML文档。要将office文档转成HTML需要使用Microsoft.HtmlTrans.Interface的程序集。这个程序集是需要安装“HTML 转换服务器”。HTML 转换服务器是 Windows SharePoint Services 服务器场的可选组件。你可以在微软网站上找到该服务器的安装文件,或单击这里下载。

按照下面的步骤安装:

1. 解压缩下载的文件,里面有文件: eng11probypass.mst htmltrbackend.msi HTML Viewer WhitePaper文档 2. 如果已经安装了office,请先卸载,然后安装支持HTML Viewer Services的Office: 在Office安装路径下,找到Setup文件所在路径; 将eng11probypass.mst文件拷贝到该路径下; 在命令提示符下输入:Setup transforms= eng11probypass.mst来安装支持HTML Viewer的Office; 3. 安装HTML Viewer Server:运行htmltrbackend.msi;

安装好以后,找到Microsoft.HtmlTrans.Interface.dll文件并把它copy到项目文件夹中。在项目中引用该文件。由于将用到命名空间Microsoft.HtmlTrans中的htmlTrLoadBalancer和htmlTrLauncher两个Romoting对象将office文档转换为HTML文件。不过需要注意:

Document types not supported are: Master documents in Word (see Word Help for an explanation of Master document) Password protected documents, workbooks, and presentations (encrypted) Word documents that use framesets Files that contain Excel 4.0 macros WordPerfect files For files with embedded objects, VBA, scripts, etc, the following rules apply: VBA is ignored and not executed; However, the VBA project (source code, dialog definitions, etc) is retained Embedded and linked objects are converted to graphic images and displayed in the approximate location where they were in the source file Linked or embedded objects with password protection are not converted

在实现中另外一个难点就是如何将HTML转换成MHTML。MHTML是 MIME Encapsulation of Aggregate HTML的缩写,它是一种网络编码格式,是用来定义在电子邮件正文中如何传送html内容的MIME标准。通俗点说,就是一个HTML文件和包括其中的.css文件、.js文件、图片等等一切的资源文件都整合在一个MHTL文件中。以下是一个典型的MHTML文件(;后为解释部分):

Mime-Version: 1.0 ; Content-Location为主文件地址,可以随意设定 Content-Location: http://www.ietf.cnri.reston.va.us/ ; Content-Type为MTHML文件的类型,这里表示MHTML文件中包含多种文件类型 ;boundary定义文件之间的分隔符,可随意定义 ;type为主文件格式 Content-Type: multipart/related; boundary="boundary-example";type="text/html"

;在前面加”--”字符表示一个文件开始 --boundary-example ;以下是文件头 ; text/html 表示该文件的文件类型;charset表示使用的字符集 Content-Type: text/html; charset="ISO-8859-1" ; Content-Transfer-Encoding:表示的是该文件的编码类型; ;一般有两种:一种是文本类型的一般使用”QUOTED-PRINTABLE”; ;另一种是二进制文件一般使用”BASE64” Content-Transfer-Encoding: QUOTED-PRINTABLE

;以下是正文 ... text of the HTML document, which might contain URIs referencing resources in other body parts, for example through statements such as:

<IMG SRC="images/ietflogo1.gif" ALT="IETF logo1"> <IMG SRC="images/ietflogo2.gif" ALT="IETF logo2"> <IMG SRC="images/ietflogo3.gif" ALT="IETF logo3">

Example of a copyright sign encoded with Quoted-Printable: =A9 Example of a copyright sign mapped onto HTML markup: ¨

--boundary-example ; Content-Location:该文件的地址,可以是绝对地址或相对主文件的相对地址 ;这里是绝对地址 Content-Location:http://www.ietf.cnri.reston.va.us/images/ietflogo1.gif Content-Type: IMAGE/GIF ;二进制文件,使用BASE64编码 Content-Transfer-Encoding: BASE64

R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5 NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A etc...

--boundary-example ;这里是相对地址 Content-Location: images/ietflogo2.gif Content-Transfer-Encoding: BASE64

R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5 NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A etc...

--boundary-example Content-Location:http://www.ietf.cnri.reston.va.us/images/ietflogo3.gif Content-Transfer-Encoding: BASE64

R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5 NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A etc... ;注意这里是结束标记,表示MHTML文件已经结束了.在定义的分隔符前后都加上”--” --boundary-example—

上面是标准的MHTML文件格式,但是按上面的标准是无法在IE里面正确浏览的。还需要注意以下几点:

1. 凡是文本类型的文件所有的”=”替换成”=3D”,例如 <IMG SRC="images/ietflogo3.gif" ALT="IETF logo3"> 要替换成 <IMG SRC=3D"images/ietflogo3.gif" ALT=3D"IETF logo3"> 2. 所有的BASE64编码的文件必须要换行; 3. 每个文件开头的分隔符要在前加上”--”,而最后一个分隔符要在前后加上”--”; 4. 正文与文件头和下一个文件的分割符都要有换行符。 实现代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System;
using System.Collections;
using System.IO;
using System.Text;
using Microsoft.HtmlTrans;

namespace MSOfficeHelper
{
    public class Conversion
    {
        //字符串的编码
        protected static Encoding encoding = Encoding.Default;
        //用于创建IHtmlTrLoadBalancer的remoting对象的url

        protected static string strServiceUrl = System.Configuration.ConfigurationSettings.AppSettings["OfficeHtmlViewService"];

        public static void ConvertMHT(string inputfile, string outputfile)
        {
            //通过url(strServiceUrl)获取一个IHtmlTrLoadBalancer的remoting对象
            IHtmlTrLoadBalancer htmlTrLoadBalancer =
                (IHtmlTrLoadBalancer) System.Activator.GetObject(
                    typeof (IHtmlTrLoadBalancer), strServiceUrl);
            //用输入文件名(inputfile)作为一个任务的任务标示(strTask)
            string strTask = inputfile;

            //根据任务标示(strTask)新建一个任务并获取任务的url(strLauncherUri)
            string strLauncherUri = htmlTrLoadBalancer.StrGetLauncher(strTask);

            //通过任务的url(strLauncherUri)获取一个IHtmlTrLauncher的remoting对象(htmlTrLauncher),
            //并用这个对象来执行该任务
            IHtmlTrLauncher htmlTrLauncher =
                (IHtmlTrLauncher) System.Activator.GetObject(typeof (IHtmlTrLauncher), strLauncherUri);

            //接下来是把输入文件(inputfile)的内容读入一个byte数组(bFile)
            byte[] bFile = null;
            FileStream fsInputMht = null;
            BinaryReader bwInputMht = null;
            try
            {
                fsInputMht = new FileStream(inputfile, FileMode.Open);
                bwInputMht = new BinaryReader(fsInputMht, encoding);
                bFile = new byte[fsInputMht.Length];
                for (long i = 0; i < bFile.LongLength; i++)
                    bFile[i] = bwInputMht.ReadByte();
                bwInputMht.Close();
                fsInputMht.Close();

            }
            catch (Exception ex)
            {
                bwInputMht.Close();
                fsInputMht.Close();
                throw ex;
            }

            //CHICreateHtml通过office文档创建HTML文件及其附件
            //CHICreateHtml(
            //string strLauncherUri,         任务的url
            //byte[] rgbFile,             office文档的二进制内容
            //Microsoft.HtmlTrans.BrowserType bt, 使用浏览类型,该参数是一个枚举类型
            //string strReqFile,           office文档的路径/url
            //string strTaskName,           任务标示名,HTML转换服务器根据其跟踪该请求
            //int timeout,                 转换超时时间,如果网络状况较差,建议值设大点
            //bool fReturnFileBits          是否返回二进制内容,分别保存在CreateHtmlInfo的rgbMainFile属性和rgrgbThicketFiles属性中
            //);
            CreateHtmlInfo chi = htmlTrLauncher.CHICreateHtml(strLauncherUri, bFile,
                                                              BrowserType.BT_IE4, inputfile, strTask, 200, true);

            //结束转换任务
            htmlTrLoadBalancer.LauncherTaskCompleted(strLauncherUri, strTask);

            //在转换HTML文件的过程中没有错误,并且存在主文件,执行以下代码
            if (chi.ce == CreationErrorType.CE_NONE && chi.fHasMainFile)
            {
                FileStream fsOutputMht = null;
                BinaryWriter bwOutputMht = null;
                try
                {
                    fsOutputMht = new FileStream(outputfile, FileMode.Create);
                    bwOutputMht = new BinaryWriter(fsOutputMht, encoding);
                    //将HTML文件及其附件转换为MHTML文件
                    byte[] bMHTMLBody = CreateMHTMLBody(chi);
                    string temp = System.Text.Encoding.Default.GetString(bMHTMLBody);

                    StringBuilder sb = new StringBuilder();

                    foreach (char c in temp.ToCharArray())
                    {
                        string t = c.ToString();
                        if ((uint) c > 500)
                        {
                            t = "&#" + ((uint) c).ToString() + ";";
                        }

                        sb.Append(t);
                    }

                    bMHTMLBody = Encoding.ASCII.GetBytes(sb.ToString());

                    bwOutputMht.Write(bMHTMLBody);
                    bwOutputMht.Close();
                    fsOutputMht.Close();
                    return;
                }
                catch (Exception ex)
                {
                    bwOutputMht.Close();
                    fsOutputMht.Close();
                    throw ex;
                }
            }
            return;
        }

        //MHTML文件头信息
        protected static string MIME =
            "MIME-Version: 1.0" + Environment.NewLine +
                "Content-Type: multipart/related; boundary=\"{0}\"" + Environment.NewLine +
                Environment.NewLine;

        //MHTML各个文件的头信息
        protected static string HEADER =
            Environment.NewLine + "--{0}" + Environment.NewLine +
                "Content-Location: {1}" + Environment.NewLine +
                "Content-Transfer-Encoding: {2}" + Environment.NewLine +
                "Content-Type: {3}" + Environment.NewLine +
                Environment.NewLine;

        //定义MHTML中各文件之间的分隔符
        protected static string BOUNDARY = "Define_It_Youself";
        //MHTML主文件的URL
        protected static string LOCATION = string.Format(@"file:///c:/{0}/",Guid.NewGuid());

        private static byte[] CreateMHTMLBody(CreateHtmlInfo creatHtmlInfo)
        {
            //将回车换行符进行编码并存储在字节数组中
            byte[] bNewLine = Encoding.UTF8.GetBytes(Environment.NewLine);
            //将3D进行编码并存储在字节数组中
            byte[] bAfterEquals = encoding.GetBytes("3D");
            //'='的byte值为61
            byte bEquals = 61;
            //MHTML文件的长度
            long lMHTMLBodyLength = 0;
            //从零开始的字节偏移量
            long lOffset = 0;
            //根据BOUNDARY的定义形成MTHML文件的头信息
            string strMIME = string.Format(MIME, BOUNDARY);
            //将头信息进行编码并存储在字节数组中
            byte[] bMIME = encoding.GetBytes(strMIME);
            //MHTML文件的长度增加bMIME.LongLength
            lMHTMLBodyLength += bMIME.LongLength;

            //根据信息定义主文件的头信息
            string strMainHeader = string.Format(HEADER,
                                                 BOUNDARY,
                                                 LOCATION + creatHtmlInfo.strMainFileName,
                                                 TransferEncoding.QUOTED_PRINTABLE,
                                                 ContentType.TEXT_HTML);

            byte[] bMainHeader = encoding.GetBytes(strMainHeader);
            lMHTMLBodyLength += bMainHeader.LongLength;

            //建立一个动态临时数组
            ArrayList alTempArray = new ArrayList();

            //主文件的正文部分所有的"="替换成"=3D"
            for (int i = 0; i < creatHtmlInfo.rgbMainFile.Length; i ++)
            {
                alTempArray.Add(creatHtmlInfo.rgbMainFile[i]);
                if (creatHtmlInfo.rgbMainFile[i] == bEquals)
                {
                    alTempArray.Add(bAfterEquals[0]);
                    alTempArray.Add(bAfterEquals[1]);
                }
            }
            //获取新的主文件的正文部分并存储在字节数组中
            byte[] bMainBody = new byte[alTempArray.Count];
            alTempArray.CopyTo(bMainBody);
            lMHTMLBodyLength += bMainBody.LongLength;
            alTempArray.Clear();

            //申明存储MHTML附件的正文内容字节数组,该数组为一个二维数组
            byte[][] bThicketContent = null;
            //申明存储MHTML附件的头信息字节数组
            string[] strThicketHeaders = null;
            //如果MHTML存在附件则执行以下代码
            if (creatHtmlInfo.fHasThicket)
            {
                bThicketContent = new byte[creatHtmlInfo.rgrgbThicketFiles.Length][];
                strThicketHeaders = new string[creatHtmlInfo.rgrgbThicketFiles.Length];
                for (int i = 0; i < strThicketHeaders.Length; i++)
                {
                    //定义附件的头信息
                    string strLocation = LOCATION +
                        creatHtmlInfo.strThicketFolderName + "/" +
                        creatHtmlInfo.rgstrThicketFileNames[i];
                    string strTransferEncoding = TransferEncoding.GetTransferEncodingByFileName
                        (creatHtmlInfo.rgstrThicketFileNames[i]);
                    string strContentType = ContentType.GetContentTypeByFileName
                        (creatHtmlInfo.rgstrThicketFileNames[i]);
                    strThicketHeaders[i] = string.Format(HEADER,
                                                         BOUNDARY,
                                                         strLocation,
                                                         strTransferEncoding,
                                                         strContentType);
                    byte[] bThicketHeader = encoding.GetBytes(strThicketHeaders[i]);

                    StringBuilder strBase64ThicketBody = new StringBuilder();
                    byte[] bThicketBody = null;
                    //如果附件二进制文件,那么用BASE64编码
                    if (strTransferEncoding ==
                        TransferEncoding.BASE64)
                    {
                        //首先将字节数组里的内容转换为Base64编码的字符串
                        strBase64ThicketBody.Append(
                            Convert.ToBase64String(creatHtmlInfo.rgrgbThicketFiles[i]));
                        //然后将字符串进行编码存储在新的字节数组中
                        bThicketBody = encoding.GetBytes(strBase64ThicketBody.ToString());
                        //每76个字节,加入一个换行符
                        int BUFFER_SIZE = 76;
                        for (int j = 0; j < bThicketBody.Length; j++)
                        {
                            alTempArray.Add(bThicketBody[j]);
                            if (j%BUFFER_SIZE == BUFFER_SIZE - 1)
                            {
                                alTempArray.Add(bNewLine[0]);
                                alTempArray.Add(bNewLine[1]);
                            }
                        }
                        bThicketBody = new byte[alTempArray.Count];
                        alTempArray.CopyTo(bThicketBody);
                        alTempArray.Clear();
                    }
                        //如果附件是以明文编码,那么明文编码,并将附件正文部分所有的"="替换成"=3D"
                    else
                    {
                        for (int j = 0; j < creatHtmlInfo.rgrgbThicketFiles[i].Length; j++)
                        {
                            alTempArray.Add(creatHtmlInfo.rgrgbThicketFiles[i][j]);
                            if (creatHtmlInfo.rgrgbThicketFiles[i][j] == bEquals)
                            {
                                alTempArray.Add(bAfterEquals[0]);
                                alTempArray.Add(bAfterEquals[1]);
                            }
                        }
                        bThicketBody = new byte[alTempArray.Count];
                        alTempArray.CopyTo(bThicketBody);
                        alTempArray.Clear();
                    }


                    //如中htm文件则进行添加base操作
                    string ext = Path.GetExtension(creatHtmlInfo.rgstrThicketFileNames[i]).ToLower();
                    if (ext == ".htm")
                    {
                        string body = Encoding.Default.GetString(bThicketBody);

                        int start = body.IndexOf("<link");

                        if (start > -1)
                        {
                            body =
                                body.Insert(
                                    start,
                                    string.Format(
                                        "\r\n<![if IE]>\r\n"
                                            + "<base href=3D\"{0}\"\r\n"
                                            + "id=3D\"webarch_temp_base_tag\">\r\n"
                                            + "<![endif]>\r\n",
                                        LOCATION + creatHtmlInfo.strThicketFolderName + @"/" + creatHtmlInfo.rgstrThicketFileNames[i]
                                        )
                                    );
                        }

                        byte[] data = Encoding.Default.GetBytes(body);
                        bThicketBody = new byte[data.Length];

                        data.CopyTo(bThicketBody, 0);
                    }
                    //将附件中的头信息字节数组和正文的字节数组合并存储在bThicketContent[i]中,
                    //并在lMHTMLBodyLength增加相应的长度
                    bThicketContent[i] = new byte[bThicketHeader.LongLength + bThicketBody.LongLength + bNewLine.LongLength];
                    Array.Copy(
                        bThicketHeader,
                        0,
                        bThicketContent[i],
                        0,
                        bThicketHeader.LongLength);
                    Array.Copy(
                        bThicketBody,
                        0,
                        bThicketContent[i],
                        bThicketHeader.LongLength,
                        bThicketBody.LongLength);
                    Array.Copy(
                        bNewLine,
                        0,
                        bThicketContent[i],
                        bThicketHeader.LongLength + bThicketBody.LongLength,
                        bNewLine.LongLength);
                    lMHTMLBodyLength += bThicketContent[i].LongLength;
                }
            }
            //MHTML文件结束分割符的存储在字节数组中
            byte[] bEndBoundary = encoding.GetBytes(
                Environment.NewLine + "--" + BOUNDARY + "--" + Environment.NewLine);
            lMHTMLBodyLength += bEndBoundary.LongLength;

            //新建一个数组,该数组用于存储MHTML文件的所有内容
            byte[] bMHTMLBody = new byte[lMHTMLBodyLength];
            //将所有的内容全部合并,并存储在数组bMHTMLBody中
            Array.Copy(bMIME, 0, bMHTMLBody, lOffset, bMIME.LongLength);
            lOffset += bMIME.LongLength;
            Array.Copy(bMainHeader, 0, bMHTMLBody, lOffset, bMainHeader.LongLength);
            lOffset += bMainHeader.LongLength;
            Array.Copy(bMainBody, 0, bMHTMLBody, lOffset, bMainBody.LongLength);
            lOffset += bMainBody.LongLength;
            if (bThicketContent != null)
                for (int i = 0; i < bThicketContent.Length; i++)
                {
                    Array.Copy(
                        bThicketContent[i],
                        0,
                        bMHTMLBody,
                        lOffset,
                        bThicketContent[i].LongLength);
                    lOffset += bThicketContent[i].LongLength;
                }
            Array.Copy(bEndBoundary, 0, bMHTMLBody, lOffset, bEndBoundary.LongLength);

            return bMHTMLBody;
        }
    }

    //根据不同的文件后缀名定义编码方式
    class TransferEncoding
    {
        public const string QUOTED_PRINTABLE = "quoted-printable";
        public const string BASE64 = "base64";

        public static string GetTransferEncodingByFileName(string fileName)
        {
            string strRusult = string.Empty;
            string strExtension = fileName.Remove(0, fileName.LastIndexOf(".")).ToUpper();
            switch (strExtension)
            {
                    //以下文件名在MTHML文件中都将以明文的形式编码
                default:
                case ".HTM":
                case ".HTML":
                case ".XML":
                    strRusult = TransferEncoding.QUOTED_PRINTABLE;
                    break;
                    //以下文件名在MHTML文件中都将以BASE64编码形式出现
                case ".JPG":
                case ".JEPG":
                case ".PNG":
                case ".MSO":
                case ".EMZ":
                case ".GIF":
                case ".WMF":
                case ".WMZ":
                case ".CSS":
                    strRusult = TransferEncoding.BASE64;
                    break;
            }
            return strRusult;
        }
    }

    //根据不同的后缀名定义文件内容的类型
    class ContentType
    {
        public const string TEXT_HTML = "text/html; charset=\"us-ascii\"";
        public const string APPLICATION_XMSO = "application/x-mso";
        public const string IMAGE_XEMZ = "image/x-emz";
        public const string IMAGE_GIF = "image/gif";
        public const string TEXT_CSS = "text/css";
        public const string TEXT_XML = "text/xml; charset=\"utf-8\"";
        public const string IMAGE_XWMF = "image/x-wmf";
        public const string IMAGE_PNG = "image/png";
        public const string IMAGE_JPEG = "image/jpeg";
        public const string TEXT_JS = "application/javascript; charset=\"us-ascii\"";
        public const string IMAGE_WMZ = "image/x-wmz";


        public static string GetContentTypeByFileName(string fileName)
        {
            string strExtension = fileName.Remove(0, fileName.LastIndexOf(".")).ToUpper();
            switch (strExtension)
            {
                    //以下文件名在MHTML文件中的类型是text/html; charset="us-ascii"
                case ".HTM":
                case ".HTML":
                    return ContentType.TEXT_HTML;
                    //以下文件名在MHTML文件中的类型是application/x-mso
                case ".MSO":
                    return ContentType.APPLICATION_XMSO;
                    //以下文件名在MHTML文件中的类型是image/x-emz
                case ".EMZ":
                    return ContentType.IMAGE_XEMZ;
                    //以下文件名在MHTML文件中的类型是image/gif
                case ".GIF":
                    return ContentType.IMAGE_GIF;
                    //以下文件名在MHTML文件中的类型是text/css
                case ".CSS":
                    return ContentType.TEXT_CSS;
                    //以下文件名在MHTML文件中的类型是text/xml; charset="utf-8"
                case ".XML":
                    return ContentType.TEXT_XML;
                    //以下文件名在MHTML文件中的类型是image/x-wmf
                case ".WMF":
                    return ContentType.IMAGE_XWMF;
                    //以下文件名在MHTML文件中的类型是image/png
                case ".PNG":
                    return ContentType.IMAGE_PNG;
                    //以下文件名在MHTML文件中的类型是image/jpeg
                case ".JPG":
                case ".JEPG":
                    return ContentType.IMAGE_JPEG;

                case ".JS":
                    return ContentType.TEXT_JS;

                case ".WMZ":
                    return ContentType.IMAGE_WMZ;
            }
            return string.Empty;
        }
    }

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2007-11-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
今天要说的是spring中循环依赖的问题,最近有大量粉丝问这个问题,也是高薪面试中经常会被问到的一个问题。
路人甲Java
2020/05/18
1.5K0
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
最新整理Spring面试题2023
好了,不开玩笑,面对这个问题我们应该怎么来回答呢?我们给大家梳理这个几个维度来回答
用户4919348
2023/03/08
2.3K0
最新整理Spring面试题2023
使用Mockito修改Bean的依赖
在使用单元测试时经常会遇到某些dependency依赖了外部资源,或者想主动绕过真正的方法执行mock返回结果而快速得到单元测试最终的期望结果,可能有以下两种场景, 对于TestCase A,设单元测试的方法是Service A的execute1方法和execute2方法,在执行execute1和execute2方法时都会调用ServiceB的不同方法,即ServiceA依赖了ServiceB;一个场景是完全对ServiceB进行Mock,如单元测试ServiceA#execute1方法时都通过Mock返回结果;一个场景是部分ServiceB的方法执行真实的业务逻辑(如查询数据库),一部分方法执行Mock返回结果,或Spy,如如单元测试ServiceA#execute2方法时,只mock ServiceB#b2结果,真正执行ServiceB#b1方法。
用户3579639
2018/10/22
2K0
Dependency Injection: 如何解决依赖注入失败问题
大家好,我是默语,擅长全栈开发、运维和人工智能技术。依赖注入(Dependency Injection)是现代软件开发中的一项关键技术,用于实现组件解耦和提高代码可维护性。然而,依赖注入有时会遇到一些问题,例如注入失败、循环依赖等。本文将深入探讨依赖注入失败的原因及解决方案,帮助大家更好地使用依赖注入技术。
默 语
2024/11/22
3130
Spring如何解决循环依赖
那么Spring是如何解决这种问题呢?今天来分析一下。不过需要先熟悉下Bean的生命周期:宏观来看Bean的生命周期分为四步:1.实例化 2.属性设置 3.初始化 4.销毁。对依赖注入而言在第二步属性设置其实已经完成了,所以只需要关注前两步即可。
默 语
2024/11/22
2260
Spring如何解决循环依赖
今日头条面试,这个问题让我与50万擦肩而过,帮忙看看!
我:当某个类上有@Configuration注解的时候,可以在这个类中使用@Bean注解向spring容器中注册bean;如果不加@Configuration注解,不能通过@Bean注解注册bean。
路人甲Java
2020/03/26
6070
Spring是如何解决循环依赖的?
A对象,它的属性是B对象,而B对象的属性也是A对象,说白了就是A依赖B,而B又依赖A
Blue_007
2023/10/21
3320
Spring是如何解决循环依赖的?
Spring系列第14篇:单例bean中使用多例bean,你未必会玩?
通常情况下,我们使用的bean都是单例的,如果一个bean需要依赖于另一个bean的时候,可以在当前bean中声明另外一个bean引用,然后注入依赖的bean,此时被依赖的bean在当前bean中自始至终都是同一个实例。
路人甲Java
2020/03/12
2.6K0
Spring中循环依赖解决方案
循环依赖是Spring框架中常见的问题之一,当两个或多个类相互引用对方时,就会出现循环依赖的情况。这种情况下,Spring框架无法确定哪个类应该先实例化和初始化,从而导致异常。常见的解决方法有:构造函数注入、setter方法注入、静态工厂方法注入以及使用第三方库等。
鱼找水需要时间
2023/08/16
7.4K0
Spring中循环依赖解决方案
Spring基础
Spring框架是一个全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层,主要包括以下七个模块:
羽毛球初学者
2024/10/22
1440
Spring系列面试题
@Controller注解 是在Spring的org.springframework.stereotype包下,org.springframework.stereotype.Controller注解类型用于指示Spring类的实例是一个控制器,使用@Controller注解的注解注解的控制器可以同时支持处理多个请求动作,使程序开发变的更加灵活。 @Controller用户标记一个类,使用它标记的类就是一个Spring MVC Controller对象,即:一个控制器类。Spring使用扫描机制查找应用程序中所有基于注解的控制器类,分发处理器会扫描使用了该注解的方法,并检测该方法是否使用了@RequestMapping注解,而使用@RequestMapping注解的方法才是真正处理请求的处理器。为了保证Spring能找到控制器,我们需要完成两件事:
用户3467126
2019/09/30
7330
Spring系列面试题
Spring系列第十九讲 @Configuration和@Bean注解详解
@Configuration这个注解可以加在类上,让这个类的功能等同于一个bean xml配置文件,如下:
易兮科技
2020/11/24
15K1
Spring解决循环依赖的思路
循环依赖也就是循环引用,指两个或多个对象互相持有对方的引用。通俗地说,假设在Spring中有3个Service Bean,分别为ServiceA、ServiceB和ServiceC,如果ServiceA引用了ServiceB,ServiceB引用了ServiceC,而ServiceC又引用了ServiceA,最终形成可一个环,这样就出现了循环依赖。
张申傲
2020/09/03
6970
Spring系列第10篇:primary可以解决什么问题?
上面代码很简单,@1:定义了一个接口IService,@2和@3创建了两个类都实现了IService接口。
路人甲Java
2020/02/26
8200
面经手册 · 第31篇《Spring Bean IOC、AOP 循环依赖解读》
大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作费劲,尤其是我能非常熟悉的软件开发行业,即使是毕业了还需要额外花钱到培训机构,在学一遍编程技术才能出去找工作。好像在校这几年压根就没学到什么!
小傅哥
2021/05/17
4490
面经手册 · 第31篇《Spring Bean IOC、AOP 循环依赖解读》
Spring官网阅读系列(二):Spring依赖注入及方法注入
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识。这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入。虽然只有一节,但是涉及的东西确不少。话不多说,开始正文。
秃顶的Java程序员
2020/03/24
4640
面试专题-框架篇
refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:
sgr997
2022/11/10
4800
面试专题-框架篇
这么回答【循环依赖】助力轻松拿下阿里P6
  上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依赖的本质是一样的,就你的完整创建要依赖与我,我的完整创建也依赖于你。相互依赖从而没法完整创建造成失败。
用户4919348
2022/10/04
2290
这么回答【循环依赖】助力轻松拿下阿里P6
Spring系列第11篇:bean中的autowire-candidate又是干什么的?
上一篇文章Spring系列第10篇:primary可以解决什么问题?中遇到的问题我们再来回顾一下,当容器中某种类型的bean存在多个的时候,此时如果我们从容器中查找这种类型的bean的时候,会报下面这个异常:
路人甲Java
2020/02/26
2.4K0
烂了大街的 Spring 循环依赖问题,你觉得自己会了吗
初学 Spring 的时候,我们就知道 IOC,控制反转么,它将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,不需要我们手动去各种 new XXX。
海星
2020/09/09
7120
推荐阅读
相关推荐
年薪50万的一个面试题,看着不难,却刷掉了99%的人!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验