Profil de 闫闰阖阎王本纪PhotosBlogListesPlus Outils Aide

Zhidong Yan

Occupation
Lieu
允公允能学技术,日新月异赚大钱
de 
de 
de 
La liste est vide.
Photo 1 sur 5
Spring Web Flow

May 2005

Discuss this Article


Introduction

Have you found as your web application gets more complex, understanding and managing the page flow – the orchestration that drives your application use cases – gets harder and harder? Are you tired of being forced into very particular ways of doing things that don’t give you much reuse? Do you feel you’re spending too much time developing your own approaches to generic problems like session state management?

Enter Spring Web Flow.

What is Spring Web Flow?

Spring Web Flow (SWF) is an emerging module of The Spring Framework. The module is part of Spring’s web application development stack, which includes Spring MVC.

Spring Web Flow aims to be the best solution for the management of web application page flow. It is a powerful controller for use when your applications demand complex controlled navigations, such as wizards, to guide the user through a series of steps within a larger application transaction.

An example of such a controlled navigation is illustrated as a UML State Diagram below:

Figure 1 - An Example Flight Booking Flow

Astute readers will recognize this as a typical flight booking flow – the kind you participate every time you book an airline reservation on-line.

Why Does Spring Web Flow Exist?

In traditional web applications, page flows like the one above are not explicit—they are not first class citizens. Take a webapp built on Struts, for example. To implement a page flow in Struts, most developers build on what the framework provides them: actions and views. In this case, a single action is associated with a specific request URL. When a request comes in at that URL, the action is executed. During execution, the action performs some processing and then selects an appropriate result view for display. It’s that simple.

So to implement a multi-step page flow in Struts, individual actions are chained together through the various views. Action URLs to process different events like “back” or “submit” are hard-coded into each view. Some form of ad-hoc session storage is used to manage flow state. Redirect after post is used to prevent duplicate submissions, etc.

Although this is a simple and functional approach, it has a major disadvantage: the overall page flow of the web application is not clear from looking at the action definitions in the struts-config.xml file. You can’t see the forest – the flow – from the trees – the many action and view definitions. Flexibility also suffers since actions and views cannot be easily reused. Finally, you simply have to do too much work—it should be easier!

Spring MVC offers a slightly higher level of functionality: form controllers that implement a predefined page flow. Two such controllers are provided out of the box: SimpleFormController and AbstractWizardFormController. However, these are still specific examples of a more general page flow concept.

Tapestry and JSF use an event-driven approach at the page level, rather than the request level, where each page and its backing controller logic are kept together. However, neither provides first-class support for a logical page flow with a well-defined lifecycle that spans several pages and potentially different paths. As you’ll see, the lifecycle of such a page flow is longer than a single request, but shorter than a session.

This is where Spring Web Flow comes in, allowing you to represent the page flow of a web application in a clear and simple way, and reuse it anywhere, including environments like Struts, Spring MVC, Tapestry, JSF, and even Portlets.

Advantages

As you will see, Spring Web Flow offers several advantages:

  • The page flow in a web application is clearly visible by looking at the corresponding web flow definition (in an XML file or Java class).
  • Web flows are designed to be self contained. This allows you to see a part of your application as a module you can reuse in multiple situations.
  • Web flows capture any reasonable page flow in a web application always using the same consistent technique. You're not forced into using specialized controllers for very particular situations.
  • Finally, a web flow is a first-class citizen with a well-defined contract for use. It has a clear, observable lifecycle that is managed for you automatically. Simply put, the system manages the complexity for you and as a result is very easy to use.

How does Spring Web Flow Work?

For now it suffices to say that a web flow is composed of a set of states. A state is a point in the flow where something happens; for instance, displaying a view or executing an action. Each state has one or more transitions that are used to move to another state.

A transition is triggered by an event .

The Book Flight Sample Web Flow

To demonstrate what a web flow definition looks like, the following piece of XML captures the flight booking process illustrated in the UML state diagram above:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN"
	"http://www.springframework.org/dtd/spring-webflow.dtd">

