feat: 学生评价的 pdf 生成

11111
winter 10 months ago
parent d5ad605b35
commit bc13f67a29

@ -10,4 +10,6 @@ public class TeamModelExtensionApplication {
SpringApplication.run(TeamModelExtensionApplication.class, args); SpringApplication.run(TeamModelExtensionApplication.class, args);
} }
} }

@ -1,12 +1,18 @@
package cn.teammodel.controller.frontend; package cn.teammodel.controller.frontend;
import cn.hutool.core.map.MapUtil;
import cn.teammodel.common.R; import cn.teammodel.common.R;
import cn.teammodel.repository.AppraiseRepository; import cn.teammodel.repository.AppraiseRepository;
import cn.teammodel.service.EvaluationService; import cn.teammodel.service.EvaluationService;
import cn.teammodel.utils.ChartUtil;
import cn.teammodel.utils.PdfUtil; import cn.teammodel.utils.PdfUtil;
import com.itextpdf.text.DocumentException; import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -14,8 +20,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Map; import java.util.Map;
@RestController @RestController
@ -43,8 +52,36 @@ public class HelloController {
@GetMapping("public/pdf") @GetMapping("public/pdf")
public void freepdf(HttpServletResponse response) throws DocumentException, IOException { public void freepdf(HttpServletResponse response) throws DocumentException, IOException {
Map<String, String> data = MapUtil.ofEntries(MapUtil.entry("Text1", "1000"), MapUtil.entry("Text2", "2000"), MapUtil.entry("Text3", "3000")); // 设置response参数
PdfUtil.fillStudentPdfForm(data, response); response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-disposition",
"attachment;filename=report_student_" + System.currentTimeMillis() + ".pdf");
ClassPathResource resource = new ClassPathResource("templates/pdf_templates/student_report.pdf");
InputStream in = resource.getInputStream();
ServletOutputStream os = response.getOutputStream();
// 处理 stampter
PdfReader pdfReader = new PdfReader(in);
PdfStamper stamper = new PdfStamper(pdfReader, os);
Map<String, String> data = PdfUtil.data();
DefaultPieDataset dataset = new DefaultPieDataset( );
dataset.setValue( "IPhone 5s" , new Double( 20 ) );
dataset.setValue( "SamSung Grand" , new Double( 20 ) );
dataset.setValue( "MotoG" , new Double( 40 ) );
dataset.setValue( "Nokia Lumia" , new Double( 10 ) );
JFreeChart pieChart = ChartUtil.pieChart("手机销量统计", dataset);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ChartUtils.writeChartAsJPEG(bos, pieChart, 850, 440);
// 填充表单
PdfUtil.fillPdfForm(stamper, data);
PdfUtil.fillImage(stamper, "praiseDistribution", bos.toByteArray());
PdfUtil.fillImage(stamper, "criticalDistribution", bos.toByteArray());
// 关闭流
stamper.setFormFlattening(true);
stamper.close();
os.close();
} }

