几款前端开源flash报表比较
1. YUI(Ext)-chart
其实Ext的chart组件来自于YUI2的chart组件,不过就是Ext做了一点自己的封装罢了,从它们的官网的示例和API你就会看出他们出奇的相似,话说YUI的chart组件也是基于另外一个开源项目。
优点:纯JS配置,事件定义多,可以方便的与其它组件交互
缺点:图表种类少(没有AreaChart导致我只能放弃)、配置不方便
2. dv-charts
一款使用xml进行配置的的chart组件,适合于需求简单的项目
优点:简单易用、API很清晰
缺点:没有明确提供JS接口,中文支持不好
3. openflashchart2
据说是一个人开发的,采用json进行配置,如果你喜欢用服务器语言去配置还是很方便的,它也提供一些JS接口来实现修改样式以及加载数据
优点:动画效果做的不错、图标种类很齐全
缺点:API比较混乱、某些组件有bug(譬如无法设置areaCheat的tooltip来显示横轴坐标)
4. FusionCharts Free
这里说的不是FusionCharts v3,区别就是Free版本是开源的,而且许多功能受限制。Free版本提供了js(通过拼写xml字符串)和xml文件两种方式对chart进行配置
优点:种类齐全、容易配置、文档很详细
缺点:API(官方的包里面就一堆例子)、加载慢(数据量大的话)、动画效果很土
5. amChart
号称最强大的chart组件,官方甚至提供了在线配置工具,支持可见即所得的方式对图表进行配置并导出
优点:功能强大、API齐全、支持csv、xml数据格式、易于使用的js接口
缺点:免费用的话左上角有个广告
dwr实现Reverse Ajax推送技术的三种方式
DWR2.x的推技术也叫DWR Reverse Ajax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。
在DWR所开的线程中使用Reverse Ajax时,通过WebContextFactory.get()获取WebContext对象,进而获取脚本Session。
在DWR之外使用Reverse Ajax时,就要用到ServerContext,在Spring环境中要得到ServerContext,就需要用到Spring的ServletContextAware接口。
一、Reverse Ajax的实现有3种方式:
DWR的逆向Ajax主要包括两种模式:主动模式和被动模式。其中主动模式包括polling和comet两种,被动模式只有piggyback这一种。
1、piggyback方式
这是默认的方式。
如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。
只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。
2、comet方式
当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。
服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。
3、polling方式
由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。只不过用了dwr之后这部分工作由框架帮我们完成了。
二、使用DWR的推技术的步骤
1、在web.xml文件中增加以下配置信息
<servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <!-- DWR默认采用piggyback方式 --> <!-- 使用polling和comet的方式 --> <init-param> <param-name>pollAndCometEnabled</param-name> <param-value>true</param-value> </init-param> <!-- comet方式 --> <!-- <init-param> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> --> <!-- polling方式:在comet方式的基础之上,再配置以下参数 --> <!-- <init-param> <param-name>org.directwebremoting.extend.ServerLoadMonitor</param-name> <param-value>org.directwebremoting.impl.PollingServerLoadMonitor</param-value> </init-param> --> <!-- 毫秒数。页面默认的请求间隔时间是5秒 --> <!-- <init-param> <param-name>disconnectedTime</param-name> <param-value>60000</param-value> </init-param> --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
2、在dwr.xml中增加以下配置信息
<create creator="new" javascript="DWRHelper"> <param name="class" value="com.cjm.web.dwr.DWRHelper"/> <include method="addMessage"/> <include method="test"/> </create> <convert converter="bean" match="com.cjm.web.dwr.Message"> <param name="include" value="id,text"/> </convert>
3、pojo类Message的源码
public class Message {
private long id = System.currentTimeMillis();
private String text;
public Message(){
}
public Message(String newText){
text = newText;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
4、DWRHelper类源码
public class DWRHelper {
private static LinkedList<Message> messages = new LinkedList<Message>();
private static ReentrantLock lock = new ReentrantLock(); //JDK5锁
public void addMessage(String text){
try{
lock.lock();
if(text!=null && text.trim().length()>0){
messages.addFirst(new Message(text));
if(messages.size()>10){
messages.removeLast();
}
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
lock.unlock();
}
//获得DWR上下文
WebContext webContext = WebContextFactory.get();
//获取当前页面URL,比如/ext3/test_tag.jsp
String currentPage = webContext.getCurrentPage();
//当前脚本sessin
ScriptSession scriptSession = webContext.getScriptSession();
//设置页面控件的值
Util util = new Util(scriptSession);
util.setValue("text", ""); //这里是清空页面输入框的值
//设置脚本sessin的属性值
scriptSession.setAttribute("uid", "cjm");
//获取脚本session的属性值
for(Iterator it=scriptSession.getAttributeNames();it.hasNext();){
String attrName = (String)it.next();
System.out.println(attrName + "=" + scriptSession.getAttribute(attrName));
}
//获取所有浏览当前页面的脚本session
Collection<ScriptSession> sessions = webContext.getScriptSessionsByPage(currentPage);
Util utilAll = new Util(sessions);
//执行客户端脚本
ScriptBuffer script = new ScriptBuffer();
script.appendScript("clientFunction(")
.appendData(scriptSession.getAttribute("uid"))
.appendScript(");");
for(ScriptSession session: sessions){
session.addScript(script);
}
//更新这些脚本session的一些元素
utilAll.removeAllOptions("messages");
utilAll.addOptions("messages", messages, "id", "text");
}
}
5、JSP页面源码
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script type='text/javascript' src='/ext3/dwr/engine.js'></script>
<script type='text/javascript' src='/ext3/dwr/util.js'></script>
<script type='text/javascript' src='/ext3/dwr/interface/DWRHelper.js'></script>
</head>
<!-- 通过 dwr.engine.setActiveReverseAjax(true); 启动该页面的Reverse Ajax功能 -->
<body onload="dwr.engine.setActiveReverseAjax(true);sendMessage();">
<p>输入信息: <input id="text" onkeypress="dwr.util.onReturn(event, sendMessage)" />
<input type="button" value="Send" onclick="sendMessage()" /></p>
<script type="text/javascript">
function sendMessage() {
DWRHelper.addMessage(dwr.util.getValue("text"));
}
</script>
<hr/>
<select id="messages"></select>
</body>
</html>
Exception java.lang.OutOfMemoryError ...growableArray.cpp. Out of swap space
遇到这样的JVM Crash异常,好像不单纯是heap size不够:
Exception java.lang.OutOfMemoryError: requested 4096000 bytesfor GrET* in C:/BUILD_AREA/jdk1.5.0_09/hotspot\src\share\vm\utilities\growableArray.cpp. Out of swap space?
原来的内存参数是:-Xms1024m -Xmx1380m
修改为::-Xms1380m -Xmx1380m
居然可以了!
Weblogic集群HTTP会话复制失败故障诊断
快速链接 为什么发生此问题? 当您使用基于内存的存储方式时,所有会话信息都存储在内存中,并且当您停止和重新启动 WebLogic Server 时,这些信息将会丢失。 会话信息存储在指定的 PersistentStoreDir 中的一个文件中。 会话信息存储在数据库表中。 会话信息存储在 cookie 中。 会话数据从一个服务器实例复制到内存中的另一个实例。 当会话复制失败时如何诊断此问题? 上面的记录消息意味着 Primary 服务器是 MyServer-1,并且在 Myserver-2 上创建了一个 Secondary 服务器,而且您将看到在 MyServer-2 中记录了类似下面的确认消息。 如果您检查 JsessionId,其形式如下: JSESSIONID 是缺省的 cookie 名称,可以在 weblogic.xml 中将其更改为任何内容。 JSESSIONID 的格式为: Every time data is changed (either set/get or removed) in the session you'll see the logging message. 如果因为任何原因而导致会话复制失败,您将在 MyServer-1 日志中看到下面的消息。 上面的消息意味着会话复制已失败。 JSESSIONID 也会显示为如下形式: JSESSIONID=1E9Xwn7nLYfOsc1obgRZIwW5s72an7HPPvSD7iaWHMXzpHga5cQj!-1587343083!NONE Secondary 服务器散列信息将变为 NONE。 若要启用: 确保服务器的 stdOutSeverity 级别为 INFO,且 StdoutDebugEnabled 被设置为“true”。调试信息将被记录到服务器日志以及标准输出中。 验证 Weblogic.xml 条目: <session-descriptor> 会话数据必须可序列化 调试消息: 解决办法:找到从中抛出错误的页面,并确保输入会话中的所有数据是可序列化的。 检查网络/组播问题: 运行 utils.MulticastTest 实用程序 java utils.MulticastTest -n name -a address [-p portnumber] [-t timeout] [-s send] 验证群集配置: 若要验证,可执行下列命令: 这样将列出群集中的所有服务器。可以将 URL 改变为群集中的每个服务器,以确保他们拥有相同的条目。 应用程序代码诊断: 请不要使用 http 会话的 putValue 和removeValue 方法,因为它们不受支持,并且当您在应用程序中使用这些方法时,可能会出现会话数据复制问题。相反,请仅使用 HttpSession 的setAttribute/removeAttribute 方法。 Cookie 与 URL Rewriting : 通过设置 WebLogic-specific 部署描述符 weblogic.xml 中、<session-param> 元素下的 URLRewritingEnabled 属性,在 WebLogic Server 中启用 URL Rewriting。此属性的缺省值为 true。 考虑序列化系统开销 控制对会话数据的帧访问 例如,尽管在逻辑上客户端应当仅创建单个会话,但帧集中的多个帧可以代表客户端应用程序创建多个会话。 为了避免意外的应用程序行为,您应认真规划如何利用帧访问会话数据。可以应用下列其中一个一般规则来避免常见问题: 在会话中存储更大量的数据 在会话中存储小量的数据
问题描述
Http 会话状态没有从 Primary 服务器复制到 Secondary 服务器。下面是一些故障症状:
故障排除
请注意,并非下面所有任务都需要完成。有些问题仅通过执行几项任务就可以解决。
会话复制失败通常是因为组播/网络问题引起的。有时候,配置问题也会导致失败(请查看“验证 Weblogic.xml 条目”一节)。此外,请确保输入到会话中的数据必须是可序列化的,否则复制可能会失败。使用下列检查清单检查配置或可能导致会话复制失败的其它潜在问题。
有五种不同的会话持久性实现方式:
考虑一个群集中有两个服务器(MyServer-1,MyServer-2)的情况。当您启用调试标志后,如果从某个客户端发送了一个请求,您将会立即看到下面的消息(请参阅启用调试标志跟踪会话复制失败)
在 MyServer-1 上:
<Oct 9, 2003 12:38:21 PM PDT> <Debug> <Cluster> <000000> <Creating primary 5165892837402719733>
<Oct 9, 2003 12:38:21 PM PDT> <Debug> <Cluster> <000000> <Created secondary for 5165892837402719733 on -7957889153726652135S: 210.23.23.1: [9001,9001, -1, -1,9001, -1, -1]: mydomain: MyServer-2>
ExecuteThread: '1' for queue: 'Replication'> <kernel identity> <> <000000> <Creating secondary 5165892837402719733>
####<Oct 9, 2003 12:38:21 PM PDT> <Debug> <Cluster> <machine1-c840> <MyServer-2> <ExecuteThread: '1' for queue: 'Replication'> <kernel identity> <> <000000> <Updated local secondary of 5165892837402719733>
在 MyServer-1 上:
<Oct 9, 2003 12:38:21 PM PDT> <Debug> <Cluster> <000000> <Updated remote secondary for 5165892837402719733>
在 MyServer-2 上:
####<Oct 9, 2003 12:38:21 PM PDT> <Debug> <Cluster> <machine1-c840> <MyServer-2> <ExecuteThread: '1' for queue: 'Replication'> <kernel identity> <> <000000> <Updated local secondary of 5165892837402719733>
<Nov 6, 2003 12:59:12 PM EST> <Debug> <Cluster> <000000> <Unable to create secondary for -5165892837402719733>
<Nov 6, 2003 12:59:12 PM EST> <Debug> <Cluster> <000000> <Error creating secondary 5165892837402719733 on -7957889153726652135S: 210.23.23.1:[9001,9001,-1,-1,9001,-1,-1]:mydomain:MyServer-2>
您可以启用 DebugCluster、DebugClusterAnnouncements、DebugFailOver、DebugReplication、DebugReplicationDetails 标志。
例如,若要在 ServerDebug Mbean 的所有管理实例(即管理服务器或托管服务器)上启用 DebugCluster:
java weblogic.Admin -url t3://localhost:6151 -username system -password weblogic SET -type ServerDebug -property DebugCluster true
<ServerDebug DebugCluster="true" Name="myserver"/>
所使用的每个会话持久性类型的检查清单:
<ServerDebug ClassFinder="true" DebugCluster="true" DebugClusterAnnouncements="true" DebugFailOver="true" DebugReplication="true" DebugReplicationDetails="true" Name="MyServer1"/>
内存(单个服务器,不复制)
文件系统持久性
JDBC 持久性
基于 Cookie 的持久性
内存中复制
确保 weblogic.xml 含有需要为每个“会话复制”类型设置的所有参数。 例如,当使用内存中复制时,样本 weblogic.xml 将类似于如下形式:
<session-param>
<param-name>
PersistentStoreType
</param-name>
<param-value>
replicated
</param-value>
</session-param>
</session-descriptor>
为了支持 HTTP 会话状态的内存中复制,所有 servlet 和 JSP 会话数据都必须是可序列化的,否则会话复制将会失败。当启用了调试标志时,Weblogic Server 将在下面输出警告消息,指示会话仍未被复制。您必须使该对象变为可序列化的对象,这样才能复制它。其它对象的会话复制将会正常进行。
<Oct 8, 2003 2:10:45 PM PDT> <Error> <Cluster> <000126> <All session objects should be serializable to replicate. Please check the objects in your session. Failed to replicate non-serializable object>
确保网络是完好的,且没有组播问题。您可以执行组播测试来确保组播 IP 工作正常。
语法形式类似于:
从群集列表中选择 Primary 服务器和 Secondary 服务器。在一个由两个服务器组成的群集中,如果该群集没有包含所有服务器,则不能选择 Secondary 服务器,从而导致会话数据不能被复制。
java weblogic.Admin -username weblogic -password weblogic -url http://oneofthemanagedserverurlinthecluster:6151/ GET -type ClusterRuntime .pretty
确保仅在应用程序代码中使用 HttpSession 中的 setAttribute/removeAttribute 方法来更新 Http 会话。如果您使用其它设置方法来更改会话内的对象,WebLogic Server 将不复制这些更改。
在某些情况下,浏览器或无线设备可能不接受 cookie,这样会使利用 cookie 的会话跟踪不能进行。当 WebLogic Server 检测到浏览器不接受 cookie 时,URL Rewriting 是对这种情况的一个可自动替换的解决方法。
序列化会话数据会给复制会话状态带来一些系统开销。系统开销随序列化对象大小的增大而增加。如果您想在会话中创建很大的对象,请测试您的 servlet 的性能,以确保性能是可接受的。
如果您正在设计使用多帧的 Web 应用程序,请记住给定帧集中的帧无法执行任何请求同步。
JDBC 持久性和文件持久性的速度将不会更快,因为会话数据必须存储在外部资源中并从中检索,并且也会因为 JDBC 访问每个会话的更新信息而存在性能开销。如果您想在会话中存储大型对象,则应考虑 JDBC 或文件持久性。
当您不需要在会话中存储大量数据时,基于 cookie 的会话持久性是最有用的。基于 cookie 的会话持久性可以使 WebLogic Server 安装的管理更加容易,因为不需要群集 Failover 逻辑。
同一个Weblogic两个Domain CookieName冲突导致session失效问题
问题描述
集成项目HT实施过程中碰到这样的问题,本次集成是把两个不同的应用集成到同一个页面框架下,部署方式为:
同一个Server ServerName = Server01,同一个Weblogic,分别建立两个Domain,Domain01(port-7001)和Domain02(port-7002),将应用App1部署在Domain01,将应用App2部署在Domain02,同时启动这两个Domain,如果完全是默认配置,单独访问两个应用是没有问题的,但是在同一个客户端如果访问App1之后再访问APP2会发现App1的Session丢失。
问题分析
客户端在访问App1时,Domain01会在该客户端保留一个名为 JSessionID的Cookie,记录了Domain01的信息,JSessionID为Weblogic cookie-name的默认值,当同一个客户端访问App2时,该客户端Cookie中JSessionID的值被Domain02刷新,此时如果在之前已经打开的IE中继续访问App1会发现Session丢失(JSessionID已经被Domain02刷新!)。
解决方案
第一种方案
在App1和App2的weblogic.xml文件添加如下属性
<session-descriptor>
<session-param>
<param-name>CookieName</param-name>
<param-value>myCookie1</param-value>
</session-param>
</session-descriptor>
将 的值更改为不同于默认值就可以
如果不添加这个,那么客户端的COOKIE中保存的SESSION ID的对象名字是JSESSIONID,来自同一个SERVER上面的应用可能会造成这个SESSION ID的丢失,因为只要是WEBLOGIC产生的SESSION ID都是保存在这个名字的COOKIE中,这段配置就是把应用中的这个名字换成我们私有的,避免和其它域中的应用产生的JSESSIONID冲突。
第二种方案
访问App1时用IP来访问,访问App2时用域名来访问。
特别注意
如果应用程序部署为Cluster的模式,将无法设定,否则部署时发生错误。
Transaction rolled back because it has been marked as rollback-only
发生这种异常的case:
public void foo() {
try{
bar();
} catch (RuntimeException re) {
// caught but not throw further

}

}
@Transactional
public void bar() {

}
Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!
可以通过配置log4j来debug Spring事务获取情况:
To delve more into it I would turn up your log4j logging to debug and also look at what ExerciseModuleController is doing at line 91, e.g.: add a logger for org.springframework.transaction
Hibernate的createSQLQuery查询Char字段被截断问题
ORACLE数据库中,字段类型CHAR(8),值12345678
hibernate中用createSQLQuery方法查询,返回的list用object[]接收,遍历取值发现object[0]输出值是1,只有一位,其他的没了。其他字段正确。
---------------------------------------------
查看数据库,发现其他字段包括VARCHAR,DATE等类型均无问题,只有char类型的出问题。
char类型是定义长度的,8代表8个字节,节省空间并且效率要高,缺点是不灵活,长度是定死的,这里用来定义站号,固定8位长度。所以,该数据库这个字段类型能解决问题,但不是最好的办法,也没找到真正原因。
-----------------------------------------------
查到现在,有了一些眉目,小结如下:
1,oracle的char字段在hibernate里映射为character类型,是varchar的子集。
2,复杂SQL用createSQLQuery方法查询没问题,如果查询多个字段,遍历用object[]造型,下标从0开始输出值,不需要映射文件;如果愿意可以写一个映射bean,方便取用。
3,如果查询SQL中是只有一个字段,那就不能用object[]数组接收,只能用object类接收,直接输出object.toString(),即是这个字段的值。
4,可以用addScalar(String arg,Type type)方法定义要返回的字段类型,如
s.createSQLQuery(shuiQingHQL).addScalar("STCD",Hibernate.STRING).addScalar("STNM");
这样就解决了CHAR字段类型只出一位字符的问题。
但是需要把其他字段也addScalar()进来!
5,addScalar(String arg)里的参数是需要大写的!