<webflow id="bookflight" start-state="obtainTripInfo">

	<action-state id="obtainTripInfo">
		<action bean="bookingActions" method="bindAndValidate"/>
		<transition on="success" to="suggestItineraries"/>
		<transition on="error" to="tryAgain"/>
	</action-state>

	<action-state id="suggestItineraries">
		<action bean="bookingActions"/>
		<transition on="success" to="displaySuggestedItineraries"/>
	</action-state>

	<view-state id="displaySuggestedItineraries" view="suggestedItenaries">
		<transition on="startOver" to="cancel"/>
		<transition on="select" to="selectItinerary"/>
	</view-state>

	<action-state id="selectItinerary">
		<action bean="bookingActions"/>
		<transition on="success" to="isPassengerInfoRequired"/>
	</action-state>

	<decision-state id="isPassengerInfoRequired">
		<if test="${requestScope.passenger == null}" then="enterPassengerInformation"/>
		<if test="${requestScope.passenger.preferences.alwaysConfirmPassengerInfo}"
			then="enterPassengerInformation" else="displayReservationVerification"/>
	</decision-state>

	<subflow-state id="enterPassengerInformation" flow="passenger">
		<attribute-mapper>
			<input value="${requestScope.passenger.id}" as="passengerId"/>
		</attribute-mapper>
		<transition on="finish" to="displayReservationVerification"/>
	</subflow-state>

	<view-state id="displayReservationVerification" view="reservationVerification">
		<transition on="startOver" to="cancel"/>
		<transition on="assignSeats" to="chooseSeatAssignments"/>
		<transition on="book" to="book"/>
	</view-state>

	<subflow-state id="chooseSeatAssignments" flow="seatAssignments">
		<attribute-mapper>
			<input value="${requestScope.passenger.id}" as="passengerId"/>
			<input name="itinerary"/>
		</attribute-mapper>
		<transition on="finish" to="displayReservationVerification"/>
	</subflow-state>

	<action-state id="book">
		<action bean="bookingActions"/>
		<transition on="success" to="displayConfirmation"/>
	</action-state>

	<end-state id="displayConfirmation" view="reservationConfirmation"/>

	<end-state id="tryAgain" view="tryAgain"/>

	<end-state id="cancel" view="home"/>

</webflow>

Figure 2 – A XML-based Flight Booking Flow definition

As you can see, just from scanning the XML definition, the logical flow driving the booking process is clearly discernable, even if you don’t yet know about Spring Web Flow implementation details.

And if you look a bit closer, you’ll see two subflows that spawn child processes of the booking flow. The first subflow guides the user through entering his passenger information. The second has the user make his seat assignments. The ability to nest flows that act as “mini application modules” is one of the most powerful capabilities of Spring Web Flow.

You could show the definition above to a business analyst and she’d probably get it. Better yet, you could engineer a visual diagram from this definition and present that to a business analyst for review. Tools to do exactly this are already appearing.

The Book Flight Flow Explained

The next part of this article breaks down the key parts of the above Book flight definition, and provides supporting dialog that illustrates how Spring Web Flow works.The Flow Definition

Starting with line 1 of the XML-based flow definition:

<webflow id="bookflight" start-state="obtainTripInfo">
	...
</webflow>

The webflow element defines the flow, specifying its id and start-state. The id is simply a unique identifier. The start state is the first state to transition to when a new flow session is activated at runtime.

So for this business case, when a new bookflight session is activated, it transitions to the obtainTripInfo state.The Obtain Trip Info Action State

Moving on to the obtainTripInfo state definition.

<action-state id="obtainTripInfo">
	<action bean="bookingActions" method="bindAndValidate"/>
	<transition on="success" to="suggestItineraries"/>
	<transition on="error" to="tryAgain"/>
</action-state>

Recall that when states are entered, behavior happens. As you’ll see, there are different state types that execute different behaviors. An action state, like obtainTripInfoabove, executes an action when entered. That action returns the logical result of its execution, and that result is mapped to a state transition. It’s that simple.

So for this business case, obtainTripInfo, when entered, executes the bindAndValidate method on the Action implementation with the bookingActions identifier. This method binds form input from the browser to a Trip domain object and validates it. If that process is successful, the suggestItineraries state is entered. If an error occurs, the tryAgain state is entered.The Booking Action

