关于tomcat的部署一个让我郁闷了一天的问题

在编写JSP程序的时候,将jsp+servlet发布的服务器选用tomcat,遇到很多问题,网上关于tomcat的文章找了很久才找到一篇讲tomcat动态发布的,觉得不错,贴出来大家看看.

Tomcat4中的部署方式:

1 部署Web应用程序的方法:

1.1 WAR方式

将应用程序包含的jsp、servlet等文件包装成一个单个的、自包含的WAR文件。WAR文件是一个JAR文件,其中包含了特殊的目录和位于他的/Web-INF目录中的web.xml文件。其结构举例如下:

hello.jsp

META-INF/

           MANIFEST.MF

Web-INF/

           web.xml

           classes/

                    example/helloWorld.class

           lib/

                    xxx.jar

创建WAR文件的最容易的方法就是,首先在开发环境中创建相应于WAR结构的目录结构。然后,创建WAR所要做的工作就是在WAR的根目录中执行下面的命令。注意,其中排除了.java源文件,它是WAR文件中不必要的内容,并且在试图部署WAR时可能会带来问题:

Jar ?cvf hello.war META-INF/MANIFEST.MF Web-INF/classes/example/*.class Web-INF/web.xml *.jsp

将WAR文件拷贝到$CATALINA_HOME/webapps目录中。当Tomcat启动时,它

就会自动对WAR文件进行解包,并且创建这个应用程序,应用程序的名字(和上下文路径Context Path)为WAR文件的名称。在这里不需要对系统或者服务器路径做任何的改动。

注意:如果在Tomcat已经启动好以后,放置WAR文件到webapps目录,则Tomcat无法动态

部署这个Web应用程序,需要重启Tomcat。 如果虚拟主机的liveDeploy属性为true就不用了。

1.2扩展目录方式

此种部署方式的优点是,当对jsp进行了修改时不必重启Tomcat,并且不必在每次修改时都要去重新建立归档文件,而且在准备好进行软件分发时也很容易地创建WAR文件。

    在server.xml文件中加入如下代码,该文件位于$CATALINA_HOME/conf目录中。

    <Context path=”/hello” docBase=”<path to root of war>” debug=”0”

              reloadable="true" crossContext="true" />

    <path to root of war>是一个按照使用的操作系统的目录惯例的绝对路径,并且不必是位于Tomcat的目录树下面。作者把这个WAR部署到Windows中,使用的是docBase=”d: lymacy”,而在Unix中,所使用的docBase=”/export/home/macy”。

注意,Tomcat要求对Windows的路径使用单个反斜杠。

______________________________________________________________________________________________

答6:

Tomcat5中的部署方式:

1 应用程序部署器(Deployer)

程序员朋友不要以为这是什么全新的东西,其实以前的版本就已经有了,只不过在Tomcat4中没有提出这个概念,且它的功能被分散在各个组件中,给人的感觉是比较支离破碎的。于是乎,在Tomcat5中对其进行了包装和增强,提出了Deployer这个逻辑概念,用于集中表示应用程序部署和发布功能。Tomcat5对其的主要改进就是进行了一些优化,增强了动态部署的功能,减少了重启Tomcat的次数,增强了服务器的健壮性和可靠性。

Deployer提供的主要功能就是静态(在tomcat启动之前)或者动态(在Tomcat运行以后)进行Web应用程序的部署和删除,在某些情况下Deployer需要和Manager管理工具联合使用。

1.1 Context descriptors

这个也不是新东西了,Tomcat4中的Manager和Admin管理工具其实就是利用它来部署的。在Tomcat5中提出了Context descriptor这个概念,且为其配置了一个专有目录,而不像Tomcat4那样大杂烩一般地放置在$appBase目录下。既然了有了名分,当然要为其单独配置一个目录才能显其身份:)

Context descriptor是一个只包含Context元素的xml格式的部署文件,其中Context元素与server.xml中的Context元素配置相同。对于一个给定的主机,Context descriptor放置在$CATALINA_HOME/conf/[enginename]/[hostname]/目录下面。Tomcat5默认安装时,在$CATALINA_HOMEconfCatalinalocalhost目录中有admin.xml和manager.xml,是两个管理工具的部署描述符文件。而这两个文件在Tomcat4中是放置在$CATALINA_HOME/webapps目录下面的。呵呵。。。果然是换汤不换药啊:)

注意事项:context descriptor的文件名可以与Web应用程序名无关,但是Tomcat在部署这个应用程序的时候所创建的程序运行上下文(Context)的名称是与Web应用程序名称匹配的。

   

1.2 静态部署

静态部署是指在Tomcat运行之前就把相关的Web应用程序放置到合适的目录,在Tomcat启动的时候自动来部署这些应用程序。

如果"deployOnStartup"属性值为true,那么在Tomcat启动时,在$appBase目录下的web应用程序将被自动部署。部署的过程如下:

? Context元素声明的Web应用程序将被首先部署,这包括server.xml和context descriptor文件中的Context元素所指的应用程序;

? 部署扩展目录形式的Web应用程序;

? 部署WAR形式的Web应用程序;

Tomcat5对于静态方式的部署的增强主要就是:

1、对于context descriptor方式的应用程序的部署。

2、如果扩展目录方式的应用程序对应有一个WAR文件,且WAR是更新过的,扩展目录将被自动删除,Web应用程序将被从WAR文件中重新部署。而在Tomcat4中,即使WAR文件已更新也无法被重新部署,仍然会使用旧的扩展目录方式的Web应用程序,除非你自己手动删除目录,记得还要重启Tomcat哦。这么麻烦?(#@($)#*$),看来还是Tomcat5好啊:)

1.3 动态部署

动态部署是指在Tomcat已经运行以后在不重启服务器的情况下部署应用程序的方式。

如果虚拟主机的"autoDeploy"属性值为true,则主机会在需要的时候试图去部署和更新应用程序。这是由虚拟主机在后台运行的一个负责自动加载的处理线程来完成的,它的工作流程如下:

1、部署新放入$appBase目录的War方式的应用程序。

2、部署新放入$appBase目录的扩展目录方式的应用程序。

3、如果一个扩展目录方式的应用程序对应的War文件更新了,则删除此目录,从War文件中重新解开并部署。如果”unpackWARs”属性值为false,则不解开,从War文件中直接运行。(记住:不用自己删除扩展目录,也不用重启服务器)

4、如果应用程序的/WEB-INF/web.xml文件被改变,则重新部署这个应用。

5、如果应用程序对应的Context元素配置发生了改变,则重新部署这个应用。这包括server.xml或者上下文描述符文件中的Context元素。

6、如果$CATALINA_HOME/conf/[enginename]/[hostname]/目录下增加了上下文描述符文件,则重新部署这个应用。

看来Tomcat5在动态部署上花费了不少功夫,其中的亮点主要就是如果我们修改了web.xml、server.xml配置文件,增加了上下文描述符文件,动态更新了War文件时都可以实现应用程序的自动部署和更新,而不用重新启动Tomcat服务器,在Tomcat4中都是必须重新启动服务器的,这是一个非常喜人的变化。毕竟在对服务器的健壮性和可靠性要求越来越高的今天,重启服务器都是一件令我们非常头疼的一件事情。以后终于可以挺直腰杆对客户说“这回坚决不用重启服务器!”嘿嘿。。。幸福啊!

1.4 用Client Deployer工具包部署

    这个才是Tomcat5中名副其实的创新,它是一个全新的部署器。

client deployer是一个集验证、编译、部署功能与一体的工具包。它使用Ant来实现应用程序的自动化验证和编译,使用Manager管理工具来实现应用程序的自动化部署。

这个工具包包含:Catalina Ant工具、Jasper编译器(用于将jsp编译为servlet)、应用程序验证工具(validator task)。默认的验证工具的实现类是org.apache.catalina.ant.ValidatorTask,它只允许以扩展目录的文件路径作为唯一的参数。

此部署工具包使用一个事先写好的Ant脚本,包含如下一些目标(target):

? compile (默认):用于验证和编译Web应用程序。它可以在不启动Tomcat的情况下被单独使用。由于使用的是新的Jasper编译器的缘故,编译后的应用程序将只能在Tomcat 5.X版本上使用。需要提醒的是,不光是jsp文件被编译为servlet, 应用程序的/WEB-INF/classes目录下的Java源文件也将被同时编译为class文件。

? deploy:将Web应用程序部署到Tomcat服务器中。

? undeploy:从服务器中解除部署已经部署的某个应用程序。

? start:启动Web应用程序

? reload:重新加载Web应用程序

? stop:停止Web应用程序

以下是Ant脚本中的一些重要属性:

? build:编译以后的文件默认放置在${build}/webapp${path}。编译目标执行完以后,生成了应用程序的War —— ${build}/webapp${path}.war.

? webapp:放置需要被验证和编译的Web应用程序(扩展目录方式)的文件路径。默认值为”myapp”。

? path:Web应用程序部署后对应的运行上下文的路径默认是”/myapp“。

? url:放置Manager管理工具的绝对路径,它被部署工具包用来部署和解除部署应用程序。默认情况下,部署器将试图使用http://localhost:8080/manager访问本机的Manager管理工具。

? username:可以使用Manager管理工具的超级用户的用户名。

? Password:超级用户的密码。

至此,Tomcat5中神秘的部署器就讲完了,大家是不是已经对它发生了浓厚的兴趣呢?那就动手去试一下吧!尽管朝$appBase目录下扔你心爱的程序吧,Tomcat5会马上让他们欢快地跑起来。速度真的比Tomcat4快多了,一种冲浪的感觉:)

 

 

 

本文章引用通告地址(TrackBack Ping URL)为:

http://blog.zol.com.cn/portal/personShowArticle.do?articleId= 18829 

从客户端往服务端发送消息的代码

客户端

public class TalkClient {

   

    public static void main(String[] args) {

        // Create application frame.

        ClientSend cs = new ClientSend();

        TalkClientFrame frame = new TalkClientFrame(cs);

       

        // Show frame

        frame.setVisible(true);

       

    }

}

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

import java.net.*;

public class ClientSend {

private DatagramSocket ds_CSend;

private DatagramPacket dp_CSend;

public ClientSend(){

try{

    ds_CSend = new DatagramSocket(8080);

}

catch(Exception e){

e.printStackTrace();

}

}

public void Sended(byte[] buf,String sip){

try{

    dp_CSend = new DatagramPacket(buf,buf.length,InetAddress.getByName(sip),8888);

    ds_CSend.send(dp_CSend);

}

catch(Exception e){

e.printStackTrace();

}

}

}

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

import java.awt.*;

import java.awt.event.*;

import java.net.*;

public class TalkClientFrame extends Frame {

     private List lst = new List(6);//存放对话内容

     private TextField tf_Data = new TextField(20);//存放发送内容       

     private TextField tf_ip = new TextField(15);//存放IP和PORT;

     private ClientSend cs;

  

     public TalkClientFrame(ClientSend cs) {

     this.cs = cs;

     tf_ip.setText("127.0.0.1");

        Panel p_Data = new Panel();//放置tf_Data,tf_ip的容器

 

     

//-----------------------布局-----------------------------------

        this.add(lst,"Center");

        this.add(p_Data,"South");

        p_Data.add(tf_ip,"West");

        p_Data.add(tf_Data,"East");

       

        tf_Data.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent evt){

        //

       

        tf_Dataactionperformed(evt);

        }

        });

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

        MenuBar menuBar = new MenuBar();

        Menu menuFile = new Menu();

        MenuItem menuFileExit = new MenuItem();

       

        menuFile.setLabel("文件(F)");

        menuFileExit.setLabel("退出(X)");

       

        // Add action listener.for the menu button

        menuFileExit.addActionListener

        (

            new ActionListener() {

                public void actionPerformed(ActionEvent e) {

                if (tf_Data.getText().length()>0)

                    TalkClientFrame.this.windowClosed();

                }

            }

        );

        menuFile.add(menuFileExit);

        menuBar.add(menuFile);

       

        setTitle("TalkClient");

        setMenuBar(menuBar);

        setSize(new Dimension(350, 400));

       

        // Add window listener.

        this.addWindowListener

        (

            new WindowAdapter() {

                public void windowClosing(WindowEvent e) {

                    TalkClientFrame.this.windowClosed();

                }

            }

        ); 

    }

   

    void tf_Dataactionperformed(ActionEvent e){

    byte[] buf = tf_Data.getText().getBytes();

    String strIp = tf_ip.getText();

    try{

        cs.Sended(buf,strIp); 

         

    }

    catch(Exception ex){

    ex.printStackTrace();

    }

    tf_Data.setText("");

    }

    /**

     * Shutdown procedure when run as an application.

     */

    protected void windowClosed() {

   

    // TODO: Check if it is safe to close the application

   

        // Exit application.

        System.exit(0);

    }

   

}

