diff --git a/Tools/RegisterService.bat b/Tools/RegisterService.bat
new file mode 100644
index 0000000..524564e
--- /dev/null
+++ b/Tools/RegisterService.bat
@@ -0,0 +1,2 @@
+sc create StaffManagement start= auto binPath= "C:\Services\FAuth\FAuth.exe"
+pause
\ No newline at end of file
diff --git a/Tools/StartService.bat b/Tools/StartService.bat
new file mode 100644
index 0000000..93fc6aa
--- /dev/null
+++ b/Tools/StartService.bat
@@ -0,0 +1,2 @@
+sc start StaffManagement
+pause
\ No newline at end of file
diff --git a/Tools/StopService.bat b/Tools/StopService.bat
new file mode 100644
index 0000000..4f4a1e2
--- /dev/null
+++ b/Tools/StopService.bat
@@ -0,0 +1,2 @@
+sc stop StaffManagement
+pause
\ No newline at end of file
diff --git a/Tools/UnRegisterService.bat b/Tools/UnRegisterService.bat
new file mode 100644
index 0000000..2cb11e9
--- /dev/null
+++ b/Tools/UnRegisterService.bat
@@ -0,0 +1,2 @@
+sc delete StaffManagement
+pause
\ No newline at end of file
diff --git a/src/StaffManagement/Controllers/ApiControllerBase.cs b/src/StaffManagement/Controllers/ApiControllerBase.cs
new file mode 100644
index 0000000..9e49e61
--- /dev/null
+++ b/src/StaffManagement/Controllers/ApiControllerBase.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Text.Encodings.Web;
+using System.Text.Json;
+using System.Text.Unicode;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using StaffManagement.Database;
+using StaffManagement.Extensions;
+
+namespace StaffManagement.Controllers
+{
+ ///
+ /// api控制器基类
+ ///
+ [Area("api")]
+ //[ApiController]
+ [Route("api/[Controller]/[Action]")]
+ [ServiceFilter(typeof(ApiExceptionFilterAttribute))]
+ [ProducesResponseType(typeof(ApiErrorResult),500)]
+ [ProducesResponseType(typeof(ApiErrorResult),400)]
+ public abstract class ApiControllerBase:ControllerBase
+ {
+ public ApiControllerBase(ILogger logger,IServiceProvider service) : base(logger,service) {
+ }
+
+ ///
+ /// 记录保存请求和响应日志
+ ///
+ /// 请求信息类型
+ /// 响应信息类型
+ /// 请求数据
+ /// 响应数据
+ protected void SaveLogger(TRequest data,TResponse result) {
+ var requestStr = this.JsonSerialize(data);
+ var responseStr = this.JsonSerialize(result);
+ var logmsg = $"{this.Prefix}\n请求消息:{requestStr}\n响应消息{responseStr}";
+ this.Logger.LogInformation(logmsg);
+ }
+ }
+}
diff --git a/src/StaffManagement/Controllers/ControllerBase.cs b/src/StaffManagement/Controllers/ControllerBase.cs
new file mode 100644
index 0000000..baf0896
--- /dev/null
+++ b/src/StaffManagement/Controllers/ControllerBase.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Text.Encodings.Web;
+using System.Text.Json;
+using System.Text.Unicode;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using StaffManagement.Database;
+using StaffManagement.Extensions;
+
+namespace StaffManagement.Controllers
+{
+ ///
+ /// 控制器类基类
+ ///
+ //[Route("[Controller]/[Action]")]
+ public abstract class ControllerBase:Controller
+ {
+ ///
+ /// 日志记录服务
+ ///
+ public ILogger Logger { get; set; }
+ ///
+ /// 服务集合
+ ///
+ public IServiceProvider Services { get; set; }
+ ///
+ /// 数据库
+ ///
+ public SMDbContext Db { get; set; }
+ ///
+ /// 缓冲帮助器
+ ///
+ public CacheHelper Cache { get; private set; }
+ ///
+ /// 获取请求的方法前缀
+ ///
+ protected string Prefix {
+ get {
+ var con = this.RouteData.Values["controller"];
+ var ac = this.RouteData.Values["action"];
+ return $":{con}:{ac}";
+ }
+ }
+
+ ///
+ /// 通过日志组件和服务集合生成控制器
+ ///
+ /// 控制器日志组件
+ /// 服务集合
+ public ControllerBase(ILogger logger,IServiceProvider service) {
+ this.Logger = logger;
+ this.Services = service;
+ this.Db = service.GetService();
+ this.Cache = service.GetService();
+ }
+
+ ///
+ /// 从对象序列化字符串
+ ///
+ /// 对象类型
+ /// 要序列化的对象
+ /// 字符串
+ protected string JsonSerialize(T obj) {
+ return JsonSerializer.Serialize(obj,new JsonSerializerOptions {
+ Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
+ });
+ }
+ ///
+ /// 从字符串反序列化对象
+ ///
+ /// 对象的类型
+ /// json字符串
+ /// 对象实例
+ protected T JsonDeserialize(string json) {
+ return JsonSerializer.Deserialize(json);
+ }
+ }
+}
diff --git a/src/StaffManagement/Controllers/HomeController.cs b/src/StaffManagement/Controllers/Web/HomeController.cs
similarity index 71%
rename from src/StaffManagement/Controllers/HomeController.cs
rename to src/StaffManagement/Controllers/Web/HomeController.cs
index 030adae..6521f31 100644
--- a/src/StaffManagement/Controllers/HomeController.cs
+++ b/src/StaffManagement/Controllers/Web/HomeController.cs
@@ -7,14 +7,11 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using StaffManagement.Models;
-namespace StaffManagement.Controllers
+namespace StaffManagement.Controllers.Web
{
- public class HomeController:Controller
+ public class HomeController:WebControllerBase
{
- private readonly ILogger _logger;
-
- public HomeController(ILogger logger) {
- _logger = logger;
+ public HomeController(ILogger logger,IServiceProvider service) : base(logger,service) {
}
public IActionResult Index() {
diff --git a/src/StaffManagement/Controllers/WebControllerBase.cs b/src/StaffManagement/Controllers/WebControllerBase.cs
new file mode 100644
index 0000000..963ae3b
--- /dev/null
+++ b/src/StaffManagement/Controllers/WebControllerBase.cs
@@ -0,0 +1,15 @@
+using System;
+using Microsoft.Extensions.Logging;
+
+namespace StaffManagement.Controllers
+{
+ ///
+ /// 控制器类基类
+ ///
+ //[Route("[Controller]/[Action]")]
+ public abstract class WebControllerBase:ControllerBase
+ {
+ public WebControllerBase(ILogger logger,IServiceProvider service) : base(logger,service) {
+ }
+ }
+}
diff --git a/src/StaffManagement/Database/SMDbContext.cs b/src/StaffManagement/Database/SMDbContext.cs
new file mode 100644
index 0000000..77386eb
--- /dev/null
+++ b/src/StaffManagement/Database/SMDbContext.cs
@@ -0,0 +1,16 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace StaffManagement.Database
+{
+ ///
+ /// 员工管理数据上下文
+ ///
+ public class SMDbContext:DbContext
+ {
+ ///
+ /// 通过配置的数据库选项获取数据库上下文
+ ///
+ ///
+ public SMDbContext(DbContextOptions options) : base(options) { }
+ }
+}
diff --git a/src/StaffManagement/Extensions/ApiErrorResult.cs b/src/StaffManagement/Extensions/ApiErrorResult.cs
new file mode 100644
index 0000000..5b219c2
--- /dev/null
+++ b/src/StaffManagement/Extensions/ApiErrorResult.cs
@@ -0,0 +1,17 @@
+namespace StaffManagement.Extensions
+{
+ ///
+ /// api返回异常
+ ///
+ public class ApiErrorResult
+ {
+ ///
+ /// 异常信息
+ ///
+ public string Message { get; set; }
+ ///
+ /// 异常编号
+ ///
+ public string Id { get; set; }
+ }
+}
diff --git a/src/StaffManagement/Extensions/ApiException.cs b/src/StaffManagement/Extensions/ApiException.cs
new file mode 100644
index 0000000..6bda5a0
--- /dev/null
+++ b/src/StaffManagement/Extensions/ApiException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace StaffManagement.Extensions
+{
+ ///
+ /// 表示请求错误,服务器无法处理
+ ///
+ public class ApiException:Exception
+ {
+ public object Param { get; set; }
+
+ ///
+ /// 通过提供异常信息,返回api错误异常
+ ///
+ /// 错误消息
+ public ApiException(string msg) : base(msg) {
+ this.Param = null;
+ }
+
+ ///
+ /// 通过提供异常信息,返回api错误异常
+ ///
+ /// 错误消息
+ /// 请求绑定参数
+ public ApiException(object param,string msg) : base(msg) {
+ this.Param = param;
+ }
+ }
+}
diff --git a/src/StaffManagement/Extensions/ApiExceptionFilterAttribute.cs b/src/StaffManagement/Extensions/ApiExceptionFilterAttribute.cs
new file mode 100644
index 0000000..f4ffe1c
--- /dev/null
+++ b/src/StaffManagement/Extensions/ApiExceptionFilterAttribute.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Text;
+using System.Text.Json;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Extensions.Logging;
+
+namespace StaffManagement.Extensions
+{
+ ///
+ /// Api控制器返回异常
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = true,Inherited = true)]
+ public class ApiExceptionFilterAttribute:ExceptionFilterAttribute
+ {
+ public ILogger Logger { get; set; }
+
+ public ApiExceptionFilterAttribute(ILogger logger) {
+ this.Logger = logger;
+ }
+ public override void OnException(ExceptionContext context) {
+ var id = Guid.NewGuid().ToString("N");
+ int code;
+ var errMsg = new StringBuilder();
+ errMsg.Append($"错误ID:{id}\n");
+ if(context.Exception is ApiException ae) {
+ code = StatusCodes.Status400BadRequest;
+ var rqStr = JsonSerializer.Serialize(ae.Param);
+ errMsg.Append($"请求参数:{rqStr}\n");
+ } else {
+ code = StatusCodes.Status500InternalServerError;
+ }
+ errMsg.Append($"异常信息:{ context.Exception}\n");
+ this.Logger.LogError(errMsg.ToString());
+
+ var result = new ApiErrorResult {
+ Message = context.Exception.Message,
+ Id = id,
+ };
+
+ context.Result = new JsonResult(result) { StatusCode = code };
+ }
+
+ }
+}
diff --git a/src/StaffManagement/Extensions/CacheHelper.cs b/src/StaffManagement/Extensions/CacheHelper.cs
new file mode 100644
index 0000000..7ba3b2b
--- /dev/null
+++ b/src/StaffManagement/Extensions/CacheHelper.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Text;
+using Falcon.Extend;
+using Microsoft.Extensions.Logging;
+
+namespace StaffManagement.Extensions
+{
+ ///
+ /// 缓冲帮助器
+ ///
+ public class CacheHelper
+ {
+ ///
+ /// 基础缓冲
+ ///
+ public ICacheProvider Cache { get; set; }
+ ///
+ /// Json序列化
+ ///
+ public IJsonProvider JsonProvider { get; set; }
+ ///
+ /// 日志记录
+ ///
+ public ILogger Logger { get; set; }
+
+ public CacheHelper(ICacheProvider c,IJsonProvider j,ILogger logger) {
+ this.Cache = c;
+ this.JsonProvider = j;
+ this.Logger = logger;
+ }
+ ///
+ /// 从缓冲中获取数据
+ ///
+ /// 用于生成key的对象类型
+ /// 数据对象类型
+ /// 缓冲方法前缀
+ /// 用于生成key的对象
+ /// 数据对象
+ public T GetT(string prefix,TKey keyObj) where T : class, new() {
+ if(this.Cache == null) {
+ return null;
+ }
+ if(this.JsonProvider == null) {
+ return null;
+ }
+ var key = generateKey(prefix,keyObj);
+ if(string.IsNullOrEmpty(key)) {
+ return null;
+ }
+ var result = this.Cache.GetObj(key);
+ if(result != null) {
+ this.Logger.LogInformation($"Get data cache by [{key}]");
+ }
+ return result;
+ }
+ ///
+ /// 保存缓冲
+ ///
+ /// 用于生成key的对象类型
+ /// 数据对象类型
+ /// 缓冲方法前缀
+ /// 用于生成key的对象
+ /// 数据对象
+ /// 缓冲时间
+ ///
+ public T SetT(string prefix,TKey keyObj,T obj,TimeSpan timeSpan) where T : class {
+ if(this.Cache == null) {
+ return obj;
+ }
+ if(this.JsonProvider == null) {
+ return obj;
+ }
+ var key = generateKey(prefix,keyObj);
+ if(string.IsNullOrEmpty(key)) {
+ return obj;
+ }
+ this.Cache.SetCache(key,obj,timeSpan);
+ this.Logger.LogInformation($"Set data cache by [{key}]");
+ return obj;
+ }
+ ///
+ /// 根据对象生成Key
+ ///
+ /// Key的类型
+ /// 前缀
+ /// Key对象
+ /// 对应的Key字符串
+ private string generateKey(string prefix,TK keyObj) {
+ var key = new StringBuilder();
+ key.Append(prefix);
+ foreach(var p in keyObj.GetType().GetProperties()) {
+ var pn = p.Name;
+ var pv = p.GetValue(keyObj) ?? "nul";
+ key.Append($":{pn}:{pv}");
+ }
+ return key.ToString();
+ }
+ }
+}
diff --git a/src/StaffManagement/Extensions/CookieHelper.cs b/src/StaffManagement/Extensions/CookieHelper.cs
new file mode 100644
index 0000000..a1d20b9
--- /dev/null
+++ b/src/StaffManagement/Extensions/CookieHelper.cs
@@ -0,0 +1,79 @@
+using System;
+using Microsoft.AspNetCore.CookiePolicy;
+using Microsoft.AspNetCore.Http;
+
+namespace StaffManagement.Extensions
+{
+ ///
+ /// cookie帮助类
+ ///
+ public static class CookieHelper
+ {
+ ///
+ /// 设置Cookie值
+ ///
+ /// http上下文
+ /// Cookie的键
+ /// cookie值
+ /// cookie有效期。分钟,无限传null或不传
+ public static void SetCookies(this HttpContext httpContext,string key,string value,int? minutes = null) {
+ SetCookies(httpContext.Response,key,value,minutes);
+ }
+
+ ///
+ /// 设置Cookie值
+ ///
+ /// http响应
+ /// Cookie的键
+ /// cookie值
+ /// cookie有效期。分钟,无限传null或不传
+ public static void SetCookies(this HttpResponse response,string key,string value,int? minutes = null) {
+ if(minutes.HasValue) {
+ response.Cookies.Append(key,value,new CookieOptions {
+ Expires = DateTime.Now.AddMinutes(minutes.Value)
+ });
+ } else {
+ response.Cookies.Append(key,value);
+ }
+ }
+ ///
+ /// 删除cookie
+ ///
+ /// http上下文
+ /// 要删除的键
+ public static void DeleteCookies(this HttpContext httpContext,string key) {
+ DeleteCookies(httpContext.Response,key);
+ }
+
+ ///
+ /// 删除cookie
+ ///
+ /// http响应
+ /// 要删除的键
+ public static void DeleteCookies(this HttpResponse response,string key) {
+ response.Cookies.Delete(key);
+ }
+ ///
+ /// 获取cookie中的值
+ ///
+ /// http上下文
+ /// cookie的键
+ /// 保存的值
+ public static string GetCookiesValue(this HttpContext httpContext,string key) {
+ return GetCookiesValue(httpContext.Request,key);
+ }
+
+ ///
+ /// 获取cookie中的值
+ ///
+ /// http请求
+ /// cookie的键
+ /// 保存的值
+ public static string GetCookiesValue(this HttpRequest request,string key) {
+ if(request.Cookies.TryGetValue(key,out string value)) {
+ return value;
+ }
+ return string.Empty;
+ }
+ }
+}
diff --git a/src/StaffManagement/StaffManagement.csproj b/src/StaffManagement/StaffManagement.csproj
index f44e8dd..3bf5232 100644
--- a/src/StaffManagement/StaffManagement.csproj
+++ b/src/StaffManagement/StaffManagement.csproj
@@ -22,6 +22,12 @@
+
+
+
+
+
+
diff --git a/src/StaffManagement/Startup.cs b/src/StaffManagement/Startup.cs
index 8af2fd3..d984c2c 100644
--- a/src/StaffManagement/Startup.cs
+++ b/src/StaffManagement/Startup.cs
@@ -1,12 +1,18 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.IO;
+using System.Text.Encodings.Web;
+using System.Text.Unicode;
+using Falcon.Extend;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Microsoft.OpenApi.Models;
+using StaffManagement.Database;
+using StaffManagement.Extensions;
namespace StaffManagement
{
@@ -18,9 +24,40 @@ namespace StaffManagement
public IConfiguration Configuration { get; }
- // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
- services.AddControllersWithViews();
+ //עJsonл
+ services.AddMsJsonProvider();
+ //עݿ
+ services.AddDbContext(option => {
+ //option.UseSqlServer(this.Configuration.GetValue("Database:connStr"));
+ option.UseMySql(this.Configuration.GetValue("Database:dbConnStr"));
+ });
+ //עRedis
+ var rop = this.Configuration.GetSection("Redis").Get();
+ services.AddRedis(rop);
+ //עỺ
+ services.AddSingleton();
+ //עMVC
+ services.AddControllersWithViews()
+ .AddJsonOptions(option => {
+ option.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
+ option.JsonSerializerOptions.PropertyNamingPolicy = null;
+ });
+
+ //עSwagger
+ services.AddSwaggerGen(c => {
+ var option = this.Configuration.GetSection("SwaggerDoc");
+ c.SwaggerDoc("V1",new OpenApiInfo {
+ Title = option.GetValue("Title"),
+ Version = option.GetValue("Version"),
+ Description = option.GetValue("Description"),
+ });
+ var basePath = AppContext.BaseDirectory;
+ c.IncludeXmlComments(Path.Combine(basePath,"StaffManagement.xml"),true);
+ c.AddXmlEnumEnable(Path.Combine(basePath,"StaffManagement.xml"));
+ });
+ //עapi
+ services.AddScoped();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -32,6 +69,16 @@ namespace StaffManagement
}
app.UseStaticFiles();
+ app.UseSwagger();
+ app.UseSwaggerUI(c => {
+ c.SwaggerEndpoint("/swagger/V1/swagger.json","ӿĵ");
+ //c.RoutePrefix = "";
+ c.DocumentTitle = "һվʽҽƾӿĵ";
+ c.InjectStylesheet("/css/swagger.css");
+ c.InjectJavascript("/lib/jquery/dist/jquery.min.js");
+ c.InjectJavascript("/js/swagger.js");
+ });
+
app.UseRouting();
app.UseAuthorization();
diff --git a/src/StaffManagement/appsettings.json b/src/StaffManagement/appsettings.json
index 81ff877..d1ad45a 100644
--- a/src/StaffManagement/appsettings.json
+++ b/src/StaffManagement/appsettings.json
@@ -6,5 +6,21 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "Database": {
+ "dbConnStr": "Server=localhost;Port=3306;Database=FAuth;Uid=falcon;Pwd=falcon;"
+ },
+ "Redis": {
+ "InstanceName": "",
+ "Configuration": "127.0.0.1:7001,password=123654"
+ },
+ "SwaggerDoc": {
+ "Title": "ԱAPIӿ",
+ "Version": "1.0",
+ "Description": "ͳһAPIӿƣ鿴ϸӿڹ淶",
+ "Contact": {
+ "Name": "֧(ӣ)",
+ "Url": ""
+ }
+ }
}