关于作者

用户名:和疯
笔名:和疯
地区: 中国-北京
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



JAVA网站

友情链接

访问统计:
文章个数:189
评论个数:104
留言条数:12




Powered by BlogDriver 2.1

JAVA程序员的成长经历——和疯BLOG

 

从种地到编程的转变,记录我的程序员经历, 人生因为JAVA而美丽。
QQ:59196266 MAIL:painisk@gmail.com JAVA交流群:2585418

文章

郭德纲 在线听
http://www.putongputong.com/dj.asp?action=list&class=19

- 作者: 和疯 2006年05月8日, 星期一 22:05  回复(2) |  引用(0) 加入博采

java关于日期的运算等处理方法
日期问题
1、获取服务器端当前日期:


<%@ page import="java.util.Date"%><% Date myDate = new Date();%>

2、获取当前年、月、日:


<%@ page import="java.util.Date"%><% Date myDate = new Date(); int thisYear = myDate.getYear() + 1900;//thisYear = 2003 int thisMonth = myDate.getMonth() + 1;//thisMonth = 5 int thisDate = myDate.getDate();//thisDate = 30%>

3、按本地时区输出当前日期


<%@ page import="java.util.Date"%><% Date myDate = new Date(); out.println(myDate.toLocaleString());%>

输出结果为:
2003-5-30
4、获取数据库中字段名为”publish_time“、类型为Datetime的值


<%@ page import="java.util.Date"%><% ...连接数据库... ResultSet rs = ... Date sDate = rs.getDate("publish_time");%>[code]5、按照指定格式打印日期[code]<%@ page import="java.util.Date"%><%@ page import="java.text.DateFormat"%><% Date dNow = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("E yyyy.MM.dd 'at' hh:mm:ss a zzz"); out.println("It is " + formatter.format(dNow));%>

输出的结果为:
It is 星期五 2003.05.30 at 11:30:46 上午 CST
(更为详尽的格式符号请参看SimpleDateFormat类)
6、将字符串转换为日期


<%@ page import="java.util.Date"%><%@ page import="java.text.DateFormat"%><% String input = "1222-11-11"; SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date t = null; try{ t = formatter.parse(input); out.println(t); }catch(ParseException e){ out.println("unparseable using " + formatter); }%>

输出结果为:
Fri Nov 11 00:00:00 CST 1222
7、计算日期之间的间隔


<%@ page import="java.util.Date"%><%@ page import="java.text.DateFormat"%><% String input = "2003-05-01"; SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date d1 = null; try{ d1 = formatter.parse(input); }catch(ParseException e){ out.println("unparseable using " + formatter); } Date d2 = new Date(); long diff = d2.getTime() - d1.getTime(); out.println("Difference is " + (diff/(1000*60*60*24)) + " days.");%>

输出结果为:
Difference is 29 days.
8、日期的加减运算
方法:用Calendar类的add()方法


<%@ page import="java.util.*"%><%@ page import="java.text.*"%><% Calendar now = Calendar.getInstance(); SimpleDateFormat formatter = new SimpleDateFormat("E yyyy.MM.dd 'at' hh:mm:ss a zzz"); out.println("It is now " + formatter.format(now.getTime())); now.add(Calendar.DAY_OF_YEAR,-(365*2)); out.println("<br>"); out.println("Two years ago was " + formatter.format(now.getTime()));%>

输出结果为:
It is now 星期五 2003.05.30 at 01:45:32 下午 CST
Two years ago was 星期三 2001.05.30 at 01:45:32 下午 CST
9、比较日期
方法:用equals()、before()、after()方法


<%@ page import="java.util.*"%><%@ page import="java.text.*"%><% DateFormat df = new SimpleDateFormat("yyy-MM-dd"); Date d1 = df.parse("2000-01-01"); Date d2 = df.parse("1999-12-31"); String relation = null; if(d1.equals(d2)) relation = "the same date as"; else if(d1.before(d2)) relation = "before"; else relation = "after"; out.println(d1 +" is " + relation + ' ' + d2);%>

输出结果为:
Sat Jan 01 00:00:00 CST 2000 is after Fri Dec 31 00:00:00 CST 1999
10、记录一件事所花费的时间
方法:调用两次System.getTimeMillis()方法,求差值


<%@ page import="java.text.*"%><% long t0,t1; t0 = System.currentTimeMillis(); out.println(quot;Cyc starts at " + t0); int k = 0; for(int i =0;i<100000;i++){ k += i; } t1 = System.currentTimeMillis(); out.println("<br>"); out.println("Cyc ends at " + t1); out.println("<br>"); out.println("This run took " + (t1-t0) + "ms.");%>

输出结果为:
Cyc starts at 1054275312432
Cyc ends at 1054275312442
This run took 10ms.

其它:如何格式化小数


<%@ page import="java.text.*"%><% DecimalFormat df = new DecimalFormat(",###.00"); double aNumber = 33665448856.6568975; String result = df.format(aNumber); out.println(result);%>

输出结果为:
33,665,448,856.66


在网上经常看到有人问如何将 获得当前时间并转换成
yyyy-MM-dd 年-月-日
hh:mm:ss 小时-分钟-秒
yyyy-MM-dd HH:mm:ss 年-月-日 小时-分钟-秒
三种格式 下面就是 jsp GUI 的使用方法


<!--
jsp获得当前日期
-->
<!-- 导入处理时间类,此类内部都是静态方法,直接调用即可. -->
<%@ page import="com.Mamak.util.TimeString" %>
<%
//获得当前日期时间
String nowDate = TimeString.getNowTime("yyyy-MM-dd");
String nowTime = TimeString.getNowTime("HH:mm:ss");
String nowDateTime = TimeString.getNowTime("yyyy-MM-dd HH:mm:ss");
out.println("nowDate: "+nowDate);
out.println("nowTime: "+nowTime);
out.println("nowDateTime: "+nowDateTime);
%>
//******************************************************
//GUI 或java 小程序获得得当前日期
public class Test()
{
public static void main(String abc[])
{
//直接包名点类名点方法名使用
System.out.println("nowDate: "+com.Mamak.util.TimeString.getNowTime("yyyy-MM-dd"));
System.out.println("nowTime: "+com.Mamak.util.TimeString.getNowTime("HH:mm:ss"));
System.out.println("nowDateTime: "+com.Mamak.util.TimeString.getNowTime("yyyy-MM-dd HH:mm:ss"));
}
}
//******************************************************
//获得时间的bean 文件名 TimeString.java
package com.Mamak.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class TimeString
{

public TimeString()
{
}

public static String getNowTime(String timeFormat)
{
SimpleDateFormat lformat = new SimpleDateFormat(timeFormat);
Calendar now = Calendar.getInstance();
String nowstr = lformat.format(now.getTime());
return nowstr;
}

public static String getNotTime()
{
return getNowTime("yyyy-MM-dd");
}
}

- 作者: 和疯 2006年04月29日, 星期六 14:45  回复(1) |  引用(0) 加入博采

JSP与树型菜单

1。原理简介
 dtree是一个免费的javascript脚本,只需定义有限的几个参数,就可以做出漂亮的树型菜单。下载目录:http://www.destroydrop.com/javascripts/tree/
 以下是dtree的用法示例:
 1)初始化菜单
 <script type="text/javascript">
  <!--
  var Tree = new Array;
  // nodeId | parentNodeId | nodeName | nodeUrl
  Tree[0]  = "1|0|Page 1|#";
  Tree[1]  = "2|1|Page 1.1|#";
  Tree[2]  = "3|1|Page 1.2|#";
  Tree[3]  = "4|3|Page 1.2.1|#";
  Tree[4]  = "5|1|Page 1.3|#";
  Tree[5]  = "6|2|Page 1.1.1|#";
  Tree[6]  = "7|6|Page 1.1.1.1|#";
  Tree[7]  = "8|6|Page 1.1.1.2|#";
  Tree[8]  = "9|1|Page 1.4|#";
  Tree[9]  = "10|9|Page 1.4.1|#";
  Tree[10] = "11|0|Page 2|#";
  //-->
 </script>
 2)调用函数
 <div class="tree">
  <script type="text/javascript">
  <!--
   createTree(Tree,1,7);  // starts the tree at the top and open it at node nr. 7
  //-->
  </script>
 </div>

 显然,如果用动态的脚本来初始化菜单数组(asp,jsp均可),那就可以很方便的实现动态的树型菜单了。

2。jsp动态实现
   分以下步骤实现动态的树型菜单:
   1)在数据库建tree_info表,有nodeId,parentNodeId,nodeName,nodeUrl四个字段,来存储节点信息。
   2)编写java类,用于从数据库找出节点信息,并且生成javascript脚本。
   3)编写tag类。用于封装逻辑,简化jsp的开发。
   4)建一个web程序进行测试。

3。详细过程
   1)在数据库建表,脚本如下:
   CREATE TABLE `test`.`tree_info` (
   `node_id` INTEGER UNSIGNED NOT NULL DEFAULT -1,
   `parent_id` INTEGER UNSIGNED NOT NULL DEFAULT -1,
   `node_name` VARCHAR(45) NOT NULL,
   `ref_url` VARCHAR(45) NOT NULL,
   PRIMARY KEY(`node_id`)
 )
 我使用mysql数据库,如果脚本细节有出入,请自行修改
    按照上面的dTree示例插入数据
   2)编写TreeInfo.java,这个类用于封装节点信息
     package com.diegoyun.web.tree;
  /**
   * @author Diegoyun
   * @version 1.0
   */
  public class TreeInfo {
   private int nodeId = -1;//node id
   private int parentId = -1;//parentId
   private String nodeName = null;//node name
   private String url = null;//url references

   public int getNodeId() {
    return nodeId;
   }

   public void setNodeId(int nodeId) {
    this.nodeId = nodeId;
   }

   public int getParentId() {
    return parentId;
   }

   public void setParentId(int parentId) {
    this.parentId = parentId;
   }

   public String getNodeName() {
    return nodeName;
   }

   public void setNodeName(String nodeName) {
    this.nodeName = nodeName;
&nsp;  }

   public String getUrl() {
    return url;
   }

   public void setUrl(String url) {
    this.url = url;
   }

  }
   编写TreeUtil.java,用于从数据库得到节点信息,封装到TreeInfo对象,并生成javascript脚本
   TreeUtil.java
   package com.diegoyun.web.tree;
  import java.util.Collection;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.Connection;
  import java.sql.DriverManager;

  /**
   * @author Diegoyun
   * @version 1.0
   */
  public class TreeUtil {
   public static List retrieveNodeInfos(){
    List coll = new ArrayList();

    String driverName = "com.mysql.jdbc.Driver";
    String host = "localhost";
    String port = ":3306";
    String serverID = "test";
    String userName = "root";
    String userPwd = "root";
    String url = "jdbc:mysql://" + host + port + "/" + serverID ;

    Connection conn = null ;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try{
     Class.forName(driverName).newInstance();
     conn = DriverManager.getConnection(url , userName , userPwd);
     String sql = "select * from tree_info";
     ps = conn.prepareStatement(sql);
     rs = ps.executeQuery();

     TreeInfo info = null;
     while(rs!=null && rs.next()){
      info = new TreeInfo();
      info.setNodeId(rs.getInt(1));
      info.setParentId(rs.getInt(2));
      info.setNodeName(rs.getString(3));
      info.setUrl(rs.getString(4));
      coll.add(info);
     }
  //            if(rs!=null){
  //                rs.close();
  //                rs=null;
  //            }
  //            if(ps!=null){
  //                ps.close();
  //                ps=null;
  //            }
    }catch(Exception e){
     System.out.println(e);
    }


    return coll;
   }
   public static String createTreeInfo(List alist){
    StringBuffer contents = new StringBuffer();
    contents.append("<!--\n");
    contents.append("var Tree = new Array;");//create a array in javascript
    TreeInfo info =null;
    for(int max = alist.size(),i=0;i<max;i++){
     info = (TreeInfo)alist.get(i);
     //define elements of array
     contents.append("Tree[");
     contents.append(i);
     contents.append("]=\"");
     contents.append(info.getNodeId());
     contents.append("|");
     contents.append(info.getParentId());
     contents.append("|");
     contents.append(info.getNodeName());
     contents.append("|");
     contents.append(info.getUrl());
     contents.append("\";");
    }

contents.append("docment.writer(Tree);");
    contents.append("//-->");

    return contents.toString();
   }
   public static void main(String[]args){
    List alist = TreeUtil.retrieveNodeInfos();
  //        TreeInfo info = null;
  //        for(Iterator i = c.iterator();i.hasNext();){
  //            info = (TreeInfo)i.next();
  //            System.out.println("*****" + info.getNodeName());
  //        }
    System.out.println(TreeUtil.createTreeInfo(alist));
   }
  }

 3)编写标签类
 InitTreeTag.java
 package com.diegoyun.web.taglibs;
 import com.diegoyun.web.tree.TreeUtil;
 import javax.servlet.jsp.tagext.TagSupport;
 import javax.servlet.jsp.JspException;
 import java.io.IOException;

 /**
  * @author Diegoyun
  * @version 1.0
  */
 public class InitTreeTag extends TagSupport{

  public int doEndTag() throws JspException {
   StringBuffer tree = new StringBuffer();
   tree.append("<script type=\"text/javascript\">\n");
   tree.append(TreeUtil.createTreeInfo(TreeUtil.retrieveNodeInfos()));
   tree.append("</script>\n");
   try{
    pageContext.getOut().println(tree.toString());
   }catch(IOException ioe){
    ioe.printStackTrace();
   }
   return super.doEndTag();
  }
 }

 ShowTreeTag.java :

 package com.diegoyun.web.taglibs;

 import javax.servlet.jsp.tagext.TagSupport;
 import javax.servlet.jsp.JspException;
 import java.io.IOException;

 /**
  * @author Diegoyun
  * @version 1.0
  */
 public class ShowTreeTag extends TagSupport{
  public int doEndTag() throws JspException {
   StringBuffer buffer = showTree();
   try {
    pageContext.getOut().println(buffer.toString());
   }
   catch (IOException ioe) {
    ioe.printStackTrace();
   }
   return super.doEndTag();
  }
  private StringBuffer showTree(){br />   StringBuffer sb = new StringBuffer();
   sb.append("<div class=\"tree\">\n");
   sb.append("<script type=\"text/javascript\">\n");
   sb.append("<!--\n");
   sb.append("createTree(Tree);\n");
   sb.append("//-->\n");
   sb.append("</script>\n");
   sb.append("</div>\n");
   return sb;
  }  
 }

 标签的tld如下:
 <?xml version="1.0" encoding="ISO-8859-1" ?>
 <!DOCTYPE taglib
   PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
 <taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>tree</short-name>
  <!--initTreeTag-->
  <tag>
   <name>init</name>
   <tag-class>com.diegoyun.web.taglibs.InitTreeTag</tag-class>
   <body-content>empty</body-content>
  </tag>
  <!--ShowTreeTag-->
  <tag>
   <name>show</name>
   <tag-class>com.diegoyun.web.taglibs.ShowTreeTag</tag-class>
   <body-content>empty</body-content>
  </tag>
 </taglib>

 4)建立web过程,编写jsp进行测试。

 index.jsp如下:
 <%@ page language="java"%>
 <%@ taglib uri="/WEB-INF/tlds/tree.tld" prefix="tree"%>


 <html>
 <head>
  <title>Tree example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <link rel="StyleSheet" href="tree.css" type="text/css">
  <script type="text/javascript" src="tree.js"></script>
  <tree:init/>
 </head>

 <body>


 <b>Tree example :</b><br /><br />
 <tree:show/>
 <br /><br />

  </body>
 </html>

 测试,enjoy yourself!

 

4。待解决问题
 dTree有点小bug,如果把css,img,js的路径改变,树就有可能不会正确显示。

- 作者: 和疯 2006年04月24日, 星期一 16:25  回复(5) |  引用(0) 加入博采

数码相机必备软件-Download篇

[磨皮类]

1.ABSoft NeatImage V4.0 Pro 汉化版
无须多说,内含注册机
2.DIGITAL GEM Airbrush Professional(for win2K and XP)
柯达近日新推出的Photoshop插件可以在实现去除皮肤瑕疵的同时保存头发、睫毛以及眉毛的细节,该插件16位色彩。
注册:
用户名:mikemike
地址:mike@kjcn.com
SN: AIRW1V8668J-87NF6W
3.CleanSkinFX V1.0 汉化版
这款软件可以对数码相机照的相片进行优化。例如:它可以把相片上人的面部做一些处理,可以让面部看上去更新光滑,产生一种淡化的感觉
4.夜景噪点杀手BlackFrame
数码相机的用友都对拍摄夜景时的噪点深恶痛绝,却又束手无策,这个软件可以成为您的有力武器.数码相机的噪点有两种,一种是随机噪点,是偶然因素带来的,位置不固定,另一种是CCD本身带来的,位置固定,这个软件用于消除后一种.拍摄时除原作品外,另外再盖上镜头盖拍一张补偿样本,两者复合运算,就能够消除第二种噪点
5.PhotoRefiner V1.2
本软件可以用来降低数码图片噪点。数码相机用户可能都遭遇过数字噪点问题。比如,在一幅人物照片中,噪点最明显的地方就是皮肤,脸部,衣服以及其他单色调的表面,它使得照片看上去不自然。本软件可以分析整个图像,找出有噪点的区域并降低噪点 Serial:2656045057

[修复类]

1.Zero Assumption Recovery V1.2
不小心删除了存储卡或移动硬盘上的照片,可以用此软件恢复。因机器死机,静电等以外原因引起的存储卡无法被识别亦有效果。一旦发现存储卡中需要有恢复的图片就一定不要再进行写操作。否则任何软件也挽救不了。对RAW等特殊文件格式无效。
2.Recover My Photos 2.5
破解文件
也是一款数码相机闪存卡数据恢复软件。可以快速便捷的恢复已被删除的数码照片,可以对Flash闪存卡、记忆棒、Smart卡或其他存储器进行数据恢复。
3.PhotoRecovery for Digital Media 3.0.3.0演示版
不支持硬盘
3.MediaRecover Pro v3.0.2.2 演示版
针对数码相机,PDA等移动储存设备的图像文件,数据文件的恢复程序,软件支持FLASH卡,SM卡,CF卡,存储棒,MICRO DRIVE,多媒体卡,ZIP磁盘,也支持硬盘。如果你不小心在删除或者格式化了你的存储戒质,软件可以帮你把数据恢复过来,存储在你指定的地方。
4.Object Rescue Digital PhotoRescue Pro v1.5.57 专业版
能从硬盘、CF卡、IBM Microdrives、MMC、SD、mp3player、PDA等闪存卡里恢复被误删、误格、损坏的文件。支持*.jpg .gif .crw .bmp .tiff .mpg .png 等格式的图象文件。
5.Digital Picture Recovery v2.1.2.8 Retail 完全版
支持流行的Raw文件的恢复,包括Canon的crw,Nikon的nef,Fuji的raf.Kodak的dcr和Minolta的mrw文件,很专业,速度也不错。恢复前可预览。
6.PhotoResue PC V2.0
支持各式的数码相机储存装置:SmartMedia记忆卡、CompactFlash(CF卡)、Memory Stick记忆卡、MicroDrive(微型硬盘),还可以针对文件、本机硬盘、逻辑硬盘来进行图片的还原动作。PhotoRescue在进行照片档还原之前,能够先让您预览可以还原的照片;并有PC专用及Mac OS X专用的版本

[边框类]

1. Turbo Photo V3.9
Turbo Photo 功能很多,边框只是一个小功能,但是它加的边框可以识别exif拍摄参数,自定义加到边框上。(DAC9T-EJ519-EZk3lY-SFFPX)
2.MiYa数码照片边框伴侣
3.Extensis PhotoFrame 2.5

[插件类]

1.Photowiz FocalBlade v1.01b For PhotoShop
FocalBlade 是一款功能强大的PhotoShop插件,专业图像锐化工具,不但让你锐化用于屏幕显示和出版打印的照片,而且可以创作出有着极好的模糊、柔化焦点、发光效果的作品
2.Adobe.Camera.Raw.and.Jpeg.2000.Plug-in.Bundle.v1.0 正式版
让photoshp识别raw文件格式的插件,photo CS 不需要此plugins.
SN:1045-0412-1010-2354-2661-7106
3.AGD Color Temperature Correction For Photoshop v3.0 Final 正式版
用于修正图片的色温。主要特征:支持24位或48位图片;支持Adobe Photoshop CS 48bpp 层;根据supersampling算法可高质量预览图片;精确的浮点算法;能校正曝光不足、感光过度和绿色不均等等

[浏览类]

1.ACDSee V7.0 正式版|注册机(speedlight推荐)|破解补丁|汉化补丁
无须多说
2.Xnview Deluex V2.15|注册机|Xnview V1.7高速版(密码:1836834664)
非常不错的浏览软件。(tvro001推荐)
3.ThumbsPlus Pro v7.0
与Acdsee齐名的图片浏览软件
Licensed:1
Code:gw7meypbj8wvu

[插值类]

1.S-Spline V2.2 汉化版
非常不错的插值放大软件,400W照片轻松变800W。效果不错。注册码:318Z1-G7BGQ-NC2J9-J5FA9-J2JJ7-EFAAC
2.STOIK Smart Resizer v1.0
一款数字照片缩放软件.通过STOIK智能缩放算法,能将数字照片放大到1000%也没有失真 它可以胜任从提升质量到增加分辨率等任务
3.OptiPix v3.0
OptiPix是一个专业图像处理软件,3.0版增加了几个令人心动的工具,交互式插值是其中最复杂的,这是用来扩大图片尺寸最复杂的一个工具,允许使用者通过一个交互式的界面来选择插值的方式同时预览插值之后的结果,以此得到截然不同的效果。新的重对焦工具是用来纠正对焦错误和去除画面模糊的一把利器。JPEG清洁器能够一步清楚JPEG图像的各种痕迹。

[拼图类]

1.REALVIZ Stitcher v4.1
高品质专业级全景制作工具,与Adobe hotoshop无缝平滑对接,广泛用于图象编辑、3D网页、虚拟旅游和超大尺寸全景图印刷等。是专业摄影师、多媒体艺术家和摄影爱好者的必备利器。
2.Photostitch v3.1
佳能公司随其数码相机一起发售的全景制作软件,用来将使用佳能数码相机全景功能拍摄的一组照片拼接成一幅完整的全景照

[其他类]

1.Ulead Photo Express v4.0 中文版
功能多多,主要用来做挂历,因为它可以自动生成日期。解压缩密码为 (www.chinaz.com)
2.NikonView 和Nikon Scan 相关专用软件

[RAW处理]

1.Nikon Capture 4.0 (sn=BAUD FOAM PORT)|Nikon Capture 4.13 Update|NC 4.13 汉化
NIkon 专用软件
2.Phase One C1 PRO 3.5.2 中文版|注册机|
通用: Canon EOS 1Ds/ 1D/ 300D/ 10D/ D60/ D30/ 1D MKII
Nikon D100/ D1x/ D70/ D1H/ D2H
Olympus E1/ E10/ E20
Fuji Pro S2
Pentax *istD

- 作者: 和疯 2006年04月22日, 星期六 20:53  回复(1) |  引用(0) 加入博采

一位台湾校长震动所有中国人的演讲
台湾有这么一所学校,学生年龄在15-18之间,每年三千多学生中,因违反校规校纪被校方开除的二、三百人。学校没有工人,没有保卫,没有大师傅,一切必要工种都由学生自己去做。学校实行学长制,三年级学生带一年级学生。全校集合只需3分钟。学生见到老师七米外要敬礼。学生没有寒署假作业,没有一个考不上大学的。这就是台湾享誉30年以道德教育为本的忠信高级工商学校。在台湾各大报纸招聘广告上,经常出现"只招忠信毕业生”字样。

以下是校长高震东在国内的讲演:

同学们,你们说“天下兴亡”的下一句是什么?(台下声音:“匹夫有责”)──不,是“我的责任”。如果今年高考每个人都额外加10分,那不等于没加吗?“天下兴亡,匹夫有责”等于大家无责。“匹夫有责”要改成“我的责任”,我是这样教我的学生的。所以说,现在我们大陆教育办得不好,是我高震东的责任,只因为这样,我才回祖国专门举办道德方面演讲。(掌声)“以天下兴亡为已任”是孟子思想。

禹是人,舜是人,我也是人!他们能做到的,我为什么不能? “天下兴亡,我的责任”,唯有这个思想,我们的国家才有希望。我们每个学生如果人人都说:学校秩序不好,是我的责任;国家教育办不好,是我的责任;国家不强盛,我的责任……人人都能主动负责,天下哪有不兴盛的国家?哪有不团结的团体?所以说,每个学生都应该把责任拉到自己身上来,而不是推出去。

我在台湾办学校就是这样,如果教室很脏,我问“怎么回事?”

假如有个学生站起来说:“报告老师,今天是32号同学值日,他没打扫卫生”。

那样,这个学生是要挨揍的。

在我的学校,学生会这样说:“老师,对不起,这是我的责任”,然后马上去打扫。灯泡坏了,哪个学生看见了,自己就会掏钱去买个安上,窗户玻璃坏了,学生自己马上买一块换上它──这才是教育,不把责任推出去,而是揽过来。也许有些人说这是吃亏,我告诉你,吃亏就是占便宜,这种教育要牢牢记在心里,我们每个中国人都要记住!

学校更应该训练学生这种“天下兴亡,我的责任”的思想。校园不干净,就应该是大家的责任。你想,这么大的一个校园,你不破坏,我不破坏,它会脏吗?脏了之后,人人都去弄干净,它会脏吗?你只指望几个工人做这个工作,说:“这是他们的事。我是来读书的,不是扫地的。”──这是什么观念?你读书干什么?读书不是为国家服务吗?眼前的务你都不服,你还能为未来服务?当前的责任你都不负,未来的责任你能负吗?

水龙头漏水,你不能堵住吗?有人会说:“那不是我的事,那是总务处的事。”这是错误的。

一般人最坏的毛病是这样:打开水龙头后,发现没水,又去开第二个,第二个也没有,又去开第三个 ──这样的学生,在我学校是要被开除的!连举一反三都不懂,第一个没水,第二个会有吗?你就没想到水会来吗?人无远虑怎么能行?

作为一个干部,作为一个人,都要想到后果,后果看得越远的人,越是一个成功的人。一个只管眼前,不顾将来的人,不是一个好干部,不是一个有用的人。水管不关,来了水后让它哗哗哗满池子去流,仍不去关注:“反正是国家的水,不是我的自己的!”──浪费国家的,就是“汉奸”!你为什么浪费国家的水?你为什么浪费国家的资源?我每天洗脸都为国家省一盆水,一年省多少水,你算算,你们学校六千多学生,每个每天节省一盆水,一年省多少水?省水就是省电,就是节省国家资源。爱国可有两种,一种是积极爱国,一种是消极爱国。积极爱国是为国家创造财富,消极爱国是为国家节省财富。国家用那么多百姓的民脂民膏来供你读书,你还浪费国家的财富,你良心何在?你上大学都如此,怎么能期望于中学生、小学生呢?怎么能期望于一般老百姓呢?你高级知识分子都不爱国,怎么能让老百姓去爱国呢?从自己身边做起,我们国家才有希望──这就是“天下兴亡,我的责任”积极负责的道德观念,这就是道德教育。

另一点,我们要有“勿以善小而不为,勿以恶小而为之”的敬业观念。天下有大事吗?没有。但任何小事都是大事。集小恶则成大恶,集小善则为大善。培养良好的道德,是从尊敬老师开始的,是从那很小很小的事开始的。这种道德是慢慢建立起来的,而不专门找到大事才干。

今天上午下课的时候,我和师大校长一块出来,礼堂里有很多废纸。我说不要捡,要等下午学生自己捡 ──同学们,谁丢下这些纸屑就是不爱国。天下无大事,请先把自己脚下的纸屑捡起来──这就是我的教材”。好的,同学们捡起自己脚下的废纸,这就爱国的开始。我给大家讲两个关于渍纸的故事。

第一个,美国有个“福特公司”,福特是一个人,他大学毕业后,去一家汽车公司应聘。和他同应聘的三四个人都比他学历高,当前面几个人面试之后,他觉得自己没有什么希望了。但既来之,则安之。他敲门走进了董事长办公室,一进办公室,他发现门口地上有一张纸,弯腰捡了起来,发现是一张渍纸,便顺手把它扔进了废纸篓里。然后才直到董事长的办公桌前,说:“我是来应聘的福特。”

事长说:“很好,很好!福特先生,你已被我们录用了。”福特惊讶地说:“董事长,我觉得前几位都比我好,你怎么把我录用了?”

董事长说:“福特先生,前面三位的确学历比你高,且仪表堂堂,但是他们眼睛只能“看见”大事,而看不见小事。你的眼睛能看见小事,我认为能看见小事的人,将来自然看到大事,一个只能“看见”大事的人,他会忽略很多小事。他是不会成功的。所以,我才录用你。”

福特就这样进了这个公司,这个公司不久就扬名天下,福特把这个公司改为“福特公司”,也相应改变了整个美国国民经济状况,使美国汽车产业在世界占居鳌头,这就是今天“美国福特公司”的创造人福特。大家说,这张废纸重要不重要?看见小事的人能看见大事,但只能 “看见”大事的人,不一定能看见小事,这是很重要的教训。

第二个渍纸的故事,当本届亚运会在日本广岛结束的时候,六万人的会场上竟没有一张废纸。全世界报纸都登文惊叹:“可敬,可怕的日本民族!”就是因为没有一张废纸,就使全世界为之惊讶。

再看看我们十月一日天安门广场升国旗的镜头,当人们散去,满地废纸,到处乱刮!外国人一看当然会这样认为:你们中国此时要同日本比,差得远呢!

大家不要总是说:我们国家地大物博,有137枚金牌──这都没用,咱们的道德水准还没上来,还差得远!

大家说这些废纸重要不重要?所以说,我让大家捡起一张废纸,这就是爱国的开始。

万事从小事做起。美国太空3号快到月球了,它却不能登上去而无奈地返回来,为什么?只是因为一节30块钱的小电池坏了,他们这个酝酿很久的航天计划被破坏了,几亿元报废了!天下有大事吗?大家看哪次飞机失事是翅膀和头一齐掉下来的?都是一节油管不通,一个轮胎放不下来才失事的。一个人的死,哪个是全身完全溃烂死掉的?都是肝坏了,或心脏有毛病,等等一个小器官不正常而死的!

──同学们,从现在开始,你们要有敬业观念。我们中国实行九年制教育目的就是这样,就是要看你怎样同老师相处,怎样与朋友相处,这就是教育的目的。从古至今,中国的教育才是最伟大的教育,你把西方的教育看作是最先进的教育,那就大错特错了。

美国的教育部长三个月前发表讲话说:“我们国家的教育是彻底失败的,我们把人教成了肉机器,我们要向东方学习人文教育!”所以说,我们祖国的教育是世界上最伟大的教育!(掌声)孔子告诉我们:学而不思则罔,思而不学则殆。一个学生要不断地学,不断地想,不断地做,这就是真正教育,这就是中国教育精髓所在。

再一个,我们要进行吃中国饭、说中国话、过中国节和穿中国服装的振兴民族文化的道德教育。一个中国人连中国饭都不吃了,能叫中国人吗?吃中国饭的第一代表是使用筷子。筷子原是中国的文化,是文明的行为。

我去美国,偶尔吃他们的西餐,他们一上西餐我就说:“请给我拿筷子来。”他们问我:“吃西餐都用刀叉,你为什么用筷子?”我说筷子是文明的象征,而你们的刀叉是野蛮标志,所以我不用。筷子可切、可削、可夹、可戳,无所不能,而你们的刀叉笨重至极,象杀人的武器。(掌声)

学生要吃烧鸡,我说可以,如果他说要吃“肯德鸡”,我要揍他,他说吃面包夹豆腐乳,可以,他说吃“汉堡”却不可以。你可以吃碉堡,但不能吃 “汉堡”。这就是中国的民族精神教育!

外国只是机器、枪炮比我们强,吃的能与中国比吗?吃外国人的东西只是种怪心态,可卑啊!我们学校的英文教学是全台湾最好的。我从美国请来两名老师,专门教我的学生学说外语。

我有一个留美班,他们一定是要留美的。但是他们所学的教材第一页上都印着我的话:

“中国人学英文是我们的国耻行为,学英文是中国最可悲的行为,但我们不能不学,因为别人超过了我们,“敌人”枪炮、科学压过了我们。今天我们必须学习他们的科学,然后才能打倒他们!超过他们!我们要以夷制夷!非把英文学好不可,所以要咬牙切齿学英文!(掌声)我们学英文目的并不是为了去美国洗盘子刷马桶,去伺侯外国人,去做丢尽祖宗八辈人的事!”(掌声)

所以,我的学生英文学得都非常好。如果一个英文老师一上课就说:“同学们,今天我们要学英文了。英文是世界语言,是世界上最美的语言!一个不会英文的民族是一个低等民族,英文太美了!太棒了!”你说这个老师要不要打屁股?所以我总是告诉这些老师:要好好教我的学生,你不要替外国人宣传,变成“汉奸”!要告诉学生雪耻图强,打败列强,这是中国人的希望(掌声)!你们这里不也有英文老师吗?外语系的学生以后不也去教英文吗?上课以前你们要对学生进行爱国学英文的教育,不要上来就替外国吹一场,你们不要认为:传道者只是传英文之道、授英文之业,而要传爱国之道,授英文之业。

好,同学们懂得了这些道理,下一步我们就要知道,我们今天的教育是很失败的。因为,我们从小就被教错了。所以,我们要进行为国家而求学问,为社会分工而学技能利他、利群的道德教育。大家先要想想为什么读书,为谁读书?你们要反思一下。

有些人也许会说,为自己找个饭碗而读书!这是多么卑鄙和渺小,多么无聊和可怜!你绝对不应该单是为找个饭碗而活着!找个饭碗吃饭太简单了!拿个刀子,找个人随便捅一下,绝对一辈子有了饭吃,而且还有人伺侯,还有人为你做饭,睡觉时还有人为你站岗,你的东西一样少不了!那不就解决吃饭了吗?你为什么不干呢?因为我告诉了你,要学好生存的技能,要懂得生命的意义和价值,那里不是创造人类价值的地方!所以,我们要知道读书绝对不是为了自己,读书是为了国家而求学问,所以,我们要告诉孩子们读书、做事要确定一个方向:先做自己应该做的事,再做自己喜欢做的事。

很多人为兴趣而读书,岂有此理!读书有什么兴趣?真正目标不应是兴趣,而是责任,在责任当中找到兴趣,但不能用兴趣代替责任。越在黑暗中越做光明的事,这就是道德教育。

