POI获取模板文件,替换数据横纵动态表格、折线图、饼状图、折线饼状组合图

news2024/9/25 1:11:03

先说几个关键的点
pom.xml依赖

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.2</version>
    <exclusions>
        <exclusion>
            <groupId>poi</groupId>
            <artifactId>poi</artifactId>
        </exclusion>
        <exclusion>
            <groupId>poi-ooxml</groupId>
            <artifactId>poi-ooxml</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
    <exclusions>
        <exclusion>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
    <exclusions>
        <exclusion>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </exclusion>
    </exclusions>
</dependency>

横纵动态表格

首先读取你的数据,做好List<Map<String, Object>> list的数据,进行横表格纵表格动态填充

//XWPFTemplate模板启动所需配置LoopRowTableRenderPolicy行表格、LoopColumnTableRenderPolicy列表格
RenderPolicy policy1 = new LoopRowTableRenderPolicy(false);
Map<RenderPolicy, List<String>> polines1 = MapUtil.builder(policy1, Arrays.asList("rankScoreMapList")).map();
RenderPolicy policy2 = new LoopColumnTableRenderPolicy(false);
Map<RenderPolicy, List<String>> polines2 = MapUtil.builder(policy2, Arrays.asList("RL")).map();
List<Map<RenderPolicy, List<String>>> configList = Arrays.asList(polines1, polines2);
//渲染生成Word
String result = processWordTemplate(filename, map, scoreMapList, configList, rankScoreMapList, rankTicketTypeMapList);
return result;

读取配置并渲染数据

@SneakyThrows
public String processWordTemplate(String filename, Map<String, Object> replacements, List<Map<String, Object>> scoreMapList, List<Map<RenderPolicy, List<String>>> configList, List<Map<String, Object>> rankScoreMapList, List<Map<String, Object>> rankTicketTypeMapList) {
   byte[] fileBytes = upmsService.getFileBytes(filename);
   ByteArrayInputStream bis = new ByteArrayInputStream(fileBytes);
   //读取配置
   Configure config = Configure.createDefault();
   if (ObjectUtil.isNotEmpty(configList)) {
       for (Map<RenderPolicy, List<String>> map : configList) {
           for (Map.Entry<RenderPolicy, List<String>> entry : map.entrySet()) {
               RenderPolicy key = entry.getKey();
               List<String> value = entry.getValue();
               value.stream().forEach(val -> config.customPolicy(val, key));
           }
       }
   }
   //1. 渲染文本和表格数据replacements
   XWPFTemplate template = XWPFTemplate.compile(bis, config).render(replacements);
   XWPFDocument document = template.getXWPFDocument();
   //2. 继续处理 -> 更改图表模板 -> 饼状图、折线图
   List<POIXMLDocumentPart> relations = document.getRelations();
   //.....详细代码见最下方。


    //完成操作后保存文档
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   document.write(bos);
   byte[] bytes = bos.toByteArray();
   PoitlIOUtils.closeQuietlyMulti(template, bos);//关闭流
   MultipartFile multipartFile = new MockMultipartFile(filename + ".docx", filename + ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", bytes);
   R r = headersRemoteUpmsService.upload(multipartFile);
   if (r != null && r.isOk() && r.getData() != null) {
       Map<String, Object> data = (Map<String, Object>) r.getData();
       if (DataJudgeUtil.isNotBankMapKey(data, "url")) {
           return data.get("url").toString();
       }
   }
   return null;
 }

效果图如下:
在这里插入图片描述
在这里插入图片描述
注意1:横动态图表会自动获取该行的宽度,然后等分到每一栏中,我们需要将变量的长度给扩大,如果需要自定义宽度,请先移步到其他博客。
注意2:如果和我的一样为不标准的表格,需要放到该列的前一列中的任一单元格去,如:得分{{RL}}。放到测评项目单元格是不对的!!
在这里插入图片描述在这里插入图片描述
更多可以参考官网:https://deepoove.com/poi-tl/#hack-loop-table

图表:

确保你的图表为这种excel表格,而不是普通的图片
在这里插入图片描述
在这里插入图片描述

图表填充(其实就是填充对应的excel表格,一行一行的填充数据)饼图为例

List<POIXMLDocumentPart> relations = document.getRelations();
for (POIXMLDocumentPart poixmlDocumentPart : relations) {
  if (poixmlDocumentPart instanceof XWPFChart) {
     XWPFChart chart = (XWPFChart) poixmlDocumentPart;
     XSSFSheet sheet = chart.getWorkbook().getSheetAt(0);
     XSSFCell cell = sheet.getRow(0).getCell(1);
	 if (cell.getStringCellValue().equals("领导班子(A票)")) {
       // 过滤掉总分标签
       rankTicketTypeMapList = rankTicketTypeMapList.stream().filter(m -> !m.get("itemName").equals("总分")).collect(Collectors.toList());
       // 设置各指标得分的单元格
       for (int i = 0; i < rankTicketTypeMapList.size(); i++) {
           Row dataRow = sheet.getRow(i + 1);
           if (dataRow == null) {
               dataRow = sheet.createRow(i + 1);
           }
           //设置标签名
           Cell itemNameCell = dataRow.getCell(0);
           if (itemNameCell == null) {
               itemNameCell = dataRow.createCell(0);
           }
           itemNameCell.setCellValue(rankTicketTypeMapList.get(i).get("itemName").toString());
           itemNameCell.setCellType(CellType.STRING);
           // 设置得分单元格
           Cell scoreCellA = dataRow.getCell(1);
           if (scoreCellA == null) {
               scoreCellA = dataRow.createCell(1);
           }
           scoreCellA.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_A").toString()));
           scoreCellA.setCellType(CellType.NUMERIC);
           Cell scoreCellB = dataRow.getCell(2);
           if (scoreCellB == null) {
               scoreCellB = dataRow.createCell(2);
           }
           scoreCellB.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_B").toString()));
           scoreCellB.setCellType(CellType.NUMERIC);
           Cell scoreCellC = dataRow.getCell(3);
           if (scoreCellC == null) {
               scoreCellC = dataRow.createCell(3);
           }
           scoreCellC.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_C").toString()));
           scoreCellC.setCellType(CellType.NUMERIC);
           Cell scoreCellALL = dataRow.getCell(4);
           if (scoreCellALL == null) {
               scoreCellALL = dataRow.createCell(4);
           }
           scoreCellALL.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_ALL").toString()));
           scoreCellALL.setCellType(CellType.NUMERIC);
       }
       firstRow = 1;
       lastRow = rankTicketTypeMapList.size();
       firstCol = 1;
       lastCol = 4;
       // 为什么默认是八行?可能和建表图的时候添加了八行?删除多余的行
       for (int i = sheet.getLastRowNum(); i > rankTicketTypeMapList.size() + 1; i--) {
           sheet.removeRow(sheet.getRow(i));
       }
   }
}

填充完数据,需要刷新图表,才会把新数据应用到图表中:
s.replaceData(cat, val);chart.plot(chartData);

XDDFChartData chartData = chart.getChartSeries().get(0);
if (chartData instanceof XDDFPieChartData) {//判断类型为饼图
   XDDFChartData.Series s = chartData.getSeries().get(0);
   XDDFDataSource cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
           new CellRangeAddress(firstRow, lastRow, 0, 0));
   XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
           new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
   s.replaceData(cat, val);
   chart.plot(chartData);
}

折线图与柱状图的组合图需要分别获取并刷新

//应用数据后刷新
XDDFChartData chartData = chart.getChartSeries().get(0);

XDDFChartData chartData0 = chart.getChartSeries().get(0);//XDDFBarChartData柱状系列数据
XDDFChartData chartData1 = chart.getChartSeries().get(1);//XDDFLineChartData折线系列数据

XDDFDataSource cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
        new CellRangeAddress(firstRow, lastRow, 0, 0));
