页面预览

就诊人管理

就诊人列表

添加就诊人

查看就诊人

![image-20230225060710

管理员系统用户管理

前面我们完成了用户登录、用户认证与就诊人管理,现在我们需要把这些信息在我们的平台管理系统中进行统一管理

用户列表

用户详情

第01章-token刷新

简单的设置redis和cookie的过期时间,会导致用户在操作的过程中掉线,为了解决这个问题,我们可以使用token续期的方案,具体的做法是生成一个刷新token。

1、存储token

设置token与refreshToken,都包含用户信息(userId、name、headimgurl),可以一样可以不一样,refreshToken比token时间更长,如token30分钟,refreshToken60分钟

ApiWxController的callback方法的return "redirect:"前面,将之前的生成token和存储token的相关代码封装到saveToken方法中。

将如下代码进行封装:

封装成如下代码:

@Resource
private AuthContextHolder authContextHolder;
UserVo userVo = new UserVo();
userVo.setName(name);
userVo.setUserId(userInfo.getId());
userVo.setHeadimgurl(userInfo.getHeadImgUrl()); authContextHolder.saveToken(userVo, response); return "redirect:" + constantProperties.getSytBaseUrl();

service-util中引入依赖

<!--实体-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>model</artifactId>
<version>1.0</version>
</dependency>

在AuthContextHolder中添加如下方法:

/**
* 将token和refreshToken保存在redis和cookie中的通用方法
* @param userVo
* @param response
*/
public void saveToken(UserVo userVo, HttpServletResponse response) { int redisMaxTime = 30;
//生成token/refreshToken
String token = getToken();
String refreshToken = getToken(); //将生成token/refreshToken存入redis:token做键,userVo做值
redisTemplate.opsForValue()//30分钟
.set("user:token:" + token, userVo, redisMaxTime, TimeUnit.MINUTES);
redisTemplate.opsForValue()//60分钟
.set("user:refreshToken:" + refreshToken, userVo, redisMaxTime * 2, TimeUnit.MINUTES); //将token、refreshToken和name存入cookie
int cookieMaxTime = 60 * 30;//30分钟
CookieUtils.setCookie(response, "token", token, cookieMaxTime);
CookieUtils.setCookie(response, "refreshToken", refreshToken, cookieMaxTime * 2);
CookieUtils.setCookie(response, "name", URLEncoder.encode(userVo.getName()), cookieMaxTime * 2);
CookieUtils.setCookie(response, "headimgurl", URLEncoder.encode(userVo.getHeadimgurl()), cookieMaxTime * 2);
}
private String getToken(){
return UUID.randomUUID().toString().replaceAll("-", "");
}

3、续期token

修改checkAuth方法,当token不存在时,续期token

/**
* 检查授权状态并续期
* @param request
* @return
*/
public Long checkAuth(HttpServletRequest request, HttpServletResponse response){
//从http请求头中获取token
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)) {
//throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
return refreshToken(request, response);//刷新token
} Object userVoObj = redisTemplate.opsForValue().get("user:token:" + token);
if(userVoObj == null){
//throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
return refreshToken(request, response);//刷新token
} UserVo userVo = (UserVo)userVoObj; return userVo.getUserId();
}
/**
* 刷新token
* @param request
* @param response
* @return
*/
public Long refreshToken(HttpServletRequest request, HttpServletResponse response) { //从cookie中获取刷新token
String refreshToken = CookieUtils.getCookie(request, "refreshToken"); //从redis中根据刷新token获取用户信息
Object userVoObj = redisTemplate.opsForValue().get("user:refreshToken:" + refreshToken);
if(userVoObj == null) {
//LOGIN_AURH(214, "登录过期"),
throw new GuiguException(ResultCodeEnum.LOGIN_TIMEOUT);//登录过期
} UserVo userVo = (UserVo) userVoObj;
saveToken(userVo, response); return userVo.getUserId();
}

4、修改checkAuth方法的调用

FrontUserInfoController和FrontFileController中的方法,添加response参数

5、cookie跨域

跨域ajax访问时,session_id不会被存储,cookie不会被传递到后端,因此需要解决cookie跨域存储的问题

解决方案:

(1)网关配置文件CorsConfig中添加如下设置:

