瀏覽代碼

科目拆分错误信息文件下载

xiatian 10 月之前
父節點
當前提交
818b6c289a

+ 1 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java

@@ -424,7 +424,7 @@ public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implem
 				}
 			}
 			if (line.length() > 0) {
-				err.append(" 第" + (index + 2) + "行 " + line);
+				err.append(" 第" + (index + 2) + "行 " + line+"\r\n");
 			}
 		}
 		if (err.length() > 0) {

+ 2 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/enums/FileType.java

@@ -8,7 +8,8 @@ public enum FileType {
     SHEET("原图", "sheet/%d/%s/%s-%d.%s"), SLICE("裁切图", "slice/%d/%s/%s-%d.%s"), JSON("作答内容", "json/%d/%s/%s.%s"), PACKAGE(
             "签到表", "package/%d/%s/%d.%s"), PAPER("试卷", "paper/%d/%s.%s"), ANSWER("标答", "answer/%d/%s.%s"), CARD("题卡",
             "card/%d/%s.%s"), EXCHANGE("文件", "exchange/%s"), ANSWER_CARD("题卡", "card/answer/%d/%s.%s"), REPORT("报表",
-            "report/%d/%s/%s.%s"), INCOMPLETE("缺页异常表", "incomplete/%d/%s.%s");
+            "report/%d/%s/%s.%s"), INCOMPLETE("缺页异常表", "incomplete/%d/%s.%s")
+    ,SUBJECTSPLITERR("科目拆分异常信息", "subject-split-err/%d/%d/%d/error.txt");
 
     private String name;
 

+ 4 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/FileService.java

@@ -84,4 +84,8 @@ public interface FileService {
 
     String getIncompleteUri(Integer examId, String name);
 
+	String getSubjectSplitErrUri(int schoolId, int examId, int userId);
+
+	void uploadSubjectSplitErr(InputStream ins, String md5, int schoolId, int examId, int userId) throws Exception;
+
 }

+ 8 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/impl/FileServiceImpl.java

@@ -120,7 +120,10 @@ public class FileServiceImpl implements FileService, InitializingBean, Disposabl
     public void uploadPackage(InputStream ins, String md5, int examId, String packageCode, int index) throws Exception {
         store.write(getPackageUri(examId, packageCode, index), ins, md5);
     }
-
+    @Override
+    public void uploadSubjectSplitErr(InputStream ins, String md5, int schoolId, int examId, int userId) throws Exception {
+        store.write(getSubjectSplitErrUri(schoolId, examId, userId), ins, md5);
+    }
     @Override
     public void uploadPaper(InputStream ins, String md5, int examId, String subjectCode, FormatType type)
             throws Exception {
@@ -203,7 +206,10 @@ public class FileServiceImpl implements FileService, InitializingBean, Disposabl
         }
         return list;
     }
