[转载]珍藏的最全的windows操作系统快捷键

07月 30th, 2008 / No Comments » / by admin

[转载]珍藏的最全的windows操作系统快捷键

珍藏的最全的windows操作系统快捷键

一、常见用法:
F1           显示当前程序或者windows的帮助内容。
F2           当你选中一个文件的话,这意味着“重命名”
F3           当你在桌面上的时候是打开“查找:所有文件” 对话框
F10或ALT        激活当前程序的菜单栏
windows键或CTRL+ESC   打开开始菜单
CTRL+ALT+DELETE     在win9x中打开关闭程序对话框
DELETE         删除被选择的选择项目,如果是文件,将被放入回收站
SHIFT+DELETE      删除被选择的选择项目,如果是文件,将被直接删除而不是放入回收站
CTRL+N         新建一个新的文件
CTRL+O         打开“打开文件”对话框
CTRL+P         打开“打印”对话框
CTRL+S         保存当前操作的文件
CTRL+X         剪切被选择的项目到剪贴板
CTRL+INSERT 或 CTRL+C  复制被选择的项目到剪贴板
SHIFT+INSERT 或 CTRL+V 粘贴剪贴板中哪谌莸降鼻拔恢?
ALT+BACKSPACE 或 CTRL+Z 撤销上一步的操作
ALT+SHIFT+BACKSPACE   重做上一步被撤销的操作
 
Windows键+M       最小化所有被打开的窗口。
Windows键+CTRL+M    重新将恢复上一项操作前窗口的大小和位置
Windows键+E       打开资源管理器
Windows键+F       打开“查找:所有文件”对话框
Windows键+R       打开“运行”对话框
Windows键+BREAK     打开“系统属性”对话框
Windows键+CTRL+F    打开“查找:计算机”对话框
SHIFT+F10或鼠标右击   打开当前活动项目的快捷菜单
SHIFT          在放入CD的时候按下不放,可以跳过自动播放CD。在打开word的时候按下不放,可以跳过自启动的宏
 
ALT+F4         关闭当前应用程序
ALT+SPACEBAR      打开程序最左上角的菜单
ALT+TAB         切换当前程序
ALT+ESC         切换当前程序
ALT+ENTER        将windows下运行的MSDOS窗口在窗口和全屏幕状态间切换
PRINT SCREEN      将当前屏幕以图象方式拷贝到剪贴板
ALT+PRINT SCREEN    将当前活动程序窗口以图象方式拷贝到剪贴板
CTRL+F4         关闭当前应用程序中的当前文本(如word中)
CTRL+F6         切换到当前应用程序中的下一个文本(加shift 可以跳到前一个窗口)

在IE中:

ALT+RIGHT ARROW     显示前一页(前进键)
ALT+LEFT ARROW     显示后一页(后退键)
CTRL+TAB        在页面上的各框架中切换(加shift反向)
F5           刷新
CTRL+F5         强行刷新

 
  目的快捷键

  激活程序中的菜单栏 F10

  执行菜单上相应的命令 ALT+菜单上带下划线的字母

  关闭多文档界面程序中的当

  前窗口 CTRL+ F4

  关闭当前窗口或退出程序 ALT+ F4

  复制 CTRL+ C

  剪切 CTRL+ X

  删除 DELETE

  显示所选对话框项目的帮助 F1

  显示当前窗口的系统菜单 ALT+空格键

  显示所选项目的快捷菜单 SHIFT+ F10

  显示“开始”菜单 CTRL+ ESC

  显示多文档界面程序的系统

  菜单 ALT+连字号(-)

  粘贴 CTR L+ V

  切换到上次使用的窗口或者

  按住 ALT然后重复按TAB,

  切换到另一个窗口 ALT+ TAB

  撤消 CTRL+ Z

二、使用“Windows资源管理器”的快捷键

  目的快捷键

  如果当前选择展开了,要折

  叠或者选择父文件夹左箭头

  折叠所选的文件夹 NUM LOCK+负号(-)

  如果当前选择折叠了,要展开

  或者选择第一个子文件夹右箭头

  展开当前选择下的所有文件夹 NUM LOCK+*

  展开所选的文件夹 NUM LOCK+加号(+)

  在左右窗格间切换 F6

三、使用 WINDOWS键

  可以使用 Microsoft自然键盘或含有 Windows徽标键的其他任何兼容键盘的以下快捷键。

  目的快捷键

  在任务栏上的按钮间循环 WINDOWS+ TAB

  显示“查找:所有文件” WINDOWS+ F

  显示“查找:计算机” CTRL+ WINDOWS+ F

  显示“帮助” WINDOWS+ F1

  显示“运行”命令 WINDOWS+ R

  显示“开始”菜单 WINDOWS

  显示“系统属性”对话框 WINDOWS+ BREAK

  显示“Windows资源管理器” WINDOWS+ E

  最小化或还原所有窗口 WINDOWS+ D

  撤消最小化所有窗口 SHIFT+ WINDOWS+ M

四、使用“我的电脑”和“Windows资源管理器”的快捷键

  目的快捷键

  关闭所选文件夹及其所有父

  文件夹按住 SHIFT键再单击“关闭按钮(仅适用于“我的电脑”)

  向后移动到上一个视图 ALT+左箭头

  向前移动到上一个视图 ALT+右箭头

  查看上一级文件夹 BACKSPACE

五、使用对话框中的快捷键

  目的快捷键

  取消当前任务 ESC

  如果当前控件是个按钮,要

  单击该按钮或者如果当前控

  件是个复选框,要选择或清

  除该复选框或者如果当前控

  件是个选项按钮,要单击该

  选项空格键

  单击相应的命令 ALT+带下划线的字母

  单击所选按钮 ENTER

  在选项上向后移动 SHIFT+ TAB

  在选项卡上向后移动 CTRL+ SHIFT+ TAB

  在选项上向前移动 TAB

  在选项卡上向前移动 CTRL+ TAB

  如果在“另存为”或“打开”

  对话框中选择了某文件夹,

  要打开上一级文件夹 BACKSPACE

  在“另存为”或“打开”对

  话框中打开“保存到”或

  “查阅” F4

  刷新“另存为”或“打开”

  对话框 F5

六、使用“桌面”、“我的电脑”和“Windows资源管理器”快捷键

  选择项目时,可以使用以下快捷键。

  目的快捷键

  插入光盘时不用“自动播放”

  功能按住 SHIFT插入 CD-ROM

  复制文件按住 CTRL拖动文件

  创建快捷方式按住 CTRL+SHIFT拖动文件

  立即删除某项目而不将其放入 SHIFT+DELETE

  “回收站”

  显示“查找:所有文件” F3

  显示项目的快捷菜单 APPLICATION键

  刷新窗口的内容 F5

  重命名项目 F2

  选择所有项目 CTRL+ A

  查看项目的属性 ALT+ ENTER或 ALT+双击

  可将 APPLICATION键用于 Microsoft自然键盘或含有 APPLICATION键的其他兼容键

七、Microsoft放大程序的快捷键

  这里运用Windows徽标键和其他键的组合。

  快捷键目的

  Windows徽标+PRINT SCREEN将屏幕复制到剪贴板(包括鼠标光标)

  Windows徽标+SCROLL LOCK将屏幕复制到剪贴板(不包括鼠标光标)

  Windows徽标+ PAGE UP切换反色。

  Windows徽标+ PAGE DOWN切换跟随鼠标光标

  Windows徽标+向上箭头增加放大率

  Windows徽标+向下箭头减小放大率

 
八、使用辅助选项快捷键

  目的快捷键

  切换筛选键开关右SHIFT八秒

  切换高对比度开关左ALT+左SHIFT+PRINT SCREEN

  切换鼠标键开关左ALT+左SHIFT+NUM LOCK

  切换粘滞键开关 SHIFT键五次

  切换切换键开关 NUM LOCK五秒

Tags:

沉痛哀悼在四川汶川大地震中遇难的同胞们

05月 19th, 2008 / No Comments » / by admin

为表达对512地震遇难同胞的沉痛哀悼,积极响应国家号召,本人博客19~21三天改为灰色!

Tags: ,

一则青原惟信禅师的语录

04月 20th, 2008 / No Comments » / by admin

《五灯会元》卷十七中,有一则青原惟信禅师的语录:“老僧三十年前未参禅时,见山是山,见水是水。及至后来亲见知识,有个入处,见山不是山,见水不是水。而今得个休歇处,依前见山只是山,见水只是水。”

