JavaBean对象与jfinal的Record对象互转

本文介绍了一种将JavaBean对象转换为Record对象以及从Record对象转换回JavaBean对象的方法。通过反射机制,该方法能够自动匹配字段并进行转换,适用于数据传输和存储场景。

JavaBean转Record方法

public static Record javaBeanToRecord(Object obj) throws IllegalArgumentException, IllegalAccessException{
		if(obj != null){
			Record record = new Record();
			Class clazz = obj.getClass();
			Field[] fields = clazz.getDeclaredFields();
			for(int i=0; i<fields.length; i++){
				Field field = fields[i];
				if(!field.isAccessible())  {
					field.setAccessible(true);
				}
				System.out.println(field.getName()+" : "+field.get(obj));
				record.set(field.getName(), field.get(obj));
			}
			return record;
		}
		return null;
	}

Record转JavaBean方法

public static Object recrodToJavaBean(Record record, Class clazz) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException{
		if(record != null){
			Object obj = clazz.newInstance();
			String[] columns = record.getColumnNames();
			for(String col: columns){
				Field field = clazz.getDeclaredField(col);
				if(field != null){
					if(!field.isAccessible()){
						field.setAccessible(true);
					}
					field.set(obj, record.getObject(col));
				}
			}
			return obj;
		}
		return null;
	}

package com.idata.ground.util;

import java.lang.reflect.Field;

import com.jfinal.plugin.activerecord.Record;
/**
 * 
 * @ClassName: RecordUtils
 * @Description: Record相关工具类
 *
 */
public class RecordUtils {
	/**
	 * 
	 * @Title: ModelToRecord
	 * @Description: javaBean对象转Record对象;
	 * @param obj
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException Record
	 */
	public static Record javaBeanToRecord(Object obj) throws IllegalArgumentException, IllegalAccessException{
		if(obj != null){
			Record record = new Record();
			Class clazz = obj.getClass();
			Field[] fields = clazz.getDeclaredFields();
			for(int i=0; i<fields.length; i++){
				Field field = fields[i];
				if(!field.isAccessible())  {
					field.setAccessible(true);
				}
				record.set(field.getName(), field.get(obj));
			}
			return record;
			
		}
		return null;
	}
	/**
	 * 
	 * @Title: RecrodToModel
	 * @Description: Record对象转javaBean对象
	 * @param record
	 * @param clazz
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws SecurityException Object
	 */
	public static Object recrodToJavaBean(Record record, Class clazz) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException{
		if(record != null){
			Object obj = clazz.newInstance();
			String[] columns = record.getColumnNames();
			for(String col: columns){
				Field field = clazz.getDeclaredField(col);
				if(field != null){
					if(!field.isAccessible()){
						field.setAccessible(true);
					}
					field.set(obj, record.getObject(col));
				}
			}
			return obj;
		}
		return null;
	}
}

