[Abp vNext微服务实践] - 业务开发

前几篇分别介绍了abp vNext微服务框架、开发环境搭建和vue element admin前端框架接入,在vue element admin中实现用户角色管理基本功能后就能够开始进行业务开发了,本篇会详细的介绍如何在abp vNext中开发业务接口和前端页面实现。html

业务接口开发

业务接口就是针对业务api接口,经过abp vNext微服务中实现并发布业务接口后,前端获取接口并进行界面开发,如此就实现了abp vNext微服务的先后端分离开发。前端

step1:建立实体(model)

abp vNext微服务框架中的业务开发一样采用了经典的ddd架构风格和ef core 的code first模式,因此一切的业务都从领域模型(domain)开始。建立数据字典模型以下:vue

public class DataDictionary : AuditedAggregateRoot<Guid>,ISoftDelete {
 [NotNull] public string Name { get; set; } 
        public string Code { get; set; } 
 [NotNull] public string FullName { get; set; } 
        public Guid? CategoryID { get; set; } 
        public string Notes { get; set; } 
        public Guid? PID { get; set; }

[NotNull] public int SEQ { get; set; } public bool IsEdit { get; set; } public bool IsDeleted { get; set; } }

step2:加入AbpDbContext:

public DbSet<DataDictionary> Dictionary { get; set; }

step3:构建ef实体:

builder.Entity<DataDictionary>(b => { b.ToTable("Dictionary"); b.ConfigureConcurrencyStamp(); b.ConfigureExtraProperties(); b.ConfigureAudited(); b.Property(x => x.Name).IsRequired().HasMaxLength(ProductConsts.MaxNameLength); b.Property(x => x.Code).HasMaxLength(ProductConsts.MaxCodeLength); b.Property(x => x.FullName).IsRequired().HasMaxLength(ProductConsts.MaxFullNameLength); b.Property(x => x.Notes).HasMaxLength(ProductConsts.MaxNotesLength); b.Property(x => x.SEQ).IsRequired(); b.HasIndex(q => q.Code); b.HasIndex(q => q.Name); b.HasIndex(q => q.CategoryID); });

step4:使用ef迁移数据库:

Add-Migration Update-Database

查看输出日志是否成功迁移。web

建立数据字典应用服务接口sql

step5:建立数据字典接口和dto以下:

 

public interface IDictionaryAppService : IApplicationService { Task<PagedResultDto<DictionaryDto>> GetAll(GetDictionaryInputDto input); Task<DictionaryDto> Get(Guid id); Task<DictionaryDto> Create(CreateDictionaryDto input); Task<DictionaryDto> Update(Guid id, UpdateDictionary input); Task Delete(List<Guid> ids); }
public class CreateDictionaryDto { [Required] [StringLength(ProductConsts.MaxNameLength)] public string Name { get; set; } [StringLength(ProductConsts.MaxCodeLength)] public string Code { get; set; } public Guid? CategoryID { get; set; } [StringLength(ProductConsts.MaxNotesLength)] public string Notes { get; set; } public Guid? PID { get; set; } public int SEQ { get; set; } public bool IsEdit { get; set; } }
public class DictionaryDto : AuditedEntityDto<Guid> { public string Name { get; set; } public string Code { get; set; } public string FullName { get; set; } public Guid? CategoryID { get; set; } public string Notes { get; set; } public Guid? PID { get; set; } public int SEQ { get; set; } public bool IsEdit { get; set; } }
public class GetDictionaryInputDto: PagedAndSortedResultRequestDto { public string Filter { get; set; } public Guid CategoryID { get; set; } }
public class UpdateDictionary { [StringLength(ProductConsts.MaxNotesLength)] public string Notes { get; set; } public Guid? PID { get; set; } public int SEQ { get; set; } }

实现数据字典应用服务数据库

step6:应用层实现以下:

 继承基类:后端

public class DictionaryAppService : ApplicationService, IDictionaryAppService

注入仓储:api

private readonly IRepository<DataDictionary, Guid> _repository;

     public DictionaryAppService( IRepository<DataDictionary, Guid> repository) { _repository = repository; }

实现接口前端框架

新增:架构

public async Task<DictionaryDto> Create(CreateDictionaryDto input) { var existingDic = await _repository.FirstOrDefaultAsync(d => d.Name == input.Name); if (existingDic != null) { throw new BusinessException("名称: "+input.Name+"已存在"); }var result = await _repository.InsertAsync(new DataDictionary { Id = GuidGenerator.Create(), Name = input.Name, Code = input.Code, FullName = input.Name, CategoryID = input.CategoryID, Notes = input.Notes, PID = input.PID, SEQ = input.SEQ, IsEdit=input.IsEdit }); return ObjectMapper.Map<DataDictionary, DictionaryDto>(result); }

