目录
对于提高识别准确性问题的解决:
1、上传的成绩表格式不同的处理问题
在上一部分中提到的对不同上传图片形式的考虑(三种不同格式的图),这样的考虑能够使用户上传的图片识别尽可能少地出现识别错误。
(1)带表格标题和表头信息的:
(2)只带表头而无标题的:
(3)无标题和表头的(这种常见于班级人数较多,一张纸没能打印完全)
在截取字符串时需要根据已截取到的字符串的前面的部分的内容进行判断到底是哪一种情况,然后再根据具体的情况再确定学生信息和成绩的开始位置,进而完成获取学生和对应成绩的功能:
String substr1 = str.split(":")[1];
System.out.println("substr1 = "+substr1);
String title = "报表";
boolean withtitle = substr1.contains(title);
System.out.println("withtitle = "+withtitle);
String substr3 = str.split(":")[3];
String header = "姓名";
System.out.println("substr3 = "+substr3);
boolean withheaderandtitle = substr3.contains(header);
boolean withonlyheader = substr1.contains(header);
if(withonlyheader){
strj1 = str.split(":")[5*i+j+1+5];
System.out.println("11"+strj1);
}
if(withtitle){
strj1 = str.split(":")[5*i+j+1+7];
System.out.println("22"+strj1);
}
if(!withtitle){
if(!withonlyheader){
strj1 = str.split(":")[5*i+j+1];
System.out.println("33"+strj1);
}
}
2、识别后的字符矫正
识别的手写部分的数据是”数字“,但是由于书写的不是很标准等问题,可能将数字错误地识别为其他的字符,这样会导致在成绩的计算过程中出错。所以需要在识别之后对字符进行校验。
下面的工具类主要用于处理成绩识别后的信息的处理,包括字符的矫正、百分制成绩对评级制成绩的转化:
package org.jeecg.modules.demo.ScoresInput.entity;
import java.util.ArrayList;
import java.util.List;
public class UtilClass {
public static List<String> listpre = new ArrayList<String>();//传入的字符串
public static List<String> listout = new ArrayList<String>();//传出的字符串
public static List<String> str_false = new ArrayList<String>();//错误列表
public static List<String> str_true = new ArrayList<String>();//正确列表
public static void main(String[] args) {
UtilClass.checkNum("1oql");
}
public static String ScrChange(String scoreint){
String score = "";
int scr = Integer.parseInt(scoreint);
if(scr>89){
score = "优";
}
if(scr>79 && scr<90){
score = "良";
}
if(scr>69 && scr<80){
score = "中";
}
if(scr>59 && scr<70){
score = "及格";
}
if(scr < 60){
score = "不及格";
}
return score;
}
//识别不准确的字符的处理
public static int checkNum(String str){
String pre = str;
int out = 0;
String outstr = "";
// System.out.println("pre = "+pre);
String single = "";
int length = pre.length();
for(int i=0;i<length;i++){
single = String.valueOf(pre.charAt(i));
// System.out.println("single = "+single);
listpre.add(single);
single = UtilClass.ChangeInList(single);
//System.out.println("single1 = "+single);
try{
Double.parseDouble(single);
}catch (Exception e){
System.out.println("有未入列表的非数字字符"+single);
single = "1";//默认为1
}
listout.add(single);
}
for(int j=0;j<length;j++){
String s = listout.get(j);
outstr = outstr + s;
}
// System.out.println("outstr = "+outstr);
out = Integer.parseInt(outstr);
// System.out.println("out = "+out);
listout.clear();
return out;
}
public static void initsf(){//初始化错误组
str_false.add(0,"o");
str_false.add(1,"l");
str_false.add(2,"q");
str_false.add(3,"b");
str_false.add(4,"(");
str_false.add(5,"≥");
str_false.add(6,"D");
str_false.add(7,"/");
}
public static void initst(){//初始化对应的正确组
str_true.add(0,"0");
str_true.add(1,"1");
str_true.add(2,"9");
str_true.add(3,"6");
str_true.add(4,"5");
str_true.add(5,"2");
str_true.add(6,"0");
str_true.add(7,"1");
}
//用对应的正确的string替换错误的
public static String ChangeInList(String str){
UtilClass.initsf();
UtilClass.initst();
String string = "";
int index = 0;
boolean bool = str_false.contains(str);
// System.out.println("bool = "+bool);
if(bool){
index = str_false.indexOf(str);
string = str_true.get(index);
}else{
string = str;
}
// System.out.println("str = "+str+", string = "+string+", index = "+index);
return string;
}
}
主要是在多次的识别测试后,建立出现过的转义序列, 即错误字符与正确字符之间的对应关系。
录入成绩的基础表格的导出:
1、对应选课学生基本信息的加载:
//获取上该课的学生名单显示在前端
@RequestMapping(value = "/stuList")
public Result<?> stuList(@RequestBody Map<String,Object> map) {
String cs_id = "";
String les_ord = "";
if (map.containsKey("les_ord")){
les_ord = map.get("les_ord").toString();
System.out.println(les_ord);
}
if (map.containsKey("cs_id")){
cs_id = map.get("cs_id").toString();
System.out.println(cs_id);
}
System.out.println("les_ord = "+les_ord+", cs_id = "+cs_id);
List<Scores> allList = scoresService.getStuList(cs_id,les_ord);
boolean bool = allList.isEmpty();
System.out.println("bool = "+bool);
return Result.ok(allList);
}
<select id="getStuList" parameterType="java.lang.String" resultType="org.jeecg.modules.demo.ScoresInput.entity.Scores">
SELECT *
FROM scores
WHERE
cs_id = #{cs_id} and les_ord=#{les_ord}
</select>
2、导出待填写的成绩表格:
因为需要老师进行手写填入学生成绩,所以需要先导出一个待填写的表格,但是框架中默认的导出方法导出的是数据库中该表的所有行的数据,显然是不符合我们要求的,因为我们需要的是该老师所教授的该班级的学生。所以需要自己写方法覆盖掉默认的导出方法。
(1)由于一开始没能找到覆盖框架中选择学生的方法,所以自己用java写了一个导出的方法:
ScoreController中的方法exToExcel:
//导出excel
@RequestMapping(value = "/exToExcel")
public Result<?> exToExcel(@RequestBody Map<String,Object> map) {
String cs_id = "";
String les_ord = "";
List<List<Object>> rowDatas = new ArrayList<List<Object>>();
List<Object> headers = new ArrayList<Object>();//加入表头
String header1 = "姓名";
String header2 = "学号";
String header3 = "考试成绩";
String header4 = "平时成绩";
String header5 = "实验成绩";
headers.add(0,header1);
headers.add(1,header2);
headers.add(2,header3);
headers.add(3,header4);
headers.add(4,header5);
rowDatas.add(headers);
if (map.containsKey("les_ord")){
les_ord = map.get("les_ord").toString();
System.out.println(les_ord);
}
if (map.containsKey("cs_id")){
cs_id = map.get("cs_id").toString();
System.out.println(cs_id);
}
System.out.println("les_ord = "+les_ord+", cs_id = "+cs_id);
List<Scores> allList = scoresService.getStuList(cs_id,les_ord);
boolean bool = allList.isEmpty();
System.out.println("bool = "+bool);
int num = allList.size();
System.out.println("allList.size = "+num);
for(int i=0;i<num;i++){
List<Object> datas = new ArrayList<Object>();
Scores s = allList.get(i);
String stu_id = s.getStuId();
String stu_name = s.getStuName();
String scrempty = "";
String exam_score = String.valueOf(s.getExamScores());
String usual_score = String.valueOf(s.getUsualScores());
String test_score = String.valueOf(s.getTestScores());
//未录入的成绩在取出时是null
if(exam_score.equals("null")){
exam_score = scrempty;
}
if(usual_score.equals("null")){
usual_score = scrempty;
}
if(test_score.equals("null")){
test_score = scrempty;
}
// datas.clear();
datas.add(0,stu_name);
datas.add(1,stu_id);
datas.add(2,exam_score);
datas.add(3,usual_score);
datas.add(4,test_score);
rowDatas.add(datas);
System.out.println("datas.size = "+datas.size());
int sizeOfRowDatas = rowDatas.size();
System.out.println("rowDatas = "+sizeOfRowDatas);
}
int sizeOfRowDatas = rowDatas.size();
System.out.println("rowDatas = "+sizeOfRowDatas);
//rowDatas.add(allList);
//调用生成excel的方法
ExToExcel.ToExcel(rowDatas, -1,"D:", "test4.xls", null);
System.out.println("-------导出为excel成功-------");
return Result.ok(allList);
}
ExToExcel工具类中的方法ToExcel:
public static boolean ToExcel(List<List<Object>>rowDatas, Integer outputType, String path, String fileName, final HttpServletResponse response) {
@SuppressWarnings("resource")
HSSFWorkbook wb = new HSSFWorkbook();//定义一个excel文件
HSSFSheet sheet = wb.createSheet();//创建第一页
HSSFCellStyle style = wb.createCellStyle();//创建样式风格
style.setAlignment(HorizontalAlignment.CENTER);//为样式设置值,这里是居中
// style.setBorderBottom(BorderStyle.DOUBLE);
HSSFRow row;
HSSFCell cell;
sheet.setDefaultColumnWidth(15);
short h =sheet.getDefaultRowHeight();
System.out.println("h = "+h);
sheet.setDefaultRowHeight((short) 450);
for(int i = 0; i < rowDatas.size(); i++) {
row = sheet.createRow(i);
for(int j = 0; j < rowDatas.get(i).size(); j++) {
cell = row.createCell(j);//创建单元格
cell.setCellStyle(style);//单元格应用样式
Object o = rowDatas.get(i).get(j);
//转换为文本格式,这样在导出文件中展示完全,可以自己尝试
if(o instanceof Integer || o instanceof Double || o instanceof Float)
cell.setCellValue(Double.parseDouble(""+o));//这里转换为文本格式
else {
cell.setCellValue(""+o);//这里转换为文本格式
}
}
}
if(outputType==-1) {
try {
FileOutputStream fout = new FileOutputStream(path+"//"+fileName);
wb.write(fout);
}catch(Exception e) {
e.printStackTrace();
}
}
else if(outputType == 1) {
OutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename="
+ URLEncoder.encode(fileName, "UTF-8"));
wb.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
(2)但是上面的导出方法使得导出的excel直接被存储到了指定的位置,不太符合用户使用web页面下载文件的使用习惯,所以后来采用了覆盖框架中导出方法:
<select id="getStuScoreList" parameterType="java.lang.String" resultType="org.jeecg.modules.demo.ScoresInput.entity.Scores">
SELECT stu_name,stu_id,exam_scores,test_scores,usual_scores
FROM scores
WHERE cs_id = #{cs_id} and les_ord=#{les_ord}
</select>
//导出excel
@RequestMapping(value = "/exToExcel_test")
public ModelAndView exToExcel_test(@RequestParam(name="les_ord") String les_ord,
@RequestParam(name="cs_id") String cs_id,
HttpServletRequest req){
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
List<List<Scores>> rowDatas = new ArrayList<List<Scores>>();
List<Scores> allList = scoresService.getStuScoreList(cs_id,les_ord);
String title = "scores";
Class clazz = Scores.class;
List<Scores> exportList = allList;
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, title); //此处设置的filename无效 ,前端会重更新设置一下
mv.addObject(NormalExcelConstants.CLASS, clazz);
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title);
exportParams.setImageBasePath(upLoadPath);
//update-end--Author:liusq Date:20210126 for:图片导出报错,ImageBasePath未设置----------------------
mv.addObject(NormalExcelConstants.PARAMS,exportParams);
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
return mv;
}
导出结果展示:
这样就能够保证老师录入成绩时对应的时自己所教授的班级的学生的成绩了。