When using Spring Web Flow with Spring IoC, the bean attribute of the action element refers to the name of an Action implementation exported in the Spring Application Context. Here, the bookingActions bean definition looks like this:

web-context.xml

<bean id="bookingActions"
class="org.springframework.samples.bookflight.BookingActions">
    <property name="bookingAgent" ref="myBookingAgent"/>
</bean>

This allows our action implementation to be managed by Spring and configured via dependency injection.The Suggest Itineraries Action State

Now take a look at the next action state that, given a bound and validated Trip object as input, returns a collection of suggested itineraries:

<action-state id="suggestItineraries">
	<action bean="bookingActions"/>
	<transition on="success" to="displaySuggestedItineraries"/>
</action-state>

The actual implementation code required to make this happen is straightforward:

public class BookingActions extends FormAction {
    ...
    public Event suggestItineraries(RequestContext context) {
        Trip trip = (Trip)context.getRequestScope().getAttribute("trip");
        Collection<Itinerary> itineraries = bookingAgent.suggestItineraries(trip);
        context.getRequestScope().setAttribute("itineraries", itineraries);
        return success();
    }
}

When the suggestItineraries state is entered, the suggestItineraries method is invoked. The other action states work in exactly the same way: entering the state invokes a method on the target action bean.The Display Suggested Itineraries View State

Once a collection of suggested itineraries is returned, the next step has the user review them so she may select the best one. This is accomplished by the following state definition:

<view-state id="displaySuggestedItineraries" view="suggestedItenaries">
	<transition on="startOver" to="cancel"/>
	<transition on="select" to="selectItinerary"/>
</view-state>

As you can see, displaySuggestedItineraries is a view state—a state type we have not yet discussed. A view state, when entered, causes the executing flow to pause, and returns control back to the client with instruction to render the configured view. Later, after some user think-time, the client signals an event describing what action the user took. That resumes the flow, and the event that occurred is mapped to a state transition, which takes the user to the next step in the flow. Again, it’s that simple.

So for this business case, when the displaySuggestedItineraries state is entered the suggestedIteneraries view is rendered and control returns to the browser. The user then decides which itinerary she wants and clicks the “select” button. That signals the select event, passing in the id of the selected itinerary as an event parameter.

The user may also choose to startOver, at which time the flow transitions to the cancel state.

Note it is the responsibility of the client environment the flow is hosted in to map the requested view name, like suggestedItineraries, to a renderable view template, like /WEB-INF/jsp/suggestedIternaries.jsp. For example, in Spring MVC, the FlowController does this using the familiar ModelAndView and ViewResolver constructs. In Struts, the FlowAction does this using the familiar ActionForward.Client Side State

At this point you might ask:

“… since the executing flow is paused when a ViewState is entered, and control is returned to the browser, how is the same flow picked up and resumed on subsequent events?”

The answer is the client tracks the unique id of the executing flow, and provides it as input when the next event is signaled. This is typically done using a hidden form field.

For example, in a jsp:

<input type="hidden" value="<c:out value="${flowExecution.id}"/>">
The “Is Passenger Info Required?” Decision State

After the user selects the Itinerary she wants, the flow has to make a contextual decision about where to go next.

Specifically, if the user has not logged in, or she has logged in but wishes to confirm her passenger information – like the credit card she will use – the flow should allow her to enter that information. On the other hand, if she has already logged in and wishes to go straight to the booking page, the flow should skip this optional step.

Basically, a dynamic decision has to be made that takes into account the user’s information and preferences.

The decision state is perfect for this. See the definition below:

<decision-state id="isPassengerInfoRequired">
	<if test="${requestScope.passenger == null}" then="enterPassengerInformation"/>
	<if test="${requestScope.passenger.preferences.alwaysConfirmPassengerInfo}"
		then="enterPassengerInformation" else="displayReservationVerification"/>
</decision-state>
The Enter Passenger Information SubFlow State

The process of managing passenger information is logically independent of the booking process. It is one part within that process, yes, but it certainly makes sense a user would want to edit her information outside of the booking context.

Subflow states facilitate this. When a subflow state is entered, a child flow is spawned. The parent flow is suspended until the child flow ends. This lets you view your application as a set of self-contained modules – flows – that you can easily embed in multiple situations in a consistent manner.

