JSONObject.fromObject()报java.lang.IllegalArgumentException异常

解决MySQL日期格式问题

解决办法:

修改sql语句中的时间类型,将select语句中的时间类型字段全部用date_format(date, type)函数处理,如:

date_format(a.birthday,'%Y-%m-%d') 
date_format(a.checkInTime,'%Y-%m-%d %H:%m:%s')

备注:所用数据库为MySql。

package com.duxiaoman.ent.webflux.controller; import com.alibaba.fastjson.JSONObject; import com.duxiaoman.ent.commons.exception.AirException; import com.duxiaoman.ent.commons.exception.AirExceptionHandler; import com.duxiaoman.ent.core.util.IDUtil; import com.duxiaoman.ent.enums.ResultStatus; import com.duxiaoman.ent.enums.RetCodeEnum; import com.duxiaoman.ent.exception.ResponseException; import com.duxiaoman.ent.exception.ServiceValidationException; import com.duxiaoman.ent.pojo.InfServiceInfoDTO; import com.duxiaoman.ent.util.InfServiceUtil; import com.duxiaoman.ent.webflux.entity.*; import com.duxiaoman.ent.webflux.feign.DatabaseServiceClient; import com.duxiaoman.ent.webflux.feign.ReactiveDatabaseServiceClient; import com.duxiaoman.ent.webflux.vo.InfServiceConfigInfoVO; import com.duxiaoman.ent.webflux.vo.InfServiceInfoVO; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; import reactor.util.retry.Retry; import sun.misc.Signal; import java.net.URI; import java.util.List; import java.util.concurrent.TimeoutException; import java.util.function.Supplier; import java.time.Duration; import java.util.Map; @Slf4j @RestController @RequestMapping("/request") public class DataSourceCallApi { private final ReactiveDatabaseServiceClient reactiveDatabaseServiceClient; private final ReactiveRedisTemplate<String, Object> redisTemplate; private final WebClient webClient; public DataSourceCallApi(ReactiveDatabaseServiceClient reactiveDatabaseServiceClient, ReactiveRedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate; this.reactiveDatabaseServiceClient = reactiveDatabaseServiceClient; this.webClient = WebClient .builder() .build(); } @PostMapping("") public Mono queryData(@RequestBody HttpServiceRequest httpServiceRequest) { // 1. 参数校验(可选,如果 serviceId 可能为空) if (StringUtils.isEmpty(httpServiceRequest.getServiceId())) { return Mono.just(AirResponse.error(RetCodeEnum.ILLEGAL_ARGUMENT, 400,"serviceId 不可为空!")); } // 2. 获取配置信息(带缓存) return getWithCache("datasource:config:" + httpServiceRequest.getServiceId(), () -> reactiveDatabaseServiceClient.queryById(httpServiceRequest.getServiceId())) .flatMap(configResponse -> { // 3. 解析配置 InfServiceInfoVO infServiceInfoVO = configResponse.getData(); // 4. 构建 实时请求 String dataRecordId = IDUtil.getSnowflakeIdStr(); ServiceRequest serviceRequest = new ServiceRequest(); serviceRequest.setServiceKey(infServiceInfoVO.getServiceKey()); serviceRequest.setServiceId(infServiceInfoVO.getServiceId()); serviceRequest.setLogId(dataRecordId); serviceRequest.setEventRecordId(httpServiceRequest.getQueryRecordId()); serviceRequest.setRequester("var"); // 5. 入参校验, 必填, keyMap, 类型转换 serviceRequest.setInputParams(httpServiceRequest.getInputParams()); serviceRequest.setParamMap(InfServiceUtil.processInputParams(infServiceInfoVO, httpServiceRequest.getInputParams())); String dataCacheKey = InfServiceUtil.getInfServiceKeyCacheStr(infServiceInfoVO.getServiceKey(), infServiceInfoVO.getCacheKeys(), httpServiceRequest.getInputParams()); // 6. 查询数据(带缓存、重试和超时) return getWithCache(infServiceInfoVO.getIsHasCache() > 0 ? dataCacheKey : null, () -> fetchDataWithRetry(serviceRequest, infServiceInfoVO)) // 7. 统一结果处理 .flatMap(data -> handleResult(data, infServiceInfoVO)) // 8. 都通知结果 .doFinally(signal -> notifyDatasource(serviceRequest, signal)); }) // 9. 全局异常处理 .onErrorResume(this::handleError); } // 带缓存的获取方法 private <T> Mono<T> getWithCache(String key, Supplier<Mono<T>> loader) { if (key == null) { return loader.get(); } return redisTemplate.opsForValue().get(key) .flatMap(cached -> { if (cached != null) { return Mono.just((T) cached); } return Mono.empty(); }) .switchIfEmpty( loader.get() .flatMap(result -> redisTemplate.opsForValue() .set(key, result, Duration.ofMinutes(30)) .thenReturn(result) ) ); } // 带重试和超时的数据获取 private Mono<ServiceResponse> fetchDataWithRetry(ServiceRequest request, InfServiceInfoVO infServiceInfoVO) { List<InfServiceConfigInfoVO> infServiceConfigList = infServiceInfoVO.getInfServiceConfigList(); if (infServiceConfigList.isEmpty()) { log.error("No service configuration found for the given service ID: {}", infServiceInfoVO.getServiceId()); return Mono.error(new IllegalArgumentException("查无数据源配置信息")); } InfServiceConfigInfoVO config = infServiceConfigList.get(0); // 1. 从配置中获取目标URL(假设config中有serviceUrl字段) String serviceUrl = config.getServiceUrl(); if (serviceUrl == null) { log.error("Service URL is missing in configuration for service ID: {}", infServiceInfoVO.getServiceId()); throw new ServiceValidationException("请求url不可为空"); } long startTime = System.currentTimeMillis(); log.info("Attempting to call service at URL: {}", serviceUrl); return webClient .post() .uri(serviceUrl) .accept(MediaType.APPLICATION_JSON) .bodyValue(request.getInputParams()) .retrieve() .onStatus( status -> !status.is2xxSuccessful(), response -> response.bodyToMono(String.class) .doOnNext(body -> log.error("Service call failed with status code: {} and body: {}", response.statusCode(), body)) .defaultIfEmpty("") .map(body -> new ResponseException("服务调用失败: " + response.statusCode() + " - " + body)) ) .bodyToMono(JSONObject.class) .map(json -> { InfBusinessResponse businessResponse = new InfBusinessResponse(RetCodeEnum.SUCCESS, json.toJSONString(), ResultStatus.Valid); businessResponse.setTimeconsume(System.currentTimeMillis() - startTime); // TODO 响应模板解析 log.info("响应模板解析 {} ", json); // 出参校验, keyMap, 类型转换 if (null != businessResponse.getTemplateData()) { businessResponse.setOutputParams(InfServiceUtil.processOutputParams(infServiceInfoVO, businessResponse.getTemplateData())); } else if (null != businessResponse.getResponseData()) { try { businessResponse.setOutputParams(InfServiceUtil.processOutputParams(infServiceInfoVO, json)); } catch (Exception e) { log.warn("数据源返回结果不能转换为json格式"); throw new ResponseException("数据源返回结果不能转换为json格式"); } } long timeConsume = System.currentTimeMillis() - startTime; log.info("数据源请求:{},耗时:{}", request.getLogId(), timeConsume); return businessResponse.convertToServiceResult(); }) .onErrorResume(e -> { log.error("Error occurred while fetching data from service.", e); return Mono.just( ServiceResponse.createErrorResponse(request, "500", e.getMessage()) ); }) .timeout(Duration.ofMillis(config.getTimeout())) .retryWhen(Retry.backoff( config.getErrorRetryIntervalTime(), Duration.ofMillis(100) ).filter(e -> e instanceof TimeoutException || isRetryable(e))); } // 结果处理 private Mono<ResponseEntity<Object>> handleResult(ServiceResponse response, InfServiceInfoVO config) { if (response.isSuccess() && null != response.getOutputParams()) { return Mono.just(ResponseEntity.ok(response.getOutputParams())); } else { return Mono.just(ResponseEntity .status(200) .body(Map.of( "error", response.getErrorMsg(), "code", response.getErrorNo() ))); } } // 响应模板解析 // private InfBusinessResponse parseOutResult(ServiceRequest request, InfBusinessResponse response) { // // if (StringUtils.isNotBlank(response.getResponseData())) { // if (infServiceTemplate.getRequestFormat().equals(MessageFormat.Xml)) { //// ServiceTemplate template = infServiceTemplate.getResponseTemplate(); //// response = TemplateParser.parseTemplate(template).parseResponse(sourceData, requestParam.getParamMap()); // } else { // if (!response.isSuccess()) { // AirExceptionHandler.publish("5005", "数据源调用失败"); // } // // 校验模板 // if (StringUtils.isNotEmpty(infServiceTemplate.getResponseCheckTemplate())) { // try { // JSONObject checkResult = VelocityTransform.transformToolsContent(infServiceTemplate.getResponseCheckTemplate(), JSONObject.parseObject(response.getResponseData())); // // if (checkResult != null) { // if (checkResult.containsKey("success")){ // response.setSuccess(checkResult.getBooleanValue("success")); // } // // if (checkResult.containsKey("billing")){ // response.setBilling(checkResult.getBooleanValue("billing")); // } // // if (checkResult.containsKey("errorRetry")){ // response.setErrorRetry(checkResult.getBooleanValue("errorRetry")); // } // if (checkResult.containsKey("errorMsg")){ // response.setErrorMsg(checkResult.getString("errorMsg")); // } // // if (!response.isSuccess()) { // response.setRetCode(RetCodeEnum.DS_5005); // } // } // } catch (Exception e) { // response.setSuccess(false); // response.setRetCode(RetCodeEnum.DS_50050003); // response.setRetMsg("调用数据源异常, 校验模版文不正确"); // } // } // if (StringUtils.isNotEmpty(infServiceTemplate.getResponseTemplate())) { // try { // JSONObject jsonResult = VelocityTransform.transformToolsContent(infServiceTemplate.getResponseTemplate(), JSONObject.parseObject(response.getResponseData())); // response.setTemplateData(jsonResult); // } catch (Exception e) { // response.setSuccess(false); // response.setRetCode(RetCodeEnum.DS_50050003); // response.setRetMsg("调用数据源异常, 响应模版文不正确"); // return response; // } // } // } // } else { // response.setSuccess(false); // response.setRetCode(RetCodeEnum.DS_5005); // response.setRetMsg("返回结果为空"); // } // // return response; // } // 通知数据库服务 private Mono<Void> notifyDatasource(ServiceRequest request, SignalType signalType) { // 根据信号类型决定通知状态 String status = switch (signalType) { case ON_COMPLETE -> "SUCCESS"; case ON_ERROR -> "FAILED"; case CANCEL -> "CANCELLED"; default -> "UNKNOWN"; }; log.debug("请求完成, requestId: {}, status: {}", request.getLogId(), status); return Mono.empty(); } // 判断是否可重试 private boolean isRetryable(Throwable e) { return e instanceof RuntimeException && !(e instanceof IllegalArgumentException); } // 错误处理 private Mono handleError(Throwable e) { if (e instanceof TimeoutException) { log.warn("请求超时"); return Mono.just(AirResponse.error(RetCodeEnum.HANDLE_TIMEOUT, 504)); } else if (e instanceof ResponseException) { log.warn("服务响应异常: {}", e.getMessage()); return Mono.just(AirResponse.error(RetCodeEnum.INTERFACE_EXCEPTION,500, e.getMessage())); } else if (e instanceof ServiceValidationException) { log.warn("参数校验异常: {}", e.getMessage()); return Mono.just(AirResponse.error(RetCodeEnum.ILLEGAL_ARGUMENT, 400, e.getMessage())); } log.error("系统未知异常: " + e.getMessage(), e); return Mono.just(AirResponse.error(RetCodeEnum.SERVER_EXCEPTION, 500)); } } package com.duxiaoman.ent.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public ReactiveRedisTemplate<String, Object> reactiveRedisTemplate( ReactiveRedisConnectionFactory factory) { Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); RedisSerializationContext<String, Object> context = RedisSerializationContext.<String, Object>newSerializationContext() .key(new StringRedisSerializer()) .value(serializer) .hashKey(new StringRedisSerializer()) .hashValue(serializer) .build(); return new ReactiveRedisTemplate<>(factory, context); } } 优化一下以下方法:: // 带缓存的获取方法 private <T> Mono<T> getWithCache(String key, Supplier<Mono<T>> loader) { if (key == null) { return loader.get(); } return redisTemplate.opsForValue().get(key) .flatMap(cached -> { if (cached != null) { return Mono.just((T) cached); } return Mono.empty(); }) .switchIfEmpty( loader.get() .flatMap(result -> redisTemplate.opsForValue() .set(key, result, Duration.ofMinutes(30)) .thenReturn(result) ) ); } 错::: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.duxiaoman.ent.webflux.entity.ResponseResult (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.duxiaoman.ent.webflux.entity.ResponseResult is in unnamed module of loader 'app') at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Assembly trace from producer [reactor.core.publisher.MonoFlatMap] : reactor.core.publisher.Mono.flatMap(Mono.java:3100) com.duxiaoman.ent.webflux.controller.DataSourceCallApi.queryData(DataSourceCallApi.java:71) Error has been observed at the following site(s): *__Mono.flatMap ⇢ at com.duxiaoman.ent.webflux.controller.DataSourceCallApi.queryData(DataSourceCallApi.java:71) Original Stack Trace: at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onNext(FluxUsingWhen.java:345) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250) at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:122) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) at io.lettuce.core.RedisPublisher$ImmediateSubscriber.onNext(RedisPublisher.java:890) at io.lettuce.core.RedisPublisher$RedisSubscription.onNext(RedisPublisher.java:291) at io.lettuce.core.RedisPublisher$SubscriptionCommand.doOnComplete(RedisPublisher.java:777) at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:65) at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:63) at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:746) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:681) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:598) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:840)
07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值