前几篇分别介绍了abp vNext微服务框架、开发环境搭建和vue element admin前端框架接入,在vue element admin中实现用户角色管理基本功能后就可以开始进行业务开发了,本篇会详细的介绍如何在abp vNext中开发业务接口和前端页面实现。
业务接口开发
业务接口就是针对业务api接口,通过abp vNext微服务中实现并发布业务接口后,前端获取接口并进行界面开发,如此就实现了abp vNext微服务的前后端分离开发。
从实体开始
abp vNext微服务框架中的业务开发同样采用了经典的ddd架构风格和ef core 的code first模式,所以一切的业务都从领域模型(domain)开始。创建数据字典模型如下:
public class DataDictionary : AuditedAggregateRoot,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; } }
加入AbpDbContext:
public DbSetDictionary { get; set; }
构建ef实体:
builder.Entity(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); });
使用ef迁移数据库:
Add-Migration
Update-Database
查看输出日志是否成功迁移。
创建数据字典应用服务接口
创建数据字典接口和dto如下:
public interface IDictionaryAppService : IApplicationService { Task> GetAll(GetDictionaryInputDto input); Task Get(Guid id); Task Create(CreateDictionaryDto input); Task Update(Guid id, UpdateDictionary input); Task Delete(List 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{ 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; } }
实现数据字典应用服务
应用层实现如下:
继承基类:
public class DictionaryAppService : ApplicationService, IDictionaryAppService
注入仓储:
private readonly IRepository_repository;public DictionaryAppService( IRepository repository) { _repository = repository; }
实现接口
新增:
public async TaskCreate(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 (result); }
删除:
public async Task Delete(Listids) { foreach (var id in ids) { await _repository.DeleteAsync(id); } }
查询:
public async TaskGet(Guid id) { var query = await _repository.GetAsync(id); var dto = ObjectMapper.Map (query);return dto; } public async Task > 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
>(items);return new PagedResultDto (totalCount, dtos); }
修改:
public async TaskUpdate(Guid id, UpdateDictionary input) {var dic = await _repository.GetAsync(id); dic.Notes = input.Notes; dic.SEQ = input.SEQ; return ObjectMapper.Map (dic); }
增加数据字典权限
权限
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"; }
构造权限
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映射
ProductManagementApplicationAutoMapperProfile中增加数据字典模型-Dto映射:
CreateMap();
数据字典web api实现
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 TaskCreate(CreateDictionaryDto input) { return _dictionaryAppService.Create(input); } [HttpPost] [Route("Delete")] public Task Delete(List ids) { return _dictionaryAppService.Delete(ids); } [HttpGet] [Route("{id}")] public Task Get(Guid id) { return _dictionaryAppService.Get(id); } [HttpGet] [Route("all")] public Task > GetAll(GetDictionaryInputDto input) { return _dictionaryAppService.GetAll(input); } [HttpPut] [Route("{id}")] public Task Update(Guid id, UpdateDictionary input) { return _dictionaryAppService.Update(id, input); } }
总结
到这里数据字典单表业务已经开发完成,启动项目查看swagger文档就可以了解接口信息了,下篇将继续介绍abp vNext业务的前端实现。