服务端

public class talkServer {

public static void main(String[] args) {

// TODO: Add your code here

talkRecv tR = new talkRecv();

tR.Recved();

}

}

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

import java.net.*;

public class talkRecv {

private DatagramSocket ds_Recv;

private DatagramPacket dp_Recv;

public boolean b_stop=true;

public talkRecv(){

try{

    ds_Recv = new DatagramSocket(8888);//将8888端口作为接受端口

    byte[] buf = new byte[1024];

    dp_Recv = new DatagramPacket(buf,1024);

}

catch(Exception e){

e.printStackTrace();

}

}

public void Recved(){

while(b_stop){

try{

    ds_Recv.receive(dp_Recv);

    String str_info = new String(dp_Recv.getData(),0,dp_Recv.getLength());

    System.out.println("  ip:"+dp_Recv.getAddress().getHostAddress());    

    System.out.println("port:"+dp_Recv.getPort());

    System.out.println("data:"+str_info);

}

catch (Exception e){

e.printStackTrace();

}

}

}

}

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

这几个类都没怎么考虑对象的释放问题,这个问题希望那位大大能够关注一下,给小弟一点指点,小弟感激不禁

一个查询登陆数据验证的程序

有两个文件

public class talkServer {

/*中间件主程序

*/

public static void main(String[] args) {

// TODO: Add your code here

db_Access db= new db_Access();

if(db.loging(args[0],args[1])){

System.out.println("验证通过");

}

else{

System.out.println("验证失败");

};

}

}

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