我们读书是为了国家。同学们,你们想想你们从小受到什么教育?尤是农村子弟,你爹妈是怎么教你的?他们这样告诉你:你要好好念书!你不好好念书,将来就不能出人头地,你必须努力奋斗好好读书,你才有前途,读书是为了你的幸福,读书是为了你的前途!读书一切是为了你!你就是在这种教育下长大的,这就是最错误的教育,这就是最糟糕的教育!所以小孩子长大以后就知道,啊哈,读书就是为了我呀,与任何不相干,为了我的前途,为了我的未来,为了我的希望,你看这个国家还有希望吗?它与国家毫不相干!他喝着国家的奶水,用着国家纳税人的钱,拿民脂民膏培养出的却是一个自私自利的小孩,培养出一批自私自利的老师,你想:这国家会有前途吗?你读书的方向都错了,读书不是为了自己,读书是为了我们的国家,国家需要人才,国家需要干部,国家需要建国的栋梁。国家为什么培养你?国家是欠你的吗?你能白白吃国家的饭吗?白白享受这里的宿舍和餐厅、白白地享受老师对你知识的传授吗?你凭什么?你对国家有什么贡献?你对社会有什么贡献?有什么牺牲?你一切都没有,你只是个造粪的机器而已。你每天吃饭了,无所事事,你对国家有什么贡献?国家在期盼着你的贡献,期盼着你的未来,因为有一天你会长大,有一天你会学成,你要为国家做事,所以国家才在你身上投资,让你为国效命。因为道德教育必须以国家教育为前提,所以今天我们要爱我们的国家。正好你们是读师大的,你们在三、四年之后要培养跨世纪的接班人,你的责任比谁都大。如果你都没有国家观念,你都不爱国,你怎么要求你的学生爱国呢?所以说今天的老师是最重要的。这就是我跑来跑去,为师范生灌输爱国思想的原因所在!

你们爱国,学生自然爱国!如果不爱国,天天发牢骚,天天想转行,天天想下海,那下一代还有什么希望?尤其是学英文的,总想好好学,将来以后到哪个公司为哪个老板、哪个董事长当翻译官,多丢脸!多没人格,多没气度!(掌声)我这里特别强调的是国家观念。

我常常给我的学生讲一个故事:

我们有一天出去旅行,忽然间暴风雨来了。我们没地方避风躲雨,孩子们向前跑,一看前面有个草棚,大家“哗”地冲了进去,一冲进去大雨就来了。大家好高兴,“哇,今天运气不错哟,刚刚找了房子大雨就来了。太快乐了!”大家也不顾虑房子干不干净,有没有人住过,只要有避雨的地方就很满足了。但这个房子在风雨中突然间要倒塌,同学们想尽办法 “扶住它,不能让房子倒塌”。在这种状况下,我很有感慨,同学们,你们说是我们需要房子呢,还是房子需要我们呢?(掌声)我看是我们需要这座房子。

这座房子就是我们的国家,再破再烂是我们的家,再穷再破,是我们的家,我们要爱她!(掌声)你怎么可以羡慕外国人呢?“唉呀,你看外国人多好!我不当中国人,我想当外国人!”那是不对的。我们国家不如别人,我们承认,但是我们有决心,我们会慢慢把它搞好,但我们一定要牺牲自己,有热爱国家的观念。

人人在砍国家、吃国家、拿国家,这个国家怎么会好呢?人人都贪污、腐败,这国家会好吗?外国有个加拿大!中国有个“大家拿”,再大的国家也会被你拿穷了。(掌声)

我走到哪里,绝对拒绝招待。我走到哪里吃自己,用自己,坐你的汽车给车钱,住你的旅馆给你旅馆钱,吃你的饭给饭钱,绝对不沾国家一毛钱。我就是要做个示范给你看!(掌声)什么叫爱国,是我们把东西把钱把命给国家,这叫爱国,你总是把国家的东西往家拿,这叫什么爱国?有些人偷国家、拿国家,还拿得津津有味,拿得大言不惭,拿得毫不要脸,这怎么得了?(掌声)

有人说:老师,你让我爱国,我可以爱国,不过,国家在哪里?我找不着!“不识庐山真面目,只缘身在此山中。”你在国家里头,不知国家在哪。

当老师的,国家就是你面前的学生。你往讲台上一站,下边的学生就是你的国家,找国家太容易了。今天我往这儿一站,下面1500人就是我的国家,我必须对你们尽心尽责,就要产生教化作用,影响作用,你就是我的国家,我爱你,就是我爱国,把我的思想传播给你,就是爱国!(掌声)那你以后往你的学生面前一站,那就是你的国家。你不能浪费他的时间,他的生命,你要好好为国家培养下一代,你给他这种爱国思想,你就是一个爱国者,不给他,你就是不爱国,你就是叛国者!(掌声)

同学们,将来你也有留学的机会,你要注意到,不要让自己丢了中国人的脸。你别去了不回来,这丢中国人的脸呢!外国人是不会看得起你的。他们会说:你看,这些留学生一点国家观念都没有,这些小亡国奴!人家怎么会看得起你呢?这很丢脸,是很难为情的一件事。

国家对我们来说非常重要,你不到国外不知道“祖国”的重要。一个没有国家的,一个国势很弱的人,实在是太可怜了!太可悲了!所以,我们今天的中国人要自强、自爱,我们要知道爱我们的国家。国家不壮大,你个人再有钱有什么用?再有地位有什么用?你永远不受人尊敬啊!

我今天讲了什么是爱国主义,哪里是爱国主义,处处都是爱国主义!任何一个行为都可以爱国。

大家都知道以色列与阿拉伯的战争。阿拉伯和以色列打仗打得正热闹的时候,世界正举行选美比赛,那年以色列小组正好当选“世界小姐”。

许多电影界的人士都围着她:“小姐签约吧,将来你可以发大财了”,“签约后你名利双收,你何必回国呢,你的国家正在打仗,那么一个小国,随时会被吃掉的!”“你回去多可怕!你现在又有钱,又有名,留在美国吧!”.......

这姑娘却在电视上发表谈话:世界小姐不是我个人想选,我只是让你们知道,以色列是一个优秀的民族,所以我出来竞选。我想让人们知道:地球上有以色列这个国家,所以我要出来竞选。我今天被选上了,就完成我的任务,我也告诉世界:以色列是个优秀的民族,因为我是世界上最漂亮的女人,同时还告诉世界:以色列这个国家正艰苦奋战,希望全世界的人民同情我们,支持我们!支持我们国家的独立!现在我的国家正在打仗,要钱何用?我们以色列亡国两千年,因为我们文化不亡,所以我们还能建国。今天我要回去,为祖国而战,要钱何用?

--她发表完这番谈话,第二天就坐飞机回国了。(掌声)这个消息发表后,全世界的人对以色列刮目相看!哇,以色列人真了不起啊!于是,以色列的军队,军心大振,他们象疯了一样,把阿拉伯的军队打得干干净净!这就是历史上最伟大的七日战争!七天打完!这就是因为一个女孩子的一句话!

所以,同学们,爱国常常在一个微小的地方。“一言以丧邦,一言以兴邦”。我们是受过高等教育的,我们肩负着国家的荣辱啊,人家看到我们就看到国家的希望。同学们,国家的前途是向后看的,个人的前途是往前看的。

老师这样一回顾,就知道二十年以后的中国是什么样子,看看小学生就知道三十年后的中国是什么现象。如果他品德良好,道德高尚,爱国,二十年后国家就有希望。如果看见这个小朋友很爱国,很有礼貌,很有道德,那么三十年后的中国人是了不起的中国人。否则看着他怠惰、自私、傲慢、无礼、没有水准,就知道三十年后的中国就是那个样子。我们今天要雪耻图强,力争做得更好。不要丢了祖宗的脸,不要丢了我们汉唐先烈的脸。

爱国是很具体的。我的学校门口有个标语:离开校门一步,肩负忠信荣辱。推而广之,离开国门一步,肩负全国荣辱。

一口痰吐在中国是小事,一口痰吐在外国,你就丢了中国十三亿同胞的脸,因为你代表十三亿中国人,而不是你个人,你千万不要以为,“好汉做事好汉当”,你错了;你做不到;你不够资格当!所以每个同学的一言一举都要注意。高老师回到国内,看到不顺眼的要讲要骂,要批评要建议,但是我离开了大陆回到台湾,不会讲大陆一句坏话。他们问:大陆好吗?我说好得不得了!太大了,太棒了。到了美国就说中国人伟大得不得了,绝对不会丢中国人的脸,一句对中国的批评也没有。但是,回来一定要实实在在地讲话,诚诚恳恳建议。有的人刚好相反,在国内他屁都不敢放一个,装得那么温顺,那么可爱,一离开中国就大放獗词,把中国骂得一文不值,这就是标准的汉奸王八蛋也!

- 作者: 和疯 2006年04月22日, 星期六 19:25  回复(2) |  引用(0) 加入博采

快速启动Eclipse的参数

eclipse.exe -nl en_US -clean -vmargs -Xverify:none -XX:+UseParallelGC -XX:PermSize=20M -XX:MaxNewSize=32M -XX:NewSize=32M -Xx256m -Xms128m

-nl 后面跟的是语言

-clean 是当启动Eclipse IDE时清空缓冲,一般来说在没有更新插件的情况下,去掉这个参数启动速度更快。

-vmargs 使用JRE的参数,后面就是JRE的参数了:

-Xverify:none 去掉JAR包数据验证,一般来说只有在网络环境下才需要验证JAR包数据的有效性。本地的话可以不用验证。

-XX:+UseParallelGC 使用并行垃圾收集机制,据说这个GC算法比较快。具体不清楚。

-XX:PermSize=20M -XX:MaxNewSize=32M -XX:NewSize=32M 这三个就是设置详细的缓冲数据了。详情看Java官方网站的介绍吧。

-Xmx256m Java虚拟机最大使用内存容量,根据你所使用机器的内容大小设置,只要不超过最大内存容量就好。

-Xms128m Java虚拟机初始化内存容量。

- 作者: 和疯 2006年04月7日, 星期五 10:41  回复(2) |  引用(0) 加入博采

Linux shell 脚本
1. Linux 脚本编写基础
1.1 语法基本介绍
1.1.1 开头
程序必须以下面的行开始(必须方在文件的第一行):
#!/bin/sh
  符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。
  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。
  要使脚本可执行:
编译 chmod +x filename 这样才能用./filename 来运行
1.1.2 注释
  在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。
如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用
及工作原理。
1.1.3 变量
  在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量
进行声明。要赋值给一个变量,您可以这样写:
#!/bin/sh
#对变量赋值:
a="hello world"
# 现在打印变量a的内容:
echo "A is:"
echo $a
有时候变量名很容易与其他文字混淆,比如:
num=2
echo "this is the $numnd"
这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,
但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:
num=2
echo "this is the ${num}nd"
  这将打印: this is the 2nd
1.1.4 环境变量
由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录
脚本中使用环境变量。
1.1.5 Shell命令和流程控制
在shell脚本中可以使用三类命令:
1)Unix 命令:
  虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来
进行文件和文字操作的。
常用命令语法及功能
  echo "some text": 将文字内容打印在屏幕上
  ls: 文件列表
  wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数
  cp sourcefile destfile: 文件拷贝
  mv oldname newname : 重命名文件或移动文件
  rm file: 删除文件
  grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt
  cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出
每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,
这是两个完全不同的命令
  cat file.txt: 输出文件内容到标准输出设备(屏幕)上
  file somefile: 得到文件类型
  read var: 提示用户输入,并将输入赋值给变量
  sort file.txt: 对file.txt文件中的行进行排序
  uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq
  expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3
  find: 搜索文件比如:根据文件名搜索find . -name filename -print
  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile
  basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin
  head file: 打印文本文件开头几行
  tail file : 打印文本文件末尾几行
  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将
结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。
不要和shell中的通配符相混淆。比如:将linuxfocus 替换为
LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。
cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印
第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
命令输出结果为:Adam Bor, IndiaKerry Miller, USA
2) 概念: 管道, 重定向和 backtick
  这些不是系统命令,但是他们真的很重要。
  管道 (|) 将一个命令的输出作为另外一个命令的输入。
grep "hello" file.txt | wc -l
  在file.txt中搜索包含有”hello”的行并计算其行数。
  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。
  重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。
  > 写入文件并覆盖旧文件
  >> 加到文件的尾部,保留旧文件内容。
反短斜线
  使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
命令:
find . -mtime -1 -type f -print
  用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您
想将所有查找到的文件打一个包,则可以使用以下脚本:
#!/bin/sh
# The ticks are backticks (`) not normal quotes ('):
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
3) 流程控制
1.if
  "if" 表达式 如果条件为真则执行then后面的部分:
if ....; then
  ....
elif ....; then
  ....
else
  ....
fi
大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件
是否存在及是否可读等等…
  通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。
[ -f "somefile" ] :判断是否是一个文件
[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
[ -n "$var" ] :判断$var变量是否有值
[ "$a" = "$b" ] :判断$a和$b是否相等
  执行man test可以查看所有测试表达式可以比较和判断的类型。
  直接执行以下脚本:
#!/bin/sh
if [ "$SHELL" = "/bin/bash" ]; then
 echo "your login shell is the bash (bourne again shell)"
else
 echo "your login shell is not bash but $SHELL"
fi
  变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
快捷操作符
熟悉C语言的朋友可能会很喜欢下面的表达式:
[ -f "/etc/shadow&quo; ] && echo "This computer uses shadow passwors"
  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。
您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在
则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是
可用的。这里有个例子:
#!/bin/sh
mailfolder=/var/spool/mail/james
[ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }
echo "$mailfolder has mail from:"
grep "^From " $mailfolder
该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读
则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:
  -打印错误信息
  -退出程序
  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。
  不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。
2.case
case :表达式可以用来匹配一个给定的字符串,而不是数字。
case ... in
...) do something here ;;
esac
  让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
file lf.gz
  这将返回:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
 我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
  unzip "$1" ;;
"$1: gzip compressed"*)
  gunzip "$1" ;;
"$1: bzip2 compressed"*)
  bunzip2 "$1" ;;
*) echo "File $1 can not be uncompressed with smartzip";;
esac
  您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。
也就是说,当我们运行:
smartzip articles.zip
$1 就是字符串 articles.zip
3. selsect
select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
select var in ... ; do
 break
done
.... now $var can be used ....
下面是一个例子:
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
    break
done
echo "You have selected $var"
  下面是该脚本运行的结果:
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
4.loop
loop表达式:
while ...; do
....
done
  while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.
关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。
  
for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
for var in ....; do
  ....
done
在下面的例子中,将分别打印ABC到屏幕上:
#!/bin/sh
for var in A B C ; do
  echo "var is $var"
done
下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:
#!/bin/sh
# list a content summary of a number of RPM packages
# USAGE: showrpm rpmfile1 rpmfile2 ...
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
for rpmpackage in $*; do
 if [ -r "$rpmpackage" ];then
  echo "=============== $rpmpackage =============="
  rpm -qi -p $rpmpackage
 else
  echo "ERROR: cannot read file $rpmpackage"
 fi
done
  这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.

5. 引号
在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符
(比如*)替换成合适的文件名,它变量替换成变量值。为了防 止程序作这种替换,您可以使用
引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。
1.2 编译SHELL脚本
#ch#!/bin/sh mod +x filename
 cho *.jpg ∪缓螅梢酝ü淙耄?./filename 来执行您的脚本。
  这将打印出"mail.jpg tux.jpg"的结果。
    引号 (单引号和双引号) 将防止这种通配符扩展:
#!/bin/sh
echo "*.jpg"
echo '*.jpg'
  这将打印"*.jpg" 两次。
  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。
#!/bin/sh
echo $SHELL
echo "$SHELL"
echo '$SHELL'
  运行结果为:
/bin/bash
/bin/bash
$SHELL
  最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:
echo *.jpg
echo $SHELL
  这将输出:
*.jpg
$SHELL
6. Here documents
当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)
一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents
就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串
还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且
使用here documents打印帮助:
#!/bin/sh
# we have less than 3 arguments. Print the help text:
if [ $# -lt 3 ] ; then
cat <
ren -- renames a number of files using sed regular expressions
USAGE: ren 'regexp' 'replacement' files...
EXAMPLE: rename all *.HTM files in *.html:
 ren 'HTM$' 'html' *.HTM
HELP
 exit 0
fi
OLD="$1"
NEW="$2"
# The shift command removes one argument from the list of
# command line arguments.
shift
shift
# $* contains now all the files:
for file in $*; do
  if [ -f "$file" ] ; then
   newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
   if [ -f "$newfile" ]; then
    echo "ERROR: $newfile exists already"
   else
    echo "renaming $file to $newfile ..."
    mv "$file" "$newfile"
   fi
  fi
done
 这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是
否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递
给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。 如果输入参数等
于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我
们使用shift命令将第一个和第二个参数从 参数列表中删除,这样原来的第三个参数就成为参
数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。
接着我 们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后
将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目 的:得到了旧文件名和新
文件名。然后使用mv命令进行重命名。
4)函数
如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,
并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:
functionname()
{
# inside the body $1 is the first argument given to the function
# $2 the second ...
body
}
您需要在每个程序的开始对函数进行声明。
  下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。
这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
  cat <
xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
USAGE: xtitlebar [-h] "string_for_titelbar"
OPTIONS: -h help text
EXAMPLE: xtitlebar "cvs"
HELP
  exit 0
}
# in case of error or if -h is given w call the function help:
[ -z "$1" ] && help
[ "$1" = "-h" ] && help
# send the escape sequence to change the xterm titelbar:
echo -e "33]0;$107"
#
在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。
命令行参数
  我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令
行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的
参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现您需要更多的
自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (
比如文件名)。
有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。
#!/bin/sh
help()
{
 cat <
This is a generic command line parser demo.
USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
 exit 0
}
while [ -n "$1" ]; do
case $1 in
  -h) help;shift 1;; # function help is called
  -f) opt_f=1;shift 1;; # variable opt_f is set
  -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
  --) shift;break;; # end of options
  -*) echo "error: no such option $1. -h for help";exit 1;;
  *) break;;
esac
done
echo "opt_f is $opt_f"
echo "opt_l is $opt_l"
echo "first arg is $1"
echo "2nd arg is $2"
  您可以这样运行该脚本:
cmdparser -l hello -f -- -somefile1 somefile2
  返回的结果是:
opt_f is 1
opt_l is hello
first arg is -somefile1
2nd arg is somefile2
  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数
与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,
首先输入的应该是包含减号的参数.
第2部分 实例
现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:
cp framework.sh myscript
 然后再插入自己的函数。
  让我们再看两个例子:
  二进制到十进制的转换
  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
 cat <
b2h -- convert binary to decimal
USAGE: b2h [-h] binarynum
OPTIONS: -h help text
EXAMPLE: b2h 111010
will return 58
HELP
 exit 0
}
error()
{
  # print an error and exit
  echo "$1"
  exit 1
}
lastchar()
{
  # return the last character of a string in $rval
  if [ -z "$1" ]; then
    # empty string
    rval=""
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
  # now cut out the last char
  rval=`echo -n "$1" | cut -b $numofchar`
}
chop()
{
  # remove the last character in string and return it in $rval
  if [ -z "$1" ]; then
    # empty string
    rval=""
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
  if [ "$numofchar" = "1" ]; then
    # only one char in string
    rval=""
    return
  fi
  numofcharminus1=`expr $numofchar "-" 1`
  # now cut all but the last char:
  rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
}
while [ -n "$1" ]; do
case $1 in
  -h) help;shift 1;; # function help is called
  --) shift;break;; # end of options
  -*) error "error: no such option $1. -h for help";;
  *) break;;
esac
done
# The main program
sum=0
weight=1
# one arg must be given:
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"
while [ -n "$binnum" ]; do
  lastchar "$binnum"
  if [ "$rval" = "1" ]; then
    sum=`expr "$weight" "+" "$sum"`
  fi
  # remove the last position in $binnum
  chop "$binnum"
  binnum="$rval"
  weight=`expr "$weight" "*" 2`
done
echo "binary $binnumorig is decimal $sum"
 该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可
以这样转换成十进制:
0 * 1 + 1 * 2 = 2
  为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,
然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。
文件循环程序
  或许您是想将所有发出的邮件保存到一个文件中的人们中的一员,但是在过了几个月
以后,这个文件可能会变得很大以至于使对该文件的访问速度变慢。下面的 脚本rotatefile
可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,
而对于outmail.1就变成了outmail.2 等等等等...
#!/bin/sh
# vim: set sw=4 ts=4 et:
ver="0.1"
help()
{
  cat <
rotatefile -- rotate the file name
USAGE: rotatefile [-h] filename
OPTIONS: -h help text
EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
and create an empty out-file
The max number is 10
version $ver
HELP
  exit 0
}
error()
{
  echo "$1"
  exit 1
}
while [ -n "$1" ]; do
case $1 in
  -h) help;shift 1;;
  --) break;;
  -*) echo "error: no such option $1. -h for help";exit 1;;
  *) break;;
esac
done
# input check:
if [ -z "$1" ] ; then
error "ERROR: you must specify a file, use -h for help"
fi
filen="$1"
# rename any .1 , .2 etc file:
for n in 9 8 7 6 5 4 3 2 1; do
  if [ -f "$filen.$n" ]; then
    p=`expr $n + 1`
    echo "mv $filen.$n $filen.$p"
    mv $filen.$n $filen.$p
  fi
done
# rename the original file:
if [ -f "$filen" ]; then
  echo "mv $filen $filen.1"
  mv $filen $filen.1
fi
echo touch $filen
touch $filen
  这个脚本是如何工作的呢?在检测用户提供了一个文件名以后,我们进行一个9到1的循环。文件9被命名为10,文件8重命名为9等等。循环完成之后,我们将原始文件命名为文件1同时建立一个与原始文件同名的空文件。
调试
  最简单的调试命令当然是使用echo命令。您可以使用echo在任何怀疑出错的地方打印任何变量值。这也是绝大多数的shell程序员要花费80%的时间来调试程序的原因。Shell程序的好处在于不需要重新编译,插入一个echo命令也不需要多少时间。
  shell也有一个真实的调试模式。如果在脚本"strangescript" 中有错误,您可以这样来进行调试:
sh -x strangescript
  这将执行该脚本并显示所有变量的值。
  shell还有一个不需要执行脚本只是检查语法的模式。可以这样使用:
sh -n your_script
  这将返回所有语法错误。

- 作者: 和疯 2006年03月23日, 星期四 10:20  回复(1) |  引用(0) 加入博采

安全配置Apache服务器的五个基本步骤
 

  市场调查公司IDC最近的一项研究显示:到2008年将有三分之一的服务器采用

  .验证你的Apache来源途径。不要以为在Google上能够搜索到合适的Apache版本。如果你需要下载最新版本的Apache,那么你最好通过一个权威的镜像站点来下载。然而,即使这样也可能有问题,事实上,曾经就有黑客入侵过apache.org官方网站。所以,采用类似PGP的工具来验证Apache的数字签名就显得尤为重要。

  .保持更新Apache的补丁程序。如果你安装了Apache,你就必须及时更新安全补丁。如果没有及时的更新,那你的系统很容易受到网络上那些高危病毒的攻击。幸好,有几个简便方法可以更新Apache的补丁。参考我们关于保持更新Apache补丁的文章了解更多关于Apache服务器公告列表、Linux包管理系统和RedHat操作系统更新服务的信息。

  .避免使用.htaccess文件(分布式配置文件)。很多情况下需要几个管理员和内容管理者共同管理Apache服务器。一个常用的共享管理办法就是使用.htaccess文件,这样可以很灵活地对管理员以外的用户提供不同的配置控制权限。然而,这些文件也使得在集中安全管理之外还有相当多的安全控制权限——这些文件允许安全专业人士以外的其他用户改变服务器的访问控制许可配置。那些对粒度访问控制根本不熟悉的用户修改的配置可能在无意中会危害到你的系统安全。所以,除非必须使用,否则我们应该尽可能地避免使用这种访问控制系统。如果需要了解更多相关信息,可以参考“摒弃Apache服务器中的.htaccess文件”这篇文章。

  .监视系统日志。Apache为管理员提供了很全面的日志管理工具来对服务器的活动进行事后分析。Apache提供了多种不同的记录日志,但是对安全专业人士最重要的是访问日志。这个灵活的工具还具有了相当多的自定义功能,你可以按照你的需要很方便地记录尽可能多或者少的日志,以保证有效的分析。至少,你应该记录那些失败的认证企图和系统产生的错误。使用像AWStats一样的免费工具可以很轻松地完成分析任务。但是必须明确的一点是:监视日志只是一种事后分析手段。你可以利用它回顾和判断对服务器的攻击(和攻击企图),但是希望及时查看日志来对紧急情况做出快速反应是不可能的。如果需要进行预判反应,你应该考虑使用入侵预防系统如信息安全杂志评选的2003年度最新兴技术奖得主:Lucid Security公司的ipAngel系统。

  .管理文件系统。我们已经讨论了使用(或不使用).htaccess文件对管理文件访问权限的重要性。禁止通过文件系统许可对Apache服务器进行非授权修改也是很重要的。特别值得一提的是,你应该保证只有根用户才能修改存储在“/usr/local/apache ”目录的文件(或者你选择的任何Apache服务器的根目录)。确保只有根用户才能修改日志文件也很关键,这样可以防止用户掩盖他们的操作。

  考虑这些基本的原则,你就能够安装配置一个安全的Apache服务器。

Linux操作系统。随着在服务器上配置Linux系统的趋势越来越明显,我们也看到采用基于Linux系统的Apache网页服务器的网站也越来越多。如果你正在使用或者考虑采用Apache网页服务器,下面这五个有关Apache的安全技巧将对你有所帮助。

- 作者: 和疯 2006年03月10日, 星期五 09:45  回复(1) |  引用(0) 加入博采

Linux下Apache与Tomcat整合的简单方法
1、准备,下载需要的文件。这里假定你已经正确安装配置好了JDK。
到Apache官方网站下载所需要的文件:
httpd-2.2.0.tar.gz
apache-tomcat-5.5.12.tar.gz
jakarta-tomcat-connectors-1.2.15-src.tar.gz
其中httpd和jakarta-tomcat-connectors为源码包,apache-tomcat为二进制包。

2、安装Apache。
代码:
# tar xzvf httpd-2.2.0.tar.gz # cd httpd-2.2.0 # ./configure --prefix=/usr/local/apache2 --enable-so # make # make install

3、安装Tomcat。
代码:
# cp apache-tomcat-5.5.12.tar.gz /usr/local/ # cd /usr/local # tar xzvf apache-tomcat-5.5.12.tar.gz # ln -s apache-tomcat-5.5.12 tomcat

4、编译生成mod_jk。
代码:
# tar xzvf jakarta-tomcat-connectors-1.2.15-src.tar.gz # cd jakarta-tomcat-connectors-1.2.15-src/jk/native # ./configure --with-apxs=/usr/local/apache2/bin/apxs # make # cp ./apache-2.0/mod_jk.so /usr/local/apache2/modules/

5、配置。
在/usr/local/apache2/conf/下面建立两个配置文件mod_jk.conf和workers.properties。

# vi mod_jk.conf
添加以下内容:
代码:
# 指出mod_jk模块工作所需要的工作文件workers.properties的位置 JkWorkersFile /usr/local/apache2/conf/workers.properties # Where to put jk logs JkLogFile /usr/local/apache2/logs/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" # JkOptions indicate to send SSL KEY SIZE, JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories # JkRequestLogFormat set the request format JkRequestLogFormat "%w %V %T" # 将所有servlet 和jsp请求通过ajp13的协议送给Tomcat,让Tomcat来处理 JkMount /servlet/* worker1 JkMount /*.jsp worker1

# vi workers.properties
添加以下内容:
代码:
# Defining a worker named worker1 and of type ajp13 worker.list=worker1 # Set properties for worker1 worker.worker1.type=ajp13 worker.worker1.host=localhost worker.worker1.port=8009 worker.worker1.lbfactor=50 worker.worker1.cachesize=10 worker.worker1.cache_timeout=600 worker.worker1.socket_keepalive=1 worker.worker1.socket_timeout=300

再配置httpd.conf,作以下修改:
将Listen 80 修改为 Listen 127.0.0.1:80
将ServerName 修改为 ServerName LocalHost:80
在DirectoryIndex中添加 index.jsp
我的网页放在/var/wwwroot下,所以要修改DocumentRoot
代码:
DocumentRoot "/var/wwwroot" <Directory "/var/wwwroot"> Options Includes FollowSymLinks AllowOverride None Order deny,allow Allow from all XBitHack on </Directory> <Directory "/var/wwwroot/WEB-INF"> Order deny,allow Deny from all </Directory>

增加关于加载mod_jk的语句:
代码:
LoadModule jk_module modules/mod_jk.so Include /usr/local/apache2/conf/mod_jk.conf

最后编辑Tomcat的配置文件server.xml,在HOST段中加入:
代码:
<Context path="" docBase="/var/wwwroot" debug="0" reloadable="true" crossContext="true"/>

在/var/wwwroot下建立一个index.jsp,启动Apache和Tomcat,用浏览器访问http://localhost/,应该可以看到正确的页面了。

- 作者: 和疯 2006年03月10日, 星期五 09:44  回复(1) |  引用(0) 加入博采

Apache服务器配置全攻略

Apache服务器的设置文件位于/usr/local/apache/conf/目录下,传统上使用三个配置文件httpd.conf,access.conf和srm.conf,来配置Apache服务器的行为。

  httpd.conf提供了最基本的服务器配置,是对守护程序httpd如何运行的技术描述;srm.conf是服务器的资源映射文件,告诉服务器各种文件的MIME类型,以及如何支持这些文件;access.conf用于配置服务器的访问权限,控制不同用户和计算机的访问限制;这三个配置文件控制着服务器的各个方面的特性,因此为了正常运行服务器便需要设置好这三个文件。

  除了这三个设置文件之外,Apache还使用mime.types文件用于标识不同文件对应的MIME类型, magic文件设置不同MIME类型文件的一些特殊标识,使得Apache 服务器从文档后缀不能判断出文件的MIME 类型时,能通过文件内容中的这些特殊标记来判断文档的MIME类型。

bash-2.02$ ls -l /usr/local/apache/conf  

total 100  

-rw-r--r-- 1 root wheel 348 Apr 16 16:01 access.conf  

-rw-r--r-- 1 root wheel 348 Feb 13 13:33 access.conf.default  

-rw-r--r-- 1 root wheel 30331 May 26 08:55 httpd.conf  

-rw-r--r-- 1 root wheel 29953 Feb 13 13:33 httpd.conf.default  

-rw-r--r-- 1 root wheel 12441 Apr 19 15:42 magic  

-rw-r--r-- 1 root wheel 12441 Feb 13 13:33 magic.default  

-rw-r--r-- 1 root wheel 7334 Feb 13 13:33 mime.types  

-rw-r--r-- 1 root wheel 383 May 13 17:01 srm.conf  

-rw-r--r-- 1 root wheel 357 Feb 13 13:33 srm.conf.efault  


  事实上当前版本的Apache将原来httpd.conf、srm.conf与access.conf中的所有配置参数均放在了一个配置文件httpd.conf中,只是为了与以前的版本兼容的原因(使用这三个设置文件的方式来源于NCSA-httpd),才使用三个配置文件。而提供的access.conf和srm.conf文件中没有具体的设置。

  由于在新版本的Apache中,所有的设置都被放在了httpd.conf中,因此只需要调整这个文件中的设置。以下使用缺省提供的httpd.conf为例,解释Apache服务器的各个设置选项。然而不必因为它提供设置的参数太多而烦恼,基本上这些参数都很明确,也可以不加改动运行Apache服务器。但如果需要调整Apache服务器的性能,以及增加对某种特性的支持,就需要了解这些设置参数的含义。

  关于Apache服务器的性能,在Internet上存在很大的争议,基本上使用Apache的使用者几乎都不怀疑它的优秀性能,Apache也支撑了很多著名的高负载的网站,但是在商业机构的评测中,Apache往往得分不高。很多人指出,在这些评测中,商业Web服务器及其操作系统往往由其专业公司的工程师进行过性能调整,而Free 的操作系统和Web服务器往往就使用其缺省配置或仅仅作很小的更改。需要指出的是,除了操作系统的性能调整之外,Apache 服务器本身的缺省配置绝不是最优化和最高效的,而是要适应几乎所有种类操作系统、所有种类硬件下的设置,多平台的软件不可能为特定平台和特定硬件提供最优化的缺省配置。因此要使用Apache的时候,性能调整是必不可少的。

  在商业评测中忽略了的另一个事实是,评测时往往对不同种类的功能进行比较,例如使用Apache的标准CGI 的性能与ISAPI,NSAPI等服务器端API比较,事实上Apache服务器与此可以比较的功能为modperl ,FastCGI,与ASP类似的功能为PHP等等,只不过由于Apache的开放模式,这些功能是由独立的开发组,作为独立的模块来实现的。但是在评测中,测试人员没有加入相应的模块评测其性能。

