Posted on 2010-12-13 10:46 
penngo 阅读(3894) 
评论(3)  编辑  收藏  所属分类: 
Java 
			 
			
		 
		因为之前有项目需要做大量报表,编写报表,花费大量时间,为了减少时间,所以研究下自定义报表实现方式。在很多报表工具,它们实现自定义报表的方式:基本都是数据集和数据显示格式这部分提取出来,实现自定义。本文也主要是数据集和数据显示格式两部分的自定义,选用技术:利用javascript定义数据集,jxl定义报表的格式。
在jdk6开始,java可以执行javascript脚本语言了,而jxl可以先定义好模板,再把数据集的内容填充模板中。本来考虑数据集的定义是做成类似sqlmap的xml配置,但是在测试时,发现灵活性欠缺。记起java可以执行javascript,如果使用javascript来定义数据集,这样就可以利用javascript的语法,数据集的定义更灵活,可配置性更高。
本文的测试代码,是用了上一篇的介绍spring mvc的例子http://www.blogjava.net/pengo/archive/2010/11/28/339229.html开发的,下面开始贴代码,以一个简单的学生成绩报表为例
测试的实体类:
学生类
 1 @Entity
@Entity
 2 @Table(name = "student")
@Table(name = "student")
 3
 public class Student implements Serializable
public class Student implements Serializable  {
{
 4 private static final long serialVersionUID = 1L;
    private static final long serialVersionUID = 1L;
 5 @Id
    @Id
 6 @Basic(optional = false)
    @Basic(optional = false)
 7 @GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 8 @Column(name = "id", nullable = false)
    @Column(name = "id", nullable = false)
 9 private Integer id;
    private Integer id;
10 @Column(name = "name")
    @Column(name = "name")
11 private String user;
    private String user;
12 @Column(name = "psw")
    @Column(name = "psw")
13 private String psw;
    private String psw;
14
 public Integer getId()
    public Integer getId()  {
{
15 return id;
        return id;
16 }
    }
17
 public void setId(Integer id)
    public void setId(Integer id)  {
{
18 this.id = id;
        this.id = id;
19 }
    }
20 
    
21
 public String getUser()
    public String getUser()  {
{
22 return user;
        return user;
23 }
    }
24
 public void setUser(String user)
    public void setUser(String user)  {
{
25 this.user = user;
        this.user = user;
26 }
    }
27
 public String getPsw()
    public String getPsw()  {
{
28 return psw;
        return psw;
29 }
    }
30
 public void setPsw(String psw)
    public void setPsw(String psw)  {
{
31 this.psw = psw;
        this.psw = psw;
32 }
    }
33 }
}
34
 
课程类
 1 @Entity
@Entity
 2 @Table(name = "course")
@Table(name = "course")
 3
 public class Course
public class Course  {
{
 4 @Id
    @Id
 5 @Basic(optional = false)
    @Basic(optional = false)
 6 @GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 7 @Column(name = "id", nullable = false)
    @Column(name = "id", nullable = false)
 8 private Integer id;
    private Integer id;
 9 @Column(name = "name")
    @Column(name = "name")
10 private String name;
    private String name;
11
 public Integer getId()
    public Integer getId()  {
{
12 return id;
        return id;
13 }
    }
14
 public void setId(Integer id)
    public void setId(Integer id)  {
{
15 this.id = id;
        this.id = id;
16 }
    }
17
 public String getName()
    public String getName()  {
{
18 return name;
        return name;
19 }
    }
20
 public void setName(String name)
    public void setName(String name)  {
{
21 this.name = name;
        this.name = name;
22 }
    }
23 }
} 
成绩类
 1 @Entity
@Entity
 2 @Table(name = "score")
@Table(name = "score")
 3
 public class Score