for (int i = 0; i < chartData0.getSeries().size(); i++) {
    XDDFChartData.Series s = chartData0.getSeries().get(i);
    XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
            new CellRangeAddress(firstRow, lastRow, firstCol + i, firstCol + i));
    s.replaceData(cat, val);
}
for (int i = 0; i < chartData1.getSeries().size(); i++) {
    XDDFChartData.Series s = chartData1.getSeries().get(i);
    XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
            new CellRangeAddress(firstRow, lastRow, firstCol + i + 2, firstCol + i + 2));
    s.replaceData(cat, val);
}
chart.plot(chartData0);
chart.plot(chartData1);

效果如图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此组合图的编辑如下:(根据自己需要的设置,填充数据后也要换成自己的刷新方式)
在这里插入图片描述

全部代码如下:

前面一直都在获取数据,主要的代码去见processWordTemplate
折线图、饼状图、折线饼状组合图均见processWordTemplate方法

package com.grp.digitization.hr.common.rest.kpiticketfeedback;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopColumnTableRenderPolicy;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.util.PoitlIOUtils;
import com.grp.digitization.admin.api.feign.RemoteUpmsService;
import com.grp.digitization.common.core.util.R;
import com.grp.digitization.common.security.annotation.Inner;
import com.grp.digitization.hr.feign.hr.HeadersRemoteUpmsService;
import com.grp.digitization.hr.utils.DataJudgeUtil;
import com.grp.digitization.platform.server.GrpServer;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController()
@RequestMapping("/KpiTicketFeedback")
@Api(value = "KPICadreFeedbackReport", tags = "中层干部考核任务->生成中层干部反馈报告WORD文件")
public class KpiTicketFeedbackController {
    @Resource
    private RemoteUpmsService upmsService;
    @Autowired
    private HeadersRemoteUpmsService headersRemoteUpmsService;

    //    private static final String filename = "tohi-FeedbackReports_Final.docx";
    private static final String filename = "tohi-88b5591ba7064d43856e162d93adb9c2.docx";


    @SneakyThrows
    @RequestMapping("/exportFeedbackWord/{code}")
    @Inner(value = false)
    @ApiOperation(value = "exportFeedbackWord", notes = "生成中层干部反馈报告")
    public R exportFeedbackWord(@PathVariable String code) {
        //拿到该评分任务下的每个用户,为每个用户生成一份反馈报告
        String personSql = "SELECT obj.USERNAME,obj.NAME,obj.DENAME,su.US_TITLE,mv.ENDTIME,mv.TITLE,mv.YEAR\n" +
                "FROM `middlecadresobjflow` obj LEFT JOIN middlecadresreview mv ON obj.MIDDLECADRESREVIEWCODE = mv.MIDDLECADRESREVIEWCODE LEFT JOIN sys_user su ON obj.USERNAME = su.username \n" +
                "WHERE obj.MIDDLECADRESREVIEWCODE = '" + code + "'";
        List<Map<String, Object>> personMapList = GrpServer.getGrpServer().excuteQueryListMap(personSql);
        Map<String, String> resultMap = personMapList.stream()
                .collect(Collectors.toMap(
                        m -> m.get("USERNAME").toString(),
                        m -> generatePersonWord(code, personMapList, m.get("USERNAME").toString())//调用方法获取生成的文件的URL
                ));
        //写入数据库
        for (Map.Entry<String, String> entry : resultMap.entrySet()) {
            log.info("生成中层干部反馈报告key:{},value:{}", entry.getKey(), entry.getValue());
            String updateSql = "UPDATE middlecadresobjflow SET FEEDBACK_URL = '" + entry.getValue() + "'" +
                    " WHERE MIDDLECADRESREVIEWCODE = '" + code + "' AND USERNAME = '" + entry.getKey() + "'";
            GrpServer.getGrpServer().excuteUpdate(updateSql);
        }

        return R.ok(resultMap);
    }