HTTP守护进程的运行参数

  httpd.conf中首先定义了一些httpd守护进程运行时需要的参数,来决定其运行方式和运行环境。

  ServerType standalone

  ServerType定义服务器的启动方式,缺省值为独立方式standalone,httpd服务器将由其本身启动,并驻留在主机中监视连接请求。在Linux下将在启动文件 /etc/rc.d/rc.local/init.d/apache中自动启动Web服务器,这种方式是推荐设置。  

  启动Apache服务器的另一种方式是inet方式,使用超级服务器inetd监视连接请求并启动服务器。当需要使用inetd启动方式时,便需要更改为这个设置,并屏蔽/etc/rc.d/rc.local/init.d/apache文件,以及更改/etc/inetd.conf并重起inetd,那么Apache就能从inetd中启动了。  

  两种方式的区别是独立方式是由服务器自身管理自己的启动进程,这样在启动时能立即启动服务器的多个副本,每个副本都驻留在内存中,一有连接请求不需要生成子进程就可以立即进行处理,对于客户浏览器的请求反应更快,性能较高。而 inetd方式要由inetd发现有连接请求后才去启动http服务器,由于inetd 要监听太多的端口,因此反应较慢、效率较低,但节约了没有连接请求时Web服务器占用的资源。因此inetd方式只用于偶尔被访问并且不要求访问速度的服务器上。事实上inetd方式不适合http的突发和多连接的特性,因为一个页面可能包含多个图象,而每个图象都会引起一个连接请求,即使虽然访问人数造成教少,但瞬间的连接请求并不少,这就受到inetd性能的限制,甚至会影响由inetd启动的其他服务器程序。

  ServerRoot "/usr/local"  

  ServerRoot用于指定守护进程httpd的运行目录,httpd在启动之后将自动将进程的当前目录改变为这个目录,因此如果设置文件中指定的文件或目录是相对路径,那么真实路径就位于这个ServerRoot定义的路径之下。  

  由于httpd会经常进行并发的文件操作,就需要使用加锁的方式来保证文件操作不冲突,由于NFS文件系统在文件加锁方面能力有限,因此这个目录应该是本地磁盘文件系统,而不应该使用NFS文件系统。

  #LockFile /var/run/httpd.lock  

  LockFile参数指定了httpd守护进程的加锁文件,一般不需要设置这个参数, Apache服务器将自动在ServerRoot下面的路径中进行操作。但如果ServerRoot为NFS文件系统,便需要使用这个参数指定本地文件系统中的路径。  


  PidFile /var/run/httpd.pid  

  PidFile指定的文件将记录httpd守护进程的进程号,由于httpd能自动复制其自身,因此系统中有多个httpd进程,但只有一个进程为最初启动的进程,它为其他进程的父进程,对这个进程发送信号将影响所有的httpd进程。PidFILE定义的文件中就记录httpd父进程的进程号。

  ScoreBoardFile /var/run/httpd.scoreboard  

  httpd使用ScoreBoardFile来维护进程的内部数据,因此通常不需要改变这个参数,除非管理员想在一台计算机上运行几个Apache服务器,这时每个Apache服务器都需要独立的设置文件htt pd.conf,并使用不同的ScoreBoardFile。  


  #ResourceConfig conf/srm.conf  

  #AccessConfig conf/access.conf  

  这两个参数ResourceConfig和AccessConfig,就用于和使用 srm.conf 和 access.conf 设置文件的老版本Apache兼容。如果没有兼容的需要,可以将对应的设置文件指定为/dev/null,这将表示不存在其他设置文件,而仅使用httpd.conf 一个文件来保存所有的设置选项。

  Timeout 300  

  Timeout定义客户程序和服务器连接的超时间隔,超过这个时间间隔(秒)后服务器将断开与客户机的连接。

  eepAlive On  

  在HTTP 1.0中,一次连接只能作传输一次HTTP请求,而KeepAlive参数用于支持HTTP 1.1版本的一次连接、多次传输功能,这样就可以在一次连接中传递多个HTTP请求。虽然只有较新的浏览器才支持这个功能,但还是打开使用这个选项。

  MaxKeepAliveRequests 100  

  MaxKeepAliveRequests为一次连接可以进行的HTTP请求的最大请求次数。将其值设为0将支持在一次连接内进行无限次的传输请求。事实上没有客户程序在一次连接中请求太多的页面,通常达不到这个上限就完成连接了。

  KeepAliveTimeout 15  

  KeepAliveTimeout测试一次连接中的多次请求传输之间的时间,如果服务器已经完成了一次请求,但一直没有接收到客户程序的下一次请求,在间隔超过了这个参数设置的值之后,服务器就断开连接。

MinSpareServers 5MaxSpareServers 10  

  在使用子进程处理HTTP请求的Web服务器上,由于要首先生成子进程才能处理客户的请求,因此反应时间就有一点延迟。但是,Apache服务器使用了一个特殊技术来摆脱这个问题,这就是预先生成多个空余的子进程驻留在系统中,一旦有请求出现,就立即使用这些空余的子进程进行处理,这样就不存在生成子进程造成的延迟了。在运行中随着客户请求的增多,启动的子进程会随之增多,但这些服务器副本在处理完一次HTTP请求之后并不立即退出,而是停留在计算机中等待下次请求。但是空余的子进程副本不能光增加不减少,太多的空余子进程没有处理任务,也占用服务器的处理能力,因此也要限制空余副本的数量,使其保持一个合适的数量,使得既能及时回应客户请求,又能减少不必要的进程数量。  

  因此就可以使用参数MinSpareServers来设置最少的空余子进程数量, 以及使用参数MaxSpareServers 来限制最多的空闲子进程数量,多余的服务器进程副本就会退出。根据服务器的实际情况来进行设置,如果服务器性能较高,并且也被频繁访问,就应该增大这两个参数的设置。对于高负载的专业网站,这两个值应该大致相同,并且等同于系统支持的最多服务器副本数量,也减少不必要的副本退出。  


  StartServers 5  

  StartServers参数就是用来设置httpd启动时启动的子进程副本数量,这个参数与上面定义的MinSpareServers和MaxSpareServers参数相关,都是用于启动空闲子进程以提高服务器的反应速度的。这个参数应该设置为前两个值之间的一个数值,小于MinSpareServers和大于MaxS pareServers都没有意义。  


  MaxClients 150  

  在另一方面,服务器的能力毕竟是有限的,不可能同时处理无限多的连接请  

求,因此参数Maxclient s就用于规定服务器支持的最多并发访问的客户数,如果这个值设置得过大,系统在繁忙时不得不在过多的进程之间进行切换来为太多的客户进行服务,这样对每个客户的反应就会减慢,并降低了整体的效率。如果这个值设置的较小,那么系统繁忙时就会拒绝一些客户的连接请求。当服务器性能较高时,就可以适当增加这个值的设置。对于专业网站,应该使用提高服务器效率的策略,因此这个参数不能超过硬件本身的限制,如果频繁出现拒绝访问现象,就说明需要升级服务器硬件了。对于非专业网站,不太在意对客户浏览器的反应速度,或者认为反应速度较慢也比拒绝连接好,就也可以略微超过硬件条件来设置这个参数。  

  这个参数限制了MinSpareServers和MaxSpareServers的设置,它们不应该大于这个参数的设置。  


  MaxRequestsPerChild 30  

  使用子进程的方式提供服务的Web服务,常用的方式是一个子进程为一次连接服务,这样造成的问题就是每次连接都需要生成、退出子进程的系统操作,使得这些额外的处理过程占据了计算机的大量处理能力。因此最好的方式是一个子进程可以为多次连接请求服务,这样就不需要这些生成、退出进程的系统消耗,Apache就采用了这样的方式,一次连接结束后,子进程并不退出,而是停留在系统中等待下一次服务请求,这样就极大的提高了性能。  

  但由于在处理过程中子进程要不断的申请和释放内存,次数多了就会造成一些内存垃圾,就会影响系统的稳定性,并且影响系统资源的有效利用。因此在一个副本处理过一定次数的请求之后,就可以让这个子进程副本退出,再从原始的httpd进程中重新复制一个干净的副本,这样就能提高系统的稳定性。这样,每个子进程处理服务请求次数由MaxRe questPerChild定义。 缺省的设置值为30,这个值对于具备高稳定性特点的Linux系统来讲是过于保守的设置,可以设置为1000甚至更高,设置为0支持每个副本进行无限次的服务处理。  


  #Listen 3000  

  #Listen 12.34.56.78:80  

  #BindAddress *  

  Listen参数可以指定服务器除了监视标准的80端口之外,还监视其他端口的HTTP请求。由于FreeBSD系统可以同时拥有多个IP地址,因此也可以指定服务器只听取对某个BindAddress< /B>的IP地址的HTTP请求。如果没有配置这一项,则服务器会回应对所有IP的请求。  

  即使使用了BindAddress参数,使得服务器只回应对一个IP地址的请求,但是通过使用扩展的Listen参数,仍然可以让HTTP守护进程回应对其他IP地址的请求。此时Listen参数的用法与上面的第二个例子相同。这种比较复杂的用法主要用于设置虚拟主机。此后可以用VirtualHost参数定义对不同IP的虚拟主机,然而这种用法是较早的HTTP 1.0标准中设置虚拟主机的方法,每针对一个虚拟主机就需要一个IP地址,实际上用处并不大。在HTTP 1.1中,增加了对单IP地址多域名的虚拟主机的支持,使得虚拟主机的设置具备更大的意义。  


LoadModule mime_magic_module libexec/apache/mod_mime_magic.so  

LoadModule info_module libexec/apache/mod_info.so  

LoadModule speling_module libexec/apache/mod_speling.so  

LoadModule proxy_module libexec/apache/libproxy.so  

LoadModule rewrite_module libexec/apache/mod_rewrite.so  

LoadModule anon_auth_module libexec/apache/mod_auth_anon.so  

LoadModule db_auth_module libexec/apache/mod_auth_db.so  

LoadModule digest_module libexec/apache/mod_digest.so  

LoadModule cern_meta_module libexec/apache/mod_cern_meta.so  

LoadModle expires_module libexec/apache/mod_expires.so  

LoadModule headers_module libexec/apache/mod_headers.so  

LoadModule usertrack_module libexec/apache/mod_usertrack.so  

LoadModule unique_id_module libexec/apache/mod_unique_id.so  


ClearModuleList  

AddModule mod_env.c  

AddModule mod_log_config.c  

AddModule mod_mime_magic.c  

AddModule mod_mime.c  

AddModule mod_negotiation.c  

AddModule mod_status.c  

AddModule mod_info.c  

AddModule mod_include.c  

AddModule mod_autoindex.c  

AddModule mod_dir.c  

AddModule mod_cgi.c  

AddModule mod_asis.c  

AddModule mod_imap.c  

AddModule mod_actions.c  

AddModule mod_speling.c  

AddModule mod_userdir.c  

AddModule mod_proxy.c  

AddModule mod_alias.c  

AddModule mod_rewrite.c  

AddModule mod_access.c  

AddModule mod_auth.c  

AddModule mod_auth_anon.c  

AddModule mod_auth_db.c  

AddModule mod_digest.c  

AddModule mod_cern_meta.c  

AddModule mod_expires.c  

AddModule mod_headers.c  

AddModule mod_usertrack.c  

AddModule mod_unique_id.c  

AddModule mod_so.c  

AddModule mod_setenvif.c  

  Apache服务器的一个重要特性就是其模块化的结构,这不但表现为其能在编译时能通过新的模块加入新的功能,还表现为其模块可以动态加载入http服务程序中,而不必载入不需要的模块。使用Apache的动态加载模块只需要设置好Load Module和AddModule参数就可以了,这种特性就是Apache的 DSO(Dynamic Shared Object)特性,然而要想充分使用DSO特性仍然不是一个简单的事情,不适当的改动这里的设置就可能造成服务器不能正常启动。因此如果不是要增加或减少服务器提供的功能,就不要改动这里的设置。  

  上面这些列表就显示了Linux下的缺省Apache服务器支持的模块,事实上很多模块是没有必要的,不必要模块不会被载入内存。模块可以静态连接到pache 服务器内部,也可以这样动态加载,将Apache的特性都编译成动态可加载模块是该Port的做法,而不是Apache的缺省做法,这样就以牺牲很小的性能的同时,带来极大的灵活性。  

  因而动态可加载的能力还是对性能有轻微的影响,因此可以重新编译Apache,将自己所需要的功能编译进Apache 服务器内部,可以让系统显得更为干净,效率也有轻微的提高。通常仅仅为了这一个目的就重新编译Apache是没有必要的,如果需要增加其他特性而重新编译Apache,不妨在增加其他模块的同时将所有的模块都静态连接入Apache 服务器。有的使用者更喜欢动态加载模块,那么也不妨全部都使用动态加载模块。  

  这些模块都被放置到/usr/local/apache/libexec/目录下, 每个模块对应Apache服务器的一个特性。详细解释每个模块的功能需要相当多的篇幅,其中比较重要的特性将在后面相应的地方中进行解释,而具体每个模块的功能及用法就需要查看Apache的文档。  


  #ExtendedStatus On  

  Apache服务器可以通过特殊的HTTP请求,来报告自身的运行状态,打开这个ExtendedStatus 参数可以让服务器报告更全面的运行状态信息。
服务器设置

  Apache服务器需要各种设置,以定义自己使用各种参数以提供Web服务。对于使用虚拟主机的情况,除了在虚拟主机的定义项中覆盖的设置之外(有的设置必须重新定义),这里的设置也是虚拟主机的缺省设置。  


  Port 80  

  Port定义了Standalone模式下httpd守护进程使用的端口,标准端口是80。这个选项只对于以独立方式启动的服务器才有效,对于以inetd方式启动的服务器则在inetd.conf中定义使用哪个端口。  

  在Unix下使用80端口需要root权限,一些管理员为了安全的原因,认为 httpd 服务器不可能没有安全漏洞,因而更愿意使用普通用户的权限来启动服务器,这样就不能使用80端口及其他小于1024的端口,而必须使用大于 1024的端口来启动httpd,一般情况下8000或8080也是常用的端口。而Apache httpd服务器本身可以在以root权限打开80端口后再改变为普通用户身份进行运行,这样就减少了危险性,因而就不需要考虑这个安全问题。但是如果普通用户也想安装配置自己的WWW服务器,那么就不得不使用大于1024的端口。  

  User nobody  

  Group nogroup  

  User和Group配置是Apache的安全保证,Apache在打开端口之后,就将其本身设置为这两个选项设置的用户和组权限进行运行,这样就降低了服务器的危险性。这个选项也只用于 Standalone模式,inetd模式在inetd.conf中指定运行Apache的用户。由于服务器必须执行改变身份的setuid()操作,因此初始进程应该具备root权限,如果是使用非root用户来启动Aapche,这个配置就不会发挥作用。  

  缺省设置为nobody和nogroup,这个用户和组在系统中不拥有文件,保证了服务器本身和由它启动的CGI 进程没有权限更改文件系统。在某些情况下,例如为了运行CGI与Unix交互,也需要让服务器来访问服务器上的文件,如果仍然使用nobody和nogroup,那么系统中将会出现属于nobody的文件,这对于系统安全是不利的,因为其他程序也会以nobody和nogroup的权限执行某些操作,就有可能访问这些nobody拥有的文件,造成安全问题。一般情况下要为Web服务设定一个特定的用户和组,同时在这里更改用户和组设置。  


  ServerAdmin you@your.address  

  配置文件中应该改变的也许只有ServerAdmin, 这一项用于配置WWW服务器的管理员的email地址,这将在HTTP服务出现错误的条件下返回给浏览器,以便让Web使用者和管理员联系,报告错误。习惯上使用服务器上的webmaster作为WWW服务器的管理员,通过邮件服务器的别名机制,将发送到webmaster 的电子邮件发送给真正的Web管理员。  


  #ServerName new.host.name  

  缺省情况下,并不需要指定这个ServerName参数,服务器将自动通过名字解析过程来获得自己的名字,但如果服务器的名字解析有问题(通常为反向解析不正确),或者没有正式的DNS名字,也可以在这里指定IP地址。当ServerName设置不正确的时候,服务器不能正常启动。  

  通常一个Web服务器可以具有多个名字,客户浏览器可以使用所有这些名字或IP地址来访问这台服务器,但在没有定义虚拟主机的情况下,服务器总是以自己的正式名字回应浏览器。ServerName就定义了Web服务器自己承认的正式名字,例如一台服务器名字(在DNS中定义了A类型)为exmaple.org.cn,同时为了方便记忆还定义了一个别名(CNAME记录)为www.exmaple.org.cn,那么Apache自动解析得到的名字就为example.org.cn,这样不管客户浏览器使用哪个名字发送请求,服务器总是告诉客户程序自己为 example.org.cn。虽然这一般并不会造成什么问题,但是考虑到某一天服务器可能迁移到其他计算机上,而只想通过更改DNS中的www别名配置就完成迁移任务,所以不想让客户在其书签中使用 Linux 记录下这个服务器的地址,就必须使用ServerName来重新指定服务器的正式名字。  


  DocumentRoot "/www/"  

  DocumentRoot定义这个服务器对外发布的超文本文档存放的路径,客户程序请求的UR L就被映射为这个目录下的网页文件。这个目录下的子目录,以及使用符号连接指出的文件和目录都能被浏览器访问,只是要在URL上使用同样的相对目录名。  

  注意,符号连接虽然逻辑上位于根文档目录之下,但实际上可以位于计算机上的任意目录中,因此可以使客户程序能访问那些根文档目录之外的目录,这在增加了灵活性的同时但减少了安全性。Apache在目录的访问控制中提供了FollowSymLinks选项来打开或关闭支持符号连接的特性。
Options FollowSymLinks  

AllowOverride None  

  Apache服务器可以针对目录进行文档的访问控制,然而访问控制可以通过两种方式来实现,一个是在设置文件 httpd.conf(或access.conf)中针对每个目录进行设置,另一个方法是在每个目录下设置访问控制文件,通常访问控制文件名字为.htaccess。虽然使用这两个方式都能用于控制浏览器的访问,然而使用配置文件的方法要求每次改动后重新启动httpd守护进程,比较不灵活,因此主要用于配置服务器系统的整体安全控制策略,而使用每个目录下的.htaccess文件设置具体目录的访问控制更为灵活方便。  

  Directory语句就是用来定义目录的访问限制的,这里可以看出它的标准语法,为一个目录定义访问限制。上例的这个设置是针对系统的根目录进行的,设置了允许符号连接的选项FollowSymLinks ,以及使用AllowOverride None表示不允许这个目录下的访问控制文件来改变这里进行的配置,这也意味着不用查看这个目录下的相应访问控制文件。  

  由于Apache对一个目录的访问控制设置是能够被下一级目录继承的,因此对根目录的设置将影响到它的下级目录。注意由于AllowOverride None的设置,使得Apache服务器不需要查看根目录下的访问控制文件,也不需要查看以下各级目录下的访问控制文件,直至httpd.conf(或access.conf )中为某个目录指定了允许Alloworride,即允许查看访问控制文件。由于Apache对目录访问控制是采用的继承方式,如果从根目录就允许查看访问控制文件,那么Apache就必须一级一级的查看访问控制文件,对系统性能会造成影响。而缺省关闭了根目录的这个特性,就使得Apache从httpd.conf中具体指定的目录向下搜寻,减少了搜寻的级数,增加了系统性能。因此对于系统根目录设置AllowOverride None不但对于系统安全有帮助,也有益于系统性能。  


Options Indexes FollowSymLinks  

AllowOverride None  

Order allow,deny  

Allow from all  

  这里定义的是系统对外发布文档的目录的访问设置,设置不同的 AllowOverride选项,以定义配置文件中的目录设置和用户目录下的安全控制文件的关系,而Options选项用于定义该目录的特性。  

  配置文件和每个目录下的访问控制文件都可以设置访问限制,设置文件是由管理员设置的,而每个目录下的访问控制文件是由目录的属主设置的,因此管理员可以规定目录的属主是否能覆盖系统在设置文件中的设置,这就需要使用 啊AllowOverride参数进行设置,通常可以设置的值为:  

AllowOverride的设置 对每个目录访问控制文件作用的影响  

All 缺省值,使访问控制文件可以覆盖系统配置  

None 服务器忽略访问控制文件的设置  

Options 允许访问控制文件中可以使用Options参数定义目录的选项  

FileInfo 允许访问控制文件中可以使用AddType等参数设置  

AuthConfig 允许访问控制文件使用AuthName,AuthType等针对每个用户的认证机制,这使目录属主能用口令和用户名来保护目录 Limit 允许对访问目录的客户机的IP地址和名字进行限制每个目录具备一定属性,可以使用Options来控制这个目录下的一些访问特性设置,以下为常用的特性选项:  


Options设置 服务器特性设置  

All 所有的目录特性都有效,这是缺省状态  

None 所有的目录特性都无效  

FollowSymLinks 允许使用符号连接,这将使浏览器有可能访问文档根目录 (DocumentRoot)之外的文档 SymLinksIfOwnerMatch 只有符号连接的目的与符号连接本身为同一用户所拥有时,才允许访问,这个设置将增加一些安全性  

ExecCGI 允许这个目录下可以执行CGI程序 Indexes 允许浏览器可以生成这个目录下所有文件的索引,使得在这个目录下没有index.html(或其他索引文件)时,能向浏览器发送这个目录下的文件列表  

 此外,上例中还使用了Order、Allow、Deny等参数,这是Limit语句中用来根据浏览器的域名和 IP地址来控制访问的一种方式。其中Order定义处理Allow和Deny的顺序,而Allow、Deny则针对名字或IP进行访问控制设置,上例使用allowfrom all,表示允许所有的客户机访问这个目录,而不进行任何限制。  


  UserDir public_html  

  当在一台Linux上运行Apache服务器时,这台计算机上的所有用户都可以有自己的网页路径,形如 http://example.org.cn/~user,使波浪符号加上用户名就可以映射到用户自己的网页目录上。映射目录为用户个人主目录下的一个子目录,其名字就用UseDir这个参数进行定义,缺省为public_html。如果不想为正式的用户提供网页服务,使用DISABLED作UserDir的参数即可。  

#
# AllowOverride FileInfo AuthConfig Limit
# Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
#
# Order allow,deny
# Allow from all
#
#
# Order deny,allow
# Deny from all
#
#  

  这里可以看到Directory的另一个用法,即可以通过简单的模式匹配方法,针对分布在不同目录下的子目录定义访问控制权限。这样设置就需要Apache服务器对每个路径进行额外的处理,因此就会降低服务器的性能,所以缺省情况并没有打开这种访问限制。

这里可以看到另外一个语句Limit,Limit语句就是用来针对具体的请求方法来设定访问控制的,其中可以使用GET、POST等各种服务器支持的请求方法做Limit的参数,来设定对不同请求方法的访问限制。一般可以打开对GET、POST、 HEAD三种请求方法,而屏蔽其他的请求方法,以增加安全性。Limit语句中,可以用Order 、Allow、Deny,Allow和Deny中可以使用匹配的方法针对域名和IP进行限制,只是对于域名是从后向前匹配,对于IP地址则从前向后匹配。  


  DirectoryIndex index.html  

  很多情况下,URL中并没有指定文档的名字,而只是给出了一个目录名。那么Apache服务器就自动返回这个目录下由DirectoryIndex定义的文件,当然可以指定多个文件名字,系统会这个目录下顺序搜索。当所有由DirectoryIndex指定的文件都不存在时,Apache服务器可以根据系统设置,生成这个目录下的所有文件列表,提供用户选择。此时该目录的访问控制选项中的Indexes选项(Options Indexes )必须打开,以使得服务器能够生成目录列表,否则Apache将拒绝访问。  


  AccessFileName .htaccess  

  AccessFileName定义每个目录下的访问控制文件的文件名,缺省为.htaccess,可以通过更改这个文件,来改变不同目录的访问控制限制。  


  Order allow,deny  

  Deny from all  

  除了可以针对目录进行访问控制之外,还可以根据文件来设置访问控制,这就是File语句的任务。使用File 语句,不管文件处于哪个目录,只要名字匹配, 就必须接受相应的访问控制。这个语句对于系统安全比较重要,例如上例将屏蔽所有的使用者不能访问.htaccess文件,这样就避免.htaccess中的关键安全信息不至于被客户获取。  


  #CacheNegotiatedDocs  

  缺省情况下如果代理服务器和Apache服务器协商是否缓存其网页,Apache给予否定的回答,不希望自己的网页被代理服务器缓存。然而这样就不能有效的利用代理服务器的优势,因此可以设置CacheNegotiatieDocs 选项, 使得代理服务器可以对网页进行缓存。然而即使不设置这个选项,有的代理服务器(或通过调整设置)也能对网页进行缓存。  


  UseCanonicalName On  

  打开这个UseCanonicalName是Web服务器的标准做法,因为客户发送的大部分请求都是对本服务器的引用,这样服务器就能使用ServerName和Port选项的设置内容构建完整的URL,并回应客户,使浏览器能得到规范的URL。如果将这个参数设置为Off,那么Apache将使用从客户请求中获得服务器的名字和端口值(支持HTTP 1.1的客户的请求中将会有这些信息),重新构建URL。  


  TypesConfig /usr/local/apache/etc/mime.types  

  TypeConfig用于设置保存有不同的MIME类型数据的文件名,在Linux下缺省设置为/usr/local/apache/etc/mime.types。  


  DefaultType text/plain  

  如果Web服务器不能决定一个文档的缺省类型,这通常表示文档使用了非标准的后缀,那么服务器就使用 DefaultType定义的MIME类型将文档发送给客户浏览器。这里的设置为text/plain,这样设置的问题是,如果服务器不能判断出文档的MIME,那么大部分情况下这个文档为一个二进制文档,但使用 text/plain格式发送回去,浏览器将在内部打开它而不会提示保存。因此建议将这个设置更改为application/octet-stream,这样浏览器将提示用户进行保存。  


  MIMEMagicFile /usr/local/apache/etc/magic  

  除了从文件的后缀出发来判断文件的MIME类型之外,Apache还可以进一步分析文件的一些特征,来判断文件的真实MIME类型。这个功能是由mod_mime_magic 模块实现的,它需要一个记录各种MIME类型特征的文件,以进行分析判断。上面的设置是一个条件语句,如果载入了这个模块,就必须指定相应的标志文件magic的位置。

通常连接时,服务器仅仅可以得到客户机的IP地址,如果要想获得客户机的主机名,以进行日志记录和提供给 CGI程序使用,就需要使用这个HostnameLookups 选项,将其设置为On打开DNS反查功能。但是这将使服务器对每次客户请求都进行DNS查询,增加了系统开销,使得反应变慢,因此缺省设置为使用Off关闭此选项。关闭选项之后,服务器就不会获得客户机的主机名,而只能使用IP地址来记录客户。  

ErrorLog /var/log/httpd-error.log
LogLevel warn
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent} "" combined  
LogFormat "%h %l %u %t "%r" %>s %b" common  
LogFormat "%{Referer}i -> %U" referer  
LogFormat "%{User-agent}i" agent  
#CustomLog /var/log/httpd-access.log common  
#CustomLog /var/log/httpd-referer.log referer  
#CustomLog /var/log/httpd-agent.log agent  
CustomLog /var/log/httpdaccess.log combined

  这里定义了系统日志的形式,对于服务器错误记录, 由ErrorLog、 LogLevel 来定义不同的错误日志文件及其记录内容。  

  对于系统的访问日志,缺省使用CustomLog参数定义日志的位置,缺省使用 combined 参数指定将所有的访问日志放在一个文件中,然而也可以将不同种类的访问日志放在不同的日志记录文件中,这是通过在 CustomLog中指定不同的记录类型来完成的。common表示普通的对单页面请求访问记录,referer表示每个页面的引用记录,可以看出一个页面中包含的请求数,agent表示对客户机的类型记录,显然可以将现有的combined 定义的设置行注释掉,并使用common、referer和agent作为CustomLog的参数,来为不同种类的日志分别指定日志记录文件。  

  显然,LogFormat是用于定义不同类型的日志进行记录时使用的格式, 这里使用了以%开头的宏定义,以记录不同的内容。  

  如果这些参数指定的文件使用的是相对路径,那么就是相对于ServerRoot的路径。  

  ServerSignature On  

  一些情况下,例如当客户请求的网页并不存在时,服务器将产生错误文档,缺省情况下由于打开了 ServerSignature选项,错误文档的最后一行将包含服务器的名字、Apache的版本等信息。有的管理员更倾向于不对外显示这些信息,就可以将这个参数设置为Off,或者设置为Email,最后一行将替换为对 ServerAdmin 的Email提示。  

Alias /icons/ "/www/icons/"  
Options Indexes MultiViews  
AllowOverride None  
Order allow,deny  
Allow from all  


  Alias参数用于将URL与服务器文件系统中的真实位置进行直接映射,一般的文档将在DocumentRoot 中进行查询,然而使用Alias定义的路径将直接映射到相应目录下,而不再到DocumentRoot 下面进行查询。因此Alias可以用来映射一些公用文件的路径,例如保存了各种常用图标的icons路径。这样使得除了使用符号连接之外,文档根目录(DocumentRoot)外的目录也可以通过使用了Alias映射,提供给浏览器访问。  

  定义好映射的路径之后,应该需要使用Directory语句设置访问限制。  

ScriptAlias /cgi-bin/ "/www/cgi-bin/"  
AllowOverride None  
Options None  
Order allow,deny  
Allow from all  

  ScriptAlias也是用于URL路径的映射,但与Alias的不同在于,ScriptAlias 是用于映射CGI程序的路径,这个路径下的文件都被定义为CGI程序,通过执行它们来获得结果,而非由服务器直接返回其内容。缺省情况下CGI程序使用cgi-bin目录作为虚拟路径。  

  # Redirect old-URI new-URL  

  Redirect参数是用来重写URL的,当浏览器访问服务器上的一个已经不存在的资源的时候,服务器返回给浏览器新的URL,告诉浏览器从该URL中获取资源。这主要用于原来存在于服务器上的文档,改变了位置之后,而又希望能使用老URL能访问到,以保持与以前的URL兼容。  