public class Score  {
{
 4 private static final long serialVersionUID = 1L;
    private static final long serialVersionUID = 1L;
 5 @Id
    @Id
 6 @Basic(optional = false)
    @Basic(optional = false)
 7 @GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 8 @Column(name = "id", nullable = false)
    @Column(name = "id", nullable = false)
 9 private Integer id;
    private Integer id;
10 @Column(name = "studentId")
    @Column(name = "studentId")
11 private Integer studentId;
    private Integer studentId;
12 @Column(name = "courseId")
    @Column(name = "courseId")
13 private Integer courseId;
    private Integer courseId;
14 @Column(name = "result")
    @Column(name = "result")
15 private Double result;
    private Double result;
16
 public Integer getId()
    public Integer getId()  {
{
17 return id;
        return id;
18 }
    }
19
 public void setId(Integer id)
    public void setId(Integer id)  {
{
20 this.id = id;
        this.id = id;
21 }
    }
22
 public Integer getStudentId()
    public Integer getStudentId()  {
{
23 return studentId;
        return studentId;
24 }
    }
25
 public void setStudentId(Integer studentId)
    public void setStudentId(Integer studentId)  {
{
26 this.studentId = studentId;
        this.studentId = studentId;
27 }
    }
28
 public Integer getCourseId()
    public Integer getCourseId()  {
{
29 return courseId;
        return courseId;
30 }
    }
31
 public void setCourseId(Integer courseId)
    public void setCourseId(Integer courseId)  {
{
32 this.courseId = courseId;
        this.courseId = courseId;
33 }
    }
34
 public Double getResult()
    public Double getResult()  {
{
35 return result;
        return result;
36 }
    }
37
 public void setResult(Double result)
    public void setResult(Double result)  {
{
38 this.result = result;
        this.result = result;
39 }
    }
40 }
} 
学生student类数据
id     psw     name
1     111     李明
2     111     张明
课程course类数据
id   name
1   数学
2   语文
3   英语
成绩score类数据
id  courseId  result  studentId
1      1             70          1
2      2             71          1
3      3             73          1
4     1              80          2
5     2              81           2
6     3              88          2
Viw只做了一个简单的jsp,页面只放了一个按钮,点击按钮时,生成一个excel文件,并返回给客户。
 1 report.jsp
report.jsp
 2 <%@ page language="java" contentType="text/html; charset=UTF-8"
<%@ page language="java" contentType="text/html; charset=UTF-8"
 3 pageEncoding="UTF-8"%>
    pageEncoding="UTF-8"%>
 4 <%@ include file="/include/head.jsp"%>
<%@ include file="/include/head.jsp"%>
 5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 6 <html>
<html>
 7 <head>
<head>
 8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 9 <title>Insert title here</title>
<title>Insert title here</title>
10 <script language="javascript" src="<%=request.getContextPath()%>/script/jquery.min.js"></script>
<script language="javascript" src="<%=request.getContextPath()%>/script/jquery.min.js"></script>
11 <script language="javascript">
<script language="javascript">
12
 function exportReport()
function exportReport() {
{
13 //通过连接参数js=studentScore,指定要生成报表的js配置文件
    //通过连接参数js=studentScore,指定要生成报表的js配置文件
14 window.location.href = "<%=request.getContextPath()%>/report.do?method=export&js=studentScore";
    window.location.href = "<%=request.getContextPath()%>/report.do?method=export&js=studentScore";
15 }
}
16 </script>
</script>
17 </head>
</head>
18 <body>
<body>
19 report eeeee<br/>
report eeeee<br/>
20 <c:out value="${name}"/>
<c:out value="${name}"/>
21 <input type="button" onclick="exportReport()" value="生成报表" />
<input type="button" onclick="exportReport()" value="生成报表" />
22 </body>
</body>
23 </html>
</html> 
Controller实现
 1 @Controller
@Controller
 2 @RequestMapping("/report.do")
@RequestMapping("/report.do")
 3
 public class ReportController