@ -20,6 +20,9 @@ import java.util.Map;
@Data @Data
@Builder @Builder
public class StudentReportVo { public class StudentReportVo {
@ApiModelProperty("学生名字")
private String name;
@ApiModelProperty("学生表扬总数") @ApiModelProperty("学生表扬总数")
private Integer praiseCount; private Integer praiseCount;

@ -18,13 +18,21 @@ import cn.teammodel.model.vo.appraise.StudentReportVo;
import cn.teammodel.repository.*; import cn.teammodel.repository.*;
import cn.teammodel.security.utils.SecurityUtil; import cn.teammodel.security.utils.SecurityUtil;
import cn.teammodel.service.EvaluationService; import cn.teammodel.service.EvaluationService;
import cn.teammodel.utils.ChartUtil;
import cn.teammodel.utils.PdfUtil;
import cn.teammodel.utils.RepositoryUtil; import cn.teammodel.utils.RepositoryUtil;
import cn.teammodel.utils.SchoolDateUtil; import cn.teammodel.utils.SchoolDateUtil;
import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.cosmos.models.CosmosPatchOperations;
import com.azure.spring.data.cosmos.core.query.CosmosPageRequest; import com.azure.spring.data.cosmos.core.query.CosmosPageRequest;
import com.itextpdf.text.DocumentException; import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -32,7 +40,9 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.*; import java.util.*;
@ -591,6 +601,7 @@ public class EvaluationServiceImpl implements EvaluationService {
String topCriticalNode = criticalNodeMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null); String topCriticalNode = criticalNodeMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
return StudentReportVo.builder() return StudentReportVo.builder()
.name(student.getName())
.praiseCount(praiseCount) .praiseCount(praiseCount)
.score(appraiseRecord.getScore()) .score(appraiseRecord.getScore())
.beyondPercent(beyondPercent) .beyondPercent(beyondPercent)
@ -608,10 +619,59 @@ public class EvaluationServiceImpl implements EvaluationService {
@Override @Override
public void exportStuReportPdf(IdRequest idRequest, HttpServletResponse response) throws IOException, DocumentException{ public void exportStuReportPdf(IdRequest idRequest, HttpServletResponse response) throws IOException, DocumentException{
// 设置response参数
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-disposition",
"attachment;filename=report_student_" + System.currentTimeMillis() + ".pdf");
ClassPathResource resource = new ClassPathResource("templates/pdf_templates/student_report.pdf");
InputStream in = resource.getInputStream();
ServletOutputStream os = response.getOutputStream(); ServletOutputStream os = response.getOutputStream();
// 获取报告数据
StudentReportVo reportVo = this.studentReport(idRequest);
// 处理 stampter
PdfReader pdfReader = new PdfReader(in);
PdfStamper stamper = new PdfStamper(pdfReader, os);
Map<String, String> data = new HashMap<>();
data.put("name", reportVo.getName());
data.put("praiseCount", String.valueOf(reportVo.getPraiseCount()));
data.put("beyondPercent", String.valueOf(reportVo.getBeyondPercent()));
data.put("topPraiseTeacher", reportVo.getTopPraiseTeacher().getName());
data.put("topCriticalTeacher", reportVo.getTopCriticalTeacher().getName());
data.put("topPraiseNode", reportVo.getTopPraiseNode());
data.put("topCriticalNode", reportVo.getTopCriticalNode());
DefaultPieDataset praiseDistributionDataset = new DefaultPieDataset( );
praiseDistributionDataset.setValue(FiveEducations.VIRTUE.getName(), reportVo.getPraiseDistribution().get(FiveEducations.VIRTUE.getCode()));
praiseDistributionDataset.setValue(FiveEducations.INTELLIGENCE.getName(), reportVo.getPraiseDistribution().get(FiveEducations.INTELLIGENCE.getCode()));
praiseDistributionDataset.setValue(FiveEducations.SPORTS.getName(), reportVo.getPraiseDistribution().get(FiveEducations.SPORTS.getCode()));
praiseDistributionDataset.setValue(FiveEducations.ART.getName(), reportVo.getPraiseDistribution().get(FiveEducations.ART.getCode()));
praiseDistributionDataset.setValue(FiveEducations.LABOUR.getName(), reportVo.getPraiseDistribution().get(FiveEducations.LABOUR.getCode()));
JFreeChart praisePieChart = ChartUtil.pieChart("五育表扬指标分布", praiseDistributionDataset);
ByteArrayOutputStream praiseBos = new ByteArrayOutputStream();
ChartUtils.writeChartAsJPEG(praiseBos, praisePieChart, 340, 330);
DefaultPieDataset criticalDistributionDataset = new DefaultPieDataset( );
criticalDistributionDataset.setValue(FiveEducations.VIRTUE.getName(), reportVo.getCriticalDistribution().get(FiveEducations.VIRTUE.getCode()));
criticalDistributionDataset.setValue(FiveEducations.INTELLIGENCE.getName(), reportVo.getCriticalDistribution().get(FiveEducations.INTELLIGENCE.getCode()));
criticalDistributionDataset.setValue(FiveEducations.SPORTS.getName(), reportVo.getCriticalDistribution().get(FiveEducations.SPORTS.getCode()));
criticalDistributionDataset.setValue(FiveEducations.ART.getName(), reportVo.getCriticalDistribution().get(FiveEducations.ART.getCode()));
criticalDistributionDataset.setValue(FiveEducations.LABOUR.getName(), reportVo.getCriticalDistribution().get(FiveEducations.LABOUR.getCode()));
JFreeChart criticalPieChart = ChartUtil.pieChart("五育待改进指标分布", criticalDistributionDataset);
ByteArrayOutputStream criticalBos = new ByteArrayOutputStream();
ChartUtils.writeChartAsJPEG(criticalBos, criticalPieChart, 340, 330);
// 填充表单
PdfUtil.fillPdfForm(stamper, data);
PdfUtil.fillImage(stamper, "praiseDistribution", praiseBos.toByteArray());
PdfUtil.fillImage(stamper, "criticalDistribution", criticalBos.toByteArray());
// 关闭流
stamper.setFormFlattening(true);
stamper.close();
os.close();
} }
/** /**

@ -0,0 +1,181 @@
package cn.teammodel.utils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import java.awt.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
/**
*
* @author winter
* @create 2023-10-30 11:12
*/
public class ChartUtil {
private static final Color[] BAR_COLORS = new Color[]{
new Color(79,129,189),
new Color(192, 80, 77),
new Color(155, 187, 89),
};
private static final Color[] LINE_COLORS = new Color[]{
new Color(237, 123, 46),
new Color(90, 154, 213),
new Color(164, 164, 164),
};
private static final Color[] PIE_COLORS = new Color[]{
new Color(75, 172, 198),
new Color(128, 100, 162),
new Color(155, 187, 89),
new Color(192, 80, 77),
new Color(79, 129, 189),
new Color(44, 77, 117),
new Color(247, 150, 70),
new Color(165, 165, 165),
};
private static StandardChartTheme initChartTheme(){
StandardChartTheme currentTheme = new StandardChartTheme("JFree");
// 横轴纵轴标题文字大小
currentTheme.setLargeFont(new Font("宋体", Font.BOLD, 15));
// 横轴纵轴数值文字大小
currentTheme.setRegularFont(new Font("宋体", Font.PLAIN, 13));
currentTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 20));
// 背景颜色
currentTheme.setPlotBackgroundPaint(new Color(255, 255, 204, 0));
// 边框线条
currentTheme.setPlotOutlinePaint(new Color(0, 0, 0, 0));
// 网格线条
currentTheme.setRangeGridlinePaint(new Color(78, 74, 74));
return currentTheme;
}
/**
* 线
*
* @param title
* @param categoryAxisLabel
* @param valueAxisLabel
* @param dataset
* @return org.jfree.chart.JFreeChart
*/
public static JFreeChart lineChart(String title, String categoryAxisLabel, String valueAxisLabel, DefaultCategoryDataset dataset){
ChartFactory.setChartTheme(initChartTheme());
JFreeChart chart = ChartFactory.createLineChart(
title,
categoryAxisLabel,
valueAxisLabel,
dataset,
PlotOrientation.VERTICAL,
true,
true,
false
);
CategoryPlot plot = chart.getCategoryPlot();
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
// 折现点显示数值
renderer.setDefaultItemLabelsVisible(true);
renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
// 更改线条颜色
for (int i = 0; i < dataset.getRowKeys().size(); i++) {
renderer.setSeriesPaint(i, LINE_COLORS[i]);
}
return chart;
}
/**
*
*
* @param title
* @param categoryAxisLabel
* @param valueAxisLabel
* @param dataset
* @return org.jfree.chart.JFreeChart
*/
public static JFreeChart barChart(String title, String categoryAxisLabel, String valueAxisLabel, DefaultCategoryDataset dataset){
ChartFactory.setChartTheme(initChartTheme());
JFreeChart chart = ChartFactory.createBarChart(
title,
categoryAxisLabel,
valueAxisLabel,
dataset,
PlotOrientation.VERTICAL,
true,
true,
false
);
CategoryPlot plot = chart.getCategoryPlot();
BarRenderer renderer = (BarRenderer) plot.getRenderer();
// 纯色显示
renderer.setBarPainter(new StandardBarPainter());
// 柱子上显示小数字
renderer.setDefaultItemLabelsVisible(true);
renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
// 设置柱子间隔
renderer.setItemMargin(0.0);
// 设置柱子颜色
for (int i = 0; i < dataset.getRowKeys().size(); i++) {
renderer.setSeriesPaint(i, BAR_COLORS[i]);
}
return chart;
}
/**
*
* @param title
* @param dataset
* @return org.jfree.chart.JFreeChart
*/
public static JFreeChart pieChart(String title, DefaultPieDataset dataset){
ChartFactory.setChartTheme(initChartTheme());
JFreeChart chart = ChartFactory.createPieChart(
title,
dataset,
true,
true,
false
);
PiePlot plot = (PiePlot) chart.getPlot();
// 设置扇区颜色
for (int i = 0; i < dataset.getKeys().size(); i++) {
plot.setSectionPaint(dataset.getKey(i), PIE_COLORS[i]);
}
// 设置扇区的线条颜色
plot.setDefaultSectionOutlinePaint(new Color(255, 255, 255));
// 设置扇区的线条大小
plot.setDefaultSectionOutlineStroke(new BasicStroke(3));
// 设置标签颜色
plot.setLabelLinkPaint(new Color(255,255,255, 0));
// 设置标签背景色
plot.setLabelBackgroundPaint(new Color(255, 255, 255,0));
// 设置标签线条颜色
plot.setLabelOutlinePaint(new Color(255, 255, 255, 0));
// 设置标签阴影颜色
plot.setLabelShadowPaint(new Color(255, 255, 255, 0));
// 设置饼图阴影颜色
plot.setShadowPaint(new Color(255, 255, 255, 0));
// 添加标签数字百分比显示
plot.setLabelGenerator(new StandardPieSectionLabelGenerator(("{0}{2}"), NumberFormat.getNumberInstance(),new DecimalFormat("0.00%")));
return chart;
}
}