    @SneakyThrows
    private String generatePersonWord(String code, List<Map<String, Object>> personMapList, String username) {
        if (StringUtils.isEmpty(username)) {
            return "";
        }
        Map<String, Object> map = new HashMap<>();//声明存放数据的map
        Optional<Map<String, Object>> first = personMapList.stream().filter(m -> m.containsKey("USERNAME") && m.get("USERNAME").toString().equals(username)).findFirst();
        if (first.isPresent()) {
            Map<String, Object> tmp = first.get();
            map.put("name", DataJudgeUtil.isNotBankMapKey(tmp, "NAME") ? tmp.get("NAME").toString() : "");
            map.put("dept", DataJudgeUtil.isNotBankMapKey(tmp, "DENAME") ? tmp.get("DENAME").toString() : "");
            map.put("title", DataJudgeUtil.isNotBankMapKey(tmp, "US_TITLE") ? tmp.get("US_TITLE").toString() : "");
            map.put("date", DataJudgeUtil.isNotBankMapKey(tmp, "ENDTIME") ? tmp.get("ENDTIME").toString().split("T")[0] : "");
            map.put("theme", DataJudgeUtil.isNotBankMapKey(tmp, "TITLE") ? tmp.get("TITLE").toString() : "");
            map.put("year", DataJudgeUtil.isNotBankMapKey(tmp, "YEAR") ? tmp.get("YEAR").toString().split("-")[0] : "");
        }


        //获取票类型以及数量(有效)
        String ticketSql = "SELECT TICKETTYPE,WEIGHT,COUNT(*) AS NUM FROM `middlecadresscore` \n" +
                "WHERE MIDDLECADRESREVIEWCODE = '" + code + "' AND TICKETSTATE = '1' GROUP BY TICKETTYPE,WEIGHT";
        List<Map<String, Object>> ticketMapList = GrpServer.getGrpServer().excuteQueryListMap(ticketSql);
        long effective_SUM = ticketMapList.stream().map(m -> Integer.valueOf(m.get("NUM").toString())).mapToLong(Integer::intValue).sum();
        Double wight_SUM = ticketMapList.stream().map(m -> Double.valueOf(m.get("WEIGHT").toString())).mapToDouble(Double::doubleValue).sum();
        ticketMapList.forEach(m -> {
            int count = Integer.valueOf(m.get("NUM").toString());
            double percentage = (count * 100.0) / effective_SUM;
            String percentageStr = String.format("%.2f", percentage) + "%";
            map.put("EFF_" + m.get("TICKETTYPE").toString(), m.get("NUM").toString());
            map.put("PE_" + m.get("TICKETTYPE").toString(), percentageStr);
            map.put("WIGHT_" + m.get("TICKETTYPE").toString(), String.format("%.2f", Double.valueOf(m.get("WEIGHT").toString())) + "%");
        });
        map.put("EFF_SUM", String.valueOf(effective_SUM));
        map.put("WIGHT_SUM", String.format("%.2f", wight_SUM) + "%");

        //总票数
        String all_ticketSql = "SELECT TICKETTYPE,WEIGHT,COUNT(*) AS NUM FROM `middlecadresscore` \n" +
                "WHERE MIDDLECADRESREVIEWCODE = '" + code + "' GROUP BY TICKETTYPE,WEIGHT";
        List<Map<String, Object>> all_ticketMapList = GrpServer.getGrpServer().excuteQueryListMap(all_ticketSql);
        long all_SUM = all_ticketMapList.stream().map(m -> Integer.valueOf(m.get("NUM").toString())).mapToLong(Integer::intValue).sum();
        all_ticketMapList.forEach(m -> {
            int count = Integer.valueOf(m.get("NUM").toString());
            double percentage = (count * 100.0) / all_SUM;
            String percentageStr = String.format("%.2f", percentage) + "%";
            map.put("ALL_" + m.get("TICKETTYPE").toString(), m.get("NUM").toString());
            map.put("PA_" + m.get("TICKETTYPE").toString(), percentageStr);
        });
        map.put("ALL_SUM", String.valueOf(all_SUM));

        // 更改图表模板-> 饼状图

        //统计所有人的测评项目、综合得分
        String all_scoreSql = "SELECT OBJECTNO,itemCode,itemName,SUM(SCORE*WEIGHT)/100 as synthesisScore FROM \n" +
                "(SELECT mcp.itemCode,mcp.itemName,mcp.OBJECTNO,ms.ticketType,ms.WEIGHT,SUM(mcp.SCORE) / COUNT(*) AS SCORE FROM middlecadresscorecp mcp \n" +
                "LEFT JOIN middlecadresscore ms ON ms.MIDDLECADRESSCORECODE = mcp.MIDDLECADRESSCORECODE WHERE ms.MIDDLECADRESREVIEWCODE = '" + code + "' AND ms.TICKETSTATE = '1' \n" +
                "GROUP BY mcp.itemCode,mcp.itemName,mcp.OBJECTNO, ms.ticketType, ms.WEIGHT) tmp \n" +
                "GROUP BY itemCode,itemName,OBJECTNO \n";
        List<Map<String, Object>> all_scoreMapList = GrpServer.getGrpServer().excuteQueryListMap(all_scoreSql);
        //统计同组人所有人的测评项目的综合得分的最低分、平均分、最高分minScore、maxScore、avgScore
        // 先计算统计每个itemCode的信息
        Map<String, DoubleSummaryStatistics> statisticsMap = all_scoreMapList.stream()
                .collect(Collectors.groupingBy(
                        m -> m.get("itemCode").toString(),
                        Collectors.mapping(m -> Double.valueOf(m.get("synthesisScore").toString()), Collectors.summarizingDouble(Double::doubleValue))
                ));
        all_scoreMapList.forEach(m -> {
            String itemCode = m.get("itemCode").toString();
            DoubleSummaryStatistics stats = statisticsMap.get(itemCode);
            if (stats != null) {
                m.put("minScore", stats.getMin());
                m.put("maxScore", stats.getMax());
                m.put("avgScore", stats.getAverage());
            }
        });
        //计算个人的相关数据-折线图
        List<Map<String, Object>> scoreMapList = all_scoreMapList.stream().filter(m -> m.containsKey("OBJECTNO") && m.get("OBJECTNO").toString().equals(username)).collect(Collectors.toList());
        double score = scoreMapList.stream().map(m -> Double.valueOf(m.get("synthesisScore").toString())).mapToDouble(Double::doubleValue).sum();
        double averageScore = scoreMapList.stream().map(m -> Double.valueOf(m.get("synthesisScore").toString())).mapToDouble(Double::doubleValue).average().orElse(0.0);
        List<String> itemName_high = scoreMapList.stream().filter(m -> Double.valueOf(m.get("synthesisScore").toString()) >= averageScore).map(m -> m.get("itemName").toString()).collect(Collectors.toList());
        List<String> itemName_low = scoreMapList.stream().filter(m -> Double.valueOf(m.get("synthesisScore").toString()) < averageScore).map(m -> m.get("itemName").toString()).collect(Collectors.toList());
        map.put("SCORE", String.format("%.2f", score));
        map.put("AVG_SCORE", String.format("%.2f", averageScore));
        map.put("ITEM_HIGH", itemName_high.isEmpty() ? "无测评项目" : String.join("、", itemName_high));
        map.put("ITEM_LOW", itemName_low.isEmpty() ? "无测评项目" : String.join("、", itemName_low));

        //为all_scoreMapList每个OBJECTNO添加总分的一行数据
        List<String> userList = all_scoreMapList.stream().map(m -> m.get("OBJECTNO").toString()).distinct().collect(Collectors.toList());
        long count = userList.size();
        userList.forEach(u -> {
            double minScoreSum = all_scoreMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("minScore").toString())).mapToDouble(Double::doubleValue).sum();
            double avgScoreSum = all_scoreMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("avgScore").toString())).mapToDouble(Double::doubleValue).sum();
            double maxScoreSum = all_scoreMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("maxScore").toString())).mapToDouble(Double::doubleValue).sum();
            double synthesisScoreSum = all_scoreMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("synthesisScore").toString())).mapToDouble(Double::doubleValue).sum();
            HashMap<String, Object> tmpMap = new HashMap<>();
            tmpMap.put("OBJECTNO", u);
            tmpMap.put("itemCode", 0);//总分编号设置为0
            tmpMap.put("itemName", "总分");
            tmpMap.put("minScore", minScoreSum);
            tmpMap.put("avgScore", avgScoreSum);
            tmpMap.put("maxScore", maxScoreSum);
            tmpMap.put("synthesisScore", synthesisScoreSum);
            all_scoreMapList.add(tmpMap);
        });
        //个人排名渲染的list
        List<Map<String, Object>> rankScoreMapList = all_scoreMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(username)).collect(Collectors.toList());
        rankScoreMapList.forEach(m -> {
            long rank = all_scoreMapList.stream().filter(m2 -> m2.get("itemCode").equals(m.get("itemCode")) && Double.valueOf(m2.get("synthesisScore").toString()) > Double.valueOf(m.get("synthesisScore").toString())).count() + 1;
            m.put("rank", rank + "/" + count);
        });
        //score格式化为两位小数
        rankScoreMapList.forEach(m -> {
            m.put("minScore", String.format("%.2f", Double.valueOf(m.get("minScore").toString())));
            m.put("avgScore", String.format("%.2f", Double.valueOf(m.get("avgScore").toString())));
            m.put("maxScore", String.format("%.2f", Double.valueOf(m.get("maxScore").toString())));
            m.put("synthesisScore", String.format("%.2f", Double.valueOf(m.get("synthesisScore").toString())));
        });
        map.put("rankScoreMapList", rankScoreMapList);
        List<String> beaItemName = rankScoreMapList.stream().filter(m -> Math.abs(Double.valueOf(m.get("synthesisScore").toString()) - averageScore) < 0.25).map(m -> m.get("itemName").toString()).collect(Collectors.toList());
        map.put("BEA_ITEM_NAME", beaItemName.isEmpty() ? "无测评项目" : String.join("、", beaItemName));

        //统计同组人所有人的测评项目的A票score_A,B票score_B,C票score_C,(规则,票类型相同的加和求平均值)以及总分score_ALL(权重wight)
        String all_ticketTypeSql = "SELECT tmp.OBJECTNO,tmp.itemCode,tmp.itemName,SUM(CASE tmp.ticketType WHEN 'A' THEN tmp.score ELSE 0 END) AS score_A,SUM(CASE tmp.ticketType WHEN 'B' THEN tmp.score ELSE 0 END) AS score_B,SUM(CASE tmp.ticketType WHEN 'C' THEN tmp.score ELSE 0 END) AS score_C, \n" +
                "ROUND(SUM(CASE tmp.ticketType WHEN 'A' THEN tmp.score * tmp.WEIGHT / 100.0 ELSE 0 END) + SUM(CASE tmp.ticketType WHEN 'B' THEN tmp.score * tmp.WEIGHT / 100.0 ELSE 0 END) + SUM(CASE tmp.ticketType WHEN 'C' THEN tmp.score * tmp.WEIGHT / 100.0 ELSE 0 END), 2) AS score_ALL \n" +
                "FROM( SELECT mcp.itemCode,mcp.itemName,mcp.OBJECTNO,ms.ticketType,ms.WEIGHT,SUM(mcp.SCORE) / COUNT(*) AS SCORE FROM middlecadresscorecp mcp LEFT JOIN middlecadresscore ms ON ms.MIDDLECADRESSCORECODE = mcp.MIDDLECADRESSCORECODE\n" +
                "    WHERE ms.MIDDLECADRESREVIEWCODE = '" + code + "' AND ms.TICKETSTATE = '1' GROUP BY mcp.itemCode, mcp.itemName, mcp.OBJECTNO, ms.ticketType, ms.WEIGHT\n" +
                ") tmp GROUP BY tmp.itemCode, tmp.itemName, tmp.OBJECTNO\n";
        List<Map<String, Object>> all_ticketTypeMapList = GrpServer.getGrpServer().excuteQueryListMap(all_ticketTypeSql);
        //为all_ticketTypeMapList每个OBJECTNO添加总分的一行数据
        userList.forEach(u -> {
            double score_A = all_ticketTypeMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("score_A").toString())).mapToDouble(Double::doubleValue).sum();
            double score_B = all_ticketTypeMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("score_B").toString())).mapToDouble(Double::doubleValue).sum();
            double score_C = all_ticketTypeMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("score_C").toString())).mapToDouble(Double::doubleValue).sum();
            double score_ALL = all_ticketTypeMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(u)).map(m -> Double.valueOf(m.get("score_ALL").toString())).mapToDouble(Double::doubleValue).sum();
            HashMap<String, Object> tmpMap = new HashMap<>();
            tmpMap.put("OBJECTNO", u);
            tmpMap.put("itemCode", 0);//总分编号设置为0
            tmpMap.put("itemName", "总分");
            tmpMap.put("score_A", score_A);
            tmpMap.put("score_B", score_B);
            tmpMap.put("score_C", score_C);
            tmpMap.put("score_ALL", score_ALL);
            all_ticketTypeMapList.add(tmpMap);
        });
        //过滤成个人信息并添加排名rank信息
        List<Map<String, Object>> rankTicketTypeMapList = all_ticketTypeMapList.stream().filter(m -> m.get("OBJECTNO").toString().equals(username)).collect(Collectors.toList());
        rankTicketTypeMapList.forEach(m -> {
            long rank_A = all_ticketTypeMapList.stream().filter(m2 -> m2.get("itemCode").equals(m.get("itemCode")) && Double.valueOf(m2.get("score_A").toString()) > Double.valueOf(m.get("score_A").toString())).count() + 1;
            m.put("rank_A", rank_A + "/" + count);
            long rank_B = all_ticketTypeMapList.stream().filter(m2 -> m2.get("itemCode").equals(m.get("itemCode")) && Double.valueOf(m2.get("score_B").toString()) > Double.valueOf(m.get("score_B").toString())).count() + 1;
            m.put("rank_B", rank_B + "/" + count);
            long rank_C = all_ticketTypeMapList.stream().filter(m2 -> m2.get("itemCode").equals(m.get("itemCode")) && Double.valueOf(m2.get("score_C").toString()) > Double.valueOf(m.get("score_C").toString())).count() + 1;
            m.put("rank_C", rank_C + "/" + count);
            long rank_ALL = all_ticketTypeMapList.stream().filter(m2 -> m2.get("itemCode").equals(m.get("itemCode")) && Double.valueOf(m2.get("score_ALL").toString()) > Double.valueOf(m.get("score_ALL").toString())).count() + 1;
            m.put("rank_ALL", rank_ALL + "/" + count);
        });
        //score格式化为两位小数
        rankTicketTypeMapList.forEach(m -> {
            m.put("score_A", String.format("%.2f", Double.valueOf(m.get("score_A").toString())));
            m.put("score_B", String.format("%.2f", Double.valueOf(m.get("score_B").toString())));
            m.put("score_C", String.format("%.2f", Double.valueOf(m.get("score_C").toString())));
            m.put("score_ALL", String.format("%.2f", Double.valueOf(m.get("score_ALL").toString())));
        });
