上一篇文章中介绍了如何下载、运行ABP Zero示例项目,这个示例项目可以直接作为模板进行二次开发,很适合做企业开发框架。

本未介绍基于ABP Zero示例项目,如何新建一个自定义的实体。

此处已EquipmentType(设备类型)为例,建立一个简单的实体。

以下是之前添加一个简单实体类的效果:

主页

公司列表

新建公司

编辑公司

删除公司


建立方法

按ABP的标准格式,完整建立一个实体,映射到数据库,作为一个基础资料,并通过前端进行增删查改功能,最小步骤如下:

  1. 新增实体类。
  2. 添加数据库映射。
  3. 同步到数据库。
  4. 新建Dto,建立Dto与实体类的映射。
  5. 建立实体类的功能接口(增删查改),并实现接口。
  6. 添加视图模型ViewModel。
  7. 添加控制器。
  8. 添加视图。
  9. 添加js脚本。
  10. 添加前端菜单(入口)。
  11. 添加权限管理。

1. 添加实体类

 namespace oMES_APServer.Equipments
{
public class EquipmentType : MESBase.MESBaseEntity
{ }
}

这里我把MES会用到的常规属性单独建了一个基类,并继承ABP全属性基类FullAuditedEntity

 using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using System.ComponentModel.DataAnnotations; namespace oMES_APServer.MESBase
{
public class MESBaseEntity : FullAuditedEntity<int>, IPassivable
{ public const int MaxCodeLength = ;
public const int MaxNameLength = ;
public const int MaxBriefNameLength = ;
public const int MaxRemarkLength = ; [Required]
[StringLength(MaxCodeLength)]
public string Code { get; set; } [Required]
[StringLength(MaxNameLength)]
public string Name { get; set; } [StringLength()]
public string BriefName { get; set; } [StringLength()]
public string Remark { get; set; }
public bool IsActive { get; set; } }
}

2. 添加数据库映射

添加以下代码:为了让EFCore能够自动生成数据库表结构。

public DbSet<EquipmentType> equipmentTypes { get; set; }

modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType").HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code");

其中.HasAlternateKey表示建立唯一键,.HasName表示键的名称。

 using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using oMES_APServer.Authorization.Roles;
using oMES_APServer.Authorization.Users;
using oMES_APServer.MultiTenancy;
using oMES_APServer.Companies;
using oMES_APServer.Equipments; namespace oMES_APServer.EntityFrameworkCore
{
public class oMES_APServerDbContext : AbpZeroDbContext<Tenant, Role, User, oMES_APServerDbContext>
{
/* Define a DbSet for each entity of the application */
public oMES_APServerDbContext(DbContextOptions<oMES_APServerDbContext> options)
: base(options)
{
} /*添加自定义实体类的数据库映射*/
public DbSet<Company> companies { get; set; }
public DbSet<Department> departments { get; set; }
public DbSet<EquipmentType> equipmentTypes { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<Company>().ToTable("Company")
.HasAlternateKey(x=>x.Code).HasName("UK_Company_Code");
modelBuilder.Entity<Department>().ToTable("Department")
.HasAlternateKey(x => x.Code).HasName("UK_Department_Code");
modelBuilder.Entity<EquipmentType>().ToTable("EquipmentType")
.HasAlternateKey(x => x.Code).HasName("UK_EquipmentType_Code");
} }
}

3. 同步到数据库。

依次执行以下两条指令:

  1. add-migration add-EquipmentType
  2. update-database

第一条表示,新建同步映射,映射名称为add-EquipmentType。

第二条表示同步数据库。

执行时,出现上述报错,不要慌,重新生成一下项目,应该有报错,解决完项目报错再执行,就可以了。

4. 新建Dto,建立Dto与实体类的映射

建立Dto

 namespace oMES_APServer.Equipments.Dto
{
public class EquipmentTypeDto : MESBaseDto.MESBaseEntityDto
{ }
}