import java.sql.*;

import java.util.*;

public class db_Access {

private Connection db_connect;//定义与数据库进行连接的对象

private ResultSet rs;         //定义数据库查询结果对象

private Statement st;         //定义数据库查询对象

// private Vector vt;            //定义结果数组

public db_Access(){

try{

    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    //知道是返回一个JDBC-ODBC的桥驱动程序对象,但是在这里这样写有什么作用

    //就不得而知了

    String url ="jdbc:odbc:talkdb";

    db_connect = DriverManager.getConnection(url);

    st = db_connect.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

       ResultSet.CONCUR_READ_ONLY); //创建statement接口对象实例

}

catch(Exception e){

//可以把异常做成一个类,不知道有没有现成的好类可以用的

e.printStackTrace();

}

}

public boolean loging(String un,String pd){

String strSQL = "SELECT count(id) AS aid FROM userinfo WHERE (username ='"

  + un +"')AND(password ='" + pd +"')" ;

try{

    rs = st.executeQuery(strSQL); //执行设计好的sql语句

        rs.next();

            if (rs.getInt(1)==0){  //这里的getInt()的字段索引居然是1,那么0是什么哪?

    return false;

    }

    else{

    return true;

    }

}

catch(Exception e){

e.printStackTrace();

}

return false;

}

}

