176142998

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  116 Posts :: 0 Stories :: 45 Comments :: 0 Trackbacks

2008年6月16日 #

官网地址
http://www.oracle.com/technetwork/cn/middleware/ias/downloads/wls-main-091116-zhs.html


各个版本的都有,以下列举出来9.2的

Oracle WebLogic Server 9.2 MP3版本

http://download.oracle.com/otn/bea/weblogic/server923_win32.exe.zip

http://download.oracle.com/otn/bea/weblogic/server923_linux32.bin.zip

http://download.oracle.com/otn/bea/weblogic/server923_solaris32.bin.zip

 

Oracle WebLogic Server 9.2 MP4版本

 

http://download.oracle.com/otn/bea/weblogic/server924_win32.zip

 

http://download.oracle.com/otn/bea/weblogic/server924_linux32.zip

http://download.oracle.com/otn/bea/weblogic/server924_solaris32.zip

 

Oracle WebLogic Server 10.0 MP2 版本

http://download.oracle.com/otn/bea/weblogic/V16484-01.zip

posted @ 2012-04-12 09:54 飞飞 阅读(1002) | 评论 (0)编辑 收藏



linux-geum:/etc/init.d # more start_oracle.sh
#this script is used to start the oracle

su - oracle -c "/opt/oracle/product/10g/bin/dbstart"

su - oracle -c "/opt/oracle/product/10g/bin/lsnrctl start"


ln -s /etc/init.d/start_oracle.sh  /etc/rc.d/rc2.d/S16start_oracle
ln -s /etc/init.d/start_oracle.sh  /etc/rc.d/rc3.d/S16start_oracle
ln -s /etc/init.d/start_oracle.sh  /etc/rc.d/rc5.d/S16start_oracle

linux-geum:/etc/init.d # more stop_oracle.sh
#this script is used to stop the oracle

su - oracle -c "/opt/oracle/product/10g/bin/lsnrctl stop"

su - oracle -c "/opt/oracle/product/10g/bin/bin/dbshut"


ln -s /etc/init.d/stop_oracle.sh  /etc/rc.d/rc2.d/S16stop_oracle
ln -s /etc/init.d/stop_oracle.sh  /etc/rc.d/rc3.d/S16stop_oracle
ln -s /etc/init.d/stop_oracle.sh  /etc/rc.d/rc5.d/S16stop_oracle

posted @ 2012-04-06 17:35 飞飞 阅读(662) | 评论 (0)编辑 收藏

在/etc/init.d 下新建after.local或者编辑after.local文件,

文件内容
/usr/local/bin/memcached -d -m 512 -u root -l 192.168.1.106 -p 11211 -c 1024 -P /tmp/memcached.pid
posted @ 2012-04-06 17:33 飞飞 阅读(525) | 评论 (0)编辑 收藏

1、主要实现用户在进行某项操作时,多数据库的更新、插入和删除详细信息。记录操作时的请求信息。
2、在进入Controller时,生成一个事物ID,在这个Controller中进行的所有DAO操作都绑定该事物ID。并进行记录日志信息。


package com.centralsoft.filter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Pattern;

import net.sf.json.JSONObject;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.centralsoft.cache.CacheService;
import com.centralsoft.cache.annotations.Cache;
import com.centralsoft.cache.entity.MemCacheKey;
import com.centralsoft.entity.SysLogDetail;
import com.centralsoft.manager.pub.ThreadBean;
import com.centralsoft.manager.pub.ThreadId;
import com.centralsoft.pub.dao.SysLogDAO;
import com.centralsoft.webservice.pub.DateSHA;

/**
 * DAO层AOP拦截器,实现记录用户操作过的所有方法和参数,并实现DAO层缓存
 *
 * @author Administrator
 *
 */
@Aspect
@Component
public class AspectAutoDAOBean {

 @Autowired
 @Qualifier("CacheService")
 private CacheService memcache;

 @Autowired
 @Qualifier("SysLogDAO")
 private SysLogDAO SysLogDAO;

 @Around("execution(* com.centralsoft.*.dao.Zr*DAO.*(..))")
 public Object before(ProceedingJoinPoint joinPoint) throws Throwable {
  // 获取请求事务ID信息
  ThreadId threadId = new ThreadBean().getThreadId();
  // 调用方法名称
  String methodName = joinPoint.getSignature().getName();
  // 调用参数
  Object[] args = joinPoint.getArgs();
  Object object = null;

  // 数据库更新操作日志
  if (Pattern.matches("(save|insert|add|delete|remove|del|update)[\\S]*",
    methodName)) {
   if (threadId != null && threadId.getTransactionalId() != null) {
    // 获取执行请求事务ID
    String transactionalId = threadId.getTransactionalId();
    // 获取执行请求用户ID
    String userId = threadId.getUserId();
    SysLogDetail sysLogDetail = new SysLogDetail();
    sysLogDetail.setXh(transactionalId);
    sysLogDetail.setUserId(userId);
    sysLogDetail.setMethod(methodName);
    JSONObject msg = new JSONObject();
    // 处理参数
    for (Object temp : args) {
     // 获取参数类型,不同参数类型数据处理不一样
     Class<? extends Object> paramClazz = temp.getClass();
     String classType = paramClazz.getName();
     if (classType.equals("java.lang.String")) {
      msg.put("key", temp);
     } else if (classType.equals("java.util.HashMap")) {
      msg.putAll((HashMap<?, ?>) temp);
     } else if (classType.startsWith("com.")) {
      try {
       Field[] f = paramClazz.getDeclaredFields();
       for (Field field : f) {
        String fieldName = field.getName();
        field.setAccessible(true);
        msg.put(fieldName, field.get(temp));
       }
      } catch (SecurityException e) {
       e.printStackTrace();
      } catch (IllegalArgumentException e) {
       e.printStackTrace();
      }
     }
    }
    sysLogDetail.setMsg(msg.toString());
    // 记录DAO数据库操作日志
    SysLogDAO.insertSysLogDetail(sysLogDetail);
   }
   // 执行数据库操作
   object = joinPoint.proceed();

   // 数据库查询缓存
  } else if (Pattern.matches("(query|load|get|select|read)[\\S]*",
    methodName)) {
   // DAO层缓存注解
   MemCacheKey cacheKey = new MemCacheKey();
   // 获取cache注解属性
   Cache cache = null;
   // 获取请求方法
   Class<?> cls = joinPoint.getTarget().getClass();
   // 获取class中的所有方法
   Method[] methods = cls.getMethods();
   for (Method m : methods) {
    // 获取执行方法前的注解信息。
    if (m.getName().equals(methodName)) {
     cache = m.getAnnotation(Cache.class);
     break;
    }
   }

   if (cache != null) {
    // 获取memcacheKey,并进行MD5加密
    cacheKey = memcacheKey(cache, args);
    // 判断缓存服务器是否存在该可以值
    if (memcache.exist(cacheKey.getMemcacheKey())) {
     object = memcache.get(cacheKey.getMemcacheKey());
    } else {
     // 执行数据库操作
     object = joinPoint.proceed();
     // 将数据存放进缓存
     if (cacheKey.getMemcacheKey() != null) {
      memcache.put(cacheKey.getMemcacheKey(),
        object == null ? "" : object, new Date(cacheKey
          .getTime()));
     }
    }
   } else {
    // 执行数据库操作
    object = joinPoint.proceed();
   }
  } else {
   // 执行数据库操作
   object = joinPoint.proceed();
  }

  return object;

 }

 /**
  * 获取根据注解中的key获取memcache的含参数key值
  *
  * @param cache
  * @param parameterObject
  * @return
  * @author fei.zhao 2011-10-10
  */
 @SuppressWarnings("unchecked")
 private static MemCacheKey memcacheKey(Cache cache, Object[] args) {
  MemCacheKey tempKey = new MemCacheKey();
  String key = "";
  boolean flag = true;
  StringBuilder keyBuilder = new StringBuilder(32);
  // 获取注解中的key值
  String cacheKey = cache.key();
  Object[] cacheArgs = cacheKey.split("\\.");

  // 设置请求参数在args[]中的序号
  // key参数进行循环遍历
  for (Object s : cacheArgs) {
   // 判断是否是格式$,$...
   if (s.toString().startsWith("$")) {
    // 获取参数名称
    String type = s.toString().substring(1);
    // 获取参数值
    Object temp = args[0];
    // 获取参数类型,不同参数类型数据处理不一样
    Class<? extends Object> paramClazz = temp.getClass();
    String classType = paramClazz.getName();
    if (classType.equals("java.lang.String")) {
     keyBuilder.append(temp);
    } else if (classType.equals("java.util.HashMap")) {
     keyBuilder.append(((HashMap) temp).get(type));
    } else if (classType.startsWith("com.")) {
     try {
      Field f = paramClazz.getDeclaredField(type);// 实体中字段
      f.setAccessible(true);// 允许访问私有字段
      keyBuilder.append(f.get(temp));
     } catch (SecurityException e) {
      flag = false;
      e.printStackTrace();
     } catch (NoSuchFieldException e) {
      flag = false;
      e.printStackTrace();
     } catch (IllegalArgumentException e) {
      flag = false;
      e.printStackTrace();
     } catch (IllegalAccessException e) {
      flag = false;
      e.printStackTrace();
     }
    }
   } else {
    keyBuilder.append(s);
   }
   // 每个参数后面添加 “.”号分隔
   keyBuilder.append(".");
  }
  if (args.length == 3) {
   keyBuilder.append(args[1] + ".").append(args[2]);
  }
  if (flag == true) {
   key = keyBuilder.toString();
   tempKey.setMemcacheKey(DateSHA.shaEncrypt(key));
   tempKey.setTime(cache.time());
  }
  return tempKey;
 }
}

posted @ 2011-11-07 19:48 飞飞 阅读(7713) | 评论 (0)编辑 收藏

一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉及到COOKIE问题的处理。我们知道目前流行的***页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用java.net.HttpURLConnection来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的“顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!

我们不可能列举所有可能的顽固,我们会针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http服务器的访问绝非易事。

Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所形侍狻?/font>

1. 读取网页(HTTP/HTTPS)内容

下面是我们给出的一个简单的例子用来访问某个页面

/*

 * Created on 2003-12-14 by Liudong

 */

package http.demo;

 

import java.io.IOException;

 

import org.apache.commons.httpclient.*;

import org.apache.commons.httpclient.methods.*;

/**

 * 最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面

 * @author Liudong

 */

public class SimpleClient {

 

    public static void main(String[] args) throws IOException

    {

        HttpClient client = new HttpClient();   

        //设置代理服务器地址和端口    

        //client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);

        //使用GET方法,如果服务器需要通过HTTPS连接,那只需要将下面URL中的http换成https

        HttpMethod method = new GetMethod("http://java.sun.com");

        //使用POST方法

        //HttpMethod method = new PostMethod("http://java.sun.com");

        client.executeMethod(method);

        //打印服务器返回的状态

        System.out.println(method.getStatusLine());

        //打印返回的信息

        System.out.println(method.getResponseBodyAsString());

        //释放连接

        method.releaseConnection();

    }
}

 

在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请求的过程,非常的简单!


2. 以GET或者POST方式向网页提交参数

其实前面一个最简单的示例中我们已经介绍了如何使用GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:

 

/*

 * Created on 2003-12-7 by Liudong

 */

package http.demo;

 

import java.io.IOException;

 

import org.apache.commons.httpclient.*;

import org.apache.commons.httpclient.methods.*;

/**

 * 提交参数演示

 * 该程序连接到一个用于查询手机号码所属地的页面

 * 以便查询号码段1330227所在的省份以及城市

 * @author Liudong

 */

public class SimpleHttpClient {

 

    public static void main(String[] args) throws IOException

    {

        HttpClient client = new HttpClient();

        client.getHostConfiguration().setHost("www.imobile.com.cn", 80, "http");

 

        HttpMethod method = getPostMethod();//使用POST方式提交数据

        client.executeMethod(method);

       //打印服务器返回的状态

        System.out.println(method.getStatusLine());

        //打印结果页面

        String response =

           new String(method.getResponseBodyAsString().getBytes("8859_1"));

       //打印返回的信息

        System.out.println(response);

        method.releaseConnection();

    }

    /**

     * 使用GET方式提交数据

     * @return

     */

    private static HttpMethod getGetMethod(){

        return new GetMethod("/simcard.php?simcard=1330227");

    }

    /**

     * 使用POST方式提交数据

     * @return

     */

    private static HttpMethod getPostMethod(){

        PostMethod post = new PostMethod("/simcard.php");

        NameValuePair simcard = new NameValuePair("simcard","1330227");

        post.setRequestBody(new NameValuePair[] { simcard});

        return post;

    }

}

在上面的例子中页面http://www.imobile.com.cn/simcard.php需要一个参数是simcard,这个参数值为手机号码段,即手机号码的前七位,服务器会返回提交的手机号码对应的省份、城市以及其他详细信息。GET的提交方法只需要在URL后加入参数信息,而POST则需要通过NameValuePair类来设置参数名称和它所对应的值

3. 处理页面重定向

在JSP/Servlet编程中response.sendRedirect方法就是使用HTTP协议中的重定向机制。它与JSP中的<jsp:forward …>的区别在于后者是在服务器中实现页面的跳转,也就是说应用容器加载了所要跳转的页面的内容并返回给客户端;而前者是返回一个状态码,这些状态码的可能值见下表,然后客户端读取需要跳转到的页面的URL并重新加载新的页面。就是这样一个过程,所以我们编程的时候就要通过HttpMethod.getStatusCode()方法判断返回值是否为下表中的某个值来判断是否需要跳转。如果已经确认需要进行页面跳转了,那么可以通过读取HTTP头中的location属性来获取新的地址。

状态码
 对应HttpServletResponse的常量
 详细描述
 
301
 SC_MOVED_PERMANENTLY
 页面已经永久移到另外一个新地址
 
302
 SC_MOVED_TEMPORARILY
 页面暂时移动到另外一个新的地址
 
303
 SC_SEE_OTHER
 客户端请求的地址必须通过另外的URL来访问
 
307
 SC_TEMPORARY_REDIRECT
 同SC_MOVED_TEMPORARILY
 


下面的代码片段演示如何处理页面的重定向

client.executeMethod(post);

        System.out.println(post.getStatusLine().toString());

        post.releaseConnection();

       

        //检查是否重定向

        int statuscode = post.getStatusCode();

        if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) ||

            (statuscode == HttpStatus.SC_MOVED_PERMANENTLY) ||

            (statuscode == HttpStatus.SC_SEE_OTHER) ||

(statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {

//读取新的URL地址

            Header header = post.getResponseHeader("location");

            if (header != null) {

                String newuri = header.getValue();

                if ((newuri == null) || (newuri.equals("")))

                    newuri = "/";

                GetMethod redirect = new GetMethod(newuri);

                client.executeMethod(redirect);

                System.out.println("Redirect:"+ redirect.getStatusLine().toString());

                redirect.releaseConnection();

            } else

                System.out.println("Invalid redirect");

        }

我们可以自行编写两个JSP页面,其中一个页面用response.sendRedirect方法重定向到另外一个页面用来测试上面的例子。

4. 模拟输入用户名和口令进行登录

本小节应该说是HTTP客户端编程中最常碰见的问题,很多网站的内容都只是对注册用户可见的,这种情况下就必须要求使用正确的用户名和口令登录成功后,方可浏览到想要的页面。因为HTTP协议是无状态的,也就是连接的有效期只限于当前请求,请求内容结束后连接就关闭了。在这种情况下为了保存用户的登录信息必须使用到Cookie机制。以JSP/Servlet为例,当浏览器请求一个JSP或者是Servlet的页面时,应用服务器会返回一个参数,名为jsessionid(因不同应用服务器而异),值是一个较长的唯一字符串的Cookie,这个字符串值也就是当前访问该站点的会话标识。浏览器在每访问该站点的其他页面时候都要带上jsessionid这样的Cookie信息,应用服务器根据读取这个会话标识来获取对应的会话信息。

对于需要用户登录的网站,一般在用户登录成功后会将用户资料保存在服务器的会话中,这样当访问到其他的页面时候,应用服务器根据浏览器送上的Cookie中读取当前请求对应的会话标识以获得对应的会话信息,然后就可以判断用户资料是否存在于会话信息中,如果存在则允许访问页面,否则跳转到登录页面中要求用户输入帐号和口令进行登录。这就是一般使用JSP开发网站在处理用户登录的比较通用的方法。

这样一来,对于HTTP的客户端来讲,如果要访问一个受保护的页面时就必须模拟浏览器所做的工作,首先就是请求登录页面,然后读取Cookie值;再次请求登录页面并加入登录页所需的每个参数;最后就是请求最终所需的页面。当然在除第一次请求外其他的请求都需要附带上Cookie信息以便服务器能判断当前请求是否已经通过验证。说了这么多,可是如果你使用httpclient的话,你甚至连一行代码都无需增加,你只需要先传递登录信息执行登录过程,然后直接访问想要的页面,跟访问一个普通的页面没有任何区别,因为类HttpClient已经帮你做了所有该做的事情了,太棒了!下面的例子实现了这样一个访问的过程。


/*

 * Created on 2003-12-7 by Liudong

 */

package http.demo;

 

import org.apache.commons.httpclient.*;

import org.apache.commons.httpclient.cookie.*;

import org.apache.commons.httpclient.methods.*;

 

/**

 * 用来演示登录表单的示例

 * @author Liudong

 */

public class FormLoginDemo {

 

    static final String LOGON_SITE = "localhost";

    static final int    LOGON_PORT = 8080;

   

    public static void main(String[] args) throws Exception{

        HttpClient client = new HttpClient();

        client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT);

      

       //模拟登录页面login.jsp->main.jsp

        PostMethod post = new PostMethod("/main.jsp");

        NameValuePair name = new NameValuePair("name", "ld");    

        NameValuePair pass = new NameValuePair("password", "ld");    

        post.setRequestBody(new NameValuePair[]{name,pass});

       int status = client.executeMethod(post);

        System.out.println(post.getResponseBodyAsString());

        post.releaseConnection(); 

      

       //查看cookie信息

        CookieSpec cookiespec = CookiePolicy.getDefaultSpec();

        Cookie[] cookies = cookiespec.match(LOGON_SITE, LOGON_PORT, "/", false, client.getState().getCookies());

       if (cookies.length == 0) {

           System.out.println("None");   

       } else {

           for (int i = 0; i < cookies.length; i++) {

               System.out.println(cookies[i].toString());   

           }

       }

       //访问所需的页面main2.jsp

        GetMethod get = new GetMethod("/main2.jsp");

        client.executeMethod(get);

        System.out.println(get.getResponseBodyAsString());

        get.releaseConnection();

    }

}

5. 提交XML格式参数

提交XML格式的参数很简单,仅仅是一个提交时候的ContentType问题,下面的例子演示从文件文件中读取XML信息并提交给服务器的过程,该过程可以用来测试Web服务。

import java.io.File;

import java.io.FileInputStream;

 

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.methods.EntityEnclosingMethod;

import org.apache.commons.httpclient.methods.PostMethod;

 

/**

 * 用来演示提交XML格式数据的例子

 */

public class PostXMLClient {

 

    public static void main(String[] args) throws Exception {

        File input = new File(“test.xml”);

        PostMethod post = new PostMethod(“http://localhost:8080/httpclient/xml.jsp”);

        // 设置请求的内容直接从文件中读取

        post.setRequestBody(new FileInputStream(input));

       

        if (input.length() < Integer.MAX_VALUE)

            post.setRequestContentLength(input.length());

        else            post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED);

       

        // 指定请求内容的类型

        post.setRequestHeader("Content-type", "text/xml; charset=GBK");

       

        HttpClient httpclient = new HttpClient();

        int result = httpclient.executeMethod(post);

        System.out.println("Response status code: " + result);

        System.out.println("Response body: ");

        System.out.println(post.getResponseBodyAsString());

        post.releaseConnection();

    }

}

6. 通过HTTP上传文件

httpclient使用了单独的一个HttpMethod子类来处理文件的上传,这个类就是MultipartPostMethod,该类已经封装了文件上传的细节,我们要做的仅仅是告诉它我们要上传文件的全路径即可,下面的代码片段演示如何使用这个类。

MultipartPostMethod filePost = new MultipartPostMethod(targetURL);

filePost.addParameter("fileName", targetFilePath);

HttpClient client = new HttpClient();

//由于要上传的文件可能比较大,因此在此设置最大的连接超时时间

client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

int status = client.executeMethod(filePost);


上面代码中,targetFilePath即为要上传的文件所在的路径。

7. 访问启用认证的页面

我们经常会碰到这样的页面,当访问它的时候会弹出一个浏览器的对话框要求输入用户名和密码后方可,这种用户认证的方式不同于我们在前面介绍的基于表单的用户身份验证。这是HTTP的认证策略,httpclient支持三种认证方式包括:基本、摘要以及NTLM认证。其中基本认证最简单、通用但也最不安全;摘要认证是在HTTP 1.1中加入的认证方式,而NTLM则是微软公司定义的而不是通用的规范,最新版本的NTLM是比摘要认证还要安全的一种方式。

下面例子是从httpclient的CVS服务器中下载的,它简单演示如何访问一个认证保护的页面:


import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.UsernamePasswordCredentials;

import org.apache.commons.httpclient.methods.GetMethod;

 

public class BasicAuthenticationExample {

    public BasicAuthenticationExample() {

    }

    public static void main(String[] args) throws Exception {

        HttpClient client = new HttpClient();

        client.getState().setCredentials(

            "www.verisign.com",

            "realm",

            new UsernamePasswordCredentials("username", "password")

        );

        GetMethod get = new GetMethod("https://www.verisign.com/products/index.html");

        get.setDoAuthentication( true );

        int status = client.executeMethod( get );

        System.out.println(status+""+ get.getResponseBodyAsString());

        get.releaseConnection();

    }

}

8. 多线程模式下使用httpclient

多线程同时访问httpclient,例如同时从一个站点上下载多个文件。对于同一个HttpConnection同一个时间只能有一个线程访问,为了保证多线程工作环境下不产生冲突,httpclient使用了一个多线程连接管理器的类:MultiThreadedHttpConnectionManager,要使用这个类很简单,只需要在构造HttpClient实例的时候传入即可,代码如下:

MultiThreadedHttpConnectionManager connectionManager =

   new MultiThreadedHttpConnectionManager();

HttpClient client = new HttpClient(connectionManager);

以后尽管访问client实例即可。

posted @ 2011-04-22 12:38 飞飞 阅读(497) | 评论 (0)编辑 收藏


import org.apache.commons.httpclient.methods.PostMethod;


public class UTF8PostMethod extends PostMethod
{
   
    public static final String ENCODE_UTF8 = "UTF-8";
   
    /**
     * 默认构造函数
     * @param url    地址
     */
    public UTF8PostMethod(String url)
    {
        super(url);
    }

    /* (non-Javadoc)
     * @see org.apache.commons.httpclient.methods.EntityEnclosingMethod#getRequestCharSet()
     */
    @Override
    public String getRequestCharSet()
    {
        return ENCODE_UTF8;
    }

    /* (non-Javadoc)
     * @see org.apache.commons.httpclient.HttpMethodBase#getResponseCharSet()
     */
    @Override
    public String getResponseCharSet()
    {
        return ENCODE_UTF8;
    }
}


package com.org.softwore;

import org.apache.commons.httpclient.methods.GetMethod;

public class UTF8GetMethod extends GetMethod {
 public static final String ENCODE_UTF8 = "UTF-8";

 /**
  * 默认构造函数
  *
  * @param url
  *            地址
  */
 public UTF8GetMethod(String url) {
  super(url);
 }

 /*
  * (non-Javadoc)
  *
  * @see
  * org.apache.commons.httpclient.methods.EntityEnclosingMethod#getRequestCharSet
  * ()
  */
 @Override
 public String getRequestCharSet() {
  return ENCODE_UTF8;
 }

 /*
  * (non-Javadoc)
  *
  * @see org.apache.commons.httpclient.HttpMethodBase#getResponseCharSet()
  */
 @Override
 public String getResponseCharSet() {
  return ENCODE_UTF8;
 }
}




测试使用!

HttpMethod method = null;
        try {
            HttpClient client = new HttpClient();
            method = new UTF8PostMethod(
                    "http://.........");
            client.executeMethod(method);
            if (method.getStatusCode() == HttpStatus.SC_OK) {
                String response = method.getResponseBodyAsString();
                System.out.println(response);
            }

        } catch (HttpException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            if (method != null) {
                method.releaseConnection();
            }
        }

posted @ 2011-04-22 11:00 飞飞 阅读(1042) | 评论 (0)编辑 收藏

 

鼎鼎大名的Spring框架3.0版在12月5日由其作者之一——Juergen Hoeller先生在博客里宣告问世,并命为里程碑版,给Spring粉丝们带来了震撼的快感。笔者即开“快车”拉了两个包回来,遗憾的是参考文档至今还没有出来(仅有API文档),这为学习Spring 3.0带来了非常大的困难,但没有阻挡笔者对新产品的兴趣。

    Spring之父Rod Johnson先生早在2003年就预言EJB将死(观点颇具争议),攻击EJB之臃肿是在虐待程序员。然而EJB 3.0出来后几乎宣判Spring死刑,但自2.0版以后Spring火爆程度已经超过EJB,两者的争斗至今仍不停息,这也是Spring 3.0连文档还没有整理出来就匆匆推出的原因。当然,Spring与EJB有很多各自独特优势之处,例如EJB的分布式运算、标准规范,Spring的IoC、AOP切面编程、偶合集成、MVC等等,取各自之长在企业中应用如虎添翼。Spring目前已经加入了J2EE规范,J2EE世界将更加精彩......

    或许是用腻了Struts1那死板的WEB框架,才对Spring MVC爱不释手,尤其是2.5版本以后,支持全注解配置方式,已经使很久没有再写过xml文件了。

    3.0版是完全兼容2.5,因此了解2.5版的@MVC则更容易接受。正如Arjen Poutsma小伙子在他的博客里说的那样,3.0时代将集中致力于表述性状态转移(REST,希望我没有翻译错,金山词霸翻译为“休息”)的网络服务和更容易的网络编程。的确增加了更多的控制器类型,并增强了SOAP/WSDL/WS这些基于分布式体系结构。

先回忆下2.5注解方式的@MVC,来一个示例:

@Controller
public class ArticleController{

  @RequestMapping("/articleView")
   public String getArticle(@RequestParam("id") String id, HttpServletRequest request){
    request.setAttribute("article", service.find(Article.class, id));
    return "articleView";
   }

}

    ArticleController没有实现任何接口,是一个最普通不过的pojo,如果浏览器来了articleView.do?id=xxx这个请求,Spring会找到getArticle()这个方法,该方法第一个参数绑定到了URL上的请求参数,第二个是J2EE标准的request对象(可见Spring MVC是非侵入式的,不像变态的Struts2),事实上还可以给定HttpServletResponse,ModelMap,甚至自己的类型,Spring都会为你将值传入进来。通过一个逻辑层service组件根据id参数值去底层查找Article对象,并放入request作用域中,最后返回的是面页视图名,这个例子中是返回到articleView.jsp中。

    上例再变通下:

@Controller
public class ArticleController{

  @RequestMapping("/articleView_*")
   public String getArticle(HttpServletRequest request){

    String id = StringUtil.getParam(request.getRequestURI(),"articleView_*");
    request.setAttribute("article", service.find(Article.class, id));
    return "articleView";
   }

}

    对于articleView_aaa.do,articleView_bbbb.do,articleView_c5h8j2.do,articleView_xxx.do,这样的请求都会由getArticle()这个方法来应付,是不是很有意思?

    Spring 3.0增加了一个@ PathVariable注解来支持可变的请求路径,将上面的代码在3.0版中再变通下:

@Controller
public class ArticleController{

  @RequestMapping("/articleView/${id}")   //可以接受articleView/aaa.do,articleView/xxx.do...
   public String getArticle(@PathVariable String id, HttpServletRequest request){
    request.setAttribute("article", service.find(Article.class, id));
    return "articleView";
   }

}

再变得复杂些:

@Controller
public class ArticleController{

  @RequestMapping("/articleList/${pageSize}/channel/*/category/${id}")   

   public String getArticles((@PathVariable Integer pageSize, @PathVariable int id, HttpServletRequest request){
    Integer channelId = StringUtil.getParam(request.getRequestURI(),"channel/*/");
    request.setAttribute("articles", service.findScroll(Article.class, pageSize,50,"channel=? and category=?",new Object[]{channelId,id}));
    
    return "articleList";
   }

}

    它已经灵活到URL地址完全可以自己随意编制。

    根据内容协商制的视图解析机制:

    2.5版是由@MVC控制器来决定视图解析器,3.0版将变得更加灵活,似乎可以通过扩展名来转到不同的解析器中,例如请求一个.pdf文件将是如何效果呢?3.0版都会带来不可思议的模式。

    HTTP方法的转换:

    先看前台页面一段Html代码

<form:form method="delete">  
<p class="submit"><input type="submit" value="Delete Pet"/></p> 
</form:form>

    HTTP规范中form表单只有两种方法——POST和GET,而3.0做了一个过滤器,可以转换这些方法至四种——GET, PUT, POST, 和 DELETE。控制器接受请求:

@Controller("/deleteArticle")
public class ArticleController{

  de style="line-height: 28px; ">@RequestMappingde>de style="line-height: 28px; ">(method = RequestMethod.DELETE)
de>   public String deleteArticle(@PathVariable String id, HttpServletRequest request){
    service.delete(Article.class, id);
    return "message";
   }

}
    3.0版仅在MVC子集中就增加了很多新特性,如果在IoC、AOP等等其它子集所有的变革,绝对可以称得上Srping创始人所述的里程碑版本。3.0版使用的注解列表如下:

? @Autowired
? @Component
? @Controller
? @InitBinder
? @ManagedAttribute
? @ManagedOperation
? @ManagedOperationParameters
? @ManagedOperationParameter
? @ManagedResource
? @PathVariable
? @PostConstruct
? @PreDestroy
? @Repository
? @RequestMapping
? @Required
? @Resource
? @Service
? @Transactional
    目前Spring 3版本已经到了M2,应该是M3完成后将推出最终正式版本,我想很快会来临,按照Spring的创始人罗德.约翰逊的预言,未来J2EE应用中Spring+Tomcat将占主导地位,是否引起争议,笔者不敢点评,不过Oracle收购Sun后,Java社区将是如何,还无从知晓,似乎罗德.约翰逊对这宗收购案也有些紧张,因为Oracle不像Sun的第一个谈判者IBM那样有过开放技术的先例(可以回忆下IBM早期的主板总线开放掀起的兼容机潮至今波涛不熄)。目前国内对新东西消化尚慢,我到图书城看了下,Spring 2.5的资料都很难找到。且很多企业都是抱着Struts1.x在做开发,尽管笔者这样说会引来很多争议,但Struts1时代的灭亡只是时间问题。Struts2虽然改进了很多,依笔者看,与Spring MVC相比仍有诸多的不足,尤其看不惯那种变态的侵入模式,看看它把HttpServletRequest、HttpSession、HttpServletResponse等servlet标准组件干成什么样?开源时代,至少我不愿意接受那种变态的潜规则。

    笔者早先常用Struts1.x框架,它搭配了一套自己的ActionForm,使得编程工作量增加,虽然可以变通使用自己的Pojo,但对于没有掌握J2EE底层工具类(BeanUtil)的开发人员来说,其类型匹配是非常复杂的事。事实上Spring MVC早在1.x版本就完全使用自己的pojo来对应表单的填充,配上属性编辑器,可以解决类型转换问题,完全实现领域模型驱动的设计模式。由于MVC层的控制器也是Spring容器的Bean而已,因此对整个项目的控制、扩展变得非常容易。同时上文也顺便点评了Struts2,可见Spring MVC在各类MVC框架的优势所在。本身罗德.约翰逊先生是设计模式高手,一个优秀的框架给我们带来的远远不只是开发效率,还有更先进的开发模式和理念...

    笔者对Spring框架研究肤浅,待日后了解掌握更多时会常在博客中述之。

posted @ 2011-04-21 11:02 飞飞 阅读(851) | 评论 (0)编辑 收藏

从4个层面分析这部分实现: 
  1. iBatis的基本实现
  2. 基于事务的iBatis的基本实现
  3. 基于事务的Spring+iBatis实现
  4. 基于回调方式的Spring+iBatis实现

1.iBatis的基本实现

iBatis通过SqlMapClient提供了一组方法用于批处理实现:
  1. startBatch() 开始批处理
  2. executeBatch() 执行批处理

代码如下:
Java代码 复制代码 收藏代码
  1. public void create(List<Reply> replyList) {   
  2.   
  3.     try {   
  4.         // 开始批处理   
  5.         sqlMapClient.startBatch();   
  6.   
  7.         for (Reply reply: replyList) {   
  8.             // 插入操作   
  9.             sqlMapClient.insert("Reply.create", reply);   
  10.         }   
  11.         // 执行批处理   
  12.         sqlMapClient.executeBatch();   
  13.   
  14.     } catch (Exception e) {   
  15.         e.printStackTrace();   
  16.     }   
  17. }  

这是基于iBatis的最基本实现,如果你一步一步debug,你会发现:其实,数据库已经执行了插入操作!
因此,除了这两个核心方法外,你还需要开启事务支持。否则,上述代码只不过是个空架子!

2.基于事务的iBatis的基本实现
事务处理:
  1. startTransaction() 开始事务
  2. commitTransaction() 提交事务
  3. endTransaction() 结束事务


我们以insert操作为例,把它们结合到一起:
Java代码 复制代码 收藏代码
  1. public void create(List<Reply> replyList) {   
  2.   
  3.     try {   
  4.         // 开始事务   
  5.         sqlMapClient.startTransaction();   
  6.         // 开始批处理   
  7.         sqlMapClient.startBatch();   
  8.   
  9.         for (Reply reply: replyList) {   
  10.             // 插入操作   
  11.             sqlMapClient.insert("Reply.create", reply);   
  12.         }   
  13.         // 执行批处理   
  14.         sqlMapClient.executeBatch();   
  15.   
  16.         // 提交事务   
  17.         sqlMapClient.commitTransaction();   
  18.   
  19.     } catch (Exception e) {   
  20.         e.printStackTrace();   
  21.     } finally {     
  22.              try {   
  23.             // 结束事务   
  24.             sqlMapClient.endTransaction();   
  25.                 } catch (SQLException e) {   
  26.                          e.printStackTrace();   
  27.                      }   
  28.     }     
  29. }  

replyList是一个List,要把这个List插入到数据库,就需要经过这三个步骤:
  1. 开始批处理 startBatch()
  2. 插入      insert()
  3. 执行批处理 executeBatch()

如果要在Spring+iBatis中进行批处理实现,需要注意使用同一个sqlMapClient!同时,将提交事务的工作交给Spring统一处理!

3.基于事务的Spring+iBatis实现
Java代码 复制代码 收藏代码
  1. public void create(List<Reply> replyList) {   
  2.     if (!CollectionUtils.isEmpty(replyList)) {   
  3.         // 注意使用同一个SqlMapClient会话   
  4.         SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();   
  5.   
  6.         try {   
  7.             // 开始事务   
  8.             sqlMapClient.startTransaction();   
  9.             // 开始批处理   
  10.             sqlMapClient.startBatch();   
  11.             for (Reply reply : replyList) {   
  12.                 // 插入操作   
  13.                 sqlMapClient.insert("Reply.create", reply);   
  14.             }   
  15.   
  16.             // 执行批处理   
  17.             sqlMapClient.executeBatch();   
  18.             // 提交事务 交给Spring统一控制   
  19.             // sqlMapClient.commitTransaction();   
  20.   
  21.         } catch (Exception e) {   
  22.             e.printStackTrace();   
  23.         } finally {     
  24.                  try {   
  25.                 // 结束事务   
  26.                 sqlMapClient.endTransaction();   
  27.                     } catch (SQLException e) {   
  28.                              e.printStackTrace();   
  29.                          }   
  30.         }     
  31.     }   
  32. }  

注意使用同一个sqlMapClient:
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
如果直接sqlMapClientTemplate执行insert()方法,将会造成异常!

想想,还有什么问题?其实问题很明显,虽然解决了批处理实现的问题,却造成了事务代码入侵的新问题。 这么做,有点恶心!
除此之外,异常的处理也很恶心,不能够简单的包装为 DataAccessException 就无法被Spring当作统一的数据库操作异常做处理。


4.基于回调方式的Spring+iBatis实现
如果观察过Spring的源代码,你一定知道,Spring为了保持事务统一控制,在实现ORM框架时通常都采用了回调模式,从而避免了事务代码入侵的可能!
修改后的代码如下:
Java代码 复制代码 收藏代码
  1. @SuppressWarnings("unchecked")   
  2. public void create(final List<Reply> replyList) {   
  3.     // 执行回调   
  4.     sqlMapClientTemplate.execute(new SqlMapClientCallback() {   
  5.         // 实现回调接口   
  6.         public Object doInSqlMapClient(SqlMapExecutor executor)   
  7.                 throws SQLException {   
  8.             // 开始批处理   
  9.             executor.startBatch();   
  10.             for (Reply reply : replyList) {   
  11.                 // 插入操作   
  12.                 executor.insert("Reply.create", reply);   
  13.   
  14.             }   
  15.             // 执行批处理   
  16.             executor.executeBatch();   
  17.   
  18.             return null;   
  19.   
  20.         }   
  21.     });   
  22.   
  23. }  

注意,待遍历的参数replyList需要加入final标识!即,待遍历对象不能修改!
引用
public void create(final List<Reply> replyList)

这样做,就将事务处理的控制权完全交给了Spring!
简述:
  1. SqlMapClientCallback 回调接口
  2. doInSqlMapClient(SqlMapExecutor executor) 回调实现方法
  3. DataAccessException 最终可能抛出的异常
posted @ 2011-04-21 10:15 飞飞 阅读(933) | 评论 (0)编辑 收藏

Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。

1. 配置文件
Log4J配置文件的基本格式如下:

#配置根Logger
log4j.rootLogger  =   [ level ]   ,  appenderName1 ,  appenderName2 ,  …

#配置日志信息输出目的地Appender
log4j.appender.appenderName  =  fully.qualified.name.of.appender.class
  log4j.appender.appenderName.option1  =  value1
  …
  log4j.appender.appenderName.optionN  =  valueN

#配置日志信息的格式(布局)
log4j.appender.appenderName.layout  =  fully.qualified.name.of.layout.class
  log4j.appender.appenderName.layout.option1  =  value1
  …
  log4j.appender.appenderName.layout.optionN  =  valueN 

其中 [level] 是日志输出级别,共有5级:


FATAL       0 
ERROR      3 
WARN       4 
INFO         6 
DEBUG      7
 
Appender 为日志输出目的地,Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
Layout:日志输出格式,Log4j提供的layout有以下几种:


org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下:


    %m   输出代码中指定的消息
  %p   输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
  %r   输出自应用启动到输出该log信息耗费的毫秒数
  %c   输出所属的类目,通常就是所在类的全名
  %t   输出产生该日志事件的线程名
  %n   输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
  %d   输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss , SSS},输出类似:2002年10月18日  22 : 10 : 28 , 921 
  %l   输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java: 10 ) 

2. 在代码中初始化Logger:
1)在程序中调用BasicConfigurator.configure()方法:给根记录器增加一个ConsoleAppender,输出格式通过PatternLayout设为"%-4r [%t] %-5p %c %x - %m%n",还有根记录器的默认级别是Level.DEBUG.
2)配置放在文件里,通过命令行参数传递文件名字,通过PropertyConfigurator.configure(args[x])解析并配置;
3)配置放在文件里,通过环境变量传递文件名等信息,利用log4j默认的初始化过程解析并配置;
4)配置放在文件里,通过应用服务器配置传递文件名等信息,利用一个特殊的servlet来完成配置。

3. 为不同的 Appender 设置日志输出级别:
当调试系统时,我们往往注意的只是异常级别的日志输出,但是通常所有级别的输出都是放在一个文件里的,如果日志输出的级别是BUG!?那就慢慢去找吧。
这时我们也许会想要是能把异常信息单独输出到一个文件里该多好啊。当然可以,Log4j已经提供了这样的功能,我们只需要在配置中修改Appender的Threshold 就能实现,比如下面的例子:

[配置文件]


 ### set log levels ###
log4j.rootLogger = debug ,  stdout ,  D ,  E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 保存异常信息到单独文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log ## 异常日志文件名
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
[代码中使用]


  public   class  TestLog4j   {
     public   static   void  main(String[] args)   {
        PropertyConfigurator.configure( " D:/Code/conf/log4j.properties " );
        Logger logger  =  Logger.getLogger(TestLog4j. class );
        logger.debug( " debug " );
        logger.error( " error " );
    }
}

运行一下,看看异常信息是不是保存在了一个单独的文件error.log中

log4j.properties 使用
一.参数意义说明
输出级别的种类
ERROR、WARN、INFO、DEBUG
ERROR 为严重错误 主要是程序的错误
WARN 为一般警告,比如session丢失
INFO 为一般要显示的信息,比如登录登出
DEBUG 为程序的调试信息
配置日志信息输出目的地
log4j.appender.appenderName = fully.qualified.name.of.appender.class
1.org.apache.log4j.ConsoleAppender(控制台)
2.org.apache.log4j.FileAppender(文件)
3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
4.org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
5.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
配置日志信息的格式
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
1.org.apache.log4j.HTMLLayout(以HTML表格形式布局),
2.org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
3.org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
4.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
控制台选项
Threshold=DEBUG:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
Target=System.err:默认情况下是:System.out,指定输出控制台
FileAppender 选项
Threshold=DEBUF:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
File=mylog.txt:指定消息输出到mylog.txt文件。
Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
RollingFileAppender 选项
Threshold=DEBUG:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
File=mylog.txt:指定消息输出到mylog.txt文件。
Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
MaxBackupIndex=2:指定可以产生的滚动文件的最大数。
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
日志信息格式中几个符号所代表的含义:
 -X号: X信息输出时左对齐;
 %p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
 %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
 %r: 输出自应用启动到输出该log信息耗费的毫秒数
 %c: 输出日志信息所属的类目,通常就是所在类的全名
 %t: 输出产生该日志事件的线程名
 %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.java:10)
 %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
 %%: 输出一个"%"字符
 %F: 输出日志消息产生时所在的文件名称
 %L: 输出代码中的行号
 %m: 输出代码中指定的消息,产生的日志具体信息
 %n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行
 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
 1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
 2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
 3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
 4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边较远输出的字符截掉。
二.文件配置Sample1
log4j.rootLogger=DEBUG,A1,R
#log4j.rootLogger=INFO,A1,R
# ConsoleAppender 输出
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
# File 输出 一天一个文件,输出路径可以定制,一般在根路径下
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=blog_log.txt
log4j.appender.R.MaxFileSize=500KB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n
文件配置Sample2
下面给出的Log4J配置文件实现了输出到控制台,文件,回滚文件,发送日志邮件,输出到数据库日志表,自定义标签等全套功能。
log4j.rootLogger=DEBUG,CONSOLE,A1,im
#DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE
log4j.addivity.org.apache=true
###################
# Console Appender
###################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
#####################
# File Appender
#####################
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis
########################
# Rolling File
########################
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
####################
# Socket Appender
####################
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
########################
# Log Factor 5 Appender
########################
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
########################
# SMTP Appender
#######################
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=chenyl@yeqiangwei.com
log4j.appender.MAIL.SMTPHost=mail.hollycrm.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=chenyl@yeqiangwei.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
########################
# JDBC Appender
#######################
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
###################
#自定义Appender
###################
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@yeqiangwei.com
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
三.高级使用
实验目的:
 1.把FATAL级错误写入2000NT日志
 2. WARN,ERROR,FATAL级错误发送email通知管理员
 3.其他级别的错误直接在后台输出
实验步骤:
 输出到2000NT日志
 1.把Log4j压缩包里的NTEventLogAppender.dll拷到WINNT\SYSTEM32目录下
 2.写配置文件log4j.properties
# 在2000系统日志输出
 log4j.logger.NTlog=FATAL, A8
 # APPENDER A8
 log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
 log4j.appender.A8.Source=JavaTest
 log4j.appender.A8.layout=org.apache.log4j.PatternLayout
 log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
3.调用代码:
 Logger logger2 = Logger.getLogger("NTlog"); //要和配置文件中设置的名字相同
 logger2.debug("debug!!!");
 logger2.info("info!!!");
 logger2.warn("warn!!!");
 logger2.error("error!!!");
 //只有这个错误才会写入2000日志
 logger2.fatal("fatal!!!");
发送email通知管理员:
 1. 首先下载JavaMail和JAF,
  http://java.sun.com/j2ee/ja/javamail/index.html
  http://java.sun.com/beans/glasgow/jaf.html
 在项目中引用mail.jar和activation.jar。
 2. 写配置文件
 # 将日志发送到email
 log4j.logger.MailLog=WARN,A5
 #  APPENDER A5
 log4j.appender.A5=org.apache.log4j.net.SMTPAppender
 log4j.appender.A5.BufferSize=5
 log4j.appender.A5.To=chunjie@yeqiangwei.com
 log4j.appender.A5.From=error@yeqiangwei.com
 log4j.appender.A5.Subject=ErrorLog
 log4j.appender.A5.SMTPHost=smtp.263.net
 log4j.appender.A5.layout=org.apache.log4j.PatternLayout
 log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
 3.调用代码:
 //把日志发送到mail
 Logger logger3 = Logger.getLogger("MailLog");
 logger3.warn("warn!!!");
 logger3.error("error!!!");
 logger3.fatal("fatal!!!");
在后台输出所有类别的错误:
 1. 写配置文件
 # 在后台输出
 log4j.logger.console=DEBUG, A1
 # APPENDER A1
 log4j.appender.A1=org.apache.log4j.ConsoleAppender
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
 log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
 2.调用代码
 Logger logger1 = Logger.getLogger("console");
 logger1.debug("debug!!!");
 logger1.info("info!!!");
 logger1.warn("warn!!!");
 logger1.error("error!!!");
 logger1.fatal("fatal!!!");
--------------------------------------------------------------------
 全部配置文件:log4j.properties
 # 在后台输出
 log4j.logger.console=DEBUG, A1
 # APPENDER A1
 log4j.appender.A1=org.apache.log4j.ConsoleAppender
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
 log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 在2000系统日志输出
 log4j.logger.NTlog=FATAL, A8
 # APPENDER A8
 log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
 log4j.appender.A8.Source=JavaTest
 log4j.appender.A8.layout=org.apache.log4j.PatternLayout
 log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 将日志发送到email
 log4j.logger.MailLog=WARN,A5
 #  APPENDER A5
 log4j.appender.A5=org.apache.log4j.net.SMTPAppender
 log4j.appender.A5.BufferSize=5
 log4j.appender.A5.To=chunjie@yeqiangwei.com
 log4j.appender.A5.From=error@yeqiangwei.com
 log4j.appender.A5.Subject=ErrorLog
 log4j.appender.A5.SMTPHost=smtp.263.net
 log4j.appender.A5.layout=org.apache.log4j.PatternLayout
 log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
全部代码:Log4jTest.java
 
/*
  * 创建日期 2003-11-13
  */
 package edu.bcu.Bean;
 import org.apache.log4j.*;
 //import org.apache.log4j.nt.*;
 //import org.apache.log4j.net.*;
 /**
  * @author yanxu
  */
 public class Log4jTest
 {
  public static void main(String args[])
  {
   PropertyConfigurator.configure("log4j.properties");
   //在后台输出
   Logger logger1 = Logger.getLogger("console");
   logger1.debug("debug!!!");
   logger1.info("info!!!");
   logger1.warn("warn!!!");
   logger1.error("error!!!");
   logger1.fatal("fatal!!!");
//在NT系统日志输出
   Logger logger2 = Logger.getLogger("NTlog");
   //NTEventLogAppender nla = new NTEventLogAppender();
   logger2.debug("debug!!!");
   logger2.info("info!!!");
   logger2.warn("warn!!!");
   logger2.error("error!!!");
   //只有这个错误才会写入2000日志
   logger2.fatal("fatal!!!");
//把日志发送到mail
   Logger logger3 = Logger.getLogger("MailLog");
   //SMTPAppender sa = new SMTPAppender();
   logger3.warn("warn!!!");
   logger3.error("error!!!");
   logger3.fatal("fatal!!!");
  }
 }

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/azheng270/archive/2008/03/12/2173430.aspx

posted @ 2011-04-18 14:14 飞飞 阅读(430) | 评论 (0)编辑 收藏

查看进行命令: ps -ef | grep tomcat
查看日志 tail -f logs/catalina.out
74文件传送跳转文件夹 /opt/transport/
复制文件命令 scp UserOperateServiceImpl.class 118.123.253.71:/opt/transport/
远程连接 ssh 118.123.253.71
结束进程命令 kill -9 31454
启动tomcat sh bin/startup.sh
搜索日志中的内容 grep '18923858130' interfaceLog.log*
本地复制文件 cp -r appMarketWebApi   appMarketWebApi2000000
删除文件命令 rm appMarketWebApi.zip
压缩文件命令  zip -r AppStoreBak1108.zip AppStore
复制文件清除.svn文件夹 xcopy appMarketWebApi1.3 11111111111 /s /i
从现网复制文件命令 scp 10.128.100.115:/opt/transport/appMarketWebApi_1111_115.zip /opt/transport/
查看文件占用量大命令 du -k|sort -t " " +0 -n -r|more
查看当前目录文件大小 du -sh .
tar包解压命令 tar -xvf
抓内存包命令 jmap -dump:format=b,file=heap20101216.bin
useradd -d /home -s /bin/sh   liyanhong
passwd liyanhong 
posted @ 2011-04-15 16:11 飞飞 阅读(292) | 评论 (0)编辑 收藏

package com.org.softwore.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.SocketException;

import org.apache.commons.net.telnet.TelnetClient;

import com.org.softwore.domain.TelnetInfo;

public class TelnetUtil {
 private TelnetClient telnet = new TelnetClient("VT220");
 private InputStream in;
 private PrintStream out;
 private String prompt = ">";
 String s;

 public void TelnetCmd(TelnetInfo telnetInfo) throws SocketException,
   IOException, InterruptedException {

  // 防火墙中高级的网络连接设置的本地连接取消选择
  // Connect to the specified server
  telnet.connect(telnetInfo.getServerIp(), telnetInfo.getServerPort());
  // Get input and output stream references
  in = telnet.getInputStream();
  out = new PrintStream(telnet.getOutputStream());

  // Login telnet
  readUntil("login: ");
  write(telnetInfo.getServerUser());
  readUntil("password: ");
  write(telnetInfo.getServerPwd());
  readUntil(prompt);

  // 执行命令
  if (telnetInfo.getMap() != null) {
   int a = 0;
   for (Integer id : telnetInfo.getMap().keySet()) {
    String temp = telnetInfo.getMap().get(id);
    write(temp);
    // 处理ftp登录,不需要执行readUntil(prompt)
    if (temp.startsWith("ftp")) {
     a = 2;
    }
    if (a > 0) {
     a = a - 1;
     continue;
    } else {
     readUntil(prompt);
    }

   }
  }
  System.out.println("\n");
 }

 public String readUntil(String pattern) throws IOException {
  char lastChar = pattern.charAt(pattern.length() - 1);
  StringBuffer sb = new StringBuffer();
  // boolean found = false;
  char ch = (char) in.read();

  while (true) {
   sb.append(ch);
   if (ch == lastChar) {
    if (sb.toString().endsWith(pattern)) {
     // 处理编码,界面显示乱码问题
     byte[] temp = sb.toString().getBytes("iso8859-1");
     System.out.print(new String(temp, "GBK"));
     return new String(temp, "GBK");
    }
   }
   ch = (char) in.read();
  }
 }

 public void write(String value) throws InterruptedException {
  out.println(value);
  out.flush();
  Thread.sleep(1000);
 }

 public void disconnect() throws IOException {
  telnet.disconnect();
 }
}


package com.org.softwore.domain;

import java.io.Serializable;
import java.util.TreeMap;

public class TelnetInfo implements Serializable {

 /**
  *
  */
 private static final long serialVersionUID = -6592407260449335815L;
 private String serverIp;
 private String serverUser;
 private String serverPwd;
 private int serverPort;
 private String ftpIp;
 private String ftpUser;
 private String ftpPwd;
 private String ftpPort;
 private TreeMap<Integer, String> map;

 public TreeMap<Integer, String> getMap() {
  return map;
 }

 public void setMap(TreeMap<Integer, String> map) {
  this.map = map;
 }

 public String getServerIp() {
  return serverIp;
 }

 public void setServerIp(String serverIp) {
  this.serverIp = serverIp;
 }

 public String getServerUser() {
  return serverUser;
 }

 public void setServerUser(String serverUser) {
  this.serverUser = serverUser;
 }

 public String getServerPwd() {
  return serverPwd;
 }

 public void setServerPwd(String serverPwd) {
  this.serverPwd = serverPwd;
 }

 public int getServerPort() {
  return serverPort;
 }

 public void setServerPort(int serverPort) {
  this.serverPort = serverPort;
 }

 public String getFtpIp() {
  return ftpIp;
 }

 public void setFtpIp(String ftpIp) {
  this.ftpIp = "ftp " + ftpIp;
 }

 public String getFtpUser() {
  return ftpUser;
 }

 public void setFtpUser(String ftpUser) {
  this.ftpUser = ftpUser;
 }

 public String getFtpPwd() {
  return ftpPwd;
 }

 public void setFtpPwd(String ftpPwd) {
  this.ftpPwd = ftpPwd;
 }

 public String getFtpPort() {
  return ftpPort;
 }

 public void setFtpPort(String ftpPort) {
  this.ftpPort = ftpPort;
 }

}



package com.org.softwore.service;

public interface TelnetService {

 public boolean windowsTelnetDownLoad();

 public boolean windowsTelnetUpLoad();

 public boolean windowsTelnetUpGrade();
 
 public boolean windowsTelnetTomcat(String stats);
 
 public boolean windowsTelnetBackUpSoftware();
}



package com.org.softwore.service.impl;

import java.io.IOException;
import java.net.SocketException;
import java.util.TreeMap;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.org.softwore.domain.TelnetInfo;
import com.org.softwore.service.TelnetService;
import com.org.softwore.util.TelnetUtil;

@Transactional
@Service("telnetService")
public class TelnetServiceImpl implements TelnetService {

 /**
  * 上传升级问价到ftp服务器
  */
 @Override
 public boolean windowsTelnetUpLoad() {
  boolean reslut = false;

  TelnetInfo telnetInfo = new TelnetInfo();
  telnetInfo.setServerIp("127.0.0.1");
  telnetInfo.setServerUser("administrator");
  telnetInfo.setServerPwd("123456");
  telnetInfo.setServerPort(23);

  TreeMap<Integer, String> map = new TreeMap<Integer, String>();
  map.put(1, "ftp 10.39.62.45");
  map.put(2, "admin");
  map.put(3, "admintianyi");
  map.put(4, "bin");
  map.put(5, "mkdir test1");
  map.put(6, "cd /test1");
  map.put(7, "put c:\\upgrade\\appMarketWebApi.zip");
  map.put(8, "put c:\\upgrade\\T_RANKSWITCHTEMP.sql");
  map.put(9, "bye");
  telnetInfo.setMap(map);

  TelnetCmd(telnetInfo);
  return reslut;
 }
 
 /**
  * 下载升级程序和文件
  */
 @Override
 public boolean windowsTelnetDownLoad() {
  boolean reslut = false;

  TelnetInfo telnetInfo = new TelnetInfo();
  //telnet
  telnetInfo.setServerIp("127.0.0.1");
  telnetInfo.setServerUser("administrator");
  telnetInfo.setServerPwd("123456");
  telnetInfo.setServerPort(23);

  TreeMap<Integer, String> map = new TreeMap<Integer, String>();
  map.put(1, "cd c:\\");
  map.put(2, "rd test /s /q");
  map.put(3, "mkdir test");
  map.put(4, "ftp 10.39.62.45");
  map.put(5, "admin");
  map.put(6, "admintianyi");
  map.put(7, "bin");
  map.put(8, "lcd c:\\test");
  map.put(9, "cd test1");
  map.put(10, "get appMarketWebApi.zip");
  map.put(11, "get T_RANKSWITCHTEMP.sql");
  map.put(12, "bye");
  telnetInfo.setMap(map);

  TelnetCmd(telnetInfo);
  return reslut;
 }
 
 /**
  * 服务器开启和关闭
  */
 @Override
 public boolean windowsTelnetTomcat(String stats) {
  //安装tomcat7,使用服务来进行启动和停止
  boolean reslut = false;

  TelnetInfo telnetInfo = new TelnetInfo();
  telnetInfo.setServerIp("127.0.0.1");
  telnetInfo.setServerUser("administrator");
  telnetInfo.setServerPwd("123456");
  telnetInfo.setServerPort(23);

  // 需要执行的sql语句
  TreeMap<Integer, String> map = new TreeMap<Integer, String>();
  if(stats.equals("start")){
   map.put(1, "net start Tomcat7");
  }
  if(stats.equals("stop")){
   map.put(1, "net stop Tomcat7");
  }
  telnetInfo.setMap(map);

  TelnetCmd(telnetInfo);
  return reslut;
 }
 
 /**
  * 备份软件程序
  */
 @Override
 public boolean windowsTelnetBackUpSoftware(){
  boolean reslut = false;
  
  TelnetInfo telnetInfo = new TelnetInfo();
  telnetInfo.setServerIp("127.0.0.1");
  telnetInfo.setServerUser("administrator");
  telnetInfo.setServerPwd("123456");
  telnetInfo.setServerPort(23);
  
  // 需要执行的sql语句
  TreeMap<Integer, String> map = new TreeMap<Integer, String>();
  //执行sql脚本
  map.put(1, "cd c:\\");
  map.put(2, "rd testback /s /q");
  map.put(3, "mkdir testback");
  map.put(4, "cd c:\\testback");
  map.put(5, "mkdir appMarketWebApi");
  map.put(6, "xcopy \"c:\\Tomcat 7.0\\webapps\\appMarketWebApi\"  appMarketWebApi /s /y");
  telnetInfo.setMap(map);
  
  TelnetCmd(telnetInfo);
  
  return reslut;
  
 }
 
 
 /**
  * 执行sql脚本和升级程序
  */
 @Override
 public boolean windowsTelnetUpGrade() {
  boolean reslut = false;

  TelnetInfo telnetInfo = new TelnetInfo();
  telnetInfo.setServerIp("127.0.0.1");
  telnetInfo.setServerUser("administrator");
  telnetInfo.setServerPwd("123456");
  telnetInfo.setServerPort(23);

  // 需要执行的sql语句
  TreeMap<Integer, String> map = new TreeMap<Integer, String>();
  //执行sql脚本
  map.put(1, "sqlplus appstore/appstore@appstore226");
  map.put(2, "@c:\\test\\T_RANKSWITCHTEMP.sql");
  map.put(3, "exit");
  
  //执行升级程序
  map.put(5, "cd c:\\test");
  map.put(6, "unzip appMarketWebApi.zip");
  map.put(7, "xcopy appMarketWebApi \"c:\\Tomcat 7.0\\webapps\\appMarketWebApi\" /s /y");
  
  telnetInfo.setMap(map);

  TelnetCmd(telnetInfo);
  return reslut;
 }

 /**
  * 公共的调用执行telnet命令
  * @param telnetInfo
  * @return
  */
 public boolean TelnetCmd(TelnetInfo telnetInfo) {
  boolean reslut = false;
  if (telnetInfo != null) {
   TelnetUtil telnet = new TelnetUtil();
   try {
    telnet.TelnetCmd(telnetInfo);
    telnet.disconnect();
    reslut = true;
   } catch (SocketException e) {
    e.printStackTrace();
   } catch (IOException e) {
    e.printStackTrace();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  return reslut;
 }
}


package com.org.softwore.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import com.org.softwore.service.TelnetService;

@Controller("telnetController")
public class TelnetController {

 @Autowired
 @Qualifier("telnetService")
 private TelnetService telnetService;

 /**
  * 上传升级问价到ftp服务器
  */
 public void windowsTelnetUpLoad() {
  telnetService.windowsTelnetUpLoad();
 }

 /**
  * 下载升级程序和文件
  */
 public void windowsTelnetDownLoad() {
  telnetService.windowsTelnetDownLoad();
 }

 /**
  * 备份软件程序
  */
 public void windowsTelnetBackUpSoftware() {
  telnetService.windowsTelnetBackUpSoftware();
 }

 /**
  * 服务关闭
  */
 public void windowsTelnetStopTomcat() {
  String stats = "stop";
  telnetService.windowsTelnetTomcat(stats);
 }

 /**
  * 执行sql脚本和升级程序
  */
 public void windowsTelnetUpGrade() {
  telnetService.windowsTelnetUpGrade();
 }

 /**
  * 服务开启
  */
 public void windowsTelnetStartTomcat() {
  String stats = "start";
  telnetService.windowsTelnetTomcat(stats);
 }
}



package com.org.softwore.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.org.softwore.controller.TelnetController;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "/applicationContext.xml" })
public class TelnetUtilTest {

 @Autowired
 @Qualifier("telnetController")
 private TelnetController telnetController;

 /**
  * 上传升级问价到ftp服务器
  */
 @Test
 public void windowsTelnetUpLoad() {
  telnetController.windowsTelnetUpLoad();
 }

 /**
  * 下载升级程序和文件
  */
 @Test
 public void windowsTelnetDownLoad() {
  telnetController.windowsTelnetDownLoad();
 }

 /**
  * 备份软件程序
  */
 @Test
 public void windowsTelnetBackUpSoftware() {
  telnetController.windowsTelnetBackUpSoftware();
 }

 /**
  * 关闭服务
  */
 @Test
 public void windowsTelnetStopTomcat() {
  telnetController.windowsTelnetStopTomcat();
 }

 /**
  * 执行sql脚本和升级程序
  */
 @Test
 public void windowsTelnetUpGrade() {
  telnetController.windowsTelnetUpGrade();
 }

 /**
  * 启动服务
  */
 @Test
 public void windowsTelnetStartTomcat() {
  telnetController.windowsTelnetStartTomcat();
 }
}

posted @ 2011-04-13 17:34 飞飞 阅读(2569) | 评论 (0)编辑 收藏

为了进行系统维护操作,有时需要再windows和linux或Unix系统之间互传文件,虽然有很多工具可以实现该功能,但我还是觉得命令行来的方便快捷,起初使用linux的scp命令,总是不成功,网上也没有相关介绍,经过几次努力之后,终于成功的摸索出了scp命令在写windows的路径时的写法,于是马上下了出来,与大家分享:

从linux系统复制文件到windows系统:scp /oracle/a.txt  administrator@192.168.3.181:/d:/

在linux环境下,将windows下的文件复制到linux系统中:scp administrator@192.168.3.181:/d:/test/config.ips  /oracle

请注意:因为windows系统本身不支持ssh协议,所以,要想上面的命令成功执行,必须在windows客户端安装ssh for windows的客户端软件,比如winsshd,使windows系统支持ssh协议才行。

posted @ 2011-04-13 15:57 飞飞 阅读(586) | 评论 (0)编辑 收藏

commons-net-2.0.jar
log4j-1.2.15.jar


package com;

import java.io.InputStream;
import java.io.PrintStream;

import org.apache.commons.net.telnet.TelnetClient;
import org.apache.log4j.Logger;

public class TelnetHandler {
 private static final Logger logger = Logger.getLogger(TelnetHandler.class);
 private TelnetClient telnet = new TelnetClient("VT220");
 private InputStream in;
 private PrintStream out;
 private String prompt=" ";
 String s;

 public void TelnetCmd(String server, String user, String password) {
  try {
   // Connect to the specified server
   telnet.connect(server, 23);
   logger.info("Login............................");
   // Get input and output stream references
   in = telnet.getInputStream();
   out = new PrintStream(telnet.getOutputStream());
   // Login
   readUntil("login: ");
   write(user);
   readUntil("password: ");
   write(password);
   // Advance to a prompt
   readUntil(prompt);
  } catch (Exception e) {
   e.printStackTrace();
   logger.info("logon failed", e);
  }
 }

 public String readUntil(String pattern) {
  try {
   char lastChar = pattern.charAt(pattern.length() - 1);
   StringBuffer sb = new StringBuffer();
   // boolean found = false;
   char ch = (char) in.read();

   while (true) {
    System.setProperty("GBK", "iso8859-1");
    System.out.print(ch);
    sb.append(ch);
    if (ch == lastChar) {
     if (sb.toString().endsWith(pattern)) {
      // System.out.print( sb.toString());
      return sb.toString();
     }
    }
    ch = (char) in.read();
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
  return null;
 }

 public void write(String value) {
  try {
   out.println(value);
   out.flush();
//   System.out.println(value);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public String sendCmd(String command) {
  try {
   write(command);
   return readUntil(s + prompt);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return null;
 }

 public void disconnect() {
  try {
   telnet.disconnect();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static void main(String[] args) {
  try {
   logger.info("发送命令开始");
   TelnetHandler telnet1 = new TelnetHandler();
   telnet1.TelnetCmd("127.0.0.1", "administrator", "123456");
   // Exec Cmd
//   telnet1.sendCmd("dir");
   telnet1.sendCmd("cd c:\\test");
   telnet1.disconnect();
//   telnet1.sendCmd("xcopy c:\\httpdownload.txt c:\\test");
   
   logger.info("发送命令结束");
   
   
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

posted @ 2011-04-12 17:37 飞飞 阅读(819) | 评论 (0)编辑 收藏

1、建一个Project取名为SOAP
2、将axis-1_4\webapps\axis\WEB-INF\lib下的所有文件拷贝到你的SOAP工程文件下
3、新建一个HelloWord.java
package com;
public class HelloWord {
public String getHelloWord(userInfo userInfo) {
return "hi!:" + userInfo.getName() + "| " + userInfo.getPassword()
+ " | " + userInfo.getArea();
}
}
 
4、新建一个userInfo.java 对象
package com;
public class userInfo implements java.io.Serializable{
/**
 * 
 */
private static final long serialVersionUID = -1536718814867769008L;
String name;
String password;
String area;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
}
5、在WEB-INF\server-config.wsdd 文件添加以下内容(注意颜色标记的地方时跟soap相关的地方)
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<handler type="java:org.apache.axis.handlers.http.URLMapper"
name="URLMapper" />
<service name="HelloWord" provider="java:RPC">
<parameter name="className" value="com.HelloWord" />
<parameter name="allowedMethods" value="getHelloWord" />
<beanMapping languageSpecificType="java:com.userInfo" qname="ns:userInfo" xmlns:ns="urn:BeanService"/>
</service>
<transport name="http">
<requestFlow>
<handler type="URLMapper" />
</requestFlow>
</transport>
</deployment> 
6、web.xml 内容
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Apache-Axis</display-name>
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
    </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jws</welcome-file>
</welcome-file-list>
</web-app>
7、访问路径 http://localhost:8080/SOAP/services/HelloWord?wsdl
8、使用soapUI 3.6.1 生成客户端JUNIT测试代码.进行单元测试!设置soapui的axis参数
9、生成客户端JUNIT测试代码
 
 
10、将生成的代码放到SOAP工程下。修改测试用例。
 
 
11、执行测试,查看结果:
posted @ 2011-04-01 17:21 飞飞 阅读(1764) | 评论 (1)编辑 收藏

Nginx作为一个后起之秀,他的迷人之处已经让很多人都投入了他的怀抱。配置简单,实现原理简单。做一个负载平衡的再好不过了。

其原理:

简单介绍一下他的安装及配置过程

官方网站
http://wiki.codemongers.com/Main

一、依赖的程序

1. gzip module requires zlib library
2. rewrite module requires pcre library
3. ssl support requires openssl library

二、安装
./configure
make
make install

默认安装的路径是/usr/local/nginx

更多的安装配置
./configure --prefix=/usr/local/nginx
--with-openssl=/usr/include (启用ssl)
--with-pcre=/usr/include/pcre/ (启用正规表达式)
--with-http_stub_status_module (安装可以查看nginx状态的程序)
--with-http_memcached_module (启用memcache缓存)
--with-http_rewrite_module (启用支持url重写)


三、启动及重启
启动:nginx
重启:kill -HUP `cat /usr/local/nginx/logs/nginx.pid`
测试配置文件:nginx -t

简单吧,安装,启动都比较方便。

四、配置文件
http://wiki.codemongers.com/NginxFullExample

#运行用户
user nobody nobody;
#启动进程
worker_processes 5;
#全局错误日志及PID文件
error_log logs/error.log notice;
pid logs/nginx.pid;
#工作模式及连接数上限
events {
#工作模式有:select(标准模式),poll(标准模式),kqueue(高效模式,适用FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 and MacOS X),
#epoll(高效模式,本例用的。适用Linux 2.6+,SuSE 8.2,),/dev/poll(高效模式,适用Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+)
use epoll;
worker_connections 1024;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型
include conf/mime.types;
default_type application/octet-stream;
#设定日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
  log_format download    '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
  #设定请求缓冲
client_header_buffer_size 10k;
large_client_header_buffers 4 4k;

#开启gzip模块,要求安装gzip 在运行./config时要指定
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;

#设定访问日志
access_log logs/access.log main;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;

#设定负载均衡的服务器列表
upstream backserver {
#weigth参数表示权值,权值越高被分配到的几率越大
#本例是指在同一台服务器,多台服务器改变ip即可
server 127.0.0.1:8081 weight=5;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
  #设定虚拟主机,默认为监听80端口,改成其他端口会出现问题
server {
listen 80;
server_name test.com www.test.com;
charset utf8;
#设定本虚拟主机的访问日志
access_log logs/test.com.log main;
#如果访问 /images/*, /js/*, /css/* 资源,则直接取本地文件,不用转发。但如果文件较多效果不是太好。
location ~ ^/(images|js|css)/ {
root /usr/local/testweb;
expires 30m;
}

#对 "/" 启用负载均衡
location / {
proxy_pass http://backserver;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
#设定查看Nginx状态的地址,在运行./config 要指定,默认是不安装的。
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
#是否要通过用户名和密码访问,测试时可以不加上。conf/htpasswd 文件的内容用 apache 提供的 htpasswd 工具来产生即可
#auth_basic_user_file conf/htpasswd;
}
}
posted @ 2010-11-25 21:15 飞飞 阅读(180) | 评论 (0)编辑 收藏

ATI Installer HOWTO for SUSE/Novell users
openSUSE 10.2
If you want or need to use the latest and greatest ATI driver, continue here .
Use  YaST -> Software -> Change installation Source -> Add  Protocol: http  Server Name: : www2.ati.com  Directory on Server: suse/10.2to add the ATI http server as additional installation source.Now use  YaST -> Software -> Install and Delete Softwareto install the ATI/fglrx driver. Select the following packages:  x11-video-fglrxG01  ati-fglrxG01-kmp-<kernel-flavor><kernel-flavor> depends on your installed kernel. Check with"uname -r" for installed default/smp/bigsmp kernel. Use "sax2 -r"for X.Org configuration.SUSE LINUX 10.1 / SLES10 / SLED10
If you want or need to use the latest and greatest ATI driver, continue here .
Update your Kernel via YOU (YaST Online Update). Use  YaST -> Software -> Change installation Source -> Add  Protocol: http  Server Name: : www2.ati.com  Directory on Server: suse/sle10to add the ATI http server as additional installation source.Now use  YaST -> Software -> Install and Delete Softwareto install the ATI/fglrx driver. Select the following packages:  x11-video-fglrx  ati-fglrx-kmp-<kernel-flavor><kernel-flavor> depends on your installed kernel. Check with "uname -r" for installed default/smp/bigsmp kernel. Use "sax2 -r"for X.Org configuration.Manual driver installation for SUSE LINUX 10.0, SLES9, NLD9 and earlier
Since ATI driver release 8.16.20 the ATI installer needs to be usedto create SUSE/Novell RPMs. Download the ATI installer from the ATI website.  http://www.ati.com --> Drivers & Software --> LinuxIt is possible to create RPMs for the following SUSE/Novell distros.This information has been retrieved by using the installer itself:  ati-driver-installer-8.35.5-x86.x86_64.run --listpkg[...]SuSE Packages:        SuSE/NLD9-IA32  NLD9        SuSE/SLES9-IA32  SLES9        SuSE/SUSE91-IA32 SUSE 9.1        SuSE/NLD9-AMD64  NLD9 (x86_64)        SuSE/SLES9-AMD64 SLES9 (x86_64)        SuSE/SUSE91-AMD64 SUSE 9.1 (x86_64)        SuSE/SUSE100-IA32 SUSE 10.0        SuSE/SUSE92-IA32 SUSE 9.2        SuSE/SUSE93-IA32 SUSE 9.3        SuSE/SUSE100-AMD64 SUSE 10.0 (x86_64)        SuSE/SUSE92-AMD64 SUSE 9.2 (x86_64)        SuSE/SUSE93-AMD64 SUSE 9.3 (x86_64)        SuSE/SLED10-IA32 SLED10        SuSE/SLES10-IA32 SLES10        SuSE/SUSE101-IA32 SUSE 10.1        SuSE/SLED10-AMD64 SLED10 (x86_64)        SuSE/SLES10-AMD64 SLES10 (x86_64)        SuSE/SUSE101-AMD64 SUSE 10.1 (x86_64)        SuSE/SUSE102-IA32 openSUSE 10.2        SuSE/SUSE102-AMD64 openSUSE 10.2 (x86_64) Example:--------Create a RPM for SUSE 10.0 (i386) by using the installer.  ./ati-driver-installer-8.35.5-x86.x86_64.run --buildpkg SuSE/SUSE100-IA32Afterwards install the created RPM by using the rpm command. In thementioned example above this would be:  rpm -Uhv fglrx_6_8_0_SUSE100-8.35.5-1.i386.rpmThe postinstall script of this RPM will try to compile the requiredkernel module. If this fails, you'll get a message how to proceed.You still need to configure the driver with SaX2. Details can be foundin /usr/share/doc/packages/fglrx/README.SuSE.Unfortunately you need to recompile the "fglrx" kernel module rightafter any kernel (security) update. Use "fglrx-kernel-build.sh" for this.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mtnk/archive/2007/03/31/1547912.aspx

posted @ 2010-10-26 16:32 飞飞 阅读(375) | 评论 (0)编辑 收藏

     摘要: Suse Linux Enterprise Server 11.0 安装、配置与管理手册 Version 1.0 1. 安装准备 l       x86计算机,20G以上硬盘,100M以太网卡,2G以上内存; l       安装介质:SuseLinux DVD 2-1...  阅读全文
posted @ 2010-10-26 10:15 飞飞 阅读(2170) | 评论 (0)编辑 收藏

  • //接受   
  • String attachmentFile = "XXXXXXXX";    
  • //u can get correct attachment filename with this method ^&^    
  • attachmentFile = MimeUtility.decodeText(attachmentFile);    
  •   
  • //发邮件的时候这样设置附件名    
  • attachmentPart.setFileName(MimeUtility.encodeText(fds.getName()));  
  • posted @ 2010-09-01 23:36 飞飞 阅读(576) | 评论 (0)编辑 收藏

     使用java mail 包收发中文邮件的编码,解码问题以及解决方法
    JSP教程-邮件相关
    编码


    邮件头(参见RFC822,RFC2047)只能包含US-ASCII字符。邮件头中任何包含非US-ASCII字符的部分必须进行编码,使其只 包含US-ASCII字符。所以使用java mail发送中文邮件必须经过编码,否则别人收到你的邮件只能是乱码一堆。不过使用java mail 包的解决方法很简单,用它自带的MimeUtility工具中encode开头的方法(如encodeText)对中文信息进行编码就可以了。



    例子:



    MimeMessage mimeMsg = new MimeMessage(mailSession);



    //让javamail决定用什么方式来编码 ,编码内容的字符集是系统字符集mimeMsg.setSubject( MimeUtility.encodeText( Subject) );



    //使用指定的base64方式编码,并指定编码内容的字符集是gb2312

    mimeMsg.setSubject( MimeUtility.encodeText( Subject,”gb2312”,”B”));



    通常对邮件头的编码方式有2种,一种是base64方式编码,一种是QP(quoted-printable)方式编码,javamail根据具体情况来选择编码方式。



    如“txt测试”编码后内容如下:

    =?GBK?Q?Txt=B2=E2=CA=D4



    里面有个=?GBK?Q?,GBK表示的是内容的字符集,?Q?表示的是以QP方式编码的,后面紧跟的才是编码后的中文字符。所以用MimeUtility工具编码后的信息里包含了编码方式的信息。



    邮件的正文也要进行编码,但它不能用MimeUtility里的方法来编码。邮件正文的编码方式的信息是要放在Content- Transfer-Encoding这个邮件头参数中的,而MimeUtility里面的方法是将编码方式的信息放在编码后的正文内容中。所以如果你对正 文也用MimeUtility进行处理,那么其他邮件程序就不会正常显示你编码的邮件,因为其他邮件软件如outlook,foxmail只会根据 Content-Transfer-Encoding这个里面的信息来对邮件正文进行解码。



    其实,邮件正文部分的编码javamail已经自动帮你做了,当你发送邮件的时候,它会自己决定编码方式,并把编码方式的信息放入 Content-Transfer-Encoding这个邮件头参数中,然后再发送。所以你所要做的就是直接把邮件正文的内容放入邮件中就可以了。



    对邮件正文的编码方式比较多,包括了base64和QP方式,还有一些如7bit,8bit等等,因为javamail自动为邮件正文编码,所以我就不一一祥叙了。



    例子:



    //处理邮件正文

    MimeBodyPart mbp=new MimeBodyPart();



    if ( ContentType() == null || ContentType.equals(""))

    mbp.setText( Content );

    else

    mbp.setContent( Content, Content );











    解码


    javamail包中的MimeUtility工具中也提供了对邮件信息解码的方法,都是以decode开头的一些方法(如decodeText)



    例子:

    String Subject = mimemsg.getSubject();

    String ChSubject = MimeUtility.decodeText(Subject);



    对于base64和QP编码后信息,decode* 方法能将他们正确的解码,但是,如果指定的字符集不对,那么javamail就会出现错误,不能正确地将其解码。



    如有的邮件系统将”txt测试”编码后如下:

    =?x-unkown?Q?Txt=B2=E2=CA=D4



    这里指定的字符集是x-unknown,是非明确的字符集,javamail就不能正确的处理了,但是”测试”这两个中文字还是按照gbk字符集编码的,所以你可以手工的将编码方式信息改正确,再用decode*方法来解码。



    例子:

    if ( str.indexOf("=?x-unknown?") >=0 ){

    str = str.replaceAll("x-unknown","gbk" ); // 将编码方式的信息由x-unkown改为gbk

    try{

    str = MimeUtility.decodeText( str ); //再重新解码

    }catch( Exception e1){

    return str ;

    }





    decode*方法都是根据在编码信息中包含的编码方式的信息来解码,所以decode*方法对邮件正文解码是无效的,因为邮件正文中不包含编码方式的信息。



    同编码一样,邮件正文的解码也是由javamail做了。Javamail根据Content-Transfer-Encoding里的信息,来对邮件的正文解码。

    客户程序从javamail取得的正文内容字符集为iso-8859-1,所以还要将字符集转换一下,例:



    String CorrectContent = new String( Content.getbytes(“iso-8859-1”),”gb2312”);



    CorrentContent为正确的邮件正文了

    posted @ 2010-09-01 23:34 飞飞 阅读(3306) | 评论 (0)编辑 收藏

         摘要: A概念 最常用的概念 1、 scalars:存储单值 字符串:简单文本由单或双引号括起来。 数字:直接使用数值。 日期:通常从数据模型获得 布尔值:true或false,通常在<#if …>标记中使用   2、 hashes:充当其它对象的容器,每个都关联一个唯一的查询名字 具有一个唯一的查询名字和他包含的每个变量...  阅读全文
    posted @ 2010-07-03 18:09 飞飞 阅读(37419) | 评论 (4)编辑 收藏

     

    windows7系统的风光。我这几天也开始玩win7,笔记本系统我都重装了5-6次了,考虑到win7还不成熟、我又比较喜欢win7,所以考虑使用装双系统XP+WIN7,花了2个小时将XPWIN7重新全部安装,打好补丁,升级,将自己常用的软件都安装上

    工作原因需要安装ORACLE,考虑双系统中都安装ORACLE,系统切换之间数据的使用也需要一起切换,考虑XPWIN7都安装ORACLE软件,公用一个数据库文件。经过几个小时的奋战,终于完成预期的目标。

    首先是双系统的安装中需要注意的,2个系统的机器名必须一样。否则再同步的时候会出现错误,这种错误也都是能再装完之后解决,所以,机器名不一样也可以,就是后面麻烦下而已。

           系统硬盘规划如下:(硬盘320G分区买来就是分的4个区,本人懒惰,也就懒得再去分小了、因安装的是双系统的原因,C盘和D盘再显示上会根据登陆的系统而变化、最后2个分区则不变化,所以将公用数据文件安装再DISK1盘)

    首先我在XP系统的系统盘上只安装10.2.0.1.0数据库软件。

    然后再单独创建数据库(单独创建的数据库文件位置存放再DISK1中如:oradb)。

    建立监听、配置本地NET服务名。

    一切完好之后再使用升级补丁,将Oracle升级至10.2.0.3.0,升级时间大约30分钟,根据电脑性能时间会有变化。

    然后再切换至WIN7系统中同样的方法安装Oracle,因为WIN7系统的oracle版本使用的是for vista 版本。版本号为10.2.0.3.0,无需升级。

    WIN7系统的系统盘上只安装10.2.0.3.0数据库软件。。

    然后再单独创建数据库(单独创建的数据库文件位置同样存放再DISK1中如:oradb,覆盖掉再XP系统中ORACLE创建的数据库文件)。

    然后回到切换至XP系统,将WIN7系统中ORACLE目录oracle"product"10.2.0"db_1"database下的SPFILEORCL.ORA复制到XP系统中oracle同级

    目录下SPFILEORCL.ORA覆盖掉。启动数据库会出现ORA-00201 ,ORA-00202错误,解决方法如下:

           进入cmd运行界面。用sysdba账号登陆。然后运行以下命令:

    create pfile from spfile;

           shutdown immediate

           startup mount pfile='d:"oracle"product"10.1.0"Db_2"database"initorcl.ora'

    show parameter compatible

    shutdown immediate

    startup

    检查运行,完成后创建表空间等信息、完成后返回WIN7系统,即可同步操作数据。此方法是双击冷备的思想。

    posted @ 2009-08-09 00:11 飞飞 阅读(1286) | 评论 (0)编辑 收藏

    在pl/sql里怎样进行半,全角转换? 
    To_Multi_Byte(str)
    To_Single_Byte(str)
    posted @ 2009-04-16 14:40 飞飞 阅读(322) | 评论 (0)编辑 收藏

    转http://www.gzit.org/27/viewspace-3306.html

    package com;

    import java.util.ArrayList;关注ITz]'p6g5n-KlX
    import java.util.List;

    public class SimpleTest{关注IT1rq3XJw8K.uk&fK$w
     关注IT IQvF'S3U
     /**
    ZyJ9l2@9@K0  *关注IT)~d3X(v*^ \jn3M
      * @return  所有公司
    t8~)^.L.kq9Y0  */关注IT_ s9A?i:^Z
     public List<Company> getAllCompany(){
    `Gq(c rzCG0  List<Company> list = new ArrayList<Company>();关注ITyc?n#P3H
      Company company = null;关注ITm n"o@a%vF#p8O
      company = new Company(1,"广西博联信息通信技术有限责任公司");关注IT7p9wloKHs
      list.add(company);
    \t%? EgoZ/Jl3FI6r0  company = new Company(2,"能创信息科技有限责任公司");关注IT:kA E+Kh#UI
      list.add(company);
    @"E}.U0t,V1I0  return list;关注IT9l#W*{"s&m
     }
    !l0{"PF/z&y R9a.o/y0 
    Ue3t N0^q%v.E0 /**
    )^ D*FpTn+a5I!e0  *关注IT[1r^3g"Q,Ih
      * @param companyId  公司编号
    -aWE)@QP&?}0  * @return  公司下所有部门
    @4M,|PVgn!H L0  */关注IT0ZGrm:b'?
     public List<Department> getDepartment(int companyId){
    W(o&TK Is0hC0  List<Department> list = new ArrayList<Department>();关注IT4V0v(t)v1J.TM,m.y
      Department department = null;
    Wvc(d"g4D eV2A0  if(companyId==1){关注IT]$Z$X*W*mv8`%qQ
       department = new Department(1,1,"软件事业部");关注IT]!A F)AV\$I5J
       list.add(department);关注ITIYRRcSj
       department = new Department(2,1,"工程部");关注ITU rCpeq8M
       list.add(department);
    5O#{ `8v8Ta)}B$L0  }else{关注IT ug,L?5[:y@k C:]
       department = new Department(1,2,"企管部");关注ITk/BY3iM/X,`%e
       list.add(department);关注IT&I7Z9{5`kV/l Avj |5L
       department = new Department(2,2,"财务部");
    b'jm;yVa'Ww;Ea0   list.add(department);
    z W Pp$yx3M0  }关注ITG gA3V5t0^ xM
      return list;
    4O v#k$x:P3n0 }关注IT$tV5JN8sF u:FJ
     
    y'b-^Bma0 /**关注IT/A(^g]jU P*u-\,H
      *关注IT:m'| NmVWtX/Y
      * @param departmentId  部门编号关注IT} l)^8GbA
      * @return   部门下所有员工关注IT.^VB |7V;b D'J'eH+n
      */
    2gkge \x/ip-c4tW0 public List<Person> getPerson(int departmentId){关注ITFR*B5bnj_2[&Q
      List<Person> list = new ArrayList<Person>();
    A@T5y8M]:H5h/c0  Person person = null;关注ITK Z-M ~MF
      if(departmentId==1){关注IT\t.T\3Mx
       person = new Person(1,1,"张三");关注ITe)_3a4xcw
       list.add(person);
    wkw2P)G u7G(Z0   person = new Person(2,1,"李四");
    { uhJ;y9V&C` H0   list.add(person);
    %q(xK1? VR0  }else{
    s|] l)J:@o,p@y0   person = new Person(1,2,"王五");关注ITi'j*FST I
       list.add(person);关注IT^@j { x US i
       person = new Person(2,2,"赵六");关注IT ux#kse o;W
       list.add(person);
    4B/cP*v5z [P0  }关注IT g Bc!D)p*jB)X
      return list;关注IT'X:[] lH
     }

    }
    d z-]6Gn/T9f1OR0

    package com;

    public class Company {

     private int id;关注IT|:NQQ,|8W,D!QV
     private String companyName;
    $ffG s&X1|I0 关注ITy*eK ~4xog
     public Company(int id,String companyName){
    .q;k2a&}j*LL0  this.id = id;
    '\ u:Jpv)j0  this.companyName = companyName;关注ITV[,Ty8Fu
     }

     public int getId() {关注IT:F| |n-n!w$sX5PL
      return id;
    NPPJ,?0 }

     public void setId(int id) {关注ITh2emjTe il+[D
      this.id = id;
    W@b ` L4i0 }

     public String getCompanyName() {关注IT$wP8oO%} ?xe4k
      return companyName;
    S0Kz%GX$?auN W0 }

     public void setCompanyName(String companyName) {
    zMv*g ic8S&YqcN0  this.companyName = companyName;
    v\'x-pT0 }

    }
    *mHu$CU~wb9x x0

    package com;

    public class Department {

     private int id;关注IT [n0zYU
     private int companyId;关注IT$S __L'FDvy2WD
     private String departmentName;

     public Department(int id, int companyId, String departmentName) {
    ,ni)o5G$yL'[o(}Q0  this.id = id;
    q3Gzw"E6v8?o.MT0  this.companyId = companyId;关注IT+r"mo:pO$L![4U
      this.departmentName = departmentName;
    /q\6Aj5]0m3G#l-P9a0 }

     public int getId() {
    w"j`I` J0  return id;
    x(P!d6tu v a"T0 }

     public void setId(int id) {关注ITlQ1r8wS5_'hb
      this.id = id;关注IT pGy3Jl{0tkW
     }

     public int getCompanyId() {
    @!PpRi0  return companyId;关注ITs c!i"DQ5_D
     }

     public void setCompanyId(int companyId) {关注ITrp` i5D/_L
      this.companyId = companyId;关注ITYT+Y6CkJ t2x
     }

     public String getDepartmentName() {
    fSa p.@9e&L0  return departmentName;关注IT!Pe L6m D7n wM
     }

     public void setDepartmentName(String departmentName) {关注IT/bD(o/RPq
      this.departmentName = departmentName;
    '|S4q p4]0 }

    }关注IT){0[0DsY:te9V A r$T

    package com;

    public class Person {

     private int id;
    U{*D:dw+i6W0 private int departmentId;
    q6a e ?5u5\ b|0?]KI0 private String userName;

     public Person(int id,int departmentId, String userName) {关注IT#c%qN s2Xup kIc
      this.id = id;关注ITs%z&uZ2T Bbj
      this.departmentId = departmentId;
    |5nI&y.LO y)Cx(C.r b"x0  this.userName = userName;关注IT_,ep*n(H
     }

     public int getDepartmentId() {关注IT&ue1rG X%WJN[
      return departmentId;
    "qn%DVY2mGh0 }

     public void setDepartmentId(int departmentId) {关注ITa? d(_7s
      this.departmentId = departmentId;关注IT+`vt Pb4oS
     }

     public String getUserName() {
    ]etq"Seza0  return userName;
    3fZn} j-z(V+ir,a0 }

     public void setUserName(String userName) {
    9pWKaR|0  this.userName = userName;
    ~FT_7a/l6lD$}V0 }

     public int getId() {
    *i:k5KIZyr'o0  return id;
    g+j[M(o`0 }

     public void setId(int id) {
    vBj&P/` DUqB0  this.id = id;
    :x:d5MOwo0 }

    }
    -KIsR)D9j7a+VDr rE3Ve0

    <?xml version="1.0" encoding="UTF-8"?>关注ITWF0A~V
    <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "dwr10.dtd" >关注IT GszT,f+Fc:RT
    <dwr>
    P/QC qq)cf0 <allow>关注IT.M%D9A4u{A&^`
      <!-- 声明哪个类可以提供JS直接调用 -->
    Nf9r/PN%N-Du)D0  <create javascript="SimpleTest" creator="new">关注IT'T G m*[5A\#|1~;`%Y
       <param name="class" value="com.SimpleTest"></param>
    \u)NR5z5QSP7t&@0   <!-- 该类里公开出来给JS调用的方法 -->
    sh+c`K#sL'T#l0   <include method="getAllCompany" />关注IT$|i'^(lf$`y[2x I
       <include method="getDepartment" />
    cP(^2LF5c:K$s*ce0   <include method="getPerson" />
    _/J0?wiqL%w0  </create>
    /zms8Vonw0  <!-- 类型转换 -->关注IT N*a#}ip*^H
      <convert match="com.Person" converter="bean">
    .pV*p:QtOB0   <param name="include" value="id,departmentId,userName"></param>
    5v8V6|3`U-WPya)nS0  </convert>
    vu| ow4J b ^)@0  <convert match="com.Department" converter="bean">关注IT.g SgkS'u S]`
       <param name="include" value="id,companyId,departmentName"></param>关注ITX~_L nT
      </convert>
    p3G!a/V;|y0  <convert match="com.Company" converter="bean">关注IT W6L q.dtp%Qv\
       <param name="include" value="id,companyName"></param>
    z+sas-D)C"PS,|0  </convert>关注ITD/g|U2c:Y
     </allow>关注IT"['f&XZ`~
    </dwr>关注IT,FruT'[ m%A1M

    <%@ page language="java" pageEncoding="GB18030"%>关注IT*B&kW!{i
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    lgX^J G0<html>关注ITi'l*l#zG(q
      <head>   
    uLA#O!~1s:c@0    <title>My JSP 'simpleTest.jsp' starting page</title>
    eI-k1b-TDW w0   关注IT7g h.ICd(r
     <meta. http-equiv="pragma" content="no-cache">关注ITQ _-x5Mm
     <meta. http-equiv="cache-control" content="no-cache">关注ITe}yN |"S
     <meta. http-equiv="expires" content="0">   关注ITax(bO%Odh
     <meta. http-equiv="keywords" content="keyword1,keyword2,keyword3">
    t%X$Wjx&VH.`0 <meta. http-equiv="description" content="This is my page">
    /[Y7V5~PEWQ p0 
    5b Z{3V!q O V5x1u!e0  </head>
    )gD&OE\0  <script. type="text/javascript" src="dwr/engine.js"></script>关注IT1r"V3R{cP/~3Jc7Q
      <script. type="text/javascript" src="dwr/util.js"></script>关注IT#bM"@K,O@ X
      <script. type="text/javascript" src="dwr/interface/SimpleTest.js"></script>关注ITi(V6w \6~!l/a A#s [
     
    6_*@k$wN0  <body nload="initial()">关注IT!nt9lT`1e/M%h
      <script. type="text/javascript">
    y]#zLJE0  /*页面初始加载公司栏目*/关注IT?%]%wR7ICTg0_
      function initial(){
    'h&BHt iEU0     SimpleTest.getAllCompany(function(data){dealSelect("i",data)});关注ITjty,Fwrb
      }关注IT&I!\_N d4xYHd
      /*获取下拉菜单的值并填充下一栏目*/
    w)UR!qK$ma0  function show(flag){关注IT(y4Ff L4U5i
         if(flag=="c"){关注ITI$o+U{]r+k[Y
         var companyId = $("company").value;
    _$|"Q7s)K-m"[/z*[)n0     SimpleTest.getDepartment(companyId,function(data){dealSelect(flag,data)});
    cAj9K(u/g] E)I v6Iw0     }else if(flag=="d"){
    J$L&o2}pD6kw0     var departmentId = $("department").value;
    u}u'`\6~d*^0     SimpleTest.getPerson(departmentId,function(data){dealSelect(flag,data)});  
    0@Vy ~cZF |0     } 
    'X#Wc ?'| nW0  }关注ITk @#n[[&L&_OP5]4_o
      /*填充select的内容*/
    NgcV,[0X0  function dealSelect(flag,data){
    G YKF-I6HRfu)d0    clearSelect(flag);
    1tC0BTVC?r3F0    if(flag=="c"){
    *Td\#}%kT(|0    DWRUtil.addOptions("department",data,"id","departmentName");
    9N#R2Pt4B0    }else if(flag=="d"){
    Oj"@2V$l,{6L:K0    DWRUtil.addOptions("person",data,"id","userName");关注IT(I'Syg7[g[ l+R5r"l
        }else if(flag=="i"){
    d'X'Fj5JJQ!Z8~0    DWRUtil.addOptions("company",data,"id","companyName");关注IT R W8[| x9a1QFq
        }
    ~m+hRysQ P T,c)?a0@0  }关注IT!e6B&wgK6a6W4f
      /*清除下拉表单的内容*/
    6n`%~ j,_RU0  function clearSelect(flag){关注ITC1z#B-a6g3f/u*_
        if(flag=="c"){
    I5c'e3n(|b0       var tmp = $("department");
    )P$oa7G0AQ/o$cb0       while(tmp.childNodes.length>1){关注ITP(vJsB?XE"@
           tmp.removeChild(tmp.lastChild);
    ew)j^q0       }
    0H+J,D R8i0    }else if(flag="d"){关注ITl UJS P)e _-W
           var tmp = $("person");关注ITb-j-[&d&S }`[
           while(tmp.childNodes.length>1){
    h8iOK4e0       tmp.removeChild(tmp.lastChild);
    qTBv)hZ#v:X{+n0       }关注ITJZ,P0_C
        }关注IT`Tt5D({7P
      } 
    y1ipi*J0  /*清空select里的内容*/
    })uTT-t"Y0  </script>关注ITc ^2Wf ]p%g
        公司:<select id='company' nchange="show('c')"><option value="">======</option></select>关注ITLAD"Ei f8zo2uO
        部门:<select id='department' nchange="show('d')"><option value="">======</option></select>
    z/VjF&{({0    成员:<select id='person'><option value="">======</option></select>
    j!IJ$dQ0  </body>
    ;R$n'W7L){ n*^P IE.tr0</html>关注ITT[$[*l;x9I] N

    posted @ 2008-10-26 19:36 飞飞 阅读(544) | 评论 (0)编辑 收藏

    12:52:31,162  INFO Logger:51 - Logging using commons-logging.
    12:52:31,287  INFO DWRServlet:51 - retrieved system configuration file: weblogic.utils.zip.SafeZipFileInputStream@2453319
    12:52:31,334  INFO DefaultConfiguration:51 - Creator 'jsf' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: javax/faces/el/ValueBinding (jsf-api.jar)
    12:52:31,349  INFO DefaultConfiguration:51 - Creator 'pageflow' not loaded due to ClassNotFoundException. This is only an problem if you wanted to use it. Cause: Beehive/Weblogic Creator not available. (可以不用理会)
    12:52:31,349  INFO DefaultConfiguration:51 - Creator 'script' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: org/apache/bsf/BSFException (bsf-2.3.0.jar)
    12:52:31,412  INFO DefaultConfiguration:51 - Converter 'jdom' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: org/jdom/Document  (jdom-1.0.jar)
    12:52:31,443  INFO DefaultConfiguration:51 - Converter 'hibernate' not loaded due to ClassNotFoundException. This is only an problem if you wanted to use it. Cause: Failed to find either org.hibernate.Hibernate or net.sf.hibernate.Hibernate (hibernate-3.0.1.jar ).
    12:52:31,459  INFO DefaultConverterManager:51 - Type 'org.jdom.Document' is not convertable due to missing converter 'jdom'. This is only an problem if you wanted to use it.
    12:52:31,459  INFO DefaultConverterManager:51 - Type 'org.jdom.Element' is not convertable due to missing converter 'jdom'. This is only an problem if you wanted to use it.

    添加相应的包,
    http://www.findjar.com/jar/jdom/jars/jdom-1.0.jar.html
    http://www.java2s.com/Code/Jar/Spring-Related/Downloadjsfapijar.htm
    查找相应的CLASS,下载包


    13:20:43,131  WARN DefaultConverterManager:59 - Missing type info for save_yhsj(0<0>). Assuming this is a map with String keys. Please add to <signatures> in dwr.xml
    13:20:43,131  WARN DefaultConverterManager:59 - Missing type info for save_yhsj(0<1>). Assuming this is a map with String keys. Please add to <signatures> in dwr.xml
    13:20:43,146  INFO ExecuteQuery:51 - Exec[0]: FyglImpl.save_yhsj()

    在页面中:
    function saveSjjl(){
       var param=new Object();
       param["S_nbxh"]=document.form1.S_nbxh.value;
       param["S_yhmc"]=document.form2.S_yhmc.value;
       param["D_cbsj"]=document.form2.D_cbsj.value;
       param["S_rqsj"]=document.form2.S_rqsj.value;
       param["S_cbry"]=document.form2.S_cbry.value;
       FyglImpl.save_yhsj(param,{
        callback:function(str) {
         $('saveSjjl').disabled = true;
         alert("保存成功!");
        },
        timeout:5000,
          errorHandler:function(message) { alert("Oops: " + message); }
       });
      }
    CLASS中:
    public void save_yhsj(Map param) {}
    解决方法:
    <signatures>
      <![CDATA[
        import java.util.Map;
        import com.fygl.implement.FyglImpl;
        FyglImpl.save_yhsj(Map<String,String> param);
        ]]>
     </signatures>
    posted @ 2008-09-05 13:07 飞飞 阅读(2802) | 评论 (2)编辑 收藏

    replace(replace(str,chr(13),''),chr(10),'')

    update hz_qyfddbr h set jl=(select replace(replace(jl,chr(13),''),chr(10),'') from hz_qyfddbr r where r.nbxh=h.nbxh  )
    posted @ 2008-09-03 12:30 飞飞 阅读(2532) | 评论 (1)编辑 收藏

    今天需要使用个本地化的问题,努力看了点资料,终于解决
    COPE点资料来保存

    用户定义指令-使用@符合来调用
    有两种不同的类型:Macro(宏)和transform(传递器),Macro是在模板中使用macro指令定义,而transform是在模板外由程序定义(基本上都是基于Java的),这里通过Macro来介绍自定义指令。
    例一:
    <#macro greet>
    <font size="+2">Hello Joe!</font>
    </#macro>
    使用:<@greet></@greet> 或 <@greet/>
    结果:<font size="+2">Hello Joe!</font>

    参数-在macro指令中可以在宏变量之后定义参数
    例二:
    <#macro greet person>
    <font size="+2">Hello ${person}!</font>
    </#macro>
    使用:<@greet person="Fred"/> and <@greet person="Batman"/>
    结果: <font size="+2">Hello Fred!</font> and <font size="+2">Hello Batman!</font>

    macro可以有多个参数,参数的次序是无关的,在macro指令中只能使用定义的参数,并且必须对所有参数赋值,可以在定义参数时指定缺省值:

    <#macro greet person color="black">
    <font size="+2" color="${color}">Hello ${person}!</font>
    </#macro>


    在自定义指令嵌套内容:模板片断中使用<#nested>指令

    <#macro border>
    <table border=4 cellspacing=0 cellpadding=4><tr><td>
    <#nested>
    </tr></td></table>
    </#macro>
    使用:<@border>The bordered text</@border>
    结果:

    <table border=4 cellspacing=0 cellpadding=4>
    <tr><td>The bordered text
    </tr></td></table>
    <#nested>指令可以被多次调用:

    <#macro do_thrice>
    <#nested>
    <#nested>
    <#nested>
    </#macro>
    使用:
    <@do_thrice>Anything.</@do_thrice>
    结果:
    Anything.
    Anything.
    Anything.

    注意:嵌套内容是无法访问到macro中的局部变量的。
    例如:

    <#macro repeat count>
    <#local y = "test">
    <#list 1..count as x>
    ${y} ${count}/${x}: <#nested>
    </#list>
    </#macro>
    <@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat>
    结果:
    test 3/1: ? ? ?
    test 3/2: ? ? ?
    test 3/3: ? ? ?


    下面是一个嵌套使用自定义指令的例子:

    <@border>
    <ul>
    <@do_thrice>
    <li><@greet person="Joe"/>
    </@do_thrice>
    </ul>
    </@border>
    结果:

    <table border=4 cellspacing=0 cellpadding=4><tr><td>
    <ul>
    <li><font size="+2">Hello Joe!</font>
    <li><font size="+2">Hello Joe!</font>
    <li><font size="+2">Hello Joe!</font>
    </ul>
    </tr></td></table>
    macro中使用循环变量-作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字:

    <#macro repeat count>
    <#list 1..count as x>
    <#nested x, x/2, x==count>
    </#list>
    </#macro>
    <@repeat count=4 ; c, halfc, last>
    ${c}. ${halfc}<#if last> Last!</#if>
    /@repeat
    结果:
    1. 0.5
    2. 1
    3. 1.5
    4. 2 Last!

    注意:循环变量和用户定义指令开始标记指定的数目可以不同,调用时少指定循环变量,则多指定的值不可见,调用时多指定循环变量,多余的循环变量不会被创建。

    模板中的变量,有三种类型:
    1.) plain(全局)变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换
    2.) 局部变量:在macro中有效,使用local指令创建和替换
    3.) 循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量

    用assign指令创建和替换的例子:

    <#assign x = 1> <#-- create variable x -->
    ${x}
    <#assign x = x + 3> <#-- replace variable x -->
    ${x}
    结果:
    1
    4

    局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:

    <#assign x = "plain">
    1. ${x} <#-- we see the plain var. here -->
    <@test/>
    6. ${x} <#-- the value of plain var. was not changed -->
    <#list ["loop"] as x>
    7. ${x} <#-- now the loop var. hides the plain var. -->
    <#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
    8. ${x} <#-- it still hides the plain var. -->
    </#list>
    9. ${x} <#-- the new value of plain var. -->

    <#macro test>
    2. ${x} <#-- we still see the plain var. here -->
    <#local x = "local">
    3. ${x} <#-- now the local var. hides it -->
    <#list ["loop"] as x>
    4. ${x} <#-- now the loop var. hides the local var. -->
    </#list>
    5. ${x} <#-- now we see the local var. again -->
    </#macro>
    结果:
    1. plain
    2. plain
    3. local
    4. loop
    5. local
    6. plain
    7. loop
    8. loop
    9. plain2

    内部循环变量隐藏同名的外部循环变量,例如:

    <#list ["loop 1"] as x>
    ${x}
    <#list ["loop 2"] as x>
    ${x}
    <#list ["loop 3"] as x>
    ${x}
    </#list>
    ${x}
    </#list>
    ${x}
    </#list>
    结果:
    loop 1
    loop 2
    loop 3
    loop 2
    loop 1

    模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:

    <#assign user = "Joe Hider">
    ${user} <#-- prints: Joe Hider -->
    ${.globals.user} <#-- prints: Big Joe -->
    命名(namespaces)空间-通常情况,只使用一个命名空间,称为主命名空间(main namespace),但你是不会意识到这些的;为了创建可重用的macro、transforms或其它变量的集合(通常称库),必须使用多命名空间,为了防止同名冲突。

    首先创建一个库(假设保存在lib/my_test.ftl中):

    <#macro copyright date>
    <p>Copyright (C) ${date} Julia Smith. All rights reserved.
    <br>Email: ${mail}</p>
    </#macro>
    <#assign mail = "jsmith@acme.com">
    使用import指令导入库到模板中,Freemarker会为导入的库创建新的命名空间,并可以通过import指令中指定的hash(散列)变量访问库中的变量:

    <#import "/lib/my_test.ftl" as my>
    <#assign mail="fred@acme.com">
    <@my.copyright date="1999-2002"/>
    ${my.mail}
    ${mail}
    结果:

    <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
    <br>Email: jsmith@acme.com</p>
    jsmith@acme.com
    fred@acme.com
    上面的例子中使用的两个同名变量并没有冲突,因为它们位于不同的命名空间

    可以使用assign指令在导入的命名空间中创建或替代变量:

    <#import "/lib/my_test.ftl" as my>
    ${my.mail}
    <#assign mail="jsmith@other.com" in my>
    ${my.mail}
    结果:
    jsmith@acme.com
    jsmith@other.com

    数据模型中的变量任何地方都可见,也包括不同的命名空间,下面修改了刚才创建的库:

    <#macro copyright date>
    <p>Copyright (C) ${date} ${user}. All rights reserved.</p>
    </#macro>
    <#assign mail = "${user}@acme.com">
    假设数据模型中的user变量的值是Fred:

    <#import "/lib/my_test.ftl" as my>
    <@my.copyright date="1999-2002"/>
    ${my.mail}
    结果:
    <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
    Fred@acme.com

    最后用macro指令解决问题,

    <#macro zch code text="dd">
      <#include "/view/xtgl/xtsjwh/zchsz${ThemeHelpersMap[code]?default(text)}.js"> 
     </#macro>
     <@zch code="jc"/>
    posted @ 2008-08-23 18:05 飞飞 阅读(627) | 评论 (0)编辑 收藏

    10:05:05,937  INFO QyFunctionImpl:16 -  Update xhgl set xh=69 where  table_name='sl_yhzcnr' 
    10:05:05,984  INFO XmlBeanDefinitionReader:158 - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
    10:05:06,000  INFO SQLErrorCodesFactory:120 - SQLErrorCodes loaded: [DB2, HSQL, MS-SQL, MySQL, Oracle, Informix, PostgreSQL, Sybase]
    10:05:06,046 ERROR DispatcherServlet:412 - Could not complete request
    org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ Update xhgl set xh=69 where  table_name='sl_yhzcnr'  ]; SQL state [S1009]; error code [0]; Connection is read-only. Queries leading to data modification are not allowed.; nested exception is java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
    java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
     at com.mysql.jdbc.SQLError.createSQLException(Ljava.lang.String;Ljava.lang.String;)Ljava.sql.SQLException;(SQLError.java:910)
     at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;Z)I(Statement.java:1265)
     at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:1235)
     at weblogic.jdbc.wrapper.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:360)
     at org.springframework.jdbc.core.JdbcTemplate$1UpdateStatementCallback.doInStatement(Ljava.sql.Statement;)Ljava.lang.Object;(JdbcTemplate.java:381)
     at org.springframework.jdbc.core.JdbcTemplate.execute(Lorg.springframework.jdbc.core.StatementCallback;)Ljava.lang.Object;(JdbcTemplate.java:254)
     at org.springframework.jdbc.core.JdbcTemplate.update(Ljava.lang.String;)I(JdbcTemplate.java:391)
     at com.yhgl.implement.QyFunctionImpl.getXh(Ljava.lang.String;)Ljava.lang.String;(QyFunctionImpl.java:17)
     at com.yhgl.implement.QyFunctionImpl$$FastClassByCGLIB$$86b27578.invoke(ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(<generated>:0)
     at net.sf.cglib.proxy.MethodProxy.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(MethodProxy.java:149)
     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()Ljava.lang.Object;(Cglib2AopProxy.java:698)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:122)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Lorg.aopalliance.intercept.MethodInvocation;)Ljava.lang.Object;(TransactionInterceptor.java:96)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:144)
     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;Lnet.sf.cglib.proxy.MethodProxy;)Ljava.lang.Object;(Cglib2AopProxy.java:643)
     at com.yhgl.implement.QyFunctionImpl$$EnhancerByCGLIB$$abfcb417.getXh(Ljava.lang.String;)Ljava.lang.String;(<generated>:0)
     at com.contorller.Yhdjcontroller.save_nr(Ljavax.servlet.http.HttpServletRequest;Lorg.springframework.web.servlet.ModelAndView;)Ljava.lang.String;(Yhdjcontroller.java:79)
     at com.contorller.Yhdjcontroller.save(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(Yhdjcontroller.java:51)
     at jrockit.reflect.NativeMethodInvoker.invoke0(Ljava.lang.Object;ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at jrockit.reflect.NativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
     at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(Ljava.lang.String;Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:403)
     at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:358)
     at org.springframework.web.servlet.mvc.AbstractController.handleRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(AbstractController.java:139)
     at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;Ljava.lang.Object;)Lorg.springframework.web.servlet.ModelAndView;(SimpleControllerHandlerAdapter.java:44)
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:684)
     at org.springframework.web.servlet.DispatcherServlet.doService(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:625)
     at org.springframework.web.servlet.FrameworkServlet.processRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:392)
     at org.springframework.web.servlet.FrameworkServlet.doPost(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:357)
     at javax.servlet.http.HttpServlet.service(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServlet.java:760)
     at javax.servlet.http.HttpServlet.service(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(HttpServlet.java:853)
    <2008-8-21 上午10时05分06秒 CST> <Error> <HTTP> <BEA-101020> <[ServletContext(id=36466092,name=SpringMVC,context-path=/SpringMVC)] Servlet failed with Exception
    org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ Update xhgl set xh=69 where  table_name='sl_yhzcnr'  ]; SQL state [S1009]; error code [0]; Connection is read-only. Queries leading to data modification are not allowed.; nested exception is java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
    java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
     at com.mysql.jdbc.SQLError.createSQLException(Ljava.lang.String;Ljava.lang.String;)Ljava.sql.SQLException;(SQLError.java:910)
     at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;Z)I(Statement.java:1265)
     at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:1235)
     at weblogic.jdbc.wrapper.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:360)
     at org.springframework.jdbc.core.JdbcTemplate$1UpdateStatementCallback.doInStatement(Ljava.sql.Statement;)Ljava.lang.Object;(JdbcTemplate.java:381)
     at org.springframework.jdbc.core.JdbcTemplate.execute(Lorg.springframework.jdbc.core.StatementCallback;)Ljava.lang.Object;(JdbcTemplate.java:254)
     at org.springframework.jdbc.core.JdbcTemplate.update(Ljava.lang.String;)I(JdbcTemplate.java:391)
     at com.yhgl.implement.QyFunctionImpl.getXh(Ljava.lang.String;)Ljava.lang.String;(QyFunctionImpl.java:17)
     at com.yhgl.implement.QyFunctionImpl$$FastClassByCGLIB$$86b27578.invoke(ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(<generated>:0)
     at net.sf.cglib.proxy.MethodProxy.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(MethodProxy.java:149)
     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()Ljava.lang.Object;(Cglib2AopProxy.java:698)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:122)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Lorg.aopalliance.intercept.MethodInvocation;)Ljava.lang.Object;(TransactionInterceptor.java:96)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:144)
     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;Lnet.sf.cglib.proxy.MethodProxy;)Ljava.lang.Object;(Cglib2AopProxy.java:643)
     at com.yhgl.implement.QyFunctionImpl$$EnhancerByCGLIB$$abfcb417.getXh(Ljava.lang.String;)Ljava.lang.String;(<generated>:0)
     at com.contorller.Yhdjcontroller.save_nr(Ljavax.servlet.http.HttpServletRequest;Lorg.springframework.web.servlet.ModelAndView;)Ljava.lang.String;(Yhdjcontroller.java:79)
     at com.contorller.Yhdjcontroller.save(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(Yhdjcontroller.java:51)
     at jrockit.reflect.NativeMethodInvoker.invoke0(Ljava.lang.Object;ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at jrockit.reflect.NativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
     at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
     at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(Ljava.lang.String;Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:403)
     at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:358)
     at org.springframework.web.servlet.mvc.AbstractController.handleRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(AbstractController.java:139)
     at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;Ljava.lang.Object;)Lorg.springframework.web.servlet.ModelAndView;(SimpleControllerHandlerAdapter.java:44)
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:684)
     at org.springframework.web.servlet.DispatcherServlet.doService(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:625)
     at org.springframework.web.servlet.FrameworkServlet.processRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:392)
     at org.springframework.web.servlet.FrameworkServlet.doPost(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:357)
     at javax.servlet.http.HttpServlet.service(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServlet.java:760)
     at javax.servlet.http.HttpServlet.service(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(HttpServlet.java:853)
    >

    <bean id="baseTxService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
      abstract="true">
      <property name="transactionManager" ref="transactionManager" />
      <property name="proxyTargetClass" value="true" />
      <property name="transactionAttributes">
       <props>
        <prop key="save*">PROPAGATION_REQUIRED</prop>
        <prop key="update*">PROPAGATION_REQUIRED</prop>
        <prop key="remove*">PROPAGATION_REQUIRED</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
        <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
       </props>
      </property>
     </bean>
    posted @ 2008-08-21 10:07 飞飞 阅读(4731) | 评论 (0)编辑 收藏

    对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间类型。

    这里是一个使用日期函数的例子。下面的查询选择了所有记录,其date_col的值是在最后30天以内:

    mysql> SELECT something FROM table
    WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) select DAYOFWEEK('1998-02-03');
    -> 3

    WEEKDAY(date)
    返回date的星期索引(0=星期一,1=星期二, ……6= 星期天)。
    mysql> select WEEKDAY('1997-10-04 22:23:00');
    -> 5
    mysql> select WEEKDAY('1997-11-05');
    -> 2

    DAYOFMONTH(date)
    返回date的月份中日期,在1到31范围内。
    mysql> select DAYOFMONTH('1998-02-03');
    -> 3

    DAYOFYEAR(date)
    返回date在一年中的日数, 在1到366范围内。
    mysql> select DAYOFYEAR('1998-02-03');
    -> 34

    MONTH(date)
    返回date的月份,范围1到12。
    mysql> select MONTH('1998-02-03');
    -> 2

    DAYNAME(date)
    返回date的星期名字。
    mysql> select DAYNAME("1998-02-05");
    -> 'Thursday'

    MONTHNAME(date)
    返回date的月份名字。
    mysql> select MONTHNAME("1998-02-05");
    -> 'February'

    QUARTER(date)
    返回date一年中的季度,范围1到4。
    mysql> select QUARTER('98-04-01');
    -> 2

    WEEK(date)
     
    WEEK(date,first)
    对于星期天是一周的第一天的地方,有一个单个参数,返回date的周数,范围在0到52。2个参数形式WEEK()允许
    你指定星期是否开始于星期天或星期一。如果第二个参数是0,星期从星期天开始,如果第二个参数是1,
    从星期一开始。
    mysql> select WEEK('1998-02-20');
    -> 7
    mysql> select WEEK('1998-02-20',0);
    -> 7
    mysql> select WEEK('1998-02-20',1);
    -> 8

    YEAR(date)
    返回date的年份,范围在1000到9999。
    mysql> select YEAR('98-02-03');
    -> 1998

    HOUR(time)
    返回time的小时,范围是0到23。
    mysql> select HOUR('10:05:03');
    -> 10

    MINUTE(time)
    返回time的分钟,范围是0到59。
    mysql> select MINUTE('98-02-03 10:05:03');
    -> 5

    SECOND(time)
    回来time的秒数,范围是0到59。
    mysql> select SECOND('10:05:03');
    -> 3

    PERIOD_ADD(P,N)
    增加N个月到阶段P(以格式YYMM或YYYYMM)。以格式YYYYMM返回值。注意阶段参数P不是日期值。
    mysql> select PERIOD_ADD(9801,2);
    -> 199803

    PERIOD_DIFF(P1,P2)
    返回在时期P1和P2之间月数,P1和P2应该以格式YYMM或YYYYMM。注意,时期参数P1和P2不是日期值。
    mysql> select PERIOD_DIFF(9802,199703);
    -> 11

    DATE_ADD(date,INTERVAL expr type)
     
    DATE_SUB(date,INTERVAL expr type)
     
    ADDDATE(date,INTERVAL expr type)
     
    SUBDATE(date,INTERVAL expr type)
    这些功能执行日期运算。对于MySQL 3.22,他们是新的。ADDDATE()和SUBDATE()是DATE_ADD()和DATE_SUB()的同义词。
    在MySQL 3.23中,你可以使用+和-而不是DATE_ADD()和DATE_SUB()。(见例子)date是一个指定开始日期的
    DATETIME或DATE值,expr是指定加到开始日期或从开始日期减去的间隔值一个表达式,expr是一个字符串;它可以以
    一个“-”开始表示负间隔。type是一个关键词,指明表达式应该如何被解释。EXTRACT(type FROM date)函数从日期
    中返回“type”间隔。下表显示了type和expr参数怎样被关联: type值 含义 期望的expr格式
    SECOND 秒 SECONDS
    MINUTE 分钟 MINUTES
    HOUR 时间 HOURS
    DAY 天 DAYS
    MONTH 月 MONTHS
    YEAR 年 YEARS
    MINUTE_SECOND 分钟和秒 "MINUTES:SECONDS"
    HOUR_MINUTE 小时和分钟 "HOURS:MINUTES"
    DAY_HOUR 天和小时 "DAYS HOURS"
    YEAR_MONTH 年和月 "YEARS-MONTHS"
    HOUR_SECOND 小时, 分钟, "HOURS:MINUTES:SECONDS"
    DAY_MINUTE 天, 小时, 分钟 "DAYS HOURS:MINUTES"
    DAY_SECOND 天, 小时, 分钟, 秒 "DAYS HOURS:MINUTES:SECONDS"

    MySQL在expr格式中允许任何标点分隔符。表示显示的是建议的分隔符。如果date参数是一个DATE值并且你的计算仅仅
    包含YEAR、MONTH和DAY部分(即,没有时间部分),结果是一个DATE值。否则结果是一个DATETIME值。

    mysql> SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
    -> 1998-01-01 00:00:00
    mysql> SELECT INTERVAL 1 DAY + "1997-12-31";
    -> 1998-01-01
    mysql> SELECT "1998-01-01" - INTERVAL 1 SECOND;
    -> 1997-12-31 23:59:59
    mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
    INTERVAL 1 SECOND);
    -> 1998-01-01 00:00:00
    mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
    INTERVAL 1 DAY);
    -> 1998-01-01 23:59:59
    mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
    INTERVAL "1:1" MINUTE_SECOND);
    -> 1998-01-01 00:01:00
    mysql> SELECT DATE_SUB("1998-01-01 00:00:00",
    INTERVAL "1 1:1:1" DAY_SECOND);
    -> 1997-12-30 22:58:59
    mysql> SELECT DATE_ADD("1998-01-01 00:00:00",
    INTERVAL "-1 10" DAY_HOUR);
    -> 1997-12-30 14:00:00
    mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
    -> 1997-12-02
    mysql> SELECT EXTRACT(YEAR FROM "1999-07-02");
    -> 1999
    mysql> SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");
    -> 199907
    mysql> SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");
    -> 20102

    如果你指定太短的间隔值(不包括type关键词期望的间隔部分),MySQL假设你省掉了间隔值的最左面部分。例如,
    如果你指定一个type是DAY_SECOND,值expr被希望有天、小时、分钟和秒部分。如果你象"1:10"这样指定值,
    MySQL假设日子和小时部分是丢失的并且值代表分钟和秒。换句话说,"1:10" DAY_SECOND以它等价于"1:10" MINUTE_SECOND
    的方式解释,这对那MySQL解释TIME值表示经过的时间而非作为一天的时间的方式有二义性。如果你使用确实不正确的日期,
    结果是NULL。如果你增加MONTH、YEAR_MONTH或YEAR并且结果日期大于新月份的最大值天数,日子在新月用最大的天调整。

    mysql> select DATE_ADD('1998-01-30', Interval 1 month);
    -> 1998-02-28

    注意,从前面的例子中词INTERVAL和type关键词不是区分大小写的。
    TO_DAYS(date)
    给出一个日期date,返回一个天数(从0年的天数)。
    mysql> select TO_DAYS(950501);
    -> 728779
    mysql> select TO_DAYS('1997-10-07');
    -> 729669

    TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。

    FROM_DAYS(N)
    给出一个天数N,返回一个DATE值。
    mysql> select FROM_DAYS(729669);
    -> '1997-10-07'

    TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。

    DATE_FORMAT(date,format)
    根据format字符串格式化date值。下列修饰符可以被用在format字符串中: %M 月名字(January……December)
    %W 星期名字(Sunday……Saturday)
    %D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
    %Y 年, 数字, 4 位
    %y 年, 数字, 2 位
    %a 缩写的星期名字(Sun……Sat)
    %d 月份中的天数, 数字(00……31)
    %e 月份中的天数, 数字(0……31)
    %m 月, 数字(01……12)
    %c 月, 数字(1……12)
    %b 缩写的月份名字(Jan……Dec)
    %j 一年中的天数(001……366)
    %H 小时(00……23)
    %k 小时(0……23)
    %h 小时(01……12)
    %I 小时(01……12)
    %l 小时(1……12)
    %i 分钟, 数字(00……59)
    %r 时间,12 小时(hh:mm:ss [AP]M)
    %T 时间,24 小时(hh:mm:ss)
    %S 秒(00……59)
    %s 秒(00……59)
    %p AM或PM
    %w 一个星期中的天数(0=Sunday ……6=Saturday )
    %U 星期(0……52), 这里星期天是星期的第一天
    %u 星期(0……52), 这里星期一是星期的第一天
    %% 一个文字“%”。

    所有的其他字符不做解释被复制到结果中。

    mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
    -> 'Saturday October 1997'
    mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
    -> '22:23:00'
    mysql> select DATE_FORMAT('1997-10-04 22:23:00',
    '%D %y %a %d %m %b %j');
    -> '4th 97 Sat 04 10 Oct 277'
    mysql> select DATE_FORMAT('1997-10-04 22:23:00',
    '%H %k %I %r %T %S %w');
    -> '22 22 10 10:23:00 PM 22:23:00 00 6'
    MySQL3.23中,在格式修饰符字符前需要%。在MySQL更早的版本中,%是可选的。

    TIME_FORMAT(time,format)
    这象上面的DATE_FORMAT()函数一样使用,但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。
    其他修饰符产生一个NULL值或0。
    CURDATE()
     
    CURRENT_DATE
    以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值,取决于函数是在一个字符串还是数字上下文被使用。
    mysql> select CURDATE();
    -> '1997-12-15'
    mysql> select CURDATE() + 0;
    -> 19971215

    CURTIME()
     
    CURRENT_TIME
    以'HH:MM:SS'或HHMMSS格式返回当前时间值,取决于函数是在一个字符串还是在数字的上下文被使用。
    mysql> select CURTIME();
    -> '23:50:26'
    mysql> select CURTIME() + 0;
    -> 235026

    NOW()
     
    SYSDATE()
     
    CURRENT_TIMESTAMP
    以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回当前的日期和时间,取决于函数是在一个字符串还是在数字的
    上下文被使用。
    mysql> select NOW();
    -> '1997-12-15 23:50:26'
    mysql> select NOW() + 0;
    -> 19971215235026

    UNIX_TIMESTAMP()
     
    UNIX_TIMESTAMP(date)
    如果没有参数调用,返回一个Unix时间戳记(从'1970-01-01 00:00:00'GMT开始的秒数)。如果UNIX_TIMESTAMP()用一
    个date参数被调用,它返回从'1970-01-01 00:00:00' GMT开始的秒数值。date可以是一个DATE字符串、一个DATETIME
    字符串、一个TIMESTAMP或以YYMMDD或YYYYMMDD格式的本地时间的一个数字。
    mysql> select UNIX_TIMESTAMP();
    -> 882226357
    mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
    -> 875996580

    当UNIX_TIMESTAMP被用于一个TIMESTAMP列,函数将直接接受值,没有隐含的“string-to-unix-timestamp”变换。

    FROM_UNIXTIME(unix_timestamp)
    以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回unix_timestamp参数所表示的值,取决于函数是在一个字符串
    还是或数字上下文中被使用。
    mysql> select FROM_UNIXTIME(875996580);
    -> '1997-10-04 22:23:00'
    mysql> select FROM_UNIXTIME(875996580) + 0;
    -> 19971004222300

    FROM_UNIXTIME(unix_timestamp,format)
    返回表示 Unix 时间标记的一个字符串,根据format字符串格式化。format可以包含与DATE_FORMAT()函数列出的条
    目同样的修饰符。
    mysql> select FROM_UNIXTIME(UNIX_TIMESTAMP(),
    '%Y %D %M %h:%i:%s %x');
    -> '1997 23rd December 03:43:30 x'

    SEC_TO_TIME(seconds)
    返回seconds参数,变换成小时、分钟和秒,值以'HH:MM:SS'或HHMMSS格式化,取决于函数是在一个字符串还是在数字
    上下文中被使用。
    mysql> select SEC_TO_TIME(2378);
    -> '00:39:38'
    mysql> select SEC_TO_TIME(2378) + 0;
    -> 3938

    TIME_TO_SEC(time)
    返回time参数,转换成秒。
    mysql> select TIME_TO_SEC('22:23:00');
    -> 80580
    mysql> select TIME_TO_SEC('00:39:38');
    -> 2378

    ---------------------------------------------------------------------------------------------------------------------------

    mysql日期处理函数

    mysql日期处理函数

    mysql自己有格式化日期格式的函数,可以在查询语句中使用
    DATE_FORMAT(date,format)
    根据format字符串格式化date值。下列修饰符可以被用在format字符串中: %M  月名字(January……December)  
    %W  星期名字(Sunday……Saturday)  
    %D  有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
    %Y  年, 数字, 4 位
    %y  年, 数字, 2 位
    %a  缩写的星期名字(Sun……Sat)  
    %d  月份中的天数, 数字(00……31)  
    %e  月份中的天数, 数字(0……31)  
    %m  月, 数字(01……12)  
    %c  月, 数字(1……12)  
    %b  缩写的月份名字(Jan……Dec)  
    %j  一年中的天数(001……366)  
    %H  小时(00……23)  
    %k  小时(0……23)  
    %h  小时(01……12)  
    %I  小时(01……12)  
    %l  小时(1……12)  
    %i  分钟, 数字(00……59)  
    %r  时间,12 小时(hh:mm:ss [AP]M)  
    %T  时间,24 小时(hh:mm:ss)  
    %S  秒(00……59)  
    %s  秒(00……59)  
    %p  AM或PM  
    %w  一个星期中的天数(0=Sunday ……6=Saturday )
    %U  星期(0……52), 这里星期天是星期的第一天
    %u  星期(0……52), 这里星期一是星期的第一天
    %%  一个文字“%”。  

    如需要用php处理,可先用strtotime函数将日期转换为unix时间戳,再用date函数格式化
    posted @ 2008-08-20 12:36 飞飞 阅读(337) | 评论 (0)编辑 收藏

    对于Weblogic8.1可直接修改eauser_projectsdomainsmydomain下的startweblogic.cmd

    找到 “Set classpath=”,加入mysql.jar的路径,如:

    set CLASSPATH=C:mysql.jar;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%jrelib t.jar;%WL_HOME%serverlibwebservices.jar;%CLASSPATH%


    mysql.jar的路径最好放在最前面。

    当weblogic合成在myeclipse中的时候,在myeclipse的weblogic的classpath中设置驱动的路径
    posted @ 2008-08-19 16:33 飞飞 阅读(775) | 评论 (0)编辑 收藏

    1)控制台报The WebLogic Server did not start up properly.
    java.io.InvalidClassException: javax.management.MBeanAttributeInfo; local class incompatible: stream classdesc serialVersionUID = 7043855487133450673, local class serialVersionUID = 8644704819898565848
    错误原因及解决办法:MBeanAttributeInfo的serialVersionUID的版本控制id不一样,说明是使用这个被使用的bean被修改过了,很显然是版本不对;修改startWebLogic.cmd文件,设置set JAVA_HOME=D:\bea\jdk141_05,使其指向weblogic自带的jdk;重启startWebLogic.cmd问题消失。

    2)错误报Deployment descriptor "web.xml" is malform
    ed. Check against the DTD: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find

    错误原因及解决办法:解析web.xml出现问题,修改OPEN_CMS\webapp\WEB-INF\web.xml文件;在该文件的 最上面添加如下内容:

    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

    重新启动错误消失。

    3)错误为Deployment descriptor "/WEB-INF/
    web.xml" is malformed. Check against the DTD: The content of element type "t
    ag" must match "(name,tag-class,tei-class?,body-content?,display-name?,small-ico
    n?,large-icon?,description?,variable*,attribute*,example?)". (line 40, column 11
    ).>

    错误原因及解决办法:由于weblogic8在解析xml文件时,对xml文件的内容格式要求特别严格;必须按照xml格式的要求

    及排列顺序,所以必须重新组织其内容,一定严格要注意顺序,如 <servlet>就不能放在<servlet-mapping>后面。

    4)错误java.lang.SecurityException: Prohibited package name: java.lang

    错误原因及解决办法:访问包可视的方法或变量错误;这个错误恨少见,一直没有想明白其中缘由;后来只能采用直接引用jar文件的法子解决该问题;

    i)利用opencms自带的build.xml文件,运行ant jar命令;生成opencms.jar和webdav.jar两个文件

    ii)在startWebLogic.cmd添加如下内容,引进上面的2个jar文件

    set CLASSPATH=%CLASSPATH%;%OPEN_CMS%\build\opencms.jar
    set CLASSPATH=%CLASSPATH%;%OPEN_CMS%\build\webdav.jar

    大家有兴趣的可以参考《透视JAVA——反编译、修补和逆向工程技术》这本书的$4.2章的内容,如果找到更好的解决方法也请来信告知,谢谢~_~

    5)其它注意事项,在eclipse下最好采用和运行weblogic一样的jdk版本进行编译,否则会出现文件访问版本不一致的bug

    posted @ 2008-08-19 14:14 飞飞 阅读(1501) | 评论 (0)编辑 收藏

     

    posted @ 2008-08-18 17:51 飞飞 阅读(11316) | 评论 (3)编辑 收藏

    2.调用有简单返回值的java方法
    2.1、dwr.xml的配置
    配置同1.1
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod2"/>
    </create>
    </allow>
    </dwr>
    2.2、javascript中调用
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数和接收返回值的回调函数
    Function callTestMethod2(){
    testClass.testMethod2(callBackFortestMethod2);
    }
    Function callBackFortestMethod2(data){
    //其中date接收方法的返回值
    //可以在这里对返回值进行处理和显示等等
    alert("the return value is " + data);
    }
    其中callBackFortestMethod2是接收返回值的回调函数


    3、调用有简单参数的java方法
    3.1、dwr.xml的配置
    配置同1.1
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod3"/>
    </create>
    </allow>
    </dwr>
    3.2、javascript中调用
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数
    Function callTestMethod3(){
    //定义要传到java方法中的参数
    var data;
    //构造参数
    data = “test String”;
    testClass.testMethod3(data);
    }


    4、调用返回JavaBean的java方法
    4.1、dwr.xml的配置
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod4"/>
    </create>
    <convert converter="bean" match=""com.dwr.TestBean">
    <param name="include" value="username,password" />
    </convert>
    </allow>
    </dwr>
    <creator>标签负责公开用于Web远程的类和类的方法,<convertor>标签则负责这些方法的参数和返回类型。convert元素的作用是告诉DWR在服务器端Java 对象表示和序列化的JavaScript之间如何转换数据类型。DWR自动地在Java和JavaScript表示之间调整简单数据类型。这些类型包括Java原生类型和它们各自的封装类表示,还有String、Date、数组和集合类型。DWR也能把JavaBean转换成JavaScript 表示,但是出于安全性的原因,要求显式的配置,<convertor>标签就是完成此功能的。converter="bean"属性指定转换的方式采用JavaBean命名规范,match=""com.dwr.TestBean"属性指定要转换的javabean名称,<param>标签指定要转换的JavaBean属性。
    4.2、javascript中调用
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数和接收返回值的回调函数
    Function callTestMethod4(){
    testClass.testMethod4(callBackFortestMethod4);
    }
    Function callBackFortestMethod4(data){
    //其中date接收方法的返回值
    //对于JavaBean返回值,有两种方式处理
    //不知道属性名称时,使用如下方法
    for(var property in data){
    alert("property:"+property);
    alert(property+":"+data[property]);
    }
    //知道属性名称时,使用如下方法
    alert(data.username);
    alert(data.password);
    }
    其中callBackFortestMethod4是接收返回值的回调函数

    5、调用有JavaBean参数的java方法
    5.1、dwr.xml的配置
    配置同4.1
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod5"/>
    </create>
    <convert converter="bean" match="com.dwr.TestBean">
    <param name="include" value="username,password" />
    </convert>
    </allow>
    </dwr>
    5.2、javascript中调用
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数
    Function callTestMethod5(){
    //定义要传到java方法中的参数
    var data;
    //构造参数,date实际上是一个object
    data = { username:"user", password:"password" }
    testClass.testMethod5(data);
    }


    6、调用返回List、Set或者Map的java方法
    6.1、dwr.xml的配置
    配置同4.1
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod6"/>
    </create>
    <convert converter="bean" match="com.dwr.TestBean">
    <param name="include" value="username,password" />
    </convert>
    </allow>
    </dwr>
    注意:如果List、Set或者Map中的元素均为简单类型(包括其封装类)或String、Date、数组和集合类型,则不需要<convert>标签。
    6.2、javascript中调用(以返回List为例,List的元素为TestBean)
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数和接收返回值的回调函数
    Function callTestMethod6(){
    testClass.testMethod6(callBackFortestMethod6);
    }
    Function callBackFortestMethod6(data){
    //其中date接收方法的返回值
    //对于JavaBean返回值,有两种方式处理
    //不知道属性名称时,使用如下方法
    for(var i=0;i<data.length;i++){
    for(var property in data){
    alert("property:"+property);
    alert(property+":"+data[property]);
    }
    }
    //知道属性名称时,使用如下方法
    for(var i=0;i<data.length;i++){
    alert(data[i].username);
    alert(data[i].password);
    }
    }


    7、调用有List、Set或者Map参数的java方法
    7.1、dwr.xml的配置
    <dwr>
    <allow>
    <create creator="new" javascript="testClass" >
    <param name="class" value="com.dwr.TestClass" />
    <include method="testMethod7"/>
    </create>
    <convert converter="bean" match="com.dwr.TestBean">
    <param name="include" value="username,password" />
    </convert>
    </allow>
    <signatures>
    <![CDATA[
    import java.util.List;
    import com.dwr.TestClass;
    import com.dwr.TestBean;
    TestClass.testMethod7(List<TestBean>);
    ]]>
    </signatures>
    </dwr>
    <signatures>标签是用来声明java方法中List、Set或者Map参数所包含的确切类,以便java代码作出判断。
    7.2、javascript中调用(以返回List为例,List的元素为TestBean)
    首先,引入javascript脚本
    其次,编写调用java方法的javascript函数
    Function callTestMethod7(){
    //定义要传到java方法中的参数
    var data;
    //构造参数,date实际上是一个object数组,即数组的每个元素均为object
    data = [
    {
    username:"user1",
    password:"password2"
    },
    {
    username:"user2",
    password:" password2"
    }
    ];
    testClass.testMethod7(data);
    }

    注意:
    1、对于第6种情况,如果java方法的返回值为Map,则在接收该返回值的javascript回调函数中如下处理:
    function callBackFortestMethod(data){
    //其中date接收方法的返回值
    for(var property in data){
    var bean = data[property];
    alert(bean.username);
    alert(bean.password);
    }
    }
    2、对于第7种情况,如果java的方法的参数为Map(假设其key为String,value为TestBean),则在调用该方法的javascript函数中用如下方法构造要传递的参数:
    function callTestMethod (){
    //定义要传到java方法中的参数
    var data;
    //构造参数,date实际上是一个object,其属性名为Map的key,属性值为Map的value
    data = {
    "key1":{
    username:"user1",
    password:"password2"
    },
    "key2":{
    username:"user2",
    password:" password2"
    }
    };
    testClass.testMethod(data);
    }
    并且在dwr.xml中增加如下的配置段
    <signatures>
    <![CDATA[
    import java.util.List;
    import com.dwr.TestClass;
    import com.dwr.TestBean;
    TestClass.testMethod7(Map<String,TestBean>);
    ]]>
    </signatures>
    3、由以上可以发现,对于java方法的返回值为List(Set)的情况,DWR将其转化为Object数组,传递个javascript;对于java方法的返回值为Map的情况,DWR将其转化为一个Object,其中Object的属性为原Map的key值,属性值为原Map相应的value值。
    4、如果java方法的参数为List(Set)和Map的情况,javascript中也要根据3种所说,构造相应的javascript数据来传递到java中。
    posted @ 2008-08-15 14:56 飞飞 阅读(377) | 评论 (0)编辑 收藏

    FreeMarker的指令的文件就称为模板(Template)。
    模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。
    数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。

    数据类型:

    一、基本:
    1、scalars:存储单值

    字符串:简单文本由单或双引号括起来。
    数字:直接使用数值。
    日期:通常从数据模型获得
    布尔值:true或false,通常在<#if …>标记中使用

    2、hashes:充当其它对象的容器,每个都关联一个唯一的查询名字

    具有一个唯一的查询名字和他包含的每个变量相关联。

    3、sequences:充当其它对象的容器,按次序访问

    使用数字和他包含的每个变量相关联。索引值从0开始。

    4、集合变量:

    除了无法访问它的大小和不能使用索引来获得它的子变量:集合可以看作只能由<#list...>指令使用的受限sequences。

    5、方法:通过传递的参数进行计算,以新对象返回结果

    方法变量通常是基于给出的参数计算值在数据模型中定义。

    6、用户自定义FTL指令:宏和变换器

    7、节点

    节点变量表示为树型结构中的一个节点,通常在XML处理中使用。

    模板:

    使用FTL(freeMarker模板语言)编写

    组成部分

    一、整体结构

    1、注释:<#--注释内容-->,不会输出。

    2、文本:直接输出。

    3、interpolation:由 ${var} 或 #{var} 限定,由计算值代替输出。

    4、FTL标记

    二、指令:
    freemarker指令有两种:
    1、预定义指令:引用方式为<#指令名称>
    2、用户定义指令:引用方式为<@指令名称>,引用用户定义指令时须将#换为@。
    注意:如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。

    freemarker指令由FTL标记来引用,FTL标记和HTML标记类似,名字前加#来加以区分。如HTML标记的形式为<h1></h1>则FTL标记的形式是<#list></#list>(此处h1标记和list指令没有任何功能上的对应关系,只是做为说明使用一下)。

    有三种FTL标记:
    1)、开始标记:<#指令名称>
    2)、结束标记:</#指令名称>
    3)、空标记:<#指令名称/>

    注意:

    1) FTL会忽略标记之中的空格,但是,<#和指令 与 </#和指令 之间不能有空格。
    2) FTL标记不能够交叉,必须合理嵌套。每个开始标记对应一个结束标记,层层嵌套。 如:
    <#list>
    <li>
    ${数据}
    <#if 变量>
    <p>game over!</p>
    </#if>
    </li>
    </#list>

    注意事项:
    1)、FTL对大小写敏感。所以使用的标记及interpolation要注意大小写。name与NAME就是不同的对象。<#list>是正确的标记,而<#List>则不是。
    2)、interpolation只能在文本部分使用,不能位于FTL标记内。如<#if ${var}>是错误的,正确的方法是:<#if var>,而且此处var必须为布尔值。
    3)、FTL标记不能位于另一个FTL标记内部,注释例外。注释可以位于标记及interpolation内部。


    三、表达式

    1、直接指定值:

    1-1、字符串:
    由双引号或单引号括起来的字符串,其中的特殊字符(如' " \等)需要转义。


    1-2、raw字符串:
    有一种特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:
    ${r"/${data}"year""}屏幕输出结果为:/${data}"year"


    转义 含义
    序列

    \" 双引号(u0022)

    \' 单引号(u0027)

    \\ 反斜杠(u005C)

    \n 换行(u000A)

    \r Return (u000D)

    \t Tab (u0009)

    \b Backspace (u0008)

    \f Form feed (u000C)

    \l <

    \g >

    \a &

    \{ {

    \xCode 4位16进制Unicode代码

    1-3、数字:直接输入,不需要引号

    1)、精度数字使用“.”分隔,不能使用分组符号
    2)、目前版本不支持科学计数法,所以“1E3”是错误的
    3)、不能省略小数点前面的0,所以“.5”是错误的
    4)、数字8、+8、08和8.00都是相同的

    1-4、布尔值:true和false,不使用引号

    1-5、序列:由逗号分隔的子变量列表,由[]方括号限定。
    1)、子变量列表可以是表达式
    2)、可以使用数字范围定义数字序列,<b>不需要方括号限定</b>,例如2..5等同于[2, 3, 4, 5],但是更有效率,可以定义反递增范围如:5..2。

    1-6、散列(hash)
    1)、由逗号分隔的键/值列表,由{}大括号限定,键和值之间用冒号分隔,如:{"key1":valu1,"key2":"character string"....}
    2)、键和值都是表达式,但是键必须是字符串。

    2、获取变量:

    2-1、顶层变量:${变量名}

    变量名只能是字母、数字、下划线、$、#、@ 的组合,且不能以数字开头。

    2-2、散列:有两种方法

    1)、点语法:变量名字和顶层变量的名字受同样的限制
    2)、方括号语法:变量名字无限制,可以是任意的表达式的结果
    book.author.name
    book.author.["name"]
    book["author"].name
    book["author"]["name"]
    以上是等价的。

    2-3、序列:使用散列的方括号语法获取变量,方括号中的表达式结果必须为数字。注意:第一个项目的索引为0。可以使用
    [startindex..endindex]语法获取序列片段。

    2-4、特殊变量:FreeMarker内定义变量,使用.variablename语法访问。

    3、字符串操作

    3-1、interpolation:使用${}或#{}在文本部分插入表达式的值,例如:

    ${"hello${username}!"}
    ${"${username}${username}${username}"}

    也可以使用+来获得同样的结果:
    ${"hello"+username+"!"}
    ${username+username+username}

    注意:${}只能用于文本部分而不能出现于标记内。

    <#if ${user.login}>或<#if "${user.login}">都是错误的;
    <#if user.login>是正确的。
    本例中user.login的值必须是布尔类型。

    3-2、子串:
    举例说明:假如user的值为"Big Joe"
    ${user[0]}${user[4]}结果是:BJ
    ${user[1..4]}结果是:ig J

    4、序列操作

    4-1、连接操作:可以使用+来操作,例如:
    ["title","author"]+["month","day"]

    5、散列操作
    5-1、连接操作:可以使用+来操作,如果有相同的KEY,则右边的值会替代左边的值,例如:
    {"title":散列,"author":"emma"}+{"month":5,"day":5}+{"month":6}结果month的值就是6。

    6、算术运算

    6-1、操作符:+、-、*、/、%
    除+号以外的其他操作符两边的数据,必须都是数字类型。
    如果+号操作符一边有一个字符型数据,会自动将另一边的数据转换为字符型数据,运算结果为字符型数据。

    6-2、比较操作符:
    1)、=
    2)、==
    3)、!=
    4)、<
    5)、<=
    6)、>
    7)、>=
    1-3的操作符,两边的数据类型必须相同,否则会产生错误
    4-7的操作符,对于日期和数字可以使用,字符串不可以使用。

    注意:
    1)、FreeMarker是精确比较,所以"x" "x " "X"是不等的。
    2)、因为<和>对FTL来说是开始和结束标记,所以,可以用两种方法来避免这种情况:
    一种是使用括号<#if (a<b)>
    另一是使用替代输出,对应如下:
    < lt
    <= lte
    > gt
    >= gte

    6-3、逻辑操作符:只能用于布尔值,否则会出现错误。

    &&(and)与运算
    ||(or)或运算
    !(not)非运算

    6-4、内建函数:使用方法类似于访问散列的子变量,只是使用?代替.例如:${test?upper_case?html}

    常用的内建函数列举如下:

    1)、字符串使用:

    html:对字符串进行HTML编码
    cap_first:字符串第一个字母大写
    lower_first:字符串第一个字母小写
    upper_case:将字符串转换成大写
    trim:去年字符前后的空白字符

    2)、序列使用:
    size:获得序列中元素的数目

    3)、数字使用:
    int:取得数字的整数部分

    7、操作符的优先顺序:

    后缀:[subbarName][subStringRange].(mathodParams)
    一元:+expr、-expr、! (not)
    内建:?
    乘法:*、/、%
    加法:+、-
    关系:<、<=、>、>= (lt、lte、gt、gte)
    相等:=、==、!=
    逻辑与:&& (and)
    逻辑或:|| (or)
    数字范围:..

    四、interpolation

    inperpolation只能用于文本,有两种类型:通用interpolation及数字interpolation

    1、通用interpolation

    如${expr}

    1-1、插入字符串值:直接输出表达式结果。
    1-2、插入数字值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:
    <#setting number_format="currency" />
    <#assign answer=42 />
    ${answer} <#-- ¥42.00 -->
    ${answer?string} <#-- ¥42.00 -->
    ${answer?string.number} <#-- 42 -->
    ${answer?string.currency} <#-- ¥42.00 -->
    ${answer?string.percent} <#-- 42,00% -->

    1-3、插入日期值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:

    ${lastupdata?string("yyyy-MM-dd HH:mm:ss zzzz")} <#-- 2003-04-08 21:24:44 Pacific Daylight Time -->
    ${lastupdata?string("EEE,MMM d, ''yy")} <#-- tue,Apr 8, '03 -->
    ${lastupdata?string("EEEE,MMMM dd, yyyy,hh:mm:ss a '('zzz')'")} <#-- Tuesday,April 08, 2003, 09:24:44 PM (PDT)-->

    1-4、插入布尔值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:
    <#assign foo=ture />
    ${foo?string("yes","no")} <#-- yes -->

    2、数字interpolation:

    有两种形式:
    1)、#{expr}
    2)、#{expr;format}:format可以用来格式化数字,format可以是如下:
    mX:小数部分最小X位
    MX:小数部分最大X位

    例如:
    <#assign x=2.582 />
    <#assign y=4 />
    #{x;M2} <#-- 2.58 -->
    #{y;M2} <#-- 4 -->
    #{x;m1} <#-- 2.582 -->
    #{y;m1} <#-- 4.0 -->
    #{x;m1M2} <#-- 2.58 -->
    #{y;m1M2} <#-- 4.0 -->


    杂项

    一、用户定义指令

    宏和变换器变量是两种不同类型的用户自定义指令,他们的区别是:

    宏可以在模板中用macro指令来定义
    变换器是在模板外由程序定义

    1、宏:和某个变量关联的模板片段,以便在模板中通过用户自定义指令使用该变量
    1-1、基本用法:
    例如:
    <#macro greet>
    <font size="+2"> Hello JOE!</font>
    </#macro>


    使用时:
    <@greet></@greet>
    如果没有体内容也可以用
    <@greet />

    1-2、变量:

    1)、可以在宏定义之后定义参数,宏参数是局部变量,只在宏定义中有效。如:

    <#macro greet person>
    <font size="+2"> Hello ${person}!</font>
    </#macro>
    使用时:
    <@greet person="emma"> and <@greet person="LEO">
    输出为:
    <font size="+2"> Hello emma!</font>
    <font size="+2"> Hello LEO!</font>

    注意:宏的参数是FTL表达式,所以,person=emma和上面的例子中具有不同的意义,这意味着将变量emma的值传给person,这个值可能是任意一种数据类型,甚至是一个复杂的表达式。


    宏可以有多个参数,使用时参数的次序是无关的,但是只能使用宏中定义的参数,并且对所有参数赋值。如:
    <#macro greet person color>
    <font size="+2" color="${color}"> Hello ${person}!</font>
    </#macro>

    使用时:
    <@greet color="black" person="emma" />正确
    <@greet person="emma" />错误,color没有赋值,此时,如果在定义宏时为color定义缺省值<#macro greet person color="black">这样的话,这个使用方法就是正确的。
    <@greet color="black" person="emma" bgcolor="yellow" />错误,宏greet定义中未指定bgcolor这个参数



    2、嵌套内容:

    2-1、自定义指令可以有嵌套内容,使用<#nested>指令,执行自定义指令开始和结束标记之间的模板片段。例如:
    <#macro greet>
    <p>
    <#nested>
    </p>
    </#macro>


    <@greet>hello Emma!</@greet>

    输出为
    <p>hello Emma!</p>

    2-2、<#nested>指令可以被多次调用,例如
    <#macro greet>
    <p>
    <#nested>
    <#nested>
    <#nested>
    <#nested>
    </p>
    </#macro>

    <@greet>hello Emma!</@greet>

    输出为
    <p>
    hello Emma!
    hello Emma!
    hello Emma!
    hello Emma!
    </p>

    2-3、嵌套的内容可以是有效的FTL,例如:
    <#macro welcome>
    <p>
    <#nested>
    </p>
    </#macro>

    <#macro greet person color="black">
    <font size="+2" color="${color}"> Hello ${person}!</font>
    </#macro>

    <@welcome>
    <@greet person="Emma" color="red" />
    <@greet person="Andrew" />
    <@greet person="Peter" />
    </@welcome>

    输出为:
    <p>
    <font size="+2" color="red"> Hello Emma!</font>
    <font size="+2" color="black"> Hello Andrew!</font>
    <font size="+2" color="black"> Hello Peter!</font>
    </p>

    2-4、宏定义中的局部变量对嵌套内容是不可见的,例如:

    <#macro repeat count>
    <#local y="test" />
    <#list 1..count as x>
    ${y}${count}/${x}:<#nested />
    </#list>
    </#macro>

    <@repeat count=3>
    ${y?default("?")}
    ${x?default("?")}
    ${count?default("?")}
    </@repeat>

    输出结果为
    test 3/1:???
    test 3/2:???
    test 3/3:???

    2-5、在宏定义中使用循环变量,通常用来重复嵌套内容,基本用法为:作为nested指令的参数,传递循环变量的实际值,而在调用自定义指令时,在标记的参数后面指定循环变量的名字。
    例如:
    <#macro repeat count>
    <#list 1..count as x>
    <#nested x,x/2,x==count />
    </#list>
    </#macro>

    <@repeat count=4;c,halfc,last>
    ${c}. ${halfc}
    <#if last>
    last!
    </#if>
    </@repeat>

    输出结果是

    1. 0.5
    2. 1
    3. 1.5
    4. 2last!

    注意:指定循环变量的数目和用户定义指令开始标记指定的不同不会有问题
    调用时,少指定循环变量,多指定的值会不见
    调用时,多指定循环变量,多余的循环变量不会被创建

    二、在模板中定义变量

    1、在模板中定义的变量有三种类型

    1-1、plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换。
    1-2、局部变量:在宏定义体中有效,使用local指令创建和替换。
    1-3、循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建。

    注意:
    1)、宏的参数是局部变量,不是循环变量。
    2)、局部变量隐藏同名的plain变量
    3)、循环变量隐藏同名的plain变量和局部变量。

    例如:

    <#assign x="plain">
    1. ${x} <#-- plain -->

    <@test />

    6. ${x}
    <#list ["loop"] as x>
    7. ${x} <#-- loop -->
    <#assign x="plain2">
    8. ${x} <#-- loop -->
    </#list>
    9. ${x} <#-- plain2 -->

    <#macro test>
    2. ${x} <#-- plain -->
    <#local x="local">
    3. ${x} <#-- local -->
    <#list ["loop"] as x>
    4. ${x} <#-- loop -->
    </#list>
    5. ${x} <#-- local -->
    </#macro>

    4)、内部循环变量隐藏同名的外部循环变量

    <#list ["loop1"] as x>
    ${x} <#-- loop1 -->
    <#list ["loop2"] as x>
    ${x} <#-- loop2 -->
    <#list ["loop3"] as x>
    ${x} <#-- loop3 -->
    </#list>
    ${x} <#-- loop2 -->
    </#list>
    ${x} <#-- loop1 -->
    </#list>

    5)、模板中的变量会隐藏数据模型中的同名变量,如果需访问数据模型中的变量,使用特殊变量global。

    例如:
    假设数据模型中的user值为Emma
    <#assign user="Man">
    ${user} <#-- Man -->
    ${.global.user} <#-- Emma -->
    posted @ 2008-08-15 14:35 飞飞 阅读(263) | 评论 (0)编辑 收藏

    一:
    myeclipse 傻瓜式的完成spring和hibernate的载入;
    注意需要把lib里面的asm-XXcommons-collections-XX 低版本的删除掉,因为载入spring和hibernate的时候会装在2个不一样的版本,包冲突.
    记得把dwr的包放进去
    数据库用mysql.
    CREATE TABLE `book` (
      `id` int(11) NOT NULL auto_increment,
      `name` varchar(11) default NULL,
      `isbm` varchar(11) default NULL,
      `author` varchar(11) default NULL,
      PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk;
    id为自动增长
    二:
    完成上步后用hibernate的反向机制,完成数据库表的映射
    如下:
    AbstractBook.java

    package com;

    /**
     * AbstractBook generated by MyEclipse Persistence Tools
     */

    public abstract class AbstractBook implements java.io.Serializable {

     // Fields

     private Integer id;
     private String name;
     private String isbm;
     private String author;

     // Constructors

     /** default constructor */
     public AbstractBook() {
     }

     /** full constructor */
     public AbstractBook(String name, String isbm, String author) {
      this.name = name;
      this.isbm = isbm;
      this.author = author;
     }

     // Property accessors

     public Integer getId() {
      return this.id;
     }

     public void setId(Integer id) {
      this.id = id;
     }

     public String getName() {
      return this.name;
     }

     public void setName(String name) {
      this.name = name;
     }

     public String getIsbm() {
      return this.isbm;
     }

     public void setIsbm(String isbm) {
      this.isbm = isbm;
     }

     public String getAuthor() {
      return this.author;
     }

     public void setAuthor(String author) {
      this.author = author;
     }

    }


    Book.java

    package com;

    // Generated by MyEclipse Persistence Tools

    /**
     * Book generated by MyEclipse Persistence Tools
     */
    public class Book extends AbstractBook implements java.io.Serializable {

     // Constructors

     /** default constructor */
     public Book() {
     }

     /** full constructor */
     public Book(String name, String isbm, String author) {
      super(name, isbm, author);
     }

    }


    BookDAO.java

    package com;

    import java.util.List;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.hibernate.LockMode;
    import org.springframework.context.ApplicationContext;
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

    /**
     * Data access object (DAO) for domain model class Book.
     *
     * @see com.Book
     * @author MyEclipse Persistence Tools
     */

    public class BookDAO extends HibernateDaoSupport {
     private static final Log log = LogFactory.getLog(BookDAO.class);

     protected void initDao() {
      // do nothing
     }

     public void save(Book transientInstance) {
      log.debug("saving Book instance");
      try {
       getHibernateTemplate().save(transientInstance);
       log.debug("save successful");
      } catch (RuntimeException re) {
       log.error("save failed", re);
       throw re;
      }
     }

     public void delete(Book persistentInstance) {
      log.debug("deleting Book instance");
      try {
       getHibernateTemplate().delete(persistentInstance);
       log.debug("delete successful");
      } catch (RuntimeException re) {
       log.error("delete failed", re);
       throw re;
      }
     }

     public Book findById(java.lang.Integer id) {
      log.debug("getting Book instance with id: " + id);
      try {
       Book instance = (Book) getHibernateTemplate().get("com.Book", id);
       return instance;
      } catch (RuntimeException re) {
       log.error("get failed", re);
       throw re;
      }
     }

     public List findByExample(Book instance) {
      log.debug("finding Book instance by example");
      try {
       List results = getHibernateTemplate().findByExample(instance);
       log.debug("find by example successful, result size: "
         + results.size());
       return results;
      } catch (RuntimeException re) {
       log.error("find by example failed", re);
       throw re;
      }
     }

     public List findByProperty(String propertyName, Object value) {
      log.debug("finding Book instance with property: " + propertyName
        + ", value: " + value);
      try {
       String queryString = "from Book as model where model."
         + propertyName + "= ?";
       return getHibernateTemplate().find(queryString, value);
      } catch (RuntimeException re) {
       log.error("find by property name failed", re);
       throw re;
      }
     }

     public List findAll() {
      log.debug("finding all Book instances");
      try {
       String queryString = "from Book";
       return getHibernateTemplate().find(queryString);
      } catch (RuntimeException re) {
       log.error("find all failed", re);
       throw re;
      }
     }

     public Book merge(Book detachedInstance) {
      log.debug("merging Book instance");
      try {
       Book result = (Book) getHibernateTemplate().merge(detachedInstance);
       log.debug("merge successful");
       return result;
      } catch (RuntimeException re) {
       log.error("merge failed", re);
       throw re;
      }
     }

     public void attachDirty(Book instance) {
      log.debug("attaching dirty Book instance");
      try {
       getHibernateTemplate().saveOrUpdate(instance);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
     }

     public void attachClean(Book instance) {
      log.debug("attaching clean Book instance");
      try {
       getHibernateTemplate().lock(instance, LockMode.NONE);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
     }

     public static BookDAO getFromApplicationContext(ApplicationContext ctx) {
      return (BookDAO) ctx.getBean("BookDAO");
     }
    }


    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
     <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/applicationContext.xml</param-value>
     </context-param>
     <listener>
      <listener-class>
       org.springframework.web.context.ContextLoaderListener
      </listener-class>
     </listener>
     <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>
     </servlet>

     <servlet-mapping>
      <servlet-name>dwr-invoker</servlet-name>
      <url-pattern>/dwr/*</url-pattern>
     </servlet-mapping>
     <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
     </welcome-file-list>
    </web-app>

     



    Book.hbm.xml

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <!--
        Mapping file autogenerated by MyEclipse Persistence Tools
    -->
    <hibernate-mapping>
        <class name="com.Book" table="book" catalog="test">
            <id name="id" type="java.lang.Integer">
                <column name="id" />
                <generator class="native" />
            </id>
            <property name="name" type="java.lang.String">
                <column name="name" length="11" />
            </property>
            <property name="isbm" type="java.lang.String">
                <column name="isbm" length="11" />
            </property>
            <property name="author" type="java.lang.String">
                <column name="author" length="11" />
            </property>
        </class>
    </hibernate-mapping>

    BookManageService.java 暴露给dwr使用的接口

    package com;

    import java.util.List;

    public interface BookManageService {

     public List<Book> getAllBooks();

     public List<Book> getBookByName(String name);

     public void updateBook(Book book);

     public void addBook(Book book);

     public void deleteBook(Integer id);
    }


    BookManageServiceImpl.java 接口的实现类

    package com;

    import java.util.List;

    public class BookManageServiceImpl implements BookManageService {

     private BookDAO bookDAO;

     public BookDAO getBookDAO() {
      return bookDAO;
     }

     public void setBookDAO(BookDAO bookDAO) {
      this.bookDAO = bookDAO;
     }
     public void addBook(Book book) {
      System.out.println("impl:"+book);
      bookDAO.save(book);
     }

     public void deleteBook(Integer id) {
      Book book = bookDAO.findById(id);
      bookDAO.delete(book);
     }


     @SuppressWarnings("unchecked")
     public List<Book> getAllBooks() {

      return bookDAO.findAll();
     }


     @SuppressWarnings("unchecked")
     public List<Book> getBookByName(String name) {

      return bookDAO.findByProperty(name, name);
     }

     public void updateBook(Book book) {
      bookDAO.attachDirty(book);
     }


    }



    applicationContext.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
     <bean id="dataSource"
      class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName"
       value="com.mysql.jdbc.Driver">
      </property>
      <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
      <property name="username" value="root"></property>
      <property name="password" value="root"></property>
     </bean>
     <bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="dataSource">
       <ref bean="dataSource" />
      </property>
      <property name="hibernateProperties">
       <props>
        <prop key="hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
        </prop>
        <prop key="hibernate.show_sql">true</prop>
       </props>
      </property>
      <property name="mappingResources">
       <list>
        <value>com/Book.hbm.xml</value>
       </list>
      </property>
     </bean>
    <bean id="BookDAO" class="com.BookDAO">
      <property name="sessionFactory">
       <ref bean="sessionFactory" />
      </property>
     </bean>
    <bean id="bookManageServiceTarget"
      class="com.BookManageServiceImpl">
      <property name="bookDAO">
       <ref bean="BookDAO" />
      </property>
     </bean>
     <bean id="transactionManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      <property name="sessionFactory">
       <ref bean="sessionFactory" />
      </property>
     </bean>
     <bean id="bookManageService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager" ref="transactionManager" />
      <property name="target" ref="bookManageServiceTarget" />
      <property name="transactionAttributes">
       <props>
        <prop key="add*">PROPAGATION_REQUIRED</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
        <prop key="update*">PROPAGATION_REQUIRED</prop>
        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
       </props>
      </property>
     </bean>
    </beans>

    dwr.xml

    <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">
    <dwr>
     <allow>
      <convert converter="bean" match="com.Book" />
      <create creator="spring" javascript="BookManageService">
       <param name="beanName" value="bookManageService" />
       <include method="getAllBooks" />
       <include method="getBookByName" />
       <include method="updateBook" />
       <include method="addBook" />
       <include method="deleteBook" />
      </create>
     </allow>
    </dwr>

    index.jsp


    <html>
     <head>
      <title>DWR test</title>
      <script type='text/javascript' src='/shdwr/dwr/interface/BookManageService.js'></script>
      <script type='text/javascript' src='/shdwr/dwr/engine.js'></script>
      <script type='text/javascript' src='/shdwr/dwr/util.js'></script>

      <script type="text/javascript">
            var bookCache ={};
            var currentBook = null;
           
            function loadAllBooks(){
                BookManageService.getAllBooks(handleGetAllBooks,handleGetAllBooksError);
            }
            function handleGetAllBooks(books){
                dwr.util.removeAllRows("booksBody",{ filter:function(tr){
           return (tr.id != "pattern");
           }});
     
                var book,id;
                for(var i = 0; i < books.length; i++){
                    book = books[i];
                  
                    id = book.id;
              
                    dwr.util.cloneNode("pattern", { idSuffix:id });
                    dwr.util.setValue("t_name" + id, book.name);
                    dwr.util.setValue("t_isbm" + id, book.isbm);
                    dwr.util.setValue("t_author" + id,book.author);
                   $("pattern" + id).style.display = "block";
                   bookCache[id] = book;
                }
            }
            function handleGetAllBooksError(msg){
                alert("Error: " + msg);
            }
           
            function addBook(){
                var book ={name:null,isbm:null,author:null};
                dwr.util.getValues(book);
                dwr.engine.beginBatch();
                     BookManageService.addBook(book);
                     loadAllBooks();
                  dwr.engine.endBatch();
            }
           
            function editBook(btId){
                currentBook = bookCache[btId.substring(4)];
                dwr.util.setValues(currentBook);
            }
           
            function updateBook(){
                var book = {id:null,name:null,isbm:null,author:null};
                dwr.util.getValues(book);
                book.id = currentBook.id;
                BookManageService.updateBook(book,handleUpdateBook,handleUpdateBookError);
            }
           
            function handleUpdateBook(){
                alert("Update book successfully!");
                loadAllBooks();
            }
           
            function handleUpdateBookError(msg){
                alert("Error: " + msg);
            }
           
            function deleteBook(btId){
                var i = confirm("Are you sure to delete the book?");
                if(i == true)
                    BookManageService.deleteBook(btId.substring(6),handleDeleteBook,handleDeleteBookError);
            }
           
            function handleDeleteBook(){
              alert("The book has been delete successfully!");
              loadAllBooks();
            }
           
            function handleDeleteBookError(msg){
              alert("Error: " + msg);
            }
            function reset(){
               dwr.util.setValue("name", "");
               dwr.util.setValue("isbm", "");
               dwr.util.setValue("author", "");
            }
        </script>
     </head>


     <body onload="loadAllBooks()">
      <div>
       <h2>
        Add book
       </h2>
       <table>
        <tr>
         <td>
          Name:
         </td>
         <td>
          <input type="text" id="name">
         </td>
        </tr>
        <tr>
         <td>
          ISBN:
         </td>
         <td>
          <input type="text" id="isbm">
         </td>
        </tr>

        <tr>
         <td>
          Author:
         </td>
         <td>
          <input type="text" id="author">
         </td>
        </tr>
        <tr>
         <td colspan="2">
          <input type="button" id="add" value="Add" onclick="addBook()">
          <input type="reset"  id="reset" value="reset" onclick="reset()">
          <input type="button" id="update" value="Update"
           onclick="updateBook()">
         </td>
        </tr>
       </table>
      </div>
      <hr>
      <div id="list">
       <table border="1">
        <thead>
         <tr>
          <th>
           Name
          </th>
          <th>
           ISBN
          </th>
          <th>
           Author
          </th>
          <th>
           Action
          </th>
         </tr>
        </thead>
        <tbody id="booksBody">
         <tr id="pattern" style="display: none;">
          <td>
           <span id="t_name"></span>
          </td>
          <td>
           <span id="t_isbm"></span>
          </td>
          <td>
           <span id="t_author"></span>
          </td>
          <td>
           <span id="action"> <input id="edit" type="button"
             value="Edit" onclick="editBook(this.id)" /> <input id="delete"
             type="button" value="Delete" onclick="deleteBook(this.id)" />
           </span>
          </td>
         </tr>
        </tbody>
       </table>
      </div>
     </body>


    posted @ 2008-08-13 19:55 飞飞 阅读(643) | 评论 (0)编辑 收藏

    1、addRows 增添数据行到指定的table
       方法基本语法:dwr.util.addRows(id, array, cellfuncs, [options]);
          * id:table 的 id (最好是一个tbody的id)
        * array: 需要被填充到table里的数据对象,可以是数组,集合等对象,每一个数组元素对应table的一行
        * cellfuncs: function数组 每个元素对应table某一列数据的取得方式
        * options: 包含几个属性的对象(可选)
      
        options:(来源:www.iocblog.net)
        # 属性rowCreator: 一个function,默认返回document.createElement("tr"),可以编辑返回自定义的tr(比如不同的样式)
        # 属性cellCreator: 一个function,默认返回document.createElement("td"),可以编辑返回自定义的tr(比如不同的样式)
        # 属性escapeHtml: 是否转义<,>,&,",'
        
        当所有call back function 都需要转义,则可以使用dwr.util.setEscapeHtml(false)

    2、removeAllRows 把指定table的所有行都移除
        方法基本语法:dwr.util.removeAllRows(id);
        * id:table 的 id (最好是一个tbody的id)
      
      
    3、byId
     你可以把它看成是document.getElementById()的替代版,如果指定的id有多个匹配项,就会返回一个element数组
        方法基本语法:dwr.util.byId(id)
        另:在引入util.js的环境下,你还可以使用$(id)代替document.getElementById(),但是为了不和Prototype相冲突,还是建议各位使用    byId。
      
    4、getValue 取得html 页面元素的value
        方法基本语法:dwr.util.getValue(id);
      
    5、getText
        用法和getValue方法相同,唯一的不同在于getText是用来取得下拉框列表的Text值,而非Value

    6、getValues
    方法基本语法:dwr.util.getValues(object) ;
    参数是一个拥有多个属性的javascript object,属性名称是html页面元素的id,属性value为html页面元素的value,该方法不返回任何东西,而是改变了object的属性值。


    7、setValue 设置html 页面元素的value
    方法基本语法:dwr.util.setValue(id, value [, options]) ;
       如果id参数指定的页面元素是select列表,该列表与value参数值相匹配的option选项会处于选中状态。

    8、setValues
    方法基本语法:dwr.util.setValues(object) ;
    参数是一个拥有多个属性的javascript object,属性名称是html页面元素的id,属性value为html页面元素的value

    9、addOptions
    方法基本语法:dwr.util.addOptions(...); 有多种调用方式:
    # dwr.util.addOptions(id,["first","second","third"]) id参数指定的页面元素可以是ol、ul或select,String数组将被set到id指定的页面元素
    # dwr.util.addOptions(id,[{name:"first",value:"1"},{name:"second",value:"2"},{name:"third",value:"3"}],"value","name")
    这种方式只对应select的情形,如上所述,Object数组里每个元素的value属性值将被set到option的value里,name属性将被set到option的text里。
    如果没有第四个参数,将会把value属性值同时set到option的value和text里。
    # dwr.util.addOptions(id,{first:"1",second:"1",third:"3"})
    这种方式也只对应select的情形,第二个参数是一个Object,属性名set到option的value里,属性值set到option的text里

    10、removeAllOptions
    方法基本语法:dwr.util.removeAllOptions(id);
    除去所有动态加载的Options或列表项,与addOptions配合使用


    11、onReturn
    方法基本语法:dwr.util.onReturn(event, func)
    当输入回车时,调用func名指定的方法

    12、useLoadingMessage
    方法基本语法:dwr.util.useLoadingMessage();
    显示一个正在加载的图片。必须在页面loaded以后调用
    posted @ 2008-08-13 15:23 飞飞 阅读(830) | 评论 (0)编辑 收藏

    一:
    用myeclipse中的傻瓜式添加spring组件。
    修改web.xml文件内容,如下:(红色标记处)

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
     <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/applicationContext-dwr.xml</param-value>
     </context-param>
     <listener>
      <listener-class>
       org.springframework.web.context.ContextLoaderListener
      </listener-class>
     </listener>
     <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>
     </servlet>

     <servlet-mapping>
      <servlet-name>dwr-invoker</servlet-name>
      <url-pattern>/dwr/*</url-pattern>
     </servlet-mapping>
     <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
     </welcome-file-list>
    </web-app>
    二:
    将文件交给spring来管理

    <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">

    <dwr>
      <allow>
        <create creator="spring" javascript="DWRUserAccess">
          <param name="beanName" value="dwrUserAccess"/>
        </create>
        <convert match="com.dwr.User" converter="bean"></convert>
      </allow>
    </dwr>

    三:
    在web-inf下新建applicationContext-dwr.xml文件,内容如下
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans default-autowire="byName">  
        <bean name="dwrUserAccess" class="com.dwr.DWRUserAccess"></bean>
    </beans>


    OK。
    posted @ 2008-08-13 11:22 飞飞 阅读(1567) | 评论 (0)编辑 收藏

    DWR(Direct Web Remoting)是一个WEB远程调用框架.利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户端利用JavaScript直接调用服务端的Java方法并返回值给JavaScript就好像直接本地客户端调用一样(DWR根据Java类来动态生成JavaScrip代码).它的最新版本DWR0.6添加许多特性如:支持Dom Trees的自动配置,支持Spring(JavaScript远程调用spring bean),更好浏览器支持,还支持一个可选的commons-logging日记操作.

    以上摘自open-open,它通过反射,将java翻译成javascript,然后利用回调机制,轻松实现了javascript调用Java代码。

    其大概开发过程如下:
    1.编写业务代码,该代码是和dwr无关的。
    2.确认业务代码中哪些类、哪些方法是要由javascript直接访问的。
    3.编写dwr组件,对步骤2的方法进行封装。
    4.配置dwr组件到dwr.xml文件中,如果有必要,配置convert,进行java和javascript类型互转。
    5.通过反射机制,dwr将步骤4的类转换成javascript代码,提供给前台页面调用。
    5.编写网页,调用步骤5的javascript中的相关方法(间接调用服务器端的相关类的方法),执行业务逻辑,将执行结果利用回调函数返回。
    6.在回调函数中,得到执行结果后,可以继续编写业务逻辑的相关javascript代码。

    下面以用户注册的例子,来说明其使用。(注意,本次例子只是用于演示,说明DWR的使用,类设计并不是最优的)。

    1.先介绍下相关的Java类

      User: 用户类,
      public class User {
    //登陆ID,主键唯一
    private String id;
    //姓名
    private String name;
    //口令
    private String password;
    //电子邮件
    private String email;
            
    //以下包含getXXX和setXXX方法
    .......
      }

      UserDAO:实现User的数据库访问,这里作为一个演示,编写测试代码
      public class UserDAO {
        //存放保存的数据
        private static Map dataMap = new HashMap();

        //持久用户
        public boolean save(User user) {
          if (dataMap.containsKey(user.getId()))
            return false;
          System.out.println("下面开始保存用户");
          System.out.println("id:"+user.getId());
          System.out.println("password:"+user.getPassword());
          System.out.println("name:"+user.getName());
          System.out.println("email:"+user.getEmail());
          dataMap.put(user.getId(), user);
          System.out.println("用户保存结束");
          return true;
        }

        //查找用户
        public User find(String id) {
          return (User)dataMap.get(id);
        }
    }

      DWRUserAccess:DWR组件,提供给javascript访问的。

      public class DWRUserAccess {

          UserDAO userDAO = new UserDAO();

          public boolean save(User user) {
            return userDAO.save(user);
          }

          public User find(String id) {
            return userDAO.find(id);
          }
      }
      

      下面说明下程序执行的流程

      1.用户在页面上输入相关注册信息,id、name、password、email,点击“提交”按钮
      2.javascript代码开始执行,根据用户填写相关信息,通过dwr提供的DWRUserAccess.js里save的方法,调用服务器端的DWRUserAccess类save方法,将注册信息保存。
      3.通过DWRUserAccess.jsp里的find方法,调用服务器端DWRUserAccess类里的find方法,执行用户信息查找。

      注意,在以上的执行过程中,DWRUserAccess是供DWR调用的,是DWR组件,因此需要将DWRUserAccess类配置到dwr中。

      接下来讲解本次dwr测试环境的配置。

      1.新建一个webapp,命名为testApp
      2.将dwr.jar拷贝到testApp的WEB-INF的lib目录下
      3.编译上面的User,UserDAO,DWRUserAccess类,放到classes目录下
      4.在web.xml中配置servlet,适配路径到dwr目录下,如下所示
        <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <display-name>DWR Servlet</display-name>
        <description>Direct Web Remoter Servlet</description>
        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
        <init-param>
          <param-name>debug</param-name>
          <param-value>true</param-value>
        </init-param>
        <init-param>
          <param-name>scriptCompressed</param-name>
          <param-value>false</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>

      以上的配置可以拦截testApp下所有指向dwr的请求,关于这个拦截器,我们会在后面介绍。

      5.WEB-INF下新建一个dwr.xml文件,内容如下:
      < xml version="1.0" encoding="UTF-8" >
    <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">

    <dwr>
      <allow>
    <create creator="new" javascript="DWRUserAccess">
          <param name="class" value="test.DWRUserAccess"/>
        </create>
    <convert converter="bean" match="test.User"/>
      </allow>
    </dwr>

      这里我们把DWRUserAccess配置到了dwr中,create元素中,creater="new"表示每调用一次DWRUserAccess时,需要new一个这样的类;javascript="DWRUserAccess",表示提供给前台页面调用的javascirpt文件是DWRUserAccess.js。

      convert元素用于数据类型转换,即java类和javascript之间相互转换,因为和前台交换的是User对象,因此需要对此使用bean转换,我们将在后面介绍这个类。

      4.编写测试的HTML页面 test.html
       <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <TITLE>DWR测试</TITLE>
    <meta http-equiv=Content-Type content="text/html; charset=gb2312">
    <script src="/oblog312/dwr/engine.js"></script>
    <script src="/oblog312/dwr/util.js"></script>
    <script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
    </HEAD>
    <BODY>
    <B>用户注册</B><br>
    ------------------------------------------------
    <Br>
    <form name="regForm">
    登陆ID:<input type="text" name="id"><br>
    口  令:<input type="password" name="password"><br>
    姓  名:<input type="text" name="name"><br>
    电子邮件:<input type="text" name="email"><br>
    <input type="button" name="submitBtn" value="提交" onclick="OnSave()"><br>
        </form>

    <br>
    <br><B>用户查询</B><br>
    ------------------------------------------------
    <Br>
    <form name="queryForm">
    登陆ID:<input type="text" name="id"><br>
    <input type="button" name="submitBtn" value="提交" onclick="OnFind()"><br>
    </form>
    <br>
    </BODY>
    </HTML>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    function saveFun(data) {
    if (data) {
      alert("注册成功!");
    } else {
      alert("登陆ID已经存在!");
    }
    }

    function OnSave() {
    var userMap = {};
    userMap.id = regForm.id.value;
    userMap.password = regForm.password.value;
    userMap.name = regForm.name.value;
    userMap.email = regForm.email.value;
    DWRUserAccess.save(userMap, saveFun);
    }

    function findFun(data) {
    if (data == null) {
      alert("无法找到用户:"+queryForm.id.value);
      return;
    }

    alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);

    }

    function OnFind() {
    DWRUserAccess.find(queryForm.id.value, findFun);
    }
    //-->
    </SCRIPT>


    以下对页面的javascript进行解释

    <script src="/oblog312/dwr/engine.js"></script>
    <script src="/oblog312/dwr/util.js"></script>
    这两个是dwr提供的,用户可以不必关心,只需要导入即可

    <script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
    是我们编写的DWRUserAccess类,经dwr反射后,生成的javascript代码,它和DWRUserAccess.java是对应的,供用户调用,实际上我们就是通过这个js文件去调用服务器端的DWRUserAccess类的。

    <SCRIPT LANGUAGE="JavaScript">
    <!--
    function saveFun(data) {
    if (data) {
      alert("注册成功!");
    } else {
      alert("用户名已经存在!");
    }
    }

    function OnSave() {
    var userMap = {};
    userMap.id = regForm.id.value;
    userMap.password = regForm.password.value;
    userMap.name = regForm.name.value;
    userMap.email = regForm.email.value;
    DWRUserAccess.save(userMap, saveFun);
    }

    function findFun(data) {
    if (data == null) {
      alert("无法找到用户:"+queryForm.id.value);
      return;
    }

    alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);

    }

    function OnFind() {
    DWRUserAccess.find(queryForm.id.value, findFun);
    }
    //-->
    </SCRIPT>

    这段javascirpt代码,我们来看下OnSave函数,首先它构造一个map,将表单数据都设置到map中,然后调用DWRUserAccess.save(userMap, saveFun),执行save操作。大家可以注意到,服务器端的DWRUserAccess中的save方法是这样的:boolean save(User user),其参数是一个User对象,返回一个boolean值;而客户端的方法是这样的:save(userMap,saveFun),第一个参数userMap是javascirpt中的map对象,在这里相当于服务器端的User对象(在服务器端执行时,会通过convert转换成User对象),前面我们提到dwr是利用回调函数来返回执行结果的,第二个参数saveFun即是一个回调函数。在函数function saveFun(data)中,data是执行结果,这里是一个bool值,非常简单的,我们通过判断data是否为真,可以知道用户名是否重复,用户是否注册成功。

    看一下OnFind查找函数,执行结果在回调函数findFun(data)中,因为服务器端返回的是一个User对象,通过convert,将会转换成javascript的一个map对象,
    于是在findFun中,通过data.id、data.name、data.password、data.email我们可以轻松的访问到这个User对象。


    好了配置完毕,启动服务器,在目录中打入localhost/testApp/test.html。

    1.在“用户注册”表单中,id框中输入admin,password中输入123456,name中输入chenbug,email中输入chenbug@zj.com,点击提交按钮,弹出对话框:“注册成功”,在服务器后台可以看到信息如下:

    下面开始保存用户
    id:admin
    password:123456
    name:chenbug
    email:chenbug@zj.com
    用户保存结束

    再次点击提交按钮,弹出对话框“登陆ID已经存在”。

    2.在“用户查询”对话框中,输入登陆ID为admin,点击提交按钮,提示找到用户,并显示相关信息,输入admin123,点击提交按钮,提示无法找到用户。

    至此,测试结束。


    后续:
    1。拦截器 uk.ltd.getahead.dwr.DWRServlet
    该类拦截所有指向dwr目录下的请求,并调用Processor的handler方法进行处理,在uk.ltd.getahead.dwr.impl.DefaultProcessor下,我们可以看到详细的处理过程。
    if (pathInfo.length() == 0 ||
                pathInfo.equals(HtmlConstants.PATH_ROOT) ||
                pathInfo.equals(req.getContextPath()))
            {
                resp.sendRedirect(req.getContextPath() + servletPath + HtmlConstants.FILE_INDEX);
            }
            else if (pathInfo.startsWith(HtmlConstants.FILE_INDEX))
            {
                index.handle(req, resp);
            }
            else if (pathInfo.startsWith(HtmlConstants.PATH_TEST))
            {
                test.handle(req, resp);
            }
            else if (pathInfo.startsWith(HtmlConstants.PATH_INTERFACE))
            {
                iface.handle(req, resp);
            }
            else if (pathInfo.startsWith(HtmlConstants.PATH_EXEC))
            {
                exec.handle(req, resp);
            }
            else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_ENGINE))
            {
                file.doFile(req, resp, HtmlConstants.FILE_ENGINE, HtmlConstants.MIME_JS);
            }
            else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_UTIL))
            {
                file.doFile(req, resp, HtmlConstants.FILE_UTIL, HtmlConstants.MIME_JS);
            }
            else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_DEPRECATED))
            {
                file.doFile(req, resp, HtmlConstants.FILE_DEPRECATED, HtmlConstants.MIME_JS);
            }
            else
            {
                log.warn("Page not found (" + pathInfo + "). In debug/test mode try viewing /[WEB-APP]/dwr/"); //$NON-NLS-1$ //$NON-NLS-2$
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            }

    通过判断request请求的servlet路径,进行处理,大家可以自己去参看,这里不详细讨论。


    2.bean转换器,<convert converter="bean" match="test.User"/>
    将dwr.jar解压缩,在路径ukltdgetaheaddwr下可以看到dwr.xml,这里配置了系统默认的一些转换器,
    <converter id="bean" class="uk.ltd.getahead.dwr.convert.BeanConverter"/>即是刚才用到User类的转换器,进入代码我们来看看它是如何在javascript和java间进行转换的。

    打开BeanConverter代码,定位到函数

    public Object convertInbound(Class paramType, InboundVariable iv, InboundContext inctx) throws ConversionException

    即是将javascript对象转换成java对象的,其中
    paramType即Class类型,在上面的例子中是test.User,
    InboundVariable iv,是传入的值,通过iv.getValue可以得到传入的javascript值串
    InboundContext inctx,是入口参数上下文,用于保存转换的后java对象。

    因为前台传入的是一个javascript的map类型,而map肯定是以{开始和以}结束的,于是在这个函数一开始进行了判断
    if (!value.startsWith(ConversionConstants.INBOUND_MAP_START))
            {
                throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingOpener", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
            }

            if (!value.endsWith(ConversionConstants.INBOUND_MAP_END))
            {
                throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingCloser", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
            }

    javascript中,map里各个项是用逗号连接的,如var userMap = {id:'admin',password:'123456',name:'chenbug',email:'chenbug@zj.com'};而每个项的键值对是用冒号连接的,
    在convertInbound函数的接下来的处理中,即是通过分析map字串,通过paramType构造java实例(即User类),然后通过反射,将这些键值对设置到java实例中,并返回。
    这样就完成了javascript到java的转换。


    另一个函数
    public String convertOutbound(Object data, String varname, OutboundContext outctx) throws ConversionException

    即是将java对象转换为javascript对象(其实是声明和赋值语句)。
    Object data ,是待转换的java对象
    String varname,是javascript中的该对象的变量名
    OutboundContext outctx,传出参数上下文,用于保存转换后的javascript值

    StringBuffer buffer = new StringBuffer();
            buffer.append("var "); //$NON-NLS-1$
            buffer.append(varname);
            buffer.append("={};"); //$NON-NLS-1$
    这里声明了map类型的变量。

    即下来来的代码即是通过反射进行变量赋值,如下
      buffer.append(varname);
                        buffer.append('.');
                        buffer.append(name);
                        buffer.append('=');
                        buffer.append(nested.getAssignCode());
                        buffer.append(';');
    大家可以自己去参看更多的代码。

    3.dwr本身提供了一个测试环境,大家在配置完后,可以在IE中输入地址http://localhost/testApp/dwr/index.html,看到配置的各DWR组件,并进行相关测试。
    posted @ 2008-08-13 10:21 飞飞 阅读(445) | 评论 (0)编辑 收藏

      DWR(直接Web远程控制)项目是在Apache许可下的一个开源的解决方案,它提供了一种简单的方式使得HTML页面上的javascript可以访问应用服务器的Java对象方法,是Ajax开发者可以方便使用的一个优雅框架。DWR具有一套Javascript功能集,它们把从HTML页面调用应用服务器上的Java对象的方法简化,操控不同类型的参数,同时保持了HTML代码的可读性。DWR实现的AJAX在某些方面很先进,包括动态生成javascript代码;隐藏http协议等。

    web.xml配置:
    <servlet>
     <servlet-name>dwr-invoker</servlet-name>
     <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>  </servlet>
    <servlet-mapping>
     <servlet-name>dwr-invoker</servlet-name>
     <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    DWRServlet是DWR主Servlet,所有的/dwr/*所有请求都由这个servlet来处理。
    DWRServlet init()主要做了以下工作:
    1实例化DWR用到的Singleton类:AccessControl,Configuration,ConverterManager,CreatorManager,Processor
    2 读去配置文件:包括dwr.jar包中的dwr.xml,WEB-INF/dwr.xml,web.xml。
    WEB-INF/dwr.xml文件告诉DWR哪些服务是要直接向JavaScript代码公开的,以DWR的test为例:
        <create creator="new" javascript="JDate">
          <param name="class" value="java.util.Date"/>
          <exclude method="getHours"/>
          <auth method="getMinutes" role="admin"/>
          <auth method="getMinutes" role="devel"/>
        </create>
    DWR会根据此自动生成对应的JDate.js文件。new意味着DWR调用类的构造函数获得实例,还可以通过跟Spring集成达到该目的。

    DWRServlet的doGet和doPost均直接调用Processor的handle方法处理,handle处理的/dwr/*请求包含以下几类:
    1 dwr/index.html,dwr/test/只能在debug模式下供调试用
    2 对dwr/engine.js,dwr/util.js,dwr/deprecated.js的请求调用,直接从包中读取相应的js文件流响应回去,
    并对相应做缓存处理,缓存以一个hashmap实现。
    3 对dwr/interface/的请求调用,DWR生成跟Java对应的javascript存根,DWR通过ConverterManager自动调整Java和javacript的参数类型匹配。
    4 客户端javascript的实际调用,将通过handler方法的doExec执行。

    由此,DWR的运作流程是:
    客户端包含3类javascript脚本
    1 java代码的存根,即通过dwr/interface/调用,如<script type='text/javascript' src='dwr/interface/JDate.js'></script>
    如上所述,该存根由DWR具体是CreatorManager和ConvertorManager根据dwr.xml的配置进行自动生成
    2 DWR核心javascript库,至少要包含<script type='text/javascript' src='dwr/engine.js'></script>,有时也需要包含util.js,util.js封装了prototype的若干函数,便于第三方javascript调用
    3 第三方javascript,该脚本需要调用第一类存根脚本所封装的Java代码,第二类的engine.js等脚本为该调用提供通信支撑。这样就达到了一个基本的RPC的目的,由于RPC本质上是同步进行,而AJAX的XMLHTTP为异步调用,为了实现异步机制,第三方javascript可以提供一个回调函数句柄传入存根,待存根函数返回调用该回调,这样即达到异步通信。
    posted @ 2008-08-12 16:41 飞飞 阅读(614) | 评论 (0)编辑 收藏

    DWR(Direct Web Remoting)是一个开放源clip_image002码的使用 Apache 许可协议的解决方案,它包含服务器端 Java 库、一个 DWR Servlet 以及 JavaScript 库。虽然 DWR 不是 Java 平台上唯一可用的 Ajax-RPC 工具包,但是它是最成熟的,而且提供了许多有用的功能。为什么要使用DWR,我们首先介绍基本AJAX流程,从中可以看到引入DWR会带来什么好处。 DWR的标准流程如右图所示:

    DWR框架基本介绍

    从最简单的角度来说,DWR 是一个引擎,可以把服务器端 Java 对象的方法公开给 JavaScript 代码。使用 DWR 可以有效地从应用程序代码中把 Ajax 的全部请求-响应循环消除掉。这意味着客户端代码再也不需要直接处理 XMLHttpRequest 对象或者服务器的响应。不再需要编写对象的序列化代码或者使用第三方工具才能把对象变成 XML。甚至不再需要编写 servlet 代码把 Ajax 请求调整成对 Java 域对象的调用。

    DWR 是作为 Web 应用程序中的 servlet 部署的。把它看作一个黑盒子,这个 servlet 有两个主要作用:首先,对于公开的每个类,DWR 动态地生成包含在 Web 页面中的 JavaScript。生成的 JavaScript 包含存根函数,代表 Java 类上的对应方法并在幕后执行 XMLHttpRequest。这些请求被发送给 DWR,这时它的第二个作用就是把请求翻译成服务器端 Java 对象上的方法调用并把方法的返回值放在 servlet 响应中发送回客户端,编码成 JavaScript。

    页面触发eventHandler()事件,事件内部调用了AjaxService.getOptions方法,当调用完成后,利用服务端返回的数据用客户端的populateList()方法进行数据展现。

    我们通过一个简单的DWR示例来说明如何使用DWR。

    为了使用DWR,需要将DWR的jar文件拷入Web应用的WEB-INF/lib目录中(可在http://getahead.org/dwr下载),在web.xml中增加一个servlet声明,并创建DWR的配置文件。

    服务端web.xml的配置:

    <!– add the Servlet for DWR –>
    <servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <display-name>DWR Servlet</display-name>
    <description>Direct Web Remoter Servlet</description>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
    <param-name>debug</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>activeReverseAjaxEnabled</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>initApplicationScopeCreatorsAtStartup</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>maxWaitAfterWrite</param-name>
    <param-value>500</param-value>
    </init-param>
    <init-param>
    <param-name>logLevel</param-name>
    <param-value>debug</param-value>
    </init-param>
    <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/dwr/dwr.xml</param-value>
    </init-param>
    <load-on-startup>6</load-on-startup>
    </servlet>
    <!– Action Servlet Mapping –>
    <servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>

    servlet-class值为uk.ltd.getahead.dwr.DWRServlet (如果dwr版本是1.0版本的,则必须用这个class)也可以是org.directwebremoting.servlet.DwrServlet

    也可以使用精简的一份配置:

    <!– add the Servlet for DWR –>
        <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <display-name>DWR Servlet</display-name>
        <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/dwr/dwr.xml</param-value>
        </init-param>
    </servlet>

        <!– Action Servlet Mapping –>
        <servlet-mapping>
            <servlet-name>dwr-invoker</servlet-name>
            <url-pattern>/dwr/*</url-pattern>
        </servlet-mapping>

    在WEB-INF中的dwr文件夹中创建文件dwr.xml:

    <?xml version=”1.0″ encoding=”UTF-8″?>
    <!DOCTYPE dwr PUBLIC “-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN”
    “http://getahead.org/dwr/dwr20.dtd”>
    <dwr>
    <allow>
    <create creator=”new” javascript=”login”>
    <param name=”class” value=”com.webex.tmis.test.Login” />
    <include method=”sayHello” />
    </create>
    <convert converter=”bean” match=”com.webex.tmis.test.User”>
    </convert>
    </allow>
    </dwr>

    服务端创建Login.java和User.java

    public class Login {
    public User sayHello(String name) {
    User user=new User();
    user.setName(name);
    user.setMessage(“Hello,”+name);
    return user;
    }
    }
    
    public class User {
    private String name;
    private String message;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public String getMessage() {
    return message;
    }
    public void setMessage(String message) {
    this.message = message;
    }
    }

    客户端的配置logon.jsp:

    <%@ page language=”java” contentType=”text/html; charset=UTF-8″
        pageEncoding=”UTF-8″%>
    <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
    <html>
    <head>
    <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
    <script type=’text/javascript’ src=’/Tms/dwr/interface/login.js’></script>
    <script type=’text/javascript’ src=’/Tms/dwr/engine.js’></script>
    <script type=’text/javascript’ src=’/Tms/dwr/util.js’></script>

    <script>
    function getDWRMessage () {
    var value=document.getElementById(’user’).value;
    //var bean= DWRUtil.getValues(value);
    login.sayHello(value,showMessage);
    }

    function showMessage(user) {
    if(user.name==’Allen’){
    alert(user.message);
    }else{
      document.getElementById(’MessageSpan’).innerHTML = user.name+” is illegal!!!”;
    }
    }
    </script>

    <title>Logon</title>
    </head>

    <body>
    <table>
        <tr>
            <td id=MessageSpan></td>
        </tr>
        <tr>
            <td><input id=’user’ type=”text” value=”"></td>
        </tr>
        <tr>
            <td><input id=’submitBtn’ type=”button” onClick=”getDWRMessage()”
                value=”Submit”></td>
        </tr>
    </table>
    </body>
    </html>

    效果如下:

    做完配置后,可以加载http://127.0.0.1:8080/Tms/dwr看看哪些服务可以用。

    Classes known to DWR:

    • login (com.webex.tmis.test.Login)

    如果你需要使用ajax完成表单提交的操作,那么你应该使用DWRUtil.getValues,参数或者是个form对象,或者是个与领域对象对应的js对象

    DWR框加的高级话题

    A.配置服务端方法的可调用范围

    在以上的2个DWR示例中,我们配置了两个JAVA类,将它们的所有属性和方法都暴露给了客户端,为了提高安全性,我们通常在dwr.xml中应该只配置那些客户端需要使用的方法和属性。DWR支持对dwr.xml更细粒度的配置来提高安全性,我们先看一下与配置有关的两个元素:

    create 元素

     

    create 元素告诉 DWR 应当公开给 Ajax 请求的服务器端类,并定义 DWR 应当如何获得要进行远程的类的实例。这里的 creator 属性被设置为值 new,这意味着 DWR 应当调用类的默认构造函数来获得实例。其他的可能有:通过代码段用 Bean 脚本框架(Bean Scripting Framework,BSF)创建实例,或者通过与 IOC 容器 Spring 进行集成来获得实例。默认情况下,到 DWR 的 Ajax 请求会调用 creator,实例化的对象处于页面范围内,因此请求完成之后就不再可用。

    create 的 javascript 属性指定从 JavaScript 代码访问对象时使用的名称。嵌套在 create 元素内的 param 元素指定 creator 要创建的 Java 类。最后,include 元素指定应当公开的方法的名称。显式地说明要公开的方法是避免偶然间允许访问有害功能的良好实践 —— 如果漏了这个元素,类的所有方法都会公开给远程调用。反过来,可以用 exclude 元素指定那些想防止被访问的方法。

    convert 元素

    convert 元素的作用是告诉 DWR 在服务器端 Java 对象表示和序列化的 JavaScript 之间如何转换数据类型。DWR 自动地在 Java 和 JavaScript 表示之间调整简单数据类型。这些类型包括 Java 原生类型和它们各自的类表示,还有 String、Date、数组和集合类型。DWR 也能把 JavaBean 转换成 JavaScript 表示,但是出于安全性的原因,做这件事要求显式的配置。

     

    DWR分模块配置

    一般来说,你只需要一个dwr.xml文件,并且放置在默认的位置:WEB-INF/dwr.xml。如果有大量的远程调用类,则可以将dwr.xml分成多个文件。 则在每web .xml中可以这样配置:

    <servlet>
    <servlet-name>dwr-user-invoker</servlet-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
    <param-name>config-user</param-name>
    <param-value>WEB-INF/dwr-user.xml</param-value>
    </init-param>
    </servlet>
    <servlet>
    <servlet-name>dwr-admin-invoker</servlet-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
    <param-name>config-admin</param-name>
    <param-value>WEB-INF/dwr-admin.xml</param-value>
    </init-param>
    </servlet>
    <servlet-mapping>
    <servlet-name>dwr-admin-invoker</servlet-name>
    <url-pattern>/dwradmin/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
    <servlet-name>dwr-user-invoker</servlet-name>
    <url-pattern>/dwruser/*</url-pattern>
    </servlet-mapping>

     

    DWR批量调用

    在 DWR 中,可以在一个 HTTP 请求中向服务器发送多个远程调用。调用 DWREngine.beginBatch() 告诉 DWR 不要直接分派后续的远程调用,而是把它们组合到一个批请求中。DWREngine.endBatch() 调用则把批请求发送到服务器。远程调用在服务器端顺序执行,然后调用每个 JavaScript 回调。

    批处理在两方面有助于降低延迟:第一,避免了为每个调用创建 XMLHttpRequest 对象并建立相关的 HTTP 连接的开销。第二,在生产环境中,Web 服务器不必处理过多的并发 HTTP 请求,改进了响应时间。

    F.DWR同步与异步

    在页面的执行中,如果在js中使用了dwr去远程调用数据,这时,下面的JS将会是继续执行,

    如果你是用作校验的话,那就导致不同步问题,返回结果无法生效,

    这时你可以通过设置DWR为同步来达到效果

    DWREngine.setAsync(false); => 默认为异步,即 true;

    调用完后,设置还原

    DWREngine.setAsync(true);

    posted @ 2008-08-12 15:38 飞飞 阅读(512) | 评论 (0)编辑 收藏

    Spring的JDBCTemplate

    当hql等查询方式不能满足性能或灵活性的要求,必须使用SQL时,大家有三种选择:

    第一、使用Hibernate 的sql 查询函数,将查询结果对象转为Entity对象。

    第二、使用Hibernate Session的getConnection 获得JDBC Connection,然后进行纯JDBC API操作;

    第三、选择把Spring的JDBCTemplate作为一种很不错的JDBC Utils来使用。

         JDBCTemplate的使用很简单,只要在ApplicationContext文件里定义一个jdbcTemplate节点,POJO获得注入后可以直接执行操作,不需要继承什么基类,详见JDBCTemplate参考文档

         AplicationContext定义:

        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>

    实际使用: 

    SqlRowSet rs = jdbcTemplate.queryForRowSet(sql, params);

    Tips1: jdbcTemplate有很多的ORM化回调操作将返回结果转为对象列表,但很多时候还是需要返回ResultSet,Spring有提供一个类似ResultSet的 Spring SqlRowSet对象。

             

    Tips2:.注意jdbcTemplate尽量只执行查询操作,莫要进行更新,否则很容易破坏Hibernate的二级缓存体系。


    Chapter 11. 使用JDBC进行数据访问

    11.1. 简介

    Spring JDBC抽象框架所带来的价值将在以下几个方面得以体现:(注:使用了Spring JDBC抽象框架之后,应用开发人员只需要完成斜体字部分的编码工作。)

    1. 指定数据库连接参数

    2. 打开数据库连接

    3. 声明SQL语句

    4. 预编译并执行SQL语句

    5. 遍历查询结果(如果需要的话)

    6. 处理每一次遍历操作

    7. 处理抛出的任何异常

    8. 处理事务

    9. 关闭数据库连接

    Spring将替我们完成所有单调乏味的JDBC底层细节处理工作。

    11.1.1. Spring JDBC包结构

    Spring JDBC抽象框架由四个包构成:coredataSourceobject以及support

    org.springframework.jdbc.core包由JdbcTemplate类以及相关的回调接口(callback interface)和类组成。

    org.springframework.jdbc.datasource包由一些用来简化DataSource访问的工具类,以及各种DataSource接口的简单实现(主要用于单元测试以及在J2EE容器之外使用JDBC)组成。工具类提供了一些静态方法,诸如通过JNDI获取数据连接以及在必要的情况下关闭这些连接。它支持绑定线程的连接,比如被用于DataSourceTransactionManager的连接。

    接下来,org.springframework.jdbc.object包由封装了查询、更新以及存储过程的类组成,这些类的对象都是线程安全并且可重复使用的。它们类似于JDO,与JDO的不同之处在于查询结果与数据库是“断开连接”的。它们是在org.springframework.jdbc.core包的基础上对JDBC更高层次的抽象。

    最后,org.springframework.jdbc.support包提供了一些SQLException的转换类以及相关的工具类。

    在JDBC处理过程中抛出的异常将被转换成org.springframework.dao包中定义的异常。因此使用Spring JDBC进行开发将不需要处理JDBC或者特定的RDBMS才会抛出的异常。所有的异常都是unchecked exception,这样我们就可以对传递到调用者的异常进行有选择的捕获。

    11.2. 利用JDBC核心类实现JDBC的基本操作和错误处理

    11.2.1. JdbcTemplate

    JdbcTemplate是core包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。

    使用JdbcTemplate进行编码只需要根据明确定义的一组契约来实现回调接口。PreparedStatementCreator回调接口通过给定的Connection创建一个PreparedStatement,包含SQL和任何相关的参数。CallableStatementCreateor实现同样的处理,只不过它创建的是CallableStatement。RowCallbackHandler接口则从数据集的每一行中提取值。

    我们可以在一个service实现类中通过传递一个DataSource引用来完成JdbcTemplate的实例化,也可以在application context中配置一个JdbcTemplate bean,来供service使用。需要注意的是DataSource在application context总是配制成一个bean,第一种情况下,DataSource bean将传递给service,第二种情况下DataSource bean传递给JdbcTemplate bean。因为JdbcTemplate使用回调接口和SQLExceptionTranslator接口作为参数,所以一般情况下没有必要通过继承JdbcTemplate来定义其子类。

    JdbcTemplate中使用的所有SQL将会以“DEBUG”级别记入日志(一般情况下日志的category是JdbcTemplate相应的全限定类名,不过如果需要对JdbcTemplate进行定制的话,可能是它的子类名)。

    11.2.2. NamedParameterJdbcTemplate

    NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用'?'占位符来表示的。 NamedParameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,并作为其代理来完成大部分工作。下面的内容主要针对NamedParameterJdbcTemplateJdbcTemplate的不同之处来加以说明,即如何在SQL语句中使用命名参数。

    通过下面的例子我们可以更好地了解NamedParameterJdbcTemplate的使用模式(在后面我们还有更好的使用方式)。

    // some JDBC-backed DAO class...
    public int countOfActorsByFirstName(String firstName) {
    String sql = "select count(0) from T_ACTOR where first_name = :first_name";
    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
    return template.queryForInt(sql, namedParameters);
    }

    在上面例子中,sql变量使用了命名参数占位符“first_name”,与其对应的值存在namedParameters变量中(类型为MapSqlParameterSource)。

    如果你喜欢的话,也可以使用基于Map风格的名值对将命名参数传递给NamedParameterJdbcTemplateNamedParameterJdbcTemplate实现了NamedParameterJdbcOperations接口,剩下的工作将由调用该接口的相应方法来完成,这里我们就不再赘述):

    // some JDBC-backed DAO class...
    public int countOfActorsByFirstName(String firstName) {
    String sql = "select count(0) from T_ACTOR where first_name = :first_name";
    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    Map namedParameters = new HashMap();
    namedParameters.put("first_name", firstName);
    return template.queryForInt(sql, namedParameters);
    }

    另外一个值得一提的特性是与NamedParameterJdbcTemplate位于同一个包中的SqlParameterSource接口。在前面的代码片断中我们已经看到了该接口的实现(即MapSqlParameterSource类),SqlParameterSource可以用来作为NamedParameterJdbcTemplate命名参数的来源。MapSqlParameterSource类是一个非常简单的实现,它仅仅是一个java.util.Map适配器,当然其用法也就不言自明了(如果还有不明了的,可以在Spring的JIRA系统中要求提供更多的相关资料)。

    SqlParameterSource接口的另一个实现--BeanPropertySqlParameterSource为我们提供了更有趣的功能。该类包装一个类似JavaBean的对象,所需要的命名参数值将由包装对象提供,下面我们使用一个例子来更清楚地说明它的用法。

    // some JavaBean-like class...
    public class Actor {
    private Long id;
    private String firstName;
    private String lastName;
    public String getFirstName() {
    return this.firstName;
    }
    public String getLastName() {
    return this.lastName;
    }
    public Long getId() {
    return this.id;
    }
    // setters omitted...
    }
    // some JDBC-backed DAO class...
    public int countOfActors(Actor exampleActor) {
    // notice how the named parameters match the properties of the above 'Actor' class
    String sql = "select count(0) from T_ACTOR where first_name = :firstName and last_name = :lastName";
    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);
    return template.queryForInt(sql, namedParameters);
    }

    大家必须牢记一点:NamedParameterJdbcTemplate类内部包装了一个标准的JdbcTemplate类。如果你需要访问其内部的JdbcTemplate实例(比如访问JdbcTemplate的一些方法)那么你需要使用getJdbcOperations()方法返回的JdbcOperations接口。(JdbcTemplate实现了JdbcOperations接口)。

    NamedParameterJdbcTemplate类是线程安全的,该类的最佳使用方式不是每次操作的时候实例化一个新的NamedParameterJdbcTemplate,而是针对每个DataSource只配置一个NamedParameterJdbcTemplate实例(比如在Spring IoC容器中使用Spring IoC来进行配置),然后在那些使用该类的DAO中共享该实例。

    11.2.3. SimpleJdbcTemplate

    [Note] Note

    请注意该类所提供的功能仅适用于Java 5 (Tiger)。

    SimpleJdbcTemplate类是JdbcTemplate类的一个包装器(wrapper),它利用了Java 5的一些语言特性,比如Varargs和Autoboxing。对那些用惯了Java 5的程序员,这些新的语言特性还是很好用的。

    SimpleJdbcTemplate 类利用Java 5的语法特性带来的好处可以通过一个例子来说明。在下面的代码片断中我们首先使用标准的JdbcTemplate进行数据访问,接下来使用SimpleJdbcTemplate做同样的事情。

    // classic JdbcTemplate-style...
    public Actor findActor(long id) {
    String sql = "select id, first_name, last_name from T_ACTOR where id = ?";
    RowMapper mapper = new RowMapper() {
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    Actor actor = new Actor();
    actor.setId(rs.getLong(Long.valueOf(rs.getLong("id"))));
    actor.setFirstName(rs.getString("first_name"));
    actor.setLastName(rs.getString("last_name"));
    return actor;
    }
    };
    // normally this would be dependency injected of course...
    JdbcTemplate jdbcTemplate = new JdbcTemplate(this.getDataSource());
    // notice the cast, and the wrapping up of the 'id' argument
    // in an array, and the boxing of the 'id' argument as a reference type
    return (Actor) jdbcTemplate.queryForObject(sql, mapper, new Object[] {Long.valueOf(id)});
    }

    下面是同一方法的另一种实现,惟一不同之处是我们使用了SimpleJdbcTemplate,这样代码显得更加清晰。

    // SimpleJdbcTemplate-style...
    public Actor findActor(long id) {
    String sql = "select id, first_name, last_name from T_ACTOR where id = ?";
    ParameterizedRowMapper<Actor> mapper = new ParameterizedRowMapper<Actor>() {
    // notice the return type with respect to Java 5 covariant return types
    public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
    Actor actor = new Actor();
    actor.setId(rs.getLong("id"));
    actor.setFirstName(rs.getString("first_name"));
    actor.setLastName(rs.getString("last_name"));
    return actor;
    }
    };
    // again, normally this would be dependency injected of course...
    SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(this.getDataSource());
    return simpleJdbcTemplate.queryForObject(sql, mapper, id);
    }

    11.2.4. DataSource接口

    为了从数据库中取得数据,我们首先需要获取一个数据库连接。 Spring通过DataSource对象来完成这个工作。 DataSource是JDBC规范的一部分, 它被视为一个通用的数据库连接工厂。通过使用DataSource, Container或Framework可以将连接池以及事务管理的细节从应用代码中分离出来。 作为一个开发人员,在开发和测试产品的过程中,你可能需要知道连接数据库的细节。 但在产品实施时,你不需要知道这些细节。通常数据库管理员会帮你设置好数据源。

    在使用Spring JDBC时,你既可以通过JNDI获得数据源,也可以自行配置数据源( 使用Spring提供的DataSource实现类)。使用后者可以更方便的脱离Web容器来进行单元测试。 这里我们将使用DriverManagerDataSource,不过DataSource有多种实现, 后面我们会讲到。使用DriverManagerDataSource和你以前获取一个JDBC连接 的做法没什么两样。你首先必须指定JDBC驱动程序的全限定名,这样DriverManager 才能加载JDBC驱动类,接着你必须提供一个url(因JDBC驱动而异,为了保证设置正确请参考相关JDBC驱动的文档), 最后你必须提供一个用户连接数据库的用户名和密码。下面我们将通过一个例子来说明如何配置一个 DriverManagerDataSource

    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
    dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
    dataSource.setUsername("sa");
    dataSource.setPassword("");

    11.2.5. SQLExceptionTranslator接口

    SQLExceptionTranslator是一个接口,如果你需要在 SQLExceptionorg.springframework.dao.DataAccessException之间作转换,那么必须实现该接口。

    转换器类的实现可以采用一般通用的做法(比如使用JDBC的SQLState code),如果为了使转换更准确,也可以进行定制(比如使用Oracle的error code)。

    SQLErrorCodeSQLExceptionTranslator是SQLExceptionTranslator的默认实现。 该实现使用指定数据库厂商的error code,比采用SQLState更精确。 转换过程基于一个JavaBean(类型为SQLErrorCodes)中的error code。 这个JavaBean由SQLErrorCodesFactory工厂类创建,其中的内容来自于 "sql-error-codes.xml"配置文件。该文件中的数据库厂商代码基于Database MetaData信息中的 DatabaseProductName,从而配合当前数据库的使用。

     

    SQLErrorCodeSQLExceptionTranslator使用以下的匹配规则:

     

    • 首先检查是否存在完成定制转换的子类实现。通常SQLErrorCodeSQLExceptionTranslator 这个类可以作为一个具体类使用,不需要进行定制,那么这个规则将不适用。

    • 接着将SQLException的error code与错误代码集中的error code进行匹配。 默认情况下错误代码集将从SQLErrorCodesFactory取得。 错误代码集来自classpath下的sql-error-codes.xml文件, 它们将与数据库metadata信息中的database name进行映射。

    • 如果仍然无法匹配,最后将调用fallbackTranslator属性的translate方法,SQLStateSQLExceptionTranslator类实例是默认的fallbackTranslator。

     

    SQLErrorCodeSQLExceptionTranslator可以采用下面的方式进行扩展:

    public class MySQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
    protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
    if (sqlex.getErrorCode() == -12345) {
    return new DeadlockLoserDataAccessException(task, sqlex);
    }
    return null;
    }
    }

    在上面的这个例子中,error code为'-12345'的SQLException 将采用该转换器进行转换,而其他的error code将由默认的转换器进行转换。 为了使用该转换器,必须将其作为参数传递给JdbcTemplate类 的setExceptionTranslator方法,并在需要使用这个转换器器的数据 存取操作中使用该JdbcTemplate。 下面的例子演示了如何使用该定制转换器:

    // create a JdbcTemplate and set data source
    JdbcTemplate jt = new JdbcTemplate();
    jt.setDataSource(dataSource);
    // create a custom translator and set the DataSource for the default translation lookup
    MySQLErrorCodesTransalator tr = new MySQLErrorCodesTransalator();
    tr.setDataSource(dataSource);
    jt.setExceptionTranslator(tr);
    // use the JdbcTemplate for this SqlUpdate
    SqlUpdate su = new SqlUpdate();
    su.setJdbcTemplate(jt);
    su.setSql("update orders set shipping_charge = shipping_charge * 1.05");
    su.compile();
    su.update();

    在上面的定制转换器中,我们给它注入了一个数据源,因为我们仍然需要 使用默认的转换器从sql-error-codes.xml中获取错误代码集。

    11.2.6. 执行SQL语句

    我们仅需要非常少的代码就可以达到执行SQL语句的目的,一旦获得一个 DataSource和一个JdbcTemplate, 我们就可以使用JdbcTemplate提供的丰富功能实现我们的操作。 下面的例子使用了极少的代码完成创建一张表的工作。

    import javax.sql.DataSource;
    import org.springframework.jdbc.core.JdbcTemplate;
    public class ExecuteAStatement {
    private JdbcTemplate jt;
    private DataSource dataSource;
    public void doExecute() {
    jt = new JdbcTemplate(dataSource);
    jt.execute("create table mytable (id integer, name varchar(100))");
    }
    public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
    }
    }

    11.2.7. 执行查询

    除了execute方法之外,JdbcTemplate还提供了大量的查询方法。 在这些查询方法中,有很大一部分是用来查询单值的。比如返回一个汇总(count)结果 或者从返回行结果中取得指定列的值。这时我们可以使用queryForInt(..)queryForLong(..)或者queryForObject(..)方法。 queryForObject方法用来将返回的JDBC类型对象转换成指定的Java对象,如果类型转换失败将抛出 InvalidDataAccessApiUsageException异常。 下面的例子演示了两个查询的用法,一个返回int值,另一个返回 String

    import javax.sql.DataSource;
    import org.springframework.jdbc.core.JdbcTemplate;
    public class RunAQuery {
    private JdbcTemplate jt;
    private DataSource dataSource;
    public int getCount() {
    jt = new JdbcTemplate(dataSource);
    int count = jt.queryForInt("select count(*) from mytable");
    return count;
    }
    public String getName() {
    jt = new JdbcTemplate(dataSource);
    String name = (String) jt.queryForObject("select name from mytable", String.class);
    return name;
    }
    public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
    }
    }

    除了返回单值的查询方法,JdbcTemplate还提供了一组返回List结果 的方法。List中的每一项对应查询返回结果中的一行。其中最简单的是queryForList方法, 该方法将返回一个List,该List中的每一条 记录是一个Map对象,对应应数据库中某一行;而该Map 中的每一项对应该数据库行中的某一列值。下面的代码片断接着上面的例子演示了如何用该方法返回表中 所有记录:

    public List getList() {
    jt = new JdbcTemplate(dataSource);
    List rows = jt.queryForList("select * from mytable");
    return rows;
    }

    返回的结果集类似下面这种形式:

    [{name=Bob, id=1}, {name=Mary, id=2}]

    11.2.8. 更新数据库

    JdbcTemplate还提供了一些更新数据库的方法。 在下面的例子中,我们根据给定的主键值对指定的列进行更新。 例子中的SQL语句中使用了“?”占位符来接受参数(这种做法在更新和查询SQL语句中很常见)。 传递的参数值位于一个对象数组中(基本类型需要被包装成其对应的对象类型)。

    import javax.sql.DataSource;
    import org.springframework.jdbc.core.JdbcTemplate;
    public class ExecuteAnUpdate {
    private JdbcTemplate jt;
    private DataSource dataSource;
    public void setName(int id, String name) {
    jt = new JdbcTemplate(dataSource);
    jt.update("update mytable set name = ? where id = ?", new Object[] {name, new Integer(id)});
    }
    public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
    }
    }

    11.3. 控制数据库连接

    11.3.1. DataSourceUtils

    DataSourceUtils作为一个帮助类提供易用且强大的数据库访问能力, 我们可以使用该类提供的静态方法从JNDI获取数据库连接以及在必要的时候关闭之。 它提供支持线程绑定的数据库连接(比如使用DataSourceTransactionManager 的时候,将把数据库连接绑定到当前的线程上)。

    注:getDataSourceFromJndi(..)方法主要用于那些没有使用bean factory 或者application context的场合。如果使用application context,那么最好是在 JndiObjectFactoryBean中配置bean或者直接使用 JdbcTemplate实例。JndiObjectFactoryBean 能够通过JNDI获取DataSource并将 DataSource作为引用参数传递给其他bean。 这样,在不同的DataSource之间切换只需要修改配置文件即可, 甚至我们可以用一个非JNDI的DataSource来替换 FactoryBean定义!

    11.3.2. SmartDataSource接口

    SmartDataSourceDataSource 接口的一个扩展,用来提供数据库连接。使用该接口的类在指定的操作之后可以检查是否需要关闭连接。 该接口在某些情况下非常有用,比如有些情况需要重用数据库连接。

    11.3.3. AbstractDataSource

    AbstractDataSource是一个实现了DataSource 接口的abstract基类。它实现了DataSource接口的 一些无关痛痒的方法,如果你需要实现自己的DataSource,那么继承 该类是个好主意。

    11.3.4. SingleConnectionDataSource

    SingleConnectionDataSourceSmartDataSource接口 的一个实现,其内部包装了一个单连接。该连接在使用之后将不会关闭,很显然它不能在多线程 的环境下使用。

    当客户端代码调用close方法的时候,如果它总是假设数据库连接来自连接池(就像使用持久化工具时一样), 你应该将suppressClose设置为true。 这样,通过该类获取的将是代理连接(禁止关闭)而不是原有的物理连接。 需要注意的是,我们不能把使用该类获取的数据库连接造型(cast)为Oracle Connection之类的本地数据库连接。

    SingleConnectionDataSource主要在测试的时候使用。 它使得测试代码很容易脱离应用服务器而在一个简单的JNDI环境下运行。 与DriverManagerDataSource不同的是,它始终只会使用同一个数据库连接, 从而避免每次建立物理连接的开销。

    11.3.5. DriverManagerDataSource

    DriverManagerDataSource类实现了 SmartDataSource接口。在applicationContext.xml中可以使用 bean properties来设置JDBC Driver属性,该类每次返回的都是一个新的连接。

    该类主要在测试以及脱离J2EE容器的独立环境中使用。它既可以用来在application context中作为一个 DataSource bean,也可以在简单的JNDI环境下使用。 由于Connection.close()仅仅只是简单的关闭数据库连接,因此任何能够获取 DataSource的持久化代码都能很好的工作。不过使用JavaBean风格的连接池 (比如commons-dbcp)也并非难事。即使是在测试环境下,使用连接池也是一种比使用 DriverManagerDataSource更好的做法。

    11.3.6. TransactionAwareDataSourceProxy

    TransactionAwareDataSourceProxy作为目标DataSource的一个代理, 在对目标DataSource包装的同时,还增加了Spring的事务管理能力, 在这一点上,这个类的功能非常像J2EE服务器所提供的事务化的JNDI DataSource

    [Note] Note

    该类几乎很少被用到,除非现有代码在被调用的时候需要一个标准的 JDBC DataSource接口实现作为参数。 这种情况下,这个类可以使现有代码参与Spring的事务管理。通常最好的做法是使用更高层的抽象 来对数据源进行管理,比如JdbcTemplateDataSourceUtils等等。

    如果需要更详细的资料,请参考TransactionAwareDataSourceProxy JavaDoc 。

    11.3.7. DataSourceTransactionManager

    DataSourceTransactionManager类是 PlatformTransactionManager接口的一个实现,用于处理单JDBC数据源。 它将从指定DataSource取得的JDBC连接绑定到当前线程,因此它也支持了每个数据源对应到一个线程。

    我们推荐在应用代码中使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,而不是使用J2EE标准的DataSource.getConnection。因为前者将抛出 unchecked的org.springframework.dao异常,而不是checked的 SQLException异常。Spring Framework中所有的类(比如 JdbcTemplate)都采用这种做法。如果不需要和这个 DataSourceTransactionManager类一起使用,DataSourceUtils 提供的功能跟一般的数据库连接策略没有什么两样,因此它可以在任何场景下使用。

    DataSourceTransactionManager类支持定制隔离级别,以及对SQL语句查询超时的设定。 为了支持后者,应用代码必须使用JdbcTemplate或者在每次创建SQL语句时调用 DataSourceUtils.applyTransactionTimeout方法。

    在使用单个数据源的情形下,你可以用DataSourceTransactionManager来替代JtaTransactionManager, 因为DataSourceTransactionManager不需要容器支持JTA。如果你使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,二者之间的切换只需要更改一些配置。最后需要注意的一点就是JtaTransactionManager不支持隔离级别的定制!

    11.4. 用Java对象来表达JDBC操作

    org.springframework.jdbc.object包下的类允许用户以更加 面向对象的方式去访问数据库。比如说,用户可以执行查询并返回一个list, 该list作为一个结果集将把从数据库中取出的列数据映射到业务对象的属性上。 用户也可以执行存储过程,以及运行更新、删除以及插入SQL语句。

    [Note] Note

    在许多Spring开发人员中间存在有一种观点,那就是下面将要提到的各种RDBMS操作类 (StoredProcedure类除外) 通常也可以直接使用JdbcTemplate相关的方法来替换。 相对于把一个查询操作封装成一个类而言,直接调用JdbcTemplate方法将更简单 而且更容易理解。

    必须说明的一点就是,这仅仅只是一种观点而已, 如果你认为你可以从直接使用RDBMS操作类中获取一些额外的好处, 你不妨根据自己的需要和喜好进行不同的选择。

    11.4.1. SqlQuery

    SqlQuery是一个可重用、线程安全的类,它封装了一个SQL查询。 其子类必须实现newResultReader()方法,该方法用来在遍历 ResultSet的时候能使用一个类来保存结果。 我们很少需要直接使用SqlQuery,因为其子类 MappingSqlQuery作为一个更加易用的实现能够将结果集中的行映射为Java对象。 SqlQuery还有另外两个扩展分别是 MappingSqlQueryWithParametersUpdatableSqlQuery

    11.4.2. MappingSqlQuery

    MappingSqlQuery是一个可重用的查询抽象类,其具体类必须实现 mapRow(ResultSet, int)抽象方法来将结果集中的每一行转换成Java对象。

    SqlQuery的各种实现中, MappingSqlQuery是最常用也是最容易使用的一个。

    下面这个例子演示了一个定制查询,它将从客户表中取得的数据映射到一个 Customer类实例。

    private class CustomerMappingQuery extends MappingSqlQuery {
    public CustomerMappingQuery(DataSource ds) {
    super(ds, "SELECT id, name FROM customer WHERE id = ?");
    super.declareParameter(new SqlParameter("id", Types.INTEGER));
    compile();
    }
    public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
    Customer cust = new Customer();
    cust.setId((Integer) rs.getObject("id"));
    cust.setName(rs.getString("name"));
    return cust;
    }
    }

    在上面的例子中,我们为用户查询提供了一个构造函数并为构造函数传递了一个 DataSource参数。在构造函数里面我们把 DataSource和一个用来返回查询结果的SQL语句作为参数 调用父类的构造函数。SQL语句将被用于生成一个PreparedStatement对象, 因此它可以包含占位符来传递参数。而每一个SQL语句的参数必须通过调用 declareParameter方法来进行声明,该方法需要一个 SqlParameter(封装了一个字段名字和一个 java.sql.Types中定义的JDBC类型)对象作为参数。 所有参数定义完之后,我们调用compile()方法来对SQL语句进行预编译。

    下面让我们看看该定制查询初始化并执行的代码:

    public Customer getCustomer(Integer id) {
    CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource);
    Object[] parms = new Object[1];
    parms[0] = id;
    List customers = custQry.execute(parms);
    if (customers.size() > 0) {
    return (Customer) customers.get(0);
    }
    else {
    return null;
    }
    }

    在上面的例子中,getCustomer方法通过传递惟一参数id来返回一个客户对象。 该方法内部在创建CustomerMappingQuery实例之后, 我们创建了一个对象数组用来包含要传递的查询参数。这里我们只有唯一的一个 Integer参数。执行CustomerMappingQuery的 execute方法之后,我们得到了一个List,该List中包含一个 Customer对象,如果有对象满足查询条件的话。

    11.4.3. SqlUpdate

    SqlUpdate类封装了一个可重复使用的SQL更新操作。 跟所有RdbmsOperation类一样,SqlUpdate可以在SQL中定义参数。

    该类提供了一系列update()方法,就像SqlQuery提供的一系列execute()方法一样。

    SqlUpdate是一个具体的类。通过在SQL语句中定义参数,这个类可以支持 不同的更新方法,我们一般不需要通过继承来实现定制。

    import java.sql.Types;
    import javax.sql.DataSource;
    import org.springframework.jdbc.core.SqlParameter;
    import org.springframework.jdbc.object.SqlUpdate;
    public class UpdateCreditRating extends SqlUpdate {
    public UpdateCreditRating(DataSource ds) {
    setDataSource(ds);
    setSql("update customer set credit_rating = ? where id = ?");
    declareParameter(new SqlParameter(Types.NUMERIC));
    declareParameter(new SqlParameter(Types.NUMERIC));
    compile();
    }
    /**
    * @param id for the Customer to be updated
    * @param rating the new value for credit rating
    * @return number of rows updated
    */
    public int run(int id, int rating) {
    Object[] params =
    new Object[] {
    new Integer(rating),
    new Integer(id)};
    return update(params);
    }
    }

    11.4.4. StoredProcedure

    StoredProcedure类是一个抽象基类,它是对RDBMS存储过程的一种抽象。 该类提供了多种execute(..)方法,不过这些方法的访问类型都是protected的。

    从父类继承的sql属性用来指定RDBMS存储过程的名字。 尽管该类提供了许多必须在JDBC3.0下使用的功能,但是我们更关注的是JDBC 3.0中引入的命名参数特性。

    下面的程序演示了如何调用Oracle中的sysdate()函数。 这里我们创建了一个继承StoredProcedure的子类,虽然它没有输入参数, 但是我必须通过使用SqlOutParameter来声明一个日期类型的输出参数。 execute()方法将返回一个map,map中的每个entry是一个用参数名作key, 以输出参数为value的名值对。

    import java.sql.Types;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import javax.sql.DataSource;
    import org.springframework.jdbc.core.SqlOutParameter;
    import org.springframework.jdbc.datasource.*;
    import org.springframework.jdbc.object.StoredProcedure;
    public class TestStoredProcedure {
    public static void main(String[] args)  {
    TestStoredProcedure t = new TestStoredProcedure();
    t.test();
    System.out.println("Done!");
    }
    void test() {
    DriverManagerDataSource ds = new DriverManagerDataSource();
    ds.setDriverClassName("oracle.jdbc.OracleDriver");
    ds.setUrl("jdbc:oracle:thin:@localhost:1521:mydb");
    ds.setUsername("scott");
    ds.setPassword("tiger");
    MyStoredProcedure sproc = new MyStoredProcedure(ds);
    Map results = sproc.execute();
    printMap(results);
    }
    private class MyStoredProcedure extends StoredProcedure {
    private static final String SQL = "sysdate";
    public MyStoredProcedure(DataSource ds) {
    setDataSource(ds);
    setFunction(true);
    setSql(SQL);
    declareParameter(new SqlOutParameter("date", Types.DATE));
    compile();
    }
    public Map execute() {
    // the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
    return execute(new HashMap());
    }
    }
    private static void printMap(Map results) {
    for (Iterator it = results.entrySet().iterator(); it.hasNext(); ) {
    System.out.println(it.next());
    }
    }
    }

    下面是StoredProcedure的另一个例子,它使用了两个Oracle游标类型的输出参数。

    import oracle.jdbc.driver.OracleTypes;
    import org.springframework.jdbc.core.SqlOutParameter;
    import org.springframework.jdbc.object.StoredProcedure;
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    public class TitlesAndGenresStoredProcedure extends StoredProcedure {
    private static final String SPROC_NAME = "AllTitlesAndGenres";
    public TitlesAndGenresStoredProcedure(DataSource dataSource) {
    super(dataSource, SPROC_NAME);
    declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper()));
    declareParameter(new SqlOutParameter("genres", OracleTypes.CURSOR, new GenreMapper()));
    compile();
    }
    public Map execute() {
    // again, this sproc has no input parameters, so an empty Map is supplied...
    return super.execute(new HashMap());
    }
    }

    值得注意的是TitlesAndGenresStoredProcedure构造函数中 declareParameter(..)SqlOutParameter参数, 该参数使用了RowMapper接口的实现。 这是一种非常方便而强大的重用方式。 下面我们来看一下RowMapper的两个具体实现。

    首先是TitleMapper类,它简单的把ResultSet中的每一行映射为一个Title Domain Object。

    import com.foo.sprocs.domain.Title;
    import org.springframework.jdbc.core.RowMapper;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    public final class TitleMapper implements RowMapper {
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    Title title = new Title();
    title.setId(rs.getLong("id"));
    title.setName(rs.getString("name"));
    return title;
    }
    }

    另一个是GenreMapper类,也是非常简单的将ResultSet中的每一行映射为一个Genre Domain Object。

    import org.springframework.jdbc.core.RowMapper;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import com.foo.domain.Genre;
    public final class GenreMapper implements RowMapper {
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    return new Genre(rs.getString("name"));
    }
    }

    如果你需要给存储过程传输入参数(这些输入参数是在RDBMS存储过程中定义好了的), 则需要提供一个指定类型的execute(..)方法, 该方法将调用基类的protected execute(Map parameters)方法。 例如:

    import oracle.jdbc.driver.OracleTypes;
    import org.springframework.jdbc.core.SqlOutParameter;
    import org.springframework.jdbc.object.StoredProcedure;
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    public class TitlesAfterDateStoredProcedure extends StoredProcedure {
    private static final String SPROC_NAME = "TitlesAfterDate";
    private static final String CUTOFF_DATE_PARAM = "cutoffDate";
    public TitlesAfterDateStoredProcedure(DataSource dataSource) {
    super(dataSource, SPROC_NAME);
    declaraParameter(new SqlParameter(CUTOFF_DATE_PARAM, Types.DATE);
    declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper()));
    compile();
    }
    public Map execute(Date cutoffDate) {
    Map inputs = new HashMap();
    inputs.put(CUTOFF_DATE_PARAM, cutoffDate);
    return super.execute(inputs);
    }
    }

    11.4.5. SqlFunction

    SqlFunction RDBMS操作类封装了一个SQL“函数”包装器(wrapper), 该包装器适用于查询并返回一个单行结果集。默认返回的是一个int值, 不过我们可以采用类似JdbcTemplate中的queryForXxx 做法自己实现来返回其它类型。SqlFunction优势在于我们不必创建 JdbcTemplate,这些它都在内部替我们做了。

    该类的主要用途是调用SQL函数来返回一个单值的结果集,比如类似“select user()”、 “select sysdate from dual”的查询。如果需要调用更复杂的存储函数, 可以使用StoredProcedureSqlCall

    SqlFunction是一个具体类,通常我们不需要它的子类。 其用法是创建该类的实例,然后声明SQL语句以及参数就可以调用相关的run方法去多次执行函数。 下面的例子用来返回指定表的记录行数:

    public int countRows() {
    SqlFunction sf = new SqlFunction(dataSource, "select count(*) from mytable");
    sf.compile();
    return sf.run();
    }
    posted @ 2008-08-12 15:31 飞飞 阅读(3925) | 评论 (2)编辑 收藏

    (1)模板 + 数据模型 = 输出

    FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念他们是分工劳动的:
    设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;
    程序员创建系统,生成设计页面要显示的数据。
    经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的。在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码。

    下面是一个例子:

    <html>
    <head>
    <title>Welcome!</title>
    </head>
    <body>
    <h1>Welcome ${user}!</h1>
    <p>Our latest product:
    <a href="${latestProduct.url}">${latestProduct.name}</a>!
    </body>
    </html>
    
    这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)。
    至于user、latestProduct.url和latestProduct.name来自于数据模型(data model)。
    数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。
    模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。

    下面是一个可能的数据模型:

    (root)
    |
    +- user = "Big Joe"
    |
    +- latestProduct
    |
    +- url = "products/greenmouse.html"
    |
    +- name = "green mouse"
    
    数据模型类似于计算机的文件系统,latestProduct可以看作是目录。

    2、数据模型

    (1)基础

    在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和sequences,其实还可以有其它更多的能力:

    • scalars:存储单值
    • hashes:充当其它对象的容器,每个都关联一个唯一的查询名字
    • sequences:充当其它对象的容器,按次序访问
    • 方法:通过传递的参数进行计算,以新对象返回结果
    • 用户自定义FTL标记:宏和变换器

    通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子:

    (root)
    |
    +- mouse = "Yerri"
    |
    +- age = 12
    |
    +- color = "brown">
    
    mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板:
    ${mouse}       <#-- use mouse as scalar -->
    ${mouse.age}   <#-- use mouse as hash -->
    ${mouse.color} <#-- use mouse as hash -->
    
    输出结果是:
    Yerri
    12
    brown
    

    (2)Scalar变量

    Scalar变量存储单值,可以是:

    • 字符串:简单文本,在模板中使用引号(单引号或双引号)括起
    • 数字:在模板中直接使用数字值
    • 日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们
    • 布尔值:true或false,通常在<#if …>标记中使用

    (3)hashes 、sequences和集合

    有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:

    • hashes:具有一个唯一的查询名字和它包含的每个变量相关联
    • sequences:使用数字和它包含的每个变量相关联,索引值从0开始

    集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list …>指令使用的受限sequences

    (4)方法

    方法变量通常是基于给出的参数计算值。

    下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值:

    The average of 3 and 5 is: ${avg(3, 5)}
    The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
    The average of the price of python and elephant is:
    ${avg(animals.python.price, animals.elephant.price)}
    

    (5)宏和变换器

    宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性

    (6)节点

    节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲

    3、模板

    (1)整体结构

    模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:

    • 文本:直接输出
    • Interpolation:由${和},或#{和}来限定,计算值替代输出
    • FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出
    • 注释:由<#--和-->限定,不会输出

    下面是以一个具体模板例子:

    <html>
    <head>
    <title>Welcome!</title>
    </head>
    <body>
    <#-- Greet the user with his/her name -->
    <h1>Welcome ${user}!</h1>
    <p>We have these animals:
    <ul>
    <#list animals as being>
    <li>${being.name} for ${being.price} Euros
    </#list>
    </ul>
    </body>
    </html>
    

    注意事项:

    • FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的
    • Interpolation只能在文本中使用
    • FTL标记不能位于另一个FTL标记内部,例如:
    <#if <#include 'foo'>='bar'>...</if>
    
    • 注释可以位于FTL标记和Interpolation内部,如下面的例子:
    <h1>Welcome ${user <#-- The name of user -->}!</h1>
    <p>We have these animals:
    <ul>
    <#list <#-- some comment... --> animals as <#-- again... --> being>
    ...
    
    • 余的空白字符会在模板输出时移除

    (2)指令

    在FreeMarker中,使用FTL标记引用指令。有三种FTL标记,这和HTML标记是类似的:

    • 开始标记:<#directivename parameters>
    • 结束标记:</#directivename>
    • 空内容指令标记:<#directivename parameters/>

    有两种类型的指令:预定义指令和用户定义指令。

    用户定义指令要使用@替换#,如<@mydirective>...</@mydirective>(会在后面讲述)。

    FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:

    <ul>
    <#list animals as being>
    <li>${being.name} for ${being.price} Euros
    <#if use = "Big Joe">
    (except for you)
    </#list>
    </#if> <#-- WRONG! -->
    </ul>
    
    如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。

    FreeMarker会忽略FTL标记中的空白字符,如下面的例子:

    <#list
    animals       as
    being
    >
    ${being.name} for ${being.price} Euros
    </#list    >
    
    但是,<、</和指令之间不允许有空白字符。

    (3)表达式

    直接指定值

    • 字符串
    使用单引号或双引号限定

    如果包含特殊字符需要转义,如下面的例子:

    ${"It's \"quoted\" and
    this is a backslash: \\"}
    ${'It\'s "quoted" and
    this is a backslash: \\'}
    
    输出结果是:
    It's "quoted" and
    this is a backslash: \
    It's "quoted" and
    this is a backslash: \
    
    下面是支持的转义序列:

    转义序列 含义
    \" 双引号(u0022)
    \' 单引号(u0027)

    反斜杠(u005C)
    \n 换行(u000A)
    \r Return (u000D)
    \t Tab (u0009)
    \b Backspace (u0008)
    \f Form feed (u000C)
    \l <
    \g >
    \a &
    \{ {
    \xCode 4位16进制Unicode代码

    有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:

    ${r"${foo}"}
    ${r"C:\foo\bar"}
    
    输出的结果是:
    ${foo}
    C:\foo\bar
    
    • 数字

    直接输入,不需要引号

    精度数字使用“.”分隔,不能使用分组符号

    目前版本不支持科学计数法,所以“1E3”是错误的

    不能省略小数点前面的0,所以“.5”是错误的

    数字8、+8、08和8.00都是相同的

    • 布尔值

    true和false,不使用引号

    • 序列

    由逗号分隔的子变量列表,由方括号限定,下面是一个例子:

    <#list ["winter", "spring", "summer", "autumn"] as x>
    ${x}
    </#list>
    
    输出的结果是:
    winter
    spring
    summer
    autumn
    
    列表的项目是表达式,所以可以有下面的例子:
    [2 + 2, [1, 2, 3, 4], "whatnot"]
    
    可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号

    可以定义反递增的数字范围,如5..2

    • 散列(hash)
    由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子:
    {"name":"green mouse", "price":150}
    
    键和值都是表达式,但是键必须是字符串

    获取变量

    • 顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头
    • 从散列中获取数据

    可以使用点语法或方括号语法,假设有下面的数据模型:

    (root)
    |
    +- book
    |   |
    |   +- title = "Breeding green mouses"
    |   |
    |   +- author
    |       |
    |       +- name = "Julia Smith"
    |       |
    |       +- info = "Biologist, 1923-1985, Canada"
    |
    +- test = "title"
    
    下面都是等价的:
    book.author.name
    book["author"].name
    book.author.["name"]
    book["author"]["name"]
    
    使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果
    • 从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0

    序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式

    • 特殊变量:FreeMarker内定义变量,使用.variablename语法访问

    字符串操作

    • Interpolation(或连接操作)

    可以使用${..}(或#{..})在文本部分插入表达式的值,例如:

    ${"Hello ${user}!"}
    ${"${user}${user}${user}${user}"}
    
    可以使用+操作符获得同样的结果
    ${"Hello " + user + "!"}
    ${user + user + user + user}
    
    ${..}只能用于文本部分,下面的代码是错误的:
    <#if ${isBig}>Wow!</#if>
    <#if "${isBig}">Wow!</#if>
    
    应该写成:
    <#if isBig>Wow!</#if>
    
    • 子串

    例子(假设user的值为“Big Joe”):

    ${user[0]}${user[4]}
    ${user[1..4]}
    
    结果是(注意第一个字符的索引是0):
    BJ
    ig J
    
    序列操作
    • 连接操作:和字符串一样,使用+,下面是一个例子:
    <#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
    - ${user}
    </#list>
    
    输出结果是:
    - Joe
    - Fred
    - Julia
    - Kate
    
    散列操作
    • 连接操作:和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如:
    <#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
    - Joe is ${ages.Joe}
    - Fred is ${ages.Fred}
    - Julia is ${ages.Julia}
    
    输出结果是:
    - Joe is 30
    - Fred is 25
    - Julia is 18
    
    算术运算
    • +、-、×、/、%,下面是一个例子:
    ${x * x - 100}
    ${x / 2}
    ${12 % 10}
    
    输出结果是(假设x为5):
    -75
    2.5
    2
    
    操作符两边必须是数字,因此下面的代码是错误的:
    ${3 * "5"} <#-- WRONG! -->
    
    使用+操作符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串,例如:
    ${3 + "5"}
    
    输出结果是:
    35
    
    使用内建的int(后面讲述)获得整数部分,例如:
    ${(x/2)?int}
    ${1.1?int}
    ${1.999?int}
    ${-1.1?int}
    ${-1.999?int}
    
    输出结果是(假设x为5):
    2
    1
    1
    -1
    -1
    
    • 比较操作符

    使用=(或==,完全相等)测试两个值是否相等,使用!= 测试两个值是否不相等

    =和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = "1">会引起错误

    Freemarker是精确比较,所以对"x"、"x "和"X"是不相等的

    对数字和日期可以使用<、<=、>和>=,但不能用于字符串

    由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免这种情况,例如<#if (x > y)>

    另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>=

    • 逻辑操作符

    &&(and)、||(or)、!(not),只能用于布尔值,否则会产生错误

    例子:

    <#if x < 12 && color = "green">
    We have less than 12 things, and they are green.
    </#if>
    <#if !hot> <#-- here hot must be a boolean -->
    It's not hot.
    </#if>
    
    • 内建函数

    内建函数的用法类似访问散列的子变量,只是使用“?”替代“.”,下面列出常用的一些函数

      • 字符串使用的:

    html:对字符串进行HTML编码

    cap_first:使字符串第一个字母大写

    lower_case:将字符串转换成小写

    upper_case:将字符串转换成大写

    trim:去掉字符串前后的空白字符

      • 序列使用的:

    size:获得序列中元素的数目

      • 数字使用的:

    int:取得数字的整数部分(如-1.9?int的结果是-1)

    例子(假设test保存字符串"Tom & Jerry"):

    ${test?html}
    ${test?upper_case?html}
    
    输出结果是:
    Tom &amp; Jerry
    TOM &amp; JERRY
    
    • 操作符优先顺序

    操作符组 操作符
    后缀 [subvarName] [subStringRange] . (methodParams)
    一元 +expr、-expr、!
    内建 ?
    乘法 *、 / 、%
    加法 +、-
    关系 <、>、<=、>=(lt、lte、gt、gte)
    相等 ==(=)、!=
    逻辑and &&
    逻辑or 双竖线
    数字范围 ..

    (4)Interpolation

    Interpolation有两种类型:

    1. 通用Interpolation:${expr}
    1. 数字Interpolation:#{expr}或#{expr; format}

    注意:Interpolation只能用于文本部分

    • 通用Interpolation

    插入字符串值:直接输出表达式结果

    插入数字值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:

    <#setting number_format="currency"/>
    <#assign answer=42/>
    ${answer}
    ${answer?string}  <#-- the same as ${answer} -->
    ${answer?string.number}
    ${answer?string.currency}
    ${answer?string.percent}
    
    输出结果是:
    $42.00
    $42.00
    42
    $42.00
    4,200%
    
    插入日期值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子:
    ${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
    ${lastUpdated?string("EEE, MMM d, ''yy")}
    ${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}
    
    输出的结果类似下面的格式:
    2003-04-08 21:24:44 Pacific Daylight Time
    Tue, Apr 8, '03
    Tuesday, April 08, 2003, 09:24:44 PM (PDT)
    
    插入布尔值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:
    <#assign foo=true/>
    ${foo?string("yes", "no")}
    
    输出结果是:
    yes
    
    • 数字Interpolation的#{expr; format}形式可以用来格式化数字,format可以是:

    mX:小数部分最小X位

    MX:小数部分最大X位

    例子:

    <#-- If the language is US English the output is: -->
    <#assign x=2.582/>
    <#assign y=4/>
    #{x; M2}   <#-- 2.58 -->
    #{y; M2}   <#-- 4    -->
    #{x; m1}   <#-- 2.6 -->
    #{y; m1}   <#-- 4.0 -->
    #{x; m1M2} <#-- 2.58 -->
    #{y; m1M2} <#-- 4.0  -->
    

    4、杂项

    (1)用户定义指令

    宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏

    • 基本用法

    宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是一个例子:

    <#macro greet>
    <font size="+2">Hello Joe!</font>
    </#macro>
    
    作为用户定义指令使用宏变量时,使用@替代FTL标记中的#
    <@greet></@greet>
    
    如果没有体内容,也可以使用:
    <@greet/>
    
    • 参数

    在macro指令中可以在宏变量之后定义参数,如:

    <#macro greet person>
    <font size="+2">Hello ${person}!</font>
    </#macro>
    
    可以这样使用这个宏变量:
    <@greet person="Fred"/> and <@greet person="Batman"/>
    
    输出结果是:
      <font size="+2">Hello Fred!</font>
    and   <font size="+2">Hello Batman!</font>
    

    宏的参数是FTL表达式,所以下面的代码具有不同的意思:

    <@greet person=Fred/>
    
    这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式

    可以有多参数,下面是一个例子:

    <#macro greet person color>
    <font size="+2" color="${color}">Hello ${person}!</font>
    </#macro>
    
    可以这样使用该宏变量:
    <@greet person="Fred" color="black"/>
    
    其中参数的次序是无关的,因此下面是等价的:
    <@greet color="black" person="Fred"/>
    
    只能使用在macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是错误的:
    <@greet person="Fred" color="black" background="green"/>
    <@greet person="Fred"/>
    
    可以在定义参数时指定缺省值,如:
    <#macro greet person color="black">
    <font size="+2" color="${color}">Hello ${person}!</font>
    </#macro>
    
    这样<@greet person="Fred"/>就正确了

    宏的参数是局部变量,只能在宏定义中有效

    • 嵌套内容

    用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板片断

    例子:

    <#macro border>
    <table border=4 cellspacing=0 cellpadding=4><tr><td>
    <#nested>
    </tr></td></table>
    </#macro>
    
    这样使用该宏变量:
    <@border>The bordered text</@border>
    
    输出结果:
      <table border=4 cellspacing=0 cellpadding=4><tr><td>
    The bordered text
    </tr></td></table>
    

    <#nested>指令可以被多次调用,例如:

    <#macro do_thrice>
    <#nested>
    <#nested>
    <#nested>
    </#macro>
    <@do_thrice>
    Anything.
    </@do_thrice>
    
    输出结果:
      Anything.
    Anything.
    Anything.
    
    嵌套内容可以是有效的FTL,下面是一个有些复杂的例子: <@border> <ul> <@do_thrice> <li><@greet person="Joe"/> </@do_thrice> </ul> </@border> }}} 输出结果:
      <table border=4 cellspacing=0 cellpadding=4><tr><td>
    <ul>
    <li><font size="+2">Hello Joe!</font>
    <li><font size="+2">Hello Joe!</font>
    <li><font size="+2">Hello Joe!</font>
    </ul>
    </tr></td></table>
    
    宏定义中的局部变量对嵌套内容是不可见的,例如:
    <#macro repeat count>
    <#local y = "test">
    <#list 1..count as x>
    ${y} ${count}/${x}: <#nested>
    </#list>
    </#macro>
    <@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat>
    
    输出结果:
        test 3/1: ? ? ?
    test 3/2: ? ? ?
    test 3/3: ? ? ?
    
    • 在宏定义中使用循环变量

    用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字

    例子:

    <#macro repeat count>
    <#list 1..count as x>
    <#nested x, x/2, x==count>
    </#list>
    </#macro>
    <@repeat count=4 ; c, halfc, last>
    ${c}. ${halfc}<#if last> Last!</#if>
    </@repeat>
    
    输出结果:
      1. 0.5
    2. 1
    3. 1.5
    4. 2 Last!
    

    指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题

    调用时少指定循环变量,则多指定的值不可见

    调用时多指定循环变量,多余的循环变量不会被创建

    (2)在模板中定义变量

    在模板中定义的变量有三种类型:

    • plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换
    • 局部变量:在宏定义体中有效,使用local指令创建和替换
    • 循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建

    宏的参数是局部变量,而不是循环变量;局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:

    <#assign x = "plain">
    1. ${x}  <#-- we see the plain var. here -->
    <@test/>
    6. ${x}  <#-- the value of plain var. was not changed -->
    <#list ["loop"] as x>
    7. ${x}  <#-- now the loop var. hides the plain var. -->
    <#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
    8. ${x}  <#-- it still hides the plain var. -->
    </#list>
    9. ${x}  <#-- the new value of plain var. -->
    <#macro test>
    2. ${x}  <#-- we still see the plain var. here -->
    <#local x = "local">
    3. ${x}  <#-- now the local var. hides it -->
    <#list ["loop"] as x>
    4. ${x}  <#-- now the loop var. hides the local var. -->
    </#list>
    5. ${x}  <#-- now we see the local var. again -->
    </#macro>
    
    输出结果:
    1. plain
    2. plain
    3. local
    4. loop
    5. local
    6. plain
    7. loop
    8. loop
    9. plain2
    

    内部循环变量隐藏同名的外部循环变量,如:

    <#list ["loop 1"] as x>
    ${x}
    <#list ["loop 2"] as x>
    ${x}
    <#list ["loop 3"] as x>
    ${x}
    </#list>
    ${x}
    </#list>
    ${x}
    </#list>
    
    输出结果:
      loop 1
    loop 2
    loop 3
    loop 2
    loop 1
    
    模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:
    <#assign user = "Joe Hider">
    ${user}          <#-- prints: Joe Hider -->
    ${.globals.user} <#-- prints: Big Joe -->
    

    (3)名字空间

    通常情况,只使用一个名字空间,称为主名字空间

    为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字空间,其目的是防止同名冲突

    • 创建库

    下面是一个创建库的例子(假设保存在lib/my_test.ftl中):

    <#macro copyright date>
    <p>Copyright (C) ${date} Julia Smith. All rights reserved.
    <br>Email: ${mail}</p>
    </#macro>
    <#assign mail = "jsmith@acme.com">
    
    使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量:
    <#import "/lib/my_test.ftl" as my>
    <#assign mail="fred@acme.com">
    <@my.copyright date="1999-2002"/>
    ${my.mail}
    ${mail}
    
    输出结果:
      <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
    <br>Email: jsmith@acme.com</p>
    jsmith@acme.com
    fred@acme.com
    
    可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间

    可以使用assign指令在导入的名字空间中创建或替代变量,下面是一个例子:

    <#import "/lib/my_test.ftl" as my>
    ${my.mail}
    <#assign mail="jsmith@other.com" in my>
    ${my.mail}
    
    输出结果:
    jsmith@acme.com
    jsmith@other.com
    
    数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库:
    <#macro copyright date>
    <p>Copyright (C) ${date} ${user}. All rights reserved.</p>
    </#macro>
    <#assign mail = "${user}@acme.com">
    
    假设数据模型中的user变量的值是Fred,则下面的代码:
    <#import "/lib/my_test.ftl" as my>
    <@my.copyright date="1999-2002"/>
    ${my.mail}
    
    输出结果:
      <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
    Fred@acme.com
    
    posted @ 2008-08-12 14:14 飞飞 阅读(210) | 评论 (0)编辑 收藏

    <a href="javascript:void(window.open('1.htm','_blank','toolbar=no,scrollbar=no,top=50,left=50,width=100,height=100'));" >Open 1.htm</a>

    <a href="javascript: var win=window.open
    ('1.htm','_blank','toolbar=no,scrollbar=no,top=50,left=50,width=100,height=100')" >Open
    1.htm</a>
    最好。
    <a href="#" onclick="window.open('1.htm','_blank','toolbar=no,scrollbar=no,top=50,left=50,width=100,height=100')" >Open 1.htm</a>
    点击后,原窗口的联接地址会发生变化,加上了#,感觉不太好:)虽然也能实现功能
    posted @ 2008-08-11 18:44 飞飞 阅读(963) | 评论 (2)编辑 收藏

    视图解析器的一些属性

    <bean id="viewResolver"

          class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="exposeSpringMacroHelpers" value="true"/>

        <property name="requestContextAttribute" value="rc"/>

        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

        <property name="prefix" value="/"/>

        <property name="suffix" value=".jsp"/>

    </bean>

    在视图解析器的定义中,“exposeSpringMacroHelpers”设置是否通过Spring的宏库暴露一个RequestContext(名为springBindRequestContext)供外部使用,默认值为false。它暴露了处理表单和验证错误信息的宏操作;

    requestContextAttribute”把SpringRequestContext对象暴露为变量rc。利用${rc.contextPath}来获取应用程序的contextPath(也就是/MyUsers);利用${rc.getMessage("user.name")}读取/WEB-INF/classes/messages.properties本地化信息。此对象对于那些不访问serlvet请求的View技术(也就是VelocityFreeMarker模板)来说是必不可少的。

    还有一些属性:

    exposeRequestAttributes:默认值false,设置是否所有的request属性在与模板进行合并之前添加到model中。(可以理解为request范围内包含的所有对象,而不是一个真正的Request对象。)

    exposeSessionAttributes:默认值false,设置是否所有的session属性在与模板进行合并之前添加到model中。(理解同上)

    posted @ 2008-08-11 17:20 飞飞 阅读(460) | 评论 (0)编辑 收藏

    Step 1:配置web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    >


        
    <display-name>springapp</display-name>
            
        
    <servlet>
            
    <servlet-name>springMVC</servlet-name>
            
    <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            
    </servlet-class>
            
    <load-on-startup>1</load-on-startup>
        
    </servlet>

        
    <servlet-mapping>
            
    <servlet-name>springMVC</servlet-name>
            
    <url-pattern>/page/*</url-pattern>
        
    </servlet-mapping>

    </web-app>
    servlet-mapping定义所有以/page/开头的url请求都会被spring 的DispatcherServlet处理转发。默认情况下DispatcherServlet会读取<servlet-name>-servlet.xml文件的配置信息初始化,该文件中urlMapping的定义决定当前请求转发给哪个controller来处理。

    Step2:
    定义/WEB-INF/springMVC-servlet.xml
     
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
        
    <!-- 方法名解析器 -->
        
    <bean id="InternalPathMethodNameResolver"
            class
    ="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
            
        
    <!-- 视图解析器 -->
        
    <bean id="viewResolver"
            class
    ="org.springframework.web.servlet.view.InternalResourceViewResolver">
            
    <property name="viewClass">
                
    <value>org.springframework.web.servlet.view.JstlView</value>
            
    </property>
        
    </bean>
        
        
    <bean id="controller" class="com.controller.IndexController">
            
    <property name="methodNameResolver">
                
    <ref bean="InternalPathMethodNameResolver" />
            
    </property>
        
    </bean>

        
    <bean id="urlMapping"
            class
    ="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            
    <property name="mappings">
                
    <props>
                    
    <prop key="/controller/*">controller</prop>
                
    </props>
            
    </property>
        
    </bean>
    </beans>
    urlMapping定义/controller/开头的url请求由名字为controller的控制器来处理,因为是多动作处理器,所以要定义MethodNameResolver来告诉springMVC应该调用controller的哪个方法,这里用的是InternalPathMethodNameResolver,该方法名解释器会把整个URL中最后一个"/"和最后一个"."之间的部分作为要调用的方法名

    Step3:定义controller类并继承MultiActionController 
    package com.controller;

    import
     java.io.IOException;
    import
     java.util.HashMap;
    import
     java.util.Map;

    import
     javax.servlet.ServletException;
    import
     javax.servlet.http.HttpServletRequest;
    import
     javax.servlet.http.HttpServletResponse;

    import
     org.springframework.web.servlet.ModelAndView;
    import
     org.springframework.web.servlet.mvc.multiaction.MultiActionController;

    public class IndexController extends MultiActionController 
    {
        
        
    public
     ModelAndView method1(HttpServletRequest request,
                HttpServletResponse respnose) 
    throws ServletException, IOException 
    {
            Map model 
    = new
     HashMap();
            model.put(
    "message""你调用的是方法1"
    );
            
    return new ModelAndView("/index.jsp""model"
    , model);
        }

        
        
    public ModelAndView method2(HttpServletRequest request,
                HttpServletResponse respnose) 
    throws ServletException, IOException 
    {
            Map model 
    = new
     HashMap();
            model.put(
    "message""你调用的是方法2"
    );
            
    return new ModelAndView("/index.jsp""model"
    , model);
        }

    }


    通过配置文件,访问上面这个controller中某个方法的url即为:localhost:8080/page/controller/方法名


    Step4:/index.jsp
    <%@ page language="java" pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"%> 


    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <html>
    <head></head>  
    <body>

        
    <c:out value="${model.message}"/>
    </body>
    </html>
    因为InternalPathMethodNameResolver方法名解释器会把整个URL中最后一个"/"和最后一个"."之间的部分作为要调用的方法名,所以你可以在这个URL后面加任意文件格式的后缀,比如:
    localhost:8080/page/controller/method1.jsp

    localhost:8080/page/controller/method2.html
    很爽吧,和真实的URL地址一样。


    另:开发环境:MyEclipse5.0M2+tomcat5.5
      需要用到spring.jar和jstl.jar两个包。
    posted @ 2008-08-11 16:02 飞飞 阅读(204) | 评论 (0)编辑 收藏

    servlet 2.5的写法
        <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
    version="2.5">

    别以为看到这里就结束了,很可惜地告诉你,这段代码是错误的。不信你尝试打开一下这个链接http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd,你会发现是no page found。

    那为什么tomcat6的范例程序能够工作呢,那是因为在tomcat6的lib里面,已经存在这个文件,所以也不需要从网络上面抓取。其实你按照这个web.xml写了servlet 2.5的程序,在tomcat6里面也是可以运行的。

    可是当我使用eclipse+xmlbuddy的时候,问题就出来了,因为web-app_2_5.xsd一直不能下载,xmlbuddy一直报错,并且没有语法提示功能。通过搜索,我发现了web-app_2_5.xsd的真实地址其实是http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd,而它的namespace是http://java.sun.com/xml/ns/javaee,于是代码应该改成:

        <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    留意一下不同的部分,其实是因为sun把j2ee改名为javaee。

    ps,另外附上servlet 2.4的写法

        <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    posted @ 2008-08-11 10:13 飞飞 阅读(526) | 评论 (0)编辑 收藏

    1. 实体(表)的命名
      1) 表以名词或名词短语命名,确定表名是采用复数还是单数形式,此外给表的别名定义简单规则(比方说,如果表名是一个单词,别名就取单词的前4 个字母;如果表名是两个单词,就各取两个单词的前两个字母组成4 个字母长的别名;如果表的名字由3 个单词组成,从头两个单词中各取一个然后从最后一个单词中再取出两个字母,结果还是组成4 字母长的别名,其余依次类推)
      对工作用表来说,表名可以加上前缀WORK_ 后面附上采用该表的应用程序的名字。在命名过程当中,根据语义拼凑缩写即可。注意,由于ORCLE会将字段名称统一成大写或者小写中的一种,所以要求加上下划线。
      举例:
      定义的缩写 Sales: Sal 销售;
      Order: Ord 订单;
      Detail: Dtl 明细;
      则销售订单明细表命名为:Sal_Ord_Dtl;
      2) 如果表或者是字段的名称仅有一个单词,那么建议不使用缩写,而是用完整的单词。
      举例:
      定义的缩写 Material Ma 物品;
      物品表名为:Material, 而不是 Ma.
      但是字段物品编码则是:Ma_ID;而不是Material_ID
      3) 所有的存储值列表的表前面加上前缀Z
      目的是将这些值列表类排序在数据库最后。
      4) 所有的冗余类的命名(主要是累计表)前面加上前缀X
      冗余类是为了提高数据库效率,非规范化数据库的时候加入的字段或者表
      5) 关联类通过用下划线连接两个基本类之后,再加前缀R的方式命名,后面按照字母顺序罗列两个表名或者表名的缩写。
      关联表用于保存多对多关系。
      如果被关联的表名大于10个字母,必须将原来的表名的进行缩写。如果没有其他原因,建议都使用缩写。
      举例:表Object与自身存在多对多的关系,则保存多对多关系的表命名为:R_Object;
      表 Depart和Employee;存在多对多的关系;则关联表命名为R_Dept_Emp
      2. 属性(列)的命名
      1) 采用有意义的列名,表内的列要针对键采用一整套设计规则。每一个表都将有一个自动ID作为主健,逻辑上的主健作为第一组候选主健来定义,如果是数据库自动生成的编码,统一命名为:ID;如果是自定义的逻辑上的编码则用缩写加“ID”的方法命名。如果键是数字类型,你可以用_NO 作为后缀;如果是字符类型则可以采用_CODE 后缀。对列名应该采用标准的前缀和后缀。
      举例:销售订单的编号字段命名:Sal_Ord_ID;如果还存在一个数据库生成的自动编号,则命名为:ID。
      2) 所有的属性加上有关类型的后缀,注意,如果还需要其它的后缀,都放在类型后缀之前。
      注: 数据类型是文本的字段,类型后缀TX可以不写。有些类型比较明显的字段,可以不写类型后缀。
      3) 采用前缀命名
      给每个表的列名都采用统一的前缀,那么在编写SQL表达式的时候会得到大大的简化。这样做也确实有缺点,比如破坏了自动表连接工具的作用,后者把公共列名同某些数据库联系起来。
      3. 视图的命名
      1) 视图以V作为前缀,其他命名规则和表的命名类似;
      2) 命名应尽量体现各视图的功能
      4. 触发器的命名
      触发器以TR作为前缀,触发器名为相应的表名加上后缀,Insert触发器加"_I",Delete触发器加"_D",Update触发器加"_U",如:

      TR_Customer_I,TR_Customer_D,TR_Customer_U。
      5. 存储过程名
      存储过程应以"UP_"开头,和系统的存储过程区分,后续部分主要以动宾形式构成,并用下划线分割各个组成部分。如增加代理商的帐户的存储过程为"UP_Ins_Agent_Account"。
      6. 变量名
      变量名采用小写,若属于词组形式,用下划线分隔每个单词,如@my_err_no。
      7. 命名中其他注意事项
      1)  以上命名都不得超过30个字符的系统限制。变量名的长度限制为29(不包括标识字符@)。
      2)  数据对象、变量的命名都采用英文字符,禁止使用中文命名。绝对不要在对象名的字符之间留空格。
      3) 小心保留词,要保证你的字段名没有和保留词、数据库系统或者常用访问方法冲突
      5) 保持字段名和类型的一致性,在命名字段并为其指定数据类型的时候一定要保证一致性。假如数据类型在一个表里是整数,那在另一个表里可就别变成字符型了。

    posted @ 2008-08-08 10:00 飞飞 阅读(431) | 评论 (0)编辑 收藏

    如果底层数据库(如Oracle)支持存储过程,也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行,速度更加快。在Oracle数据库中可以定义一个名为batchUpdateStudent()的存储过程,代码如下:

    create or replace procedure batchUpdateStudent(p_age in number) as
    begin
    update STUDENT set AGE=AGE+1 where AGE>p_age;
    end;

    以上存储过程有一个参数p_age,代表学生的年龄,应用程序可按照以下方式调用存储过程:

    tx = session.beginTransaction();
    Connection con=session.connection();

    String procedure = "{call batchUpdateStudent(?) }";
    CallableStatement cstmt = con.prepareCall(procedure);
    cstmt.setInt(1,0); //把年龄参数设为0
    cstmt.executeUpdate();
    tx.commit();

    在以上代码中,用的是Hibernate的 Transaction接口来声明事务,而不是采用JDBC API来声明事务。

    posted @ 2008-08-08 09:53 飞飞 阅读(324) | 评论 (0)编辑 收藏

    BUG1
    2008-08-07 11:25:01,015 DEBUG (FacesSetupInterceptor.java:136) - Unable to initialize faces
     java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
     at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:256)
     at org.apache.struts2.jsf.FacesSetupInterceptor.init(FacesSetupInterceptor.java:133)
     at com.opensymphony.xwork2.ObjectFactory.buildInterceptor(ObjectFactory.java:186)
     at com.opensymphony.xwork2.config.providers.InterceptorBuilder.constructInterceptorReference(InterceptorBuilder.java:57)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.lookupInterceptorReference(XmlConfigurationProvider.java:905)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStack(XmlConfigurationProvider.java:743)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStacks(XmlConfigurationProvider.java:756)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptors(XmlConfigurationProvider.java:777)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:410)
     at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:239)
     at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:111)
     at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reload(DefaultConfiguration.java:152)
     at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:52)
     at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:395)
     at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:452)
     at org.apache.struts2.dispatcher.FilterDispatcher.init(FilterDispatcher.java:201)
     at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
     at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
     at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108)
     at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3693)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4340)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

    这个错误是由配置文件引起。在session-factory段加入:
    <property name="current_session_context_class">thread</property>
    posted @ 2008-08-07 11:31 飞飞 阅读(407) | 评论 (0)编辑 收藏

         摘要: 一. 简介 1. 简介 目前的版本是:4.0 正式版 发布于2008-05-30 2. 注意事项 My97DatePicker目录是一个整体,不可破坏里面的目录结构,也不可对里面的文件改名,可以改目录名 My97DatePicker.htm是必须文件,不可删除 各目录及文件的用途: WdatePicker.js 配置文件,在调用的地方仅需使用该文...  阅读全文
    posted @ 2008-08-06 09:09 飞飞 阅读(2978) | 评论 (0)编辑 收藏

    1、MyEclipse下建立新的Web Porject

    2、Copy Struts2的lib文件到工程的WEB-INF/lib下非*-plugin-2.0.6.jar的所有的包加上struts2-spring- plugin-2.0.6.jar,最小的包可以在struts-2.0.6\apps\struts2-blank-2.0.6\WEB-INF\ lib下找到,不过因为使用Spring、Hiberate那点包是不够用的

    3.1、工程名上右键->MyEclipse->Add Spring Capabilities点击出现对话框

    3.2、由于我用的MyEclipse中Spring的插件是1.2的,所以没使用MyEclipse下的包,不选择MyEclipse Libraries

    3.3、选中Copy checked library contents to project folder (TLDs always copied)

    3.4、使用默认的Library Folder:/WebRoot/WEB-INF/lib,Next

    3.5、Folder点周Brower选中项目的WebRoot/WEB-INF/

    3.6、点击Finish

    4、配置MyEclipse数据库设置

    4.1、菜单Windows->Preferences->MyEclipse->Database Explorer->Drivers

    4.2、点击New设置数据库连接,例:
    Driver template : Oracle (Thin driver)
    Driver name : Oracle (Thin driver)
    Connection URL : jdbc:oracle:thin:@<server>[:<1521>]:<database_name>
    Driver JARs: ojdbc14.jar
    Dirver classname : oracle.jdbc.driver.OracleDriver

    4.3、点击OK、OK

    5、忘了Copy Spring 2的jar包到工程中了,不过没关系,现在Copy也一样,Copy spring-framework-2.0.3\dist\spring.jar 到/WebRoot/WEB-INF/lib下就可以了,如果想Copy专用的包可以Copy spring-framework-2.0.3\dist\modules下的

    5.1、菜单Windows->Open perspective->MyEclipse Database Explorer

    5.2、在DB Brower点右键->New

    5.3、配置例子如下:
    Profile name: test
    Driver: Oracle (Thin driver)
    URL: jdbc:oracle:thin:@127.0.0.1:1521:test
    User name: test
    Password: test
    选中Save password

    5.4、点击Finish

    6.1、配置Hibernate

    6.2 工程名上右键->MyEclipse->Add Hiberate Capabilities点击出现对话框

    6.3、选中Copy checked Library Jars to project forlder and add to build-path 点击Next

    6.4、选中Spring configuration file (applicationContext.xml)点击Next

    6.5、选中Existing Spring configuration file,MyEclipse会帮你自动找到Spring Config文件的

    6.6、SessionFactory ID填写sessionFactory点击Next

    6.7、Bean Id填写dataSource,选中DB Profile下刚才建好的test,点击Next

    6.8、不选择Create SessionFactory class?点击Finish

    7、这时候会提示你某些类没发现,Copy commons-dbcp-1.2.1.jar到lib下就OK了


    8 配置struts.properties文件,指定spring作为struts的IoC容器
    struts.objectFactory = spring
    (1)默认的autowiring模式是:by name
    即如果applicationContext.xml文件中的bean id与struts.xml文件中的action name相同,就
    (2)如果要改为其他模式:
    struts.objectFactory.spring.autoWire = name|type|auto|constructor

    例:

    struts.i18n.encoding=ISO-8859-1
    struts.locale=de_DE
    struts.objectFactory=spring
    ### Load custom default resource bundles
    struts.custom.i18n.resources=testmessages
    ### XSLT Cache
    struts.xslt.nocache = true


    9配置web.xml文件,启动Spring侦听器
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    10 在WEB-INF目录下的applicationContext.xml文件
    例:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans default-autowire="autodetect">
    <bean id="personManager" class="com.acme.PersonManager"/>
    </beans >

    11 设置由Spring来初始化action
    11.1  在Spring的applicationContext.xml文件中配置bean(即action类)
    11.2  将struts.xml中的action的class属性,由class名改为Spring中定义的bean名
    例如:
    (1)applicationContext.xml中,定义bean id是bar
    <beans default-autowire="autodetect">
    <bean id="bar" class="com.my.BarClass" singleton="false"/>
    ...
    </beans>
    (2)struts.xml中,action的class="bar",而不是通常的类名
    <package name="secure" namespace="/secure" extends="default">
    <action name="bar" class="bar">
    <result>bar.ftl</result>
    </action>
    </package >

    启动运行:
    报错
    log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
    log4j:WARN Please initialize the log4j system properly.
    2008-8-6 9:29:16 org.apache.catalina.core.ApplicationContext log
    信息: Initializing Spring root WebApplicationContext
    2008-8-6 9:29:18 org.apache.catalina.core.StandardContext listenerStart
    严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:883)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:839)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:440)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
     at java.security.AccessController.doPrivileged(Native Method)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
     at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
     at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
     at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
     at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3827)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4334)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
     at java.lang.Class.getDeclaredConstructors0(Native Method)
     at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
     at java.lang.Class.getConstructor0(Unknown Source)
     at java.lang.Class.getDeclaredConstructor(Unknown Source)
     at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:54)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:877)
     ... 40 more
    2008-8-6 9:29:18 org.apache.catalina.core.StandardContext start
    严重: Error listenerStart
    2008-8-6 9:29:18 org.apache.catalina.core.StandardContext start
    严重: Context [/ssh] startup failed due to previous errors

    原因:
    找不到 Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
    就Apache所提供的基本对象池。

    解决:
    到这里http://commons.apache.org/downloads/download_pool.cgi下载包,然后,把里面的commons-pool-x.jar复制到项目的lib文件夹下

    错误:
    log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
    log4j:WARN Please initialize the log4j system properly.

    解决:
    在WEB-INF/class 目录下建立一个log4j.properties文件,内容如下:
    log4j.rootLogger=DEBUG,stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n

    警告:

    信息: Starting Servlet Engine: Apache Tomcat/6.0.13
    log4j:WARN No appenders could be found for logger (org.apache.struts.util.PropertyMessageResources).
    log4j:WARN Please initialize the log4j system properly.
    2008-8-6 9:40:09 org.apache.catalina.core.ApplicationContext log
    信息: Initializing WebApplicationContext for Struts ActionServlet 'action', module ''
    2008-08-06 09:40:29,859 DEBUG (CollectionFactory.java:195) - Creating [java.util.concurrent.ConcurrentHashMap]
     2008-8-6 9:40:29 org.apache.catalina.core.ApplicationContext log
    信息: Initializing Spring root WebApplicationContext
    2008-08-06 09:40:29,906  INFO (ContextLoader.java:189) - Root WebApplicationContext: initialization started
     2008-08-06 09:40:30,203  INFO (AbstractApplicationContext.java:412) - Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1df59bd: display name [Root WebApplicationContext]; startup date [Wed Aug 06 09:40:30 CST 2008]; root of context hierarchy
     2008-08-06 09:40:30,406 DEBUG (CollectionFactory.java:195) - Creating [java.util.concurrent.ConcurrentHashMap]


    index.jsp

    <%@ page language="java" pageEncoding="GBK"%>
    <%@ taglib prefix="s" uri="/struts-tags"%>
    <html>
     <head>
      <title>登录</title>
      <style type="text/css">
    .label {
     font-style: italic;
    }

    .errorLabel {
     font-style: italic;
     color: red;
    }

    .errorMessage {
     font-weight: bold;
     color: red;
    }
    </style>
     </head>
     <s:head theme="ajax" />
     <body>
     <s:debug>
      <s:form action="First">
       <s:textfield name="username" label="用户名" />
       <s:textfield name="password" label="密码" />
       <s:submit value="登录" />
       <s:a href="First.action">登录</s:a>
      </s:form>
    </s:debug>
     </body>
    </html>



    BUG:
    2008-8-6 10:58:02 org.apache.catalina.core.StandardWrapperValve invoke
    严重: Servlet.service() for servlet jsp threw exception
    The Struts dispatcher cannot be found.  This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the request has passed through its servlet filter, which initializes the Struts dispatcher needed for this tag. - [unknown location]
     at org.apache.struts2.views.jsp.TagUtils.getStack(TagUtils.java:60)
     at org.apache.struts2.views.jsp.StrutsBodyTagSupport.getStack(StrutsBodyTagSupport.java:52)
     at org.apache.struts2.views.jsp.ComponentTagSupport.doStartTag(ComponentTagSupport.java:49)
     at org.apache.jsp.index_jsp._jspx_meth_s_005fhead_005f0(index_jsp.java:126)
     at org.apache.jsp.index_jsp._jspService(index_jsp.java:94)
     at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
     at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
     at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
     at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
     at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
     at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)
     at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
     at java.lang.Thread.run(Unknown Source)

    解决:web.xml添加
    <filter>
      <filter-name>struts2</filter-name>
      <filter-class>
       org.apache.struts2.dispatcher.FilterDispatcher
      </filter-class>
     </filter>
     <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
     </filter-mapping>


    posted @ 2008-08-06 09:07 飞飞 阅读(1979) | 评论 (0)编辑 收藏

    window.opener 实际上就是通过window.open打开的窗体的父窗体。

    比如在父窗体parentForm里面 通过 window.open("subForm.html"),那么在subform.html中 window.opener

    就代表parentForm,可以通过这种方式设置父窗体的值或者调用js方法。

    如:1,window.opener.test(); ---调用父窗体中的test()方法

        2,如果window.opener存在,设置parentForm中stockBox的值。

        if (window.opener && !window.opener.closed) {

           window.opener.document.parentForm.stockBox.value = symbol;

    }

    1>window.opener 的用法

    在一般的用法中,只是用来解决关闭窗口时不提示弹出窗口,   而对它更深层的了解一般比较少。其   实   window.opener是指调用window.open方法的窗口。
         在工作中主要是用来解决部分提交的。这种跨页操作对工作是非常有帮助的。
    如果你在主窗口打开了一个页面,并且希望主窗口刷新就用这个,打开页面的window.opener就相当于
    主窗口的window。
    主窗口的刷新你可以用
    window.opener.location.reload();
    如果你用虚拟的目录:如struts的*.do会提示你重试

    你可以改成这样 window.opener.yourformname.submit()
    就好了

    2〉

    在应用中有这样一个情况,
    在A窗口中打开B窗口,在B窗口中操作完以后关闭B窗口,同时自动刷新A窗口


    function closeWin(){
             hasClosed = true;
             window.opener.location="javascript:reloadPage();";
             window.close();
         }
         function window.onbeforeunload(){
             if(!hasClosed){
                 window.opener.location="javascript:reloadPage();";
             }
         }

    </script>
    上面的代码在关闭B窗口的时候会提示错误,说缺少Object,正确的代码如下:
    function closeWin(){
             hasClosed = true;
             window.opener.location="javascript:reloadPage();";
             window.opener=null;
             window.close();
         }
         function window.onbeforeunload(){
             if(!hasClosed){//如果已经执行了closeWin方法,则不执行本方法
                 window.opener.location="javascript:reloadPage();";
             }
         }

    </script>
    reloadPage方法如下:
    function reloadPage() {
             history.go(0);
             document.execCommand("refresh")
             document.location = document.location;
             document.location.reload();
         }
    PS:由于需要支持正常关闭和强制关闭窗口时能捕捉到事件,用了全局变量hasClosed

    ==============================================

    补充,在父窗口是frame的时候在刷新父窗口的时候会出现问题:

    The page cannot be refreshed without resending the information.
    后修改如下:
    window.opener.parent.document.frames.item('mainFrame').location.href = window.opener.location.href;
    不需要执行自带的reload()方法,注意,不要再画蛇添足加上这一句:

    window.opener.parent.document.frames.item('mainFrame').location.reload();

    ========================================================================================
    最后,为了同时支持刷新普通父窗口和frame父窗口,代码如下:
    function closeWin() {
             hasClosed = true;
         <%if(null != frame){%>
             window.opener.parent.document.frames.item('mainFrame').location.href = window.opener.location.href;
         <%}else{%>
             window.opener.location = "javascript:reloadPage();";
         <%}%>
             //window.opener.top.mainFrame.location="javascript:reloadPage();";
             //self.opener.frames.mainFrame.location.reload(true);
             window.opener = null;
             window.close();
         }
         function window.onbeforeunload(){
             if (!hasClosed) {
             <%if(null != frame){%>
                 window.opener.parent.document.frames.item('mainFrame').location.href = window.opener.location.href;
             <%}else{%>
                 window.opener.location = "javascript:reloadPage();";
             <%}%>
                 window.opener = null;
             }
         }

    关于window.opener

    window.opener 的用法

        window.opener 返回的是创建当前窗口的那个窗口的引用,比如点击了a.htm上的一个链接而打开了b.htm,然后我们打算在b.htm上输入一个值然后赋予a.htm上的一个id为“name”的textbox中,就可以写为:

        window.opener.document.getElementById("name").value = "输入的数据";

        对于javascrīpt中的window.opener没有很好的理解。

        为什么框架中不能使用,弹出窗口的父窗口不能在框架里面的某个页面呢?那怎样通过弹出窗口操作框架中的父窗口呢?

        opener.parent.frames['frameName'].document.all.input1.value 试试这个:)

    正确使用window.open返回对象的opener

     

    众所周知JavaScript中:

    var win = window.open(url,windowName,...); 的使用,

    而win.opener则是指向父窗口的引用

    然而,有种情况却比较特别,

    假如有两个窗口window1和window2

    按下列步骤执行:

    var win = window.open(url,windowName,...);// (window1)

    var win = window.open(url,windowName,...);//(window2)

    其中先后这两次打开的子窗口的windowName一样

    此时你会发现在window2中的win.opener却不是指向window2的,却是指向window1.

    如果你想在子窗口关闭父窗口的话,就不正确了,因此可以修改上面的执行方法为:

    var win = window.open(url,windowName,...);? (window1)

    win.opener = window;

    var win = window.open(url,windowName,...);? (window2)

    win.opener = window;

    只有这样修改才OK

     

     

     

    通过window.showModalDialog或者.showModelessDialog弹出的页面

    这种情况需要两个步骤:
    1 在父窗口.showModalDialog或.showModelessDialog方法的第二个参数传递window对象
    比如: window.showModelessDialog('a.htm',window);
    2 在a.htm中就可以通过window.dialogArguments获取该参数
    比如: window.dialogArguments.fun1();
    PS:子窗口可以通过设置window.returnValue设置页面返回值

    比如: window.returnValue=OK;window.close();

    strRtn=window.showModalDialog(......)

    这时,strRtn='ok'


    页面中实现:
    父页面
    function reloadPage() {
             document.form1.submit();
         }
    弹出页面调用closeWin();
    function closeWin(){
             hasClosed = true;
             window.opener.location="javascript:reloadPage();";
             window.opener=null;
             window.close();
         }
    posted @ 2008-08-05 16:05 飞飞 阅读(480) | 评论 (1)编辑 收藏

    名称 必填 缺省值 类型 描述
    emptyOption false false Boolean 是否在题头选项后面添加一个空的(--)选项
    headerKey false   Object/String 设置列表的题头主键值. 一定不能为空值! "'-1'"或"''"是正确的取值, ""是错误的取值.
    headerValue false   Object/String 列表的题头选项值
    multiple false   Object/String 创建一个多选列表. 如果value属性指定了一个数组(正确的元素类型), 那么将预先选中数组中指定的多个选项.
    size false   Integer 该组件列表框的大小 (显示元素的个数)
    list true   Object/String 创建列表的可迭代数据源. 如果该列表是一个Map(key, value), 那么Map的主键将作为选项(<option>)的"value"属性, 而该主键对应的值作为选项的文本内容.
    listKey false   Object/String 列表数据源中元素对象的属性, 用于获取选项的值
    listValue false   Object/String 列表数据源中元素对象的属性, 用于获取选项的文本内容
    theme false   Object/String 输出元素时使用的主题(theme)(不使用缺省的)
    template false   Object/String 输出元素时使用的模板(template)(不使用缺省的)
    cssClass false   Object/String 输出元素时的class属性
    cssStyle false   Object/String 输出元素时的css样式定义(译者注:就是html元素的style属性)
    title false   Object/String 在输出元素时设置html属性title
    disabled false   Object/String 在输出元素时设置html属性disabled
    label false   Object/String 用于输出一个元素对应的label的表达式
    labelPosition false left Object/String 不赞成使用.
    labelposition false   Object/String 定义元素标签的位置(top/left)
    requiredposition false   Object/String 定义required属性输出的位置(left|right)
    name false   Object/String 元素的名字
    required false false Boolean 如果设置为true, 在输出标签时将显示出此字段是必须输入的(译者注:如果使用默认模板,将会标示为"*")
    tabindex false   Object/String 在输出元素时设置html属性tabindex
    value false   Object/String 预设input元素的value属性.
    onclick false   Object/String 在输出元素时设置html属性onclick
    ondblclick false   Object/String 在输出元素时设置html属性ondblclick
    onmousedown false   Object/String 在输出元素时设置html属性onmousedown
    onmouseup false   Object/String 在输出元素时设置html属性onmouseup
    onmouseover false   Object/String 在输出元素时设置html属性onmouseover
    onmousemove false   Object/String 在输出元素时设置html属性onmousemove
    onmouseout false   Object/String 在输出元素时设置html属性onmouseout
    onfocus false   Object/String 在输出元素时设置html属性onfocus
    onblur false   Object/String 在输出元素时设置html属性onblur
    onkeypress false   Object/String 在输出元素时设置html属性onkeypress
    onkeydown false   Object/String 在输出元素时设置html属性onkeydown
    onkeyup false   Object/String 在输出元素时设置html属性onkeyup
    onselect false   Object/String 在输出元素时设置html属性onselect
    onchange false   Object/String 在输出元素时设置html属性onchange
    tooltip false   String 设置元素的tooltip属性(译者注:tooltip为工具栏提示)
    tooltipConfig false   String 设置tooltip属性的配置
    id false   Object/String id是定位元素时使用的. 对于UI和表单标签它会被用作HTML的id属性
     1<ww:select label="Pets"
     2       name="petIds"
     3       list="petDao.pets"
     4       listKey="id"
     5       listValue="name"
     6       multiple="true"
     7       size="3"
     8       required="true"
     9/>
    10
    11<ww:select label="Months"
    12       name="months"
    13       headerKey="-1" headerValue="Select Month"
    14       list="#{'01':'Jan', '02':'Feb', []}"
    15       value="selectedMonth"
    16       required="true"
    17/>
    18
    posted @ 2008-08-04 20:21 飞飞 阅读(350) | 评论 (0)编辑 收藏

    Struts2技术学习专题-IT168http://tech.it168.com/zt/struts2/index.html
    MLDN struts2专题:http://www.mldn.cn/topic/struts2/struts2.htm
    中国IT实验室 : http://java.chinaitlab.com/List_213.html
    一个不错的blog: http://www.blogjava.net/max/

    http://www.blogjava.net/max/category/16130.html

    Java学习http://www.java3z.com/cwbwebhome/type.jsp?type=struts

     

    Struts 2 相关文档下载:
    struts2.0中文帮助手册.chm

    posted @ 2008-08-04 15:17 飞飞 阅读(221) | 评论 (0)编辑 收藏

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/struts-tags" prefix="s"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
        + request.getServerName() + ":" + request.getServerPort()
        + path + "/";
    %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
       <base href="<%=basePath%>">

       <title>Struts 2 标签之s:property的用法</title>

       <meta http-equiv="pragma" content="no-cache">
       <meta http-equiv="cache-control" content="no-cache">
       <meta http-equiv="expires" content="0">
       <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
       <meta http-equiv="description" content="This is my page">
       <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

    </head>

    <body>
       <table border="1">
        <tr>
         <th>编号</th>
         <th>书名</th>
         <th>作者</th>
        </tr>
        <s:iterator value="#{'Spring 2.0':'李刚','Java':'张三','j2ee study':'李四'}" id="name" status="st">
         <tr <s:if test="#st.odd">style="background-color:#bbbbbb"</s:if> >
          <td><s:property value="#st.count"/></td>
          <td><s:property value="key"/></td>
          <td><s:property value="value"/></td>
         </tr>
        </s:iterator>
       </table>
    </body>
    </html>
    效果图:

    posted @ 2008-08-04 15:15 飞飞 阅读(305) | 评论 (0)编辑 收藏

    1 实现权限控制拦截器
    本示例应用要求用户登陆,且必须为指定用户名才可以查看系统中某个视图资源;否则,系统直接转入登陆页面。对于上面的需求,可以在每个Action的执行实际处理逻辑之前,先执行权限检查逻辑,但这种做法不利于代码复用。因为大部分Action里的权限检查代码都大同小异,故将这些权限检查的逻辑放在拦截器中进行将会更加优雅。

    检查用户是否登陆,通常都是通过跟踪用户的Session来完成的,通过ActionContext即可访问到Session中的属性,拦截器的intercepte(ActionInvocation invocation)方法的invocation参数可以很轻易地访问到请求相关的ActionContext实例。
    权限检查拦截器类的代码如下:
    //权限检查拦截器继承AbstractInterceptor类
    public class AuthorityInterceptor extends AbstractInterceptor
    {
    //拦截Action处理的拦截方法
    public String intercept(ActionInvocation invocation) throws Exception
    {
    //取得请求相关的ActionContext实例
    ActionContext ctx = invocation.getInvocationContext();
    Map session = ctx.getSession();
    //取出名为user的Session属性
    String user = (String)session.get("user");
    //如果没有登陆,或者登陆所用的用户名不是scott,都返回重新登陆
    if (user != null && user.equals("scott") )
    {
    return invocation.invoke();
    }
    //没有登陆,将服务器提示设置成一个HttpServletRequest属性
    ctx.put("tip" , "您还没有登陆,请输入scott,tiger登陆系统");
    //直接返回login的逻辑视图
    return Action.LOGIN;
    }
    }
    上面拦截器代码非常简单,先通过ActionInvocation参数取得用户的Session实例的引用,然后从中取出user属性,通过判断该属性值来确定用户是否登陆系统,从而判断是否需要转入登陆页面。

    2 配置权限控制拦截器
    一旦实现了上面的权限检查拦截器,就可以在所有需要实现权限控制的Action中复用上面的拦截器。
    为了使用该拦截器,首先在struts.xml文件中定义该拦截器,定义拦截器的配置片段如下:
    <!-- 用户拦截器定义在该元素下 -->
    <interceptors>
    <!-- 定义了一个名为authority的拦截器 -->
    <interceptor name="authority" class="lee.AuthorityInterceptor"/>
    </interceptors>
    定义了该拦截器之后,可以在Action中应用该拦截器,应用该拦截器的配置片段如下:
    <!-- 定义一个名为viewBook的Action,其实现类为ActionSupport -->
    <action name="viewBook">
    <!-- 返回success视图名时,转入/WEB-INF/jsp/viewBook.jsp页面 -->
    <result>/WEB-INF/jsp/viewBook.jsp</result>
    <!-- 拦截器一般配置在result元素之后! -->
    <interceptor-ref name="defaultStack"/>
    <!-- 应用自定义拦截器 -->
    <interceptor-ref name="authority"/>
    </action>

    上面名为viewBook的Action,没有指定class属性,默认使用ActionSupport类,配置该Action时,只是指定了一个Result,指定返回success字符串时,系统将转入/WEB-INF/jsp/viewBook.jsp页面。但并为未配置login视图对应的JSP页面。
    考虑到这个拦截器的重复使用,可能在多个Action都需要跳转到login逻辑试图,故将login Result定义成一个全局Result。下面是配置login Result的配置片段:
    <!-- 定义全局Result -->
    <global-results>
    <!-- 当返回login视图名时,转入/login.jsp页面 -->
    <result name="login">/login.jsp</result>
    </global-results>

    经过上面的配置,如果浏览者在浏览器中直接发送viewBook请求,将会转入如图所示的页面。
    这种通过拦截器进行权限控制的方式,显然具有更好的代码复用。
    如果为了简化struts.xml文件的配置,避免在每个Action中重复配置该拦截器,可以将该拦截器配置成一个默认拦截器栈(这个默认拦截器栈应该包括default-stack拦截器栈和权限检查拦截器)。
    定义自己的默认拦截器栈的配置片段如下:
    <interceptors>
    <!-- 定义权限检查拦截器 -->
    <interceptor name="authority" class="lee.AuthorityInterceptor"/>
    <!-- 定义一个包含权限检查的拦截器栈 -->
    <interceptor-stack name="mydefault">
    <!-- 定义拦截器栈包含default-stack拦截器栈 -->
    <interceptor-ref name="default-stack"/>
    <!-- 定义拦截器栈包含authority拦截器 -->
    <interceptor-ref name=" authority"/>
    </interceptor- stack >
    </interceptors>

    一旦定义了上面的mydefault拦截器栈,这个拦截器栈包含了权限检查拦截器和系统默认的拦截器栈。如果将这个拦截器栈定义成默认拦截器,则可以避免在每个Action需要重复定义权限检查拦截器。
    下面是定义默认拦截器的配置片段:
    <default-interceptor-ref name="mydefault"/>
    一旦在某个包下定义了上面的默认拦截器栈,在该包下的所有Action都会自动增加权限检查功能。对于那些不需要使用权限控制的Action,将它们定义在另外的包中——这个包中依然使用系统原来的默认拦截器栈,将不会有权限控制功能。
    posted @ 2008-08-04 15:06 飞飞 阅读(1338) | 评论 (1)编辑 收藏

     在struts2中,提供了日期控件,以方便地选择日期和时间,这是通过 标签来实现的。该日期控件是通过DOJO来实现的,会在客户端生成一段JS代码,所以,要让该日期控件生效,需要加入以下代码:   
    代码
    1. <s:head theme="ajax" />

        这样,就可以在页面中使用 标签了。如:

    代码
    <s:datetimepicker name="todayDate" value="2007-8-9" label="Format (yyyy-MM-dd)" displayFormat="yyyy-MM-dd"/>

        在页面中,就会显示出日期控件,其中displayFormat是要显示的日期格式。效果如下所示:

     

    posted @ 2008-08-04 14:52 飞飞 阅读(579) | 评论 (0)编辑 收藏

    代码:

    <%@ page language="java" pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
       <title>s:tree的使用</title>
       <s:head theme="ajax"/>
    </head>

    <body>
    <H3>s:tree的使用</H3>
       <s:tree label="计算机图书" theme="ajax" id="book" showGrid="true"
        showRootGrid="true" treeSelectedTopic="tree selected">
        <s:treenode theme="ajax" label="李刚" id="ligang">
         <s:treenode theme="ajax" label="Jsp study" id="jsp"></s:treenode>
         <s:treenode theme="ajax" label="java study" id="java"></s:treenode>
         <s:treenode theme="ajax" label="php study" id="php"></s:treenode>
        </s:treenode>
        <s:treenode theme="ajax" label="张三" id="zhangsan">
         <s:treenode theme="ajax" label="test study" id="test1"></s:treenode>
         <s:treenode theme="ajax" label="test study" id="test2"></s:treenode>
         <s:treenode theme="ajax" label="test study" id="test3"></s:treenode>
        </s:treenode>
        <s:treenode theme="ajax" label="李四" id="lisi">
         <s:treenode theme="ajax" label="Jsp study" id="test4"></s:treenode>
         <s:treenode theme="ajax" label="java study" id="test5"></s:treenode>
         <s:treenode theme="ajax" label="php study" id="test6"></s:treenode>
        </s:treenode>
       </s:tree>

    </body>
    </html>

    posted @ 2008-08-04 14:47 飞飞 阅读(309) | 评论 (0)编辑 收藏

         摘要: 一: 首先是在自动生成的DAO里面加上如下代码  public List findAll()...{                  String sql="FROM Au...  阅读全文
    posted @ 2008-08-04 14:22 飞飞 阅读(1268) | 评论 (0)编辑 收藏

         摘要: Struts2提供了大量丰富的标签供使用,它不再像Struts1中一样,将种类标签进行分门列别,但可以根据其使用的用途用以区别。本文通过对Struts2中数据标签的学习,来对Struts2中标签的学习起到一个抛砖引玉的作用。文中将介绍Action标签、Bean标签、Data标签、Include标签、Param标签、Set标签、Text标签、Property标签等标签。 一、<s:actio...  阅读全文
    posted @ 2008-08-04 10:58 飞飞 阅读(363) | 评论 (1)编辑 收藏

    1、sturts2的标签很丰富。用起来也很方便,但是它的样式不太好,最好能够自定义一套样式!若不想用sturts2
       缺省的样式,就使用theme="simple"。
       sturts2中的有些标签,是用js框架写的,需要加载这些框架(如:dojo)。在jsp页面中使用<s:head/>加载这些框架和css!
      
     2、sturts2中的国际化,又其拦截器完成。拦截器会根据用户浏览器设置的不同来,自动适配!只需要定义多个资源文件
       就可以!
       资源文件可以是全局的(在classes中),也可以是局部的(在各个特定的包中)!
       对资源文件的要求:
         要注意资源文件的命名规范!例如:package_en_US.properties和package_zh_CN.properties
         
       I、两种实现国际化的方法,key和lable方式!
         例如:
          a、<s:textfield label="%{getText('username')}" name="username"/>
          b、<s:textfield key="username" name="username"/>
        
        II、单个的资源信息提取的两种方式:
         例如:
          a、<s:property value="getText('main.message')"/>
          b、<s:text name="main.message"/>
         
       III、在s:datetimepicker标签中可以使用,key和label两种方式来进行国际化
              key="date"
              label="%{getText('date')}"
              这个日期标签,在中文环境和英文环境下的显示形式是不一样的
              中文:2007-11-12
              英文:11/14/2007
              所以在进行日期处理的时候要小心
         
     3、对于分步表单提交和“后退”网页过期的问题有待继续研究!
       对于表单重复提交的问题可以使用<s:token/>来解决!
       在使用token时,需要配置拦截器,而且在Action中需要定一个常量!
       例如:
         页面:<s:token/>
         xml: <interceptor-ref name="defaultStack" />
                  <interceptor-ref name="token" />
         Action:private static final long serialVersionUID = 6820659617470261780L;
      
     4、个人感觉struts2的Validation(验证框架)不是很好,效率也不高,而且需要定义比较复杂的XXXAction-validation.xml文件.
         所以对于页面上的限制还是使用js或js框架(如:jquery,dojo,portaltype)!
         
     5、<s:submit key="back" name="redirect-action:crud!list" />这种实现方式比较好!
       <s:submit key="back" onclick="#:history.back();" />
       这种实现方式不好,因为它会自动刷新页面;当有添加,删除,更新操作时,就重复的刷新页面!不推荐使用!
      
     6、<s:select label="%{getText('user.from')}"  
         name="user.from"
         headerKey=""
         headerValue="Select From"
         list="fromArray"
         listKey="id"
         listValue="name"
         value="user.from"
         required="true" />
         <%--
            name="user.from"是用于通过struts2内在的机制给Action自动赋值
            list="fromArray"是一个封装了bean的list,其中的bean 有id和name属性
            listKey="id"
            listValue="name"
            那么,当用户提交表单的时候,sturts2的内在机制,会自动为我们装载的!
            需要我们在Action里定义一个user bean,其中user中有一个from属性
            要是嵌套定义,如:user bean 中又定义了一个bean(DateBean)。那么在页面就要使用user.date.year这种形式,来向Action传值!
            其中,date是user bean 中的一个属性,struts2会自动为你装载!
         --%>
    posted @ 2008-08-04 09:38 飞飞 阅读(652) | 评论 (0)编辑 收藏

    插件提供了一种名为json的ResultType,一旦为某个Action指定了一个类型为json的Result,则该Result无需映射到任何视图资源。因为JSON插件会负责将Action里的状态信息序列化成JSON格式的数据,并将该数据返回给客户端页面的JavaScript。

      简单地说,JSON插件允许我们在JavaScript中异步调用Action,而且Action不再需要使用视图资源来显示该Action里的状态信息,而是由JSON插件负责将Action里的状态信息返回给调用页面——通过这种方式,就可以完成Ajax交互。

      Struts2提供了一种可插拔方式来管理插件,安装Struts2的JSON插件与安装普通插件并没有太大的区别,一样只需要将Struts2插件的JAR文件复制到Web应用的WEB-INF/lib路径下即可。

      安装JSON插件按如下步骤进行:

      (1)登陆http://code.google.com/p/jsonplugin/downloads/list站点,下载Struts2的JSON插件的最新版本,当前最新版本是0.7,我们可以下载该版本的JSON插件。

      (2)将下载到的jsonplugin-0.7.jar文件复制到Web应用的WEB-INF路径下,即可完成JSON插件的安装。

      实现Actio逻辑

      假设wo,en输入页面中包含了三个表单域,这三个表单域对于三个请求参数,因此应该使用Action来封装这三个请求参数。三个表单域的name分别为field1、field2和field3。

      处理该请求的Action类代码如下:   public class JSONExample
      {
      //封装请求参数的三个属性
      private String field1;
      private transient String field2;
      private String field3;
      //封装处理结果的属性
      private int[] ints = {10, 20};
      private Map map = new HashMap();
      private String customName = "custom";
      //三个请求参数对应的setter和getter方法
      public String getField1()
      {
      return field1;
      }
      public void setField1(String field1)
      {
      this.field1 = field1;
      }
      //此处省略了field1和field2两个字段的setter和getter方法
      ...
      //封装处理结果的属性的setter和getter方法
      public int[] getInts()
      {
      return ints;
      }
      public void setInts(int[] ints)
      {
      this.ints = ints;
      }
      public Map getMap()
      {
      return map;
      }
      public void setMap(Map map)
      {
      this.map = map;
      }
      //使用注释语法来改变该属性序列化后的属性名
      @JSON(name="newName")
      public String getCustomName()
      {
      return this.customName;
      }
      public String execute()
      {
      map.put("name", "yeeku");
      return Action.SUCCESS;
      }
      }
      在上面代码中,使用了JSON注释,注释时指定了name域,name域指定Action属性被序列化成JSON对象的属性名。除此之外,JSON注释还支持如下几个域:


      

    serialize:设置是否序列化该属性

      deserialize:设置是否反序列化该属性。

      format:设置用于格式化输出、解析日期表单域的格式。例如"yyyy-MM-dd'T'HH:mm:ss"。

      配置该Action与配置普通Action存在小小的区别,应该为该Action配置类型为json的Result。而这个Result无需配置任何视图资源。

      配置该Action的struts.xml文件代码如下:  <?xml version="1.0" encoding="GBK"?>
    <!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="example" extends="json-default">
    <action name="JSONExample" class="lee.JSONExample">
    <result type="json"/>
    </action>
    </package>
    </struts>  
      在上面配置文件中有两个值得注意的地方:

      第一个地方是配置struts.i18n.encoding常量时,不再是使用GBK编码,而是UTF-8编码,这是因为Ajax的POST请求都是以UTF-8的方式进行编码的。

      第二个地方是配置包时,自己的包继承了json-default包,而不再继承默认的default包,这是因为只有在该包下才有json类型的Result。
    posted @ 2008-08-04 09:33 飞飞 阅读(195) | 评论 (0)编辑 收藏

         摘要: div标签用于在页面上生成一个div元素,但这个div元素内容不是静态内容,而是从服务器上获取数据,为了让该div能够取得服务器上的数据,必须为div标签指定一个href属性,这个href属性必须是一个action,该action负责生成该div的内容 因为div是一个ajax标签,因此要为这个标签增加theme="ajax"属性 web.xml   <?xml&nbs...  阅读全文
    posted @ 2008-08-04 09:29 飞飞 阅读(2082) | 评论 (0)编辑 收藏

    一、iterator.

    这个标签主要的的作用就是跌代出集合。。

    value属性表示需要跌代显示出来的值。

    status属性,又来保存跌代时的一些状态值。

    注:1.如果需要引用valueStack中的值,需要使用这样的形式。

    <s:iterator value="#userList" />  //userList在action部分被保存在Request中,所以使用#加属性名来引用值。

    2.如果集合的值是通过action的方法,假设我们的action中有一个getListMenu方法,返回一个List集合。

    我们可以使用如下的形式来引用这个集合,并用s:iterator来输出。

    <s:iterator value="listMenu" />

    3.iterator的value使用定义好的方式,如:

    <s:iterator value="{1,2,3,4}" />         //这样跌代输出的值就是1.2.3.4这四个值。

    二、iterator中输出具体值,如果,在上面我们的list中的对象,有两个属性,都是String类型,一个是name,一个是url。

    我们可以这样来引用。

    1.      <s:property value="name" />       //这样我们将可以输出跌代对象的name属性值。

    2.     如果我们希望使用<s:url />来将跳转过后的url进行处理,该如何来做?

             <s:url value="%{url}"/>            //%{}ognl的表达式,这样的值能够将url的值进行<s:url/>的处理

             实际上就是转为绝对路径。这样,我们就可以对付一些因跳转换产生的路径问题。

        原因:因为<s:iteratotr />以后,当前的对象应该就在ValueStack顶部了,这样当然的url实际上就是对象的url          属性了

    三、使用ognl输出对应的值。

    <s:textfield name="loginName" value="%{#request.loginNames}"/>

     

    使用此表达式,会生成一个文本框,并且,如果request.attribute中有loginNames属性,将会做为些文本框的默认值。

    如果只使用#request.loginNames在struts2的标签内部,是不会显示任何值的,注意外面加上的%{}附号,才会被正常的使用。

    如果希望如EL语言一样直接输出文件,如在一个<a></a>之间的innerHTML文本为#request.loginNames的值,我们只要使用:<s:property value="#request.loginNames" />使可以正常使用!

     

    注:

    1.${}是EL语言的 %{}这样的形式是ognl表过式语言的,在struts2的标签内部,使用%{}这样的形式,在标签外部可以使用${}EL语言的方式。如果在struts2的标签内部使用${}这样的方式,会出现以下的错误提示:

    According to TLD or attribute directive in tag file, attribute value does not accept any expressions

    2.很多时候,我们使用struts2的一些标签,属性是需要接受集合的,如果集合是保存在request,session,或者是值栈(非根对象的栈顶),可以使用#变量名的方式,如果获取的值是在Action中通过特定的方法来获取,就需要使用如 value="userList"这样的方式,只是去掉了前面的#。

     

    3.可能我对一些值栈,根对象,栈顶的一些ognl知识有些不错误,如果发现了问题,请帮助指出,谢谢。

    posted @ 2008-08-04 09:25 飞飞 阅读(220) | 评论 (0)编辑 收藏

         摘要: Struts.xml 文件 Java代码 <?xml version="1.0" encoding="UTF-8" ?>    <!DOCTYPE struts PUBLIC        "-/...  阅读全文
    posted @ 2008-08-04 00:26 飞飞 阅读(324) | 评论 (0)编辑 收藏

       1. <%@ page contentType="text/html; charset=GBK" language="java"%> 
       2.
    <%@taglib prefix="s" uri="/struts-tags"%> 
       3.
    <html> 
       4.
    <head> 
       5.
    <title>s:if标签测试</title> 
       6.
    </head> 
       7.
    <body> 
       8.
    <s:set name="age" value="29"/> 
       9.
    <s:if test="${age > 60}"> 
      10.     老年人 
      11.
    </s:if> 
      12.
    <s:elseif test="${age > 35}"> 
      13.     中年人 
      14.
    </s:elseif> 
      15.
    <s:elseif test="${age > 15}" id="wawa"> 
      16.     青年人 
      17.
    </s:elseif> 
      18.
    <s:else> 
      19.     少年 
      20.
    </s:else> 
      21.
    </body> 
      22.
    </html> 


    比如登陆模块
    <s:textfield label="用户名" name="user.username"/>
    <s:password label="密码" name="user.password"/>
    这样写的话,他会默认换行,可以不换行吗?

    只要你将它的这个theme属性设成simple那么它就不会用Struts2的格式了,每个STRUTS1的标签都有这样的一个性!!!!



    问题:No result defined for action cn.bbs.nhpop.web.action.ReplyTopic Action and result input 错误

    意思是说没定义input的跳转结果.

        @Override
        
    public String execute() throws Exception {
            topic 
    = topicService.getTopic(topicId);
            reply.setTopic(topic);
            replyService.replyTopic(reply);
            
    return this.SUCCESS;
        }

    原因:我的cn.bbs.nhpop.web.action.ReplyTopic Action execute方法返回SUCCESS,但是实际运行中出现了错误(抛了异常),Action并没有返回SUCCESS而是返回INPUT(Action出现错误时默认的返回值),而我的struts.xml配置文件中并没有定义与INPUT对应的Result

            <action name="replyTopic"
                class
    ="cn.bbs.nhpop.web.action.ReplyTopic">
                
    <result name="success" type="chain">
                    
    <param name="actionName">listTopicsDetails</param>
                
    </result>
            
    </action>

     

    解决方法:你可以添加一个与INPUT对应的Result或者解决Action方法实际运行中的异常。

    我的Action到底抛了个什么异常呢?

            <s:form action="replyTopic">
                
    <s:hidden name="topicId" value="%{topicId}"></s:hidden>
    <%--            <s:param name="topicId" value="%{topicId}"></s:param>--%>

    </s:form>
    这是我的reply.jsp,开始我使用<s:param></s:param>传topicId,想当然的认为可以与<s:form></s:form>合用传参,导致replyTopic Action无法获取到topicId的值
        @Override
        
    public String execute() throws Exception {
            topic 
    = topicService.getTopic(topicId);
            reply.setTopic(topic);
            replyService.replyTopic(reply);
            
    return this.SUCCESS;
        }
    topic为null抛异常。(<s:url action=""><s:param></s:param></s:url>是可以这样传参的,但与<s:form></s:form>不行)
    后来用<s:hidden></s:hidden>代替解决。另外
    <s:hidden name="topicId" value="topicId"></s:hidden>
    value="%{topicId}"切不可省去%{}否则Action中的topicId的值为字符串为"topicId"而不是我希望的int值1,%{topicId}相当于
    <s:property value="topicId"/>
    你可以使用%{}或嵌套<s:property>标签。struts2标签的属性可以接受一个字符串的值的时候请大家尤其注意,必须使用%{} 或<s:property>才会是你想要的值。比如:
    <s:hidden name="topicId" value="%{topicId}"></s:hidden>


                
    <s:url id="toReply" action="toReply">
                    
    <s:param name="topicId" value="topicId"></s:param>
                
    </s:url>

                
    <tr>
                    
    <td height="18" colspan="2">
                        
    &nbsp;
                        
    <s:a href="%{toReply}">回复 </s:a> &nbsp;
                    
    </td>
                
    </tr>


    <s:select name="page" list="page" listKey="key" listValue="value" value="page"></s:select>

    @SuppressWarnings("unchecked")
     public List<HashMap> getPage(){
      List<HashMap> numPage = new ArrayList<HashMap>();   
      
      for(int i=0;i<10;i++){
       HashMap m=new HashMap();
       m.put("key", i);
       m.put("value", i+1);
       numPage.add(m);
      } 
      return numPage;
      
     }
    posted @ 2008-08-01 14:23 飞飞 阅读(2783) | 评论 (2)编辑 收藏

    在Struts2里,如果需要在Action中使用session,可以通过下面两种方式得到
    1.通过ActionContext class中的方法getSession得到
    2.Action实现org.apache.struts2.interceptor.SessionAware接口的方式来对session进行操作
     
    下面先看一个采用第一种方式,在action中得到session的例子

    package s2.ex.action;

     

    import java.util.Map;

     

    import com.opensymphony.xwork2.ActionContext;

    import com.opensymphony.xwork2.ActionSupport;

     

    public class SessionTestAction extends ActionSupport {

     

        public String execute() {

           ActionContext actionContext = ActionContext.getContext();

           Map session = actionContext.getSession();

           session.put("USER_NAME", "Test User");

           return SUCCESS;

        }

    }
    在这个例子中,通过ActionContext得到session,并往session里放置一个key为USER_NAME,值为Test User的内容。
     
    下面是一个实现org.apache.struts2.interceptor.SessionAware接口来对session操作的例子

    package s2.ex.action;

     

    import java.util.Map;

     

    import org.apache.struts2.interceptor.SessionAware;

     

    import com.opensymphony.xwork2.ActionSupport;

     

    public class SessionTest1Action extends ActionSupport implements SessionAware {

        private Map session;

        public void setSession(Map session) {

           this.session = session;

     

        }

        public String execute() {

           this.session.put("USER_NAME", "Test User 1");

           return SUCCESS;

        }

     

    }
    在这个例子中实现了接口SessionAware中的setSession方法。
     
    上面两种方式都可以得到session,能实现的功能都是一样的。
    这里推荐通过第二种方式来使用session,原因是便于做单体测试,用第二种方式,只需要构造一个Map就可以对action class进行单体测试了。
    在一个项目中可能会有很多action都需要用到session,如果每个action都来实现org.apache.struts2.interceptor.SessionAware这个接口,可能会显得比较麻烦,所以建议作一个抽象的BaseAction类来实现org.apache.struts2.interceptor.SessionAware接口,以后所有的action只要继承这个BaseAction就可以了。
     
    下面是一个如何在JSP中使用session的例子。

    <%@ page contentType="text/html; charset=UTF-8" %>

    <%@page pageEncoding="utf-8" %>

    <%@taglib prefix="s" uri="/struts-tags" %>

    <html>

    <head>

        <title>Session Test</title>

    </head>

     

    <body>

    <h1><s:property value="#session.USER_NAME"/></h1>

    <h1>${session.USER_NAME}</h1>

    </body>

    </html>
    一般在项目中往往会往session里放置一个Object,必如说user,user里有个boolean admin和String userName,如果user里存在isAdmin的方法,在jsp中可以通过<s:if test="#session.user.admin">来判断用户有没有管理权限,通过<s:property value="#session.user.userName">或者${session.user.userName}来取得用户名。
    posted @ 2008-08-01 14:13 飞飞 阅读(223) | 评论 (0)编辑 收藏

    Struts2中最简单的验证数据的方法是使用validate。我们从ActionSupport类的源代码中可以看到,ActionSupport类实现了一个Validateable接口。这个接口只有一个validate方法。如果Action类实现了这个接口,Struts2在调用execute方法之前首先会调用这个方法,我们可以在validate方法中验证,如果发生错误,可以根据错误的level选择字段级错误,还是动作级错误。并且可使用addFieldErroraddActionError加入相应的错误信息,如果存在ActionField错误,Struts2会返回“input”(这个并不用开发人员写,由Struts2自动返回),如果返回了“input”,Struts2就不会再调用execute方法了。如果不存在错误信息,Struts2在最后会调用execute方法。

    这两个add方法和ActionErrors类中的add方法类似,只是add方法的错误信息需要一个ActionMessage对象,比较麻烦。除了加入错误信息外,还可以使用addActionMessage方法加入成功提交后的信息。当提交成功后,可以显示这些信息。

    以上三个add方法都在ValidationAware接口中定义,并且在ActionSupport类中有一个默认的实现。其实,在ActionSupport类中的实现实际上是调用了ValidationAwareSupport中的相应的方法,也就是这三个add方法是在ValidationAwareSupport类中实现的,代码如下:
    private final ValidationAwareSupport validationAware = new ValidationAwareSupport();

    public void addActionError(String anErrorMessage) 
    {      validationAware.addActionError(anErrorMessage);
    }
    public void addActionMessage(String aMessage) 
    {
        validationAware.addActionMessage(aMessage);
    }
    public void addFieldError(String fieldName, String errorMessage) 
    {
        validationAware.addFieldError(fieldName, errorMessage);
    }

    下面我们来实现一个简单的验证程序,来体验一个validate方法的使用。

    先来在Web根目录建立一个主页面(validate.jsp),代码如下:


    <%@ page language="java"  pageEncoding="GBK"%>
    <%@ taglib prefix="s" uri="/struts-tags"%>

    <html>
     <head>
      <title>输入操作数</title>

      <style type="text/css">
    .label {
     font-style: italic;
    }

    .errorLabel {
     font-style: italic;
     color: red;
    }

    .errorMessage {
     font-weight: bold;
     color: red;
    }
    </style>

     
    </head>

     <body>
      求代数和
      <br />
      <s:form action="First">
       <s:textfield name="operand1" label=" 操作数1" />
       <s:textfield name="operand2" label=" 操作数2" />
       <s:submit value="代数和" />
      </s:form>
     </body>
    </html>

    在上面的代码中,使用了Struts2tag<s:actionerror><s:fielderror><s:actionmessage>,分别用来显示动作错误信息,字段错误信息,和动作信息。如果信息为空,则不显示。

    现在我们来实现一个动作类,代码如下:


    package action;

    import com.opensymphony.xwork2.ActionSupport;

    @SuppressWarnings("serial")
    public class FirstAction extends ActionSupport {
     private int operand1;
     private int operand2;

     public String execute() throws Exception {
      System.out.println(getFirst() + "//////////");
      if (getFirst() <= 0) // 如果代码数和是非负整数,跳到positive.jsp页面
      {
       return INPUT;
      }
      return SUCCESS;
     }

     public int getOperand1() {
      return operand1;
     }

     public void setOperand1(int operand1) {
      System.out.println("operand1:" + operand1);
      this.operand1 = operand1;
     }

     public int getOperand2() {
      return operand2;
     }

     public void setOperand2(int operand2) {
      System.out.println("operand2:" + operand2);
      this.operand2 = operand2;
     }

     public int getFirst() {
      return operand1 + operand2; // 计算两个整数的代码数和
     }

    }


    大家从上面的代码可以看出,Field错误需要一个key(一般用来表示是哪一个属性出的错误),而Action错误和Action消息只要提供一个信息字符串就可以了。

    最后来配置一下这个Action,代码如下:

    <?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="struts2" extends="struts-default">
      <action name="First" class="First">
       <result name="input">/index.jsp</result>
       <result name="success">/positive.jsp</result>
     </action>
     </package>
    </struts>


     

    我们还可以使用ValidationAware接口的其他方法(由ValidationAwareSupport类实现)获得或设置字段错误信息、动作错误信息以及动作消息。如hasActionErrors方法判断是否存在动作层的错误,getFieldErrors获得字段错误信息(一个Map对象)。下面是ValidationAware接口提供的所有的方法:


    package com.opensymphony.xwork2;

    import java.util.Collection;
    import java.util.Map;

    public interface ValidationAware
    {
        
    void setActionErrors(Collection errorMessages);
        Collection getActionErrors();

        
    void setActionMessages(Collection messages);
        Collection getActionMessages();
        
    void setFieldErrors(Map errorMap);
        Map getFieldErrors();
        
    void addActionError(String anErrorMessage);
        
    void addActionMessage(String aMessage);
        
    void addFieldError(String fieldName, String errorMessage);
        
    boolean hasActionErrors();
        
    boolean hasActionMessages();
        
    boolean hasErrors();
        
    boolean hasFieldErrors();
    }

    关于其他更详细的验证规则,请读者访问http://struts.apache.org/2.0.11.1/docs/validation.html来查看。

    struts2验证信息重复出现解决方案

    你的action是不是被spring代管了?


          我一看,是啊,我的action是被spring代管了。

          接着他又写道:

          你的action class是不是用的bean 的id?

          我一边看还一边点头,是啊,我的真是这样的,怎么这么了解我!(其实人人都这样写)

          最后他说:

          把你action 的class改成全路径,问题就会得到解决。


          是吗?我当时想,那就是说不要spring代管了,那我还要向这个action 注属性的,这样改了肯定注不进去了。

          正如我所说的,这样改了验证的问题是得到解决了,可是属性注不进去了。那不是正了一样又歪了一样,问题并没有得到根本性的解决。

          正在有点想抓狂中,却无意发现我的这个bean怎么没有写scope="prototype",这个属性是告诉spring,每来一个action给我产生一个新的实例。就这么简单,问题得以真正的解决。

    posted @ 2008-08-01 11:48 飞飞 阅读(529) | 评论 (0)编辑 收藏

    struts.xmlstruts.properties

        其中struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等。除此之外,Struts 2框架还包含一个struts.properties文件,该文件定义了Struts 2框架的大量属性,开发者可以通过改变这些属性来满足应用的需求。

         struts.properties文件是一个标准的Properties文件,该文件包含了系列的key-value对象,每个key就是一个Struts 2属性,该key对应的value就是一个Struts 2属性值。

          struts.properties文件通常放在Web应用的WEB-INF/classes路径下。实际上,只要将该文件放在Web应用的CLASSPATH路径下,Struts 2框架就可以加载该文件。



          其实,struts.properties文件的内容均可在struts.xml中以<constant name="" value=""></constant>加载。

    下面将该文件的配置参数详细列举出来,方便大家查看;

    struts.configuration

        该属性指定加载Struts 2配置文件的配置文件管理器。该属性的默认值是org.apache.Struts2.config.DefaultConfiguration,这是Struts 2默认的配置文件管理器。如果需要实现自己的配置管理器,开发者则可以实现一个实现Configuration接口的类,该类可以自己加载Struts 2配置文件。


    struts.locale

    指定Web应用的默认Locale。

    struts.i18n.encoding

         指定Web应用的默认编码集。该属性对于处理中文请求参数非常有用,对于获取中文请求参数值,应该将该属性值设置为GBK或者GB2312。

    提示  当设置该参数为GBK时,相当于调用HttpServletRequest的setCharacterEncoding方法。


    struts.objectFactory

        指定Struts 2默认的ObjectFactory Bean,该属性默认值是spring。

    struts.objectFactory.spring.autoWrite

         指定Spring框架的自动装配模式,该属性的默认值是name,即默认根据Bean的name属性自动装配。

    struts.objectFactory.spring.useClassCache

          该属性指定整合Spring框架时,是否缓存Bean实例,该属性只允许使用true和false两个属性值,它的默认值是true。通常不建议修改该属性值。



    struts.objectTypeDeterminer
        该属性指定Struts 2的类型检测机制,通常支持tiger和notiger两个属性值。


     struts.multipart.parser:该属性指定处理multipart/form-data的MIME类型(文件上传)请求的框架,该属性支持cos、pell和jakarta等属性值,即分别对应使用cos的文件上传框架、pell上传及common-fileupload文件上传框架。该属性的默认值为jakarta。

    注意  如果需要使用cos或者pell的文件上传方式,则应该将对应的JAR文件复制到Web应用中。例如,使用cos上传方式,则需要自己下载cos框架的JAR文件,并将该文件放在WEB-INF/lib路径下。

    struts.multipart.saveDir
        该属性指定上传文件的临时保存路径,该属性的默认值是javax.servlet.context.tempdir。

     struts.multipart.maxSize
    该属性指定Struts 2文件上传中整个请求内容允许的最大字节数。

    struts.custom.properties
        该属性指定Struts 2应用加载用户自定义的属性文件,该自定义属性文件指定的属性不会覆盖struts.properties文件中指定的属性。如果需要加载多个自定义属性文件,多个自定义属性文件的文件名以英文逗号(,)隔开。

    struts.mapper.class
        指定将HTTP请求映射到指定Action的映射器,Struts 2提供了默认的映射器:org.apache.struts2.dispatcher.mapper.DefaultActionMapper。默认映射器根据请求的前缀与Action的name属性完成映射。

    struts.action.extension
         该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts 2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。

    struts.serve.static
        该属性设置是否通过JAR文件提供静态内容服务,该属性只支持true和false属性值,该属性的默认属性值是true。

    struts.serve.static.browserCache
        该属性设置浏览器是否缓存静态内容。当应用处于开发阶段时,我们希望每次请求都获得服务器的最新响应,则可设置该属性为false。

     struts.enable.DynamicMethodInvocation
       该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false。

    struts.enable.SlashesInActionNames
       该属性设置Struts 2是否允许在Action名中使用斜线,该属性的默认值是false。如果开发者希望允许在Action名中使用斜线,则可设置该属性为true。

     struts.tag.altSyntax
       该属性指定是否允许在Struts 2标签中使用表达式语法,因为通常都需要在标签中使用表达式语法,故此属性应该设置为true,该属性的默认值是true。

     struts.devMode
    该属性设置Struts 2应用是否使用开发模式。如果设置该属性为true,则可以在应用出错时显示更多、更友好的出错提示。该属性只接受true和flase两个值,该属性的默认值是false。通常,应用在开发阶段,将该属性设置为true,当进入产品发布阶段后,则该属性设置为false。

    struts.i18n.reload
    该属性设置是否每次HTTP请求到达时,系统都重新加载资源文件。该属性默认值是false。在开发阶段将该属性设置为true会更有利于开发,但在产品发布阶段应将该属性设置为false。

    提示  开发阶段将该属性设置了true,将可以在每次请求时都重新加载国际化资源文件,从而可以让开发者看到实时开发效果;产品发布阶段应该将该属性设置为false,是为了提供响应性能,每次请求都需要重新加载资源文件会大大降低应用的性能。

    struts.ui.theme
    该属性指定视图标签默认的视图主题,该属性的默认值是xhtml。

    struts.ui.templateDir
    该属性指定视图主题所需要模板文件的位置,该属性的默认值是template,即默认加载template路径下的模板文件。

    struts.ui.templateSuffix
    该属性指定模板文件的后缀,该属性的默认属性值是ftl。该属性还允许使用ftl、vm或jsp,分别对应FreeMarker、Velocity和JSP模板。

    struts.configuration.xml.reload
    该属性设置当struts.xml文件改变后,系统是否自动重新加载该文件。该属性的默认值是false。

    struts.velocity.configfile
    该属性指定Velocity框架所需的velocity.properties文件的位置。该属性的默认值为velocity.properties。

     struts.velocity.contexts
    该属性指定Velocity框架的Context位置,如果该框架有多个Context,则多个Context之间以英文逗号(,)隔开。

    struts.velocity.toolboxlocation
    该属性指定Velocity框架的toolbox的位置。

    struts.url.http.port
    该属性指定Web应用所在的监听端口。该属性通常没有太大的用户,只是当Struts 2需要生成URL时(例如Url标签),该属性才提供Web应用的默认端口。

    struts.url.https.port
    该属性类似于struts.url.http.port属性的作用,区别是该属性指定的是Web应用的加密服务端口。

    struts.url.includeParams
    该属性指定Struts 2生成URL时是否包含请求参数。该属性接受none、get和all三个属性值,分别对应于不包含、仅包含GET类型请求参数和包含全部请求参数。


      struts.custom.i18n.resources
    该属性指定Struts 2应用所需要的国际化资源文件,如果有多份国际化资源文件,则多个资源文件的文件名以英文逗号(,)隔开。


    struts.dispatcher.parametersWorkaround
        对于某些Java EE服务器,不支持HttpServlet Request调用getParameterMap()方法,此时可以设置该属性值为true来解决该问题。该属性的默认值是false。对于WebLogic、Orion和OC4J服务器,通常应该设置该属性为true。

     struts.freemarker.manager.classname
        该属性指定Struts 2使用的FreeMarker管理器。该属性的默认值是org.apache.struts2.views.freemarker.FreemarkerManager,这是Struts 2内建的FreeMarker管理器。

    struts.freemarker.wrapper.altMap
    该属性只支持true和false两个属性值,默认值是true。通常无需修改该属性值。

     struts.xslt.nocache
        该属性指定XSLT Result是否使用样式表缓存。当应用处于开发阶段时,该属性通常被设置为true;当应用处于产品使用阶段时,该属性通常被设置为false。

    struts.configuration.files
        该属性指定Struts 2框架默认加载的配置文件,如果需要指定默认加载多个配置文件,则多个配置文件的文件名之间以英文逗号(,)隔开。该属性的默认值为struts-default.xml,struts-plugin.xml,struts.xml,看到该属性值,读者应该明白为什么Struts 2框架默认加载struts.xml文件了。
    posted @ 2008-08-01 11:23 飞飞 阅读(162) | 评论 (0)编辑 收藏

    所谓间接实现零配置,是指只要做些初始化的配置之后,在以后的开发中基本上不用在对每个Action做配置 struts.xml这样配置
        <action name="*/*" method="{2}" class="workbench.web.actions.{1}Action">
           <result name="custom">/view/{1}/${target}.jsp</result>
        </action>struts.properties的配置:
       
    XML codestruts.objectFactory = spring
        struts.objectFactory.spring.autoWire = name
        struts.devMode = true
        struts.enable.DynamicMethodInvocation = false
        struts.action.extension =
        struts.enable.SlashesInActionNames = true然后写一个BaseAction:
        public abstract class BaseAction {
            protected final String CUSTOM = "custom";
            private String target;
            protected final Log logger = LogFactory.getLog(getClass());
            public String getTarget() {
                return target;
            }
            public void setTarget(String target) {
                this.target = target;
            }

            protected String render(String _target){
                setTarget(_target);
                return CUSTOM;
            }
        }
        这样其余的Action都可以直接继承BaseAction,不用再做任何配置 通过return render(target)转发到指定的jsp页面,从而间接实现零配置
        public class UserAction extends BaseAction{
            private User user;
            private UserService userService;
            public void setUserService(UserService userService) {
                this.userService = userService;
            }

            public User getUser() {
                return user;
            }
            public void setUser(User user) {
                this.user = user;
            }
            public String test(){
                user = userService.get(1l);
                return render("test");
            }
        }


    但是在我的SSH框架中,没能时间间接零配置,,,有那个高手帮我解决下????

    posted @ 2008-08-01 10:30 飞飞 阅读(302) | 评论 (0)编辑 收藏


     @SuppressWarnings("unchecked")
     public List getAll(final int pageNow, final int pageSize) {
      final String hql = " from Mount ";
      return getHibernateTemplate().executeFind(new HibernateCallback() {

       public Object doInHibernate(Session s) throws HibernateException,
         SQLException {

        Query queryAll = s.createQuery(hql);
        queryAll.setFirstResult(pageSize * pageNow);
        queryAll.setMaxResults(pageSize);
        return queryAll.list();
       }
      });
     }

    posted @ 2008-07-31 23:00 飞飞 阅读(206) | 评论 (0)编辑 收藏

    转载于在webwork的文章
    1 配置struts.properties文件,指定spring作为struts的IoC容器
    struts.objectFactory = spring
    (1)默认的autowiring模式是:by name
    即如果applicationContext.xml文件中的bean id与struts.xml文件中的action name相同,就
    (2)如果要改为其他模式:
    struts.objectFactory.spring.autoWire = name|type|auto|constructor
    2 配置web.xml文件,启动Spring侦听器
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    3 在WEB-INF目录下增加applicationContext.xml文件
    例:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans default-autowire="autodetect">
    <bean id="personManager" class="com.acme.PersonManager"/>
    ...
    </beans>
    4 设置由Spring来初始化action
    4.1  在Spring的applicationContext.xml文件中配置bean(即action类)
    4.2  将struts.xml中的action的class属性,由class名改为Spring中定义的bean名
    例如:
    (1)applicationContext.xml中,定义bean id是bar
    <beans default-autowire="autodetect">
    <bean id="bar" class="com.my.BarClass" singleton="false"/>
    ...
    </beans>
    (2)struts.xml中,action的class="bar",而不是通常的类名
    <package name="secure" namespace="/secure" extends="default">
    <action name="bar" class="bar">
    <result>bar.ftl</result>
    </action>
    </package>
    posted @ 2008-07-31 17:28 飞飞 阅读(461) | 评论 (0)编辑 收藏

    2008-7-31 16:49:25 org.apache.struts2.config.Settings getLocale
    警告: Settings: Could not parse struts.locale setting, substituting default VM locale
    2008-7-31 16:49:26 com.opensymphony.xwork2.util.ObjectTypeDeterminerFactory <clinit>
    信息: Setting DefaultObjectTypeDeterminer as default ...

    错误信息 : WARN [struts2.config.Settings] Settings: Could not parse struts.locale setting, substituting default VM locale
    解决方法 : 在 struts.properties 文件中加上 struts.locale=en_US
    或者在struts.xml中加入<constant name="struts.locale" value="en_US"/>



    信息: Server startup in 23313 ms
    2008-7-31 16:59:47 org.apache.struts2.components.Form evaluateExtraParamsServletRequest
    警告: No configuration found for the specified action: '/mystruts/sum.action' in namespace: ''. Form action defaulting to 'action' attribute's literal value.
    2008-7-31 16:59:50 org.apache.struts2.components.Form evaluateExtraParamsServletRequest
    警告: No configuration found for the specified action: '/mystruts/sum.action' in namespace: ''. Form action defaulting to 'action' attribute's literal value.


    在struts.xml 中的sction 中取消namespace="/mystruts" 则会无此信息


    信息: Container org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/struts2] has not been started
    2008-7-31 17:34:12 org.apache.catalina.core.ApplicationContext log
    信息: Initializing Spring root WebApplicationContext
    log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
    log4j:WARN Please initialize the log4j system properly.
    2008-7-31 17:34:14 org.apache.catalina.core.StandardContext filterStart
    严重: Exception starting filter struts2
    Cannot locate the chosen ObjectFactory implementation: com.opensymphony.xwork2.ObjectFactory  - [unknown location]
     at org.apache.struts2.config.BeanSelectionProvider.alias(BeanSelectionProvider.java:224)
     at org.apache.struts2.config.BeanSelectionProvider.alias(BeanSelectionProvider.java:195)
     at org.apache.struts2.config.BeanSelectionProvider.register(BeanSelectionProvider.java:153)
     at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reload(DefaultConfiguration.java:131)
     at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:52)
     at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:395)
     at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:452)
     at org.apache.struts2.dispatcher.FilterDispatcher.init(FilterDispatcher.java:201)
     at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
     at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
     at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108)
     at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3693)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4340)
     at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1105)
     at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1203)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:293)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
     at java.lang.Thread.run(Unknown Source)
    2008-7-31 17:34:14 org.apache.catalina.core.StandardContext start
    严重: Error filterStart
    2008-7-31 17:34:14 org.apache.catalina.core.StandardContext start
    严重: Context [/struts2] startup failed due to previous errors
    2008-7-31 17:34:14 org.apache.catalina.core.ApplicationContext log
    信息: Closing Spring root WebApplicationContext


    struts.properties 文件设置如下:

             struts.objectFactory = spring


    原因:

            缺少 struts2-spring-plugin-2.0.11.1.jar

     

    Struts2 中使用 Spring 的 IOC 应加入以下 jar 包

            spring-core-2.0.5.jar

            spring-beans-2.0.5.jar

            spring-context-2.0.5.jar

            spring-web-2.0.5.jar

            struts2-spring-plugin-2.0.11.1.jar

     

    /WEB-INF/web.xml 文件中加入SpringContextLoaderListener 监听器,方便Spring与Web容器交互。

            <listener>
                 <listener-class>
                       org.springframework.web.context.ContextLoaderListener
                 </listener-class>
             </listener>

    posted @ 2008-07-31 17:06 飞飞 阅读(1157) | 评论 (0)编辑 收藏

    //dao注入
    private static String hqlname = "from User u where u.name=?";
     private static String hqlpassword = "from User u where u.password=?";

    public boolean isValidUser(String one,int i){
      List userList;
      if(i==0){
        userList=this.getHibernateTemplate().find(hqlname+"",one);
      }else{
        userList=this.getHibernateTemplate().find(hqlpassword+"",one);
       
      }
      if (userList.size() > 0) {
       return true;
      }
      
      return false;
      
     }


    //action

      if(userDao.isValidUser(name, password)){
       
       //return mapping.findForward("welcome");
       return new ActionForward("/pages/welcome.jsp");
      }else{
       
       ActionMessages message = new ActionMessages();
       
       if(userDao.isValidUser(name,0)){
        
       }else{
        message.add("name",new ActionMessage("name.error",true));
       }
       if(userDao.isValidUser(password,1)){
        
       }else{
        message.add("password",new ActionMessage("password.error",true));
       }

       this.saveErrors(request,message);
       //return new ActionForward("/pages/login.jsp");
       return mapping.findForward("welcome");
      }

    posted @ 2008-07-31 16:15 飞飞 阅读(324) | 评论 (0)编辑 收藏

    color=violet][/color][color=violet]本系列教程为转载自http://www.blogjava.net/nokiaguy/archive

    在本系列教程中我们将学习到Struts2的各种技术。在本教程中使用的工具和程序库的版本如下:
    开发工具:MyEclipse6

    Web服务器:Tomcat6

    Struts版本:Struts2.0.11.1

    JDK版本:JDK1.5.0_12

    J2EE版本:Java EE5.0

    在本系列教程中Web工程的上下文路径都是struts2,如果在Web根目录有一个index.jsp文件,则访问路径如下:

    http://localhost:8080/struts2/index.jsp

    由于MyEclipse6目前并不支持Struts2,所以我们需要到struts.apache.org去下载Struts2安装包。要想正常使用Struts2,至少需要如下五个包(可能会因为Struts2的版本不同,包名略有差异,但包名的前半部是一样的)。

    struts2-core-2.0.11.1.jar

    xwork-2.0.4.jar

    commons-logging-1.0.4.jar

    freemarker-2.3.8.jar

    ognl-2.6.11.jar

    Struts2虽然在大版本号上是第二个版本,但基本上在配置和使用上已经完全颠覆了Struts1.x的方式(当然,Struts2仍然是基于MVC模式的,也是动作驱动的,可能这是唯一没变的东西)。Struts2实际上是在Webwork基础上构建起来的MVC框架。我们从Struts2的源代码中可以看到,有很多都是直接使用的xwork(Webwork的核心技术)的包。既然从技术上来说Struts2是全新的框架,那么就让我们来学习一下这个新的框架的使用方法。

    如果大家使用过Struts1.x,应该对建立基于Struts1.x的Web程序的基本步骤非常清楚。让我们先来回顾一下建立基于Struts1.x的Web程序的基本步骤。

    1. 安装Struts。由于Struts的入口点是ActionServlet,所以得在web.xml中配置一下这个Servlet。

    2. 编写Action类(一般从org.apache.struts.action.Action类继承)。

    3. 编写ActionForm类(一般从org.apache.struts.action.ActionForm类继承),这一步不是必须的,如果要接收客户端提交的数据,需要执行这一步。

    4. 在struts-config.xml文件中配置Action和ActionForm。

    5. 如果要采集用户录入的数据,一般需要编写若干JSP页面,并通过这些JSP页面中的form将数据提交给Action。

    下面我们就按着编写struts1.x程序的这五步和struts2.x程序的编写过程一一对应,看看它们谁更“酷”。下面我们来编写一个基于Struts2的Web程序。这个程序的功能是让用户录入两个整数,并提交给一个Struts Action,并计算这两个数的代数和,如果代码和为非负数,则跳转到positive.jsp页面,否则跳转到negative.jsp页面。



    【第1步】 安装Struts2

    这一步对于Struts1.x和Struts2都是必须的,只是安装的方法不同。Struts1的入口点是一个Servlet,而Struts2的入口点是一个过滤器(Filter)。因此,Struts2要按过滤器的方式配置。下面是在web.xml中配置Struts2的代码:

    <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
    org.apache.struts2.dispatcher.FilterDispatcher
    </filter-class>
    </filter>
    <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>


    【第2步】 编写Action类

    这一步和Struts1.x也必须进行。只是Struts1.x中的动作类必须从Action类中继承,而Struts2.x的动作类需要从com.opensymphony.xwork2.ActionSupport类继承。下面是计算两个整数代码和的Action类,代码如下:
    package action;

    import com.opensymphony.xwork2.ActionSupport;

    public class FirstAction extends ActionSupport
    {
    private int operand1;
    private int operand2;

    public String execute() throws Exception
    {
    if (getSum() >= 0) // 如果代码数和是非负整数,跳到positive.jsp页面
    {
    return "positive";
    }
    else // 如果代码数和是负整数,跳到negative.jsp页面
    {
    return "negative";
    }
    }

    public int getOperand1()
    {
    return operand1;
    }

    public void setOperand1(int operand1)
    {
    System.out.println(operand1);
    this.operand1 = operand1;
    }

    public int getOperand2()
    {
    return operand2;
    }
    public void setOperand2(int operand2)
    {
    System.out.println(operand2);
    this.operand2 = operand2;
    }
    public int getSum()
    {
    return operand1 + operand2; // 计算两个整数的代码数和
    }
    }

    从上面的代码可以看出,动作类的一个特征就是要覆盖execute方法,只是Struts2的execute方法没有参数了,而Struts1.x的execute方法有四个参数。而且execute方法的返回值也不同的。Struts2只返回一个String,用于表述执行结果(就是一个标志)。上面代码的其他部分将在下面讲解。



    【第3步】 编写ActionForm类

    在本例中当然需要使用ActionForm了。在Struts1.x中,必须要单独建立一个ActionForm类(或是定义一个动作Form),而在Struts2中ActionForm和Action已经二合一了。从第二步的代码可以看出,后面的部分就是应该写在ActionForm类中的内容。所以在第2步,本例的ActionForm类已经编写完成(就是Action类的后半部分)。

    【第4步】 配置Action类

    这一步struts1.x和struts2.x都是必须的,只是在struts1.x中的配置文件一般叫struts-config.xml(当然也可以是其他的文件名),而且一般放到WEB-INF目录中。而在struts2.x中的配置文件一般为struts.xml,放到WEB-INF"classes目录中。下面是在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="struts2" namespace="/mystruts"
    extends="struts-default">
    <action name="sum" class="action.FirstAction">
    <result name="positive">/positive.jsp</result>
    <result name="negative">/negative.jsp</result>
    </action>
    </package>
    </struts>

    在<struts>标签中可以有多个<package>,第一个<package>可以指定一个Servlet访问路径(不包括动作名),如“/mystruts”。extends属性继承一个默认的配置文件“struts-default”,一般都继承于它,大家可以先不去管它。<action>标签中的name属性表示动作名,class表示动作类名。

    <result>标签的name实际上就是execute方法返回的字符串,如果返回的是“positive”,就跳转到positive.jsp页面,如果是“negative”,就跳转到negative.jsp页面。在<struts>中可以有多个<package>,在<package>中可以有多个<action>。我们可以用如下的URL来访问这个动作:

    http://localhost:8080/struts2/mystruts/sum.action

    注:Struts1.x的动作一般都以.do结尾,而Struts2是以.action结尾。

    【第5步】 编写用户录入接口(JSP页面)

    1. 主界面(sum.jsp)

    在Web根目录建立一个sum.jsp,代码如下:

    <%@ page language="java" import="java.util.*" pageEncoding="GBK" %>
    <%@ taglib prefix="s" uri="/struts-tags"%>

    <html>
    <head>
    <title>输入操作数</title>
    </head>

    <body>
    求代数和
    <br/>
    <s:form action="mystruts/sum.action" >
    <s:textfield name="operand1" label=" 操作数1"/>
    <s:textfield name="operand2" label=" 操作数2" />
    <s:submit value="代数和" />
    </s:form>
    </body>
    </html>

    在sum.jsp中使用了Struts2带的tag。在Struts2中已经将Struts1.x的好几个标签库都统一了,在Struts2中只有一个标签库/struts-tags。这里面包含了所有的Struts2标签。但使用Struts2的标签大家要注意一下。在<s:form>中最好都使用Struts2标签,尽量不要用HTML或普通文本,大家可以将sum.jsp的代码改为如下的形式,看看会出现什么效果:

    ... ...

    求代数和

    <br/>

    <s:form action="mystruts/sum.action" >

    操作数1:<s:textfield name="operand1" /><br/>

    操作数2:<s:textfield name="operand1" /><br/>

    <s:submit value="代数和" />

    </s:form>

    ... ...

    提示一下,在<s:form>中Struts2使用<table>定位。

    2. positive.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>

    <html>
    <head>
    <title>显示代数和</title>
    </head>

    <body>
    代数和为非负整数<h1><s:property value="sum" /></h1>
    </body>
    </html>

    3. negative.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>

    <html>
    <head>
    <title>显示代数和</title>
    </head>

    <body>
    代数和为负整数<h1><s:property value="sum" /></h1>

    </body>
    </html>


    这两个jsp页面的实现代码基本一样,只使用了一个<s:property>标签来显示Action类中的sum属性值。<s:property>标签是从request对象中获得了一个对象中得到的sum属性,如我们可以使用如下的代码来代替<s:property value=”sum”/>:


    <%

    com.opensymphony.xwork2.util.OgnlValueStack ovs =

    (com.opensymphony.xwork2.util.OgnlValueStack)request.getAttribute("struts.valueStack");

    out.println(ovs.findString("sum"));

    %>

    启动Tomcat后,在IE中输入如下的URL来测试这个例子:
    posted @ 2008-07-31 16:10 飞飞 阅读(215) | 评论 (0)编辑 收藏

    <2008-7-30 上午10时05分22秒 CST> <Error> <HTTP> <BEA-101020> <[ServletContext(id=3534409,name=WebRoot,context-path=/WebRoot)] Servlet failed with Exception
    java.lang.IllegalStateException: Root context attribute is not of type WebApplicationContext: org.springframework.web.context.support.XmlWebApplicationContext: display name [Root WebApplicationContext]; startup date [Wed Jul 30 10:00:52 CST 2008]; root of context hierarchy; config locations [/WEB-INF/classes/applicationContext.xml,/WEB-INF/classes/applicationContext-lucene.xml,/WEB-INF/classes/applicationContext-webservice.xml,/WEB-INF/classes/applicationContext-manager.xml]
     at org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:66)
     at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:84)
     at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:221)
     at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:207)
     at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:146)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:78)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:6458)
     at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
     at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:118)
     at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3661)
     at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2630)
     at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:219)
     at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:178)
    >




    2008-07-30 14:19:25,015 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]>
    2008-07-30 14:19:25,093 INFO [org.springframework.jdbc.support.SQLErrorCodesFactory] - <SQLErrorCodes loaded: [DB2, HSQL, MS-SQL, MySQL, Oracle, Informix, PostgreSQL, Sybase]>
    2008-07-30 14:19:25,296 INFO [org.codehaus.xfire.handler.DefaultFaultHandler] - <Fault occurred!>
    org.codehaus.xfire.fault.XFireFault: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.centralsoft.domain.XtUser user where user.userName like ?]; nested exception is org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.centralsoft.domain.XtUser user where user.userName like ?]
     at org.codehaus.xfire.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:68)
     at org.codehaus.xfire.service.binding.ServiceInvocationHandler.sendMessage(ServiceInvocationHandler.java:271)
     at org.codehaus.xfire.service.binding.ServiceInvocationHandler$1.run(ServiceInvocationHandler.java:85)
     at org.codehaus.xfire.service.binding.ServiceInvocationHandler.execute(ServiceInvocationHandler.java:132)
     at org.codehaus.xfire.service.binding.ServiceInvocationHandler.invoke(ServiceInvocationHandler.java:107)
     at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:98)
     at org.codehaus.xfire.transport.DefaultEndpoint.onReceive(DefaultEndpoint.java:61)
     at org.codehaus.xfire.transport.AbstractChannel.receive(AbstractChannel.java:38)
     at org.codehaus.xfire.transport.http.XFireServletController.invoke(XFireServletController.java:278)
     at org.codehaus.xfire.transport.http.XFireServletController.doService(XFireServletController.java:144)
     at org.codehaus.xfire.spring.remoting.XFireServletControllerAdapter.handleRequest(XFireServletControllerAdapter.java:63)
     at org.codehaus.xfire.spring.remoting.XFireExporter.handleRequest(XFireExporter.java:44)
     at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:45)
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:796)
     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:727)
     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:396)
     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:360)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
     at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:996)
     at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:419)
     at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:28)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:78)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:6458)
     at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
     at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:118)
     at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3661)
     at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2630)
     at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:219)
     at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:178)
    Caused by: org.springframework.orm.hibernate3.HibernateQueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.centralsoft.domain.XtUser user where user.userName like ?]; nested exception is org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.centralsoft.domain.XtUser user where user.userName like ?]
     at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:647)
     at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:413)
     at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:371)
     at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:822)
     at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:818)
     at com.centralsoft.framework.commons.BaseHibernateDao.find(BaseHibernateDao.java:59)
     at com.centralsoft.logic.GsManager.findUserByName(GsManager.java:252)
     at com.centralsoft.logic.GsManager$$FastClassByCGLIB$$e34716b5.invoke(<generated>)
     at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:710)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:100)
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:648)
     at com.centralsoft.logic.GsManager$$EnhancerByCGLIB$$cdf7d204.findUserByName(<generated>)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:324)
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:288)
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:165)
     at $Proxy11.findUserByName(Unknown Source)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:324)
     at org.codehaus.xfire.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:52)
     ... 35 more
    Caused by: org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [from com.centralsoft.domain.XtUser user where user.userName like ?]
     at org.hibernate.hql.ast.HqlLexer.panic(HqlLexer.java:57)
     at antlr.CharScanner.setTokenObjectClass(CharScanner.java:340)
     at org.hibernate.hql.ast.HqlLexer.setTokenObjectClass(HqlLexer.java:31)
     at antlr.CharScanner.<init>(CharScanner.java:51)
     at antlr.CharScanner.<init>(CharScanner.java:60)
     at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:56)
     at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:53)
     at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:50)
     at org.hibernate.hql.ast.HqlLexer.<init>(HqlLexer.java:26)
     at org.hibernate.hql.ast.HqlParser.getInstance(HqlParser.java:44)
     at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:232)
     at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:155)
     at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:109)
     at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:75)
     at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:54)
     at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:71)
     at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
     at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)
     at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1583)
     at org.springframework.orm.hibernate3.HibernateTemplate$29.doInHibernate(HibernateTemplate.java:824)
     at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:366)
     ... 59 more



    2008/8/1 9:57:2 : ----AFF_NAME & AFF_ACTION & PAGE_URL:com.centralsoft.gs.affair.sldj.QyslsjqyAff   querywdqy   qy_sl_sjqywdcx
    weblogic.jdbc.common.internal.RmiDataSource@10fe215
    org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: Unexpected character '"' (code 34) in DOCTYPE declaration; expected a space between public and system identifiers
     at [row,col {unknown-source}]: [1,55]
    org.codehaus.xfire.fault.XFireFault: Unexpected character '"' (code 34) in DOCTYPE declaration; expected a space between public and system identifiers
     at [row,col {unknown-source}]: [1,55]
     at org.codehaus.xfire.fault.XFireFault.createFault(XFireFault.java:89)
     at org.codehaus.xfire.client.Client.onReceive(Client.java:467)
     at org.codehaus.xfire.transport.http.HttpChannel.sendViaClient(HttpChannel.java:182)
     at org.codehaus.xfire.transport.http.HttpChannel.send(HttpChannel.java:67)
     at org.codehaus.xfire.handler.OutMessageSender.invoke(OutMessageSender.java:26)
     at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:98)
     at org.codehaus.xfire.client.Client.invoke(Client.java:360)
     at org.codehaus.xfire.client.XFireProxy.handleRequest(XFireProxy.java:77)
     at org.codehaus.xfire.client.XFireProxy.invoke(XFireProxy.java:57)
     at $Proxy13.findQyListByIndex(Unknown Source)
     at com.centralsoft.client.GsServiceClent.findQyListByIndex(GsServiceClent.java:85)
     at com.centralsoft.gs.affair.sldj.QyslsjqyAff.querywdqy(QyslsjqyAff.java:571)
     at com.centralsoft.gs.affair.sldj.QyslsjqyAff.goToAction(QyslsjqyAff.java:23)
     at com.centralsoft.gs.affair.Affair.doAct(Affair.java:37)
     at com.centralsoft.gs.dao.JDBCcontainer.doAff(JDBCcontainer.java:93)
     at com.centralsoft.gs.servlet.GSServlet.doAff(GSServlet.java:194)
     at com.centralsoft.gs.servlet.GSServlet.doPost(GSServlet.java:147)
     at com.centralsoft.gs.servlet.GSServlet.doGet(GSServlet.java:58)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
     at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:996)
     at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:419)
     at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:28)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at com.centralsoft.gs.util.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:75)
     at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:27)
     at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:6458)
     at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
     at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:118)
     at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3661)
     at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2630)
     at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:219)
     at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:178)
    Caused by: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '"' (code 34) in DOCTYPE declaration; expected a space between public and system identifiers
     at [row,col {unknown-source}]: [1,55]
     at com.ctc.wstx.sr.StreamScanner.throwUnexpectedChar(StreamScanner.java:600)
     at com.ctc.wstx.sr.BasicStreamReader.startDTD(BasicStreamReader.java:2318)
     at com.ctc.wstx.sr.BasicStreamReader.nextFromPrologBang(BasicStreamReader.java:2234)
     at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:1900)
     at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1026)
     at org.codehaus.xfire.soap.handler.ReadHeadersHandler.invoke(ReadHeadersHandler.java:44)
     at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:98)
     at org.codehaus.xfire.client.Client.onReceive(Client.java:450)
     ... 31 more
    posted @ 2008-07-30 10:25 飞飞 阅读(3759) | 评论 (2)编辑 收藏

    如果用Hibernate与数据库 Microsoft SQLServer 2000组合,在取子表集合的时候会抛出异常:
    org.hibernate.exception.GenericJDBCException: could not initialize a collection:
    和异常:SQL Server 2000 Driver for JDBC ResultSet can not re-read row data for column 1
    这是因为微软的Microsoft SQLServer驱动有以下问题:
    1、如果采用jdbc-odbc驱动,那么就必须按照查询顺序来一次读取(不论有没有image或text类型)

    2、如果采用微软提供的ms sql server jdbc driver,如果查询语句中,不存在image或text类型字段,那么可以按照无序获取

    3、如果采用微软提供的ms sql server jdbc driver,如果查询语句中,存在image或text类型字段,那么就必须按照顺序读取,否则就会报告Driver]ResultSet can not re-read row data for column之类的错误

    4、如果想不查询语句中有没有image或text类型字段,都可以不按照顺序获取,或重复获取。
    Hibernate在取子表集合时,它的不是按查询顺序来一次读取的,所以会抛出上述异常.
    解决办法:
    更换Microsoft SQLServer驱动,我现在用的是jtds-1.2.jar,这个驱动包大家可以到CSDN下载.
    它的连接字符串是:jdbc:jtds:sqlserver://localhost:1433;DatabaseName=数据库名
    驱动类:net.sourceforge.jtds.jdbc.Driver,
    问题解决了. 

    posted @ 2008-07-30 10:01 飞飞 阅读(1513) | 评论 (0)编辑 收藏

     前段时间也用XFire(xfire-1.1.1)做WebService,是QName类冲突:  
      stax-api-1.0.jar中的javax.xml.namespace.QName   和   WebLogic:   bea8.1.2\weblogic81\server\lib\目录中的相应jar包中的相同类有版本冲突(在Win2000professional直接搜索包含文字:QName,以查找哪些jar包中包含QName;   注意::Win2003版本改变了查找方式,不能这样查找)  
       
      解决办法:    
              删除WebLogic的上述目录中含有QName类的jar文件中的namespace目录,再将XFire提供的stax-api-1.0.jar文件复制到WebLogic的上述目录中.

    以下包有QNAME
    weblogic.jar
    webserviceclient.jar
    webserviceclient+ssl.jar
    webserviceclient+ssl_pj.jar
    wsclient81.jar
    posted @ 2008-07-30 09:53 飞飞 阅读(2457) | 评论 (2)编辑 收藏

    信息: Initializing WebApplicationContext for Struts ActionServlet 'action', module ''
    2008-7-27 22:26:03 org.apache.catalina.core.ApplicationContext log
    严重: action: null
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
    Caused by: java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
     at java.lang.Class.getDeclaredConstructors0(Native Method)
     at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
     at java.lang.Class.getConstructor0(Unknown Source)
     at java.lang.Class.getDeclaredConstructor(Unknown Source)
     at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:54)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:759)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:724)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:387)
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287)
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
     at org.springframework.web.struts.ContextLoaderPlugIn.createWebApplicationContext(ContextLoaderPlugIn.java:355)
     at org.springframework.web.struts.ContextLoaderPlugIn.initWebApplicationContext(ContextLoaderPlugIn.java:296)
     at org.springframework.web.struts.ContextLoaderPlugIn.init(ContextLoaderPlugIn.java:225)
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:871)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:26:03 org.apache.catalina.core.ApplicationContext log
    信息: Marking servlet action as unavailable
    2008-7-27 22:26:03 org.apache.catalina.core.StandardContext loadOnStartup
    严重: Servlet /hyrqSystem threw load() exception
    javax.servlet.UnavailableException
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:880)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:26:03 org.apache.coyote.http11.Http11Protocol start
    信息: Starting Coyote HTTP/1.1 on http-8080
    2008-7-27 22:26:03 org.apache.jk.common.ChannelSocket init
    信息: JK: ajp13 listening on /0.0.0.0:8009
    2008-7-27 22:26:03 org.apache.jk.server.JkMain start
    信息: Jk running ID=0 time=0/47  config=null
    2008-7-27 22:26:03 org.apache.catalina.startup.Catalina start
    信息: Server startup in 8940 ms

    今天做了webwork+spring+hibernate框架的集成,
    一启动Tomcat服务器就出了一大堆异常
    报的错误是java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
    在网上查找错误的原因,说是缺少了一个commons-pool.jar文件
    在myeclipse的安装目录下搜索,得到这个文件.放进lib文件夹.
    问题解决!



    严重: action: null
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
    Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
    Caused by: java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource': no matching editors or conversion strategy found
     at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:231)
     at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138)
     at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:380)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1112)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:862)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:424)
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:284)
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
     at org.springframework.web.struts.ContextLoaderPlugIn.createWebApplicationContext(ContextLoaderPlugIn.java:355)
     at org.springframework.web.struts.ContextLoaderPlugIn.initWebApplicationContext(ContextLoaderPlugIn.java:296)
     at org.springframework.web.struts.ContextLoaderPlugIn.init(ContextLoaderPlugIn.java:225)
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:871)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:29:15 org.apache.catalina.core.ApplicationContext log
    信息: Marking servlet action as unavailable
    2008-7-27 22:29:15 org.apache.catalina.core.StandardContext loadOnStartup
    严重: Servlet /hyrqSystem threw load() exception
    javax.servlet.UnavailableException
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:880)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:29:16 org.apache.coyote.http11.Http11Protocol start
    信息: Starting Coyote HTTP/1.1 on http-8080
    2008-7-27 22:29:16 org.apache.jk.common.ChannelSocket init
    信息: JK: ajp13 listening on /0.0.0.0:8009
    2008-7-27 22:29:16 org.apache.jk.server.JkMain start
    信息: Jk running ID=0 time=0/47  config=null
    2008-7-27 22:29:16 org.apache.catalina.startup.Catalina start
    信息: Server startup in 9498 ms

    从报错机制可以看出来,spring出现异常不同于普通的java异常,我们查异常的习惯一般是关注第一行,但是sping恰恰相反,要在sping中查错,你必须分解他,因为spring的嵌套层次比较多,它报错是从最高层报起,然后逐层往下,每个层次都会要报错,直到最终出错的地方,因此查sping的错必须逐层分解到最底层,那里才是真正出错的地方。

    OK,现在看出来了,真正错误的原因是:
    java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [javax.sql.DataSource] for property 'dataSource'



    严重: action: null
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.SecurityException: class "org.apache.commons.collections.SequencedHashMap"'s signer information does not match signer information of other classes in the same package
    Caused by: java.lang.SecurityException: class "org.apache.commons.collections.SequencedHashMap"'s signer information does not match signer information of other classes in the same package
     at java.lang.ClassLoader.checkCerts(Unknown Source)
     at java.lang.ClassLoader.preDefineClass(Unknown Source)
     at java.lang.ClassLoader.defineClass(Unknown Source)
     at java.security.SecureClassLoader.defineClass(Unknown Source)
     at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1817)
     at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:872)
     at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1325)
     at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
     at java.lang.ClassLoader.loadClassInternal(Unknown Source)
     at org.hibernate.mapping.Table.<init>(Table.java:33)
     at org.hibernate.cfg.Mappings.addTable(Mappings.java:165)
     at org.hibernate.cfg.HbmBinder.bindRootPersistentClassCommonValues(HbmBinder.java:299)
     at org.hibernate.cfg.HbmBinder.bindRootClass(HbmBinder.java:282)
     at org.hibernate.cfg.HbmBinder.bindRoot(HbmBinder.java:153)
     at org.hibernate.cfg.Configuration.add(Configuration.java:386)
     at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:427)
     at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:656)
     at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:134)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1202)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1172)
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:428)
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:284)
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
     at org.springframework.web.struts.ContextLoaderPlugIn.createWebApplicationContext(ContextLoaderPlugIn.java:355)
     at org.springframework.web.struts.ContextLoaderPlugIn.initWebApplicationContext(ContextLoaderPlugIn.java:296)
     at org.springframework.web.struts.ContextLoaderPlugIn.init(ContextLoaderPlugIn.java:225)
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:871)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:36:57 org.apache.catalina.core.ApplicationContext log
    信息: Marking servlet action as unavailable
    2008-7-27 22:36:57 org.apache.catalina.core.StandardContext loadOnStartup
    严重: Servlet /hyrqSystem threw load() exception
    javax.servlet.UnavailableException
     at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:880)
     at org.apache.struts.action.ActionServlet.init(ActionServlet.java:359)
     at javax.servlet.GenericServlet.init(GenericServlet.java:212)
     at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
     at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
     at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4042)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:4348)
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
     at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
     at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
     at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
     at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
     at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
     at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
     at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
     at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
     at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
     at org.apache.catalina.core.StandardService.start(StandardService.java:516)
     at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
     at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
     at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    2008-7-27 22:36:57 org.apache.coyote.http11.Http11Protocol start
    信息: Starting Coyote HTTP/1.1 on http-8080

    这种问题,我认为是你工程里的commons-collections.jar包与其它包不匹配导致的,例如如果你用commons-beanutils-1.7.0.jar,commons-collections-3.2.jar时会出现你的那种问题,如果是commons-beanutils-1.7.0.jar,commons-collections-3.1.jar就不会就这种问题了
    posted @ 2008-07-27 22:27 飞飞 阅读(5136) | 评论 (0)编辑 收藏

    如果struts-taglib.jar在classpath上,那么在jsp当中只要这样写就行:

    <%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %>
    <%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %>
    <%@ taglib prefix="logic" uri="http://struts.apache.org/tags-logic"%>
    posted @ 2008-07-27 12:43 飞飞 阅读(1248) | 评论 (2)编辑 收藏

    org.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'addUser' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Class that bean class [test.spring.InsertUser] depends on not found; nested exception is java.lang.NoClassDefFoundError: net/sf/hibernate/HibernateException
    java.lang.NoClassDefFoundError: net/sf/hibernate/HibernateException
            at java.lang.Class.forName0(Native Method)
            at java.lang.Class.forName(Class.java:242)
            at org.springframework.util.ClassUtils.forName(ClassUtils.java:108)
            at org.springframework.beans.factory.support.BeanDefinitionReaderUtils.createBeanDefinition(BeanDefinitionReaderUtils.java:65)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitionElement(DefaultXmlBeanDefinitionParser.java:426)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitionElement(DefaultXmlBeanDefinitionParser.java:392)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitions(DefaultXmlBeanDefinitionParser.java:307)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.registerBeanDefinitions(DefaultXmlBeanDefinitionParser.java:191)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:295)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:223)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:173)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:148)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:126)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:142)
            at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:126)
            at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
            at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:89)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:269)
            at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:134)
            at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:246)
            at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:184)
            at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)
            at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3764)
            at org.apache.catalina.core.StandardContext.start(StandardContext.java:4216)
            at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:760)
            at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:740)
    2007-07-02 15:02:49,312 ERROR  Catalina .[localhost].[/jbeingo]:3768  -> Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'addUser' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Class that bean class [test.spring.InsertUser] depends on not found; nested exception is java.lang.NoClassDefFoundError: net/sf/hibernate/HibernateException
    java.lang.NoClassDefFoundError: net/sf/hibernate/HibernateException
            at java.lang.Class.forName0(Native Method)
            at java.lang.Class.forName(Class.java:242)
            at org.springframework.util.ClassUtils.forName(ClassUtils.java:108)
            at org.springframework.beans.factory.support.BeanDefinitionReaderUtils.createBeanDefinition(BeanDefinitionReaderUtils.java:65)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitionElement(DefaultXmlBeanDefinitionParser.java:426)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitionElement(DefaultXmlBeanDefinitionParser.java:392)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.parseBeanDefinitions(DefaultXmlBeanDefinitionParser.java:307)
            at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.registerBeanDefinitions(DefaultXmlBeanDefinitionParser.java:191)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:295)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:223)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:173)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:148)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:126)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:142)
            at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:126)
            at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
            at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:89)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:269)
            at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:134)
            at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:246)
            at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:184)
            at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)
            at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3764)
            at org.apache.catalina.core.StandardContext.start(StandardContext.java:4216)
            at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:760)
            at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:740)
            at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:544)
            at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
            at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
            at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
            at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
            at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
            at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:120)
            at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1022)
            at org.apache.catalina.core.StandardHost.start(StandardHost.java:736)
            at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
            at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
            at org.apache.catalina.core.StandardService.start(StandardService.java:448)
            at org.apache.catalina.core.StandardServer.start(StandardServer.java:700)
            at org.apache.catalina.startup.Catalina.start(Catalina.java:552)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:585)
            at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295)
            at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433)
    2007-07-02 15:02:49,328 INFO   Catalina .[localhost].[/jbeingo]:647  -> Closing Spring root WebApplicationContext

    解决方案:
    下载commons-beanutils-1.7.0.zip;
    将其中commons-beanutils.jar文件替换Tomcat6.0下WEB-INF/lib/commons-beanutils-1.7;
    解决问题.
    posted @ 2008-07-27 12:29 飞飞 阅读(1240) | 评论 (0)编辑 收藏

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>css菜单</title>
    <style>
    body{
    background-color:#B8B8A0;
    }
    #fbtn{
    display:none;
    overflow:hidden;
    border-style:solid;
    border-width:1px;
    border-color:#e1e1c9 #e1e1c9 #6e6e56 #6e6e56;
    padding:1 1 1 1;
    width:115px;
    height:30px;
    }
    #fbtn_txt{
    position:relative;
    }
    #fbtn_txt div{
    height:30px;
    padding-top:11px;
    font-size:12px;
    color:#800080;
    text-align:center;
    cursor:hand;
    }
    #fbtn_mask{
    background-color:#ffffff;
    position:relative;
    width:100%;
    height:100%;
    }
    </style>
    </head>
    <body>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>G1</div>
    <div>good morning</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>G2</div>
    <div>good evening</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>M1</div>
    <div>my name is fireyy</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>M2</div>
    <div>mm mm i love u</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>G1</div>
    <div>good morning</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>G2</div>
    <div>good evening</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>M1</div>
    <div>my name is fireyy</div>
    </div>
    </div>
    <div id=fbtn>
    <div id=fbtn_mask></div>
    <div id=fbtn_txt>
    <div>M2</div>
    <div>mm mm i love u</div>
    </div>
    </div>
    <script>
    var current=null;
    var t=null;
    for(var i=0;i<fbtn.length;i++){
    fbtn_txt[i].style.posTop=-30;
    fbtn_mask[i].style.posTop=-30;
    fbtn[i].index=i;
    fbtn[i].style.display="block";
    fbtn[i].onmouseover=function(){
    if(!current){
    current=this;
    domove(this.index);
    }
    else
    if(current!=this){
    domove(current.index);
    domove(this.index);
    current=this;
    }
    }
    fbtn[i].onmouseout=function(){
    if(event.toElement==this.parentElement&t==this){
    domove(this.index);
    current=null;
    }
    }
    }
    function domove(num){
    var o=fbtn_txt[num];
    var m=fbtn_mask[num];
    if(o.style.posTop<-60){
    o.style.display="none";
    var t=o.children[1].innerHTML;
    o.children[1].innerHTML=o.children[0].innerHTML;
    o.children[0].innerHTML=t;
    o.style.posTop=-30;
    o.style.display="block";
    if(m.style.posTop>30)
    m.style.posTop=-30;
    else
    m.style.posTop=0;
    }
    else{
    m.style.posTop+=3;
    o.style.posTop-=3;
    setTimeout('domove('+num+')',15);
    }
    }
    </script>
    </body>
    </html>
    posted @ 2008-07-25 18:56 飞飞 阅读(307) | 评论 (0)编辑 收藏

    不明原因抛出 异常如下

    org.springframework.beans.factory.BeanDefinitionStoreException: Unrecognized xbean namespace mapping: http://XFire.codehaus.org/config/1.0
    org.apache.xbean.spring.context.v1.XBeanXmlBeanDefinitionParser.parseBeanFromExtensionElement(XBeanXmlBeanDefinitionParser.java:182)
    org.apache.xbean.spring.context.v1.XBeanXmlBeanDefinitionParser.parseBeanDefinitions(XBeanXmlBeanDefinitionParser.java:807)
    org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.registerBeanDefinitions(DefaultXmlBeanDefinitionParser.java:191)
    org.apache.xbean.spring.context.v1.XBeanXmlBeanDefinitionReader.registerBeanDefinitions(XBeanXmlBeanDefinitionReader.java:78)
    org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:223)
    org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:173)
    org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:148)
    org.codehaus.xfire.spring.XFireConfigLoader.getXFireApplicationContext(XFireConfigLoader.java:103)
    org.codehaus.xfire.spring.XFireConfigLoader.loadContext(XFireConfigLoader.java:41)
    org.codehaus.xfire.transport.http.XFireConfigurableServlet.loadConfig(XFireConfigurableServlet.java:86)
    org.codehaus.xfire.transport.http.XFireConfigurableServlet.createXFire(XFireConfigurableServlet.java:54)
    org.codehaus.xfire.transport.http.XFireServlet.init(XFireServlet.java:45)
    javax.servlet.GenericServlet.init(GenericServlet.java:211)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
    org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
    org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
    org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
    java.lang.Thread.run(Unknown Source)
    估计问题出在配置文件 services.xml
    查阅官方文档,发现 xmlns="http://xfire.codehaus.org/config/1.0"> 是全部小写,立即替换,解决!
    以下是一个实例
     
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xfire.codehaus.org/config/1.0">
    <service>
       <name>HelloWorldService</name>
       <namespace>http://localhost:8080/HelloService</namespace>
       <serviceClass>
        com.tom.pojo.HelloService
       </serviceClass>
       <implementationClass>
        com.tom.pojo.HelloServiceImp
       </implementationClass>
    </service>
    </beans>
    posted @ 2008-07-25 18:54 飞飞 阅读(4936) | 评论 (2)编辑 收藏

    下载XFrie
    首先,去http://xfire.codehaus.org下载最新版本的XFire

    搭建webservice工程环境
    在eclipse里创建一个叫webservice的java工程,然后依次添加src-service、src-conf、src-test和src-util这几个Source Folder以及web这个Folder
    目录结构及文件如下:

    代码
    1. webservice   
    2.      src-service   
    3.          cn.hidetoishandsome.xfire.model   
    4.              Book.java   
    5.          cn.hidetoishandsome.xfire.service   
    6.              BookService.java   
    7.          cn.hidetoishandsome.xfire.service.impl   
    8.              BookServiceImpl.java   
    9.      src-conf   
    10.          META-INF   
    11.              xfire   
    12.                  services.xml   
    13.      src-test   
    14.          cn.hidetoishandsome.xfire.test   
    15.              BookServiceTest.java   
    16.      src-util   
    17.          cn.hidetoishandsome.xfire.util   
    18.              XfireClientFactory.java   
    19.      web   
    20.          WEB-INF   
    21.              lib   
    22.              web.xml   
    23.          index.html   

    然后将解压后的xfire的lib目录下所有jar包和xfire-all-1.*.jar复制到WEB-INF/lib目录
    web.xml内容如下:
    代码
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"  
    3.          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
    4.   
    5.     <servlet>  
    6.         <servlet-name>xfire</servlet-name>  
    7.         <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>  
    8.     </servlet>  
    9.   
    10.     <servlet-mapping>  
    11.         <servlet-name>xfire</servlet-name>  
    12.         <url-pattern>/services/*</url-pattern>  
    13.     </servlet-mapping>  
    14.   
    15. </web-app>  

     

    写一个BookService
    我们将创建一个从ISBM号得到Book的Title的简单查询Web服务
    首先创建Book.java

    代码
    1. package cn.hidetoishandsome.xfire.model;   
    2.   
    3. public class Book {   
    4.   
    5.     private String title;   
    6.   
    7.     private String isbn;   
    8.   
    9.     public String getIsbn() {   
    10.         return isbn;   
    11.      }   
    12.   
    13.     public void setIsbn(String isbn) {   
    14.         this.isbn = isbn;   
    15.      }   
    16.   
    17.     public String getTitle() {   
    18.         return title;   
    19.      }   
    20.   
    21.     public void setTitle(String title) {   
    22.         this.title = title;   
    23.      }   
    24.   
    25. }   

    然后写一个BookService接口BookService.java
    代码
    1. package cn.hidetoishandsome.xfire.service;   
    2.   
    3. import cn.hidetoishandsome.xfire.model.Book;   
    4.   
    5. public interface BookService {   
    6.      Book findBookByISBN(String isbn);   
    7. }   

    然后是BookService的实现BookServiceImpl.java
    代码
    1. package cn.hidetoishandsome.xfire.service.impl;   
    2.   
    3. import cn.hidetoishandsome.xfire.model.Book;   
    4. import cn.hidetoishandsome.xfire.service.BookService;   
    5.   
    6. public class BookServiceImpl implements BookService {   
    7.   
    8.     private Book book;   
    9.   
    10.     public BookServiceImpl() {   
    11.          book = new Book();   
    12.          book.setTitle("XFire Quick Start");   
    13.          book.setIsbn("123456");   
    14.      }   
    15.   
    16.     public Book findBookByISBN(String isbn) {   
    17.         if (isbn.equals(book.getIsbn()))   
    18.             return book;   
    19.         throw new RuntimeException("Can't find book");   
    20.      }   
    21.   
    22. }   

     

    在services.xml中配置要发布的服务
    在src-conf的META-INF/xfire目录创建services.xml

    代码
    1. <beans xmlns="http://xfire.codehaus.org/config/1.0">  
    2.     <service>  
    3.         <name>BookService</name>  
    4.         <namespace>http://localhost:8080/xfire/services/BookService</namespace>  
    5.         <serviceClass>cn.hidetoishandsome.xfire.service.BookService</serviceClass>  
    6.         <implementationClass>cn.hidetoishandsome.xfire.service.impl.BookServiceImpl</implementationClass>  
    7.     </service>  
    8. </beans>  

    其中name标签决定了我们创建的该服务的WSDL的URL为http://xx.xx.xx/xx/xx/BookService?wsdl

     

    在Tomcat中发布
    可以简单的修改Tomcat的server.xml来发布该Web服务,在<Host>标签中添加以下内容:

    代码
    1. Context path="/webservice" docBase="D:\project\webservice\web" reloadable="true"/>   

    现在打开浏览器访问http://localhost:8080/webservice/services/BookService?wsdl来看看生成的WSDL文档

     

    客户端调用测试
    我们将使用一个XfireClientFactory.java工具类来帮我们调用该Web服务:

    代码
    1. package cn.hidetoishandsome.xfire.util;   
    2.   
    3. import java.net.MalformedURLException;   
    4.   
    5. import org.apache.commons.logging.Log;   
    6. import org.apache.commons.logging.LogFactory;   
    7. import org.codehaus.xfire.client.XFireProxyFactory;   
    8. import org.codehaus.xfire.service.Service;   
    9. import org.codehaus.xfire.service.binding.ObjectServiceFactory;   
    10. import org.springframework.util.Assert;   
    11.   
    12. public class XfireClientFactory {   
    13.     private static XFireProxyFactory serviceFactory = new XFireProxyFactory();   
    14.   
    15.     private static final Log log = LogFactory.getLog(XfireClientFactory.class);   
    16.   
    17.     private XfireClientFactory() {   
    18.      }   
    19.   
    20.     public static <T> T getClient(String serviceURL, Class<T> serviceClass) {   
    21.          Assert.notNull(serviceURL);   
    22.          Assert.notNull(serviceClass);   
    23.          Service serviceModel = new ObjectServiceFactory().create(serviceClass);   
    24.         try {   
    25.             return (T) serviceFactory.create(serviceModel, serviceURL);   
    26.          } catch (MalformedURLException e) {   
    27.              log.error(e.getMessage(), e);   
    28.             return null;   
    29.          }   
    30.      }   
    31.   
    32. }   

    然后编写一个BookServiceTest.java来调用我们刚才发布的Web服务:
    代码
    1. package cn.hidetoishandsome.xfire.test;   
    2.   
    3. import cn.hidetoishandsome.xfire.service.BookService;   
    4. import cn.hidetoishandsome.xfire.util.XfireClientFactory;   
    5.   
    6. public class BookServieTest {   
    7.   
    8.     public static void main(String[] args) {   
    9.          String serviceURL = "http://localhost:8080/webservice/services/BookService";   
    10.         try {   
    11.              BookService service = XfireClientFactory.getClient(serviceURL, BookService.class);   
    12.              System.out.println("Book with ISBN '123456': 《" + service.findBookByISBN("123456").getTitle() + "》");   
    13.          } catch (Exception e) {   
    14.              e.printStackTrace();   
    15.          }   
    16.   
    17.      }   
    18. }   

    服务调用成功,Console打印内容如下:
    代码
    1. Book with ISBN '123456': 《XFire Quick Start》   
    posted @ 2008-07-25 18:53 飞飞 阅读(310) | 评论 (0)编辑 收藏

     终于,使用Java完成了一个WebService的例子,其中的一个非常小的问题,折腾了我将近一天的时间。下面给出步骤,说明在Java平台上如何开发WebService。

        采用的工具:Eclipse3.1.2 + Tomcat5.5 + XFire1.1 。使用XFire开发WebService应该说非常的容易,只需要按照下面例子的步骤来做:

    (1)在Eclipse中新建一个dynamic Web Project ,假设名为XFireZhuweiTest。

    (2)导入XFire用户库。该库中应包含xfire-1.1目录下的xfire-all-1.1.jar文件,以及xfire-1.1\lib目录下的所有文件。

    (3)将上述的XFire用户库中的所有文件拷贝到XFireZhuweiTest项目的WebContent\WEB-INF\lib目录下。

    (4)修改WebContent\WEB-INF\web.xml配置文件的内容,下面是修改后web.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
         <display-name>
         XFireZhuweiTest</display-name>
         <welcome-file-list>
             <welcome-file>index.html</welcome-file>
             <welcome-file>index.htm</welcome-file>
             <welcome-file>index.jsp</welcome-file>
             <welcome-file>default.html</welcome-file>
             <welcome-file>default.htm</welcome-file>
             <welcome-file>default.jsp</welcome-file>
         </welcome-file-list>
        
         <servlet>
              <servlet-name>XFireServlet</servlet-name>
              <servlet-class>
                      org.codehaus.xfire.transport.http.XFireConfigurableServlet
              </servlet-class>
          </servlet>
         
          <servlet-mapping>
              <servlet-name>XFireServlet</servlet-name>
              <url-pattern>/servlet/XFireServlet/*</url-pattern>
          </servlet-mapping>

          <servlet-mapping>
              <servlet-name>XFireServlet</servlet-name>
               <url-pattern>/services/*</url-pattern>
          </servlet-mapping>
        
    </web-app>

        web.xml中添加的servlet映射表明,所有匹配“/services/*”的url请求全部交给org.codehaus.xfire.transport.http.XFireConfigurableServlet来处理。

    (5)编写需要发布为WebService的Java类,这个例子中是一个非常简单的MathService.java。

    package com.zhuweisky.xfireDemo;
    public class MathService
    {
        
    public int Add(int a ,int b)
         {
            
    return a+b ;
         }
    }

    (6)在WebContent\META-INF目录下新建xfire文件夹,然后在xfire目录下添加一个XFire使用的配置文件services.xml,该配置文件中的内容反映了要将哪些java类发布为web服务。本例中的services.xml内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xfire.codehaus.org/config/1.0">
        
    <service>
          
    <name>MathService</name>
          
    <namespace>http://com.zhuweisky.xfireDemo/MathService</namespace>
          <serviceClass>com.zhuweisky.xfireDemo.MathService</serviceClass>
        
    </service>
    </beans>


        XFire会借助Spring来解析services.xml,从中提取需要发布为WebService的配置信息。

         很多文章介绍到这里就完了,然而当我按照他们所说的启动WebService ,然后通过http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 来访问服务描述时,却抛出了异常,说services.xml文件不存在--
    “org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/xfire/services.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/xfire/services.xml] cannot be opened because it does not exist”。  

    (7)非常关键的一点,就是这个小难题花费了我将近一天的时间。
        在WebContent\WEB-INF目录下新建classes文件夹,然后需要将WebContent下的整个META-INF文件夹剪切到新建的classes文件夹下。
        到这里,项目的完整目录结构如下:


       (8)在处理完这个问题后.从新部署并运Tomcat.但接着问题又来了错误内容如下:Unrecognized xbean element mapping: services in namespace                         http://xfire.codeh.
                经过分析得出XFire1.26需要xalan.jar包的支持.但它自身的Lib下无此jar。需要我们在apache官方下载.然后将此包放入工程的lib下
       (9)再次从新编译运行.本以为一切OK了.但还是出来问题java.lang.NoClassDefFoundError: org/apache/xml/serializer/TreeWalker错误
                 这次通过在Apache官方找到了出错误的原因:
                 原本这个类是包含在xalan.jar中的,但是xalan-j2.7.0版的发布包中,将serializer包中的类单独打包成serializer.jar,不再包含在xalan.jar中,所以才会即使添加了
                xalan.jar也无法找到该类,添加后即可解决问题
    (10)OK。一切搞定在IE中输入 http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 会得到正确的web服务描述文档

    posted @ 2008-07-25 18:52 飞飞 阅读(801) | 评论 (0)编辑 收藏

     

    Java 社区一直试图将 POJO 的作用发挥到极致,降低 Java 应用实现的难度,最近的尝试是将 EJB3.0 建立在 POJO 之上;另一方面,SOA 是目前 Java 社区炙手可热的名词,非常多的企业都在努力应用和实施 SOA;XFire 为这两方面的需求提供了一种魔术般的解决方式,我们很快能够发现使用 XFire 创建和发布 Web 服务可以直接基于 POJO,将烦人的继承关系和一大堆其他可能的约束丢在一边。

    POJO、SOA 概述

    被重新审视的 POJO

    POJO(Plain Old Java Object,简单 Java 对象)是 Java 社区中最早的成员(回想您学习 Java 时第一个兴奋的时刻,那个简单的 "Hello World!" 例子),也是最简单、最容易实现的方式。

    然而现实中 Java 的发展已经远远超越了 POJO 的范围,成为面向对象技术应用中最成功的编程语言,尤其是继承、多态的应用为我们造就了一大批开发框架(如 Struts)和标准(如 EJB),随之而来的就是实现的复杂化,我们必须面对一大堆继承关系的限制。比如说:要开发一个基于 Struts 的应用,我们必须了解 Struts 特定的继承关系如 ActionForm、ValidateActionForm;要开发一个 EJB 应用,我们必须继承 EJBObject、SessionEJB 等。

    为了抛开这些限制,降低 Java 应用实现的难度,Java 社区开始重新审视 POJO 的价值,试图将 POJO 的作用发挥到极致,最新的努力是 EJB3.0。Java 社区将 EJB3.0 设计为基于 POJO,而不是为他准备更多的继承关系等限制。

    让人爱恨交加的 SOA

    SOA 已经成为了目前 Java 社区中炙手可热的名词,几乎所有的软件厂商都在讨论它,为他提供解决方案和产品支持,大部分的企业也已经在企业内部实施或者正在考虑实施 SOA。

    然而 SOA 在企业内的实施却不是一项简单的任务,即使抛开新建系统直接基于 SOA 架构实施的因素,要把企业已有系统纳入 SOA 框架也不是一件容易的事情。企业必须在对当前架构深入了解的基础上,对已有系统进行大规模的改造才能满足新的要求。如何经济的从原有技术架构切换到 SOA 架构成为很多企业的难题。




    XFire 概述

    XFire 是 codeHaus 组织提供的一个开源框架,它构建了 POJO 和 SOA 之间的桥梁,主要特性就是支持将 POJO 通过非常简单的方式发布成 Web 服务,这种处理方式不仅充分发挥了 POJO 的作用,简化了 Java 应用转化为 Web 服务的步骤和过程,也直接降低了 SOA 的实现难度,为企业转向 SOA 架构提供了一种简单可行的方式。

    XFire 目前最新的版本是 1.2.2,目前支持的特性主要包括:

    • 支持将 Web 服务绑定到 POJO、XMLBeans、JAXB1.1、JAXB2.0 和 Castor;
    • 支持基于 HTTP、JMS、XMPP 等多种协议访问 Web 服务;
    • 支持多种 Web 服务业界重要标准如 SOAP、WSDL、Web 服务寻址(WS-Addressing)、Web 服务安全(WS-Security)等;
    • 支持 JSR181,可以通过 JDK5 配置 Web 服务;
    • 高性能的 SOAP 实现;
    • 服务器端、客户端代码辅助生成;
    • 对 Spring、Pico、Plexus 等项目的支持等。




    XFire 安装包

    XFire 框架目前的最新版本是 1.2.6,可以访问 xfire.codehaus.org 下载 XFire 框架的安装包,下载时请选择“全部二进制发布包(Binary Distribution in zip package)”,而不仅仅是“XFire jar 文件(Jar of all XFire modules)”。

    下载完成后,我们可以将下载的 .zip 文件解压缩到任意的文件夹中(后面的章节中使用 % XFIRE_HOME % 表示 XFire 框架的安装目录),解压缩后形成的文件目录结构如下:

    • api(目录)

      api 目录中是 XFire 框架中所有类(class)对应的 API 文档,为开发者使用 XFire 完成应用开发提供帮助。

    • examples(目录)

      examples 目录中包含了所有随 XFire 二进制包发布的实例,包括这些实例的源代码和相关 Web 应用配置内容。

    • lib(目录)

      lib 目录中包含 XFire 运行所需要的外部支持类包(.jar文件),可以根据不同项目所需的 XFire 特性选择所需要的支持类包。保守的方法是在 Web 项目中包含所有的外部支持类包(.jar文件)。

    • manual(目录)

      manual 目录中包含有 XFire 框架的帮助文档,开发者可以从这些帮助文档中学习更多运用 XFire 框架实现 SOA 的知识和技巧。

    • modules(目录)

      modules 目录中包含了 XFire 框架根据不同特性分别编译的二进制包文件。发布基于 XFire 框架的 Web 项目时,可以选择使用该目录下的所有 .jar 文件,也可以选择 XFire-all-1.2.6.jar 文件。

    • XFire-all-1.2.6.jar

      XFire 框架的二进制包文件,包含了全部的模块(modules)。

    • LICENSE.txt

      LICENSE.txt 文件中包含了 XFire 框架的授权协议。

    • NOTICE.txt
    • README.txt

      这两个文件中包含了 XFire 发布时的一些有用的信息。





    XFire 框架支撑环境

    XFire框架是一种基于Servlet技术的SOA应用开发框架,要正常运行基于XFire应用框架开发的企业应用,除了XFire框架本身之外,还需要JDK和Servlet容器的支持。

    1.JDK 版本选择、下载和安装

    XFire 支持非常多的特性,其中不同的特性对 JDK 版本的要求有所不同,比如如果项目中选择基于 JSR181 标准发布 Web 服务,我们就需要选择 JDK5 或者以上版本,如果仅仅选择将 Web 服务绑定到最简单的 POJO,我们只需要选择 JDK1.4 版本即可。

    JDK 各版本均可以在 java.sun.com 网站上下载,如何安装 JDK 请参考 SUN 公司的相关技术文档和 JDK 的帮助文档。

    2.Servlet 容器下载和安装

    XFire 是一种基于 Servlet 技术的 SOA 应用开发框架,需要 Servlet 容器的支持。XFire 支持在多种 Servlet 容器中运行,包括 Websphere、Weblogic、TOMCAT 等。为了说明的简单,我们选择使用 TOMCAT(版本5.0.30)作为 XFire 的运行容器,所有配置过程和发布步骤的说明也均是针对 TOMCAT,如果读者使用 TOMCAT 之外的其它 Servlet 容器或者选择了 TOMCAT 的其它版本,下面的配置过程和步骤可能需要做出调整,请读者根据实际 Servlet 容器的帮助文档进行相应调整。

    TOMCAT 各版本均可以在 tomcat.apache.org 网站上下载,如何正确安装 TOMCAT 服务器请参考 TOMCAT 服务器的帮助文档。

    3.xalan

    XFire 需要 xalan 项目的支持,然而 1.2.6 版本中并没有带有相应的 jar 文件,因此请访问 xml.apache.org,下载 xalan 项目的二进制包。





    XFire 应用配置

    前面的章节中我们下载和安装了 XFire 安装包和所需要的支持环境,现在我们开始学习如何从零开始创建 XFire 应用开发环境。下面的所有配置过程和发布步骤均针对 TOMCAT(版本5.0.30)服务器,如果选择其它的 Servlet 容器,下面的配置过程和步骤可能需要做出调整,请读者根据实际 Servlet 容器的帮助文档进行相应调整。

    1、创建 Web 应用目录和基本元素

    1. 在 %TOMCAT_HOME%/webapps 目录下创建新的 Web 应用目录 “XFire”

      [注] 其中的 %TOMCAT_HOME% 指向 TOMCAT 的安装目录。

    2. 在 ”XFire”目录下创建 ”WEB-INF”目录、
    3. 在 ” WEB-INF”目录下创建 ”lib”目录和 ”classes”目录
    4. 在 ” WEB-INF”目录下创建 Web 应用描述文件 ”web.xml”, ”web.xml”文件的内容见 清单 1-1

    清单 1-1 WEB-INF\web.xml
                    
                1、 <?xml version="1.0" encoding="ISO-8859-1"?>
                2、 <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
                3、       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                4、       xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   
                http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
                5、       version="2.4">
                6、
                7、       <display-name>XFire实例</display-name>
                8、       <description>
                9、            基于XFire框架发布Web服务的例子
                10、       </description>
                11、
                12、 </web-app>

    2、拷贝 XFire 所需的支持类包文件

    拷贝 %XFIRE_HOME%/lib 目录下所有文件到 “1、创建 Web 应用目录和基本元素” 中所创建的 ”lib”目录下,将 %XFIRE_HOME%/XFire-all-1.2.6.jar 文件也拷贝到 “1、创建 Web 应用目录和基本元素” 中所创建的 ”lib”目录下。将 xalan 安装包中的所有 jar 文件和所需要的支持 jar 文件拷贝到相同的 ”lib”目录下。

    [注] 为了减少拷贝的 jar 文件的数目,开发者可以根据项目的需要选择需要拷贝的 jar 文件,而不是全部拷贝,如何根据需要选择拷贝合适的类包文件请访问 XFire 站点

    3、配置 XFire 框架运行所需的 Servlet

    修改 web.xml 文件,在其中增加如下 Servlet 定义内容。

    1、 <servlet>
                2、       <servlet-name>XFireServlet</servlet-name>
                3、       <display-name>XFire Servlet</display-name>
                4、       <servlet-class>
                5、           org.codehaus.xfire.transport.http.XFireConfigurableServlet
                6、       </servlet-class>
                7、     </servlet>
                8、
                9、     <servlet-mapping>
                10、       <servlet-name>XFireServlet</servlet-name>
                11、       <url-pattern>/servlet/XFireServlet/*</url-pattern>
                12、     </servlet-mapping>
                13、
                14、     <servlet-mapping>
                15、       <servlet-name>XFireServlet</servlet-name>
                16、       <url-pattern>/services/*</url-pattern>
                17、 </servlet-mapping>

    4、创建 XFire 框架的服务发布文件 services.xml

    1. “1、创建 Web 应用目录和基本元素” 中创建的 classes 目录下新建目录 ”META-INF\xfire”;
    2. 在步骤 a) 中新建的 ”xfire”文件目录下创建新文件 services.xml,文件的默认内容如 清单1-2

    清单 1-2 WEB-INF\classes\META-INF\xfire\services.xml
                    
                1、 <beans xmlns="http://XFire.codehaus.org/config/1.0">
                2、 </beans>





    将 POJO 发布成 Web 服务

    XFire 框架中,我们有两种方式将 POJO 发布成 Web 服务:

    • 一种方式是直接使用 Web 服务接口和 Web 服务实现类(POJO)来发布;
    • 另一种方式是基于 JSR181 标准和注释技术将被注释的 POJO 发布成 Web 服务;

    下面的章节中我们将学习使用第一种方式来完成 POJO 的 Web 服务发布。我们将使用经典的 ”Hello World!”例子来演示将 POJO 发布成 Web 服务所需要的步骤,不过我们不再是简单的访问一个 Java 方法来输出 ”Hello World!”字符串,而是转为在 SOA 环境下实现:Web 服务客户端通过访问服务器端发布成 Web 服务的 POJO 获得返回的 ”Hello World!”字符串后输出到客户端的控制台上。

    将 POJO 发布成 Web 服务的基本步骤如下:

    1. 创建 Web 服务接口,声明该 Web 服务对外暴露的接口;
    2. 创建 Web 服务实现类,为 Web 服务接口提供实现;
    3. 修改 XFire 框架的服务发布文件 ---- services.xml,将 POJO 发布成 Web 服务。

    下面我们通过创建 ”Hello World!”例子来具体说明如何实现这三个步骤。

    1.创建 Web 服务接口 ---- HelloWorldService

    要将 POJO 发布成 Web 服务,首先需要创建 Web 服务接口,在接口中声明该 Web 服务需要对外暴露的接口。

    我们根据需要创建 Web 服务接口 ” HelloWorldService”,在其中声明一个 ”sayHello”方法,该方法返回 ”String ”类型的内容。” HelloWorldService”接口对应的 Java 文件代码如 清单 1-3


    清单 1-3 WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldService.java
                    
                1.package org.vivianj.xfire.pojo;
                2.
                3. /**
                4. * HelloWorldService 中声明需要发布成 Web 服务的所有 Java 方法
                5. * HelloWorldService 作为Web服务接口
                6. */
                7. public interface HelloWorldService {
                8. /**
                9.        * sayHello 方法声明了 Web 服务对外暴露的接口
                10.  *
                11.  * @return 返回给客户端的字符串
                12.  */
                13. public String sayHello();
                14.}

    2.创建 Web 服务实现类 ”HelloWorldServiceImpl”

    创建 Web 服务实现类 ”HelloWorldServiceImpl”,它继承 ”1、创建Web服务接口 ---- HelloWorldService” 中创建的 HelloWorldService 接口,并且为它声明的 ”sayHello”方法提供具体实现: 返回字符串”Hello World!”。 ”HelloWorldServiceImpl”类对应的 Java 文件代码如 清单 1-4


    清单 1-4 WEB-INF\classes\org\vivianj\xfire\pojo\HelloWorldServiceImpl.java
                    
                1.package org.vivianj.xfire.pojo;
                2.
                3./**
                4. * HelloWorldServiceImpl 中为 Web 服务接口中声明的所有 Java 方法提供具体实现
                5. * HelloWorldServiceImpl 作为 Web 服务的实现类
                6. */
                7.public class HelloWorldServiceImpl implements HelloWorldService {
                8.
                9. /*
                10.  * sayHello 方法为 HelloWorldService 服务接口定义的 sayHello 方法提供具体实现
                11.  *  
                12.  * @see org.vivianj.XFire.pojo.HelloWorldService#sayHelloToXFire()
                13.  */
                14. public String sayHello() {
                15.  return "Hello World!";
                16. }
                17.
                18.}

    3.修改 services.xml,将 POJO 发布成 Web 服务

    我们可以在 WEB-INF\classes\META-INF\XFire\services.xml 文件中的 <beans …> 和 </beans> 元素中间加入如下的 xml 内容将上面创建的 HelloWorldService 发布成 Web 服务。

    1.<service>
                2. <name>HelloWorldService</name>
                3. <namespace>http://vivianj.org/HelloWorldService</namespace>
                4. <serviceClass>
                5.  org.vivianj.xfire.pojo.HelloWorldService
                6. </serviceClass>
                7. <implementationClass>
                8.  org.vivianj.xfire.pojo.HelloWorldServiceImpl
                9. </implementationClass>
                10.</service>

    其中各元素的功能如下:

    • service

      service 标签和它所包含的 xml 内容为发布成 Web 服务的 POJO 提供完整的描述。

    • name

      Web 服务被发布时所采用的唯一名称。

    • namespace

      Web 服务发布时所使用的命名空间。

    • serviceClass

      Web 服务接口类的全名,包括包名和类名。

    • implemetationClass

      Web 服务实现类的全名,包括包名和类名。

    更多 service 元素的子元素和它们的用法请参考 XFire 站点

    通过上面的三个步骤,我们已经将新创建的HelloWorldService发布成了Web服务,我们可以使用下面的步骤测试一下创建的Web服务是否能够正常运行:

    1. 编译上面的步骤中创建的 Java 接口和类;
    2. 启动 TOMCAT 服务器。
    3. 等 TOMCAT 服务器完全启动后,打开浏览器,在地址栏中输入 http://localhost:8080/XFire/services/HelloWorldService?wsdl。

    其中 HelloWorldServcie 是配置文件中 service\name 元素所定义的内容,”wsdl”参数表示查看该 Web 服务的 WSDL(Web服务描述语言)文件。

    如果浏览器中出现如下图所示类似的内容,表示 Web 服务发布成功,我们可以编写客户端访问该 Web 服务从服务器获取返回字符串,本文下载资源中提供的下载文件中包含有可供参考的客户端类 org.vivianj.xfire.pojo.client.HelloWorldServiceClient。


    图:浏览器中访问效果

    如果浏览器中出现错误提示,请按照上面的步骤和说明检查已经完成的开发、配置过程是否完全正确。





    结束语

    本文中作者首先讲解了 XFire 框架的主要特性,XFire 框架的运行环境以及基于 XFire 框架开发 SOA 应用的基本步骤,并且借助于 SOA 环境下的 ”Hello World!”例子,详细的讲解和演示了如何基于 XFire 框架、经过简单的开发、配置步骤就将一个 POJO 类中包含的方法发布成Web服务。从 ”Hello World!”例子实现的过程中,我们可以发现 XFire 框架最大化的发挥了 POJO 的作用,减少了 SOA 实施时对框架本身的依赖,降低了 SOA 实施的难度,企业实施 SOA 时并不需要增加太多的投入就可以实现目标。






    下载

    名字 大小 下载方法
    xfire.war 6 KB HTTP
    关于下载方法的信息


    参考资料

    学习

    获得产品和技术
    posted @ 2008-07-25 18:48 飞飞 阅读(241) | 评论 (0)编辑 收藏

    作用域 功能 快捷键
    文本编辑器 查找上一个 Ctrl+Shift+K
    文本编辑器 查找下一个 Ctrl+K
    全局 恢复上一个选择 Alt+Shift+↓
    全局 快速修正 Ctrl1+1
    全局 内容辅助 Alt+/
    全局 上下文信息 Alt+?
    Alt+Shift+?
    Ctrl+Shift+Space
    Java编辑器 显示工具提示描述 F2
    Java编辑器 选择封装元素 Alt+Shift+↑
    Java编辑器 选择上一个元素 Alt+Shift+←
    Java编辑器 选择下一个元素 Alt+Shift+→
    文本编辑器 增量查找 Ctrl+J
    文本编辑器 增量逆向查找 Ctrl+Shift+J
    全局 重做 Ctrl+Y


    查看
    作用域 功能 快捷键
    全局 放大 Ctrl+=
    全局 缩小 Ctrl+-


    窗口
    作用域 功能 快捷键
    全局 激活编辑器 F12
    全局 切换编辑器 Ctrl+Shift+W
    全局 上一个编辑器 Ctrl+Shift+F6
    全局 上一个视图 Ctrl+Shift+F7
    全局 上一个透视图 Ctrl+Shift+F8
    全局 下一个编辑器 Ctrl+F6
    全局 下一个视图 Ctrl+F7
    全局 下一个透视图 Ctrl+F8
    文本编辑器 显示标尺上下文菜单 Ctrl+W
    全局 显示视图菜单 Ctrl+F10
    全局 显示系统菜单 Alt+-


    导航
    作用域 功能 快捷键
    Java编辑器 打开结构 Ctrl+F3
    全局 打开类型 Ctrl+Shift+T
    全局 打开类型层次结构 F4
    全局 打开声明 F3
    全局 打开外部javadoc Shift+F2
    全局 打开资源 Ctrl+Shift+R
    全局 后退历史记录 Alt+←
    全局 前进历史记录 Alt+→
    全局 上一个 Ctrl+,
    全局 下一个 Ctrl+.
    Java编辑器 显示大纲 Ctrl+O
    全局 在层次结构中打开类型 Ctrl+Shift+H
    全局 转至匹配的括号 Ctrl+Shift+P
    全局 转至上一个编辑位置 Ctrl+Q
    Java编辑器 转至上一个成员 Ctrl+Shift+↑
    Java编辑器 转至下一个成员 Ctrl+Shift+↓
    文本编辑器 转至行 Ctrl+L

    搜索
    作用域 功能 快捷键
    全局 出现在文件中 Ctrl+Shift+U
    全局 打开搜索对话框 Ctrl+H
    全局 工作区中的声明 Ctrl+G
    全局 工作区中的引用 Ctrl+Shift+G

    文本编辑
    作用域 功能 快捷键
    文本编辑器 改写切换 Insert
    文本编辑器 上滚行 Ctrl+↑
    文本编辑器 下滚行 Ctrl+↓

    文件
    作用域 功能 快捷键
    全局 打印 Ctrl+P
    全局 全部保存 Ctrl+Shift+S
    全局 全部关闭 Ctrl+Shift+F4
    全局 属性 Alt+Enter

    项目
    作用域 功能 快捷键
    全局 全部构建 Ctrl+B

    源代码
    作用域 功能 快捷键
    Java编辑器 格式化 Ctrl+Shift+F
    Java编辑器 取消注释 Ctrl+\
    Java编辑器 注释 Ctrl+/
    Java编辑器 添加导入 Ctrl+Shift+M
    Java编辑器 组织导入 Ctrl+Shift+O

    运行
    作用域 功能 快捷键
    全局 单步跳入选择 Ctrl+F5
    全局 调试上次启动 F11
    全局 使用过滤器单步执行 Shift+F5
    全局 添加/去除断点 Ctrl+Shift+B
    全局 显示 Ctrl+D
    全局 运行上次启动 Ctrl+F11
    全局 执行 Ctrl+U

    重构
    作用域 功能 快捷键
    全局 撤销重构 Alt+Shift+Z
    全局 抽取方法 Alt+Shift+M
    全局 抽取局部变量 Alt+Shift+L
    全局 内联 Alt+Shift+I
    全局 移动 Alt+Shift+V
    全局 重命名 Alt+Shift+R
    全局 重做 Alt+Shift+Y
    posted @ 2008-07-23 13:06 飞飞 阅读(1168) | 评论 (1)编辑 收藏

    方法如下:

     

    <select onbeforeactivate="return false" onfocus="this.blur()" onmouseover="this.setCapture()" onmouseout="this.releaseCapture()"> 
    <option>1</option>
    </select>
    posted @ 2008-07-22 16:47 飞飞 阅读(477) | 评论 (0)编辑 收藏

    作者:阿捷 2005-4-11 16:54:52

    尽管在我的网站和文章里都有提到CSS制作菜单的方法,但很多初学者还是不太清楚如何实现,以及实现原理,我想专门写一篇详细教程会对大家比较有帮助。

    我们先来看一个菜单的例子,最终效果是:

    然后我们来详细讲解步骤

    第一步:建立一个无序列表

    我们先建立一个无序列表,来建立菜单的结构。代码是:

    <ul>
    <li><a href="1">首页</a></li>
    <li><a href="2">产品介绍</a></li>
    <li><a href="3">服务介绍</a></li>
    <li><a href="4">技术支持</a></li>
    <li><a href="5">立刻购买</a></li>
    <li><a href="6">联系我们</a></li>
    </ul>

    效果是:

    第二步:隐藏li的默认样式

    因为看起来不是很好看,菜单通常都不需要li默认的圆点,我们给UL定义一个样式来消除这些圆点。

    当然,为了更好的控制整个菜单,我们把菜单放在一个div里。页面代码变成:

    <div class="test"> <ul>
    <li><a href="1">首页</a></li>
    <li><a href="2">产品介绍</a></li>
    <li><a href="3">服务介绍</a></li>
    <li><a href="4">技术支持</a></li>
    <li><a href="5">立刻购买</a></li>
    <li><a href="6">联系我们</a></li>
    </ul> </div>

    CSS定义为:

    .test ul{list-style:none;}

    说明:“.test ul”表示我要定义的样式将作用在test的层里的ul标签上。

    现在的效果是没有圆点了:

    第三步:关键的浮动

    这里是菜单变成横向的关键,我们给li元素加上一个“float:left;”属性,让每个li浮动在前面一个li的左面。

    CSS定义为:

    .test li{float:left;}

    效果是:

    看,菜单变横向了。就这么简单!下面需要做的就是优化细节了。

    第四步:调整宽度

    菜单都挤在一起不好看怎么办?我们来调节li的宽度。

    在CSS中添加定义width:100px指定一个li的宽度是100px,当然你可以根据你的需要调整数值:

    .test li{float:left;width:100px;}

    效果是:

    如果我们同时定义外面div的宽度,li就会根据div的宽度自动换行,例如定义了div宽350px,6个li的总宽度是600px,一行排不下就自动变成两行:

    .test{width:350px;}

    效果是:

    第五步:设置基本链接效果

    接下来,我们通过CSS来设置链接的样式,分别定义:link、:visited、:hover的状态

    .test a:link{color:#666;background:#CCC;text-decoration:none;}
    .test a:visited{color:#666;text-decoration:underline;}
    .test a:hover{color:#FFF; font-weight:bold;text-decoration:underline;background:#F00;}

    效果是:

    第六步:将链接以块级元素显示

    有朋友问,菜单链接的背景色为什么没有填满整个li的宽度?恩,解决的方法很简单,在a的样式定义中增加display:block,使链接以块级元素显示。

    同时我们微调了如下细节:

    • 用text-align:center将菜单文字居中;
    • 用height:30px增加背景的高度;
    • 用margin-left:3px使每个菜单之间空3px距离;
    • 用line-height:30px;定义行高,使链接文字纵向居中;

    CSS定义象这样:

    .test a{display:block;text-align:center;height:30px;}
    .test li{float:left;width:100px;background:#CCC;margin-left:3px;line-height:30px;}

    效果变成:

    这样就漂亮多了吧。

    第七步:定义背景图片

    我们通常都会在每个链接前加一个小图标,这样导航更清楚。CSS是采用定义li的背景图片来实现的:

    .test a:link{color:#666;background:url(arrow_off.gif) #CCC no-repeat 5px 12px;text-decoration:none;}
    .test a:hover{color:#FFF; font-weight:bold;text-decoration:none;background:url(arrow_on.gif) #F00 no-repeat 5px 12px;}

    说明:“background:url(arrow_off.gif) #CCC no-repeat 5px 12px;”这句代码是一个CSS缩写,表示背景图片是arrow_off.gif;背景颜色是#CCC;背景图片不重复"no-repeat",背景图片的位置是左边距5px、上边距12px;

    默认状态下,图标为arrow.off.gif,当鼠标移动到链接上,图标变为arrow_on.gif

    效果变成:

    现在css的完整代码是:

    .test ul{list-style:none;}
    .test li{float:left;width:100px;background:#CCC;margin-left:3px;line-height:30px;}
    .test a{display:block;text-align:center;height:30px;}
    .test a:link{color:#666;background:url(arrow_off.gif) #CCC no-repeat 5px 12px;text-decoration:none;}
    .test a:visited{color:#666;text-decoration:underline;}
    .test a:hover{color:#FFF; font-weight:bold;text-decoration:none;background:url(arrow_on.gif) #F00 no-repeat 5px 12px;}

    页面的完整代码是:

    <div class="test">
    <ul>
    <li><a href="1">首页</a></li>
    <li><a href="2">产品介绍</a></li>
    <li><a href="3">服务介绍</a></li>
    <li><a href="4">技术支持</a></li>
    <li><a href="5">立刻购买</a></li>
    <li><a href="6">联系我们</a></li>
    </ul>
    </div>

    好了,主要步骤就是这7步,立刻拷贝和修改代码试试,你也可以用CSS做横向菜单了!

    posted @ 2008-07-10 10:51 飞飞 阅读(157) | 评论 (0)编辑 收藏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>POPHint 弹出提示框</title>
    <style type="text/css">
    <!--
    body {margin: 3em; font: 12px "宋体"; background: #EAEAEA}
    input {font: 12px "宋体"; color: #666666}
    .case {padding: 2em; border: solid 1px #EAEAEA; background: #FFFFFF; margin-bottom: 3em; line-height: 150%}
    a {color: #666666; text-decoration: none}
    a:hover {color: #333333}

    /* popHint Start */
    #popHint {position: absolute}
    #popHint .popLeft, #popHint .popRight, #popHint .popAngle span, #popHintText, #popHint .popIcon {background-image: url(http://i.namipan.com/files/48ee6e2804bb4b1d84ecea96218e4a50081349ba960100008f09/0/PopHint.gif)}
    #popHint .popHeader {height: 1%; overflow: hidden !important; overflow /**/: visible}
        #popHint .popLeft {float: left; width: 5px; height: 24px; background-position: 0 0; background-repeat: no-repeat}
        #popHint .popRight {float: left; width: 5px; height: 24px; background-position: -10px -25px; background-repeat: no-repeat}
        #popHint .popAngle {clear: both; position: relative; height: 10px}
        #popHint .popAngle span {position: absolute; top: -3px; left: 15px; width: 7px; height: 13px; background-position: 0 -75px; background-repeat: no-repeat}
    #popHintText {float: left; color: #975400; height: 19px !important; height /**/: 24px; padding: 5px 0 0 0; white-space: nowrap; background-position: 0 -50px; background-repeat: repeat-x; overflow: hidden}
        #popHintText .popIcon {float: left; width: 15px; height: 10px; margin: 1px 3px 0 0}
        #popHint .wrong {background-position: 0 -90px; background-repeat: no-repeat}
        #popHint .right {background-position: 0 -105px; background-repeat: no-repeat}
        /* 这里可以自己扩展图标.(15*10) */
    /* popHint End */
    -->
    </style>
    <script language="javascript" type="text/javascript">
    <!--

    // 这里都是公用函数,挺多的...
    var

    // 获取元素
    $ = function(element) {
        return (typeof(element) == 'object' ? element : document.getElementById(element));
    },

    // 生成元素到refNode
    appendElement = function(tagName, Attribute, strHtml, refNode) {
        var cEle = document.createElement(tagName);
        // 属性值
        for (var i in Attribute){
            cEle.setAttribute(i, Attribute[i]);
        }
        cEle.innerHTML = strHtml;
       
        refNode.appendChild(cEle);
        return cEle;
    },

    // 获取元素坐标
    getCoords = function(node){
        var x = node.offsetLeft;
        var y = node.offsetTop;
        var parent = node.offsetParent;
        while (parent != null){
            x += parent.offsetLeft;
            y += parent.offsetTop;
            parent = parent.offsetParent;
        }
        return {x: x, y: y};
    },

    // 事件操作(可保留原有事件)
    eventListeners = [],
    findEventListener = function(node, event, handler){
        var i;
        for (i in eventListeners){
            if (eventListeners[i].node == node && eventListeners[i].event == event && eventListeners[i].handler == handler){
                return i;
            }
        }
        return null;
    },
    myAddEventListener = function(node, event, handler){
        if (findEventListener(node, event, handler) != null){
            return;
        }
        if (!node.addEventListener){
            node.attachEvent('on' + event, handler);
        }else{
            node.addEventListener(event, handler, false);
        }
        eventListeners.push({node: node, event: event, handler: handler});
    },
    removeEventListenerIndex = function(index){
        var eventListener = eventListeners[index];
        delete eventListeners[index];
        if (!eventListener.node.removeEventListener){
            eventListener.node.detachEvent('on' + eventListener.event,
            eventListener.handler);
        }else{
            eventListener.node.removeEventListener(eventListener.event,
            eventListener.handler, false);
        }
    },
    myRemoveEventListener = function(node, event, handler){
        var index = findEventListener(node, event, handler);
        if (index == null) return;
        removeEventListenerIndex(index);
    },
    cleanupEventListeners = function(){
        var i;
        for (i = eventListeners.length; i > 0; i--){
            if (eventListeners[i] != undefined){
                removeEventListenerIndex(i);
            }
        }
    };

     


    /*********************************************
        - POPHint 弹出提示框
        - By Mudoo 2008.5
    **********************************************/
    function popHint(obj, msg, initValues) {
        var
        _obj = $(obj),
        _objHint = $("popHint"),
        _msg = msg,
        _init = initValues;
       
        // 初始化失败...
        if(_obj==undefined || _msg==undefined || _msg=="") return;
       
        // 设置初始值
        _init = _init==undefined ? {_type : "wrong", _event : "click"} : _init;
        // obj如果不可见。设置弹出对象为obj父元素
        if(_obj.style.display=='none' || _obj.style.visibility=='hidden' || _obj.getAttribute('type')=='hidden') _obj = _obj.parentNode;
       
        var
        _type = null,
        _event = null,
        _place = getCoords(_obj),
        _marTop = null,
        _objText = $("popHintText"),
       
        // 初始化
        init = function() {
            _hint = _obj.getAttribute("hint");
            if(_hint=="false") return;
           
            // 有的时候initValues不为空.但是只设置一个值...避免发所错误.再次设置初始值...
            _type = _init._type==undefined ? "wrong" : _init._type;
            _type = _type.toLowerCase();
            _event = _init._event==undefined ? "click" : _init._event;
            _event = _event.toLowerCase();
           
            /*
            ******************************************
            popHtml
            ******************************************
            <div id="popHint">
                <div id="popHeader">
                    <div class="popLeft"></div>
                    <div id="popHintText"><span class=\"popIcon wrong></span>请输入您的用户名!</div>
                    <div class="popRight"></div>
                </div>
                <div class="popAngle"><span></span></div>
            </div>
            */
           
            // 好了.输出...
            var _Html = "<div id=\"popHeader\">" +
                        "    <div class=\"popLeft\"></div>" +
                        "    <div id=\"popHintText\"></div>" +
                        "    <div class=\"popRight\"></div>" +
                        "</div>"+
                        "<div class=\"popAngle\"><span></span></div>"
           
            if(_objHint==null) {
                _objHint = appendElement("div", {"id" : "popHint"}, _Html, document.body);
                _objHint.style.display = "none";
                _objText = $("popHintText");
            }
           
            show();
        },
        // 显示
        show = function() {
            _objHint.style.display = "";
            _marTop = _objHint.offsetHeight;
           
            _msg = "<span class=\"popIcon "+ _type +"\"></span>"+ _msg;
            _objText.innerHTML = _msg;
           
            _objHint.style.left = _place.x +"px";
            _objHint.style.top = (_place.y-_marTop+8) +"px";
           
            // 关闭触发事件
            switch(_event) {
                case "blur" :
                    myAddEventListener(_obj, 'blur', hide);
                    break;
                //default :
                case "click" :
                    myAddEventListener(document, 'mousedown', hide);
                    break;
                //这里可以自己扩展很多事件...
            }
        },
        // 关闭
        hide = function() {
            _objHint.style.display = "none";
            _objText.innerHTML = "";
            // 移除关闭触发事件
            myRemoveEventListener(_obj, 'blur', hide);
            myRemoveEventListener(document, 'mousedown', hide);
        };
       
        init();
    }

     

    /*********************************************
    - 这里是测试函数
    *********************************************/
    function testPopHint() {
        if($('Test2').value==''){
            popHint($('Test2'), 'Test2不能为空...', {_event : 'blur'});
            $('Test2').focus();
            return false;
        }
        if($('Test3').value==''){
            popHint($('Test3'), 'Test3也不能为空...', 'blur');
            $('Test3').focus();
            return false;
        }
        if($('Test4').value==''){
            popHint($('Test4'), 'Test4虽然看不见,但也不能为空...');
            $('Test4').value='填一点进去...';
            return false;
        }
        if($('Test5').value==''){
            popHint($('Test5'), 'Test5也一样...');
            return false;
        }
    }

    -->
    </script>
    </head>

    <body>

    <div class="case">
        好了.可以继续了.
        接下来调用方法.<br />
        ===========================================================<br />
        popHint(Element, Hint, {Type, Event});<br />
        ===========================================================<br />
        Element:弹出对象。根据它来定位的。<br />
        Hint:弹出的信息。<br />

        Type:弹出类型。其实说类型是不对的。只是定义个图标而已...(可自己在样式里加很多很多"类型")<br />
        Event:关闭触发事件。(默认click=document.onmousedown,blur=Element.onblur) 一样可以自己定义很多事件.
    </div>
        <div class="case">
        测试:<input name="Test1_0" id="Test1_0" type="text" size="20" maxlength="20" onfocus="popHint(this, '失去焦点不会关闭提示.按TAB键看看');" value="" />
        blur不触发关闭<a href="###"> </a>
        <br />

        测试blur关闭:<input name="Test1_1" id="Test1_1" type="text" size="20" maxlength="20" onfocus="popHint(this, '文本框失去焦点就关闭.', {_event : 'blur'});" value="" />
    </div>
    <div class="case">
        <div>Test2:<input name="Test2" id="Test2" type="text" size="20" maxlength="20" value="" /></div>
        <div>Test3:<input name="Test3" id="Test3" type="text" size="20" maxlength="20" value="" /></div>
        <div>Test4:<input name="Test4" id="Test4" type="hidden" size="20" maxlength="20" value="" /></div>
        <div>Test5:<input name="Test5" id="Test5" type="text" size="20" maxlength="20" value="" style="display:none" /></div>

        <input name="" type="button" onclick="testPopHint();" value="测试" />
    </div>
    </body>
    </html>

    posted @ 2008-07-10 09:42 飞飞 阅读(2964) | 评论 (3)编辑 收藏

    信息: Illegal access: this web application instance has been stopped already.  Could not load java.net.BindException.  The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
    java.lang.IllegalStateException
     at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1244)
     at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
     at java.lang.ClassLoader.loadClassInternal(Unknown Source)
     at com.mysql.jdbc.SQLError.createLinkFailureMessageBasedOnHeuristics(SQLError.java:1220)
     at com.mysql.jdbc.CommunicationsException.<init>(CommunicationsException.java:51)
     at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1070)
     at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3246)
     at com.mysql.jdbc.MysqlIO.quit(MysqlIO.java:1656)
     at com.mysql.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:4261)
     at com.mysql.jdbc.ConnectionImpl.cleanup(ConnectionImpl.java:1248)
     at com.mysql.jdbc.ConnectionImpl.finalize(ConnectionImpl.java:2655)
     at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
     at java.lang.ref.Finalizer.runFinalizer(Unknown Source)
     at java.lang.ref.Finalizer.access$100(Unknown Source)
     at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
    log4j:WARN No appenders could be found for logger (org.apache.struts.util.PropertyMessageResources).
    log4j:WARN Please initialize the log4j system properly.
    2008-7-10 8:56:40 org.apache.catalina.core.ApplicationContext log
    信息: Initializing WebApplicationContext for Struts ActionServlet 'action', module ''


    Question: What causes these frequent Tomcat catalina.log messages "INFO: Illegal access: this web application instance has been stopped already."? I do not want to disable INFO level logging, so it would be nice to stop the root of the problem. I tried disabling RSS and Lucence and they still keep coming out. The full log entry looks like this: May 8, 2005 9:34:09 PM org.apache.catalina.loader.WebappClassLoader loadClass INFO: Illegal access: this web application instance has been stopped already. Could not load org.xml.sax.helpers.XMLReaderFactory. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.

    A:I found this explanation from web: It is possible that this is caused by Tomcat unsuccessfully reloading the web application. The app is unloaded, but all threads don't get shut down properly. As a result, when the threads try to run, they get clobbered by the fact that Tomcat has shut down its classloader, and an error is logged. The best fix is to turn off automatic webapp reloading for the application: in Tomcat's server.xml , find the <Context> declaration, and ensure it is set to: reloadable="false"

    posted @ 2008-07-10 09:00 飞飞 阅读(12479) | 评论 (6)编辑 收藏

    分析:EOFException表示输入过程中意外地到达文件尾或流尾的信号,导致从session中获取数据失败。异常是tomcat本身的问题,由于tomcat上次非正常关闭时有一些活动session被持久化(表现为一些临时文件),在重启时,tomcat尝试去恢复这些session的持久化数据但又读取失败造成的。此异常不影响系统的使用。
    解决办法:将tomcat5.5\work\Catalina\localhost\peam\SESSIONS.ser删除。如果正常关闭服务端,该文件是自动删除的。
    posted @ 2008-07-09 22:59 飞飞 阅读(193) | 评论 (0)编辑 收藏

    当增加Hibernate Capabilites后增加Struts Capabilites,运行项目时,控制台报错信息:
    /----------------------------------------------org.apache.commons.collections.SequencedHashMap
    ......
    /----------------------------------------------
    解决方案:
    下载commons-beanutils-1.7.0.zip;
    将其中commons-beanutils.jar文件替换Tomcat6.0下WEB-INF/lib/commons-beanutils-1.7;
    解决问题.

    这个错误可能是myeclipse6.0版本的一个问题,就是在整合web层和struts层出现的问题

    解决方法如下:

    1)下载6.0.1版本的myeclipse开发

    2)下载最新的org.apache.commons.collections,讲原来的去掉就行了,然后讲最新的加进去

    posted @ 2008-07-09 20:53 飞飞 阅读(769) | 评论 (0)编辑 收藏

    <html:messages>
    Action 中 :
            ActionMessages message = new ActionMessages();
            message.add(" 消息句柄 ",new ActionMessage(" 资源文件中 Key 值 ",String 类型描述信息 ));
            this.addMessages(request,message);
            return ActionForward;
    JSP 页面中 :
            <html:messages id=" 指定使用消息的标识 " property=" 消息句柄 " message="true|false">
               <bean:write name=" 以上所指 ID 标识 "/>
            </html:messages>

    例如:

    Action方法中:
    saveMessage(request,"页面要显示的消息");

    Action的调用的方法,可以写真Action实现类的父类 BaseDispatchAction :

    public ActionMessages saveMessage(HttpServletRequest request, String key) {
          ActionMessages messages = new ActionMessages();
          return saveMessage(messages, request, key);
    }

    protected ActionMessages saveMessage(ActionMessages messages,
           HttpServletRequest request, String key) {

          messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(key));
          saveMessages(request, messages);
          return messages;
    }

    页面:

    <html:messages id="msg" message="true"><bean:write name="msg"/></html:messages>

     

    <html:errors>
    Action 中 :
            ActionMessages message = new ActionMessages();
            message.add(" 消息句柄 ",new ActionMessage(" 资源文件中 Key 值 ",String 类型描述信息 ));
            this.saveErrors(request,message);
            return ActionForward;
    JSP 页面中 :
            <html:errors property=" 消息句柄 "/>

    如果Action中这样设定(false),页面的提示信息将不从资源文件里读取:
            ActionMessages message = new ActionMessages();
            message.add("消息句柄",new ActionMessage("String类型描述信息));",false));
            this.saveErrors(request,message);
            return ActionForward;
    JSP页面:
            <html:errors/>或<html:errors property="消息句柄"/>

    posted @ 2008-07-09 17:21 飞飞 阅读(323) | 评论 (0)编辑 收藏

    源码下载:http://ishare.iask.sina.com.cn/cgi-bin/fileid.cgi?fileid=2857703

    1. 准备

    工具:MyEclipse 6.0.1 GAmysql-connector-java-5.0.4-bin.jarMySql GUI Tools 5.0(便于管理MySql数据库,不是必须)

    环境:Tomcat 5.5MySql 5.0

    1.1. 新建工程

    操作:[Menu] File/New/Web Project

    工程名:login

    2. Struts 部分


    2.1. 添加 Struts 功能支持

    操作:[Menu] MyEclipse/Project Capabilities/Add Struts Capabilities

     

    2.2. 创建 ActionForm 类

    操作:[Ctrl+N] MyEclipse/Web-Struts/Struts 1.2 Form

    类名:LoginForm

    在 “Form Properties” 选项卡为 loginForm 新增两个属性:username、password;

    在 “JSP” 选项卡钩选 “Create JSP form” 选项,将新建路径改为 “/login.jsp”(login.jsp文件将被自动创建)。

    2.3. 创建 Action 类

    操作:[Ctrl+N] MyEclipse/Web-Struts/Struts 1.2 Action

    类名:LoginAction

    在 “Form” 选项卡的 “Name” 项选择 “loginForm”,”Input Source” 项输入 “/login.jsp”。

    2.4. 创建 index.jsp 文件

    如果没有,创建 index.jsp 文件,并添加一个指向 login.jsp 的链接:<a href=”login.jsp”>Login</a>

    2.5. 创建Forword类

    操作:[Ctrl+N] MyEclipse/Web-Struts/Struts 1.2 Forword

    类名:indexForword

    “Name” 项输入 “indexForword” ,”Path” 项输入 “/index.jsp” 。

    2.6. 修改 LoginAction.java 文件

    修改 LoginAction 类的 execute 方法:

    public class LoginAction extends Action {

    public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) {
    LoginForm loginForm = (LoginForm) form;
    String username=loginForm.getUsername();
    String password=loginForm.getPassword();
    if(username.equals(”test”)||password.equals(”test”)){
    return mapping.findForward(”indexForword”);
    }else{
    return mapping.getInputForward();
    }
    }
    }

    2.7. 修改 login.jsp 文件

    修改 <html:form> 标签:<html:form action=”/login”>

    2.8. 测试

    操作:[Menu] Run/Run,选择 MyEclipse Server Application 方式运行

    要正常执行Run操作,需先安装 Tomcat5.5 。

    点击 index.jsp 页面的 “Login” 链接,跳转到 login.jsp 页面。在 login.jsp 页面输入 “test/test”,应该会登录成功,然后跳转到 index.jsp 页面;输入 “test/123″ ,应该保持在 login.jsp 页面。

    如果测试成功,证明 Structs 运行正常。

    3. Spring 部分


    3.1. 添加 Spring 功能支持

    操作:[Menu] MyEclipse/Project Capabilities/Add Spring Capabilities

    Spring 版本( Spring version )选择 “Spring 1″;

    开发包(libraries)选择 “Spring 1.2 AOP Libraries、Spring 1.2 Core Libraries、Spring 1.2 Persistence Core Libraries、Spring 1.2 Persistence JDBC Libraries” 四项;

    JAR Library Installation 选择 “copy checked…” ,”Library Folder” 项选择 “/WebRoot/WEB-INF/lib”(这样的话所需的类库都将拷贝到项目目录,方便以后的布署)。

    点击 “下一步(Next)” 创建配置文件,修改文件路径(Folder)到 “WebRoot/WEB-INF” 目录(以便和Struts配置文件一起管理),文件名称为默认的”applicationContext.xml”。

    点击 “完成(Finish)” 。

    3.2. 配置 struts-config.xml 文件

    添加 Spring 插件(在 <message-resources> 标签后面添加):

    <plug-in className=”org.springframework.web.struts.ContextLoaderPlugIn”>
    <set-property property=”contextConfigLocation” value=”/WEB-INF/applicationContext.xml” />
    </plug-in>

    修改 LoginAction 的配置(只需修改 type 属性):

    <action-mappings >
    <action
    attribute=”loginForm”
    input=”/login.jsp”
    name=”loginForm”
    path=”/login”
    scope=”request”
    type=”org.springframework.web.struts.DelegatingActionProxy” />

    </action-mappings>

    绿色字体部份为被修改过的内容,这里将使用 spring 的代理器 DelegatingActionProxy 来对 Action 进行控制。

    3.3. 修改 Spring 配置文件 applicationContext.xml

    <?xml version=”1.0″ encoding=”UTF-8″?>
    <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

    <beans>
    <bean name=”/login” class=”com.login.struts.action.LoginAction” singleton=”false”></bean>
    </beans>

    绿色字体是关于接受和处理 Action 控制权的配置内容,”com.login.struts.action.LoginAction” 即为原 struts 里的配置。

    3.4. 测试

    同上一次测试。测试成功证明 Spring 运行正常。

    4. Hibernate 部分

    下面开始 Hibernate 部分,将原例修改为使用数据库进行用户名/密码验证。

    4.1. 创建 mysql 数据库和表

    添加表的代码如下:

    CREATE TABLE user_table(
    ID int NOT NULL auto_increment,
    USERNAME varchar(45) NOT NULL default ”,
    PASSWORD varchar(45) NOT NULL default ”,
    PRIMARY KEY (ID)
    )

    再添加一条记录:

    insert into user_table (USERNAME,PASSWORD) values (’test’,'test’)

    4.2. 创建 MyEclipse 数据库驱动(DB Driver)

    操作:[Menu] MyEclipse/Prefrences/MyEclipse/Database Explorer/Database Driver/DB Brower

    在 DB Brower 的菜单中选择 “New” ,”Driver Name” 项输入 “login-conn” ,”Connection URL” 项输入 “jdbc:mysql://localhost:3306/test” ,然后输入正确的用户名(User Name)和密码(Password)按实际情况输入;

    在 “Driver JARs” 项添加 “mysql-connector-java-5.0.4-bin.jar” (可从网上下载),在 “Driver classname” 里选择 “com.mysql.jdbc.Driver” ,其它自选。

    点击 “完成(Finish)”。

    4.3. 添加 Hibernate 功能支持

    操作:[Menu] MyEclipse/Project Capabilities/Add Hibernate Capabilities

    Hibernate 版本(Hibernate Specification)选择 “Hibernate 3.1″ ,开发包(libraries)选择 Hibernate 3.1 Core Libraries 一项;

    JAR Library Installation 选择 “copy checked…” ,”Library Folder” 选择 “/WebRoot/WEB-INF/lib” 。

    点击 “下一步(Next)” 设置配置文件,选择 “Spring configuration file (applicationContext.xml)” 。

    “下一步(Next)” 设置 Spring-Hibernate,选择 “Existing Spring configuration file” ,”SessionFactory ID” 项输入 “sessionFactory” 。

     

    “下一步(Next)” 创建数据源对象,在 Bean Id 中输入 dataSource,”DataSource” 项选择 “Use JDBC Dirver” ,DB Driver 项选择 “login-conn” ,其余项会自动填充;

    记得选中 “Copy DB driver jar(s) to project and add to buidpath” 项,以便将数据连接的库文件复制到项目,方便以后的布署。

    “下一步(Next)” 创建 SessionFactory 类,”Java package” 项设置为 “com.login.Hibernate” (没有则点击”New”按钮添加),”Class name” 项修改为”SessionFactory” ,Java Compliance Level选择和创建项目时选择的Java版本。(本例中并没有用到SessionFactory类,留作今后扩展)

    点击 “完成(Finish)”。

    4.4. 创建对象关系映射(ORM)的相关文件

    操作:[Menu] Window/Open Perspective/MyEclipse Database Explorer

    选中 user_table 表,点击右键,在出现的菜单中选择 “Hibernate Reverse Engnieering” 。

    在弹出的窗口中保持 “Java package” 项为 “com.login” ;

    选中 “Hibernate mapping file (*.hbm.xml) for each databases table” ,并保持 “Update hibernate…” 项选中;

    选中 “Java Data Object” 项,并保持 “Create abstract class” 选中;

    “Base persistent class” 项留空;

    取消 “Java Data Access Object…” 项和 “Use custom templates” 项。

    点击 “下一步(Next)” ,再点击 “下一步(Next)” ,在 “Configure reverse engineering details” 页选中 “user_table” 表,在右边出现的 “Class Name” 项中输入 “com.login.User”,其它不变。

    点击 “完成(Finish)”。

    完成此操作,会在 “com.login” 包下创建三个文件:AbstractUser.java、User.java、User.hbm.xml。

    4.5. 创建 UserDAO.java 接口和 UserDAOImpl.java 类

    UserDAO 和 UserDAOImpl 通过 Hibernate 访问数据库。

    UseDAO.java 内容如下:

    package com.login;

    public interface UserDAO {
    public abstract boolean isValidUser(String username, String password);
    }

    UserDAOImpl.java 内容如下:

    package com.login;

    import java.util.List;
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

    public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
    private static String hql = “from User u where u.username=? “;

    public boolean isValidUser(String username, String password) {
    // 验证用户
    List userList = this.getHibernateTemplate().find(hql, username);
    if (userList.size() > 0) {
    return true;
    }
    return false;
    }
    }

    4.6. 修改 LoginAction.java 文件

    使用 UseDAO 对象来验证:

    package com.login.struts.action;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.struts.action.Action;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionForward;
    import org.apache.struts.action.ActionMapping;
    import com.login.struts.form.LoginForm;
    import com.login.UserDAO;

    public class LoginAction extends Action {
    private UserDAO userDAO;

    public UserDAO getUserDAO() {
    return userDAO;
    }

    public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
    }

    public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) {

    LoginForm loginForm = (LoginForm) form;
    String username=loginForm.getUsername();
    String password=loginForm.getPassword();

    if( userDAO.isValidUser( username, password ) ){
    return mapping.findForward( “indexForword” );
    }else{
    return mapping.getInputForward();
    }
    }
    }

    绿色字体为修改部分。

    4.7. Spring 的最终配制文件 applicationContext.xml

    <?xml version=”1.0″ encoding=”UTF-8″?>
    <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

    <beans>

    <bean id=”dataSource”
    class=”org.apache.commons.dbcp.BasicDataSource”>
    <property name=”driverClassName” value=”com.mysql.jdbc.Driver”></property>
    <property name=”url” value=”jdbc:mysql://localhost:3306/test”></property>
    <property name=”username” value=”root”></property>
    <property name=”password” value=”root”></property>
    </bean>

    <!– 配置sessionFactory, 注意这里引入的包的不同 –>
    <bean id=”sessionFactory” class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>
    <property name=”dataSource”>
    <ref local=”dataSource” />
    </property>
    <property name=”mappingResources”>
    <list>
    <value>com/login/User.hbm.xml</value>
    </list>
    </property>
    <property name=”hibernateProperties”>
    <props>
    <prop key=”hibernate.dialect”>org.hibernate.dialect.MySQLDialect</prop>
    <prop key=”hibernate.show_sql”>true</prop>
    </props>
    </property>
    </bean>

    <bean id=”transactionManager” class=”org.springframework.orm.hibernate3.HibernateTransactionManager”>
    <property name=”sessionFactory”>
    <ref local=”sessionFactory” />
    </property>
    </bean>

    <bean id=”userDAO” class=”com.login.UserDAOImpl”>
    <property name=”sessionFactory”>
    <ref local=”sessionFactory” />
    </property>
    </bean>

    <bean id=”userDAOProxy” class=”org.springframework.transaction.interceptor.TransactionProxyFactoryBean”>
    <property name=”transactionManager”>
    <ref bean=”transactionManager” />
    </property>
    <property name=”target”>
    <ref local=”userDAO” />
    </property>
    <property name=”transactionAttributes”>
    <props>
    <prop key=”insert*”>PROPAGATION_REQUIRED</prop>
    <prop key=”get*”>PROPAGATION_REQUIRED,readOnly</prop>
    <prop key=”is*”>PROPAGATION_REQUIRED,readOnly</prop>
    </props>
    </property>
    </bean>

    <bean name=”/login” class=”com.login.struts.action.LoginAction” singleton=”false”>
    <property name=”userDAO”>
    <ref bean=”userDAOProxy” />
    </property>
    </bean>

    </beans>

    4.8. 测试

    同第一次测试。 

    posted @ 2008-07-09 14:13 飞飞 阅读(3455) | 评论 (2)编辑 收藏

    在spring2.0中,bean没有“singleton”这个属性,而是在“scope”中对它进行设定。“scope”可以设定为“singleton”和“prototype”默认情况下是“singleton”即和原先的“singleton=true”性质一样,如果要实现单例模式则将“scope”设定为“prototype”,即和原先版本的“singleton=false”一样。参考文档链接地址:http://www.springframework.org/schema/beans/spring-beans-2.0.xsd



    根据用户名和密码进行校验的方法
     public boolean verify(String userName, String userPwd) {
      final String HQL="FROM UserTable u where u.userName=? and u.userPwd=?";
      String[] hqlParameter=new String[2];
      hqlParameter[0]=userName;
      hqlParameter[1]=userPwd;
      List list=this.getHibernateTemplate().find(HQL,hqlParameter);
      if(list.size()>0){
       return true;
      }
      
      return false;
     }
    posted @ 2008-07-09 13:03 飞飞 阅读(2950) | 评论 (0)编辑 收藏

    mysql-administrator的安装与使用(图文)
      
    准备工作
    在D盘建立一个mysql-software的目录,把刚才下载的 mysql-administrator-1.0.19-win-noinstall.zip 复制到这个子目录中,解压,得到一个 MySQL Administrator 1.0 的目录。
    同样如此操作 mysql-query-browser-1.1.5-win-noinstall.zip,得到一个 MySQL Query Browser 1.1 的目录。
      
    启动服务
    ·
    双击D:mysql-softwareMySQL Administrator 1.0 目录下的 MySQLSystemTrayMonitor.exe,这时会在任务栏右侧出现一个图标。点击“Start Instance”,运行MySQL。

    ·
    然后双击 D:mysql-softwareMySQL Administrator 1.0 目录中的 MySQLAdministrator.exe,或者直接点击上面右键菜单中的“MySQL Administrator ”:

    ·
    创建一个连接名,可以随便填,这里是“mxj”,用户名:root,密码空着。这是因为mysql默认有一个没有密码的root帐号。点击“OK”,出现管理窗口:

    这没什么好说的,英文也很简单。只谈谈上面勾选的两项。
    更改密码

    好了,我的root帐号的密码设置为:javamxj    最后,点击“Apply Change”。
    ● 初始的

    数据库



    上图可以看到,初始有两个

    数据库

    ,mysql库中含有各种配置信息,不要在这个库中进行表操作。
    test库初始是空的。另外,建立表时,不要和mysql库中的表名取名相同,以免冲突。
    数据创建与查询(兼谈谈字符编码)
    ·
    现在来到查询浏览器,还是右击右下角“MySQL System Tray Monitor”图标,从中选择“MySQL Query Browser”,因为已经更改过root的密码,所以要填入新密码。

    ·
    进入主界面,右击test

    数据库

    ,创建一个新表。

    ·
    如下简单创建一个表

    ·
    切换到“Table Options”:

    如果了解

    数据库

    的话,这些应该是很熟悉的,不多说了。注意字符设置默认是“Latin1”(保存改变,再次切换到这一栏,就能看到了)。
    ·
    填入一些测试数据:

    ·
    关闭“MySQL Query Browser”,再重新打开它,切换到testtable表,看到了没有?刚才输入的中文变成了“??????”,为什么呢? 再次切换到“Table Options”:

    知道为什么了吧,原来默认字符是“latin1”,因为MySQL是瑞典一家公司的产品。中国人看来要努力了!
    ● 解决方法:
    ·
    停止MySql服务,关闭所有与MySql相关的程序,打开Windows的系统安装目录下的 my.ini 文件,如下修改:
    E:WINDOWSmy.ini

    [WinMySQLAdmin]
      
    Server

    =D:/mysql/bin/mysqld-nt.exe
      
    [mysqld]
      
    basedir
    =D:/mysql
      
    datadir
    =D:/mysql-data/data
      
    default-character-set
    =gbk
      
    [client]
      
    default-character-set
    =gbk
    添加的两条语句的含义是在客户端和服务端都使用GBK字符集进行编码。
    保存后,重新激活 MySql 服务,打开“MySQL Query Browser”,再次创建一个表,输入中文,一切OK!

    备份时会出错,以下日志:
    ----------------------------------------
    2008-07-03 14:18 - Backup started.
    Preparing backup for for profile mysql.
    Connections loaded from file C:\Documents and Settings\Administrator\Application Data\MySQL\mysqlx_user_connections.xml.
    Connection NewConnection selected.
    Cannot connect to MySQL Server. Access denied for user 'root'@'localhost' (using password: NO) (Error Number 1045)

    在mysqlx_user_connections.xml.文件中加个密码进去
    <?xml version="1.0"?>
    <user_connections>
      <last_connection>0</last_connection>
      <password_storage_type>2</password_storage_type>
      <user_connection>
        <connection_name>NewConnection</connection_name>
        <username>root</username>
        <hostname>127.0.0.1</hostname>
        <port>3306</port>
        <schema>test</schema>
        <advanced_options/>
        <storage_path></storage_path>
        <notes></notes>
        <connection_type>0</connection_type>
        <storage_type>1</storage_type>
        <password_storage_type>2</password_storage_type>
        <password>root</password>
      </user_connection>
    </user_connections>

    但是在备份的时候还是会出现错误

    根据提示选择open options 选择 password storage
    OK
    电脑每次自己启动MySQLSystemTrayMonitor 就会在定制的时间备份数据库

    Your account information:
    Name: fei zhao
    Email: feifeixia2003@yahoo.com.cn
    Password: nehaifrowa
    You can log in to your new account and edit your profile options at:
      http://www.mysql.com/login.php
    posted @ 2008-07-03 13:54 飞飞 阅读(10016) | 评论 (1)编辑 收藏

    http://www.net.cn/static/customercare/support/demo/outlook/outlook.htm
    fei.zhao@centralsoft.com.cn
    211.155.226.126
    posted @ 2008-07-02 09:22 飞飞 阅读(960) | 评论 (0)编辑 收藏

    有些事情现在已经很容易被忘记了,但是在开发原创的 Mac OS 的时候,业界到处出现新的图形用户接口(GUI),人们所做的工作差别相当小。Macintosh 的设计团队在很多事情上是正确的,这很大程度上是因为他们在自己正在干什么这个问题上付出了难以想像的思考。虽然我要为 Internet Developer(英特网开发者)书写一些脚本方面的集体思想,但我还是想去看一些过去的 Macintosh 人机界面指南,并且看看这些指导原则如何才能用到 Web 界面上,我认为这是很值当的。我很少去找可以拷贝的具体部件,而更多地寻找这个以友好闻名的界面后面隐藏的设计原则。

    原则之一就是无模式。这个原则打动了我,因为它特别适合于 Web。正如 Mac 的设计者描述的那样,模式界面(在这种界面下,您能做什么取决于您当前处于什么模式下)会“把用户锁定在一个操作上,用户在该操作完成之前不允许进行其它任何操作”。使用单纯的老版本HTML时,从某种意义上看,所有界面都是模式的,进行任何修改都需要装载一个新的页面。举例来说,假定您在填充一个表单时需要一些帮助,则您必须转到包含帮助信息的新页面,然后再回到原来的页面,以完成表单的填写。

    换句话说,您或者处于“帮助”模式,或者处于“表单填写”模式。这凸显了 Web 的两个主要的限制:无态(即当点击帮助连接时,您在表单中已经输入的信息将会丢失)和迟延(即您必须等待页面装载)。因此我决定写一点脚本来帮助处理这些问题。这些脚本通过动态 HTML (DHTML)技术在您点击连接时弹出一个带有帮助信息的方框。在我的演示中,就是使用它们来弹出与表单填写相关的上下文帮助信息。这些脚本也可以用在别的地方,比如弹出一篇论文的术语定义。上述的两种情况都以合理的方式给出了上下文相关的信息,即无模式的方式。同时,这个解决方案也避免了无态和迟延的问题。

    实际上,我写的这些基本函数可以用在任何需要在页面上移动和改变对象可视性的地方。我做了一个快速下拉菜单的实例,就是为了演示同样这些代码的另外一种使用方式,您可能会用得到。

    您可能会担心有人还在使用版本比较老的浏览器,对此,我们可以相当轻松地使这些脚本自然地回退到原来的状态,使那些使用老版本浏览器的用户可以简单地从一个单独的页面上获得信息。我将在下面的“如何使用脚本”的部分中解释如何实现这个目标。

    脚本的目标

    这个脚本将创建动态菜单和弹出式对象。它包括一些跨浏览器的基本函数,用于移动和改变DHTML对象的可视性。在 Netscape 4.x 中,一个 DHTML 对象是一个通过绝对位置定位的 DIV,而对 Safari,Internet Explorer 4 和 5,或者 Netscape 6 来说,则是任何 HTML 元素。这些函数可以被用在大量的 DHTML 应用中;这里还给出的两个实例,向您演示如何创建一个弹出式的提示(tip)和下拉式菜单。脚本中的主要函数如下:

    • changeObjectVisibility,用来翻转一个 DHTML 对象的可视性。
    • moveObject,用来在浏览器窗口中把一个 DHTML 对象移动到特定的位置上。
    • getStyleObject,这个函数通过获得一个风格对象的引用简化了跨浏览器的 DTHML,我们可以从这个对象中读取属性,或者进行属性设定,包括位置,可视性,颜色,尺寸,等等。

    编码的挑战

    遗憾的是,由于长期以来浏览器都是由各个厂商自行实现,所以书写跨浏览器和跨平台的 DHTML 通常是拜占庭式的条件分支。为任何一个浏览器书写这些脚本都是非常轻松的;为了使它们工作在 Netscape 4 及其升级版本,以及工作在 Internet Explorer 4 及其升级版本上,事情就要复杂一些了;而使它们可以回退到比较老版本的浏览器的状态,又增加了更多的复杂度。问题在于各个浏览器在如何寻找和操作 Web 页面上的对象方面都有很多独特之处,虽然我们对这种状态已经比较熟悉了。为了方便,我写了处理这些条件分支的代码。

    这些函数中有一些功能不能工作在更老一些的浏览器上,比如 Netscape 3。然而,使这些功能自然地退化并补台困难。您只需进行如下操作:

    • 直接把这些脚本包含在页面上,而不是使用连接的 .js 文件。
    • 只在提供相关支持的浏览器上使用 JavaScript 进行弹出式的 DIV 的输出。实现这个控制的代码大致如下:
      if(document.getElementById || document.all
          || document.layers) {
          // write out div tag with document.write
          }

    我发现的最大挑战是必须考虑浏览器处理事件的不同方式。事件发生时(比如 click 或者 mouseover 事件)光标的位置存储在一个事件对象中,而不同浏览器对事件对象的处理有轻微的不同。当事件发生时,Netscape 4 和6都产生一个新的事件对象,您可以把这个对象作为一个参数传递到函数中;而 Internet Explorer 则使用一个独立的全局 window.event 对象。对于这个问题,我在抛弃几个现在看来很草率的解决方案之后,发现把事件对象显式地传递给函数的做法可以适用于这两种浏览器:

    <a href="#" onclick="showPopup('popupName',
    event);">click</a>

    请注意,在事件边上少了引号标识。那是因为它是一个对象,而不是文本。现在,在您的函数中就可以以如下方式使用传入的事件对象了:

    function showPopup(nameOfPopup, eventObject) {
    alert(eventObject.clientX);
    }

    一旦把对象传递给函数,您就可以通过读取 pageXpageY 属性(Netscape 4 和 6)或者 clientXclientY 属性(IE 4+)来获得光标的位置。然而请注意,clientXclientY 属性并没有考虑页面可能被滚动的情况,因为这两个坐标是相对于窗口的左上角的,而不是整个文档。为了解决这个问题,我们加上 IE 的 document.body.scrollLeft document.body.scrollTop 属性的值。如果您感兴趣的话,事件对象还有一连串有用的属性,包括一个事件触发对象的引用(在 IE 上是 srcElement,而在 Netscape 上则是 target)。

    把事件对象作为参数进行传递的唯一麻烦是在不支持事件对象的老版本浏览器上不能工作。为了绕开这个问题,我们在 popup.js 文件中包含一个函数,该函数为那些不存在事件对象的浏览器创建一个假的对象,在装载文档时运行:

    function createFakeEventObj() {
    // create a fake event object for older browsers
    //to avoid errors in function call when we
    //need to pass the event object
    if (!window.event) {
    window.event = false;
    }
    }

    这个函数把 window.event 设定为 false(假)。这样以后,我们就可以在使用之前进行检测,看看是否存在真正的事件对象。

    在 Mac 版的 Internet Explorer 5 上有一个问题,即当弹出层出现在文本的上方时,只有部分内容可以被显示。但是当我移动 DIV 标识,使之成为文档体的第一个元素时,这个问题神秘地消失了。

    还是在 Mac 版的 IE 5 上,由于某些原因,document.onclick 事件只有在页面上存在实际文本时才能被触发。为了绕过这个缺陷(以便使您可以通过点击窗口中的任意位置来关闭窗口),我在页面中增加了一个不包含任何内容的,通过绝对位置定位的 DIV,然后用 JavaScript 来改变这个 DIV 的尺寸,使之覆盖整个窗口。相关的代码大致如下:

    function resizeBlankDiv() {
    // resize blank placeholder div so IE 5
    // on mac will get all clicks in window
    if ((navigator.appVersion.indexOf('MSIE 5') != -1)
    && (navigator.platform.indexOf('Mac') != -1)
    && getStyleObject('blankDiv')) {
    getStyleObject('blankDiv').width =
    document.body.clientWidth - 20;
    getStyleObject('blankDiv').height =
    document.body.clientHeight - 20;
    }
    }

    遗憾的是,如果浏览器的尺寸被改变了,则只有一种方法可以恢复尺寸,即重新装载整个文档(您可能认为,只要用 window.onresize 事件就可以了。然而由于这个事件在窗口的尺寸真正被改变之前就已经发生了,所以采用这种方法最终会产生不必要的滚动条)。为了恢复页面尺寸,我们又写了一个函数,在窗口尺寸被改变的任何时候,该函数可以从 Mac 平台上的 IE5 的缓存中重新装载页面。

    在 Mac 版的 Internet Explorer 5 上,当您点击一个连接时,会出现一个绝对大的轮廓,这个轮廓会和将要弹出的内容相重叠。为了解决这个问题,我在连接上增加了一条风格规则:

    .popupLink { outline: none }

    Netscape 4 在 DIV 的命名上有一些怪异的问题。以数字开头的名称(比如“1div”),以及有些带有下划线的名称(比如“my_div”)不能转化为层,因此我通常都避免这两种情况,把我的 DIV 按类似于 myDiv 或者 div1 的形式来命名。

    Netscape 4 还有一个严重的缺陷,即当窗口的尺寸被改变时,所有的风格规则都会丢失。我没有把修复这个缺陷的代码包含进来,因为已经有好几个这样的代码公布出来了,比如 Webmonke 上的这个.

    最后,在 Netscape 4 中,如果您把 javascript: 放在 hrefs 中,会导致页面的重新装载,并把函数的返回值当成页面的唯一内容显示出来。因此我们不应该采取下面的方式:

    <a href="javascript:myFunction();">clickme</a>

    而必须采取象下面的做法:

    <a href="#" onclick="myFunction();
    return false;">clickme</a>

    实际上,这也是确保您的脚本在不能运行这些函数的浏览器上自然退化的好方法。请注意“return false”这行代码,它使浏览器停止装载 href 参数指定的URL。这样,如果浏览器中 JavaScript 被关闭,或者浏览器不能处理 JavaScript,则您可以提供一个不同的页面;但是如果这里的函数可以运行,则连接不会被打开。

    在这个演示中,我们讨论的更深一些:

    <a href="#" onclick="return
    !showPopup('nameFieldPopup', event);">
    clickme</a>

    我们不去深入到所有的细节,只是大概看看这行代码,它的意思是运行 showPopup 函数,然后返回该函数返回值的非。那样,如果 showPopup 返回 true(意思是它成功显示了弹出层),我们就把 false 返回给连接,这样连接就不会改变页面。另外一方面,如果 showPopup 返回 false(意思是它不能显示弹出层),则我们就继续执行脚本,跟着连接进入到一个独立的页面,该页面具有和弹出层相同的信息。这个逻辑看起来可能有点混淆,但是只要记住一条就可以了:如果您返回 false,连接就不起作用了。

    使用脚本

    如果要使用这些脚本来实现弹出机制,请按照如下这些步骤来进行:

    • 如果要进行层的弹出,则需要把层工具和实现弹出机制的脚本文件都包含进您的页面。这可以通过把下面两条语句包含到您的文档头部来实现:
       <script src="utility.js"></script>
          <script src="popup.js"></script>
    • 确保有可以被弹出的 DIV。这些 DIV 必须被绝对定位,并且在开始是应该被隐藏。例如:
      <DIV onclick="event.cancelBubble = true;"
          class=popup id=nameOfPopup>
          Popup text goes here.<br>
          <a href="#" onclick="hideCurrentPopup();
          return false;">
          You can include a link like this to
          close the DIV if you like
          </a>
          </DIV>
      确保在DIV中包含onclick="event.cancelBubble = true;"这行代码。它告诉JavaScript在您点击DIV时不要把点击事件传递给页面中的其它对象。如果省略这行代码,则弹出层在被点击时就会关闭(对于大多数浏览器来说),因为我们已经设定了一个关闭弹出层的事件处理函数。把这行代码包含到页面中的基本目的是告诉浏览器“当人们点击除了弹出层自身(或者打开弹出层的原始连接)之外的任何地方时,关闭弹出层”。
    • 如果要改变弹出层的外观,请编辑风格表单中的.popup的风格规则。
    • 在每一个应该触发弹出层的地方调用showPopup函数,把nameOfPopup改为您希望显示的弹出层名称(但是把它放在单引号中):
      <a href="http://url.for.older.browsers"
          onclick="return !showPopup
          ('nameOfPopup', event);">
          clickme</a>
      如果您希望当鼠标在连接上滚动时出发弹出层,则只要修改触发事件就可以了:
      <a href="http://url.for.older.browsers"
          onmouseover="showPopup('nameOfPopup', event);"
          onmouseout="hideCurrentPopup();">clickme
          </a>
    • (可选)修改popup.js文件中的两个变量,这两个变量用来控制弹出层出现的位置,该位置是相对于当前光标位置的:
      var xOffset = 30;
          var yOffset = -5;

    下面对相关的函数逐一进行说明:

    • changeObjectVisibility(objectId, newVisibility):调用这个函数时,objectId 应该是您希望显示或者隐藏的对象名称。函数希望这个参数是文本类型的,因此您需要把它包含在引号中。newVisibility 参数的值或者是 visible(可视)或者是 hidden(隐藏)。再次说明一下,这个值是一个字符串类型的,因此需要把它包含在引号中。下面这个实例把一个名为 myBigLayer: 的对象隐藏起来:
      changeObjectVisibility('myBigLayer', 'hidden')
    • moveObject(objectId, newXCoordinate, newYCoordinate):同样的,objectId 应该是您希望移动的对象名称。它是一个文本类型的参数,因此应该放在引号里面。newXCoordinatenewYCoordinate a 是数字类型的(因此没有引号),描述您希望把对象移动到什么地方。因此,如果要把 myBigLayer 对象移动到距离窗口左边 300 p 像素,距离窗口上边10像素的位置,书写如下代码就可以了:
      moveObject('myBigLayer', 300, 10)
    • getStyleObject(objectId):上述两个函数都使用这个函数来把对象的名称转变为属于该对象的风格对象的引用。对于 Netscape 4+ 和 IE 4+ 两款浏览器来说,这个函数都能返回正确的引用,因此您不必担心浏览器在工作方式上的差别。(请注意:有一种情况在 Netscape 4 上处理不了,那就是聚集层,因此您必须避免把层放到其它层上)。

      在您需要改变对象的 CSS 属性的任何时候,您都可以脱离这里描述的上下文来使用这个函数。例如,假定我们要给 myBigLayer 设定一个绿的背景色,可以书写如下代码:

      ar myBigLayerStyleObject =
          getStyleObject('myBigLayer');
          myBigLayerStyleObject.backgroundColor =
          'green';

      Or, for shorthand, you could just do this:

      getStyleObject('myBigLayer').backgroundColor
          = 'green';






      utility.txt

      // Copyright ?2000 by Apple Computer, Inc., All Rights Reserved.
          //
          // You may incorporate this Apple sample code into your own code
          // without restriction. This Apple sample code has been provided "AS IS"
          // and the responsibility for its operation is yours. You may redistribute
          // this code, but you are not permitted to redistribute it as
          // "Apple sample code" after having made changes.
          //
          // ************************
          // layer utility routines *
          // ************************
          function getStyleObject(objectId) {
          // cross-browser function to get an object's style object given its id
          if(document.getElementById && document.getElementById(objectId)) {
          // W3C DOM
          return document.getElementById(objectId).style;
          } else if (document.all && document.all(objectId)) {
          // MSIE 4 DOM
          return document.all(objectId).style;
          } else if (document.layers && document.layers[objectId]) {
          // NN 4 DOM.. note: this won't find nested layers
          return document.layers[objectId];
          } else {
          return false;
          }
          } // getStyleObject
          function changeObjectVisibility(objectId, newVisibility) {
          // get a reference to the cross-browser style object and make sure the object exists
          var styleObject = getStyleObject(objectId);
          if(styleObject) {
          styleObject.visibility = newVisibility;
          return true;
          } else {
          // we couldn't find the object, so we can't change its visibility
          return false;
          }
          } // changeObjectVisibility
          function moveObject(objectId, newXCoordinate, newYCoordinate) {
          // get a reference to the cross-browser style object and make sure the object exists
          var styleObject = getStyleObject(objectId);
          if(styleObject) {
          styleObject.left = newXCoordinate;
          styleObject.top = newYCoordinate;
          return true;
          } else {
          // we couldn't find the object, so we can't very well move it
          return false;
          }
          } // moveObject
          
      popup.txt
      // Copyright ?2000 by Apple Computer, Inc., All Rights Reserved.
          //
          // You may incorporate this Apple sample code into your own code
          // without restriction. This Apple sample code has been provided "AS IS"
          // and the responsibility for its operation is yours. You may redistribute
          // this code, but you are not permitted to redistribute it as
          // "Apple sample code" after having made changes.
          // ********************************
          // application-specific functions *
          // ********************************
          // store variables to control where the popup will appear relative to the cursor position
          // positive numbers are below and to the right of the cursor, negative numbers are above and to the left
          var xOffset = 30;
          var yOffset = -5;
          function showPopup (targetObjectId, eventObj) {
          if(eventObj) {
          // hide any currently-visible popups
          hideCurrentPopup();
          // stop event from bubbling up any farther
          eventObj.cancelBubble = true;
          // move popup div to current cursor position
          // (add scrollTop to account for scrolling for IE)
          var newXCoordinate = (eventObj.pageX)?eventObj.pageX + xOffset:eventObj.x + xOffset + ((document.body.scrollLeft)?document.body.scrollLeft:0);
          var newYCoordinate = (eventObj.pageY)?eventObj.pageY + yOffset:eventObj.y + yOffset + ((document.body.scrollTop)?document.body.scrollTop:0);
          moveObject(targetObjectId, newXCoordinate, newYCoordinate);
          // and make it visible
          if( changeObjectVisibility(targetObjectId, 'visible') ) {
          // if we successfully showed the popup
          // store its Id on a globally-accessible object
          window.currentlyVisiblePopup = targetObjectId;
          return true;
          } else {
          // we couldn't show the popup, boo hoo!
          return false;
          }
          } else {
          // there was no event object, so we won't be able to position anything, so give up
          return false;
          }
          } // showPopup
          function hideCurrentPopup() {
          // note: we've stored the currently-visible popup on the global object window.currentlyVisiblePopup
          if(window.currentlyVisiblePopup) {
          changeObjectVisibility(window.currentlyVisiblePopup, 'hidden');
          window.currentlyVisiblePopup = false;
          }
          } // hideCurrentPopup
          // ***********************
          // hacks and workarounds *
          // ***********************
          // initialize hacks whenever the page loads
          window.onload = initializeHacks;
          // setup an event handler to hide popups for generic clicks on the document
          document.onclick = hideCurrentPopup;
          function initializeHacks() {
          // this ugly little hack resizes a blank div to make sure you can click
          // anywhere in the window for Mac MSIE 5
          if ((navigator.appVersion.indexOf('MSIE 5') != -1)
          && (navigator.platform.indexOf('Mac') != -1)
          && getStyleObject('blankDiv')) {
          window.onresize = explorerMacResizeFix;
          }
          resizeBlankDiv();
          // this next function creates a placeholder object for older browsers
          createFakeEventObj();
          }
          function createFakeEventObj() {
          // create a fake event object for older browsers to avoid errors in function call
          // when we need to pass the event object to functions
          if (!window.event) {
          window.event = false;
          }
          } // createFakeEventObj
          function resizeBlankDiv() {
          // resize blank placeholder div so IE 5 on mac will get all clicks in window
          if ((navigator.appVersion.indexOf('MSIE 5') != -1)
          && (navigator.platform.indexOf('Mac') != -1)
          && getStyleObject('blankDiv')) {
          getStyleObject('blankDiv').width = document.body.clientWidth - 20;
          getStyleObject('blankDiv').height = document.body.clientHeight - 20;
          }
          }
          function explorerMacResizeFix () {
          location.reload(false);
          }
          
      弹出式帮助的实例

      <HTML><HEAD>

      <script src="utility.txt"></script>

      <script src="popup.txt"></script>


      <STYLE>

      .popupLink { COLOR: red; outline: none }

      .popup { POSITION: absolute; VISIBILITY: hidden; BACKGROUND-COLOR: yellow; LAYER-BACKGROUND-COLOR: yellow; width: 200; BORDER-LEFT: 1px solid black; BORDER-TOP: 1px solid black; BORDER-BOTTOM: 3px solid black; BORDER-RIGHT: 3px solid black; PADDING: 3px; z-index: 10 }

      </STYLE>


      <BODY bgcolor="#ffffff">


      <!-- keep the popup divs as the first things on the page or else MSIE 5 on the mac sometimes has trouble rendering them on top of text -->

      <DIV onclick='event.cancelBubble = true;' class=popup id=nameFieldPopup>Hi, [your name here]! We need to know your <b>name</b> so we can address you a bit more personally. [<a class=closeLink href='#' onclick='hideCurrentPopup(); return false;'>close this tip</a>]</DIV>

      <DIV onclick='event.cancelBubble = true;' class=popup id=emailFieldPopup>Well, yeah, you could put in a fake <b>email address</b>, but then we couldn't send you occasional updates. Oh and, um, we promise not to spam you. [<a class=closeLink href='#' onclick='hideCurrentPopup(); return false;'>close this tip</a>]</DIV>


      <!-- begin body of document -->

      <form>
          <p>Fill in the form:</p>


          <P>Name: <input type=text> [<a href="non_js_help.html" class=popupLink onclick="return !showPopup('nameFieldPopup', event);">help</a>]</P>
          <P>Email: <input type=text> [<a href="non_js_help.html" class=popupLink onclick="return !showPopup('emailFieldPopup', event);">help</a>]</P>
      </form>

       


      <!-- leave this blank div in here to make sure you can click anywhere on the document for MSIE 5 mac -->
      <div id="blankDiv" style="position: absolute; left: 0; top: 0; visibility: hidden"></div>


      </BODY></HTML>
      http://www.apple.com.cn/developer/internet/webcontent/hideshow_layer.html









    posted @ 2008-06-24 17:30 飞飞 阅读(855) | 评论 (0)编辑 收藏

       在怎合struts+hibernate+spring时,Tomcat出现了Error Listenerstart错误码,郁闷的很,在网上找了很多的资料,提问的不少,但都没有很标准的解释以用解决的办法,有的说是jar包的版本冲突,有的说是Tomcat的自身问题,各解释都有,基本上所有的方法我都试过了。就这个问题搞了两天。终于找到了解决的办法:在web.xml时将:

    <!-- 使用监听方式载入Spring上下文 -->
    <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    改为:

    <!-- 使用监听方式载入Spring上下文 -->
    <servlet>
       <servlet-name>SpringContextServlet</servlet-name>
       <servlet-class>
        org.springframework.web.context.ContextLoaderServlet
       </servlet-class>
       <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
       <servlet-name>SpringLog4jConfigServlet</servlet-name>
       <servlet-class>
        org.springframework.web.util.Log4jConfigServlet
       </servlet-class>
    </servlet>
    <servlet>
       <servlet-name>web</servlet-name>
       <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
       </servlet-class>
    </servlet>

    posted @ 2008-06-22 11:46 飞飞 阅读(7551) | 评论 (1)编辑 收藏

    一、在Myeclipse软件中部署

    1、 Myeclipse中,创建好工程后,在Myeclipse菜单栏中选择 Windows -> Preferences -> Myeclipse -> Tomcat5,选择"Enable";Tomact Home Directory要选择你机器上Tomcat所安装的目录。然后,再Windows -> Preferences -> Myeclipse -> Tomcat5 ->JDK,确保这个是有对应的jdk版本,若没有,则通过"Add"添加其安装路径。ok

    2、选择工具栏上的 按钮,在”Project”中选择你要部署的工程,然后”Add”,再选择”Tomcat”Finish

    3、 在工具栏上选择 ,启动Tomcat

    4、 运行程序。在IE中输入http://localhost:8080/aa/WebRoot/index.jsp(aa为工程名字)

    二、在Tomcatserver.xml配置文件中部署

    1、在Tomcat下,找到conf文件下的server.xml,打开。

    2、在<Host></host>之间加上如下代码:

    1 
    2 <Context path="/虚拟目录名" docBase="目标目录位置" debug="0" reloadable="true" >
    3 </Context>

    (严格区分大小写,当path=""时,此时的虚拟目录直接为root--->http://localhost:8080/)
           
    参数:

             path:表示在浏览器中输入http://localhost:8080/虚拟目录名

             docBase:表示你的程序包的物理绝对路径,默认的绝对路径是     %tomcat_home%/webapps

             reloadable :为true,则tomcat会自动检测应用程序的/WEB-INF/lib /WEB-INF/classes目录的变化,自动装载新的应用程序,我们可以在不重起tomcat的情况下改变应用程序;为false则不自动加载。

     (我觉得这种部署方法就好在这里,可以不用重新启动Tomcat。不知道前一种方法是不是在哪个地方进行配置即可实现同样的效果。若有,请高人指点!)

    示例:

    1        
    2 <!-- 我的自定义目录-->
    3 <Context path="/wess" debug="0" docBase="C:\Documents and Settings\tt\workspace\Welcome_SS\WebRoot" reloadable="true">
    4 </Context> 
    5 4

    3、 启动Tomcat

    Myeclipse工具栏上选择 ,启动Tomcat。或者在Tomcat下,找到bin文件下的startup.bat,打开进行启动。

    4、 运行程序。在IE地址中输入http://localhost/wess/index.jsp(引用上面示例配置时的情况)

    附:

        在lib下的struts-config.xml可以添加下面三句进行主页默认的配置,即在IE中只需输入到主页所在目录,而不必写出主页。如上面的配置就可只输入http://localhost/wess

     <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

     

    posted @ 2008-06-22 09:07 飞飞 阅读(386) | 评论 (1)编辑 收藏

    为你的数据库属性hibernate.dialect设置正确的 org.hibernate.dialect.Dialect子类. 如果你指定一种方言, Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫.

    表 4.8.  Hibernate SQL方言 (hibernate.dialect)
    RDBMS 方言
    DB2 org.hibernate.dialect.DB2Dialect
    DB2 AS/400 org.hibernate.dialect.DB2400Dialect
    DB2 OS390 org.hibernate.dialect.DB2390Dialect
    PostgreSQL org.hibernate.dialect.PostgreSQLDialect
    MySQL org.hibernate.dialect.MySQLDialect
    MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
    MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
    Oracle (any version) org.hibernate.dialect.OracleDialect
    Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
    Sybase org.hibernate.dialect.SybaseDialect
    Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
    Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
    SAP DB org.hibernate.dialect.SAPDBDialect
    Informix org.hibernate.dialect.InformixDialect
    HypersonicSQL org.hibernate.dialect.HSQLDialect
    Ingres org.hibernate.dialect.IngresDialect
    Progress org.hibernate.dialect.ProgressDialect
    Mckoi SQL org.hibernate.dialect.MckoiDialect
    Interbase org.hibernate.dialect.InterbaseDialect
    Pointbase org.hibernate.dialect.PointbaseDialect
    FrontBase org.hibernate.dialect.FrontbaseDialect
    Firebird org.hibernate.dialect.FirebirdDialect

    posted @ 2008-06-19 23:33 飞飞 阅读(172) | 评论 (0)编辑 收藏

    Oracle导入excel数据方法汇总
    摘要:在程序编制过程和数据汇总交换过程中,经常会碰到需要将其他人员在office办公环境下编制的文件数据内容导入oracle中的情况。目前程序开发者经常使用的方法有如下几种:1,使用oracle提供的导入工具sql*loader;2,使用plsql developer工具;3使用其他数据转移工具做中转站。下面我们采用实例的方式分别描述几种导入方式的优缺点及其操作步骤。假设‘e:\test.xls’文件中存在三列数据分别代表客户编号,客户名称和联系电话。其内容如下:
    10001
    zjaxi01
    13562485246
    10002
    zjaxi02
    13562485247
    10003
    zjaxi03
    13562485248
    10004
    zjaxi04
    13562485249
    10005
    zjaxi05
    13562485250
    10006
    zjaxi06
    13562485251
    10007
    zjaxi07
    13562485252
    10008
    zjaxi08
    13562485253
    10009
    zjaxi09
    13562485254
    10010
    zjaxi10
    13562485255
    10011
    zjaxi11
    13562485256
    10012
    zjaxi12
    13562485257
    10013
    zjaxi13
    13562485258
    10014
    zjaxi14
    13562485259
    使用sql *loader
    SQL*LOADER是oracle的数据加载工具,在NT下sql*loader的命令为SQLLDR,在UNIX下一般为SQLLDR/SQLLOAD。通常用来将操作系统文件迁移到oracle数据库中。它是大型数据仓库选择使用的加载方法,因为它提供了最快速的途径(direct,parallel)。但这种方法要求存储数据的oracle表是已经存在的。
    使用这种方法导入excel内容到oracle时,首先需要将excel文件另存为文本格式,文件类型选文本类型或者csv类型即将e:\test.xls另存为e:\test.csv。
    如果oracle没有对应存储数据的表结构,则需要创建表test(id,name,telphone)。
    用记事本创建sql*loader控制文件test.ctl(ctl后缀是企图证明这是一个控制文件,但实际上这个文件后缀不重要,用户可以自由选择,但文件格式一定要是文本格式),内容如下:
    Load data
    Infile ‘e:\test.csv’          --数据源文件名称
    Append|insert|replace       --append在表后追加,insert插入空表,replace替代原有内容
    Into table test            --要导入的数据库表名称
    [when id = id_memo]     --过滤条件
    Fields terminated by X’09’ --字段分隔符
    (id,name,telphone)        --字段名称列表
    最后在命令窗口输入sqlldr命令行执行导入操作Sqlldr userid = system/manager control=’e:\test.ctl’
    Sqlldr的函数关键字说明:
    Userid   --oracle用户名 userid = username/password
    Control --控制文件名称 control = ‘e:\insert.ctl’
    Log     –-日志文件名称 log = ‘e:\insert.log’
    Bad     --损坏文件名称
    Data     --data file name
    Discard    --discard file name
    Discardmax --number of discards to allow(默认全部)
    Skip       --导入时跳过的记录行数(默认0)
    Load       --导入时导入的记录行数(默认全部)
    Errors    --允许错误的记录行数(默认50)
    使用plsql developer
    PL/SQL Developer是一种专门用于开发、测试、调试和优化oracle PL/SQL存储程序单元,比如触发器,存储过程,函数和程序包等集成开发环境。
    在单个文件数据不多(小于10w行),并且目的表结构已经存在的情况下可以使用plsql developer工具将excel内容直接通过简单的copy,paste操作导入oracle数据库。具体操作方式如下:
    l         在plsql developer的sql window里输入select * from test for update,其中test是要导入的oracle数据表名称;
    l         执行查询(通过点击按钮或者快捷键F8可以实现);
    l         点击查询结果上面的锁状按钮,使得查询到的内容处于编辑状态。
    l         从excel数据表中copy(ctrl +C)要导入oracle中的数据,如果是单列数据导入,可以先按plsql developer中查询结果上面的“添加(+)”按钮,使得数据表处于添加数据状态,然后将鼠标在plsql developer的列名称上单击,最后使用快捷键ctrl + v 完成数据导入操作,并单击plsql developer中的“提交(对号)”按钮提交所做的修改。
    l         如果是同时导入所有列,首先选择copy所有数据,然后点增加(+)并点击编辑那一行最前面的星号使得整行数据都处于被选择状态,最后paste即可将数据导入。
    l         如果分列导入数据,则需要逐列完成,首先选择copy要导入的数据,然后然后点增加(+)并点击编辑那一列的名称,使得整列数据都处于被选择状态,最后paste即可将数据导入。
    使用PLSQL developer执行数据的导入和导出操作主要存在的问题是在大数据量情况下对中文数据可能出错,估计将接收数据表的类型定义为nvarchar2的类型会比较好一点。另外,就是这种方法需要人工更多的参与,不能达到自动导入的效果。
    使用sql server中转
        这部操作执行时,需要先用sqlserver的导入导出工具将excel内容导入sqlserver数据库中,然后使用同样的工具将sqlserver中转内容导入oracle数据库,这里需要两次的数据复制与IO操作,效率相对是比较低的。并且根据csdn网友jkflyfox的描述,这种方式下需要将oracle文件的名称全部大写,否则会出错。
     
    posted @ 2008-06-16 15:17 飞飞 阅读(537) | 评论 (0)编辑 收藏

    实现的功能:

    每隔一分钟自动向getSysDate表中插入当前的系统时间。

    一、创测试表

    create table getSysDate(test date);

    二、创要定时执行的存储过程

    create or replace procedure insertSysDate as

    begin

    insert into getSysDate values (sysdate);

    end ;

    三、创建JOB,即创建待执行的定时任务过程

    variable job1 number;

    begin

    dbms_job.submit(:job1,'insertSysdate;',sysdate,'sysdate+1/1440');

    end;

    四、启动JOB,即启动并运行定时任务过程

    begin

    dbms_job.run(:job1);

    end;

    五、查看运行效果

    select to_char(test,'yyyy/mm/dd hh24:mi:ss') from getSysDate;

    结果如下:

    2007/08/03 10:53:11

    2007/08/03 11:05:51

    部分重点参数补充说明:

    DBMS_JOB.SUBMIT(:jobno,//job号

    'your_procedure;',//要执行的过程

    trunc(sysdate)+1/24,//下次执行时间

    'trunc(sysdate)+1/24+1'//每次间隔时间

    );

    删除job:dbms_job.remove(jobno);

    修改要执行的操作:job:dbms_job.what(jobno,what);

    修改下次执行时间:dbms_job.next_date(job,next_date);

    修改间隔时间:dbms_job.interval(job,interval);

    停止job:dbms.broken(job,broken,nextdate);

    启动job:dbms_job.run(jobno);

    修改job_queue_processes的值:(保证其不为0否则JOB不自动运行)

    可通过select * from v$parameter;查看其值;

    或者直接用show parameter job_queue_processes;查看如下:

    NAME TYPE VALUE

    --------------- ----------- ------------

    job_queue_processes integer 10

    方法1.startup pfile='C:oracleora90databaseinitorcl.ora';

    //这个方法用来修改initorcl.ora文件的job_queue_processes参数,然后重新启动数据库

    方法2.alter system set job_queue_processes=10

    //这个方法不用重启数据库就可以生效,系统自动修改init.ora文件以后即可生效 。

    posted @ 2008-06-16 12:07 飞飞 阅读(384) | 评论 (0)编辑 收藏