Kotlin& Java 开发的 SpringBootStarter 附件操作库开源!包含图片处理、附件增删改查、HTTP 端点等功能。

2021-06-21 08:00:53 +08:00
 skypyb

这是一个由 Kotlin&Java 混编开发的附件操作库 (SpringBootStarter)。
纯 Java 开发的 SpringBoot 工程可以直接引入一键使用。
经历过生产环境验证,基本功能方面没发现有什么问题。
核心用处请参考下方 README 或仓库。


代码结构友好。适合学习 Kotlin 和参考编写属于你的 SpringBootStarter 。


如果你觉得多少有些用处的话,请不要吝啬你的 star 。QAQ


仓库地址: https://github.com/sorakylin/poet

下面是 README, 可以进 github 那边观看。



poet

这是由 Kotlin 编写的 SpringBoot Starter 附件操作库。 一键集成进你的应用使其能够更便捷的操作附件



概述

在系统开发中对于附件的操作多少得废些功夫, 尤其体现在个人开发者业余时间写项目时, 脱离了公司基础服务的情况下基本只能一个个去手写文件的增删改查。

使用云服务时如果你的附件不太正经,为了避免触发风控你还是得在本地保存一份。

此项目即是为了提升开发者的效率而诞生,基于本地文件系统。 一键引入即可实现对附件的各种操作。 由个人开发并在个人项目中使用过一段时间后开源。

使用 Kotlin & Java 混编开发,所有的逻辑都基于 Kotlin 实现。 为了方便没有使用过 Kotlin 的开发者也能够轻松的看源码+自定义组件的扩展, 所有接口抽象层使用了 Java 来定义



功能特性



快速开始:

上面说起来似乎东西不少, 但实际上用默认的组件+傻瓜式配置已经足以满足大部分需求


1 、首先通过 Maven 引入依赖

<dependency>
  <groupId>com.skypyb.poet</groupId>
  <artifactId>poet-spring-boot-starter</artifactId>
  <version>v1.1.0.RELEASE</version>
</dependency>


2 、然后在项目的application.yml中进行最小配置

poet:
  #存储路径 支持 windows 系统, 如 E:\tempfile\annex
  storage-location: /home/static/poet

3 、即可开始愉快使用





配置项

key 默认值 说明
poet.storageLocation 非空. 附件默认默认储存位置。 附件最终保存的路径为 storageLocation+module+name
poet.enableDBStore true 是否使用 DB 储存附件信息, 关闭的话则无法使用 HTTP 相关操作
poet.enableWebResource true 是否启用 web 资源层.
poet.webUrlPrefix /poet web 资源接口请求路径前缀
poet.defaultModule 默认模块, 在文件保存时若不指定则将直接保存到此模块之中. 为空时直接保存在 storageLocation
poet.tableName poet_annex 储存附件信息的表名



默认 HTTP 端点

端点 说明 入参
GET /poet/view/{name} 预览文件, 解析后缀响应对应的 Content-Type 。 可直接显示图片
GET /poet/view-media/{name} 预览媒体, 包括视频和音频
GET /poet/download/{name} 下载附件
POST /up 上传附件, 可指定模块(非必须) file: MultipartFile, module: String?
GET /bs/{name} 获取 DB 中存储的附件业务信息
DELETE /bs/{name} 删除一个附件



图片处理

图片处理的统一接口, 可自行拓展图片处理方式。
自带默认的处理实现DefaultImageHandler,可自定义宽、高、压缩比、输出格式(不支持 webp)

@FunctionalInterface
public interface PoetImageHandler {

    /**
     * 涉及到图片处理,  原名已经无意义了。
     * 这个图片的原名在流程中将会被抹去,  自己保存时定义新的名字
     *
     * @param bytes 图片字节数组
     * @return 新图片的字节数组
     */
    byte[] handle(@NotNull byte[] bytes);
}

使用方法:

//得到原图的 Bytes, 也可以是 InputStream 。InputStream 在传入 warp()后会被自动关闭
byte[] imgBytes = getBytes(originImage);

//创建一个将图片处理为宽度 980px + 压缩比 0.8 + 格式化为 jpg 的处理器
DefaultImageHandler handler = new DefaultImageHandler(980, Integer.MAX_VALUE, 0.8f, "jpg");

//得到的结果 Map 中,key 即为 use 时传入的 key, value 是处理完毕的结果。 
//可多次调用 use(), invoke()内的回调将会循环触发。Map 结果是所有 use 的 key + handler 处理结果
Map<String, PoetAnnex> invokeResult = PoetImageWrap.<String>warp(imgBytes)
    .use("w980", handler)
    .invoke((k, bytes) -> {//k = "w980"
        return poetAnnexContext.save(bytes, "name.jpg", "module");
    });

//通过指定的 key 得到 Map 中对应经过对应处理的图片
PoetAnnex thumbnailAnnex = invokeResult.get("w980");



拦截器

实现 PoetHandlerInterceptor 接口+交给 Spring 控制 即可注册拦截器, 支持排序

返回 true 表示通过, 也可以自定义异常抛出来中止操作

Mode 有三种, 分别为 ACCESS 、DELETE 、SAVE , 更多细节注释可以查看源码


示例:

@Slf4j
@Component
public class LogInterceptor implements PoetHandlerInterceptor {

    @Override
    public boolean preHandle(Mode mode, String name, @Nullable String module) {
        log.info("Annex operation record. mode:{}, name:{}, module:{} ", mode, name, module);
        return true;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}



组件扩展

这是一个基本的扩展配置示例

@Configuration
public class PoetAnnexConfig {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //使用自带的 Pg 存储替换默认的 MySQL
    @Bean
    public PoetAnnexRepository poetAnnexRepository() {
        return new PostgresPoetAnnexRepository(jdbcTemplate);
    }

    //自定义附件的目录结构分割方式
    @Bean
    public PoetAnnexSlicer poetAnnexSlicer() {
        return new Hash2AnnexSlicer();
    }

    //自定义附件名字生成策略 (默认 UUID,  需保证全局唯一)
    @Bean
    public PoetAnnexNameGenerator poetAnnexNameGenerator() {
        return new RandomNameGenerator();
    }
}

看出来了吧? 只要你实现了对应的接口, 并且将其作为一个 Bean 交给 Spring 管理。 那么就会替换掉默认的实现


目前所有支持自定义的组件



附录

附件操作上下文提供的所有操作附件方法

public interface PoetAnnexContext {

    PoetAnnex save(InputStream in, String name);


    PoetAnnex save(InputStream in, String name, String module);


    PoetAnnex save(byte[] data, String name);


    PoetAnnex save(byte[] data, String name, String module);


    boolean exist(String name);


    void delete(String name);


    byte[] getBytes(String name);


    void view(String name, HttpServletResponse response);


    void viewMedia(String name, HttpServletResponse response);


    void viewMedia(String name, HttpServletRequest request, HttpServletResponse response);


    void down(String name, HttpServletResponse response);


    void down(String name, String realName, HttpServletResponse response);

}


说在最后

嘛... 总之无限欢迎 PR
如果帮到了你,请点个 star~



823 次点击
所在节点    分享创造
2 条回复
kylix
2021-06-21 10:29:38 +08:00
好,这就去看看...
skypyb
2021-06-21 15:34:51 +08:00
好凉凉= =

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/784697

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX