Tidebuy.Platform开发指引

3 篇文章 0 订阅
2 篇文章 0 订阅

Tidebuy.Platform 开发指引[内部使用]

  本文档仅为开发内部开发使用,不做对外宣传。

1、工程结构

  本系统以ABP为依托,根据公司实际情况,进行部分调整,最终结构如图所示:
工程结构
工程命名前缀为:Tidebuy.Platform.**,各项目解释如下:

  • Tidebuy.Platform.Test:测试工程
  • Tidebuy.Platform.Application:应用层,常规业务逻辑层
  • Tidebuy.Platform.EntityFramework:EF框架层,包括数据库存储,仓储实现,系统缓存等部分。
  • Tidebuy.Platform.Model:Model层,包括Model和ViewModel(DTO)
  • Tidebuy.Platform.Utility:基础设施层,常规的各种帮助方法的实现
  • Tidebuy.Platform.Web:Web应用层,MVC中的Controller和View
  • Tidebuy.Platform.WebApi:WebAPI应用层,能自动扫描注册接口,对外发布。

2、开发指引

  本系统采用ABP基础框架,自动集成了Repository实现,所以对于部分基础功能开发,只需要创建Model和实现Application即可。

2.1、创建Model

  在Model层创建所需Model,为了便于区分业务逻辑,人为给Model层分了多个物理文件夹,如图:
Model层分类

  按照实际需要,创建了Amazon[亚马逊],Ebay[易贝],Common[通用],Systems[系统]等文件夹,若后续需要,可继续扩充。
  此实例以PlatformInfo**[站点信息]**为例,做开发说明:
  在Systems中创建PlatformInfos的文件夹,为避免命名空间的冲突,将文件夹以复数形式命名。创建PlatformInfo的代码如下:

using Abp.Domain.Entities;

namespace Tidebuy.Platform.Common.PlatformInfos
{
    /// <summary>
    /// 平台信息
    /// </summary>
    public class PlatformInfo : Entity<int>
    {
        /// <summary>
        /// 名称
        /// </summary>
        public virtual string Name { get; set; }

        /// <summary>
        /// 英文名称
        /// </summary>
        public virtual string EnName { get; set; }

        /// <summary>
        /// 备注信息
        /// </summary>
        public virtual string Remark { get; set; }
    }
}

  在上述代码中,PlatformInfo需要继承Entity的实例类,若需声明Id类型,可以进行标注,如本例中的Entity<int>Entity<long>等。如此声明,该实体可自动继承Id熟悉。
  若需其他集成类,ABP提供了如:CreationAuditedEntity,AuditedEntity,FullAuditedEntity等,具体可参考ABP的说明文档

在DbContext中添加Model的声明,如下:

public class TBPFDbContext : AbpDbContext
{
    /// <summary>
    /// 站点信息
    /// </summary>
    public virtual IDbSet<Systems.PlatformInfos.PlatformInfo> PlatformInfo { get; set; }

    //Other Code ...
 }

此步骤很重要,否则Model将无法注册


2.2、创建DTO

  在数据传输中,我们需要定义DTO(Data Transfer Objects)类,展现层传入数据传输对象(DTO)调用一个应用服务方法,接着应用服务通过领域对象执行一些特定的业务逻辑并且返回DTO给展现层。这样展现层和领域层被完全分离开了。在具有良好分层的应用程序中,展现层不会直接使用领域对象(仓库,实体)。
  为了统一管理,我们直接在Model层中对应的文件夹内创建DTO,如在PlatformInfos中创建DTO,如图:
DTO
  DTO的分为数据展示,数据列表,数据查询等,分为为XXXDto,XXXListDto,XXXQueryDto,在此实例中,分别如下:

PlatformInfoDto*数据展示,编辑,详情等使用*

using Abp.Application.Services.Dto;
using Abp.AutoMapper;

namespace Tidebuy.Platform.Systems.PlatformInfos
{
    /// <summary>
    /// 站点信息显示Dto
    /// </summary>
    [AutoMap(typeof(PlatformInfo))]
    public class PlatformInfoDto : EntityDto
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 英文名称
        /// </summary>
        public string EnName { get; set; }