建立实体类和Dto的映射

 using AutoMapper;

 namespace oMES_APServer.Equipments.Dto
{
public class EquipmentTypeMapProfile : Profile
{
public EquipmentTypeMapProfile()
{
CreateMap<EquipmentType, EquipmentTypeDto>();
CreateMap<EquipmentTypeDto, EquipmentType>();
CreateMap<EquipmentTypeDto, EquipmentType>()
.ForMember(x => x.CreationTime, opt => opt.Ignore());
}
}
}

引申:

ABP Zero的Dto类文件夹中,会有一个 PagedxxxResultRequestDto.cs类,这个是用于按给定条件查找数据列表,并进行分页的类。目前还没有学习到,所以仅按照现有的实体类进行仿照编程,不做额外处理。

 using Abp.Application.Services.Dto;

 namespace oMES_APServer.Equipments.Dto
{
public class PagedEquipmentTypeResultRequestDto : PagedResultRequestDto
{ public string Code { get; set; } public string Name { get; set; } public bool? IsActive { get; set; } }
}

5. 建立实体类的功能接口(增删查改),并实现接口。

建立接口:因为ABP接口已经实现了基础功能(增删查改)的方法定义,所以直接继承IAsyncCrudAppService即可,写法参照已有的User相关类。

 using Abp.Application.Services;
using oMES_APServer.Companies.Dto; namespace oMES_APServer.Equipments
{
public interface IEquipmentTypesAppService : IAsyncCrudAppService<CompanyDto, int, PagedCompanyResultRequestDto, CompanyDto, CompanyDto>
{ }
}

自定义实现基础接口:

 using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using oMES_APServer.Equipments.Dto; namespace oMES_APServer.Equipments
{
public class EquipmentTypesAppService : AsyncCrudAppService<EquipmentType, EquipmentTypeDto, int, PagedEquipmentTypeResultRequestDto, EquipmentTypeDto, EquipmentTypeDto>, IEquipmentTypeAppService
{
private readonly IRepository<EquipmentType> _equipmentTypeRepository; public EquipmentTypesAppService(IRepository<EquipmentType> equipmentTypeRepository)
: base(equipmentTypeRepository)
{
_equipmentTypeRepository = equipmentTypeRepository; LocalizationSourceName = oMES_APServerConsts.LocalizationSourceName;
} public override async Task<EquipmentTypeDto> Get(EntityDto<int> input)
{
var equipmentType = await _equipmentTypeRepository
.GetAsync(input.Id); return ObjectMapper.Map<EquipmentTypeDto>(equipmentType);
} public override async Task<PagedResultDto<EquipmentTypeDto>> GetAll(PagedEquipmentTypeResultRequestDto input)
{
var equipmentTypes = Repository.GetAll()
.WhereIf(!input.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Name))
.WhereIf(!input.Code.IsNullOrWhiteSpace(), x => x.Code.Contains(input.Code))
.WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive)
.OrderBy(x => x.Code); return await Task.FromResult(new PagedResultDto<EquipmentTypeDto>(equipmentTypes.CountAsync().Result,
ObjectMapper.Map<List<EquipmentTypeDto>>(equipmentTypes)
));
} public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input)
{ //判断CODE是否已存在
var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model != null)
{
throw new UserFriendlyException(L("EquipmentType code already exists"));
} //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
} var entity = ObjectMapper.Map<EquipmentType>(input);
await _equipmentTypeRepository.InsertAsync(entity);
return MapToEntityDto(entity);
} public override async Task<EquipmentTypeDto> Update(EquipmentTypeDto input)
{
var entity = await _equipmentTypeRepository.GetAsync(input.Id); ObjectMapper.Map(input, entity); await _equipmentTypeRepository.UpdateAsync(entity); return MapToEntityDto(entity);
} public override async Task Delete(EntityDto<int> input)
{
var entity = await _equipmentTypeRepository.GetAsync(input.Id);
await _equipmentTypeRepository.DeleteAsync(entity);
} }
}

其中,创建的代码如下:在基类中,我们设置了Code字段为唯一键,所以需要先确定Code不存在

 public override async Task<EquipmentTypeDto> Create(EquipmentTypeDto input)
{ //判断CODE是否已存在
var model = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model != null)
{
throw new UserFriendlyException(L("EquipmentType code already exists"));
} //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
} var entity = ObjectMapper.Map<EquipmentType>(input);
await _equipmentTypeRepository.InsertAsync(entity);
return MapToEntityDto(entity);
}

