一、创建项目
1. 表示层 解决方案名:ZhouYu.Market 、ZhouYu.Market.Web
2. 业务层 ZhouYu.Market.Service
3. 数据访问层 ZhouYu.Market.Repository
4. 实体层 ZhouYu.Market.Model
5. 公共层 ZhouYu.Market.Infrastructure
6. 页面实体层---用于放Success/date ZhouYu.Market.ViewModel
7. 组件层----服务 ZhouYu.Market.Components
8. 第三方--短信
9. WebApi
注意:
1. 除表示层创建为Web项目、其他层皆为.NETCore类库
2. 框架搭好之后每个层添加所用到的引用
二、实体层操作
2.1 在实体层添加AdminInfo管理员类(vs版本2.1直接添加、3.0版本用命令执行)
/// <summary> /// 管理员信息表 /// </summary> public class AdminInfo { /// <summary> /// 管理员Id /// </summary> [Key] public int AdminId { get; set; } /// <summary> /// 真实姓名 /// </summary> [MaxLength(50)] public string RealName { get; set; } /// <summary> /// 登录名 /// </summary> public string LoginName { get; set; } /// <summary> /// 登录密码 /// </summary> public string LoginPwd { get; set; } /// <summary> /// 性别 /// </summary> public short Sex { get; set; } /// <summary> /// 手机号 /// </summary> public Int64 Telphone { get; set; } /// <summary> /// 邮箱 /// </summary> public string Email { get; set; } /// <summary> /// 角色Id /// </summary> public int RoleId { get; set; } /// <summary> /// 备注 /// </summary> public string Remark { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime CreateTime { get; set; } /// <summary> /// 最后一次登录时间 /// </summary> public DateTime LastLoginTime { get; set; } /// <summary> /// 登录时间 /// </summary> public DateTime LoginTime { get; set; } /// <summary> /// 修改时间 /// </summary> public DateTime UpdateTime { get; set; } /// <summary> /// QQ /// </summary> public string QQ { get; set; } /// <summary> /// 状态1:启用 0:禁用 /// </summary> public short Status { get; set; } }
2.2 打开Nuget管理窗口
2.3 在实体层安装Nuget包
Install-Package Microsoft.EntityFrameworkCore.SqlServer -version 2.1.1 Install-Package Microsoft.EntityFrameworkCore.Tools -version 2.1.1 Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
2.4 创建一个MarketContext类
public class MarketContext: DbContext //管理上下文类---设置连接字符串 { public DbSet<AdminInfo> AdminInfo { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder dbContextOptionsBuilder) { dbContextOptionsBuilder.UseSqlServer("server=localhost;database=Market;uid=sa;pwd=sa"); } }
2.5 数据迁移
Add-Migration build125、Update-Database
三、数据访问层操作
注意:(添加Nuget包System.Linq.Dynamic.Core)
3.1 创建IRepository接口
/// <summary> /// 定义泛型仓储接口 /// </summary> /// <typeparam name="TEntity">实体类型</typeparam> public interface IRepository<T> where T : class { #region 同步 /// <summary> /// 判断记录是否存在 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> bool IsExist(Expression<Func<T, bool>> predicate); /// <summary> /// 新增实体 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> bool Add(T entity, bool autoSave = true); /// <summary> /// 批量添加 /// </summary> /// <param name="entities">实体列表</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> bool AddRange(IEnumerable<T> entities, bool autoSave = true); /// <summary> /// 更新实体 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> bool Update(T entity, bool autoSave = true); /// <summary> /// 更新部分属性 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <param name="updatedProperties">要更新的字段</param> /// <returns></returns> bool Update(T entity, bool autoSave = true, params Expression<Func<T, object>>[] updatedProperties); /// <summary> /// 更新实体部分属性,泛型方法 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <param name="updatedProperties">要更新的字段</param> /// <returns></returns> bool Update<Entity>(Entity entity, bool autoSave = true, params Expression<Func<Entity, object>>[] updatedProperties) where Entity : class; /// <summary> /// 批量更新实体 /// </summary> /// <param name="entities">实体列表</param> /// <param name="autoSave">是否立即执行保存</param> bool UpdateRange(IEnumerable<T> entities, bool autoSave = true); /// <summary> /// 删除实体 /// </summary> /// <param name="entity">要删除的实体</param> /// <param name="autoSave">是否立即执行保存</param> bool Delete(T entity, bool autoSave = true); /// <summary> /// 批量删除 /// </summary> /// <param name="T">对象集合</param> /// <returns></returns> bool Delete(IEnumerable<T> entities); /// <summary> /// 批量删除 /// </summary> /// <param name="T">对象集合</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> bool Delete(IEnumerable<T> entities, bool autoSave = true); /// <summary> /// 获取实体集合 /// </summary> /// <returns></returns> IQueryable<T> GetList(); /// <summary> /// 根据lambda表达式条件获取实体集合 /// </summary> /// <param name="top">前几条</param> /// <param name="predicate">查询条件</param> /// <param name="ordering">排序</param> /// <param name="args">条件参数</param> /// <returns></returns> IQueryable<T> GetList(int top, string predicate, string ordering, params object[] args); /// <summary> /// 根据lambda表达式条件获取实体集合 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> IQueryable<T> GetList(Expression<Func<T, bool>> predicat); /// <summary> /// 根据lambda表达式条件获取单个实体 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> T GetModel(Expression<Func<T, bool>> predicate); /// <summary> /// 分页查询 /// </summary> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">页大小</param> /// <param name="predicate">条件</param> /// <param name="ordering">排序</param> /// <param name="args">条件参数</param> /// <returns></returns> IQueryable<T> GetPagedList(int pageIndex, int pageSize, string predicate, string ordering, params object[] args); /// <summary> /// 获取记录总数 /// </summary> /// <param name="predicate">查询条件</param> /// <param name="args">条件参数</param> /// <returns></returns> int GetRecordCount(string predicate, params object[] args); /// <summary> /// 保存 /// </summary> int Save(); #endregion }
3.2 创建RepositoryBase类
/// <summary> /// 仓储基类 /// </summary> /// <typeparam name="T">实体类型</typeparam> public abstract class RepositoryBase<T> : IRepository<T> where T : class { //定义数据访问上下文对象 protected readonly SyDbContext _dbContext; /// <summary> /// 通过构造函数注入得到数据上下文对象实例 /// </summary> /// <param name="dbContext"></param> public RepositoryBase(SyDbContext dbContext) { _dbContext = dbContext; } #region 同步 /// <summary> /// 判断记录是否存在 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> public bool IsExist(Expression<Func<T, bool>> predicate) { return _dbContext.Set<T>().Any(predicate); } /// <summary> /// 新增实体 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> public bool Add(T entity, bool autoSave = true) { int row = 0; _dbContext.Set<T>().Add(entity); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 批量添加 /// </summary> /// <param name="entities">实体列表</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> public bool AddRange(IEnumerable<T> entities, bool autoSave = true) { int row = 0; _dbContext.Set<T>().AddRange(entities); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 更新实体 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> public bool Update(T entity, bool autoSave = true) { int row = 0; _dbContext.Update(entity); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 更新实体部分属性 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <param name="updatedProperties">要更新的字段</param> /// <returns></returns> public bool Update(T entity, bool autoSave = true, params Expression<Func<T, object>>[] updatedProperties) { int row = 0; //告诉EF Core开始跟踪实体的更改, //因为调用DbContext.Attach方法后,EF Core会将实体的State值 //更改回EntityState.Unchanged, _dbContext.Attach(entity); if (updatedProperties.Any()) { foreach (var property in updatedProperties) { //告诉EF Core实体的属性已经更改。将属性的IsModified设置为true后, //也会将实体的State值更改为EntityState.Modified, //这样就保证了下面SaveChanges的时候会将实体的属性值Update到数据库中。 _dbContext.Entry(entity).Property(property).IsModified = true; } } if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 更新实体部分属性,泛型方法 /// </summary> /// <param name="entity">实体</param> /// <param name="autoSave">是否立即执行保存</param> /// <param name="updatedProperties">要更新的字段</param> /// <returns></returns> public bool Update<Entity>(Entity entity, bool autoSave = true, params Expression<Func<Entity, object>>[] updatedProperties) where Entity : class { int row = 0; //告诉EF Core开始跟踪实体的更改, //因为调用DbContext.Attach方法后,EF Core会将实体的State值 //更改回EntityState.Unchanged, _dbContext.Attach(entity); if (updatedProperties.Any()) { foreach (var property in updatedProperties) { //告诉EF Core实体的属性已经更改。将属性的IsModified设置为true后, //也会将实体的State值更改为EntityState.Modified, //这样就保证了下面SaveChanges的时候会将实体的属性值Update到数据库中。 _dbContext.Entry(entity).Property(property).IsModified = true; } } if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 批量更新实体 /// </summary> /// <param name="entities">实体列表</param> /// <param name="autoSave">是否立即执行保存</param> public bool UpdateRange(IEnumerable<T> entities, bool autoSave = true) { int row = 0; _dbContext.UpdateRange(entities); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 根据lambda表达式条件获取单个实体 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> public T GetModel(Expression<Func<T, bool>> predicate) { return _dbContext.Set<T>().FirstOrDefault(predicate); } /// <summary> /// 删除实体 /// </summary> /// <param name="entity">要删除的实体</param> /// <param name="autoSave">是否立即执行保存</param> public bool Delete(T entity, bool autoSave = true) { int row = 0; _dbContext.Set<T>().Remove(entity); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 批量删除 /// </summary> /// <param name="T">对象集合</param> /// <returns></returns> public bool Delete(IEnumerable<T> entities) { _dbContext.Set<T>().RemoveRange(entities); int row = _dbContext.SaveChanges(); return (row > 0); } /// <summary> /// 批量删除 /// </summary> /// <param name="T">对象集合</param> /// <param name="autoSave">是否立即执行保存</param> /// <returns></returns> public bool Delete(IEnumerable<T> entities, bool autoSave = true) { int row = 0; _dbContext.Set<T>().RemoveRange(entities); if (autoSave) row = Save(); return (row > 0); } /// <summary> /// 获取实体集合 /// </summary> /// <returns></returns> public virtual IQueryable<T> GetList() { return _dbContext.Set<T>().AsQueryable(); } /// <summary> /// 根据lambda表达式条件获取单个实体 /// </summary> /// <param name="predicate">lambda表达式条件</param> /// <returns></returns> public virtual IQueryable<T> GetList(Expression<Func<T, bool>> predicate) { return _dbContext.Set<T>().Where(predicate); } /// <summary> /// 根据lambda表达式条件获取实体集合 /// </summary> /// <param name="top">前几条</param> /// <param name="predicate">查询条件</param> /// <param name="ordering">排序</param> /// <param name="args">条件参数</param> /// <returns></returns> public virtual IQueryable<T> GetList(int top, string predicate, string ordering, params object[] args) { var result = _dbContext.Set<T>().AsQueryable(); if (!string.IsNullOrWhiteSpace(predicate)) result = result.Where(predicate, args); if (!string.IsNullOrWhiteSpace(ordering)) result = result.OrderBy(ordering); if (top > 0) { result = result.Take(top); } return result; } /// <summary> /// 分页查询,返回实体对象 /// </summary> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">页大小</param> /// <param name="predicate">条件</param> /// <param name="ordering">排序</param> /// <param name="args">条件参数</param> /// <returns></returns> public virtual IQueryable<T> GetPagedList(int pageIndex, int pageSize, string predicate, string ordering, params object[] args) { var result = (from p in _dbContext.Set<T>() select p).AsQueryable(); if (!string.IsNullOrWhiteSpace(predicate)) result = result.Where(predicate, args); if (!string.IsNullOrWhiteSpace(ordering)) result = result.OrderBy(ordering); return result.Skip((pageIndex - 1) * pageSize).Take(pageSize); } /// <summary> /// 获取记录总数 /// </summary> /// <param name="predicate">查询条件</param> /// <param name="args">条件参数</param> /// <returns></returns> public virtual int GetRecordCount(string predicate, params object[] args) { if (string.IsNullOrWhiteSpace(predicate)) { return _dbContext.Set<T>().Count(); } else { return _dbContext.Set<T>().Where(predicate, args).Count(); } } /// <summary> /// 事务性保存 /// </summary> public int Save() { int result = _dbContext.SaveChanges(); return result; } #endregion }
3.3 创建SyDbContext管理上下文类
public class SyDbContext:DbContext //管理上下文类 { public DbSet<AdminInfo> AdminInfos { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="options"></param> public SyDbContext(DbContextOptions<SyDbContext> options) : base(options) { } public virtual DbSet<AdminInfo> AdminInfo { get; set; } }
注意:此时删掉实体层中MarketContext类与Migrations文件夹、同时在表示层中appsettings.json文件添加配置连接字符串
"ConnectionStrings": { "ConnectionString": "server=localhost;database=Market;uid=sa;pwd=sa" }
3.4 在表示层Program类中添加读取配置文件的代码
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) { //读取配置文件 var configuration = new ConfigurationBuilder() .SetBasePath(Environment.CurrentDirectory) .AddJsonFile("appsettings.json")//读取配置文件,获取启动的端口号 .Build(); return WebHost.CreateDefaultBuilder(args) .UseConfiguration(configuration) .UseStartup<Startup>(); } //=> //WebHost.CreateDefaultBuilder(args) // .UseStartup<Startup>(); }
3.5 在表示层Startup类ConfigureServices方法中添加代码
//数据库上下文注入 使用DbContext池,提高性能 services.AddDbContextPool<SyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ConnectionString")));
四、组件层操作
注意:(添加Nuget包Microsoft.Extensions.DependencyInjection)
4.1 在组件层中新建Extensions文件夹其中添加DataServiceExtension类
public static class DataServiceExtension { /// <summary> /// 注入数据 /// </summary> /// <param name="services"></param> public static IServiceCollection AddDataService(this IServiceCollection services) { #region 范围依赖注入 services.AddScoped<IAdminInfoService, AdminInfoService>(); #endregion return services; } }
4.2 在表示层Startup类ConfigureServices方法中添加数据服务注入代码
//数据服务注入 services.AddDataService();
五、公共层操作
5.1 在公共层新建Encrytp文件夹其中添加MD5Encrypt类
public class MD5Encrypt { /// <summary> /// MD5加密 /// </summary> /// <param name="source"></param> /// <returns></returns> public static string Encrypt(string source) { if (string.IsNullOrEmpty(source)) return string.Empty; HashAlgorithm provider = CryptoConfig.CreateFromName("MD5") as HashAlgorithm; byte[] bytes = Encoding.UTF8.GetBytes(source);//这里需要区别编码的 byte[] hashValue = provider.ComputeHash(bytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 16; i++) { sb.Append(hashValue[i].ToString("x2")); } return sb.ToString(); } }
5.2 添加一个EnumExtension类
/// <summary> /// 枚举扩展属性 /// </summary> public static class EnumExtension { private static Dictionary<string, Dictionary<string, string>> enumCache; private static Dictionary<string, Dictionary<string, string>> EnumCache { get { if (enumCache == null) { enumCache = new Dictionary<string, Dictionary<string, string>>(); } return enumCache; } set { enumCache = value; } } /// <summary> /// 获得枚举提示文本 /// </summary> /// <param name="en"></param> /// <returns></returns> public static string GetEnumText(this Enum en) { string enString = string.Empty; if (null == en) return enString; var type = en.GetType(); enString = en.ToString(); if (!EnumCache.ContainsKey(type.FullName)) { var fields = type.GetFields(); Dictionary<string, string> temp = new Dictionary<string, string>(); foreach (var item in fields) { var attrs = item.GetCustomAttributes(typeof(TextAttribute), false); if (attrs.Length == 1) { var v = ((TextAttribute)attrs[0]).Value; temp.Add(item.Name, v); } } EnumCache.Add(type.FullName, temp); } if (EnumCache[type.FullName].ContainsKey(enString)) { return EnumCache[type.FullName][enString]; } return enString; } } public class TextAttribute : Attribute { public TextAttribute(string value) { Value = value; } public string Value { get; set; } }
六、业务层操作
6.1 在业务层新建IService文件夹其中添加IAdminInfoService接口
public interface IAdminInfoService { //验证登录 ResponseResult ValidateLogin(string userName, string userPwd); }
6.2 在业务层新建Service文件夹其中添加AdminInfoService类
public class AdminInfoService : RepositoryBase<AdminInfo>, IAdminInfoService { /// <summary> /// 构造函数 /// </summary> /// <param name="syDbContext"></param> public AdminInfoService(SyDbContext syDbContext) : base(syDbContext) { } /// <summary> /// 验证登录 /// </summary> /// <param name="userName"></param> /// <param name="userPwd"></param> /// <returns></returns> public ResponseResult ValidateLogin(string userName, string userPwd) { ResponseResult responseResult = new ResponseResult(); //MD5加密 var md5 = MD5Encrypt.Encrypt(userPwd); //查询 var model = GetModel(a => a.LoginName == userName && a.LoginPwd == md5); if (model != null) { responseResult.success = true; responseResult.data = model; } else { responseResult.success = false; responseResult.msg = "账号或密码错误!"; } return responseResult; } }
七、页面实体层操作
7.1 在页面实体层添加一个ResponseEnum类
public enum ResponseEnum { /// <summary> /// 请求(或处理)成功 /// </summary> [Text("请求(或处理)成功")] Status = 200, //请求(或处理)成功 /// <summary> /// 内部请求出错 /// </summary> [Text("内部请求出错")] Error = 500, //内部请求出错 /// <summary> /// 未授权标识 /// </summary> [Text("未授权标识")] Unauthorized = 401,//未授权标识 /// <summary> /// 请求参数不完整或不正确 /// </summary> [Text("请求参数不完整或不正确")] ParameterError = 400,//请求参数不完整或不正确 /// <summary> /// 请求TOKEN失效 /// </summary> [Text("请求TOKEN失效")] TokenInvalid = 403,//请求TOKEN失效 /// <summary> /// HTTP请求类型不合法 /// </summary> [Text("HTTP请求类型不合法")] HttpMehtodError = 405,//HTTP请求类型不合法 /// <summary> /// HTTP请求不合法,请求参数可能被篡改 /// </summary> [Text("HTTP请求不合法,请求参数可能被篡改")] HttpRequestError = 406,//HTTP请求不合法 /// <summary> /// 该URL已经失效 /// </summary> [Text("该URL已经失效")] URLExpireError = 407,//HTTP请求不合法 }
7.2 在页面实体层添加一个ResponseResult类
/// <summary> /// 请求返回统一格式 /// </summary> public class ResponseResult { /// <summary> /// 构造函数 /// </summary> public ResponseResult() { } /// <summary> /// 构造函数 /// </summary> /// <param name="success">是否成功</param> /// <param name="code">状态码</param> /// <param name="list">数据</param> /// <param name="recordCount">总记录数</param> public ResponseResult(bool success, string msg, int code, dynamic list, int recordCount) { this.success = success; this.msg = msg; this.code = code; this.data = list; this.count = recordCount; } /// <summary> /// 构造函数,成功返回列表 /// </summary> /// <param name="list">数据</param> /// <param name="recordCount">总记录数</param> public ResponseResult(dynamic list, int recordCount) { this.success = true; this.data = list; this.count = recordCount; } /// <summary> /// 构造函数,操作是否成功 /// </summary> /// <param name="list">数据</param> /// <param name="code">状态码</param> /// <param name="recordCount">总记录数</param> public ResponseResult(bool success, int code, string msg) { this.success = success; this.code = code; this.msg = msg; } /// <summary> /// 构造函数,操作是否成功 /// </summary> /// <param name="list">数据</param> /// <param name="recordCount">总记录数</param> public ResponseResult(bool success, string msg) { this.success = success; if (success) { this.code = 200; } else { this.code = 500; } this.msg = msg; } /// <summary> /// 是否成功 /// </summary> public bool success { get; set; } = true; /// <summary> /// 状态码 /// </summary> public int code { set; get; } = 0; /// <summary> /// 总记录数 /// </summary> public int count { set; get; } = 0; /// <summary> /// 数据 /// </summary> public dynamic data { set; get; } /// <summary> /// 返回信息 /// </summary> public string msg { set; get; } /// <summary> /// 序列化为字符串 /// </summary> /// <returns></returns> public override string ToString() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } }
7.3 在表示层Startup类ConfigureServices方法中添加全局配置Json序列化处理代码
// 注册MVC到Container services.AddMvc() //全局配置Json序列化处理 .AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; options.SerializerSettings.ContractResolver = new DefaultContractResolver(); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
八、表示层操作
8.1 在wwwroot中的文件夹加入所用到的js、css、images、layui文件夹
8.2 在Controllers文件夹中添加一个AccountController控制器
public class AccountController : Controller { //接口注入 public IAdminInfoService _adminInfoService; public AccountController(IAdminInfoService adminInfoService) { _adminInfoService = adminInfoService; } /// <summary> /// 登录页 /// </summary> /// <returns></returns> public IActionResult Login() { return View(); } /// <summary> /// 验证登录 /// </summary> /// <returns></returns> public IActionResult ValidateLogin(string userName, string userPwd) { //调用验证登录方法 var result = _adminInfoService.ValidateLogin(userName, userPwd); return Json(result); } /// <summary> /// 退出登录 /// </summary> /// <returns></returns> public IActionResult LoginOut() { ViewData["Message"] = "Your contact page."; return View(); } }
8.3 在View文件夹中新建Account文件夹其次再添加一个Login.cshtml页面
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>系统登录 - 超市账单管理系统</title> <link rel="stylesheet" href="~/css/style.css" /> <link rel="stylesheet" href="~/lib/layui-v2.5.4/layui/css/modules/layer/default/layer.css" /> <script type="text/javascript" src="~/lib/jquery/dist/jquery.min.js"></script> <script type="text/javascript" src="~/lib/layui-v2.5.4/layui/lay/modules/layer.js"></script> </head> <body class="login_bg"> <section class="loginBox"> <header class="loginHeader"> <h1>超市账单管理系统</h1> </header> <section class="loginCont"> <form class="loginForm" action="welcome.html"> <div class="inputbox"> <label for="user">用户名:</label> <input id="user" type="text" name="username" placeholder="请输入用户名" required /> </div> <div class="inputbox"> <label for="mima">密码:</label> <input id="mima" type="password" name="password" placeholder="请输入密码" required /> </div> <div class="subBtn"> <input type="submit" value="登录" /> <input type="reset" value="重置" /> </div> </form> </section> </section> </body> </html>
8.4 在_ViewStart.cshtml中添加取消网站模板的代码
@{ Layout =null; }
本文仅用于转载,收藏
————————————————
版权声明:本文为CSDN博主「黑人问号?」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45408840/article/details/102774892