Take a look at the enterPassengerInformation subflow state:

<subflow-state id="enterPassengerInformation" flow="passenger">
 	<attribute-mapper>
		<input value="${requestScope.passenger.id}" as="passengerId"/>
	</attribute-mapper>
	<transition on="finish" to="displayReservationVerification"/>
</subflow-state>

The flow attribute is the id of the flow to spawn when this state is entered. The attribute-mapper element maps attributes to and from the subflow. Input mappings map attributes down to the subflow. Output mappings map attributes back up to the parent flow when the subflow ends. As you can see, expressions (in this case OGNL) are also supported.

So for this business case, when the enterPassengerInformation state is entered, the passenger flow is spawned. The passengerId attribute is passed down to the flow as input. From there, the subflow does whatever it wants. It’s a black box as far the parent flow is concerned. When the subflow ends, the parent flow resumes, responding to the ending result to determine where to go next—in this case, to reservation verification. The Display Confirmation End State

There is one last core state type that has yet to be discussed: the end state. When an end state is entered, the active flow session terminates. Upon termination, all resources associated with the flow are cleaned up for you automatically.

Below is the displayConfirmation end state that displays confirmation after an itinerary is successfully booked:

<end-state id="displayConfirmation" view="reservationConfirmation"/>

When this state is entered, the bookflight flow ends and the reservationConfirmation view displays.  Because the bookflight flow was acting as the root flow, and not a subflow, it and any allocated resources are automatically cleaned up.

Note: had the ending flow been acting as a subflow, the entered end state is treated as a subflow result the resuming parent flow can respond to.  More specifically, the entered end state ID is used as grounds for a state transition in the resuming parent flow's subflow state.  You can see this in action by taking a look at the "enterPassengerInformation" subflow state definition.  Note how it responds to the "finish" result of the subflow, which corresponds to a "finish" end state within the passenger flow.

Flow Deployment

So far you’ve learned what Spring Web Flow is all about, and you’ve seen an example of a realistic flow definition. What you haven’t seen yet is how to deploy that flow definition for execution in a particular environment, like Spring MVC in a servlet environment.

Doing this is a cinch. Here’s all you have to do with Spring MVC:

<bean name="/booking.htm" class="org.springframework.web.flow.mvc.FlowController">
    <property name="flow">
        <ref bean="bookingFlow"/>
    </property>
</bean>
 
<bean id="bookingFlow" class="org.springframework.web.flow.config.XmlFlowFactoryBean">
   <property name="location" value="classpath:bookflight-flow.xml"/>
</bean>

This automatically exports the bookingFlow at the /booking.htm URL for use in a servlet environment.

Advanced Topics

The following section introduces some of the more advanced features of Spring Web Flow.

Flow Execution Listeners

The FlowExecutionListener construct is an observer that allows you to listen and respond to the lifecycle of an executing flow. You can use this feature to do anything from state precondition and post condition checks, to auditing and security.

Flow Execution Storage Strategies

The mechanism by which the state of an executing flow is saved and restored is fully pluggable. HttpSession-based storage is the default, and SWF provides two other storage strategies out of the box: one using server-side continuation-based session storage, another using full client-side serialization. Defining your own custom storage, for example to store flow state in a Database, is trivial.

When Is Spring Web Flow Right For You?

It should be noted that Spring Web Flow is not a one-size-fits-all solution. As you’ve seen, it’s a stateful system that automates the management of page flows that drive business processes. It should not be used when simpler, stateless solutions are more appropriate. For example, it should not be used where sites require free navigations, where the user is free to “click around” anywhere they please. Spring Web Flow is designed to power controlled navigations, where the user is guided through a process with a clear business goal and lifecycle.

To further make the use case more concrete, here are some examples of “good flows”, where the SWF system would be appropriate:

  • Book a flight
  • Pay your taxes
  • Apply for a loan

Here are some examples where Spring Web Flow would not be appropriate:

  • Index pages
  • Welcome pages
  • Menus
  • Simple form flows (one page)

Spring Web Flow is meant to be used as a compliment to traditional controllers within any web environment, such as Spring MVC, Struts, Tapestry, Web Work, JSF, or Portlets. A single site should combine use of simple controllers with web flows where appropriate.