怎样让 XmlHttpRequest 跨站点访问

04月 20th, 2008 / No Comments » / by admin

This post is more technical and detailed than what I usually write on fettig.net. I’m going to talk about a technique I’ve been working on to work around a limitation in the XmlHttpRequest object used in Ajax applications. Web geeks, please read on.

Updates to this post

See this post for an updated version of this techinique that works (hack-free) in Firefox 1.5.

The problem

XmlHttpRequest objects are bound by the same origin security policy of browsers, which prevents a page from accessing data from another server. This has put a serious limitation on Ajax developers: you can use XmlHttpRequests to make background calls to a server, but it has to be the same server that served up the current page. Known workarounds for this limitation involve either server-side reverse proxying or bypassing XmlHttpRequest entirely.

In my case neither of these approaches was going to work. I wanted to use LivePage, the live-update framework developed by Donovan Preston and other brilliant hackers at Divmod. LivePage works because it uses Twisted, which is good at handling lots of long-lasting network connections at the same time. Since Apache isn’t good at handling lots of long-lasting connections, putting an Apache reverse proxy in front of the Twisted server would put a major hurt on performance and scalability. And since LivePage is bound to XmlHttpRequest, I couldn’t use a non-XmlHttpRequest alternative.

Our approach with JotSpot Live has been to let a Twisted server handle all page requests and XmlHttpRequest calls. That’s fine as long as JotSpot Live is a standalone, dedicated web site. But what our customers are asking for (and what we want) is the ability to have Live-style realtime updates in ordinary xxx.jot.com sites. And we don’t want to put a Twisted server in front of every site in our domain. So I’ve been trying to find a way to let any page in our domain communicate with live.jot.com through XmlHttpRequests. As it turns out, it is possible, but you have to jump through some hoops.

A couple of notes on the examples here:

  • I’m not really using two different servers. In my examples, a page on http://fettig.net/ is attempting to make an XmlHttpRequest call to http://www.fettig.net/. The fact that my Apache setup maps these to the same virtual host makes no difference to a browser, though: they’re not the same hostname, and they’re treated no differently than if they were two different sites with different content. The results would be the same if I was trying to make XmlHttpRequest calls to an ajax.fettig.net server with its own IP address.
  • I’m using a simple XmlHttpRequest wrapper library that provides a getUrl function. getUrl takes a URL and a callback function, opens an XmlHttpRequest connection to that URL, and calls the function with the results. If you’re interested you can view the full code here.
  • The service to which I’m making XmlHttpRequest calls is a simple PHP page, ajaxdata.php, that prints out the current UNIX time on the server: Not particularly useful in real life, but good enough for testing purposes.

First attempt: the naive approach

Here’s the first thing I tried: a standard XmlHttpRequest with the full URL of a page in a different subdomain. I was pretty sure this wouldn’t work, but I wanted to verify it for myself:

<html>
<head>
<script type=”text/javascript” src=”xmlhttp.js”></script>
<script type=”text/javascript”>
var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;
function getTime(){
getUrl(AJAX_URL, gotTime);
}
function gotTime(status, headers, result) {
document.getElementById(’time’).innerHTML = result;
setTimeout(getTime, 1000)
}
window.onload = getTime;
</script>
</head>
<body>
<div id=”time”></div>
</body>
</html>

This page is served from fettig.net, and tries to make an XmlHttpRequest call to www.fettig.net. In real life, these are the same server, but the browser doesn’t know that. Unsurprisingly, this doesn’t work in any browser. You get a security error such as this one (from Firefox):

Error: uncaught exception: Permission denied to call method XMLHttpRequest.open

You can try this for yourself here.

Second attempt: using an iframe and document.domain

On my last trip to the JotSpot office Alex pointed me toward iframes and the document.domain property. iframes are similar to XmlHttpRequests in that they load data into the current page from another page. But iframes aren’t limited to pulling pages from same web server as their containing page - they can load any URL. To prevent cross-site security problems, browsers enforce the same origin policy in the javascript object model: scripts running in one frame can’t access any objects inside another iframe, unless both pages came from the same server.

There’s an exception to this rule, however. If both pages come from the same parent domain, and both of them set the property document.domain to the same parent domain, scripts running in either frame will be allowed to talk to each other. For example, say the page http://www.example.com/ loads the page http://ajax.example.com/ in an iframe. Since both pages are in the domain example.com, if both set document.domain to “example.com” they will be be given the ability to programatically access each other’s data. While there are a few differences

So, can you use an iframe with document.domain to make XmlHttpRequest connections? Yes, with two restrictions:

  1. The iframe must be served from the server to which you’ll be making XmlHttpRequest calls.
  2. You have to open the XmlHttpRequest connection before you set document.domain.

 

Here’s the code I used. First, the page test2.html:

<html>
<head>
<script type=”text/javascript”>
document.domain=”fettig.net”;
function gotTime(result) {
document.getElementById(’time’).innerHTML = “Server timestamp: ” + result;
}
</script>
</head>
<body>
Single XmlHttpRequest. Works in all modern browsers.
<div id=”time”></div>
<iframe src=”http://www.fettig.net/playground/ajax-subdomain/test2-iframe.html”>
</iframe>
</body>
</html>

This script in this page sets document.domain, and defines the function gotTime to handle the results of the XmlHttpRequest call. All the XmlHttpRequest stuff happens in an iframe, though. Here’s the code in test2-iframe.html:

<html>
<head>
<script type=”text/javascript” src=”xmlhttp.js”></script>
<script type=”text/javascript”>
var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;
function gotResult(status, headers, result) {
document.domain = “fettig.net”; // set d.d before talking to parent frame
window.parent.gotTime(result);
}
getUrl(AJAX_URL, gotResult);
</script>
</head>
</html>

test2-iframe.html makes the XmlHttpRequest call to www.fettig.net. It’s allowed to do this because it was served from www.fettig.net, so it’s just talking to its originating server. Once it gets the response back, it sets document.domain to fettig.net, to match the document.domain value of the parent frame. Now it’s allowed to talk to the parent frame using javascript, so it’s able to call window.parent.gotTime.

The key is to do this in the right order. Once you set document.domain (to anything other then the actual host the page was served from) you lose the ability to make XmlHttpRequest calls. So you’ve got to take care of your XmlHttpRequest business before you set document.domain and to enable communicating with the parent frame.

Follow those rules, though, and you’re good to go. This technique seems to work in all modern browsers (I tested in IE 6, Firefox 1.0.7, Safari 1.3, Opera 8.5, and Konqueror 3.4), and it doesn’t contain anything I’d consider a hack. You can try it yourself here. So far so good!

Third attempt: repeated XmlHttpRequests

I was happy to have figured out a way to make a single XmlHttpRequest to another server in our domain. But as presented so far, this technique has a pretty severe limitation: You can only make XmlHttpRequest calls up to the point where you set document.domain. Once you do that, you gain the ability to communicate with the parent frame, but you lose the ability to make future XmlHttpRequest calls. This wasn’t good enough for LivePage, which needs the ability to continuously make XmlHttpRequest calls to the server and handle the results. I needed a way to let the iframe communicate with both the server (using XmlHttpRequests) and the parent frame (which it can only do by setting document.domain).

This raised the question: is setting the document.domain property one-time-only, or is it possible to switch it on the fly? If it can be changed back and forth, it might be possible to change it back and forth as needed. Here’s test3-iframe.html, a modified version of the iframe page:

<html>
<head>
<script type=”text/javascript” src=”xmlhttp.js”></script>
<script type=”text/javascript”>
var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;
function gotResult(status, headers, result) {
var oldDomain = document.domain;
document.domain = “fettig.net”;
window.parent.gotTime(result);
document.domain = oldDomain;
setTimeout(getTime, 1000);
}
function getTime(){
getUrl(AJAX_URL, gotResult);
}
getTime();
</script>
</head>
</html>

Like in test2-iframe.html, the gotResult function in test3-iframe.html sets document.domain to fettig.net (to enable access to the parent frame) and then calls window.parent.gotTime. But first it stores the current value of document.domain, which defaults to the host the page was served from. After it’s finished working with the parent frame, it sets document.domain back to the original value, which restores the ability to make XmlHttpRequests. It then uses setTimeout to set up another XmlHttpRequest call. The result should be a continually updated timestamp on the main page.