IndexOptions FancyIndexing  
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip  
AddIconByType (TXT,/icons/text.gif) text/*  
AddIconByType (IMG,/icons/image2.gif) image/*  
AddIconByType (SND,/icons/sound2.gif) audio/*  
AddIconByType (VID,/icons/movie.gif) video/*  
AddIcon /icons/binary.gif .bin .exe  
AddIcon /icons/binhex.gif .hqx  
AddIcon /icons/tar.gif .tar  
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv  
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip  
AddIcon /icons/a.gif .ps .ai .eps  
AddIcon /icons/layout.gif .html .shtml .htm .pdf  
AddIcon /icons/text.gif .txt  
AddIcon /icons/c.gif .c  
AddIcon /icons/p.gif .pl .py  
AddIcon /icons/f.gif .for  
AddIcon /icons/dvi.gif .dvi  
AddIcon /icons/uuencoded.gif .uu  
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl  
AddIcon /icons/tex.gif .tex  
AddIcon /icons/bomb.gif core  
AddIcon /icons/back.gif ..  
AddIcon /icons/hand.right.gif README  
AddIcon /icons/folder.gif ^^DIRECTORY^^  
AddIcon /icons/blank.gif ^^BLANKICON^^  
DefaultIcon /icons/unknown.gif  
#AddDescription "GZIP compressed document" .gz  
#AddDescription "tar archive" .tar  
#AddDescription "GZIP compressed tar archive" .tgz  
ReadmeName README  
HeaderName HEADER  
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t  

  当一个HTTP请求的URL为一个目录的时候,服务器返回这个目录中的索引文件。但如果一个目录中不存在缺省的索引文件,并且该服务器又许可显示目录文件列表的时候,就会显示出这个目录中的文件列表,为了使得这个文件列表能具有可理解性,而不仅仅是一个简单的列表,就需要前面的这些设置参数。

如果使用了IndexOptions FancyIndexing选项,可以让服务器产生的目录列表中针对各种不同类型的文档引用各种图标。而哪种文件使用哪种图标,则使用下面的 AddIconByEncoding、AddIconByType以及AddIcon来定义,分别依据MIME 的编码、类型以及文件的后缀来判断使用何种图标。如果不能确定文档使用的图标,就使用 DefaultIcon定义的缺省图标。

  同样,使用AddDescription可以为不同类型的文档加入不同的描述。并且,服务器还在目录下,查询使用ReadmeName和HeaderName定义的文件(自动加上 .html后缀,如果没有发现,再使用.txt后缀进行搜索),如果发现了这些文件,就在文件列表之前首先显示这些文件的内容,以使得普通目录列表具备更大的可理解性。

  IndexIgnore让服务器在列出文件列表时忽略相应的文件, 这里使用模式配置的方式定义文件名。

  AddEncoding x-compress Z

  AddEncoding x-gzip gz

  AddEncoding用于告诉一些使用压缩的MIME类型,这样可以让浏览器进行解压缩操作。

  AddLanguage en .en

  AddLanguage fr .fr

  AddLanguage de .de

  AddLanguage da .da

  AddLanguage el .el

  AddLanguage it .it

  LanguagePriority en fr de

  一个HTML文档可以同时具备多个语言的版本,如对于file1.html文档可以具备file1.html.en、file1.html.fr 等不同的版本,每个语言后缀必须使用 AddLanguage进行定义。这样服务器可以针对不同国家的客户,通过与浏览器进行协商,发送不同的语言版本。而LanguagePriority 定义不同语言的优先级,以便在浏览器没有特殊要求时,按照顺序使用不同的语言版本回应对file1.html 的请求。这个国际化的能力实际的应用并不多。

  #AddType application/x-httpd-php .phtml

  #AddType application/x-httpd-php-source .phps

  AddType参数可以为特定后缀的文件指定MIME类型,这里的设置将覆盖 mime.types中的设置。

  #AddHandler cgi-script .cgi

  AddHandler是用于指定非静态的处理类型,用于定义文档为一个非静态的文档类型,需要进行处理,再向浏览器返回处理结果。例如上面注释中的设置是将以.cgi结尾的文件设置为cgi-script类型,那么服务器将启动这个CGI程序以进行处理。如果需要在前面AliasScript定义的路径之外执行CGI程序,就需要使用这个参数进行设置,此后以.cgi结尾的文件将被当作CGI程序执行。

  在配置文件、这个目录中的.htaccess以及其上级目录的.htaccess中必须允许执行CGI程序,这需要通过Options ExecCGI参数设定。

  #AddType text/html .shtml

  #AddHandler server-parsed .shtml

  另外一种动态进行处理的类型为server-parsed,由服务器自身预先分析网页内的标记,将标记更改为正确的HTML标识。由于server-parsed需要对text/html 类型的文档进行处理,因此首先定义了对应的.shtml为text/html类型。

  然而要支持SSI,还要首先要在配置文件(或.htaccess)中使用Options Includes允许该目录下的文档可以为SSI类型,或使用Options IncludesNOExec让执行普通的SSI标志,但不执行其中引用的外部程序。

  另一种指定server-parsed类型的方式为使用XBitBack设置选项,如果将 XBitHack设置为On,服务器将检查所有text/html类型的文档(包括.html后缀的文档),如果发现文件属性具备执行位 “x",则服务器就认为它是服务器分析文档,需要服务器进行处理。推荐使用AddHandler进行设置,而将XBitBack 设置为Off,因为使用XBitBack将对所有的HTML文档都执行额外的检查,降低了效率。

  #AddHandler send-as-is asis

  #AddHandler imap-file map

  #AddHandler type-map var

  上面被注释的AddHandler用于支持Apache服务器的asis、map和var处理能力。

  # Action media/type /cgi-script/location

  # Action handler-name /cgi-script/location

  因为Apache内部提供的处理功能有限,因此可以使用Action为服务器定义外部程序作为可处理的动态文档类型,这些外部程序与标准CGI程序相同,都是对输入的数据处理之后,再输出不同MIME类型的结果。例如要定义一个对特殊后缀wri都先执行wri2txt进行处理操作,再返回结果的操作,可以使用:

  Action windows-writer /bin/wri2txt

  AddHandler windows-writer wri

  更进一步,可以直接使用Action定义对某个MIME类型预先进行处理操作,这需要例子中第一种格式的Action 参数设置方式。这样设置方式就不再需要额外的AddHandler用来将处理操作与文件后缀联系起来,而是使用Action直接处理MIME类型的文件。但如果文档后缀没有正式的MIME类型,还需要先定义一个MIME类型。

  #MetaDir .web

  #MetaSuffix .meta

  Meta信息是在文档发送给客户之前,预先发送给客户浏览器一些数据,因此浏览器可以通过HEAD请求来访问这些Meta信息而不必真正通过GET来返回全部文档数据。服务器通常发送给浏览器的是一些标准的HTTP头信息,如果要想增加额外的信息,就需要使用MetaDir来定义Meta数据存放的目录, 而MetaS uffix用于指定包含Meta数据的文件后缀。

  #ErrorDocument 500 "The server made a boo boo.

  #ErrorDocument 404 /missing.html

  #ErrorDocument 404 /cgi-bin/missing_handler.pl

  #ErrorDocument 402

  http://some.other_server.com/subscription_info.html

  如果客户请求的网页不存在,或者没有访问权限等情况发生时,服务器将产生一个错误代码,同时也将回应客户浏览器一个标识错误的网页

  ErrorDocument就用于设置当出现哪个错误时应该回应客户浏览器那些内容,ErrorDocument的第一个参数为错误的序号,第二个参数为回应的数据,可以为简单的文本,本地网页,本地CGI程序,以及远程主机上的网页

  BrowserMatch "Mozilla/2" nokeepalive

  BrowserMatch "MSIE 4.0b2;" nokeepalive downgrade-1.0 force-response-1.0

  BrowserMatch "RealPlayer 4.0" force-response-1.0

  BrowserMatch "Java/1.0" force-response-1.0

  BrowserMatch "JDK/1.0" force-response-1.0

  BrowserMatch命令为特定的客户程序,设置特殊的参数,以保证对老版本浏览器的兼容性,并支持新浏览器的新特性。

  #

  # SetHandler server-status

  # Order deny,allow

  # Deny from all

  # Allow from .your_domain.com

  #

  #

  # SetHandler server-info

  # Order deny,allow

  # Deny from all

  # Allow from .your_domain.com

  #

  #

  # Deny from all

  # ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi

用于设置访问控制的设置主要是针对目录和文件进行设置的,然而也可以针对不同的URL进行访问控制的设置,这样就不必担心ScriptAlias、Alias是否将路径设置到了受控制的目录之外了。针对URL进行控制的语句为 Location语句,这样不但能对服务器上的文件、CGI提供保护,此外,它还能保护不能找到对应文件,而是由服务器本身提供的特殊功能URL。http://servername/server-status用于报告当前Apache服务器的状态,http://servername/server-info用于报告Apache 服务器的统计信息。与此相关的设置还有ExtendedStatus参数,可以让服务器输出更详细的的报告。

  #

  #ProxyRequests On

  #

  #

  # Order deny,allow

  # Deny from all

  # Allow from .your_domain.com

  #

  #ProxyVia On

  #CacheRoot "/www/proxy"

  #CacheSize 5

  #CacheGcInterval 4

  #CacheMaxExpire 24

  #CacheLastModifiedFactor 0.1

  #CacheDefaultExpire 1
  
  #NoCache a_domain.com another_domain.edu joes.garage_sale.com

  #

  Apache服务器本身就具备代理的功能,然而这要求加载入mod_proxy模块。这能使用IfModule语句进行判断,如果存在mod_proxy模块,就使用ProxyRequests打开代理支持。此后的Directory用于设置对Proxy功能的访问权限设置,以及用于设置缓冲的各个参数设置。

  虚拟主机

  #NameVirtualHost 12.34.56.78:80

  #NameVirtualHost 12.34.56.78

  #

  # ServerAdmin webmaster@host.some_domain.com

  # DcumentRoot /www/docs/host.some_domain.com

  # ServerName host.some_domain.com

  # ErrorLog logs/host.some_domain.com-error_log

  # CustomLog logs/host.some_domain.com-access_log common

  #
 
  #

  缺省设置文件中的这些内容是用于设置命名基础的虚拟主机服务器时使用。

  其中NameVirtualHost 来指定虚拟主机使用的IP地址,这个IP地址将对应多个 DNS名字,如果Apache使用了Listen 参数控制了多个端口,那么就可以在这里加上端口号以进一步进行区分对不同端口的不同连接请求。此后,使用 VirtualHost 语句,使用NameVirtualHost指定的IP地址作参数,对每个名字都定义对应的虚拟主机设置。

  虚拟主机是在一台Web服务器上,可以为多个单独域名提供Web服务,并且每个域名都完全独立,包括具有完全独立的文档目录结构及设置,这样域名之间完全独立,不但使用每个域名访问到的内容完全独立,并且使用另一个域名无法访问其他域名提供的网页内容。

  虚拟主机的概念对于ISP来讲非常有用,因为虽然一个组织可以将自己的网页挂在具备其他域名的服务器上的下级往址上,但使用独立的域名和根网址更为正式,易为众人接受。传统上,必须自己设立一台服务器才能达到单独域名的目的,然而这需要维护一个单独的服务器,很多小单位缺乏足够的维护能力,更为合适的方式是租用别人维护的服务器。ISP也没有必要为一个机构提供一个单独的服务器,完全可以使用虚拟主机能力,使服务器为多个域名提供Web服务,而且不同的服务互不干扰,对外就表现为多个不同的服务器

  有两种设定虚拟主机的方式,一种是基于HTTP 1.0标准,需要一个具备多IP地址的服务器,再配置DNS 服务器,给每个IP地址以不同的域名,最后才能配置Apache的配置文件,使服务器对不同域名返回不同的Web文档。由于这需要使用额外的IP地址,对每个要提供服务的域名都要使用单独的IP地址,因此这种方式实现起来问题较多。

  可以在一个网络界面上绑定多个IP地址,Linux下需要使用ifconfig的 alias参数来进行这个配置,但此时会影响网络性能。

  HTTP 1.1标准在协议中规定了对浏览器和服务器通信时,服务器能够跟踪浏览器请求的是哪个主机名字。因此可以利用这个新特性,使用更轻松的方式设定虚拟主机。这种方式不需要额外的IP地址,但需要新版本的浏览器支持。这种方式已经成为建立虚拟主机的标准方式。

  要建立非IP基础的虚拟主机,多个域名是不可少的配置,因为每个域名就对应一个要服务的虚拟主机。因此需要更改DNS服务器的配置,为服务器增加多个C NAME选项,如:

  linux IN A 192.168.1.64

  vhost1 IN CNAME linux

  vhost2 IN CNAME linux

  基本的设置选项都是为了linux主机设定的,如果要为vhost1和vhost2设定虚拟主机,就要使用VirtualHost语句定义不同的选项,在语句中可以使用配置文件前面中的大部分选项,而可以重新定义几乎所有的针对服务器的设置。

  NameVirtualHost 192.168.1.64

  DocumentRoot /www/data

  ServerName linux.example.org.cn

  DocumentRoot /vhost1

  ServerName vhost1.example.org.cn

  DocumentRoot /vhost2

  ServerName vhost2.example.org.cn

  这里需要注意的是,VirtualHost的参数地址一定要和NameVirtualHost定义的地址相一致,必须保证所有的值严格一致,Apache服务器才承认这些定义是为这个IP地址定义的虚拟主机。

  此外,定义过NameVirtualHost之后,那么对这个IP地址的访问都被区分不同的虚拟主机进行处理,而对其他IP地址的访问,例如127.0.0.1,才应用前面定义的缺省选项。

- 作者: 和疯 2006年03月10日, 星期五 09:30  回复(1) |  引用(0) 加入博采

Linux下两种自动启动Tomcat的方法
很多办法可以让Tomcat在系统启动的时候自动运行,我这里介绍两种方法,一种简单,另外一种复杂而专业。在介绍这两个方法前你应该先装JDK,Tomcat。Tomcat的安装很简单,下载二进制压缩包 xxx.tar.gz ,用 tar zxvf xxx.tar.gz -C [target],[target]是安装Tomcat的目录。
设置环境变量JDK_HOME和JAVA_HOME都指向JDK的安装目录即可。

一. 简单的方法

Tomcat安装目录下的bin目录有两个脚本分别用来启动和停止Tomcat,分别是startup.sh, shutdown.sh,你可以用这两个脚本来手工启动和停止Tomcat服务并进行安装后的测试。

我们最简单的方法就是通过startup.sh来自动启动Tomcat,编辑/etc/rc.d/rc.local 增加内容(假设JDK目录是/usr/jdk,Tomcat目录是/apache/tomcat)
export JDK_HOME=/usr/jdk
export JAVA_HOME=/usr/jdk
/apache/tomcat/bin/startup.sh

这样在系统重启后就可以自动启动Tomcat

二. 复杂而专业的方法

前面介绍的应该是最简单的让Tomcat自动启动的方法了,但是它有两个不足

1. 无法指定启动Tomcat服务的用户,会导致Tomcat已超级用户运行,存在重大的安全隐患
2. 系统关闭的时候无法自动停止Tomcat服务

在Linux下,Tomcat可以作为一个守护进程来启动以及停止,这个必须借助于项目commons-daemon中的jsvc工具。Tomcat安装完后就带有这个工具的源码{tomcat}/bin/jsvc.tar.gz。按照下列命令安装这个工具:

解压: tar zxvf jsvc.tar.gz
配置: cd jsvc-src
    &bsp;   chmod +x configure
       ./configure --with-java=/usr/jdk
编译: make
检验: ./jsvc -help

jsvc工具本身带了一个脚本(在native目录下)用来启动和停止Tomcat守护进程,但是在试验中发现该脚本无法设置为自动启动,显示的错误信息是:tomcat 服务不支持 chkconfig,因此修改了此脚本
程序代码:


#!/bin/sh 

# Startup Script for Tomcat5 

# chkconfig: 345 87 13 
# description: Tomcat Daemon 
# processname: jsvc 
# pidfile: /var/run/jsvc.pid 
# config: 

# Source function library.
. /etc/rc.d/init.d/functions 

prog=tomcat 

# Small shell script to show how to start/stop Tomcat using jsvc 
# If you want to have Tomcat running on port 80 please modify the server.xml 
# file: 

# <!-- Define a non-SSL HTTP/1.1 Connector on port 80 --> 
# <Connector className="org.apache.catalina.connector.http.HttpConnector" 
# port="80" minProcessors="5" maxProcessors="75" 
# enableLookups="true" redirectPort="8443" 
# acceptCount="10" debug="0" connectionTimeout="60000"/> 

# You need a developement version of Tomcat (Apache Tomcat/4.1-dev) 

# Adapt the following lines to your configuration 

JAVA_HOME=/usr/jdk1.5.0 
CATALINA_HOME=/apache/tomcat
DAEMON_HOME=$CATALINA_HOME/bin/jsvc-src 
TOMCAT_USER=root
TMP_DIR=/var/tmp 
CATALINA_OPTS= 
CLASSPATH=$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/bin/commons-daemon.jar:$CATALINA_HOME/bin/bootstrap.jar

start(){ 
echo -n $"Starting $prog: " 
    #
    # Start Tomcat
    #
    $DAEMON_HOME/jsvc \
    -user $TOMCAT_USER \
    -home $JAVA_HOME \
    -Dcatalina.home=$CATALINA_HOME \
    -Djava.io.tmpdir=$TMP_DIR \
    -outfile $CATALINA_HOME/logs/catalina.out \
    -errfile '&1' \
    $CATALINA_OPTS \
    -cp $CLASSPATH \
    org.apache.catalina.startup.Bootstrap
    #
    # To get a verbose JVM
    #-verbose \
    # To get a debug of jsvc.
    #-debug \
    RETVAL=$? 
    [ $RETVAL = 0 ] && touch /var/lock/subsys/jsvc 
    [ $RETVAL = 0 ] && echo_success || echo_failure 
    echo 
    return $RETVAL 

stop(){ 
    echo -n $"Stopping $prog: " 
    # 
    # Stop Tomcat 
    # 
    PID=`cat /var/run/jsvc.pid` 
    kill $PID 
    RETVAL=$? 
    [ $RETVAL = 0 ] && rm /var/lock/subsys/jsvc 
    [ $RETVAL = 0 ] && echo_success || echo_failure 
    echo 
    return $RETVAL 


case "$1" in 
start) 
start 
;; 

stop) 
stop 
;; 

restart|reload) 
stop 
start 
;; 

*) 
echo "Usage $0 start/stop" 
exit 1;; 
esac

修改下载的脚本里面有关路径的信息以及要启动Tomcat的用户(用户必须已存在)
拷贝脚本到/etc/rc.d/init.d目录下的tomcat文件,给该脚本赋予可执行权限

chmod +x tomcat
你可以使用命令

/etc/rc.d/init.d/tomcat start|stop 

来验证守护进程是否可以正常启动和停止。

接下来就是把这个脚本设置成系统启动时自动执行,系统关闭时自动停止,使用如下命令:
chkconfig --add tomcat
重新启动系统后可以启动的过程中看到Starting Tomcat ..... [OK]的信息,这样就完成设置过程。

- 作者: 和疯 2006年03月2日, 星期四 22:20  回复(3) |  引用(0) 加入博采

在Fedora core 4 上美化字体的最高境界,以无招胜有招!!!!!
美化字体不许要补丁,也不需要打命令,方法如下:
1:安装完毕后进入
[root@S01 ~]#cd /usr/share/fonts/zh_CN/TrueType
2:删除:
gbsn00lp.ttf  gkai00mp.ttf字体文件
[root@S01 ~]#rm -rf gbsn00lp.ttf  gkai00mp.ttf
3:将simsun.ttc重命名为:gbsn00lp.ttf  gkai00mp.ttf,并放到cd /usr/share/fonts/zh_CN/TrueType下
4:重起系统就可以看到保留英文字体,而中文字体变成新宋体的操作界面了!
这个方法在Redhat AS 4.2下没有通过,没办法 只好修改字体配置,全部改为simsun.ttc.

- 作者: 和疯 2006年03月2日, 星期四 18:02  回复(1) |  引用(0) 加入博采

用vsFTPd自架Linux网络安装服务器,以及Redhat局域网安装的解决办法
为了验证局域网网络安装Linux,近两天做了一个实验,目的就是为了写一个比较完整的帖子。

约定:

1。本帖操作环境是Redhat 9.0,vsFTPd的版本是Redhat 9.0所带的vsftpd-1.1.3-8.i386.rpm,在安装盘的第三张中

2。vsFTPd实现的最基本的目的:用系统中存在的真实用户能登入FTP,能用匿名访问。

3。本帖中vsFTPd运行模式是在standalone模式下运行的,也就是说,本帖中vsFTPd所有的功能都是在standalone模式下运行的。至于有些功能是否能在xinetd模式下运行,您就得测试了,不能照搬照抄。因为有些功能是必须运行在特定的模式下的。


3。服务器的IP和和DNS设定

第一块网卡
IP:192.168.0.1
子掩码:255.255.255.0
网关不设置:
第二块网卡:
IP:192.168.0.2
子掩码:255.255.255.0
网关不设置

因为我的操作环境是一个小型的局域网,所以其它的机器的IP都是在192.168.0这个网段上。ADSL是接在服务器的第一个网卡上。服务器的第二个网卡是接集线器,其它的客户机都是接在集线器上。为了能让ADSL访问internet,因为自己手动设置了IP,所以DNS也要自己来设置,DNS如下:

202.96.134.133
202.96.168.68

设置工具是:

[root@linuxsir001 root]# redhat-config-network

相应参考资料:vsFTPd官方文档:

http://www.linuxsir.com/bbs/showthre...threadid=43451

一。用vsFTPd来架设FTP服务器,vsFTPd服务器是目前最好的FTP服务器软件,优点是体积小,可定制强,效率高

1。查看是否安装了vsFTPd软件
[root@linuxsir001 root]# rpm -qa | grep vsftpd
如果没有任何显示,说明没有把vsFTPd安装上,如果出现的是下面的这样的提示,就证明已经安装上了。

[root@linuxsir001 root]# rpm -qa | grep vsftpd
vsftpd-1.1.3-8

我以Redhat 9.0,以其自带的vsFTPd包vsftpd-1.1.3-8版本来为本帖约定。

[root@linuxsir001 root]# rpm -ivh vsftpd*.rpm

2。打开vsFTPd服务器。

[root@linuxsir001 root]# ntsysv

把vsftpd服务器打开,也就是在运行 ntsysv命令后,把vsftpd服务选中。
[*] vsftpd

3。运行/etc/init.d/vsftpd start

[root@linuxsir001 root]# /etc/init.d/vsftpd start
为 vsftpd 启动 vsftpd: [ 确定 ]
[root@linuxsir001 root]#

4。配制vsFTPd,vsFTPd的运行有两种模式,一种是standalone "initd"模式,另外一种是xinetd模式,上面我们所说的就是standalone "initd"运行模式。两种模式运行机制不是相同的,stardard initd模式,适合专业FTP,且FTP总是一直有人访问,占用资源也是比较大,如果您的FTP总是有人访问和登入。就要用这种模式。如果您的FTP访问人数比较小,建议您用xinetd模式。xinetd模式,是当用户请求时,vsFTPd才会启动。

不同的环境,当然得用不同的启动模式。

如果想了解更多的,请在本帖后面跟帖,我会慢慢补充xinetd模式,以及虚拟用户如何设置方面的问题。


1]我们主要把vsFTPd的配制文件改一下就行了。配制文件在/etc/vsftpd/vsftpd.conf,用您喜欢的编辑器打开。请参考下面的配制文件。


# Example config file /etc/vsftpd.conf
#
# The default compiled in settings are very paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
#
# Allow anonymous FTP?
anonymous_enable=YES
#
# Uncomment this to allow local users to log in.
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
#
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
local_umask=022
#
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
#anon_upload_enable=YES
#
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
#anon_mkdir_write_enable=YES
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=YES
#
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
#chown_uploads=YES
#chown_username=whoever
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/vsftpd.log
#
# If you want, you can have your log file in standard ftpd xferlog format
xferlog_std_format=YES
#
# You may change the default value for timing out an idle session.
#idle_session_timeout=600
#
# You may change the default value for timing out a data connection.
#data_connection_timeout=120
#
# It is recommended that you define on your system a unique user which the
# ftp server can use as a totally isolated and unprivileged user.
#nopriv_user=ftpsecure
#
# Enable this and the server will recognise asynchronous ABOR requests. Not
# recommended for security (the code is non-trivial). Not enabling it,
# however, may confuse older FTP clients.
#async_abor_enable=YES
#
# By default the server will pretend to allow ASCII mode but in fact ignore
# the request. Turn on the below options to have the server actually do ASCII
# mangling on files when in ASCII mode.
# Beware that turning on ascii_download_enable enables malicious remote parties
# to consume your I/O resources, by issuing the command "SIZE /big/file" in
# ASCII mode.
# These ASCII options are split into upload and download because you may wish
# to enable ASCII uploads (to prevent uploaded scripts etc. from breaking),
# without the DoS risk of SIZE and ASCII downloads. ASCII mangling should be
# on the client anyway..
#ascii_upload_enable=YES
#ascii_download_enable=YES
#
# You may fully customise the login banner string:
#ftpd_banner=Welcome to blah FTP service.
#
# You may specify a file of disallowed anonymous e-mail addresses. Apparently
# useful for combatting certain DoS attacks.
#deny_email_enable=YES
# (default follows)
#banned_email_file=/etc/vsftpd.banned_emails
#
# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
#chroot_list_enable=YES
# (default follows)
#chroot_list_file=/etc/vsftpd.chroot_list
#
# You may activate the "-R" option to the builtin ls. This is isabled by
# default to avoid remote users being able to cause excessive I/O on large
# sites. However, some broken FTP clients such as "ncftp" and "mirror" assume
# the presence of the "-R" option, so there is a strong case for enabling it.
#ls_recurse_enable=YES

pam_service_name=vsftpd
userlist_enable=YES
#enable for standalone mode
listen=YES
tcp_wrappers=YES

2]更改完配制文件后,我们可以用下面的命令来重启vsFTPd服务器

[root@linuxsir001 root]# /etc/init.d/vsftpd restart
关闭 vsftpd: [ 确定 ]
为 vsftpd 启动 vsftpd: [ 确定 ]
[root@linuxsir001 root]#

3]以匿名方式来访问测试,在text模式下:

注意:在text模式下,要用用户名ftp,密码ftp来访问,这才是在text中匿名访问FTP。看如下的操作:

[root@linuxsir001 root]# ftp 192.168.0.1
Connected to 192.168.0.1.
220 (vsFTPd 1.1.3)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (192.168.0.1:root): ftp 这里写上ftp
331 Please specify the password.
Password:[这里添写ftp的密码],匿名登入密码也是ftp
230 Login successful. Have fun.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (192,168,0,1,137,151)
150 Here comes the directory listing.
drwxr-xr-x 6 0 0 4096 May 25 13:54 RedHat90
drwxr-xr-x 2 0 0 4096 Feb 28 19:21 pub
226 Directory send OK.
ftp>
那匿名用户所访问的是哪个目录?是/var/ftp这个目录

出现问题的解决:有时出错,是因为没有ftp和nobody用户,所以要在系统中添加这两个用户,一般的情况下,这两个用户在系统中是存在的。看下面的操作。
[root@linuxsir001 root]# adduser ftp
adduser: user ftp exists
[root@linuxsir001 root]# adduser nobody
adduser: user nobody exists

从上面的操作中可知ftp和nobody用户是存在的,所以没有必要添加ftp和nobody用户了。如果不存在,一定要添加这两个用户,否则会出现匿名用户不能访问的情况。

4]如果要以系统中存在的普通用户登入FTP,也没有什么可以设置的,添加一个用户就行。比如我要添加beinan这个用户,就要用下面的办法

[root@linuxsir001 root]# adduser beinan
[root@linuxsir001 root]# passwd beinan
Changing password for user beinan.
New password:
BAD PASSWORD: it does not contain enough DIFFERENT characters
Retype new password:
passwd: all authentication tokens updated successfully.
[root@linuxsir001 root]#

这样的话,就在/home目录中出现一个beinan的用户目录:如下:

[root@linuxsir001 root]# ls /home/
beinan


如果我们想让beinan这个用户作为虚拟用户,也就是说,beinan这个用户是不能登入系统的,只能是登入FTP。 那这样的用户应该如何添加呢??

[root@linuxsir001 backupNow]# adduser -g ftp -s /sbin/nologin beinan
[root@linuxsir001 backupNow]# passwd beinan
Changing password for user beinan.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@linuxsir001 backupNow]#

注:这仅仅是vsFTPd添加虚拟用户的一个方法,还有更好的办法需要我们去学习!另外的办法也在测试之中。严格上来说,这种办法不能算虚拟用户。还有另外的一个办法,就是通过pam认证,用db_load来添加用户,目前我也弄成功了,不过相对要复杂一点。正在测试之中。


如果我们想把用户目录定位到别的目录应该怎么办呢??这个也比较简单,看一下useradd就比较明白了。比如我想添加beinan这个用户,并把目录放在/opt目录中:如下操作:

[root@linuxsir001 root]# adduser -d /opt/beinan beinan
[root@linuxsir001 root]# passwd beinan
Changing password for user beinan.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

如果是添加虚拟用户,也就是不让用户登入系统,只能登入FTP的用户。如果我们想把beinan这个用户目录定位在/opt/beinan这个目录中,根据上面的方法。我们应该如下操作
[root@linuxsir001 backupNow]# adduser -d /opt/beinan -g ftp -s /sbin/nologin beinan
[root@linuxsir001 backupNow]# passwd beinan
Changing password for user beinan.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@linuxsir001 backupNow]#

看一下是不是已经成功添加到了beinan这个用户,并把beinan的家目录放在了/opt目录中呢??

[root@linuxsir001 root]# ls /opt/
beinan

证明已经成功。

我们可以在text模式下以beinan用户登入,然后来访问ftp。

[root@linuxsir001 root]# ftp 192.168.0.1
Connected to 192.168.0.1.
220 (vsFTPd 1.1.3)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (192.168.0.1:root): beinan
331 Please specify the password.
Password:
230 Login successful. Have fun.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

是不是成功了???

我们也可以用gftp来访问beinan用户,并上传相应的东西,所传上的东西就放在beinan用户所在的家目录中,普通用户的家目录在哪里,写您所用的添加用户的方法有关。我在前面已经说了两种办法,一种是默认的添加方法,就是放在/home目录中。

在本例中,我是采用默认的添加用户的方法。也就是不特别指定用户用户,这样的话,用户目录就在/home目录中。比如用beinan登入FTP时,访问的就是/home/beinan这个目录。让传的东西也在这个目录中。

那匿名用户所访问的是哪个目录呢???

应该是:/var/ftp这个目录


5]访问ftp的几种方法

第一种方法就是text访问,也就是用ftp命令来访问。这个前面已经说过了。

第二种方法是以客户端FTP软件来访问,在linux中有gftp。在本例中,我的FTP地址是通过局域网访问的。地址栏中,添上192.168.0.1,端口是21,用户名和密码的添写,如果您是用匿名登入,请不要添写用户名和密码。如果用普通用户登入,这个是必须要用用户名和密码的。

第三种办法是和浏览器访问:如果匿名登入,就直接用下面的方法:
ftp://192.168.0.1
如果是用户登入方式,应该是
ftp://beinan@192.168.0.1

如果想让在互联网上的用户能访问到,如果您是用ADSL来访问互联网,要查找到您的动态IP,用下面的办法
[root@linuxsir001 root]# ifconfig ppp0
ppp0 Link encap:Point-to-Point Protocol
inet addr:218.61.7.23 P-t-P:218.61.7.1 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:24245 errors:0 dropped:0 overruns:0 frame:0
TX packets:20411 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:23103297 (22.0 Mb) TX bytes:3588337 (3.4 Mb)

从上面的可以知道,能让在internet访问的地址是:218.61.7.23


二。如何让局域网通过这个FTP安装Linux呢??以Redhat 9.0为例:

1。我们要在/var/ftp中,为每个发行版建一个目录,然后把每个发行版的每个版本再建一个目录。把每个版本的ISO都解压到相应的目录里。举个例子:

比如我想让其它的客户机,通过我的服务器来安装Redhat9.0,我就要在/var/ftp目录中建一个RedHat90的目录,然后把RedHat 9.0的三个ISO都解到这个目录中。

这样服务器的设置就完成了。

2。客户机方面如何引导及设置???我们可以做一个系统的引志盘,但有的发行版也没有必要。这也要以各个发行版的情况而定。比如Redhat 9.0的安装,如果您的客户机上有windows,就直接通过局域网的FTP,dosutils images isolinux三个目录放到一个在fat32分区中建的目录中,比如说在客户机上建一个Redhat9的目录,然后把三个文件拷到客户机中的fat32分区中的Redhat9的目录中。

3.客户机安装及操作:

以DOS盘引导,不要加载CDROM,直接进入客户机中fat32分区Redhat9\dosutils目录,执行下面的命令。

autoboot

这样就开始了安装:

4.出现的画面中,我们要选ftp安装。在设置网络环境时,我们要设置好IP和网关之类的。

以我的局域网为例:

客户机的IP设置成192.168.0.5,掩码也是2552555.255.0,网关设置成192.168.0.1。name 服务可以不设置。以匿名方式访问FTP。

下一步会出现让们添写FTP,及安装源的地址,还是以我的局域网为例:

地址:192.168.0.1
路径:因为我是把三个ISO放在了/var/ftp/RedHat90的目录下,我应该写如下的

/RedHat90

这样就OK了,一切和其它的安装方式都是一样的了。


因为每个发行版不太一样,所以通过网络安装,有的要做引导盘,如何做引导盘,我想大家早就知道了。如果不知道这方面的,请用搜索来找这方面的帖子。

- 作者: 和疯 2006年03月2日, 星期四 16:59  回复(1) |  引用(0) 加入博采

Linux上JDK的安装- -
1.    去http://java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK,建议下载RPM自解压格式的(RPM in self-extracting file,j2sdk-1_4_2_06-linux-i586-rpm.bin);
2.    上载到Linux服务器上,在shell下执行命令:
[root@LinuxServer rpm]# chmod 755 j2sdk-1_4_2_06-linux-i586-rpm.bin
[root@LinuxServer rpm]# ./j2sdk-1_4_2_06-linux-i586-rpm.bin

这时会有一段Sun的协议,敲几次空格键,当询问是否同意的时候,敲yes就可以了。
              Sun Microsystems, Inc.
          Binary Code License Agreement
                   for the
JAVATM 2 SOFTWARE DEVELOPMENT KIT (J2SDK), STANDARD
EDITION, VERSION 1.4.2_X
...
Do you agree to the above license terms? [yes or no]yes
Unpacking...
Checksumming...
0
0
Extracting...
UnZipSFX 5.40 of 28 November 1998, by Info-ZIP (Zip-Bugs@lists.wku.edu).
  inflating: j2sdk-1_4_2_06-linux-i586.rpm 
Done.

3.    程序会自动生成一个j2sdk-1_4_2_06-linux-i586.rpm文件,这是主程序包,下面来安装;
[root@LinuxServer rpm]#rpm -ivh j2sdk-1_4_2_06-linux-i586.rpm
Preparing...               ########################################### [100%]
   1:j2sdk               ########################################### [100%]

4.    设置环境变量
通常都喜欢用export命令直接在shell下设置
[root@LinuxServer rpm]# export JAVA_HOME=/usr/java/j2sdk1.4.2_06
[root@LinuxServer rpm]# export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
[root@LinuxServer rpm]# export PATH=$PATH:$JAVA_HOME/bin
当然这样设置环境变量是可以生效的,但是只对当前shell生效。如果从另外一个shell登陆,将不能使用刚才设置的变量。所以最好的方法还是修改.bashrc文件。
[root@LinuxServer rpm]#vi .bashrc
set JAVA_HOME=/usr/java/j2sdk1.4.2_06
export JAVA_HOME
set PATH=$PATH:$JAVA_HOME/bin
export PATH
set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH
当然也可以通过更改/etc/profile来实现,不过不推荐这么做,因为这样的设置将对所以用户的shell都生效,对系统安全会产生影响。下面来验证一下变量设置是否生效(在验证前先logout一下,再重新登陆);
[root@LinuxServer rpm]# echo $JAVA_HOME
/usr/java/j2sdk1.4.2_06/
[root@LinuxServer rpm]# echo $CLASSPATH
/usr/java/j2sdk1.4.2_06/lib/dt.jar:/usr/java/j2sdk1.4.2_06/lib/tools.jar
[root@LinuxServer rpm]# echo $PATH
/usr/java/j2sdk1.4.2_06/bin/:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[root@LinuxServer rpm]# JAVA-version
JAVA version "1.4.2_06"
JAVA(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03)
JAVA HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode)

5.    环境设置OK,看看JDK是否能正常工作,我们来写一个测试文件test.java
[root@LinuxServer rpm]#vi test.java
class test
{
       public static void main(String[] args)
       {
              System.out.println("Hello World!");
       }
}

保存退出,下面来编译、执行;
[root@LinuxServer text]# javac test.java
[root@LinuxServer text]# JAVA test
Hello World!

OK,工作正常。
6.    如果要使某个用户具有运行java命令的权限,只要修改其bash初始化文件即可。
比如要给用户longware以运行java命令的权限,
[root@LinuxServer root]# vi /home/longware/.bashrc
set JAVA_HOME=/usr/java/j2sdk1.4.2_06
export JAVA_HOME
set PATH=$PATH:$JAVA_HOME/bin
export PATH
set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH

7.    至此,Linux上JDK的安装完毕。

- 作者: 和疯 2006年03月2日, 星期四 14:12  回复(2) |  引用(0) 加入博采

linux下VNC的安装与使用

   VNC的安装与使用
说明:文章内容比较简单,献给那些初学者作为参考。
      文章分为两部分,第一部分为VNC简介,第二部分为VNC的安装与使用。
      文章为小弟结合书籍与小弟的实际操作总结出来的,如有错误与疏漏之处,还请指出。
fish_ys  2003.8.25

『VNC简介』
  网络遥控技术是指由一部计算机(主控端)去控制另一部计算机(被控端),而且当主控端在控制端时,就如同用户亲自坐在被控端前操作一样,可以执行被控端的应用程序,及使用被控端的系统资源。
  VNC(Virtual Network Computing)是一套由AT&T实验室所开发的可操控远程的计算机的软件,其采用了GPL授权条款,任何人都可免费取得该软件。VNC软件主要由两个部分组成:VNC server及VNC viewer。用户需先将VNC server安装在被控端的计算机上后,才能在主控端执行VNC viewer控制被控端。
(在windows中也由一套著名的网络遥控软件――Symantec公司推出的pcAnywhere。
  VNC server与VNC viewer支持多种操作系统,如Unix系列(Unix,Linux,Solaris等),windows及MacOS,因此可将VNC server 及VNC viewer分别安装在不同的操作系统中进行控制。如果目前操作的主控端计算机没有安装VNC viewer,也可以通过一般的网页浏览器来控制被控端。
  整个VNC运行的工作流程如下:
(1)        VNC客户端通过浏览器或VNC Viewer连接至VNC Server。
(2)        VNC Server传送一对话窗口至客户端,要求输入连接密码,以及存取的VNC Server显示装置。
(3)        在客户端输入联机密码后,VNC Server验证客户端是否具有存取权限。
(4)        若是客户端通过VNC Server的验证,客户端即要求VNC Server显示桌面环境。
(5)        VNC Server通过X Protocol 要求X Server将画面显示控制权交由VNC Server负责。
(6)        VNC Server将来由 X Server的桌面环境利用VNC通信协议送至客户端,并且允许客户端控制VNC Server的桌面环境及输入装置。

『VNC的安装与使用』
本人的操作环境:被控端 Redhat8.0,主控端Windows XP。
1.        载VNC Server与VNC viewer.
VNC Server下载地址:http://www.linuxeden.com/download/softdetail.php?softid=744
VNC viewer下载地址:http://download.pchome.net/php/dl.php?sid=2603
2.安装。
rpm –Uvh vnc-3.3.6-2.i386.rpm (如果是源代码请看包里的说明)
安装winvnc.exe
3.在Linux上启动VNC Server
执行vncserver命令:
[root@linux root]# vncserver
You will require a password to access your desktops.
Password:                       ----为了不想任何人都可以任意遥控此计算机。因此当第
Verify:                          ---1次启动VNC server时,会要求设置网络遥控的密码。
New ‘X’ desktop is linux:1         ----一定要记住这一行稍后会用到。
Creating default startup script /root/.vnc/xstartup
Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/linux:1.log
(经上述步骤后,便已启动了VNC Server。如果你想要更改VNC Server的密码,只要执行vncpasswd命令即可。)
4.在Microsoft Windows上运行VNC Viewer
直接运行“vncviewer.exe”,系统会出现”Connection details”对话框。
在“Connection details”对话框中的“VNC server”文本框中输入VNC Server的IP地址(或主机名及显示装置编号,(请看3。在Linux上启动VNC server的这一行,New ‘X’ desktop is linux:1 得到此信息),例如:192.168.0.1:1(冒号后面的1是执行VNC Server生成的显示装置编号),单击“OK”按钮后,VNC Server即会开始检查所输入的信息,若是信息错误,系统会出现“Failed to connect to server”的错误信息:若是信息正确,则会接着出现“VNC Authentication”对话框。
  若是在“VNC Authentication”对话框中输入的密码正确,就可以成功地打开Linux的桌面窗口。
5. 从浏览器远程遥控。
启动VNC Server 后直接打开浏览器,在地址栏中输入被控端的网址或IP地址,并在网址后加上“:5800+显示编号”的端口号即可操控该计算机。
例如:http://192.168.01.:5801 (如果显示编号为1,一般第一次设置的显示编号都是1,就用5800+1=5801。)

6.FAQ
A.为什么连接后,不能显示桌面,而只有一个Terminal窗口?
试着修改/root/.vnc/xstartup,把最后一行 twm& 改成 gnome-session& or  kde&(据说KDE在目前的VNC Viewer上的表现不太稳定)

B.        为什么重新启动VNC Server后,连接不上了?
因为重新启动VNC Server时,系统会指定一个新的显示编号,需使用此新的编号,否则就无法连接。
(以上只是本人遇到的一些问题,而且用VNC也不是很多,很不全面,还望多提宝贵意见)

 


  

- 作者: 和疯 2006年03月2日, 星期四 13:41  回复(2) |  引用(0) 加入博采

[原创]Tomcat 5.5.15 和SQLServer2000 SP3的连接池

Tomcat 5.5.15 和SQLServer2000 SP3基于SQLServer2000JDBC SP3 的连接池配制
一、准备
需要下载:
1. tomcat5.5.15
2. Tomcat5.5.15admin
3. SQLServer2000JDBC SP3或者jtds

安装tomcat。并添加admin角色和用户。
将jdbc驱动包放到tomcat_home\common\lib目录下。
在MyEclipse建立一个新的Web项目。使用刚才配置的tomcat作为服务器。

启动tomcat。

二、配置
打开tomcat。
 
登录 Tomcat Web Server Administration Tool.

 
点击左侧的Data Sources。
 
在右侧Available Actions下拉菜单中选择Create New Data Source.
 
输入
JNDI Name:
Data Source URL:
JDBC Driver Class:
User Name:
Password:
Max.Active Connections:最大活动连结数 ,0为不限 。
Max.Idle Connections:最大等待连结数 ,0为不限 。
Max.Wait for Connection:建立连接超时时间ms,-1为无限 。

注:使用SQLServer的官方JDBC驱动,Class=com.microsoft.jdbc.sqlserver.SQLServerDriver,URL=jdbc:Microsoft:sqlserver://127.0.0.1:1433;databaseName=aa;使用开源的驱动Jtds,Class=net.sourceforge.jtds.jdbc.sqlserver,URL=jdbc:jtds:sqlserver://127.0.0.1:1433/aa

输入完毕,点击“Save”按钮保存。
 
点击页面右上侧“Commit Changes”按钮,保存刚才的设置。(这一步很重要哦!)

打开tomcat_home\conf\server.xml的< GlobalNamingResources></ GlobalNamingResources>中找到

    <Resource
      name="jdbc/mydbcp"
      type="javax.sql.DataSource"
      password="aa"
      driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
      maxIdle="2"
      maxWait="5000"
      username="aa"
      url="jdbc:microsoft:sqlserver://10.0.2.37:1433;databaseName=aa"
      maxActive="4"/>
这是JNDI的主要配置文件,可以不使用图形界面直接写入server.xml中。
在tomcat_home\webapps\dbcp\ META-INF\context.xml的<context></context>中填入上面的代码。
如果更改了JNDI,则必须手动更改context.xml。

    <Resource
      name="mydbcp" 注:此处不同
      type="javax.sql.DataSource"
      password="aa"
      driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
      maxIdle="2"
      maxWait="5000"
      username="aa"
      url="jdbc:microsoft:sqlserver://10.0.2.37:1433;databaseName=aa"
      maxActive="4"/>

  <ResourceLink
    global="jdbc/mydbcp"
    name="jdbc/mydbcp"
type="javax.sql.DataSource"/>

重起tomcat。

连接方法:

    Context initCtx = new InitialContext();
    Context envCtx = (Context) initCtx.lookup("java:comp/env");
    DataSource ds = (DataSource) envCtx.lookup("jdbc/mydbcp");
    Connection conn = ds.getConnection();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select * from systypes");
三、测试

测试实例:test.jsp

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="java.sql.*,javax.sql.DataSource,javax.naming.*"%>
<html>
 <head>
  <title>
   tomcat 连接池
  </title>
 </head>
 <body bgcolor="#ffffff">
  <h3>
   test
   <br>
   连接池3
  </h3>
  <%try {
    Context initCtx = new InitialContext();
    Context envCtx = (Context) initCtx.lookup("java:comp/env");
    DataSource ds = (DataSource) envCtx.lookup("jdbc/mydbcp");
    Connection conn = ds.getConnection();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select * from systypes");
    while (rs.next()) {%>

  <br>
  <%=rs.getString(1)%>
  <%}%>
  <%out.print("<br>Successful!成功!!\n");%>
  <%rs.close();
    stmt.close();
    conn.close();
   } catch (Exception e) {
    out.print("出现例外!" + e.getMessage());
    e.printStackTrace();
   }

  %>

 </body>
</html>

四、错误

错误1:Cannot load JDBC driver class 'com.microsoft.jdbc.sqlserver.SQLServerDriver'
是没有将sql jdbc driver包放在common\lib\目录下。

错误2:Cannot create PoolableConnectionFactory ([Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket.)
SQL数据库补丁包的问题,如果访问的数据库是SP3,任何问题没有。不是SP3就会出现上面的错误。

错误3:Name mydbcp is not bound in this Context
在context.xml中加入
<ResourceLink
    global="jdbc/mydbcp"
    name="jdbc/mydbcp"
type="javax.sql.DataSource"/>

- 作者: 和疯 2006年02月22日, 星期三 17:43  回复(0) |  引用(0) 加入博采

JSP连接各类据库大全

一、jsp连接Oracle8/8i/9i数据库(用thin模式)

   testoracle.jsp如下:

<%@ page contentType=
"text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName
("oracle.jdbc.driver.OracleDriver").newInstance(); 
  String url="jdbc:oracle:thin:@localhost:1521:orcl"; 
  //orcl为你的数据库的SID 
  String user="scott"; 
  String password="tiger"; 
  Connection conn= 
DriverManager.getConnection(url,user,password); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>




二、jsp连接Sql Server7.0/2000数据库

  testsqlserver.jsp如下:
<%@ page contentType=
"text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver")
.newInstance(); 
  String url="jdbc:microsoft:sqlserver:
//localhost:1433;DatabaseName=pubs"; 
  //pubs为你的数据库的 
  String user="sa"; 
  String password="";   
  Connection conn= DriverManager.getConnection
(url,user,password); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close();   
  %> 
  </body> 
  </html>


三、jsp连接DB2数据库

  testdb2.jsp如下: 
<%@ page contentType=
"text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName
("com.ibm.db2.jdbc.app.DB2Driver ").newInstance(); 
  String url="jdbc:db2://localhost:5000/sample"; 
  //sample为你的数据库名 
  String user="admin"; 
  String password=""; 
  Connection conn= 
DriverManager.getConnection(url,user,password); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>


四、jsp连接Informix数据库

   testinformix.jsp如下:

<%@ page contentType="text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName("com.informix.jdbc.IfxDriver").newInstance(); 
  String url = 
  "jdbc:informix-sqli://123.45.67.89:1533
/testDB:INFORMIXSERVER=myserver; 
  user=testuser;password=testpassword"; 
  //testDB为你的数据库名 
  Connection conn= DriverManager.getConnection(url); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>


五、jsp连接Sybase数据库

  testmysql.jsp如下:
<%@ page contentType
="text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName
("com.sybase.jdbc.SybDriver").newInstance(); 
  String url =" jdbc:sybase:Tds:localhost:5007/tsdata"; 
  //tsdata为你的数据库名 
  Properties sysProps = System.getProperties(); 
  SysProps.put("user","userid"); 
  SysProps.put("password","user_password"); 
  Connection conn= 
DriverManager.getConnection(url, SysProps); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>


六、jsp连接MySQL数据库

  testmysql.jsp如下: 
<%@ page contentType
="text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName("org.gjt.mm.mysql.Driver").newInstance(); 
  String url="jdbc:mysql://localhost/softforum?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" 
  //testDB为你的数据库名 
  Connection conn= DriverManager.getConnection(url); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCRLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>


七、jsp连接PostgreSQL数据库

  testmysql.jsp如下:  
<%@ page contentType
="text/html;charset=gb2312"%> 
  <%@ page import="java.sql.*"%> 
  <html> 
  <body> 
  <%Class.forName("org.postgresql.Driver").newInstance(); 
  String url ="jdbc:postgresql://localhost/soft" 
  //soft为你的数据库名 
  String user="myuser"; 
  String password="mypassword"; 
  Connection conn= 
DriverManager.getConnection(url,user,password); 
  Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
  String sql="select * from test"; 
  ResultSet rs=stmt.executeQuery(sql); 
  while(rs.next()) {%> 
  您的第一个字段内容为:<%=rs.getString(1)%> 
  您的第二个字段内容为:<%=rs.getString(2)%> 
  <%}%> 
  <%out.print("数据库操作成功,恭喜你");%> 
  <%rs.close(); 
  stmt.close(); 
  conn.close(); 
  %> 
  </body> 
  </html>

- 作者: 和疯 2006年02月22日, 星期三 17:04  回复(1) |  引用(2) 加入博采

WEB应用中读取配置文件

假设你的属性文件Proxool.properties中有数据库配置信息:
jdbc-0.proxool.alias=Access
jdbc-0.proxool.driver-class=sun.jdbc.odbc.JdbcOdbcDriver
jdbc-0.proxool.driver-url=jdbc:odbc:cwb

jdbc-0.proxool.maximum-connection-count=20
jdbc-0.proxool.prototype-count=4

jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE
jdbc-0.proxool.verbose=true
jdbc-0.proxool.statistics=10s,1m,1d
jdbc-0.proxool.statistics-log-level=ERROR

你将这个属性文件放到你的WEB应用程序的web-info/classes目录下,在bean或类文件中访问这个属性文件
的传统方法莫过如此:

package examples;
import java.io.*;
import java.util.*;

public class EnvironmentConfig {
	static EnvironmentConfig ec;//创建对象ec
	private static Hashtable register = new Hashtable();//静态对象初始化[在其它对象之前]

    private EnvironmentConfig() {
        super();
    }

    /**
     * 取得EnvironmentConfig的一个实例
     * @return ec
     */
    public static EnvironmentConfig getInstance() {
        if (ec==null)
            ec = new EnvironmentConfig();//创建EnvironmentConfig对象
        return ec;//返回EnvironmentConfig对象
    }

    /**
     * 读取配置文件
     * @param java.lang.String fileName
     * @return Properties
     */

    public Properties getProperties(String fileName) {//传递配置文件路径
        InputStream is=null;//定义输入流is
        Properties p = null;
        try{
            p = (Properties)register.get(fileName);//将fileName存于一个HashTable
            /**
             * 如果为空就尝试输入进文件
             */
            if (p==null) {
                try{
                    is = new FileInputStream(fileName);//创建输入流
                }
                catch(Exception e){
                    if (fileName.startsWith("/"))
                        //用getResourceAsStream()方法用于定位并打开外部文件。
                        is = EnvironmentConfig.class.getResourceAsStream(fileName);
                    else
                        is = EnvironmentConfig.class.getResourceAsStream("/"+fileName);
                }
                p = new Properties();
                p.load(is);//加载输入流
                register.put(fileName, p);//将其存放于HashTable缓存
                is.close();//关闭输入流
            }
		}
		catch(Exception e){
		     e.printStackTrace(System.out);
		}
        return p;//返回Properties对象
    }

    /**
     * 此处插入方法描述。
     * 创建日期:(2003-8-10 12:30:09)
     * @param fileName java.lang.String
     * @param strKey java.lang.String
     */

    public String getPropertyValue(String fileName, String strKey) {
        Properties p = getProperties(fileName);
		try{
            return (String)p.getProperty(strKey);
        }
        catch(Exception e){
            e.printStackTrace(System.out);
        }
        return null;
    }
}

