xiatian 2 meses atrás
pai
commit
5e5a0e03a1

+ 10 - 1
pom.xml

@@ -24,8 +24,17 @@
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <qmth-boot-version>1.0.5</qmth-boot-version>
     </properties>
-
 	<dependencies>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <version>3.17</version>
+            <artifactId>poi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <version>3.17</version>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
 		<dependency>
             <groupId>com.qmth.boot</groupId>
             <artifactId>starter-api</artifactId>

+ 183 - 0
src/main/java/cn/com/qmth/am/bean/ExportExcelDto.java

@@ -0,0 +1,183 @@
+package cn.com.qmth.am.bean;
+
+import cn.com.qmth.am.utils.ExcelProperty;
+
+public class ExportExcelDto {
+
+    @ExcelProperty(name = "考试", width = 25, index = 1)
+    private String examId;
+
+    @ExcelProperty(name = "科目代码", width = 25, index = 2)
+    private String subjectCode;
+
+    @ExcelProperty(name = "科目名称", width = 25, index = 3)
+    private String subjectName;
+
+    @ExcelProperty(name = "题型", width = 25, index = 4)
+    private String questionTitle;
+
+    @ExcelProperty(name = "题号", width = 25, index = 5)
+    private String quetionNum;
+
+    @ExcelProperty(name = "满分", width = 25, index = 6)
+    private String fullScore;
+
+    @ExcelProperty(name = "样本数", width = 25, index = 7)
+    private String totalCount;
+
+    @ExcelProperty(name = "人评均分", width = 25, index = 8)
+    private String markingAvg;
+
+    @ExcelProperty(name = "一致率分值", width = 25, index = 9)
+    private String sameScoreRange;
+
+    @ExcelProperty(name = "有效样本数", width = 25, index = 10)
+    private String validCount;
+
+    @ExcelProperty(name = "相关系数", width = 25, index = 11)
+    private String xgxs;
+
+    @ExcelProperty(name = "机评均分", width = 25, index = 12)
+    private String aiAvg;
+
+    @ExcelProperty(name = "均分差值", width = 25, index = 13)
+    private String avgDiff;
+
+    @ExcelProperty(name = "一致率", width = 25, index = 14)
+    private String same;
+
+    @ExcelProperty(name = "一致率样本数", width = 25, index = 15)
+    private String sameCount;
+
+    @ExcelProperty(name = "一致率明细", width = 25, index = 16)
+    private String sameDesc;
+
+    public String getExamId() {
+        return examId;
+    }
+
+    public void setExamId(String examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getQuestionTitle() {
+        return questionTitle;
+    }
+
+    public void setQuestionTitle(String questionTitle) {
+        this.questionTitle = questionTitle;
+    }
+
+    public String getQuetionNum() {
+        return quetionNum;
+    }
+
+    public void setQuetionNum(String quetionNum) {
+        this.quetionNum = quetionNum;
+    }
+
+    public String getFullScore() {
+        return fullScore;
+    }
+
+    public void setFullScore(String fullScore) {
+        this.fullScore = fullScore;
+    }
+
+    public String getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(String totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public String getMarkingAvg() {
+        return markingAvg;
+    }
+
+    public void setMarkingAvg(String markingAvg) {
+        this.markingAvg = markingAvg;
+    }
+
+    public String getSameScoreRange() {
+        return sameScoreRange;
+    }
+
+    public void setSameScoreRange(String sameScoreRange) {
+        this.sameScoreRange = sameScoreRange;
+    }
+
+    public String getValidCount() {
+        return validCount;
+    }
+
+    public void setValidCount(String validCount) {
+        this.validCount = validCount;
+    }
+
+    public String getXgxs() {
+        return xgxs;
+    }
+
+    public void setXgxs(String xgxs) {
+        this.xgxs = xgxs;
+    }
+
+    public String getAiAvg() {
+        return aiAvg;
+    }
+
+    public void setAiAvg(String aiAvg) {
+        this.aiAvg = aiAvg;
+    }
+
+    public String getAvgDiff() {
+        return avgDiff;
+    }
+
+    public void setAvgDiff(String avgDiff) {
+        this.avgDiff = avgDiff;
+    }
+
+    public String getSame() {
+        return same;
+    }
+
+    public void setSame(String same) {
+        this.same = same;
+    }
+
+    public String getSameCount() {
+        return sameCount;
+    }
+
+    public void setSameCount(String sameCount) {
+        this.sameCount = sameCount;
+    }
+
+    public String getSameDesc() {
+        return sameDesc;
+    }
+
+    public void setSameDesc(String sameDesc) {
+        this.sameDesc = sameDesc;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+}

+ 99 - 0
src/main/java/cn/com/qmth/am/controller/AdminController.java

@@ -31,6 +31,7 @@ import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.boot.core.concurrent.service.ConcurrentService;
 
 import cn.com.qmth.am.bean.DataKey;
+import cn.com.qmth.am.bean.ExportExcelDto;
 import cn.com.qmth.am.bean.ModelSpeed;
 import cn.com.qmth.am.bean.StudentScoreVo;
 import cn.com.qmth.am.config.SysProperty;
@@ -43,6 +44,7 @@ import cn.com.qmth.am.service.QuestionService;
 import cn.com.qmth.am.service.StudentScoreService;
 import cn.com.qmth.am.service.StudentService;
 import cn.com.qmth.am.utils.Calculator;
+import cn.com.qmth.am.utils.ExportUtils;
 import io.swagger.annotations.ApiOperation;
 
 @RestController
@@ -68,6 +70,57 @@ public class AdminController {
     @Autowired
     private ConcurrentService concurrentService;
 
+    @ApiOperation(value = "导出数据")
+    @RequestMapping(value = "export", method = RequestMethod.GET)
+    public void exportExcel(HttpServletResponse response, @RequestParam Long examId,
+            @RequestParam(required = false) String subjectCode, @RequestParam(required = false) Boolean exZero,
+            @RequestParam(required = false) Integer count, @RequestParam(required = false) Integer score) {
+        List<ExportExcelDto> ret = new ArrayList<>();
+        List<QuestionEntity> qs = questionService.findByExamIdAndSubject(examId, subjectCode);
+        if (CollectionUtils.isNotEmpty(qs)) {
+
+            for (QuestionEntity q : qs) {
+                List<StudentScoreEntity> scores = studentScoreService.findBy(q.getId(), exZero, count, score);
+                if (CollectionUtils.isNotEmpty(scores)) {
+                    ExportExcelDto dto = new ExportExcelDto();
+                    ret.add(dto);
+                    double[] a = new double[scores.size()];
+                    double[] b = new double[scores.size()];
+                    int i = 0;
+                    for (StudentScoreEntity s : scores) {
+                        a[i] = s.getAiScore();
+                        b[i] = s.getMarkingScore();
+                        i++;
+                    }
+                    dto.setExamId(q.getExamId() + "");
+                    dto.setXgxs(new BigDecimal(Calculator.correlation(a, b)).setScale(2, BigDecimal.ROUND_HALF_UP)
+                            .doubleValue() + "");
+                    double avg1 = new BigDecimal(Calculator.mean(a)).setScale(2, BigDecimal.ROUND_HALF_UP)
+                            .doubleValue();
+                    dto.setAiAvg(avg1 + "");
+                    double avg2 = new BigDecimal(Calculator.mean(b)).setScale(2, BigDecimal.ROUND_HALF_UP)
+                            .doubleValue();
+                    dto.setSubjectCode(q.getSubjectCode());
+                    dto.setMarkingAvg(avg2 + "");
+                    dto.setSubjectName(q.getSubjectName());
+                    dto.setQuestionTitle(q.getTitle());
+                    dto.setQuetionNum(q.getMainNumber() + "-" + q.getSubNumber());
+                    dto.setFullScore(q.getFullScore().toString());
+                    dto.setTotalCount(scores.size() + "");
+                    dto.setValidCount(scores.size() + "");
+                    double avgdiff = Calculator.subtract(avg1, avg2, 2);
+                    if (avgdiff < 0) {
+                        avgdiff = 0 - avgdiff;
+                    }
+                    dto.setAvgDiff(avgdiff + "");
+                    fill(scores, dto, q.getFullScore(), score);
+                }
+            }
+
+        }
+        ExportUtils.exportExcel("机评数据", ExportExcelDto.class, ret, response);
+    }
+
     @ApiOperation(value = "分析数据")
     @RequestMapping(value = "fenxi", method = RequestMethod.GET)
     public void fenxi(HttpServletResponse response, @RequestParam Long examId,
@@ -119,6 +172,52 @@ public class AdminController {
         returnJson(sb.toString(), response);
     }
 
+    private void fill(List<StudentScoreEntity> scores, ExportExcelDto dto, Double questionScore, Integer score) {
+        int total = scores.size();
+        int st = 0;
+        Map<DataKey, Integer> ret = new HashMap<>();
+        for (StudentScoreEntity s : scores) {
+            DataKey k = getKey(s.getAiScore() - s.getMarkingScore());
+            Integer tem = ret.get(k);
+            if (tem == null) {
+                tem = 0;
+            }
+            ret.put(k, tem + 1);
+        }
+        List<DataKey> ks = new ArrayList<>(ret.keySet());
+        ks.sort(new Comparator<DataKey>() {
+
+            @Override
+            public int compare(DataKey o1, DataKey o2) {
+                int c1 = o1.getIndex();
+                int c2 = o2.getIndex();
+                if (c1 < c2) {
+                    return -1;
+                } else if (c1 > c2) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        });
+        double roundedValue = Math.round(questionScore * 0.3);
+        if (score != null) {
+            roundedValue = score;
+        }
+        dto.setSameScoreRange(roundedValue + "");
+        StringBuilder sb = new StringBuilder();
+        for (DataKey k : ks) {
+            Integer c = ret.get(k);
+            if (k.getIndex() < roundedValue) {
+                st = st + c;
+            }
+            sb.append("            " + k.getKey() + "  " + c + "  " + Calculator.percentage(c, total, 2) + " \r\n");
+        }
+        dto.setSame(Calculator.percentage(st, total, 2));
+        dto.setSameCount(st + "");
+        dto.setSameDesc(sb.toString());
+    }
+
     private void fill(List<StudentScoreEntity> scores, StringBuilder sb, Double questionScore, Integer score) {
         int total = scores.size();
         int st = 0;

+ 60 - 0
src/main/java/cn/com/qmth/am/utils/ColumnSetting.java

@@ -0,0 +1,60 @@
+package cn.com.qmth.am.utils;
+
+public class ColumnSetting implements Comparable<ColumnSetting> {
+
+    private String header;
+
+    private String getMethodName;
+
+    private int width;
+
+    private int index;
+
+    public ColumnSetting(String header, String getMethodName, int width, int index) {
+        this.header = header;
+        this.getMethodName = getMethodName;
+        this.width = width;
+        this.index = index;
+    }
+
+    public String getHeader() {
+        return header;
+    }
+
+    public void setHeader(String header) {
+        this.header = header;
+    }
+
+    public String getGetMethodName() {
+        return getMethodName;
+    }
+
+    public void setGetMethodName(String getMethodName) {
+        this.getMethodName = getMethodName;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    @Override
+    public int compareTo(ColumnSetting columnSetting) {
+        if (index < columnSetting.getIndex())
+            return -1;
+        if (index > columnSetting.getIndex())
+            return 1;
+        return 0;
+    }
+}

+ 31 - 0
src/main/java/cn/com/qmth/am/utils/ExcelProperty.java

@@ -0,0 +1,31 @@
+package cn.com.qmth.am.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelProperty {
+
+    /**
+     * 导出时列名
+     */
+    String name() default "";
+
+    /**
+     * 导出时列宽
+     */
+    int width() default 0;
+
+    /**
+     * 排序
+     */
+    int index();
+
+    /**
+     * 类型 0:导入(读excel) 1:导出(写excel) 2:导入&导出
+     */
+    int type() default 2;
+}

+ 78 - 0
src/main/java/cn/com/qmth/am/utils/ExcelUtils.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.am.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class ExcelUtils {
+
+    private Class<?> dataClass;
+
+    private List<ColumnSetting> columnSettings;
+
+    public ExcelUtils(Class<?> dataClass) {
+        this.dataClass = dataClass;
+        this.columnSettings = getColumnSettings(dataClass);
+    }
+
+    public Class<?> getDataClass() {
+        return dataClass;
+    }
+
+    public void setDataClass(Class<?> dataClass) {
+        this.dataClass = dataClass;
+    }
+
+    public List<ColumnSetting> getColumnSettings() {
+        return columnSettings;
+    }
+
+    public void setColumnSettings(List<ColumnSetting> columnSettings) {
+        this.columnSettings = columnSettings;
+    }
+
+    /**
+     * 提取ExcelProperty注解类的字段信息
+     * 
+     * @param dataClass
+     *            需要解析 写入excel的数据类型
+     * @return
+     */
+    protected List<ColumnSetting> getColumnSettings(Class<?> dataClass) {
+        List<ColumnSetting> columnSettings = new ArrayList<>();
+        // 先在方法上找ExcelProperty注解
+        Method[] methods = dataClass.getDeclaredMethods();
+        for (Method method : methods) {
+            ExcelProperty exportProperty = method.getAnnotation(ExcelProperty.class);
+            if (exportProperty != null && exportProperty.name().trim().length() > 0) {
+                ColumnSetting columnSetting = new ColumnSetting(exportProperty.name(), method.getName(),
+                        exportProperty.width(), exportProperty.index());
+                columnSettings.add(columnSetting);
+            }
+        }
+        // 如果方法上找不到注解,再到属性上找
+        if (columnSettings.size() == 0) {
+            Field[] fields = dataClass.getDeclaredFields();
+            for (Field field : fields) {
+                ExcelProperty exportProperty = field.getAnnotation(ExcelProperty.class);
+                if (exportProperty != null && exportProperty.name().trim().length() > 0) {
+                    ColumnSetting columnSetting = new ColumnSetting(exportProperty.name(),
+                            "get" + toUpperCaseFirstOne(field.getName()), exportProperty.width(),
+                            exportProperty.index());
+                    columnSettings.add(columnSetting);
+                }
+            }
+        }
+        Collections.sort(columnSettings);
+        return columnSettings;
+    }
+
+    private static String toUpperCaseFirstOne(String s) {
+        if (Character.isUpperCase(s.charAt(0)))
+            return s;
+        else
+            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
+    }
+}

+ 95 - 0
src/main/java/cn/com/qmth/am/utils/ExcelWriter.java

@@ -0,0 +1,95 @@
+package cn.com.qmth.am.utils;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.awt.Color;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+
+public class ExcelWriter extends ExcelUtils {
+
+    private XSSFWorkbook workbook;// 工作簿
+
+    private Sheet sheet; // 工作表
+
+    private Row row = null;// 创建一行
+
+    private Cell cell = null;
+
+    private XSSFCellStyle style;
+
+    private XSSFCellStyle style2;
+
+    public ExcelWriter(Class<?> dataClass, String sheetName) {
+        super(dataClass);
+        // 声明一个工作薄
+        // workbook = new SXSSFWorkbook(100);//使用该方法会有权限问题
+        workbook = new XSSFWorkbook();
+        // 生成一个表格
+        sheet = workbook.createSheet(sheetName);
+        // 设置表格默认列宽度为15个字节
+        sheet.setDefaultColumnWidth((short) 15);
+    }
+
+    private List<ColumnSetting> createColumnSettings() {
+        List<ColumnSetting> columnSettings = this.getColumnSettings();
+        // 产生表格标题行
+        row = sheet.createRow(0);
+        for (short i = 0; i < columnSettings.size(); i++) {
+            cell = row.createCell(i);
+            style = workbook.createCellStyle();
+            style.setFillForegroundColor(new XSSFColor(new Color(227, 239, 217)));
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            cell.setCellStyle(style);
+            XSSFRichTextString text = new XSSFRichTextString(columnSettings.get(i).getHeader());
+            cell.setCellValue(text);
+            if (columnSettings.get(i).getWidth() > 0) {
+                sheet.setColumnWidth(i, columnSettings.get(i).getWidth() * 256);
+            }
+        }
+        return columnSettings;
+    }
+
+    /**
+     * 写入excel
+     *
+     * @param dataset
+     *            数据集合
+     * @param out
+     *            输出流
+     * @throws SecurityException
+     * @throws NoSuchMethodException
+     * @throws InvocationTargetException
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     */
+    public void write(Collection<?> dataset, OutputStream out) throws Exception {
+        List<ColumnSetting> columnSettings = this.createColumnSettings();
+        int index = 0;
+        for (Object obj : dataset) {
+            index++;
+            row = sheet.createRow(index);// 创建行
+            // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
+            for (short i = 0; i < columnSettings.size(); i++) {
+                cell = row.createCell(i);// 创建列
+                cell.setCellStyle(style2);
+                String methodName = columnSettings.get(i).getGetMethodName();
+                Method method = this.getDataClass().getMethod(methodName, new Class[] {});
+                Object value = method.invoke(obj, new Object[] {});
+                cell.setCellValue(value == null ? "" : value.toString());
+            }
+        }
+        workbook.write(out);
+    }
+
+}

+ 53 - 0
src/main/java/cn/com/qmth/am/utils/ExportUtils.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.am.utils;
+
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.util.Collection;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * excel导出工具
+ */
+public class ExportUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(ExportUtils.class);
+
+    private static final String DEFALUT_CONTENT_TYPE = "application/vnd.ms-excel";
+
+    private static final String DEFALUT_EXT = ".xlsx";
+
+    public static void exportExcel(String fileName, Class<?> dataClass, Collection<?> dataset,
+            HttpServletResponse response) {
+        log.debug("导出Excel开始...");
+        try {
+            response.setHeader("Content-Disposition",
+                    "inline;filename=" + URLEncoder.encode(fileName, "UTF-8") + DEFALUT_EXT);
+            response.setContentType(DEFALUT_CONTENT_TYPE);
+            ServletOutputStream outputStream = response.getOutputStream();
+
+            ExcelWriter excelExporter = new ExcelWriter(dataClass, "sheet1");
+            excelExporter.write(dataset, outputStream);
+            outputStream.flush();
+            outputStream.close();
+            log.debug("导出Excel结束");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void makeExcel(Class<?> dataClass, Collection<?> dataset, OutputStream outputStream) {
+        log.debug("生成Excel开始...");
+        ExcelWriter excelExporter = new ExcelWriter(dataClass, "sheet1");
+        try {
+            excelExporter.write(dataset, outputStream);
+            log.debug("生成Excel结束");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}