云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

[WARNING] POM for 'org.hibernate:jtidy:pom:r8-20060801:runtime' is invalid. It will be ignored for artifact resolution. Reason: Parse error reading PO
M. Reason: TEXT must be immediately followed by END_TAG and not START_TAG (position: START_TAG seen ...<licenses>\n\t\t\t<license>... @12:13)  for pro
ject org.hibernate:jtidy at F:\Document\Datafile\repository\org\hibernate\jtidy\r8-20060801\jtidy-r8-20060801.pom

把原来的maven的local repository里面org\hibernate\jtidy\r8-20060801\jtidy-r8-20060801.pom目录下的pom.xml文件中
 <licenses>
  <licenses>
   <license>
    <name>Java HTML Tidy License</name>
    <url>http://svn.sourceforge.net/viewvc/*checkout*/jtidy/trunk/jtidy/LICENSE.txt?revision=95</url>
    <distribution>repo</distribution>
   </license>
  </licenses>
 </licenses>

改为:
 <licenses>
   <license>
    <name>Java HTML Tidy License</name>
    <url>http://svn.sourceforge.net/viewvc/*checkout*/jtidy/trunk/jtidy/LICENSE.txt?revision=95</url>
    <distribution>repo</distribution>
   </license>
 </licenses>
也就是删除多余的<licenese>起止标签.

应该是central的repository里面的这个文件有问题。

posted @ 2008-12-01 20:13 云自无心水自闲 阅读(1002) | 评论 (0)编辑 收藏

在FreeMarker中可以使用Strust2的标签set调用Java类的方法来获取返回值
<@s.set name="val" value="@com.test.utils.Property@getInstance().get('Value')"/>

然后就可以使用以下的语句在FreeMarker中取得val的值
<#if (Request.appType)?default("") == "OK">
</#if>

posted @ 2008-11-21 07:59 云自无心水自闲 阅读(2563) | 评论 (2)编辑 收藏

使用方法:
var now = new Date();

now.format("m/dd/yy");
// Returns, e.g., 6/09/07

// Can also be used as a standalone function
dateFormat(now, "dddd, mmmm dS, yyyy, h:MM:ss TT");
// Saturday, June 9th, 2007, 5:46:21 PM

// You can use one of several named masks
now.format("isoDateTime");
// 2007-06-09T17:46:21

// ...Or add your own
dateFormat.masks.hammerTime = 'HH:MM! "Can\'t touch this!"';
now.format("hammerTime");
// 17:46! Can't touch this!

// When using the standalone dateFormat function,
// you can also provide the date as a string
dateFormat("Jun 9 2007", "fullDate");
// Saturday, June 9, 2007

// Note that if you don't include the mask argument,
// dateFormat.masks.default is used
now.format();
// Sat Jun 09 2007 17:46:21

// And if you don't include the date argument,
// the current date and time is used
dateFormat();
// Sat Jun 09 2007 17:46:22

// You can also skip the date argument (as long as your mask doesn't
// contain any numbers), in which case the current date/time is used
dateFormat("longTime");
// 5:46:22 PM EST

// And finally, you can convert local time to UTC time. Either pass in
// true as an additional argument (no argument skipping allowed in this case):
dateFormat(now, "longTime", true);
now.format("longTime", true);
// Both lines return, e.g., 10:46:21 PM UTC

// ...Or add the prefix "UTC:" to your mask.
now.format("UTC:h:MM:ss TT Z");
// 10:46:21 PM UTC