You can see this in action at http://fettig.net/playground/ajax-subdomain/test3.html . This page makes repeated XmlHttpRequests, with the iframe calling a function in the parent page each time it gets a result from the server. Unfortunately, while this technique works great in IE, Safari, and Konqueror, it doesn’t work in Mozilla and Opera. The first XmlHttpRequest will work, but when you try to change document.domain back to the original value you get an error. From Firefox:

Error: [Exception... "Illegal document.domain value"
code: “1009″
nsresult: “0×805303f1 (NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN)”
location: “http://www.fettig.net/playground/ajax-subdomain/test3-iframe.html
Line: 13″]

Mozilla and Opera are more strict about the value of document.domain - it can only be set to the current value or a higher-level domain. For example, if the host is aaa.bbb.example.com, I could set document.domain to bbb.example.com. At that point I could change it again, to example.com, but I couldn’t change it back to aaa.bbb.example.com. Once you move to a higher-level domain, you’re stuck there.

 

Fourth attempt: Making it work in Mozilla

I could live without Opera, but not Mozilla. So I set out to find a way - any way - to work around this problem. After thinking about it for a while I started wondering: just how strict are security limitations on communications between frames? We know that browsers don’t let frames access each other’s objects unless they have the same document.domain. So setting a child frame’s document.domain to something different from the parent’s and then trying to look at window.parent.foo isn’t going to work. But what if you could set an attribute in the child frame that pointed to a function in the parent frame, and then changed the document domain? Would the child frame still be able to call that function?

The answer is yes, and that was the break I needed to get this thing working in Mozilla. The trick is to use two frames:

parent window
bridge iframe
child iframe

The bridge iframe and child iframe are both served from the server to which you’ll be making XmlHttpRequest calls. The parent page code is the same as in the previous examples: it defines a function to handle the XmlHttpRequest result, and loads an iframe, this time containing the bridge code, which looks like this:

<html>
<head>
<script type=”text/javascript” src=”xmlhttp.js”></script>
<script type=”text/javascript”>
function gotTime(result) {
window.parent.gotTime(result); // pass result up to the parent
}
window.onload = function(){
var subframe = document.createElement(’iframe’);
document.body.appendChild(subframe);
subframe.src = “test4-iframe.html”;
subframe.contentWindow.bridgeGotTime = gotTime;
document.domain = “fettig.net”;
}
</script>
</head>
<body></body>
</html>

 

When this frame loads, it loads another frame inside itself. Since the child frame is loading from the same server as the bridge frame, the bridge frame can access the child frame’s objects through script. The bridge frame takes advantage of this to set subframe.contentWindow.bridgeGotTime to its own gotTime function. Next, the bridge frame changes its document.domain to match that of the parent window. At this point the bridge frame loses the ability to talk directly to the child frame, since their document.domain properties no longer match. But the child frame retains the ability to communicate with the bridge frame through the bridgeGotTime function, which was set up first. And since the bridge frame’s document.domain now matches the parent frame’s document.domain, the bridge and parent can communicate freely.

 

In my limited testing, this techinique only seems to work on Mozilla-based browsers (I haven’t found a solution for Opera yet, but I haven’t spent much time on it). My final example uses a hybrid approach that tries to use document.domain switching, and then falls back on the bridge-iframe approach if the browser raises an error when you try to reset document.domain. Here’s the main page code:

<html>
<head>
<script type=”text/javascript”>
document.domain=”fettig.net”;
function gotTime(result) {
document.getElementById(’time’).innerHTML = “Server timestamp: ” + result;    }
</script>
</head>
<body>
<div id=”time”></div>
<iframe src=”http://www.fettig.net/playground/ajax-subdomain/test4-iframe.html”></iframe>
</body>
</html>

 

Same as everything else so far except that the iframe is loaded from test4-iframe.html. Here’s the code in that page:

 

<html>
<head>
<script type=”text/javascript” src=”xmlhttp.js”></script>
<script type=”text/javascript”>
var AJAX_URL=”http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php”;    function getTime(){
getUrl(AJAX_URL, gotTime);
}
function gotTime(status, headers, result) {
var oldDomain = document.domain;
if (window.bridgeGotTime) {
window.bridgeGotTime(result);
} else {
document.domain = “fettig.net”;
window.parent.gotTime(result);
}
try {
document.domain = oldDomain;
setTimeout(getTime, 1000);
} catch(e) {
// denied access to switching the domain, use bridge instead
document.location.replace(”test4-bridge.html”);
}
}
getTime();
</script>
</head>
</html>

 

This code tries to switch document.domain back and forth as needed to communicate with both the XmlHttpRequest server and parent frame. If this fails, however, it loads the bridge iframe in its place. To keep from having two different pages doing the same thing, this page also acts as the child of the bridge frame. If it sees a window.bridgeGotTime attribute it knows it’s running under the bridge iframe, so it calls window.bridgeGotTime instead of trying to talk directly to window.parent.

You can see this in action in test4.html. It works in all the latest browsers except Opera. Update:use test5.html instead. See this post for details.

End result: it’s possible to make XmlHttpRequest calls to another server in your domain. You can make repeated calls too, if you’re willing to deal with a little setup overhead. This has a number of possible benefits:

  1. You could have a dedicated Twisted server handling LivePage requests, while the main content of pages if served by Apache or some other web server.
  2. You could have a dedicated server for handling web services, including XmlHttpRequests
  3. You can use DNS to free XmlHttpRequest from the two-max-connections limit of browsers. Browsers don’t let you have more then two open connections to a server at a time - this gums things up if you’re using an app like JotSpot Live and try to have more then one tab going at a time. But if the XmlHttpRequests don’t have to be going to the same server, you can use wildcard DNS and set each page to make XmlHttpRequest calls something like randomhash.livepage.yourdomain.com.

If you’re read this far, thanks for hanging in there! I hope this is a useful tool in your bag of Ajax tricks. I’m sure there’s more to be explored here, but having gotten this far I wanted to write this post and put it up for comments. If you think I’ve overlooked something, that there’s a better way, or that all of this is an ugly hack, please tell me about it in the comments.

Tags:

Tomcat环境下,字符编码的filter

04月 20th, 2008 / No Comments » / by admin

在web.xml中,配置”Set Character Encoding” filter,可以实现客户端传入服务器端的Request对象中的数据的正确解码。

我使用的filter是Craig McClanahan写的,这位仁兄大名鼎鼎,他是Struts框架的主要体系设计师和开发者,Tomcat4的主设计师和Java Web Services Developer Pack实现包的主设计师,领导着Sun的JavaServer Faces规范开发,同时也是Java EE平台的Web Layer Archiecture。filter的代码附在文后。

web.xml中的配置如下:

<!– GBK Encodinbg Filter definition –>
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>

<!– GBK Encoding Filter mapping –>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES or CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package filters;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* <p>Example filter that sets the character encoding to be used in parsing the
* incoming request, either unconditionally or only if the client did not
* specify a character encoding. Configuration of this filter is based on
* the following initialization parameters:</p>
* <ul>
* <li><strong>encoding</strong> - The character encoding to be configured
* for this request, either conditionally or unconditionally based on
* the <code>ignore</code> initialization parameter. This parameter
* is required, so there is no default.</li>
* <li><strong>ignore</strong> - If set to “true”, any character encoding
* specified by the client is ignored, and the value returned by the
* <code>selectEncoding()</code> method is set. If set to “false,
* <code>selectEncoding()</code> is called <strong>only</strong> if the
* client has not already specified an encoding. By default, this
* parameter is set to “true”.</li>
* </ul>
*
* <p>Although this filter can be used unchanged, it is also easy to
* subclass it and make the <code>selectEncoding()</code> method more
* intelligent about what encoding to choose, based on characteristics of
* the incoming request (such as the values of the <code>Accept-Language</code>
* and <code>User-Agent</code> headers, or a value stashed in the current
* user’s session.</p>
*
* @author Craig McClanahan
* @version $Revision: 1.2 $ $Date: 2004/03/18 16:40:33 $
*/

public class SetCharacterEncodingFilter implements Filter {

// —————————————————– Instance Variables

/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;

/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;

/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;

// ——————————————————— Public Methods

/**
* Take this filter out of service.
*/
public void destroy() {

this.encoding = null;
this.filterConfig = null;

}

/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {

// Conditionally select and set the character encoding to be used
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}

// Pass control on to the next filter
chain.doFilter(request, response);

}

/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {

this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter(”encoding”);
String value = filterConfig.getInitParameter(”ignore”);
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase(”true”))
this.ignore = true;
else if (value.equalsIgnoreCase(”yes”))
this.ignore = true;
else
this.ignore = false;

}

