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

相关文章

如何自定义一个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)配置依

解决Maven项目idea找不到本地仓库jar包问题以及使用mvn install:install-file

《解决Maven项目idea找不到本地仓库jar包问题以及使用mvninstall:install-file》:本文主要介绍解决Maven项目idea找不到本地仓库jar包问题以及使用mvnin... 目录Maven项目idea找不到本地仓库jar包以及使用mvn install:install-file基

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现