初识ABP vNext(9):ABP模块化开发-文件管理

初识ABP vNext(9):ABP模块化开发-文件管理

Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章。

前言

在之前的章节中介绍过ABP扩展实体,当时在用户表扩展了用户头像字段,用户头像就涉及到文件上传和文件存储。文件上传是很多系统都会涉及到的一个基础功能,在ABP的模块化思路下,文件管理可以做成一个通用的模块,便于以后在多个项目中复用。单纯实现一个文件上传的功能并不复杂,本文就借着这个简单的功能来介绍一下ABP模块化开发的最基本步骤。

开始

创建模块

首先使用ABP CLI创建一个模块:abp new Xhznl.FileManagement -t module --no-ui

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

创建完成后会得到如下文件:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

在主项目中添加对应模块的引用,Application=>Application,Domain=>Domain,HttpApi=>HttpApi 等等。例如:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

需要添加引用的项目:Application、Application.Contracts、Domain、Domain.Shared、EntityFrameworkCore、HttpApi、HttpApi.Client

手动添加这些引用比较麻烦,你可以搭建自己的私有NuGet服务器,把模块的包发布到私有NuGet上,然后通过NuGet来安装引用。两种方式各有优缺点,具体请参考自定义现有模块,关于私有NuGet搭建可以参考:十分钟搭建自己的私有NuGet服务器-BaGet

然后给这些项目的模块类添加对应的依赖,例如:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

通过上面的方式引用模块,使用visual studio是无法编译通过的:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

需要在解决方案目录下,手动执行dotnet restore命令即可:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

模块开发

接下来关于文件管理功能的开发,都在模块Xhznl.FileManagement中进行,它是一个独立的解决方案。初学ABP,下面就以尽量简单的方式来实现这个模块。

应用服务

模块开发通常从Domain层实体建立开始,但是这里先跳过。先在FileManagement.Application.Contracts项目添加应用服务接口和Dto。

modules\file-management\src\Xhznl.FileManagement.Application.Contracts\Files\IFileAppService.cs:

public interface IFileAppService : IApplicationService
{
    Task<byte[]> GetAsync(string name);

    Task<string> CreateAsync(FileUploadInputDto input);
}

modules\file-management\src\Xhznl.FileManagement.Application.Contracts\Files\FileUploadInputDto.cs:

public class FileUploadInputDto
{
    [Required]
    public byte[] Bytes { get; set; }

    [Required]
    public string Name { get; set; }
}

然后是FileManagement.Application项目,实现应用服务,先定义一个配置类。

modules\file-management\src\Xhznl.FileManagement.Application\Files\FileOptions.cs:

public class FileOptions
{
    /// <summary>
    /// 文件上传目录
    /// </summary>
    public string FileUploadLocalFolder { get; set; }

    /// <summary>
    /// 允许的文件最大大小
    /// </summary>
    public long MaxFileSize { get; set; } = 1048576;//1MB

    /// <summary>
    /// 允许的文件类型
    /// </summary>
    public string[] AllowedUploadFormats { get; set; } = { ".jpg", ".jpeg", ".png", "gif", ".txt" };
}

modules\file-management\src\Xhznl.FileManagement.Application\Files\FileAppService.cs:

public class FileAppService : FileManagementAppService, IFileAppService
{
    private readonly FileOptions _fileOptions;

    public FileAppService(IOptions<FileOptions> fileOptions)
    {
        _fileOptions = fileOptions.Value;
    }

    public Task<byte[]> GetAsync(string name)
    {
        Check.NotNullOrWhiteSpace(name, nameof(name));

        var filePath = Path.Combine(_fileOptions.FileUploadLocalFolder, name);

        if (File.Exists(filePath))
        {
            return Task.FromResult(File.ReadAllBytes(filePath));
        }

        return Task.FromResult(new byte[0]);
    }

    [Authorize]
    public Task<string> CreateAsync(FileUploadInputDto input)
    {
        if (input.Bytes.IsNullOrEmpty())
        {
            throw new AbpValidationException("Bytes can not be null or empty!",
                new List<ValidationResult>
                {
                    new ValidationResult("Bytes can not be null or empty!", new[] {"Bytes"})
                });
        }

        if (input.Bytes.Length > _fileOptions.MaxFileSize)
        {
            throw new UserFriendlyException($"File exceeds the maximum upload size ({_fileOptions.MaxFileSize / 1024 / 1024} MB)!");
        }

        if (!_fileOptions.AllowedUploadFormats.Contains(Path.GetExtension(input.Name)))
        {
            throw new UserFriendlyException("Not a valid file format!");
        }

        var fileName = Guid.NewGuid().ToString("N") + Path.GetExtension(input.Name);
        var filePath = Path.Combine(_fileOptions.FileUploadLocalFolder, fileName);

        if (!Directory.Exists(_fileOptions.FileUploadLocalFolder))
        {
            Directory.CreateDirectory(_fileOptions.FileUploadLocalFolder);
        }

        File.WriteAllBytes(filePath, input.Bytes);

        return Task.FromResult("/api/file-management/files/" + fileName);
    }
}

服务实现很简单,就是基于本地文件系统的读写操作。

下面是FileManagement.HttpApi项目,添加控制器,暴露服务API接口。

modules\file-management\src\Xhznl.FileManagement.HttpApi\Files\FileController.cs:

[RemoteService]
[Route("api/file-management/files")]
public class FileController : FileManagementController
{
    private readonly IFileAppService _fileAppService;

