资源服务
基本介绍
提供 oss 存储,sms 短信,附件,文档等接口服务,持久化数据到数据库进行管理。
引入依赖
txt
<!-- 资源 -->
<dependency>
<groupId>com.kyny</groupId>
<artifactId>cbb-service-resource</artifactId>
</dependency>
动态 oss
在 oss 对象存储的基础上,支持数据库动态配置。
解释:ossBuilder.template()会从数据库加载当前启用的对象存储,动态构建好一个 OssTemplate 提供使用。
注入 OssBuilder 使用
java
@RestController
@AllArgsConstructor
public class OssController {
private final OssBuilder ossBuilder;
@PostMapping("/upload/file")
@SneakyThrows
public R<CbbFile> uploadFile(@RequestParam MultipartFile file) {
return R.data(ossBuilder.template().putFile(file));
}
}
动态 sms
在 sms 短信的基础上,支持数据库动态配置。
解释:smsBuilder.template()会从数据库加载当前启用的 sms 短信通道,动态构建好一个 SmsTemplate 提供使用。
注入 SmsBuilder 使用
java
@RestController
@AllArgsConstructor
public class SmsController {
private final SmsBuilder smsBuilder;
@PostMapping("send-message")
public SmsResponse sendMessage(String phone) {
Map<String, String> param = Kv.newMap();
param.put("code", "xxxx");
SmsData smsData = new SmsData(param).setKey("code");
return smsBuilder.template().sendMessage(smsData, Collections.singleton(phone));
}
}
附件
引入依赖后,默认会提供 OSS 端点接口,其中包含上传附件的接口,使用该接口后,文件即可上传到文件服务器,并且数据库附件表也有存储记录。
java
@RestController
@AllArgsConstructor
@RequestMapping("/oss/endpoint")
@Api(value = "对象存储端点", tags = "对象存储端点")
public class OssEndpoint {
/**
* 对象存储构建类
*/
private final OssBuilder ossBuilder;
/**
* 附件表服务
*/
private final AttachService attachService;
/**
* 上传文件并保存至附件表
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-attach")
public R<CbbFile> putFileAttach(@RequestParam MultipartFile file) {
String fileName = file.getOriginalFilename();
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer attachId = buildAttach(fileName, file.getSize(), cbbFile);
cbbFile.setAttachId(attachId);
return R.data(cbbFile);
}
/**
* 上传文件并保存至附件表
* @param fileName 存储桶对象名称
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-attach-by-name")
public R<CbbFile> putFileAttach(@RequestParam String fileName, @RequestParam MultipartFile file) {
String originFileName = file.getOriginalFilename();
String extension = FileUtil.getSuffix(fileName);
if (StrUtil.isBlank(extension)) {
fileName = fileName + StringPool.DOT + FileUtil.getSuffix(originFileName);
}
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer attachId = buildAttach(fileName, file.getSize(), cbbFile);
cbbFile.setAttachId(attachId);
return R.data(cbbFile);
}
/**
* 构建附件表
* @param fileName 文件名
* @param fileSize 文件大小
* @param cbbFile 对象存储文件
* @return attachId
*/
private Integer buildAttach(String fileName, Long fileSize, CbbFile cbbFile) {
String fileExtension = FileUtil.getSuffix(fileName);
Attach attach = new Attach();
attach.setDomain(cbbFile.getDomain());
attach.setLink(cbbFile.getLink());
attach.setName(cbbFile.getName());
attach.setOriginalName(cbbFile.getOriginalName());
attach.setAttachSize(fileSize);
attach.setExtension(fileExtension);
attachService.save(attach);
return attach.getId();
}
}
文档
文档也属于对象存储的一部分,OSS 端点接口中也包含上传文档的接口,使用该接口后,文件即可上传到文件服务器,并且数据库文档表也有存储记录。
java
@RestController
@AllArgsConstructor
@RequestMapping("/oss/endpoint")
@Api(value = "对象存储端点", tags = "对象存储端点")
public class OssEndpoint {
/**
* 对象存储构建类
*/
private final OssBuilder ossBuilder;
/**
* 文档表服务
*/
private final DocsService docsService;
/**
* 上传文件并保存至文档
* @param fileName 存储桶对象名称
* @param nodeId 节点id
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-docs-by-name")
public R<CbbFile> putFileDocs(@RequestParam String fileName, @RequestParam Integer nodeId,
@RequestParam MultipartFile file) {
String originFileName = file.getOriginalFilename();
String extension = FileUtil.getSuffix(fileName);
if (StrUtil.isBlank(extension)) {
fileName = fileName + StringPool.DOT + FileUtil.getSuffix(originFileName);
}
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer docsId = buildDocs(nodeId, fileName, file.getSize(), cbbFile);
cbbFile.setDocsId(docsId);
return R.data(cbbFile);
}
/**
* 构建文档数据并保存
* @param nodeId 节点id
* @param fileName 文件名
* @param fileSize 文件大小
* @param cbbFile 对象存储文件
* @return attachId
*/
private Integer buildDocs(Integer nodeId, String fileName, Long fileSize, CbbFile cbbFile) {
String fileExtension = FileUtil.getSuffix(fileName);
Docs docs = new Docs();
docs.setDomain(cbbFile.getDomain());
docs.setLink(cbbFile.getLink());
docs.setName(cbbFile.getName());
docs.setOriginalName(cbbFile.getOriginalName());
docs.setAttachSize(fileSize);
docs.setNodeId(nodeId);
docs.setExtension(fileExtension);
docsService.save(docs);
return docs.getId();
}
}
对象存储端点
接口内容如下
java
@RestController
@AllArgsConstructor
@RequestMapping("/oss/endpoint")
@Api(value = "对象存储端点", tags = "对象存储端点")
public class OssEndpoint {
/**
* 对象存储构建类
*/
private final OssBuilder ossBuilder;
/**
* 附件表服务
*/
private final AttachService attachService;
/**
* 文档表服务
*/
private final DocsService docsService;
/**
* 创建存储桶
* @param bucketName 存储桶名称
* @return Bucket
*/
@SneakyThrows
@PostMapping("/make-bucket")
public R<String> makeBucket(@RequestParam String bucketName) {
ossBuilder.template().makeBucket(bucketName);
return R.success("创建成功");
}
/**
* 创建存储桶
* @param bucketName 存储桶名称
* @return R
*/
@SneakyThrows
@PostMapping("/remove-bucket")
public R<String> removeBucket(@RequestParam String bucketName) {
ossBuilder.template().removeBucket(bucketName);
return R.success("删除成功");
}
/**
* 拷贝文件
* @param fileName 存储桶对象名称
* @param destBucketName 目标存储桶名称
* @param destFileName 目标存储桶对象名称
* @return R
*/
@SneakyThrows
@PostMapping("/copy-file")
public R<String> copyFile(@RequestParam String fileName, @RequestParam String destBucketName, String destFileName) {
ossBuilder.template().copyFile(fileName, destBucketName, destFileName);
return R.success("操作成功");
}
/**
* 获取文件信息
* @param fileName 存储桶对象名称
* @return InputStream
*/
@SneakyThrows
@GetMapping("/stat-file")
public R<OssFile> statFile(@RequestParam String fileName) {
return R.data(ossBuilder.template().statFile(fileName));
}
/**
* 获取文件相对路径
* @param fileName 存储桶对象名称
* @return String
*/
@SneakyThrows
@GetMapping("/file-path")
public R<String> filePath(@RequestParam String fileName) {
return R.data(ossBuilder.template().filePath(fileName));
}
/**
* 获取文件外链
* @param fileName 存储桶对象名称
* @return String
*/
@SneakyThrows
@GetMapping("/file-link")
public R<String> fileLink(@RequestParam String fileName) {
return R.data(ossBuilder.template().fileLink(fileName));
}
/**
* 上传文件
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file")
public R<CbbFile> putFile(@RequestParam MultipartFile file) {
CbbFile cbbFile = ossBuilder.template().putFile(file.getOriginalFilename(), file.getInputStream());
return R.data(cbbFile);
}
/**
* 上传文件
* @param fileName 存储桶对象名称
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-by-name")
public R<CbbFile> putFile(@RequestParam String fileName, @RequestParam MultipartFile file) {
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
return R.data(cbbFile);
}
/**
* 上传文件并保存至附件表
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-attach")
public R<CbbFile> putFileAttach(@RequestParam MultipartFile file) {
String fileName = file.getOriginalFilename();
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer attachId = buildAttach(fileName, file.getSize(), cbbFile);
cbbFile.setAttachId(attachId);
return R.data(cbbFile);
}
/**
* 上传文件并保存至附件表
* @param fileName 存储桶对象名称
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-attach-by-name")
public R<CbbFile> putFileAttach(@RequestParam String fileName, @RequestParam MultipartFile file) {
String originFileName = file.getOriginalFilename();
String extension = FileUtil.getSuffix(fileName);
if (StrUtil.isBlank(extension)) {
fileName = fileName + StringPool.DOT + FileUtil.getSuffix(originFileName);
}
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer attachId = buildAttach(fileName, file.getSize(), cbbFile);
cbbFile.setAttachId(attachId);
return R.data(cbbFile);
}
/**
* 上传文件并保存至附件表
* @param fileName 存储桶对象名称
* @param file 文件
* @return ObjectStat
*/
@SneakyThrows
@PostMapping("/put-file-docs-by-name")
public R<CbbFile> putFileDocs(@RequestParam String fileName, @RequestParam Integer nodeId,
@RequestParam MultipartFile file) {
String originFileName = file.getOriginalFilename();
String extension = FileUtil.getSuffix(fileName);
if (StrUtil.isBlank(extension)) {
fileName = fileName + StringPool.DOT + FileUtil.getSuffix(originFileName);
}
CbbFile cbbFile = ossBuilder.template().putFile(fileName, file.getInputStream());
Integer docsId = buildDocs(nodeId, fileName, file.getSize(), cbbFile);
cbbFile.setDocsId(docsId);
return R.data(cbbFile);
}
/**
* 构建附件表
* @param fileName 文件名
* @param fileSize 文件大小
* @param cbbFile 对象存储文件
* @return attachId
*/
private Integer buildAttach(String fileName, Long fileSize, CbbFile cbbFile) {
String fileExtension = FileUtil.getSuffix(fileName);
Attach attach = new Attach();
attach.setDomain(cbbFile.getDomain());
attach.setLink(cbbFile.getLink());
attach.setName(cbbFile.getName());
attach.setOriginalName(cbbFile.getOriginalName());
attach.setAttachSize(fileSize);
attach.setExtension(fileExtension);
attachService.save(attach);
return attach.getId();
}
/**
* 构建附件表
* @param fileName 文件名
* @param fileSize 文件大小
* @param cbbFile 对象存储文件
* @return attachId
*/
private Integer buildDocs(Integer nodeId, String fileName, Long fileSize, CbbFile cbbFile) {
String fileExtension = FileUtil.getSuffix(fileName);
Docs docs = new Docs();
docs.setDomain(cbbFile.getDomain());
docs.setLink(cbbFile.getLink());
docs.setName(cbbFile.getName());
docs.setOriginalName(cbbFile.getOriginalName());
docs.setAttachSize(fileSize);
docs.setNodeId(nodeId);
docs.setExtension(fileExtension);
docsService.save(docs);
return docs.getId();
}
/**
* 删除文件
* @param fileName 存储桶对象名称
* @return R
*/
@SneakyThrows
@PostMapping("/remove-file")
public R<String> removeFile(@RequestParam String fileName) {
ossBuilder.template().removeFile(fileName);
return R.success("操作成功");
}
/**
* 批量删除文件
* @param fileNames 存储桶对象名称集合
* @return R
*/
@SneakyThrows
@PostMapping("/remove-files")
public R<String> removeFiles(@RequestParam String fileNames) {
ossBuilder.template().removeFiles(StrUtil.split(fileNames, ','));
return R.success("操作成功");
}
}
短信端点
接口内容如下
java
@RestController
@AllArgsConstructor
@RequestMapping("/sms/endpoint")
@Api(value = "短信服务端点", tags = "短信服务端点")
public class SmsEndpoint {
/**
* 短信服务构建类
*/
private final SmsBuilder smsBuilder;
// ================================= 短信服务校验 =================================
/**
* 短信验证码发送
* @param phone 手机号
*/
@SneakyThrows
@PostMapping("/send-validate")
public R<SmsCode> sendValidate(@RequestParam String phone) {
Map<String, String> params = new HashMap<>(1);
params.put(PARAM_KEY, RandomUtil.randomNumbers(6));
SmsCode smsCode = smsBuilder.template().sendValidate(new SmsData(params).setKey(PARAM_KEY), phone);
return smsCode.isSuccess() ? R.data(smsCode, SEND_SUCCESS) : R.fail(SEND_FAIL);
}
/**
* 校验短信
* @param smsCode 短信校验信息
*/
@SneakyThrows
@PostMapping("/validate-message")
public R<String> validateMessage(SmsCode smsCode) {
boolean validate = smsBuilder.template().validateMessage(smsCode);
return validate ? R.success(VALIDATE_SUCCESS) : R.fail(VALIDATE_FAIL);
}
// ========== 通用短信自定义发送(支持自定义params参数传递, 推荐用于测试, 不推荐用于生产环境) ==========
/**
* 发送信息
* @param params 自定义短信参数
* @param phones 手机号集合
*/
@SneakyThrows
@PostMapping("/send-message")
public R<String> sendMessage(@RequestParam String code, @RequestParam String params, @RequestParam String phones) {
SmsData smsData = new SmsData(JsonUtil.readMap(params, String.class, String.class));
return send(code, smsData, phones);
}
// ========== 指定短信服务发送(可根据各种场景自定拓展定制, 损失灵活性增加安全性, 推荐用于生产环境) ==========
/**
* 短信通知
* @param phones 手机号集合
*/
@SneakyThrows
@PostMapping("/send-notice")
public R<String> sendNotice(@RequestParam String phones) {
Map<String, String> params = new HashMap<>(3);
params.put("title", "通知标题");
params.put("content", "通知内容");
params.put("date", "通知时间");
SmsData smsData = new SmsData(params);
return send(smsData, phones);
}
// ================================= 通用短信发送接口 =================================
/**
* 通用短信发送接口
* @param smsData 短信内容
* @param phones 手机号列表
* @return 是否发送成功
*/
private R<String> send(SmsData smsData, String phones) {
SmsResponse response = smsBuilder.template().sendMessage(smsData, StrUtil.split(phones, ','));
return response.isSuccess() ? R.success(SEND_SUCCESS) : R.fail(SEND_FAIL);
}
/**
* 通用短信发送接口
* @param code 资源编号
* @param smsData 短信内容
* @param phones 手机号列表
* @return 是否发送成功
*/
private R<String> send(String code, SmsData smsData, String phones) {
SmsResponse response = smsBuilder.template(code).sendMessage(smsData, StrUtil.split(phones, ','));
return response.isSuccess() ? R.success(SEND_SUCCESS) : R.fail(SEND_FAIL);
}
}