//        map.put("rankTicketTypeMapList",rankTicketTypeMapList);
        map.put("RL", rankTicketTypeMapList);

        //提取每张票上的建议
        String suggestionSql = "SELECT SUGGESTION FROM `middlecadresscore` WHERE MIDDLECADRESREVIEWCODE = '" + code + "' AND TICKETSTATE = '1'";
        List<Map<String, Object>> suggestionMapList = GrpServer.getGrpServer().excuteQueryListMap(suggestionSql);
        if (suggestionMapList.size() >= 0) {
            List<String> suggestionList = suggestionMapList.stream().filter(m -> m != null && m.containsKey("SUGGESTION") && DataJudgeUtil.isNotBankMapKey(m, "SUGGESTION")).map(m -> m.get("SUGGESTION").toString()).collect(Collectors.toList());
            map.put("suggestion", String.join("\n", suggestionList));
        } else {
            map.put("suggestion", "无");
        }


        //XWPFTemplate模板启动所需配置LoopRowTableRenderPolicy行表格、LoopColumnTableRenderPolicy列表格
        RenderPolicy policy1 = new LoopRowTableRenderPolicy(false);
        Map<RenderPolicy, List<String>> polines1 = MapUtil.builder(policy1, Arrays.asList("rankScoreMapList")).map();
        RenderPolicy policy2 = new LoopColumnTableRenderPolicy(false);
        Map<RenderPolicy, List<String>> polines2 = MapUtil.builder(policy2, Arrays.asList("RL")).map();
        List<Map<RenderPolicy, List<String>>> configList = Arrays.asList(polines1, polines2);
        //渲染生成Word
        String result = processWordTemplate(filename, map, scoreMapList, configList, rankScoreMapList, rankTicketTypeMapList);
        return result;
    }


    @SneakyThrows
    public String processWordTemplate(String filename, Map<String, Object> replacements, List<Map<String, Object>> scoreMapList, List<Map<RenderPolicy, List<String>>> configList, List<Map<String, Object>> rankScoreMapList, List<Map<String, Object>> rankTicketTypeMapList) {
        byte[] fileBytes = upmsService.getFileBytes(filename);
        ByteArrayInputStream bis = new ByteArrayInputStream(fileBytes);
        //读取配置
        Configure config = Configure.createDefault();
        if (ObjectUtil.isNotEmpty(configList)) {
            for (Map<RenderPolicy, List<String>> map : configList) {
                for (Map.Entry<RenderPolicy, List<String>> entry : map.entrySet()) {
                    RenderPolicy key = entry.getKey();
                    List<String> value = entry.getValue();
                    value.stream().forEach(val -> config.customPolicy(val, key));
                }
            }
        }
        //1. 渲染文本和表格数据replacements
        XWPFTemplate template = XWPFTemplate.compile(bis, config).render(replacements);
        XWPFDocument document = template.getXWPFDocument();
        //2. 继续处理 -> 更改图表模板 -> 饼状图、折线图
        List<POIXMLDocumentPart> relations = document.getRelations();
        for (POIXMLDocumentPart poixmlDocumentPart : relations) {
            if (poixmlDocumentPart instanceof XWPFChart) {
                int firstRow = 0;
                int lastRow = 0;
                int firstCol = 0;
                int lastCol = 0;
                XWPFChart chart = (XWPFChart) poixmlDocumentPart;
                XSSFSheet sheet = chart.getWorkbook().getSheetAt(0);
                XSSFCell cell = sheet.getRow(0).getCell(1);
                //饼图
                if (cell.getStringCellValue().equals("主体人数")) {
                    sheet.getRow(1).getCell(1).setCellValue(percentageStrToDouble(replacements.get("PE_A").toString()));
                    sheet.getRow(2).getCell(1).setCellValue(percentageStrToDouble(replacements.get("PE_B").toString()));
                    sheet.getRow(3).getCell(1).setCellValue(percentageStrToDouble(replacements.get("PE_C").toString()));
                    sheet.getRow(1).getCell(1).setCellType(CellType.NUMERIC);
                    sheet.getRow(2).getCell(1).setCellType(CellType.NUMERIC);
                    sheet.getRow(3).getCell(1).setCellType(CellType.NUMERIC);
                    firstRow = 1;
                    lastRow = 3;
                    firstCol = 1;
                    lastCol = 1;
                }
                //饼图
                if (cell.getStringCellValue().equals("主体权重")) {
                    sheet.getRow(1).getCell(1).setCellValue(percentageStrToDouble(replacements.get("WIGHT_A").toString()));
                    sheet.getRow(2).getCell(1).setCellValue(percentageStrToDouble(replacements.get("WIGHT_B").toString()));
                    sheet.getRow(3).getCell(1).setCellValue(percentageStrToDouble(replacements.get("WIGHT_C").toString()));
                    sheet.getRow(1).getCell(1).setCellType(CellType.NUMERIC);
                    sheet.getRow(2).getCell(1).setCellType(CellType.NUMERIC);
                    sheet.getRow(3).getCell(1).setCellType(CellType.NUMERIC);
                    firstRow = 1;
                    lastRow = 3;
                    firstCol = 1;
                    lastCol = 1;
                }
                //折线图
                if (cell.getStringCellValue().equals("各指标得分")) {
                    double averageScore = scoreMapList.stream().map(m -> Double.valueOf(m.get("synthesisScore").toString())).mapToDouble(Double::doubleValue).average().orElse(0.0);
                    String formattedAverageScore = String.format("%.2f", averageScore);
                    sheet.getRow(0).getCell(2).setCellValue("各指标平均分 " + formattedAverageScore);//TODO 设置标题后怎么刷新??
                    // 设置各指标得分的单元格
                    for (int i = 0; i < scoreMapList.size(); i++) {
                        Row dataRow = sheet.getRow(i + 1);
                        if (dataRow == null) {
                            dataRow = sheet.createRow(i + 1);
                        }
                        //设置标签名
                        Cell itemNameCell = dataRow.getCell(0);
                        if (itemNameCell == null) {
                            itemNameCell = dataRow.createCell(0);
                        }
                        itemNameCell.setCellValue(scoreMapList.get(i).get("itemName").toString());
                        itemNameCell.setCellType(CellType.STRING);
                        // 设置得分单元格
                        Cell scoreCell = dataRow.getCell(1);
                        if (scoreCell == null) {
                            scoreCell = dataRow.createCell(1);
                        }
                        scoreCell.setCellValue(Double.valueOf(scoreMapList.get(i).get("synthesisScore").toString()));
                        scoreCell.setCellType(CellType.NUMERIC);
                        // 设置平均分单元格
                        Cell avgCell = dataRow.getCell(2);
                        if (avgCell == null) {
                            avgCell = dataRow.createCell(2);
                        }
                        avgCell.setCellValue(Double.valueOf(formattedAverageScore));
                        avgCell.setCellType(CellType.NUMERIC);
                    }
                    firstRow = 1;
                    lastRow = scoreMapList.size();
                    firstCol = 1;
                    lastCol = 2;
                    // 为什么默认是八行?可能和建表图的时候添加了八行?删除多余的行
                    for (int i = sheet.getLastRowNum(); i > scoreMapList.size() + 1; i--) {
                        sheet.removeRow(sheet.getRow(i));
                    }
                }
                //折线图与柱状图的组合图
                if (cell.getStringCellValue().equals("同组人员得分范围下限")) {
                    // 过滤掉总分标签
                    rankScoreMapList = rankScoreMapList.stream().filter(m -> !m.get("itemName").equals("总分")).collect(Collectors.toList());
                    // 设置各指标得分的单元格
                    for (int i = 0; i < rankScoreMapList.size(); i++) {
                        Row dataRow = sheet.getRow(i + 1);
                        if (dataRow == null) {
                            dataRow = sheet.createRow(i + 1);
                        }
                        //设置标签名
                        Cell itemNameCell = dataRow.getCell(0);
                        if (itemNameCell == null) {
                            itemNameCell = dataRow.createCell(0);
                        }
                        itemNameCell.setCellValue(rankScoreMapList.get(i).get("itemName").toString());
                        itemNameCell.setCellType(CellType.STRING);
                        // 设置同组人员得分下限
                        Cell scoreLowCell = dataRow.getCell(1);
                        if (scoreLowCell == null) {
                            scoreLowCell = dataRow.createCell(1);
                        }
                        scoreLowCell.setCellValue(Double.valueOf(rankScoreMapList.get(i).get("minScore").toString()));
                        scoreLowCell.setCellType(CellType.NUMERIC);
                        // 设置同组人员得分范围
                        Cell scoreRangeCell = dataRow.getCell(2);
                        if (scoreRangeCell == null) {
                            scoreRangeCell = dataRow.createCell(2);
                        }
                        scoreRangeCell.setCellValue(Double.valueOf(rankScoreMapList.get(i).get("maxScore").toString()) - Double.valueOf(rankScoreMapList.get(i).get("minScore").toString()));
                        scoreRangeCell.setCellType(CellType.NUMERIC);
                        // 设置平均分单元格
                        Cell avgCell = dataRow.getCell(3);
                        if (avgCell == null) {
                            avgCell = dataRow.createCell(3);
                        }
                        avgCell.setCellValue(Double.valueOf(rankScoreMapList.get(i).get("avgScore").toString()));
                        avgCell.setCellType(CellType.NUMERIC);
                        // 设置平均分单元格
                        Cell synthesisScoreCell = dataRow.getCell(4);
                        if (synthesisScoreCell == null) {
                            synthesisScoreCell = dataRow.createCell(4);
                        }
                        synthesisScoreCell.setCellValue(Double.valueOf(rankScoreMapList.get(i).get("synthesisScore").toString()));
                        synthesisScoreCell.setCellType(CellType.NUMERIC);
                    }

                    firstRow = 1;
                    lastRow = rankScoreMapList.size();
                    firstCol = 1;
                    lastCol = 4;
                    //删除多余的行
                    for (int i = sheet.getLastRowNum(); i > rankScoreMapList.size() + 1; i--) {
                        sheet.removeRow(sheet.getRow(i));
                    }
                }
                //折线图
                if (cell.getStringCellValue().equals("领导班子(A票)")) {
                    // 过滤掉总分标签
                    rankTicketTypeMapList = rankTicketTypeMapList.stream().filter(m -> !m.get("itemName").equals("总分")).collect(Collectors.toList());
                    // 设置各指标得分的单元格
                    for (int i = 0; i < rankTicketTypeMapList.size(); i++) {
                        Row dataRow = sheet.getRow(i + 1);
                        if (dataRow == null) {
                            dataRow = sheet.createRow(i + 1);
                        }
                        //设置标签名
                        Cell itemNameCell = dataRow.getCell(0);
                        if (itemNameCell == null) {
                            itemNameCell = dataRow.createCell(0);
                        }
                        itemNameCell.setCellValue(rankTicketTypeMapList.get(i).get("itemName").toString());
                        itemNameCell.setCellType(CellType.STRING);
                        // 设置得分单元格
                        Cell scoreCellA = dataRow.getCell(1);
                        if (scoreCellA == null) {
                            scoreCellA = dataRow.createCell(1);
                        }
                        scoreCellA.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_A").toString()));
                        scoreCellA.setCellType(CellType.NUMERIC);
                        Cell scoreCellB = dataRow.getCell(2);
                        if (scoreCellB == null) {
                            scoreCellB = dataRow.createCell(2);
                        }
                        scoreCellB.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_B").toString()));
                        scoreCellB.setCellType(CellType.NUMERIC);
                        Cell scoreCellC = dataRow.getCell(3);
                        if (scoreCellC == null) {
                            scoreCellC = dataRow.createCell(3);
                        }
                        scoreCellC.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_C").toString()));
                        scoreCellC.setCellType(CellType.NUMERIC);
                        Cell scoreCellALL = dataRow.getCell(4);
                        if (scoreCellALL == null) {
                            scoreCellALL = dataRow.createCell(4);
                        }
                        scoreCellALL.setCellValue(Double.valueOf(rankTicketTypeMapList.get(i).get("score_ALL").toString()));
                        scoreCellALL.setCellType(CellType.NUMERIC);
                    }
                    firstRow = 1;
                    lastRow = rankTicketTypeMapList.size();
                    firstCol = 1;
                    lastCol = 4;
                    // 为什么默认是八行?可能和建表图的时候添加了八行?删除多余的行
                    for (int i = sheet.getLastRowNum(); i > rankTicketTypeMapList.size() + 1; i--) {
                        sheet.removeRow(sheet.getRow(i));
                    }
                }
                //应用数据后刷新
                XDDFChartData chartData = chart.getChartSeries().get(0);
                if (chartData instanceof XDDFPieChartData) {//饼图
                    XDDFChartData.Series s = chartData.getSeries().get(0);
                    XDDFDataSource cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                            new CellRangeAddress(firstRow, lastRow, 0, 0));
                    XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                            new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
                    s.replaceData(cat, val);
                    chart.plot(chartData);
                } else if (chartData instanceof XDDFLineChartData) {//折线图
                    XDDFDataSource cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                            new CellRangeAddress(firstRow, lastRow, 0, 0));
                    for (int i = 0; i < chartData.getSeries().size(); i++) {
                        XDDFChartData.Series s = chartData.getSeries().get(i);
                        XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                                new CellRangeAddress(firstRow, lastRow, firstCol + i, firstCol + i));
                        s.replaceData(cat, val);
                    }
                    chart.plot(chartData);
                } else {//折线图与柱状图的组合图
                    XDDFChartData chartData0 = chart.getChartSeries().get(0);//XDDFBarChartData柱状系列数据
                    XDDFChartData chartData1 = chart.getChartSeries().get(1);//XDDFLineChartData折线系列数据

                    XDDFDataSource cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                            new CellRangeAddress(firstRow, lastRow, 0, 0));
                    for (int i = 0; i < chartData0.getSeries().size(); i++) {
                        XDDFChartData.Series s = chartData0.getSeries().get(i);
                        XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                                new CellRangeAddress(firstRow, lastRow, firstCol + i, firstCol + i));
                        s.replaceData(cat, val);
                    }
                    for (int i = 0; i < chartData1.getSeries().size(); i++) {
                        XDDFChartData.Series s = chartData1.getSeries().get(i);
                        XDDFNumericalDataSource val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                                new CellRangeAddress(firstRow, lastRow, firstCol + i + 2, firstCol + i + 2));
                        s.replaceData(cat, val);
                    }
                    chart.plot(chartData0);
                    chart.plot(chartData1);
                }
            }
        }

        //完成操作后保存文档
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        document.write(bos);
        byte[] bytes = bos.toByteArray();
        PoitlIOUtils.closeQuietlyMulti(template, bos);//关闭流
        MultipartFile multipartFile = new MockMultipartFile(filename + ".docx", filename + ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", bytes);
        R r = headersRemoteUpmsService.upload(multipartFile);
        if (r != null && r.isOk() && r.getData() != null) {
            Map<String, Object> data = (Map<String, Object>) r.getData();
            if (DataJudgeUtil.isNotBankMapKey(data, "url")) {
                return data.get("url").toString();
            }
        }
        return null;
    }

    public Double percentageStrToDouble(String percentageStr) {
        String cleanedStr = percentageStr.replace("%", "");
        double value = Double.parseDouble(cleanedStr);
        double result = value / 100;
        return result;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2161984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

现代桌面UI框架科普及WPF入门1

现代桌面UI框架科普及WPF入门 文章目录 现代桌面UI框架科普及WPF入门桌面应用程序框架介绍过时的UI框架MFC (Microsoft Foundation Class)缺点 经典的UI框架**WinForms****QT****WPF** 未来的UI框架**MAUI****AvaloniaUI** WPF相对于Winform&#xff0c;QT&#xff0c;MFC的独立…

【深度学习】(5)--搭建卷积神经网络

文章目录 搭建卷积神经网络一、数据预处理1. 下载数据集2. 创建DataLoader&#xff08;数据加载器&#xff09; 二、搭建神经网络三、训练数据四、优化模型 总结 搭建卷积神经网络 一、数据预处理 1. 下载数据集 在PyTorch中&#xff0c;有许多封装了很多与图像相关的模型、…

二阶滤波算法总结(对RC滤波算法整理的部分修正和完善)

文章目录 1、一阶低通滤波2、一阶高通滤波3、二阶低通滤波器3.1 二阶RC低通滤波器的连续域数学模型3.2 二阶RC低通滤波器的算法推导3.3 matlab仿真 4、二阶高通滤波器4.1 二阶RC高通滤波器的连续域数学模型4.2 二阶RC高通滤波器的算法推导4.3 matlab仿真 5、陷波滤波6、带通滤波…

要大爆发的AI Agent是什么?(软件测试人员需要掌握)

什么是AI Agent&#xff1f; AI Agent 是一种软件程序&#xff0c;可以与环境交互&#xff0c;收集数据&#xff0c;并使用数据执行自主任务以实现预定目标。即人类设定目标&#xff0c;AI Agent 独立选择实现这些目标所需的最佳行动。 简单来说&#xff0c;AI Agent是一个能够…

复选框选择示例【JavaScript】

这段代码实现的功能是一个简单的复选框示例&#xff0c;它可以进行全选、反选和取消选中操作。 实现功能&#xff1a; 1. 全选&#xff1a;当点击标签"全选"旁边的复选框时&#xff0c;该页面上所有具有"item"类的复选框都会被选中&#xff08;或者取消选…

七种修复错误:由于找不到msvcr110.dll 无法继续执行的方法

当你在运行某些程序时遇到“找不到msvcr110.dll”的错误提示&#xff0c;这通常意味着你的系统缺少了Microsoft Visual C 2012 Redistributable包中的一个重要文件。这个DLL文件是Microsoft Visual C Redistributable的一部分&#xff0c;用于支持许多使用Visual C编写的软件和…

回答网友的一个SQL问题

网友问&#xff1a; CODE NAME 1 A 1 B 如何得到下面的值&#xff0c;该如何写SQL CODE NAME 1 AB 1 AB 俺的回答&#xff1a; declare t table(code varchar(50),name varchar(50)) insert into t(code,name) select 1,A union select…

【Pleiades卫星】

Pleiades卫星 Pleiades卫星是法国研制的高分辨率光学成像卫星&#xff0c;旨在满足民用和国防领域对高分辨率地球观测数据的需求。以下是对Pleiades卫星的详细介绍&#xff1a; 一、基本概况 名称&#xff1a;Pleiades&#xff0c;中文名称为昴宿星卫星。研制国家&#xff…

数电学习基础(逻辑门电路+)

1.逻辑门电路 1.1逻辑门电路的简介 1.1.1各种逻辑门电路的简介 基本概念 &#xff08;1&#xff09;实现基本逻辑运算和常用逻辑运算的电路称为逻辑门电路&#xff0c;简称门电路。逻辑门电路是组成各种数字电路的基本单元电路。将构成门电路的元器件制作一块半导体芯片上再…

Allegro视频去除走线的小方块

走线出现小方块图如下&#xff1a; 其实这种情况并不影响PCB生产和布线的联通性&#xff0c;只是多少会影响美观和性能&#xff0c;在Allegro视频中去除的方法比较简单&#xff0c;是由模块复用以后&#xff0c;没有打散模块引起的。只要我们将模块的打散即可。具体操作如下:…

stm32 gpio I/O模式以及iic访问

1&#xff0c;硬件补充连接原理图引脚 #define FLASH_BASE ((uint32_t)0x08000000) /*!< FLASH(up to 1 MB) base address in the alias region */ #define CCMDATARAM_BASE ((uint32_t)0x10000000) /*!< CCM(core coupled mem…

球体检测系统源码分享

球体检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

元素循环分析再添新成员:铜、钼、镍、钴、硒微量元素数据库注释

微量营养元素&#xff08;例如Fe、Cu、Mo、Ni等&#xff09;是光合作用、呼吸作用、生物大分子合成、氧化还原平衡、细胞生长和免疫系统功能等微生物驱动过程的重要调节因子。虽然生物体需要少量的微量营养元素&#xff0c;但缺乏微量营养元素会严重限制生物体的生长和生物过程…

快手IP归属地怎么设置别的地方

在当今数字化时代&#xff0c;社交媒体平台如快手已成为人们日常生活中不可或缺的一部分。快手通过显示用户的IP归属地&#xff0c;增加了信息的透明度和互动性。然而&#xff0c;有些用户可能出于个人需求或特定情境&#xff0c;希望将自己的IP归属地设置为别的地方。本文将深…

前端开发必须了解的css知识

文本过长省略显示 单行 .ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap; }多行 方法一&#xff1a; .ellipsis {overflow: hidden;text-overflow: ellipsis;-webkit-line-clamp: 3;word-break: break-all; }方法二&#xff1a; .ellipsis {ove…

