DataCap 自定义 File 转换器

2024-06-15 02:28

本文主要是介绍DataCap 自定义 File 转换器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

DataCap 支持自定义 File 转换器,使用者可以编写自己的文件转换器集成到 DataCap 中。该文档主要讲解如何快速集成一个文件转换器到 DataCap 系统中。

该模块我们主要使用到的是 file 模块内的代码,我们本文使用 json 来做示例。

模块基本配置


新建项目后在 pom.xml 文件中增加以下内容:

<dependencies><dependency><groupId>org.jetbrains.kotlin</groupId><artifactId>kotlin-reflect</artifactId></dependency><dependency><groupId>com.google.inject</groupId><artifactId>guice</artifactId></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></dependency><dependency><groupId>io.edurt.datacap</groupId><artifactId>datacap-file-spi</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency>
</dependencies><build><plugins><plugin><groupId>org.jetbrains.dokka</groupId><artifactId>dokka-maven-plugin</artifactId></plugin></plugins>
</build>

我们添加 datacap-file-spi 依赖,这样我们就可以实现集成文件转换器。

Json Module 加载器


package io.edurt.datacap.file.jsonimport com.google.inject.multibindings.Multibinder
import io.edurt.datacap.file.File
import io.edurt.datacap.file.FileModuleclass JsonModule : FileModule()
{override fun configure(){Multibinder.newSetBinder(this.binder(), File::class.java).addBinding().to(JsonFile::class.java)}
}

Json File 转换器


package io.edurt.datacap.file.jsonimport com.fasterxml.jackson.core.JsonEncoding
import com.fasterxml.jackson.core.JsonFactory
import com.fasterxml.jackson.core.JsonGenerationException
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import io.edurt.datacap.common.utils.DateUtils
import io.edurt.datacap.file.File
import io.edurt.datacap.file.FileConvert.formatFile
import io.edurt.datacap.file.model.FileRequest
import io.edurt.datacap.file.model.FileResponse
import org.slf4j.LoggerFactory.getLogger
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.Objects.requireNonNullclass JsonFile : File
{private val log = getLogger(this::class.java)override fun format(request: FileRequest): FileResponse{val response = FileResponse()try{log.info("${name()} format start time [ ${DateUtils.now()} ]")log.info("${name()} format headers start")response.headers = request.headerslog.info("${name()} format headers end")log.info("${name()} format columns start")val mapper = ObjectMapper()val columns = mutableListOf<Any>()request.columns.forEach { column ->val jsonNode = mapper.createObjectNode()for (headerIndex in request.headers.indices){val header = request.headers[headerIndex] as Stringwhen (column){is List<*> -> jsonNode.putPOJO(header, column[headerIndex])else -> jsonNode.putPOJO(header, column)}}columns.add(jsonNode)}response.columns = columnslog.info("${name()} format columns end")log.info("${name()} format end time [ ${DateUtils.now()} ]")response.successful = true}catch (e: IOException){response.successful = falseresponse.message = e.message}return response}override fun formatStream(request: FileRequest): FileResponse{val response = FileResponse()try{requireNonNull("Stream must not be null")log.info("${name()} format stream start time [ ${DateUtils.now()} ]")val mapper = ObjectMapper()request.stream?.let {BufferedReader(InputStreamReader(it, Charsets.UTF_8)).use { reader ->val jsonNode: JsonNode = mapper.readTree(reader)log.info("${name()} format stream json node count [ ${jsonNode.size()} ]")val headers = mutableListOf<Any>()if (jsonNode.isArray && jsonNode.size() > 0){jsonNode[0].fieldNames().forEachRemaining { headers.add(it) }}response.headers = headersval columns = mutableListOf<Any>()if (jsonNode.isArray){jsonNode.elements().forEachRemaining { node ->val column = mutableMapOf<String, Any?>()node.fields().forEachRemaining { field ->column[field.key] = field.value}columns.add(column)}}response.columns = columnsit.close()}}log.info("${name()} format stream end time [ ${DateUtils.now()} ]")response.successful = true}catch (e: IOException){response.successful = falseresponse.message = e.message}return response}override fun writer(request: FileRequest): FileResponse{val response = FileResponse()try{log.info("${name()} writer origin path [ ${request.path} ]")log.info("${name()} writer start time [ ${DateUtils.now()} ]")val file = formatFile(request, name())log.info("${name()} writer file absolute path [ ${file.absolutePath} ]")val factory = JsonFactory()factory.createGenerator(file, JsonEncoding.UTF8).use { generator ->generator.writeStartArray()request.columns.forEach { column ->generator.writeStartObject()for (headerIndex in request.headers.indices){when (column){is List<*> -> generator.writeObjectField(request.headers[headerIndex] as String, column[headerIndex])is ObjectNode ->{generator.codec = ObjectMapper()val header = request.headers[headerIndex] as Stringgenerator.writeObjectField(header, column.get(header))}else -> generator.writeObjectField(request.headers[headerIndex] as String, column)}}generator.writeEndObject()}generator.writeEndArray()}log.info("${name()} writer end time [ ${DateUtils.now()} ]")response.path = file.absolutePathresponse.successful = true}catch (e: IOException){response.successful = falseresponse.message = e.message}catch (e: JsonGenerationException){response.successful = falseresponse.message = e.message}return response}override fun reader(request: FileRequest): FileResponse{val response = FileResponse()try{log.info("${name()} reader origin path [ ${request.path} ]")log.info("${name()} reader start time [ ${DateUtils.now()} ]")val file = formatFile(request, name())log.info("${name()} reader file absolute path [ ${file.absolutePath} ]")val mapper = ObjectMapper()val jsonNode: JsonNode = mapper.readTree(file)log.info("${name()} reader file json node count [ ${jsonNode.size()} ]")log.info("${name()} reader file headers start")val headers = mutableListOf<Any>()if (jsonNode.isArray && jsonNode.size() > 0){jsonNode[0].fieldNames().forEachRemaining { headers.add(it) }}response.headers = headerslog.info("${name()} reader file headers end")log.info("${name()} reader file columns start")val columns = mutableListOf<Any>()if (jsonNode.isArray){jsonNode.elements().forEachRemaining { node ->val column = mutableMapOf<String, Any?>()node.fields().forEachRemaining { field ->column[field.key] = field.value}columns.add(column)}}response.columns = columnslog.info("${name()} reader file columns end")response.successful = true}catch (e: Exception){response.successful = falseresponse.message = e.message}return response}
}