ABP的全属性类FullAuditedEntity中,预置了软删除功能,如果一条数据被软删除了(IsDeleted字段为1),那么直接查找是招不到的。

需要临时关闭软删除的过滤器,才能找到:在using中,使用正常的查询代码,就能查到已被软删除的数据。

 //检查是否已被软删除,已经软删除的数据,无法通过
using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
//判断CODE是否已存在
var model0 = await Repository.GetAllIncluding().FirstOrDefaultAsync(x => x.Code == input.Code);
if (model0 != null)
{
throw new UserFriendlyException(L("EquipmentType code is deleted"));
}
}

6. 添加视图模型ViewModel。

添加查询视图模型,这里没有做特殊处理,直接使用Dto

 using oMES_APServer.Equipments.Dto;
using System.Collections.Generic; namespace oMES_APServer.Web.Models.EquipmentTypes
{
public class EquipmentTypeListViewModel
{
public IReadOnlyList<EquipmentTypeDto> EquipmentTypes { get; set; }
}
}

添加编辑视图模型

 using oMES_APServer.Equipments.Dto;

 namespace oMES_APServer.Web.Models.EquipmentTypes
{
public class EditEquipmentTypeModalViewModel
{
public EquipmentTypeDto EquipmentType { get; set; }
}
}

7. 添加控制器。

控制器中添加两个方法Index和Edit.

 using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Microsoft.AspNetCore.Mvc;
using oMES_APServer.Controllers;
using oMES_APServer.Equipments;
using oMES_APServer.Equipments.Dto;
using oMES_APServer.Web.Models.EquipmentTypes; namespace oMES_APServer.Web.Mvc.Controllers
{
public class EquipmentTypesController : oMES_APServerControllerBase
{ private readonly IEquipmentTypeAppService _equipmentTypeAppService; public EquipmentTypesController(IEquipmentTypeAppService equipmentTypeAppService)
{
_equipmentTypeAppService = equipmentTypeAppService;
} public async Task<IActionResult> Index()
{
var modelDto = (await _equipmentTypeAppService
.GetAll(new PagedEquipmentTypeResultRequestDto { MaxResultCount = int.MaxValue })
).Items;
var viewModel = new EquipmentTypeListViewModel
{
EquipmentTypeList = modelDto
};
return View(viewModel);
} public async Task<ActionResult> EditEquipmentTypeModal(int id)
{
var modelDto = await _equipmentTypeAppService.Get(new EntityDto(id));
var editViewModel = new EditEquipmentTypeModalViewModel
{
EquipmentType = modelDto
};
return View("_EditEquipmentTypeModal", editViewModel);
} }
}

8. 添加视图。

视图由user中相关视图复制而来,将名称user更改为equipmentType相关即可使用。

查看&新建视图

 @using oMES_APServer.Web.Startup
