<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>魔力猫咪</title>
    <description></description>
    <link>http://wlmouse.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>简单解决CHM文件无法在XP环境下阅读</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/185863" style="color:red;">http://wlmouse.javaeye.com/blog/185863</a>&nbsp;
          发表时间: 2008年04月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　猫咪以前就很少从网上下载CHM格式的电子书。因为很多都莫名其妙的无法在XP环境下打开。但是有一些却可以正常打开。 <br />　　猫咪也在网上看到有人通过修改注册表来解决这个问题。不过猫咪觉得这么做对系统安全不好。猫咪不是注册表专家，不知道这几行到底代表了什么，所以能不改就不改。 最近又从网上下载了JQuery的文档，也是CHM的。发现同样无法打开。 <img style="float: left;" src="../../../upload/attachment/21536/0278b1f4-3e0d-3d11-bbb3-33111c4eb080.jpg" alt="" width="813" height="493" /><br />　　</p>
<p>　　猫咪找了半天，没有找到PDF格式的。难道只能修改注册表吗？猫咪无聊的查看这个CHM文件的属性的时候，发现有这么一个按钮&ldquo;解除锁定&rdquo;。 <br /><img src="../../../upload/attachment/21534/0be612d6-a2d4-3bb9-a350-6e87f528675c.jpg" alt="" width="369" height="474" /></p>
<p>　　这是什么？猫咪尝试着按下了&ldquo;解除锁定&rdquo;，然后点击&ldquo;应用&rdquo;。按钮和边上的安全提示消失了。当猫咪再次尝试打开文件的时候，CHM文件可以正常显示了。 <br /><img src="../../../upload/attachment/21532/b97f7482-dc36-31b3-a871-fd4cf31033d1.jpg" alt="" />　　　　　　在此猫咪把这个技巧写出来，让大家不用用改注册表等高危方式就可以阅读原来不能阅读的CHM文件。不过这种修改只限于这个CHM文件本身。如果你拿来一个别的不能打开的CHM文件，你也同样需要解除锁定。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/185863#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Apr 2008 13:20:06 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/185863</link>
        <guid>http://wlmouse.javaeye.com/blog/185863</guid>
      </item>
          <item>
        <title>Restlet第一个Resource（翻译）</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/184083" style="color:red;">http://wlmouse.javaeye.com/blog/184083</a>&nbsp;
          发表时间: 2008年04月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          猫咪继续翻译Restlet教程。看了这篇文章，应该对Restlet框架有所了解。<br /><br />Restlet第一个Resource<br />目录<br />这篇文章说明Resource如何处理GET，POST，PUT和DELETE方法。<br />1.引言<br />2.例子应用<br />3.实现Items Resource<br />4.实现Item Resource<br />5.实现Base Resource<br />6.运行应用<br />7.客户端应用<br />8.结尾<br /><br />引言<br />在开始开发前，我们需要简单介绍一下Restlet框架的Resource概念。REST告诉我们，Resource根据URL进行辨认，同时能够有一种或多种表现（也被称作变异体）呈现（Oaxaca的天气），能够响应处理方法。<br />在Restlet框架中，服务器连接的标准响应由Resource的实例对象最终处理。一个Resource负责声明支持的表现方式列表（Variant对象的实例）和实现你想要支持的REST方法。<br />	GET依赖可更改的“variants”列表和“getRepresentation(Variant)”方法。<br />	POST依赖“allowPost”方法和“post(Representation)”方法。<br />	DELETE依赖“allowPut”方法和“put(Representation)”方法。<br />	DELETE依赖“allowDelete”方法和“delete()”方法。<br />还有，每一个到达的响应由一个专门的Resource实例处理，你不需要操心这些方法的线程安全。<br />我们假设你已经读过“第一步”（http://www.restlet.org/documentation/1.0/firstSteps），并且有了一些元件和应用的概念。<br /><br />例子应用<br />让我们开始描述我们的例子应用。一个Item列表用来管理创建，读取，更新，和删除活动像一个简单的CRUD应用。一个Item是以名字和描述的简单特征。在简短的分析后，我们定义了两个资源：<br />	Items Resource等于所有可用Item的集合。<br />	Item Resource等于一个单独的item。<br />现在，让我们定义Resource URIs。假设我们的应用运行在本机“localhost”并且监听8182端口：<br />	http://localhost:8182/firstResource/items：“items”Resource URI。<br />	http://localhost:8182/firstResource/items/{itemName}：“item”Resource URI，每个{itemName}代表一个Item的名字。<br />下一步，该定义允许访问每个Resource的方法列表。<br />	“items”Resource响应GET请求并以一个XML文档展示当前注册的Item列表。另外，Resource支持通过POST请求创建新的Item。提交的实体包含新Item的名字和描述并接收格式化的Web表单。如果Resource成功创建新Item，它返回一个“Success - resource created”状态（HTTP 201状态代码）并且告诉客户端新Resource在哪里可以找到（HTTP "Location" header）。否则，它返回一个“Client error”状态（HTTP 404状态代码）和一个简单的错误信息。<br />	“item”Resource响应GET请求并以一个XML文档来展示该Resource的名字和描述。通过PUT和DELETE请求也能更新和删除Resource。<br />在描述两个Resource对象前，先编写你的应用。为了简化，注册的Item列表做为应用的一个属性简单地保存到内存里，并不保存到一个真实的数据库。不管怎样，我们假设你想邀请你的朋友们同时测试这个应用。因为我们只有一个“FirstResourceApplication”实例在运行，所以不得不考虑线程安全。这也就是为什么你会发现Map对象Items是不变的，是一个ConcurrentHashMap对象的实例。<br /><pre name="code" class="java">
package firstResource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.Router;
public class FirstResourceApplication extends Application {
   /** The list of items is persisted in memory. */
   private final Map&lt;String, Item> items;
   public FirstResourceApplication(Context parentContext) {
      super(parentContext);
      // We make sure that this attribute will support concurrent access.
      items = new ConcurrentHashMap&lt;String, Item>();
   }
   /**
    * Creates a root Restlet that will receive all incoming calls.
    */
   @Override
   public synchronized Restlet createRoot() {
      // Create a router Restlet that defines routes.
      Router router = new Router(getContext());
      // Defines a route for the resource "list of items"
      router.attach("/items", ItemsResource.class);
      // Defines a route for the resource "item"
      router.attach("/items/{itemName}", ItemResource.class);
      return router;
   }
   /**
    * Returns the list of registered items.
    * @return the list of registered items.
    */
   public Map&lt;String, Item> getItems() {
      return items;
   }
}
</pre><br /><br />实现Items Resource<br />让我们开始编写Items Resource。如上文所示，允许GET和POST请求。POST请求支持通过“post(Representation)”方法确定你如何处理消息实体。此外，资源通过“allowPost”方法支持POST。缺省情况下，资源是不可更改的，拒绝POST、PUT和DELETE方法并返回“Method not allowed”状态（HTTP 405状态代码）。同样，GET响应支持通过“represent(Variant)”方法确定你如何依照特定的Variant生成实体。假设，我们只生成“text/xml”形式。<br /><pre name="code" class="java">
import java.io.IOException;
import java.util.Collection;
import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.DomRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
 * Resource that manages a list of items.
 * 
 */