@ -1,16 +1,13 @@
package cn.teammodel.utils; package cn.teammodel.utils;
import com.itextpdf.text.DocumentException; import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields; import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.PdfStamper;
import org.springframework.core.io.ClassPathResource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map; import java.util.Map;
/** /**
@ -18,27 +15,24 @@ import java.util.Map;
* @create 2024-01-24 16:02 * @create 2024-01-24 16:02
*/ */
public class PdfUtil { public class PdfUtil {
public static void fillPdfForm(PdfStamper stamper, Map<String, String> data) throws IOException, DocumentException {
public static void fillStudentPdfForm(Map<String, String> data, HttpServletResponse response) throws IOException, DocumentException {
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-disposition",
"attachment;filename=report_student_" + System.currentTimeMillis() + ".pdf");
ClassPathResource resource = new ClassPathResource("templates/pdf_templates/template.pdf");
InputStream in = resource.getInputStream();
ServletOutputStream os = response.getOutputStream();
fillPdfForm(in, os, data);
}
public static void fillPdfForm(InputStream in, OutputStream os, Map<String, String> data) throws IOException, DocumentException {
PdfReader pdfReader = new PdfReader(in);
PdfStamper stamper = new PdfStamper(pdfReader, os);
AcroFields fields = stamper.getAcroFields(); AcroFields fields = stamper.getAcroFields();
for (Map.Entry<String, String> entry : data.entrySet()) { for (Map.Entry<String, String> entry : data.entrySet()) {
fields.setField(entry.getKey(), entry.getValue()); fields.setField(entry.getKey(), entry.getValue());
} }
stamper.setFormFlattening(true);
stamper.close();
os.close();
} }
public static void fillImage(PdfStamper stamper, String imgFieldName, byte[] data) throws DocumentException, IOException {
AcroFields acroFields = stamper.getAcroFields();
Image image = Image.getInstance(data);
int pageNo = acroFields.getFieldPositions(imgFieldName).get(0).page;
Rectangle rectangle = acroFields.getFieldPositions(imgFieldName).get(0).position;
float x = rectangle.getLeft();
float y = rectangle.getBottom();
PdfContentByte content = stamper.getOverContent(pageNo);
image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
image.setAbsolutePosition(x, y);
content.addImage(image);
}
} }
Loading…
Cancel
Save