This commit is contained in:
huzhengkao 2025-05-30 16:21:59 +08:00
parent 9b6996e024
commit 2857b0c4d7
11 changed files with 178 additions and 37 deletions

47
.gitignore vendored Normal file
View File

@ -0,0 +1,47 @@
######################################################################
# Build Tools
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
target/
!.mvn/wrapper/maven-wrapper.jar
######################################################################
# IDE
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### JRebel ###
rebel.xml
### NetBeans ###
nbproject/private/
build/*
nbbuild/
dist/
nbdist/
.nb-gradle/
######################################################################
# Others
*.log
*.xml.versionsBackup
*.swp
!*/build/*.java
!*/build/*.html
!*/build/*.xml

View File

@ -100,17 +100,16 @@ public class ProvTestServerController {
// List<DomesticPharmaBaseInfo> list= XmlStringParser.parseVaccineManufacturers(xml,eventPojo.getSubType());
//解析并保存数据
// XmlStringParser.parseXml(xml, "1011", data -> {
// domesticPharmaBaseInfoService.save((DomesticPharmaBaseInfo) data);
// });
XmlStringParser.parseXml(xml, "1011", data -> {
domesticPharmaBaseInfoService.save((DomesticPharmaBaseInfo) data);
});
List<DomesticProducer> producers = xmlParserService.parseMultiDataXml(
xml,
VTTSBasic.class,
DomesticProducer.class
);
// List<DomesticProducer> producers = xmlParserService.parseMultiDataXml(
// xml,
// DomesticProducer.class
// );
logger.info("解析后的数据条数:{}", producers.size());
logger.info("解析后的数据条数:{}", "");
return ResponseBuilder.success();
}catch (Exception e){

View File

@ -131,7 +131,8 @@ public class DomesticProducer extends BaseEntity<DomesticProducer>{
@Override
public String getDatasetName() {
return "境内药品生产企业基本信息数据子集";
return "境内药品生产企业基本信息数据子集1111";
}
}
}

View File

@ -14,20 +14,17 @@ import java.util.List;
@XmlRootElement(name = "VTTSBasic")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@XmlSeeAlso({DomesticProducer.class})
public class VTTSBasic<T> {
@XmlElement(name = "datasetName")
private String datasetName;
@XmlElementWrapper(name = "dataset")
//@XmlElements(@XmlElement(name = "data"))
@XmlElement(name = "data")
private List<T> dataset = new ArrayList<>(); // 必须初始化集合
// private List<T> dataset; // 必须初始化集合
private List<DomesticProducer> dataset;
// 确保有无参构造器
public VTTSBasic() {}
// 添加@XmlSeeAlso指定实现类
@XmlSeeAlso({
DomesticProducer.class
})
public static class KnownTypes {}
}

View File

@ -1,23 +1,24 @@
package com.alihealth.d2d.provtest.service;
import com.alihealth.d2d.provtest.domain.DomesticProducer;
import com.alihealth.d2d.provtest.entity.VTTSBasic;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* @author Jason
@ -26,35 +27,104 @@ import java.util.List;
@Service
public class XmlParserService {
private static final Map<Class<?>, JAXBContext> CONTEXT_CACHE = new ConcurrentHashMap<>();
/**
* 解析包含多个data节点的XML
* @param xml 完整XML内容
* @param wrapperClass 外层包装类如VTTSBasic.class
* @param dataClass 内部data节点对应的实体类
*/
public <T> List<T> parseMultiDataXml(
public <T> List<DomesticProducer> parseMultiDataXml(
String xml,
Class<?> wrapperClass,
Class<T> dataClass) throws Exception {
JAXBContext context = JAXBContext.newInstance(wrapperClass, dataClass);
Unmarshaller unmarshaller = context.createUnmarshaller();
// 1. 参数校验
if (xml == null || xml.trim().isEmpty()) {
throw new IllegalArgumentException("XML内容不能为空");
}
// 使用StAX提高安全性
// 2. 创建包含包装类和数据类的JAXB上下文
JAXBContext context = JAXBContext.newInstance(
VTTSBasic.class,
dataClass // 包含实际要解析的数据类型
);
// 3. 配置安全的Unmarshaller防止XXE攻击
Unmarshaller unmarshaller = context.createUnmarshaller();
XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));
// 4. 解析XML
try (StringReader reader = new StringReader(xml)) {
// XMLStreamReader xsr = xif.createXMLStreamReader(reader);
// JAXBElement<VTTSBasic> root = unmarshaller.unmarshal(xsr, VTTSBasic.class);
//
// // 5. 获取解析结果
// VTTSBasic<T> wrapper = root.getValue();
// List<T> result = wrapper.getDataset();
//
// // 6. 类型安全检查
// if (!result.isEmpty() && !dataClass.isInstance(result.get(0))) {
// throw new ClassCastException("XML中包含类型不匹配的数据");
// }
//
// return result;
// 创建 JAXBContext 时包含所有相关类
// JAXBContext jc = JAXBContext.newInstance(VTTSBasic.class, Data.class);
//Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<?> root = unmarshaller.unmarshal(xsr, wrapperClass);
Field datasetField = wrapperClass.getDeclaredField("dataset");
datasetField.setAccessible(true);
// 解析 XML
XMLStreamReader xsr = xif.createXMLStreamReader(reader);
JAXBElement<VTTSBasic> root = unmarshaller.unmarshal(xsr, VTTSBasic.class);
@SuppressWarnings("unchecked")
List<T> result = (List<T>) datasetField.get(root.getValue());
// 获取解析结果
VTTSBasic wrapper = root.getValue();
List<DomesticProducer> result = wrapper.getDataset();
return result != null ? result : Collections.emptyList();
return result;
}
}
@SuppressWarnings("unchecked")
public static <T> VTTSBasic<T> parseXml(String xml, Class<T> dataType) throws Exception {
JAXBContext context = getOrCreateContext(VTTSBasic.class, dataType);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<VTTSBasic> element = unmarshaller.unmarshal(
new StreamSource(new StringReader(xml)),
VTTSBasic.class
);
return element.getValue();
}
public static <T> String toXml(VTTSBasic<T> vttsBasic, Class<T> dataType) throws Exception {
JAXBContext context = getOrCreateContext(VTTSBasic.class, dataType);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(vttsBasic, writer);
return writer.toString();
}
private static JAXBContext getOrCreateContext(Class<?>... classes) throws JAXBException {
String key = Arrays.stream(classes)
.map(Class::getName)
.sorted()
.collect(Collectors.joining("|"));
return CONTEXT_CACHE.computeIfAbsent(key.getClass(), k -> {
try {
// 为泛型类型创建JAXB上下文
return JAXBContext.newInstance(classes);
} catch (JAXBException e) {
throw new RuntimeException("Failed to create JAXBContext", e);
}
});
}
}