        /// <summary>
        /// 备注信息
        /// </summary>
        public string Remark { get; set; }
    }
}

  该Dto继承自EntityDto,可自动继承Id熟悉,并通过AutoMapper,可自动将PlatformInfo转换为PlatformInfoDto,需要添加[AutoMap(typeof(PlatformInfo))]属性。

PlatformInfoListDto*列表展示DTO,用于列表展示,可只包括Model的部分字段*

using Abp.Application.Services.Dto;
using Abp.AutoMapper;

namespace Tidebuy.Platform.Systems.PlatformInfos
{
    [AutoMapFrom(typeof(PlatformInfo))]
    public class PlatformInfoListDto : EntityDto
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 英文名称
        /// </summary>
        public string EnName { get; set; }

        /// <summary>
        /// 备注信息
        /// </summary>
        public string Remark { get; set; }
    }
}

  其中的[AutoMapFrom(typeof(PlatformInfo))]属性,可自动将PlatformInfo自动转换为PlatformInfoListDto。

PlatformInfoQueryDto 查询使用,包括一些通用查询熟悉,如分页信息等

namespace Tidebuy.Platform.Systems.PlatformInfos
{
    /// <summary>
    /// 系统菜单查询
    /// </summary>
    public class PlatformInfoQueryDto
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 英文名称
        /// </summary>
        public string EnName { get; set; }
    }
}

  此示例中没有集成查询信息。


2.3、实现仓储

  若对象所需方法比较复杂,如需要通过Sql语句,存储过程等与数据库交互,或者有其他较为复杂的方法,则可通过添加仓储层进行实现,如下:
  在该项目中,我们将仓储层存放在Tidebuy.Platform.EntityFrame层中,以便直接与数据库进行交互。
按照业务逻辑,我们也会添加部分物理文件夹,以便做区分,结构如下:

仓储层结构

  我们以SysUser为例,说明仓储层的实现,首先定义ISysUserRepository接口,以便定义方法,代码如下:

using Abp.Domain.Repositories;
using Tidebuy.Platform.Systems.SysUsers;

namespace Tidebuy.Platform.Repositories.Systems.SysUsers
{
    /// <summary>
    /// 系统用户
    /// </summary>
    public interface ISysUserRepository : IRepository<SysUser, int>
    {
        /// <summary>
        /// 获取系统用户
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        SysUserDto GetUser(SysUserQueryDto dto);
    }
}

  为了能够使用系统自带的仓储方法,我们将ISysUserRepository继承自IRepository

using Abp.Dependency;
using Abp.EntityFramework;
using Abp.Extensions;
using Abp.Linq.Extensions;
using System.Linq;
using Tidebuy.Platform.Systems.SysUsers;

namespace Tidebuy.Platform.Repositories.Systems.SysUsers
{
    public class SysUserRepository : TBPFRepositoryBase<SysUser, int>, ISysUserRepository, ITransientDependency
    {
        public SysUserRepository(IDbContextProvider<TBPFDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public SysUserDto GetUser(SysUserQueryDto dto)
        {
            using (var db = new TBPFDbContext())
            {
                var userdto = db.SysUser
                    .WhereIf(dto.UserId.HasValue, a => a.UserId == dto.UserId.Value)
                    .WhereIf(!dto.UserName.IsNullOrWhiteSpace(), a => a.UserName == dto.UserName)
                    .WhereIf(!dto.Email.IsNullOrWhiteSpace(), a => a.Email == dto.Email)
                     .Join(db.SysUserExt, user => user.UserId, ext => ext.UserId, (user, ext) => new SysUserDto()
                     {
                         User = user,
                         SysUserExt = ext
                     }).FirstOrDefault();

                return userdto;
            }
        }
    }
}

  在这里,SysUserRepository继承了较多的接口和父类,注意不要漏写。
  具体的方法实现,在这里可直接操作数据库,实现存储过程,Sql语句等。


2.3、实现Application

  因PlatformInfo比较简单,无需单独去实现仓储功能,因此可直接实现Application。
  Application层的主要功能是实现业务逻辑,分为服务接口和服务实现两类。
  在Tidebuy.Platform.Application项目中,同Model一样,按照业务逻辑,添加了物理文件夹,如图:
Application分类

