1
0
Pārlūkot izejas kodu

考生导出、成绩导出表头配置

xiatian 12 stundas atpakaļ
vecāks
revīzija
f3ded42e58

+ 255 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/bean/ExamStudentExportVo.java

@@ -0,0 +1,255 @@
+package cn.com.qmth.stmms.biz.exam.bean;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+public class ExamStudentExportVo {
+
+    @ExcelField(title = "准考证号", align = 2, sort = 10)
+    private String examNumber;
+
+    @ExcelField(title = "密号", align = 2, sort = 20)
+    private String secretNumber;
+
+    @ExcelField(title = "姓名", align = 2, sort = 30)
+    private String name;
+
+    @ExcelField(title = "学号", align = 2, sort = 40)
+    private String studentCode;
+
+    @ExcelField(title = "科目", align = 2, sort = 50)
+    private String subjectText;
+
+    @ExcelField(title = "试卷类型", align = 2, sort = 60)
+    private String paperType;
+
+    @ExcelField(title = "层次", align = 2, sort = 70)
+    private String subjectLevel;
+
+    @ExcelField(title = "专业类型", align = 2, sort = 80)
+    private String subjectCategory;
+
+    @ExcelField(title = "扫描识别", align = 2, sort = 90)
+    private String scanStatus;
+
+    @ExcelField(title = "扫描张数", align = 2, sort = 100)
+    private Integer paperCount;
+
+    @ExcelField(title = "人工指定", align = 2, sort = 110)
+    private String breachText;
+
+    @ExcelField(title = "批次编号", align = 2, sort = 120)
+    private String batchCode;
+
+    @ExcelField(title = "签到表编号", align = 2, sort = 130)
+    private String packageCode;
+
+    @ExcelField(title = "学院", align = 2, sort = 140)
+    private String college;
+
+    @ExcelField(title = "班级", align = 2, sort = 150)
+    private String className;
+
+    @ExcelField(title = "任课老师", align = 2, sort = 160)
+    private String teacher;
+
+    @ExcelField(title = "考点", align = 2, sort = 170)
+    private String examSite;
+
+    @ExcelField(title = "考场", align = 2, sort = 180)
+    private String examRoom;
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getSecretNumber() {
+        return secretNumber;
+    }
+
+    public void setSecretNumber(String secretNumber) {
+        this.secretNumber = secretNumber;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getSubjectText() {
+        return subjectText;
+    }
+
+    public void setSubjectText(String subjectText) {
+        this.subjectText = subjectText;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public String getSubjectLevel() {
+        return subjectLevel;
+    }
+
+    public void setSubjectLevel(String subjectLevel) {
+        this.subjectLevel = subjectLevel;
+    }
+
+    public String getSubjectCategory() {
+        return subjectCategory;
+    }
+
+    public void setSubjectCategory(String subjectCategory) {
+        this.subjectCategory = subjectCategory;
+    }
+
+    public String getScanStatus() {
+        return scanStatus;
+    }
+
+    public void setScanStatus(String scanStatus) {
+        this.scanStatus = scanStatus;
+    }
+
+    public Integer getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(Integer paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public String getBreachText() {
+        return breachText;
+    }
+
+    public void setBreachText(String breachText) {
+        this.breachText = breachText;
+    }
+
+    public String getBatchCode() {
+        return batchCode;
+    }
+
+    public void setBatchCode(String batchCode) {
+        this.batchCode = batchCode;
+    }
+
+    public String getPackageCode() {
+        return packageCode;
+    }
+
+    public void setPackageCode(String packageCode) {
+        this.packageCode = packageCode;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+    public static ExamStudentExportVo of(ExamStudent from) {
+        if (from == null) {
+            return null;
+        }
+        ExamStudentExportVo ret = new ExamStudentExportVo();
+        ret.setExamNumber(from.getExamNumber());
+        ret.setSecretNumber(from.getSecretNumber());
+        ret.setName(from.getName());
+        ret.setStudentCode(from.getStudentCode());
+        ret.setSubjectText(from.getSubjectCode() + "-" + from.getSubjectName());
+        ret.setPaperType(from.getPaperType());
+        ret.setSubjectLevel(from.getSubject().getLevel());
+        ret.setSubjectCategory(from.getSubject().getCategory());
+        StringBuilder sb1 = new StringBuilder();
+        if (from.isUpload() == false) {
+            sb1.append("未上传");
+        } else {
+            sb1.append("已上传");
+            if (from.isAbsent() == true) {
+                sb1.append(" 缺考");
+            } else {
+                sb1.append(" 正常");
+            }
+        }
+        ret.setScanStatus(sb1.toString());
+
+        ret.setPaperCount(from.getSheetCount() / 2);
+        StringBuilder sb2 = new StringBuilder();
+        if (from.isBreach() == false) {
+            sb2.append("正常");
+        } else {
+            sb2.append("违纪");
+            if (from.isManualAbsent() == true) {
+                sb2.append(" 正常");
+            } else {
+                sb2.append(" 人工指定");
+            }
+        }
+        ret.setBreachText(sb2.toString());
+
+        ret.setBatchCode(from.getBatchCode());
+        ret.setPackageCode(from.getPackageCode());
+        ret.setCollege(from.getCollege());
+        ret.setClassName(from.getClassName());
+        ret.setTeacher(from.getTeacher());
+        ret.setExamSite(from.getExamSite());
+        ret.setExamRoom(from.getExamRoom());
+        return ret;
+    }
+}

+ 288 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ExamStudentScoreDTO.java

@@ -0,0 +1,288 @@
+package cn.com.qmth.stmms.admin.dto;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+public class ExamStudentScoreDTO {
+
+    @ExcelField(title = "准考证号", align = 2, sort = 10)
+    private String examNumber;
+
+    @ExcelField(title = "姓名", align = 2, sort = 20)
+    private String name;
+
+    @ExcelField(title = "学号", align = 2, sort = 30)
+    private String studentCode;
+
+    @ExcelField(title = "科目", align = 2, sort = 40)
+    private String subjectText;
+
+    @ExcelField(title = "层次", align = 2, sort = 50)
+    private String subjectLevel;
+
+    @ExcelField(title = "专业类型", align = 2, sort = 60)
+    private String subjectCategory;
+
+    @ExcelField(title = "客观总分", align = 2, sort = 70)
+    private String objectiveScore;
+
+    @ExcelField(title = "主观总分", align = 2, sort = 80)
+    private String subjectiveScore;
+
+    @ExcelField(title = "全卷总分", align = 2, sort = 90)
+    private String totalScore;
+
+    @ExcelField(title = "评分明细", align = 2, sort = 100)
+    private String subjectiveScoreList;
+
+    @ExcelField(title = "是否缺考", align = 2, sort = 110)
+    private String absentText;
+
+    @ExcelField(title = "是否上传", align = 2, sort = 120)
+    private String uploadText;
+
+    @ExcelField(title = "是否违纪", align = 2, sort = 130)
+    private String breach;
+
+    @ExcelField(title = "学院", align = 2, sort = 140)
+    private String college;
+
+    @ExcelField(title = "班级", align = 2, sort = 150)
+    private String className;
+
+    @ExcelField(title = "任课老师", align = 2, sort = 160)
+    private String teacher;
+
+    @ExcelField(title = "考点", align = 2, sort = 170)
+    private String examSite;
+
+    @ExcelField(title = "考场", align = 2, sort = 180)
+    private String examRoom;
+
+    private List<ScoreItem> objectiveList;
+
+    private List<String> subjectiveList;
+
+    public static final String SPLIT = ";";
+
+    public ExamStudentScoreDTO(ExamStudent student) {
+        setSubjectText(student.getSubjectCode() + "-" + student.getSubjectName());
+        setSubjectLevel(student.getSubjectLevel());
+        setSubjectCategory(student.getSubjectCategory());
+        setExamNumber(student.getExamNumber());
+        setStudentCode(student.getStudentCode());
+        setName(student.getName());
+        setSubjectiveScoreList(StringUtils.trimToEmpty(student.getSubjectiveScoreList()));
+        if (!student.isUpload() || student.isAbsent()) {
+            setTotalScore("-");
+            setObjectiveScore("-");
+            setSubjectiveScore("-");
+        } else if (student.isBreach()) {
+            setTotalScore("0");
+            setObjectiveScore("0");
+            setSubjectiveScore("0");
+        } else {
+            setObjectiveScore(String.valueOf(student.getObjectiveScore()));
+            setSubjectiveScore(String.valueOf(student.getSubjectiveScore()));
+            setTotalScore(String.valueOf(student.getTotalScore()));
+        }
+        if (student.isAbsent()) {
+            setUploadText("缺考");
+        } else {
+            setUploadText("");
+        }
+        if (student.isUpload()) {
+            setUploadText("已上传");
+        } else {
+            setUploadText("未上传");
+        }
+
+        if (student.isBreach()) {
+            setBreach("违纪");
+        } else {
+            setBreach("");
+        }
+        setClassName(student.getClassName());
+        setCollege(student.getCollege());
+        setTeacher(student.getTeacher());
+        setExamSite(student.getExamSite());
+        setExamRoom(student.getExamRoom());
+        setObjectiveList(student.getScoreList(true));
+
+        List<String> subjectiveList = new LinkedList<String>();
+        if (StringUtils.isNotBlank(student.getSubjectiveScoreList())) {
+            String[] values = StringUtils.split(student.getSubjectiveScoreList(), SPLIT);
+            for (String value : values) {
+                subjectiveList.add(value);
+            }
+        }
+        setSubjectiveList(subjectiveList);
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(String totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public String getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(String objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public String getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(String subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public String getSubjectiveScoreList() {
+        return subjectiveScoreList;
+    }
+
+    public void setSubjectiveScoreList(String subjectiveScoreList) {
+        this.subjectiveScoreList = subjectiveScoreList;
+    }
+
+    public String getSubjectLevel() {
+        return subjectLevel;
+    }
+
+    public void setSubjectLevel(String subjectLevel) {
+        this.subjectLevel = subjectLevel;
+    }
+
+    public String getSubjectCategory() {
+        return subjectCategory;
+    }
+
+    public void setSubjectCategory(String subjectCategory) {
+        this.subjectCategory = subjectCategory;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    public List<ScoreItem> getObjectiveList() {
+        return objectiveList;
+    }
+
+    public void setObjectiveList(List<ScoreItem> objectiveList) {
+        this.objectiveList = objectiveList;
+    }
+
+    public List<String> getSubjectiveList() {
+        return subjectiveList;
+    }
+
+    public void setSubjectiveList(List<String> subjectiveList) {
+        this.subjectiveList = subjectiveList;
+    }
+
+    public String getBreach() {
+        return breach;
+    }
+
+    public void setBreach(String breach) {
+        this.breach = breach;
+    }
+
+    public String getSubjectText() {
+        return subjectText;
+    }
+
+    public void setSubjectText(String subjectText) {
+        this.subjectText = subjectText;
+    }
+
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+    public String getAbsentText() {
+        return absentText;
+    }
+
+    public void setAbsentText(String absentText) {
+        this.absentText = absentText;
+    }
+
+    public String getUploadText() {
+        return uploadText;
+    }
+
+    public void setUploadText(String uploadText) {
+        this.uploadText = uploadText;
+    }
+
+}

+ 20 - 8
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScoreController.java

@@ -2,7 +2,11 @@ package cn.com.qmth.stmms.admin.exam;
 
 import java.io.ByteArrayInputStream;
 import java.math.BigDecimal;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -19,12 +23,20 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import com.qmth.boot.tools.io.ZipWriter;
 
-import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
+import cn.com.qmth.stmms.admin.dto.ExamStudentScoreDTO;
 import cn.com.qmth.stmms.admin.dto.ScoreEditDTO;
 import cn.com.qmth.stmms.admin.utils.ExportStudentExcel;
-import cn.com.qmth.stmms.biz.exam.model.*;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
-import cn.com.qmth.stmms.biz.exam.service.*;
+import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.annotation.Logging;
@@ -258,7 +270,7 @@ public class ScoreController extends BaseExamController {
             }
         }
         try {
-            List<ExamStudentDTO> list = new LinkedList<>();
+            List<ExamStudentScoreDTO> list = new LinkedList<>();
             // 可导出科目不为空时,才能执行查询操作
             if (!subjectSet.isEmpty()) {
                 query.setSubjectCodes(new ArrayList<>(subjectSet));
@@ -276,12 +288,12 @@ public class ScoreController extends BaseExamController {
                         student.setSubjectiveScoreList(
                                 student.getSubjectiveScoreList().replace(UN_SELECTIVE_SCORE, "/"));
                     }
-                    list.add(new ExamStudentDTO(student));
+                    list.add(new ExamStudentScoreDTO(student));
                 }
             }
             if (StringUtils.isNotBlank(query.getSubjectCode())) {
                 List<String> headerList = getOptionHeader(exam.getId(), query.getSubjectCode());
-                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentDTO.class);
+                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentScoreDTO.class);
                 excel.setDataList(list, true);
                 excel.write(response, fileName).dispose();
                 return null;
@@ -289,7 +301,7 @@ public class ScoreController extends BaseExamController {
                 response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("成绩单.zip"));
                 ZipWriter writer = ZipWriter.create(response.getOutputStream());
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
-                new ExportExcel("成绩单", ExamStudentDTO.class).setDataList(list).write(os);
+                new ExportExcel("成绩单", ExamStudentScoreDTO.class).setDataList(list).write(os);
                 byte[] value = os.toByteArray();
                 writer.write(new ByteArrayInputStream(value), fileName);
                 if (!error.isEmpty()) {

+ 20 - 16
stmms-web/src/main/java/cn/com/qmth/stmms/admin/utils/ExportStudentExcel.java

@@ -12,6 +12,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.servlet.http.HttpServletResponse;
 
@@ -32,15 +33,16 @@ import org.apache.poi.xssf.usermodel.XSSFRichTextString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Lists;
+
 import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
+import cn.com.qmth.stmms.admin.dto.ExamStudentScoreDTO;
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.annotation.ExcelField;
 import cn.com.qmth.stmms.common.utils.Encodes;
 import cn.com.qmth.stmms.common.utils.Reflections;
 
-import com.google.common.collect.Lists;
-
 public class ExportStudentExcel {
 
     private static Logger log = LoggerFactory.getLogger(ExportStudentExcel.class);
@@ -79,7 +81,11 @@ public class ExportStudentExcel {
      *            实体对象,通过annotation.ExportField获取标题
      */
     public ExportStudentExcel(String title, List<String> headerList, Class<?> cls) {
-        this(title, cls, 1, headerList);
+        this(null, title, cls, 1, headerList);
+    }
+
+    public ExportStudentExcel(String title, List<String> headerList, Class<?> cls, Set<String> cols) {
+        this(cols, title, cls, 1, headerList);
     }
 
     /**
@@ -94,12 +100,13 @@ public class ExportStudentExcel {
      * @param groups
      *            导入分组
      */
-    public ExportStudentExcel(String title, Class<?> cls, int type, List<String> addHeaderList, int... groups) {
+    public ExportStudentExcel(Set<String> cols, String title, Class<?> cls, int type, List<String> addHeaderList,
+            int... groups) {
         // Get annotation field
         Field[] fs = cls.getDeclaredFields();
         for (Field f : fs) {
             ExcelField ef = f.getAnnotation(ExcelField.class);
-            if (ef != null && (ef.type() == 0 || ef.type() == type)) {
+            if (ef != null && (ef.type() == 0 || ef.type() == type) && (cols == null || cols.contains(f.getName()))) {
                 if (groups != null && groups.length > 0) {
                     boolean inGroup = false;
                     for (int g : groups) {
@@ -210,8 +217,8 @@ public class ExportStudentExcel {
             Cell titleCell = titleRow.createCell(0);
             titleCell.setCellStyle(styles.get("title"));
             titleCell.setCellValue(title);
-            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(),
-                    titleRow.getRowNum(), headerList.size() - 1));
+            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
+                    headerList.size() - 1));
         }
         // Create header
         if (headerList == null) {
@@ -225,8 +232,8 @@ public class ExportStudentExcel {
             String[] ss = StringUtils.split(headerList.get(i), "**", 2);
             if (ss.length == 2) {
                 cell.setCellValue(ss[0]);
-                Comment comment = this.sheet.createDrawingPatriarch().createCellComment(
-                        new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
+                Comment comment = this.sheet.createDrawingPatriarch()
+                        .createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
                 comment.setString(new XSSFRichTextString(ss[1]));
                 cell.setCellComment(comment);
             } else {
@@ -371,11 +378,8 @@ public class ExportStudentExcel {
                     cell.setCellValue((String) fieldType.getMethod("setValue", Object.class).invoke(null, val));
                 } else {
                     cell.setCellValue((String) Class
-                            .forName(
-                                    this.getClass()
-                                            .getName()
-                                            .replaceAll(this.getClass().getSimpleName(),
-                                                    "fieldtype." + val.getClass().getSimpleName() + "Type"))
+                            .forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
+                                    "fieldtype." + val.getClass().getSimpleName() + "Type"))
                             .getMethod("setValue", Object.class).invoke(null, val));
                 }
             }
@@ -392,8 +396,8 @@ public class ExportStudentExcel {
      * 
      * @return list 数据列表
      */
-    public <E> ExportStudentExcel setDataList(List<ExamStudentDTO> list, boolean addOptions) {
-        for (ExamStudentDTO e : list) {
+    public <E> ExportStudentExcel setDataList(List<ExamStudentScoreDTO> list, boolean addOptions) {
+        for (ExamStudentScoreDTO e : list) {
             int colunm = 0;
             Row row = this.addRow();
             StringBuilder sb = new StringBuilder();

+ 27 - 7
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/admin/ScoreController.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.stmms.api.controller.admin;
 
 import java.io.ByteArrayInputStream;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -13,14 +14,18 @@ import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import com.qmth.boot.core.collection.PageResult;
+import com.qmth.boot.core.exception.StatusException;
 import com.qmth.boot.tools.io.ZipWriter;
 
-import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
+import cn.com.qmth.stmms.admin.dto.ExamStudentScoreDTO;
 import cn.com.qmth.stmms.admin.utils.ExportStudentExcel;
 import cn.com.qmth.stmms.api.controller.BaseApiController;
 import cn.com.qmth.stmms.biz.exam.bean.ScoreVo;
@@ -35,14 +40,15 @@ import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
-import com.qmth.boot.core.exception.StatusException;
 import cn.com.qmth.stmms.biz.file.service.FileService;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
 import cn.com.qmth.stmms.biz.utils.PageUtil;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.domain.ApiUser;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.utils.Encodes;
-import cn.com.qmth.stmms.common.utils.ExportExcel;
+import cn.com.qmth.stmms.common.utils.ExportExcelByCols;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -52,6 +58,9 @@ import io.swagger.annotations.ApiOperation;
 @RequestMapping("/api/admin/exam/score")
 public class ScoreController extends BaseApiController {
 
+    @Autowired
+    private UserService userService;
+
     @Autowired
     private ExamSubjectService subjectService;
 
@@ -171,6 +180,17 @@ public class ScoreController extends BaseApiController {
     @ResponseBody
     public void export(ExamStudentSearchQuery query, HttpServletResponse response) {
         ApiUser wu = getApiUser();
+        User user = userService.findById(wu.getId());
+        if (StringUtils.isBlank(user.getScoreExportCols())) {
+            throw new StatusException("表头配置没有勾选任何字段");
+        }
+        Gson gson = new Gson();
+        Type setType = new TypeToken<Set<String>>() {
+        }.getType();
+        Set<String> cols = gson.fromJson(user.getScoreExportCols(), setType);
+        if (CollectionUtils.isEmpty(cols)) {
+            throw new StatusException("表头配置没有勾选任何字段");
+        }
         Exam exam = examService.findById(getSessionExamId());
         if (exam == null || !exam.getSchoolId().equals(wu.getUser().getSchoolId())) {
             throw new StatusException("请选择正确的考试");
@@ -208,7 +228,7 @@ public class ScoreController extends BaseApiController {
             }
         }
         try {
-            List<ExamStudentDTO> list = new LinkedList<>();
+            List<ExamStudentScoreDTO> list = new LinkedList<>();
             // 可导出科目不为空时,才能执行查询操作
             if (!subjectSet.isEmpty()) {
                 query.setSubjectCodes(new ArrayList<>(subjectSet));
@@ -226,19 +246,19 @@ public class ScoreController extends BaseApiController {
                         student.setSubjectiveScoreList(
                                 student.getSubjectiveScoreList().replace(UN_SELECTIVE_SCORE, "/"));
                     }
-                    list.add(new ExamStudentDTO(student));
+                    list.add(new ExamStudentScoreDTO(student));
                 }
             }
             if (StringUtils.isNotBlank(query.getSubjectCode())) {
                 List<String> headerList = getOptionHeader(exam.getId(), query.getSubjectCode());
-                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentDTO.class);
+                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentScoreDTO.class, cols);
                 excel.setDataList(list, true);
                 excel.write(response, fileName).dispose();
             } else {
                 response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("成绩单.zip"));
                 ZipWriter writer = ZipWriter.create(response.getOutputStream());
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
-                new ExportExcel("成绩单", ExamStudentDTO.class).setDataList(list).write(os);
+                new ExportExcelByCols("成绩单", ExamStudentScoreDTO.class, cols).setDataList(list).write(os);
                 byte[] value = os.toByteArray();
                 writer.write(new ByteArrayInputStream(value), fileName);
                 if (!error.isEmpty()) {

+ 34 - 22
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/admin/StudentController.java

@@ -1,9 +1,12 @@
 package cn.com.qmth.stmms.api.controller.admin;
 
+import java.lang.reflect.Type;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -16,6 +19,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Controller;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -23,6 +27,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;
 
 import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import com.qmth.boot.core.collection.PageResult;
 import com.qmth.boot.core.exception.StatusException;
 
@@ -31,6 +37,7 @@ import cn.com.qmth.stmms.admin.vo.ExamStudentVO;
 import cn.com.qmth.stmms.admin.vo.UploadStudentVO;
 import cn.com.qmth.stmms.api.controller.BaseApiController;
 import cn.com.qmth.stmms.biz.exam.bean.AnswerAiCheckSaveParam;
+import cn.com.qmth.stmms.biz.exam.bean.ExamStudentExportVo;
 import cn.com.qmth.stmms.biz.exam.bean.ResultMessage;
 import cn.com.qmth.stmms.biz.exam.model.CollationLabel;
 import cn.com.qmth.stmms.biz.exam.model.Exam;
@@ -47,6 +54,8 @@ import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.mark.service.MarkService;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
 import cn.com.qmth.stmms.biz.utils.PageUtil;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.enums.ExamType;
@@ -54,6 +63,7 @@ import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.enums.MarkStatus;
 import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
+import cn.com.qmth.stmms.common.utils.ExportExcelByCols;
 import cn.com.qmth.stmms.common.utils.ImportExcel;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 import io.swagger.annotations.Api;
@@ -88,6 +98,9 @@ public class StudentController extends BaseApiController {
     @Autowired
     private MarkGroupService groupService;
 
+    @Autowired
+    private UserService userService;
+
     @Autowired
     private CollationLabelService collationLabelService;
 
@@ -290,8 +303,7 @@ public class StudentController extends BaseApiController {
             list.add(new ExamStudent());
             new ExportExcel("考生数据", ExamStudent.class, 2).setDataList(list).write(response, fileName).dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导入模板下载失败!失败信息:" + e.getMessage());
         }
     }
@@ -366,7 +378,6 @@ public class StudentController extends BaseApiController {
             return result(message + failureMsg);
         } catch (Exception e) {
             log.error("Batch import student error!", e);
-            e.printStackTrace();
             throw new StatusException("导入考生失败!失败信息:" + e.getMessage());
         }
     }
@@ -388,6 +399,17 @@ public class StudentController extends BaseApiController {
     @Logging(menu = "导出考生", type = LogType.EXPORT)
     @RequestMapping(value = "/export", method = RequestMethod.POST)
     public void exportFile(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response) {
+        User user = userService.findById(getApiUser().getId());
+        if (StringUtils.isBlank(user.getStudentExportCols())) {
+            throw new StatusException("表头配置没有勾选任何字段");
+        }
+        Gson gson = new Gson();
+        Type setType = new TypeToken<Set<String>>() {
+        }.getType();
+        Set<String> cols = gson.fromJson(user.getStudentExportCols(), setType);
+        if (CollectionUtils.isEmpty(cols)) {
+            throw new StatusException("表头配置没有勾选任何字段");
+        }
         try {
             int examId = getSessionExamId(request);
             query.setPageNumber(1);
@@ -395,19 +417,17 @@ public class StudentController extends BaseApiController {
             query.setExamId(examId);
             query.addSort("id", Sort.Direction.ASC);
             query = studentService.findByQuery(query);
+            List<ExamStudentExportVo> ret = new ArrayList<>();
             for (ExamStudent student : query.getResult()) {
                 ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
-                student.setSubjectName(subject != null ? subject.getName() : "");
-                student.setSubjectLevel(subject != null ? subject.getLevel() : "");
-                student.setSubjectCategory(subject != null ? subject.getCategory() : "");
-                student.setSubjectRemark(subject != null ? subject.getRemark() : "");
+                student.setSubject(subject);
+                ret.add(ExamStudentExportVo.of(student));
             }
             String fileName = "考生数据.xlsx";
-            new ExportExcel("考生数据", ExamStudent.class).setDataList(query.getResult()).write(response, fileName)
+            new ExportExcelByCols("考生数据", ExamStudentExportVo.class, cols).setDataList(ret).write(response, fileName)
                     .dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导出考生数据失败!" + e.getMessage());
         }
     }
@@ -421,8 +441,7 @@ public class StudentController extends BaseApiController {
             list.add(new ExamStudentVO());
             new ExportExcel("缺考考生", ExamStudentVO.class, 2).setDataList(list).write(response, fileName).dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导入模板下载失败!失败信息:" + e.getMessage());
         }
     }
@@ -462,7 +481,6 @@ public class StudentController extends BaseApiController {
             return result(message + failureMsg);
         } catch (Exception e) {
             log.error("Batch import absentStudent error!", e);
-            e.printStackTrace();
             throw new StatusException("导入缺考考生失败!失败信息:" + e.getMessage());
         }
     }
@@ -476,8 +494,7 @@ public class StudentController extends BaseApiController {
             list.add(new ExamStudentVO());
             new ExportExcel("违纪考生", ExamStudentVO.class, 2).setDataList(list).write(response, fileName).dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导入模板下载失败!失败信息:" + e.getMessage());
         }
     }
@@ -516,7 +533,6 @@ public class StudentController extends BaseApiController {
             return result(message + failureMsg);
         } catch (Exception e) {
             log.error("Batch import BreachStudent error!", e);
-            e.printStackTrace();
             throw new StatusException("导入违纪考生失败!失败信息:" + e.getMessage());
         }
     }
@@ -549,8 +565,7 @@ public class StudentController extends BaseApiController {
             list.add(new UploadStudentVO());
             new ExportExcel("多媒体考生上传", UploadStudentVO.class, 2).setDataList(list).write(response, fileName).dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导入模板下载失败!失败信息:" + e.getMessage());
         }
     }
@@ -606,7 +621,6 @@ public class StudentController extends BaseApiController {
             return result("已成功导入 " + successNum + " 条用户" + failureMsg);
         } catch (Exception e) {
             log.error("Batch import BreachStudent error!", e);
-            e.printStackTrace();
             throw new StatusException("导入上传考生失败!失败信息:" + e.getMessage());
         }
     }
@@ -620,8 +634,7 @@ public class StudentController extends BaseApiController {
             list.add(new ExamStudentVO());
             new ExportExcel("整理异常", CollationLabelVO.class, 2).setDataList(list).write(response, fileName).dispose();
         } catch (Exception e) {
-            log.error(e.getMessage());
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
             throw new StatusException("导入模板下载失败!失败信息:" + e.getMessage());
         }
     }
@@ -666,7 +679,6 @@ public class StudentController extends BaseApiController {
             return result(message + failureMsg);
         } catch (Exception e) {
             log.error("Batch import CollationLabel error!", e);
-            e.printStackTrace();
             throw new StatusException("导入整理异常失败!失败信息:" + e.getMessage());
         }
     }

+ 461 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/common/utils/ExportExcelByCols.java

@@ -0,0 +1,461 @@
+package cn.com.qmth.stmms.common.utils;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+public class ExportExcelByCols {
+
+    private static Logger log = LoggerFactory.getLogger(ExportExcelByCols.class);
+
+    /**
+     * 工作薄对象
+     */
+    private SXSSFWorkbook wb;
+
+    /**
+     * 工作表对象
+     */
+    private Sheet sheet;
+
+    /**
+     * 样式列表
+     */
+    private Map<String, CellStyle> styles;
+
+    /**
+     * 当前行号
+     */
+    private int rownum;
+
+    /**
+     * 注解列表(Object[]{ ExcelField, Field/Method })
+     */
+    List<Object[]> annotationList = Lists.newArrayList();
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param cls
+     *            实体对象,通过annotation.ExportField获取标题
+     */
+    public ExportExcelByCols(String title, Class<?> cls, Set<String> cols) {
+        this(cols, title, cls);
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param cls
+     *            实体对象,通过annotation.ExportField获取标题
+     * @param type
+     *            导出类型(1:导出数据;2:导出模板)
+     * @param groups
+     *            导入分组
+     */
+    public ExportExcelByCols(Set<String> cols, String title, Class<?> cls) {
+        // Get annotation field
+        Field[] fs = cls.getDeclaredFields();
+        for (Field f : fs) {
+            ExcelField ef = f.getAnnotation(ExcelField.class);
+            if (ef != null && cols.contains(f.getName())) {
+                annotationList.add(new Object[] { ef, f });
+            }
+        }
+        // Field sorting
+        Collections.sort(annotationList, new Comparator<Object[]>() {
+
+            public int compare(Object[] o1, Object[] o2) {
+                return new Integer(((ExcelField) o1[0]).sort()).compareTo(new Integer(((ExcelField) o2[0]).sort()));
+            };
+        });
+        // Initialize
+        List<String> headerList = Lists.newArrayList();
+        for (Object[] os : annotationList) {
+            String t = ((ExcelField) os[0]).title();
+            headerList.add(t);
+        }
+        initialize(title, headerList);
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headers
+     *            表头数组
+     */
+    public ExportExcelByCols(String title, String[] headers) {
+        initialize(title, Lists.newArrayList(headers));
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headerList
+     *            表头列表
+     */
+    public ExportExcelByCols(String title, List<String> headerList) {
+        initialize(title, headerList);
+    }
+
+    /**
+     * 初始化函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headerList
+     *            表头列表
+     */
+    private void initialize(String title, List<String> headerList) {
+        this.wb = new SXSSFWorkbook(500);
+        this.sheet = wb.createSheet("Export");
+        this.styles = createStyles(wb);
+        // Create title
+        if (StringUtils.isNotBlank(title)) {
+            Row titleRow = sheet.createRow(rownum++);
+            titleRow.setHeightInPoints(30);
+            Cell titleCell = titleRow.createCell(0);
+            titleCell.setCellStyle(styles.get("title"));
+            titleCell.setCellValue(title);
+            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
+                    headerList.size() - 1));
+        }
+        // Create header
+        if (headerList == null) {
+            throw new RuntimeException("headerList not null!");
+        }
+        Row headerRow = sheet.createRow(rownum++);
+        headerRow.setHeightInPoints(16);
+        for (int i = 0; i < headerList.size(); i++) {
+            Cell cell = headerRow.createCell(i);
+            cell.setCellStyle(styles.get("header"));
+            String[] ss = StringUtils.split(headerList.get(i), "**", 2);
+            if (ss.length == 2) {
+                cell.setCellValue(ss[0]);
+                Comment comment = this.sheet.createDrawingPatriarch()
+                        .createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
+                comment.setString(new XSSFRichTextString(ss[1]));
+                cell.setCellComment(comment);
+            } else {
+                cell.setCellValue(headerList.get(i));
+            }
+            sheet.autoSizeColumn(i);
+        }
+        for (int i = 0; i < headerList.size(); i++) {
+            int colWidth = sheet.getColumnWidth(i) * 2;
+            sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth);
+        }
+        log.debug("Initialize success.");
+    }
+
+    /**
+     * 创建表格样式
+     * 
+     * @param wb
+     *            工作薄对象
+     * @return 样式列表
+     */
+    private Map<String, CellStyle> createStyles(Workbook wb) {
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+
+        CellStyle style = wb.createCellStyle();
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+        Font titleFont = wb.createFont();
+        titleFont.setFontName("Arial");
+        titleFont.setFontHeightInPoints((short) 16);
+        titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        style = wb.createCellStyle();
+        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+        style.setBorderRight(CellStyle.BORDER_THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(CellStyle.BORDER_THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(CellStyle.BORDER_THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(CellStyle.BORDER_THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        Font dataFont = wb.createFont();
+        dataFont.setFontName("Arial");
+        dataFont.setFontHeightInPoints((short) 10);
+        style.setFont(dataFont);
+        styles.put("data", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_LEFT);
+        styles.put("data1", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        styles.put("data2", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_RIGHT);
+        styles.put("data3", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        // style.setWrapText(true);
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
+        Font headerFont = wb.createFont();
+        headerFont.setFontName("Arial");
+        headerFont.setFontHeightInPoints((short) 10);
+        headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+        headerFont.setColor(IndexedColors.WHITE.getIndex());
+        style.setFont(headerFont);
+        styles.put("header", style);
+
+        return styles;
+    }
+
+    /**
+     * 添加一行
+     * 
+     * @return 行对象
+     */
+    public Row addRow() {
+        return sheet.createRow(rownum++);
+    }
+
+    /**
+     * 添加一个单元格
+     * 
+     * @param row
+     *            添加的行
+     * @param column
+     *            添加列号
+     * @param val
+     *            添加值
+     * @return 单元格对象
+     */
+    public Cell addCell(Row row, int column, Object val) {
+        return this.addCell(row, column, val, 0, Class.class);
+    }
+
+    /**
+     * 添加一个单元格
+     * 
+     * @param row
+     *            添加的行
+     * @param column
+     *            添加列号
+     * @param val
+     *            添加值
+     * @param align
+     *            对齐方式(1:靠左;2:居中;3:靠右)
+     * @return 单元格对象
+     */
+    public Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType) {
+        Cell cell = row.createCell(column);
+        CellStyle style = styles.get("data" + (align >= 1 && align <= 3 ? align : ""));
+        try {
+            if (val == null) {
+                cell.setCellValue("");
+            } else if (val instanceof String) {
+                cell.setCellValue((String) val);
+            } else if (val instanceof Integer) {
+                cell.setCellValue((Integer) val);
+            } else if (val instanceof Long) {
+                cell.setCellValue((Long) val);
+            } else if (val instanceof Double) {
+                cell.setCellValue((Double) val);
+            } else if (val instanceof Float) {
+                cell.setCellValue((Float) val);
+            } else if (val instanceof Date) {
+                DataFormat format = wb.createDataFormat();
+                style.setDataFormat(format.getFormat("yyyy-MM-dd"));
+                cell.setCellValue((Date) val);
+            } else {
+                if (fieldType != Class.class) {
+                    cell.setCellValue((String) fieldType.getMethod("setValue", Object.class).invoke(null, val));
+                } else {
+                    cell.setCellValue((String) Class
+                            .forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
+                                    "fieldtype." + val.getClass().getSimpleName() + "Type"))
+                            .getMethod("setValue", Object.class).invoke(null, val));
+                }
+            }
+        } catch (Exception ex) {
+            log.info("Set cell value [" + row.getRowNum() + "," + column + "] error: " + ex.toString());
+            cell.setCellValue(val.toString());
+        }
+        cell.setCellStyle(style);
+        return cell;
+    }
+
+    /**
+     * 添加数据(通过annotation.ExportField添加数据)
+     * 
+     * @return list 数据列表
+     */
+    public <E> ExportExcelByCols setDataList(List<E> list) {
+        for (E e : list) {
+            int colunm = 0;
+            Row row = this.addRow();
+            StringBuilder sb = new StringBuilder();
+            for (Object[] os : annotationList) {
+                ExcelField ef = (ExcelField) os[0];
+                Object val = null;
+                // Get entity value
+                try {
+                    if (StringUtils.isNotBlank(ef.value())) {
+                        val = Reflections.invokeGetter(e, ef.value());
+                    } else {
+                        if (os[1] instanceof Field) {
+                            val = Reflections.invokeGetter(e, ((Field) os[1]).getName());
+                        } else if (os[1] instanceof Method) {
+                            val = Reflections.invokeMethod(e, ((Method) os[1]).getName(), new Class[] {},
+                                    new Object[] {});
+                        }
+                    }
+                    // If is dict, get dict label
+                    /*
+                     * if (StringUtils.isNotBlank(ef.dictType())){ val =
+                     * DictUtils.getDictLabel(val==null?"":val.toString(),
+                     * ef.dictType(), ""); }
+                     */
+                } catch (Exception ex) {
+                    // Failure to ignore
+                    log.info(ex.toString());
+                    val = "";
+                }
+                this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
+                sb.append(val + ", ");
+            }
+            log.debug("Write success: [" + row.getRowNum() + "] " + sb.toString());
+        }
+        return this;
+    }
+
+    /**
+     * 输出数据流
+     * 
+     * @param os
+     *            输出数据流
+     */
+    public ExportExcelByCols write(OutputStream os) throws IOException {
+        wb.write(os);
+        return this;
+    }
+
+    /**
+     * 输出到客户端
+     * 
+     * @param fileName
+     *            输出文件名
+     */
+    public ExportExcelByCols write(HttpServletResponse response, String fileName) throws IOException {
+        response.reset();
+        response.setContentType("application/octet-stream; charset=utf-8");
+        response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode(fileName));
+        write(response.getOutputStream());
+        return this;
+    }
+
+    /**
+     * 输出到文件
+     * 
+     * @param fileName
+     *            输出文件名
+     */
+    public ExportExcelByCols writeFile(String name) throws FileNotFoundException, IOException {
+        FileOutputStream os = new FileOutputStream(name);
+        this.write(os);
+        return this;
+    }
+
+    /**
+     * 清理临时文件
+     */
+    public ExportExcelByCols dispose() {
+        wb.dispose();
+        return this;
+    }
+
+    // /**
+    // * 导出测试
+    // */
+    // public static void main(String[] args) throws Throwable {
+    //
+    // List<String> headerList = Lists.newArrayList();
+    // for (int i = 1; i <= 10; i++) {
+    // headerList.add("表头"+i);
+    // }
+    //
+    // List<String> dataRowList = Lists.newArrayList();
+    // for (int i = 1; i <= headerList.size(); i++) {
+    // dataRowList.add("数据"+i);
+    // }
+    //
+    // List<List<String>> dataList = Lists.newArrayList();
+    // for (int i = 1; i <=1000000; i++) {
+    // dataList.add(dataRowList);
+    // }
+    //
+    // ExportExcel ee = new ExportExcel("表格标题", headerList);
+    //
+    // for (int i = 0; i < dataList.size(); i++) {
+    // Row row = ee.addRow();
+    // for (int j = 0; j < dataList.get(i).size(); j++) {
+    // ee.addCell(row, j, dataList.get(i).get(j));
+    // }
+    // }
+    //
+    // ee.writeFile("target/export.xlsx");
+    //
+    // ee.dispose();
+    //
+    // log.debug("Export success.");
+    //
+    // }
+
+}