<think>我们之前已经讨论过通过HTTP将Flink数据写入Doris的基本方法,现在用户明确要求将Java Bean对象通过HTTP写入Doris。结合引用内容,我们需要特别注意: 1. 引用[1]中提到:`DorisMapFunction`将javaBean对象换为对应的json字符串对象,并且将驼峰式命名方式修改为蛇形命名方式 2. 引用[2]和[3]展示了具体的数据结构和写入方式 因此,实现步骤应该包括: 1. 将Java Bean对象换为JSON字符串(注意字段名映射) 2. 通过HTTP Stream Load接口将JSON数据写入Doris 以下为详细实现方案:</think>### Flink 将 Java Bean 对象数据通过 HTTP 写入 Doris 的实现方案 根据引用内容,特别是引用[1]中提到的 `DorisMapFunction` 和引用[3]中的 Java Bean 结构,以下是完整的实现流程: #### 1. 核心实现步骤 1. **Java Bean 定义**:创建数据模型类(如引用[3]的 User 类) 2. **数据换**:使用 `DorisMapFunction` 将 Bean 为 JSON 并做命名换 3. **HTTP 写入**:通过 Stream Load API 提交数据到 Doris #### 2. 完整代码实现 ```java import org.apache.flink.configuration.Configuration; import org.apache.flink.streaming.api.functions.sink.RichSinkFunction; import com.alibaba.fastjson.JSON; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; // 1. Java Bean定义(引用[3]) @Data @Builder public class User { public int id; public String name; public int age; } // 2. 数据换函数(引用[1]的DorisMapFunction) public class DorisMapFunction implements MapFunction<User, String> { @Override public String map(User user) throws Exception { // 驼峰蛇形命名 return JSON.toJSONString(user, new PropertyNamingStrategyPropertyFilter(PropertyNamingStrategy.SnakeCase) ); } } // 3. Doris HTTP Sink(增强版) public class DorisHttpSink extends RichSinkFunction<String> { private final String dorisUrl; // http://fe_host:8030/api/db/table/_stream_load private final String user; private final String password; private List<String> buffer = new ArrayList<>(); private long lastFlush = System.currentTimeMillis(); @Override public void open(Configuration parameters) { // 初始化连接池等资源 } @Override public void invoke(String jsonStr, Context context) { buffer.add(jsonStr); // 批量写入(每100条或1秒刷写) if(buffer.size() >= 100 || System.currentTimeMillis() - lastFlush > 1000) { flushBuffer(); } } private void flushBuffer() { try { String batchData = "[" + String.join(",", buffer) + "]"; sendToDoris(batchData); buffer.clear(); lastFlush = System.currentTimeMillis(); } catch (Exception e) { // 加入死信队列或重试逻辑 } } private void sendToDoris(String data) throws Exception { URL url = new URL(dorisUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("PUT"); conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString((user + ":" + password).getBytes())); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("strip_outer_array", "true"); // 关键参数! conn.setDoOutput(true); try (OutputStream os = conn.getOutputStream()) { os.write(data.getBytes(StandardCharsets.UTF_8)); } if (conn.getResponseCode() != 200) { throw new RuntimeException("Doris写入失败: " + IOUtils.toString(conn.getErrorStream(), StandardCharsets.UTF_8)); } } } // 4. Flink作业集成 public class DorisSinkJob { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); DataStream<User> userStream = env .addSource(new FlinkKafkaConsumer<>("topic", new UserDeserializer(), properties)) .map(record -> User.builder() .id(record.getId()) .name(record.getName()) .age(record.getAge()) .build()); userStream .map(new DorisMapFunction()) // BeanJSON .addSink(new DorisHttpSink( "http://doris-fe:8030/api/mydb.users/_stream_load", "admin", "password123" )); env.execute("Doris HTTP Sink Job"); } } ``` #### 3. 关键配置说明 | **参数** | **示例值** | **作用** | |----------|------------|----------| | `strip_outer_array` | true | 使Doris将`[{"id":1},...]`识别为多行数据 | | `format` | json | 指定JSON格式解析(需在Doris表定义) | | `column_separator` | \x02 | CSV格式字段分隔符(非JSON需设置) | | `batchSize` | 100 | 控制单次HTTP请求的数据量 | | `flushInterval` | 1000ms | 最大缓冲时间 | #### 4. 性能优化技巧 1. **批量写入**:如代码所示,合并多条记录为JSON数组提交 2. **连接复用**:在`open()`中初始化HTTP连接池 3. **压缩传输**:添加请求头`"Content-Encoding", "gzip"` ```java conn.setRequestProperty("Content-Encoding", "gzip"); try (GZIPOutputStream gzipOS = new GZIPOutputStream(conn.getOutputStream())) { gzipOS.write(data.getBytes()); } ``` 4. **错误恢复**:实现`CheckpointedFunction`接口保证状态一致性 #### 5. Doris 表结构建议(引用[2]) ```sql CREATE TABLE `users` ( `id` INT NULL COMMENT "用户ID", `name` VARCHAR(200) NULL COMMENT "姓名", `age` INT NULL COMMENT "年龄" ) ENGINE=OLAP DUPLICATE KEY(`id`) -- 指定主键 DISTRIBUTED BY HASH(`id`) BUCKETS 10 PROPERTIES ( "replication_num" = "3", "storage_format" = "V2" ); ``` > **重要提示**:生产环境建议使用官方 [Flink-Doris-Connector](https://github.com/apache/doris-flink-connector),它封装了: > - 自动Schema映射 > - 精确一次语义(Exactly-Once) > - 动态分区管理 > - 指标监控集成 --- ### 相关问题 1. 如何验证 Flink 到 Doris 的数据一致性? 2. Stream Load 其他写入方式(如 Insert Into)有何性能差异? 3. 如何处理 Java Bean 字段变更 Doris 表结构的兼容性问题? 4. 在 Kafka+Flink+Doris 架构中,如何设计端到端的 Exactly-Once 处理流程? 5. 如何监控 Flink 到 Doris 的 HTTP 写入性能?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值