config.setAllowCredentials(true); //避免跨域访问时session_id每次不一致

(2)前端axios初始化文件request.js添加如下设置:

withCredentials: true //避免跨域访问时session_id每次不一致

6、前端request.js拦截处理

如果接口返回214状态(登录超时),说明用户超时未操作,直接退出。

// http response 拦截器
service.interceptors.response.use(
response => { //如果响应码是214,则需要登录超时
if (response.data.code === 214) {
// to re-login
MessageBox.confirm('登录超时, 请重新登录', '确认退出', {
confirmButtonText: '重新登录',
cancelButtonText: '回到首页',
type: 'warning'
}).then(() => {
window.location.href = process.env.BASE_API + '/front/user/wx/login'
}).catch(()=>{
window.location.href = '/'
}) }else if (response.data.code !== 200) {
Message({
message: response.data.message,
type: 'error',
duration: 5 * 1000
}) return Promise.reject(response.data)
} else {
return response.data
}
},
error => {
return Promise.reject(error.response)
})

7、myheader.vue

myheader.vue中showInfo方法的修改,保证token过期后,用户名信息依然显示

showInfo() {
let refreshToken = cookie.get('refreshToken')
if (refreshToken) {
this.name = cookie.get('name')
this.headimgurl = cookie.get('headimgurl')
}
},

myheader.vue中退出登录方法的修改,需要清空refreshToken

cookie.set('name', '', {domain: 'localhost'})
cookie.set('token', '', {domain: 'localhost'})
cookie.set('refreshToken', '', {domain: 'localhost'}) //清空refreshToken
cookie.set('headimgurl', '', {domain: 'localhost'})

补充:由于我们解决了cookie的ajax传递跨域问题,因此之前通过header传输的token其实可以不必要了,我们可以直接在后端从cookie中获取token的值,如下:

String token = request.getHeader("token");

//以上可以替换为如下:

String token = CookieUtils.getCookie(request, "token");

第02章-就诊人管理

1、后端接口

1.1、添加就诊人

FrontPatientController:

package com.atguigu.syt.user.controller.front;

@Api(tags = "就诊人管理")
@RestController
@RequestMapping("/front/user/patient")
public class FrontPatientController { @Resource
private PatientService patientService; @Resource
private AuthContextHolder authContextHolder; @ApiOperation("添加就诊人")
@ApiImplicitParam(name = "patient",value = "就诊人对象", required = true)
@PostMapping("/auth/save")
public Result savePatient(@RequestBody Patient patient, HttpServletRequest request, HttpServletResponse response) { Long userId = authContextHolder.checkAuth(request, response);
patient.setUserId(userId);
patientService.save(patient); return Result.ok().message("保存成功");
}
}

1.2、修改

FrontPatientController:

@ApiOperation("修改就诊人")
@ApiImplicitParam(name = "patient",value = "就诊人对象", required = true)
@PutMapping("/auth/update")
public Result updatePatient(@RequestBody Patient patient, HttpServletRequest request, HttpServletResponse response) { authContextHolder.checkAuth(request, response);
patientService.updateById(patient);
return Result.ok().message("修改成功");
}

1.3、根据id获取就诊人

FrontPatientController:

@ApiOperation("根据id获取就诊人信息")
@ApiImplicitParam(name = "id",value = "就诊人id", required = true)
@GetMapping("/auth/get/{id}")
public Result<Patient> getPatient(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { Long userId = authContextHolder.checkAuth(request, response);
//加上userId参数,只可以获取自己名下的就诊人信息
Patient patient = patientService.getPatientById(id, userId);
return Result.ok(patient);
}

接口:PatientService

/**
* 根据id获取本人名下的就诊人信息
* @param id
* @param userId
* @return
*/
Patient getPatientById(Long id, Long userId);

实现:PatientServiceImpl

@Override
public Patient getPatientById(Long id, Long userId) { LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId).eq(Patient::getId, id);
Patient patient = baseMapper.selectOne(queryWrapper);
//封装数据
return this.packPatient(patient);
}

辅助方法

