华企号 后端开发 在文件上传模块中采用选项模式上传和FTP文件上传

在文件上传模块中采用选项模式上传和FTP文件上传

1、文件上传处理

在前面我们介绍过,文件上传处理的逻辑中有两部分,一个是本地文件处理,一个是FTP文件处理,它们选择那种方式,依赖于配置参数的信息,如下示意图所示。

在本地文件处理过程中,如果是Web API方式调用服务层,那么就在Web API所在的文件系统中,如果是Winform界面直接调用服务层,那么就是在当前系统中处理文件,这种方式可以有效的管理我们的文件信息。

在FTP文件处理过程中,则是根据选项参数的信息,调用FluentFTP类库进行文件的上传操作。

在Winform界面中上传文件的界面如下所示,它对于采用哪种方式是不知道的,具体由配置参数决定。

 

而所有的附件信息我们存储在数据库里面,文件则存放在对应的文件夹里面,可以统一进行管理查看和管理。

 

2、选项模式【Options】的处理

首先根据我们的处理方式,我们定义一个对象,用于承载上传参数的信息,如下代码所示。

复制代码
    /// <summary>
    /// 文件上传处理的选项信息
    /// </summary>
    public class UploadSettingOptions
    {
        /// <summary>
        /// 可指定的存储物理地址,如C:\Attachment,如果没有配置项AttachmentBasePath,则默认一个相对目录。
        /// </summary>
        public string AttachmentBasePath { get; set; }

        /// <summary>
        /// 指定附件上传的方式,如ftp为FTP方式,为空则为普通方式
        /// </summary>
        public string AttachmentUploadType { get; set; }

        /// <summary>
        /// FTP服务地址
        /// </summary>
        public string FtpServer { get; set; }

        /// <summary>
        /// FTP用户名
        /// </summary>
        public string FtpUser { get; set; }

        /// <summary>
        /// FTP密码
        /// </summary>
        public string FtpPassword { get; set; }

        /// <summary>
        /// FTP的基础路径,如可以指定为IIS的路径:http://www.iqidi.com:8000 ,方便下载打开
        /// </summary>
        public string FtpBaseUrl { get; set; }
    }
复制代码

然后在项目中添加Microsoft.Extensions.Options引用。

我们定义文件上传服务类的和它的构造函数,以便于选项模式的处理。

