2022-11-30 18:19:20 +08:00

599 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: XiaodaERP
date: 2021-03-23 10:30:31
author: 文永达
top_img: https://gcore.jsdelivr.net/gh/volantis-x/cdn-wallpaper/abstract/67239FBB-E15D-4F4F-8EE8-0F1C9F3C4E7C.jpeg
---
# XiaodaERP
## 访问地址: [XiaodaERP](http://120.46.194.61:81/)
## 技术选形
- ASP.Net 6
- Entity Framework Core 6
- Microsoft SQL Server
## 开发手册
本节以用户模块开发为模板
首先数据库建表
### 数据库建模PDM
#### 表名
![image-20221130162410150](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130162410150.png)
#### 表结构
![image-20221130162426950](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130162426950.png)
### SQL Server数据库建表
![image-20221130162700170](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130162700170.png)
### EF Core 建立POCO对象
#### 创建POCO
POCO全称 Plain Old CLR Object 普通旧CLR对象 作为 ORM映射
在**解决方案资源管理器**中已创建的**Models**文件夹中新建 `User.cs`
![image-20221130162955888](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130162955888.png)
参照数据库表结构将对应列添加进属性中
需要加 **? **代表可空数据类型
其中 **Role**是另一个POCO在这里的作用是多表联查用户与角色为多对一关系
```c#
namespace XiaodaERP.Models
{
public class User
{
public string? UserId { get; set; }
public string? UserName { get; set; }
public string? RealName { get; set;}
public string? Avatar { get; set;}
public string? Desc { get; set;}
public string? PassWord { get; set; }
public string? HomePath { get; set; }
public Role? Role { get; set; }
public string? RoleId { get; set; }
public string? Email { get; set;}
public string? CreateUser { get; set; }
public DateTime? CreateTime { get; set; }
public DateTime? UpdateTime{ get; set; }
public string? DeptId { get; set; }
}
}
```
#### 创建Mapping映射
建立ORM映射
在**解决方案资源管理器**中已创建的**Mapping**文件夹中新建 `UserMap.cs`类
![image-20221130170549473](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130170549473.png)
根据数据库表结构配置映射
```c#
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using XiaodaERP.Models;
namespace XiaodaERP.Mapping
{
public class UserMap : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
// 数据库表名
builder.ToTable("BASE_USER");
// 数据库主键
builder.HasKey(t => t.UserId);
// 数据库列名
builder.Property(t => t.UserId).HasColumnName("USERID");
builder.Property(t => t.UserName).HasColumnName("USERNAME");
builder.Property(t => t.RealName).HasColumnName("REALNAME");
builder.Property(t => t.Avatar).HasColumnName("AVATAR");
builder.Property(t => t.Desc).HasColumnName("DESC");
builder.Property(t => t.PassWord).HasColumnName("PASSWORD");
builder.Property(t => t.HomePath).HasColumnName("HOMEPATH");
builder.Property(t => t.CreateUser).HasColumnName("CREATEUSER");
builder.Property(t => t.CreateTime).HasColumnName("CREATETIME");
builder.Property(t => t.UpdateTime).HasColumnName("UPDATETIME");
builder.Property(t => t.Email).HasColumnName("EMAIL");
builder.Property(t => t.RoleId).HasColumnName("ROLEID");
builder.Property(t => t.DeptId).HasColumnName("DEPTID");
// User包含一个Role 一个Role对应多个User
builder.HasOne(u => u.Role).WithMany();
}
}
}
```
#### 配置DbContext
DbContext为EF Core数据库上下文
打开创建好的 `SqlServerDbContext.cs`
加入DbSet, Mapping映射
```c#
using Microsoft.EntityFrameworkCore;
using XiaodaERP.Mapping;
using XiaodaERP.Models;
namespace XiaodaERP
{
public class SqlServerDbContext : DbContext
{
public SqlServerDbContext(DbContextOptions<SqlServerDbContext> options)
: base(options)
{
}
// DbSet
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Mapping映射
modelBuilder.ApplyConfiguration<User>(new UserMap());
base.OnModelCreating(modelBuilder);
}
}
}
```
#### 创建VO
VO全称ViewObject 视图对象 作为 API与前端数据交换的媒介
在**解决方案资源管理器**中已创建的**Models**文件夹中新建 `ViewUser.cs`类
```c#
using System.Security.Permissions;
namespace XiaodaERP.Models
{
public class ViewUser
{
public string? UserId { get; set; }
public string? UserName { get; set; }
public string? RealName { get; set; }
public string? Avatar { get; set; }
public string? Desc { get; set; }
public string? PassWord { get; set; }
public string? Token { get; set; }
public string? HomePath { get; set; }
public string? RoleId { get; set; }
public string? RoleName { get; set; }
public string? Email { get; set; }
public string? CreateUser { get; set; }
public string? DeptId { get; set; }
public Role[]? Roles { get; set; }
public int? Total { get; set; }
}
}
```
#### 创建 `Service`
在**解决方案资源管理器**中已创建的**Services**文件夹的**IServices**文件夹中新建 `IUserService.cs`接口
![image-20221130173255597](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130173255597.png)
```c#
using XiaodaERP.Models;
using XiaodaERP.Utils;
namespace XiaodaERP.Services.IServices
{
public interface IUserService
{
// 查询所有User 条件查询
List<ViewUser> GetAllUsers(string DeptId, string? userName, string? realName);
// 添加与更新User
bool UpdateUser(ViewUser viewUser);
// 删除User根据主键ID
bool DeleteUser(string UserId);
bool ResetToDefaultPassword(string UserId);
// 分页条件查询User
PageResult<ViewUser> GetAllUsersPagination(int page, int pageSize, string DeptId, string? userName, string? realName);
}
}
```
在**Services**文件夹中新建 `UserService.cs`类,并实现 `IUserService.cs`接口
```c#
using AutoMapper;
using Castle.Core.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Validations;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using XiaodaERP.Models;
using XiaodaERP.Services.IServices;
using XiaodaERP.Utils;
namespace XiaodaERP.Services
{
public class UserService : IUserService
{
// 通过构造方法注入DbContext
private readonly OracleDbContext _oracleDbContext;
private readonly SqlServerDbContext _sqlServerDbContext;
public UserService(OracleDbContext oracleDbContext, SqlServerDbContext sqlServerDbContext)
{
_oracleDbContext = oracleDbContext;
_sqlServerDbContext = sqlServerDbContext;
}
// 实现删除User根据主键ID方法
public bool DeleteUser(string UserId)
{
// 根据UserId主键查询表中是否存在该User
var res = _sqlServerDbContext.Users.Where(t => t.UserId == UserId).FirstOrDefault();\
// 如果存在
if (res != null)
{
// 删除User
_sqlServerDbContext.Users.Remove(res);
// 提交
return _sqlServerDbContext.SaveChanges() > 0;
}
else
{
return false;
}
}
// 实现查询所有User 条件查询方法
public List<ViewUser> GetAllUsers(string DeptId, string? userName, string? realName)
{
var res = new List<User>();
// 部门DeptId不为空
if (!string.IsNullOrEmpty(DeptId))
{
// 根据DeptId查询一级部门
var pdeptRes = _sqlServerDbContext.Depts
.Where(t => t.Id == DeptId).Select(t => t.ParentDept).FirstOrDefault();
// 如果pdept是空的是一级部门
if (string.IsNullOrEmpty(pdeptRes))
{
// userName不为空
if (!userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = _sqlServerDbContext.Users.Include(user => user.Role)
.Where(u => (_sqlServerDbContext.Depts.Where(d => d.ParentDept == DeptId)
.Select(d => d.Id)
.ToList())
.Contains(u.DeptId))
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%")).ToList();
}
// realName不为空
if (!realName.IsNullOrEmpty() && userName.IsNullOrEmpty())
{
res = _sqlServerDbContext.Users.Include(user => user.Role)
.Where(u => (_sqlServerDbContext.Depts.Where(d => d.ParentDept == DeptId)
.Select(d => d.Id)
.ToList())
.Contains(u.DeptId))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).ToList();
}
// userName不为空 realName不为空
if (!userName.IsNullOrEmpty() && !realName.IsNullOrEmpty())
{
res = _sqlServerDbContext.Users.Include(user => user.Role)
.Where(u => (_sqlServerDbContext.Depts.Where(d => d.ParentDept == DeptId)
.Select(d => d.Id)
.ToList())
.Contains(u.DeptId))
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).ToList();
}
// 不跟据条件查询
if (userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = _sqlServerDbContext.Users.Include(user => user.Role)
.Where(u => (_sqlServerDbContext.Depts.Where(d => d.ParentDept == DeptId)
.Select(d => d.Id)
.ToList())
.Contains(u.DeptId)).ToList();
}
}
else // 二级部门查询,此处简写
{
res = _sqlServerDbContext.Users
.Include(user => user.Role)
.Where(u => u.DeptId == DeptId).ToList();
}
}
else // 不跟据部门查询
{
res = _sqlServerDbContext.Users.Include(user => user.Role).ToList();
}
List<ViewUser> viewUsers = new();
// 使用AutoMapper映射POCO至VO
var config = new MapperConfiguration(cfg => cfg.CreateMap<User, ViewUser>()
.ForMember(dest => dest.RoleId, opt => opt.MapFrom(src => src.Role.Id)) // 从POCO Role属性对象中取出Id属性映射到 VO RoleId属性
.ForMember(dest => dest.RoleName, opt => opt.MapFrom(src => src.Role.RoleName))); // 从POCO Role属性对象中取出RoleName属性映射到 VO RoleName属性
var mapper = config.CreateMapper();
foreach (var user in res)
{
viewUsers.Add(
mapper.Map<ViewUser>(user) // 映射
) ;
}
return viewUsers;
}
// 实现添加与更新User方法
public bool UpdateUser(ViewUser viewUser)
{
var res = _sqlServerDbContext.Users.FirstOrDefault(x => x.UserId == viewUser.UserId);
var config = new MapperConfiguration(cfg => cfg.CreateMap<ViewUser, User>()
.BeforeMap((src, des) => src.UserId = Guid.NewGuid().ToString().Replace("-", "").ToUpper())
.BeforeMap((src, des) => src.PassWord = this.Md5Encoding("123456")));
var mapper = config.CreateMapper();
if (res == null)
{
_sqlServerDbContext.Users.Add(
mapper.Map<User>(viewUser)
);
}
else
{
res = new MapperConfiguration(cfg => cfg.CreateMap<ViewUser, User>())
.CreateMapper().Map(viewUser, res);
}
return _sqlServerDbContext.SaveChanges() > 0;
}
/// <summary>
/// MD5 加密字符串
/// </summary>
/// <param name="rawPass">源字符串</param>
/// <returns>加密后字符串</returns>
public string Md5Encoding(string rawPass)
{
// 创建MD5类的默认实例MD5CryptoServiceProvider
var md5 = MD5.Create();
var bs = Encoding.UTF8.GetBytes(rawPass);
var hs = md5.ComputeHash(bs);
var sb = new StringBuilder();
foreach (var b in hs)
{
// 以十六进制格式格式化
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
public bool ResetToDefaultPassword(string UserId)
{
var res = _sqlServerDbContext.Users.Where(t => t.UserId == UserId).FirstOrDefault();
if (res != null)
{
res.PassWord = Md5Encoding("123456");
return _sqlServerDbContext.SaveChanges() > 0;
}
else
{
return false;
}
}
// 实现分页条件查询User方法
public PageResult<ViewUser> GetAllUsersPagination(int page, int pageSize, string DeptId, string? userName, string? realName)
{
var res = new List<User>();
int count = 0;
if (!string.IsNullOrEmpty(DeptId))
{
var pdeptRes = _sqlServerDbContext.Depts
.Where(t => t.Id == DeptId).Select(t => t.ParentDept).FirstOrDefault();
// 如果pdept是空的是一级部门 一级部门查询
if (string.IsNullOrEmpty(pdeptRes))
{
var sql = _sqlServerDbContext.Users.Include(user => user.Role)
.Where(u => (_sqlServerDbContext.Depts.Where(d => d.ParentDept == DeptId)
.Select(d => d.Id)
.ToList())
.Contains(u.DeptId))
.AsQueryable(); // 创建可拼接的LINQ 查询
if (!userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList(); // 分页查询
count = sql.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%")).Count();
}
if (!realName.IsNullOrEmpty() && userName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).Count();
}
if (!userName.IsNullOrEmpty() && !realName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).Count();
}
if (userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = sql.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Count();
}
} // 二级部门查询
else
{
var sql = _sqlServerDbContext.Users
.Include(user => user.Role)
.Where(u => u.DeptId == DeptId).AsQueryable();
if (!userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%")).Count();
}
if (!realName.IsNullOrEmpty() && userName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).Count();
}
if (!userName.IsNullOrEmpty() && !realName.IsNullOrEmpty())
{
res = sql
.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%"))
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
count = sql.Where(u => EF.Functions.Like(u.UserName, "%" + userName + "%"))
.Where(u => EF.Functions.Like(u.RealName, "%" + realName + "%")).Count();
}
if (userName.IsNullOrEmpty() && realName.IsNullOrEmpty())
{
res = sql.ToList();
count = sql.Count();
}
}
}
else
{
res = _sqlServerDbContext.Users.Include(user => user.Role).ToList();
count = _sqlServerDbContext.Users.Include(user => user.Role).Count();
}
List<ViewUser> viewUsers = new();
var config = new MapperConfiguration(cfg => cfg.CreateMap<User, ViewUser>()
.ForMember(dest => dest.RoleId, opt => opt.MapFrom(src => src.Role.Id))
.ForMember(dest => dest.RoleName, opt => opt.MapFrom(src => src.Role.RoleName))
.AfterMap((src, des) => des.PassWord = null));
var mapper = config.CreateMapper();
foreach (var user in res)
{
viewUsers.Add(
mapper.Map<ViewUser>(user)
);
}
return new PageResult<ViewUser>
{
Items = viewUsers, // 数据列表
Total = count // 不分页数据列表元素数量汇总
};
}
}
}
```
#### 创建 `Controller`
Controller即控制器API负责后端与前端数据交互
在**解决方案资源管理器**中已创建的**Controllers**文件夹中新建 `UserController.cs`类
![image-20221130181148128](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221130181148128.png)
遵循RestFul风格 查询使用Get请求增加与更新使用Post请求删除使用Delete请求
```c#
using Microsoft.AspNetCore.Mvc;
using XiaodaERP.Models;
using XiaodaERP.Services;
using XiaodaERP.Services.IServices;
using XiaodaERP.Utils;
namespace XiaodaERP.Controllers
{
// 使用WebAPI
[ApiController]
[Route("/api/[controller]/[action]")] // 规定API URL格式
public class UserController : ControllerBase
{
// 注入UserService
private readonly IUserService _userService;
public UserController (IUserService userService)
{
_userService = userService;
}
// 添加与更新User Post请求 Name指定 action 的Url
[HttpPost(Name = "postUser")]
public ResultUtil PostUser(ViewUser viewUser) =>
ResultUtil.ok(_userService.UpdateUser(viewUser));
[HttpGet(Name = "getAllUserList")]
public ResultUtil GetAllUserList(int? page, int? pageSize, string? deptId, string? userName, string? realName)
{
if (page != null && pageSize != null)
{
return ResultUtil.ok(_userService.GetAllUsersPagination((int) page, (int) pageSize, deptId, userName, realName));
}
else
{
return ResultUtil.ok(_userService.GetAllUsers(deptId, userName, realName));
}
}
[HttpPut(Name = "resetToDefaultPassword")]
public ResultUtil ResetToDefaultPassword(string userId)
=> ResultUtil.ok(_userService.ResetToDefaultPassword(userId));
[HttpDelete(Name = "deleteUser")]
public ResultUtil DeleteUser(string userId) => ResultUtil.ok(_userService.DeleteUser(userId));
}
}
```