1.activitiå¨çº¿è®¾è®¡-Activiti6.0ä¸å¦ä½è®¾è®¡åå
³è表åï¼
2.redis为ä»ä¹è¦åºåå
3.objectmapper 线ç¨å®å
¨å
4.javaå¦ä½å¯¼å
¥å
5.Java泛型 | Jackson TypeReference获取泛型类型信息
6.解决 Elasticsearch 8.x Java API 中 Update 写入 null 值无效的源码问题
activitiå¨çº¿è®¾è®¡-Activiti6.0ä¸å¦ä½è®¾è®¡åå ³è表åï¼
activiti6çæµç¨ç¼è¾å¨æä¹æ´åè¿èªå·±ç项ç®ä¸
å»ºè®®ä½ å¯ä»¥çä¸ä¸åå¡å çç¸å ³ææ¯åæ:
ç½é¡µé¾æ¥
,
activiti6åactiviti5æ´åæ¹å¼ä¸è´
1.为ä»ä¹è¦æ´å
Activiti5.çæ¬æåæ¬ç¬ç«çActivitiModeler模åæ´åå°äºActivitiExplorerä¸,两è ç¸ç»å使ç¨èµ·æ¥å¾æ¹ä¾¿,éè¿Modeler设计çæµç¨æ¨¡åå¯ä»¥ç´æ¥é¨ç½²å°å¼æ,ä¹å¯ä»¥æå·²ç»é¨ç½²çæµç¨è½¬æ¢ä¸ºModelä»èå¨Modelerä¸ç¼è¾ã
å¨å®é åºç¨ä¸ä¹æè¿æ ·çéæ±,æModeleræ´åå°ä¸å¡ç³»ç»ä¸å¯ä»¥ä¾ç®¡çå使ç¨,æè ä½ä¸ºBPMå¹³å°çä¸é¨ååå¨,å¾éæ¾å®æ¹æ²¡æç»åºå¦ä½æ´åModelerçææ¡£ã
2.æ´åå·¥ä½
2.1ä¸è½½æºç
é¦å éè¦ä»Githubä¸è½½æºç :
2.2å¤å¶æ件
å¤å¶çæææ件åå¨activiti-webapp-explorer2ç®å½ä¸ã
src/main/resourcesä¸çããå°é¡¹ç®æºç çæºç æ ¹ç®å½,ä¿è¯ç¼è¯ä¹åå¨classesæ ¹ç®å½
src/main/webappä¸çapiãeditorãexplorerãlibså°é¡¹ç®çwebappç®å½(ä¸WEB-INFç®å½å级)
2.3æ·»å ä¾èµ
<dependency>__<groupid></groupid>__<artifactid>activiti-explorer</artifactid>__<version>5.</version>__<exclusions>____<exclusion>______<artifactid>vaadin</artifactid>______<groupid></groupid>____</exclusion>____<exclusion>______<artifactid>dcharts-widget</artifactid>______<groupid></groupid>____</exclusion>____<exclusion>______<artifactid>activiti-simple-workflow</artifactid>______<groupid></groupid>____</exclusion>__</exclusions></dependency><dependency>__<groupid></groupid>__<artifactid>activiti-modeler</artifactid>__<version>5.</version></dependency>
2.4æ·»å Javaç±»
æ·»å ä¸ä¸ªç±»ä¿åå°é¡¹ç®ä¸,注åäºä¸äºRESTè·¯ç±ã
package;
import;import;import;import;import;import;
publicclassExplorerRestApplicationextendsActivitiRestApplication{
publicExplorerRestApplication(){ __super();_}_/**_*CreatesarootRestletthatwillreceiveallincomingcalls._*/_@Override_publicsynchronizedRestletcreateInboundRoot(){ __Routerrouter=newRouter(getContext());__();__(router);__(router);__JsonpFilterjsonpFilter=newJsonpFilter(getContext());__(router);__returnjsonpFilter;_}
}
2.5é ç½®
å¨æ件ä¸æ·»å å¦ä¸é ç½®:
<!--Restletadapter,usedtoexposemodelerfunctionalitythroughREST--><servlet>__<servlet-name>RestletServlet</servlet-name>__<servlet-class></servlet-class>__<init-param>____<!--Applicationclassname-->____<param-name></param-name>____<param-value></param-value>__</init-param></servlet>
<!--Catchallservicerequests--><servlet-mapping>__<servlet-name>RestletServlet</servlet-name>__<url-pattern>/service/*</url-pattern></servlet-mapping>
2.6æ§å¶å¨
使ç¨SpringMVCåäºä¸ä¸ªç®åçå°è£ ,ä¹å¯ä»¥ä½¿ç¨å ¶ä»çMVCå®ç°ã
package;
import;import;
import;import;
import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;import;
/***æµç¨æ¨¡åæ§å¶å¨**@authorhenryyan*/@Controller@RequestMapping(value="/workflow/model")publicclassModelController{
protectedLoggerlogger=(getClass());
@Autowired_RepositoryServicerepositoryService;
/**_*模åå表_*/_@RequestMapping(value="list")_publicModelAndViewmodelList(){ __ModelAndViewmav=newModelAndView("workflow/model-list");__List<model>list=().list();__("list",list);__returnmav;_}
/**_*å建模å_*/_@RequestMapping(value="create")_publicvoidcreate(@RequestParam("name")Stringname,@RequestParam("key")Stringkey,@RequestParam("description")Stringdescription,_____HttpServletRequestrequest,HttpServletResponseresponse){ __try{ ___ObjectMapperobjectMapper=newObjectMapper();___ObjectNodeeditorNode=();___("id","canvas");___("resourceId","canvas");___ObjectNodestencilSetNode=();___("namespace","#");___("stencilset",stencilSetNode);___ModelmodelData=();
ObjectNodemodelObjectNode=();___(_NAME,name);___(_REVISION,1);___description=(description);___(_DESCRIPTION,description);___(());___(name);___((key));
(modelData);___((),().getBytes("utf-8"));
(()+"/service/editor?id="+());__}catch(Exceptione){ ___("å建模å失败:",e);__}_}
/**_*æ ¹æ®Modelé¨ç½²æµç¨_*/_@RequestMapping(value="deploy/{ modelId}")_publicStringdeploy(@PathVariable("modelId")StringmodelId,RedirectAttributesredirectAttributes){ __try{ ___ModelmodelData=(modelId);___ObjectNodemodelNode=(ObjectNode)newObjectMapper().readTree((()));___byte[]bpmnBytes=null;
BpmnModelmodel=newBpmnJsonConverter().convertToBpmnModel(modelNode);___bpmnBytes=newBpmnXMLConverter().convertToXML(model);
StringprocessName=()+".";___Deploymentdeployment=().name(()).addString(processName,newString(bpmnBytes)).deploy();___("message","é¨ç½²æå,é¨ç½²ID="+());__}catch(Exceptione){ ___("æ ¹æ®æ¨¡åé¨ç½²æµç¨å¤±è´¥:modelId={ }",modelId,e);__}__return"redirect:/workflow/model/list";_}
/**_*导åºmodelçxmlæ件_*/_@RequestMapping(value="export/{ modelId}")_publicvoidexport(@PathVariable("modelId")StringmodelId,HttpServletResponseresponse){ __try{ ___ModelmodelData=(modelId);___BpmnJsonConverterjsonConverter=newBpmnJsonConverter();___JsonNodeeditorNode=newObjectMapper().readTree((()));___BpmnModelbpmnModel=(editorNode);___BpmnXMLConverterxmlConverter=newBpmnXMLConverter();___byte[]bpmnBytes=(bpmnModel);
ByteArrayInputStreamin=newByteArrayInputStream(bpmnBytes);___(in,());___Stringfilename=().getId()+".";___("Content-Disposition","attachment;filename="+filename);___();__}catch(Exceptione){ ___("导åºmodelçxmlæ件失败:modelId={ }",modelId,e);__}_}
}</pre>
###2.7注æäºé¡¹
å¦æ使ç¨Spring代çå¼æ,并ä¸å¨é¡¹ç®ä¸åæ¶ææ件(ä¸ç®¡å¨main/resourcesè¿æ¯test/resourcesç®å½),å¨éé¢çå¼æä¸æ·»å ä¸é¢çé ç½®åæ°,å¦åä¼å¯¼è´æå¼Modelerçç¼è¾é¡µé¢æ¶è¯»åæ°æ®è¿å****ç¶æç ã
<preclass="brush:xml"><propertyname="processEngineName"value="test"></property></pre>
å¼æé»è®¤å称为default,()æ¥è¯¢æ¶ä¼å æ£ç´¢main/resources,ç¶ååæ£ç´¢test/resourcesçåæ件,æ以å½main/resourcesçæµä¸å°æå®æ件æ¶å°±ä¼å¯¼è´è¯¥å¼æ被å½åwebåºç¨çå¼æ对象,è¿æ ·ä¼å¯¼è´æ两个å¼æ,æ以æå¼æçå称æ¹ä¸ºéé»è®¤çâdefaultâã
##3.ä¸æä¹±ç é®é¢è§£å³åæ³
å¨JVMåæ°ä¸æ·»å åæ°:
>-=UTF-8-=UTF-8
**åè**:[å¨ActivitiModelerä¸è®¾è®¡çæµç¨å å«å¥æ°ä¸ªä¸ææ¶ä¸è½é¨ç½²é®é¢](
##4.æææªå¾
å¨ææ°çkft-activiti-demoçæ¬(1.7.0)ä¸å·²ç»éæäºActivitiModeler,å¯ä»¥å¨çº¿è®¿é®,ä¹å¯ä»¥ä¸è½½æºç å¦ä¹ å¦ä½é ç½®ã
ç»å½[
![kft-activiti-demoä¸çæææªå¾](/files///)![kft-activiti-demoä¸çæææªå¾](/files///)</model>
Activiti6.0ä¸å¦ä½è®¾è®¡åå ³è表åï¼æ°å¢äºç¯èç¨æ·ä»»å¡,è¿æ¶ç´§è·çæ°å¢ä¸ä¸ªè¡¨åå³å¯,以åèæ¬ãæ ·å¼ãWebAPI;å é¤äºç¯èç¨æ·ä»»å¡,è¿æ¶å¯ä»¥ä¸ç¨ç®¡,为顾åæ§çæ¬çæµç¨å®ä¹,å ¶å¯¹åºç表åè¿éè¦ä¿ç,并ä¸è½å é¤;ä¿®æ¹äºç¯èç¨æ·ä»»å¡,æ¯å¦å¨Aç¯èæ°å¢äºä¸¤ä¸ªå段,åæ¶å¨Bç¯èåå°äºä¸¤ä¸ªå段,è¿æ¶å°±è¦ä¸ºAãB两个ç¯èåèªéæ°å建表åãéæ°å建èæ¬ãæ ·å¼ã以åéæ°å建WebAPI,å 为表ååäº,é£ä¹ä¸å¡ä¹å°±åäº,SQL(表)ä¹é½è·çåäºã
ãActivitiå®æãepubä¸è½½å¨çº¿é è¯»å ¨æï¼æ±ç¾åº¦ç½çäºèµæºãActivitiå®æã(é«æ´ªç£)çµå书ç½çä¸è½½å è´¹å¨çº¿é 读
é¾æ¥:
æåç :xdni
书å:Activitiå®æ
è±ç£è¯å:7.2
ä½è :é«æ´ªç£
åºç社:_åã²å éå«
åºçå¹´:-1-1
页æ°:
å 容ç®ä»:
ãActivitiå®æãç«è¶³äºå®è·µ,ä¸ä» 让读è ç¥å ¶ç¶,å ¨é¢ææ¡Activitiæ¶æãåè½ãç¨æ³ãæå·§åæä½³å®è·µ,广度足å¤;èä¸è®©è¯»è ç¥å ¶æ以ç¶,æ·±å ¥ç解Activitiçæºä»£ç å®ç°ã设计模å¼åPVM,深度ä¹è¶³å¤ã
ãActivitiå®æãä¸å ±å个é¨å:åå¤ç¯(1~2ç« )ä»ç»äºActivitiçæ¦å¿µãç¹ç¹ãåºç¨ãä½ç³»ç»æ,以åå¼åç¯å¢çæ建åé ç½®;åºç¡ç¯(3~4ç« )é¦å 讲解äºActivitiModelerãActivitiDesigner两ç§æµç¨è®¾è®¡å·¥å ·ç详ç»ä½¿ç¨,ç¶å详ç»è®²è§£äºBPMN2.0è§è;å®æç¯(5~ç« )ç³»ç»è®²è§£äºActivitiçç¨æ³ãæå·§åæä½³å®è·µ,å å«æµç¨å®ä¹ãæµç¨å®ä¾ãä»»å¡ãåæµç¨ãå¤å®ä¾ãäºä»¶ä»¥åçå¬å¨ç;é«çº§ç¯(~)éè¿éæWebServiceãè§åå¼æãJPAãESBçåç§æå¡åä¸é´ä»¶æ¥éè¿°äºActivitiä¸ä» ä» æ¯å¼æ,å®é ä¸æ¯ä¸ä¸ªBPMå¹³å°,æåè¿éè¿æºä»£ç 对å®ç设计模å¼åPVMè¿è¡äºåæã
ä½è ç®ä»:
é«æ´ªç£(åå¡å )èµæ·±è½¯ä»¶å¼åå·¥ç¨å¸åæ¶æå¸,为Activitiè´¡ç®äºå¤§é代ç ,为Activitiå¨ä¸å½çæ¨å¹¿ä¸æ®ååäºå¤§éçå·¥ä½,å¨ç¤¾ç¾¤ä¸æå¾é«çå¨æåç¥å度,被称为ä¸å½Activitié¢åç第ä¸äººãå¤å¹´æ¥ä¸ç´ä»äºOAãERPçç³»ç»çå¼åä¸æ¶æ设计工ä½,æç»å ³æ³¨å¹¶æ·±å ¥ç 究工ä½æµå¼æ,ç®åå°±èäºå°é©¬è´è½¦,æ ä»»æ¶æå¸ä¸è,并è´è´£å ¬å¸å é¨å·¥ä½æµå¹³å°ç建设工ä½ã
redis为ä»ä¹è¦åºåå
åºååæç»çç®çæ¯ä¸ºäºå¯¹è±¡å¯ä»¥è·¨å¹³å°åå¨ï¼åè¿è¡ç½ç»ä¼ è¾ãèæ们è¿è¡è·¨å¹³å°åå¨åç½ç»ä¼ è¾çæ¹å¼å°±æ¯IOï¼èæ们çIOæ¯æçæ°æ®æ ¼å¼å°±æ¯åèæ°ç»ã ï¼æ¨èå¦ä¹ ï¼Redisè§é¢æç¨ï¼
éè¿ä¸é¢ææ³ä½ å·²ç»ç¥éäºå¡æ¯éè¦è¿è¡â跨平å°åå¨âåâç½ç»ä¼ è¾âçæ°æ®ï¼é½éè¦è¿è¡åºååã
æ¬è´¨ä¸åå¨åç½ç»ä¼ è¾ é½éè¦ç»è¿ æä¸ä¸ªå¯¹è±¡ç¶æä¿åæä¸ç§è·¨å¹³å°è¯å«çåèæ ¼å¼ï¼ç¶åå ¶ä»çå¹³å°æå¯ä»¥éè¿åèä¿¡æ¯è§£æè¿å对象信æ¯ã
redisåºååæ¹å¼å¯¹æ¯ï¼
redisçé»è®¤æ¹å¼æ¯JdkSerializationRedisSerializer
JdkSerializationRedisSerializer: 使ç¨JDKæä¾çåºåååè½ã
ä¼ç¹æ¯ååºååæ¶ä¸éè¦æä¾ç±»åä¿¡æ¯(class)ï¼ä½ç¼ºç¹æ¯éè¦å®ç°Serializableæ¥å£ï¼è¿æåºåååçç»æé常åºå¤§ï¼æ¯JSONæ ¼å¼ç5åå·¦å³ï¼è¿æ ·å°±ä¼æ¶èredisæå¡å¨ç大éå åã
Jackson2JsonRedisSerializerï¼ ä½¿ç¨Jacksonåºå°å¯¹è±¡åºåå为JSONå符串ã
ä¼ç¹æ¯é度快ï¼åºåååçå符串çå°ç²¾æï¼ä¸éè¦å®ç°Serializableæ¥å£ã
ä½ç¼ºç¹ä¹é常è´å½ï¼é£å°±æ¯æ¤ç±»çæé å½æ°ä¸æä¸ä¸ªç±»ååæ°ï¼å¿ é¡»æä¾è¦åºåå对象çç±»åä¿¡æ¯(.class对象)ã éè¿æ¥çæºä»£ç ï¼åç°å ¶åªå¨ååºååè¿ç¨ä¸ç¨å°äºç±»åä¿¡æ¯ã
é®é¢ï¼ä½¿ç¨é»è®¤çJDKåºååæ¹å¼ï¼å¨RDMå·¥å ·ä¸æ¥çk-vå¼æ¶ä¼åºç°âä¹±ç âï¼ä¸æ¹ä¾¿æ¥çã
解å³ï¼èªå®ä¹ç³»ååæ¹å¼ï¼ä½¿ç¨Jackson2JsonRedisSerializer
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/
*** Redisé ç½®
*
* @author LinJie
*/
@Configuration
public class RedisConfig {
/
*** Redis repository redis repository.
*
* @param redisTemplate the redis template
* @return the redis repository
*/
@Bean
public RedisRepository redisRepository(RedisTemplate redisTemplate) {
// 使ç¨Jackson2JsonRedisSerialize æ¿æ¢é»è®¤åºåå
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// keyéç¨Stringçåºååæ¹å¼
redisTemplate.setKeySerializer(stringRedisSerializer);
// hashçkeyä¹éç¨Stringçåºååæ¹å¼
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// valueåºååæ¹å¼éç¨jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hashçvalueåºååæ¹å¼éç¨jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return new RedisRepository(redisTemplate);
}
}æ´å¤Redisç¸å ³ææ¯æç« ï¼è¯·è®¿é®Redisæ°æ®åºä½¿ç¨å ¥é¨æç¨æ ç®è¿è¡å¦ä¹ ï¼
objectmapper 线ç¨å®å ¨å
æ¯çº¿ç¨å®å ¨ç,è¿ä¸ªObjectMapperæºç ä¸ç注éä¸å·²ç»åäº:Mapper instances are fully thread-safeprovided that ALL configuration of the instance occurs before ANY read or write calls. If configuration of a mapper instance is modified after first usage, changes may or may not take effect, and configuration calls themselves may fail.
javaå¦ä½å¯¼å ¥å
1ãé¦å å¨é¡¹ç®ä¸å建ä¸ä¸ªæ°çæ件夹ï¼ç¨æ¥ä¿åjarå ãå¨é¡¹ç®åä¸ç¹å»é¼ æ å³é®ï¼æ顺åºç¹å»ãNewãâãFloderãï¼æå¼æ°å»ºæ件夹ççªå£2ãè¾å ¥æ件夹å称ãlibãï¼ç¹å»ãokããé常å¨libæ件夹ä¸åæ¾ä»å¤é¨å¼å ¥çjarå
3ãæ¾å°è¦å¼å ¥çjarå ï¼é¼ æ éä¸éè¦ç¨çjarå ï¼ç¶åæä½é¼ æ å·¦é®ä¸æ¾ï¼æjarå æå¨å°libæ件夹ä¸ãåæè æ¯å å¤å¶jarå ï¼æ¥çå¨libæ件夹ä¸å³å»ï¼éæ©å¤å¶ãæå¼éæ©æ¡ï¼å¨å¼¹åºçéæ©æ¡ä¸éæ©é»è®¤çãcopy filesãï¼ç¹å»ãOKãå ³éãæ¥çå°±å¯ä»¥å¨libæ件夹ä¸çå°å¤å¶æåçjarå ã
4ãè¿æ¶ï¼åªæ¯æjarå å¤å¶å°é¡¹ç®ä¸ï¼è¿ä¸è½å¤ä½¿ç¨ãéè¦åå¨é¡¹ç®åä¸ç¹å»é¼ æ å³é®ï¼æ顺åºéæ©
ãBuild PathãâãConfigure Build Path...ãã
5ãå¨æå¼ççªå£ä¸ï¼éä¸ãLibrariesã页ï¼ä»å³è¾¹ä¸æ çæé®ä¸ç¹å»ãadd JARs...ã
6ãå¨æå¼ççªå£ä¸ï¼æç §é¡ºåºå±å¼æ¬é¡¹ç®ålibæ件夹ï¼ç¶åéä¸ååå¤å¶å°é¡¹ç®ä¸çjarå ï¼ç¹å»ãOKãå ³éçªå£
7ãå¨ååæå¼çãLibrariesã页é¢ä¸ï¼å¯ä»¥çå°ååå¼å ¥çjarå å称ãç¹å»ãOKã确认ã
8ãè¿ä¸ªæ¶åï¼å¨ãEclipseãä¸ï¼å°±å¯ä»¥æ¾å°å¹¶ä¸å¼å§ä½¿ç¨è¿ä¸ªjarå äºã
Java泛型 | Jackson TypeReference获取泛型类型信息
前言
Jackson 是一个流行的 Json 序列化和反序列化框架,本文将探讨如何利用 TypeReference 实现涉及泛型的源码反序列化,并深入解析 TypeReference 的源码实现原理。对于需要获取泛型类型信息的源码场景,TypeReference 提供了一个通用的源码解决方案。
实例
Jackson 的源码关注任务平台源码 ObjectMapper 可以将 Json 字符串反序列化为 Java 对象。例如,源码以下代码将 Json 字符串反序列化为 List 类型:
Json 字符串:
json
[{ "id":null,源码"name":" ","age":,"gender":false,"email":"email","employed":true,"salary":}]
UserResource 实体类:
java
public class UserResource {
private Integer id;
private String name;
private Integer age;
private boolean gender;
private String email;
private boolean employed;
private double salary;
}
理想的实现方式
理想的实现方式是明确告诉 ObjectMapper 的 readValue 方法,我们需要的源码是 List 类型,以便将其反序列化为指定类型。源码然而,源码Java 编译器会报错,源码指出无法从参数化类型中选择,源码这是源码由于 Java 编译器将 List 视为 Class 类型,而非具体类型。源码
换一种方式实现
既然直接使用 List.class 不可行,我们尝试通过告诉 ObjectMapper,开心乐园开奖源码我们想要的是 List 类型,但返回值类型为 List,会怎样呢?结果是,虽然编译没有错误,但会出现警告:`Unchecked assignment: 'java.util.List' to 'java.util.List'`。ObjectMapper 实际上无法将序列化结果反序列化为 UserResource 类型,而是将其反序列化为 LinkedHashMap 类型。
TypeReference 的跌下必买源码实现方式
为解决上述问题,Jackson 提供了 ObjectMapper 的 readValue 方法,接受一个 TypeReference 类型的实例作为第二个参数。通过创建 TypeReference 的子类实例,如 `new TypeReference<List>() { }`,可以获取完整的泛型类型信息,并将 Json 字符串反序列化为指定泛型类型。
TypeReference 实现原理
TypeReference 的核心在于通过继承自 Class 类的 getGenericSuperclass 方法,获取父类中的起名小程序 源码参数化类型(ParameterizedType)。此方法返回一个 Type 类型的对象,该对象准确反映了源代码中使用的实际类型参数。
Class 的 genericInfo 属性
在获取到 ParameterizedType 后,通过调用 getActualTypeArguments 方法,可以获得泛型参数的实际类型。这样,即使在编译时无法显式指定类型参数,通过 TypeReference 也可以在运行时获取和使用泛型信息。火鸟门户源码后门
总结
解决 Elasticsearch 8.x Java API 中 Update 写入 null 值无效的问题
Elasticsearch 是一个强大而灵活的搜索和分析引擎,广泛应用于大数据场景。本文深入探讨 Elasticsearch 8.x Java API 中 Update 操作中写入 null 值无效的问题,分享问题排查与解决方法。
在使用 Elasticsearch 进行数据新增时,我们通常会优先考虑使用 Update 操作,避免对整个文档进行覆盖,以便处理多表汇聚场景中的部分字段更新需求。然而,在进行多个 Update 操作时,用 BulkOperation 构建请求,并将某个值设为 null,却发现这个值没有被正确写入 Index,返回结果中的 result 为 “noop”。
通过在 Kibana 控制台进行实验,我们发现更新数据时遇到的诡异问题是代码中导致的。起初怀疑 Elasticsearch Java API 本身存在 Bug,但深入分析代码后发现,初始化 ElasticsearchTransport 时使用的 JacksonJsonpMapper 通过默认配置导致了 null 值被排除。查看源码得知,这一配置是在初始化 ObjectMapper 时进行的,从而决定了序列化器是否处理 null 值。
解决此问题的关键在于自定义 ObjectMapper 并传递给 JacksonJsonpMapper。修正此配置后,null 值能够成功写入 Elasticsearch。这一经验强调了在使用 Elasticsearch Java API 进行开发时,需仔细审核配置及序列化器设置的重要性,以避免潜在的兼容性问题。
总结而言,本文解析了使用 Elasticsearch 8.x Java API 进行 Update 操作时,写入 null 值无效的问题,并提供了针对性的解决策略。同时,反思在实际开发过程中,应增强对 Elasticsearch 内部实现与配置的理解,以及在项目中的代码审查和测试质量,以确保应用稳定可靠运行。