1、员工管理界面
1、新增员工 1、EmployeeController.cs ProgramBackEnd\SkyServer\controller\admin\EmployeeController.cs
该文件中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [HttpPost ] public async Task<Result<string >> Save([FromBody] EmployeeDTO employeeDTO){ _logger.LogInformation("创建新员工: {Name}" , employeeDTO.Name); await _employeeService.Save(employeeDTO); return Result<string >.Success("员工创建成功" ); }
2、EmployeeService 在ProgramBackEnd\SkyServer\service\IEmployeeService.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Task<Employee> Save (EmployeeDTO employeeDTO ) ;
在ProgramBackEnd\SkyServer\service\Impl\EmployeeServiceImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public async Task<Employee> Save (EmployeeDTO employeeDTO ){ long ? currentEmpId = BaseContext.GetCurrentId(); if (!currentEmpId.HasValue) { _logger.LogWarning("创建员工失败:未能获取当前操作人信息" ); throw new BaseException("未获取到当前登录用户信息" ); } if (employeeDTO == null ) { throw new ArgumentNullException(nameof (employeeDTO), "员工信息不能为空" ); } if (string .IsNullOrEmpty(employeeDTO.Username)) { throw new ArgumentException("用户名不能为空" , nameof (employeeDTO)); } if (string .IsNullOrEmpty(employeeDTO.Name)) { throw new ArgumentException("姓名不能为空" , nameof (employeeDTO)); } DateTime now = DateTime.Now; Employee employee = new Employee { Username = employeeDTO.Username?.Trim(), Name = employeeDTO.Name?.Trim(), Password = MD5Util.ComputeHash(PasswordConstant.DEFAULT_PASSWORD), Phone = employeeDTO.Phone?.Trim(), Sex = employeeDTO.Sex?.Trim(), IdNumber = employeeDTO.IdNumber?.Trim(), Status = StatusConstant.ENABLE, CreateTime = now, UpdateTime = now, CreateUser = currentEmpId.Value, UpdateUser = currentEmpId.Value }; _logger.LogInformation("创建员工:用户名 {Username}, 姓名 {Name}" , employee.Username, employee.Name); return await _employeeMapper.Insert(employee); }
3、EmployeeMapper 在ProgramBackEnd\SkyServer\mapper\IEmployeeMapper.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Task<Employee> Insert (Employee employee ) ;
在ProgramBackEnd\SkyServer\mapper\Impl\EmployeeMapperImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public async Task<Employee> Insert (Employee employee ){ if (employee == null ) { throw new ArgumentNullException(nameof (employee), "员工对象不能为空" ); } try { await _context.Employees.AddAsync(employee); await _context.SaveChangesAsync(); return employee; } catch (DbUpdateException ex) { string errorMessage = ex.InnerException?.Message?.Contains("Duplicate entry" ) == true ? "员工用户名已存在,请使用其他用户名" : $"保存员工数据时发生错误: {ex.Message} " ; throw new DbUpdateException(errorMessage, ex); } catch (Exception ex) { throw new InvalidOperationException("保存员工数据时发生未知错误" , ex); } }
由于在Employee中需要指定创建与更新成员的指定者,因此需要通过拦截器等内容注入到ThreadLocal中
4、JwtTokenValidationMiddleware.cs 在ProgramBackEnd\SkyServer\Middlewares\JwtTokenValidationMiddleware.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 using Microsoft.AspNetCore.Http;using Microsoft.Extensions.Options;using ProgramBackEnd.SkyCommon.constant;using ProgramBackEnd.SkyCommon.context;using ProgramBackEnd.SkyCommon.properties;using ProgramBackEnd.SkyCommon.result;using ProgramBackEnd.SkyCommon.utils;using System.Text.Json;namespace ProgramBackEnd.SkyServer.Middlewares { public class JwtTokenValidationMiddleware { private readonly RequestDelegate _next; private readonly ILogger<JwtTokenValidationMiddleware> _logger; private readonly JwtProperties _jwtProperties; private static readonly HashSet<string > _excludedPaths = new (StringComparer.OrdinalIgnoreCase) { "/admin/employee/login" }; public JwtTokenValidationMiddleware ( RequestDelegate next, ILogger<JwtTokenValidationMiddleware> logger, IOptions<JwtProperties> jwtOptions ) { _next = next ?? throw new ArgumentNullException(nameof (next), "请求委托不能为空" ); _logger = logger ?? throw new ArgumentNullException(nameof (logger), "日志记录器不能为空" ); _jwtProperties = jwtOptions?.Value ?? throw new ArgumentNullException(nameof (jwtOptions), "JWT配置不能为空" ); } public async Task InvokeAsync (HttpContext context ) { try { string path = context.Request.Path.Value?.ToLower() ?? "" ; if (path.StartsWith("/admin/" , StringComparison.OrdinalIgnoreCase) && !_excludedPaths.Contains(path)) { _logger.LogInformation("开始JWT验证: {Path}" , path); var (success, employeeId) = ValidateToken(context); if (!success) { _logger.LogWarning("JWT验证失败: {Path}" , context.Request.Path); await SendUnauthorizedResponseAsync(context); return ; } context.Items["EmpId" ] = employeeId; BaseContext.SetCurrentId(employeeId); _logger.LogInformation("员工ID {EmpId} 已设置到请求上下文和线程存储" , employeeId); } await _next(context); } finally { BaseContext.RemoveCurrentId(); } } private (bool Success, long EmployeeId) ValidateToken(HttpContext context) { try { string token = ExtractToken(context); if (string .IsNullOrEmpty(token)) { return (false , 0 ); } _logger.LogInformation("正在验证JWT令牌" ); Dictionary<string , object > claims = JwtUtil.ParseJWT(_jwtProperties.AdminSecretKey, token); if (!TryGetEmployeeId(claims, out long empId)) { _logger.LogWarning("JWT令牌不包含有效的员工ID" ); return (false , 0 ); } _logger.LogInformation("JWT验证成功, 员工ID: {EmpId}" , empId); return (true , empId); } catch (Exception ex) { _logger.LogWarning(ex, "JWT验证过程发生异常: {Message}" , ex.Message); return (false , 0 ); } } private string ExtractToken (HttpContext context ) { if (!context.Request.Headers.TryGetValue(_jwtProperties.AdminTokenName, out var tokenValues) || tokenValues.Count == 0 ) { _logger.LogWarning("请求缺少JWT令牌: {TokenName}" , _jwtProperties.AdminTokenName); return null ; } string token = tokenValues.First(); if (string .IsNullOrEmpty(token)) { _logger.LogWarning("JWT令牌为空" ); return null ; } return token; } private bool TryGetEmployeeId (Dictionary<string , object > claims, out long employeeId ) { employeeId = 0 ; if (!claims.TryGetValue(JwtClaimsConstant.EMP_ID, out object empIdObj) || empIdObj == null ) { return false ; } try { employeeId = Convert.ToInt64(empIdObj.ToString()); return employeeId > 0 ; } catch (FormatException ex) { _logger.LogWarning(ex, "员工ID格式无效: {Value}" , empIdObj); return false ; } catch (OverflowException ex) { _logger.LogWarning(ex, "员工ID数值溢出: {Value}" , empIdObj); return false ; } } private static async Task SendUnauthorizedResponseAsync (HttpContext context ) { context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json; charset=utf-8" ; var result = Result<string >.Error(MessageConstant.NOT_LOGIN); await context.Response.WriteAsJsonAsync(result, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); } } }
5、JwtUtil 在ProgramBackEnd\SkyCommon\utils\JwtUtil.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 using Microsoft.IdentityModel.Tokens;using ProgramBackEnd.SkyCommon.exception;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Text;namespace ProgramBackEnd.SkyCommon.utils { public static class JwtUtil { public static string CreateJWT (string secretKey, long ttlMillis, Dictionary<string , object > claims ) { if (string .IsNullOrEmpty(secretKey)) throw new ArgumentNullException(nameof (secretKey), "JWT密钥不能为空" ); if (ttlMillis <= 0 ) throw new ArgumentException("令牌有效期必须大于0" , nameof (ttlMillis)); var issuedAt = DateTime.UtcNow; var expiration = issuedAt.AddMilliseconds(ttlMillis); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var tokenDescriptor = new SecurityTokenDescriptor { IssuedAt = issuedAt, NotBefore = issuedAt, Expires = expiration, SigningCredentials = credentials }; if (claims != null && claims.Count > 0 ) { var claimsList = new List<Claim>(); foreach (var claim in claims) { string value = claim.Value?.ToString() ?? "" ; claimsList.Add(new Claim(claim.Key, value )); } tokenDescriptor.Subject = new ClaimsIdentity(claimsList); } var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } public static Dictionary<string , object > ParseJWT (string secretKey, string token ) { if (string .IsNullOrEmpty(secretKey)) throw new ArgumentNullException(nameof (secretKey), "JWT密钥不能为空" ); if (string .IsNullOrEmpty(token)) throw new ArgumentNullException(nameof (token), "JWT令牌不能为空" ); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true , IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), ValidateIssuer = false , ValidIssuer = null , ValidateAudience = false , ValidAudience = null , ValidateLifetime = true , ClockSkew = TimeSpan.Zero, RequireExpirationTime = true }; var tokenHandler = new JwtSecurityTokenHandler(); try { ClaimsPrincipal principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); if (!(validatedToken is JwtSecurityToken jwtToken) || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) { throw new SecurityTokenException("无效的令牌" ); } var claims = principal.Claims; var claimsDictionary = new Dictionary<string , object >(); foreach (var claim in claims) { claimsDictionary[claim.Type] = claim.Value; } return claimsDictionary; } catch (SecurityTokenExpiredException) { throw new JWTTokenException("令牌已过期" ); } catch (SecurityTokenInvalidSignatureException) { throw new JWTTokenException("令牌签名无效" ); } catch (SecurityTokenException ex) { throw new JWTTokenException($"令牌验证失败: {ex.Message} " ); } } } }
6、Program.cs 在ProgramBackEnd\Program.cs中添加如下内容以使用中间件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using ProgramBackEnd.SkyCommon.properties; using ProgramBackEnd.SkyServer.config; using ProgramBackEnd.SkyServer.Handler; using ProgramBackEnd.SkyServer.Interceptors; using ProgramBackEnd.SkyServer.Middlewares; var builder = WebApplication.CreateBuilder(args );builder.Services.AddDbContext<SkyDbContext>(options => options.UseMySql( builder.Configuration.GetConnectionString("DefaultConnection" ), new MySqlServerVersion(new Version(9 , 3 , 0 )) ) ); builder.Services.Configure<JwtProperties>(builder.Configuration.GetSection("JwtConfig" )); builder.Services.AddControllers().AddGlobalExceptionHandler(); builder.Services.RegisterAllServices(); var app = builder.Build();app.UseRouting(); app.UseMiddleware<JwtTokenValidationMiddleware>(); app.MapControllers(); app.Run();
用户存在:
用户未存在:
2、员工分页查询 1、EmployeeController.cs ProgramBackEnd\SkyServer\controller\admin\EmployeeController.cs
该文件中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 [HttpGet("page" ) ] public async Task<Result<PageResult>> Page([FromQuery] EmployeePageQueryDTO employeePageQueryDTO){ _logger.LogInformation("员工分页查询开始,查询参数:{EmployeePageQueryDTO}" , employeePageQueryDTO); try { PageResult pageResult = await _employeeService.PageQuery(employeePageQueryDTO); _logger.LogInformation("员工分页查询成功,共返回 {Count} 条记录,总记录数 {Total}" ,pageResult.Records?.Count ?? 0 , pageResult.Total); return Result<PageResult>.Success(pageResult); } catch (Exception ex) { _logger.LogError(ex, "员工分页查询异常:{Message}" , ex.Message); throw ; } }
2、EmployeeService 在ProgramBackEnd\SkyServer\service\IEmployeeService.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Task<PageResult> PageQuery (EmployeePageQueryDTO employeePageQueryDTO ) ;
在ProgramBackEnd\SkyServer\service\Impl\EmployeeServiceImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public async Task<PageResult> PageQuery (EmployeePageQueryDTO employeePageQueryDTO ){ _logger.LogInformation("开始执行员工分页查询,查询参数:{EmployeePageQueryDTO}" , employeePageQueryDTO); try { if (employeePageQueryDTO == null ) { throw new ArgumentNullException(nameof (employeePageQueryDTO), "分页查询参数不能为空" ); } if (employeePageQueryDTO.Page < 1 ) { _logger.LogWarning("页码参数无效(值为{Page}),已自动调整为默认值1" , employeePageQueryDTO.Page); employeePageQueryDTO.Page = 1 ; } if (employeePageQueryDTO.PageSize < 1 ) { _logger.LogWarning("每页记录数参数无效(值为{PageSize}),已自动调整为默认值10" , employeePageQueryDTO.PageSize); employeePageQueryDTO.PageSize = 10 ; } (int total, List<Employee> employees) = await _employeeMapper.PageQuery(employeePageQueryDTO); _logger.LogDebug("查询成功,共获取{Count}条记录,总记录数{Total}" , employees.Count, total); PageResult pageResult = new PageResult { Total = total, Records = employees }; _logger.LogInformation("员工分页查询成功完成,返回记录数:{Count}" , employees.Count); return pageResult; } catch (Exception ex) { _logger.LogError(ex, "员工分页查询过程中发生异常:{Message}" , ex.Message); throw ; } }
3、EmployeeMapper 在ProgramBackEnd\SkyServer\mapper\IEmployeeMapper.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Task<(int total, List<Employee> employees)> PageQuery(EmployeePageQueryDTO employeePageQueryDTO);
在ProgramBackEnd\SkyServer\mapper\Impl\EmployeeMapperImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public async Task<(int total, List<Employee> employees)> PageQuery(EmployeePageQueryDTO employeePageQueryDTO){ if (employeePageQueryDTO == null ) { throw new ArgumentNullException(nameof (employeePageQueryDTO), "查询参数不能为空" ); } int pageNumber = Math.Max(1 , employeePageQueryDTO.Page); int pageSize = Math.Max(1 , employeePageQueryDTO.PageSize); try { IQueryable<Employee> query = _context.Employees; if (!string .IsNullOrWhiteSpace(employeePageQueryDTO.Name)) { string name = employeePageQueryDTO.Name.Trim(); query = query.Where(e => e.Name.Contains(name)); } int total = await query.CountAsync(); List<Employee> employees = await query .OrderByDescending(e => e.CreateTime) .ThenBy(e => e.Id) .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToListAsync(); return (total, employees); } catch (Exception ex) when (ex is not ArgumentNullException) { throw new InvalidOperationException($"执行员工分页查询时发生错误: {ex.Message} " , ex); } }
由于分页查询中涉及日期格式的转换,因此构建中间件以自动优化格式。
4、JacksonObjectMapper 在ProgramBackEnd\SkyCommon\json\JacksonObjectMapper.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 using Newtonsoft.Json;using Newtonsoft.Json.Converters;using Newtonsoft.Json.Serialization;using System.Globalization;using JsonConverter = Newtonsoft.Json.JsonConverter;using JsonSerializer = Newtonsoft.Json.JsonSerializer;namespace ProgramBackEnd.SkyCommon.json { public class JacksonObjectMapper { public static readonly string DEFAULT_DATE_FORMAT = "yyyy-MM-dd" ; public static readonly string DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm" ; public static readonly string DEFAULT_TIME_FORMAT = "HH:mm:ss" ; private readonly JsonSerializerSettings _settings; public JacksonObjectMapper () { _settings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver() }; _settings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = DEFAULT_DATE_TIME_FORMAT, Culture = CultureInfo.InvariantCulture }); _settings.Converters.Add(new DateOnlyJsonConverter(DEFAULT_DATE_FORMAT)); _settings.Converters.Add(new TimeOnlyJsonConverter(DEFAULT_TIME_FORMAT)); } public string WriteValueAsString (object obj ) { return JsonConvert.SerializeObject(obj, _settings); } public T ReadValue <T >(string json ) { return JsonConvert.DeserializeObject<T>(json, _settings); } public JsonSerializerSettings GetSerializerSettings () { return _settings; } } public class DateOnlyJsonConverter : JsonConverter { private readonly string _dateFormat; public DateOnlyJsonConverter (string dateFormat ) { _dateFormat = dateFormat; } public override bool CanConvert (Type objectType ) { return objectType == typeof (DateTime) || objectType == typeof (DateTime?); } public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) { if (reader.TokenType == JsonToken.Null) { return null ; } string dateStr = reader.Value?.ToString(); if (DateTime.TryParseExact(dateStr, _dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date)) { return date.Date; } return DateTime.Parse(dateStr, CultureInfo.InvariantCulture); } public override void WriteJson (JsonWriter writer, object value , JsonSerializer serializer ) { if (value == null ) { writer.WriteNull(); return ; } writer.WriteValue(((DateTime)value ).ToString(_dateFormat, CultureInfo.InvariantCulture)); } } public class TimeOnlyJsonConverter : JsonConverter { private readonly string _timeFormat; public TimeOnlyJsonConverter (string timeFormat ) { _timeFormat = timeFormat; } public override bool CanConvert (Type objectType ) { return objectType == typeof (TimeSpan) || objectType == typeof (TimeSpan?); } public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) { if (reader.TokenType == JsonToken.Null) { return null ; } string timeStr = reader.Value?.ToString(); if (TimeSpan.TryParseExact(timeStr, _timeFormat, CultureInfo.InvariantCulture, out TimeSpan time)) { return time; } return TimeSpan.Parse(timeStr, CultureInfo.InvariantCulture); } public override void WriteJson (JsonWriter writer, object value , JsonSerializer serializer ) { if (value == null ) { writer.WriteNull(); return ; } var timeSpan = (TimeSpan)value ; var formattedTime = $"{timeSpan.Hours:D2} :{timeSpan.Minutes:D2} :{timeSpan.Seconds:D2} " ; writer.WriteValue(formattedTime); } } }
在ProgramBackEnd\SkyServer\Middlewares\JsonFormatterMiddleware.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 using Newtonsoft.Json;using ProgramBackEnd.SkyCommon.json;using System.Text;namespace ProgramBackEnd.SkyServer.Middlewares { public class JsonFormatterMiddleware { private readonly RequestDelegate _next; private readonly JacksonObjectMapper _jacksonMapper; public JsonFormatterMiddleware (RequestDelegate next ) { _next = next ?? throw new ArgumentNullException(nameof (next)); _jacksonMapper = new JacksonObjectMapper(); } public async Task InvokeAsync (HttpContext context ) { if (context == null ) throw new ArgumentNullException(nameof (context)); var originalBodyStream = context.Response.Body; try { using var responseBody = new MemoryStream(); context.Response.Body = responseBody; await _next(context); if (IsJsonResponse(context.Response)) { await FormatJsonResponseAsync(context.Response, responseBody); } responseBody.Seek(0 , SeekOrigin.Begin); await responseBody.CopyToAsync(originalBodyStream); } finally { context.Response.Body = originalBodyStream; } } private static bool IsJsonResponse (HttpResponse response ) { return response.ContentType != null && response.ContentType.ToLower().Contains("application/json" ); } private async Task FormatJsonResponseAsync (HttpResponse response, MemoryStream responseStream ) { responseStream.Seek(0 , SeekOrigin.Begin); var responseBodyText = await new StreamReader(responseStream).ReadToEndAsync(); if (string .IsNullOrEmpty(responseBodyText)) { return ; } try { var deserializedObject = JsonConvert.DeserializeObject(responseBodyText); var reformattedJson = _jacksonMapper.WriteValueAsString(deserializedObject); responseStream.SetLength(0 ); var bytes = Encoding.UTF8.GetBytes(reformattedJson); await responseStream.WriteAsync(bytes, 0 , bytes.Length); } catch (JsonException ex) { Console.WriteLine($"JSON格式化失败: {ex.Message} , 路径: {ex.Path} " ); responseStream.SetLength(0 ); var bytes = Encoding.UTF8.GetBytes(responseBodyText); await responseStream.WriteAsync(bytes, 0 , bytes.Length); } catch (Exception ex) { Console.WriteLine($"JSON处理过程中发生意外错误: {ex.Message} " ); responseStream.SetLength(0 ); var bytes = Encoding.UTF8.GetBytes(responseBodyText); await responseStream.WriteAsync(bytes, 0 , bytes.Length); } } } }
3、启用、禁用员工账户 1、EmployeeController.cs ProgramBackEnd\SkyServer\controller\admin\EmployeeController.cs
该文件中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 [HttpPost("status/{status}" ) ] public async Task<Result<string >> StartOrStop([FromRoute] int status, [FromQuery] long id){ if (status != 0 && status != 1 ) { _logger.LogWarning("员工状态修改失败:无效的状态值 {Status},员工ID {Id}" , status, id); throw new ArgumentException("状态值只能是0(禁用)或1(启用)" ); } string actionType = status == 1 ? "启用" : "禁用" ; _logger.LogInformation("正在{ActionType}员工账号,员工ID:{Id}" , actionType, id); await _employeeService.StartOrStop(status, id); _logger.LogInformation("已成功{ActionType}员工账号,员工ID:{Id}" , actionType, id); return Result<string >.Success($"员工账号{actionType} 成功" ); }
2、EmployeeService 在ProgramBackEnd\SkyServer\service\IEmployeeService.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Task<Employee> StartOrStop (int status, long id ) ;
在ProgramBackEnd\SkyServer\service\Impl\EmployeeServiceImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public async Task<Employee> StartOrStop (int status, long id ){ if (status != StatusConstant.ENABLE && status != StatusConstant.DISABLE) { _logger.LogWarning("修改员工状态失败:无效的状态值 {Status},员工ID {Id}" , status, id); throw new ArgumentException("状态值只能是0(禁用)或1(启用)" ); } long ? currentEmpId = BaseContext.GetCurrentId(); if (!currentEmpId.HasValue) { _logger.LogWarning("修改员工状态失败:未能获取当前操作人信息" ); throw new BaseException("未获取到当前登录用户信息" ); } string actionType = status == StatusConstant.ENABLE ? "启用" : "禁用" ; _logger.LogInformation("开始{ActionType}员工账号,员工ID:{Id},操作人ID:{OperatorId}" , actionType, id, currentEmpId.Value); Employee employee = new Employee { Id = id, Status = status, UpdateTime = DateTime.Now, UpdateUser = currentEmpId.Value }; try { employee = await _employeeMapper.Update(employee); _logger.LogInformation("已成功{ActionType}员工账号,员工ID:{Id}" , actionType, id); return employee; } catch (Exception ex) { _logger.LogError(ex, "员工状态修改失败,员工ID:{Id},目标状态:{Status}" , id, status); throw ; } }
3、EmployeeMapper 在ProgramBackEnd\SkyServer\mapper\IEmployeeMapper.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 Task<Employee> Update (Employee employee ) ;
在ProgramBackEnd\SkyServer\mapper\Impl\EmployeeMapperImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public async Task<(int total, List<Employee> employees)> PageQuery(EmployeePageQueryDTO employeePageQueryDTO){ if (employeePageQueryDTO == null ) { throw new ArgumentNullException(nameof (employeePageQueryDTO), "查询参数不能为空" ); } int pageNumber = Math.Max(1 , employeePageQueryDTO.Page); int pageSize = Math.Max(1 , employeePageQueryDTO.PageSize); try { IQueryable<Employee> query = _context.Employees; if (!string .IsNullOrWhiteSpace(employeePageQueryDTO.Name)) { string name = employeePageQueryDTO.Name.Trim(); query = query.Where(e => e.Name.Contains(name)); } int total = await query.CountAsync(); List<Employee> employees = await query .OrderByDescending(e => e.CreateTime) .ThenBy(e => e.Id) .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToListAsync(); return (total, employees); } catch (Exception ex) when (ex is not ArgumentNullException) { throw new InvalidOperationException($"执行员工分页查询时发生错误: {ex.Message} " , ex); } }
4、编辑员工 1、EmployeeController.cs ProgramBackEnd\SkyServer\controller\admin\EmployeeController.cs
该文件中完整内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 [HttpGet("{id}" ) ] public async Task<Result<Employee>> GetById([FromRoute] long id){ _logger.LogInformation("查询员工详细信息,员工ID:{Id}" , id); Employee employee = await _employeeService.GetById(id); if (employee == null ) { _logger.LogWarning("未找到员工信息,员工ID:{Id}" , id); throw new Exception($"未找到ID为{id} 的员工" ); } _logger.LogInformation("员工信息查询成功,员工ID:{Id},姓名:{Name}" , id, employee.Name); return Result<Employee>.Success(employee); } [HttpPut ] public async Task<Result<string >> Update([FromBody] EmployeeDTO employeeDTO){ _logger.LogInformation("更新员工信息,员工ID:{Id},姓名:{Name}" , employeeDTO.Id, employeeDTO.Name); await _employeeService.Update(employeeDTO); _logger.LogInformation("员工信息更新成功,员工ID:{Id}" , employeeDTO.Id); return Result<string >.Success("员工信息更新成功" ); }
2、EmployeeService 在ProgramBackEnd\SkyServer\service\IEmployeeService.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Task<Employee?> GetById(long id); Task Update (EmployeeDTO employeeDTO ) ;
在ProgramBackEnd\SkyServer\service\Impl\EmployeeServiceImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 public async Task<Employee?> GetById(long id){ if (id <= 0 ) { _logger.LogWarning("查询员工信息失败:无效的员工ID {Id}" , id); throw new ArgumentException("员工ID必须大于0" , nameof (id)); } _logger.LogInformation("查询员工信息,员工ID:{Id}" , id); Employee? employee = await _employeeMapper.GetById(id); if (employee == null ) { _logger.LogInformation("未找到指定的员工信息,员工ID:{Id}" , id); return null ; } employee.Password = null ; _logger.LogInformation("成功获取员工信息,员工ID:{Id},姓名:{Name}" , id, employee.Name); return employee; } public async Task Update (EmployeeDTO employeeDTO ){ if (employeeDTO == null ) { throw new ArgumentNullException(nameof (employeeDTO), "员工信息不能为空" ); } if (employeeDTO.Id <= 0 ) { throw new ArgumentException("员工ID无效" , nameof (employeeDTO)); } long ? currentEmpId = BaseContext.GetCurrentId(); if (!currentEmpId.HasValue) { _logger.LogWarning("更新员工信息失败:未能获取当前操作人信息" ); throw new BaseException("未获取到当前登录用户信息" ); } _logger.LogInformation("开始更新员工信息,员工ID:{Id},操作人ID:{OperatorId}" , employeeDTO.Id, currentEmpId.Value); Employee employee = new () { Id = employeeDTO.Id, UpdateTime = DateTime.Now, UpdateUser = currentEmpId.Value }; PropertyUtil.CopyPropertiesIgnoreNull(employeeDTO, employee); await _employeeMapper.Update(employee); _logger.LogInformation("员工信息更新成功,员工ID:{Id}" , employeeDTO.Id); }
3、EmployeeMapper 在ProgramBackEnd\SkyServer\mapper\IEmployeeMapper.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Task<Employee?> GetById(long id);
在ProgramBackEnd\SkyServer\mapper\Impl\EmployeeMapperImpl.cs中添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public async Task<Employee?> GetById(long id){ if (id <= 0 ) { throw new ArgumentException("员工ID必须大于0" , nameof (id)); } try { return await _context.Employees.FirstOrDefaultAsync(e => e.Id == id); } catch (Exception ex) { throw new InvalidOperationException($"查询ID为 {id} 的员工信息时发生错误" , ex); } }
2、分类管理界面
1、CategoryController ProgramBackEnd\SkyServer\controller\admin\CategoryController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 using Microsoft.AspNetCore.Mvc;using ProgramBackEnd.SkyCommon.result;using ProgramBackEnd.SkyPojo.dto;using ProgramBackEnd.SkyPojo.entity;using ProgramBackEnd.SkyServer.service;namespace ProgramBackEnd.SkyServer.controller.admin { [ApiController ] [Route("/admin/category" ) ] public class CategoryController : ControllerBase { private readonly ILogger<CategoryController> _logger; private readonly ICategoryService _categoryService; public CategoryController (ILogger<CategoryController> logger, ICategoryService categoryService ) { _logger = logger; _categoryService = categoryService; } [HttpPost ] public async Task<Result<string >> Save([FromBody] CategoryDTO categoryDTO) { _logger.LogInformation("开始保存分类信息: {@CategoryDTO}" , categoryDTO); await _categoryService.Save(categoryDTO); return Result<string >.Success("分类保存成功" ); } [HttpGet("page" ) ] public async Task<Result<PageResult>> Page([FromQuery] CategoryPageQueryDTO categoryPageQueryDTO) { _logger.LogInformation("获取分类分页信息: {@CategoryPageQueryDTO}" , categoryPageQueryDTO); PageResult page = await _categoryService.PageQuery(categoryPageQueryDTO); return Result<PageResult>.Success(page); } [HttpDelete ] public async Task<Result<string >> DeleteById([FromQuery] long id) { _logger.LogInformation("删除分类,ID: {Id}" , id); await _categoryService.DeleteById(id); return Result<string >.Success("删除分类成功" ); } [HttpPut ] public async Task<Result<string >> Update([FromBody] CategoryDTO categoryDTO) { _logger.LogInformation("更新分类信息: {@CategoryDTO}" , categoryDTO); await _categoryService.Update(categoryDTO); return Result<string >.Success("修改分类成功" ); } [HttpPost("status/{status}" ) ] public async Task<Result<string >> StartOrStop([FromRoute] int status, [FromQuery] long id) { _logger.LogInformation("更改分类状态,ID: {Id},目标状态: {Status}" , id, status); await _categoryService.StartOrStop(status, id); return Result<string >.Success("修改分类状态成功" ); } [HttpGet("list" ) ] public async Task<Result<List<Category>>> List([FromQuery] int type) { _logger.LogInformation("获取分类列表,类型: {Type}" , type); List<Category> categories = await _categoryService.GetCategoriesByType(type); return Result<List<Category>>.Success(categories); } } }
2、CategoryService ProgramBackEnd\SkyServer\service\ICategoryService.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 using ProgramBackEnd.SkyCommon.result;using ProgramBackEnd.SkyPojo.dto;using ProgramBackEnd.SkyPojo.entity;namespace ProgramBackEnd.SkyServer.service { public interface ICategoryService { Task Save (CategoryDTO categoryDTO ) ; Task DeleteById (long id ) ; Task Update (CategoryDTO categoryDTO ) ; Task<PageResult> PageQuery (CategoryPageQueryDTO categoryPageQueryDTO ) ; Task StartOrStop (int status, long id ) ; Task<List<Category>> GetCategoriesByType(int type); } }
ProgramBackEnd\SkyServer\service\Impl\CategoryServiceImpl.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 using ProgramBackEnd.SkyCommon.constant;using ProgramBackEnd.SkyCommon.context;using ProgramBackEnd.SkyCommon.result;using ProgramBackEnd.SkyCommon.utils;using ProgramBackEnd.SkyPojo.dto;using ProgramBackEnd.SkyPojo.entity;using ProgramBackEnd.SkyServer.mapper;namespace ProgramBackEnd.SkyServer.service.Impl { public class CategoryServiceImpl : ICategoryService { private readonly ICategoryMapper _categoryMapper; private readonly ILogger<CategoryServiceImpl> _logger; public CategoryServiceImpl (ICategoryMapper categoryMapper, ILogger<CategoryServiceImpl> logger ) { _categoryMapper = categoryMapper ?? throw new ArgumentNullException(nameof (categoryMapper)); _logger = logger ?? throw new ArgumentNullException(nameof (logger)); } public async Task DeleteById (long id ) { if (id <= 0 ) { _logger.LogWarning("删除分类失败:无效的分类ID {Id}" , id); throw new ArgumentException("分类ID无效" , nameof (id)); } _logger.LogInformation("开始删除分类,ID:{Id}" , id); await _categoryMapper.DeleteById(id); _logger.LogInformation("分类删除成功,ID:{Id}" , id); } public async Task<List<Category>> GetCategoriesByType(int type) { _logger.LogInformation("查询分类列表,类型:{Type}" , type); List<Category> categories = await _categoryMapper.GetCategoriesByType(type); _logger.LogInformation("查询到{Count}条分类记录,类型:{Type}" , categories.Count, type); return categories; } public async Task<PageResult> PageQuery (CategoryPageQueryDTO categoryPageQueryDTO ) { _logger.LogInformation("开始执行分类分页查询,参数:{@CategoryPageQueryDTO}" , categoryPageQueryDTO); (int total, List<Category> categories) = await _categoryMapper.PageQuery(categoryPageQueryDTO); PageResult pageResult = new () { Total = total, Records = categories }; _logger.LogInformation("分类分页查询完成,共返回{Count}条记录,总记录数{Total}" , categories.Count, total); return pageResult; } public async Task Save (CategoryDTO categoryDTO ) { long ? currentUserId = BaseContext.GetCurrentId(); if (currentUserId == null ) { _logger.LogWarning("新增分类失败:未获取到当前登录用户信息" ); throw new ArgumentException("当前用户ID不能为空,请先登录" ); } if (categoryDTO == null || string .IsNullOrEmpty(categoryDTO.Name)) { _logger.LogWarning("新增分类失败:分类数据无效" ); throw new ArgumentException("分类数据无效" ); } Category category = new Category(); PropertyUtil.CopyProperties(categoryDTO, category); DateTime now = DateTime.Now; category.CreateUser = currentUserId.Value; category.UpdateUser = currentUserId.Value; category.CreateTime = now; category.UpdateTime = now; category.Status = StatusConstant.ENABLE; _logger.LogInformation("准备保存分类信息: {@Category}" , category); await _categoryMapper.Insert(category); _logger.LogInformation("分类信息保存成功,名称:{Name}, 类型:{Type}" , category.Name, category.Type); } public async Task StartOrStop (int status, long id ) { if (status != StatusConstant.ENABLE && status != StatusConstant.DISABLE) { _logger.LogWarning("分类状态修改失败:无效的状态值 {Status}" , status); throw new ArgumentException("状态值只能是0(禁用)或1(启用)" , nameof (status)); } if (id <= 0 ) { _logger.LogWarning("分类状态修改失败:无效的分类ID {Id}" , id); throw new ArgumentException("分类ID无效" , nameof (id)); } long ? currentUserId = BaseContext.GetCurrentId(); if (currentUserId == null ) { _logger.LogWarning("分类状态修改失败:未获取到当前登录用户信息" ); throw new ArgumentException("未获取到当前登录用户信息" ); } string actionType = status == StatusConstant.ENABLE ? "启用" : "禁用" ; _logger.LogInformation("开始{ActionType}分类,ID:{Id}" , actionType, id); Category category = new Category { Id = id, Status = status, UpdateUser = currentUserId.Value, UpdateTime = DateTime.Now }; await _categoryMapper.Update(category); _logger.LogInformation("已成功{ActionType}分类,ID:{Id}" , actionType, id); } public async Task Update (CategoryDTO categoryDTO ) { if (categoryDTO == null || categoryDTO.Id <= 0 ) { _logger.LogWarning("更新分类失败:无效的分类数据或ID" ); throw new ArgumentException("分类数据或ID无效" ); } long ? currentUserId = BaseContext.GetCurrentId(); if (currentUserId == null ) { _logger.LogWarning("更新分类失败:未获取到当前登录用户信息" ); throw new ArgumentException("未获取到当前登录用户信息" ); } _logger.LogInformation("开始更新分类信息,ID:{Id},名称:{Name}" , categoryDTO.Id, categoryDTO.Name); Category category = new Category(); PropertyUtil.CopyProperties(categoryDTO, category); category.UpdateUser = currentUserId.Value; category.UpdateTime = DateTime.Now; await _categoryMapper.Update(category); _logger.LogInformation("分类信息更新成功,ID:{Id}" , categoryDTO.Id); } } }
3、CategoryMapper ProgramBackEnd\SkyServer\mapper\ICategoryMapper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 using ProgramBackEnd.SkyPojo.dto;using ProgramBackEnd.SkyPojo.entity;namespace ProgramBackEnd.SkyServer.mapper { public interface ICategoryMapper { Task Insert (Category category ) ; Task Update (Category category ) ; Task DeleteById (long id ) ; Task<(int total, List<Category> categories)> PageQuery(CategoryPageQueryDTO categoryPageQueryDTO); Task<List<Category>> GetCategoriesByType(int type); } }
ProgramBackEnd\SkyServer\mapper\Impl\CategoryMapperImpl.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 using Microsoft.EntityFrameworkCore;using ProgramBackEnd.SkyPojo.dto;using ProgramBackEnd.SkyPojo.entity;using ProgramBackEnd.SkyServer.config;namespace ProgramBackEnd.SkyServer.mapper.Impl { public class CategoryMapperImpl : ICategoryMapper { private readonly SkyDbContext _skyDbContext; public CategoryMapperImpl (SkyDbContext skyDbContext ) { _skyDbContext = skyDbContext ?? throw new ArgumentNullException(nameof (skyDbContext), "数据库上下文不能为空" ); } public async Task DeleteById (long id ) { if (id <= 0 ) { throw new ArgumentException("分类ID必须大于0" , nameof (id)); } var category = await _skyDbContext.Categories.FindAsync(id); if (category != null ) { _skyDbContext.Categories.Remove(category); await _skyDbContext.SaveChangesAsync(); } } public async Task<List<Category>> GetCategoriesByType(int type) { IQueryable<Category> query = _skyDbContext.Categories; query = query.Where(c => c.Type == type); return await query .OrderBy(c => c.Sort) .ThenBy(c => c.CreateTime) .ToListAsync(); } public async Task Insert (Category category ) { if (category == null ) { throw new ArgumentNullException(nameof (category), "分类对象不能为空" ); } await _skyDbContext.Categories.AddAsync(category); await _skyDbContext.SaveChangesAsync(); } public async Task<(int total, List<Category> categories)> PageQuery(CategoryPageQueryDTO categoryPageQueryDTO) { if (categoryPageQueryDTO == null ) { throw new ArgumentNullException(nameof (categoryPageQueryDTO), "查询参数不能为空" ); } int pageNumber = Math.Max(1 , categoryPageQueryDTO.Page); int pageSize = Math.Max(1 , categoryPageQueryDTO.PageSize); IQueryable<Category> query = _skyDbContext.Categories; if (!string .IsNullOrWhiteSpace(categoryPageQueryDTO.Name)) { string name = categoryPageQueryDTO.Name.Trim(); query = query.Where(c => c.Name != null && c.Name.Contains(name)); } if (categoryPageQueryDTO.Type.HasValue) { int type = categoryPageQueryDTO.Type.Value; query = query.Where(c => c.Type == type); } int total = await query.CountAsync(); List<Category> categories = await query .OrderBy(c => c.Sort) .ThenByDescending(c => c.CreateTime) .ThenBy(c => c.Id) .Skip((pageNumber - 1 ) * pageSize) .Take(pageSize) .ToListAsync(); return (total, categories); } public async Task Update (Category category ) { if (category == null ) { throw new ArgumentNullException(nameof (category), "分类对象不能为空" ); } if (category.Id <= 0 ) { throw new ArgumentException("分类ID无效" , nameof (category)); } var existingCategory = await _skyDbContext.Categories.FirstOrDefaultAsync(c => c.Id == category.Id) ?? throw new InvalidOperationException($"未找到ID为 {category.Id} 的分类记录" ); if (!string .IsNullOrEmpty(category.Name)) existingCategory.Name = category.Name; if (category.Type.HasValue) existingCategory.Type = category.Type; if (category.Sort.HasValue) existingCategory.Sort = category.Sort; if (category.Status.HasValue) existingCategory.Status = category.Status; if (category.UpdateTime != default ) existingCategory.UpdateTime = category.UpdateTime; if (category.UpdateUser > 0 ) existingCategory.UpdateUser = category.UpdateUser; await _skyDbContext.SaveChangesAsync(); } } }
4、结果展示 1、新增分类
2、分类分页查询
3、删除分类
4、更新分类信息
5、启用或禁用分类
6、根据类型查询分类列表