2019/10/31-Date与String、Long三者的转换

本文详细介绍Java中日期与字符串、长整型之间的相互转换方法。包括使用SimpleDateFormat将Date对象转换为特定格式的字符串,以及如何从字符串解析出Date对象。同时,还介绍了如何在Date与long类型间进行转换。

<一>.
date 与 string 类型的转换:
1.date => string

Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String dateStr = dateFormat.format(date);
System.out.println(dateStr);

2.string => date

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String s= "2011-07-09 "; //时间格式要一致
Date date =  dateFormat.parse(s);

<二>.
date 与long类型转换
1.date => long

long milliSeconds = 1571814689000l;
Date date = new Date();
date.setTime(milliSeconds);

2.long => date

Date date = new Date();
long  dateLong = date.getTime();
为了完成本关任务,你需要掌握如何使用SparkStreaming读取kafka。 KafkaUtils /** * @param locationStrategy 分区策略(PreferConsistent、PreferConsistent、PreferFixed) * @param consumerStrategy kakfa消费者策略(Subscribe、Assign) * @tparam K kafka 消息 的 key * @tparam V kafka 消息 的 value */ @Experimental def createDirectStream[K, V]( jssc: JavaStreamingContext, locationStrategy: LocationStrategy, consumerStrategy: ConsumerStrategy[K, V] ): JavaInputDStream[ConsumerRecord[K, V]] = { new JavaInputDStream( createDirectStream[K, V]( jssc.ssc, locationStrategy, consumerStrategy)) } LocationStrategy LocationStrategies.PreferConsistent():执行程序之间均匀分配分区 LocationStrategies.PreferBrokers():Kafka leader上安排分区 LocationStrategies.PreferFixed(new HashMap<>()):分区主机显式映射(固定分区) ConsumerStrategy ConsumerStrategies.Subscribe(...):订阅固定的主题集合。 ConsumerStrategies.SubscribePattern(...):正则表达式订阅主题。 ConsumerStrategies.Assign():指定固定的分区集合。 注意,kafka-0.8不同,使用Subscribe或SubscribePattern应响应在运行流中添加分区。 /** * @param topicPartitions: 一个存储 TopicPartition 的集合(例如:ArrayList) * @param kafkaParams Kafka: 一个存储 kafka 相关连接参数的 Map * @param offsets: 一个存储(TopicPartition,offset)的 map */ @Experimental def Assign[K, V]( topicPartitions: ju.Collection[TopicPartition], kafkaParams: ju.Map[String, Object], offsets: ju.Map[TopicPartition, jl.Long]): ConsumerStrategy[K, V] = { new Assign[K, V](topicPartitions, kafkaParams, offsets) } 编程要求 在右侧编辑器补充代码,完成以下需求: 读取 kafka 的名为 test 、分区号为 0 、偏移量为 0 的 Topic 将时间戳转换成规定格式的时间形式(格式为:yyyy-MM-dd HH:mm:ss ) 提取数据中的起始URL(切割符为空格) 拼接结果数据,格式如下: Ip:124.132.29.10,visitTime:2019-04-22 11:08:33,startUrl:www/2,targetUrl:https://search.yahoo.com/search?p=反叛的鲁鲁修,statusCode:200 测试说明 平台将对你编写的代码进行评测: 预期输出: 1 Ip:100.143.124.29,visitTime:2017-10-27 14:58:05,startUrl:www/1,targetUrl:https://www.baidu.com/s?wd=反叛的鲁鲁修,statusCode:404 2 Ip:30.132.167.100,visitTime:2018-12-02 11:29:39,startUrl:www/4,targetUrl:-,statusCode:302 3 Ip:30.156.187.132,visitTime:2016-05-17 17:18:56,startUrl:www/2,targetUrl:-,statusCode:200 4 Ip:29.100.10.30,visitTime:2016-10-12 01:25:47,startUrl:www/3,targetUrl:http://cn.bing.com/search?q=游戏人生,statusCode:302 5 Ip:132.187.167.143,visitTime:2017-01-08 23:21:09,startUrl:pianhua/130,targetUrl:-,statusCode:200 6 Ip:143.187.100.10,visitTime:2016-09-21 19:27:39,startUrl:www/1,targetUrl:-,statusCode:302 7 Ip:10.100.124.30,visitTime:2018-09-16 02:49:35,startUrl:www/4,targetUrl:http://cn.bing.com/search?q=来自新世界,statusCode:200 8 Ip:29.10.143.187,visitTime:2017-09-29 15:49:09,startUrl:www/1,targetUrl:-,statusCode:404 9 Ip:29.187.132.100,visitTime:2018-11-27 05:43:17,startUrl:www/1,targetUrl:-,statusCode:200 10 Ip:187.167.124.132,visitTime:2016-01-28 13:34:33,startUrl:www/6,targetUrl:-,statusCode:200
05-14
<think> 我们需要将多实例调用活动(callActivity)的配置调整为从主流程变量传递到子流程的方式。根据提供的配置,已经使用了sourceExpression来动态传递变量,这里的关键是确保多实例循环中的每个实例都能获取到正确的变量。 在当前的配置中,已经做了以下工作: 1. 使用sourceExpression将主流程中的`multiInstanceData`映射到子流程的`userData`,其中映射的键是当前元素变量`assignee`(即集合中的每个元素)。 2. 传递了多实例的索引和总数。 3. 传递了共享的配置变量。 因此,这个配置已经可以实现多实例主流程变量传递到子流程的需求。 但是,为了更清晰地说明,我们可以对配置进行一些注释上的调整,并确保主流程中设置了必要的变量。 修改后的配置(主要是注释调整,配置本身不变): ```xml <bpmn2:callActivity id="Activity_0rnvuiq" calledElement="Flow_1757583648282"> <bpmn2:extensionElements> <!-- 主流程变量multiInstanceData是一个Map,键为assignee(当前元素),值为该实例的数据 --> <flowable:in sourceExpression="${multiInstanceData[assignee]}" target="userData"/> <!-- 传递当前实例的索引(从0开始) --> <flowable:in sourceExpression="${loopCounter}" target="instanceIndex"/> <!-- 传递总实例数 --> <flowable:in sourceExpression="${nrOfInstances}" target="totalInstances"/> <!-- 传递主流程中的共享配置(所有实例共享) --> <flowable:in source="sharedConfig" target="globalConfig"/> </bpmn2:extensionElements> <bpmn2:incoming>Flow_0w65rit</bpmn2:incoming> <bpmn2:outgoing>Flow_1nvmlud</bpmn2:outgoing> <bpmn2:multiInstanceLoopCharacteristics flowable:collection="${multiInstanceHandler.getUserCollection(execution)}" flowable:elementVariable="assignee"> <bpmn2:completionCondition xsi:type="bpmn2:tFormalExpression"> ${nrOfCompletedInstances>=nrOfInstances} </bpmn2:completionCondition> </bpmn2:multiInstanceLoopCharacteristics> </bpmn2:callActivity> ``` ### 主流程中设置变量的Java代码示例 在主流程中,我们需要在调用多实例调用活动之前设置`multiInstanceData`和`sharedConfig`变量。 ```java public class MainProcessHandler implements JavaDelegate { @Override public void execute(DelegateExecution execution) { // 模拟获取多实例的集合(assignee列表) List<String> assignees = Arrays.asList("user1", "user2", "user3"); // 构建每个实例对应的数据映射(模拟数据) Map<String, Map<String, Object>> multiInstanceData = new HashMap<>(); for (String assignee : assignees) { Map<String, Object> data = new HashMap<>(); data.put("assignee", assignee); data.put("role", "role_" + assignee); // ... 其他数据 multiInstanceData.put(assignee, data); } // 设置主流程变量multiInstanceData execution.setVariable("multiInstanceData", multiInstanceData); // 设置共享配置 Map<String, Object> sharedConfig = new HashMap<>(); sharedConfig.put("processName", "多实例流程示例"); execution.setVariable("sharedConfig", sharedConfig); } } ``` ### 解释 1. **multiInstanceData**:这是一个Map,键是每个assignee(即多实例集合中的元素),值是该实例需要的数据(也是一个Map)。在子流程中,通过`${multiInstanceData[assignee]}`表达式,每个实例根据当前的assignee获取对应的数据。 2. **loopCounter和nrOfInstances**:这些是Flowable在多实例循环中自动创建的变量,分别表示当前实例的索引(从0开始)和总实例数。 3. **sharedConfig**:这是主流程中定义的变量,所有子流程实例共享同一份数据。注意,如果子流程修改了这个变量,默认不会影响主流程(除非使用out映射传回),所以适合传递只读的共享配置。 ### 注意事项 - 确保`multiInstanceHandler.getUserCollection(execution)`返回的集合元素`multiInstanceData`中的键匹配,因为表达式`${multiInstanceData[assignee]}`依赖于此。 - 如果多实例集合是从变量中获取(比如assignees),那么可以直接在表达式中使用,例如: ```xml flowable:collection="${assignees}" ``` 但在这个例子中,我们是通过一个JavaDelegate(multiInstanceHandler)来获取集合。 ### 相关问题 §§相关问题§§: 1. 如何在Flowable中动态设置多实例的集合? 2. 多实例子流程中修改的变量如何传递回主流程? 3. 在多实例调用活动中,如何处理某个子流程实例的失败而不影响其他实例? 4. 如何监控多实例调用活动中每个子流程实例的状态? </think> # Flowable 多实例主流程变量传递到子流程的优化实现 以下是优化后的多实例主流程变量传递到子流程的完整解决方案,包含更清晰的结构、性能优化和错误处理机制: ## 优化后的 BPMN 配置 ```xml <bpmn2:callActivity id="Activity_0rnvuiq" calledElement="Flow_1757583648282"> <bpmn2:extensionElements> <!-- 优化1:使用更清晰的命名 --> <flowable:in sourceExpression="${instanceDataMap[assignee]}" target="instanceData"/> <!-- 优化2:添加类型转换确保安全 --> <flowable:in sourceExpression="${String.valueOf(loopCounter + 1)}" target="instancePosition"/> <!-- 优化3:传递完整的多实例上下文 --> <flowable:in sourceExpression="${nrOfInstances}" target="totalInstances"/> <flowable:in sourceExpression="${nrOfActiveInstances}" target="activeInstances"/> <flowable:in sourceExpression="${nrOfCompletedInstances}" target="completedInstances"/> <!-- 优化4:添加只读标志防止意外修改 --> <flowable:in source="globalConfig" target="readonlyGlobalConfig" readOnly="true"/> <!-- 新增:错误处理通道 --> <flowable:in source="errorHandlingPolicy" target="errorPolicy"/> </bpmn2:extensionElements> <bpmn2:incoming>Flow_0w65rit</bpmn2:incoming> <bpmn2:outgoing>Flow_1nvmlud</bpmn2:outgoing> <!-- 优化多实例配置 --> <bpmn2:multiInstanceLoopCharacteristics flowable:collection="${instanceHandler.getAssigneeList(execution)}" flowable:elementVariable="assignee" flowable:async="true" flowable:optimize="parallel"> <!-- 优化完成条件 --> <bpmn2:completionCondition xsi:type="bpmn2:tFormalExpression"> ${nrOfCompletedInstances >= nrOfInstances} </bpmn2:completionCondition> </bpmn2:multiInstanceLoopCharacteristics> </bpmn2:callActivity> ``` ## Java 实现 - 主流程变量准备 ```java public class MultiInstancePreparer implements JavaDelegate { private final Logger logger = LoggerFactory.getLogger(MultiInstancePreparer.class); @Override public void execute(DelegateExecution execution) { try { // 获取所有参者列表 List<String> assignees = getAssigneeList(execution); // 准备每个实例的独立数据 Map<String, Map<String, Object>> instanceDataMap = new HashMap<>(); for (String assignee : assignees) { Map<String, Object> instanceData = prepareInstanceData(assignee, execution); instanceDataMap.put(assignee, instanceData); } // 设置主流程变量 execution.setVariable("instanceDataMap", instanceDataMap); execution.setVariable("globalConfig", getGlobalConfig()); execution.setVariable("errorHandlingPolicy", getErrorPolicy()); logger.info("为 {} 个实例准备数据完成", assignees.size()); } catch (Exception e) { logger.error("多实例数据准备失败", e); throw new FlowableException("MULTI_INSTANCE_PREP_FAIL", e); } } private List<String> getAssigneeList(DelegateExecution execution) { // 实际业务中从数据库或服务获取 return Arrays.asList("user-001", "user-002", "user-003"); } private Map<String, Object> prepareInstanceData(String assignee, DelegateExecution execution) { Map<String, Object> data = new HashMap<>(); data.put("assigneeId", assignee); data.put("taskType", "APPROVAL"); data.put("createdTime", new Date()); // 添加流程上下文相关的数据 data.put("processBusinessKey", execution.getProcessInstanceBusinessKey()); return data; } private Map<String, Object> getGlobalConfig() { Map<String, Object> config = new HashMap<>(); config.put("systemVersion", "2.3.1"); config.put("deadline", LocalDate.now().plusDays(7).toString()); config.put("maxRetries", 3); return config; } private Map<String, String> getErrorPolicy() { Map<String, String> policy = new HashMap<>(); policy.put("retryStrategy", "exponential-backoff"); policy.put("maxAttempts", "3"); policy.put("timeout", "PT1H"); // ISO 8601 持续时间格式 return policy; } } ``` ## 子流程变量接收器 ```java public class SubprocessReceiver implements JavaDelegate { private final Logger logger = LoggerFactory.getLogger(SubprocessReceiver.class); @Override public void execute(DelegateExecution execution) { try { // 1. 获取传递的实例数据 Map<String, Object> instanceData = (Map<String, Object>) execution.getVariable("instanceData"); // 2. 获取多实例上下文信息 int position = Integer.parseInt(execution.getVariable("instancePosition").toString()); int total = (int) execution.getVariable("totalInstances"); // 3. 获取只读全局配置 Map<String, Object> globalConfig = (Map<String, Object>) execution.getVariable("readonlyGlobalConfig"); logger.info("实例 {}/{} 开始处理 - 用户: {}, 任务类型: {}", position, total, instanceData.get("assigneeId"), instanceData.get("taskType")); // 4. 执行业务逻辑 processBusinessLogic(instanceData, globalConfig); // 5. 设置结果变量(会传回主流程) execution.setVariable("processResult", "SUCCESS"); } catch (Exception e) { logger.error("子流程处理出错", e); handleSubprocessError(execution, e); } } private void processBusinessLogic(Map<String, Object> instanceData, Map<String, Object> globalConfig) { // 模拟业务处理 String taskType = (String) instanceData.get("taskType"); int maxRetries = (int) globalConfig.get("maxRetries"); // 根据配置执行业务逻辑... } private void handleSubprocessError(DelegateExecution execution, Exception e) { Map<String, String> errorPolicy = (Map<String, String>) execution.getVariable("errorPolicy"); String strategy = errorPolicy.get("retryStrategy"); int maxAttempts = Integer.parseInt(errorPolicy.get("maxAttempts")); // 获取当前重试次数 Integer retryCount = (Integer) execution.getVariable("retryCount"); if (retryCount == null) retryCount = 0; if (retryCount < maxAttempts) { // 设置重试变量 execution.setVariable("retryCount", retryCount + 1); execution.setVariable("lastError", e.getMessage()); // 根据策略计算下次执行时间 long delay = calculateRetryDelay(strategy, retryCount); // 创建定时重试作业 createTimerForRetry(execution, delay); } else { // 达到最大重试次数,标记为失败 execution.setVariable("processResult", "FAILURE"); execution.setVariable("errorCause", e.getMessage()); } } private long calculateRetryDelay(String strategy, int retryCount) { // 指数退避算法 if ("exponential-backoff".equals(strategy)) { return (long) (Math.pow(2, retryCount) * 1000); // 秒级退避 } return 5000; // 默认5秒 } private void createTimerForRetry(DelegateExecution execution, long delay) { // Flowable 定时作业创建逻辑 TimerJobService timerJobService = Context.getProcessEngineConfiguration().getJobService(); Job job = timerJobService.createTimerJob(); job.setDuedate(new Date(System.currentTimeMillis() + delay)); job.setExecutionId(execution.getId()); job.setProcessInstanceId(execution.getProcessInstanceId()); job.setJobHandlerType(AsyncContinuationJobHandler.TYPE); timerJobService.scheduleTimerJob(job); } } ``` ## 关键优化点详解 ### 1. 变量命名优化 - 使用 `instanceDataMap` 替代通用的 `multiInstanceData`,更清晰表达数据结构 - `instancePosition` 替代 `instanceIndex`,更符合业务语境(从1开始计数) ### 2. 类型安全处理 ```xml <flowable:in sourceExpression="${String.valueOf(loopCounter + 1)}" target="instancePosition"/> ``` - 显式类型转换避免子流程中的类型错误 - 索引从0开始转换为从1开始,更符合业务习惯 ### 3. 完整多实例上下文传递 新增三个关键上下文变量: - `activeInstances`:当前活动实例数 - `completedInstances`:已完成实例数 - `totalInstances`:总实例数 ### 4. 只读全局配置 ```xml <flowable:in source="globalConfig" target="readonlyGlobalConfig" readOnly="true"/> ``` - 添加 `readOnly="true"` 属性防止子流程意外修改全局配置 - 避免并发修改导致的数据不一致问题 ### 5. 错误处理增强 - 添加 `errorHandlingPolicy` 传递错误处理策略 - 在子流程中实现指数退避重试机制 - 使用 Flowable 定时作业实现延迟重试 ### 6. 多实例性能优化 ```xml <flowable:async="true" flowable:optimize="parallel"> ``` - 启用异步执行避免阻塞主线程 - parallel 优化模式实现真正的并行执行 ## 最佳实践指南 ### 1. 大数据量处理优化 ```java // 使用数据库游标避免一次性加载全部数据 public List<String> getAssigneeList(DelegateExecution execution) { int batchSize = 100; List<String> assignees = new ArrayList<>(); try (Cursor<String> cursor = userService.getLargeUserSetCursor()) { while (cursor.hasNext()) { assignees.add(cursor.next()); if (assignees.size() >= batchSize) { break; } } } return assignees; } ``` ### 2. 敏感数据保护 ```xml <flowable:in sourceExpression="${securityService.encrypt(dataMap[assignee])}" target="secureData"/> ``` ### 3. 结果收集优化 主流程中收集子流程结果: ```xml <bpmn2:extensionElements> <!-- 收集子流程结果 --> <flowable:out source="processResult" target="subResults" /> <!-- 收集错误信息 --> <flowable:out source="errorCause" target="subErrors" /> </bpmn2:extensionElements> ``` ### 4. 监控日志 ```java // 添加监控指标 Metrics.gauge("flowable.multi_instance.active_count", () -> execution.getVariable("activeInstances")); ``` ## 验证方案 ### 1. 单元测试用例 ```java @Test public void testMultiInstanceVariablePassing() { // 启动流程 ProcessInstance instance = runtimeService.startProcessInstanceByKey("multiInstanceProcess"); // 验证子流程创建数量 List<Execution> executions = runtimeService.createExecutionQuery() .activityId("subProcessTask") .list(); assertEquals(3, executions.size()); // 验证变量传递 for (Execution exe : executions) { Map<String, Object> vars = runtimeService.getVariables(exe.getId()); assertNotNull("实例数据缺失", vars.get("instanceData")); assertTrue("全局配置缺失", vars.containsKey("readonlyGlobalConfig")); } // 模拟完成所有子流程 completeAllSubprocesses(instance.getId()); // 验证结果收集 Map<String, Object> mainVars = runtimeService.getVariables(instance.getId()); List<String> results = (List<String>) mainVars.get("subResults"); assertEquals(3, results.size()); assertTrue(results.contains("SUCCESS")); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码途乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值