File SPI 加载器


resources 源目录下添加 META-INFservices 目录,格式为 resources/META-INF/services,创建 io.edurt.datacap.file.FileModule 文件,内容如下

io.edurt.datacap.file.json.JsonModule

通过以上内容我们实现了 Json 文件转换器的支持。我们只需要在要使用 Json 文件转换器的地方引用该模块即可。比如我们在 server 模块中使用到该模块,则在 server/pom.xml 文件中增加以下内容

<dependency><groupId>io.edurt.datacap</groupId><artifactId>datacap-file-json</artifactId><version>${project.version}</version>
</dependency>

Json Module 测试


package io.edurt.datacap.file.jsonimport com.google.inject.Guice.createInjector
import com.google.inject.Injector
import com.google.inject.Key
import com.google.inject.TypeLiteral
import io.edurt.datacap.file.File
import io.edurt.datacap.file.FileManager
import org.junit.Assert.assertEquals
import org.junit.Testclass JsonModuleTest
{private val injector: Injector = createInjector(FileManager())@Testfun test(){injector.getInstance(Key.get(object : TypeLiteral<Set<File>>(){})).stream().findFirst().ifPresent {assertEquals("Json", it.name())}}
}

Json SPI 测试


package io.edurt.datacap.file.jsonimport com.google.inject.Guice.createInjector
import com.google.inject.Injector
import io.edurt.datacap.file.FileFilter
import io.edurt.datacap.file.FileManager
import io.edurt.datacap.file.model.FileRequest
import org.junit.Before
import org.junit.Test
import org.slf4j.LoggerFactory.getLogger
import java.io.File
import java.io.FileInputStream
import kotlin.test.assertTrueclass JsonFileTest
{private val log = getLogger(this::class.java)private val name = "Json"private var injector: Injector? = nullprivate val request: FileRequest = FileRequest()@Beforefun before(){injector = createInjector(FileManager())request.name = "test"request.path = System.getProperty("user.dir")request.headers = listOf("name", "age")val l1 = listOf("Test", 12)val l2 = listOf("Test1", 121)request.columns = listOf(l1, l2)}@Testfun testFormat(){injector?.let { injector ->FileFilter.filter(injector, name).ifPresent { file ->val response = file.format(request)log.info("headers: [ ${response.headers} ]")response.columns.let { columns ->columns.forEachIndexed { index, line ->log.info("index: [ $index ], line: [ $line ]")}}assertTrue {response.successful == true}}}}@Testfun testFormatStream(){injector?.let { injector ->FileFilter.filter(injector, name).ifPresent { file ->request.stream = FileInputStream(File("${System.getProperty("user.dir")}/${request.name}.json"))val response = file.formatStream(request)log.info("headers: [ ${response.headers} ]")response.columns.let { columns ->columns.forEachIndexed { index, line ->log.info("index: [ $index ], line: [ $line ]")}}assertTrue {response.successful == true}}}}@Testfun testWriter(){injector?.let { injector ->FileFilter.filter(injector, name).ifPresent { file ->assertTrue {file.writer(request).successful == true}}}}@Testfun testReader(){injector?.let { injector ->FileFilter.filter(injector, name).ifPresent { file ->val response = file.reader(request)log.info("headers: ${response.headers}")response.columns.forEach {log.info("columns: $it")}assertTrue {response.successful == true}}}}
}

这篇关于DataCap 自定义 File 转换器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062172

相关文章

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Druid连接池实现自定义数据库密码加解密功能

《Druid连接池实现自定义数据库密码加解密功能》在现代应用开发中,数据安全是至关重要的,本文将介绍如何在​​Druid​​连接池中实现自定义的数据库密码加解密功能,有需要的小伙伴可以参考一下... 目录1. 环境准备2. 密码加密算法的选择3. 自定义 ​​DruidDataSource​​ 的密码解密3

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依