@using oMES_APServer.Equipments
@model oMES_APServer.Web.Models.EquipmentTypes.EquipmentTypeListViewModel
@{
ViewBag.CurrentPageName = PageNames.EquipmentTypes;
}
@section scripts
{
<environment names="Development">
<script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script>
</environment> <environment names="Staging,Production">
<script src="~/view-resources/Views/EquipmentTypes/Index.js" asp-append-version="true"></script>
</environment>
}
<div class="row clearfix">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="card">
<div class="header">
<h2>
@L("EquipmentType")
</h2>
<ul class="header-dropdown m-r--5">
<li class="dropdown">
<a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<i class="material-icons">more_vert</i>
</a>
<ul class="dropdown-menu pull-right">
<li><a id="RefreshButton" href="javascript:void(0);" class="waves-effect waves-block"><i class="material-icons">refresh</i>@L("Refresh")</a></li>
</ul>
</li>
</ul>
</div>
<div class="body table-responsive">
<table class="table">
<thead>
<tr>
<th>@L("Code")</th>
<th>@L("Name")</th>
<th>@L("BriefName")</th>
<th>@L("Remark")</th>
<th>@L("CreationTime")</th>
<th>@L("CreatorUserId")</th>
<th>@L("LastModificationTime")</th>
<th>@L("LastModifierUserId")</th>
</tr>
</thead>
<tbody>
@foreach (var viewModel in Model.EquipmentTypeList)
{
<tr>
<td>@viewModel.Code</td>
<td>@viewModel.Name</td>
<td>@viewModel.BriefName</td>
<td>@viewModel.Remark</td>
<td>@viewModel.CreationTime</td>
<td>@viewModel.CreatorUserId</td>
<td>@viewModel.LastModificationTime</td>
<td>@viewModel.LastModifierUserId</td> <td class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<i class="material-icons">menu</i>
</a>
<ul class="dropdown-menu pull-right">
<li><a href="#" class="waves-effect waves-block edit-equipmentType" data-equipmentType-id="@viewModel.Id" data-toggle="modal" data-target="#EquipmentTypeEditModal"><i class="material-icons">edit</i>@L("Edit")</a></li>
<li><a href="#" class="waves-effect waves-block delete-equipmentType" data-equipmentType-id="@viewModel.Id" data-equipmentType-name="@viewModel.Name"><i class="material-icons">delete_sweep</i>@L("Delete")</a></li>
</ul>
</td>
</tr>
}
</tbody>
</table>
<button type="button" class="btn btn-primary btn-circle waves-effect waves-circle waves-float pull-right" data-toggle="modal" data-target="#EquipmentTypeCreateModal">
<i class="material-icons">add</i>
</button>
</div>
</div>
</div>
</div> <div class="modal fade" id="EquipmentTypeCreateModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeCreateModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form name="equipmentTypeCreateForm" role="form" novalidate class="form-validation">
<div class="modal-header">
<h4 class="modal-title">
<span>@L("CreateNewEquipmentType")</span>
</h4>
</div>
<div class="modal-body">
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Code" required maxlength="@EquipmentType.MaxCodeLength">
<label class="form-label">@L("Code")</label>
</div>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Name" required maxlength="@EquipmentType.MaxNameLength">
<label class="form-label">@L("Name")</label>
</div>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="BriefName" maxlength="@EquipmentType.MaxBriefNameLength">
<label class="form-label">@L("BriefName")</label>
</div>
<div class="form-group form-float">
<div class="form-line">
<input class="form-control" type="text" name="Remark" maxlength="@EquipmentType.MaxRemarkLength">
<label class="form-label">@L("Remark")</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default waves-effect" data-dismiss="modal">@L("Cancel")</button>
<button type="submit" class="btn btn-primary waves-effect">@L("Save")</button>
</div>
</form>
</div>
</div>
</div> <div class="modal fade" id="EquipmentTypeEditModal" tabindex="-1" role="dialog" aria-labelledby="EquipmentTypeEditModalLabel" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content"> </div>
</div>
</div>

编辑视图

 @using oMES_APServer.Web.Models.Common.Modals
@model oMES_APServer.Web.Models.EquipmentTypes.EditEquipmentTypeModalViewModel
@{
Layout = null;
}
@Html.Partial("~/Views/Shared/Modals/_ModalHeader.cshtml", new ModalHeaderViewModel(L("EditEquipmentType"))) <div class="modal-body">
<form name="EquipmentTypeEditForm" role="form" novalidate class="form-validation">
<input type="hidden" name="Id" value="@Model.EquipmentType.Id" />
<ul class="nav nav-tabs tab-nav-right" role="tablist">
<li role="presentation" class="active"><a href="#edit-equipmentType-details" data-toggle="tab">@L("EquipmentTypeDetails")</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane animated fadeIn active" id="edit-equipmentType-details"> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="code" type="text" name="Code" value="@Model.EquipmentType.Code" required maxlength="" minlength="" class="validate form-control">
<label for="code" class="form-label">@L("Code")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="name" type="text" name="Name" value="@Model.EquipmentType.Name" required maxlength="" minlength="" class="validate form-control">
<label for="name" class="form-label">@L("Name")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="briefname" type="text" name="BriefName" value="@Model.EquipmentType.BriefName" maxlength="" minlength="" class="validate form-control">
<label for="briefname" class="form-label">@L("BriefName")</label>
</div>
</div>
</div>
</div> <div class="row clearfix" style="margin-top:10px;">
<div class="col-sm-12">
<div class="form-group form-float">
<div class="form-line">
<input id="remark" type="text" name="Remark" value="@Model.EquipmentType.Remark" maxlength="" minlength="" class="validate form-control">
<label for="remark" class="form-label">@L("Remark")</label>
</div>
</div>
</div>
</div> </div>
</div>
</form>
</div> @Html.Partial("~/Views/Shared/Modals/_ModalFooterWithSaveAndCancel.cshtml") <script src="~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js" asp-append-version="true"></script>