@Resource
private DictFeignClient dictFeignClient; @Resource
private RegionFeignClient regionFeignClient;
/**
* 封装Patient对象里面其他参数
* @param patient
* @return
*/
private Patient packPatient(Patient patient) { String certificatesTypeString = dictFeignClient.getName(DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),patient.getCertificatesType());
String contactsCertificatesTypeString = dictFeignClient.getName(
DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),patient.getContactsCertificatesType());
String provinceString = regionFeignClient.getName(patient.getProvinceCode());
String cityString = regionFeignClient.getName(patient.getCityCode());
String districtString = regionFeignClient.getName(patient.getDistrictCode()); patient.getParam().put("certificatesTypeString", certificatesTypeString);
patient.getParam().put("contactsCertificatesTypeString", contactsCertificatesTypeString);
patient.getParam().put("provinceString", provinceString);
patient.getParam().put("cityString", cityString);
patient.getParam().put("districtString", districtString);
patient.getParam().put("fullAddress",
provinceString + cityString + districtString + patient.getAddress());
return patient;
}

1.4、获取就诊人列表

FrontPatientController

@ApiOperation("获取就诊人列表")
@GetMapping("/auth/findAll")
public Result<List<Patient>> findAll(HttpServletRequest request, HttpServletResponse response) { Long userId = authContextHolder.checkAuth(request, response);
List<Patient> list = patientService.findByUserId(userId);
return Result.ok(list);
}

接口:PatientService

/**
* 根据userId获取就诊人列表
* @param userId
* @return
*/
List<Patient> findByUserId(Long userId);

实现:PatientServiceImpl

@Override
public List<Patient> findByUserId(Long userId) { LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId); List<Patient> patientList = baseMapper.selectList(queryWrapper);
patientList.forEach(patient -> {
patient.getParam().put("expenseMethod", patient.getIsInsure()==0?"自费":"医保");
});
return patientList;
}

1.5、删除就诊人

FrontPatientController:

@ApiOperation("删除就诊人")
@DeleteMapping("/auth/remove/{id}")
public Result removePatient(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { Long userId = authContextHolder.checkAuth(request, response);
//加上userId参数,只可以删除自己名下的就诊人信息
patientService.removeById(id, userId);
return Result.ok();
}

接口:PatientService

/**
* 根据id删除自己名下的就诊人信息
* @param id
* @param userId
*/
void removeById(Long id, Long userId);

实现:PatientServiceImpl

@Override
public void removeById(Long id, Long userId) { LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId).eq(Patient::getId, id);
baseMapper.delete(queryWrapper);
}

2、前端整合

2.1、api

创建api/patient.js

import request from '~/utils/request'

export default {

  save(patient) {
return request({
url: `/front/user/patient/auth/save`,
method: 'post',
data: patient
})
}, updateById(patient) {
return request({
url: `/front/user/patient/auth/update`,
method: 'put',
data: patient
})
}, getById(id) {
return request({
url: `/front/user/patient/auth/get/${id}`,
method: 'get'
})
}, findList() {
return request({
url: `/front/user/patient/auth/findAll`,
method: `get`
})
}, removeById(id) {
return request({
url: `/front/user/patient/auth/remove/${id}`,
method: 'delete'
})
}
}

2.2、页面渲染

资料:资料>就诊人管理>

就诊人列表:pages/patient/index.vue

就诊人添加与修改 :pages/patient/add.vue

就诊人详情与删除:pages/patient/show.vue

第03章-管理系统用户管理(作业)

1、后端接口

1.1、用户列表

AdminUserInfoController:

package com.atguigu.syt.user.controller.admin;

@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/admin/user/userInfo")
public class AdminUserInfoController { @Resource
private UserInfoService userInfoService; @ApiOperation("分页条件查询")
@ApiImplicitParams({
@ApiImplicitParam(name = "page",value = "页码",required = true),
@ApiImplicitParam(name = "limit",value = "每页记录数",required = true),
@ApiImplicitParam(name = "userInfoQueryVo",value = "查询对象",required = false)
})
@GetMapping("/{page}/{limit}")
public Result<IPage<UserInfo>> list(
@PathVariable Long page,
@PathVariable Long limit,
UserInfoQueryVo userInfoQueryVo
) {
Page<UserInfo> pageParam = new Page<>(page,limit);
IPage<UserInfo> pageModel = userInfoService.selectPage(pageParam, userInfoQueryVo);
return Result.ok(pageModel);
}
}