分布式锁总结1 - 为什么需要分布式锁?

目录 1. 最基本的业务逻辑是&#xff1a; 2. 高并发场景下常见的缓存问题 2.1问题一 缓存穿透 : 一直查询不存在的数据 解决方案 : 短暂缓存null结果 2.2 问题二 缓存雪崩 : 大量key同时过期大量请求直击数据库 解决方案 : 在原有的过期时间上加一个随机的值&#xff0c;…

国联安基金前置机用朝天椒USB Server实现了虚拟化

国联安基金近期上线了朝天椒USB Server产品&#xff0c;影响了虚拟化进程的物理前置机逐步退出了历史舞台&#xff0c;实现了虚拟化&#xff0c;通过USB服务器&#xff0c;虚拟机中也能网络识别各个前置机系统的认证U盾。 一、背景 国联安基金在金融业务运营过程中&#xff0c…

进度条QProgressBar

进度条控价&#xff0c;用来只是任务的完成情况 值 包括当前值、最大值、最小值 // 获取和设置当前值 int value() const; void setValue(int);// 获取和设置最大值 int maximum() const; void setMaximum(int);// 获取和设置最小值 int minimum() const; void setMinimum(i…

Datawhale X 南瓜书 task01学习笔记

机器学习三观 机器学习工程领先理论 what:什么是机器学习? 机器学习定义&#xff1a;研究关于“学习算法”(一类能从数据中学习出其背后潜在规律的算法)的一门学科PS:深度学习指的是&#xff1a;神经网络那一类学习算法&#xff0c;因此是机器学习的子集把深度学习单列出来…

Linux网络命令:用于请求和配置网络地址的命令dhclient详解

目录 一、概述 二、功能描述 三、基本使用 1. 命令格式 2. 常用选项 3. 获取帮助 ​编辑 4. 基本操作 四、工作原理 1. 发送DHCP请求 2. 接收DHCP响应 3. 请求IP地址 4. 确认IP地址 5. 配置网络接口 五、功能特点 六、配置文件 七、常用命令和示例 1、启动…