Road Map

Spring Web Flow 1.0 final will be released with Spring 1.3, scheduled right before JavaOne in June. Between now and then, expect regular, stable-for-development-use preview releases. The offering is already quite mature in terms of feature set and sample applications.

As the development team pushes closer to a final release, here are some of the most important features we will be working on:

Integration

As a standalone library, Spring Web Flow is a strong fit for integration with other frameworks. Out of the box Spring MVC, Struts, and Portlet MVC integration is already provided. JSF and Tapestry integration are expected by the final release.

Flow Management

With Spring 1.2, exporting beans in an MBeanServer for management and monitoring is easy. A strongly typed FlowExecutionMBean management interface already exists, and we plan to extend that so global statistics on all flows executing on the server can be centrally monitored through a JMX console.

Pluggability

Every construct in the system will be made pluggable for easy extension and customization, even from the xml definition. This includes States and Transitions, among other concepts.

Compensating Transactions

Supporting features and sample applications demonstrating use of compensating transactions to rollback previously committed work during execution of a flow is of high interest to us.

Conclusion

Spring Web Flow is a powerful solution for managing controlled navigations that drive business processes. And it’s fun to work with. If you haven’t tried it already, what are you waiting for?

References

Spring Web Flow is covered in the Core Spring training course offered by Interface21 - http://www.springframework.com/training

The Spring Framework, http://www.springframework.org

The Spring Web Flow Wiki, http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home

The kdonald blog, http://www.jroller.com/page/kdonald

Struts, http://struts.apache.org

Java Server Faces, http://java.sun.com/j2ee/javaserverfaces/

Tapestry, http://jakarta.apache.org/tapestry

WebWork, http://www.opensymphony.com/webwork/

JMX, http://java.sun.com/jmx

JavaOne, http://java.sun.com/javaone/

Biographies

Keith Donald is an Interface21 principal and a core Spring Framework project member. An experienced developer and mentor, Keith has built applications for customers spanning a diverse set of industries including banking, network management, information assurance, education, and retail. He specializes in translating business requirements into technical solutions. Keith is the founder of the Spring Rich Client Project and co-lead of Spring Web Flow with Erwin Vervaet. Lately you can find him leading Spring Training courses across the US and abroad, and as a guest speaker on Spring with the NoFluffJustStuff (NFJS) tour.

Erwin Vervaet is a software engineer with a keen interest in applying modern IT concepts and tools. He has been using the Java language since 1996, and has a master's degree in computer science from the Katholieke Universiteit Leuven in Belgium. He has been involved in IT research, e-commerce projects, open source initiatives, and industrial software systems. Erwin currently works as an independent consultant.

07/01/2008

每日一博 感觉OpenJPA的实现比较烂

现在java的动态代理技术已经很成熟了,居然还在使用代码预编译的方式,不稀饭
06/01/2008

英语是“一维文字”,汉字是“二维文字”

 

英语是“一维文字”,汉字是“二维文字”

——关于汉字改革问题的一些思考

黄佶

1,英语是一维的,而汉字是二维的

  英语仅通过水平方向的字母变化传递信息,例如“one”和“two”,而汉字可以在垂直方向通过笔划的变化,传递不同的信息,例如“一”和“二”。

  在电脑中,每一个英文字母需要一个字节(byte)来代表,因此,一个单词中包含的字母越多,占用的字节数也越多。不幸的是,学过英语的人都知道,一个英语单词的含义越复杂,单词中包含的字母也越多,例如我的专业:metallurgy(冶金学)。这个英语单词在电脑里需要十个字节来存储。而它对应的汉语“冶金学”只占用六个字节,因为一个汉字不论多么复杂,含义多么丰富,只需要两个字节来代表。根本原因就在于汉字来自“图画”(象形文字),是一种“二维文字”。

  归纳起来可以这么说:汉字是二维文字,在同样的“宽度”中,包含了较多的信息,因为它在“高度”方向也可以变化,也可以携带信息。在印刷品中可以看得很清楚,汉语的字体稍大,但是表达同样含义的句子较短;而英语的字体可以稍小,但是行数较多,页面上很多空间用于行的分隔。

  汉语拼音化,实际上是把汉语从“二维文字”改造成“一维文字”。也许从这个角度讨论汉字改造问题会有新的思路?

