|
2008年11月28日
#
在同si chen的沟通中,他觉得pentaho是一个很不错的东东,如果把它同业务数据结合起来进行分析,可能会产生一些非常美妙的结果.于是有想好好了解一下pentaho的愿望.
本人的学习习惯一直的方针是:如果一个东东不能让我在30分钟内跑出它的demo,我暂时是不会去了解它的(窃以为这叫不够友好也不够成品化)
pentaho这点很争气,下载下来解压,双击"start-pentaho.bat" 文件就顺利的跑起来了. (不过究竟应该下载哪个文件让我头痛好久, 网上大多都是介绍1.x的安装,我睁大眼也没找到啥pre-install版本,犯迷糊的兄弟直接在 http://sourceforge.net/projects/pentaho/ 下载 Business Intelligence Server 吧)
接下来先看看它包含的内容 (http://www.pentaho.com/about/) :
依惯例开篇先吹水:
Pentaho是一个可以替代商业智能的开源方案.Pentaho Open BI套件提供全面的报表,OLAP分析,仪表板,数据集成,数据采集及商业智能平台,是世界领先而且广泛使用的开源商业智能套件.Pentaho商业开源业务模型减少了软件授权费用,提供支持,服务以及产品增强年度订阅.从Pentaho开创至今一直是开源商业智能的先锋,Pentaho产品已经被下载超过3百万次,产品应用于从小企业到全球2000强的企业中.
经验丰富的团队
由包括 Business Objects, Cognos, Hyperion, IBM, JBoss, Oracle, Red Hat, 及SAS协会等业界领导者供应商的退休人士创建
广泛的能力
报表 数据集成
分析 数据采集
仪表板 商业智能平台
高伸缩性
Pentaho是世界广泛部署的开源商业智能套件.可以提供给不同规模不同行业的企业使用.
Pentaho是在开源领域内首个且唯一的全面商业智能平台,全部来源于开源社区中.
Pentaho是唯一在开源商业智能套件领域内即是核心项目领导者也是赞助者的产品.其它整合非他们赞助或控制的第三方商业智能模块的商业智能套件,不能提供专业水准、服务承诺、或产品路线图。而Pentaho可以做到。
Pentaho商业开源业务模型减少软件授权费用,提供支持,服务以及通过年度订阅获得产品增强内容。
可伸缩的部署
完整,集成的商业智能平台
独立的,开箱即用的产品
为Java开发人员提供可嵌入的组件
高品质的专业服务
特制的支持提供
有经验的顾问及世界范围内的顾问合作者
一站式,公共,在线培训及专业认证项
提供使用Pentaho技术进行OEM服务
嗯,看着好象很不错的样子,以后每天看半小时!
本人译自 http://www.pentaho.com/about/ , 转载请注明出处!
2008年11月19日
#
摘要: 我们在制作单证或报表时,客户经常要我们把最后的合计数转写中文大写金额。这个需求很合理,但感觉并不容易实现,如何在JasperReport中加入大写金额的实现呢?提供一种实现的方法给大家参考。
实现思路:
在报表执行过程中使用scirptlet将存放着数字金额的变量读出转换成大写金额字符串后放入大写金额变量中。报表即可象显示普通字符变量一样显示大写金额。
TransChineseMon... 阅读全文
2008年11月18日
#
2008年11月17日
#
放一些屏幕截图来看图说话吧
流程设计界面
左边下拉框放至了我所有允许定义流程的业务对象类型,可通过底部的"新增"\"修改"\"删除"等操作进行维护.点击已定义的流程可以查看对应的流程设置
新增流程界面
新增时可为该流程设置相关启用条件,优先级别及审批步骤等
审批人的待办工作台,可以这里统一处理各类待办业务:
待办业务的查看界面:
审批流转界面(以通过为例)
2008年11月8日
#
下面给出UML图供大家参考:
其中:
流程类型、流程、活动、流转条件、外部应用为设计时对象,用于描述流程规则
流程实例、活动实例、活动记录为运行时对象,用于记录实际发生的流程运行状况
需要解决的问题是,如何将我们的应用与此工作流引擎进行结合?我的解决方法是:
1、流程类型约定业务对象类型(即此流程可以与哪种业务对象关联)
2、业务对象中的属性或其组合可以定义为流转条件(即实现业务对象信息影响工作流流转)
3、活动执行者可以选择业务系统的组织机构、角色、人员定义(我是通过接口方式进行约定,IOC注入)
4、活动可调用已定义的应用(可多个)
5、业务对象可以通过报批动作启动工作流实例,之后由工作流按照设计信息与业务信息进行自动流转或全程提供表单与审批按钮支持。
由于此工作流系统是出于简化的目的进行设计的,设计时与运行时信息我都使用数据库信息来表示,设计器也未提供拖拉界面来进行设计,而是采用顺序定义的方式来操作。在实际运作过程中,我觉得它可以满足一般规模不大(文职人员100人左右)的企业的OA应用。
本人原创文章,欢迎转载,转载请注明出处!
2008年11月4日
#
工作流引擎产品无论国内或国外都有不少成熟之作,开源的工作流产品也有诸如shark之类的精品。但工作流产品做为一个独立的中间件,无论是其本身或通过它进行流程设计及与你自己的系统整合,对很多使用过工作流产品的开发人员来说都是一件不容易的事。特别是在一些其实只是一些很简单的流程控制应用需要时,我们是否需要一个独立的工作流产品来运作呢?
也许你可以尝试自己做一个工作流组件?听起来好象有点儿难,但其实并不是一件很恐怖的工作。让我们先从通常会使用到工作流引擎的情景分析下我们需要什么?
情景:某公司需要对员工请假进行管理,员工请假需进行系统填写申请,如果请假天数<=1天,可以部门主管批准。如果请假天数>1天,需由部门主管->副总经理进行再行批复。批准后的请假自动记入考勤系统。
从这个简单的业务需求,我们进行分析它的需求:
1、工作流程的选择是由业务信息(请假单)相关联的,工作流独立存在是无意义的。
2、业务信息中的内容会决定流程的选择与流向。如:请假天数,或是主管的批复意见
3、工作流程的流转与组织结构、角色、员工相关。
4、工作流程通常会调用相关业务应用(记入考勤)来完成多应用系统之间的协作。
结合以上需求,我们定义出工作流系统所需功能与数据:
1、流程定义工具(负责生成工作流引擎能明白的流程控制信息),对应于XPDL
2、工作流控制变量定义(即用于控制流程流转的控制量,如请假天数与各级审批意见,可由系统根据流程实体信息自动注入至工作流引擎)
3、工作流相关数据,即与业务过程相关的数据,如:业务表单、组织结构、角色、员工等
4、工作流引擎,负责解释流程定义,创建过程实例并控制其执行,并可能提供相关的监控界面以保障工作流的正确运转。
5、外部应用,可由工作流引擎进行调用完成多个业务系统的流程衔接。这通常是工作流引擎的最大亮点。
未完待续>>
本人原创文章,欢迎转载,转载请注明出处!
2008年10月31日
#
* 如何在minilang中使用Java静态方法获得数据
使用beanshell脚本:
<set field="notApplied" value="${bsh:org.ofbiz.accounting.invoice.InvoiceWorker.getInvoiceNotApplied(invoice)}" type="Double"/>
警告:你必须使用type=""来转换你的结果类型,否则的话,它将返回字符串类型.
* 如何在minilang中调用Java程序
你可以在minilang中插入一段beanshell代码,类似于 applications/ecommerce/script/org/ofbiz/ecommerce/customer/CustomerEvents.xml的示例:
<call-bsh><![CDATA[
String password = (String) userLoginContext.get("currentPassword");
String confirmPassword = (String) userLoginContext.get("currentPasswordVerify");
String passwordHint = (String) userLoginContext.get("passwordHint");
org.ofbiz.securityext.login.LoginServices.checkNewPassword(newUserLogin, null, password, confirmPassword, passwordHint, error_list, true, locale);
]]></call-bsh>
在beanshell脚本中可以访问在minilang中所有的变量
* 清除 与 刷新的比较
<clear-field field-name="foo"/> 设置它为null. 这可以是一个类的属性或是集合中的一个值
<refresh-value value-name="foo"/> 从数据库中重新获得foo的值. foo必须是一个GenericValue.
* 如何设置一个布尔值
我无法找到任何例子,但是我这样做是成功的:
<set field="orderAvailableCtx.countNewReturnItems" value="true" type="Boolean"/>
我想minilang使用type=""中的类型与value中的值的做为构造调用.猜想在某天我看到这些代码时能证明我是对的...
本文档译自ofbiz 4.0 cookbooks,本人翻译,欢迎转载,请注明出处.
2008年10月27日
#
我的产品是被要求运行在多种常见数据库平台下(mysql/sqlserver/oracle)下,在开发中需要严格遵循相关的规范以确保能够实现跨数据库类型的要求.(相关的要点在我的"你的系统真的因为使用hibernate就可以适应各种数据库吗? "一文中已提及).在初始开发时有一个问题是比较困扰我的团队的,我们开发的时候必定是基于某个特定的数据库开发的(比如mysql),但在测试阶段是需要在不同的数据库平台下进行兼容性测试,由于开发过程中数据库结构与种子数据变化非常快,全部编写sql方式非常浪费时间,如何能找到一种高效的数据库相互迁移的工具,是我们当时所急需的解决方案.
其实也没啥选择,比较常用的数据库迁移工具就是Sqlserver自带的DTS,这玩意在sql server数据库间进行数据导入/导出时倒确实比较好用,在不同数据库类型进行操作时,就会出多多问题,如:类型转换需手工指定/导出字段有双引号...
所以最后的选择就是自己做一个DTS好啦,思路如下:
1、选择源数据库连接与目标数据库连接
2、根据源数据库遍历所有数据库对象(表),做为基准
3、删除目标数据库所有表外键及索引、删除所有种字数据(根据约定)数据、字段均允许null
4、遍历源数据库中所有表,为目标数据库修改结构(如增删字段,字段改类型、大小)
5、将源数据库中种子数据表数据拷贝至目标数据库中
6、根据源数据库为目标数据库中的表创建外键及索引、设置是否允许为null
7、搞掂!
完工后总代码量不过两千行(因为需考虑不同数据库的SQL Dialet,否则应该更少)
用户界面基于Eclipse RCP技术开发,使用JFace Wizard向导(如果不是想用向导的话,你可以用SWT来做)对话框获得源数据库与目标数据库的连接内容,并在用户点击完成按钮后,在进度条中提示用户执行情况.用了这个玩意以后,测试同事的数据库兼容性测试就再也不用来烦我们开发组啦!真是爽呀!当然很多喜欢折腾的客户(比如突然在哪里听说oracle是大型数据库,非让你帮他弄过去)此类朝三暮四也就自然不在话下啦!



本人原创文章,欢迎转载,转载请注明出处!
2008年10月26日
#
* 如何为SELECT SUM(QUANTITY - CANCEL_QUANTITY) AS QUANTITY之类的语句设置别名
<alias entity-alias="OI" name="quantity" function="sum">
<complex-alias operator="-">
<complex-alias-field entity-alias="OI" field="quantity" default-value="0"/>
<complex-alias-field entity-alias="OI" field="cancelQuantity" default-value="0"/>
</complex-alias>
</alias>
SELECT SUM(COALESCE(OI.QUANTITY,'0') - COALESCE(0I.CANCEL_QUANTITY)) AS QUANTITY在结果集包含默认值是一个好的习惯,否则如果有一项为null,那么最终相减的结果就也为null了.
操作符可以为任何你当前使用数据库所支持的SQL操作符,比如算术运算符+, -, * 和/ 或者字符串连接符 ||.
你可以增加function=""标签来完成在complex-alias-field中的min, max, sum, avg, count, count-distinct, upper 及lower集合运算. 示例, 以上的定义可以用另一种方法表示为:
<alias entity-alias="OI" name="quantity">
<complex-alias operator="-">
<complex-alias-field entity-alias="OI" field="quantity" default-value="0" function="sum"/>
<complex-alias-field entity-alias="OI" field="cancelQuantity" default-value="0" function="sum"/>
</complex-alias>
</alias>
即为SELECT (SUM(COALESCE(OI.QUANTITY,'0')) - SUM(COALESCE(OI.CANCEL_QUANTITY,'0'))) AS QUANTITY查询结果集
* 我讨厌OFBiz的实体引擎,我要自己的JDBC连接!
好的,以下是你获得JDBC连接的方法:
import org.ofbiz.entity.jdbc.ConnectionFactory;

String helperName = delegator.getGroupHelperName("org.ofbiz"); // gets the helper (localderby, localmysql, localpostgres, etc.) for your entity group org.ofbiz
Connection conn = ConnectionFactory.getConnection(helperName);
Statement statement = conn.createStatement();
statement.execute("SELECT * FROM PARTY");
ResultSet results = statement.getResultSet();

// 通过普通JDBC 的结果集来操作

//Alternatively, you can use the SQLProcessor like this:

SQLProcessor sqlproc = new SQLProcessor(helperName);
sqlproc.prepareStatement("SELECT * FROM PARTY");
ResultSet rs1 = sqlproc.executeQuery();

ResultSet rs2 = sqlproc.executeQuery("SELECT * FROM PRODUCT");

你可以查看framework/webtools/webapp/webtools/WEB-INF/actions/entity/EntitySQLProcessor.bsh了解它的使用
在以下网址你可以获得相关JavaDoc的内容:
http://www.opentaps.org/javadocs/version-1.0/framework/api/org/ofbiz/entity/jdbc/SQLProcessor.html
http://www.opentaps.org/javadocs/version-1.0/framework/api/org/ofbiz/entity/jdbc/ConnectionFactory.html
*** 请先考虑以下内容: 你放弃数据库的无关性意味着你在某些方法将无法与框架或其它程序集成.你确定你要这么做吗?
获得更好的做法,请访问 http://www.opentaps.org/docs/index.php/Using_the_Query_Tool
* 关于时间比较方法的一些警告
在你用 GREATER_THAN比较一个 Timestamp类型数据时, 你有可能获得相同的时间数据:
delegator.findByAnd("XXX", UtilMisc.toList(new EntityExpr("fromDate", EntityOperator.GREATER_THAN, "2007-12-31 23:59:59.998")));
有可能包含fromDate=2007-12-31 23:59:59.998的数据. (此种情况发生于PostgreSQL 8.1并且GenericDAO 类生成的SQL代码是'FROM_DATE > ' so 所以我也不明白发生这个问题的原因.) 所以确保安全的方法是, 增加1秒到需要比较的时间中然后使用 GREATER_THAN_EQUAL_TO方法
delegator.findByAnd("XXX", UtilMisc.toList(new EntityExpr("fromDate", EntityOperator.GREATER_THAN_EQUAL_TO, "2008-01-01 00:00:00.998")));
* 警告: 在空集合中使用EntityOperator.IN
请小心如果使用EntityOperator.IN去判断一个非空集合在一个空集合中的包含项,你有可能获得一个语法错误: 在Derby或者其它一些不为人知的数据库中可能会出错.
所以建议你能在使用EntityOperator.IN之间,通常执行UtilValidate.isNotEmpty方法来判断一下结果集是否为空
* 警告: delegator.getNextSubSeqId 不能确保唯一性
很多实体有很多合成的主键.示例OrderItem's 主键是orderId + orderItemSeqId. InventoryItemDetail's 主键是inventoryItemId +inventoryItemSeqId. 通常, delegator.getNextSubSeqId 通常是获得一个序列值,但是在多线程的访问下有可能无法确保生成的值的唯一性. 此段内容在 http://issues.apache.org/jira/browse/OFBIZ-1636 中有相关文档记录.
当前, 如果有可能多个线程尝试同时写入实体组合键时,可以使用delegator.getNextSeqId来替代getNextSubSeqId. (此问题不会发生于OrderItem, 因为它只使用单线程写入, 但有可能发生于 InventoryItemDetail, 它使用多线程来创建库存记录项.)
完>>
本文档译自ofbiz 4.0 cookbooks,本人翻译,欢迎转载,请注明出处.
2008年10月25日
#
* 我可以在entitymodel.xml文件中定义自己的view-entities吗?
不能, 你可以动态定义它们.你可以查看org.ofbiz.party.party.PartyServices中的findParty方法学习它的使用
* 如果为有效期间创建条件?
我们提供了一组非常有用的方法EntityUtil.getFilterByDateExpr ,它能返回一个EntityConditionList根据有效期间来筛选一个结果集.
* 如何在大数据结果集下工作
如果你检出一个大的数据结果集,你应当使用EntityListIterator通过迭代方式读取数据,而非List.
示例,如果你使用:
List products = delegator.findAll("Product");
你可能获得一个"java.lang.OutOfMemoryError". 这是由于你通过findAll, findByAnd, findByCondition等方法来获得一个大的内存数据结果集导致内存溢出. 在这种情况下, 应该使用EntityListIterator迭代方式来读取你的数据. 这个示例应改写成:
productsELI = delegator.findListIteratorByCondition("Product", new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), UtilMisc.toList("productId"), null);
注意获得EntityListIterator的方法只用通过条件, 所以你需要将你的条件重写为EntityExpr (在此次情况下,productId是主键字段不可能为空的, 所以将返回所有Proudct实例,)或 EntityConditionList.
此方法参数中包含检出的字段(这里为productId)以及排序字段(这里不需要,所以赋了null)
你可以传递一个null作为EntityCondition参数来获得所有结果.然后这不一定在所有数据库下都能正常工作! 在maxdb及其它不常用的数据库下时你要小心使用这些高级功能.
* 如何使用EntityListIterator
当我们通过EntityListIterator迭代访问数据时, 通常是这样:
 while ((nextProduct = productsELI.next()) != null) {
 .
// operations on nextProduct
}
在EntityListIterator 中使用 .hasNext()方法是一种不经济的做法.
在你完成你的操作后,要记得关闭此迭代
productsELI.close();
* 如何查询无重结果集
当前只能通过list iterator方法并指定EntityFindOptions参数,示例如下:
listIt = delegator.findListIteratorByCondition(entityName, findConditions,
null, // EntityConditions参数
fieldsToSelectList,
fieldsToOrderByList,
//关键部分. 第一个true表示"specifyTypeAndConcur"
// 第二个true指完是一个滤重查询. 显然在实体引擎中只能通过这个方法来进行滤重查询
new EntityFindOptions(true, EntityFindOptions.TYPE_SCROLL_INSENSITIVE, EntityFindOptions.CONCUR_READ_ONLY, true));
在minilang, 它会更简单:
<entity-condition entity-name="${entityName}" list-name="${resultList}" distinct="true">
<select field="${fieldName}"/>
.
* 如何进行一个大小写不敏感的查询(即不分大小写)
你需要查询条件表达式两边均转为大写,示例:
andExprs.add(new EntityExpr("lastName", true, EntityOperator.LIKE, "%"+lastName+"%", true));
(来源org.ofbiz.party.party.PartyServices)
* 如何将EntityListIterator转换成List
使用EntityListIterator.getCompleteList() 及getPartialList 方法
* 如何自动获得下一个ID值
在minilang 中使用 <sequence-id-to-env ...> 或在Java中通过delegator.getNextSeqId(...) 获得 . id序列存放于SequenceValueItem中.
* 关于ID值的一些警告
不要在种子/演示数据中使用10000做为数据的ID,当系统尝试自动创建数据时,它们都将尝试10000,这将导致一个键值冲突错误.
* 如何从一个明细项中获得序列ID
有些实体,比如拥有itemSeqId 的InvoiceItem(发票明细项) and OrderItem(订单明细项).此项通常在你处一次为item生成GenericValue 时自动生成ID,之后向delegator要求生成项目的seq Id:
GenericValue orderItem = delegator.makeValue("OrderItem", orderItemValues);
delegator.setNextSubSeqId(orderItem, "orderItemSeqId", ORDER_ITEM_PADDING, 1);
未完待续>>
本文档译自ofbiz 4.0 cookbooks,本人翻译,欢迎转载,请注明出处.
|