9. 添加js脚本。

视图中添加了js脚本,此处添加合适的js脚本,此脚本由user.js复制而来,更改为equipmentType即可使用。

添加的位置如上述视图中代码所示:"~/view-resources/Views/EquipmentTypes/_EditEquipmentTypeModal.js"

index.js如下

 (function () {
$(function () { var _equipmentTypeService = abp.services.app.equipmentType;
var _$modal = $('#EquipmentTypeCreateModal');
var _$form = _$modal.find('form'); _$form.validate(); $('#RefreshButton').click(function () {
refreshequipmentTypeList();
}); //删除方法
$('.delete-equipmentType').click(function () {
var equipmentTypeId = $(this).attr("data-equipmentType-id");
var tenancyName = $(this).attr('data-equipmentType-name'); deleteequipmentType(equipmentTypeId, tenancyName);
}); //编辑方法
$('.edit-equipmentType').click(function (e) {
var equipmentTypeId = $(this).attr("data-equipmentType-id"); e.preventDefault();
$.ajax({
url: abp.appPath + 'equipmentTypes/EditEquipmentTypeModal?equipmentTypeId=' + equipmentTypeId,
type: 'POST',
contentType: 'application/html',
success: function (content) {
$('#EquipmentTypeEditModal div.modal-content').html(content);
},
error: function (e) { }
});
}); _$form.find('button[type="submit"]').click(function (e) {
e.preventDefault(); if (!_$form.valid()) {
return;
} var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js abp.ui.setBusy(_$modal);
_equipmentTypeService.create(equipmentType).done(function () {
_$modal.modal('hide');
location.reload(true); //reload page to see new equipmentType!
}).always(function () {
abp.ui.clearBusy(_$modal);
});
}); _$modal.on('shown.bs.modal', function () {
_$modal.find('input:not([type=hidden]):first').focus();
}); function refreshequipmentTypeList() {
location.reload(true); //reload page to see new equipmentType!
} function deleteequipmentType(equipmentTypeId, equipmentTypeName) {
abp.message.confirm(
abp.utils.formatString(abp.localization.localize('AreYouSureWantToDelete', 'oMES_APServer'), equipmentTypeName),
function (isConfirmed) {
if (isConfirmed) {
_equipmentTypeService.delete({
id: equipmentTypeId
}).done(function () {
refreshequipmentTypeList();
});
}
}
);
}
});
})();

编辑模型的脚本_EditEquipmentTypeModal.js如下

 (function ($) {

     var _equipmentTypeService = abp.services.app.equipmentType;
var _$modal = $('#EquipmentTypeEditModal');
var _$form = $('form[name=EquipmentTypeEditForm]'); function save() { if (!_$form.valid()) {
return;
} var equipmentType = _$form.serializeFormToObject(); //serializeFormToObject is defined in main.js abp.ui.setBusy(_$form);
_equipmentTypeService.update(equipmentType).done(function () {
_$modal.modal('hide');
location.reload(true); //reload page to see edited equipmentType!
}).always(function () {
abp.ui.clearBusy(_$modal);
});
} //Handle save button click
_$form.closest('div.modal-content').find(".save-button").click(function (e) {
e.preventDefault();
save();
}); //Handle enter key
_$form.find('input').on('keypress', function (e) {
if (e.which === ) {
e.preventDefault();
save();
}
}); $.AdminBSB.input.activate(_$form); _$modal.on('shown.bs.modal', function () {
_$form.find('input[type=text]:first').focus();
});
})(jQuery);