Service接口:UserInfoService

/**
* 查询用户分页列表
* @param pageParam
* @param userInfoQueryVo
* @return
*/
IPage<UserInfo> selectPage(Page<UserInfo> pageParam, UserInfoQueryVo userInfoQueryVo);

Service实现:UserInfoServiceImpl

@Override
public IPage<UserInfo> selectPage(Page<UserInfo> pageParam, UserInfoQueryVo userInfoQueryVo) {
//UserInfoQueryVo获取条件值
String keyword = userInfoQueryVo.getKeyword(); //用户名称
String createTimeBegin = userInfoQueryVo.getCreateTimeBegin(); //开始时间
String createTimeEnd = userInfoQueryVo.getCreateTimeEnd(); //结束时间
//对条件值进行非空判断
LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.and(!StringUtils.isEmpty(keyword),
i -> i.like(UserInfo::getName, keyword).or().like(UserInfo::getPhone, keyword))
.ge(!StringUtils.isEmpty(createTimeBegin), UserInfo::getCreateTime, createTimeBegin)
.le(!StringUtils.isEmpty(createTimeEnd), UserInfo::getCreateTime, createTimeEnd);
//调用mapper的方法
IPage<UserInfo> pages = baseMapper.selectPage(pageParam, wrapper);
//编号变成对应值封装
pages.getRecords().forEach(this::packUserInfoForList);
return pages;
}

辅助方法:

/**
* 封装用户状态、认证状态、证件类型信息
* @param userInfo
* @return
*/
private UserInfo packUserInfoForList(UserInfo userInfo) { //判断用户是否已经提交实名认证
if(userInfo.getAuthStatus().intValue() != AuthStatusEnum.NO_AUTH.getStatus().intValue()){
String certificatesTypeString = dictFeignClient.getName(
DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),
userInfo.getCertificatesType()
);
userInfo.getParam().put("certificatesTypeString", certificatesTypeString);
} userInfo.getParam().put("authStatusString", AuthStatusEnum.getStatusNameByStatus(userInfo.getAuthStatus()));
userInfo.getParam().put("statusString", UserStatusEnum.getStatusNameByStatus(userInfo.getStatus())); return userInfo;
}

1.2、锁定和解锁

Controller:在AdminUserInfoController中添加方法

@ApiOperation("锁定和解锁")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true),
@ApiImplicitParam(name = "status",value = "用户状态",required = true)
})
@PutMapping("lock/{userId}/{status}")
public Result lock(
@PathVariable("userId") Long userId,
@PathVariable("status") Integer status){
boolean result = userInfoService.lock(userId, status);
if(result){
return Result.ok().message("设置成功");
}else{
return Result.ok().message("设置失败");
}
}

Service接口:UserInfoService

/**
* 锁定和解锁用户
* @param userId
* @param status
* @return
*/
boolean lock(Long userId, Integer status);

Service实现:UserInfoServiceImpl

@Override
public boolean lock(Long userId, Integer status) {
if(status == 0 || status == 1){
UserInfo userInfo = new UserInfo();
userInfo.setId(userId);
userInfo.setStatus(status);
return this.updateById(userInfo);
}
return false;
}

1.3、用户详情

Controller:在AdminUserInfoController中添加方法

@ApiOperation("用户详情")
@ApiImplicitParam(name = "userId",value = "用户id",required = true)
@GetMapping("show/{userId}")
public Result<Map<String, Object>> show(@PathVariable Long userId) {
return Result.ok(userInfoService.show(userId));
}

Service接口:UserInfoService

/**
* 根据用户id获取用户详情
* @param userId
* @return
*/
Map<String, Object> show(Long userId);

Service实现:UserInfoServiceImpl

@Resource
private PatientService patientService;
@Override
public Map<String, Object> show(Long userId) {
Map<String,Object> map = new HashMap<>();
//根据userid查询用户信息
UserInfo userInfo = this.packUserInfo(baseMapper.selectById(userId));
map.put("userInfo",userInfo); //根据userid查询就诊人信息
List<Patient> patientList = patientService.findByUserId(userId);
map.put("patientList",patientList);
return map;
}

1.4、用户认证审批

Controller:在AdminUserInfoController中添加方法

