DrewJhung's Blog

数据列表及导出Excel报表功能简述

数据列表及导出Excel报表功能简述

实现思路

  1. 基于反射

以自定义的bean为驱动, 通过bean的类名反射出相应的class,利用class对象得到bean的属性、方法、注解等等;

  1. 基于规约

以车贷系统为例,left.jsp为该系统导航页,该导航页中的链接大部分是load相应bean或者DTO的数据,数据列表展示方式大概2种:jsp分页展示、导出excel。如果你想要添加一个新的bean或者DTO只需要在导航页的链接里写规定的链接格式即可,示例:

<a data-url='${path}/report/template/GpsInfo' data-name="业务管理>>合同管理>>GPS安装信息" >GPS安装信息</a>

解释:示例中的url: ${path}/report/template/GpsInfo

${path}是当前应用的上下文路径

/report/template为规约的固定路径(必须这样写)

GpsInfo为用户自定义的bean,如果你想要添加新的bean把这里替换成你自己的bean名称即可

除了在链接中规约之外,在相应的Dao中的方法中也要写上和Bean一样的名字,示例:

1
2
3
4
public interface CreditReportDao extends MyBatisDao<CreditReport> {
List gpsInfo(Map<String, Object> params); // query all data
List gpsInfo(Map<String, Object> params, Pageable pageable); // query data by pageable
}

比如你的bean是GpsInfo 那么你的接口方法就写成bean对应的驼峰式写法:gpsInfo, 还有一种例外,上面我说的都是bean的通用写法, 如果是dto那么dao接口方法中需要去掉’Dto’,示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 自定义dto
public class CarAudittingMonitorDto extends BaseExcelDto{
private int id;
private String carName;
// setter and getter
}
// 你需要这样写自定义dto对应的接口方法
public interface CreditReportDao extends MyBatisDao<CreditReport> {
// 注意接口方法名字,还是驼峰式写法, 只是去掉了Dto
List carAudittingMonitor(Map<String, Object> params);
// 注意接口方法名字,还是驼峰式写法, 只是去掉了Dto
List carAudittingMonitor(Map<String, Object> params, Pageable pageable);
}

基于规约的总结:

  1. left.jsp 中的链接通用格式:${path}/report/template/{你的bean名称}
  2. Dao接口方法中,如果是bean则将bean的名称写成驼峰式,如果是Dto则将名称写成驼峰式并且去掉最后的Dto

想做个分页列表和Excel数据导出

  1. 首先自定义你的Bean或者Dto, 然后用注解表示出字段与列名一一对应的关系,举个栗子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// value表示报表名称或者列表标题, hasOperant 表示你的列表中是否需要显示操作
@Excel(value="GPS安装信息", hasOperant=true)
public class GpsInfo {
private int id;
// name 表示这个字段对应的列名, index 表示按大小升序展示每个字段
@ExcelField(name="有线GPS数量", index = 6) private int wireGpsCnt;
@ExcelField(name="无线GPS数量", index = 7) private int wirelessGpsCnt;
private String wireGpsDeviceNo;
private String wirelessGpsDeviceNo;
@ExcelField(skip=true, hidden=true, index=0) private int contractInfoId;
private int packageId;
private String busiNode;
@ExcelField(name="门店", index = 4) private String busiNodeName;
@ExcelField(name="客户姓名", index = 2) private String customerName;
@ExcelField(name="车牌号", index = 3) private String licenseNo;
private int checkStatus;
@ExcelField(name="复核提交时间", index = 5, style = ExcelField.DateTimeStyleEnum.DATETIME_EN) private Date checkSubmitTime;
private transient String[] wireDevices;
private transient String[] wirelessDevices;
@ExcelField(name="进件号", index = 1) private String packageNo;
private int gpsCheckStatus;
// 各种 getter setter 以下省略
}
  1. 在left.jsp 中添加导航到GpsInfo的列表,链接写为:${path}/report/template/GpsInfo

  2. 分别在CreditReportDao.java和CreditReportMapper.xml中写出你需要查询的方法、SQL

    CreditReportDao.java

1
2
3
4
public interface CreditReportDao extends MyBatisDao<CreditReport> {
List gpsInfo(Map<String, Object> params); // 导出全部数据到excel中
List gpsInfo(Map<String, Object> params, Pageable pageable); // jsp中分页查询
}

CreditReportMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- gps info -->
<select id="gpsInfo" resultMap="com.hexin.contract.repository.ContractInfoDao.gpsMap" parameterType="map">
select * from gps_info
<where>
<if test="busiNode!=null and busiNode!=''"> AND busi_node=#{busiNode}</if>
<if test="customerName!=null and customerName!=''"> AND customer_name=#{customerName}</if>
<if test="startTime!=null and startTime!=''">
<![CDATA[ AND check_submit_time>=#{startTime} ]]>
</if>
<if test="endTime!=null and endTime!=''">
<![CDATA[ AND check_submit_time<=#{endTime} ]]>
</if>
<if test="licenseNo!=null and licenseNo!=''"> AND license_no=#{licenseNo}</if>
<if test="packageNo!=null and packageNo!=''"> AND package_no=#{packageNo}</if>
<if test="gpsCheckStatus!=null and gpsCheckStatus!=0">
AND gps_check_status=#{gpsCheckStatus}
</if>
<if test="gpsCheckStatus==null or gpsCheckStatus==0">
AND gps_check_status=1
</if>
<!--<if test="checkStatus!=null and checkStatus!=0">
AND contract_check_status=#{checkStatus}
</if>
<if test="checkStatus==null or checkStatus==0">
AND contract_check_status=1
</if>-->
</where>
ORDER BY id DESC
</select>
  1. 后端获取数据的东西有了, 还差个展示bean或者Dto数据列表以及筛选这些数据的过滤条件的jsp, 我把所有的jsp 展示放在reportTemplate.jsp页面中,在该页面中保留共性(列表展示+EXCEL导出),抽出个性(满足不同的筛选条件)到filterCondition.jsp, 在该页面中, 需要根据bean或者Dto名称做if判断,还是以GpsInfo为参照, 上栗子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!-- 根据该变量 判断是不是GpsInfo, GpsInfo 可以替换成你自定义的Bean, 如果你自定的是Dto那么需要去掉最后的Dto -_-|| -->
<c:if test="${reqList == 'GpsInfo'}">
<table>
<tr>
<td align="right" width="6%" style="font-size: 12px;">进件编号: </td>
<td width="15%">
<input name="packageNo" id="packageNo" style="width: 150px;">
</td>
<td align="right" width="6%" style="font-size: 12px;">客户姓名: </td>
<td width="15%">
<input name="customerName" id="customerName" style="width: 150px;">
</td>
<td align="right" width="6%" style="font-size: 12px;">车牌号: </td>
<td width="15%">
<input name="licenseNo" style="width: 150px;">
</td>
</tr>
<tr>
<td align="right" width="6%" style="font-size: 12px;">门店: </td>
<td width="15%">
<input name="busiNode" id="recorderCode" style="width: 150px;">
</td>
<td align="right" width="6%" style="font-size: 12px;">提交时间:</td>
<td width="15%">
<input class="easyui-datetimebox" id="submitStartTime" name="startTime" style="width: 100px; ">~<input class="easyui-datetimebox" id="submitEndTime" name="endTime" style="width: 100px; ">
</td>
<td align="right" width="5%" style="font-size: 12px" colspan="2">
<a onclick="searchConstants()" class="easyui-linkbutton" iconCls="icon-search">查找</a>
<a style="padding-left: 15px;" onclick="reset()" class="easyui-linkbutton" iconCls="icon-remove">重置</a>
</td>
</tr>
</table>
<!-- 这里判断你的列表中是否有操作栏, 比如GpsInfo列表中 需要展示‘GPS安装信息’操作, 这里固定写这个变量名字就好了, 这个变量设置也是在Bean 或者Dto中的@Excel注解中添加即可, 具体设置参见GpsInfo.java -->
<c:if test="${operant}">
<script>
function operation(value,row,index){
var val = '';
val += '<a class="label label-primary" style="color: blue;" onclick="getGpsDetail(' + index + ')">&nbsp; &nbsp;GPS安装信息 </a>';
return val;
}
function getGpsDetail(index){
$("#loanReportList").datagrid("selectRow",index);
var selRow = $("#loanReportList").datagrid("getSelected");
if (selRow) {
$("#loanReportList").after("<div id='apply_auditingInfo_dialog_ids' style='padding:10px; '></div>");
$("#apply_auditingInfo_dialog_ids").dialog({
resizable: false,
title: 'GPS安装信息',
href: '${path}/contract/gps/'+selRow.contractInfoId,
loadMsg:'数据加载中......',
width: 800,
modal: true,
height: 500,
top: 200,
left: 500,
buttons: [
{
text: '确认',
iconCls: 'icon-ok',
handler: function () {
$("#apply_auditingInfo_dialog_ids").dialog('close');
}
}
],
onClose: function () {
$(this).dialog('destroy');
}
});
}
}
</script>
</c:if>
</c:if>

后语

无规矩不成方圆, 只要按规矩写,可解决一般性需求。