2,汉字的“二维”信息被预先存储在电脑里了

  参加汉字通讯的电脑,预先都会安装汉化平台,例如中文windows。安装汉化平台时,我们实际上已经把汉字的二维信息存储在电脑里了。电脑接受到两个字节后,会自动地、迅速地把这两个字节还原成它们对应的那个汉字。

  也就是说,在汉字的传输过程中,有很大一部分信息根本不需要传输。汉字虽然书写困难,但是传输汉字时并非传输它的写法,而是仅仅传输它的代码。它的写法早已在安装汉化平台时就已经输入电脑了,代码到达接受方电脑时,电脑自动地给它们“对号入座”。

  我在这里创造一个新词:“字节文字”。字节文字的基本特征是用不同的数字组合来代表文字。例如当我们把代表“冶金学”这三个汉字的六个字节,从左到右顺序排列,我们就得到了对应“冶金学”的“字节文字”。

  我们在电脑上输入汉字后,电脑随即把汉字转化成“字节文字”加以存储。

  实际上,从方便书写、方便输入、方便存储、方便传输等方面考虑,把汉字从“象形文字”改造成“字节文字”比改造成“拼音文字”更加合理。“字节文字”还可以彻底解决汉字的同音字问题,而这是汉字拼音化遇到的最大问题。

  然而,文字的最主要功能是供人类识别,拼音文字以发音帮助阅读者识别,象形文字以形象帮助阅读者识别,而字节文字只能靠预先死记硬背存储在大脑中的记忆识别,因此非常难以掌握。所以“字节文字”没有被人类用于相互交流,而是用于擅长死记硬背的电脑。

3,技术的进步具有根本性质的影响

  电脑因为预先存储汉字的二维信息而减少了汉字占用的存储空间和传输带宽。

  电脑的存储器(内存和硬盘)越来越便宜,预先存储更多的东西已经成为可能,例如字组(汉字输入的联想功能)、汉字字形(汉字自动识别——OCR)等等。

  电脑的处理能力越来越大,原来不可能的事情现在已经可以实现了,而且成本很低,能够普及。例如手写汉字识别,语音识别等。

  即将到来的传输线路带宽突破性的拓宽,不仅将使文字型文件(文件大小在100Kbyte以内)的传输不再成为问题,而且图象文件(文件大小在1Mbyte以内)的全球传输也可在瞬间完成,传输瓶颈将上移到音频和视频文件(文件大小在1Gbyte量级)。

  这一切都应该在文字改革研究者的视野里。

  当年电脑的发明者为了节约两个字节的存储空间,而省略年份的前两位,结果造成后人全球大战千年虫。

  为了克服眼前的一个小困难,而给后人留下一个大麻烦,肯定不会是大家希望发生的事情吧。

  网上有一则幽默说,在解决千年虫问题时,应该再增加一位,以免我们的后人大战“万年虫”。虽然是笑话,但充分证明说笑话的人有着常人所没有的高瞻远瞩。

1999年10月19日于上海

返回目录

每日一博 Spring2.x之AOP

可以在xml使用特有标签进行描述
aop:config aop配置
aop:pointcut 一个切点的配置,可以使用aspectJ的表达式或者正则表达式苗粟
aop:advice 声明一个advice
aop:advisor 声明一个advisor (spring特有aop概念)
aop:aspect 声明一个切面
 
使用spring ide最酷的是,xml文件中定义好之后,类源码文件被pointcut定义的类方法左侧会出现箭头标记,so cool! 
 
aop之introduction, 通过aop的方法为target类添加接口或者成员
04/01/2008

每日一博 Jan 4, 2008 Eclipse 3.3 RCP 之新特性

提供了扩展点,可以在启动的splash界面中添加UI元素并响应操作
注意点:
1、eclipse product 必须设置启动splash属性为login ....
2、eventLoop中抛出运行时异常则该扩展点失效,eclipse rcp直接跳过splash进入workbench界面
 
03/01/2008

Jan 3, 2008 之日志 java特性之新发现-序列化

