最终效果
pom依赖
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11.1</version>
</dependency>
代码
XStreamUtil
这个直接复制即可
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer;
import com.thoughtworks.xstream.io.xml.XppDriver;
import java.io.Writer;
import java.lang.reflect.Field;
public class XStreamUtil {
public static XStream getXStream(Class<?> targetClass,Class<?> targetClass2) {
XStream stream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = false;
@Override
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
cdata = needCDATA(targetClass, name);
if(!cdata && targetClass2 != null ){
cdata = needCDATA(targetClass2, name);
}
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
return stream;
}
private static boolean needCDATA(Class<?> targetClass, String fieldAlias){
boolean cdata = false;
//first, scan self
cdata = existsCDATA(targetClass, fieldAlias);
if(cdata){
return cdata;
}
//if cdata is false, scan supperClass until java.lang.Object
Class<?> superClass = targetClass.getSuperclass();
while(!superClass.equals(Object.class)){
cdata = existsCDATA(superClass, fieldAlias);
if(cdata) {
return cdata;
}
superClass = superClass.getSuperclass();
}
return false;
}
private static boolean existsCDATA(Class<?> clazz, String fieldAlias){
//scan fields
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//1. exists XStreamCDATA
if(field.getAnnotation(XStreamCDATA.class) != null ){
XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
//2. exists XStreamAlias
if(null != xStreamAlias){
if(fieldAlias.equals(xStreamAlias.value())){//matched
return true;
}
}else{// not exists XStreamAlias
if(fieldAlias.equals(field.getName())){
return true;
}
}
}
}
return false;
}
public static XStream getXStream(Class<?> targetClass, Class<?>... subClasses) {
XStream stream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out, new XmlFriendlyReplacer("_-", "_")) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = false;
@Override
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
cdata = needCDATA(targetClass, name);
if (subClasses != null && !cdata) {
for (Class<?> subClass : subClasses) {
if (subClass != null) {
cdata = needCDATA(subClass, name);
}
}
}
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
return stream;
}
}
ResponseSetUtils
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ResponseSetUtils {
public static void set(HttpServletResponse response, HttpServletRequest request) {
response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.addHeader("Access-Control-Allow-Headers", "Accept,Authorization,DNT,Content-Type,Referer,User-Agent");
response.addHeader("Access-Control-Allow-Credentials", "true");
}
/**
* 设置下载头
*/
public static void setResponseHeader(HttpServletResponse response, String fileName) {
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Cache-control", "no-cache");
}
}
controller
/**
* 导出到xml
*
* @param response
* @param request
* @param param
* @return
*/
@PostMapping(value = "export-2-xml")
public ResultModel<JSONObject> export2Xml(HttpServletResponse response, HttpServletRequest request,
@RequestBody AdvertiseItemExportParam param) throws IOException {
ResultModel<JSONObject> rst = new ResultModel<>();
JSONObject track = new JSONObject().fluentPut("param", param);
rst.setModule(track);
try {
// 登录校验;
StringBuilder checkLoginMsg = new StringBuilder();
BucSSOUser user = checkLoginUser(response, request, checkLoginMsg);
if (StringUtils.isNotBlank(checkLoginMsg.toString())) {
return ResultModel.failed(checkLoginMsg.toString());
}
// 用户信息;
boolean agent = RealmIdEnum.AGENT_TENANT.getTenantId().equals(user.getRealmId());
String no = agent ? user.getCorpUserId() : user.getEmpId();
LoginUserRoleEnum loginUserRole = agent ? LoginUserRoleEnum.AGENT : LoginUserRoleEnum.INNER_USER;
LoginUserModel userModel = new LoginUserModel(no, user.getNickNameCn(), agent, loginUserRole.name());
// 分页查询数据;
List allData = advertiseCommonController.getAllRows(param, userModel);
// 转xml;
XStream xStream;
if (agent) {
// 代理
xStream = XStreamUtil.getXStream(OfferExportAgency.class);
xStream.processAnnotations(OfferExportAgency.class);
} else {
// 非代理:运营、管理
xStream = XStreamUtil.getXStream(OfferExportOperator.class);
xStream.processAnnotations(OfferExportOperator.class);
}
xStream.alias("offerList", List.class);
// 写输出流;
String fileName = UUID.randomUUID().toString().replace("-", "") + ".xml";
ResponseSetUtils.set(response, request);
ResponseSetUtils.setResponseHeader(response, fileName);
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(XML_VERSION_1_0_ENCODING_UTF_8.getBytes(StandardCharsets.UTF_8));
xStream.toXML(allData, outputStream);
outputStream.flush();
outputStream.close();
// 返回结果;
rst.setSuccess(true);
return rst;
} catch (IOException e) {
LOGGER.error("AdvertiseItemController.export2Xml process error,param:{}",
JSON.toJSONObject(param), e);
rst.setErrorMsg("控制器异常:" + e.getMessage());
return rst;
}
}
分页获取导出的数据
/**
* 循环导出
*
* @param param 参数
* @return
*/
public List getAllRows(AdvertiseItemExportParam param, LoginUserModel userModel) {
List allRows = new ArrayList<>();
ResultModel<PageResult<BottomPoolOfferDTO>> queryList;
int index = 1;
do {
param.setPageNum(index++);
param.setPageSize(500);
queryList = advertiseItemService.queryList(param, userModel);
AssertUtil.isTrue(Objects.nonNull(queryList) && queryList.isSuccess(), "查询商品数据失败");
AssertUtil.notNull(queryList.getModule(), "查询商品数据失败");
List<BottomPoolOfferDTO> records = queryList.getModule().getResultList();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(records)) {
if (userModel.isAgentUser()) {
// 代理
allRows.addAll(records.stream()
.map(OfferExportAgency::fromBottomPoolOfferDTO)
.collect(Collectors.toList()));
} else {
// 运营
allRows.addAll(records.stream()
.map(OfferExportOperator::fromBottomPoolOfferDTO)
.collect(Collectors.toList()));
}
}
}
// 如果当前已导出数据小于全量数据,同时后面还有可查询页时,继续循环查询;
while ((allRows.size() < param.getExportSize()) && (index <= queryList.getModule().getPaginator()
.getTotalPage()));
return allRows;
}
实体类
@Data
@XStreamAlias("offer")
public class OfferExportAgency {
@HeaderName(value = "商品主图", width = 50)
@XStreamCDATA
private String mainUrl;
@HeaderName(value = "商品id", width = 20)
private Long itemId;
@HeaderName(value = "商品名称", width = 30)
@XStreamCDATA
private String title;
@HeaderName(value = "权益标签", width = 25)
private String benefitLabels;
@HeaderName("起批量")
private Long startOrderNumber;
@HeaderName("热度")
private Long hotIndex;
@HeaderName("吸引力")
private Long attractionIndex;
@HeaderName(value = "一级分类", width = 20)
@XStreamCDATA
private String cateLevel1Name;
@HeaderName("二级分类")
@XStreamCDATA
private String cateLevel2Name;
@HeaderName(value = "三级分类", width = 20)
@XStreamCDATA
private String cateLevel3Name;
@HeaderName(value = "店铺名称", width = 30)
@XStreamCDATA
private String shopName;
@HeaderName(value = "商品图url", width = 100)
@XStreamCDATA
private String imageUrls;
public static OfferExportAgency fromBottomPoolOfferDTO(BottomPoolOfferDTO offerDTO) {
OfferExportAgency offer = new OfferExportAgency();
BeanUtils.copyProperties(offerDTO, offer);
// 权益标签
if (offerDTO.getBenefitLabels() != null) {
offer.setBenefitLabels(
offerDTO.getBenefitLabels().parallelStream()
.map(AdvertiseItemPageQueryParam.BenefitLabelEnum::getDescByCode)
.collect(Collectors.toList()).toString()
);
}
return offer;
}
}
XStreamCDATA注解
package com.alibaba.china.tagnore.web.utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface XStreamCDATA {
}