View File

@ -0,0 +1,27 @@
com\alihealth\d2d\provtest\entity\BaseEntity.class
com\alihealth\d2d\provtest\factory\EntityFactoryManager.class
com\alihealth\d2d\provtest\utils\XmlStringParser.class
com\alihealth\d2d\provtest\service\impl\DomesticPharmaBaseInfoServiceImpl.class
com\alihealth\d2d\provtest\service\XmlParserService.class
com\alihealth\d2d\provtest\mapper\DomesticPharmaBaseInfoMapper.class
com\alihealth\d2d\provtest\service\IDomesticPharmaBaseInfoService.class
com\alihealth\d2d\provtest\utils\RequestWrapper$1.class
com\alihealth\d2d\provtest\utils\RequestWrapper.class
com\alihealth\d2d\provtest\domain\DomesticPharmaBaseInfo.class
com\alihealth\d2d\provtest\utils\BouncyCastlePFXGenerator.class
com\alihealth\d2d\provtest\utils\EventPojo.class
com\alihealth\d2d\provtest\factory\DomesticPharmaBaseInfoFactory.class
com\alihealth\d2d\provtest\utils\Base64.class
com\alihealth\d2d\provtest\utils\StreamUtil.class
com\alihealth\d2d\provtest\controller\ProvTestServerController.class
com\alihealth\d2d\provtest\factory\EntityFactory.class
com\alihealth\d2d\provtest\utils\EntityProcessor.class
com\alihealth\d2d\provtest\entity\XmlEntity.class
com\alihealth\d2d\provtest\utils\KeyStoreUtil.class
com\alihealth\d2d\provtest\enums\BuzStatusEnum.class
com\alihealth\d2d\provtest\enums\StatusEnum.class
com\alihealth\d2d\provtest\domain\DomesticProducer.class
com\alihealth\d2d\provtest\ProvtestApplication.class
com\alihealth\d2d\provtest\entity\VTTSBasic.class
com\alihealth\d2d\provtest\ProvTestClient.class
com\alihealth\d2d\provtest\utils\ResponseBuilder.class