在上一篇中了解了JXLS的工作原理后,这次来对上篇结尾的问题进行分析。
因为一个JXLS报表模板中的表达式往往对应一个或者多个JAVA对象数据(实例集合或者实例)比如${stus}和${grade}两个。
所以在接到新需求中,要创建新的report,这样不可避免的要创建新对应的JAVA Bean。那有没有一种方法可以动态的去创建JAVA类呢(所谓动态则是不需要物理存在的java类文件),我们可以配置一些类的属性在文件或数据库中,然后动态的去创建一个类,根据配置设置类的属性,以及设置好属性的值。
后来发现其实CGLIB这个类库(在很多开源框架中使用)已经实现了这些功能(BeanGenerator)。
下面代码是一个简单的封装
class="java" name="code">import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import net.sf.cglib.beans.BeanGenerator; import net.sf.cglib.beans.BeanMap; import net.sf.jxls.exception.ParsePropertyException; import net.sf.jxls.transformer.XLSTransformer; /** * The class which use to generate dynamic bean for jxls display. */ public class ReportJXLSGenerateBeanHelper { /** * Generate single DTO Bean. * @param properties properties list for a single DTO bean * @return DTO bean (Object type) */ public Object generateObject(final Map<String, Class<?>> properties) { BeanGenerator generator = new BeanGenerator(); Set<String> keySet = properties.keySet(); for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext();) { String key = (String) iterator.next(); generator.addProperty(key, (Class<?>) properties.get(key)); } return generator.create(); } /** * Getter value. * @param obj DTO Object * @param property property * @return property value */ public Object getValue(final Object obj, final String property) { BeanMap beanMap = BeanMap.create(obj); return beanMap.get(property); } /** * Setter value. * @param obj DTO Object * @param property property * @param rawValue property value * @throws Exception */ public void setValue(final Object obj, final String property, final Object rawValue){ Object value = rawValue; if (value == null) { value = ""; } BeanMap beanMap = BeanMap.create(obj); try { beanMap.put(property, value); } catch (ClassCastException e) { LogServices.app.info("ReportJXLSGenerateBeanHelper.setValue():" + e.getMessage()); } } /** * generate report. * @param templateFile report template * @param beans * @param outputPath * @throws IOException * @throws InvalidFormatException * @throws ParsePropertyException */ public void exportExcel(final String templateFile, final Map<String, Object> beans, final String outputPath) throws ParsePropertyException, InvalidFormatException, IOException { XLSTransformer transformer = new XLSTransformer(); LogServices.app.debug2("generate report begin" + Calendar.getInstance().getTime().toString()); transformer.transformXLS(templateFile, beans, outputPath); LogServices.app.debug2("generate report end" + Calendar.getInstance().getTime().toString()); } }
?这个帮助类中有4个方法:
1.?exportExcel 想必很熟悉,就是用来生成目标报表文件
2.?generateObject 这个就是自动生产一个Object,他的参数是一个Map类型,每一对KAY VALUE即是这个Object中的一个属性和类型,比如:
Map<String, Class<?>> fieldMap = new HashMap<String, Class<?>>(); fieldMap.put("vendorName", Class.forName("java.lang.String")); fieldMap.put("productName", Class.forName("java.lang.String"));
有个属性叫vendorname是String类型,另外一个是productName是个String类型(集合也是支持的,比如List)。
3. setValue 设置对象某个属性的值
4. getValue 取得对象某个属性的值
?接下来用这个方法可以达到获取一个对象集合的目的
/** * Return single DTO bean list. * @param fieldMap * @param resultList rs from the DB * @return dtoBeanList * @throws ClassCastException * @throws Exception */ public List<Object> getSingleDTOBeanList(Map<String, Class<?>> fieldMap, List<ListOrderedMap> resultList) throws ClassCastException, Exception { List<Object> dtoBeanList = new ArrayList<Object>(); for (Iterator<ListOrderedMap> iterator = resultList.iterator(); iterator.hasNext();) { ListOrderedMap listOrderedMap = iterator.next(); Object object = generateObject(fieldMap); Iterator<?> iter = fieldMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, Class<?>> entry = (Map.Entry<String, Class<?>>) iter.next(); Object key = entry.getKey(); setValue(object, key.toString(), listOrderedMap.get(key.toString().toUpperCase())); } dtoBeanList.add(object); } return dtoBeanList; }
?
OK 到了这里大家应该都明白了,剩下的工作就是怎么管理我们的配置,这里用到的是DB配置
RPT_JXLS_OID PROP_SEQ PROP_NAME DATA_TYPE 3702 1 vendorName String 3702 2 productName String这里值得注意的是PROP_NAME得和SQL中结果中的别名一样(忽略大小写)。
?
有了上面的基础,以后有新的需求只要配置这张表和新建相应XLS模板即可,不用物理创建对应的JAVA类了。
?
?
?
?
?
?
?