双层遍历jstl取值 和动态的显示 学生课程 成绩信息 加Excel导出
双层遍历jstl取值 和动态的显示 学生课程 成绩信息 加Excel导出
先说jstl双层遍历取值
<!--第一层-->
<c:forEach items="${lists}" var="ItemList">
<tr>
<td>${ItemList.stuId}</td>
<td>${ItemList.stuName}</td>
<!--第二层-->
<c:forEach items="${letter}" var="Item">
<!--这里要嵌套取得话不能${ ItemList.${Item}} 只能这么取${ ItemList[Item]}-->
<td>${ ItemList[Item]}</td>
</c:forEach>
<td>${ItemList.className}</td>
</tr>
</c:forEach>
好了现在进入正题
首先声明:这个功能非常简单,各位大佬都能写,之所有放在上面一是为了我自己好抄,二是想求个解决方案,本人得轮子是自己造的(轮子很烂),我想看看更好的轮子
本人的毕业设计有个功能是动态的将各个学院的各个科目的成绩显示出来 所以表头就的变动,实体类的属性因为各个学院的科目肯定是不一样的所以就得变动,下面就请大家看看我自己粗制滥造功能。。。。。
首先数据库查询起始语句,实不相瞒这个我也是百度的。。。。
效果大概就是这样
SELECT s.`stu_id`,s.`stu_name`,
SUM(CASE WHEN co.course_name='大学物理' THEN g.result ELSE 0 END) AS '大学物理',
SUM(CASE WHEN co.course_name='毛概' THEN g.result ELSE 0 END) AS '毛概',
SUM(CASE WHEN co.course_name='asd' THEN g.result ELSE 0 END) AS 'asd',
SUM(CASE WHEN co.course_name='概率论' THEN g.result ELSE 0 END) AS '概率论'
FROM grade g,student s,major m ,clazz z,course co ,grade_class gc WHERE
g.`course_id`=co.`course_id`AND s.`class_id`=z.`class_id` AND m.`major_id`=co.`major_id` AND s.`stu_id`=g.`stu_id` AND gc.`grade_class_id`=z.`grade_class_id` AND m.`major_id`=1
GROUP BY s.stu_id
再说实体类吧
因为每个学院的课程名字,课程数量肯定是不一样的所以实体类也不能写死
我的思路是 先查该学院有多少课程List,然后把size传到动态sql里面
因为mybatis 是根据列名和实体类的名字对应注入的(字段映射就不谈了,直接再application里面配就完事了,看下面) 所以查询的时候 课程名就 AS a As b As c 这样就和实体类对应了
//下划线转驼峰 springboot 项目
mybatis.configuration.map-underscore-to-camel-case=true
package com.huas.entities;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 存放学习各科成绩的的实现类
* 迫不得已 才写 A,B,C,D,E,F,G
* 还有种解决方案是 把所有的课程信息 列出来
* @author 500R5H
*
*/
//自动加有参构造器
@AllArgsConstructor
//自动加无参构造器
@NoArgsConstructor
//自动加Get,Set方法
@Data
public class GradeDetailWithTable {
// 成绩
private String stuId;
private String stuName;
private String className;
//虽然丑了点 但还是 开始吧
private Integer a;
private Integer b;
private Integer c;
private Integer d;
private Integer e;
private Integer f;
private Integer j;
private Integer h;
private Integer i;
}
然后就是provider动态sql
/**
* 详情展示相关开始:根据 marjorId ,classId,gradeClassId 查询学生的成绩
*
* @return
*/
public static String buildStudentGradeDetials(@Param("courseName") final List<String> courseName,@Param("majorId") final String majorId, @Param("gradeClassId") final String gradeClassId,
@Param("clazzId") final String clazzId) {
// 判断班级是否为空
boolean clazzFlag = clazzId != null && !"".equals(clazzId);
// 判断年级是否为空
boolean gradeClassFlag = gradeClassId != null && !"".equals(gradeClassId);
StringBuilder sb = new StringBuilder();
//定义这个是为了呼应 GradeDetailWithTable 实体类 中定义 的存放 数据库的 属性
String str = "ABCDEFGHIJKLMNPQRSTUVWXYZ".toLowerCase();
sb.append("SELECT s.stu_id,s.stu_name , ");
// {0}占位符 当'{0} ={0} 失效 当 ''{0}'' 时 就相当于 'asd'
for (int i = 0; i < courseName.size(); i++) {
sb.append(MessageFormat.format("SUM(CASE WHEN co.course_name=''{0}'' THEN g.result ELSE 0 END) AS '"+str.charAt(i)+"'",
courseName.get(i)));
if (i < courseName.size() - 1) {
sb.append(",");
}
}
//后面一定要有空格 否则 会报错
sb.append(", z.class_name ");
sb.append("FROM grade g,student s,major m ,clazz z,course co ,grade_class gc ");
// 判断年级是否为空
// 如果有年级 就带年级查
if (gradeClassFlag) {
// 判断班级有没有
if (clazzFlag) {
sb.append(
"WHERE g.course_id=co.course_id AND s.class_id=z.class_id AND m.major_id=co.major_id AND s.stu_id=g.stu_id AND gc.grade_class_id=z.grade_class_id AND z.class_id=#{clazzId} ");
} else {
sb.append(
"WHERE g.course_id=co.course_id AND s.class_id=z.class_id AND m.major_id=co.major_id AND s.stu_id=g.stu_id AND gc.grade_class_id=z.grade_class_id AND m.major_id=#{majorId} AND gc.grade_class_id=#{gradeClassId}");
}
// 不带年级查询
} else {
sb.append(
"WHERE g.course_id=co.course_id AND s.class_id=z.class_id AND m.major_id=co.major_id AND s.stu_id=g.stu_id AND gc.grade_class_id=z.grade_class_id AND m.major_id=#{majorId} ");
}
sb.append(" GROUP BY s.stu_id");
return sb.toString();
}
mapper
//查询全部课程信息
@Select("SELECT course_name FROM course WHERE major_id= #{majorId} ")
List<String> findCourseNameByMajorId(@Param("majorId")Integer majorId);
//动态查询学生各个科目的成绩信息
@SelectProvider(type = GradeProvider.class, method = "buildStudentGradeDetials")
List<GradeDetailWithTable> findStudentAndCourseAndResult(@Param("courseName") List<String> courseName,@Param("majorId") String majorId, @Param("gradeClassId") String gradeClassId,
@Param("clazzId") String clazzId);
服务层就不贴上来了 就是调mapper
然后就是控制层了
/**
* 表格详情展示页面 进入主页面
*/
@RequestMapping(value="/detailsWithTable")
public String intostugradeDetalWithTable(String clazzId, String majorId,String gradeClassId){
HttpServletRequest request = ConstantUtils.getRequest();
// 在session里面查找用户信息
User u = (User) request.getSession().getAttribute(ConstantUtils.SESSION_USER);
request.setAttribute("user", u);
String gId="";
String cId="";
//不能为空判断开始
if (gradeClassId != null && !"".equals(gradeClassId)) {
gId=gradeClassId;
}
if (clazzId != null && !"".equals(clazzId)) {
cId=clazzId;
}
if (majorId != null && !"".equals(majorId)) {
//查询所有的专业下的课程信息
List<String> courseName =service.findCourseNameByMajorId(majorId);
//定义这个是因为 在前端用jstl的时候 ${items.a} .b .c 肯定不能写死 要通过第二层循环遍历出来 拼接的
List<String> letter =new ArrayList();
String str = "ABCDEFGHIJKLMNPQRSTUVWXYZ".toLowerCase();
// 根据课程数量 存字母 ,因为我动态sql里 也是同样按照这种方式 在AS 后面加的字母
for(int i=0;i<courseName.size();i++){
letter.add(String.valueOf(str.charAt(i)));
}
//存信息
//用于动态生成学生信息
request.setAttribute("letter",letter);
//表头
request.setAttribute("courseName",courseName);
request.setAttribute("lists",service.findStudentAndCourseAndResult(courseName,majorId, gId, cId));
System.out.println(service.findStudentAndCourseAndResult(courseName,majorId, gId, cId));
}
return "stugradeDetalWithTable";
}
然后前端
肯定有精准搜索,比如我选择院系的时候 专业哪里要出现改院系下的专业,班级也是一样
就不贴代码了
然后就前端遍历 啊什么,然后第一次进入页面你肯定就没有数据 我是给页面下方加了
名人名言 https://v1.alapi.cn/api/mingyan?typeid=7 就这个网上免费的api
<c:choose>
<c:when test="${not empty courseName }">
<table class="table table-hover" id="tab">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<c:forEach items="${courseName}" var="ItemList">
<th>${ItemList }</th>
</c:forEach>
<th>班级</th>
</tr>
</thead>
<tbody>
<c:forEach items="${lists}" var="ItemList">
<tr>
<td>${ItemList.stuId}</td>
<td>${ItemList.stuName}</td>
<c:forEach items="${letter}" var="Item">
<c:choose>
<c:when test="${ItemList[Item]>=60}">
<td>${ ItemList[Item]}</td>
</c:when>
<c:otherwise>
<td><font color="red">${ ItemList[Item]}</font></td>
</c:otherwise>
</c:choose>
</c:forEach>
<td>${ItemList.className}</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:when>
<c:otherwise>
<center>
<div class="row"style="margin-top:150px;cursor: pointer" >
<p id="pText" style="font-size:20px;font-family: sans-serif"></p>
<p id="pName" style="margin-top:50px"></p>
</div>
</center>
</c:otherwise>
</c:choose>
<center>
<span id="tipSpan"></span>
</center>
就这么多了 如果有错误欢迎指正,当然我自己也觉得这种解决方式很烂,希望能看到更好的解决方案,更好的轮子
加个excel导出
excel导出的时候 在注入表格体的每一列时 学生id和姓名是确定的,班级是确定的 而每个学院的课程是不确定的所以 在调用getXXX时就不能写死 要动态调用get方法 并且要判断调用哪个方法
/**
* 导出excel:成绩管理详情
*/
@Override
public void buildStudentGradeExportExcel( String majorId, String gradeClassId,
String clazzId,HttpServletResponse response) {
//表头
List<String> courseName= mapper.findCourseNameByMajorId(Integer.valueOf(majorId));
List<GradeDetailWithTable> list= mapper.buildStudentGradeExportExcel(courseName, majorId, gradeClassId, clazzId);
WritableWorkbook workbook;
// 1.文件下载响应头
//response.setHeader("Content-Disposition", "attachment;filename=studentMessage.xls");
String fileName="学生成绩详情表";
// 2.响应到浏览器
try {
fileName = new String(fileName.getBytes(),"iso-8859-1");
response.setCharacterEncoding("gb2312");response.reset();
response.setContentType("application/OCTET-STREAM;charset=gb2312");
response.setHeader("pragma", "no-cache");
response.addHeader("Content-Disposition", "attachment;filename=\""+ fileName + ".xls\"");// 点击导出excle按钮时候页面显示的默认名称
workbook = Workbook.createWorkbook(response.getOutputStream());
// 创建工作簿sheet
WritableSheet sheet = workbook.createSheet("学生成绩表", 0);
// 设置字体的attribute
WritableFont font = new WritableFont(WritableFont.createFont("宋体"), 12, WritableFont.NO_BOLD);
WritableCellFormat format = new WritableCellFormat(font);
// 3.设置column名
sheet.addCell(new Label(0, 0,"学号", format));
sheet.addCell(new Label(1, 0, "姓名", format));
for(int i=0;i<courseName.size();i++){
System.out.println(courseName.get(i));
//遍历表头
sheet.addCell(new Label(2+i, 0, courseName.get(i), format));
}
sheet.addCell(new Label(courseName.size()+2, 0, "班级", format));
//准备 好方法名
List<String> letter =new ArrayList();
String str = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
for(int i=0;i<courseName.size();i++){
StringBuffer bf=new StringBuffer();
//拼接get方法的名字
bf.append("get").append(String.valueOf(str.charAt(i)));
letter.add(bf.toString());
}
// 导入行
for (int i = 0, j = 1; i < list.size(); i++, j++) {
// 设置列宽
sheet.setColumnView(i, 16);
// 重新设置部分列宽
sheet.setColumnView(courseName.size()+2, 20);
// 设置行高
sheet.setRowView(i, 350);
// 设置字体的attribute
WritableFont font1 = new WritableFont(WritableFont.createFont("楷体 _GB2312"), 12, WritableFont.NO_BOLD);
WritableFont font2 = new WritableFont(WritableFont.createFont("楷体 _GB2312"), 12,
WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,
jxl.format.Colour.CORAL);
WritableCellFormat format1 = new WritableCellFormat(font1);
WritableCellFormat format2 = new WritableCellFormat(font2);
GradeDetailWithTable g = list.get(i);
Class<?> c = g.getClass();
//获取该类的所有方法
Method[] method= c.getMethods();
sheet.addCell(new Label(0, j,g.getStuId(), format1));
sheet.addCell(new Label(1, j,g.getStuName(), format1));
for(int z=0;z<method.length;z++){
for(int n=0;n<letter.size();n++){
//如果方法名相同就执行get方法
if(method[z].getName().equals(letter.get(n))){
//如果成绩大于等于60 显黑色
if((Integer)method[z].invoke(g)>=60){
sheet.addCell(new Label(2+n, j,String.valueOf(method[z].invoke(g)) , format1));
//如果成绩小于60显示红色
}else{
sheet.addCell(new Label(2+n, j,String.valueOf(method[z].invoke(g)) , format2));
}
}
}
}
sheet.addCell(new Label(courseName.size()+2, j,g.getClassName(), format1));
}
// 5.写入数据
workbook.write();
// 6.关闭资源
workbook.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
本文作者:KwFruit
本文链接:https://www.cnblogs.com/mangoubiubiu/p/12860276.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步