项目第九天(分页+报表)
1:分页
原理分析:
userIndex.jsp
userList.jsp
原理:
pub.js(dom对象的ajax封装)
1:在userIndex.jsp中存在2个Form表单(Form1和Form2)
2:传递表单Form1中的元素作为参数传递给服务器的参数,在服务器端进行处理,将处理后的结果(即分页后的结果)显示在userList.jsp中
3:将userList.jsp的内容,放置到userIndex.jsp的Form2中
整合项目步骤:
第一步:导入2个java文件,放置到util包下
表示:
PageBean中的内容:
private int pageNo;//存放当前页
private boolean firstPage;//当前页是否是第一页:是:true
private boolean lastPage; //当前页是否是最后一页:是:true
private int sumPage;//总页数
private int pageSize ;//当前页最多显示几条记录
private int totalResult ;//总记录数
第二步:导入一个js文件,page.js放置到script包下
第三步:修改userIndex.jsp的内容:
(1)添加:
<script language="javascript" src="${pageContext.request.contextPath }/script/page.js"></script>
<script language="javascript" src="${pageContext.request.contextPath }/script/validate.js"></script>
<script language="javascript"
src="${pageContext.request.contextPath }/script/pub.js"></script>
(2)修改【查询】按钮的连接
<input style="font-size:12px; color:black; height=20;width=80" id="BT_Add" type="button" value="查询" name="BT_find"
onclick="gotoquery('elecUserAction_home.do')">
(3)在Form1的表单中添加2个隐藏域
<s:hidden name="initPage" value="1"></s:hidden>
<!-- 处理分页必须要传递的属性(当前页) -->
<s:hidden name="pageNO"></s:hidden>
(4)在Form2的表单中,加载pageUI.jsp,这个jsp页面显示分页的相关信息,添加:
<%@include file="/WEB-INF/page/pageUI.jsp" %>
第四步:将userIndex.jsp的Form2表单的内容,单独提取出来,命名为userList.jsp
第五步:在struts.xml中添加:
<result name="list">/WEB-INF/page/system/userList.jsp</result>
第六步:在Action类中添加:
//判断:什么情况调整到userList.jsp,什么情况调整到userIndex.jsp
String initPage = request.getParameter("initPage");
if(initPage!=null && initPage.equals("1")){
//调整到userList.jsp(执行ajax的分页)
return "list";
}
第七步:在Service类中添加:
PageInfo pageInfo = new PageInfo(ServletActionContext.getRequest());
* currentPageNo:表示当前页(从PageNO中获取)
* pageSize:表示默认该页最多显示多少条记录
* req:存放request对象
List<ElecUser> list = elecUserDao.findCollectionByConditionWithPage(condition, params, orderby,pageInfo);
ServletActionContext.getRequest().setAttribute("page",pageInfo.getPageBean());
第八步:在Dao类中添加:
pageInfo.setTotalResult(query.list().size());
* totalResult:存放总记录数
* totalPage:存放总页数
query.setFirstResult(pageInfo.getBeginResult());//当前页从第几条开始检索,默认是0,0表示第1条
* currentPageNo:存放当前页;
* beginResult:表示当前页从第几条开始检索,默认是0;
* pageSize:表示当前页做多显示的记录数;
query.setMaxResults(pageInfo.getPageSize());//表示当前页最多显示多少条记录
2:POI报表(excel文件的导出)
(1)POI报表整合项目
第一步:导入jar包:
第二步:导入java文件(使用poi生成excel报表,放置到输出流中),类放置到util包下
第三步:在userIndex.jsp中定义:
(1)添加按钮
<input style="font-size:12px; color:black; height=20;width=80" id="BT_Export" type="button" value="导出设置" name="BT_Export" onclick="openWindow('${pageContext.request.contextPath }/system/elecExportFieldsAction_setExportExcel.do?belongTo=5-1','700','400')">
<input style="font-size:12px; color:black; height=20;width=80" id="BT_Add" type="button" value="导出" name="BT_Add" onclick="exportExcel()">
(2)js代码:
//导出excel
function exportExcel(){
var userName = document.getElementById("userName").value;
userName = encodeURI(userName,"UTF-8");
userName = encodeURI(userName,"UTF-8");
var jctID = document.getElementById("jctID").value;
var onDutyDateBegin = document.getElementById("onDutyDateBegin").value;
var onDutyDateEnd = document.getElementById("onDutyDateEnd").value;
openWindow('${pageContext.request.contextPath }/system/elecUserAction_exportExcel.do?userName='+userName+'&jctID='+jctID+'&onDutyDateBegin='+onDutyDateBegin+'&onDutyDateEnd='+onDutyDateEnd,'700','400')
}
第四步:在Action类中定义:
/**
* @Name: exportExcel
* @Description: 用户列表的信息动态导出excel
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Create Date:
* @Parameters: 无
* @Return: String:null(不使用struts2的方式,完成流的操作)
*/
public String exportExcel() throws Exception{
//构造2个数据集合
//构造excel的标题
ArrayList<String> fieldName = elecUserService.findExcelFiledName();
//构造excel的数据
ArrayList<ArrayList<String>> fieldData = elecUserService.findExcelFieldData(elecUser);
//使用ExcelFileGenerator完成导出
ExcelFileGenerator excelFileGenerator = new ExcelFileGenerator(fieldName,fieldData);
OutputStream os = response.getOutputStream();
//导出excel建议加上重置输出流,可以不加该代码,但是如果不加必须要保证输出流中不应该在存在其他数据,否则导出会有问题
response.reset();
//配置:
//文件名
String fileName = "用户报表("+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+").xls";
fileName = new String(fileName.getBytes("gbk"),"iso-8859-1");
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition", "attachment;filename="+fileName);
response.setBufferSize(1024);
//导出excel的操作
excelFileGenerator.expordExcel(os);
return null;
}
/**
* @Name: exportExcel
* @Description: 用户列表的信息动态导出excel
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Create Date:
* @Parameters: 无
* @Return: String:success(使用struts2的方式,完成流的操作)
*/
public String exportExcel() throws Exception{
//构造2个数据集合
//构造excel的标题
ArrayList<String> fieldName = elecUserService.findExcelFiledName();
//构造excel的数据
ArrayList<ArrayList<String>> fieldData = elecUserService.findExcelFieldData(elecUser);
//使用ExcelFileGenerator完成导出
ExcelFileGenerator excelFileGenerator = new ExcelFileGenerator(fieldName,fieldData);
ByteArrayOutputStream os = new ByteArrayOutputStream();
//导出excel建议加上重置输出流,可以不加该代码,但是如果不加必须要保证输出流中不应该在存在其他数据,否则导出会有问题
response.reset();
//配置:
//文件名
String fileName = "用户报表("+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+").xls";
fileName = new String(fileName.getBytes("gbk"),"iso-8859-1");
request.setAttribute("filename", fileName);
//导出excel的操作
excelFileGenerator.expordExcel(os);
//将输入流的文件,放置到栈顶的Inputstream中
byte [] buf = os.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(buf);
elecUser.setInputStream(in);
return "success";
}
第五步:在Service类中定义(构造数据集合):
/**
* @Name: findExcelFiledName
* @Description: 构造excel的标题内容
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Parameters: 无
* @Return: ArrayList<String>:excel的标题:
* ArrayList<String> fieldName
fieldName.add("登录名");
fieldName.add("用户姓名");
...
*/
public ArrayList<String> findExcelFiledName() {
//查询导出设置表,主键是用户管理5-1的设置
ElecExportFields elecExportFields = elecExportFieldsDao.findObjectByID("5-1");
//获取导出中文的名称
String zName = elecExportFields.getExpNameList();
//将String类型的字符,按照#号分割成集合
List<String> list = StringToListUtils.stringToList(zName, "#");
ArrayList<String> filedName = new ArrayList<String>(list);
return filedName;
}
/**
* @Name: findExcelFieldData
* @Description: 构造excel的数据内容
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Create Date:
* @Parameters: ElecUser:VO对象
* @Return: ArrayList<ArrayList<String>> fieldData:存放的时候所有的数据
ArrayList<String> data1:存放的是每一条的数据
data1.add("liubei");
data1.add("刘备");
...
ArrayList<String> data2:存放的是每一条的数据
data2.add("zhugeliang");
data2.add("诸葛亮");
…
fieldData.add(data1);
fieldData.add(data2);
*/
public ArrayList<ArrayList<String>> findExcelFieldData(ElecUser elecUser) {
//返回最后的结果集
ArrayList<ArrayList<String>> fieldData = new ArrayList<ArrayList<String>>();
//查询导出设置表,主键是用户管理5-1的设置
ElecExportFields elecExportFields = elecExportFieldsDao.findObjectByID("5-1");
//获取导出中文的名称
String zName = elecExportFields.getExpNameList();
//将String类型的字符,按照#号分割成集合
List<String> zlist = StringToListUtils.stringToList(zName, "#");
//获取导出英文的名称
String eName = elecExportFields.getExpFieldName();
//将英文字段的#号替换成逗号
String selectCondition = eName.replace("#", ",");
//封装查询条件
String condition = "";
List<Object> paramsList = new ArrayList<Object>();
//姓名
String userName = elecUser.getUserName();
//处理乱码
try {
userName = URLDecoder.decode(userName, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if(StringUtils.isNotBlank(userName)){
condition += " and o.userName like ?";
paramsList.add("%"+userName+"%");
}
//所属单位
if(StringUtils.isNotBlank(elecUser.getJctID())){
condition += " and o.jctID = ?";
paramsList.add(elecUser.getJctID());
}
//入职开始时间
if(elecUser.getOnDutyDateBegin()!=null){
condition += " and o.onDutyDate >= ?";
paramsList.add(elecUser.getOnDutyDateBegin());
}
//入职结束时间
if(elecUser.getOnDutyDateEnd()!=null){
condition += " and o.onDutyDate <= ?";
paramsList.add(elecUser.getOnDutyDateEnd());
}
Object [] params = paramsList.toArray();
//排序:按照入职时间升序
Map<String, String> orderby = new LinkedHashMap<String, String>();
orderby.put("o.onDutyDate", "asc");
//处理查询,list总存放的时候所有的记录
List list = elecUserDao.findCollectionByConditionNoPageWithSelectCondition(condition, params, orderby,selectCondition);
//遍历list
if(list!=null && list.size()>0){
for(int i=0;i<list.size();i++){
//统一使用数组的方式存放每一条的数据
Object [] arrays = null;
//如果投影查询是多个字段,返回的是Object数组对象
if(selectCondition.contains(",")){
arrays = (Object[]) list.get(i);
}
//如果投影查询是一个字段,返回的是Object对象
else{
arrays = new Object[1];
arrays[0] = list.get(i);
}
//封装成每一条的数据
ArrayList<String> data = new ArrayList<String>();
if(arrays!=null && arrays.length>0){
for(int j=0;j<arrays.length;j++){
//获取每个字段的值
Object o = arrays[j];
//数据字典的转换(由于使用的中文和英文要一一对应)
if(zlist!=null && zlist.get(j).equals("性别") || zlist.get(j).equals("所属单位") || zlist.get(j).equals("职位") || zlist.get(j).equals("是否在职")){
data.add(o!=null?elecSystemDDLDao.findDdlNameByKeywordAndDdlCode(zlist.get(j), o.toString()):"");
}
else{
data.add(o!=null?o.toString():"");
}
}
}
fieldData.add(data);
}
}
return fieldData;
}
第六步:使用struts2方式的导出
(1)配置struts.xml
<result name="success" type="stream">
<param name="contentType">application/vnd.ms-excel</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${#request.filename}.xls"</param>
<param name="bufferSize">1024</param>
</result>
(2)在模型驱动的对象中添加:
//导出excel文件的流
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
(2)POI报表的几个核心对象
(3)POI报表(应对面试)
面试的时候,如果问到使用poi报表如何处理数据导出的?
导出功能:
(1)作用一:导出excel报表
(2)作用二:分公司每个月将每个月录入的数据,【导出】excel报表,传递给总部,总部可以执行【导入】,将数据添加到总部的系统
3:Get请求出现乱码的解决方案
Get请求出现乱码,模拟一般出现的场景。
(2)超链接
(3)window.opon(“url?name=张三&age=18”)
解决方案:
方案一:
在jsp中的js代码定义:
userName = encodeURI(userName,"UTF-8");
在Action类中定义:
//获取流程定义的key
String userName = elecUser.getUserName();
try {
userName = new String(userName.getBytes("iso-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
方案二:
在jsp中定义:
userName = encodeURI(userName,"UTF-8");
userName = encodeURI(userName,"UTF-8");//将中文转换成二进制的格式
在Action类中定义:
//获取流程定义的key
String userName = elecUser.getUserName();
try {
userName = URLDecoder.decode(userName, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
方案三:
修改服务器(tomcat)的配置文件
Server.xml中的配置:
4:JXL报表(excel文件的导入)
(1)JXL报表整合项目
第一步:导入jar包:
第二步:导入java文件(完成封装),从文件中获取Excel的数据,读取excel的数据,写到集合中,将类放置到util包下。
第三步:导入jsp文件,实现文件上传,使用<s:file>
标签
指定导入模板,用户在导入模板上填写数据,从导入模板获取数据并读取数据,导入到数据库中。
第四步:在userIndex.jsp中定义:
<input style="font-size:12px; color:black; height=20;width=80" id="BT_Add" type="button" value="导入" name="BT_Add" onclick="openWindow('${pageContext.request.contextPath }/system/elecUserAction_importPage.do','700','400')">
第五步:在struts.xml中定义:跳转到导入excel的页面(文件上传)
<result name="importPage">/WEB-INF/page/system/userImport.jsp</result>
第六步:在Action类中定义:
/**
* @Name: importPage
* @Description: 跳转到导入excel报表的页面
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Create Date:
* @Parameters: 无
* @Return: String:跳转到system/userImport.jsp
*/
public String importPage(){
return "importPage";
}
/**
* @Name: importData
* @Description: 从excel中读取数据,将数据保存到数据库表中
* @Author: 刘洋(作者)
* @Version: V1.00 (版本号)
* @Create Date:
* @Parameters: 无
* @Return: String:跳转到system/userImport.jsp
*/
public String importData() throws Exception{
//获取上传的文件File
File formFile = elecUser.getFile();
GenerateSqlFromExcel fromExcel = new GenerateSqlFromExcel();
ArrayList<String[]> data = fromExcel.generateUserSql(formFile);
//定义一个错误的集合,String用来存放错误的信息
List<String> errorList = new ArrayList<String>();
//组织PO对象,完成保存
List<ElecUser> list = this.convertFromExcelToUser(data,errorList);
//说明存在了错误信息
if(errorList!=null && errorList.size()>0){
//将错误的信息在页面中显示
request.setAttribute("errorList", errorList);
}
//说明不存在错误信息
else{
//执行批量的保存
elecUserService.saveUserList(list);
}
return "importPage";
}
/**组织PO对象的集合,校验的方法*/
private List<ElecUser> convertFromExcelToUser(ArrayList<String[]> data,List<String> errorList) {
//定义返回的用户PO的集合
List<ElecUser> list = new ArrayList<ElecUser>();
if(data!=null && data.size()>0){
for(int i=0;i<data.size();i++){
//每一行的数据,格式:gj 123 郭靖 男 北京 北京中关村 是 1982-1-10 部门经理
String arrays [] = data.get(i);
//组织成对象,满足数据库保存字段的格式要正确
ElecUser elecUser = new ElecUser();
//登录名
if(StringUtils.isNotBlank(arrays[0])){
String message = elecUserService.checkUserByLogonName(arrays[0]);
if(message!=null && message.equals("3")){
elecUser.setLogonName(arrays[0]);
}
else{
errorList.add("第"+(i+2)+"行,第"+(0+1)+"列,登录名在数据库中出现重复!");
}
}
else{
errorList.add("第"+(i+2)+"行,第"+(0+1)+"列,登录名为空!");
}
//密码
//添加默认密码
if(StringUtils.isBlank(arrays[1])){
arrays[1] = "123";
}
if(StringUtils.isNotBlank(arrays[1])){
MD5keyBean md5keyBean = new MD5keyBean();
String md5LogonPwd = md5keyBean.getkeyBeanofStr(arrays[1]);
elecUser.setLogonPwd(md5LogonPwd);
}
//用户姓名
if(StringUtils.isNotBlank(arrays[2])){
elecUser.setUserName(arrays[2]);
}
//性别
if(StringUtils.isNotBlank(arrays[3])){
//数据字典转换
String ddlCode = elecSystemDDLService.findDdlCodeByKeywordAndDdlName("性别", arrays[3]);
if(StringUtils.isNotBlank(ddlCode)){
elecUser.setSexID(ddlCode);
}
else{
errorList.add("第"+(i+2)+"行,第"+(3+1)+"列,性别转换出现异常!");
}
}
else{
errorList.add("第"+(i+2)+"行,第"+(3+1)+"列,性别不能为空!");
}
//所属单位
if(StringUtils.isNotBlank(arrays[4])){
//数据字典转换
String ddlCode = elecSystemDDLService.findDdlCodeByKeywordAndDdlName("所属单位", arrays[4]);
if(StringUtils.isNotBlank(ddlCode)){
elecUser.setJctID(ddlCode);
}
else{
errorList.add("第"+(i+2)+"行,第"+(4+1)+"列,所属单位转换出现异常!");
}
}
else{
errorList.add("第"+(i+2)+"行,第"+(4+1)+"列,所属单位不能为空!");
}
//联系地址
if(StringUtils.isNotBlank(arrays[5])){
elecUser.setAddress(arrays[5]);
}
//是否在职
if(StringUtils.isNotBlank(arrays[6])){
//数据字典转换
String ddlCode = elecSystemDDLService.findDdlCodeByKeywordAndDdlName("是否在职", arrays[6]);
if(StringUtils.isNotBlank(ddlCode)){
elecUser.setIsDuty(ddlCode);
}
else{
errorList.add("第"+(i+2)+"行,第"+(6+1)+"列,是否在职转换出现异常!");
}
}
else{
errorList.add("第"+(i+2)+"行,第"+(6+1)+"列,是否在职不能为空!");
}
//出生时间
if(StringUtils.isNotBlank(arrays[7])){
Date birthday = DateUtils.stringToDate(arrays[7]);
elecUser.setBirthday(birthday);
}
//职位
if(StringUtils.isNotBlank(arrays[8])){
//数据字典转换
String ddlCode = elecSystemDDLService.findDdlCodeByKeywordAndDdlName("职位", arrays[8]);
if(StringUtils.isNotBlank(ddlCode)){
elecUser.setPostID(ddlCode);
}
else{
errorList.add("第"+(i+2)+"行,第"+(8+1)+"列,职位转换出现异常!");
}
}
else{
errorList.add("第"+(i+2)+"行,第"+(8+1)+"列,职位不能为空!");
}
list.add(elecUser);
}
}
return list;
}
第七步:在Service类中定义:
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
public void saveUserList(List<ElecUser> list) {
elecUserDao.saveObjectList(list);
}
第八步:在Dao类中定义:
/**批量保存对象集合*/
public void saveObjectList(List<T> list) {
this.getHibernateTemplate().saveOrUpdateAll(list);
}
(2)JXL报表的几个核心对象
(3)JXL报表(应对面试)
面试的时候,如果问到如何实现excel报表数据导入的?即导入流程:
(4)扩展:excel字段实现动态导入
分析:导入和未导入字段的设置
保存数据库的结果:(字段显示的是导入中文字段和导入英文字段)
即:按照导入的中文字段生成excel模板
操作步骤如下:
注意:JXL报表只支持office2003的操作,不支持office2007的操作,即只支持.xls格式的文件,不支持.xlsx类型的文件,那么此时可以使用POI报表完成导入。
导入的相关操作:大家可以参考【技术资料\poi报表\附加:使用poi报表完成excel文件的导入】中的《帮助.doc》
5:需要掌握的知识点总结
重点:分页+报表
了解:报表的导入和导出的设计思想、分页思想