下面是jsp测试:testpro.jsp

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="examples.EnvironmentConfig" %>
<%@ page import="java.util.*" %>

配置文件测试<br>
<%
EnvironmentConfig ec=EnvironmentConfig.getInstance();
//Properties p=ec.getProperties("/Proxool.properties");
String s=ec.getPropertyValue("/Proxool.properties","jdbc-0.proxool.driver-class");
out.println("jdbc-0.proxool.driver-class="+s);


%>

运行结果:

配置文件测试
jdbc-0.proxool.driver-class=sun.jdbc.odbc.JdbcOdbcDriver

在tomcat 5.5.x下测试成功。

- 作者: 和疯 2006年02月22日, 星期三 15:01  回复(1) |  引用(2) 加入博采

Connection Pooling Proxool

SECTION 01 为何需要 connection pooling

当我们进入了 Java 的开发世界, pool 也是一门学问, 如何让 connection 先建立好与 DB 的连结, 后来的人可以使用已经存在于 pool 的 connection, 减少连结的时间, 这么优秀的功能, 在许多 application server 都已经实现好了, 你只要简单地按照说明文件配置, 包括最大连结数量, 初始连结数量, 最大等待数量等等的参数, 当然, Tomcat 也有内建 commons-dbcp 相关的 connection pooling 机制, 请查阅
Tomcat JNDI Datasource 设定!!


而 proxool 是一个强大的 connection pooling 项目, 兼容于 jdk 1.3 以及 1.4. 也已经实现了 监控, 纪录等等的功能, 对于一个有限制 connection 数量, 及注重 performation 的项目来说, 是一套非常完整的解决方案.

下载区, 目前版本 0.7.2

http://sourceforge.net/projects/proxool/


SECTION 02 设置 AdminServlet

首先, 你要把下载 proxool 的 lib 下面所有的 jar 文件, 放到 WEB-INF/lib 下面,

另外, 把你的 jdbc driver 也放到相同的 lib,

接著就是配置 /WEB-INF/web.xml

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"/WEB-INF/dtds/web-app_2_3.dtd">
<web-app>
<display-name>proxool</display-name>
<servlet>
  <servlet-name>Admin</servlet-name>
  <servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>Admin</servlet-name>
  <url-pattern>/admin</url-pattern>
</servlet-mapping> 

</web-app>



SECTION 03 通过 ProxoolDriver 取得 connection

建立一个 jsp or DAO Bean, 通过 org.logicalcobwebs.proxool.ProxoolDriver 建立 Connection



test.jsp

<%@page import="java.sql.*"%>
<%
Connection connection = null;
try {
Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");

connection = DriverManager.getConnection(
"proxool.test:org.gjt.mm.mysql.Driver:jdbc:mysql://localhost:3306/test",
"root",
"password"
);
} catch (Exception e) {
	out.println(e)
}
out.println("OK");
%>



SECTION 04 检视 pooling 现在状态

执行 http://localhost:8080/proxool-test/admin ( proxool-test 是你的应用名称 ) 如果没有任何 pool 状态的时候, 你只会看到 Pools 这几个字, 所以你先执行 http://localhost:8080/proxool-test/test.jsp 建立一个 connection, 就可以监控 connection pooling 的状态了.

Pools
>test -> jdbc:mysql://www:3306/test

Defintition for test
URLjdbc:mysql://localhost:3306/test
Driverorg.gjt.mm.mysql.Driver
Connections0 (min), 15 (max)
Prototypingoff
Connection Lifetime11:00:00
Maximum active time07:05:00
House keeping sleep time30s
House keeping test SQLoff
Fatal SQL exceptionsoff
Statisticsoff

Snapshot at 21:12:53
Start date01-??-2003 21:12:30
Connections1 (active), 0 (available), 15 (max)
  
Served1
Refused0
Details
#bornlast
start
la
(ms)
 thread
1 21:12:31 21:12:3122432   Thread-15
less information

Proxool 0.7.2 (29-Apr-2003 00:33)



SECTION 05 使用 properties 或者 xml 来设置 DB URL 及 Driver

可以采用 xml 配置文件, 在程序中使用 JAXPConfigurator.configure("proxool.xml", false); 配置文件设置如下

WEB-INF/proxool.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- the proxool configuration can be embedded within your own application's.
Anything outside the "proxool" tag is ignored. -->
<something-else-entirely>
  <proxool>
    <alias>xml-test</alias>
    <driver-url>jdbc:mysql://localhost:3306/test</driver-url>
    <driver-class>org.gjt.mm.mysql.Driver</driver-class>
    <driver-properties>
      <property name="user" value="root"/>
      <property name="password" value="password"/>
    </driver-properties>
    <maximum-connection-count>10</maximum-connection-count>
    <house-keeping-test-sql>select CURRENT_DATE</house-keeping-test-sql>
  </proxool>
</something-else-entirely>






也可以采用 properties, 在程序 PropertyConfigurator.configure("proxool.properties"); 文件设置

WEB-INF/proxool.properties
jdbc-0.proxool.alias=property-test
jdbc-0.proxool.driver-url=jdbc:mysql://localhost:3306/test
jdbc-0.proxool.driver-class=org.gjt.mm.mysql.Driver
jdbc-0.user=root
jdbc-0.password=password
jdbc-0.proxool.maximum-connection-count=10
jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE






如果在 Web 使用, 在 web.xml 也可以设置 ServletConfigurator Servlet 来注册

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"/WEB-INF/dtds/web-app_2_3.dtd">
<web-app>
	<display-name>proxool</display-name>

	<servlet>
	  <servlet-name>ServletConfigurator</servlet-name>
	  <servlet-class>
	  org.logicalcobwebs.proxool.configuration.ServletConfigurator
	  </servlet-class>
	 
	  <init-param>
		<param-name>xmlFile</param-name>
		<param-value>WEB-INF/proxool.xml</param-value>
	  </init-param>

	   <load-on-startup>1</load-on-startup>

	</servlet> 


	<servlet>
	  <servlet-name>Admin</servlet-name>
	  <servlet-class>
	  org.logicalcobwebs.proxool.admin.servlet.AdminServlet
	  </servlet-class>
	</servlet>

	<servlet-mapping>
	  <servlet-name>Admin</servlet-name>
	  <url-pattern>/admin</url-pattern>
	</servlet-mapping> 

</web-app>

在程序中, 只需要利用到别名就可以呼叫 connection pool 里面的 connection 来使用了

<%@page import="java.sql.*;"%>
<%
Connection connection = null;
try {
	Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
	connection = DriverManager.getConnection("proxool.xml-test");

} catch (Exception e) {
	out.println(e);
}

out.println("ok");
%>



SECTION 06 使用 connection.close() 关闭 connection

以上的范例我都没有写 close, 希望大家在 connection 做完之后记得使用 close() 来关闭, 将 connection 还到 pool , 以免有 java.sql.SQLException: org.logicalcobwebs.proxool.ProxoolException: ConnectionCount is 10. Maximum connection count of 10 cannot be exceeded. 的现象发生.
参考 -- 相关书目或相关文章

  1. Proxool :
    http://proxool.sourceforge.net/
  2. Proxool API:
    http://proxool.sourceforge.net/api-dev/index.html

- 作者: 和疯 2006年02月22日, 星期三 14:29  回复(3) |  引用(2) 加入博采

在JSP页面中实现检索数据的分页显示
在页面中,当检索的数据很多时,通常需要分页显示数据,并要实现翻页。 

下面将通过一些例程来说明实现JSP页面翻页技术的实现。 

首先,在JSP中,通过JAVA servlet 来检索数据,而用JSP来调用结果来显示。 

因而,此技术可分为两个部分(依赖关系): 

1. 在服务器端的servlet 中的实现 

要点: 

& 将查询条件保存到session中,取session中的查询条件 

& 设置Statement对象的MaxRows(确定一页显示多少行数据) 

& 顺序地通过执行SQL语句查询数据,按maxRows 来检索一个maxRows的数据, 

下一页再检索下一maxRows的数据,以此类推。 

2. 在JSP中的显示实现 

要点: 

& 显示maxRows条数据 

& 通过“下一页”按钮或超链再次调用刚才的servlet查询下一maxRows的数据 

流程如图所示: 



下面通过一个例程来说明(一个servlet程序和一个JSP程序): 

l querymedicine. java (Medicin. querymedicine) 

package Medicine; 

import javax.servlet.*; 

import javax.servlet.http.*; 

import java.io.*; 

import java.util.*; 

import java.sql.*; 

import Medicine.medicinelist; 

import Medicine.searchData; 

//////////////////////////////////////////////////// 

// 接---mutiquery.jsp页面,并从request中得到5条查询条件 /// 

// 按条件查询药品,并将结果存进session的“medicinelist”中。 /// 

// 张乾 2000年3月15日 /// 

//////////////////////////////////////////////////// 

