一、引入依赖  
<dependency>
     <groupId>org.jxls</groupId>
     <artifactId>jxls-poi</artifactId>
     <version>2.12.0</version>
 </dependency>二、准备解析的数据封装   
package com.dst.modules.business.after.sale.parts.sparepartsprocurepo.service;
import com.dst.common.util.ConvertCNMoneyUtils;
import com.dstcar.common.utils.date.DateUtil;
import com.dstcar.common.utils.spring.BeanUtil;
import com.dstcar.entitys.sparepartsprocurepo.*;
import lombok.extern.slf4j.Slf4j;
import org.jxls.common.Context;
import org.jxls.util.JxlsHelper;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@Slf4j
@Component
public class SparePartsProcurePoQuoteTemplateRender {
    private Resource spTemplate;
    @PostConstruct
    protected void init() {
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        spTemplate = resourceLoader.getResource("classpath:/templates/excelTemp/SparePartsProcurePoQuoteTemplate.xlsx");
    }
    /**
     * 渲染
     * @param os    输出流
     */
    public void render(SparePartsProcurePoDTO procurePoDTO, OutputStream os) {
        try (InputStream is = spTemplate.getInputStream()) {
            Context context = new Context();
            context.putVar("data", buildData(procurePoDTO));
            JxlsHelper.getInstance().processTemplate(is, os, context);
        } catch (Exception e) {
            log.error("采购订单模版渲染异常", e);
        }
    }
    private SpareParsProcurePoQuoteTemplateData buildData(SparePartsProcurePoDTO procurePoDTO) {
        final SpareParsProcurePoQuoteTemplateData templateData = new SpareParsProcurePoQuoteTemplateData();
        SparePartsProcurePo sparePartsProcurePo = procurePoDTO.getSparePartsProcurePo();
        BeanUtil.copyProperties(sparePartsProcurePo,templateData);
        List<SparePartsProcurePoDetail> procurePoDetailList = procurePoDTO.getProcurePoDetailList();
        AtomicReference<Integer> i = new AtomicReference<>(1);
        final List<SpareParsProcurePoQuoteSkuTemplateData> skuTemplateData = procurePoDetailList.stream().map(pro -> {
            final SpareParsProcurePoQuoteSkuTemplateData quoteSkuTemplateData = new SpareParsProcurePoQuoteSkuTemplateData();
            quoteSkuTemplateData.setSequence(i.getAndSet(i.get() + 1));
            BeanUtil.copyProperties(pro, quoteSkuTemplateData);
            return quoteSkuTemplateData;
        }).sorted(Comparator.comparing(SpareParsProcurePoQuoteSkuTemplateData::getSequence)).collect(Collectors.toList());
        //大小写金额转换
        templateData.setTotalAmountStr(ConvertCNMoneyUtils.toChinese(String.valueOf(templateData.getTotalAmount())));
        templateData.setTotalPurchaseQuantity(skuTemplateData.stream().map(SpareParsProcurePoQuoteSkuTemplateData::getPurchaseQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        templateData.setOrderTime(DateUtil.convert2String(sparePartsProcurePo.getOrderTime(), DateUtil.DATEFORMAT));
        templateData.setContractCode(procurePoDetailList.get(0).getContractCode());
        templateData.setDetails(skuTemplateData);
        return templateData;
    }
}
三、对应导出excel数据的实体类  
1.订单主档  
package com.dstcar.entitys.sparepartsprocurepo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class SpareParsProcurePoQuoteTemplateData {
    /** 采购订单号 规则:CGDD+日期+流水号,按日期累加 **/
    private String orderCode;
    /** 订单日期 **/
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private String orderTime;
    /** 甲方名称 **/
    private String partyAName;
    /** 乙方名称 **/
    private String partyBName;
    /** 需方授权代表 **/
    private String demandAgent;
    /** 供方授权代表 **/
    private String supplierAgent;
    /** 需方地址 **/
    private String demandAddress;
    /** 供方地址 **/
    private String supplierAddress;
    /** 需方联系方式 **/
    private String demandContactsStyle;
    /** 供方联系方式 **/
    private String supplierContactsStyle;
    /** 结算方式:1月结30天|2月结60天|3月结90天|4先款后货(字典:spare_parts_payment_method) **/
    private String paymentMethodName;
    /** 发票类型:1增值税发票2普通发票(字典:spare_parts_po_invoice_type) **/
    private String invoiceTypeName;
    /** 订单总额(产品明细含税总额合计【含税总额(含税单价unitPriceIncludeTax * 采购数量purchaseQuantity)】) **/
    private BigDecimal totalAmount;
    /**
     * 订单总额大写文字
     */
    private String totalAmountStr;
    /**
     * 总的采购数量
     */
    private BigDecimal totalPurchaseQuantity;
    /** 备注 **/
    private String remark;
    /** 关联合同号 **/
    private String contractCode;
    /** po订单明细 */
    private List<SpareParsProcurePoQuoteSkuTemplateData> details;
}
2.订单明细实体  
package com.dstcar.entitys.sparepartsprocurepo;
import com.dstcar.common.translation.Translation;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class SpareParsProcurePoQuoteSkuTemplateData {
    /**
     * 序号
     */
    private Integer sequence;
    /** 零配件编码,逗号分割 **/
    @Translation(convertName = "partsMaterialNameBatchConvert", convertTo = {"materialCodes-materialName"})
    private String materialCodes;
    /**
     * 物料名称
     */
    private String materialName;
    /** 零配件规格 */
    private String specs;
    /** 计量单位 */
    private String productUnitName;
    /** 采购数量 **/
    private BigDecimal purchaseQuantity;
    /** 含税单价 **/
    private BigDecimal unitPriceIncludeTax;
    /** 税率 **/
    private BigDecimal taxRate;
    /** 含税总额(含税单价*采购数量) **/
    private BigDecimal includeTotalAmount;
    /** 收货人 **/
    private String receivedPerson;
    /** 收货人联系电话 **/
    private String receivedPhone;
    /** 收货人地址 **/
    private String receivedAddress;
    /** 备注 **/
    private String remark;
}
3.转化为导出url路径  
    /**
     * 下载po订单模板接口
     * @param id
     * @return
     */
    public Results downloadOrder(String id,SSOUser ssoUser) {
        SparePartsProcurePoDTO procurePoDTO = this.getProcurePoDetailById(id);
        Integer priceSource = procurePoDTO.getProcurePoDetailList().get(0).getPriceSource();
        // 渲染
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        if (SparePartsFirmConstant.PRICE_SOURCE_2.equals(priceSource) ||
                SparePartsFirmConstant.PRICE_SOURCE_1.equals(priceSource) ||
                SparePartsFirmConstant.PRICE_SOURCE_4.equals(priceSource)) {
            sparePartsProcurePoCatalogTemplateRender.render(procurePoDTO, outputStream);
        } else if (SparePartsFirmConstant.PRICE_SOURCE_3.equals(priceSource) ||
                SparePartsFirmConstant.PRICE_SOURCE_5.equals(priceSource) ){
            sparePartsProcurePoQuoteTemplateRender.render(procurePoDTO, outputStream);
        } else {
            log.error("价格来源类型不存在:{}",priceSource);
            sparePartsProcurePoQuoteTemplateRender.render(procurePoDTO, outputStream);
        }
        // 上传
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        String fileName = getFileName();
        final String aliObjName = genAliObjName(fileName);
        final String fileUrl = aliOSSStoreClient.uploadFile(inputStream, aliObjName, fileName);
        log.info("渲染采购订单模板并上传路径:{}, 文件名:{}", aliObjName, fileName);
        uploadExcel(AliOSSHelper.getAccessUrl(fileUrl),fileName,ssoUser);
        return succeed();
    }
    /**
     * 生成订单附件文件
     * @return
     */
    private String getFileName() {
        return "易维&供应商名称-采购订单" + ".xlsx";
    }
    /**
     * 生成文件上传路径
     * @return
     */
    private String genAliObjName(String FileName) {
        return "/operate/spare/parts/procure/po/template/"+dstIdUtils.getPrimaryKey()+"/" + FileName;
    }
    /**
     *
     * @param url
     * @param fileName
     */
    public  void uploadExcel(String url, String fileName, SSOUser ssoUser){
        Date date = new Date();
        ExportRecord exportRecord = new ExportRecord();
        exportRecord.setFileUrl(url);
        exportRecord.setFileName(fileName);
        exportRecord.setModule(10);
        exportRecord.setModuleName("零配件采购订单");
        //处理完成
        exportRecord.setStatus(2);
        exportRecord.setSource(0);
        exportRecord.setFileClassification(0);
        exportRecord.setRequestMethod("GET");
        exportRecord.setServerName("dst-operate-basic-api");
        exportRecord.setFileType(FileTypeConstant.EXCEL_2007);
        exportRecord.setCreateUserId(ssoUser.getId());
        exportRecord.setCreateUserName(ssoUser.getRealname());
        exportRecord.setCreateTime(date);
        exportRecord.setUpdateUserId(ssoUser.getId());
        exportRecord.setUpdateUserName(ssoUser.getRealname());
        exportRecord.setUpdateTime(date);
        exportRecordService.save(exportRecord);
    } 4.导出订单模板填充  
 
    采 购 订 单 签订时间:${data.orderTime} 订单编号:${data.orderCode} 需方(甲方):${data.partyAName} 供方(乙方):${data.partyBName} 授权代表:${data.demandAgent} 授权代表:${data.supplierAgent} 地址:${data.demandAddress} 地址:${data.supplierAddress} 联系方式:${data.demandContactsStyle} 联系方式:${data.supplierContactsStyle} 经双方友好协议确认,根据下列条款订立本合同: 一、内容:(甲方向乙方订购以下货物): 序号 物料名称 物料编码 物料规格及描述 单位 数量 单价(元) 税率(%) 金额(元) 收货人 收货人联系方式 收货地址 备注(交期) ${detail.sequence} ${detail.materialName} ${detail.materialCodes} ${detail.specs} ${detail.productUnitName} ${detail.purchaseQuantity} ${detail.unitPriceIncludeTax} ${detail.taxRate} ${detail.includeTotalAmount} ${detail.receivedPerson} ${detail.receivedPhone} ${detail.receivedAddress} ${detail.remark} 货款合计(大写):(含税费及运费) ${data.totalAmountStr}   ${data.totalPurchaseQuantity} 小写合计 ${data.totalAmount}         备注 交付时间由甲乙双方书面确认。 二、结算方式:${data.paymentMethodName} 三、订单有效期: 四、质保期: 五、包装标准和要求:物品的包装除可靠保护内存物品外,必须整洁完好,并符合国内各地常规仓储条件的包装要求;外标识清晰正确,并与送货单所示内容一致,乙方应按照包装要求进行包装,并承担运费。甲方应自收到上述物料之日起【2】个工作日内完成上述物料的清点及验收。甲方对乙方上述物料的验收仅视为对其数量、规格、外包装等确认,不代表对物料质量的确认。 六、质量要求与交付期限要求:乙方保证货品质量和品质符合甲方要求,按甲方技术要求、图纸成封样为准,产品封样后未经甲方书面许可,乙方不可擅自更改任何材料和生产工艺、否则导致所供产品质量下降,最终使产品质量下降而需蒙受重大损失(包括:人员全检损失、特采损失,返工更换等待损失、甲方客户退货损失等),乙方要承担造成甲方损失的全部责任,质量不满足要求的,甲方有权要求乙方免费退换物料,乙方需按照本订单约定的交付时间完成物料交付,如因乙方未正常交货影响甲方整个项目进程的,乙方需承担本订单总金额50%的违约责任,违约金不足以弥补甲方损失的,乙方还应继续承担损害赔偿责任。 七、其他约定: 甲 方 乙 方 甲 方(盖章): ${data.partyAName} 乙 方(盖章): ${data.partyBName} 授权代表(签字): 授权代表(签字): 
 
 
四、效果预览