// —————————————————— Protected Methods

/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* <code>null</code>.
* <p>
* The default implementation unconditionally returns the value configured
* by the <strong>encoding</strong> initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {

return (this.encoding);

}

}

Tags:

Spring配置,属性,bean和local的区别

04月 20th, 2008 / No Comments » / by admin

经常的<ref bean=”aaa”/>或者<ref local=”bbb”/>,这两者有什么区别?

看了http://www.springframework.org/dtd/spring-beans.dtd才明白,原来bean的类型是CDATA,local是IDREF,这表示,如果用local,那么,当前xml中必须存在id为”bbb”的bean声明,否则xml validator会报错的。

这也是local的本来含义,“本地”的bean。

如果<ref>指向的bean是在其它的配置中声明的,那么,必须用bean属性设置

Tags:

Hibernate的缓存机制介绍

04月 20th, 2008 / No Comments » / by admin

缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。

  缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。

  Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。

  Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存的两个特性:缓存的范围和缓存的并发访问策略。

持久化层的缓存的范围

  缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。

  1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。

  2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。

  3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。

  对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。

  持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。

持久化层的缓存的并发访问策略

  当多个并发的事务同时访问持久化层的缓存的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。

  在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下四种类型的并发访问策略,每一种策略对应一种事务隔离级别。

  事务型:仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。

  读写型:提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。

  非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。

  只读型:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。

  事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。

什么样的数据适合存放到第二级缓存中?

1 很少被修改的数据

2 不是很重要的数据,允许出现偶尔并发的数据

3 不会被并发访问的数据

4 参考数据

不适合存放到第二级缓存的数据?

1 经常被修改的数据

2 财务数据,绝对不允许出现并发

3 与其他应用共享的数据。

Hibernate的二级缓存

  如前所述,Hibernate提供了两级缓存,第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID

  第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。

Hibernate的二级缓存策略的一般过程如下:

1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。

2) 把获得的所有数据对象根据ID放入到第二级缓存中。

3) Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

4) 删除、更新、增加数据的时候,同时更新缓存。

  Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query缓存。

HibernateQuery缓存策略的过程如下:

1) Hibernate首先根据这些信息组成一个Query KeyQuery Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。

2) Hibernate根据这个Query KeyQuery缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。

3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。

Tags: ,

林锐-大学十年

04月 20th, 2008 / No Comments » / by admin

偶然间在网上看到林锐的《大学十年》,看了感触很深,受到很大启发
早在大一的时候就听说过他的传闻,做为学弟的我以他为荣,如果早几年看到他的文章就好了,或许我的大学生活会因为他的文章而改变 呵呵~!(自己没好好学找个借口^_^)

林锐-大学十年

一、主动去创造环境,否则你无法设计人生。 
二、生活和工作要充满激情,否则你无法体会到淋漓尽致的欢乐与痛苦。 
林锐-大学十年  

作者:林锐 
写此文使我很为难,一是担心读者误以为我轻浮得现在就开始写自传,二是担心朋友们误 以为我得了绝症而早早留下遗作。 
不论是落俗套还是不落俗套地评价,我在大学十年里都是出类拔萃的好学生。并且一直以来我对朋友们和一些低年级的学生们都有很大的正面影响。这十年是一个从幼稚到成熟的 过程,交织着聪明与蠢笨、勤奋与懒散、狂热与怯懦、成功与失败。做对了的事可树立为 榜样,做错的事可挂作为警钟。我写下经历与感受,期望以此引导和勉励无数比我年轻的 学生们。我资历尚浅,既没有哲学家的深遂,也没有诗人的风华,不足以堂皇地育人,只能讲一些故事以表心愿。 

我出生在1973年的春节,属牛,是”牛头”。父母为我起了很好听的名字叫”林锐”。这暗示 着上天对我别有用心,将降大任于我,可是这时候上帝去了一趟厕所。天堂与人间的时差 如此之大,就在上帝大小便的几分钟内,我混混沌沌地度过了童年和少年,天才因此成为凡人。 
我小时候生长在浙江黄岩的偏僻山区。父母都是中学教师,由于山区师资缺乏,父母经常 要从一个山头调到另一个山头教学。我换读过的小学的数目比我的年龄还大,没有伙伴,也没有家的概念。我就象活在货郎担里的小鸡,缩成一团,在高兴或恐惧时至多”啾”"啾” 地叫几声。我在读小学与初中的8年里,既不聪明活泼,也不调皮捣蛋,确切地说象块木头,简直是我名字的反义词。在学习上我没有受过一次表扬,也没有任何值得留念的人或事。唉,无论我现在多么努力都已无法追回失去的8年金色年华,好心痛! 
我草草地并且稀里糊涂地在13岁时从初中毕业,无处可去。这下我发慌了,开始渴望学习。我灰溜溜地离开山区,可怜巴巴地到一个比较好的乡下中学重读初三。我勤快得早晨4: 30就起来读英语,脑袋似乎也被吓开窍了,”数理化”学得很好,并且生平第一次在物理考试中得了满分。当我”再一次”从初中毕业时,我以全校第一的成绩考入了黄岩中学读高中。 
黄岩中学分农村班与城市班,我当然是农民阶级。”阶级区别与歧视”对我是相当有促进作用的。我连任了几年的卫生委员,星期六和星期天同学们习惯地把活留我,我这小官当得有滋有味。《物理》学得极好,有一种直觉帮我快速准确地解题,常常是老师刚把题目 写完我就报出答案来。上物理课时我没法讲废话,因为我一开口就是标准答案。 
可惜我的文科成绩极差。那时期盛传”学好数理化,走遍天下都不怕”,我们年少不懂事,糟踏了学文科的好时光。我写作文的最高目标就是不逃题,考试前我总是反复祈祷:我没 干过坏事,保佑我作文不逃题吧!历史考试时填写”任课老师某年某月某日在我家乡英勇就义”,比谁的成绩更接近零分。更让我沮丧的是,这些行径都不是我发明的,我顶多是个跟屁虫而已,一点回忆的自豪感都没有。 
我现在认为文科教育实质是素质教育,如果素质不高,男孩再聪明也难以成大器,当然也难以吸引好女孩。 
高考时我语文得了54分(是班里的中上水平),总分只比重点线高十几分。我不敢报考好 地方,只好选择内地。选来选去觉得西安与成都两个城市还不错,我拿把尺子在地图上一量,发现我家乡离西安的直线距离较短,于是就选了西安。老师们只听说过西安交通大学比较有名气,但谁也不了解。我以为在西安交通大学是学习开火车、开轮船的,尽管我也很渴望能开车开船,但考虑到自己的身材单小,就忍痛割爱了。我觉得西安电子科技大学 的名字很好听,符合我做科学家的梦想,于是就报考西安电子科技大学(以下简称西电) 技术物理系。 
上帝精神拌擞地从厕所回来,发现我已经上大学。也许他原先想把我安排在清华或者北大的,但事已至此,干脆也就撒手不管了。他这一偷懒反而是好事,我在读大学的十年中自由发展,成了卓而不群的学生。
刚进西电,首先吸引我的是麻雀和馍。那麻雀滚圆滚圆的,简直是会飞的肉弹。它们不怕人,成堆聚集吵闹,常让我误以为是没有人管教的一群小鸡。那馍又白又大,既不放盐也 不放糖,既不象馒头也不象包子。馍凉了后贼硬,据说有同学被楼上扔下的半块馍砸中脑 袋,当场长出一个”肉包子”。最好笑的是人们把”馍夹肉”叫成”肉夹馍”,那东西实在好吃。 
西电原是军校,作风严谨,校园并不华丽,生活有些单调。尽管我来自山清水秀的地方, 可我的确喜欢西电的粗犷与憨厚。有一天我看到一个新生写的很肉麻的赞美西电的大字报 ,有一句是”我踏上了东去的列车”,我不禁笑掉牙。这一笑意味着”大个子欺负小个子”历 史的结束,”小个子欺负大个子”新纪元的开始。 
上大学的第一个学期刚好碰上美国打伊拉克(”沙漠风暴”行动)。那时全国都在谈电子战,我们全校都是研究电子的,而且以军事应用为主。在那种气氛里,同学们都有很强的使 命感,并且被鼓动得信心十足。 
一日,系主任视察早读,偏偏有同学迟到。系主任喝问:”你为什么迟到了?” 
“因为我来迟了,”同学毫不含糊地回答,昂然入座。那时候的学生充满了理由。 
我在班里年龄小个子也小,上课时就象猩猩堆里的猴子那么显眼。由于我们是物理系学生 ,第一学期的《普通物理》课程就显得非常重要。系副主任给我们上课,他长得象叶利钦,口若悬河,板书极快。象在高中上物理课那样,我常在”叶利钦”刚写完题目时就报出答 案。开头几次,”叶利钦”满脸疑狐地扫视我们,好像是要抓住拔掉他自行车气门芯的那个捣蛋鬼。后来他在第一排发现了我,我俩乐得裂了嘴。课间休息时,”叶利钦”常坐在我旁边,乘他给同学们答疑时,我就用笔拔弄他硕大无比的手指,在他指甲上涂点什么。 
在第一学年,我就象乱草丛中的野花那样脱颖而出,倍受老师和同学们的关怀。就在我光 荣到感觉屁股都能绽放光彩的时候,发现了令我胆战心惊的学习缺陷——不会做实验。一进实验室,我就束手无策,浑身发抖。我相信大一的学生们都有虚荣心,为了维护”最聪明”这个荣耀,我完全可以掩盖、躲避甚至偷偷地弥补实验能力的不足。 我做了一件了不起的事:为了对抗虚荣的引诱,我夸大其辞地把”缺陷”告诉每一个我认识的人,让我没有机会欺骗自己。 
聪明的人并不见得都有智慧,他可能缺乏”真实”这种品质。虽然我是在硕士毕业的时候才立下誓言——”做真实、正直、优秀的科技人员”,但我在18岁的时候就已经做到了”真实” ,我必定一生保持。 
第一年暑假回家,得到一个惊喜:家里竟然有了电路实验室! 
因为我常在信中鼓吹自己实验能力何等之差,”长此以往,下场将极为悲惨”。父母经不起 这种”恐吓”,当英语教师的父亲将半年的工资连同”私有财产”全部捐出,每周到很远的商品交易市场购买电子元件以及器材,在家里建立了实验室。父亲很威严,我从小就怕他,但那个暑假我一点也不怕他。我们一起做实验,都从零学起,话不投机就用电烙铁”交流” ,完全是同事关系。后来,我的兴趣转向了计算机,家里的实验室就由父亲独掌,继续发扬光大。现在父亲修理电器的水平在家乡远近闻名,学生们都忘了他是英语教师。 母亲是数学教师,年轻时略有姿色,智力远胜我父亲。当她与他在山头的学校里相遇时,他一顿热情洋溢的饭菜就把她缴械了。我小时候家里很贫穷,家就象一条飘荡的小船,父亲划桨,母亲掌舵。当我6岁上学时,母亲就说:”儿子啊,你将来只能靠笔吃饭而不能靠 锄头吃饭。”小时候,母亲怕我变狡诈而不允许我学下棋。尽管我在大学里已经相当出色, 
母亲来信总不忘叮嘱”德智体全面发展”。她常用独特的方式检查我: 
(1)看我是否变胖。如果我胖了,表明我懒了。因为勤奋的人没有理由变胖。 
(2)看我说话是否还快。如果我说话慢条斯理,表明我变笨了。因为脑子灵活的人没有理由说话不快。 
我读博士研究生时,母亲的眉头才舒开。她经常在师生中发表自由言论:”儿子的智力与性格完全是我遗传的,他爸毫无半点功劳。”  