序列化inner class,则outter class也必须是可序列化的,否则序列化失败
public class OutterClass implements Serializable {
 /**
  *
  */
 private static final long serialVersionUID = -5954189492075374737L;
 Entry<String, byte[]> getEntry(String key, byte[] value) {
  return new SeriliazableMapEntry<String, byte[]>(key, value);
 }
 class SeriliazableMapEntry<K extends Serializable, V extends Serializable>
   implements Entry<K, V>, Serializable {
  private static final long serialVersionUID = -523966016744401526L;
  private K key;
  private V value;
  public SeriliazableMapEntry(K key, V value) {
   this.key = key;
   this.value = value;
  }
  public K getKey() {
   return key;
  }
  public V getValue() {
   return value;
  }
  public V setValue(V value) {
   this.value = value;
   return this.value;
  }
 }
}
 
public static void main(String[] args) throws IOException,
   ClassNotFoundException {
  byte[] b = new byte[1000];
  for (int i = 0; i < 1000; i++) {
   b[i] = (byte) (i % 128);
  }
  Entry<String, byte[]> entry = new OutterClass().getEntry(UUID
    .randomUUID().toString(), b);
  System.out.println(entry.getKey());
  System.out.println(entry.getValue());
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(bos);
  oos.writeObject(entry);
  ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  ObjectInputStream ois = new ObjectInputStream(bis);
  Entry<String, byte[]> newEntry = (Entry<String, byte[]>) ois
    .readObject();
  System.out.println(newEntry.getKey());
  System.out.println(newEntry.getValue());
  byte[] nb = newEntry.getValue();
  System.out.println(nb.length);
  for (int i = 0; i < nb.length; i++) {
   System.out.println(nb[i]);
  }
 }
18/05/2007

兔子的故事完整版

一天,一只兔子在山洞前写文章,
>>>一只狼走了过来,问:“兔子啊,你在干什么?”
>>>答曰:“写文章。”问:“什么题目?”答曰:“《浅谈兔子是怎样吃掉狼的》。”
>>>狼哈哈大笑,表示不信,于是兔子把狼领进山洞。
>>>过了一会,兔子独自走出山洞,继续写文章。
>>>一只野猪走了过来,问:“兔子你在写什么?”答:“文 章。”问:“题目是什么?
>>”
>>>答:“《浅谈兔子是如何把野猪吃掉的》。”野猪不信,于是同样的事情发生。
>>>最后,在山洞里,一只狮子在一堆白骨之间,满意的剔着牙读着兔子交给它的文
章,
>>>题目:“《一只动物,能力大小关键要看你的老板是谁》。”
>>>
>>>这只兔子有次不小心告诉了他的一个兔子朋友,这消息逐渐在森林中传播;
>>>狮子知道后非常生气,他告诉兔子:“如果这个星期没有食物进洞,我就吃你。”
>>>于是兔子继续在洞口写文章
>>>一只小鹿走过来,“兔子,你在干什么啊?”
>>>“写文章”“什么题目”““《浅谈兔子是怎样吃掉狼的》”
>>>“哈哈,这个事情全森林都知道啊,你别胡弄我了,我是不会进洞的”
>>>“我马上要退休了,狮子说要找个人顶替我,难道你不想这篇文章的兔子变成小鹿

>>”
>>>小鹿想了想,终于忍不住诱惑,跟随兔子走进洞里。
>>>过了一会,兔子独自走出山洞,继续写文章
>>>一只小马走过来,同样是事情发生了。
>>>最后,在山洞里,一只狮子在一堆白骨之间,满意的剔着牙读着兔子交给它的文章
>>>题目是:如何发展下线动物为老板提供食物
>>>
>>>随着时间的推移,狮子越长越大,兔子的食物已远远不能填饱肚子。
>>>一日,他告诉兔子:“我的食物量要加倍,例如:原来4天一只小鹿,现在要2天一