10. 添加前端菜单(入口)。

菜单需在startup文件夹 xxxNavigationProvider类中,添加.AddItem代码。

.AddItem放置的顺序不同,界面中的显示顺序就不同。

 using Abp.Application.Navigation;
using Abp.Localization;
using oMES_APServer.Authorization; namespace oMES_APServer.Web.Startup
{
/// <summary>
/// This class defines menus for the application.
/// </summary>
public class oMES_APServerNavigationProvider : NavigationProvider
{
public override void SetNavigation(INavigationProviderContext context)
{
context.Manager.MainMenu
.AddItem(
new MenuItemDefinition(
PageNames.EquipmentTypes,
L("EquipmentTypes"),
url: "EquipmentTypes",
icon: "info"
)
)
以下省略
MenuItemDefinition的各参数看名字就能理解,从上到下依次是:
菜单名称,
菜单显示名称,
url:链接,即控制器名称
icon:图标名称,会根据名称自动查找对应的图标文件。

11. 添加权限管理。

通常的权限管理方式为:人员->角色->权限。

即为人员分配角色,为角色分配权限,这样就避免了多人相同权限时,重复分配的工作。

此处将设备管理功能(菜单)分配给对应的角色。

需要添加如下代码:

1、添加权限名称

 namespace oMES_APServer.Authorization
{
public static class PermissionNames
{
public const string Pages_Tenants = "Pages.Tenants";
public const string Pages_Users = "Pages.Users";
public const string Pages_Roles = "Pages.Roles";
//添加自定义权限名称
public const string Pages_Companies = "Pages.Companies";
public const string Pages_Departments = "Pages.Departments"; public const string Pages_EquipmentTypes = "Pages.EquipmentTypes";
}
}

2、系统权限列表中,添加该权限名称

 using Abp.Authorization;
using Abp.Localization;
using Abp.MultiTenancy; namespace oMES_APServer.Authorization
{
public class oMES_APServerAuthorizationProvider : AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host); //添加自定义权限
context.CreatePermission(PermissionNames.Pages_Companies, L("Companies"));
context.CreatePermission(PermissionNames.Pages_Departments, L("Departments"));
context.CreatePermission(PermissionNames.Pages_EquipmentTypes, L("EquipmentTypes"));
} private static ILocalizableString L(string name)
{
return new LocalizableString(name, oMES_APServerConsts.LocalizationSourceName);
}
}
}

3、菜单中添加权限控制

requiredPermissionName: PermissionNames.Pages_Companies

4、控制器中添加权限控制

[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]

5、应用服务方法中添加权限控制

[AbpAuthorize(PermissionNames.Pages_EquipmentTypes)]

添加完成后,运行程序,角色管理中,就可以单独选择该功能的权限了。

12. 文本翻译。

ABP的翻译方法在xxx.Core项目Localization文件夹中

默认支持9种语言。

添加中文翻译,只需在xxx-zh-Hans.xml文件中添加相应字段即可。

这要注意一下:xml中的子项,如果name值相同的话,会报错。所以每次添加新翻译时,先检查一下name值是否重复。

如下添加即可:

到此,一个基础资料的基础功能就完成了。

之后会继续完善所有的基础功能,中间有对ABP功能的研究也会一点一点写出来。