删除:

public async Task Delete(List<Guid> ids) { foreach (var id in ids) { await _repository.DeleteAsync(id); } }

查询:

public async Task<DictionaryDto> Get(Guid id) { var query = await _repository.GetAsync(id); var dto = ObjectMapper.Map<DataDictionary, DictionaryDto>(query);return dto; } public async Task<PagedResultDto<DictionaryDto>> GetAll(GetDictionaryInputDto input) { var query = _repository .Where(d => d.CategoryID == input.CategoryID) .WhereIf(!string.IsNullOrEmpty(input.Filter), d => d.Name.Contains(input.Filter) || d.Code.Contains(input.Filter)); var items = await query.OrderBy(input.Sorting ?? "SEQ") .Skip(input.SkipCount) .Take(input.MaxResultCount).ToListAsync(); var totalCount = await query.CountAsync(); var dtos = ObjectMapper.Map<List<DataDictionary>, List<DictionaryDto>>(items);return new PagedResultDto<DictionaryDto>(totalCount, dtos); }

修改:

public async Task<DictionaryDto> Update(Guid id, UpdateDictionary input) {var dic = await _repository.GetAsync(id); dic.Notes = input.Notes; dic.SEQ = input.SEQ; return ObjectMapper.Map<DataDictionary, DictionaryDto>(dic); }

增长数据字典权限

step7:权限

ProductManagementPermissions中增长静态类DataDictionary:

public static class DataDictionary { public const string Default = BasicDataManagement + ".DataDictionary"; public const string Delete = Default + ".Delete"; public const string Update = Default + ".Update"; public const string Create = Default + ".Create"; }

step8:构造权限

ProductManagementPermissionDefinitionProvider中增长dataDictionary:

var dataDictionary = basicDataManagementGroup.AddPermission(ProductManagementPermissions.DataDictionary.Default, L("DataDictionary")); dataDictionary.AddChild(ProductManagementPermissions.DataDictionary.Create, L("Permission:Create")); dataDictionary.AddChild(ProductManagementPermissions.DataDictionary.Delete, L("Permission:Delete")); dataDictionary.AddChild(ProductManagementPermissions.DataDictionary.Update, L("Permission:Edit"));

增长完成后在数据字典应用服务中分别加上权限过滤器

[Authorize(ProductManagementPermissions.DataDictionary.Default)] [Authorize(ProductManagementPermissions.DataDictionary.Create)] [Authorize(ProductManagementPermissions.DataDictionary.Delete)] [Authorize(ProductManagementPermissions.DataDictionary.Update)]

数据字典DTO映射

step9:ProductManagementApplicationAutoMapperProfile中增长数据字典模型-Dto映射:

CreateMap<DataDictionary, DictionaryDto>();

数据字典web api实现

step10:abp vNext中没有使用原先的应用服务动态api,如今api须要在控制器中实现

 [RemoteService] [Area("basicData")] [Route("api/basicData/dataDictionary")] public class DataDictionaryController : AbpController, IDictionaryAppService { private readonly IDictionaryAppService _dictionaryAppService; public DataDictionaryController(IDictionaryAppService dictionaryAppService) { _dictionaryAppService = dictionaryAppService; } [HttpPost] public Task<DictionaryDto> Create(CreateDictionaryDto input) { return _dictionaryAppService.Create(input); } [HttpPost] [Route("Delete")] public Task Delete(List<Guid> ids) { return _dictionaryAppService.Delete(ids); } [HttpGet] [Route("{id}")] public Task<DictionaryDto> Get(Guid id) { return _dictionaryAppService.Get(id); } [HttpGet] [Route("all")] public Task<PagedResultDto<DictionaryDto>> GetAll(GetDictionaryInputDto input) { return _dictionaryAppService.GetAll(input); } [HttpPut] [Route("{id}")] public Task<DictionaryDto> Update(Guid id, UpdateDictionary input) { return _dictionaryAppService.Update(id, input); } }

swagger文档

总结

abp vNext的业务开发模式并无作太多改动,虽然接口开发的过程有些繁琐,可是对于业务拆分和模型解耦来讲是很是有必要的。ddd的架构风格让开发人员无需依赖于sql语法,能够使用抽象的仓储进行轻松高效的查询,这对于代码维护和项目交接来讲是十分幸运的。此外,abp vNext还将身份、权限、模型验证、异常处理等进行了完美封装,使得开发人员能够专一于业务开发。

文章目录:https://www.cnblogs.com/william-xu/p/12047529.html

相关文章
相关标签/搜索