public class ItemsResource extends BaseResource {
   /** List of items. */
   Collection&lt;Item> items;
   public ItemsResource(Context context, Request request, Response response) {
      super(context, request, response);
      // Get the items directly from the "persistence layer".
      items = getItems().values();
      // Declare the kind of representations supported by this resource.
      getVariants().add(new Variant(MediaType.TEXT_XML));
   }
   @Override
   public boolean allowPost() {
      return true;
   }
   /**
    * Returns a listing of all registered items.
    */
   @Override
   public Representation getRepresentation(Variant variant) {
      // Generate the right representation according to its media type.
      if (MediaType.TEXT_XML.equals(variant.getMediaType())) {
         try {
            DomRepresentation representation = new DomRepresentation(
                  MediaType.TEXT_XML);
            // Generate a DOM document representing the list of
            // items.
            Document d = representation.getDocument();
            Element r = d.createElement("items");
            d.appendChild(r);
            for (Item item : items) {
               Element eltItem = d.createElement("item");
               Element eltName = d.createElement("name");
               eltName.appendChild(d.createTextNode(item.getName()));
               eltItem.appendChild(eltName);
               Element eltDescription = d.createElement("description");
               eltDescription.appendChild(d.createTextNode(item
                     .getDescription()));
               eltItem.appendChild(eltDescription);
               r.appendChild(eltItem);
            }
            d.normalizeDocument();
            // Returns the XML representation of this document.
            return representation;
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return null;
   }
   /**
    * Handle POST requests: create a new item.
    */
   @Override
   public void post(Representation entity) {
      // Parse the given representation and retrieve pairs of
      // "name=value" tokens.
      Form form = new Form(entity);
      String itemName = form.getFirstValue("name");
      String itemDescription = form.getFirstValue("description");
      // Check that the item is not already registered.
      if (getItems().containsKey(itemName)) {
         generateErrorRepresentation(
               "Item " + itemName + " already exists.", "1", getResponse());
      } else {
         // Register the new item
         getItems().put(itemName, new Item(itemName, itemDescription));
         // Set the response's status and entity
         getResponse().setStatus(Status.SUCCESS_CREATED);
         Representation rep = new StringRepresentation("Item created",
               MediaType.TEXT_PLAIN);
         // Indicates where is located the new resource.
         rep.setIdentifier(getRequest().getResourceRef().getIdentifier()
               + "/" + itemName);
         getResponse().setEntity(rep);
      }
   }
   /**
    * Generate an XML representation of an error response.
    * 
    * @param errorMessage
    *            the error message.
    * @param errorCode
    *            the error code.
    */
   private void generateErrorRepresentation(String errorMessage,
         String errorCode, Response response) {
      // This is an error
      response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
      try {
         // Generate the output representation
         DomRepresentation representation = new DomRepresentation(
               MediaType.TEXT_XML);
         Document d = representation.getDocument();
         Element eltError = d.createElement("error");
         Element eltCode = d.createElement("code");
         eltCode.appendChild(d.createTextNode(errorCode));
         eltError.appendChild(eltCode);
         Element eltMessage = d.createElement("message");
         eltMessage.appendChild(d.createTextNode(errorMessage));
         eltError.appendChild(eltMessage);
         response.setEntity(new DomRepresentation(MediaType.TEXT_XML, d));
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}
</pre><br /><br />实现Item Resource<br />让我们继续编写Item Resource。如上文所示，允许GET，PUT和DELETE请求。PUT请求支持通过“put(Representation)”方法确定你如何处理消息实体。<br />同样，DELETE请求支持执行“delete()”方法。<br /><pre name="code" class="java">
import java.io.IOException;
import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.DomRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.Variant;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class ItemResource extends BaseResource {
   /** The underlying Item object. */
   Item item;
   /** The sequence of characters that identifies the resource. */
   String itemName;
   public ItemResource(Context context, Request request, Response response) {
      super(context, request, response);
      // Get the "itemName" attribute value taken from the URI template
      // /items/{itemName}.
      this.itemName = (String) getRequest().getAttributes().get("itemName");
      // Get the item directly from the "persistence layer".
      this.item = getItems().get(itemName);
      if (this.item != null) {
         // Define the supported variant.
         getVariants().add(new Variant(MediaType.TEXT_XML));
      }
   }
   /**
    * This resource supports DELETE requests.
    */
   @Override
   public boolean allowDelete() {
      return true;
   }
   /**
    * This resource supports PUT requests.
    */
   @Override
   public boolean allowPut() {
      return true;
   }
   /**
    * Handle DELETE requests.
    */
   @Override
   public void delete() {
      if (item != null) {
         // Remove the item from the list.
         getItems().remove(item.getName());
      }
      // Tells the client that the request has been successfully fulfilled.
      getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
   }
   @Override
   public Representation getRepresentation(Variant variant) {
      if (MediaType.TEXT_XML.equals(variant.getMediaType())) {
         // Generate the XML representation of this resource.
         try {
            // Generate a DOM document representing the item.
            DomRepresentation representation = new DomRepresentation(
                  MediaType.TEXT_XML);
            Document d = representation.getDocument();
            Element eltItem = d.createElement("item");
            d.appendChild(eltItem);
            Element eltName = d.createElement("name");
            eltName.appendChild(d.createTextNode(item.getName()));
            eltItem.appendChild(eltName);
            Element eltDescription = d.createElement("description");
            eltDescription.appendChild(d.createTextNode(item
                  .getDescription()));
            eltItem.appendChild(eltDescription);
            d.normalizeDocument();
            // Returns the XML representation of this document.
            return representation;
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return null;
   }
   /**
    * Handle PUT requests.
    */
   @Override
   public void put(Representation entity) {
      // Tells if the item is to be created of not.
      boolean creation = (item == null);
      // The PUT request updates or creates the resource.
      if (item == null) {
         item = new Item(itemName);
      }
      // Update the description.
      Form form = new Form(entity);
      item.setDescription(form.getFirstValue("description"));
      // Update the item in the list.
      getItems().put(item.getName(), item);
      if (creation) {
         getResponse().setStatus(Status.SUCCESS_CREATED);
      } else {
         getResponse().setStatus(Status.SUCCESS_OK);
      }
   }
}
</pre><br /><br />实现Base Resource<br />由于我们的Resource都需要访问“FirstResourceApplication”实例中保存Item的Map，这些方法因此被放入父类“BaseResource”。<br /><pre name="code" class="java">
import java.util.Map;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Resource;
/**
 * Base resource class that supports common behaviours or attributes shared by
 * all resources.
 * 
 */
public abstract class BaseResource extends Resource {
   public BaseResource(Context context, Request request, Response response) {
      super(context, request, response);
   }
   /**
    * Returns the map of items managed by this application.
    * 
    * @return the map of items managed by this application.
    */
   protected Map&lt;String, Item> getItems() {
      return ((FirstResourceApplication) getContext().getAttributes().get(
            Application.KEY)).getItems();
   }
}
</pre><br /><br />运行应用<br />请查阅“第一步”（http://www.restlet.org/documentation/1.0/firstSteps）的相关章节学习如何在一个Servlet容器中运行应用或作为一个单独应用执行。<br /><br />客户端应用<br />一旦我们的应用在一个Servlet容器或作为一个单独应用开始运行，我们建议你通过一个简单的客户端应用测试我们的Resource。它简单地创建、读取、更新和删除一个Item Resource并在每一个操作执行时打印标准输出结果。<br />客户端应用作为单独Java应用运行的时候需要如下的Jar包：<br />	org.restlet.jar <br />	com.noelios.restlet.jar <br />	com.noelios.restlet.ext.httpclient.jar <br />	org.apache.commons.httpclient.jar<br /><pre name="code" class="java">
import java.io.IOException;
import org.restlet.Client;
import org.restlet.data.Form;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
public class FirstResourceClientMain {
   public static void main(String[] args) throws IOException {
      // Define our Restlet HTTP client.
      Client client = new Client(Protocol.HTTP);
      // The URI of the resource "list of items".
      Reference itemsUri = new Reference(
            "http://localhost:8182/firstResource/items");
      // Create a new item
      Item item = new Item("item1", "this is an item.");
      Reference itemUri = createItem(item, client, itemsUri);
      if (itemUri != null) {
         // Prints the representation of the newly created resource.
         get(client, itemUri);
      }
      // Prints the list of registered items.
      get(client, itemsUri);
      // Update the item
      item.setDescription("This is an other description");
      updateItem(item, client, itemUri);
      // Prints the list of registered items.
      get(client, itemsUri);
      // delete the item
      deleteItem(client, itemUri);
      // Print the list of registered items.
      get(client, itemsUri);
   }
   /**
    * Try to create a new item.
    *
    * @param item
    *            the new item.
    * @param client
    *            the Restlet HTTP client.
    * @param itemsUri
    *            where to POST the data.
    * @return the Reference of the new resource if the creation succeeds,
    *         null otherwise.
    */
   public static Reference createItem(Item item, Client client,
         Reference itemsUri) {
      // Gathering informations into a Web form.
      Form form = new Form();
      form.add("name", item.getName());
      form.add("description", item.getDescription());
      Representation rep = form.getWebRepresentation();
      // Launch the request
      Response response = client.post(itemsUri, rep);
      if (response.getStatus().isSuccess()) {
         if (response.isEntityAvailable()) {
            try {
               // Always consume the response's entity, if available.
               response.getEntity().write(System.out);
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
         return response.getEntity().getIdentifier();
      }
      return null;
   }
   /**
    * Prints the resource's representation.
    *
    * @param client
    *            client Restlet.
    * @param reference
    *            the resource's URI
    * @throws IOException
    */
   public static void get(Client client, Reference reference)
         throws IOException {
      Response response = client.get(reference);
      if (response.getStatus().isSuccess()) {
         if (response.isEntityAvailable()) {
            response.getEntity().write(System.out);
         }
      }
   }
   /**
    * Try to update an item.
    *
    * @param item
    *            the item.
    * @param client
    *            the Restlet HTTP client.
    * @param itemUri
    *            the resource's URI.
    */
   public static boolean updateItem(Item item, Client client,
            Reference itemUri) {
      // Gathering informations into a Web form.
      Form form = new Form();
      form.add("name", item.getName());
      form.add("description", item.getDescription());
      Representation rep = form.getWebRepresentation();
      // Launch the request
      Response response = client.put(itemUri, rep);
      if (response.isEntityAvailable()) {
         try {
            // Always consume the response's entity, if available.
            response.getEntity().write(System.out);
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return response.getStatus().isSuccess();
   }
   /**
    * Try to delete an item.
    *
    * @param client
    *            the Restlet HTTP client.
    * @param itemUri
    *            the resource's URI.
    */
   public static boolean deleteItem(Client client, Reference itemUri) {
      // Launch the request
      Response response = client.delete(itemUri);
      if (response.isEntityAvailable()) {
         try {
            // Always consume the response's entity, if available.
            response.getEntity().write(System.out);
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return response.getStatus().isSuccess();
   }
}
</pre><br />你可以从http://www.restlet.org/documentation/1.0/examples/firstResource/sources.zip下载这个例子应用的源文件。<br /><br />结尾<br />这篇文章说明了使用Restlet框架的重要方法。当思考你的Resource的时候，记住这些重要问题：<br />	我应该如何识别我的Resource?<br />	它们能够生成哪些表现？<br />	它们有哪些处理方法？<br />	我需要把同级Resource的哪些行为和属性共享？<br />我们希望你喜欢这些简单步骤并且我们现在鼓励你开始深入Restlet Tutorial。<br /><br />备注：<br />	感谢Tim Peierls反馈线程安全方面的考虑。
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/184083#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Apr 2008 13:50:12 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/184083</link>
        <guid>http://wlmouse.javaeye.com/blog/184083</guid>
      </item>
          <item>
        <title>RestLet－第一步（翻译）</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/182843" style="color:red;">http://wlmouse.javaeye.com/blog/182843</a>&nbsp;
          发表时间: 2008年04月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          猫咪最近看了些REST的东西，被搞得昏头昏脑的。就下了个RestLet框架想试试看。猫咪尝试着把RestLet的入门例子文档翻译成了中文，希望能以此加深对REST的了解。猫咪在此贴出来，希望对大家能有所帮助。猫咪翻译的不好，大家多多指教。这是目前的第二稿。猫咪今天又做了一次修改。<br /><br />Restlet第一步<br />目录<br />这篇文章让你在10分钟内尝试简单的Restlet框架。告诉你如何创建一个说“hello, world”的Resource。<br />1.我需要什么？<br />2.“hello, world”应用<br />3.在Servlet容器中运行<br />4.作为一个单独的Java应用运行<br />5.结尾<br /><br />我需要什么？<br />我们假设你已经有了一个可以马上使用的开发环境，并且你已经安装了JRE1.5（或更高）。如果你还没有下载Restlet，请选择最新的Restlet Framework 1.0发行版。<br /><br />“hello, world”应用<br />让我们开始一个REST应用：“Resource”的核心。这些单一Resource代码，确定了一个简单应用。拷贝/粘贴代码到“HelloWorldResource”类中。<br /><pre name="code" class="java">
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;
public class HelloWorldResource extends Resource {
    public HelloWorldResource(Context context, Request request,
            Response response) {
        super(context, request, response);
        // This representation has only one type of representation.
        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
    }
    @Override
    public Representation getRepresentation(Variant variant) {
        Representation representation = new StringRepresentation(
                "hello, world", MediaType.TEXT_PLAIN);
        return representation;
    }
}
</pre><br />然后创建应用例子。我们创建名为“FirstStepsApplication”对象并拷贝/粘贴下面的代码：<br /><pre name="code" class="java">
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.Router;
public class FirstStepsApplication extends Application {
    public FirstStepsApplication(Context parentContext) {
        super(parentContext);
    }
    @Override
    public synchronized Restlet createRoot() {
        // Create a router Restlet that routes each call to a
        // new instance of HelloWorldResource.
        Router router = new Router(getContext());
        // Defines only one route
        router.attachDefault(HelloWorldResource.class);
        return router;
    }
}
</pre><br /><br />在Servlet容器中运行<br />你可能更熟悉Servlets，我们建议你运行Restlet应用在你喜欢的Servlet容器里。像往常一样创建一个新的Servlet应用，添加“com.firstStepsServlet”包并把Resource和Application类放进去。把下面列出的jar包放入lib目录。<br />	org.restlet.jar<br />	com.noelios.restlet.jar<br />	com.noelios.restlet.ext.servlet_2.4.jar<br />然后按下面的配置修改“web.xml”配置文件：<br /><pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;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">
   &lt;display-name>first steps servlet&lt;/display-name>
   &lt;!-- Application class name -->
   &lt;context-param>
      &lt;param-name>org.restlet.application&lt;/param-name>
      &lt;param-value>
         com.firstStepsServlet.FirstStepsApplication
      &lt;/param-value>
   &lt;/context-param>
   &lt;!-- Restlet adapter -->
   &lt;servlet>
      &lt;servlet-name>RestletServlet&lt;/servlet-name>
      &lt;servlet-class>
         com.noelios.restlet.ext.servlet.ServerServlet
      &lt;/servlet-class>
   &lt;/servlet>
   &lt;!-- Catch all requests -->
   &lt;servlet-mapping>
      &lt;servlet-name>RestletServlet&lt;/servlet-name>
      &lt;url-pattern>/*&lt;/url-pattern>
   &lt;/servlet-mapping>
&lt;/web-app>
</pre><br />最好，将程序打包成一个war文件，例如“firstStepsServlet.war”，并部署到你的Servlet容器里。启动Servlet容器后，打开你喜欢的浏览器，输入URL：“http://&lt;你的服务器名>:&lt;端口号>/firstStepsServlet”。服务器将高兴地用“hello, world”欢迎你。<br />你可以直接从http://www.restlet.org/documentation/1.0/examples/firstSteps/sources.zip下载“First steps application”的war文件（已包含Restlet 1.0.7的lilb包）。<br /><br />作为一个单独的Java应用运行<br />Restlet应用并不只能运行在Servlet容器里，也可以使用下面几个Jar包所为一个独立应用运行：<br />	org.restlet.jar<br />	com.noelios.restlet.jar<br />	com.noelios.restlet.ext.simple.jar<br />	org.simpleframework.jar<br />如果你想要理解后面两个Jar包的意义，你可以参考连接器（http://www.restlet.org/documentation/1.0/connectors）。<br />	创建一个主类，拷贝/粘贴下面的代码。建立一个新的HTTP服务器监听端口8182并委托所有的请求给“FirstStepsApplication”。<br /><pre name="code" class="java">
public static void main(String[] args) {
    try {
        // Create a new Component.
        Component component = new Component();
        // Add a new HTTP server listening on port 8182.
        component.getServers().add(Protocol.HTTP, 8182);
        // Attach the sample application.
        component.getDefaultHost().attach(
                new FirstStepsApplication(component.getContext()));
        // Start the component.
        component.start();
    } catch (Exception e) {
        // Something is wrong.
        e.printStackTrace();
    }
}
</pre><br />启动Main对象，打开你喜欢的浏览器，输入URL：“http://localhost:8182/”，服务器将高兴地用“hello, world”欢迎你。否则，确认Classpath正确且没有其他应用占用8182端口。<br />你能在http://www.restlet.org/documentation/1.0/examples/firstSteps/sources.zip找到这个例子应用的源文件。<br /><br />结尾<br />我们希望你喜欢这个简单的例子，我们现在鼓励你进一步阅读“第一个Resource”（http://www.restlet.org/documentation/1.0/firstResource）或开始深入Restlet Tutorial（http://www.restlet.org/documentation/1.0/tutorial）。<br /><br />备注：<br />感谢Didier Girard提议写这篇文章。
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/182843#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 15 Apr 2008 11:48:39 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/182843</link>
        <guid>http://wlmouse.javaeye.com/blog/182843</guid>
      </item>
          <item>
        <title>配置Glassfish多机集群</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/179637" style="color:red;">http://wlmouse.javaeye.com/blog/179637</a>&nbsp;
          发表时间: 2008年04月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　猫咪在论坛看到有人尝试配置Glassfish多机集群失败。猫咪也在网上搜索了一下，Glassfish有关配置集群的文章很少，仅有的几篇居然多是在一台机器上配置多个实例。昏死，那还叫什么集群！　　 <br />　　猫咪又在网上和Sun的官方网站上反复搜索，终于发现一篇Glassfish配置多机集群的文章（<a href="http://blogs.sun.com/anilam/entry/glassfish_v2_admin_console_series" target="_blank">http://blogs.sun.com/anilam/entry/glassfish_v2_admin_console_series</a>）。猫咪根据这篇文章在自己的VMware上配置成功。现把自己的经验写下来，帮助有需要的朋友。 <br />　　猫咪自己是在VMware中建立两个虚拟计算机，使用的是Windows Server 2003。本来是想用Linux的，但是Ubuntu每次总要联机查补丁，慢得要死，所以只好装2003了。 <br />　　两台虚拟机器，IP地址一个是192.168.1.103，一个是192.168.1.104。其中192.168.1.104作为主控代理服务器和其中一个节点服务器。 <br />　　首先在每台计算机上下载安装JDK6（至少也得是JDK5），安装过程在此不再叙述。 <br />　　然后是安装Glassfish。猫咪用的是Glassfish v2ur1多语言版。从网上下载来后，执行 <br />　　java &ndash;Xmx256m &ndash;jar glassfish-installer-v2ur1-b09d-windows-ml.jar<br />　　将安装文档解压缩。然后进入Glassfish下，执行 <br />　　lib\ant\bin\ant &ndash;f setup-cluster.xml <br />　　两台都要这么做。 <br />　　其实理论上应该是一台代理服务器，多台节点服务器。不过猫咪怕自己机器吃不消，所以就只用了两台机器。不过其中一台机器既做代理又做节点，性能上有问题。自己试验可以，实际中这么配可不行。 <br />如果&ldquo;ant &ndash;f setup-cluster.xml&rdquo;执行没有问题，那么在两台服务器上就都建立了一个支持集群的服务器实例。 <br />　　首先，在代理服务器上进入Glassfish的bin目录启动实例， <br />　　asadmin strat-domain domain1 <br />　　&ldquo;domain1&rdquo;是系统自动建立的缺省实例，你也可以建立自己的实例。格式是&ldquo;create-domain --profile cluster --adminport 4848 &lt;实例名&gt;&rdquo;，&ldquo;--profile cluster&rdquo;表示实例是集群实例，&ldquo;--adminport 4848&rdquo;表示管理端口是4848。 <br />　　分别在两个节点服务器上建立节点代理（目前192.168.1.104还兼任代理服务器职责）。 <br />　　asadmin create-node-agent --host 192.168.1.104 --port 4848 agentOnFirst <br />　　建立第一个代理节点。 <br />　　asadmin create-node-agent --host 192.168.1.104 --port 4848 agentOnSecond <br />　　建立第二个代理节点。 <br />　　建立的时候，要求你输入代理服务器的用户名、密码和主密码。缺省是用户名&ldquo;admin&rdquo;，密码&ldquo;adminadmin&rdquo;，主密码我是自己建立的实例，也设定成了&ldquo;adminadmin&rdquo;。如果你用的是缺省实例，主密码应该是&ldquo;changeit&rdquo;。命令要分别在两个节点服务器上执行，不要在代理服务器上执行。然后分别启动这两个节点代理 <br />　　asadmin start-node-agent agentOnFirst <br />　　asadmin start-node-agent agentOnSecond <br />　　启动的时候同样要求你输入代理服务器用户名、密码和主密码。如果没有问题，系统会显示节点启动成功。 <br />现在通过浏览器登录&ldquo;http://192.168.1.104:4848&rdquo;，进行集群的创建和配置。进入控制台后，选择&ldquo;群集&rdquo;，然后选择&ldquo;新建&rdquo;按钮。输入集群名称后按&ldquo;确定&rdquo;。猫咪把自己的集群叫&ldquo;MiaoCluster&rdquo;。然后点击这个集群实例，选择右边的&ldquo;实例&rdquo;选项卡，然后将刚才创建的两个节点代理分别添加进去就可以了。最后在&ldquo;常规&rdquo;选项卡中按&ldquo;启动群集&rdquo;按钮，如果之前一切正常，两个节点均正常连接的情况下，集群就会成功启动。现在就可以在&ldquo;应用程序&rdquo;选项卡中进行应用部署了。猫咪自己写了一个缺省的JavaEE应用，只有一个缺省的index.jsp文件，上面就一句话&ldquo;&lt;%=&rdquo;Hello WOrld!&rdquo;%&gt;&rdquo;。因为不涉及到任何其他东西，所以部署很成功。 <br />　　然后在浏览器上输入&ldquo;http://192.168.1.104:38080/hello&rdquo;。其中38080是集群的访问端口，猫咪的应用叫hello。浏览器成功显示出了&ldquo;Hello World!&rdquo;。然后再访问&ldquo;http://192.168.1.103:38080/hello&rdquo;，同样成功显示。去每个节点服务器的节点目录下，可以看到在&ldquo;C:\glassfish\nodeagents\&lt;节点名&gt;\&lt;实例名&gt;\applications\j2ee-modules\&rdquo;下有hello目录。如果你觉得这么访问不方便，一会儿103一会儿104的，你可以在代理服务器上配置HTTP负载均衡。 <br />截图是浏览器分别访问两个节点成功的画面。 <br /><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/179637#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Apr 2008 11:53:58 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/179637</link>
        <guid>http://wlmouse.javaeye.com/blog/179637</guid>
      </item>
          <item>
        <title>Eclipse中开发Perl </title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/177991" style="color:red;">http://wlmouse.javaeye.com/blog/177991</a>&nbsp;
          发表时间: 2008年03月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div style="text-indent: 2em">喵。猫咪最近开始看《精通正则表达式》。因为作者喜欢用Perl来表现代码。所以猫咪也安装了一个Perl来学习。不过猫咪被可视化开发惯坏了，所以打算用Eclipse来做Perl的开发环境。</div><div style="text-indent: 2em">首先猫咪去网上下来Perl的安装程序。猫咪是从<span style="font-family: 宋体"><a href="http://strawberryperl.com/"><span style="color: #333333">http://strawberryperl.com/</span></a>下载的5.10.0安装包。不过可惜这个安装包目前不能在Vista下运行。</span></div><div style="text-indent: 2em">然后是下载Eclipse的Perl插件。猫咪推荐用Eclipse的远程下载插件功能。地址是<a href="http://e-p-i-c.sourceforge.net/updates/testing"><span style="color: #333333">http://e-p-i-c.sourceforge.net/updates/testing</span></a>。</div><div style="text-indent: 2em"><span style="font-family: Courier New">安装完成后Eclipse重新启动，安装就完成了。</span></div><div style="text-indent: 2em"><span style="font-family: Courier New">然后我们把Eclipse的视图改成Perl的，就可以建立Perl项目进行Perl开发了。不过有一点要注意，Perl源代码文件必须写扩展名，比如pl。不然Eclipse无法执行代码。网上没有任何人对此进行提示。昏死，猫咪手头的一本《Perl入门》上说写不写扩展名无所谓，所以造成猫咪为此折腾了一个上午。</span></div>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/177991#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 31 Mar 2008 12:06:13 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/177991</link>
        <guid>http://wlmouse.javaeye.com/blog/177991</guid>
      </item>
          <item>
        <title>猫读《软件估算》三</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/160713" style="color:red;">http://wlmouse.javaeye.com/blog/160713</a>&nbsp;
          发表时间: 2008年01月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　喵。大家有做我上一篇文章的测试题吗？我会在本篇的最后公布答案，以免有人通过预览之类的功能作弊。当然，也许有人已经通过搜索引擎找到了正确答案和自己的对比。那么你得了多少分？<br />　　你的得分很低的话，那么你就要好好想想为什么会这样了。人们为什么会低估呢？低估的压力来自于哪里？是否是因为怕因为自己估值估的太宽了让别人笑话？是否是自己的荣誉感、自尊心作祟？因为你会想，太阳表面温度？我不知道。不过把从宇宙绝对零度到1亿度都估算进去，总能包上。呵呵，这当然正确。但是你会觉得自己会成为别人的笑柄。书上这里给出一个忠告，如果&ldquo;感觉到有进行过窄估算的压力，请确认其不是来自自身&rdquo;。<br />　　进行估算的时候，是高估好还是低估好？<br />　　首先是高估。当然，不是漫天要价。比如把一个100W的项目要1亿的资金。而是说一个项目如果估算可能在2到3个月完成，那么我们应该取那个值比较好呢？3个月完成的可能性比较大，但是时间长。2个月完成的可能性比较小，但是如果按时完成，成本比价低（少花一个月薪水）。反对高估的理由是所谓的&ldquo;帕金森法则&rdquo;，用咱们的话来说就是磨洋工。1天干的活给了2天时间。所以程序员会在第一天把活干完后去玩《魔兽》、看动画片。因为给的指标是2天，到2天上我给出了产品，所以你管我怎么用时间（对管理者来说浪费一天）。还有就是&ldquo;学生综合征&rdquo;，程序员会在开始的时候浪费时间，最后的时候赶工。其实我们小时候放寒暑假就经常这么干。刚放假的时候尽情的玩，反正时间很长，假期作业晚点写也没关系。结果到快开学的时候发现，一点也没有动。于是点灯熬油的彻夜奋战赶作业。<br />　　所以，很多客户和管理者都觉得程序员给出的估算是一个超乐观估算。如果要求1年的时间的话，最快6个月就可以。而且很多人喜欢看到别人每天紧张地忙碌，美其名曰&ldquo;有紧迫感&rdquo;。所以更加压缩时间。1年的话我压到6个月，最多再多给2个月。虽然我不相信他们能在6个月内完工，但是8个月应该够了。反正最后1年无论如何也完了。而且我还可以以此打击他们，比如要求赔偿（虽然我实际上不在乎1年开发完，但是给你们的是6-8个月，所以不能要那么多钱）、要求增加新功能（我已经给了足够宽的时间，所以要多干一些）。<br />　　然后是低估。也就是说按照估值的低点做计划。2-3个月的估2个月，甚至1个半月。反对低估的一般情况下主要是程序员。因为人微言轻，所以很难反抗成功。反对的理由是太过乐观的假设会造成计划的有效性降低、赶工造成无法做出正常的系统。</p><p>　　估算的偏差理论上最好的是正负10%，实际上能有一倍的误差就烧高香了。统计学显示，程序员的估值一般比实际低20%到30%。也就是说程序员提出的估算实际上多半都已经是估算的低点了（实际工作量可能比估算的最高点还要高很多），那么这么大的实际和计划偏差，计划也就是让客户养养眼的废纸而已。还有，低估会引发大量问题，项目团队为了赶进度无休止的加班，造成大量错误代码，而为了修正这些错误，要花费大量的时间。为了到时候能够有东西拿出来，什么分析、设计的统统一边站。单元测试、持续集成？每天连吃饭到睡觉都不够6小时了，写代码都来不及，谁还有工夫管这些。怎么写快怎么写。只要能跑起来就成，什么BUG、设计不合理、性能低下以后再说。到时候指不定是哪个倒霉蛋接手呢，反正多半不是我（已经决定项目完成后就跳，什么？你说跑不掉？这么多加班、没加班费。只要有证据，去劳动部门一告一个准，敢不放我走！）。最后的结果就是留给客户一个只能扔到垃圾箱的&ldquo;半成品&rdquo;。<br />　　猫咪就当过那个倒霉蛋。维护过一段时间一个恶心的产品。这是一个从需求到完成只有2个月的中型项目。所有成员没日没夜，不眠不休制造出来的垃圾。Java的分层设计什么的根本没有。设计上到处都是BUG。数据库表乱七八糟，如果不是因为数据库第一范式违反了表就建不起来了，他们估计连第一范式也不打算遵守了。冗余字段到处都是，有时候居然一表多用。比如把新闻的分类和考试试题的分类用一张表存，班级通讯录不是去用户表读用户信息，而是单建了一张。程序里也是，重复混乱的代码到处都是。表现层的Action大家都知道，应该是一个功能一个Action（或Action中的一个方法）。他们倒好，一个Action中塞3、4个差不多的业务逻辑，而且用丑陋的if...else判断。每个分支里面的代码都是重复粘贴的。还好我那段时间没什么赶进度的事情，不然非要了猫咪的老命。<br />　　最佳的项目结果来自最佳估算。如果估算过高，那么就会出现&ldquo;帕金森法则&rdquo;和&ldquo;学生综合症&rdquo;，过低则出现&ldquo;项目计划误差&rdquo;、大量缺陷和使用不成熟产品造成的损失。所以，作者提出的结论是，无论如何都不要低估。宁可高估也不要低估。因为即使高估，造成的损失是可以预期的。最多就是把预算花光、程序员比较清闲而已。这些问题可以通过积极的管理和项目控制解决。但是如果低估就不成了，大量的错误和返工、程序员的抱怨、法律风险（因项目延期的客户索赔、程序员因为加班过多的法律诉讼和罢工）等等都会找上门。你无法预测低估到底会造成多大损失。<br />　　喵。猫咪多么希望客户和管理者能多高估而不要低估。可惜国内的客户最爱低估了。猫咪参与过一个项目，还好只是调研需求。这个项目，客户自己先进行了一年多的调研（真不知道为什么用了这么长时间）。然后是几个月的招标。最后是不到3个月的开发。领导下令，必须按期完成，不许讲条件。还好猫咪只是借调过去敷衍客户，不然不死也这身猫皮也保不住了（是谓&ldquo;不死脱层皮&rdquo;）。之所以是去敷衍客户，其实是因为招标结束后才开始组建开发团队。但是销售的对客户大包大揽，客户以为团队已经开始工作了，所以只好把猫咪借调过去挡枪。客户对猫咪说，不许说3个月不够。你们应该招标完成前就开始工作的（昏死，合同还八字没一撇就干活？那要是没中标不是白干了！）。<br />今天就说到这里了，猫咪继续看书。<br />　　下面是上一篇测试题的答案：<br />1.10,000华氏度/6,000摄氏度<br />2.北纬31<br />3.17,139,000平方英里/44,390,000平方公里<br />4.公元前356年<br />5.7,199亿美元<br />6.5,500立方英里、23,000立方公里，24*10(22)立方英尺、6.8&times;10（20）立方米、<br />7.18.35亿美元<br />8.135,663公里<br />9.2千2百万册<br />10.170吨</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/160713#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 31 Jan 2008 13:41:45 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/160713</link>
        <guid>http://wlmouse.javaeye.com/blog/160713</guid>
      </item>
          <item>
        <title>猫读《软件估算》二</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/160326" style="color:red;">http://wlmouse.javaeye.com/blog/160326</a>&nbsp;
          发表时间: 2008年01月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　从昨天猫咪拿到这本书后，就开始阅读。猫咪虽然只读了三章，但是猫咪已经认定这本书是一本难得的好书了。猫咪推荐所有接触软件开发领域的人员都来读。前三章总共才30页，但是猫咪觉得每读一次，都有不少新的心得。<br />　　猫咪自己给出的估算的定义就是：开发人员根据客户的需求，给出一个完成所有需求所需要的时间（或者资源）的估算值。然后根据这个指定目标。最后根据目标制定计划。也就是说估算理论上应该是一个项目的开始，当获得最初的需求后，就应该进行估算。其实我们本来也就是这么做的，但很多地方出现了混淆。客户或上面给出开发需求，然后我们自然会在心里估算出一个时间。先别管这个时间怎么来的，是否科学，总之我们会说出一个时间。<br />　　但是问题在于，客户经常会根据自己的情况，指定一个时间。客户问你什么时间完成，不是让你估算，而是要一个根据他要求制定的开发计划。我倒不是说客户定的时间没有道理。问题在于客户只会根据自己的业务情况制定时间，并不了解软件开发，没有把软件开发中的各种问题考虑进去。所以，客户和项目组之间为此经常扯皮。特别是开发人员在很多情况下自己也无法说清楚自己是如何得出软件需要多长时间完成的。所以客户就更不愿意按程序员给出的时间开发。<br />　　喵。现在读者可以先做一个对自己估算能力的测试，很有趣的。<br />　　1.太阳表面温度 _________到__________     <br />　　2.上海纬度 _________到__________   <br />　　3.亚洲大陆的面积 _________到__________   <br />　　4.亚历山大大帝出生的年份 _________到__________<br />　　5.2004年美国货币的流通总量 _________到__________<br />　　6.北美五大湖的总水量 _________到__________<br />　　7.电影《泰坦尼克号》在全世界的票房总收入 _________到__________  <br />　　8.太平洋海岸线的总长度 ________到__________<br />　　9.1776年以来美国出版的书目数量 _________到__________<br />　　10.有过记载的最重的蓝鲸的重量 _________到__________<br />　　对每个问题，按照你的观点填入一个范围边界让他包含正确值的可能性达到90%。请注意，不要把范围设定得过宽或过窄。请根据你的判断，让范围足够宽，能够有90%的可能包括正确答案。均为必填，10分钟内完成，不得进行任何调查（比如上搜索引擎进行查询）。每正确1题为1分，满分10分。<br />　　正确答案猫咪会在下一篇文章中给出，以免作弊。<br />　　猫咪的得分是2分。呵呵，很惨吧。绝大多数人的得分都很少。猫咪让同事一起做。加上猫咪一共5个人，总共才得了11分（2人4分，猫咪2分，1人1分，1人0分）。平均才2.2分。不知道你能得多少分呢？这就说明，如果没有科学的统计数据做支持，凭空估算是没有任何实际意义的。<br />　　如果猫咪的90%估算是正确的，猫咪应该可以得到大约9分。但是实际上猫咪只得到2分。这就表明，在某些情况下如果猫咪说有9成可能完成某件事情，实际上猫咪只有2成可能完成。<br />　　书上给出的测试统计数据是大多数人在1到3分。约6%的0分，18%的1分，24%的2分，18%的3分，13%的4分，9%的5分，4%的6分，3%的7分，2%的8分，1%的9分。也就是说只有1%的人做对了9道题，全对的一个也没有。呵呵呵......<br />　　这篇感想猫咪就写到这里，稍微有些短。大家读完后，自己好好想想，自己来做这些题，应该把范围取多宽？<br />　　喵。再写就漏题了，下次见。
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/160326#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 30 Jan 2008 11:02:38 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/160326</link>
        <guid>http://wlmouse.javaeye.com/blog/160326</guid>
      </item>
          <item>
        <title>猫读《软件估算》一</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/160192" style="color:red;">http://wlmouse.javaeye.com/blog/160192</a>&nbsp;
          发表时间: 2008年01月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　最近猫咪在学习Grails。但是从网上找到的《Grails入门指南》看着太累。特别是做测试的时候，要一边看书一边干活，来回切换桌面实在麻烦。就去卓越网（现在已经是亚马逊中国了）订购《Grails权威指南》。在买书的时候，发现了《软件估算-&ldquo;黑匣子&rdquo;揭秘》一书。是讲如何成功进行软件估算的。感觉比较新鲜，而且自己以往在开发中对应该如何估算工作量也一直没有头绪（基本上是想当然一个可能的大概值，但是基本上没有任何数据去支持这个大概值），看了一下价格，标价49，打折后36.7。觉得价格不贵，就一同买下打算闲着没事的时候看看。28号下单，卓越网给出的是《软件估算》约31日送达，《Grails权威指南》倒要2月4日送到。昏死。结果今天早上《软件估算》就来了。得了，反正《Grails权威指南》还要好几天，猫咪就先看《软件估算》好了。 <br />　　估算，定义是：对项目将持续多长时间或者将花费多少成本的预测。 <br />　　我们一般做项目的都是某某领导给出一个时间点，然后大家针对这个时间点开始干活。无论遇到什么问题，都要在这个点之前完成。如果不能在正常工作时间完成，那么就要不断加班加点。结果就是对老板的怨气，因为这代表每天要回去得更晚，星期六、日不能在家好好打游戏、甚至节假日也要干活。同时国内很多公司对加班费不能按时按量给付和加班时间超过正常承受能力，更是让大家的怨气冲天。消极怠工者有之、边骂边干者有之，还有到劳动部门举报的。呵呵，猫咪也是深受这种荼毒。 <br />　　猫咪以前基本上没有写过读书心得笔记之类的东西，这里也就是一些感想，可能很混乱，大家多多包涵。 <br />　　一般情况下，我们开发一个项目的时候，客户提出一些已知的需求。然后我们根据这些需求得到一个大概的时间。然后我们会和客户就这个时间进度进行扯皮。我说需要3个月，然后客户告诉我只能2个月。然后两边开始扯皮，互相要求对方答应自己的条件。不过国内多是买方市场。唉，谁叫中国人多呢。客户经常用&ldquo;你不做有人做&rdquo;的理由压缩工期、压缩报价。你呢，多半在压力下屈服，先答应下来，以拿到合同。开工后再和客户沟通，以图把压缩的时间要回来。如果要不回来，就用加班压榨程序员的办法赶时间。什么软件工程、结构分层、领域建模、足够的测试等等都尽可能不要，只要到时候能跑起来就可以。 <br />　　客户觉得项目到时候不能用，就告诉他以这个时间就能做到这个程度，而且有证据。看，项目组的程序员已经因不堪重负而病倒若干、住院若干、辞职若干。甚至于殉职若干。而且客户到了这个地步，也不可能停下来。已经投入了这么多了，不做下去就全费了，所以只能先凑合着用，然后再改进。但是项目组又有了新项目，去加班加点干新项目去了。继续完善维护这个项目的人员大幅度缩水，而且因为开发时赶工期，没分析、没设计，代码混乱，结构乱七八糟，几乎无法继续，最后下一版只能重新开发。唯一获得的就是第二次的需求比第一次要明确得多（毕竟用过了一个半成品）。但是，如果第一次积累了大量的数据，而这些数据的结构因为当初赶工设计得不合理，结果新项目因为要保留旧数据，不得不继承原来的不合理结构。 <br />　　说得有点跑题。但是这就是猫咪对现在国内开发的现状的看法。猫咪希望能通过读《软件估算》，学到如何计算有大量不确定因素的情况下能够合理估算需要花费的时间和资源。以免自己给出一个自己无法完成的承诺。猫咪希望能够在上面给出一个目标的时候，能够估算出一个合理的工作量。如果两者偏离太大，那么可以和对方讨价还价。就好像买办公用品，桌子、椅子、电脑、笔、纸张或者打印机什么的，需要很多。但是预算就那么多，大家就坐下来，把那些不太重要的先去掉。以在一个可以接受的预算买到最需要的东西。如果你能拿出一个有足够科学支持的理由，就很可能说服客户，修改目标。比如在时间点不能变更的时候，是否去掉一些不太重要的功能。猫咪觉得只要你能提出足够的，有依据的理由，客户还是很容易说服的。客户希望的是应用能够给他带来效益，赶工出来的半成品除了让双方承受损失之外，没有任何价值。当然，不排除遇到蛮不讲理的家伙，猫咪觉得与其到时候完不成被开掉，不如现在就另谋高就。毕竟身体是自己的，如果答应了对方的要求就是做出了承诺，多累也得去完成。结果到时候仍然完不成，钱当然也没有（没有人会为废品买单），身体也完了。 <br />　　软件估算，首先就要把估算与目标、承诺区分开。不要随便用自己直觉估算出来的东西作为承诺。同时也要明白对方要的是对目标的估算还是对目标的承诺。还有就是估算、目标和承诺的沟通，也就是明确对方要的到底是完成这个目标的估算还是完成目标的计划。比如上面要求为3个月后的展示会完成一个软件，问你大概需要多少时间。但是你却估出了5个月的工作量。不好的沟通就是双方都没有明确对方要什么，在什么时候完成上面扯皮。其实展会并不等于软件上市，拿出一个测试版本，能够把需要展示的部分完成就可以了。但是你却总说需要5个月。其实是没搞明白对方要的是什么，对方要的是3个月的时候能拿出一个能让大家看的应用的计划，当然能够全完成就此上市更好。 <br />　　所有估算出来的单点值不是100%的。如果说需要10个人月，那么这个值到底有多少可能性呢？100%是不存在的。书上给出的是一个理论上是钟型的曲线。如果你要告诉对方一个估算结果，最好是带有可信度的单点值，或一个多点范围。比如&ldquo;70%可信度在20人月完成&rdquo;或需要&ldquo;15-30人月&rdquo;之类的。承诺应该在估算区间内，并根据承诺指定计划。 <br />　　一个&ldquo;良好的估算&rdquo;，大师提出一个好的估算可以做到正负10%。但是，这是和CMM成熟度相关的。没有良好控制的项目是无法做到的。考虑到国内的情况，能到CMM2都是烧高香了（真正达到，那些为评级而搞出来的作秀品不算）。 <br />　　估算对项目控制会产生很大影响。只要你做出了估算，那么你就会根据估算做出承诺并制定完成这个承诺的计划。一般只要最后完成时的花费在&ldquo;估算&rdquo;之内，大家就会说估算是成功的。但是实际上开发过程中不确定的事情太多，而且因为需求的不断更改，可能最后完成的东西和最初定义的东西完全不是一个东西。所以估算的真正目标是确定项目目标是否足够现实，而不是预测项目的结果。 <br />　　书中第一章的最后给出了一个&ldquo;什么是良好的估算&rdquo;的定义：良好的估算是对项目实际情况有足够清晰看法的估算，它让项目负责人可以做出控制项目达到目标的好的决策。 <p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/160192#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 29 Jan 2008 18:07:13 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/160192</link>
        <guid>http://wlmouse.javaeye.com/blog/160192</guid>
      </item>
          <item>
        <title>猫学Grails之完善编写的第一个程序和数据库设置 </title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/159147" style="color:red;">http://wlmouse.javaeye.com/blog/159147</a>&nbsp;
          发表时间: 2008年01月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　在上一篇中程序已经基本成型了。但是还有很多地方需要完善。Grails的缺省设置是一个HQLDB的内存数据库。每次启动时建立，关闭时销毁，不能保留下来。而且输入数据的校验目前还只局限在是否为Null。 <br />　　猫咪先来说如何修改数据库配置。首先在机器上安装一个MySQL数据库，当然别的数据库也可以。不过如果装了Oralce和DB2，机器配置又低跑不动别找我。数据库配置的结构已经和书上说得完全不一样了。&ldquo;grails-app\conf&rdquo;下并没有书上说的DevelopmentDataSource.groovy、TestDataSource.groovy和ProductionDataSource.groovy这三个文件。只有一个把这三个配置放到一起的DataSource.groovy。 <br />内容如下： <br /><pre name="code" class="java">//缺省的数据库配置模板 
dataSource { 
pooled = false 
driverClassName = &quot;org.hsqldb.jdbcDriver&quot; 
username = &quot;sa&quot; 
password = &quot;&quot; 
} 
//Hibernate缓存配置 
hibernate { 
cache.use_second_level_cache=true 
cache.use_query_cache=true 
cache.provider_class='org.hibernate.cache.EhCacheProvider' 
} 
// environment specific settings 
environments { 
//开发环境配置 
development { 
dataSource { 
dbCreate = &quot;create-drop&quot; // one of 'create', 'create-drop','update' 
url = &quot;jdbc:hsqldb:mem:devDB&quot; 
} 
} 
//测试环境配置 
test { 
dataSource { 
dbCreate = &quot;update&quot; 
url = &quot;jdbc:hsqldb:mem:testDb&quot; 
} 
} 
//生产环境配置 
production { 
dataSource { 
dbCreate = &quot;update&quot; 
url = &quot;jdbc:hsqldb:file:prodDb;shutdown=true&quot; 
} 
} 
} 
</pre>&nbsp;<br />　　很好改的。如果要把开发数据库换成MySQL只要把开发部分的数据库配置改了就是了。这种配置格式，经常修改Unix下各种软件的配置的人应该很熟悉。 <br />首先把MySQL的数据库驱动拷贝到lib目录下，然后修改配置文件的开发数据库配置。 <br /><pre name="code" class="java">development { 
dataSource { 
dbCreate = &quot;update&quot; 
pooled = true 
driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
username = &quot;root&quot; 
password = &quot;****&quot; 
url = &quot;jdbc:mysql://localhost:3306/MyMiao&quot; 
} 
} </pre><p><br />　　和一般的数据库连接池的设置没什么不一样的。不过&ldquo;dbCreate&rdquo;要注意。它有三个值：&ldquo;create&rdquo;（如果数据库不存在则创建）、&ldquo;create-drop&rdquo;（启动的时候建立数据库，结束的时候销毁数据库）、&ldquo;update&rdquo;（当数据库表和程序不一致时，修改数据库结构）。不过我不能在MySQL数据库上使用&ldquo;create&rdquo;和&ldquo;create-drop&rdquo;这两个属性。一用就出现异常。看来目前这两个属性只用于内嵌的HQLDB。不过MySQL倒不用建表，只要建立一个空数据库就可以了。系统在启动的时候，会自动在数据库里建立表（不能建立数据库）。如果大家使用其他的数据库，可以试试看能否自动建库。如果你不想Grails对你的数据库动手动脚，把这条去了就是了。 <br />　　下面是对领域对象建立验证和页面的属性显示顺序。如果验证错误，是无法写入数据库的。 <br />在Race类中添加下面的代码： </p><pre name="code" class="java">static constraints ={ 
name(maxlength:50,blank:false)//名字最长50，不许为Null 
startDateTime(validator:{return (it&gt;new Date())})//不能输入过去的时间。这是自定义验证，返回布尔值。it表示这个属性。 
city(maxLength:30,blank:false)//最长30，不能为Null 
state(inList:[&quot;BeiJing&quot;,&quot;TianJin&quot;,&quot;ShangHai&quot;,&quot;ChongQing&quot;],blank:false)//只能输入的值必须在四地中，不能为Null。书上是美国的四个州。我用咱们直辖市代替了。不过目前还不能在这里写中文。页面上能正确显示，但是验证过不去 
maxRunners() 
distance(min:3.1f,max:100f)//跑道长度。最小3.1最长100。（100英里，即160千米。快4个马拉松了） 
cost(min:0f,max:999.99f)//费用必须在0到999.99美元之间 
} 
</pre><p>&nbsp;</p>　　 <p>　　constraints同时也决定了属性出现在页面上的顺序。如果只是想规定某个属性的位置但是没有验证，那么直接放进去就可以了，比如maxRunners。注：这个顺序是输入页面的顺序。然后另一个对象也加入验证。 </p><pre name="code" class="java">static constraints = { 
name(maxLength:50,blank:false)//最长50，不能为Null 
dateOfBirth(nullable:false)//非空 
gender(inList:[&quot;M&quot;,&quot;F&quot;])//输入只能是两者之一 
postalAddress(maxLength:255)//最长255 
emailAddress(maxLength:50,email:true)//最长50，符合Email格式 
race(nullable:false)//非空 
} </pre><p><br />　　看记录详细信息的时候，&ldquo;Registration : 1&rdquo;之类的东西很难看吧。解决的方法就是重写toString()方法。 </p><pre name="code" class="java">Race 
String toString(){&quot;${this.name}:${this.city}:${this.state}&quot;} 
Registration 
String toString(){&quot;${this.name}:${this.emailAddress}&quot;} </pre><p><br />　　好了最初的架子就到此为止了。大家可以多试试。</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/159147#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Jan 2008 17:02:52 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/159147</link>
        <guid>http://wlmouse.javaeye.com/blog/159147</guid>
      </item>
          <item>
        <title>猫学Grails之第一个程序</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/158960" style="color:red;">http://wlmouse.javaeye.com/blog/158960</a>&nbsp;
          发表时间: 2008年01月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div style="text-indent: 2em"><p><span style="font-family: 宋体">最近新浪论坛老不稳定，上传图片总不成功。不过JavaEye这里更厉害，发布的时候总出错，如果放多了图片就一定出错，都白写了。唉...</span></p><p><span style="font-family: 宋体">继续转载猫咪自己的文章。</span></p><p><span style="font-family: 宋体">完成了安装可以开始编写程序了。猫咪是按照书上的例子一步步做的。书上用的是一个赛跑俱乐部的例子。<br />首先定义领域对象，这里有两个对象，跑道和注册。这是个1:N的关系。</span></p><p><span style="font-family: 宋体">代码如下：</span></p><span style="font-family: 宋体"><pre name="code" class="java">//跑道
class Race {
    String name //名称
   Date startDateTime //开始时间
   String city //城市
   String state 状态
   Float distance
    Float cost
    Integer maxRunners = 10000 //最大人数
   static hasMany = [registrations:Registration] //Race有很多Registration
}
//注册
class Registration {
     Race race //所属跑道
   String name //名字
   Date dateOfBirth
    String gender='F'
    String postalAddress
    String emailAddress
    Date createdAt = new Date()
    static belongTo = Race //表示Registration 属于Race
    static optionals =[&quot;postalAddress&quot;] //表示该属性可选
}</pre><p>&nbsp;<span style="font-family: 宋体">在项目根目录下使用&ldquo;grails create-domain-class&rdquo;命令建立对象。执行后提示输入对象名，输入Race。然后用同样方法建立Registration。可以看到，在grails-app的domain目录下，有两个新的文件Race.groovy和Registration.groovy。里面类是空的，把代码拷贝进去。OK。这样领域模型就建立好了。Grails会根据领域对象自动建立数据库表。对象关系映射之类的系统会自动帮你做好。</span></p></span><p>其中，在Race中的hasMany表示一个跑道有多个注册。同时，在Registration中用belongTo表示注册属于跑道。这样就可以在删除跑道的时候同时删除注册。而删除注册的时候不会删除跑道。</p><p>然后创建控制器，我们就可以进行简单的CRUD了。在项目根目录下输入&ldquo;grails create-controller&rdquo;，然后输入Race就可以建立Race对象的控制器了。然后再同样建立Registration的。</p><p><span style="font-family: 宋体">现在可以在grails-app\controllers下看到<span style="font-family: 宋体">RaceController.groovy和<span style="font-family: 宋体">RegistrationController.groovy文件。这就是控制器的源文件。同时在test目录中会生成单元测试用例。</span></span></span></p><p>现在要让控制器进行对象的CRUD。修改这两个控制器如下：</p><pre name="code" class="java">RaceController.groovy
class RaceController {
    def scaffold = Race
}

RegistrationController.groovy
class RegistrationController {
    def scaffold = Registration
}

</pre><p>&nbsp;</p><p>这样就可以了。Grails看到这两行代码，就可以自动生成全部的网页和代码。但是现在只支持非空验证。下次猫咪会把各种验证加上的。现在先跑一下吧。执行&ldquo;grails run-app&rdquo;命令。然后就可以进浏览器看结果了。网址<a href="http://localhost:8080/MyMiao/">http://localhost:8080/MyMiao/</a>。</p><p>可以看到，页面上有两个控制器的连接。点击进去就可以进行简单的CRUD操作了。</p><p><a href="http://album.sina.com.cn/pic/537c5aab4446ebbfab245" target="_blank"></a></p><a href="file:///2" target="_blank"></a></div>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/158960#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Jan 2008 10:52:04 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/158960</link>
        <guid>http://wlmouse.javaeye.com/blog/158960</guid>
      </item>
          <item>
        <title>猫学Grails之安装篇</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/158547" style="color:red;">http://wlmouse.javaeye.com/blog/158547</a>&nbsp;
          发表时间: 2008年01月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　猫咪的文章一般都发在自己新浪的博客里。但是访问者太少，只好把文章转到别的站上。谁知道哪里有能同时更新多个Blog站点的工具呢？ <br />　　喵。猫咪最近一直很清闲。所以开始学习新技术。把以前买来和下载的书翻出来，开始学习（呵呵，虽然是以前买的，但是书上的内容比起猫咪目前开发中使用的技术算新的了）。猫咪打算把自己学习的过程写在这里，让大家也分享一下猫咪的经验。不过有言在先，猫咪不定什么时候就懒了或没时间了，所以连载更新不定时。 <br />　　Grails是一套快速开发框架。使用了Groovy语言（Groovy是运行于Java虚拟机上的一种脚本语言。Groovy被编译成Java字节码而在虚拟机上运行）作为开发语言，Spring和Hibernate作为骨架。它可以看作是Ruby on Rails成功以后，Java社区根据Rails的成功经验，集合了Java的现有框架，开发出来的一套快速框架。 <br />看到这里，猫咪总想到微软的.NET平台。.NET平台支持多语言，只要能够被编译成.NET平台的中间代码，就可以被执行。现在在Java上好像也有这种势头。除了Groovy，Scale、Jython(跑在Java上的Python)、JRuby等脚本语言出了不少。 <br />　　猫咪用来学习的书是《Grails入门指南》迷你书。是从http://www.Infoq.com上免费下载的迷你书，PDF格式。虽然上面使用的版本是Grails0.3.1（够老的），但是国内能找到的Grails的书也就这么一两本（另一本是《GRAILS权威指南》，当当网有卖）。而且这本还是免费的，所以就不能计较太多了。 <br />　　首先我们先从Grails的网站http://grails.codehaus.org上下载Grails。猫咪使用的是最新的1.0RC4，虽然是RC版，但是1.0的正式版马上就要发布了。 <br />下来之后，把ZIP文件解压缩到一个目录里。比如猫咪的是c:\grails。然后在&ldquo;环境变量&rdquo;中添加一个变量&ldquo;GRAILS_HOME&rdquo;，值&ldquo;c:\grails&rdquo;。然后在&ldquo;PATH&rdquo;变量中添加&ldquo;%GRAILS_HOME%\bin;&rdquo;。如果你配置过JavaJDK的环境变量，应该是很熟悉的。配置完了，我们也就完成了开发环境的最初搭建。在命令行工具中输入&ldquo;grails&rdquo;，如果看到出现提示，那么就表示Grails安装成功。 <br />　　好了，猫咪开始做自己的第一个Grails程序了。首先建立一个开发目录，用于存放程序。猫咪一直爱用&ldquo;Miao&rdquo;作为自己的工作目录。然后输入&ldquo;grails create-app&rdquo;创建一个新的工程。然后输入工程名称&ldquo;MyMiao&rdquo;。系统会自动生成MyMiao目录，并在这个目录下建立一系列目录和配置文件。 <br />　　现在其实一个网站的最基本架构已经完成，而且可以运行了。我们还没有写一行代码呢（因为一个代码也没写，所以网站也就只有一个首页）。在MyMiao目录下输入&ldquo;grails run-app&rdquo;，网站自动启动。现在打开浏览器，输入&ldquo;http://localhost:8080/MyMiao/&rdquo;就可以看到缺省页面了。喵! <br />　　来看看工程的结构吧。现在的结构已经和书上有了不小的变化。因为有免费的书可以看，所以猫咪写得不是很详细，大家想看详细的，可以看书。如果写得太详细了就成了抄书了，猫咪重点写自己的一些操作和书上不同的地方。 <br /><br />MyMiao&nbsp; <br />&nbsp;&nbsp; |- grails-app <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-conf 配置设置 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-hibernate Hibernate配置 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-spring Spring配置 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-controllers 控制器 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-domain 领域对象 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-i18n 国际化资源文件 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-services 服务层对象 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-taglib 标签 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-utils (不知道，开发文档里也没找到) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-views GSP视图&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|-layouts 布局 <br />&nbsp;&nbsp; |- lib 自定义类库&nbsp;<br />&nbsp;&nbsp;&nbsp;|- scripts GantScripts 类似Ant脚本的东东&nbsp;<br />&nbsp;&nbsp;&nbsp;|- src <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-groovy Groovy源文件（除了Domain、控制器、Service之外的源文件） <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-java Java源文件 <br />&nbsp;&nbsp; |- test 单元测试用例 <br />&nbsp;&nbsp; |- web-app 网站目录 <br />&nbsp;&nbsp; - 项目信息 <br /><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/158547#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Jan 2008 10:01:12 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/158547</link>
        <guid>http://wlmouse.javaeye.com/blog/158547</guid>
      </item>
          <item>
        <title>Hibernate 中Blob字段的使用</title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/158040" style="color:red;">http://wlmouse.javaeye.com/blog/158040</a>&nbsp;
          发表时间: 2008年01月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div style="text-indent: 2em">猫咪以前发了一个关于在Hibernate中使用Clob字段的文章。可以做到以String的方式，直接把大量文字写入字段中而不用进行复杂编码。现在猫咪把使用Blob的方法也写出来。猫咪很懒，所以很久没有更新博客了。大家多多包涵！</div><div style="text-indent: 2em">下面是猫咪的例子（仍然使用Oracle，请确保使用最新的JDBC驱动）</div><div style="text-indent: 2em">首先建立一个数据库表</div><p style="text-indent: 2em">create table textblob (tid number(38,0),lob blob)</p><p style="text-indent: 2em">然后建立对应的Java对象</p><pre name="code" class="java">public class testblob {
         private long id;
         private byte[] lob;
         //set和get方法略...
    }</pre><p style="text-indent: 2em">&nbsp;最后是Hibernate配置和映射文件。</p><pre name="code" class="xml">&lt;hibernate-configuration&gt;
        &lt;session-factory&gt;
        &lt;property name=&quot;connection.driver_class&quot;&gt;
            oracle.jdbc.driver.OracleDriver
            &lt;/property&gt;
            &lt;property name=&quot;connection.url&quot;&gt;
            jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:orcl
            &lt;/property&gt;
            &lt;property name=&quot;connection.useUnicode&quot;&gt;true&lt;/property&gt;
            &lt;property name=&quot;connection.characterEncoding&quot;&gt;UTF-8&lt;/property&gt;
            &lt;property name=&quot;connection.username&quot;&gt;xxxxxx&lt;/property&gt;
            &lt;property name=&quot;connection.password&quot;&gt;xxxxxx&lt;/property&gt;
            &lt;property name=&quot;hibernate.connection.provider_class&quot;&gt;
            org.hibernate.connection.C3P0ConnectionProvider
            &lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.max_size&quot;&gt;20&lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.min_size&quot;&gt;5&lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.timeout&quot;&gt;120&lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.max_statements&quot;&gt;100&lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.idle_test_period&quot;&gt;120&lt;/property&gt;
            &lt;property name=&quot;hibernate.c3p0.acquire_increment&quot;&gt;2&lt;/property&gt;
            &lt;property name=&quot;hibernate.connection.SetBigStringTryClob&quot;&gt;
            true
            &lt;/property&gt;
            &lt;property name=&quot;hibernate.jdbc.use_streams_for_binary&quot;&gt;
            true
            &lt;/property&gt;
            &lt;property name=&quot;dialect&quot;&gt;
            org.hibernate.dialect.Oracle9Dialect
            &lt;/property&gt;
            &lt;property name=&quot;hibernate.show_sql&quot;&gt;true&lt;/property&gt;
            &lt;property name=&quot;hibernate.transaction.factory_class&quot;&gt;
            org.hibernate.transaction.JDBCTransactionFactory
            &lt;/property&gt;

      &lt;mapping resource=&quot;org/Miao/testblob.hbm.xml&quot; /&gt;
         &lt;/session-factory&gt;
     &lt;/hibernate-configuration&gt;</pre><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em"><span style="font-family: 宋体">注意配置文件中&ldquo;hibernate.jdbc.use_streams_for_binary&rdquo;这个部分。这是Oracle必须添加的属性。其它配置没有什么特别的。SQL Server不需要这个属性。同时配置文件配置了一个C3P0数据库连接池。</span></p><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em">映射文件如下：</p><pre name="code" class="xml">&lt;hibernate-mapping package=&quot;org.Miao&quot;&gt;
        &lt;class name=&quot;testblob&quot; table=&quot;tblob&quot;&gt;
            &lt;id name=&quot;id&quot; column=&quot;tid&quot;&gt;
               &lt;generator class=&quot;native&quot;&gt;&lt;/generator&gt;
            &lt;/id&gt;
        &lt;property name=&quot;lob&quot; column=&quot;tlob&quot; type=&quot;binary&quot;&gt;

    &lt;/property&gt;
     &lt;/class&gt;
&lt;/hibernate-mapping&gt;</pre><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em">然后就可以测试一下了。写一个运行的测试类Run.class。</p><pre name="code" class="java">public class run {
      public static void main(String[] args) {
         Configuration configuration = new Configuration();
         configuration.configure();
         SessionFactory sessionFactory = configuration.buildSessionFactory();
         Session session = sessionFactory.openSession();
         File f = new File(&quot;d:/f.exe&quot;);
         byte[] tmp = new byte[(int) f.length()];
         try {
               FileInputStream fi = new FileInputStream(f);
               fi.read(tmp);
          } catch (FileNotFoundException e1) {
          e1.printStackTrace();
          } catch (IOException e) {
          e.printStackTrace();
          }
          testblob test = new testblob();
          test.setId(5);
          test.setLob(tmp);
          Transaction t = session.beginTransaction();
          try {
              session.saveOrUpdate(test);
              t.commit();
          } catch (HibernateException e) {
             e.printStackTrace();
             t.rollback();
          } finally {
             session.close();
          }
    }

}</pre><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em">现在进入数据库的话，可以看到数据库记录中已经增加了一条，文件已经被保存到数据库里了。但是，这么做有一个很大的问题，那就是内存。在Eclipse+WTP的环境下，加入的文件稍微大一点，就会造成OutofMemony异常。因为用这种方法存入数据库，需要把文件全部读入内存才可以。文件一大，就会造成内存溢出，即使把JVM使用的内存调大，保存大文件也是非常慢的。我的调试环境，存一个10M的文件，单用户Tomcat（内存调整到256-512M）跑，Oracle10g又是远程，需要好几分钟。多用户条件下，性能可想而知。而且，一旦多用户同时保存或同时读取大文件，立马会造成内存占用暴增，最后溢出。所以，使用这种方式处理Blob，一定要注意，不要保存大文件，我觉得最好不要超过1M。</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/158040#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 21 Jan 2008 15:04:51 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/158040</link>
        <guid>http://wlmouse.javaeye.com/blog/158040</guid>
      </item>
          <item>
        <title>使用Common Email轻松发送邮件 </title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/157290" style="color:red;">http://wlmouse.javaeye.com/blog/157290</a>&nbsp;
          发表时间: 2008年01月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          　　喵。猫咪最近一直比较无聊，所以终于打算多更新一下Blog以免自己成为一只懒死的猫。 <br />　　我们在Java开发中，对于发送邮件，Sun给出了JavaMail框架。但是这个框架调用比较复杂，所以出了很多封装来简化使用。比如Spring就对JavaMail进行了封装。今天猫咪介绍的是Apache的Common组件中的Email组件，封装得很不错。 <br />　　首先从Sun的网站上下载JavaMail框架实现，最新的版本是1.4.1。然后是JavaBeans Activation Framework，最新版本1.1.1，JavaMail需要这个框架。不过如果JDK是1.6的话就不用下了。1.6已经包括了JavaBeans Activation Framework。 <br />　　最后从<a href="http://commons.apache.org/email/" target="_blank">http://commons.apache.org/email/</a>下载最新的Common Email，版本1.1。 <br />首先在Eclipse中建立一个新的Java工程，然后把JavaMail和Common Email解压缩，在工程中添加解压缩出来的所有Jar的引用。 <br />　　好了，我们来发一封最简单的邮件吧。 <br /><pre name="code" class="java">package org.Miao.Mail;

import org.apache.commons.mail.EmailException;
    import org.apache.commons.mail.SimpleEmail;

public class Mail {
         public static void main(String[] args) throws EmailException {
              SimpleEmail email = new SimpleEmail();
              email.setHostName(&quot;smtp.sina.com&quot;);//邮件服务器
              email.setAuthentication(&quot;*****@sina.com&quot;, &quot;******&quot;);//smtp认证的用户名和密码
              email.addTo(&quot;xxxxxx@sohu.com&quot;,&quot;兔子&quot;);//收信者
              email.setFrom(&quot;xxxxxx@sina.com&quot;, &quot;猫咪&quot;);//发信者
              email.setSubject(&quot;猫咪的测试邮件&quot;);//标题
              email.setCharset(&quot;UTF-8&quot;);//编码格式
              email.setMsg(&quot;这是一封猫咪的测试邮件&quot;);//内容
              email.send();//发送
         }

}</pre><br />　　现在去你的目标邮箱，就可以看到信已经在那里了。注意，如果没有指定编码格式的话（setCharset(&quot;UTF-8&quot;)），那么正文就会变成乱码（都是？？？？？）。当然你也可以指定其他编码格式，比如&ldquo;GBK&rdquo;。 <br />　　如果你的JavaMail的Session是从JNDI中获取或其他方式获得的，Common Email可以通过setMailSession()和setMailSessionFromJNDI()方法进行设置。 <br />　　Common Email除了可以发送普通邮件，也可以发送HTML格式的邮件和带附件的邮件。例子在项目主页上有，大家可以参考。 <br /><br />文章引用自： <br /><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/157290#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jan 2008 15:00:59 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/157290</link>
        <guid>http://wlmouse.javaeye.com/blog/157290</guid>
      </item>
          <item>
        <title>Hibernate 中Clob字段的使用 </title>
        <author>魔力猫咪</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlmouse.javaeye.com">魔力猫咪</a>&nbsp;
                    链接：<a href="http://wlmouse.javaeye.com/blog/118730" style="color:red;">http://wlmouse.javaeye.com/blog/118730</a>&nbsp;
          发表时间: 2007年08月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div id="articleContent" class="middleSize"><p style="text-indent: 2em">数据库的大字段操作向来属于数据库操作中最麻烦的部分。以前在Java开发中，无论是使用JDBC还是使用Hibernate这样的持久化映射工具。大字段操作的代码都是又丑又长，散发出一种&ldquo;坏味道&rdquo;。</p><p style="text-indent: 2em">我们在网上搜索一下，能找到的代码大多非常复杂。其实，随着厂商的不断努力，对于大字段的操作已经越来越容易了。比如SQL Server 2005中推出了新的大字段类型，可以向操作varchar等普通字段类型一样操作大字段。Oracle也推出了支持以String的方式处理Clob的新驱动程序(仅限10g及其以上版本，不过听说9i也可以使用10g的驱动实现这个功能)。</p><p style="text-indent: 2em">Java开发中，持久化工具首选Hibernate。但是网上和参考书上的Hibernate操作大字段例子要么是古老的1.x版本的，在新版本下已经无法执行了。要么是自己写自定义类型，晕呼呼的没几个人看得明白。其实，配合各家厂商推出的新特性，Hibernate可以很容易的操作Clob字段了。</p><p style="text-indent: 2em">猫咪最近需要在数据库中插入一个Clob的字段。看了一些网上的零星例子，试验成功使用String直接映射Clob。不用去转换Clob开流，也不用写Hibernate自定义类型，更不用必须和Spring耦合，使用Spring的专用Hibernate支持。</p><p style="text-indent: 2em">下面是猫咪的代码（Oracle例子）：</p><p style="text-indent: 2em">首先在数据库里建立一个表</p><blockquote dir="ltr" style="margin-right: 0px"><div class="code_title">sql 代码</div><div class="dp-highlighter"><ol class="dp-sql"><li class="alt"><span><span class="keyword">create</span><span>&nbsp;</span><span class="keyword">table</span><span>&nbsp;textclob&nbsp;(tid&nbsp;number(38,0),</span><span class="keyword">name</span><span>&nbsp;varchar2(100),text&nbsp;clob) &nbsp;&nbsp;</span></span> </li><li><span>&nbsp;&nbsp;</span> </li></ol></div><p>然后建立对应的Java类</p></blockquote><div class="code_title">java 代码</div><blockquote dir="ltr" style="margin-right: 0px"><div class="dp-highlighter"><ol class="dp-j"><li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;textclob&nbsp;{ &nbsp;&nbsp;</span></span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;id; &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;name; &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;text; &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span><span class="comment">//set和get方法略... </span><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>} &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li></ol></div>然后写Hibernate配置文件和映射文件。</blockquote><p style="text-indent: 2em">Hibernate的配置文件没有什么特别的，Oracle10g数据库需要添加一个专有属性，同时要保证JDBC驱动一定是网上最新的（支持1.4及以上版本且是最新发布的）。SQL Server数据库的配置不则需要做任何修改，驱动方面2000推荐使用jtds驱动，不推荐Microsoft自己的(微软SQL Server 2000的JDBC驱动太烂了)。2005推荐jtds和Microsoft驱动。</p><p style="text-indent: 2em">配置文件如下：<span style="font-family: 宋体"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; </span></p><div class="code_title">xml 代码</div><p style="text-indent: 2em">&nbsp;</p><div class="dp-highlighter"><ol class="dp-xml"><li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">hibernate-configuration</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span> </li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">session-factory</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;SessionFactory&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.driver_class&quot;</span><span class="tag">&gt;</span><span>oracle.jdbc.driver.OracleDriver</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.password&quot;</span><span class="tag">&gt;</span><span>********</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.SetBigStringTryClob&quot;</span><span class="tag">&gt;</span><span>true</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.url&quot;</span><span class="tag">&gt;</span><span>jdbc:oracle:thin:@***.***.***.**:1521:orcl</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.username&quot;</span><span class="tag">&gt;</span><span>********</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.dialect&quot;</span><span class="tag">&gt;</span><span>org.hibernate.dialect.Oracle9Dialect</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.show_sql&quot;</span><span class="tag">&gt;</span><span>true</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.pool_size&quot;</span><span class="tag">&gt;</span><span>10</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.connection.provider_class&quot;</span><span class="tag">&gt;</span><span>org.hibernate.connection.C3P0ConnectionProvider</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.c3p0.min_size&quot;</span><span class="tag">&gt;</span><span>1</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.c3p0.max_size&quot;</span><span class="tag">&gt;</span><span>5</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.c3p0.timeout&quot;</span><span class="tag">&gt;</span><span>2500</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;hibernate.c3p0.max_statements&quot;</span><span class="tag">&gt;</span><span>50</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">mapping</span><span>&nbsp;</span><span class="attribute">resource</span><span>=</span><span class="attribute-value">&quot;org/Miao/Domains/Clob.hbm.xml&quot;</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag"><span class="tag-name">session-factory</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span class="tag"><span class="tag-name">hibernate-configuration</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li></ol></div><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em; margin-right: 0px" dir="ltr"><span style="font-family: 宋体">注意配置文件中&quot;hibernate.connection.SetBigStringTryClob&quot;部分。这是Oracle必须添加的属性。其它配置没有什么特别的。SQL Server不需要这个属性。同时配置文件配置了一个C3P0数据库连接池。</span></p><p style="text-indent: 2em">&nbsp;</p><p style="text-indent: 2em">映射文件如下：</p><p style="text-indent: 2em"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; </span></p><div class="code_title">xml 代码</div><div class="dp-highlighter"><ol class="dp-xml"><li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">hibernate-mapping</span><span>&nbsp;</span><span class="attribute">package</span><span>=</span><span class="attribute-value">&quot;org.Miao.Domains&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span> </li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">class</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;Clob&quot;</span><span>&nbsp;</span><span class="attribute">table</span><span>=</span><span class="attribute-value">&quot;clobs&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">id</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;id&quot;</span><span>&nbsp;</span><span class="attribute">column</span><span>=</span><span class="attribute-value">&quot;cid&quot;</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">generator</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;assigned&quot;</span><span class="tag">&gt;</span><span class="tag"><span class="tag-name">generator</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag"><span class="tag-name">id</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;name&quot;</span><span class="tag">&gt;</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">property</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;text&quot;</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">&quot;text&quot;</span><span>&nbsp;</span><span class="attribute">column</span><span>=</span><span class="attribute-value">&quot;itext&quot;</span><span class="tag">&gt;</span><span class="tag"><span class="tag-name">property</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag"><span class="tag-name">class</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag"><span class="tag-name">hibernate-mapping</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li></ol></div><p style="text-indent: 2em">然后就可以测试一下了。写一个运行的测试类Run.class。</p><blockquote dir="ltr" style="margin-right: 0px"><div class="code_title">java 代码</div><div class="dp-highlighter"><ol class="dp-j"><li class="alt"><span><span class="keyword">package</span><span>&nbsp;org.Miao; &nbsp;&nbsp;</span></span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span class="keyword">import</span><span>&nbsp;org.Miao.Domains.Clob; &nbsp;&nbsp;</span> </li><li><span class="keyword">import</span><span>&nbsp;org.hibernate.HibernateException; &nbsp;&nbsp;</span> </li><li class="alt"><span class="keyword">import</span><span>&nbsp;org.hibernate.Session; &nbsp;&nbsp;</span> </li><li><span class="keyword">import</span><span>&nbsp;org.hibernate.SessionFactory; &nbsp;&nbsp;</span> </li><li class="alt"><span class="keyword">import</span><span>&nbsp;org.hibernate.Transaction; &nbsp;&nbsp;</span> </li><li><span class="keyword">import</span><span>&nbsp;org.hibernate.cfg.Configuration; &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span> </li><li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Run&nbsp;{ &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;</span><span class="comment">/** </span>&nbsp; </li><li class="alt"><span><span class="comment">&nbsp;&nbsp;*&nbsp;@param&nbsp;args </span>&nbsp;</span> </li><li><span><span class="comment">&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span> </li><li class="alt"><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span><span class="comment">//&nbsp;启动Hibernate </span><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;Configuration&nbsp;cfg&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Configuration(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;cfg.configure(); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;SessionFactory&nbsp;sf&nbsp;=&nbsp;cfg.buildSessionFactory(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span><span class="comment">//得到Session，向数据库中插入一条数据 </span><span>&nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;sf.openSession(); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;Transaction&nbsp;transaction&nbsp;=&nbsp;session.beginTransaction(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;Clob&nbsp;clob&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Clob(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;clob.setId(</span><span class="number">50</span><span>); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;clob.setName(</span><span class="string">&quot;test&quot;</span><span>); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;StringBuffer(); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;</span> </li><li class="alt"><span class="comment">//将主席的诗累加1万次，诗中字加标点共64个。累加1万次就是64万字。 </span><span>&nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i=</span><span class="number">0</span><span>;i&lt;</span><span class="number">10000</span><span>;i++){ &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;sb.append(</span><span class="string">&quot;钟山风雨起苍黄，百万雄师过大江。虎踞龙盘今胜昔，天翻地覆慨而慷。宜将剩勇追穷寇，不可沽名学霸王。天若有情天亦老，人间正道是沧桑。&quot;</span><span>); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;clob.setText(sb.toString()); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;session.save(clob); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;transaction.commit(); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(HibernateException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;&nbsp;transaction.rollback(); &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;}&nbsp;</span><span class="keyword">finally</span><span>&nbsp;{ &nbsp;&nbsp;</span> </li><li><span>&nbsp;&nbsp;&nbsp;session.close(); &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li><li><span>&nbsp;} &nbsp;&nbsp;</span> </li><li class="alt"><span>&nbsp;&nbsp;</span> </li><li><span>}&nbsp;&nbsp;</span> </li></ol></div><p>现在去数据库里看一下，表里已经新加了一条记录，其中其Clob字段中有64万字。如果换成SQL Server数据库，只需要更改一下配置文件就可以了，映射文件和代码一个字也不用改。不过使用SQL Server的话，最好使用2005，2005支持varchar(max)类型，比text和ntext类型好用得多。</p></blockquote><div id="reference" class="invisible">文章引用自：<a href="http://www.javaeye.com/javascripts/fckeditor/editor/" target="_blank"></a> </div><div class="invisible"><span style="font-family: Arial"><a href="http://blog.sina.com.cn/u/1400658603">http://blog.sina.com.cn/u/1400658603</a> 欢迎大家来我的博客做客</span></div></div>
          <br/>
          <span style="color:red;">
            <a href="http://wlmouse.javaeye.com/blog/118730#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 31 Aug 2007 09:40:33 +0800</pubDate>
        <link>http://wlmouse.javaeye.com/blog/118730</link>
        <guid>http://wlmouse.javaeye.com/blog/118730</guid>
      </item>
      </channel>
</rss>