/*
 * Date Format 1.2.2
 * (c) 2007-2008 Steven Levithan <stevenlevithan.com>
 * MIT license
 * Includes enhancements by Scott Trenda <scott.trenda.net> and Kris Kowal <cixar.com/~kris.kowal/>
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 
*/
var dateFormat = function () {
    
var    token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
        timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
        timezoneClip = /[^-+\dA-Z]/g,
        pad = function (val, len) {
            val = String(val);
            len = len || 2;
            while (val.length < len) val = 
"0" + val;
            return val;
        };

    // Regexes and supporting functions are cached through closure
    return function (date, mask, utc) {
        var dF = dateFormat;

        // You can't provide utc if you skip other args (use the 
"UTC:" mask prefix)
        if (arguments.length == 1 && (typeof date == 
"string" || date instanceof String) && !/\d/.test(date)) {
            mask = date;
            date = undefined;
        }

        // Passing date through Date applies Date.parse, if necessary
        date = date ? new Date(date) : new Date();
        if (isNaN(date)) throw new SyntaxError(
"invalid date");

        mask = String(dF.masks[mask] || mask || dF.masks[
"default"]);

        // Allow setting the utc argument via the mask
        if (mask.slice(0, 4) == 
"UTC:") {
            mask = mask.slice(4);
            utc = true;
        }

        var    _ = utc ? 
"getUTC" : "get",
            d = date[_ + 
"Date"](),
            D = date[_ + 
"Day"](),
            m = date[_ + 
"Month"](),
            y = date[_ + 
"FullYear"](),
            H = date[_ + 
"Hours"](),
            M = date[_ + 
"Minutes"](),
            s = date[_ + 
"Seconds"](),
            L = date[_ + 
"Milliseconds"](),
            o = utc ? 0 : date.getTimezoneOffset(),
            flags = {
                d:    d,
                dd:   pad(d),
                ddd:  dF.i18n.dayNames[D],
                dddd: dF.i18n.dayNames[D + 7],
                m:    m + 1,
                mm:   pad(m + 1),
                mmm:  dF.i18n.monthNames[m],
                mmmm: dF.i18n.monthNames[m + 12],
                yy:   String(y).slice(2),
                yyyy: y,
                h:    H % 12 || 12,
                hh:   pad(H % 12 || 12),
                H:    H,
                HH:   pad(H),
                M:    M,
                MM:   pad(M),
                s:    s,
                ss:   pad(s),
                l:    pad(L, 3),
                L:    pad(L > 99 ? Math.round(L / 10) : L),
                t:    H < 12 ? 
"a"  : "p",
                tt:   H < 12 ? 
"am" : "pm",
                T:    H < 12 ? 
"A"  : "P",
                TT:   H < 12 ? 
"AM" : "PM",
                Z:    utc ? 
"UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
                o:    (o > 0 ? 
"-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
                S:    [
"th""st""nd""rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
            };

        return mask.replace(token, function ($0) {
            return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
        });
    };
}();

// Some common format strings
dateFormat.masks = {
    
"default":      "ddd mmm dd yyyy HH:MM:ss",
    shortDate:      
"m/d/yy",
    mediumDate:     
"mmm d, yyyy",
    longDate:       
"mmmm d, yyyy",
    fullDate:       
"dddd, mmmm d, yyyy",
    shortTime:      
"h:MM TT",
    mediumTime:     
"h:MM:ss TT",
    longTime:       
"h:MM:ss TT Z",
    isoDate:        
"yyyy-mm-dd",
    isoTime:        
"HH:MM:ss",
    isoDateTime:    
"yyyy-mm-dd'T'HH:MM:ss",
    isoUtcDateTime: 
"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// Internationalization strings
dateFormat.i18n = {
    dayNames: [
        
"Sun""Mon""Tue""Wed""Thu""Fri""Sat",
        
"Sunday""Monday""Tuesday""Wednesday""Thursday""Friday""Saturday"
    ],
    monthNames: [
        
"Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct""Nov""Dec",
        
"January""February""March""April""May""June""July""August""September""October""November""December"
    ]
};

// For convenience
Date.prototype.format = function (mask, utc) {
    return dateFormat(this, mask, utc);
};




补充说明:
Mask Description
d Day of the month as digits; no leading zero for single-digit days.
dd Day of the month as digits; leading zero for single-digit days.
ddd Day of the week as a three-letter abbreviation.
dddd Day of the week as its full name.
m Month as digits; no leading zero for single-digit months.
mm Month as digits; leading zero for single-digit months.
mmm Month as a three-letter abbreviation.
mmmm Month as its full name.
yy Year as last two digits; leading zero for years less than 10.
yyyy Year represented by four digits.
h Hours; no leading zero for single-digit hours (12-hour clock).
hh Hours; leading zero for single-digit hours (12-hour clock).
H Hours; no leading zero for single-digit hours (24-hour clock).
HH Hours; leading zero for single-digit hours (24-hour clock).
M Minutes; no leading zero for single-digit minutes.
Uppercase M unlike CF timeFormat's m to avoid conflict with months.
MM Minutes; leading zero for single-digit minutes.
Uppercase MM unlike CF timeFormat's mm to avoid conflict with months.
s Seconds; no leading zero for single-digit seconds.
ss Seconds; leading zero for single-digit seconds.
l or L Milliseconds. l gives 3 digits. L gives 2 digits.
t Lowercase, single-character time marker string: a or p.
No equivalent in CF.
tt Lowercase, two-character time marker string: am or pm.
No equivalent in CF.
T Uppercase, single-character time marker string: A or P.
Uppercase T unlike CF's t to allow for user-specified casing.
TT Uppercase, two-character time marker string: AM or PM.
Uppercase TT unlike CF's tt to allow for user-specified casing.
Z US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500
No equivalent in CF.
o GMT/UTC timezone offset, e.g. -0500 or +0230.
No equivalent in CF.
S The date's ordinal suffix (st, nd, rd, or th). Works well with d.
No equivalent in CF.
'…' or "…" Literal character sequence. Surrounding quotes are removed.
No equivalent in CF.
UTC: Must be the first four characters of the mask. Converts the date from local time to UTC/GMT/Zulu time before applying the mask. The "UTC:" prefix is removed.
No equivalent in CF.

And here are the named masks provided by default (you can easily change these or add your own):

Name Mask Example
default ddd mmm dd yyyy HH:MM:ss Sat Jun 09 2007 17:46:21
shortDate m/d/yy 6/9/07
mediumDate mmm d, yyyy Jun 9, 2007
longDate mmmm d, yyyy June 9, 2007
fullDate dddd, mmmm d, yyyy Saturday, June 9, 2007
shortTime h:MM TT 5:46 PM
mediumTime h:MM:ss TT 5:46:21 PM
longTime h:MM:ss TT Z 5:46:21 PM EST
isoDate yyyy-mm-dd 2007-06-09
isoTime HH:MM:ss 17:46:21
isoDateTime yyyy-mm-dd'T'HH:MM:ss 2007-06-09T17:46:21
isoUtcDateTime UTC:yyyy-mm-dd'T'HH:MM:ss'Z' 2007-06-09T22:46:21Z

A couple issues:

  • In the unlikely event that there is ambiguity in the meaning of your mask (e.g., m followed by mm, with no separating characters), put a pair of empty quotes between your metasequences. The quotes will be removed automatically.
  • If you need to include literal quotes in your mask, the following rules apply:
    • Unpaired quotes do not need special handling.
    • To include literal quotes inside masks which contain any other quote marks of the same type, you need to enclose them with the alternative quote type (i.e., double quotes for single quotes, and vice versa). E.g., date.format('h "o\'clock, y\'all!"') returns "6 o'clock, y'all". This can get a little hairy, perhaps, but I doubt people will really run into it that often. The previous example can also be written as date.format("h") + "o'clock, y'all!".

posted @ 2008-11-12 09:19 云自无心水自闲 阅读(1345) | 评论 (0)编辑 收藏

通过上两篇文章的研究,
详见:
我的struts2项目性能调优三步曲:http://www.blogjava.net/usherlight/archive/2008/07/01/211869.html
我的struts2项目性能调优三步曲(续):http://www.blogjava.net/usherlight/archive/2008/07/12/214462.html
得出的结论是:影响Struts2性能的原因在于Ognl的Value Stack的性能不佳。那么如果解决呢:


* 我首先尝试使用JSF。
一开始选择JSF的原因主要是:
1、Stuts2自己提供了JSF的Plugin
2、JSF是Sun作为标准提出,而且已经通过的。从Google的趋势搜索上也可以看出,搜索JSF的人在增多。
3、JSF作为一种以组件为基础的Web Framework有其独到之处,其内建的和其他许多开源的组件使用起来相当方便、强大。当然,对于不同的应用来说也有不利之处(后面会提到),但是如果能够坚持长期使用,逐渐积累组件库的话,JSF是一个很好的选择。
4、JSF的文档(或者说是书籍)还是比较多的。


经过测试使用后,发现其性能与Struts2相比确实提升不少。但是后来遇到了一个问题,所以最后还是放弃了JSF。这个问题是关于JSF的DataTable的,JSF提供的DataTable其实使用起来很方便,可定制化程度也不错,只是刚好缺少了我所希望的功能(也可能是我不知道如何实现)。我的应用中的DataTable是一个动态的结果集,也就是说输出的列是不能预先确定的,而DataTable却要求先声明好所有的DataColumn,我不知道如何解决这个问题。所以最后放弃了JSF。


* 我的第二个选择是FreeMarker
选择FreeMarker的原因是:
1、FreeMarker是Struts2缺少的模板引擎,Struts2的标签大部分是使用FreeMarker的,使用FreeMarker的话,连Plugin都省去了。
2、FreeMarker相对比较轻量级、因为他本身只是一个模板引擎,与JSF这样一个大而全的WebFramework相对,轻巧多了。
3、FreeMarker的学习起来非常容易,只要把他网站上的Document过一遍,基本上就OK了。
4、FreeMarker虽然体积小,功能还是相当强的,I18N,Converter之类的东西基本都全了,至少我所需要的功能全有。
5、FreeMarker相当灵活,他不象JSF把底层的东西封装了以后,暴露出一些属性可以设置,如果你需要的属性不能设置,你就没有办法了。在FreeMarker你直接操作最底层的东西,拥有很大的灵活性。当然,牺牲了一些方便性,比如,要用FreeMarker生成一个下拉框,就需要较多的工作量了。


测试之后,使用FreeMarker的性能很不错,在大数据量操作的情况下,至少一个数量级的性能提升。

主要原因是freeMarker的值直接从action中取得的,所以避开了ognl的stack value.


* 我的最终结论,如果要在Struts2中,展示或者操作大量数据,强烈推荐使用FreeMarker。


posted @ 2008-09-02 21:02 云自无心水自闲 阅读(5439) | 评论 (5)编辑 收藏

原文链接:http://www.theserverside.com/news/thread.tss?thread_id=50360

Jt2.7已经发布了,Jt是一个针对Java应用快速实现的面向模式的框架。Jt已经在数个重要的大型系统被采用。Jt实现了很多个被熟知的模式,包括:Dao,GoF的设计模式以及一些J2EE的模式。

Jt2.7的部分部件的功能得到了增强,而且增加了一个Jt自动化向导。Jt向导一个在Jt框架上建起来的应用,能够自动生成应用的框架结构。Jt向导能够在设计模式(包括Jt消息、DAO,MVC,GoF)的基础上自动生成应用模块。目前Jt向导实现了与MVC Struts和DAO Hibernate的集成。DAO的映射文件,Struts的配置文件,视图(JSPs),Java类都能够使用Jt向导来自动生成。
具体的功能包括:

* 实现了J2EE设计模式,包括J2EE business delegate,J2EE Session Facade,J2EE Service Locator和J2EE Value Object。

* 通过实现Web Service适配器和代理集成Web Service。Jt messaging API极大地简化了web service的开发和部署。

* 与business process modeling(BPM)的集成。Jt框架提供了一个jBPM的适配器。jBPM是一个BPM技术的开源实现。Jt应用现在可以使用流程图来模块化,这是一个非常好的模块化业务流程的方法。

* 与MVC设计模式和Ajax的集成。统一化的Jt模块和适配器提供了Jt框架API和上述两种技术间的透明接口。业务逻辑可以由Jt框架模块或BPM业务流程来实现。

* 与Hibernate的集成。Jt适配器提供了与Hibernate的透明接口。

* 与JDBC的集成

* 通过实现命令模式,支持Log,排队机制和操作的回退。

* 与JavaMail的集成

* 与EJB的集成。EJB客户端可以透明地存取远程框架对象。比EJB开发要简单的多。另外还实现了J2EE Service Locator模式。

* 方便的定制应用。主要通过配置文件完成:对象的属性可以从资源文件中加载。

* 与JSP的集成

* 通过XML适配器、助手、和内建的bean/XML映射与XML API的集成

Jt的在线文档: http://jt.dev.java.net/servlets/ProjectDocumentList

其他的一些信息可以在这里找到:http://jt.dev.java.net

posted @ 2008-08-20 19:47 云自无心水自闲 阅读(450) | 评论 (0)编辑 收藏

前一阵子使用了DHtmlx的Tree,视觉效果不错,功能也不弱。具体参见:http://dhtmlx.com
现在把Struts2结合DHtmlxTree的经验心得整理一下,发表出来:
一、Struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
  
<struts>

    <package name="demo" extends="struts-default">
        <action name="menu" method="execute" class="demo.TreeMenuAction">
                <result>/WEB-INF/menu.jsp</result>
        </action>
    </package>
</struts>


二、tree.jsp

<%@ taglib prefix="s" uri="/struts-tags"%>
<%
String 
path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path;
%
>
 
<html>
 
<head>
 
<title>Main Page</title>
 
<!-- 注意此处的路径需要根据各自具体情况修改 --> 
<link rel="STYLESHEET" type="text/css" href="styles/dhtmlxtree.css">
<script src="scripts/dhtmlxcommon.js"></script> 
<script src="scripts/dhtmlxtree.js"></script>
 
</head>
 
<body onload="loadTree(); " style="padding: 0; margin: 0; overflow: hidden; height: 100%;">
 
 
<script>
String.prototype._dhx_trim = function(){
    return this.replace(/
&nbsp;/g," ").replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g,"");
}
 
 
/* init tree */
 var tree;
  
function loadTree(){
    tree=new dhtmlXTreeObject("doctree_box","100%","100%",0);
    tree.setImagePath("images/");    
<!-- 注意此处的路径需要根据各自具体情况修改 --> 
    tree.setOnClickHandler(
        function(id){ openPathDocs(id); }
    );
    tree.loadXML("
<%=basePath%>/menu.do"); 
 }
 
/* open path funtion */

function openPathDocs(id){
    if (tree.getUserData(id, "thisurl") != null ){
        window.frames.sampleframe.location.href = "
<%=path%>/" + tree.getUserData(id, "thisurl") + ".do";
        return;
    }
}
 
function autoselectNode(){
    tree.selectItem(node,true);
    tree.openItem(node);

 
</script>
 
 
 
 
<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">
    
<tr>
        
<td valign="top" width="276">
            
<div id="doctree_box" style="width: 274px; height: 100%;"></div>
        
</td>
        
<td width="10" background="images/grid.gif">
            
&nbsp;
        
</td>
        
<td align="right"> 
            
<iframe id="sampleframe" name="sampleframe" width="100%" height="99%" frameborder="0" src="blank.html" style="border: 0px solid #cecece;"></iframe>
        
</td>
    
</tr>
</table>
 
 
</body>
</html>
 

上面的JavaScript基本上是从dhtmlx的例子中修改而来,理解起来并不复杂,只有
String.prototype._dhx_trim = function(){
 return this.replace(/&nbsp;/g," ").replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g,"");
}
这一段代码含义不明。


三、Action

package demo;
 
public class TreeMenuAction {
 
    
private String menuString;
 
    
public String execute() {
        StringBuffer buf 
= new StringBuffer();
        buf.append(
"<tree id=\"0\">");
        buf.append(
" <item text=\"Java\">");
        buf.append(
" <item text=\"Thinking in java\">");
        buf.append(
" <userdata name=\"thisurl\">java_tij.do</userdata>");
        buf.append(
" </item>");
        buf.append(
" <item text=\"Head first design pattern\">");
        buf.append(
" <userdata name=\"thisurl\">java_hfdp.do</userdata>");
        buf.append(
" </item>");
        buf.append(
" </item>");
        buf.append(
" <item text=\"Fiction\">");
        buf.append(
" <item text=\"Harry Porter\">");
        buf.append(
" <userdata name=\"thisurl\">fiction_hp.do</userdata>");
        buf.append(
" </item>");
        buf.append(
" <item text=\"Oliver Twist\">");
        buf.append(
" <userdata name=\"thisurl\">fiction_ot.do</userdata>");
        buf.append(
" </item>");
        buf.append(
" </item>");
        buf.append(
"</tree>");
         
        menuString 
= buf.toString();
         
        
return "success";
    }

     
     
    
public String getMenuString() {
        
return menuString;
    }

     
     
    
public void setMenuString(String menuString) {
        
this.menuString = menuString;
    }

}

 

 
四、menu.jsp
 

<%@ page contentType="text/xml;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<s:property value="menuXmlString" escape="false"/>


过程是这样的:首先在浏览器地址栏中输入:http://......./tree.jsp
展示tree.jsp,在load函数中调用menu.do

menu.do对应TreeMenuAction,返回menu.jsp,而menu.jsp只包含menuString的值,注意在menu.jsp中的escape="false"

posted @ 2008-08-07 20:16 云自无心水自闲 阅读(5617) | 评论 (6)编辑 收藏

最近,继续研究了Struts2性能的调优方法,总结了一下,得出新三步曲:

4. 使用FreeMarker的最新版本2.3.13,因为在版本2.3.11中,FreeMarker针对性能进行了改进,以下是FreeMarker2.3.11的release notes:
2.3.11
Date of release: 2007-12-04
This release contains several performance and usability improvements.

5. ognl2.7
所称ognl2.7相对于2.6在性能上有了“显著”的提升,于是下载了2.7以及2.7所需要的javassist-3.8.0.GA.jar

其实,经过上面2个步骤,我并没有发现应用的性能有显著的改善,可能我的页面中从ValueStack中的存取操作并不是特别多,也不是特别的复杂,所以,Ognl对我的影响并不明显。

6. 最后使用了JProfiler对Tomcat进行了监控,最后发现问题在自定义模板上,我将页面的自定义模板全部删除,果然页面的响应速度有了较大的提升。

 

posted @ 2008-07-12 18:57 云自无心水自闲 阅读(3631) | 评论 (3)编辑 收藏

前一段时间有反映说是一个使用了struts2的生产系统的页面显示速度太慢。登录后发现确实如此,于是进行了一番性能调优的研究和测试。
一,根据struts2官方的性能调优说明进行了一些参数的修改。
http://struts.apache.org/2.x/docs/performance-tuning.html
http://cwiki.apache.org/WW/performance-tuning.html

Turn off logging and devMode.(关闭logging和Devmode)
这个当然没问题,但是全部关闭logging不现实,我只是关闭了struts2相关package的logging

Do not use interceptors you do not need.
把struts.xml中不需要的interceptor统统删除

Use the correct HTTP headers (Cache-Control & Expires).
不确定应该如何修改

Copy the static content from the Struts 2 jar when using the Ajax theme (Dojo) or the Calendar tag.
关于这点,后面会提到

Create a freemarker.properties file in your WEB-INF/classes directory.
照做

Create the freemarker.properties file and add the following setting (or whatever value you deem fitting):
template_update_delay=60000
照做

Enable Freemarker template caching
As of Struts 2.0.10, setting the property struts.freemarker.templatesCache to true will enable the Struts internal caching of Freemarker templates. This property is set to false by default.
照做

进行上述修改后,发现页面打开的速度并没有明显的提高.

二,此时我已经基本锁定网页打开速度慢的原因与ajax(或者说是dojo)有关。因为dojo的js库大概有450K左右,先尝试使用gzip压缩javascript,减小传输量,看能否加快页面的加载速度
在Tomcat的server.xml的connector中添加如下配置,激活gzip功能
 compression="on"
 compressionMinSize="2048"
 noCompressionUserAgents="gozilla, traviata"
 compressableMimeType="text/html,text/xml,text/javascript,application/x-javascript,application/javascript"
进行上述修改后,发现页面打开的速度还是没有明显的提高.

三,经过上述两个实验,觉得应该是struts2所封闭的dojo的性能问题了。于是引入JQuery.
JQuery的js文件最小是55K, gzip后应该更小,页面的响应速度明显改善(一个数量级以上的提高),主要原因在于与服务器交互的处理上极大地提升了效率。而且页面处理代码更加简洁明了。

最后,我删除了所有的<s:head theme="ajax"/>和 <s:head/>(如果页面中加入<s:head />,那么在Struts2生成的html中后包含dojo.js),使用JQuery来完成所有的Ajax和javascript功能。

posted @ 2008-07-01 13:33 云自无心水自闲 阅读(6668) | 评论 (7)编辑 收藏

 

在利用网页展示查询结果,经常会遇到要求导出成Excel的需求。采用这种方法可以定制输出的格式和内容(还不支持合并单元格和公式),生成真正的Excel格式(不是csv)的Excel。
一、struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
  
<struts>

    <constant name="struts.i18n.encoding" value="UTF-8"/>

    <package name="demo" extends="struts-default">
        <action name="excel" method="execute" class="demo.ExcelAction">
                <result name="excel" type="stream">
                    <param name="contentType">application/vnd.ms-excel</param>    <!-- 注意这里的ContentType -->
                    <param name="inputName">excelStream</param>                   <!-- 这里需要和Action里的变量名一致 -->
                    <param name="contentDisposition">filename="standard.xls"</param>
                    <param name="bufferSize">1024</param>
                </result>
        </action>
    </package>
</struts>

二、Struts2的 Action

package demo;
public class ExcelAction {
    private InputStream excelStream; // 需要生成getter和setter

    public String execute() throws Exception {
        StringBuffer excelBuf = new StringBuffer();
        excelBuf.append("BookName").append("\t").append("Year").append("\t").append("author").append("\n");
        excelBuf.append("Thinking in Java").append("\t").append("2001").append("\t").append("Eckel").append("\n");
        excelBuf.append("Spring in action").append("\t").append("2005").append("\t").append("Rod").append("\n");
        String excelString = excelBuf.toString();
        logger.debug("result excel String: " + excelString);
        excelStream = new ByteArrayInputStream(excelString.getBytes(), 0, excelString.length());
        return "excel";
    }

    // getter and setter
    ...
}

三、Jsp页面

<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
  <s:head />
 </head>

 <body>

    <s:form action="" method="post">
       <s:submit key="button.submit"/>
    </s:form>
 </body>
</html>

posted @ 2008-06-23 20:14 云自无心水自闲 阅读(10759) | 评论 (15)编辑 收藏

iBatis自己带了一个simple的数据库连接池,基本的功能都有。但是在处理部分数据库(比如mysql)的连接空闲时间太长(mysql是8小时)自动超时的时候,就比不上象c3p0这样的连接池软件了(c3p0能自动处理数据库连接被关闭的情况)。
我目前采用的方法是iBatis本身提供的一种算得上是取巧的办法,基本思想就是每隔一段时间往数据库发一条查询语句,这样使得数据库空闲时间不会太长,而使得其自动关闭。
方法是在SqlMapConfig.xml的dataSource进行如下配置:
<dataSource type="SIMPLE">
    <property name="JDBC.Driver" value="${jdbc.driverClassName}"/>
    <property name="JDBC.ConnectionURL" value="${jdbc.url}"/>
    <property name="JDBC.Username" value="${jdbc.username}"/>
    <property name="JDBC.Password" value="${jdbc.password}"/>
    <property name="Pool.PingEnabled" value="true"/>
    <property name="Pool.PingQuery" value="select 1"/>
    <property name="Pool.PingConnectionsOlderThan" value="0"/>
    <property name="Pool.PingConnectionsNotUsedFor" value="3600000"/>
</dataSource>
开始的3行是关于数据库连接信息的,不需要说明了。
Pool.PingEnabled:是用于设置开启是否允许检测连接状态
Pool.PingQuery:是用于检测连接的查询语名,当然是越简单越好
Pool.PingConnectionOlderThan:对持续连接时间超过设定值(毫秒)的连接进行检测,我将其设置为0(不进行此项检测),否则,iBatis在超过这个时间后,执行每个sql以前检测连接,对于性能可能会有一定的影响。
Pool.PingConnectionsNotUsedFor:对空闲超过设定值(毫秒)的连接进行检测,我设置为1小时(mysql缺省的关闭时间是8小时)

当然,还有一个办法是使用c3p0这样的连接池
但是需要自己写一部分代码,实现以下接口:
public interface DataSourceFactory {
public void initialize(Map map);
public DataSource getDataSource();
}

posted @ 2008-05-13 11:08 云自无心水自闲 阅读(7480) | 评论 (1)编辑 收藏

仅列出标题
共29页: First 上一页 12 13 14 15 16 17 18 19 20 下一页 Last