本科第三学期的主要课程是电路分析。电路题目常常很滑稽,当你满头大汗地解完方程式时,答案往往是零。我归纳了不少公式用于简化计算,所以照样能在老师画完电路图时报出答案。学习是如此的轻松以致于我有太多的课余时间。 
在课余我常做两件有意思的事: 
(1)我为学习较差的十几名同学办了补习班,给他们讲课,改作业,出考题。我就象老母鸡那样看护着一群小鸡,使班长、学习委员等班干部形同虚设。我这样做既提高了自己的表达能力,又帮助了同学。这事不是老师叫我干的,是我自己的主意。 
(2)我经常在宿舍里焊接电子线路,技艺渐精。我曾花了两天时间,把磁带盒做成能发声、发光的精美礼物,乐颠颠地送给一个女孩子。可惜不久后我迷上了计算机,从此再也没亲手做过好玩的东西。 
上大学以前我根本没见过计算机。在第四学期时我遇到了十年来最敬爱的老师周维真,从而对编程产生了强烈的兴趣。他教我们Fortran语言,Fortran语言本身对我没有影响,影响我的是周老师高尚的师德以及他在教学和科研中的敬业精神。我从他那里学到的是怎样做人,怎样做事。 
很多计算机系老师改作业时喜欢打”√”或打”×”了事。周老师不仅把作业里的错误都找出来,而且逐一评注”好在哪里”和”差在哪里”。为了不让周老师过于劳累,全系同学有一个约定:上课时不准吵闹,否则别来;作业必须清楚,否则别交;提的问题必须有质量,否则闭嘴。 
Fortran语言期末考试,我的卷面成绩是97分,有个女同学考了99分。我当时官为课代表,想不到被一个女生超过,甚为沮丧。可是报到系里的成绩单上,我的成绩是99分,那个女同学是97分。我以为周老师搞错了,跑去问他。周老师笑笑说:”你平时的学习表现,该得满分。不能因为考试中的一个失误而打击你的积极性,所以给你加2分作为鼓励。而她一上机就束手无策,要让她知道考试成绩高并不表示已经学好了,扣她2分以示警告。你本来就是第一名。”这时又跑来一个”查”成绩的同学,他得了59分,哀求周老师让他及格。周老师说:”你的试卷我看了好几遍,的的确确是59分。而你平时的学习表现也不会超过59分。 这一分不能加,否则我会害你一生。” 
在我这一级(90级),周老师至少为技术物理系教出两名软件高手——我和马佩军。我和马佩军读到硕士时已在软件方面雄霸西电,计算机系学生毫无翻身之望。由于马佩军不好名利,风头让我一人独得。我离开西电数年后,余威尚在。可惜我和周老师相处不到一年,他便调到北京信息工程学院。然而师恩的厚薄不在于时间长短,好的老师会让人想念、感激一辈子。 

在上大学的前三个学期,学习如同表演,有趣而且轻松。自从第四学期学习了计算机课程,我就有了新的追求,我多么渴望拥有一台计算机,可以天天编程。如果挨一个巴掌能换取一分钟上机时间的话,我愿意每天挨1440个巴掌。如果非得加上一个期限不可,我希望是一万年。我本科的专业是半导体物理,一二年级由系里负责教学,三四年级由微电子所负责教学。 
在第四学期末,我央求系里把我推荐到微电子所参加科研,贾新章教授”收留”了我。我踏进微电子所的那一脚,让我从纯粹学习转向了科研,从”高分低能”转向了”低分高能”。 