public class ReportController  {
{
 4 protected final transient Log log = LogFactory
    protected final transient Log log = LogFactory
 5 .getLog(ReportController.class);
            .getLog(ReportController.class);
 6 @Autowired
    @Autowired
 7 private ReportService reportService;
    private ReportService reportService;
 8
 9 @RequestMapping
    @RequestMapping
10
 public String load(ModelMap modelMap)
    public String load(ModelMap modelMap)  {
{
11 return "report";
        return "report";
12 }
    }
13
14 @RequestMapping(params = "method=export")
    @RequestMapping(params = "method=export")
15 public void export(HttpServletRequest request,
    public void export(HttpServletRequest request,
16
 HttpServletResponse response, ModelMap modelMap) throws Exception
            HttpServletResponse response, ModelMap modelMap) throws Exception  {
{
17 Map beans = new HashMap();
        Map beans = new HashMap();
18 String jsFile = request.getParameter("js");
        String jsFile = request.getParameter("js");
19 String path = request.getSession().getServletContext().getRealPath("")
        String path = request.getSession().getServletContext().getRealPath("")
20 + "/WEB-INF";
                + "/WEB-INF";
21 ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngineManager factory = new ScriptEngineManager();
22 ScriptEngine engine = factory.getEngineByName("JavaScript");
        ScriptEngine engine = factory.getEngineByName("JavaScript");
23 //加载js脚本
        //加载js脚本
24 InputStreamReader in = new InputStreamReader(new FileInputStream(path
        InputStreamReader in = new InputStreamReader(new FileInputStream(path
25 + "/config/" + jsFile + ".js"));
                + "/config/" + jsFile + ".js"));
26 engine.eval(in);
        engine.eval(in);
27 Invocable inv = (Invocable) engine;
        Invocable inv = (Invocable) engine;
28 String excel = engine.get("excel").toString();
        String excel = engine.get("excel").toString();
29 //获取js文件中配置的sql,取得数据集,并将数据集传给jxl
        //获取js文件中配置的sql,取得数据集,并将数据集传给jxl
30 Object reObj = inv.invokeFunction("init");
        Object reObj = inv.invokeFunction("init");
31 NativeArray myArray = (NativeArray) reObj;
        NativeArray myArray = (NativeArray) reObj;
32 Object[] array = new Object[(int) myArray.getLength()];
        Object[] array = new Object[(int) myArray.getLength()];
33
 for (Object o : myArray.getIds())
        for (Object o : myArray.getIds())  {
{
34 int index = (Integer) o;
            int index = (Integer) o;
35 array[index] = myArray.get(index, null);
            array[index] = myArray.get(index, null);
36 NativeObject aObj = (NativeObject) array[index];
            NativeObject aObj = (NativeObject) array[index];
37 String name = aObj.get("name", null).toString();
            String name = aObj.get("name", null).toString();
38 String method = aObj.get("method", null).toString();
            String method = aObj.get("method", null).toString();
39 String hql = inv.invokeFunction(method).toString();
            String hql = inv.invokeFunction(method).toString();
40 List list = reportService.getList(hql);
            List list = reportService.getList(hql);
41 beans.put(name, list);
            beans.put(name, list);
42 }
        }
43 Connection conn = reportService.getConnection();
        Connection conn = reportService.getConnection();
44 String templateFileName = path + excel;
        String templateFileName = path + excel;
45 ReportManager rm = new ReportManagerImpl(conn, beans);
        ReportManager rm = new ReportManagerImpl(conn, beans);
46 beans.put("rm", rm);
        beans.put("rm", rm);
47 InputStream is = new BufferedInputStream(new FileInputStream(
        InputStream is = new BufferedInputStream(new FileInputStream(
48 templateFileName));
                templateFileName));
49 //jxl根据数据集,生成excel报表
        //jxl根据数据集,生成excel报表
50 XLSTransformer transformer = new XLSTransformer();
        XLSTransformer transformer = new XLSTransformer();
51 Workbook resultWorkbook = transformer.transformXLS(is, beans);
        Workbook resultWorkbook = transformer.transformXLS(is, beans);
52 response.setHeader("Content-Transfer-Encoding", "base64");
        response.setHeader("Content-Transfer-Encoding", "base64");
53 response.setContentType("application/octet-stream");
        response.setContentType("application/octet-stream");
54 String contentDisposition = "attachment;filename=\"score.xls\"";
        String contentDisposition = "attachment;filename=\"score.xls\"";
55 response.setHeader("Content-Disposition", contentDisposition);
        response.setHeader("Content-Disposition", contentDisposition);
56 java.io.OutputStream outputStream = response.getOutputStream();
        java.io.OutputStream outputStream = response.getOutputStream();
57 resultWorkbook.write(outputStream);
        resultWorkbook.write(outputStream);
58 outputStream.flush();
        outputStream.flush();
59 outputStream.close();
        outputStream.close();
60 outputStream = null;
        outputStream = null;
61 resultWorkbook = null;
        resultWorkbook = null;
62 }
    }
63 }
} 
Service类实现
 1 @Service