@ApiOperation("认证审批")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true),
@ApiImplicitParam(name = "authStatus",value = "用户认证审批状态",required = true)
})
@PutMapping("approval/{userId}/{authStatus}")
public Result approval(@PathVariable Long userId, @PathVariable Integer authStatus) {
boolean result = userInfoService.approval(userId,authStatus);
if(result){
return Result.ok().message("审批成功");
}else{
return Result.ok().message("审批失败");
}
}

Service接口:UserInfoService

/**
* 审核用户
* @param userId
* @param authStatus
* @return
*/
boolean approval(Long userId, Integer authStatus);

Service实现:UserInfoServiceImpl

/**
* 认证审批 2通过 -1不通过
* @param userId
* @param authStatus
* @return
*/
@Override
public boolean approval(Long userId, Integer authStatus) {
if(authStatus == AuthStatusEnum.AUTH_SUCCESS.getStatus()
|| authStatus == AuthStatusEnum.AUTH_FAIL.getStatus()){
UserInfo userInfo = new UserInfo();
userInfo.setId(userId);
userInfo.setAuthStatus(authStatus);
return this.updateById(userInfo);
}
return false;
}

2、前端整合

2.1、页面

在后台管理系统前端项目中添加如下页面,资料:资料>用户管理

用户列表:src/views/syt/userInfo/list.vue

用户详情,详情页面展示用户信息、用户就诊人信息:src/views/syt/userInfo/show.vue

2.2、路由

静态路由:

  {
path: '/userInfo',
component: Layout,
redirect: '/userInfo/list',
name: 'userInfo',
meta: { title: '用户管理', icon: 'user' },
alwaysShow: true,
children: [
{
path: 'list',
name: 'userInfoList',
component: () => import('@/views/syt/userInfo/list'),
meta: { title: '用户列表', icon: 'el-icon-s-unfold' }
},
{
path: 'show/:id',
name: 'userInfoShow',
component: () => import('@/views/syt/userInfo/show'),
meta: { title: '查看用户' },
hidden: true
}
]
},

动态路由:

用户管理:

用户列表:

查看用户:

2.3、api

创建src/api/syt/userInfo.js

import request from '@/utils/request'

const apiName = '/admin/user/userInfo'
export default { //用户列表
getPageList(page, limit, searchObj) {
return request({
url: `${apiName}/${page}/${limit}`,
method: 'get',
params: searchObj
})
}, //锁定与解锁
lock(id, status) {
return request({
url: `${apiName}/lock/${id}/${status}`,
method: 'put'
})
}, //用户详情
show(id) {
return request({
url: `${apiName}/show/${id}`,
method: 'get'
})
}, //认证审批
approval(id, authStatus) {
return request({
url: `${apiName}/approval/${id}/${authStatus}`,
method: 'put'
})
}
}

源码:https://gitee.com/dengyaojava/guigu-syt-parent