我终于有了一台286电脑,那个暑假我就睡在实验室里,时时刻刻守着它,深夜里我一个人冲着它发笑,一会儿盖上布,一会儿掀开布,一会儿摸摸它的”脸”,一会儿理理它的”辨子”。我很快地完成了任务:设计一个”立方运算”的模拟电路,并且学会了C语言。西电有个好传统,每年冬季举办一次全校性的”星火杯”学生科技作品竞赛。每届都有六七百件作品展示,低年级的学生看后无不热血沸腾,跃跃欲试。我很希望能独立开发一套软件,参加本届”星火杯”竞赛。贾新章老师是研究集成电路可靠性的,见我如此热切,就让我开发”集成电路可靠性分析软件”。 
我开始一边研究数值算法,一边设计软件。从炎热的8月份到发冷的十一月,几乎天天通宵编程,程序很快增长到一万多行。在离竞赛还剩一个月左右的时候,出现了大量的问题。不仅程序老是出错误,而且发现原先的算法并不有效。此时已经没人能够”救”我。贾老师不会编程,不知道问题究竟出在程序上还是出在算法上(实质上两者都有问题)。而那些懂软件开发的年青教师,实在看不明白我的上万行程序是如何组织的。他们只能悲伤地看着我挣扎。由于我经常逃课,好学生变成了坏学生。系里意见极大,贾老师十分为难。不少老师和同学劝我赶紧”改邪归正”,放弃项目,不值得因小失大。 
当时我有个无法动摇的信念:如果放弃一次,那么碰到下一个挫折时我就会继续放弃;如果坚持而成功,那么碰到下一个挑战时我会激励自己再取成功。 
在压力面前,我依然坚挺。每当略有进展时,心里就一阵狂喜,但很快又会碰到新的困难,有时一坐就是20个小时。每天在喜悦的颠峰与苦恼的深渊之间反复折腾。在竞赛前两天,我终于成功地完成了软件研发,结果获得软件与论文两个二等奖。这个荣誉本身不值得一提,并且我付出很重的代价——对物理专业失去兴趣而彻底抛弃了它。但那时我才19岁,在极限状态下,我磨练了意志,使我日后充满激情。 
在本科四年级,我认识了微电子所的郝跃老师。他是数学博士,是微电子所最有才华、最潇洒、最有领导风范的青年学者。我常去向他请教数学问题,他讲得意气风发,我听得如痴如醉。我俩一个月的”交流量”很多硕士花一年时间也得不到。有一天,郝老师说:”你做我的学生吧。”我就毫不迟疑地从贾老师门下”跳槽”到郝老师门下。郝老师后来是我的硕士导师,他高兴时喜欢说:”好,很好,非常好!”我看着他升教授,升博导,升副校长,师生两人分别在各自的阶层中名声显赫。 
在三四年级,我的专业课程没有一门及格过。但由于微电子所的老师们已经认可了我,就把我的卷面成绩作为及格线,”水涨船高,水落船底”,我对同学们的帮助莫大于此!如果要我考研究生,我绝对考不上。系主任安毓英觉得我将来很有前途,于是不顾别人反对,一锤定音让我免试读硕士研究生。 

读硕士研究生时,我的科研条件相当好。导师十分开明,任我自由发展。我最喜欢做的事是设计图形用户界面和开发数据可视化软件。图形软件的最大魅力是即便它毫无用处,你也可以自我欣赏。总有人担心”花很多精力、物力让界面那么漂亮,图形那么逼真是否值得 ?”这种问题不能强求别人与你一致。我当时赞美女孩子的最高境界就是把她和我的图形软件相提并论。 
我喜欢设计用户界面是因为自己有相当好的美感。在读本科时我模仿过六七个流行软件的界面。那时期大家编程都用Turbo C 2.0,我伪造了一个”Turbo C 2.6″。有个北大的博士生来实验室参观,看”Turbo C 2.6″后对我导师说:”郝老师,你们的工具比我们的先进多了”。 
我常常向同学演示、卖弄自己开发的软件。觉得还不过瘾,就写了一篇名为”用户界面设计美学”的短文。凡是路过我实验室的同学都被我逮住,被迫听完我得意之极的朗读,茫然者与痛苦者居多。不久我的朗读便所向披糜,闻声者逃之夭夭。这篇文章我6年后照搬到博士学位论文中,可见当初写时的确有所”超前”。 
我的研究工作基本上以集成电路的数值计算为主,数值计算产生的一堆数据常把我搞得晕头转向。我发现用图形来表征、解释数据可以让自己不再迷糊下去,那感觉就象刚睡醒时冲凉水一样。我硕士学位论文中的软件就是用图形来仿真集成电路生产过程中”缺陷”对成品率的影响。我并不是在看了学术论文后才开始研究可视化技术的,我是在做了工作后才发现那些好玩的技术叫做”可视化”。由于我肚子里头的确有货,在硕士一年级,我没有使用”剪刀”与”浆糊”(这是很多人写书的法宝),只化了三个月时间就写完第一本著作《微机科学可视化系统设计》。 
我在读硕士期间的工作强度与本科时的相当,但工作方式有很大不同。我有了明确的目标 :(1)开发自主版权的软件产品;(2)培养做领导的才能。这个目标可以通过团队工作,参加全国性大学生科技竞赛而实现。 
我在西电成立了”可视创意软件小组”,马佩军、戴玉宏、马晓宇是我的主要技术伙伴,帮手很多。有几个漂亮的女生负责宣传(有一个长得像孟庭苇)。办公室里贴满了标语,如”创造性的事业要靠激情来推动”,”生于忧患,死于安乐”,”让春天消失”。还有大幅的”作战图”,倒计时牌。每个伙伴写了一张”军令状”放在机器上,我迄今还记录着那些纯真、活泼、充满激情的文字。那是多么艰苦而幸福的日子,夜里放震耳欲聋的音乐、咬尖辣椒提神,有伙伴累得蹲在厕所里睡着了。 
在1994年和1995年的冬季,我们的软件作品分别获中国大学生应用科技发明大奖赛二等奖和全国大学生”挑战杯”学术科技作品竞赛二等奖。在西北地区,我们是”老大”。我成了西电学生的榜样,仰慕我的学生有一大批,我刚到浙大读博士时,收到一个西电计算机系学生的信,他说:”你走了,我呆在西电没有意思,我准备考浙大的硕士生,你到哪里我就跟到哪里。” 
在硕士毕业前,我在鉴定表上这样写道:”我热爱科技事业,如同热爱生命一样。近5年的科研工作带给我最充实的生活,也寄托着我美好的向往。可我同时也感到了痛苦,因为5年来我耳闻目睹科研中太多的弄虚作假。我发誓做一名真实、正直、优秀的科技人员,以正身自勉。” 

我在西电度过了幸福的6年半,最让我牵肠挂肚的是”吃”、”友情”和”爱情”。 
当我第一次吃红红的和青青的辣椒时,”感动”得满脸是泪,那滋味让我觉得前17年白活了。我在读硕士时已经能自力更生,我开发的软件不仅竞赛获奖争了名气,而且还挣了钱(卖了二十多份软件,平均每份挣500元)。写书得稿费7000元,那时我简直就是富翁。这些钱的小部分用来给女孩子买礼物,大部分用于和与哥儿们吃香的喝辣的。 
我相信自己已经尝遍了西安的小吃,并且发现了一个”秘密”:最好吃的东西都在地摊上,最香的东西一定是辣的,最辣的东西一定是香的。曾经沧海难为水,我在浙大的三年里很少再吃辣椒,因为怕它玷污我心目中的辣椒。 
在我小时候,我爸很讨厌土豆(在困难时期他吃了太多的土豆),他竟然因此不让我吃土豆。我哪敢跟他论理,于是忍啊忍,一直忍到我上大学”远走高飞”。如果说辣椒是我新交的女朋友,那么土豆就是我天生的命。我在西电经常用电炉(从来都没被抓住过)做”以土豆为核心”的菜,天长日久,朋友们干脆叫我”土豆”。 
我吃饱土豆和辣椒后不免深思而感叹,人要是认认真真地吃,真的花不了多少钱,那些贪官究竟是怎么吃掉巨款的?我将来怎么吃得掉自己挣来的钱? 
我在读中学与本科时,满头白发,脑袋可以当白炽灯泡用。当我硕士毕业再照镜子时,吓了一跳,白头发不见了!我不知道究竟是哪种食物起的作用(估计是辣椒)。那些早生白发的小伙子们,你们就到西安上学吧。 