数据库格式为 id username password

有个问题,为什么当我故意查找错误的username和password的时候,

rs.getInt老是抛出"非法游标状态"的异常?正确的密码组合到没事情

我用的是select count啊,应该返回0这个值的啊,亲娘唉,真令人费解啊.

classpath 问题

很简单的类的调用,但是在JCREAT中用工程和工作空间能够编译运行,但是在cmd下用java命令却运行不了

package killgod;

public class A {

/**

* Method sayHellow

*

*

*/

public void sayHellow() {

// TODO: Add your code here

String s1 = "我要发财",s2 = "我要发财";

if (s1 == s2 ){

  System.out.println("第一次试验:"+s1);

}

else System.out.println("世界和平");

s1 = new String("我要发财");

s2 = new String("我要发财");

if (s1 == s2 ){

  System.out.println("第2次试验:" + s1);

}

else System.out.println("第2次试验:世界和平");

}

}

运行类

package killgod;

public class SencondDemo {

public int x = 1;

/**

* Method main

*

*

* @param args

*

*/

public static void main(String[] args) {

// TODO: Add your code here

if(args.length > 0 ){

System.out.println("第一个参数是 "+args[0]);

}

else{

new SencondDemo().callA(new A());

}

}

/**

* Method callA

*

*

* @param a

*

*/

public static void callA(A a) {

// TODO: Add your code here

a.sayHellow();

}

}

