Skip to content
On this page

资源服务

基本介绍

提供 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);
	}

}