马佩军是我在西电最早的朋友。刚入学时我们分到一个宿舍,他象国民党兵盘问良家妇女那样上下打量我,问:”喜欢干啥?” 
我怯生生地回答:”打乒乓球。” 
他再问:”什么风格。” 
我答:”快球。” 
他突然象阎锡山那样怪笑,拍拍我的肩膀说,”好!我喜欢,以后你就是我的朋友。我是陕西人,农民,会开拖拉机和卡车。这里是我的家,以后你有啥事,就对我吱一声。” 
马佩军和我打乒乓球时口中念念有词:”哼!你对我狠,我对你更狠;你对我好,我对你更好。”他好几次说要把世上最好吃的板栗送给我一袋,这一袋板栗我到现在都没拿到。马佩军夜里极能侃,吹他家乡的人跑得快,常把野兔追断气。有时他吹得太离谱,常令我们6个舍友群起而攻之。为了把我们一举歼灭,他白天到图书查”资料”,夜里再挑起事端。双方就象印度与巴基斯坦,常干两个秃子争一把梳子的事。 
马佩军上大学前也没见过计算机,但他对计算机技术有极强的领悟力。我们第一次上机时,他把我拉到打印机旁边说:”帮我防着管机房的,我要修理这台打印机”。还没等我反应过来,他就开始”肢解”打印机。我无比深刻地体会到:歹徒在作案时都不害怕,最提心吊胆的就是那个放风的。他在5分钟内修好了打印机,我佩服得五体投地,甘愿下次再跟他干”坏事”。 
我们读本科和硕士时主要用DOS操作系统,那时期病毒泛滥。马佩军杀病毒不用软件,用手杀。看他杀病毒简直是一种享受:噼里啪啦地敲一阵子汇编命令,然后机器就好了。求救电话太多,他经常无怨无悔地带着那双铁手游荡于西电各个角落,却不知道编写个杀病毒软件来赚钱。 
我一直认为马佩军是西电编程第一高手,他编程的时候根本不是人,是指针。之所以我的名气大,一是因为他不好名利,二是我把他的程序写上了我的名字(并且卖了不少钱)。 

马佩军的女朋友是我介绍的,我一眼就看出她将嫁给他。后来俩人果真结婚了,只是他嫁给了她,现在他还有了一只”小马驹”。硕士毕业后,马佩军留在西电读博。前年我再见到他时,他说我害死他了,快乐得要宰了我。马佩军在西电已经呆了十年,禀承了西电所有的优点与缺点——”很土但结实耐用”。我在西电时很土气,离开西电后变得”半土不洋”。 
马佩军简直就是西电人自己的”兵马俑”,每次看到他或者想起他时,我就明白自己的”根” 还在西电。我喜欢陕西人源于马佩军。 

宋任儒是我们的班长,也是班里最早的党员,满口仁义之道,比唐僧还让人受不了。在二年级时,我迷上一个比我大一岁有了男朋友的女同学,多日沮丧。他看在眼里痛在心里,跑去把那女同学教育了一通。苏联解体的时候他十分沉痛,在思想教育课上,他向我们作了深刻的检讨,好象是他没有管教好戈尔巴乔夫那小子。最后他为我们点燃了希望:在不久的将来,”苏联”将重新成为苏联,共产主义旗帜将继续在全世界飘扬。 
在本科三四年级,他对跳舞十分入迷,连上厕所都滑翔而去。我那时常把自己关在实验室里搞科研,极少有空与他玩乐,等到本科毕业时,猛地发现他已经风度翩翩。 宋任儒在读本科时学习既不好也不差,我们从来没有合作研究过什么。我喜欢他是因为他很有情趣,不落俗套,并且刚正不阿。也许,我俩本来就有相似的秉性,只是表现不同而已。 
本科毕业时,他分到威海工作,走之前我为他饯行。可在硕士开学时,我的房门被人一脚踢开,他对我喊了一声”林子啊,我又回来了”。我就象祥林嫂见到了被狼叼走的孩子那样惊喜。 
宋任儒读硕士时被发配到临憧771所,他在那里过上了乐不思蜀的日子。有一天,他带来两个看上去很文静的女孩子(一个读硕士,一个读本科)来串门。就在我洗水果的几分钟里,三个人已玩得乐翻了天,两个女孩满屋子追他,一会儿把他按到桌子上打,一会按到床上打。我惊诧至极而又羡慕至极,恨不得挨打的人是我。想不到上学竟然会有这等欢乐, 
看来我读硕士的日子白过了。 
后来,那个大一点的女孩子嫁给了他。当他带她去见公婆时,公公长叹一声:”把儿子交给你,我就放心了。”而婆婆已乐得合不拢嘴,竟然无法叹气。 
现在,宋任儒已从复旦大学获得博士学位,比我更早地成家立业。他和她既是夫妻,又象兄妹,还象伙伴。他叫她”聪聪”,她叫他”笨笨”。 
“聪聪”问”笨笨”:”老公啊,人活着为了什么?” 
“笨笨”答:”就是让咱们每天快快乐乐。” 
我亲眼看到的幸福莫过于此。 

我在大二时曾为系里学习最差的十几名同学办了补习班,谢伟在这个补习班里名列倒数前茅。在他睡懒觉时,我象催命鬼那样喊他捅他。他无比吃力地抬起沉重的眼皮,就象软弱 无力的举重运动员,还没有挺起来就趴下了。 
他开始呻吟:”这一次就饶了我吧,下一次我一定,一定会去的,求你了。” 
我不肯。 
“那么让我再睡5分钟,”他不死心。 
我仍不同意。 
“那么你就从1数到10,要慢一点,”他讨价还价。 
当我数到9时,他就接着数9.1,9.2, 9.3 …… 
一开始他觉得我很好玩,后来他就离不开我了。并不是因为我学习好,而是那时侯我天真并且充满活力。在三四年级我忙于科研时,他照顾我的生活,叫我”少爷”,既做管家又做兄长。我们不仅共用饭菜票,并且共用仅有的一个碗,总是他买饭菜和洗碗。 
我们那一级的学生大多崇拜巨人公司的创始人史玉柱,我问谢伟:”我是不是和史玉柱一样能吃苦?” 
他说:”如果考虑年龄因素,你已经比他更能吃苦。你将来一定能做大事业,我就把希望寄托于你了。” 
在我们都还不成熟的时候,我成了他心中的灯塔,只要灯不灭,希望就在。现在他为了娶一个日本姑娘,披荆斩棘追到日本,有了新的希望。 
二十几年来,我就为一个男人哭过,那时他本科毕业离校。 

我读硕士研究生时,由于受我的影响,本系三四年级的学生蜂涌至微电子所参加科研。夜里看十二层高的科技大楼,灯火通明、热闹非凡的那一层就是微电子所。那时,我在微电子所学生中的地位仿佛伊拉克的萨达姆,手下兵将极多。 
我写第一本书时,有好几个人帮我输入稿子,使我没时间慢腾腾地打草稿。我就象金庸写小说,有如神来之笔,想到那里就写到那里,写了一段他们马上输入一段,一气呵成。那本科技书写得很滑稽,同学们看得笑出眼泪,编辑看了拍案叫绝,只改了几个字就出版了。 
那时侯我的心情是如此之好,为一男同学乱蓬蓬的头发写了一篇散文,并送他一把梳子。 
又把一女同学的实验报告写成评书。我的文笔大概就是这样练出来的。 
这一群学生中,戴玉宏、史江一和马晓华是我最好的伙伴(我们都属于牛)。 
戴玉宏其貌甚帅,眉中有一根白毛闪闪发光,因此号称”白眉鹰王”。”白眉鹰王”武功了得 ,是我软件产品的核心开发人员,我们合作最深最久。后来我开公司,他就从广州辞职到杭州为我助威,令我感动不已,可见读大学时期我们有多铁!戴玉宏有一次打饱嗝,整整打了两天两夜,我差点心疼死。 
我尚未发迹之日曾与戴玉宏在校园里卖花,无人问津,就请电子工程系的鲁洁救助。鲁洁温柔貌美,她一言一笑尤如春风吹拂苏堤的杨柳,令人心里一荡再荡。顷刻间就有男生围观,有人看花,有人看”贵妃”,鲁洁一走,我和戴玉宏可怜得就象两根蜡烛。鲁洁读大学时调皮捣蛋,到四年级时还不太会编程。她的本科毕业设计是仿真”雷达跟踪飞行物”,程序基本上全是我编写的。我已记不起用了什么公式,只知道每次计算后都弹出一个对话框”报告长官,击中目标”。鲁洁毕业后到深圳的一家软件公司工作,几年一过,她成了行家。再与她交谈时,我只有听的份,象鸡啄米一样点头。 
史江一和马晓华都是陕西人,和马佩军一样厚道热情。史江一性格稳重,属于”你办事我放心”的那类人。我对微电子专业一窍不通,全靠他帮我混过实验这一关。后来我开公司失败,陷入经济危机,就把希望工程的一个小孩托给了他。 
马晓华是我最不放心的人。他常常为别人做事情,但热情过头就忘了自己的事情。有几个不道德的学生就利用他的这个缺点,经常使唤他,并且借他的钱不还。马晓华喜欢为那些人”卖命”并且挨训,他总是在受虐待够了的时候再跟我们嘀咕,我们实在气不过,只好对着他的屁股追加一顿拳脚,并给他一个绰号”受虐狂”。但愿他找个好老婆,我可以早日放心。 
我们这一群小伙子同时喜欢上一个女孩子,她叫姜姗,是她班里的四大美人之一。我们不仅没有争风吃醋,而且心甘情愿地让她坐遍每个人的脖子。姜姗小姐5岁时她爸姜晓鸿成了我的同事,我们经常一起去钓鱼,亲得象一家人。姜姗喜欢大喊大叫,声音高过帕瓦罗蒂,我们教唆她喊她爸”姜球球”。 
我常带姜姗到小吃摊去吃女孩子不敢吃的东西,并哄她:”世上最好吃的东西是鸡屁股。” 

