176142998

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

2011年4月21日 #

官网地址
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 飞飞 阅读(1017) | 评论 (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 飞飞 阅读(679) | 评论 (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 飞飞 阅读(538) | 评论 (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 飞飞 阅读(7737) | 评论 (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 飞飞 阅读(511) | 评论 (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 飞飞 阅读(1054) | 评论 (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 飞飞 阅读(865) | 评论 (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 飞飞 阅读(946) | 评论 (0)编辑 收藏