  • 定义IPlatformInfoAppService接口

      在Application中,需要定义服务接口,如IPlatformInfoAppService,代码如下:

using Abp.Application.Services;
using System.Collections.Generic;

namespace Tidebuy.Platform.Systems.PlatformInfos
{
    /// <summary>
    /// 平台站点AppSvc
    /// </summary>
    public interface IPlatformInfoAppService : IApplicationService
    {
        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        List<PlatformInfoListDto> GetList(PlatformInfoQueryDto dto);

        /// <summary>
        /// 获取编辑对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        PlatformInfoDto GetForEdit(int? id);

        /// <summary>
        /// 创建或更新
        /// </summary>
        /// <param name="dto"></param>
        /// <returns>数据库新增ID</returns>
        int CreateOrUpdate(PlatformInfoDto dto);

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        bool Delete(int? id);
    }
}

  在该接口中,我们定义了基础的CRUD功能,若需其他接口,请自行添加。IPlatformInfoAppService继承了IApplicationService,系统自动实现了一些基础功能。

  • 实现PlatformInfoAppService

      PlatformInfoAppService继承IPlatformInfoAppService,TBPFAppServiceBase,其中TBPFAppServiceBase是系统自由的基础服务类,可在其中定义一些通用的方法。

TBPF是TidebuyPlatform的缩写,便于整体使用

  • 构造函数

PlatformInfoAppService

public class PlatformInfoAppService : TBPFAppServiceBase, IPlatformInfoAppService
{
    private readonly IRepository<PlatformInfo> _platformInfoRepository;

    /// <summary>
    /// 构造函数
    /// 将Repository注入
    /// </summary>
    /// <param name="platformInfoRepository"></param>
    public PlatformInfoAppService(IRepository<PlatformInfo> platformInfoRepository)
    {
        _platformInfoRepository = platformInfoRepository;
    }
}

//Other Code...

  在没有单独定义和实现IRepository的情况下,可以通过系统自带的IRepository<TEntity>进行实现,在本例中,使用了IRepository<PlatformInfo>,然后通过构造函数进行注入,即可在上下文中使用。

  • CreateOrUpdate
/// <summary>
/// 创建或更新
///
/// 根据ID的存在情况,自动创建或者更新实体
/// </summary>
/// <param name="dto">
/// DTO信息,通过Controller或者JS调用进行传递
/// 转换为Model对象后,进行保存
/// </param>
/// <returns>新增或者更新后的ID</returns>
public int CreateOrUpdate(PlatformInfoDto dto)
{
    try
    {
        //将DTO对象转换为Model对象
        var model = dto.MapTo<PlatformInfo>();
        //调用仓储的InsertOrUpdateAndGetId方法,保存后返回ID
        return _platformInfoRepository.InsertOrUpdateAndGetId(model);
    }
    catch (Exception exp)
    {
        Logger.Error("PlatformInf新增出错", exp);
        return -1;
    }
}
  • Delete
/// <summary>
/// 删除
/// </summary>
/// <param name="id">被删除ID</param>
/// <returns>是否产出成功</returns>
public bool Delete(int? id)
{
    try
    {
        //调用删除方法,正常返回true
        _platformInfoRepository.Delete(id.Value);
        return true;
    }
    catch (Exception exp)
    {
        //删除出错,记录日志,返回false
        Logger.Error("PlatformInfo删除出错", exp);
        return false;
    }
}
  • GetForEdit
/// <summary>
/// 获取编辑对象
/// </summary>
/// <param name="id">ID</param>
/// <returns>编辑DTO</returns>
public PlatformInfoDto GetForEdit(int? id)
{
    try
    {
        //获取对象
        var dto = _platformInfoRepository.Get(id.Value);
        //转换为DTO
        return dto.MapTo<PlatformInfoDto>();
    }
    catch (Exception exp)
    {
        Logger.Error("获取编辑对象出错", exp);
        return null;
    }
}
  • GetList
/// <summary>
/// 获取对象列表
/// </summary>
/// <param name="dto">查询DTO</param>
/// <returns>ListDTO列表</returns>
public List<PlatformInfoListDto> GetList(PlatformInfoQueryDto dto)
{
    var lst = _platformInfoRepository.GetAll()
        //过滤Name
        .WhereIf(dto.Name.IsNullOrWhiteSpace(), a => a.Name.Contains(dto.Name))
        //过滤EnName
        .WhereIf(dto.EnName.IsNullOrWhiteSpace(), a => a.EnName.Contains(dto.EnName))
        .ToList();

    return lst.MapTo<List<PlatformInfoListDto>>();
}

2.4、添加Controller