尚医通-day12【token续期和就诊人管理】(内附源码)的更多相关文章

  1. WmS详解(一)之token到底是什么?基于Android7.0源码

    做Android有些年头了,Framework层三大核心View系统,WmS.AmS最近在研究中,这三大块,每一块都够写一个小册子来介绍,其中View系统的介绍,我之前有一个系列的博客(不过由于时间原 ...

  2. 又到毕业季,尚学堂喊你免费领取100个Java毕设项目(含源码视频),限时一周哦!

    你还在为毕设发愁?不知道该如何命题?不知道从哪里下手?担心毕设过不了影响毕业? 尚学堂首家隆重推出了刷爆朋友圈的毕设100个项目,别说你还没去下载观看!!最最重要的是:免费!免费!免费!而且限时一周! ...

  3. Django-jwt token生成源码分析

    一. 认证的发展历程简介 这里真的很简单的提一下认证的发展历程.以前大都是采用cookie.session的形式来进行客户端的认证,带来的结果就是在数据库上大量存储session导致数据库压力增大,大 ...

  4. 高通sdm845_la2.0源码编译及使用QFIL刷机

    一.下载源码 高通芯片代码下载地址:https://chipcode.qti.qualcomm.com/ . *_amss_standard_oem : 高通私有源码(*为sdm845-la--. * ...

  5. IdentityServer4源码颁发token分析及性能优化

    IdentityServer4源码地址 IdentityModel源码地址 以下的流程用ResourceOwnerPassword类型获取token作为介绍 分两种获取形式说明 token请求地址为默 ...

  6. 16Aspx.com-书通网中小学生免费在线学习网站源码 带采集带手机版帝国cms内核

    =============================================== 源码站长资源交易专业网-商业源码下载,VIP源码,程序交易,毕业设计交易,站长交易|- 16aspx.c ...

  7. Android通过微信实现第三方登录并使用OKHttp获得Token及源码下载

    这里对于App在微信开放平台上申请AppID和secret在这里就略过了,我们微信的授权登录流程,腾讯官网给的流程如下: 1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用 ...

  8. 没必要看源码。。把文档学通就已经牛逼了(我们大多还是在应用层,还达不到研究的程度。附class与examples大全链接)

    [学霸]深圳-鑫 2017/7/11 13:54:07只是学习怎么用QT的话,不用看源码.看帮助文档就很好要学习编码风格与思路,就看看源码 [学神]武汉-朝菌 2017/7/11 13:54:39没必 ...

  9. day12——生成器、推导式、简单内置函数

    day12 生成器 迭代器:python中内置的一种节省空间的工具 生成器的本质就是一个迭代器 迭代器和生成器的区别:一个是pyhton自带的,一个是程序员自己写的 写一个生成器 基于函数 在函数中将 ...

  10. Django drf:认证及组件、token、局部钩子源码分析

    一.drf认证功能 二.token讲解 三.局部钩子源码分析 一.drf认证功能 1.认证简介: 只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录则不能查 ...

随机推荐

  1. Hyperf框架环境搭建

    https://hyperf.wiki/2.2/#/README 1.PHP 7.2 以上查看PHP : php -vcurl 127.0.0.1:9501 查看是否装swoole: php --ri ...

  2. innerHTML和outerHTML区别

     1.innerHTML <body> <p>你好</p> <div id="test"><h5>就是喜欢你</h ...

  3. [小迪安全]笔记 day12、13 MySQL注入

    1. 简单案例 1.1 简易代码分析SQL注入原理 http://localhost:8085/sqli-labs/Less-2/index.php?id=2 id=2 正常查询 http://loc ...

  4. 免费,小巧好用的pdf阅读器以及护眼模式颜色代码

    免费,迷你,小巧pdf阅读器 https://www.sumatrapdfreader.org/downloadafter 网络上流行的眼神RGB值和颜色代码 绿色豆沙可以有效减轻长时间使用电脑的眼睛 ...

  5. flask-sqlalchemy入门

    Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展.它致力于简化在 Flask 中 SQLAlchemy 的使用.SQLAlchemy 是目前pytho ...

  6. pysimplegui之使用多线程,避免程序卡死

    这个问题我也遇到过,就是还需要一个while循环的时候,放到gui本身循环会卡死,这时候就需要启动多线程 需要"长时间"的操作 如果您是 Windows 用户,您会在其标题栏中看到 ...

  7. MySQL笔记之一致性视图与MVCC实现

    一致性读视图是InnoDB在实现MVCC用到的虚拟结构,用于读提交(RC)和可重复度(RR)隔离级别的实现. 一致性视图没有物理结构,主要是在事务执行期间用来定义该事物可以看到什么数据. 一.Read ...

  8. Java线程创建

    程序.进程.线程 程序:指令和数据的有序集合,静态 进程:程序的一次执行过程,动态,系统分配资源的单位 线程:一个进程可以包含多个线程,一个进程至少有一个线程,线程是CPU调度的基本单位 线程创建 三 ...

  9. layUI之DataTable组件V1.0(父子表管理传值/数据表格与select&laydate结合等)

    layUI之DataTable数据表格组件V1.0 目录 layUI之DataTable数据表格组件V1.0 概述 一.下载与引用 二.组件功能介绍 三.父表格渲染 1. HTML中声明空table一 ...

  10. Qt5.9 UI设计(七)——统一样式设计

    前言 前面已经将UI设计部分实现,各页面也做了最简单的设计,本章介绍一下qss样式的使用.样式设计最终的显示效果如下图: 操作步骤 将stylesheet.qss 样式文件添加进工程 styleshe ...