    public FileController(IFileAppService fileAppService)
    {
        _fileAppService = fileAppService;
    }

    [HttpGet]
    [Route("{name}")]
    public async Task<FileResult> GetAsync(string name)
    {
        var bytes = await _fileAppService.GetAsync(name);
        return File(bytes, MimeTypes.GetByExtension(Path.GetExtension(name)));
    }

    [HttpPost]
    [Route("upload")]
    [Authorize]
    public async Task<JsonResult> CreateAsync(IFormFile file)
    {
        if (file == null)
        {
            throw new UserFriendlyException("No file found!");
        }

        var bytes = await file.GetAllBytesAsync();
        var result = await _fileAppService.CreateAsync(new FileUploadInputDto()
        {
            Bytes = bytes,
            Name = file.FileName
        });
        return Json(result);
    }

}

运行模块

ABP的模板是可以独立运行的,在FileManagement.HttpApi.Host项目的模块类FileManagementHttpApiHostModule配置FileOptions:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

修改FileManagement.HttpApi.Host和FileManagement.IdentityServer项目的数据库连接配置,然后启动这2个项目,不出意外的话可以看到如下界面。

FileManagement.HttpApi.Host:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

FileManagement.IdentityServer:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

现在你可以使用postman来测试一下File的2个API,当然也可以编写单元测试。

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

单元测试

更好的方法是编写单元测试,关于如何做好单元测试可以参考ABP源码,下面只做一个简单示例:

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

模块使用

模块测试通过后,回到主项目。模块引用,模块依赖前面都已经做好了,现在只需配置一下FileOptions,就可以使用了。

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

<span>初识ABP vNext(9):ABP模块化开发-文件管理</span>

目前FileManagement.Domain、FileManagement.Domain.Shared、FileManagement.EntityFrameworkCore这几个项目暂时没用到,项目结构也不是固定的,可以根据自己实际情况来调整。

最后

本文的模块示例比较简单,只是完成了一个文件上传和显示的基本功能,关于实体,数据库,领域服务,仓储之类的都暂时没用到。但是相信可以通过这个简单的例子,感受到ABP插件式的开发体验,这是一个好的开始,更多详细内容后面再做介绍。本文参考了ABP blogging模块的文件管理,关于文件存储,ABP中也有一个BLOB系统可以了解一下。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/2638.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 如何系统备份ghost_服务器可以用pe备份吗

    如何系统备份ghost_服务器可以用pe备份吗电脑出现系统故障是一个很正常的现象,在这个时候只能通过重组系统的方法来解决故障,如果我们此前有将正常的系统备份到U盘里面那么重装系统就会变得很简单,接下来就教给大家怎样用GHOST备份系统。1、首先把装有一键GHOST装系统的U盘插在电脑上,然后打开电脑马上按F2或DEL键入BIOS界面,然后就选择BOOT打USDHDD模式选择好,然后按F10键保存,电脑就会马上重启。2、重启后电脑就会进入一键…

  • jmeter基本使用方法面试题目_java 面试 高质量 集合面试问题

    jmeter基本使用方法面试题目_java 面试 高质量 集合面试问题最近有个分析反馈,自己在面试的时候,遇到一个jmeter题目,要我帮忙看下,题目如下:进入http://www.weather.com.cn/网站,用jmeter编写脚本实现如下操作(下列要求在同一个测试脚本):(1)编写获取北京天气紫外线、穿衣、洗车、感冒指数的压测脚本,要求将城市参数化10个(城市名字自定义),将城市的当前实时天气>10度作为断言,并将天气数字输出打印到日志,设置200用户并发持续运行3天(2)编写获取周边景点的脚本,并景点返回的个数作为断言,并将各景点名

  • html超链接位置怎么改,如何修改HTML超链接样式?

    html超链接位置怎么改,如何修改HTML超链接样式?在网页开发中,我们不免会用到超链接,将内容链接到原网页上。如果不对超链接进行设置,链接默认以固定样式显示,过于单一。那么我们要如何修改HTML中的超链接呢?这篇文章W3Cschool小编为大家介绍一下。我们都知道,超链接是用标签来显示的。如果我们需要修改样式,则需要通过CSS修改它的样式。标签的样式还分为四个类型,分别为未访问、已访问、鼠标滑过、点击。a:link:未被访问的链接a:v…

  • jdk9新特性

    jdk9新特性jdk目录结构变化JDK=JRE+开发工具集(javac编译工具等)JRE=JVM+JavaSE标准类库jdk8的目录结构:jdk9目录结构:模块化先创建两个modul

  • nginx启动、重启、关闭

    方式一:传统方法一、启动  cdusr/local/nginx/sbin./nginx二、重启  更改配置重启nginx  kill-HUP主进程号或进程号文件路径或者使用cd/usr/local/nginx/sbin./nginx-sreload  判断配置文件是否正确 nginx-t-c/usr/local/nginx/conf/nginx.conf或者cd…

  • div在div中垂直居中水平居中(css如何让div水平居中)

    最近写网页经常需要将div在屏幕中居中显示,遂记录下几个常用的方法,都比较简单。水平居中直接加上&amp;lt;center&amp;gt;标签即可,或者设置margin:auto;当然也可以用下面的方法下面说两种在屏幕正中(水平居中+垂直居中)的方法放上示范的html代码:&amp;lt;body&amp;gt;&amp;lt;divclass=&amp;quot;main&amp;quot;&amp;gt;

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号