  在准备好Application接口及方法之后,即可添加对应的Controller信息,同理,Tidebuy.Platform.Web层也按照逻辑关系,划分了不同的Areas,如图所示:
Web分层

  按照之前的约定,我们将平台信息放入Systems区域中,添加Controller,并做适当修改,如下:

/// <summary>
/// 平台信息
/// </summary>
public class PlatformInfoController : TBPFControllerBase
{
    private IPlatformInfoAppService _platformInfoAppService;

    public PlatformInfoController(IPlatformInfoAppService platformInfoAppService)
    {
        _platformInfoAppService = platformInfoAppService;
    }
    //Other Code...
}

  在此将IPlatformInfoAppService在构造函数里进行注入,以便上下文可以正常使用。注意Controller需要继承TBPFControllerBase。

  其他对应方法如下:

// GET: Systems/PlatformInfo
public ActionResult Index()
{
    return View();
}

/// <summary>
/// 获取平台数据
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public JsonResult GetPlatformInfo(PlatformInfoQueryDto dto)
{
    var stores = _platformInfoAppService.GetList(dto);

    return new JsonResult() { Data = stores, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

/// <summary>
/// 创建或新增
/// 此方法可进行批量创建
/// </summary>
/// <param name="dtos">DTO对象</param>
/// <returns>处理结果的JSON信息</returns>
[HttpPost]
public ActionResult CreateOrUpdate(List<PlatformInfoDto> dtos)
{
    try
    {
        _platformInfoAppService.BatchCreateOrUpdate(dtos);

        return Json(new { Success = true, Content = "平台更新成功" }, JsonRequestBehavior.AllowGet);
    }
    catch (Exception exp)
    {
        Logger.Error("平台批量更新失败", exp);
        return Json(new { Success = false, Content = "平台批量更新失败" }, JsonRequestBehavior.AllowGet);
    }
}

/// <summary>
/// 创建站点信息
/// </summary>
/// <param name="dto">DTO对象</param>
/// <returns>处理结果的JSON信息</returns>
[HttpPost]
public ActionResult Create(PlatformInfoDto dto)
{
    try
    {
        if (!dto.Name.IsNullOrWhiteSpace())
        {
            var result = _platformInfoAppService.CreateOrUpdate(dto);

            return Json(new { Success = result > 0, Content = result > 0 ? result.ToString() : "站点插入失败" }, JsonRequestBehavior.AllowGet);
        }
        else
        {
            return Json(new { Success = false, Content = "站点名称不能为空" }, JsonRequestBehavior.AllowGet);
        }
    }
    catch (Exception exp)
    {
        Logger.Error("站点插入失败", exp);
        return Json(new { Success = false, Content = "站点插入失败" }, JsonRequestBehavior.AllowGet);
    }
}

/// <summary>
/// 删除站点
/// </summary>
/// <param name="id">ID</param>
/// <returns>处理结果的JSON信息</returns>
[HttpPost]
public ActionResult Delete(int id)
{
    try
    {
        var result = _platformInfoAppService.Delete(id);
        return Json(new { Success = result, Content = result ? "站点删除成功" : "站点删除失败" });
    }
    catch (Exception exp)
    {
        Logger.Error("站点删除失败", exp);
        return Json(new { Success = false, Content = "站点删除失败" });
    }
}

2.6、添加View展示层

  在本项目中,使用EasyUI作为数据展示的控件,具体使用方法,请参考官网

  在对应的Views中,添加相应的Action方法,如Index,Create,Details等,具体使用同正常MVC开发一样,在此不再详述。


2.7、页面展示

  最终页面效果如下:
平台管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值