帝可得- 人员管理
一.需求说明
人员管理业务流程如下:
-
登录系统: 首先,后台管理人员需要登录到帝可得后台管理系统中。
-
新增工作人员: 登录系统后,管理人员可以新增工作人员,包括姓名、联系方式等信息。
-
关联角色: 确定此员工是运维人员还是运营人员,这将影响他们的职责和权限。
-
关联区域: 确定员工负责的区域范围,确保工作人员能够高效地完成区域内的设备安装、维修、商品补货等工作。
graph TDA[登录系统] A --> B[新增员工]B --> C[关联角色]B --> D[关联区域]
对于人员和其他管理数据,下面是示意图:
-
关系字段:role_id、region_id
-
数据字典:status(1启用、0停用)
-
冗余字段:region_name、role_code、role_name(单表,提高查询效率)
二. 生成基础代码
2.1 创建目录菜单
2.2 添加数据字典
2.3 配置代码生成信息
2.3.1 导入表(员工tb_emp、角色tb_role)
2.3.2 配置信息
员工
角色
2.4 下载代码并导入项目
数据库 sql
前后端
重启项目运行
三. 人员列表改造
3.1 基础页面
参考产品原型进行修改
将新增人员列表对话框的角色和所属区域改为下拉框需要这么几步
-
引入通过id查询角色/区域列表的api接口
-
写查询角色/区域列表的函数方法
-
将组件改为下拉框,数据对应
前端接收参数的时候一定要看好后端响应的数据是什么样的
效果完成✌
代码实现
在emp/index.vue视图组件中修改
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"><el-form-item label="人员名称" prop="userName"><el-input v-model="queryParams.userName" placeholder="请输入人员名称" clearable @keyup.enter="handleQuery" /></el-form-item><el-form-item><el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button><el-button icon="Refresh" @click="resetQuery">重置</el-button></el-form-item>
</el-form>
<!-- 人员列表 -->
<el-table v-loading="loading" :data="empList" @selection-change="handleSelectionChange"><el-table-column type="selection" width="55" align="center" /><el-table-column label="序号" type="index" width="80" align="center" prop="id" /><el-table-column label="人员名称" align="center" prop="userName" /><el-table-column label="归属区域" align="center" prop="regionName" /><el-table-column label="角色" align="center" prop="roleName" /><el-table-column label="联系电话" align="center" prop="mobile" /><el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template #default="scope"><el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['manage:emp:edit']">修改</el-button><el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['manage:emp:remove']">删除</el-button></template></el-table-column>
</el-table>
<!-- 添加或修改人员列表对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body><el-form ref="empRef" :model="form" :rules="rules" label-width="80px"><el-form-item label="员工名称" prop="userName"><el-input v-model="form.userName" placeholder="请输入员工名称" /></el-form-item><el-form-item label="角色" prop="roleId"><!-- <el-input v-model="form.roleId" placeholder="请输入角色id" /> --><el-select v-model="form.roleId" placeholder="请选择角色"><el-option v-for="item in roleList" :key="item.roleId" :label="item.roleName" :value="item.roleId" /></el-select></el-form-item><el-form-item label="联系电话" prop="mobile"><el-input v-model="form.mobile" placeholder="请输入联系电话" /></el-form-item><el-form-item label="创建时间" prop="createTime" v-if="form.id!=null">{{form.createTime }}</el-form-item><el-form-item label="负责区域" prop="regionId"><!-- <el-input v-model="form.regionId" placeholder="请输入所属区域Id" /> --><el-select v-model="form.regionId" placeholder="请选择所属区域"><el-option v-for="item in regionList" :key="item.id" :label="item.regionName" :value="item.id" /></el-select></el-form-item><el-form-item label="员工头像" prop="image"><image-upload v-model="form.image" /></el-form-item><el-form-item label="是否启用" prop="status"><el-radio-group v-model="form.status"><el-radio v-for="dict in emp_status" :key="dict.value":label="parseInt(dict.value)">{{ dict.label }}</el-radio></el-radio-group></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></template>
</el-dialog>
<script>import { listRegion } from "@/api/manage/region";import { listRole } from "@/api/manage/role";import { loadAllParams } from "@/api/page";
// 查询角色列表const roleList = ref([]);function getRoleList() {listRole(loadAllParams).then(response => {roleList.value = response.rows;});}// 查询区域列表const regionList = ref([]);function getRegionList() {listRegion(loadAllParams).then(response => {regionList.value = response.rows;});}getRegionList();getRoleList();
</script>
新增员工
我们新增员工之后会发现归属区域和角色名称没有新增上,需要后端新增时候进行字段补充新增,同样的修改时也需要进行维护,实现如下
@Autowiredprivate RegionMapper regionMapper;
@Autowiredprivate RoleMapper roleMapper;
/*** 新增人员列表* * @param emp 人员列表* @return 结果*/@Overridepublic int insertEmp(Emp emp){emp.setCreateTime(DateUtils.getNowDate());
// 补充区域名称emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
// 补充角色信息Role role = roleMapper.selectRoleByRoleId(emp.getRoleId());emp.setRoleName(role.getRoleName());emp.setRoleCode(role.getRoleCode());return empMapper.insertEmp(emp);}
/*** 修改人员列表* * @param emp 人员列表* @return 结果*/@Overridepublic int updateEmp(Emp emp){emp.setUpdateTime(DateUtils.getNowDate());// 补充区域名称emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
// 补充角色信息Role role = roleMapper.selectRoleByRoleId(emp.getRoleId());emp.setRoleName(role.getRoleName());emp.setRoleCode(role.getRoleCode());return empMapper.updateEmp(emp);}
页面和数据库都可以成功新增,完美✌
3.2 同步存储
3.2.1 实现思路
同步存储:在员工表中有区域名称的冗余字段,在更新区域表的同时,同步更新员工表中区域名称。
-
优点:由于是单表查询操作,查询列表效率最高。
-
缺点:需要在区域修改时修改员工表中的数据,有额外的开销,数据也可能不一致。
比如修改了区域的名称,但是员工对应的负责区域还是无法进行同步修改,所以需要手动的在后端进行业务操作,实现步骤如下:
3.2.2 实现
-
sql
-- 根据区域id修改区域名称
update tb_emp set region_name='北京市奥体中心' where region_id=5
-
EmpMapper层
-
在RegionServiceImpl实现类进行区域新增时,同步更新员工表区域名称,需要进行事务管理,同成同败
效果如下✌
3.3 文件存储
3.3.1 本地存储
问题分析说明: 在若依框架目前的实现中,是把图片存储到了服务器本地的目录,通过服务进行访问,这样做存储的是比较省事,但是缺点也有很多:
-
硬件与网络要求:服务器通常需要高性能的硬件和稳定的网络环境,以保证文件传输的效率和稳定性。这可能会增加硬件和网络资源的成本和维护难度。
-
管理难度:服务器目录需要管理员进行配置和管理,包括权限设置、备份策略等。如果管理不善或配置不当,可能会引发一些安全问题和性能问题。
-
性能瓶颈:如果服务器处理能力不足或网络带宽不够,可能会导致性能瓶颈,影响文件上传、下载和访问的速度。
-
单点故障风险:服务器故障可能导致所有存储在其上的文件无法访问,尽管可以通过备份和冗余措施来降低这种风险,但单点故障的风险仍然存在。
为了解决上述问题呢,通常有两种解决方案:
-
自己搭建存储服务器,如:fastDFS 、MinIO
-
使用现成的云服务,如:阿里云,腾讯云,华为云
3.3.2 阿里云OSS
1.介绍
阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
在我们使用了阿里云OSS对象存储服务之后,我们的项目当中如果涉及到文件上传这样的业务,在前端进行文件上传并请求到服务端时,在服务器本地磁盘当中就不需要再来存储文件了。我们直接将接收到的文件上传到oss,由 oss帮我们存储和管理,同时阿里云的oss存储服务还保障了我们所存储内容的安全可靠。
使用的阿里云oss对象存储服务具体的使用步骤。
Bucket:存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。
SDK:Software Development Kit 的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。
简单说,sdk中包含了我们使用第三方云服务时所需要的依赖,以及一些示例代码。我们可以参照sdk所提供的示例代码就可以完成入门程序。
2.账号准备
下面我们根据之前介绍的使用步骤,完成准备工作:
-
注册阿里云账户(注册完成后需要实名认证)
阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
-
注册完账号之后,就可以登录阿里云
3.开通OSS云服务
登录之后搜索OSS
还未开通的新用户可以免费开通
回到OSS控制台,购买完成了~
创建Bucket
注意需要配置Bucket的访问权限:允许公共访问,公共读!!!
帝可得项目是通过管理系统实现文件上传,是Java代码与阿里云OSS实现对接,对接需要一个身份验证的凭证,这个凭证就是AccessKey。
-
创建AccessKey
-
配置AK & SK
以管理员身份打开CMD命令行,执行如下命令,配置系统的环境变量。
set OSS_ACCESS_KEY_ID=LTxxxxxxxxxxxxxxxxxxxxxku
set OSS_ACCESS_KEY_SECRET=JaaxxxxxxxxxxxxxxxxxxxxxxN2k
注意:将上述的ACCESS_KEY_ID 与 ACCESS_KEY_SECRET 的值一定一定一定一定一定一定要替换成自己的 。
-
执行一下命令,使更改生效
setx OSS_ACCESS_KEY_ID "%OSS_ACCESS_KEY_ID%"
setx OSS_ACCESS_KEY_SECRET "%OSS_ACCESS_KEY_SECRET%"
-
执行如下命令,验证环境变量是否生效。
echo %OSS_ACCESS_KEY_ID%
echo %OSS_ACCESS_KEY_SECRET%
到此环境变量配置成功了,环境变量的目的是为了SDK入门案例使用
3.3.3 阿里云OSS入门
-
打开文档
在Java公共模块common中导入SDK依赖
演示代码
新建test测试类,讲测试代码复制粘贴就ok✌
参照官方提供的SDK还有自己的bucket桶的配置改造一下代码,重启idea加载环境变量,即可实现文件上传功能:
需要替换的内容为:
-
endpoint:阿里云OSS中的bucket对应的域名
-
bucketName:Bucket名称
-
objectName:对象名称,在Bucket中存储的对象的名称
-
filePath:文件路径
package com.dkd.common;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class test {public static void main(String[] args) throws com.aliyuncs.exceptions.ClientException {// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-beijing.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "dkd-xiaoyang";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "头像.jpg";// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。String filePath= "D:\\学习\\images\\头像.jpg";
// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {InputStream inputStream = new FileInputStream(filePath);// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);// 创建PutObject请求。PutObjectResult result = ossClient.putObject(putObjectRequest);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
回到阿里云查看图片
3.3.4 x-file-storage
1.介绍
官方地址:X File Storage
一行代码实现多平台的存储,强大(๑•̀ㅂ•́)و✧
一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS、百度云 BOS、又拍云 USS、MinIO、 Amazon S3、GoogleCloud Storage、FastDFS、 Azure Blob Storage、Cloudflare R2、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 网易数帆 NOS、Ucloud US3、青云 QingStor、平安云 OBS、首云 OSS、IBM COS、其它兼容 S3 协议的存储平台。
2.集成步骤
-
在dkd-common的pom.xml中引入依赖
-
在dkd-admin的
application.yml
配置文件中先添加以下基础配置,再添加对应平台的配置
-
在启动类上加上
@EnableFileStorage
注解
-
找到照片上传的请求路径common/upload
-
找到ruoyi-admin模块中的CommonController类,修改单个文件上传的方法
原本的照片下载到若依默认的本地存储,现在需要使用x-file-storage将照片下载到阿里云OSS当中
修改代码👇
@Autowiredprivate FileStorageService fileStorageService;//注入实列/*** 通用上传请求(单个)*/@PostMapping("/upload")public AjaxResult uploadFile(MultipartFile file) throws Exception{try{
// // 上传文件路径
// String filePath = RuoYiConfig.getUploadPath();
// // 上传并返回新文件名称
// String fileName = FileUploadUtils.upload(filePath, file);
// String url = serverConfig.getUrl() + fileName;// 指定oss保存文件路径 dkd-images/2024/04/27/文件名String objectName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))+"/";
// 上传图片,返回文件信息FileInfo fileInfo = fileStorageService.of(file).setPath(objectName) //保存到相对路径下,为了方便管理,不需要可以不写.upload();AjaxResult ajax = AjaxResult.success();ajax.put("url", fileInfo.getUrl());ajax.put("fileName", fileInfo.getUrl()); // 注意:这里的值需要改为URL,因为前端的访问地址会做一个判断,如果以http开头就直接显示ajax.put("newFileName", fileInfo.getUrl());ajax.put("originalFilename", file.getOriginalFilename());return ajax;}catch (Exception e){return AjaxResult.error(e.getMessage());}}
需要注意的是fileName的值,前端进行判断,如果以http开头的话,不需要拼接,直接返回
重新启动项目,新增人员进行测试
在阿里云Backet进行查看,成功通过x-file-storage将照片下载到阿里云OSS当中~✌