-
+    @Override
+    public String getSubjectSplitErrUri(int schoolId,int examId, int userId) {
+        return FileType.SUBJECTSPLITERR.getPath(schoolId, examId, userId);
+    }
     @Override
     public String getPaperUri(int examId, String subjectCode, FormatType type) {
         return FileType.PAPER.getPath(examId, subjectCode, type.getExtName());

+ 93 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/utils/MD5Util.java

@@ -0,0 +1,93 @@
+package cn.com.qmth.stmms.common.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+/**
+ * @Description: MD5加密工具类
+ */
+public class MD5Util {
+	public static final String CHARSET_NAME = "UTF-8";
+
+    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
+    
+    public static final String MD5 = "MD5";
+
+    /**
+     * MD5加密
+     *
+     * @param text
+     * @return
+     * @throws Exception
+     */
+    public static String encoder(String text) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        MessageDigest digest = MessageDigest.getInstance(MD5);
+        digest.update(text.getBytes(CHARSET));
+        byte s[] = digest.digest();
+        StringJoiner result = new StringJoiner("");
+        for (int i = 0; i < s.length; i++) {
+            result.add(Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6));
+        }
+        return result.toString();
+    }
+
+    /**
+     * MD5校验
+     *
+     * @param text
+     * @param md5
+     * @return
+     * @throws Exception
+     */
+    public static boolean verify(String text, String md5) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        md5 = Optional.of(md5).get();
+        //根据传入的密钥进行验证
+        String md5Text = encoder(text);
+        if (md5Text.equalsIgnoreCase(md5)) {
+            return true;
+        }
+        return false;
+    }
+    
+	public static String md5Hex(File file) {
+		FileInputStream in = null;
+		try {
+			in = new FileInputStream(file);
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+	
+	public static String md5Hex(InputStream in) {
+		try {
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+}
+

+ 27 - 3
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/SubjectController.java

@@ -1,17 +1,22 @@
 package cn.com.qmth.stmms.admin.exam;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 import java.util.stream.Collectors;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -27,16 +32,20 @@ import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
+import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.biz.school.model.School;
 import cn.com.qmth.stmms.biz.school.service.SchoolService;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.annotation.RoleRequire;
+import cn.com.qmth.stmms.common.domain.WebUser;
 import cn.com.qmth.stmms.common.enums.ExamStatus;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.enums.Role;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.ImportExcel;
+import cn.com.qmth.stmms.common.utils.MD5Util;
+import cn.com.qmth.stmms.common.utils.RequestUtils;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
 import net.sf.json.JsonConfig;
@@ -50,10 +59,14 @@ public class SubjectController extends BaseExamController {
 
 	@Autowired
 	private ExamService examService;
-
+	@Autowired
+	private FileService fileService;
+	
 	@Autowired
 	private SchoolService schoolService;
-
+    @Value("${file.temp}")
+    private String tempFile;
+    
 	@RequestMapping("/list")
 	@ResponseBody
 	public JSONArray list(HttpServletRequest request, @RequestParam Integer examId) {
@@ -163,7 +176,18 @@ public class SubjectController extends BaseExamController {
 			if(StringUtils.isBlank(errMsg)) {
 				model.addAttribute("message", "已成功导入");
 			}else {
-				model.addAttribute("errmsg", errMsg);
+				WebUser wu = RequestUtils.getWebUser(request);
+				File errFile = new File(tempFile + File.separator +UUID.randomUUID().toString()+ ".txt");
+				try {
+					errFile.getParentFile().mkdirs();
+					FileUtils.write(errFile, errMsg,"utf-8");
+					fileService.uploadSubjectSplitErr(new FileInputStream(errFile), MD5Util.md5Hex(errFile), schoolId,
+							examId, wu.getId());
+					model.addAttribute("errmsgUrl", fileService.getFileServer()+fileService.getSubjectSplitErrUri(schoolId, examId, wu.getId()));
+					model.addAttribute("errmsg", "导入信息有误,请查看error.txt文件");
+				} finally {
+					errFile.delete();
+				}
 			}
 		}catch (Exception e) {
 			log.error("导入失败",e);

+ 71 - 33
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/subjectSplit.jsp

@@ -1,11 +1,11 @@
-<%@ page contentType="text/html;charset=UTF-8" %>
-<%@ include file="/WEB-INF/views/include/taglib.jsp" %>
+<%@ page contentType="text/html;charset=UTF-8"%>
+<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
 <html>
 <head>
-    <title>新建学校</title>
-    <meta name="decorator" content="default"/>
-    <%@include file="/WEB-INF/views/include/head.jsp" %>
-    <script type="text/javascript">
+<title>新建学校</title>
+<meta name="decorator" content="default" />
+<%@include file="/WEB-INF/views/include/head.jsp"%>
+<script type="text/javascript">
         $(document).ready(function () {
          	$("#uploadFile").change(function (e) {
          		var ob=e.currentTarget.files[0];
@@ -39,50 +39,88 @@
                 }
             });
         });
+        function urlToBlob(url, cb) {
+        	  const xhr = new XMLHttpRequest();
+        	  xhr.open('GET', url, true);
+        	  xhr.responseType = 'blob';
+        	  xhr.onload = function () {
+        	    if (xhr.status == 200) {
+        	      cb(URL.createObjectURL(xhr.response));
+        	    }
+        	  };
+        	  xhr.send();
+        	}
+
+        	function saveAs(blob, filename) {
+        	  if (window.navigator.msSaveOrOpenBlob) {
+        	    navigator.msSaveBlob(blob, filename);
+        	  } else {
+        	    console.log('blob', blob);
+        	    var link = document.createElement('a');
+        	    var body = document.querySelector('body');
+        	    link.href = blob;
+        	    link.download = filename;
+        	    link.style.display = 'none';
+        	    body.appendChild(link);
+        	    link.click();
+        	    body.removeChild(link);
+        	    window.URL.revokeObjectURL(link.href);
+        	  }
+        	}
+
+        	function downloadByCrossUrl(url, filename) {
+        	  urlToBlob(url, (blob) => {
+        	    saveAs(blob, filename);
+        	  });
+        	}
     </script>
 </head>
 <body>
-<form:form id="inputForm" action="${ctx}/admin/exam/subject/split/save" method="post" class="form-horizontal" enctype="multipart/form-data">
-    <tags:message content="${message}"/>
-    <tags:message content="${errmsg}" type="error" />
-    <input type="hidden" id="schoolId" name="schoolId" value="${schoolId}" />
+	<form:form id="inputForm" action="${ctx}/admin/exam/subject/split/save"
+		method="post" class="form-horizontal" enctype="multipart/form-data">
+		<tags:message content="${message}" />
+		<tags:message content="${errmsg}" type="error" />
+		<input type="hidden" id="schoolId" name="schoolId" value="${schoolId}" />
 		<div class="control-group">
 			<label class="control-label">名称</label>
-			<div class="controls"><input type="text" disabled="disabled"
-				id="schoolName" name="schoolName" value="${schoolName}"/>
-				</div>
+			<div class="controls">
+				<input type="text" disabled="disabled" id="schoolName"
+					name="schoolName" value="${schoolName}" />
+			</div>
 		</div>
 		<div class="control-group">
 			<label class="control-label">考试</label>
 			<div class="controls">
-			<select class="input-large required" name="examId" id="examId">
-				<option value="" selected="selected">请选择考试</option>
-				<c:forEach items="${examList}" var="item">
-					<option <c:if test="${item.id==examId}">selected</c:if> value="${item.id}">${item.id}-${item.name}</option>
-				</c:forEach>
-			</select>
+				<select class="input-large required" name="examId" id="examId">
+					<option value="" selected="selected">请选择考试</option>
+					<c:forEach items="${examList}" var="item">
+						<option <c:if test="${item.id==examId}">selected</c:if>
+							value="${item.id}">${item.id}-${item.name}</option>
+					</c:forEach>
+				</select>
 			</div>
 		</div>
 		<div class="control-group">
-		<label class="control-label">导入拆分表</label>
+			<label class="control-label">导入拆分表</label>
 			<div class="controls">
-			<input id="uploadFile" name="file" type="file" style="width:210px" class="required"
-			accept=".xls,.xlsx"
-			/> 
+				<input id="uploadFile" name="file" type="file" style="width: 210px"
+					class="required" accept=".xls,.xlsx" />
 			</div>
 		</div>
 		<div class="control-group">
 			<label class="control-label"></label>
 			<div class="controls">
-            	<a href="${ctx}/admin/exam/subject/split/template">下载模板</a>
-            </div>
-        </div>
-    <div class="form-actions">
-            <input id="btnSubmit" class="btn btn-primary" type="submit"
-				value="导入"/> 
-			&nbsp; 
-			<a href="${ctx}/admin/sys/school" class="btn">返回</a>
-    </div>
-</form:form>
+				<a href="${ctx}/admin/exam/subject/split/template">下载模板</a>
+				<c:if test="${errmsgUrl!=null}">
+					<a href="#" style="margin-left: 50px"
+						onclick="downloadByCrossUrl('${errmsgUrl}','error.txt')">error.txt</a>
+				</c:if>
+			</div>
+		</div>
+		<div class="form-actions">
+			<input id="btnSubmit" class="btn btn-primary" type="submit"
+				value="导入" /> &nbsp; <a href="${ctx}/admin/sys/school" class="btn">返回</a>
+		</div>
+	</form:form>
 </body>
 </html>