接着来
首先我们看看配置文件,web.xml:
这个没什么特别的,自动生成
然后是Struts2.xml:
其他几个action先不用管,就关注MainAction...
当我们输入http://localhost:8080/main的时候,action拦截到请求,会把我们带到layout.jsp页面,也就是我们的主页面
主页面是用Jquery.easyUI写的,非常简单干净:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>web 文件导入导出Demo</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="css/common.css" />
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/jquery-1.7.2.min.js"></script>
<link rel="stylesheet" type="text/css" href="../js/jquery-easyui-1.2.6/themes/default/easyui.css" />
<link rel="stylesheet" type="text/css" href="../js/jquery-easyui-1.2.6/themes/icon.css" />
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/jquery.easyui.min.js"></script>
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript">
$(function(){
$('a[title]').click(function(){
var src = $(this).attr('title');
var title = $(this).html();
//当前标签页是否存在,存在就选择,不存在就新加上去 from JqueryUI
if($('#tt').tabs('exists' ,title)){
$('#tt').tabs('select',title);
} else {
$('#tt').tabs('add',{
title:title,
content:'<iframe frameborder=0 style=width:100%;height:100% src='+ src +' ></iframe>',
closable:true
});
}
});
});
</script>
</head>
<body>
<div id="cc" class="easyui-layout" fit=true style="width:100%;height:100%;">
<div region="west" split="true" title="菜单" style="width:200px;">
<div id="aa" class="easyui-accordion" fit=true >
<div title="Excel导入导出" selected="true" style="overflow:auto;padding:10px;">
<a title="jsp/importList.jsp" >数据导入</a> <br/>
<a title="jsp/studentList.jsp" >学生信息</a>
</div>
</div>
</div>
<div region="center" title="主界面" style="padding:5px;">
<div id="tt" class="easyui-tabs" fit=true style="width:500px;height:250px;">
</div>
</div>
</div>
</body>
</html>
好了,到这儿我们的基本框架和主页面就搭建起来了。运行看看:
非常简洁的界面
接下来我们看看学生信息一项。当点击学生信息的时候,右边的效果是这样的:
要想达到这个效果,我们需要做些事情。
1.用Mysql或者别的都行,只要你喜欢,建立一个student的库,设置上图对应的6个字段
2.往你建的表中插入几条数据
3.建立一个Model类,关联你表的字段,提供get/set方法
4.建立StudentService类,实现对数据库的CRUD
5.建立StudentAction类,并在struts2.xml中配置
6.界面布局和分页用的是easyUI的API,简单易懂
好的,我们1个1个来,首先数据库建表部分就省略了。这个板块需要注意的就是可能从Mysql上查询出的数据有中文乱码;怎么解决自行百度。
插入测试数据省略....
model类省略....
struts的配置我在上边已经给大家展示了:
需要注意的是有一点:
这里用的name="student-*",struts2在我们平时用的时候,大家习惯直接用student?getList.action。这种方式,但是官方是不推荐这样的,最好还是用上图这种
studentList.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'importList.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="css/common.css" />
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/jquery-1.7.2.min.js"></script>
<link rel="stylesheet" type="text/css" href="../js/jquery-easyui-1.2.6/themes/default/easyui.css" />
<link rel="stylesheet" type="text/css" href="../js/jquery-easyui-1.2.6/themes/icon.css" />
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/jquery.easyui.min.js"></script>
<script type="text/javascript" src="../js/jquery-easyui-1.2.6/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="../js/commons.js"></script>
<script type="text/javascript">
$(function(){
/**
* 初始化数据表格
*/
$('#t_student').datagrid({
idField:'id' ,
title:'数据列表' ,
fit:true , //自动补全
height:450 ,
url:'student-list' , //访问地址
fitColumns:true ,
striped: true , //隔行变色特性
loadMsg: '数据正在加载,请耐心的等待...' ,
rownumbers:true ,
frozenColumns:[[ //冻结列特性 ,不要与fitColumns 特性一起使用
{
field:'ck' ,
width:50 ,
checkbox: true
}
]],
columns:[[ //每个列具体内容
{
field:'sid' ,
title:'Student id' ,
hidden:true
},{
field:'stunum' ,
title:'编号' ,
width:100 ,
sortable : true
},{
field:'stuname' ,
title:'姓名' ,
width:100 ,
sortable : true
},{
field:'stuage' ,
title:'年龄' ,
width:100
},{
field:'stusex' ,
title:'性别' ,
width:100
},{
field:'stubirthday' ,
title:'出生日期' ,
width:100
},{
field:'stuhobby' ,
title:'爱好' ,
width:100
}
]] ,
pagination: true , //显示分页
pageSize: 10 , //分页大小
pageList:[5,10,15,20,50], //每页个数
toolbar:[ //工具条
{
text:'导出excel',
iconCls:'icon-save',
handler:function(){ //回调函数
//获取后台传递参数 className methodName
var className = $('#t_student').datagrid('getData').className;
var methodName = $('#t_student').datagrid('getData').methodName;
//alert(JSON.stringify($('#t_student').datagrid('getData')))
//获取表头信息
var header = $('#t_student').datagrid('options').columns[0];
//alert(JSON.stringify($('#t_student').datagrid('options')));
var fields = "";
var titles = "";
for(var i = 0;i<header.length;i++){
var field = header[i].field;
var title = header[i].title;
var hiddenFlag = header[i].hidden;//sid默认为true 隐藏
if(!hiddenFlag){
var dh = i == (header.length -1) ? "" :",";
fields = fields + field + dh;
titles = titles + title + dh;
}
}
//向后台发送请求
var form = $("<form>");//定义一个form表单
form.attr('style','display:none');
form.attr('target','');
form.attr('method','post');
form.attr('action','student-export');
//添加input
var input1 = $("<input>");
input1.attr('type','hidden');
input1.attr('name','fields');
input1.attr('value',fields);
var input2 = $("<input>");
input2.attr('type','hidden');
input2.attr('name','titles');
input2.attr('value',titles);
var input3 = $("<input>");
input3.attr('type','hidden');
input3.attr('name','className');
input3.attr('value',className);
var input4 = $("<input>");
input4.attr('type','hidden');
input4.attr('name','methodName');
input4.attr('value',methodName);
//将表单放到body中
$('body').append(form);
form.append(input1);
form.append(input2);
form.append(input3);
form.append(input4);
form.submit();//提交表单
}
}
]
});
});
</script>
</head>
<body>
<div id="lay" class="easyui-layout" style="width: 100%;height:100%" >
<div region="center" >
<table id="t_student"></table>
</div>
</div>
</body>
</html>
service类:
package com.huangteng.demo.service;
import com.huangteng.demo.model.Student;
import com.huangteng.demo.utils.DB;
import org.apache.commons.lang3.StringUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class StudentService {
/**
* 分页查询学生信息
* @param currentPage
* @param pageSize
* @param sort
* @param order
* @return list
*/
public List<Student> list(int currentPage, int pageSize,String sort,String order){
Connection conn = DB.creatConn();
String sql = "select * from t_student where 1=1 ";
if(StringUtils.isNotBlank(sort)){
sql += "order by " + sort ;
}
if(StringUtils.isNotBlank(order)){
sql += " " + order ;
}
if(currentPage>0 && pageSize >0){
sql += " limit " + (currentPage-1)*pageSize +" , " + pageSize ;
}
PreparedStatement ps = DB.prepare(conn,sql);
List<Student> list1 = new ArrayList<Student>();
try {
ResultSet rs = ps.executeQuery();
Student s = null;
while (rs.next()){
s = new Student();
s.setSid(rs.getInt("sid"));
s.setStunum(rs.getString("stunum"));
s.setStuname(rs.getString("stuname"));
s.setStuage(rs.getString("stuage"));
s.setStusex(rs.getString("stusex"));
s.setStubirthday(rs.getString("stubirthday"));
s.setStuhobby(rs.getString("stuhobby"));
list1.add(s);
}
} catch (SQLException e) {
e.printStackTrace();
}
DB.close(conn);
DB.close(ps);
return list1;
}
//获取总数
public int getTotal(){
Connection conn = DB.creatConn();
int total = 0;
String sql = "select count(*) from t_student";
PreparedStatement ps = DB.prepare(conn,sql);
try {
ResultSet rs = ps.executeQuery();
while(rs.next()){
total = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
DB.close(ps);
DB.close(conn);
return total;
}
}
这里的DB是我写的一个工具类,就是获取Connection,然后用prepareStatement执行sql语句,最后提供关闭连接和流的close方法。
这里希望大家也自己动手写写工具类,并保存,以后在项目中直接引用就行,就不必再写了。
再看看Action:
package com.huangteng.demo.action;
import com.alibaba.fastjson.JSON;
import com.huangteng.demo.model.Student;
import com.huangteng.demo.service.StudentService;
import com.huangteng.demo.utils.ExportUtils;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.struts2.ServletActionContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
/**
* Created by ht on 2016/8/7.
*/
public class StudentAction extends ActionSupport{
private static final long serialVersionUID = 1L;
private StudentService studentService = new StudentService();
//分页
private int page;
private int rows;
private String sort;
private String order;
private String className;
private String methodName;
private String fields;
private String titles;
public String getTitles() {
return titles;
}
public void setTitles(String titles) {
this.titles = titles;
}
public String getFields() {
return fields;
}
public void setFields(String fields) {
this.fields = fields;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
public void list(){
//System.out.print("进入list方法中...");
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html;charset=utf-8");
int total = studentService.getTotal();
List<Student> slist = getStudents();
//System.out.println("JSON数组:"+ JSON.toJSONString(slist));
String json = "{\"total\":"+total+" , " +
"\"rows\":"+JSON.toJSONString(slist)+ "," +
"\"className\":\"" + StudentAction.class.getName() + "\"," +
"\"methodName\":\"getStudents\"}";
//System.out.println(json);
try {
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
}
public List<Student> getStudents(){
//System.out.print("进入getStudents....");
List<Student> slist = studentService.list(page,rows,sort,order);
return slist;
}
public void export(){
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=export.xls");
//创建Excel
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("sheet0");
/*
导出学生信息时需要再次从后台查询数据,利用反射实现
*/
try {
Class clazz = Class.forName(className); //加载类
Object obj = clazz.newInstance(); //创建对象
Method m = clazz.getDeclaredMethod(methodName); //获取方法
List list = (List) m.invoke(obj);
ExportUtils.outputHeaders(titles.split(","),sheet);//导出header
ExportUtils.outputColumns(fields.split(","),list,sheet,1);//导出内容
//获取输出流,写入数据
ServletOutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里细细谈谈我的总结:
在这个action中,业务逻辑很简单,就是调用service层的方法从数据库查询学生的信息,返回一个list<Student>的集合。然后通过response把数据反馈给前台,当然这个数据要
做一下处理,把list转成JSON数组,我本来考虑的是用JSONArray.fromObject();但是没成功而且效率低下,后来考虑用阿里巴巴温少开发的fastjson.这是一个开源项目,
通过序列化和反序列话实现,效率很高,而且轻量方便。这儿就不过多安利了,有兴趣的百度。
在struts2中后台获取前台传过来的数据有三种方法,我这里就是直接使用的,声明属性,提供get/set方法即可。
在studentAction中共有8个属性,前四个是实现分页的。 中间的两个是获取类名和方法名,然后用来实现反射,后两个是获取到每一列的字段名,然后用反射来获取值得。
Action中的ExportUtils是我封装的一个工具类,用于实现页面数据导出为Excel
ExportUtils:
package com.huangteng.demo.utils;
import org.apache.poi.hssf.record.chart.ObjectLinkRecord;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import java.lang.reflect.Method;
import java.util.List;
/**
* Created by ht on 2016/8/8.
* 导出为Excel文件的工具类
*/
public class ExportUtils {
//导出header
public static void outputHeaders(String[] headersInfo, HSSFSheet sheet){
HSSFRow row = sheet.createRow(0);
for(int i =0;i<headersInfo.length;i++){
sheet.setColumnWidth(i,4000);
row.createCell(i).setCellValue(headersInfo[i]);
}
}
//导出主体内容
public static void outputColumns(String[] headersInfo, List columnsInfo,HSSFSheet sheet,int rowIndex ){
HSSFRow row ;
int headerSize = headersInfo.length;
int columnSize = columnsInfo.size();
//循环导出数据
for (int i = 0; i < columnsInfo.size(); i++) {
row = sheet.createRow(rowIndex+i);
Object obj = columnsInfo.get(i);
//每一列
for (int j = 0; j < headersInfo.length; j++) {
Object value = getFieldValueByName(headersInfo[j],obj);
row.createCell(j).setCellValue(value.toString());
}
}
}
/**
* 利用反射,通过get/set方法来获取每一column对应的值
* @param fieldName
* @param obj
* @return
*/
private static Object getFieldValueByName(String fieldName, Object obj) {
String firstLetter = fieldName.substring(0,1).toUpperCase();
String getter = "get" +firstLetter + fieldName.substring(1);
try {
Method method = obj.getClass().getMethod(getter, new Class[]{});
Object value = method.invoke(obj, new Object[]{});
return value;
} catch (Exception e) {
e.printStackTrace();
System.out.println("反射异常");
return null;
}
}
}
当你完成这一步的时候,页面应该是这样了:
这时候你点及左上的导出Excel:
它应该是这样的:
1.下载成功
2.打开excel文件
ok
这一部分就结束了。后续是如何解析一个XML文件生成固定格式的Excel模板,可以下载上传。
//打游戏去了.....