复制代码
    /// <summary>
    /// 上传附件信息 应用层服务接口实现
    /// </summary>
    public class FileUploadService : MyCrudService<FileUploadInfo,string, FileUploadPagedDto>, IFileUploadService
    {
        //微软引入选项模式,它是用于配置框架服务使用的设置. 选项模式由Microsoft.Extensions.Options NuGet包实现
        //在你需要获得一个选项值时,将 IOptions<TOption> 服务注入到你的类中,使用它的 .Value 属性得到值.
        private readonly UploadSettingOptions _options;

        /// <summary>
        /// 参数化构造,注入上传处理设置信息
        /// </summary>
        /// <param name="options"></param>
        public FileUploadService(IOptions<UploadSettingOptions> options) 
        {
            _options = options.Value;
        }
复制代码

我们看到这里提供了一个注入接口的参数信息,这样完成参数的注入加载后,我们在该服务类调用的时候,就可以使用它的选项参数信息了。

例如我们在其中通用的上传处理方法上如下所示。

复制代码
        /// <summary>
        /// 上传文件(根据配置文件选择合适的上传方式)
        /// </summary>
        /// <param name="info">文件信息(包含流数据)</param>
        /// <returns></returns>
        public async Task<CommonResult> Upload(FileUploadInfo info)
        {
            var uploadType = this._options.AttachmentUploadType;

            if (string.IsNullOrEmpty(uploadType))
            {
                return await this.UploadByNormal(info);
            }
            else if (uploadType.Equals("ftp", StringComparison.OrdinalIgnoreCase))
            {
                return await this.UploadByFTP(info);
            }
            else
            {
                throw new ArgumentException("AttachmentUploadType配置指定了无效的值, 请置空或者填写ftp。");
            }
        }
复制代码

我们来通过读取选项参数的信息,来决定采用哪种上传文件的方式。

我们在基于.net framewrok的Winform项目App.config中指定下面的配置信息

复制代码
  <appSettings>
    <!--保存目录及FTP配置信息-->
    <!--可指定的存储物理地址,如C:\Attachment,如果没有配置则默认相对目录。-->
    <add key="AttachmentBasePath" value="" />
    <!--指定附件默认上传的方式, 如为FTP方式:ftp,为空则为普通方式-->
    <add key="AttachmentUploadType" value="" />
    <!--非空的时候,读取下面的FTP信息-->
    <add key="FtpServer" value="114.215.106.96" />
    <add key="FtpUser" value="web2" />
    <add key="FtpPassword" value="" />
    <!--可以指定为HTTP或者FTP的路径,供下载查看-->
    <add key="FtpBaseUrl" value="http://www.iqidi.com/ftp" />
  </appSettings>
复制代码

而在项目启动的时候,我们需要注入选项参数的内容,以达到完成配置文件信息的读取。

复制代码
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            // IServiceCollection负责注册
            IServiceCollection services = new ServiceCollection();//添加IApiUserSession实现类
            services.AddSingleton<IApiUserSession, ApiUserPrincipal>(); //CurrentPrincipal实现方式

            //构造对应环境下的UploadSettingOptions信息
            services.Configure<UploadSettingOptions>(option =>
            {
                SetUploadOptions(option);
            });
复制代码
复制代码
        /// <summary>
        /// 构造对应环境下的UploadSettingOptions信息
        /// </summary>
        /// <returns></returns>
        private static UploadSettingOptions SetUploadOptions(UploadSettingOptions option)
        {
            var config = new AppConfig();
            option.AttachmentBasePath = config.AppConfigGet("AttachmentBasePath");
            option.AttachmentUploadType = config.AppConfigGet("AttachmentUploadType");
            option.FtpServer = config.AppConfigGet("FtpServer");
            option.FtpUser = config.AppConfigGet("FtpUser");
            option.FtpPassword = config.AppConfigGet("FtpPassword");
            option.FtpBaseUrl = config.AppConfigGet("FtpBaseUrl");

            return option;
        }
复制代码

就这样,在.net framework的WInform项目启动的时候,我们就完成了文件上传选项参数的读取加载,这样在 FileUploadService 里面的构造函数,就可以获得对应的选项参数信息对象了。

对于.netcore的程序,我们知道它的配置信息是appSettings.json,如下节点所示。

复制代码
    "UploadSettingOptions": {
      "AttachmentBasePath": "", //可指定的存储物理地址,如C:\Attachment,如果没有配置则默认相对目录。
      "AttachmentUploadType": "", //ftp或空,为空则为普通方式
      "FtpServer": "114.215.106.96", //FTP服务器地址
      "FtpUser": "web2", //FTP账号
      "FtpPassword": "", //FTP密码
      "FtpBaseUrl": "http://www.iqidi.com/ftp"//可以指定为HTTP或者FTP的路径,供下载查看
    }
复制代码

例如对于我们在Web API的初始化选项对象信息,具体加载的代码如下所示。

builder.Services.Configure<UploadSettingOptions>(builder.Configuration.GetSection("UploadSettingOptions"));

相对.net framework的处理来说,使用扩展函数来简化了不少。

这样,我们在文件上传处理的服务类中就可以顺利获得对应的配置信息了。

复制代码
    /// <summary>
    /// 上传附件信息 应用层服务接口实现
    /// </summary>
    public class FileUploadService : MyCrudService<FileUploadInfo,string, FileUploadPagedDto>, IFileUploadService
    {
        //微软引入选项模式,它是用于配置框架服务使用的设置. 选项模式由Microsoft.Extensions.Options NuGet包实现
        //在你需要获得一个选项值时,将 IOptions<TOption> 服务注入到你的类中,使用它的 .Value 属性得到值.
        private readonly UploadSettingOptions _options;

        /// <summary>
        /// 参数化构造,注入上传处理设置信息
        /// </summary>
        /// <param name="options"></param>
        public FileUploadService(IOptions<UploadSettingOptions> options) 
        {
            _options = options.Value;
        }
复制代码

我们在使用FTP上传文件的时候,使用了FluentFtp类库实现FTP文件的上传处理的,构建FTP对象的处理代码如下所示。

复制代码
//使用FluentFTP操作FTP文件
var client = new FtpClient(this._options.FtpServer, this._options.FtpUser, this._options.FtpPassword);

//如果配置指定了端口,则使用特定端口
if (!string.IsNullOrEmpty(this._options.FtpServer) && this._options.FtpServer.Contains(":"))
{
    string port = this._options.FtpServer.Split(':')[1];
    if (!string.IsNullOrEmpty(port))
    {
        client.Port = port.ToInt32();
    }
}
复制代码

上传FTP文件的代码如下所示。

复制代码
    //确定日期时间目录(格式:yyyy-MM),不存在则创建
    string savePath = string.Format("/{0}-{1:D2}/{2}", DateTime.Now.Year, DateTime.Now.Month, category);
    bool isExistDir = client.DirectoryExists(savePath);
    if (!isExistDir)
    {
        client.CreateDirectory(savePath);
    }

    //使用FTP上传文件
    //避免文件重复,使用GUID命名
    var ext = FileUtil.GetExtension(info.FileName);
    var newFileName = string.Format("{0}{1}", Guid.NewGuid().ToString(), ext);//FileUtil.GetFileName(file);

    savePath = savePath.UriCombine(newFileName);
    var uploaded = await client.UploadAsync(info.FileData, savePath, FtpRemoteExists.Overwrite, true);

    //成功后,写入数据库
    if (uploaded == FtpStatus.Success)
    {
复制代码

 

作者: 华企网通王鹏程序员

我是程序员王鹏,热爱互联网软件开发和设计,专注于大数据、数据分析、数据库、php、java、python、scala、k8s、docker等知识总结。 我的座右铭:"业精于勤荒于嬉,行成于思毁于随"
上一篇
下一篇

发表回复

联系我们

联系我们

028-84868647

在线咨询: QQ交谈

邮箱: tech@68v8.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部