>>,如果一周之内改变不了局面我就吃你。
>>>于是,兔子离开洞口,跑进森林深处,他见到一只狼
>>>“你相信兔子能轻松吃掉狼吗”
>>>狼哈哈大笑,表示不信,于是兔子把狼领进山洞。
>>>过了一会,兔子独自走出山洞,继续进入森林深处
>>>这回他碰到一只野猪----“你相信兔子能轻松吃掉野猪吗”
>>>野猪不信,于是同样的事情发生了。
>>>原来森林深处的动物并不知道兔子和狮子的故事
>>>最后,在山洞里,一只狮子在一堆白骨之间,满意的剔着牙读着兔子交给它的文章
>>>题目是:如何实现由坐商到行商的转型为老板提供更多的食物
>>>
>>>
>>>时间飞快,转眼之间,兔子在森林里的名气越来越大
>>>因为大家都知道它有一个很历害的老板
>>>这只小兔开始横行霸道,欺上欺下,没有动物敢惹
>>>它时时想起和乌龟赛跑的羞辱
>>>它找到乌龟说:“三天之内,见我老板!”扬长而去
>>>乌龟难过的哭了
>>>这时却碰到了一位猎人
>>>乌龟把这事告诉了他
>>>猎人哈哈大笑
>>>于是森林里发生了一件重大事情
>>>猎人披着狮子皮和乌龟一起在吃兔子火锅
>>>地下丢了半张纸片歪歪扭扭的写着:山外青山楼外楼,强中还有强中手啊!!
>>>
>>>
>>>在很长一段时间里森林里恢复了往日的宁静,兔子吃狼的故事似乎快要被大家忘记

>>>不过一只年轻的老虎在听说了这个故事后,被激发了灵感
>>>于是他抓住了一只羚羊,对羚羊说,如果你可以象以前的兔子那样为我带来食物那

>>就不吃你。
>>>于是,羚羊无奈的答应了老虎,而老虎也悠然自得的进了山洞。
>>>可是三天过去了,也没有见羚羊领一只动物进洞。他实在憋不住了,想出来看看情
>>况。
>>>羚羊早已不在了,他异常愤怒。正在他暴跳如雷的时候突然发现了羚羊写的一篇文

>>>题目是:《想要做好老板先要懂得怎样留住员工》
17/04/2007

作文

今天是星期天,天气真不错呀,万里无云的天空上飘着朵朵白云,火红的太阳照着大地。我怀着愉快的心情出了门,拿着妈妈给我的2块钱去买酱油,买酱油要到百货商店,我站在家门口的21路车站等公交车。
    等了好久,公交车终于来了,我象兔子般的窜上了公交车,刷了学生卡,啊,只剩一个座位了,我好幸运呀,我飞快的做了上座。
  车开动了,我看着窗外的高楼大厦,心里想∶祖国的变化真是日新月遗呀,我们生活在这个年代真是性福啊!
     正在我暗自思考的时候,车又靠站了,没有人下车,却上来了一个人,我定精一看,是一个老奶奶,只见她满头白发,满脸大汗,脸色发黄,好象是有病了,我再一看,她左手住着拐杖,原来她左腿没了,右手拿着一个竹竿,不停的在地上敲打,原来她是个瞎子。我又一看,她背后还背着一个小宝宝。我最后一看,她的肚子大大的,圆圆的,还不停的吐酸水,啊,她是一个孕妇。
    车上做着的其他叔叔阿姨们,看到她都把脸扭到外面,假装没看见。车开动了,看着她一晃一晃的,我的心难受起来,司机叔叔按了一下广播,“各位乘客,如果车有老、弱、病、残、孕以及报小孩的乘客,请您将座位让给他们。”我心里想∶爸爸妈妈和老师从小就教育我要做个懂礼貌的好孩子,我应该把座位让给这位老奶奶。可我又一想,只有一个座位了呀,我还要做2个小时才能到百货商店呢!这时∶雷锋、董存瑞、罗生教、黄继光、刘胡兰、焦裕禄、赵春峨、陈思德、孔融、马克思的形象出现在我的脑海里。他们的事迹激励了我,是呀,我不能为了我自己舒服尔不顾他人的性福呀!但是我又下不了决心。
    就这样,我不停的做着激烈的思想斗争。不知过了多久,我终于下定了决心,把座位让给了老奶奶。老奶奶激动的对我说∶“小朋友,谢谢你呀,你叫什么名字呀?”
    刚好车停了,我到站了。我一边下车一边说∶“老奶奶,我叫红领巾!”
     透过远去的车窗,我看到老奶奶流下了激动的泪水。