oss 模块搭建与实现
这里采用的方式是通过后端传 oss,可以对比下 谷粒商城里面的,从后端拿上传凭证,然后前端直传的方式
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!-- 阿里云oss依赖 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
配置文件
server.port=8207
spring.application.name=service-oss
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.cloud.nacos.discovery.server-addr=localhost:8848
aliyun.oss.endpoint=oss-cn-hangzhou.aliyuncs.com
aliyun.oss.accessKeyId=LTAI5tCvwJjdKorLjaS9ynds
aliyun.oss.secret=xxxx
aliyun.oss.bucket=xxxx
配置常量读取
@Component
public class ConstantOssPropertiesUtils implements InitializingBean {
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.secret}")
private String secret;
@Value("${aliyun.oss.bucket}")
private String bucket;
public static String EDNPOINT;
public static String ACCESS_KEY_ID;
public static String SECRECT;
public static String BUCKET;
@Override
public void afterPropertiesSet() throws Exception {
EDNPOINT = endpoint;
ACCESS_KEY_ID = accessKeyId;
SECRECT = secret;
BUCKET = bucket;
}
}
Service 核心实现
@Service
public class FileServiceImpl implements FileService {
//获取上传文件
@Override
public String upload(MultipartFile file) {
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = ConstantOssPropertiesUtils.EDNPOINT;
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = ConstantOssPropertiesUtils.ACCESS_KEY_ID;
String accessKeySecret = ConstantOssPropertiesUtils.SECRECT;
String bucketName = ConstantOssPropertiesUtils.BUCKET;
try {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 获取文件流
InputStream inputStream = file.getInputStream();
String filename = file.getOriginalFilename();
//为防止文件名重复造成文件覆盖,生成随机值,添加到文件中
String uuid = UUID.randomUUID().toString().replaceAll("-","");
filename = uuid + filename;
//按照当前日期创建文件夹,上传到当前文件夹里面 /2021/02/01/01.jpg
String timeUrl = new DateTime().toString("yyyy/MM/dd");
filename = timeUrl + "/" + filename;
// 调用方法,实现上传 参数2为上传文件(路径+)名称
ossClient.putObject(bucketName, filename, inputStream);
// 关闭OSSClient。
ossClient.shutdown();
// 返回上传后文件路径
// 例:https://yygh-atguigu-li.oss-cn-beijing.aliyuncs.com/qq.jpg
String url = "https://" + bucketName + "." + endpoint + "/" + filename;
return url;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
controller
@RestController
@RequestMapping("/api/oss/file")
public class FileApiController {
@Autowired
private FileService fileService;
//上传文件到阿里云
@PostMapping("fileUpload")
public Result fileUpload(MultipartFile file){ //通过MultipartFile可以得到上传文件
//获取上传文件
String url = fileService.upload(file); //上传后得到路径
return Result.ok(url);
}
}
用户认证功能实现
用户登录成功后都要进行身份认证,认证通过后才可以预约挂号
认证过程:用户填写信息(姓名、证件类型、证件号码和证件照片)==> 平台审批
用户认证设计接口:
1、提交认证
2、上传证件图片
3、获取提交认证信息
后端实现
service
@Override
public void userAuth(Long userId, UserAuthVo userAuthVo) {
//1.根据用户id查询用户信息
UserInfo userInfo = baseMapper.selectById(userId);
//2.设置认证信息
//认证人姓名
userInfo.setName(userAuthVo.getName());
//其他认证信息
userInfo.setCertificatesType(userAuthVo.getCertificatesType());
userInfo.setCertificatesNo(userAuthVo.getCertificatesNo());
userInfo.setCertificatesUrl(userAuthVo.getCertificatesUrl());
userInfo.setAuthStatus(AuthStatusEnum.AUTH_RUN.getStatus());
//3.进行信息更新
baseMapper.updateById(userInfo);
}
用户信息解析
public class AuthContextHolder {
//获取当前用户id
public static Long getUserId(HttpServletRequest request) {
//从header中获取token
String token = request.getHeader("token");
//从token中获取userid
Long userId = JwtHelper.getUserId(token);
return userId;
}
//获取当前用户名称
public static String getUserName(HttpServletRequest request) {
//从header中获取token
String token = request.getHeader("token");
//从token中获取userid
String userName = JwtHelper.getUserName(token);
return userName;
}
}
接口实现
@ApiOperation("用户认证接口")
@PostMapping("auth/userAuth")
public Result userAuth(@RequestBody UserAuthVo userAuthVo, HttpServletRequest request) {
// 传递 用户id 和 认证数据vo对象
userInfoService.userAuth(AuthContextHolder.getUserId(request), userAuthVo);
return Result.ok();
}
@ApiOperation("获取用户id信息接口")
@GetMapping("auth/getUserInfo")
public Result getUserInfo(HttpServletRequest request) {
Long userId = AuthContextHolder.getUserId(request);
UserInfo userInfo = userInfoService.getById(userId);
return Result.ok(userInfo);
}
前端实现
//用户认证接口
saveUserAuth(userAuth) {
return request({
url: `${api_name}/auth/userAuth`,
method: 'post',
data: userAuth
})
},
//根据userid获取用户信息
getUserInfo() {
return request({
url: `${api_name}/auth/getUserInfo`,
method: `get`
})
},
<template>
<!-- header -->
<div class="nav-container page-component">
<!--左侧导航 #start -->
<div class="nav left-nav">
<div class="nav-item selected">
<span
class="v-link selected dark"
οnclick="javascript:window.location='/user'"
>实名认证
</span>
</div>
<div class="nav-item">
<span
class="v-link selected dark"
οnclick="javascript:window.location='/order'"
>
挂号订单
</span>
</div>
<div class="nav-item">
<span
class="v-link clickable dark"
οnclick="javascript:window.location='/patient'"
>
就诊人管理
</span>
</div>
<div class="nav-item">
<span class="v-link clickable dark"> 修改账号信息 </span>
</div>
<div class="nav-item">
<span class="v-link clickable dark"> 意见反馈 </span>
</div>
</div>
<!-- 左侧导航 #end -->
<!-- 右侧内容 #start -->
<div class="page-container">
<div>
<div class="title">实名认证</div>
<div class="status-bar">
<div class="status-wrapper">
<span class="iconfont"></span>{{ userInfo.param.authStatusString }}
</div>
</div>
<div class="tips">
<span class="iconfont"></span>
完成实名认证后才能添加就诊人,正常进行挂号,为了不影响后续步骤,建议提前实名认证。
</div>
<div class="form-wrapper" v-if="userInfo.authStatus == 0">
<div>
<el-form
:model="userAuah"
label-width="110px"
label-position="left"
>
<el-form-item prop="name" label="姓名:" class="form-normal">
<div class="name-input">
<el-input
v-model="userAuah.name"
placeholder="请输入联系人姓名全称"
class="input v-input"
/>
</div>
</el-form-item>
<el-form-item prop="certificatesType" label="证件类型:">
<el-select
v-model="userAuah.certificatesType"
placeholder="请选择证件类型"
class="v-select patient-select"
>
<el-option
v-for="item in certificatesTypeList"
:key="item.value"
:label="item.name"
:value="item.name"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="certificatesNo" label="证件号码:">
<el-input
v-model="userAuah.certificatesNo"
placeholder="请输入联系人证件号码"
class="input v-input"
/>
</el-form-item>
<el-form-item prop="name" label="上传证件:">
<div class="upload-wrapper">
<div class="avatar-uploader">
<el-upload
class="avatar-uploader"
:action="fileUrl"
:show-file-list="false"
:on-success="onUploadSuccess"
>
<div class="upload-inner-wrapper">
<img
v-if="userAuah.certificatesUrl"
:src="userAuah.certificatesUrl"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<div v-if="!userAuah.certificatesUrl" class="text">
上传证件合照
</div>
</div>
</el-upload>
</div>
<img
src="//img.114yygh.com/static/web/auth_example.png"
class="example"
/>
</div>
</el-form-item>
</el-form>
<div class="bottom-wrapper">
<div class="button-wrapper">
<div class="v-button" @click="saveUserAuah()">
{{ submitBnt }}
</div>
</div>
</div>
</div>
</div>
<div class="context-container" v-if="userInfo.authStatus != 0">
<div>
<el-form
:model="formData"
label-width="110px"
label-position="right"
>
<el-form-item prop="name" label="姓名:" class="form-normal">
<div class="name-input">
{{ userInfo.name }}
</div>
</el-form-item>
<el-form-item prop="name" label="证件类型:">
{{ userInfo.certificatesType }}
</el-form-item>
<el-form-item prop="name" label="证件号码:">
{{ userInfo.certificatesNo }}
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
<!-- 右侧内容 #end -->
<!-- 登录弹出框 -->
</div>
<!-- footer -->
</template>
<script>
import "~/assets/css/hospital_personal.css";
import "~/assets/css/hospital.css";
import "~/assets/css/personal.css";
import dictApi from "@/api/dict";
import userInfoApi from "@/api/userInfo";
const defaultForm = {
name: "",
certificatesType: "",
certificatesNo: "",
certificatesUrl: "",
};
export default {
data() {
return {
userAuah: defaultForm,
certificatesTypeList: [],
fileUrl: "http://localhost:81/api/oss/file/fileUpload",
userInfo: {
param: {},
},
submitBnt: "提交",
};
},
created() {
this.init();
},
methods: {
init() {
this.getUserInfo();
this.getDict();
},
getUserInfo() {
userInfoApi.getUserInfo().then((response) => {
this.userInfo = response.data;
});
},
saveUserAuah() {
if (this.submitBnt == "正在提交...") {
this.$message.info("重复提交");
return;
}
this.submitBnt = "正在提交...";
userInfoApi
.saveUserAuth(this.userAuah)
.then((response) => {
this.$message.success("提交成功");
window.location.reload();
})
.catch((e) => {
this.submitBnt = "提交";
});
},
getDict() {
dictApi.findByDictCode("CertificatesType").then((response) => {
this.certificatesTypeList = response.data;
});
},
onUploadSuccess(response, file) {
if (response.code !== 200) {
this.$message.error("上传失败");
return;
}
// 填充上传文件列表
this.userAuah.certificatesUrl = file.response.data;
},
},
};
</script>
<style>
.header-wrapper .title {
font-size: 16px;
margin-top: 0;
}
.content-wrapper {
margin-left: 0;
}
.patient-card .el-card__header .detail {
font-size: 14px;
}
.page-container .title {
letter-spacing: 1px;
font-weight: 700;
color: #333;
font-size: 16px;
margin-top: 0;
margin-bottom: 20px;
}
.page-container .tips {
width: 100%;
padding-left: 0;
}
.page-container .form-wrapper {
padding-left: 92px;
width: 580px;
}
.form-normal {
height: 40px;
}
.bottom-wrapper {
width: 100%;
padding: 0;
margin-top: 0;
}
</style>
上传文件报错
oss模块添加配置
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB
预约挂号页面调整
预约挂号前验证 是否实名认证
// 预约
schedule(depcode) {
// 登录判断
let token = cookie.get("token");
if (!token) {
loginEvent.$emit("loginDialogEvent");
return;
} //判断认证
userInfoApi.getUserInfo().then((response) => {
let authStatus = response.data.authStatus; // 状态为2认证通过
if (!authStatus || authStatus != 2) {
window.location.href = "/user";
return;
}
});
window.location.href =
"/hospital/schedule?hoscode=" +
this.hospital.hoscode +
"&depcode=" +
depcode;
},
就诊人管理
预约下单需要选择就诊人,因此我们要实现就诊人管理,前端就诊人管理其实就是要实现一个完整的增删改查
user 远程调用 cmn 模块,查看数据字典
这个功能需要提一下的这块的处理,对于数据的封装,所有的基础资料只存了 code, 剩余的信息远程调用 cmn 模块获取,重点注意下这里的
//根据登录用户id获取就诊列表
@Override
public List<Patient> findAllUserId(Long userId) {
//据登录用户id查询所有就诊人信息列表
QueryWrapper<Patient> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId);
List<Patient> patientList = baseMapper.selectList(wrapper);
//通过远程调用得到部分编码对应的具体内容,查询数据字典表中的内容 例如 编号2000对应的是身份证方式
patientList.stream().forEach(item -> {
this.packPatient(item); //将param中的一些属性封装进patient中
});
return patientList;
}
//将param中的一些属性封装进patient中
private Patient packPatient(Patient patient) {
//根据证件类型,获取证件类型名称
String certificatesTypeString = dictFeignClient.getName
(DictEnum.CERTIFICATES_TYPE.getDictCode(), patient.getCertificatesType());
//联系人证件类型
String contactsCertificatesTypeString = dictFeignClient.getName
(DictEnum.CERTIFICATES_TYPE.getDictCode(), patient.getContactsCertificatesType());
//省
String provinceString = dictFeignClient.getName(patient.getProvinceCode());
//市
String cityString = dictFeignClient.getName(patient.getCityCode());
//区
String districtString = dictFeignClient.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;
}
其他代码可自行参考资料中的代码
做完之后的效果
![image-20221127190249380](https://i-blog.csdnimg.cn/blog_migrate/caf0830b75fd6249497a4b0e0aea28e2.png)
![image-20221127190304821](https://i-blog.csdnimg.cn/blog_migrate/f23573d8e454d3740a73ba274698cd8c.png)
用户管理
前面我们做了用户登录、用户认证与就诊人,现在我们需要把这些信息在我们的平台管理系统做一个统一管理
除去增删查改还有 锁定,认证审批接口,也比较常规,简单看下效果,代码就不看了