【ABP】从零开始学习ABP_001_新建实体功能的更多相关文章

  1. 【ABP】从零开始学习ABP_入门介绍

    本文介绍自己入坑ABP的过程,一些ABP的相关文章.QQ群,以及ABP Zero示例项目的运行. 背景 作为一个半路出家学习编程的新人,之前工作中也断断续续写过一些代码,但底层核心一直没机会学习,所以 ...

  2. ASP.NET从零开始学习EF的增删改查

           ASP.NET从零开始学习EF的增删改查           最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...

  3. Microsoft Dynamics CRM 2011 新建实体 需要注意的细节

    新建一个实体,需要红色框内的是否勾选的意义,可以进一步加深对CRM的理解.如图: 下面对部分的进行了自我的理解,不对的地方,还请大家指出来.互相学习. 1.CRM2011中,在活动方面加强的新特性包括 ...

  4. 从零开始学习CocoaPods安装和使用

    从零开始学习CocoaPods安装和使用   转载: Code4App原创:http://code4app.com/article/cocoapods-install-usage http://m.i ...

  5. ABP Framework V4.4 RC 新增功能介绍

    目录 新增功能概述 启动模板删除 EntityFrameworkCore.DbMigrations 项目 CMS-Kit 动态菜单管理 Razor引擎对文本模板的支持 DbContext/Entiti ...

  6. 结合ABP源码实现邮件发送功能

    1. 前言 2. 实现过程 1. 代码图(重) 2.具体实现 2.1 定义AppSettingNames及AppSettingProvider 2.2 EmailSenderConfiguration ...

  7. 从零开始学习jQuery (五) 事件与事件对象

    本系列文章导航 从零开始学习jQuery (五) 事件与事件对象 一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解 ...

  8. 从零开始学习jQuery (二) 万能的选择器

    本系列文章导航 从零开始学习jQuery (二) 万能的选择器 一.摘要 本章讲解jQuery最重要的选择器部分的知识. 有了jQuery的选择器我们几乎可以获取页面上任意的一个或一组对象, 可以明显 ...

  9. 从零开始学习jQuery (一) 入门篇

    本系列文章导航 从零开始学习jQuery (一) 入门篇 一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些 ...

随机推荐

  1. idea如何提取变量(拆分变量赋值和声明)

    需求描述: 我们时常遇到某个在某个局部作用域声明的变量,想要用在另一个地方,此时就需要在作用域外部声明变量,在作用域中给变量赋值. 在eclipse中这个功能和提取变量在一起,我们可以方便的拆分变量的 ...

  2. matplotlib显示AttributeError: 'module' object has no attribute 'verbose'

    解决办法:file-settings-tools-python scientific,将show plots in toolwindow前面的对号去掉即可.

  3. WordPress 网站迁移

    最近想把本地的WordPress迁移到我的Linux虚拟机里面,是不是很无聊,哈哈哈,接下来就是一过程了,其实这个和迁移到线上是一样的, 1.首先将本地的文件WordPress通过FTP传到虚拟机上: ...

  4. Servlet的基本使用

    1.pom.xml导入包 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax ...

  5. Linux OS 集群 免密登录

    1. ssh-keygen  生成密钥 2. ssh-copy-id  集群主机名 参考: [图文详解]linux下配置远程免密登录

  6. 研发2nm芯片,台积电如何做到天下第一?

    日前,台积电宣布,正式启动2nm芯片工艺的研发,工厂将会设置在台湾新竹的南方科技园,预计2024年投入量产,发言人称:2nm工艺是一个重要节点,目标是比3nm制程缩小23%.科技先锋总会打脸分析专家, ...

  7. 【Android多线程】异步信息处理机制

    https://www.bilibili.com/video/av65170691?p=3 (本文为此视频听课笔记) 一.线程和线程之间为什么要进行通讯 各线程之间要传递数据 二.线程和线程之间如何通 ...

  8. Codeforces1140D. Minimum Triangulation

    题目链接 本题是区间dp里的三角剖分,板子题,dp[i][j]表示凸多边形i-j构成的最值,转移方程为dp[i][j] = min/max(dp[i][k]+dp[k][j]+w[i,j,k])(i& ...

  9. 「AHOI2014/JSOI2014」奇怪的计算器

    「AHOI2014/JSOI2014」奇怪的计算器 传送门 我拿到这题首先是懵b的,因为感觉没有任何性质... 后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发 ...

  10. 国外电商网站snapdeal爬取流程

    首页爬取 1.首页获取各个目录的url 如所有优惠all_offers的其中urlhttps://www.snapdeal.com/products/men-apparel-shirts?sort=p ...