目录
创建项目,引入EF框架
声明:该项目用的是3.1版本
新建项目
创建三层,在项目里面再新建三个类库
最终效果:
新创建项目之间的依赖关系如下:
Service层:业务处理层,(里面有接口和实现类)
Model层:模型层(将需要的数据进行封装,给Service层进行数据逻辑处理)
Controller层:控制层(调用Service层封装的方法)
DataDepository层:将数据库的表存储在项目里,
需要先下载EF程序包
需要的三个包效果:
生成数据库Model之前要将此程序设置为启动项目
选项工具打开控制台
将我们的 DataDepository层设置为启动项目
接着在控制台输入这段代码(注意修改自己的用户名和密码以及要连接的数据库名):Scaffold-DbContext "Data Source=.;Initial Catalog=Hospital;User ID=sa;Password=root" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
说明成功 完成展示:
配置DbContext使用依赖注入
什么是依赖注入?这些专业名词解释起来会比较麻烦,介绍起来会比较繁琐,推荐百度去弄清楚逻辑,后面会经常用到依赖注入,不弄清楚可能会对后面的步骤造成影响,建议先去弄清楚概念
appsettings.json,
注意更改自己要连接的数据库和账号和密码
"ConnectionStrings": {
"HospitalConnnStr": "Data Source=.;Initial Catalog=Hospital;User ID=sa;Password=123456"
}
Startup.cs类
//数据库的依赖注入
var constr = Configuration.GetConnectionString("HospitalConnnStr");
services.AddDbContext<HospitalContext>(opt =>
{
opt.UseSqlServer(constr);
});
添加注入后,运行测试看是否有误:
可以运行,就说明没有错误,出现这个也不用担心,正常现象
实现登录
Service层:业务处理层,(里面有接口和实现类)
Model层:模型层(将需要的数据进行封装,给Service层进行数据逻辑处理)
Controller层:控制层(调用Service层封装的方法)
DataDepository层:将数据库的表存储在项目里,
后面的操作大部分都是先Model层(将需要的数据从DataDepository层获取)-->Service层(从Model层获取到需要的值进行逻辑代码编写)-->Controller层(调用Service层方法形成接口)
在Controller层添加UserController控制器,用来实现账号密码登录的前端界面
接着在UserController的index方法添加视图行页面编写样式
添加好视图之后,就要添加Layui的布局,这样我们就可以使用Layui的样式进行前端布局
添加Layout布局同样是在Controller层进行操作
在_Layout.cshtml的页面添加上Layout的css和js样式,官网Layui 开发使用文档 - 入门指南
将这两段放入页面中
- <!-- 引入 layui.css -->
- <link rel="stylesheet" href="//unpkg.com/layui@2.6.8/dist/css/layui.css">
- <!-- 引入 layui.js -->
- <script src="//unpkg.com/layui@2.6.8/dist/layui.js">
效果:
注意:引入JS的时候,注意补全
然后添加前端布局在刚刚创建的index视图里面,创建的视图在View文件夹里面的User包下,User包就是我们所创建的控制台省去了Controller的后缀
添加前端样式
<form class="layui-form" action="">
<div class="layui-form-item">
<label class="layui-form-label">输入框</label>
<div class="layui-input-block">
<input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码框</label>
<div class="layui-input-block">
<input type="password" name="pwd" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<script>
//Demo:提交登录
window.onload = function () {
layui.use('form', function () {
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function (data) {
// layer.msg(JSON.stringify(data.field));
$.post("/user/login2", data.field, function (res) {
if (res == "success") {
layer.msg("恭喜您,登录成功");
//location.href = "/main/index";
} else {
layer.msg("登录失败,请检查用户名和密码是否正确");
}
});
return false;
});
});
}
</script>
5、接口测试:
账号密码验证
刚刚我们只是实现了登录的一个界面,提交之后总是失败,是因为我们还没有实现登录的验证
1、Model层
Model层:模型层(将需要的数据进行封装,这个数据是来自DataDepository数据层,然后给Service层进行数据逻辑处理)
创建一个UserModel类,在登录的时候验证用户和密码是否在数据库里,这里的属性要与DataDepository的Doctor类属性的一样
public class UserModel
{
public string UserName { get; set; }
public string pwd { get; set; }
}
2、Service层
Service层:业务处理层,(里面有接口和实现类)
先创建接口和实现类(IUserService和UserService)
效果:
实现步骤:
注意一个是接口,一个是类
注意:在接口和类都要加上一个public:访问权限修饰符,表示被修饰者有公共访问权限
接口(IUserService):
在IUserService接口创建一个方法
或者手动生成(但是推荐使用快捷键,后面会经常用到)
IUserService效果:
注意: 现在接口声明的方法中有两个参数-->username和pwd,分别代表用户名和密码,这两个参数的名字要和我们在controller层声明的index视图的参数要一样
继承接口类(UserService):
类需要继承接口:冒号“ :”代表继承
而且需要实现接口的方法(这样是为了方便后面的修改,因为接口是可以多个类去继承并实现不同的业务逻辑,这样如果后续需要修改就只用找到我们想要修改的类直接去修改,如果修改接口,那么继承该接口的实现类也要去修改业务逻辑,会增加工作量)
实现接口方法快捷键Alt+回车键,快捷键在后面不多介绍,记住快捷键,有利于开发效率
效果:
此外,我们还需要添加一些属性
接着需要新建一个有参构造器,把我们刚刚声明的属性放在构造器里面
为什么要新建一个构造函数呢?解释起来会比较啰嗦,就不介绍了,目前就只用明白,只要添加了属性,而且要使用该属性就要重新定义一个有参的构造函数,想要更加了解有参和无参构造器,可以百度查查。
效果:
最后需要对方法进行逻辑代码编写:
public Doctor Login2(string username, string pwd, JwtOpt jwtOpt)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(pwd))
{
return null;
}
//FirstOrDefault:如果有数据那么只取第一条,如果没有返回数据那么就返回null
var doctor = _hospitalContext.Doctors.Where(doct => doct.UserName == username
&& doct.Password == pwd).FirstOrDefault();
//如果为null,表示用户不存在,那么就登录失败
return doctor;
}
3、Controller层,Startup类添加依赖注入
Controller层:控制层(调用Service层封装的方法)
先依赖注入:在Controller层的启动类Startup.cs类中配置
创建UserController控制器
Controller层实现Service层方法,形成接口
接口测试:接口不区分答案小写
因为这里我们还没有进行登录,所有验证的时候返回的值是fail
进行登录验证
cookie验证登录
//使用cookie登录
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(option =>
{
option.LoginPath = "/user/login";
option.AccessDeniedPath = "/user/login";
});
效果
2、接着在startup.cs加入中间件,先后顺序不能弄错
//身份验证,用来解析、验证token
app.UseAuthentication();
//授予权限,权限的判断
app.UseAuthorization();
效果
3、在Controller层在我们调用登录方法中加入cookie验证
public async Task<string> Login2(UserModel userModel)
{
var doctor = _userService.Login2(userModel.UserName, userModel.pwd);
if (doctor == null)
{
return "fail";
}
//生成coken
var claims = new[]
{
//Dictionary<string,string>
new Claim(ClaimTypes.Name,doctor.UserName),
new Claim("userid",doctor.DId.ToString()),
new Claim(ClaimTypes.Role,"admin")
};
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme));
//生成cookie
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
return "success";
}
效果
4、最终效果,登录后生成cookie代表成功
JWT验证
1、在Controller层的项目下安装JWT
2、在appsettings.json配置类设置
"JwtOpt": {
"Audience": "https://localhost:44359",
"Issuer": "https://localhost:44359",
"SecurityKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB"
}
3、Model层新建类JwtOpt.cs用以映射返回给前端,前面我们也建立了一个UserModel,但这里新建的作用是将我们从后端获得的数据用前端的方式返回给前端
注意:不能有错,属性不能有错
public string Audience { get; set; }
public string Issuer { get; set; }
public string SecurityKey { get; set; }
然后将JwtOpt.cs添加到我们的Serivice层的IUserService接口中
接口改变了,对应的实现类也要进行更改
与之逻辑相同,Service层的代码发生更改,那么Controller调用Service层的方法也要进行一个修改
4、在controller层的启动类(Startup.cs)配置,每次新建的一个类,而且在使用之前,都要先进行依赖注入,牢记
进行注入:
报红是没有引入,使用快捷键Alt+回车键快速引入
//验证的方式(配置为jwt):JwtBearerDefaults.AuthenticationScheme
//配置怎么去验证token以及谁来验证token
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var jwtOpt = Configuration.GetSection("JwtOpt").Get<JwtOpt>();
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,//是否验证颁发者
ValidateAudience = false,//是否验证客户端
ValidateLifetime = true,//验证token的有效期
ClockSkew = TimeSpan.FromSeconds(10),//验证过期时间有一点偏差
ValidateIssuerSigningKey = true,//验证签名
ValidIssuer = jwtOpt.Issuer, //配置颁发者
ValidAudience = jwtOpt.Audience, //配置客户端
//配置加密的key
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOpt.SecurityKey))
};
});
还要进行一个全局配置,也是在注入的地方Startup类进行添加
services.AddControllersWithViews().AddJsonOptions(options =>
{
//解决中文输出后被编码了,设置支持所有字符集
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
}).AddMvcOptions(opt =>
{
//全局配置必须登录才能访问整个网站的所有接口
opt.Filters.Add(new AuthorizeFilter());
});
然后进行接口测试,看我们是否添加上了jwt的验证
进行测试:
发现我们现在不论是什么接口的页面都无法进行访问,而且还出现了401的接口访问权限,说明我们的接口访问是正确的,只是开启了jwt验证而没有权限进行访问
5、解决jwt权限的认证,
我们只用在Controller层找到对我们的控制器编译器加上一个注解就能解决了401的接口权限问题
[AllowAnonymous]
表示允许访问该方法
效果:
登录跳转页面
跳转大致思路:
先加入一个需要页面-->Controller层编写接口跳转到页面-->最后使用跳转路径到指定页面
需要整入后台框架样板布局,效果如下:
先在公共页面复制粘贴_Layout1.cshtml页面为_Layout2.cshtml,(当然可以自己随意取,但要方便辨认)用于跳转到框架布局,页面内容就是框架的布局
如果想导入自己下载的JS和CSS文件,需要将下载的文件存放到wwwroot文件夹下面,但是推荐直接使用官网路径,因为自己下载的可能会造成一些样式的缺失
接着去官网获取样式布局,网址:Layui 管理界面大框架布局 - 在线演示
对了,添加上布局,别忘了把官网的css和js布局引入进去
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 管理系统大布局 - Layui</title>
@*<link rel="stylesheet" href="./layui/css/layui.css">*@
<link href="https://cdn.staticfile.org/layui/2.7.6/css/layui.css" rel="stylesheet">
</head>
<body>
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black">layout demo</div>
<!-- 头部区域(可配合layui 已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<!-- 移动端显示 -->
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-header-event="menuLeft">
<i class="layui-icon layui-icon-spread-left"></i>
</li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 1</a></li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 2</a></li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 3</a></li>
<li class="layui-nav-item">
<a href="javascript:;">nav groups</a>
<dl class="layui-nav-child">
<dd><a href="">menu 11</a></dd>
<dd><a href="">menu 22</a></dd>
<dd><a href="">menu 33</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="javascript:;">
<img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" class="layui-nav-img">
tester
</a>
<dl class="layui-nav-child">
<dd><a href="">Your Profile</a></dd>
<dd><a href="">Settings</a></dd>
<dd><a href="">Sign out</a></dd>
</dl>
</li>
<li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
<a href="javascript:;">
<i class="layui-icon layui-icon-more-vertical"></i>
</a>
</li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">menu group 1</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">menu 1</a></dd>
<dd><a href="javascript:;">menu 2</a></dd>
<dd><a href="javascript:;">menu 3</a></dd>
<dd><a href="">the links</a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">menu group 2</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">list 1</a></dd>
<dd><a href="javascript:;">list 2</a></dd>
<dd><a href="">超链接</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="javascript:;">click menu item</a></li>
<li class="layui-nav-item"><a href="">the links</a></li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;">内容主体区域。记得修改 layui.css 和 js 的路径</div>
</div>
<div class="layui-footer">
<!-- 底部固定区域 -->
底部固定区域
</div>
</div>
@*<script src="./layui/layui.js"></script>*@
<script src="https://cdn.staticfile.org/layui/2.7.6/layui.js"></script>
<script>
//JS
layui.use(['element', 'layer', 'util'], function () {
var element = layui.element
, layer = layui.layer
, util = layui.util
, $ = layui.$;
//头部事件
util.event('lay-header-event', {
//左侧菜单事件
menuLeft: function (othis) {
layer.msg('展开左侧菜单的操作', { icon: 0 });
}
, menuRight: function () {
layer.open({
type: 1
, content: '<div style="padding: 15px;">处理右侧面板的操作</div>'
, area: ['260px', '100%']
, offset: 'rt' //右上角
, anim: 5
, shadeClose: true
});
}
});
});
</script>
</body>
</html>
为了验证我们是否成功添加上了布局我们还需要在Controller层新建一个控制器命名为MainController,用来我们的后台样式布局首页面,在Main视图里添加一个新的视图文件,同时也用于登录成功之后跳转到我们的后台管理页面
提示:在实现登录里对视图,控制器,接口和类等添加 方面都有比较详细的介绍,到后面就会比较直接快速的建立类以此来避免不必要的重复,如在后面对这些添加类等比较模糊,可以看看实现登录的部分
添加视图效果:
将Main构造器里的index视图数据绑定到前面创造的 _Layout2.cshtml页面下
在视图里加了一个h1标签,是为了验证是否是main里的index视图
别忘了我们前面加入了jwt验证,需要加上可访问的注解在Controller层的方法上
[AllowAnonymous]
现在就能进行接口的访问
访问main/index接口出现了问题,报错原因提示我们index的页面没有渲染到我们指定的页面上
解决方法:
在我们要跳转的页面即/Views/Shared/_Layout2.cshtml页面上添加一个@RenderBody注解
解释:@RenderBody是一个占位符,是留给子页面的位置,子页面使用这个模版,子页面中的内容会被放到@RenderBody的位置。合并后当作一个整体加载。
不过还要注意添加的位置,不要弄错了
再次进行接口访问:
成功
为了方便,我们更改调试的默认页面为登录页面,利于开发效率,根据自己的控制器的名称和方法去修改
修改:
同样是不区别大小写的
最后在登录页面,登录成功之后进行成功路径的跳转
location.href = "/main/index";
//路径根据自己的接口去修改,后面也是一样不会过多的重复
登录成功跳转验证:
提交登录之后确实跳转到了我们指定的路径页面
退出登录操作
退出大致思路:
编写一个方法进行路径跳转到登录页面-->登录成功后调用接口跳转页面
我们在UserController控制层新增一个退出方法LoginOut
对方法编辑 :
HttpContext.SignOutAsync();
return Redirect("/user/index");//路径根据自己编写的去更改jwt权限认证也别忘记添加
最后在_Layout2.cshtml页面进行路径的跳转,达到退出登录效果
退出登录测试:
点击之后就退出到了我们的登录验证页面就代表完成了退出登录操作
页面数据渲染
渲染大致思路:
在Main控制器的index视图中进行页面布局-->编写接口获取到数据库的表数据-->对页面布局将数据渲染在视图中
先进行页面布局,网址:在线示例 - Layui
@{
Layout = "~/Views/Shared/_Layout2.cshtml";
}
<h1>我是main里的index视图</h1>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<a class="layui-btn layui-btn-xs" lay-event="more">更多 <i class="layui-icon layui-icon-down"></i></a>
</script>
<script>
layui.config({
version: '1632428048355' //为了更新 js 缓存,可忽略
});
//加载模块
layui.use(function(){ //亦可加载特定模块:layui.use(['layer', 'laydate', function(){
//得到各种内置组件
var layer = layui.layer //弹层
,laypage = layui.laypage //分页
,laydate = layui.laydate //日期
,table = layui.table //表格
,carousel = layui.carousel //轮播
,upload = layui.upload //上传
,element = layui.element //元素操作
,slider = layui.slider //滑块
,dropdown = layui.dropdown //下拉菜单
//向世界问个好
layer.msg('Hello World');
//监听Tab切换
element.on('tab(demo)', function(data){
layer.tips('切换了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//执行一个 table 实例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //数据接口
,url: '../demo/table/user/-page=1&limit=20.js' //数据接口
,title: '用户表'
,page: true //开启分页
,toolbar: 'default' //开启工具栏,此处显示默认图标,可以自定义模板,详见文档
,totalRow: true //开启合计行
,cols: [[ //表头
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合计:'}
,{field: 'username', title: '用户名', width:80}
,{field: 'experience', title: '积分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性别', width:80, sort: true}
,{field: 'score', title: '评分', width: 80, sort: true, totalRow: '{{ parseInt(d.TOTAL_NUMS) }} 分'}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '签名', width: 200}
,{field: 'classify', title: '职业', width: 100}
,{field: 'wealth', title: '财富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 150, align:'center', toolbar: '#barDemo'}
]]
});
//监听头工具栏事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //获取选中的数据
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('请选择一行');
} else if(data.length > 1){
layer.msg('只能同时编辑一个');
} else {
layer.alert('编辑 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('请选择一行');
} else {
layer.msg('删除');
}
break;
};
});
//监听行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
,layEvent = obj.event; //获得 lay-event 对应的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'more'){
//下拉菜单
dropdown.render({
elem: this //触发事件的 DOM 对象
,show: true //外部事件触发即显示
,data: [{
title: '编辑'
,id: 'edit'
},{
title: '删除'
,id: 'del'
}]
,click: function(menudata){
if(menudata.id === 'del'){
layer.confirm('真的删除行么', function(index){
obj.del(); //删除对应行(tr)的DOM结构
layer.close(index);
//向服务端发送删除指令
});
} else if(menudata.id === 'edit'){
layer.msg('编辑操作,当前行 ID:'+ data.id);
}
}
,align: 'right' //右对齐弹出(v2.6.8 新增)
,style: 'box-shadow: 1px 1px 10px rgb(0 0 0 / 12%);' //设置额外样式
})
}
});
//执行一个轮播实例
carousel.render({
elem: '#test1'
,width: '100%' //设置容器宽度
,height: 200
,arrow: 'none' //不显示箭头
,anim: 'fade' //切换动画方式
});
//将日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否开启公历重要节日
,mark: { //标记重要日子
'0-10-14': '生日'
,'2020-01-18': '小年'
,'2020-01-24': '除夕'
,'2020-01-25': '春节'
,'2020-02-01': '上班'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分页
laypage.render({
elem: 'pageDemo' //分页容器的id
,count: 1000 //数据总数
,limit: 10 //每页显示的数据条数
,skin: '#1E9FFF' //自定义选中色值
//,layout: ['prev', 'page', 'next', 'count', 'limit', 'refresh', 'skip'] //自定义排版
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'页', {offset: 'b'});
}
}
});
//上传
upload.render({
elem: '#uploadDemo'
,url: '' //此处配置你自己的上传接口即可
,done: function(res){
layer.msg('上传成功');
layui.$('#uploadDemoView').removeClass('layui-hide').find('img').attr('src', res.files.file);
console.log(res)
}
,before: function(){
layer.msg('上传中', {icon: 16, time: 0});
}
});
//滑块
var sliderInst = slider.render({
elem: '#sliderDemo'
,input: true //输入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
进行接口测试是否成功添加布局数据:
还是和之前一样,并且通过F12发现还报错了
这个报错原因,意思是没有加载完就使用:解决方法添加window.οnlοad=function(){ }把index页面的script样式给包括住
再次测试:
成功
我们可以把main控制器中index页面不需要的布局删除
<script>
window.onload = function () {
//加载模块
layui.use(function () { //亦可加载特定模块:layui.use(['layer', 'laydate', function(){
//得到各种内置组件
var layer = layui.layer //弹层
, laypage = layui.laypage //分页
, laydate = layui.laydate //日期
, table = layui.table //表格
, carousel = layui.carousel //轮播
, upload = layui.upload //上传
, element = layui.element //元素操作
, slider = layui.slider //滑块
, dropdown = layui.dropdown //下拉菜单
//向世界问个好
layer.msg('Hello World');
//监听Tab切换
element.on('tab(demo)', function (data) {
layer.tips('切换了 ' + data.index + ':' + this.innerHTML, this, {
tips: 1
});
});
//执行一个 table 实例
table.render({
elem: '#demo'
, height: 420
, url: '/demo/table/user/' //数据接口
, url: '../demo/table/user/-page=1&limit=20.js' //数据接口
, title: '用户表'
, page: true //开启分页
, toolbar: 'default' //开启工具栏,此处显示默认图标,可以自定义模板,详见文档
, totalRow: true //开启合计行
, cols: [[ //表头
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left', totalRowText: '合计:' }
, { field: 'username', title: '用户名', width: 80 }
, { field: 'experience', title: '积分', width: 90, sort: true, totalRow: true }
, { field: 'sex', title: '性别', width: 80, sort: true }
, { field: 'score', title: '评分', width: 80, sort: true, totalRow: '{{ parseInt(d.TOTAL_NUMS) }} 分' }
, { field: 'city', title: '城市', width: 150 }
, { field: 'sign', title: '签名', width: 200 }
, { field: 'classify', title: '职业', width: 100 }
, { field: 'wealth', title: '财富', width: 135, sort: true, totalRow: true }
, { fixed: 'right', width: 150, align: 'center', toolbar: '#barDemo' }
]]
});
//监听头工具栏事件
table.on('toolbar(test)', function (obj) {
var checkStatus = table.checkStatus(obj.config.id)
, data = checkStatus.data; //获取选中的数据
switch (obj.event) {
case 'add':
layer.msg('添加');
break;
case 'update':
if (data.length === 0) {
layer.msg('请选择一行');
} else if (data.length > 1) {
layer.msg('只能同时编辑一个');
} else {
layer.alert('编辑 [id]:' + checkStatus.data[0].id);
}
break;
case 'delete':
if (data.length === 0) {
layer.msg('请选择一行');
} else {
layer.msg('删除');
}
break;
};
});
//监听行工具事件
table.on('tool(test)', function (obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
, layEvent = obj.event; //获得 lay-event 对应的值
if (layEvent === 'detail') {
layer.msg('查看操作');
} else if (layEvent === 'more') {
//下拉菜单
dropdown.render({
elem: this //触发事件的 DOM 对象
, show: true //外部事件触发即显示
, data: [{
title: '编辑'
, id: 'edit'
}, {
title: '删除'
, id: 'del'
}]
, click: function (menudata) {
if (menudata.id === 'del') {
layer.confirm('真的删除行么', function (index) {
obj.del(); //删除对应行(tr)的DOM结构
layer.close(index);
//向服务端发送删除指令
});
} else if (menudata.id === 'edit') {
layer.msg('编辑操作,当前行 ID:' + data.id);
}
}
, align: 'right' //右对齐弹出(v2.6.8 新增)
, style: 'box-shadow: 1px 1px 10px rgb(0 0 0 / 12%);' //设置额外样式
})
}
});
//分页
laypage.render({
elem: 'pageDemo' //分页容器的id
, count: 1000 //数据总数
, limit: 10 //每页显示的数据条数
, skin: '#1E9FFF' //自定义选中色值
//,layout: ['prev', 'page', 'next', 'count', 'limit', 'refresh', 'skip'] //自定义排版
, jump: function (obj, first) {
if (!first) {
layer.msg('第' + obj.curr + '页', { offset: 'b' });
}
}
});
});
}
</script>
编写数据接口
大致思路:
1、先在Model层新建类将我们要获取到的数据从DataDepository获取出来
2、Service层编写业务逻辑
3、Controller层编写方法调用Service层,形成接口
4、获取接口,前端样式调用接口
5、在前端接口对需要的数据进行绑定
6、测试页面
我们先获取医生列表的数据,这个类Model层就可以先不用新建类,因为在DataDepository层就有Doctor医生列表的属性字段。
跳到第二步,编写Service层
为了区分前面写的登录写的接口,这里我们要用到的是医生列表数据,所以我们新建一个接口以及对应的实现类(IDoctorService和DoctorService)
IDoctorService:
DoctorService:
接口编写方法,实现类编写逻辑代码
Controller层调用方法,调用之前先依赖注入刚刚创建的接口IDoctorService和实现类DoctorService
依赖注入:
同时在Controller层创建一个新的控制器医生管理器,这样集中管理医生列表的数据,命名为DoctorController.cs
同时进行属性的调用
调用接口方法IDoctorService,实现接口数据
记得加上jwt验证权限
进行接口数据访问,能够获得到数据,说明已经成功了
返回给前端的样式需要进行完善,统一返回数据格式,显得专业高大上,类似于这种
先在Model层建立一个返回前端样式数据的类HttpResModel.cs,注意,这里的字段不要打错字,不然会造成前端无法接收到数据
/// <summary>
/// 状态码,code==0就是成功,其它可以自定义
/// </summary>
public int code { get; set; }
/// <summary>
/// msg提示信息:msg:成功
/// </summary>
public string msg { get; set; }
/// <summary>
/// count数据的总条数
/// </summary>
public int count { get; set; }
/// <summary>
/// data:具体的数据
/// </summary>
public T data { get; set; }
效果:
我们立马去DoctorController控制层编写方法看看两者的效果:
紧接着去Main控制层下的index页面调用我们生成的数据接口,将数据渲染到layui样式布局里面
接着通过接口的数据渲染到页面上去
实现数据渲染效果:
最后更改管理系统的英文字符,_Layout2.cshtml类中修改
链接多表渲染数据
大致思路梳理:在Model层先建一个类去存放我们有关医生的信息属性,一样的数据是从DataDepository中获取,属性字段要一样-->Service层,接口编写新的方法,实现类编写逻辑代码-->Controller层测试接口是否获取到我们需要的数据-->前端样式调用接口,最后将数据渲染到页面
Join和Linq两种方式进行连接
像我们前面的数据渲染是医生类里面就有的属性,我们可以跳过Mocel层这个步骤,可是我们的数据库往往会存在主键,多个表之间都会存在联系,为了获取到其他表的数据,需要多一步Model层进行数据封装
Join连接
1、Model层创建类DoctorViewModel.cs
2、 Service层,接口(IDoctorService)和实现类(DoctorService)
IDoctorService:
DoctorService:
//连接两张表数据-->Join(内连接)方法
public List<DoctorViewModel> GetViewModel()
{
return _hospitalContext.Doctors.Join(
_hospitalContext.Departments, //要关联的表名
doct => doct.DeptId, //指定用第一张表(Doctor表)的哪个字段去关联
dept => dept.DeptId, //指定用第二张表(Department表)的哪个字段去关联
(t1, t2) => new DoctorViewModel //关联之后要返回两张表的哪些字段值
{
DId = t1.DId,
DeptId = t1.DeptId,
Password = t1.Password,
PhoneNum = t1.PhoneNum,
RealName = t1.RealName,
UserName = t1.UserName,
RId = t1.RId,
Sex = t1.Sex,
DName = t2.DName,
DDesc = t2.DDesc
}).ToList();
}
3、Controller层测试
4、前端样式调用接口,渲染数据
在Main控制层的index页面进行需改
5、效果展示
Join链接三张表
但是需要注意数据表中的所关联的主键和复键,有些表需要先连接才能根据所连接上的表中的主键才能去连接其他的数据表,在编写逻辑代码的时候也要有顺序
1、修改Model层DoctorViewModel.cs
2、 修改Service层,接口(IDoctorService)和实现类(DoctorService)
IDoctorService:
DoctorService:
代码:
public List<DoctorViewModel> GetViewModel2()
{
//Join(内连接)
return _hospitalContext.Doctors.Join(
_hospitalContext.Departments, //要关联的表名
doct => doct.DeptId, //指定用第一张表(Doctor表)的哪个字段去关联
dept => dept.DeptId, //指定用第二张表(Department表)的哪个字段去关联
(t1, t2) => new DoctorViewModel //关联之后要返回两张表的哪些字段值
{
DId = t1.DId,
DeptId = t1.DeptId,
Password = t1.Password,
PhoneNum = t1.PhoneNum,
RealName = t1.RealName,
UserName = t1.UserName,
RId = t1.RId,
Sex = t1.Sex,
DName = t2.DName,
DDesc= t2.DDesc
}).Join(
_hospitalContext.DoctorProfessionals,
doctView => doctView.DId,
dProf => dProf.DId, (t1, t2) => new DoctorViewModel
{
DId = t1.DId,
DeptId = t1.DeptId,
Password = t1.Password,
PhoneNum = t1.PhoneNum,
RealName = t1.RealName,
UserName = t1.UserName,
RId = t1.RId,
Sex = t1.Sex,
DName = t1.DName,
DDesc=t1.DDesc,
PId = t2.PId.Value
}).Join(_hospitalContext.ProfessionalTitles, doctView2 => doctView2.PId, pTitle => pTitle.PId,
(t1, t2) => new DoctorViewModel
{
DId = t1.DId,
DeptId = t1.DeptId,
Password = t1.Password,
PhoneNum = t1.PhoneNum,
RealName = t1.RealName,
UserName = t1.UserName,
RId = t1.RId,
Sex = t1.Sex,
DName = t1.DName,
DDesc = t1.DDesc,
PId = t1.PId,
pName = t2.PName
}).ToList();
3、Controller层测试
测试接口数据:
4、前端样式调用接口,渲染数据
5、效果展示
Linq连接
我们上面使用Join连接表的时候发现,当连接多个表的数据的时候重复的步骤很多,比较冗杂。使用Linq连接就能解决这个问题
1、Model层用以及编辑好的DoctorViewModel.cs.cs
2、修改Service层,接口(IDoctorService)和实现类(DoctorService)
IDoctorService:(接口)
DoctorService:(实现类操作)
代码:
//连接多表数据-->Linq(查询)方法
public List<DoctorViewModel> GetViewModel3()
{
//foreach(LINQ查询),写法更像数据库连接操作
var doctQuery = from doct in _hospitalContext.Doctors
join dept in _hospitalContext.Departments
on doct.DeptId equals dept.DeptId
join dProf in _hospitalContext.DoctorProfessionals
on doct.DId equals dProf.DId
join pTitle in _hospitalContext.ProfessionalTitles
on dProf.PId equals pTitle.PId
select new DoctorViewModel
{
DId = doct.DId,
DeptId = doct.DeptId,
Password = doct.Password,
PhoneNum = doct.PhoneNum,
RealName = doct.RealName,
UserName = doct.UserName,
RId = doct.RId,
Sex = doct.Sex,
DName = dept.DName,
DDesc= dept.DDesc,
PId = dProf.PId.Value,
pName = pTitle.PName
};
return doctQuery.ToList();
}
3、Controller层测试
测试接口:
访问数据一样,但是接口改变了
4、前端样式调用接口,渲染数据
5、效果展示
和Join连接实现的效果一样
实现分页
实现分页要在连接多表的基础上实现布局
1、Model层用以及编辑好的DoctorViewModel.cs.cs
2、修改Service层,接口(IDoctorService)和实现类(DoctorService)
IDoctorService:(接口)
DoctorService:(实现类操作)
JWT验证千万不要忘记了
代码:
//实现分页
/// <summary>
/// page页码,1表示第一页,2:表示第二页
/// </summary>
/// <param name="page"></param>
/// <param name="limit">每页的条数</param>
/// //out:把值返出去给别人用
/// <returns></returns>
public List<DoctorViewModel> GetListPage(int page, int limit, out int totalCount)
{
//foreach(LINQ查询),写法更像数据库连接操作
var doctQuery = from doct in _hospitalContext.Doctors
join dept in _hospitalContext.Departments
on doct.DeptId equals dept.DeptId
join dProf in _hospitalContext.DoctorProfessionals
on doct.DId equals dProf.DId
join pTitle in _hospitalContext.ProfessionalTitles
on dProf.PId equals pTitle.PId
select new DoctorViewModel
{
DId = doct.DId,
DeptId = doct.DeptId,
Password = doct.Password,
PhoneNum = doct.PhoneNum,
RealName = doct.RealName,
UserName = doct.UserName,
RId = doct.RId,
Sex = doct.Sex,
DName = dept.DName,
DDesc = dept.DDesc,
PId = dProf.PId.Value,
pName = pTitle.PName
};
//OrderBy:排序
//OrderBy:升序(1,2,3,4...),OrderByDescending:降序,(5,4,3,2,1)
//Skip:跳过,page=1:0;page=2:5
//Take:要取多少条数据
totalCount = doctQuery.Count();//分页之前,表里面的总条数
return doctQuery.OrderByDescending(m => m.DId).Skip((page - 1) * limit).Take(limit).ToList();
}
3、Controller层测试
测试分页接口,但是分页接口属于有参方法,我们直接访问该接口无法进行传参,不能像之前一样直接访问该接口,但是直接跳到第四步进行检验测试
4、前端样式调用分页接口
因为我们的分页设置是10条数据进行分页,我们的数据库数据没有这么多,需要添加多几条数据上去来达到分页效果
因为主键复键关系,我们添加数据的时候有关联的表都要添加上数据,不然只添加一个表会造成访问的时候没有该数据
完成分页效果
增删改查
查询
思路:设计前端界面按钮-->进行Service层逻辑编写-->Controller层编写接口-->前端调用进行参数获取
1、添加界面按钮-->main控制器的index页面下操作
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">关键字</label>
<div class="layui-input-inline">
<input type="text" name="keyword" id="keyword" placeholder="请输入姓名/部门名称/手机号"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">验证邮箱</label>
<div class="layui-input-inline">
<input type="text" name="email" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<div class="layui-input-inline">
<button class="layui-btn" lay-submit="" lay-filter="demo1">搜索</button>
</div>
</div>
</div>
</form>
2、Service层逻辑编写
在分页的基础上实现查询功能
IDoctorService:(接口)
DoctorService:(实现类操作)
代码:
//查询功能
public List<DoctorViewModel> Inquire(int page, int limit, string keyword, out int totalCount)
{
//foreach(LINQ查询),写法更像数据库连接操作
var doctQuery = from doct in _hospitalContext.Doctors
join dept in _hospitalContext.Departments
on doct.DeptId equals dept.DeptId
join dProf in _hospitalContext.DoctorProfessionals
on doct.DId equals dProf.DId
join pTitle in _hospitalContext.ProfessionalTitles
on dProf.PId equals pTitle.PId
select new DoctorViewModel
{
DId = doct.DId,
DeptId = doct.DeptId,
Password = doct.Password,
PhoneNum = doct.PhoneNum,
RealName = doct.RealName,
UserName = doct.UserName,
RId = doct.RId,
Sex = doct.Sex,
DName = dept.DName,
DDesc = dept.DDesc,
PId = dProf.PId.Value,
pName = pTitle.PName
};
// 搜索
if (!string.IsNullOrEmpty(keyword))
{
//Contains(包含)类似indexOf
//"赵三丰".contains("三"):模糊搜索,like
//var str = "hello";
//str=str + "world";//hello world
doctQuery = doctQuery.Where(doctView => doctView.RealName.Contains(keyword) ||
doctView.DName.Contains(keyword) || doctView.PhoneNum == keyword);
}
//OrderBy:排序
//OrderBy:升序(1,2,3,4...),OrderByDescending:降序,(5,4,3,2,1)
//Skip:跳过,page=1:0;page=2:5
//Take:要取多少条数据
totalCount = doctQuery.Count();//分页之前,表里面的总条数
return doctQuery.OrderByDescending(m => m.DId).Skip((page - 1) * limit).Take(limit).ToList();
}
3、Controller层编写接口
4、前端调用进行参数获取
进行测试:
当我们查询名字的时候报错,提示我们需要引入JQ
引入JQ,在_Layout2.cshtml上操作
再次测试:
姓名模糊查询:
部门模糊查询:
联系方式查询:
为空显示全部数据:
删除
删除分为单条删除和批量删除
实现删除思路:设进行Service层逻辑编写-->Controller层编写接口-->前端调用接口进行删除判断
1、Service层
IDoctorService:(接口)
DoctorService:(实现类操作)
代码:
//实现删除
public int Delete(int id)
{
//var doctor = _hospitalContext.Doctors.Where(doct => doct.DId == id).FirstOrDefault();
//如果是通过主键ID删除的话,那么可以直接使用find方法
var doctor = _hospitalContext.Doctors.Find(id);
if (doctor != null)
{
var doctProf = _hospitalContext.DoctorProfessionals.Where(dProf => dProf.DId == id).FirstOrDefault();
//因为外键的原因,所以要删除doctor表的数据,必须先删除DoctorProfessional表的数据
_hospitalContext.DoctorProfessionals.Remove(doctProf);
//Remove:删除,在内存中删除
_hospitalContext.Doctors.Remove(doctor);
//SaveChanges:保存更改,只有调用了这个方法才会真正地去数据库里面删除
//SaveChanges:会返回受影响的行数
return _hospitalContext.SaveChanges();
}
return 0;
}
2、Controller层
代码:
//实现删除
[AllowAnonymous]
public IActionResult Delete(int id)
{
var httpResModel = new Hospital.Model.HttpResModel<int>();
httpResModel.code = 0;
httpResModel.msg = "删除成功";
var ret = _doctorService.Delete(id);
if (ret == 0)
{
httpResModel.code = -1;
httpResModel.msg = "删除失败";
}
httpResModel.count = 0;
httpResModel.data = ret;
return Json(httpResModel);
}
3、前端调用接口
4、选中id进行删除
5、前往数据库,查看是否还有该数据,验证是否真正删除
实现批量删除
大致思路和删除是一样
1、Service层
IDoctorService:(接口)
DoctorService:(实现类操作)
注意:如果逻辑代码实现的时候返回的数据是字符串的话,后台实现的数据库方法是模糊查询,然后有些数据因为关联会出现问题
代码:
//实现批量删除
public int DelAll(string ids)
{
if (string.IsNullOrEmpty(ids))
{
return 0; //删除失败
}
//StringSplitOptions.RemoveEmptyEntries去掉空白项
//string[]
var idArr = ids.Split(",", StringSplitOptions.RemoveEmptyEntries);
//string
//var idArr = ids;
//id in(1,33,22)
var doctors = _hospitalContext.Doctors.Where(doct => idArr.Contains(doct.DId.ToString())).ToList();
if (doctors != null && doctors.Count > 0)
{
var doctProfs = _hospitalContext.DoctorProfessionals.Where(doctProf => idArr.Contains(doctProf.DId.ToString())).ToList();
//RemoveRange同时删除多条数据
_hospitalContext.DoctorProfessionals.RemoveRange(doctProfs);
_hospitalContext.Doctors.RemoveRange(doctors);
return _hospitalContext.SaveChanges();
}
return 0;
}
2、Controller层
代码:
//实现批量删除
[AllowAnonymous]
public IActionResult DelAll(string ids)
{
var httpResModel = new HttpResModel<int>();
httpResModel.code = 0;
httpResModel.msg = "删除成功";
var ret = _doctorService.DelAll(ids);
if (ret == 0)
{
httpResModel.code = -1;//删除失败
httpResModel.msg = "删除失败";
}
httpResModel.count = 0;
httpResModel.data = ret;
return Json(httpResModel);
}
3、前端调用接口并编写删除判断逻辑
4、选中多个id进行删除
5、前往数据库,查看是否还有该数据,验证是否真正删除
增加数据
大致思路分析:添加数据首先要有一个表格填写想要增加的数据,所以需要新建一个添加的页面-->Service层改动--Controller层编写接口-->前端样式调用接口-->数据库查看新增数据
1、进行添加页面样式布局,新增页面视图为add
进行编辑布局:
代码:
@{
ViewData["Title"] = "Add";
Layout = "~/Views/Shared/_Layout2.cshtml";
}
@*学生练习页面*@
<form class="layui-form" action="" lay-filter="addform">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="username" lay-verify="required" lay-reqtext="用户名是必填项,岂能为空?" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="password" name="password" lay-verify="required" lay-reqtext="密码是必填项,岂能为空?" autocomplete="off" placeholder="请输入密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">真实姓名</label>
<div class="layui-input-block">
<input type="text" name="realname" lay-verify="required" lay-reqtext="真实姓名是必填项,岂能为空?" placeholder="请输入真实姓名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机号</label>
<div class="layui-input-block">
<input type="text" name="phonenum" lay-verify="required|phone" lay-reqtext="手机号是必填项,岂能为空?" placeholder="请输入手机号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">性别</label>
<div class="layui-input-block">
<input type="radio" name="sex" value="男" title="男" checked="">
<input type="radio" name="sex" value="女" title="女">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所属部门</label>
<div class="layui-input-block">
<select name="deptID" id="deptID" lay-filter="department">
<option value=""></option>
@* <option value="0">写作</option>
<option value="1">阅读</option>
<option value="2">游戏</option>
<option value="3">音乐</option>
<option value="4">旅行</option>*@
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">职称</label>
<div class="layui-input-block">
<select name="pid" id="pfession">
<option value=""></option>
@* <option value="0">写作</option>
<option value="1">阅读</option>
<option value="2">游戏</option>
<option value="3">音乐</option>
<option value="4">旅行</option>*@
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">角色</label>
<div class="layui-input-block">
<select name="RId" id="role" lay-filter="role">
<option value=""></option>
@* <option value="0">写作</option>
<option value="1">阅读</option>
<option value="2">游戏</option>
<option value="3">音乐</option>
<option value="4">旅行</option>*@
</select>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit="" lay-filter="btnsubmit">立即提交</button>
</div>
</div>
</form>
<div style="height:200px;"></div>
<script>
window.onload = function () {
layui.use(function () {
var form = layui.form;
form.on('submit(btnsubmit)', function (data) {
//console.log(data.elem) //被执行事件的元素DOM对象,一般为button对象
//console.log(data.form) //被执行提交的form对象,一般在存在form标签时才会返回
//console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}
var data1 = data.field;
return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
});
});
}
</script>
效果:
所属部门这几个不应该是我们自己填写,而是供我们选择的一个下拉框,所以需要对这几个进行一个数据绑定,实现下拉渲染
这三个下拉选项对应着不同的数据表,所以需要我们新建接口获取对应下拉数据
2、Service层处理业务逻辑
进行下拉渲染接口编写:
所属部门:
IDeptService:(实现类操作)
DeptService:(实现类操作)
Controller层:
依赖注入:
创建DeptController控制器并实现接口:
职称:
角色:
添加页面进行下拉绑定:记得更换自己的接口名称
代码:
//下拉框绑定部门名称
$.get("/dept/getdeptlist", function (data) {
if (data != null && data.length > 0) {
var strOptionHtml = "";
for (var i = 0; i < data.length; i++) {
strOptionHtml += '<option value="' + data[i].deptId + '">' + data[i].dName + '</option>';
}
$("#deptID").append(strOptionHtml);
form.render("select");
}
});
下拉渲染效果:
剩下的职称和角色步骤一样,就不过多复述
实现添加功能
1、Service层编写:
IDoctorService:(接口)
DoctorService:(实现类操作)
2、Controller层:
形成接口
3、前端样式调用接口
4、效果测试
数据库检查数据
更改数据
大致思路和增加数据一样就不过多复述
更改数据和增加一样都要先有一个表去进行更改,但是我们根据id选中数据进行更改的时候,还要将该数据的信息显示出来
1、增加一个修改的页面
直接复制前面我们的添加页面就好了,然后Controller层添加接口用来访问该页面
新建接口访问页面
2、Service层
因为修改数据是根据id来选中该数据,需要获取到单条数据
IDoctorService:
DoctorService:
代码:
//获取单条数据
public DoctorViewModel Get(int id)
{
var doctQuery = from doct in _hospitalContext.Doctors
join dProf in _hospitalContext.DoctorProfessionals
on doct.DId equals dProf.DId
where doct.DId == id
select new DoctorViewModel
{
DId = doct.DId,
DeptId = doct.DeptId,
Password = doct.Password,
PhoneNum = doct.PhoneNum,
RealName = doct.RealName,
UserName = doct.UserName,
RId = doct.RId,
Sex = doct.Sex,
PId = dProf.PId.Value,//职称id
};
return doctQuery.FirstOrDefault();
}
修改控制层:
//新增添加数据视图
[AllowAnonymous]
/// <summary>
/// 编辑
/// </summary>
/// <returns></returns>
public IActionResult Edit(int id)
{
//为了不报空引用异常
//?和??的区别?
//??代表的是判断左边的值是不是等于null,如果等于null那么返回右侧的值,
//否则就返回左边的值
//a==b?a:b
//var doct1 =_doctorService?.Get(id);//null.Get()
var doct = _doctorService.Get(id) ?? new DoctorViewModel();
return View(doct);
}
将修改数据的接口放到前端样式布局里面
测试:
接着根据id跳转修改属性id的时候,进行跳转之后的数据渲染
但是性别的数据绑定需要进行一些逻辑判断
下拉框的绑定需要设置选中操作
再次测试:
此时数据渲染成功
进行修改逻辑编写:
IDoctorService:
DoctorService:
代码:
//修改数据
public int Update(Doctor doctor, int pid)
{
_hospitalContext.Doctors.Update(doctor);
//获取到数据
var doctProf = _hospitalContext.DoctorProfessionals
.Where(doctProf => doctProf.DId == doctor.DId).FirstOrDefault();
//对返回值进行判断
if (doctProf != null)
{
_hospitalContext.DoctorProfessionals.Update(doctProf);
}
return _hospitalContext.SaveChanges();
}
再次进行Controller层操作:
更给前端样式接口:
还记得我们的接口吗?
有关int参数,就是用来获取我们要更改的id的值,是我们必须要进行传入的值
传入方式:
5、最后效果
结尾