@Service
 2
 public class ReportService
public class ReportService  {
{
 3 protected final transient Log log = LogFactory
    protected final transient Log log = LogFactory
 4 .getLog(ReportService.class);
    .getLog(ReportService.class);
 5 @Autowired
    @Autowired
 6 private EntityDao entityDao;
    private EntityDao entityDao;
 7 
    
 8 @Transactional
    @Transactional
 9
 public List getList(String hql)
    public List getList(String hql) {
{
10 StringBuffer sff = new StringBuffer();
        StringBuffer sff = new StringBuffer();
11 sff.append(hql);
        sff.append(hql);
12 return entityDao.createQuery(sff.toString());
        return entityDao.createQuery(sff.toString());
13 }
    }
14 
    
15
 public Connection getConnection()
    public Connection getConnection() {
{
16 return entityDao.getConnection();
        return entityDao.getConnection();
17 }
    }
18 }
} 
studentScore.js配置数据集的获取
 1 function HqlObject(name, method)
function HqlObject(name, method)
 2

 {
{
 3 this.name = name;
    this.name = name;
 4 this.method = method;
    this.method = method;
 5 this.state = 0;
    this.state = 0;
 6 }
}
 7 var excel = "/temple/studentscore.xls";
var excel = "/temple/studentscore.xls";
 8
 function init()
function init() {
{
 9 var hql1 = new HqlObject("students", "getStudents");
    var hql1 = new HqlObject("students", "getStudents");
10 var hql2 = new HqlObject("courses", "getCourses");
    var hql2 = new HqlObject("courses", "getCourses");
11 var myArray = new Array(2);
    var myArray = new Array(2);
12 myArray[0] = hql1;
    myArray[0] = hql1;
13 myArray[1] = hql2;
    myArray[1] = hql2;
14 return myArray;
    return myArray;
15 }
}
16
17
 function getStudents(parame)
function getStudents(parame) {
{
18 var sql = "select a from Student a where a.id = 1";
    var sql = "select a from Student a where a.id = 1";
19 return sql;
    return sql;
20 }
}
21
22
 function getCourses(parame)
function getCourses(parame) {
{
23 var sql = "select a from Course a";
    var sql = "select a from Course a";
24 return sql;
    return sql;
25 }
} 
jxl的excel模板
 
表达式内容:
学生 | <jx:forEach items="${courses}" var="c"> | ${c.name} | </jx:forEach>
<jx:forEach items="${students}" var="st">   
${st.user} | <jx:forEach items="${rm.exec('select * from score where studentId=' + st.id + ' order by courseId 
asc ')}" var="sc"> | ${sc.result} | </jx:forEach>
</jx:forEach>
下面看测试运行效果
 
 
如果有兴趣的,欢迎交流学习。
源码