她无师自通地加上一句:”世上最好听的屁是鸡放的屁。” 
我常想着将来生个儿子并把他培养成天才,但如果能有姜姗这样的女儿,不要儿子也罢。 

在本科三年级我第一次参加”星火杯”竞赛并获得软件二等奖后,马上成为低年级学生眼中的明星。我义务当上了一年级学生的上机辅导员。一天晚上我巡视机房,一女生请求帮助 。我见屏幕上空白一片,根本没有一行程序,十分疑惑地问:”什么问题?” ”没有问题。”她把书往我手上一塞说:”这些作业你帮我做。”然后就自个子跟她的同学玩乐,把我撇在一边,似乎我辛辛苦苦地学习就是为了给她做作业。 
我定神对她细看,发觉她简直就是《射雕英雄传》里的黄蓉再世,顿时心就”突突突”直跳。当天晚上我没睡着,接下几天的课不知所云。在选修课《操作系统》考试时,我给家里写了一封超短信:请快寄钱来,我谈恋爱了。我交了白卷直奔她去。 
我的初恋只有两个月,却让我思念了8年。她离我而去时没有任何理由,而我却失魂落魄。 
在我本科毕业前的18个月里,白天我狂热工作强作笑容,夜深人静时心痛如刀割而无法抑制。没有人为我”疗伤”,我是硬挺过去的,这一段经历使我日后心理承受能力极强。后来我开公司的失败虽然对信心有所打击,但根本无痛可言。 
我们分手后并未成为陌生人,就象两只刺猬,离得远了就有点留恋,离得近了,就刺着对方。认识她时我虽然已略显才气,但并不具备成熟男人的魅力,很多事情我并不知道怎么去把握。有时”喜欢”并不能成为”爱”,感情也许是永远研究不透的学问。 

我读硕士研究生时有了一群生机勃勃的朋友,感情的伤痛被淹没了。朋友堆里夹着一位女生,她文雅而富有气质。平日里无拘无束,大伙戏称她是我的秘书。我的言行举止和穿着都经过她的调教,俩人出双入对,十分亲近,不知不觉有了感情。别人已经把我们当成恋人,我和她牵着小姜姗散步时,简直就象一家人。 
可是我当时着迷于事业,认为自己不久将干一番惊天动地的事。鉴于史玉柱在创业时就离过婚,所以我认为感情是事业的累赘,两者不可得兼。 
更糟糕的是,我和第一个朋友藕断丝连,偏偏她俩是同班同学。我知道脚踩两只船没有好下场,可我的的确确同时喜欢着两个人,并梦想她俩能合二为一。我情愿被人指责,也不愿掩饰真实的感觉。有时她俩一同走过,我站在路上丢了魂似的看着俩人的背影,任凭看热闹的人指指点点。 
我和第二个朋友已经有了很深的感情,她毕业后我曾坐火车千里送鲜花给她,让她感动过。而我固执的性格和对初恋的思念终于让她心碎。尽管我们已经几年没见,我依然看得见她留在我心里的那颗眼泪。 

我在西电六年半的学习和生活也许是一生中最珍贵的,叫我怎能不爱西电。 
两年前我回西电,惊奇地发现校园里房前屋后长满了待收割的小麦!这所大学是从事电子科技的,种小麦干啥呀? 
朱总理曾讲过:”目前国家粮食充足,再来三年自然灾害也不怕。”现在国泰民安,似乎用不着”深挖洞,广积粮”吧。我素知西电提倡勤俭节约、自力更生,但与其种小麦还不如种蔬菜呢。 
老同学告诉我,种小麦是为了应付”211″工程(为21世纪选拔100所重点大学)的检查团,因为”211″工程有较高的绿化指标。偏偏检查赶在冬天,那时的西北极难长草。西电本来就人多地少,地上一长草马上就会被谈恋爱的学生给折磨死。一到冬天,整个校园就光秃秃一片。小麦在年轻的时候还真和青草长得一个模样,用小麦绿化校园可谓千古绝笔,检查团的那些权贵人士早已五谷不分,岂知所见的”草坪”乃是麦田。 

浙江大学依山而傍西湖,是个美丽而高贵的大学。1997年春天,我就象干儿子那样挤进她的怀抱,并期望得到关爱。我到了向往已久的计算机辅助设计与图形学(CAD&CG)国家重点实验室读博士学位。导师是石教英教授,石老师虽然年过六旬,但精力充沛,红光满面,施拉普纳不及他半分精神。 
我幸福地幻想着大干一番自己喜爱的专业,并计划在35岁左右成为实验室主任。开学的第一天,我兴冲冲地奔向实验室。进门不到5分钟,就因不懂规矩被看门的年青女子训了几次。为了不再冒犯规矩,我就老老实实地抓起一份计算机报纸并且站着阅读,心想这下不得罪谁了吧! 
突然一个气得脸色铁青的男人(机房管理员之一)对我断喝:”你在干什么!你怎么可以不经允许就翻看别人的报纸!”似乎我是他一生中见到的最无耻的人。 
我就象一个情窦初开的少年飘飘然地去拥抱梦中情人,不料迎来两个耳光,此下场比《猫和老鼠》中的猫还惨。如果这两个年轻人有幸看到我这篇文章,应该好好悔过自新,她与他的工作态度打击过数十个学生的积极性。我本是因为向往CAD&CG实验室而来的,得到的却是极坏的第一印象。(我博士毕业后,这两人也离开了实验室,我替后来的学生们谢天谢地。) 
CAD&CG实验室在理论研究方面很有名气,但我的兴趣是开发实用的软件,”嫁错人”了。我颇费周折地考入CAD&CG实验室,却尚未热身就全力而退,决心自立门户。至今我都没有用实验室的计算机编过一行程序。 

刚读博士时我穷困潦倒,只有一床,一盆,一壶,一碗。我那些穷朋友们象挤牙膏一样挤一些钱资肋我。我买了一台计算机,在宿舍里开发软件产品”可视化软件开发工具 VA 4.0 ”。1997年8月,我去北京参加首届中国大学生电脑大赛软件展示,路费也是借的。同学为我壮胆时说:”如果不能获奖,就回到实验室干活吧。” 
我说一定会拿第一名,不然去干啥。 
在软件展示时,我们发现很多好的作品是国家的科研项目,根本不是学生个人的作品,违背了竞赛的宗旨。如果允许这样做的话,学校可以运几条生产线过来。我写了一份抗议书,找了十几个人签名(很多人敢恨而不敢签)。但抗议能顶屁用,我参加过的科技竞赛、听过见过的科研鉴定多了,哪一次我没看到虚假?我写抗议书是因为眼里容不得沙子。如果我在北大读政治,恐怕早就遭殃了。 
这次竞赛选出十个”软件明星”,只有我的软件和清华大学博士生的项目值得一看。他的项目水平很高,但那不是他个人的作品(评委甚至认识他的导师,知道项目的来龙去脉)。 
综合诸多因素,我的作品被评为第一,他的项目被评为第二。组委会来拍电视,可是找不到浙江大学的展板。因为浙江大学没有任何准备,我是一个人来的,我的作品夹在杭电的作品之中,没名没姓。我只好从塑料袋上剪下”浙江大学”四个字,贴在展板上撑撑门面。 

自新中国成立以来,清华大学就一直在浙江大学头上”作威作福”,我好歹也争了一口气。可是颁奖时,组委会竟按地方顺序从北京念起,我沦落到第七,差点咽气。 
我曾在上海的一辆公共汽车上与一位北京来的旅客聊天,此公极健谈。似乎他到上海旅游的目的就是为了发掘北京的优