我在cmd下面使用了 set CLASSPATH = ?????的命令,结果还是没有效果,真是奇怪啊!

看来classpath问题要好好研究一下了。

一个猴子扮苞谷的程序

先写点习作熟悉一下JAVA的工作

class monky

{

int[] goods = new int[100];

//getGood作为litte monky的行为成员

void getGood(int good,int i)

{

goods[i] = good;

}

//开始计算扳了多少

void count()

{

int all =0;

for(int i=0;i<100;i++)

{

all = all+goods[i];

  System.out.print(goods[i]+",");

}

  System.out.println(" ");

  System.out.print("总重:"+all);

}

}

class monkyPlay

{

public static void main(String[] args)

{

  monky mk = new monky();

for(int i=0;i<100;i++)

//随机产生不同重量的苞谷

  mk.getGood((int)(Math.random()*3000),i); 

  mk.count();  

}

}

初识

编程年龄也有6年多了,都是再使用DELPHI和C++等,最近刚开始学习JAVA语言,对这个领域相对很陌生,基本上算是从0开始。

所谓万丈高楼平地起,什么事情都要一步一步来。

这两天接触并查阅了大量的关于JAVA的资料,发现说它是一个庞大的家族并不为过,相反自己倒有点看的头晕目眩的了,为了不迷失在这片茂密的JAVA森林里面,决定定下初步的学习方向,由于本人过去做的都是基于C/S结构的应用程序,所以现在本人将目标放在了B/S的目标上面。

提起JAVA首先几乎所有程序员都知道它的语言的开放性和在世界级的广泛应用(相形之下本人以前学习的DELPHI和C++都可怜的很),而且还有伴随着JAVA的J2EE/J2ME等等架构。

我学习的第一个疑问就是J2EE究竟是什么,它到底有什么用处?

翻阅了很多网络上的资料,但是发现各位发资料的大大们好像都是高手中的高手,将一个J2EE写的惊天动地的,看了半天也完全没看明白。最后只好清楚的认识到自己的水平实在太低了,遂打消掉一步登天的念头决定从最简单的开始做起。