public class querymedicine extends HttpServlet { 

private DBConnectionManager connMgr; 

//Initialize global variables 

public void init(ServletConfig config) throws ServletException { 

super.init(config); 

connMgr = DBConnectionManager.getInstance(); 



//========================处理 HTTP Get 请求============================ 

public void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { 

Statement stmt=null; 

Connection con = connMgr.getConnection("medicine"); 

if (con == null) { 

response.sendRedirect("/medicine/con_error.html"); 

return; 



// ==================== 创建数据库Statement ============================= 

try { 

stmt=con.createStatement(); 



catch (Exception e) 



connMgr.freeConnection("medicine",con); 

response.sendRedirect("/medicine/stmt_error.html"); 

return; 



//------------------------------------------------------------- 

long all_count=0; //存满足条件的药品总数 

//===================从request中得到session====================== 

try{ 

HttpSession session = request.getSession(false); 

if (session == null) { 

connMgr.freeConnection("medicine",con); 

response.sendRedirect("/medicine/session_error.html"); 

return; 



//----------------------------------------------------------- 

//======从“下一页”提交来的参数取得前页最后一条数据的药品编码======= 

String ll_pos=request.getParameter("pos"); 
//如果pos=-1则表示要从头开始查 

//---------------------------------------------------------- 

//=====================查询用的SQL语句串========================== 

String sqlstatment="SELECT medicines.ypbm, medsmalltypes.zlmc, medsupertypes.clmc, 
medtypes.dlmc, medicines.ypm, medicines.zyyx, medicines.ypzy FROM medicines, 
medsmalltypes,medsupertypes,medtypes WHERE medicines.ypbm>"+ll_pos+" 
and (( medsmalltypes.zlbm = medicines.zlbm ) and ( medsupertypes.clbm = medicines.clbm ) 
and ( medtypes.dlbm = medicines.dlbm ) and ( ( medicines.del_flag = 0 ) "; 

//----------------------------------------------------- 

String zlbm; 

String dlbm; 

String clbm; 

String zyyx; 

String ypm; 

searchData slist=new searchData(); 

synchronized (session) { 

slist=(searchData)session.getAttribute("searchList"); 



if(ll_pos.equals("-1")){ 

//===表示不是由“下一页”过来要从头开始查数据========== 

if(slist!=null){ 

synchronized (session) { 

session.removeAttribute("searchList"); 





slist=new searchData(); 

//=============从设置查询条件页面取得查询条件的参数=================== 

zlbm=request.getParameter("zlbm"); 

dlbm=request.getParameter("dlbm"); 

clbm=request.getParameter("clbm"); 

zyyx=request.getParameter("zyyx"); 

ypm=request.getParameter("ypm"); 

//------------------------------------------------------ 

//=================将查询条件参数通过Vector存到session中========== 

slist.setZlbm (zlbm); 

slist.setDlbm (dlbm); 

slist.setClbm (clbm); 

slist.setZyyx (zyyx); 

slist.setYpm (ypm); 

synchronized (session) { 

session.setAttribute ("searchList",slist); 



//--------------------------------------------------------- 



//-------------------------------------------------------- 

else 



//============================取出查询条件参数==================== 

if(slist!=null){ 

zlbm=slist.getZlbm(); 

dlbm=slist.getDlbm(); 

clbm=slist.getClbm(); 

zyyx=slist.getZyyx(); 

ypm=slist.getYpm(); 



else{ 

if(stmt!=null) stmt.close(); 

stmt.setMaxRows(0); 

connMgr.freeConnection("medicine",con); 

response.sendRedirect("/medicine/session_error.html"); 

return; 



//------------------------------------------------- 



String sql2="select count(*) from medicines where del_flag=0"; 

//=====================根据条件参数设置SQL语句======================= 

if(!(zlbm.trim().equals("0"))) { 

sqlstatment+=(" and ( medicines.zlbm='"+zlbm.trim()+"' ) "); 

sql2+=(" and zlbm='"+zlbm.trim()+"'"); 



if(!(dlbm.trim().equals("0"))) { 

sqlstatment+=(" and ( medicines.dlbm='"+dlbm.trim()+"' )"); 

sql2+=(" and dlbm='"+dlbm.trim()+"'"); 



if(!(clbm.trim().equals("0"))) { 

sqlstatment+=(" and ( medicines.clbm='"+clbm.trim()+"' ) "); 

sql2+=(" and clbm='"+clbm.trim()+"'"); 



if(!(zyyx.trim().length ()==0)) { 

sqlstatment+=(" and ( medicines.zyyx like '%"+zyyx.trim()+"%' ) "); 

sql2+=(" and zyyx like '%"+zyyx.trim()+"%'"); 



if(!(ypm.trim().length ()==0)) { 

sqlstatment+=(" and ( medicines.ypm like '%"+yp.trim()+"%' ) "); 

sql2+=(" and ypm like '%"+ypm.trim()+"%'"); 



sqlstatment+=" )) ORDER BY medicines.ypbm ASC "; 

//------------------------------------------------------------- 

Vector list = new Vector(); 

//================= 设置一页显示的数据条数(一次检索出的数据条数)=========== 

stmt.setMaxRows(25); 

//---------------------------------------------------------------------- 

//===================执行查询将结果放到ResultSet中================ 

ResultSet rs = stmt.executeQuery(sqlstatment); 

ResultSet rs2 = stmt.executeQuery(sql2); 

//------------------------------------------------ 

if(rs==null){ //如果没有查询结果数据 

if(stmt!=null) stmt.close(); 

stmt.setMaxRows(0); 

connMgr.freeConnection("medicine",con); 

response.sendRedirect("/medicine/no_medicine.html"); //定向到一个页面 

return; 



//====================将药品信息填入数据对象并存入Vector中================ 

if(rs2.next()){ 

all_count=rs2.getLong(1); //取得总条数 



if(rs2!=null)rs2.close(); 

while(rs.next()){ 

medicinelist m = new medicinelist(); 

m.setYpbm(rs.getInt("ypbm")); 

m.setZlmc(rs.getString("zlmc")); 

m.setClmc(rs.getString("clmc")); 

m.setDlmc(rs.getString("dlmc")); 

m.setYpm(rs.getString("ypm")); 

m.setZyyx(rs.getString("zyyx")); 

m.setYpzy(rs.getString("ypzy")); 

m.setClbm(clbm); 

m.setDlbm(dlbm); 

m.setZlbm(zlbm); 

list.addElement(m); 



//---------------------------------------------------------- 

if(rs!=null)rs.close(); 

stmt.setMaxRows(0); 

if(stmt!=null)stmt.close(); 

connMgr.freeConnection("medicine",con); 

//========================存入session中=========================== 

synchronized (session) { 

session.setAttribute("medicinelist",list); 



//----------------------------------------------- 

}catch (SQLException e){ 

connMgr.freeConnection("medicine",con); 

response.sendRedirect("/Medicine/sql_error.html"); 

return;} 

//=======================重定向到一个JSP页面========================== 

String url="/medicine/querymedicine.jsp?all_count="+all_count; 

ServletContext sc = getServletContext(); 

RequestDispatcher rd = sc.getRequestDispatcher(url); 

rd.forward(request, response); 

//------------------------------------------------------- 



public void destroy() { 

// =================== 在Servlet退出时终止数据库连接,取消Statement对象 

if(connMgr!=null) connMgr.release(); 

//------------------------------------------------------------------------ 



//========================处理HTTP Post 请求 ============================ 

public void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { 

doGet(request,response); 



//==========================取得 Servlet 信息 ============================ 

public String getServletInfo() { 

return "medicine.querymedicine Information"; 





l querymedicine.jsp 

<%@ page language="java" session="true" import="java.util.*, 
Medicine.method, Medicine.medicinelist"contentType="text/html;charset=gbk" %> 

<script language="javascript"> 

function next(){ 

var ls_pos=document.form2.maxpos.value; 

document.location="/servlet/Medicine.querymedicine?pos="+ls_pos; 



function detail(ypbm){ 

document.location="/servlet/Medicine.Detail?ypbm="+ypbm; 



</script> 

<!--add head--> 

<div align="center"> 

<body topmargin="0" leftmargin="10" rightmargin="10” bgcolor="#FFFFFF"> 
<div align="center"> 

<center><IFRAME WIDTH=760 height=130 NORESIZE SCROLLING=no FRAMEBORDER=0 
MARGINHEIGHT=0 MARGINWIDTH=0 SRC="..\medicinetitle.html"></iframe> 

</div> 

<!--finish--> 

<title>商品列表</title> 

<% 

method md = new method(); 

Vector sklist; 

synchronized (session) { 

sklist = (Vector) session.getAttribute("medicinelist"); 



%> 

<!----------------------------- 显示表头 --------------------------------> 

<% 

if (sklist == null or sklist.size() <= 0) 



response.sendRedirect("/medicine/no_medicine.html"); 

return; 



else 

{%> 

<center>您好!以下是商品的列表,共有<font color=#ff0000> 
<%=request.getParameter("all_count")%></font>条符合条件的药品信息 

</center> 

<div align="center"> 

<center> 

<table border="1" cellpadding="0" cellspacing="0" width="840" 
bordercolorlight="#FFFFFF" bordercolordark="#000000"> 

<tr bgcolor="#339933"> 

<td width=42 align="center"><font color="#339933"><b>明细</b></font></td> 

<td width=160 align="center"><font color="#FFFFFF"><b>商品名称</b></font></td> 

<td width=52 align="center"><font color="#FFFFFF"><b>超类</b></font></td> 

<td width=145 align="center"><font color="#FFFFFF"><b>大类</b></font></td> 

<td width=145 align="center"><font color="#FFFFFF"><b>子类</b></font></td> 

<td width=270 align="center"><font color="#FFFFFF"><b>描述</b></font></tdgt; 

</tr> 

<!-------------------------------------------------------------------------------------------------------------------> 

<% 

medicinelist d=new medicinelist(); 

for (int index=0; index < sklist.size();index++) 



d = (medicinelist)sklist.elementAt(index); 

String lshref; 

if (d.getYpzy()==null or d.getYpzy().equals("http://") or d.getYpzy().equals("")) 



lshref=""; 

}else{ 

lshref="<a href="+d.getYpzy()+">"; 



out.println("<form name=form1 method=post action=/servlet/Medicine.Detail?ypbm="+d.getYpbm()+">"); 

out.println("<tr bgcolor=#F3F3E9><td align=center><font color=#000000 size=2> 
<input type=submit name=submit1 value=明细></font></td><td align=center><font color=#000000 size=2>"); 

out.println(lshref+d.getYpm()+"</a></font></td><td align=center><font color=#000000 size=2>"); 

out.println(d.getClmc()+"</font></td><td align=center><font color=#000000 size=2>" 
+d.getDlmc()+"</font></td><td align=center><font color=#000000 size=2>"); 

out.println(d.getZlmc()+"</font></td><td align=center><font color=#000000 size=2>" 
+md.notNull(d.getZyyx())+"</font></td></tr></form>"); 

out.flush(); 



%> 

<form name=form2 id=form2> 

<input type=hidden name=maxpos id=maxpos value=<%=d.getYpbm()%>> 

</form> 

<% 



%> 

</table> 

<p></p> 

<% 

String ssll=request.getParameter("all_count"); 

Long temp=new Long(ssll); 

long cou= temp.longValue(); 

if(sklist.size()==25&&cou>25) 

{%> 

<input type=button value=" 下页 " onclick="next(1);"> 

<%}%> 

<% 

synchronized (session) { 

if(session.getAttribute("medicinelist")!=null){ 

session.removeValue("medicinelist"); 





%> 

</center> 

<p align="center"><input type="button" value=" 返回 " name="B3" onclick="history.back()"> 

<br><br><br> 

<!--add bottom--> 

<div align="center"> 

<center><IFRAME WIDTH=760 height=140 NORESIZE SCROLLING=no FRAMEBORDER=0 
MARGINHEIGHT=0 MARGINWIDTH=0 SRC="..\bottom.html"></iframe> 

</div> 

<!--finish--> 

- 作者: 和疯 2006年02月22日, 星期三 09:44  回复(1) |  引用(2) 加入博采

基于JDBC的数据库连接池技术研究与应用
转自:动态网站制作指南 | www.knowsky.com

  引言

  近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机应用程序已从传统的桌面应用转到Web应用。基于B/S(Browser/Server)架构的3层开发模式逐渐取代C/S(Client/Server)架构的开发模式,成为开发企业级应用和电子商务普遍采用的技术。在Web应用开发的早期,主要使用的技术是CGI﹑ASP﹑PHP等。之后,Sun公司推出了基于Java语言的Servlet+Jsp+JavaBean技术。相比传统的开发技术,它具有跨平台﹑安全﹑有效﹑可移植等特性,这使其更便于使用和开发。

  Java应用程序访问数据库的基本原理

  在Java语言中,JDBC(Java DataBase Connection)是应用程序与数据库沟通的桥梁,

  即Java语言通过JDBC技术访问数据库。JDBC是一种“开放”的方案,它为数据库应用开发人员﹑数据库前台工具开发人员提供了一种标准的应用程序设计接口,使开发人员可以用纯Java语言编写完整的数据库应用程序。JDBC提供两种API,分别是面向开发人员的API和面向底层的JDBC驱动程序API,底层主要通过直接的JDBC驱动和JDBC-ODBC桥驱动实现与数据库的连接。

  一般来说,Java应用程序访问数据库的过程(如图1所示)是:

  ①装载数据库驱动程序;

  ②通过JDBC建立数据库连接;

  ③访问数据库,执行SQL语句;

  ④断开数据库连接。


图1 Java数据库访问机制
  JDBC作为一种数据库访问技术,具有简单易用的优点。但使用这种模式进行Web应用
  程序开发,存在很多问题:首先,每一次Web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的Web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
 
  数据库连接池(connection pool)的工作原理
  1、基本概念及原理
  由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,
  对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。连接池的基本工作原理见下图2。

图2 连接池的基本工作原理
  2、服务器自带的连接池
  JDBC的API中没有提供连接池的方法。一些大型的WEB应用服务器如BEA的WebLogic和IBM的WebSphere等提供了连接池的机制,但是必须有其第三方的专用类方法支持连接池的用法。
  连接池关键问题分析
  1、并发问题
  为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:
public synchronized Connection getConnection()
  2、多数据库服务器和多用户
  对于大型的企业级应用,常常需要同时连接不同的数据库(如连接Oracle和Sybase)。如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址(<poolName.url>)﹑用户名(<poolName.user>)﹑密码(<poolName.password>)等信息。如tx.url=172.21.15.123:5000/tx_it,tx.user=yang,tx.password=yang321。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。
  对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。
  3、事务处理
  我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。
  在Java语言中,Connection类本身提供了对事务的支持,可以通过设置Connection的AutoCommit属性为false,然后显式的调用commit或rollback方法来实现。但要高效的进行Connection复用,就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现,这种方法可以大大降低事务管理的复杂性。
  4、连接池的分配与释放
  连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。
  对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxConn),如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout,则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。
  5、连接池的配置与维护
  连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConn)和最大连接数(maxConn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。
  如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。
 
  连接池的实现
  1、连接池模型
  本文讨论的连接池包括一个连接池类(DBConnectionPool)和一个连接池管理类(DBConnetionPoolManager)。连接池类是对某一数据库所有连接的“缓冲池”,主要实现以下功能:①从连接池获取或创建可用连接;②使用完毕之后,把连接返还给连接池;③在系统关闭前,断开所有连接并释放连接占用的系统资源;④还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。
  连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。其主要用于对多个连接池对象的管理,具有以下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,创建连接池对象;③为方便管理多个连接池对象,为每一个连接池对象取一个名字,实现连接池名字与其实例之间的映射;④跟踪客户使用连接情况,以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理,如系统需要连接不同的数据库,或连接相同的数据库但由于安全性问题,需要不同的用户使用不同的名称和密码。
  2、连接池实现
  下面给出连接池类和连接池管理类的主要属性及所要实现的基本接口:
public class DBConnectionPool implements TimerListener{
private int checkedOut;//已被分配出去的连接数
private ArrayList freeConnections = new ArrayList();//容器,空闲池,根据//创建时间顺序存放已创建但尚未分配出去的连接
private int minConn;//连接池里连接的最小数量
private int maxConn;//连接池里允许存在的最大连接数
private String name;//为这个连接池取个名字,方便管理
private String password;//连接数据库时需要的密码
private String url;//所要创建连接的数据库的地址
private String user;//连接数据库时需要的用户名
public Timer timer;//定时器
public DBConnectionPool(String name, String URL, String user, String
password, int maxConn)//公开的构造函数
public synchronized void freeConnection(Connection con) //使用完毕之后,//把连接返还给空闲池
public synchronized Connection getConnection(long timeout)//得到一个连接,//timeout是等待时间
public synchronized void release()//断开所有连接,释放占用的系统资源
private Connection newConnection()//新建一个数据库连接
public synchronized void TimerEvent() //定时器事件处理函数
}
public class DBConnecionManager {
static private DBConnectionManager instance;//连接池管理类的唯一实例
static private int clients;//客户数量
private ArrayList drivers = new ArrayList();//容器,存放数据库驱动程序
private HashMap pools = new HashMap ();//以name/value的形式存取连接池//对象的名字及连接池对象
static synchronized public DBConnectionManager getInstance()//如果唯一的//实例instance已经创建,直接返回这个实例;否则,调用私有构造函数,创//建连接池管理类的唯一实例
private DBConnectionManager()//私有构造函数,在其中调用初始化函数init()
public void freeConnection(String name, Connection con)// 释放一个连接,//name是一个连接池对象的名字
public Connection getConnection(String name)//从名字为name的连接池对象//中得到一个连接
public Connection getConnection(String name, long time)//从名字为name
//的连接池对象中取得一个连接,time是等待时间
public synchronized void release()//释放所有资源
private void createPools(Properties props)//根据属性文件提供的信息,创建//一个或多个连接池
private void init()//初始化连接池管理类的唯一实例,由私有构造函数调用
private void loadDrivers(Properties props)//装载数据库驱动程序
  3、连接池使用
  上面所实现的连接池在程序开发时如何应用到系统中呢?下面以Servlet为例说明连接池的使用。
  Servlet的生命周期是:在开始建立servlet时,调用其初始化(init)方法。之后每个用户请求都导致一个调用前面建立的实例的service方法的线程。最后,当服务器决定卸载一个servlet时,它首先调用该servlet的 destroy方法。
  根据servlet的特点,我们可以在初始化函数中生成连接池管理类的唯一实例(其中包括创建一个或多个连接池)。如:
public void init() throws ServletException
{
 connMgr = DBConnectionManager.getInstance();
  然后就可以在service方法中通过连接池名称使用连接池,执行数据库操作。最后在destroy方法中释放占用的系统资源,如:
public void destroy() {
 connMgr.release(); super.destroy();
}
  结束语
  在使用JDBC进行与数据库有关的应用开发中,数据库连接的管理是一个难点。很多时候,连接的混乱管理所造成的系统资源开销过大成为制约大型企业级应用效率的瓶颈。对于众多用户访问的Web应用,采用数据库连接技术的系统在效率和稳定性上比采用传统的其他方式的系统要好很多。本文阐述了使用JDBC访问数据库的技术﹑讨论了基于连接池技术的数据库连接管理的关键问题并给出了一个实现模型。文章所给出的是连接池管理程序的一种基本模式,为提高系统的整体性能,在此基础上还可以进行很多有意义的扩展。

- 作者: 和疯 2006年02月22日, 星期三 08:52  回复(2) |  引用(2) 加入博采

DBConnectionManager连接池类用法
摘要:JDBC Java Servlet作为首选的服务器端数据处理技术,正在迅速取代CGI脚本。Servlet超越CGI的优势之一在于,不仅多个请求可以共享公用资源,而且还可以在不同用户请求之间保留持续数据。本文介绍一种充分发挥该特色的实用技术,即数据库连接池。 查看全文

- 作者: 和疯 2006年02月21日, 星期二 17:30  回复(1) |  引用(2) 加入博采

JSP+JDBC(Thin模式)连接Oracle

在JSP中连接到Oracle一般有2种方式:

  1、Oracle JDBC的oci8方式

  2、Oracle JDBC的thin方式 

  我比较喜欢第2种,因为WEB发布服务器与数据库服务器一般都不会放在同一台电脑中,而在使用thin方式连接时,WEB服务器端无须安装oracle的客户端。

  在动手先代码之前,我们先把环境配置妥善。先从安装了Oracle的数据库服务器中,找到Oracle安装目录,然后将该目录下的jdbc\lib\classes12.jar文件拷贝到WEB发布服务器的某个目录。假设就直接放在C:\根目录下吧,然后把该路径添加到‘系统--高级--环境变量’中变量名为‘CLASSPATH’的值中,如:D:\Program Files\SQLLIB\java\db2java.zip;D:\Program Files\SQLLIB\java\runtime.zip;c:classes12.jar; 也就是让java能够找到这个包。

  配置好环境后,我们就开始开始动手写代码了。关于数据库连接的代码,应该写个专门的连接类来调用,没必要想网络上有些文章那样,直接写到JSP的代码中。

  关于连接的代码很简单

private Connection newConnection(String user,String password) {
Connection con = null; 
try { 
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); 
con = DriverManager.getConnection (“jdbc:oracle:thin:@192.168.96.1:1521:oracle9i”,user,password); 

catch (SQLException e) { 
return null; 

return con; 
}  

  如果帐号密码没有错,那这个函数就应该能返回个可用的连接。但如此简单的连接在一个项目中使用,是远远达不到效果的。我们可以在这个数据库连接类中加入更多的功能,如连接池等等。下面我就把该数据库连接类的代码详细的列来,大家可以参考参考。

/*
* @Title 公司网站
* @Author: zf
* @Version 1.0
* @Memo:定义数据库连接及其数据库连接池等
*/
package com.kingson.db;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;

public class DBConnectionManager {
static private DBConnectionManager instance; // 唯一实例
static private int clients;

private Vector drivers = new Vector();
private PrintWriter log;
private Hashtable pools = new Hashtable();

/**
* 返回唯一实例.如果是第一次调用此方法,则创建实例
*
* @return DBConnectionManager 唯一实例
*/
static synchronized public DBConnectionManager getInstance() {
if (instance == null) {
instance = new DBConnectionManager();
}
clients++;
return instance;
}

/**
* 建构函数私有以防止其它对象创建本类实例
*/
private DBConnectionManager() {
init();
}

/**
* 将连接对象返回给由名字指定的连接池
*
* @param name 在属性文件中定义的连接池名字
* @param con 连接对象
*/
public void freeConnection(String name, Connection con) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
pool.freeConnection(con);
}
}

/**
* 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
* 限制,则创建并返回新连接
*
* @param name 在属性文件中定义的连接池名字
* @return Connection 可用连接或null
*/
public Connection getConnection(String name) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
return pool.getConnection();
}
return null;
}

/**
* 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
* 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
*
* @param name 连接池名字
* @param time 以毫秒计的等待时间
* @return Connection 可用连接或null
*/
public Connection getConnection(String name, long time) {
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null) {
return pool.getConnection(time);
}
return null;
}

/**
* 关闭所有连接,撤销驱动程序的注册
*/
public synchronized void release() {
// 等待直到最后一个客户程序调用
if (--clients != 0) {
return;
}

Enumeration allPools = pools.elements();
while (allPools.hasMoreElements()) {
DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
pool.release();
}
Enumeration allDrivers = drivers.elements();
while (allDrivers.hasMoreElements()) {
Driver driver = (Driver) allDrivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册");
}
catch (SQLException e) {
log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
}
}
}

/**
* 根据指定属性创建连接池实例.
*
* @param props 连接池属性
*/
private void createPools(Properties props) {
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
if (name.endsWith(".url")) {
String poolName = name.substring(0, name.lastIndexOf("."));
String url = props.getProperty(poolName + ".url");
if (url == null) {
log("没有为连接池" + poolName + "指定URL");
continue;
}
String user = props.getProperty(poolName + ".user");
String password = props.getProperty(poolName + ".password");
String dbip = props.getProperty(poolName + ".db_ip", "192.168.96.1");
String dbport = props.getProperty(poolName + ".db_port", "1521");
String dbuid = props.getProperty(poolName + ".db_uid", "ORACLE9I");
String maxconn = props.getProperty(poolName + ".maxconn", "0");
//连接信息
String dbInfo = user + "/" + password + "@" + dbip + ":" + dbport + ":" + dbuid;
int max;
try {
max = Integer.valueOf(maxconn).intValue();
}
catch (NumberFormatException e) {
log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
max = 0;
}
DBConnectionPool pool = new DBConnectionPool(poolName, url,dbInfo, max);
pools.put(poolName, pool);
log("成功创建连接池" + poolName);
}
}
}

/**
* 读取属性完成初始化
*/
private void init() {
InputStream is = getClass().getResourceAsStream("db.properties");
Properties dbProps = new Properties();
try {
dbProps.load(is);
}
catch (Exception e) {
System.err.println("不能读取属性文件. " +
"请确保db.properties在CLASSPATH指定的路径中");
return;
}
String logFile = dbProps.getProperty("logfile", "newslog.txt");
try {
log = new PrintWriter(new FileWriter(logFile, true), true);
}
catch (IOException e) {
System.err.println("无法打开日志文件: " + logFile);
log = new PrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
}

/**
* 装载和注册所有JDBC驱动程序
*
* @param props 属性
*/
private void loadDrivers(Properties props) {
String driverClasses = props.getProperty("driver");
StringTokenizer st = new StringTokenizer(driverClasses);
while (st.hasMoreElements()) {
String driverClassName = st.nextToken().trim();
try {
Driver driver = (Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
log("成功注册JDBC驱动程序" + driverClassName);
}
catch (Exception e) {
log("无法注册JDBC驱动程序: " +
driverClassName + ", 错误: " + e);
}
}
}

/**
* 将文本信息写入日志文件
*/
private void log(String msg) {
log.println(ew Date() + ": " + msg);
}

/**
* 将文本信息与异常写入日志文件
*/
private void log(Throwable e, String msg) {
log.println(new Date() + ": " + msg);
e.printStackTrace(log);
}

/***************连接池类*************************************************/

/**
* 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最
* 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.
*/
class DBConnectionPool {
private int checkedOut;
private Vector freeConnections = new Vector();
private int maxConn;
private String name;
private String URL;
private String dbInfo;

/**
* 创建新的连接池
*
* @param name 连接池名字
* @param URL 数据库的JDBC URL
* @param dbInfo 数据库连接信息
* @param maxConn 此连接池允许建立的最大连接数
*/
public DBConnectionPool(String name, String URL, String dbInfo, int maxConn) {
this.name = name;
this.URL = URL;
this.dbInfo = dbInfo;
this.maxConn = maxConn;
}

/**
* 将不再使用的连接返回给连接池
*
* @param con 客户程序释放的连接
*/
public synchronized void freeConnection(Connection con) {
// 将指定连接加入到向量末尾
freeConnections.addElement(con);
checkedOut--;
notifyAll();
}

/**
* 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
* 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
* 然后递归调用自己以尝试新的可用连接.
*/
public synchronized Connection getConnection() {
Connection con = null;
if (freeConnections.size() > 0) {
// 获取向量中第一个可用连接
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
if (con.isClosed()) {
log("从连接池" + name+"删除一个无效连接");
// 递归调用自己,尝试再次获取可用连接
con = getConnection();
}
}
catch (SQLException e) {
log("从连接池" + name+"删除一个无效连接");
// 递归调用自己,尝试再次获取可用连接
con = getConnection();
}
}
else if (maxConn == 0 || checkedOut < maxConn) {
con = newConnection();
}
if (con != null) {
checkedOut++;
}
return con;
}

/**
* 从连接池获取可用连接.可以指定客户程序能够等待的最长时间
* 参见前一个getConnection()方法.
*
* @param timeout 以毫秒计的等待时间限制
*/
public synchronized Connection getConnection(long timeout) {
long startTime = new Date().getTime();
Connection con;
while ((con = getConnection()) == null) {
try {
wait(timeout);
}
catch (InterruptedException e) {}
if ((new Date().getTime() - startTime) >= timeout) {
// wait()返回的原因是超时
return null;
}
}
return con;
}

/**
* 关闭所有连接
*/
public synchronized void release() {
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection con = (Connection) allConnections.nextElement();
try {
con.close();
log("关闭连接池" + name+"中的一个连接");
}
catch (SQLException e) {
log(e, "无法关闭连接池" + name+"中的连接");
}
}
freeConnections.removeAllElements();
}

/**
* 创建新的连接
*/
private Connection newConnection() {
Connection con = null; 
try { 
con = DriverManager.getConnection(URL+dbInfo); 
log("连接池" + name+"创建一个新的连接"); 

catch (SQLException e) { 
log(e, "无法创建下列URL的连接: " + URL); 
return null; 

return con; 



}
}
 

- 作者: 和疯 2006年02月21日, 星期二 17:28  回复(2) |  引用(2) 加入博采

JSP+MYSQL+Java类优化分页的实例

  在JSP中经常要用到查询数据库中的数据,但常用的查询方法有一个缺点,当数据库很大的时候查询的速度会变的很慢。

  在JSP中经常要用到查询数据库中的数据,同常我们的做法是使用SQL语句“select * from tablename order by id desc”,这样的做法有一个缺点,当数据库很大的时候查询的速度会变的很慢,在ASP中有一种方法 "select top "&recpage&" * from tablename where id not in (select top "&(recpage*(currentpage-1))&" id from products order by id desc) order by id desc"其中recpage为每页显示个数, currentpage为当前页数.不过在MYSQL数据库中没有“select top * " 语句,而可以代替的语句是”select * from tablename limit position, counter “position 指示从哪里开始查询,如果是0则是从头开始,counter 表示查询的个数,通过JSP+JAVA查询数据库,查询获取的数据暂时存放在内存中在JSP中通过调取JAVA类,直接从内存中提取数据,速度有了很大提高。

  下面的例子是一个关于网友评论的部分程序,假如你有一个专门供网友浏览的网站,而现在又想和网友互动起来,加一个评论是不错的想法,那么你可以把下面的程序加上,建一个表其中加一个photo_id字段和你的表关联起来后,就可以让网友对你的图片点评了。

  Comment.java是一个评论的类

//<--------Comment.java ------->
package dbconnection;
public class Comment
{
 private String id;
 private String album_id;
 private String title;
 private String content;
 private String modi_time;
 private String user;
 public void setId(String ids)
 {
  this.id=ids;
 }
 public void setalbum_id(String album_ids) {
  this.album_id=album_ids;
 }
 public void setTitle(String titles)
 {
  this.title=titles;
 }
 public void setContent(String contents)
 {
  this.content=contents;
 }
 public void setModi_time(String modi_times)
 {
  this.modi_time=modi_times;
 }
 public void setUser(String users)
 {
  this.user=users;
 }
 public String getId()
 {
  return id;
 }
 public String getalbum_id()
 {
  return album_id;
 }
 public String getTitle()
 {
  return title;
 }
 public String getContent()
 {
  return content;
 }
 public String getModi_time()
 {
  return modi_time;
 }
 public String getUser()
 {
  return user;
 }
}

  TestSql.java就是我们查询数据库要用到的类了,具体的调用请看下面的comment.jsp文件。

/**
* Title jsp+mysql优化分页的例子
* @author: cyd
* Copyright: Copyright (c) 2003
* @version 1.0
* 日期 2004-9-22
*/

//<--------TestSql.java ------->

package dbconnection;
import java.sql.*;
import java.util.*;
public class TestSql
{
 Statement stmt=null;
 ResultSet rs=null;
 conn c=null;
 Comment comments[]=null;
 Vector v=null;
 int total;
 int PageSize;
 int PageCount;
 public TestSql(Connection cn) throws SQLException
 {
  stmt=cn.createStatement();
 }
 //查询获取记录
 public Comment[] getComment(int pagesize,int page) throws SQLException
 {
  this.PageSize=pagesize;
  String sql="select * from comment order by id desc limit "+(page-1)*pagesize+","+pagesize;
  Comment comments[]=null;
  v=new Vector();
  try
  {
   rs=stmt.executeQuery(sql);
   while(rs.next())
   {
    Comment p=new Comment();
    p.setId(rs.getString("id"));
    p.setTitle(rs.getString("title"));
    p.setContent(rs.getString("content"));
    p.setModi_time(rs.getString("modi_time"));
    p.setUser(rs.getString("user"));
    v.add(p);
   }
  }
  catch(SQLException e)
  {
   System.err.println("err");
  }
  comments=new Comment[v.size()];
  v.copyInto(comments);
  return comments;
 }

 //获取总记录数
 public int getTotal()
 {
  return total;
 }
 //获取总页数
 public int getPageCount()
 {
  try
  {
   rs=stmt.executeQuery("select count(*) from comment ");
   rs.next();
   this.total=rs.getInt(1);
   this.PageCount=(rs.getInt(1)+PageSize-1)/PageSize;
  }
  catch(SQLException e)
  {
   System.err.println("err");
  }
  return PageCount;
 }
 //释放资源
 public void close() throws SQLException
 {
  if (stmt != null)
  {
   stmt.close();
   stmt = null;
  }
  if (rs!=null)
  {
   rs.close();
   rs=null;
  }
 }
}

<!--comment.jsp -------------------------------------------------------------------->

<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" %>
<%@ page import="java.io.*" %>
<%@ page import="dbconnection.DBConnectionManager" %>
<%
 DBConnectionManager connMgr;//这是数据库连接池的类,具体源码你可以在网找到。
 connMgr = DBConnectionManager.getInstance();
 Connection con = connMgr.getConnection("idb");//从连接池中获的一个连接

 int CurrentPage=1;
 int intPageCount,intRowCount;
 if(request.getParameter("page")!=null)
  CurrentPage=Integer.parseInt(request.getParameter("page"));
 if(CurrentPage<1)
  CurrentPage=1;
  int intPageSize=5;//设置每页显示5条
%>
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
<!--
.style3 {color: #FF0000}
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
background-color: #FFFDDF;
}
-->
</style>
<script language="javascript">
function goto(frm)
{
 var gourl ="comment.jsp?";
 gourl += "&page=" + (frm.page.value);
 var hid=parseInt(frm.hid.value);
 if(parseInt(frm.page.value)>hid||frm.page.value<=0){
  alert("错误!请确定你输入的数字在1-"+hid+"之间");
  return false;
 }
 window.location.href(gourl);
}</script>
</head>
<body>
<%
Comment[] p=null;
TestSql ts=null;
try
{
 ts=new TestSql(con);
 p=ts.getComment(intPageSize,CurrentPage);//ts=.getComments(PageSize(每页显示个数),Page(页数))
 intPageCount =ts.getPageCount(); //获的页数
 intRowCount=p.length;
 if(CurrentPage>intPageCount)
  CurrentPage = intPageCount;
  int total=ts.getTotal(); //获取记录总数
 %>
 <table width="748" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td>
<table width="100%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="17"><table width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#EBEADF">
<tr>
<td height="25" bgcolor="#A7E081"><div align="center" class="style3">网友评论</div></td>
</tr>
<!-- start loop by tr -------------------------->
<%
if(intRowCount>0)
{
 for(int i=0;i<intRowCount;i++)
 {
  %>
  <tr>
  <td height="20">
  <table width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#EBEADF">
  <tr>
   <td height="20"> &nbsp;<img src="image/dot11.gif" width="9" height="9"> <%=p[i].getUser()%>于 < %=p[i].getModi_time()%> 留言 </td>
  </tr>
  <tr>
   <td bgcolor="#FBFBF9" style="padding:5px 5px 5px 5px;line-height:18px;">&nbsp;<%=p[i].getContent()%></td>
  </tr>
</table>
</td>
</tr>
<%
}
}
else
{
%>
<tr>
<td height="20" bgcolor="#EBEADF">
<%
out.print("&nbsp;&nbsp;&nbsp;暂时没有评论");
}
%>
</td>
</tr>
<!-- end loop by tr -------------------------->
</table></td>
</tr>
<tr>
<td height="17" bgcolor="#FBFBF9">
<div align="center">
<form style="margin:0 0 0 0 ">
<div align="center">第<%=CurrentPage%>页&nbsp;&nbsp;共<%=intPageCount%>页&nbsp;&nbsp;
<%if(CurrentPage>1){%>
<a href="comment.jsp?page=<%=CurrentPage-1%>">上一页</a>&nbsp;&nbsp;
<%}else{%>
上一页&nbsp;&nbsp;
<%}%>
<%if(CurrentPage>=intPageCount){%>
下一页
<%}else{%>
<a href="comment.jsp?page=<%=CurrentPage+1%>">下一页</a>
<%}%>
跳至
<input type="hidden" name="hid" value="<%=intPageCount%>">
<input name="page" type="text" siz="2" onChange="goto(this.form)">

<input type="button" name="Button2" value="Go->" style="font-size:12px ">
</div>
</form>
</div></td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
<%
}
catch(Exception e)
{
 e.printStackTrace();
}
finally{
 connMgr.freeConnection("idb", con);
 connMgr.release();
 ts.close();
 p=null;
}
%>

  注:win2000+tomcat5.0调试通过;Redhat9+tomcat5.0调试通过

- 作者: 和疯 2006年02月21日, 星期二 17:27  回复(1) |  引用(2) 加入博采

JSP显示在线人数代码
/**
* 编写以下SessionCounter.java
* 并编译为SessiionCounter.class
* 然后放到你的网站的classpath的
* SessionCount(自己建立此目录)下面
*/

package SessionCount;
import javax.servlet.*;
import javax.servlet.http.*;

public class SessionCounter implements HttpSessionListener {

private static int activeSessions = 0;

public void sessionCreated(HttpSessionEvent se) {
activeSessions++;
}

public void sessionDestroyed(HttpSessionEvent se) {
if(activeSessions > 0)
activeSessions--;
}

public static int getActiveSessions() {
return activeSessions;
}
}

接着建立online.jsp文件用于显示在线人数

在线:

然后需要在你的网站的WEB-INF中建立web.xml
文件内容如下:
<!-- Web.xml -->
<?xml version="1.0" encoding="ISO-8859-1"?>

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

<web-app>

<!-- Listeners -->
<listener>
<listener-class>
SessionCount.SessionCounter
</listener-class>
</listener>

</web-app>
然后重新启动你的应用服务器,访问online.jsp检查是否显示正确。

本程序在Tomcat5.5X下调试成功,请多多指教!

- 作者: 和疯 2006年02月21日, 星期二 17:21  回复(3) |  引用(2) 加入博采

JSP数据库连接池的必要性
最近我作了数据库JSP的频繁连接,在此给出数据库连接池的必要性,对于JSP来说一个很好的J2EE服务器是很必要的,JBOOS,WebLogic都是很好的解决方案。

一般情况下,在使用开发基于数据库的WEB程序时,传统的模式基本是按以下步骤:
  1. 在主程序(如Servlet、Beans)中建立数据库连接。
  2. 进行SQL操作,取出数据。
  3. 断开数据库连接。
  使用这种模式开发,存在很多问题。首先,我们要为每一次WEB请求(例如察看某一篇文章的内容)建立一次数据库连接,对于一次或几次操作来讲,或许你觉察不到系统的开销,但是,对于WEB程序来讲,即使在某一较短的时间段内,其操作请求数也远远不是一两次,而是数十上百次(想想全世界的网友都有可能在您的网页上查找资料),在这种情况下,系统开销是相当大的。事实上,在一个基于数据库的WEB系统中,建立数据库连接的操作将是系统中代价最大的操作之一。很多时候,可能您的网站速度瓶颈就在于此。
  其次,使用传统的模式,你必须去管理每一个连接,确保他们能被正确关闭,如果出现程序异常而导致某些连接未能关闭,将导致数据库系统中的内存泄露,最终我们将不得不重启数据库。
  针对以上问题,我们首先想到可以采用一个全局的Connection对象,创建后就不关闭,以后程序一直使用它,这样就不存在每次创建、关闭连接的问题了。但是,同一个连接使用次数过多,将会导致连接的不稳定,进而会导致WEB SERVER的频频重启。故而,这种方法也不可取。实际上,我们可以使用连接池技术来解决上述问题。首先,介绍一下连接池技术的基本原理。顾名思义,连接池最基本的思想就是预先建立一些连接放置于内存对象中以备使用:

如图所示,当程序中需要建立数据库连接时,只须从内存中取一个来用而不用新建。同样,使用完毕后,只需放回内存即可。而连接的建立、断开都有连接池自身来管理。同时,我们还可以通过设置连接池的参数来控制连接池中的连接数、每个连接的最大使用次数等等。通过使用连接池,将大大提高程序效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。下面我们以一个名为ConnectionPool的连接池为例来看看连接池的实现。先看看ConnectionPool的基本属性:
  m_ConnectionPoolSize:连接池中连接数量下限
  m_ConnectionPoolMax:连接池中连接数量上限
  m_ConnectionUseCount:一个连接的最大使用次数
  m_ConnectionTimeout:一个连接的最长空闲时间
  m_MaxConnections = -1:同一时间的最大连接数
  m_timer:定时器
  这些属性定义了连接池与其中的每个连接的有效状态值。连接池的自我管理,实际上就是通过定时的对每个连接的状态、连接的数量进行判断而进行相应操作。其管理流程如下:

通过上图,我们可以定义出ConnectionPool要完成管理所需要的基本接口:
public class ConnectionPool implements TimerListener{
  public boolean initialize() //连接池初始化
  public void destroy() //连接池的销毁
  public synchronized java.sql.Connection getConnection() //取一个连接
  public synchronized void close() //关闭一个连接
  private synchronized void removeFromPool() //把一个连接从连接池中删除
  private synchronized void fillPool() //维护连接池大小   public synchronized void TimerEvent() //定时器事件处理函数
}
  通过这几个接口,已经可以完成连接池的基本管理。在TimeEvent()函数中完成连接池的状态检验工作,fillPool()时连接池至少保持最小连接数。因为我们要保存每一个连接的状态,所以还需要一个数据库连接对象:
class ConnectionObject{
  public java.sql.Connection con; public boolean inUse; //是否被使用标志
  public long lastAccess; //最近一次开始使用时间
  public int useCount; //被使用次数
}
加入了ConnectionObject对象后,在ConnectionPool中操作的应该只是ConnectionObject,而其他进程需要的只是ConnectionObject的con属性,因此我们再加入一个类,作为其他进程获得与返回连接的接口: CLASS Conn{
  GetConnection(); //从连接池中取出一个有效连接
  CloseConnection(); //返回连接,此时并没有关闭连接,只是放回了连接池
  DestroyPool(); //销毁连接池
}
  最后我们的整个系统总的架构如下:

通过上面的介绍,我们可以看出,连接池技术的关键就是其自身的管理机制,以上的管理流程只是本人一点见解,关键是想向大家介绍一种思路,在此基础上,您可以进一步完善连接池技术为您所用。

- 作者: 和疯 2006年02月21日, 星期二 17:20  回复(2) |  引用(2) 加入博采

提升JSP应用程序的七大绝招

      你时常被客户抱怨JSP页面响应速度很慢吗?你想过当客户访问次数剧增时,你的WEB应用能承受日益增加的访问量吗?

      本文讲述了调整JSP和servlet的一些非常实用的方法,它可使你的servlet和JSP页面响应更快,扩展性更强。而且在用户数增加的情况下,系统负载会呈现出平滑上长的趋势。在本文中,我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。其中,某些调优技术是在你的编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中,我们将详细地描述怎样通过调整servlet和JSP页面,来提高你的应用程序的总体性能。在阅读本文之前,假设你有基本的servlet和JSP的知识。   

      方法一:在servlet的init()方法中缓存数据

   当应用服务器初始化servlet实例之后,为客户端请求提供服务之前,它会调用这个servlet的init()方法。在一个servlet的生命周期中,init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作,就可大大地提高系统性能。

   例如,通过在init()方法中建立一个JDBC连接池是一个最佳例子,假设我们是用jdbc2.0的DataSource接口来取得数据库连接,在通常的情况下,我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中,如果每次SQL请求都要执行一次JNDI查询的话,那系统性能将会急剧下降。解决方法是如下代码,它通过缓存DataSource,使得下一次SQL调用时仍然可以继续利用它: public class ControllerServlet extends HttpServlet {  private javax.sql.DataSource testDS = null;  public void init(ServletConfig config) throws ServletException  {   super.init(config);   Context ctx = null;   try   {    ctx = new InitialContext();    testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");   }   catch(NamingException ne)   {    ne.printStackTrace();   }   catch(Exception e)   {    e.printStackTrace();   }  }  public javax.sql.DataSource getTestDS()  {   return testDS;  }  ...  ... }

   方法 2:禁止servlet和JSP 自动重载(auto-reloading)

   Servlet/JSP提供了一个实用的技术,即自动重载技术,它为开发人员提供了一个好的开发环境,当你改变servlet和JSP页面后而不必重启应用服务器。然而,这种技术在产品运行阶段对系统的资源是一个极大的损耗,因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。

   方法 3: 不要滥用HttpSession

   在很多应用中,我们的程序需要保持客户端的状态,以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性,从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中,是通过HttpSession对像来实现session的功能的,但在方便的同时,它也给系统带来了不小的负担。因为每当你获得或更新session时,系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能:

如果没有必要,就应该关闭JSP页面中对HttpSession的缺省设置: 如果你没有明确指定的话,每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话,那可以通过如下的JSP页面指示符来禁止它: <%@ page session="false"%>

 不要在HttpSession中存放大的数据对像:如果你在HttpSession中存放大的数据对像的话,每当对它进行读写时,应用服务器都将对其进行序列化,从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大,那系统的性能就下降得越快。

当你不需要HttpSession时,尽快地释放它:当你不再需要session时,你可以通过调用HttpSession.invalidate()方法来释放它。

 尽量将session的超时时间设得短一点:在JSP应用服务器中,有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话,系统会将相关的session自动从内存中释放。超时时间设得越大,系统的性能就会越低,因此最好的方法就是尽量使得它的值保持在一个较低的水平。

    方法 4: 将页面输出进行压缩

   压缩是解决数据冗余的一个好的方法,特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩,这种方法可以戏剧性地减少HTML文件的下载时间。因此,如果你将servlet或JSP页面生成的HTML页面进行压缩的话,那用户就会觉得页面浏览速度会非常快。但不幸的是,不是所有的浏览器都支持gzip压缩,但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段:

 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {  OutputStream out = null  String encoding = request.getHeader("Accept-Encoding");  if (encoding != null && encoding.indexOf("gzip") != -1)  {   request.setHeader("Content-Encoding" , "gzip");   out = new GZIPOutputStream(request.getOutputStream());  }  else if (encoding != null && encoding.indexOf("compress") != -1)  {   request.setHeader("Content-Encoding" , "compress");   out = new ZIPOutputStream(request.getOutputStream());  }  else  {   out = request.getOutputStream();  }  ...  ... }

   方法 5: 使用线程池

   应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理,并为它们分派service()方法,当service()方法调用完成后,与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源,这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外,我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时,它会创建数量等于最小线程数的一个线程池,当客户有请求时,相应地从池从取出一个线程来进行处理,当处理完成后,再将线程重新放入到池中。如果池中的线程不够地话,系统会自动地增加池中线程的数量,但总量不能超过最大线程数。通过使用线程池,当客户端请求急剧增加时,系统的负载就会呈现的平滑的上升曲线,从提高的系统的可伸缩性。

   方法 6: 选择正确的页面包含机制
  在JSP中有两种方法可以用来包含另一个页面:1、使用include指示符(<%@ includee file=”test.jsp” %>)。2、使用jsp指示符(<jsp:includee page=”test.jsp” flush=”true”/>)。在实际中我发现,如果使用第一种方法的话,可以使得系统性能更高。

   方法 7:正确地确定javabean的生命周期

   JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用<jsp:useBean>标签,可以将javabean直接插入到一个JSP页面中。它的使用方法如下: <jsp:useBean id="name" scope="page|request|session|application" class= "package.className" type="typeName"></jsp:useBean>

   其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话,它将影响系统的性能。

   举例来说,如果你只想在一次请求中使用某个bean,但你却将这个bean的生命周期设置成了session,那当这次请求结束后,这个bean将仍然保留在内存中,除非session超时或用户关闭浏览器。这样会耗费一定的内存,并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命周期,并在bean的使命结束后尽快地清理它们,会使用系统性能有一个提高。

   其它一些有用的方法   ? 在字符串连接操作中尽量不使用“+”操作符:在java编程中,我们常常使用“+”操作符来将几个字符串连接起来,但你或许从来没有想到过它居然会对系统性能造成影响吧?由于字符串是常量,因此JVM会产生一些临时的对像。你使用的“+”越多,生成的临时对像就越多,这样也会给系统性能带来一些影响。解决的方法是用StringBuffer对像来代替“+”操作符。

   ? 避免使用System.out.println()方法:由于System.out.println()是一种同步调用,即在调用它时,磁盘I/O操作必须等待它的完成,因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具,为了解决这个矛盾,我建议你最好使用Log4j工具(http://Jakarta.apache.org ;),它既可以方便调试,而不会产生System.out.println()这样的方法。

   ? ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销,因为它将所有的原始输出都转换为字符流来输出,因此如果使用它来作为页面输出的话,系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题,但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。

   总结。

      本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能,并因此提升整个J2EE应用的性能。通过这些调优技术,你可以发现其实并不是某种技术平台(比如J2EE和.NET之争)决定了你的应用程序的性能,重要是你要对这种平台有一个较为深入的了解,这样你才能从根本上对自己的应用程序做一个优化!

- 作者: 和疯 2006年02月21日, 星期二 17:19  回复(3) |  引用(2) 加入博采

经常用到的javaScript技术代码
一、验证类
1、数字验证内
1.1 整数
1.2 大于0的整数 (用于传来的ID的验证)
1.3 负整数的验证
1.4 整数不能大于iMax
1.5 整数不能小于iMin
2、时间类
2.1 短时间,形如 (13:04:06)
2.2 短日期,形如 (2003-12-05)
2.3 长时间,形如 (2003-12-05 13:04:06)
2.4 只有年和月。形如(2003-05,或者2003-5)
2.5 只有小时和分钟,形如(12:03)
3、表单类
3.1 所有的表单的值都不能为空
3.2 多行文本框的值不能为空。
3.3 多行文本框的值不能超过sMaxStrleng
3.4 多行文本框的值不能少于sMixStrleng
3.5 判断单选框是否选择。
3.6 判断复选框是否选择.
3.7 复选框的全选,多选,全不选,反选
3.8 文件上传过程中判断文件类型
4、字符类
4.1 判断字符全部由a-Z或者是A-Z的字字母组成
4.2 判断字符由字母和数字组成。
4.3 判断字符由字母和数字,下划线,点号组成.且开头的只能是下划线和字母
4.4 字符串替换函数.Replace();
5、浏览器类
5.1 判断浏览器的类型
5.2 判断ie的版本
5.3 判断客户端的分辨率

6、结合类
6.1 email的判断。
6.2 手机号码的验证
6.3 身份证的验证


二、功能类

1、时间与相关控件类
1.1 日历
1.2 时间控件
1.3 万年历
1.4 显示动态显示时钟效果(文本,如OA中时间)
1.5 显示动态显示时钟效果 (图像,像手表)
2、表单类
2.1 自动生成表单
2.2 动态添加,修改,删除下拉框中的元素
2.3 可以输入内容的下拉框
2.4 多行文本框中只能输入iMax文字。如果多输入了,自动减少到iMax个文字(多用于短信发送)

3、打印类
3.1 打印控件
4、事件类
4.1 屏蔽右键
4.2 屏蔽所有功能键
4.3 --> 和<-- F5 F11,F9,F1
4.4 屏蔽组合键ctrl+N
5、网页设计类
5.1 连续滚动的文字,图片(注意是连续的,两段文字和图片中没有空白出现)
5.2 html编辑控件类
5.3 颜色选取框控件
5.4 下拉菜单
5.5 两层或多层次的下拉菜单
5.6 仿IE菜单的按钮。(效果如rongshuxa.com的导航栏目)
5.7 状态栏,title栏的动态效果(例子很多,可以研究一下)
5.8 双击后,网页自动滚屏
6、树型结构。
6.1 asp+SQL版
6.2 asp+xml+sql版
6.3 java+sql或者java+sql+xml
7、无边框效果的制作
8、连动下拉框技术
9、文本排序
---------------------------------------------------------------------------------------

一、验证类
1、数字验证内
1.1 整数
/^(-|\+)?\d+$/.test(str)
1.2 大于0的整数 (用于传来的ID的验证)
/^\d+$/.test(str)
1.3 负整数的验证
/^-\d+$/.test(str)
2、时间类
2.1 短时间,形如 (13:04:06)
function isTime(str)
{
var a = str.match(/^(\d{1,2})(?(\d{1,2})\2(\d{1,2})$/);
if (a == null) {alert('输入的参数不是时间格式'); return false;}
if (a[1]>24 || a[3]>60 || a[4]>60)
{
alert("时间格式不对");
return false
}
return true;
}
2.2 短日期,形如 (2003-12-05)
function strDateTime(str)
{
var r = str.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);
if(r==null)return false;
var d= new Date(r[1], r[3]-1, r[4]);
return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]);
}
2.3 长时间,形如 (2003-12-05 13:04:06)
function strDateTime(str)
{
var reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2})\d{1,2})\d{1,2})$/;
var r = str.match(reg);
if(r==null)return false;
var d= new Date(r[1], r[3]-1,r[4],r[5],r[6],r[7]);
return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]&&d.getHours()==r[5]&&d.getMinutes()==r[6]&&d.getSeconds()==r[7]);
}
2.4 只有年和月。形如(2003-05,或者2003-5)
2.5 只有小时和分钟,形如(12:03)
3、表单类
3.1 所有的表单的值都不能为空

3.2 多行文本框的值不能为空。
3.3 多行文本框的值不能超过sMaxStrleng
3.4 多行文本框的值不能少于sMixStrleng
3.5 判断单选框是否选择。
3.6 判断复选框是否选择.
3.7 复选框的全选,多选,全选,反选
3.8 文件上传过程中判断文件类型
4、字符类
4.1 判断字符全部由a-Z或者是A-Z的字字母组成

4.2 判断字符由字母和数字组成。

4.3 判断字符由字母和数字,下划线,点号组成.且开头的只能是下划线和字母
/^([a-zA-z_]{1})([\w]*)$/g.test(str)
4.4 字符串替换函数.Replace();
5、浏览器类
5.1 判断浏览器的类型
window.navigator.appName
5.2 判断ie的版本
window.navigator.appVersion
5.3 判断客户端的分辨率
window.screen.height; window.screen.width;

6、结合类
6.1 email的判断。
function ismail(mail)
{
return(new RegExp(/^\w+((-\w+)|(\.\w+))*\-AT-[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/).test(mail));
}
6.2 手机号码的验证
6.3 身份证的验证
function isIdCardNo(num)
{
if (isNaN(num)) {alert("输入的不是数字!"); return false;}
var len = num.length, re;
if (len == 15)
re = new RegExp(/^(\d{6})()?(\d{2})(\d{2})(\d{2})(\d{3})$/);
else if (len == 18)
re = new RegExp(/^(\d{6})()?(\d{4})(\d{2})(\d{2})(\d{3})(\d)$/);
else {alert("输入的数字位数不对!"); return false;}
var a = num.match(re);
if (a != null)
{
if (len==15)
{
var D = new Date("19"+a[3]+"/"+a[4]+"/"+a[5]);
var B = D.getYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
}
else
{
var D = new Date(a[3]+"/"+a[4]+"/"+a[5]);
var B = D.getFullYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
}
if (!B) {alert("输入的身份证号 "+ a[0] +" 里出生日期不对!"); return false;}
}
return true;
}
-------------------------------------------------------------------------------------

3.7 复选框的全选,多选,全不选,反选

全选


全选

function checkAll(str)
{
var a = document.getElementsByName(str);
var n = a.length;
for (var i=0; ia[i].checked = window.event.srcElement.checked;
}
function checkItem(str)
{
var e = window.event.srcElement;
var all = eval("document.hrong."+ str);
if (e.checked)
{
var a = document.getElementsByName(e.name);
all.checked = true;
for (var i=0; i{
if (!a[i].checked){ all.checked = false; break;}
}
}
else all.checked = false;
}


3.8 文件上传过程中判断文件类型


-------------------------------------------------------------------------------------
1.身份证严格验证:

2.验证IP地址

function isip(s){
var check=function(v){try{return (v<=255 && v>=0)}catch(x){return false}};
var re=s.split(".")
return (re.length==4)?(check(re[0]) && check(re[1]) && check(re[2]) && check(re[3])):false
}

var s="202.197.78.129";
alert(isip(s))

3.加sp1后还能用的无边框窗口!!


/*--- Special Thanks For andot ---*/

/*
This following code are designed and writen by Windy_sk
You can use it freely, but u must held all the copyright items!
/

/- Thanks For andot Again ---*/

var CW_width = 400;
var CW_height = 300;
var CW_top = 100;
var CW_left = 100;
var CW_url = "/";
var New_CW = window.createPopup();
var CW_Body = New_CW.document.body;
var content = "";
var CSStext = "margin:1px;color:black; border:2px outset;border-style:expression(onmouseout=onmouseup=function(){this.style.borderStyle='outset'}, onmousedown=function(){if(event.button!=2)this.style.borderStyle='inset'});background-color:buttonface;width:16px;height:14px;font-size:12px;line-height:11px;cursor:Default;";

//Build Window
include.startDownload(CW_url, function(source){content=source});

function insert_content(){
var temp = "";
CW_Body.style.overflow = "hidden";
CW_Body.style.backgroundColor = "white";
CW_Body.style.border = "solid black 1px";
content = content.replace(/]*)>/g,"");
temp += "";
temp += "";
temp += "Chromeless Window For IE6 SP1";
temp += "";
temp += "?";
temp += "0";
temp += "1";
temp += "x";
temp += "";
temp += "";
temp += content;
temp += "

";
temp += "";
CW_Body.innerHTML = temp;
}

setTimeout("insert_content()",1000);

var if_max = true;
function show_CW(){
window.moveTo(10000, 10000);
if(if_max){
New_CW.show(CW_top, CW_left, CW_width, CW_height);
if(typeof(New_CW.document.all.include)!="undefined"){
New_CW.document.all.include.style.width = CW_width;
New_CW.document.all.Max.innerText = "1";
}

}else{
New_CW.show(0, 0, screen.width, screen.height);
New_CW.document.all.include.style.width = screen.width;
}
}

window.onfocus = show_CW;
window.onresize = show_CW;

// Move Window
var drag_x,drag_y,draging=false

function drag_move(e){
if (draging){
New_CW.show(e.screenX-drag_x, e.screenY-drag_y, CW_width, CW_height);
return false;
}
}

function drag_down(e){
if(e.button==2)return;
if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height)return;
drag_x=e.clientX;
drag_y=e.clientY;
draging=true;
e.srcElement.setCapture();
}

function drag_up(e){
draging=false;
e.srcElement.releaseCapture();
if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height) return;
CW_top = e.screenX-drag_x;
CW_left = e.screenY-drag_y;
}


 
电话号码的验证

要求:
  (1)电话号码由数字、"("、")"和"-"构成
  (2)电话号码为3到8位
  (3)如果电话号码中包含有区号,那么区号为三位或四位
  (4)区号用"("、")"或"-"和其他部分隔开
  (5)移动电话号码为11或12位,如果为12位,那么第一位为0
  (6)11位移动电话号码的第一位和第二位为"13"
  (7)12位移动电话号码的第二位和第三位为"13"
  根据这几条规则,可以与出以下正则表达式:
  (^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)

function PhoneCheck(s) {
var str=s;
var reg=/(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)/
alert(reg.test(str));
}

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


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

//检验法人代码
function isCorporationCode(s){
var patrn=/^(\d){15}$/;
if (!patrn.exec(s)) return false
return true
}

//校验登录名:只能输入5-20个以字母开头、可带数字、“_”、“.”的字串
function isRegisterUserName(s)
{
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9._]){4,19}$/;
if (!patrn.exec(s)) return false
return true
}
//校验用户姓名:只能输入1-30个以字母开头的字串
function isTrueName(s)
{
var patrn=/^[^`~!@#$%^&*()+-=|\\\[\]\{\}:;\'\,.<>/? 0-9]{2,19}$/;
if (!patrn.exec(s)) return false
return true
}

//校验密码:只能输入6-15个字母、数字
function isPasswd(s)
{
var patrn=/^[a-zA-Z0-9]{6,15}$/;
if (!patrn.exec(s)) return false
return true
}

//检验体重
function isAvoirdupois(s)
{
var patrn=/^[1-9]{1}[0-9]{0,2}$/;
var patrn2=/^[1-9]{1}$/;
var intPart=s.indexOf('.');
var decPart=s.lastIndexOf('.');
if (intPart==-1 && patrn.exec(s) && eval(s)>=2 && eval(s)<=200) return true
if (intPart!=decPart|| intPart==0 || intPart+2!=s.length) return false
if (!patrn.exec(s.substring(0,intPart)) || !patrn2.exec(s.substring(decPart+1))) return false
if (eval(s)<2 || eval(s)>200) return false
return true
}

//校验普通电话、传真号码:可以“+”开头,除数字外,可含有“-”
function isTel(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校验手机号码:必须以数字开头,除数字外,可含有“-”
function isMobile(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校验地区代码
function isAreaCode(s)
{
var patrn=/^(\d){6}$/;
if (!patrn.exec(s)) return false
return true
}

//校验邮政编码
function isPostalCode(s)
{
var patrn=/^[1-9]{1}(\d){5}$/;
if (!patrn.exec(s)) return false
return true
}

//校验搜索关键字
function isSearch(s)
{
var patrn=/^[^`~!@#$%^&*()+=|\\\[\]\{\}:;\'\,.<>/? ]{1}[^`~!@$%^&()+=|\\\[\]\{\}:;\'\,.<>?]{0,19}$/;
if (!patrn.exec(s)) return false
return true
}

//校验是否为ip地址
function isIP(s)
{
var patrn=/^[0-9.]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}

//检验页码是否正确
function isPage(s)
{
var patrn=/^[1-9]{1}[0-9]{0,2}$/;
if (!patrn.exec(s)) return false
return true
}

//表单输入值错误提示
function vErr(o,s){
alert(s);
if (o) o.focus();
return false;
}

//判断单选
function chkRadio(o){
for (i=0;iif (o[i].checked) return true;
}
return false;
}
//====================================表单类================================
// 文件上传过程中判断文件类型
/*

/

//表单的值不能为空
function isNull(elem){
//var pattern=/^\s+|\s+$/;
if(elem.replace(/(^\s+|\s$)/g, "")==""){
return false;
}else{
return true;
}
}
//不能超过imax字符
function imax(elem){
if(elem.length>imax){
return false;
}else{
return true;
}
}
//不能少于imix字符
function imix(elem){
if(elem.lengthreturn false;
}else{
return true;
}
}
//输入为中文判断
function isChinese(elem){
var pattern=/[^\x00-\xff]/g;
if(pattern.test(elem)){
//包含中文
return false;
}else{
//不包含中文
return true;
}
}

/ *********************************************************************************************************************

.cMenu {
FILTER: alpha(opacity=0);BACKGROUND-COLOR: #D6D3CE;BORDER-BOTTOM: #666666 2px solid; BORDER-LEFT: #E4E4E4 2px solid; BORDER-RIGHT: #666666 2px solid; BORDER-TOP: #E4E4E4 2px solid; COLOR: #000000; CURSOR: default; FONT-SIZE: 9pt; color:#000000;FONT-WEIGHT: normal; LINE-HEIGHT: 20px; POSITION: absolute; VISIBILITY: hidden; WIDTH: 110px
}
.menuitems {
font-size:9pt;
MARGIN: 2px;
PADDING-BOTTOM: 0px;
PADDING-LEFT: 15px;
PADDING-RIGHT: 3px;
PADDING-TOP: 0px;
}

<!--[if IE]>
onmouseover=highlightie5()>

电话号码的验证

要求:
  (1)电话号码由数字、"("、")"和"-"构成
  (2)电话号码为3到8位
  (3)如果电话号码中包含有区号,那么区号为三位或四位
  (4)区号用"("、")"或"-"和其他部分隔开
  (5)移动电话号码为11或12位,如果为12位,那么第一位为0
  (6)11位移动电话号码的第一位和第二位为"13"
  (7)12位移动电话号码的第二位和第三位为"13"
  根据这几条规则,可以与出以下正则表达式:
  (^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)


<script language="javascript">
function PhoneCheck(s) {
var str=s;
var reg=/(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)/
alert(reg.test(str));
}
</script>
<input type=text name="iphone">
<input type=button onclick="PhoneCheck(document.all.iphone.value)" value="Check">
----------------------------------------------------------------------------------------

<%
'********************************************
'函数功能:正则表达式校验
'参数patrn:要校验的类型
' "User" - 用户名
' "Truename" - 英文姓名
' "Passwd" - 密码
' "Tel" - 电话/传真
' "Mobil" - 手机
' "Date" - 日期(格式:yyyy-mm-dd)
' "Email" - 电子邮件
' "Postalcode" - 邮政编码
' "Search" - 搜索关键字
' "Int" - 整数
'参数strng:要校验的字串
'返回值:校验结果,正确返回true,错误返回false
'********************************************
Function IsVerify(patrn,strng)
strng=Trim(strng)
Select Case patrn
Case "User" '用户名
patrn="^[a-z]{1}([a-z0-9]|[._]){2,19}$"
Case "Truename" '英文姓名
patrn="^[a-zA-Z]{1,30}$"
Case "Passwd" '密码
patrn="^(\w){6,20}$"
Case "Tel" '电话/传真
patrn="^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$"
Case "Mobil" '手机
patrn="^(\d)+[-]?(\d){6,12}$"
Case "Date" '日期(格式:yyyy-mm-dd)
patrn="^[12]{1}(\d){3}[-][01]?(\d){1}[-][0123]?(\d){1}$"
Case "Email" '电子邮件
patrn="^((\w)|[-]|[.])+@(((\w)|[-])+[.])+[a-z]{2,4}$"
Case "Postalcode" '邮政编码
patrn="^[a-z0-9 ]{3,12}$"
Case "Search" '搜索关键字
patrn="^[^`~!@#$%^&*()+=|\\\[\]\{\}:;\'\,.<>/?]{1}[^`~!@$%^&()+=|\\\[\]\{\}:;\'\,.<>?]{0,19}$"
Case "Int" '整数
patrn="^[1-9]{1}[0-9]{0,6}$"
Case "Array"
patrn="^[0-9]{1}([0-9]|[\,]){0,150}$"
End Select
Dim regEx
Dim Match
Set regEx = New RegExp
regEx.Pattern = patrn
regEx.IgnoreCase = True
regEx.Global = True
Matches = regEx.test(strng)
IsVerify = Matches
Set regEx = Nothing
End Function

'********************************************
'函数功能:对输入框的特殊字串进行过滤保存
'参数strPass:过滤前的字符串
'返回值:过滤后的字符串
'********************************************
Function SQLencode(byVal strPass)
strPass = Replace(strPass, "&", "&")
strPass = Replace(strPass, "<", "<")
strPass = Replace(strPass, ">", ">")
strPass = Replace(strPass, """", """)
strPass = Replace(strPass, "'", "'")
strPass = Replace(strPass, " ", " ")
strPass = Replace(strPass,chr(13)&chr(10),"<br/>")
SQLencode = strPass
End Function

'********************************************
'函数功能:对SQLencode函数过滤后的字符串进行还原
'参数strPass:经过过滤后的字符串
'返回值:还原的过滤前的字符串
'********************************************
Function SQLdecode(byVal strPass)
If Not isNull(strPass) Then
strPass = Replace(strPass, "<", "<")
strPass = Replace(strPass, ">", ">")
strPass = Replace(strPass, ""","""" )
strPass = Replace(strPass, "'","'" )
strPass = Replace(strPass,"<br/>",chr(13)&chr(10))
End If
SQLdecode = strPass
End Function

'********************************************
'函数功能:生成随机密码(字符为数字与大小写字母集合)
'参数length:密码长度
'返回值:随机密码
'*******************************************
Function random(length)
Dim n,str
rnds=""
Randomize
For i=1 To length
n=Int(75*Rnd+48)
If (n>57 and n<65) Or (n>90 and n<97) Then
i=i-1
Else
rnds=rnds&Chr(n)
End If
Next
random=rnds
End Function

'********************************************
'函数功能:对密码进行加密/解密(最大长度为15位)
'********************************************
Function Encrypt(preString)
Dim pwds,s
pwds=""
s=Left(preString,15)
For i=1 To Len(s)
seed=170-Asc(Mid(s,i,1))-i
pwds=pwds & Chr(seed)
Next
Encrypt=pwds
End Function

'********************************************
'函数功能:格式化当前时间字串
'参数:无
'返回值:返回当前时间的纯数字字符串方式的表示(例如:当前时间2001-10-3 2:34:6,返回字符串"20011003023406")
'********************************************
Function TheDate()
y=year(date())
m=month(date())
d=day(date())
h=Hour(time())
n=Minute(time())
s=Second(time())
If Len(m)=1 Then m="0"&m
If Len(d)=1 Then d="0"&d
If Len(h)=1 Then h="0"&h
If Len(n)=1 Then n="0"&n
If Len(s)=1 Then s="0"&s
thedate=y&m&d&h&n&s
End Function

'********************************************
'函数功能:返回字符串的长度
'参数:字符串
'返回值:字符串长度
'********************************************
Function strLen(str)
dim p_len
p_len=0
strlen=0
if trim(str)<>"" then
p_len=len(trim(str))
for xx=1 to p_len
if asc(mid(str,xx,1))<0 then
strlen=int(strlen) + 2
else
strlen=int(strlen) + 1
end if
next
end if
End Function

'********************************************
'函数功能:发送邮件通知
'参数:字符串
'返回值:成功/失败
'********************************************
Function SendMail(ToAddress, Subject, Body)
On Error Resume Next
Set objMail = Server.CreateObject("JMail.Message")
objMail.From = ADR_Email
objMail.FromName = "ADR管理中心"
objMail.Subject = Subject
objMail.AddRecipient ToAddress
objMail.Body = Body
If objMail.Send("") Then
SendMail = True
Else
SendMail = False
End If
If Err.Number<> 0 Then SendMail = False
Set objMail = Nothing
On Error Goto 0
End Function
%>
-----------------------------------------------------------------------------------

//检验法人代码
function isCorporationCode(s){
var patrn=/^(\d){15}$/;
if (!patrn.exec(s)) return false
return true
}

//校验登录名:只能输入5-20个以字母开头、可带数字、“_”、“.”的字串
function isRegisterUserName(s)
{
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9._]){4,19}$/;
if (!patrn.exec(s)) return false
return true
}
//校验用户姓名:只能输入1-30个以字母开头的字串
function isTrueName(s)
{
var patrn=/^[^`~!@#$%^&*()+-=|\\\[\]\{\}:;\'\,.<>/? 0-9]{2,19}$/;
if (!patrn.exec(s)) return false
return true
}

//校验密码:只能输入6-15个字母、数字
function isPasswd(s)
{
var patrn=/^[a-zA-Z0-9]{6,15}$/;
if (!patrn.exec(s)) return false
return true
}

//检验体重
function isAvoirdupois(s)
{
var patrn=/^[1-9]{1}[0-9]{0,2}$/;
var patrn2=/^[1-9]{1}$/;
var intPart=s.indexOf('.');
var decPart=s.lastIndexOf('.');
if (intPart==-1 && patrn.exec(s) && eval(s)>=2 && eval(s)<=200) return true
if (intPart!=decPart || intPart==0 || intPart+2!=s.length) return false
if (!patrn.exec(s.substring(0,intPart)) || !patrn2.exec(s.substring(decPart+1))) return false
if (eval(s)<2 || eval(s)>200) return false
return true
}

//校验普通电话、传真号码:可以“+”开头,除数字外,可含有“-”
function isTel(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校验手机号码:必须以数字开头,除数字外,可含有“-”
function isMobile(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校验地区代码
function isAreaCode(s)
{
var patrn=/^(\d){6}$/;
if (!patrn.exec(s)) return false
return true
}

//校验邮政编码
function isPostalCode(s)
{
var patrn=/^[1-9]{1}(\d){5}$/;
if (!patrn.exec(s)) return false
return true
}

//校验搜索关键字
function isSearch(s)
{
var patrn=/^[^`~!@#$%^&*()+=|\\\[\]\{\}:;\'\,.<>/? ]{1}[^`~!@$%^&()+=|\\\[\]\{\}:;\'\,.<>?]{0,19}$/;
if (!patrn.exec(s)) return false
return true
}

//校验是否为ip地址
function isIP(s)
{
var patrn=/^[0-9.]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}

//检验页码是否正确
function isPage(s)
{
var patrn=/^[1-9]{1}[0-9]{0,2}$/;
if (!patrn.exec(s)) return false
return true
}

//表单输入值错误提示
function vErr(o,s){
alert(s);
if (o) o.focus();
return false;
}

//判断单选
function chkRadio(o){
for (i=0;i<o.length;i++){
if (o[i].checked) return true;
}
return false;
}

- 作者: 和疯 2006年02月17日, 星期五 10:58  回复(4) |  引用(2) 加入博采

配置Eclpise+tomcat并实现JSP的编写与部署
1,配置tomcat服务器访问端口,只需配置Connector的port端口即可。Tomcat默认为8080,现修改port参数值为80。

<!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080 -->

<Connector port="80"

maxThreads="150" minSpareThreads="25" maxSpareThreads="75"

enableLookups="false" redirectPort="8443" acceptCount="100"

debug="0" connectionTimeout="20000" 

disableUploadTimeout="true" URIEncoding="GBK"/>

2,配置tomcat支持URL中文参数,只需添加Connector的URIEncoding参数即可,默认情况下该参数未被配置。要支持URL参数支持中文,加上URIEncoding=”GBK”就行了(见1中附代码最后一行)。


3,配置新的webApp:找到host尾标记</Host>,插入新的context即可。
如:
(1)<Context path="" docBase="ROOT" debug="0"/>
(2)<Context path="/xkb" docBase="F:\XKB6\webApp" debug="5" reloadable="true" crossContext="true">

<Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_DBTest_log." suffix=".txt" timestamp="true"/>

<Resource name="jdbc/SqlServerDB" auth="Container" type="javax.sql.DataSource"/>

<ResourceParams name="jdbc/SqlServerDB">

<parameter>

<name>factory</name>

<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>

</parameter>

<!-- Maximum number of dB connections in pool. Make sure you configure your mysqld max_connections large enough to handle all of your db connections. Set to 0 for no limit.-->

<parameter>

<name>maxActive</name>

<value>50</value>

</parameter>

<!-- Maximum number of idle dB connections to retain in pool. Set to 0 for no limit.-->

<parameter>

<name>maxIdle</name>

<value>20</value>

</parameter>

<!-- Maximum time to wait for a dB connection to become available in ms, in this example 0.5 seconds. An Exception is thrown if this timeout is exceeded. Set to -1 to wait indefinitely. -->

<parameter>

<name>maxWait</name>

<value>500</value>

</parameter>

<!-- msSQL dB username and password for dB connections -->

<parameter>

<name>username</name>

<value>sa</value>

</parameter>


<parameter>

<name>password</name>

<value>wangnewton</value>

</parameter>

<!-- Class name for SQLServer2000 JDBC driver -->

<parameter>

<name>driverClassName</name>

<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>

</parameter>

<!-- The JDBC connection url for connecting to your MS SQL Server dB.The autoReconnect=true argument to the url makes sure that the mm.Sql Server JDBC Driver will automatically reconnect if mysqld closed the connection. mysqld by default closes idle connections after 8 hours.-->

<parameter>

<name>url</name>

<value>jdbc:microsoft:sqlserver://localhost:1433;databaseName=XKBCourse</value>

<!--must use & not use & -->

</parameter>

</ResourceParams>

</Context> 


tomcat5.5.x 配置记录。

1.下载:
http://www.eu.apache.org/dist/jakarta/tomcat-5/
http://www.apache.org/dist/jakarta/tomcat-5/v5.5.x/bin/jakarta-tomcat-5.5.x-admin.zip
http://www.apache.org/dist/jakarta/tomcat-5/v5.5.x/bin/jakarta-tomcat-5.5.x-compat.zip
http://www.apache.org/dist/jakarta/tomcat-5/v5.5.x/bin/jakarta-tomcat-5.5.x.zip
http://www.apache.org/dist/jakarta/tomcat-5/v5.5.x/bin/jakarta-tomcat-5.5.x-deployer.zip
把jakarta-tomcat-5.5.x.zip
和jakarta-tomcat-5.5.x-compat.zip
和jakarta-tomcat-5.5.x-admin.zip
(Tomcat 默认是没有内置admin模块了
Tomcat's administration web application is no longer installed by default. Download and install the "admin" package to use it. )
都解压到同一个目录下面。比如:D:\jakarta-tomcat-5.5.x\
(如果使用jdk1.4,才需要compat.zip用jdk1.5就可以免了这个。) 

2.修改jakarta-tomcat-5.5.x\conf\tomcat-users.xml.
添加管理员账号lizongbo,密码为lizongbopass.
新xml如下:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager"/>
<role rolename="admin"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="role1" password="tomcat" roles="role1"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="lizongbo" password="lizongbopass" roles="admin,manager"/>
</tomcat-users>

3.修改jakarta-tomcat-5.5.x\conf\server.xml来解决编码问题。
(给Connector 添加URIEncoding参数,参考http://blog.csdn.net/darkxie/archive/2004/10/25/TOMCATAPP.aspx)
(可以设置成GB18030)
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="200"
connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="GBK"
compression="on" compressionMinSize="2048" 
noCompressionUserAgents="gozilla, traviata" 
compressableMimeType="text/html,text/xml"/>

<Connector port="8009" 
enableLookups="false" redirectPort="8443" protocol="AJP/1.3" URIEncoding="GBK"/>


4.启用支持gzip压缩.
(http://www.linuxaid.com.cn/forum/showdoc.jsp?l=1&i=81169)
添加下列属性
compression="on" 
compressionMinSize="2048" 
noCompressionUserAgents="gozilla, traviata" 
compressableMimeType="text/html,text/xml"

5.设置虚拟主机。
在jakarta-tomcat-5.5.x\下建立文件夹vhost\www.mydomain.com。
然后修改jakarta-tomcat-5.5.x\conf\server.xml

<Engine defaultHost="localhost" name="Catalina">
<Host appBase="vhost/www.mydomain.com" name="www.mydomain.com">
</Host>
<Host appBase="webapps" name="localhost">
</Host&g;
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"/>
</Engine>

6.添加数据库驱动,更新mail.jar和actiovation.jar
复制mysql-connector-java-3.0.16-ga-bin.jar,pg74.215.jdbc3.jar到 jakarta-tomcat-5.5.x\common\lib\
还有javamail 1.3.2的mail.jar,jaf-1_0_2的 activation.jar
msSQl 2000 JDBC sp3,msbase.jar,msutil,jar,mssqlserver.jar


7.配置SSL
参考 http://jakarta.apache.org/tomcat/tomcat-5.5-doc/ssl-howto.html
D:\j2sdk1.4.2_06\bin>%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
输入keystore密码: lizongbossl
您的名字与姓氏是什么?
[tomcat5.5.x]: tomcat5.5.x
您的组织单位名称是什么?
[jakarta]: jakarta
您的组织名称是什么?
[apache]: apache
您所在的城市或区域名称是什么?
[hzcity]: hzcity
您所在的州或省份名称是什么?
[gdp]: gdp
该单位的两字母国家代码是什么
[CN]: CN
CN=tomcat5.5.x, OU=jakarta, O=apache, L=hzcity, ST=gdp, C=CN 正确吗?
[否]: y

输入<tomcat>的主密码
(如果和 keystore 密码相同,按回车):

(必须密码一致,因此直接回车)
然后再把userhome(例如:C:\Documents and Settings\lizongbo\)下的.keystore复制到
tomcat的conf\目录下。
(例如:D:\jakarta-tomcat-5.5.x\conf\.keystore )
配置jakarta-tomcat-5.5.x\conf\server.xml
加上
<Connector port="8443" 
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" 
keystoreFile="conf/.keystore" 
keystorePass="lizongbossl"> <!--与先前设置的密码一致-->
</Connector>
8.禁止文件目录列表,
修改jakarta-tomcat-5.5.x\conf\web.xml,把listing设置为false

<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

9.指定了自己的javaEncoding
(参考 http://gceclub.sun.com.cn/staticcontent/html/sunone/app7/app7-dg-webapp/ch6/ch6-4.html )

<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>javaEncoding</param-name>
<param-value>GB18030</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
10.添加rar,iso等的mime-type映射 
避免在浏览器里直接打开。
<mime-mapping>
<extension>mht</extension>
<mime-type>text/x-mht</mime-type>
</mime-mapping>
<mime-mapping>
<extension>rar</extension>
<mime-type>application/octet-stream</mime-type>
</mime-mapping>
<mime-mapping>
<extension>iso</extension>
<mime-type>application/octet-stream</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ape</extension>
<mime-type>application/octet-stream</mime-type>
</mime-mapping>
<mime-mapping>
<extension>rmvb</extension>
<mime-type>application/octet-stream</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ico</extension>
<mime-type>image/x-icon</mime-type>
</mime-mapping>
10.1对html静态页面设置编码
<!-- 修改下面两行以支持静态超文本的自动编码 
--> 
<mime-mapping>
<extension>htm</extension> 
<mime-type>text/html;charset=gb2312</mime-type> 
</mime-mapping>
<mime-mapping>
<extension>html</extension> 
<mime-type>text/html;charset=gb2312</mime-type> 
</mime-mapping>
</web-app>

11.添加welcome-file-list,并调整顺序。
<welcome-file-list> 
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list> 


Tomcat中文编码问题解决方案(简) 

liyonghai 04/08/30 

编码问题的根源可参考http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml

Tomcat 4.x解决方法: 
获取中文:request.setCharacterEncoding("gb2312"); 
输出中文:<%@ page contentType="text/html;charset=gb2312" %>,必要时需要转码 

Tomcat 5.x解决方法: 
获取中文: 
提交表单时 
1)post:request.setCharacterEncoding("gb2312"); 
2)get:修改server.xml,在Connector中加入URIEncoding="gb2312" 
如: <Connector port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" 
enableLookups="false" redirectPort="8443" acceptCount="100" 
debug="0" connectionTimeout="20000" 
disableUploadTimeout="true" URIEncoding="gb2312" /> 
或者使用useBodyEncodingForURI,使tomcat 5.x兼容tomcat 4.x 
输出中文:<%@ page contentType="text/html;charset=gb2312" %>,必要时需要转码 

附:Tomcat 5.x与Tomcat 4.x在解析提交表单时发生了变化,Tomcat 4.x无论是post还是get,都使用 
相同的编码,而Tomcat 5.x 却把get方法单独了出来.具体可查看tomcat的source code. 

get方式的处理比较好,对于post方式建议用配置过滤器的方式来解决,因为这样,配置一个地方整个系统都不用操心了。 

简单说明: 
web.xml 
<filter> 
<filter-name>Set Character Encoding</filter-name> 
<filter-class>SetCharacterEncodingFilter</filter-class> 
</filter> 
<filter-mapping> 
<filter-name>Set Character Encoding</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 
/************************/ 

SetCharacterEncodingFilter.java 
-------------------------------------------- 
import java.io.IOException; 
import javax.servlet.Filter;&nsp;
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.UnavailableException; 

/** 
* Example filter that sets the character encoding to be used in parsing the 
* incoming request 
*/ 
public class SetCharacterEncodingFilter implements Filter { 

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

/** 
* Select and set (if specified) the character encoding to be used to 
* interpret request parameters for this request. 
*/ 
public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)throws IOException, ServletException { 

request.setCharacterEncoding("GBK"); 

// 传递控制到下一个过滤器 
chain.doFilter(request, response); 


public void init(FilterConfig filterConfig) throws ServletException { 


////也可以把编码做为参数传递进去。 


12.如果你的webapp需要只能够进行https方式访问,那么在webapp的web.xml里加上:
<security-constraint>
<web-resource-collection>
<web-resource-name>must https</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
参考:http://jakarta.apache.org/tomcat/faq/security.html#https
http://marc.theaimsgroup.com/?l=tomcat-user&m=104951559722619&w=2

13.修改远程关闭服务器的命令。
server.xml默认有下面一行:
<Server port="8005" shutdown="SHUTDOWN">
这样允许任何人只要telnet到服务器的8005端口,输入"SHUTDOWN",然后回车,服务器立即就被关掉了。
从安全的角度上考虑,我们需要把这个shutdown指令改成一个别人不容易猜测的字符串。
例如修改如下:
<Server port="8006" shutdown="lizongbo">,这样就只有在telnet到8005,并且输入"lizongbo"才能够关闭Tomcat.
注意:这个修改不影响shutdown.bat的执行。运行shutdown.bat一样可以关闭服务器。
参考:http://jakarta.apache.org/tomcat/faq/security.html#8005


以下皆可以参考:http://www.cnjsp.org/document/user/tuman/valve.html


14.配置http访问日志。Tomcat自带的能够记录的http访问日志已经很详细了
取消下面这段的注释:

<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="common" resolveHosts="false"/>

然后修改为:
<Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="combined" resolveHosts="false" fileDateFormat="yyyy-MM-dd.HH"/>

pattern="combined" 记录的日志内容更详细,fileDateFormat="yyyy-MM-dd.HH",会让日志文件按小时进行滚卷,
比默认的按天滚卷要好些,尤其是访问量大的网站,可以考虑写成fileDateFormat="yyyy-MM-dd.HH.mm",就会是每分钟一个日志文件了。
而且可以分别按Engine, Host, or Context,来记录自己的日志
详情参考:
http://jakarta.apache.org/tomcat/tomcat-5.5-doc/config/valve.html
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/logger.html
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/host.html#Access%20Logs
而且还可以配合awstats来进行日志统计分析: http://www.chedong.com/tech/awstats.html http://blog.csdn.net/lizongbo/archive/2005/02/18/291929.aspx


15.限制ip,限制主机访问等。
如果想禁止指定的ip或者主机名来拒绝某些机器访问,或者指定某些机器来访问。
也支持分别按Engine, Host, or Context,进行以下配置:
<Context path="/examples" ...> ...
<Valve className="org.apache.catalina.valves.RemoteHostValve"
allow="*.mycompany.com,www.yourcompany.com"/>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny="192.168.1.*"/>
</Context>
参考:
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/context.html

16.发布webapp到网站根目录
1。直接复制到ROOT目录下。
2.因为无法创建无名字的xml文件,并且在xml文件里指定path也是无效的(tomcat靠文件名字来判断的),
因此必须在server.xml里写下面一段:
<Context docBase="${catalina.home}/vhost/www.lizongbo.com" path="/"
privileged="true" antiResourceLocking="false" antiJARLocking="false">
<Manager className="org.apache.catalina.session.StandardManager" algorithm="SHA-512" sessionIdLength="40">
<Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
directory="logs" prefix="localhost_mytest_access_log." suffix=".txt"
pattern="combined" resolveHosts="true" fileDateFormat="yyyy-MM-dd.HH"/> 

</Context>
而且必须把ROOT目录删除掉,否则Tomcat还是优先部署ROOT目录为"/"。

17.在重新启动Tomcat的webapp的时候,禁止把session写入文件。
修改conf/web.xml
取消注释:
<!---->
<Manager pathname="" />

18.增强SessiionID的生成算法和长度。

<Manager className="org.apache.catalina.session.StandardManager" algorithm="SHA-512" sessionIdLength="40">
</Manager>

(Tomcat默认算法是MD5,默认长度是16位。) 


tomcat+jsp经典配置

Tomcat下JSP、Servlet和JavaBean环境的配置 

经常看到jsp的初学者问tomcat下如何配置jsp、servlet和bean的问题,于是总结了一下如何tomcat下配置jsp、servlet和ben,希望对那些初学者有所帮助。 
一、开发环境配置 
第一步:下载j2sdk和tomcat:到sun官方站点(http://java.sun.com/j2se/1.4.2/download.html)下载j2sdk,注意下载版本为Windows Offline Installation的SDK,同时最好下载J2SE 1.4.2 Documentation,然后到tomcat官方站点(http://www.apache.org/dist/jakarta/tomcat-4/)下载tomcat(下载最新4.1.x版本的tomcat); 
第二步:安装和配置你的j2sdk和tomcat:执行j2sdk和tomcat的安装程序,然后按默认设置进行安装即可。 
1.安装j2sdk以后,需要配置一下环境变量,在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量(假定你的j2sdk安装在c:\j2sdk1.4.2): 
JAVA_HOME=c:\j2sdk1.4.2 
classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(.;一定不能少,因为它代表当前路径) 
path=%JAVA_HOME%\bin 
接着可以写一个简单的java程序来测试J2SDK是否已安装成功: 
public class Test{ 
public static void main(String args[]){ 
System.out.println("This is a test program."); 


将上面的这段程序保存为文件名为Test.java的文件。 
然后打开命令提示符窗口,cd到你的Test.java所在目录,然后键入下面的命令 
javac Test.java 
java Test 
此时如果看到打印出来This is a test program.的话说明安装成功了,如果没有打印出这句话,你需要仔细检查一下你的配置情况。 
2.安装Tomcat后,在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量(假定你的tomcat安装在c:\tomcat): 
CATALINA_HOME=c:\tomcat 
CATALINA_BASE=c:\tomcat 
然后修改环境变量中的classpath,把tomat安装目录下的common\lib下的(可以根据实际追加)servlet.jar追加到classpath中去,修改后的classpath如下: 
classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\common\lib\servlet.jar; 
接着可以启动tomcat,在IE中访问http://localhost:8080,如果看到tomcat的欢迎页面的话说明安装成功了。 
第三步:建立自己的jsp app目录 
1.到Tomcat的安装目录的webapps目录,可以看到ROOT,examples, tomcat-docs之类Tomcat自带的的目录; 
2.在webapps目录下新建一个目录,起名叫myapp; 
3.myapp下新建一个目录WEB-INF,注意,目录名称是区分大小写的; 
4.WEB-INF下新建一个文件web.xml,内容如下: 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
" " target="_blank">http://java.sun.com/dtd/web-app_2_3.dtd"> 
<web-app> 
<display-name>My Web Application</display-name> 
<description> 
A application for test. 
</description> 
</web-app> 
5.在myapp下新建一个测试的jsp页面,文件名为index.jsp,文件内容如下: 
<html><body><center> 
Now time is: <%=new java.util.Date()%> 
</center></body></html> 
6.重启Tomcat 
7.打开浏览器,输入http://localhost:8080/myapp/index.jsp 看到当前时间的话说明就成功了。 
第四步:建立自己的Servlet: 
1.用你最熟悉的编辑器(建议使用有语法检查的java ide)新建一个servlet程序,文件名为Test.java,文件内容如下: 
package test; 
import java.io.IOException; 
import java.io.PrintWriter; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
public class Test extends HttpServlet { 
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { 
PrintWriter out=response.getWriter(); 
out.println("<html><body><h1>This is a servlet test.</h1></body></html>"); 
out.flush(); 


2 .编译 
将Test.java放在c:\test下,使用如下命令编译: 
C:\Test>javac Test.java 
然后在c:\Test下会产生一个编译后的servlet文件:Test.class 
3 .将结构test\Test.class剪切到%CATALINA_HOME%\webapps\myapp\WEB-INF\classes下,也就是剪切那个test目录到classes目录下,如果classes目录不存在,就新建一个。 现在webapps\myapp\WEB-INF\classes下有test\Test.class的文件目录结构 
4 .修改webapps\myapp\WEB-INF\web.xml,添加servlet和servlet-mapping 
编辑后的web.xml如下所示,红色为添加的内容: 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
" " target="_blank">http://java.sun.com/dtd/web-app_2_3.dtd"> 
<web-app> 
<display-name>My Web Application</display-name> 
<description> 
A application for test. 
</description> 
<servlet> 
<servlet-name>Test</servlet-name> 
<display-name>Test</display-name> 
<description>A test Servlet</description> 
<servlet-class>test.Test</servlet-class> 
</servlet> 
<servlet-mapping> 
<servlet-name>Test</servlet-name> 
<url-pattern>/Test</url-pattern> 
</servlet-mapping> 
</web-app> 
这段话中的servlet这一段声明了你要调用的Servlet,而servlet-mapping则是将声明的servlet"映射"到地址/Test上 
5 .好了,重启动Tomcat,启动浏览器,输入http://localhost:8080/myapp/Test 如果看到输出This is a servlet test.就说明编写的servlet成功了。 
注意:修改了web.xml以及新加了class,都要重启Tomcat 
第四步:建立自己的Bean: 
1.用你最熟悉的编辑器(建议使用有语法检查的java ide)新建一个java程序,文件名为TestBean.java,文件内容如下: 
package test; 
public class TestBean{ 
private String name = null; 
public TestBean(String strName_p){ 
this.name=strName_p; 

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

public String getName(){ 
return this.name; 


2 .编译 
将TestBean.java放在c:\test下,使用如下命令编译: 
C:\Test>javac TestBean.java 
然后在c:\Test下会产生一个编译后的bean文件:TestBean.class 
3 .将TestBean.class文件剪切到 %CATALINA_HOME%\webapps\myapp\WEB-INF\classes\test下, 
4 .新建一个TestBean.jsp文件,文件内容为: 
<%@ page import="test.TestBean" %> 
<html><body><center> 
<% 
TestBean testBean=new TestBean("This is a test java bean."); 
%> 
Java bean name is: <%=testBean.getName()%> 
</center></body></html> 
5 .好了,重启Tomcat,启动浏览器,输入http://localhost:8080/myapp/TestBean.jsp 如果看到输出Java bean name is: This is a test java bean.就说明编写的Bean成功了。 
这样就完成了整个Tomcat下的jsp、servlet和javabean的配置。接下来需要做的事就是多看书、多读别人的好代码,自己多动手写代码以增强自己在这方面开发的能力了。 

jvm应填写到 
c:\j2sdk\bin 

给你一个简单的配置:::: 

JSP环境配置心得 
首先要说的是,使用jdk+tomcat完全可以配置我们的jsp服务器,不再需要其实任何东东,有很多文章介绍了Apache,其实根本用不着,一般的学习调试tomcat完全可以胜任了。 
安装jdk后,tomcat在安装之前会自动找到jdk的安装路径,一路点击"下一步",经过一段时间的文件复制,最后"close",完成comcat的安装。 
您最好去下载一个版本较高的tomcat,比如4.1以上的,因为它不需要设置太多的系统变量,右击"我的电脑",选择"属性"->"高级"->"环境变量"->"系统变量",新建一个TOMCAT_HOME,值设置成你的tomcat所在的路径,比如:D:\Program Files\Apache Group\Tomcat 4.1,配置完成。 
从开始菜单中找到tomcat选项,一般打开顺序是:开始->程序->Apache Tomcat 4.1,选择"Start Tomcat",让jsp服务器开始运行,此时会打开一个类似Dos的窗口,会显示一些相关的信息。 
如果您使用代理上网,一定要先撤掉代理,不然您的jsp程序永远也得不到执行。如果不是代理的,这一步就跳过了。 
打开浏览器,在地址栏中输入:http://localhost:8080,如果看到有老虎(我也不知道是老虎还是猫)的画面,恭喜您,您成功了一半。 
先来享受一下成功的喜悦吧,请输入下面的代码: 
<html> 
<head> 
<title>First Page</title> 
</head> 
<body> 
<H3>Today is: h 
<%= new java.util.Date() %> 
</H3> 
</body> 
</html> 
将该程序保存为:First.jsp,放到Tomcat的ROOT目录下,然后在浏览器的地址栏中输入:http://localhost:8080/First.jsp,(First.jsp跟我们保存的文件名的大小写要一致)回车,如果不出意外,应该可以看到形如Today is: h Fri Apr 11 08:32:38 CST 2003 的结果。 
注意:ROOT是tomcat的默认虚拟目录,如果要改成自己的虚拟目录怎么办呢?请继续往下看吧。 
要改成自己的虚拟目录,就要请出server.xml来了,该文件是一个配置文件,在Tomcat\conf目录下,使用任何文本编辑软件都能打开它,我们先找到下面一句: 
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector" 
port="8080" minProcessors="5" maxProcessors="75" 
enableLookups="true" redirectPort="8443" 
acceptCount="100" debug="0" connectionTimeout="20000" 
useURIValidationHack="false" disableUploadTimeout="true" /> 
这里的port="8080"就是端口,我们完全可以用别的端口来代替,但不能是被系统占用的端口(0--1023),这里简单提一下。 
下面我们再往下找,会发现以下的语句: 
</Context> 
</Host> 
我们就应该找到这两个语句,如果不懂E文,您就认定这两个语句好了。然后我们将该语句更改如下: 
</Context> 
<Context path="/myjsp" debug="0" docBase="e:/myjsp" reloadable="true"> 
</Context> 
</Host> 
这里的path="/myjsp"就是我们就配置的虚拟目录了,以后在地址栏中输入http://localhost:8080/myjsp即可。而docBase="e:/myjsp" 则是机器本地路径,他们通过这个语句形成一个映射关系,其它照抄。 
将上面的First.jsp文件放到e:/myjsp目录下,输入http://localhost:8080/myjsp/First.jsp,是不是有一种喜上眉梢的感觉? 
在论坛里我见得最多的就是很多人不知道javaBean文件放到哪里,老实说开始我也不知道,更令人不解的是,十个人有九种不同的说法,这更让我们茫然。其实这问题也不是我们想像的那么复杂,我们以一个例子说明: 
先建立一个java程序,代码如下: 
package hall; 
public class SimpleBean { 
private String message = "No message specified"; 
public String getMessage() { 
return(message); 

public void setMessage(String message) { 
this.message = message; 


保存为SimpleBean.java,编译后会生成一个包,其实就相当于一个目录,也就是SimpleBean.class会存放在hall目录中,暂且保存起来,将来备用。 
再输入以下代码: 
<HTML> 
<HEAD> 
<TITLE>Reusing JavaBeans in JSP</TITLE> 
</HEAD> 
<BODY> 
<CENTER> 
<TABLE BORDER=5> 
<TR><TH CLASS="TITLE"> 
Reusing JavaBeans in JSP</TABLE> 
</CENTER> 
<P> 
<jsp:useBean id="test" class="hall.SimpleBean" /> 
<jsp:setProperty name="test" property="message" value="Hello WWW" /> 
<H1>Message: <I> 
<jsp:getProperty name="test" property="message" /> 
</I></H1> 
</BODY> 
保存在我们刚才建立的虚拟目录e:/myjsp下面,并命名为:BeanTest.jsp。 
现在我们应该将hall(包)目录放在哪儿呢?别急,我们先在e:/myjsp下建立一个文件夹WEB-INF,然后再在WEB-INF下建立一个classes文件夹,最后将hall目录放到classes下,当然,hall下的字节码文件SimpleBean.class也一并要移过来,而SimpleBean.java就和BeanTest.jsp放到同一目录吧(可以不需要放的,自己试试)。 
好了,大功告成了,重新启动机器(如果您试了好多次都不行,这一步一定要做),在浏览器中输入:http://localhost:8080/myjsp/BeanTest.jsp,您看到了什么?呵,别告诉我您什么都没看到,那肯定是您设置的问题了。 
好了,文章写完了,我也只是一只菜鸟,所以有写的不准备的地方请多多指教。祝您jsp之旅一路顺风!!! 
Java学习 - 技术文章中心 
初学者问的诸如:《怎样配置环境变量》《怎样运行Servlet》啊?这样的问题太多了,现在我写一个初学者入门必读,以便对初学者有指导作用! 
首先是下载工具: 
我建议初学者用Editplus+JDK,我觉得如果用例如JB,Eclipse,JCreator,虽然刚开始的时候比较方便,但是确使初学者门不知道怎样配置环境变量, 
从而难以达到知其然,知其所以然的地步 
可以通过如下地址下载: 
Editplus(最新版本是v2.11):http://count.skycn.com/softdown.php?id=3641&url=http://sc-http.skycn.net/down/epp211a_cn.exe(要照注册码就自己找吧,网上很多的) 
JDK(最新版本是Java2sdk1_4_2):http://count.skycn.com/softdown.php?id=3116&url=http://sc-http.skycn.net/down/j2sdk-1_4_2-windows-i586.exe(这是For Windows) 
然后就是安装JDK,我是把它装到从c:\JDK目录下面: 
然后就是CLASSPATH的问题了: 
正如操作系统利用PATH来搜索可执行程序一样,Java运行环境也会遍历CLASSPATH来查找类,即便是HelloWorld这样简单的程序,JVM也会遍历 
CLASSPATH定义的每一个路径,直到找到相应的文件为止。 
相信大家用的系统不是2k就是XP,然后就应当如下设置Path: 
我的电脑->属性->高级->环境变量 
然后在环境变量的Path后面追加: C:\JDK\bin;.;C:\JDK\lib 
也可以这样配置:C:\JDK\bin;.;C:\JDK\lib\dt.jar;C:\JDK\lib\tools.jar 
★记住:环境变量中的 . 切记不能少,它表示当前路径,如果少掉出现的错误等会就说! 
dt.jar是关于运行环境的类库,tools.jar是关于一些工具的类库 
如果没有配置:C:\JDK\bin,则会出现 " jvac´ 不是内部或外部命令,也不是可运行的程序或批处理文件。"这样的错误。 
然后下面就该写程序了: 
首先是(HelloWorld.java),打开Editplus,新建一个Java文件,请照着如下输入,要一字不漏,并且分清大小写: 
public class HelloWorld{ 
public static void main(String[] args){ 
System.out.println("Hello,World!"); 


然后把这个文件保存(ctrl + s)到HelloWorld.java,记住大小写一定要分清,是HelloWorld.java不是helloworld.java或者其它的 
下面就该运行了,开始->运行->cmd 
在控制台中把目录切换到当前目录: 
javac HelloWorld.java 
java HelloWorld 
你就会在控制台上看见输出的Hello,World!(没出来?我把电脑吃了:)) 
javac是编译命令,它把HelloWorld.java编译成HelloWorld.class 
java就是解释命令,JVM把HelloWorld.class解释执行. 
在这个时候: 
1。如果出现Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld 
那就是你在环境变量中没有加上那个.(dot) 
2。如果出现Exception in thread "main" java.lang.NoSuchMethodError: main 
或者HelloWorld.java:1: Public class helloworld must be defined in a file called 
"HelloWorld.java". 
那就是你没有分清大小写的写入这个HelloWorld,或者保存得时候没有保存为HelloWorld.java 
这个名字一定要跟public class的名字一样 
对于环境变量的问题就说到这里,下面我先所说怎么在Editplus里面编译和运行,在Tools->参数设置->配置用户工具 
1.添加工具(添加应用程序) 
菜单文字:Compile Java Program 
程序:C:\JDK\bin\javac.exe 
参数:文件名称 
初始目录:文件目录 
2.添加工具(添加应用程序) 
菜单文字:Run Java Program 
程序:C:\JDK\bin\java.exe 
参数:文件名称(不含扩展名) 
初始目录:文件目录 
工具组名称可以随便添,比如Debug Java Program 
然后在Tools的下拉菜单中,你就会看见Compile Java Program以及Run Java Program这两个选项,以后你就可以利用ctrl + 1编译和ctrl +2运行程序了 

下面就讨论Servlet的运行: 
首先要运行Servlet,则需要JSP/Servlet container,我建议初学者用Tomcat 
Tomcat(最新版本5.0):http://cvs.apache.org/builds/jakarta-tomcat-5/nightly/jakarta-tomcat-5-bin-20030725.zip 
然后把这个压缩包解压到: 
C:\Tomcat 
然后再配置环境变量: 
添加三个系统变量: 
JAVA_HOME: C:\JDK 
TOMCAT_HOME: C:\Tomcat 
CLASSPATH: %JAVA_HOME%\lib;%TOMCAT_HOME%\lib 
Tomcat的环境变量就配置完毕了,下面检验Tomcat是否能够运行: 
在控制台中转到C:\Tomcat\bin这个目录,运行startup,然后回出现一个窗口,连跳一大串东西,最后表示Server已经运行 
在浏览器中输入http://localhost:8080,出现欢迎界面,则表示Tomcat没问题了 
然后和上面一样,写入你的第一个Servlet 
import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 
public class HelloWorld extends HttpServlet 

public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException 

response.setContentType("text/html"); 
PrintWriter out = response.getWriter(); 
out.println("<html><head><title>"); 
out.println("This is my first Servlet"); 
out.println("</title></head><body>"); 
out.println("<h1>Hello,World!</h1>"); 
out.println("</body></html>"); 



然后照样用javac HelloWorld.java来编译这个文件,如果出现无法import javax.servlet.* 
那么就是应该把C:\Tomcat\common\lib里面的servlet.jar(根据实际来看)文件拷贝到C:\JDK\jre\lib\ext中,再次编译,就没有问题了! 
然后在Tomcat目录里面的C:\Tomcat\webapps\ROOT里面按如下的文件结构: 
ROOT\index.html 
ROOT\welcom.jsp 
ROOT\WEB-INF\lib\MyServlet.jar(如果你的servlet的.class打成了.jar文件,则放在lib下面) 
ROOT\WEB-INF\classes\HelloWorld.class(把上面生成的HelloWorld.class文件放在这个里面) 
然后在浏览器中输入http://localhost:8080/servlet/HelloWorld,于是Server众望所归的报错了:Error 404--Not Found 
怎么回事呢? 
Servlet必须使用C:\Tomcat\webapps\ROOT\WEB-INF这个目录下面的web.xml文件进行注册,用EP打开这个web.xml文件, 
在里面加入 
<servlet> 
<servlet-name>HelloWorld</servlet-name> 
<servlet-class>HelloWorld</servlet-class> 
</servlet> 
<servlet-mapping> 
<servlet-name>HelloWorld</servlet-name> 
<url-pattern>/servlet/helloworld</url-pattern> 
</servlet-mapping> 
这样的结构 
<servlet> 
<servlet-name>HelloWorld</servlet-name> 
<servlet-class>HelloWorld</servlet-class> 
</servlet> 
表示指定包含的servlet类. 
而以下的结构 
<servlet-mapping> 
<servlet-name>HelloWorld</servlet-name> 
<url-pattern>/servlet/HelloWorld</url-pattern> 
</servlet-mapping> 
表示指定HelloServlet应当映射到哪一种URL模式。 
在修改web.xml完毕过后,重新启动Server,然后再输入http://localhost:8080/servlet/HelloWorld

- 作者: 和疯 2006年02月13日, 星期一 13:24  回复(1) |  引用(2) 加入博采

BIRT 总览(翻译)
报表介绍
   
    BIRT 是为 Web 应用程序开发的基于 Eclipse 的开源报表系统,特别之处在于它是以 Java 和 J2EE 为基础。BIRT 有两个主要组件:基于 Eclipse 的报表设计器,以及部署到应用服务器上的运行时组件。BIRT 也提供了图标引擎让你能为应用增加图标。
   
    当前发行的版本是 1.0.1。我们鼓励你下载、试用 BIRT,请通过 newsgroups and Bugzilla 向我们提意见。
   
    有了 BIRT,你可以为应用程序构建丰富的报表。
   
    列表 - 列表是最简单的报表。当列表变长时,你可以把相关数据增加到同一分组(基于客户的订单分组,基于供应商的产品分组)。如果数据是数字类型的,你可以轻松的添加到“总数”、“平均”、或其他汇总中。
    图表 - 当需要图表表现时,数字型数据比较好理解。BIRT 也提供饼状、线状以及柱状图标等。
    交叉表 - 交叉表(也叫做十字表格或矩阵)用两种维度展示数据:sales per quarter or hits per web page。(交叉表在 1.0.1 中没有提供,但计划在将来提供。)
    信函和文档 - 通知、信件、以及其他文本文档都很容易通过 BIRT 方便建立。文档包括正文、格式、列表、图表等。
    混合报表 - 很多报表需要联合以上所有的报表构成单一文档。例如,一份客户声明会列出客户所需要的信息,为当前促进(promotions)提供文本,以及提供并行的出帐和入帐列表。一份财政报表将包括声明、图表、表格,所有这些都将进行全方位的格式化,来匹配共有的配色方案。
   
    剖析一份报表
   
    BIRT 报表包含四个部分:数据、数据转换、业务逻辑、陈述。
    数据 - 数据库、Web 服务、Java 对象,这些都可以作为 BIRT 报表源。1.0.1 版本提供 JDBC 支持,也支持利用编码来获取其他地方的数据。BIRT 的 ODA(Open Data Access) 框架允许任何人构建新的 UI 以及运行时支持任何类型的表格式数据。未来,单一报表可包含从任意多个数据源获取数据。
   
    数据转换 - 报表通过对数据的分类、统计、过滤以及分组来适应用户需求。当然,数据库能实现这些功能,当遇到普通文件和 Java 对象时 BIRT 必须以 "simple" 数据源方式处理。BIRT 允许复杂的操作,比如总合分组、整体共计的百分比,等等。
   
    业务逻辑 - 真实世界的数据很少提供你理想的结构良好的报表。许多报表要求用具体逻辑把原始数据转换成用户的有用信息。如果该逻辑仅仅用于该报表,你可以用 BIRT 的 JavaScript 脚本支持。如果你的程序中已包含这些逻辑,你可以调用已有的 Java 代码。
   
    表现 - 一旦数据准备好了,你可以在很大的范围内选择表现形式。表格、图表、文字等等都可以。单一数据集可以有多种方式表现,而单一报表可以表现多个数据集。
   
J2EE 应用中的 BIRT
   
    BIRT 报表引擎以 JAR 文件方式打包,可以方便的添加到你的 J2EE 应用中。报表引擎是一系列的 POJO(Plain Old Java Objects),便于你可以在 JSP 页面集成报表。    

    BIRT 与你的应用有四个主要集成点:
   
        UI 参数 - 多数报表允许用户指定一些输入,这些数据叫做"报表参数"。例如,客户报表要求显示客户数据。你的参数页面可能是静态的:为每个报表进行用户定制设计。或者,可以使用参数元数据提供的动态页面,以便该单一页面为所有的报表提供服务。
       
        运行报表 - 用户提交表单参数时,你的 web 应用通过这些参数向 BIRT 报表引擎说明读取哪个报表设计文件,并读取数据,再产生报表输出。当引擎运行报表时 BIRT 的术语称为"工厂"。
   
        数据访问 - 报表如何从你的应用获得数据已在上面解释了。Java 程序通常利用 Java 对象为 BIRT 工厂提供数据。
   
        显示 - 附加的 JSP 页面,叫做阅读器,允许用户查看报表输出。
   
    一个报表应用程序包含一个参数页,你可以为每个报表创建自定义的 UI,或者使用 BIRT 带来的参数元数据提供单一报表来处理多种不同报表。
   
样品阅读器
    
    BIRT 项目提供一个样品 "viewer" 来帮你起步。样品阅读器常被用于在 Eclipse 中预览报表:BIRT 内置一个 Apache Tomcat 服务器,每次预览报表时调用。阅读器也可被用于任何与 JSP 兼容的 J2EE 服务器。
   
    BIRT 的 1.0.1 版本提供单一页面的 web 输出。计划在将来的版本中提供多页面输出,而且阅读器 UI 也将提供多页面之间的导航功能。
   
报表设计

     BIRT 应用开发从报表设计开始。基于 Eclipse 插件提供多种快速构建报表工具。
        
         数据浏览器 - 把你的数据源(连接)以及数据集(查询)组织起来。数据集编辑器允许你测试数据集,以确保报表接收数据的正确性。
         布局视图 - 所见即所得编辑器为你的报表提供以拽方式来创建表现内容。包含一个标准报表条目调色板。
         属性编辑器 - 以便利的格局表现大多数通用的用户属性使编辑更快速和容易。BIRT 也集成了标准 Eclipse 属性视图,为每个条目提供详细的属性列表。
         报表预览 - 你可以在任何时间采用真实数据测试你的报表。预览窗口直接内嵌在 Eclipse 中。
         代码编辑器 - 在访问数据以及报表生成或浏览时,脚本把业务逻辑添加给报表。在编辑脚本时代码编辑器提供标准的 Eclipse 特性:语法加色、自动完成等等。BIRT 用很简单的脚本来表达,expression builder 能更容易的创建这些表达。
         略图 - BIRT 报表被组织为一个树型结构作为整体报表的根,并且为样式、报表内容、数据源、数据集、报表参数等分类。略图视图提供你整个报表结构紧凑的预览。
         Cheat Sheets - 学习新工具永远是种挑战,但是 Eclipse 提供一种创新方案:cheat sheets。它们是一些帮助你完成新任务的文档。
        
数据定制
   
    正如前面所提到的,报表通常为要表现的数据添加业务逻辑。BIRT 提供多个工具来完成这一操作:
   
        栏位计算-数据库为存储组织数据,但这些数据通常为结合表现层而预先整理好。栏位计算让你能定义基于业务逻辑的附加数据集栏位。这种逻辑是一个简单的语法、脚本或调用一个已有的 Java 逻辑。
        输入以及输出参数-许多数据源都支持参数:在查询时传入或传出数据的能力。比如,SQL Select 语句可包含输入参数。存储过程既有传入又有传出参数。
        栏位元数据-当数据源提供的名字是 unintuitive 的,你可以提供栏位别名。
        过滤 - 有些数据源,尤其是 SQL,提供良好的内置过滤特性。然而,有些数据源(单纯的文件,应用程序对象)却没有提供过滤特性。另外,过滤器条件是定义在脚本或 Java 代码中的。你可把过滤器定义为报表的一部分,BIRT 引擎会自动调用它们。
        脚本化数据集 - 有些报表需要访问专门或不常用的数据。你可以在 Java 或脚本创建访问,利用脚本化数据集可在报表中集成这些逻辑。
       
条件格式化
   
    有些报表有着固定的格式,其他的却需要条件格式化。例如,某报表列出了交易记录来表现不同的销售与利润之比。或者,一个客户服务报表要按照不同规则进行色彩显示。BIRT 提供多个条件格式化特性:
   
    条件可见度 - 你可以根据数据隐藏报表元素。在上述的交易报表中,你可以创建销售和交易收入两部分,接着隐藏报表指定记录中不需要的部分。
   
    值映射 - 数据库数据通常使用代码值:M/F 代表男性或性,1/2 代表销售和收入,等等。值映射让你定义一个从数据库值到显示值的映射。例如,我们可把值“1”对应到“Sale”,把“2”对应到“Return”。
   
    加强 - 简单的标识可让你对特定报表套用样式。例如,在客户服务报表中,我们可以使用绿色表示上一的计划,红色表示下一计划。
   
    脚本

    BIRT 提供基于 JavaScript(与知名的 ECMAScript 形式上相同)的脚本。JavaScript 经常作为客户端脚本语言,但是它也可以用于用于表达业务逻辑。特别的,JavaScript 能与你的现有 Java 逻辑进行良好集成,能非常轻松地从 BIRT 报表调用业务逻辑。
   
    BIRT 提供从 JavaScript 对象访问报表对象模型(Report Object Model)的整套方案:同时表现报表设计和运行时的状况,允许报表的完全控制处理甚至最复杂的报表格式化工作。
   
项目管理

    BIRT 集成了 Eclipse 项目管理特性来组织相关报表。BIRT 也可以与 Eclipse CVS 协作进行源码管理。BIRT 的 XML 报表设计格式让它能容易的比较两份报表,或者两个不同版本的相同报表,并跟踪变更。
   
    样式

    任何设计 web 页面的人都知道有时会反复使用相同的样式。CSS 允许 web 设计者从内容中提取样式信息,并复用样式。
   
    BIRT 提供类似的特性。当然,BIRT 样式也是基于 CSS 的,这样使得网页应用开发人员能容易得设计 BIRT 表现形式。BIRT 样式可堆叠,允许你在一个地方设置样式后套用到所有报表或报表的一部分或单一报表中。
   
    库

    典型的应用中会包括许多有关联的报表。一个简单的客户应用将包括一个按照字母排序的客户列表、按照地理位置分类的客户群,为客户指定的销售代表,客户身份筛选等等。总之,用户不停的地变化报表以解决具体业务需要。
   
    这样一来,最终的报表应用将包含多组相关报表。相同的数据源、样式、业务逻辑、报表条目。
   
    将来的 BIRT 版本将包含组织这些共享资源的支持库。这些库可包含任何报表元素,比如样式、数据源、报表条目、脚本等等。
   
国际化

    全世界都可以访问你的 web 应用程序。BIRT 为国际化和本地化提供良好的支持。
   
    文本本地化 - 你可以建立一份把字符串自动变成用户本地语言显示的简单报表。所有的表单和报表文本都能以标准的 Java 本地化规则进行翻译。在运行时,BIRT 使用资源 key 找出文本的正确翻译。
   
    本地化 - BIRT 提供 locale-aware 格式化数据,意味着对于美国用户的日期数据可以以 mm/dd/yy 的格式出现,而欧洲用户则是 dd-mm-yy 格式。
   
    动态格式化 - 中文文本非常紧凑,德文有时又有点冗长,而英文正好是中等大小。BIRT 自动调整报表条目的大小来适合其中的内容,避免每次翻译都要进行报表测试。
   
扩展性

    报表应用程序的范围是十分庞大的,BIRT 团队不能为每个应用提供很具体的特性。可利用 BIRT 脚本来扩展 BIRT,另外还可构建 BIRT 扩展插件到 BIRT 中。
    
    数据访问
   
    BIRT 提供 ODA(Open Data Access) 框架来支持自定义数据访问方法。数据访问的范围还包括一个获取数据的运行时组件。也包括构建自定义查询的自定义设计时 UI。例如,打包后的应用程序可以让 ODA 构建数据访问 UI 并运行在自己的数据模型中。
    
    报表栏目
   
    BIRT 为要表现的数据提供一致的报表栏目集。可以在应用程序中自定义附件报表栏目,并像 BIRT 自身的报表栏目一样运行在设计器和引擎中。例如,性能管理应用程序要添加报表栏目来高亮显示停止项、尺度表以及其他用来衡量性能的可视标志。
   
    图表类型
   
    BIRT 图表包提供了很多的图表类型。但是,一些行业需要很特殊的图表样式。开发者可以在 BIRT 图表引擎中创建图表插件来提供这些图表样式。
   
    输出格式
   
    BIRT 1.0.1 支持输出到 HTML 和 PDF。当然,也可能需要其他类型输出:Excel、RTF(Rich Text Format)、SVG(Scalable Vector Graphic)、图像、等等。BIRT 在今后会提供其中一些,除开这些的其他格式可能需要的用户就很少了。开发者可利用 BIRT 引擎接口添加转换器以达到目的。

- 作者: 和疯 2006年02月7日, 星期二 21:53  回复(3) |  引用(2) 加入博采