`
韩悠悠
  • 浏览: 827005 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

19tomcat的服务器和服务

 
阅读更多
Server服务器
Server接口表示整个Catalina Servlet容器以及其它组件。
它提供了一种优雅的机制来启动和停止整个系统。不必再单独的启动连接器和容器了。
当服务器启动的时候,它启动它内部的所有组件。然后无限期的等待关闭命令,
如果你想要关闭系统,发送一个关闭命令道指定端口即可。当服务器收到正确的关闭指令后,它停止所有组件的服务。
服务器还使用了另外一个组件,服务(service),它用来持有组件
public interface Server {


    // ------------------------------------------------------------- Properties


    /**
     * Return descriptive information about this Server implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the global naming resources.
     */
    public NamingResources getGlobalNamingResources();


    /**
     * Set the global naming resources.
     * 
     * @param namingResources The new global naming resources
     */
    public void setGlobalNamingResources
        (NamingResources globalNamingResources);


    /**
     * Return the port number we listen to for shutdown commands.
     */
    public int getPort();


    /**
     * Set the port number we listen to for shutdown commands.
     *
     * @param port The new port number
     */
    public void setPort(int port);


    /**
     * Return the shutdown command string we are waiting for.
     */
    public String getShutdown();


    /**
     * Set the shutdown command we are waiting for.
     *
     * @param shutdown The new shutdown command
     */
    public void setShutdown(String shutdown);


    // --------------------------------------------------------- Public Methods


    /**
     * Add a new Service to the set of defined Services.
     *
     * @param service The Service to be added
     */
    public void addService(Service service);


    /**
     * Wait until a proper shutdown command is received, then return.
     */
    public void await();


    /**
     * Return the specified Service (if it exists); otherwise return
     * <code>null</code>.
     *
     * @param name Name of the Service to be returned
     */
    public Service findService(String name);


    /**
     * Return the set of Services defined within this Server.
     */
    public Service[] findServices();


    /**
     * Remove the specified Service from the set associated from this
     * Server.
     *
     * @param service The Service to be removed
     */
    public void removeService(Service service);

    /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     *
     * @exception LifecycleException If this server was already initialized.
     */
    public void initialize()
    throws LifecycleException;
}

 

属性shutdown用来持有一个停止服务的指令。属性port则是服务器等待关闭命令的端口。
可以调用服务器的addService方法将服务添加到服务器。使用removeService方法将服务删除。
findServices返回所有服务器中所有的服务。Initialize方法包括在启动之前需要执行的代码。

StandardServer类
StandardServer类是服务器的标准实现
一个服务器可以有零个或多个服务,StandardServer类提供了addService、removeService、findServices方法的实现。
另外还有四个跟生命周期相关的方法:initialize 、tart 、stop以及await。
initialize方法
Initialize方法用于初始化要添加到服务器实例上的服务

public void initialize()
    throws LifecycleException {
        if (initialized)
            throw new LifecycleException (
                sm.getString("standardServer.initialize.initialized"));
        initialized = true;

        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) {
            services[i].initialize();
        }
    }

 

注意该方法使用了一个名为initialized的变量来避免多次启动该服务器

 


start方法
可以使用start方法来启动一个服务器,StandardServer的start方法的实现将会启动所有服务及其相关组件,例如连接器和容器

 public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("standardServer.start.started"));
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Services
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).start();
            }
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }

 

该方法使用了一个started布尔变量来避免一个服务器被启动两次。Stop方法会重置该变量的值

 

stop方法

 public void stop() throws LifecycleException {

        // Validate and update our current component state
        if (!started)
            throw new LifecycleException
                (sm.getString("standardServer.stop.notStarted"));

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;

        // Stop our defined Services
        for (int i = 0; i < services.length; i++) {
            if (services[i] instanceof Lifecycle)
                ((Lifecycle) services[i]).stop();
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

    }

 

 


await方法
Await负责整个Tomcat部署的停止机制

 

public void await() {

        // Set up a server socket to wait on
        ServerSocket serverSocket = null;
        try {
            serverSocket =
                new ServerSocket(port, 1,
                                 InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            System.err.println("StandardServer.await: create[" + port
                               + "]: " + e);
            e.printStackTrace();
            System.exit(1);
        }

        // Loop waiting for a connection and a valid command
        while (true) {

            // Wait for the next connection
            Socket socket = null;
            InputStream stream = null;
            try {
                socket = serverSocket.accept();
                socket.setSoTimeout(10 * 1000);  // Ten seconds
                stream = socket.getInputStream();
            } catch (AccessControlException ace) {
                System.err.println("StandardServer.accept security exception: "
                                   + ace.getMessage());
                continue;
            } catch (IOException e) {
                System.err.println("StandardServer.await: accept: " + e);
                e.printStackTrace();
                System.exit(1);
            }

            // Read a set of characters from the socket
            StringBuffer command = new StringBuffer();
            int expected = 1024; // Cut off to avoid DoS attack
            while (expected < shutdown.length()) {
                if (random == null)
                    random = new Random(System.currentTimeMillis());
                expected += (random.nextInt() % 1024);
            }
            while (expected > 0) {
                int ch = -1;
                try {
                    ch = stream.read();
                } catch (IOException e) {
                    System.err.println("StandardServer.await: read: " + e);
                    e.printStackTrace();
                    ch = -1;
                }
                if (ch < 32)  // Control character or EOF terminates loop
                    break;
                command.append((char) ch);
                expected--;
            }

            // Close the socket now that we are done with it
            try {
                socket.close();
            } catch (IOException e) {
                ;
            }

            // Match against our command string
            boolean match = command.toString().equals(shutdown);
            if (match) {
                break;
            } else
                System.err.println("StandardServer.await: Invalid command '" +
                                   command.toString() + "' received");

        }

        // Close the server socket and return
        try {
            serverSocket.close();
        } catch (IOException e) {
            ;
        }

    }

 

方法await在8085端口创建一个ServerSocket对象,在while循环调用它的accept方法。
Accept方法仅仅接受8085端口的信息。它将接受到的信息跟shutdown命令进行匹配,
如果匹配的话跳出循环关闭SocketServer,如果不匹配继续while循环等待另一个命令。

服务
org.apache.catalina.Service接口用于表示服务。一个服务可以可以有一个容器和多个连接器。
可以添加多个连接器 ,并将它们跟容器相关联

 

public interface Service {


    // ------------------------------------------------------------- Properties


    /**
     * Return the <code>Container</code> that handles requests for all
     * <code>Connectors</code> associated with this Service.
     */
    public Container getContainer();


    /**
     * Set the <code>Container</code> that handles requests for all
     * <code>Connectors</code> associated with this Service.
     *
     * @param container The new Container
     */
    public void setContainer(Container container);


    /**
     * Return descriptive information about this Service implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the name of this Service.
     */
    public String getName();


    /**
     * Set the name of this Service.
     *
     * @param name The new service name
     */
    public void setName(String name);


    /**
     * Return the <code>Server</code> with which we are associated (if any).
     */
    public Server getServer();


    /**
     * Set the <code>Server</code> with which we are associated (if any).
     *
     * @param server The server that owns this Service
     */
    public void setServer(Server server);

    
    // --------------------------------------------------------- Public Methods


    /**
     * Add a new Connector to the set of defined Connectors, and associate it
     * with this Service's Container.
     *
     * @param connector The Connector to be added
     */
    public void addConnector(Connector connector);


    /**
     * Find and return the set of Connectors associated with this Service.
     */
    public Connector[] findConnectors();


    /**
     * Remove the specified Connector from the set associated from this
     * Service.  The removed Connector will also be disassociated from our
     * Container.
     *
     * @param connector The Connector to be removed
     */
    public void removeConnector(Connector connector);

    /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     *
     * @exception LifecycleException If this server was already initialized.
     */
    public void initialize()
    throws LifecycleException;

}

 

 

StandardService类

StandardService类是Service接口的标准实现。StandardService类的initialize方法初始化所有的添加到该服务的连接器

public void initialize()
    throws LifecycleException {
        if (initialized)
            throw new LifecycleException (
                sm.getString("standardService.initialize.initialized"));
        initialized = true;

        // Initialize our defined Connectors
        synchronized (connectors) {
                for (int i = 0; i < connectors.length; i++) {
                    connectors[i].initialize();
                }
        }
    }

 

容器和连接器
一个StandardService实例包括两种组件:一个容器和多个连接器。
多个连接器可以使得Tomcat能服务于多个协议。一个协议用处处理HTTP请求,另一个用于处理HTTPS请求。
StandardService类用container变量来持有容器实例,用connectors数组来持有所有的连接器
private Container container = null;
private Connector connectors[] = new Connector[0];

要将一个容器跟一个服务相关联,可以使用它的setContainer方法

 

 

public void setContainer(Container container) {

        Container oldContainer = this.container;
        if ((oldContainer != null) && (oldContainer instanceof Engine))
            ((Engine) oldContainer).setService(null);
        this.container = container;
        if ((this.container != null) && (this.container instanceof Engine))
            ((Engine) this.container).setService(this);
        if (started && (this.container != null) &&
            (this.container instanceof Lifecycle)) {
            try {
                ((Lifecycle) this.container).start();
            } catch (LifecycleException e) {
                ;
            }
        }
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++)
                connectors[i].setContainer(this.container);
        }
        if (started && (oldContainer != null) &&
            (oldContainer instanceof Lifecycle)) {
            try {
                ((Lifecycle) oldContainer).stop();
            } catch (LifecycleException e) {
                ;
            }
        }

        // Report this property change to interested listeners
        support.firePropertyChange("container", oldContainer, this.container);

    }

 


要与服务相关联的容器传递给该每个连接器,这样来建立容器和每个连接器的关系。

要给一个服务添加连接器,可以使用addConnector方法。要删除一个连接器,可以使用removeConnector方法

 public void addConnector(Connector connector) {

        synchronized (connectors) {
            connector.setContainer(this.container);
            connector.setService(this);
            Connector results[] = new Connector[connectors.length + 1];
            System.arraycopy(connectors, 0, results, 0, connectors.length);
            results[connectors.length] = connector;
            connectors = results;

            if (initialized) {
                try {
                    connector.initialize();
                } catch (LifecycleException e) {
                    e.printStackTrace(System.err);
                }
            }

            if (started && (connector instanceof Lifecycle)) {
                try {
                    ((Lifecycle) connector).start();
                } catch (LifecycleException e) {
                    ;
                }
            }

            // Report this property change to interested listeners
            support.firePropertyChange("connector", null, connector);
        }

    }

    public void removeConnector(Connector connector) {

        synchronized (connectors) {
            int j = -1;
            for (int i = 0; i < connectors.length; i++) {
                if (connector == connectors[i]) {
                    j = i;
                    break;
                }
            }
            if (j < 0)
                return;
            if (started && (connectors[j] instanceof Lifecycle)) {
                try {
                    ((Lifecycle) connectors[j]).stop();
                } catch (LifecycleException e) {
                    ;
                }
            }
            connectors[j].setContainer(null);
            connector.setService(null);
            int k = 0;
            Connector results[] = new Connector[connectors.length - 1];
            for (int i = 0; i < connectors.length; i++) {
                if (i != j)
                    results[k++] = connectors[i];
            }
            connectors = results;

            // Report this property change to interested listeners
            support.firePropertyChange("connector", connector, null);
        }

    }

 

Start方法用于启动相关联的连接器和容器

public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started) {
            throw new LifecycleException
                (sm.getString("standardService.start.started"));
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        System.out.println
            (sm.getString("standardService.start.name", this.name));
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Container first
        if (container != null) {
            synchronized (container) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).start();
                }
            }
        }

        // Start our defined Connectors second
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++) {
                if (connectors[i] instanceof Lifecycle)
                    ((Lifecycle) connectors[i]).start();
            }
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }

 

 

Stop方法关闭所有关联连接器和容器

public void stop() throws LifecycleException {

        // Validate and update our current component state
        if (!started) {
            throw new LifecycleException
                (sm.getString("standardService.stop.notStarted"));
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

        lifecycle.fireLifecycleEvent(STOP_EVENT, null);

        System.out.println
            (sm.getString("standardService.stop.name", this.name));
        started = false;

        // Stop our defined Connectors first
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++) {
                if (connectors[i] instanceof Lifecycle)
                    ((Lifecycle) connectors[i]).stop();
            }
        }

        // Stop our defined Container second
        if (container != null) {
            synchronized (container) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).stop();
                }
            }
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

  }

 

 

例子

public final class Bootstrap {
	public static void main(String[] args) {
		System.setProperty("catalina.base", System.getProperty("user.dir"));
		Connector connector = new HttpConnector();
		Wrapper wrapper1 = new StandardWrapper();
		wrapper1.setName("Primitive");
		wrapper1.setServletClass("PrimitiveServlet");
		Wrapper wrapper2 = new StandardWrapper();
		wrapper2.setName("Modern"); 
		wrapper2.setServletClass("ModernServlet"); 
		Context context = new StandardContext();
		// StandardContext's start method adds a default mapper 
		context.setPath("/app1"); 
		context.setDocBase("app1"); 
		context.addChild(wrapper1); 
		context.addChild(wrapper2); 
		LifecycleListener listener = new SimpleContextConfig(); 
		((Lifecycle) context).addLifecycleListener(listener);
		Host host = new StandardHost(); 
		host.addChild(context);
		host.setName("localhost"); 
		host.setAppBase("webapps"); 
		Loader loader = new WebappLoader();
		context.setLoader(loader);
		// context.addServletMapping(pattern, name); 
		context.addServletMapping("/Primitive", "Primitive"); 
		context.addServletMapping("/Modern", "Modern"); 
		Engine engine = new StandardEngine(); 
		engine.addChild(host); 
		engine.setDefaultHost("localhost");
		Service service = new StandardService(); 
		service.setName("Stand-alone Service");
		Server server = new StandardServer(); 
		server.addService(service);
		service.addConnector(connector);
		service.setContainer(engine);
		if (server instanceof Lifecycle) {
			try { 
				server.initialize(); 
				((Lifecycle) server).start();
				server.await();
				// the program waits until the await method returns,
				// i.e. until a shutdown command is received. 
			}
			catch (LifecycleException e) {
				e.printStackTrace(System.out);
			}
		}

		if (server instanceof Lifecycle) { 
			try { 
				((Lifecycle) server).stop(); 
			} catch (LifecycleException e) { 
				e.printStackTrace(System.out);
			}
		}
	{
}

 

 

Bootstrap主方法创建了一个连接器、两个包装器、一个上下文、一个主机以及一个引擎。
然后将包装器添加到上下文,将上下文添加到主机,主机添加到引擎。它并没有将连接器和引擎相关联,
而是创建了一个一个服务对象,设置它的名字,创建一个服务器对象,并给该服务器添加服务。
然后,主方法将连接器和引擎添加到服务上。
这样讲连接器添加到服务上,连接器在服务上跟容器相关联。
然后主方法调用服务器的initialize和start方法。初始化连接器并启动它以及容器。

Stopper类
Stopper类提供了一种优雅的方式来关闭Catalina服务器。它还保证了所有生命周期组件的stop方法会被调用

public class Stopper {
	public static void main(String[] args) {
		// the following code is taken from the Stop method of 
		// the org.apache.catalina.startup.Catalina class 
		int port = 8005;
		try { 
			Socket socket = new Socket("127.0.0.1", port); 
			OutputStream stream = socket.getOutputStream(); 
			String shutdown = "SHUTDOWN";
			for (int i = 0; i < shutdown.length(); i++)
				stream.write(shutdown.charAt(i));
			stream.flush();
			stream.close();
			socket.close();
			System.out.println("The server was successfully shut down."); 
		} catch (IOException e) {
			System.out.println("Error. The server has not been started."); 
		}
	}
}

 

分享到:
评论

相关推荐

    第19章 Tomcat服务器和Servlet.pdf

    第19章 Tomcat服务器和Servlet.pdf

    Tomcat服务器的安装、配置及修改目录.doc

    HYPERLINK"http://www.blogjava.net/beansoft/archive/2007/07/19/131286.html"Tomcat服务器配置、运行、更改目录的整理一、配置Tomcat服务器1)下载并安装对应操作系统上的JDK5或者6HYPERLINK.../opt/jdk15或

    Web服务器性能测试研究

    目 录 摘 要 I Abstract III 第一章 绪论 1 ...4.2.3 Tomcat服务器测试jsp网站页面 50 4.3 测试结果分析 51 4.4 本章小结 55 第五章 总结与展望 57 5.1 结论 57 5.2 进一步工作 57 致 谢 59 参考文献 61

    在Tomcat服务器下使用连接池连接Oracle数据库

    下面介绍在Tomcat服务器下使用连接池来连接数据库的操作 一:修改web.xml文件: 代码如下: &lt;?xml version=”1.0″ encoding=”UTF-8″?&gt; &lt;web-app xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance...

    《深入剖析Tomcat(中文版+英文版)》.rar

    《深入剖析Tomcat(中文版+英文版)》.rar ...第14章 服务器组件和服务组件 第15章 digester库 第16章 关闭钩子 第17章 启动tomcat 第18章 部署器 第19章 manager应用程序的servlet类 第20章 基于jmx的管理

    Tomcat汤姆猫

    Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制...

    基于java+tomcat+apache+sqlserver的大学生求职就业毕业设计源码

    (2)启动tomcat,在开始菜单中选择“所有程序”-----“apache tomcat 6.0”-----“monitor tomcat”,然后在屏幕右下角,右击tomcat服务器图标,选择“start service”,这样tomcat服务器就启动了。打开IE浏览器,...

    SSM实现跨服务器上传图片,并用Ajax实现图片回显,以及商品的的修改、查询和删除功能

    项目ssmImage19部署在Tomcat7.0上,作为图片服务器,端口号为8003。 2.访问地址是http://localhost/springmvc19_day02_01/items/list.do 3.数据库中保存商品图片的相对路径,以及商品的基本信息。 4.在eclipse环境下...

    腾讯云安全中心监测到  Apache Tomcat 修复了2个严重级别的漏洞,

    19 日,腾讯云安全中心监测到 Apache Tomcat 修复了2个严重级别的漏洞, 分别为: 信息泄露漏洞(CVE-2017-12616)、远程代码执行漏洞(CVE-2017-12615),在某些场景下,攻击者将分别能通过这两个漏洞,获取用户...

    实战Nginx:取代Apache的高性能Web服务器 第一章

    5.1 Nginx与JSP(Tomcat)在Linux上的安装、配置 5.2 Nginx与ASP.NET(Mono+FastCGI)在Linux上的安装、配置 5.3 Nginx与Perl(FastCGI)在Linux上的安装、配置 第6章 Nginx HTTP负载均衡和反向代理的配置与优化 6.1...

    TR069-OPENACS服务器搭建.doc

    TR069 Openacs服务器搭建 目录 一、安装JDK 3 二、安装MySQL数据库及驱动 5 三、JBOSS服务器 13 四、在ANT下编译ACS源码 16 五、在JBOSS中部署编译后的openacs项目 19 六、OPENACS操作简要手册 22 1 、CPE的设置 22 ...

    Linux下Tomcat重新启动

    在Linux系统下,重启Tomcat使用命令操作的!  首先,进入Tomcat下的bin目录  cd /usr/local/tomcat/bin... root 1971 1 0 Apr19 ? 00:00:04 /opt/jdk1.6.0_37/bin/java -Djava.util.logging.config.file=/opt/t

    Nginx高性能WEB服务器视频.zip

    目录网盘文件永久链接 1 Nginx入门简介.ts 2 Nginx工作原理及安装配置.ts 3 Nginx常用命令管理及升级.ts ...19 构建企业级Nginx+Keepalived集群架构.ts 20 企业Nginx+Keepalived双主架构案例实战.ts ..........

    Nginx高性能WEB服务器视频.rar

    1 Nginx入门简介.rar 网盘文件永久链接 2 Nginx工作原理及安装配置.rar 3 Nginx常用命令管理及升级.rar ...19构建企业级Nginx+Keepalived集群架构.rar 20企业Nginx-+Keepalived双主架构案例实战.rar

    java web 大学生求职就业网 (毕设课设+源码+数据库+说明文档)

    (2)启动tomcat,在开始菜单中选择“所有程序”-----“apache tomcat 6.0”-----“monitor tomcat”,然后在屏幕右下角,右击tomcat服务器图标,选择“start service”,这样tomcat服务器就启动了。打开IE浏览器,...

    实战Nginx.取代Apache的高性能Web服务器

    5.1 Nginx与JSP(Tomcat)在Linux上的安装、配置 5.2 Nginx与ASP.NET(Mono+FastCGI)在Linux上的安装、配置 5.3 Nginx与Perl(FastCGI)在Linux上的安装、配置 第6章 Nginx HTTP负载均衡和反向代理的配置与优化 ...

    项目源码java大学生求职就业网(web端)

    (2)启动tomcat,在开始菜单中选择“所有程序”-----“apache tomcat 6.0”-----“monitor tomcat”,然后在屏幕右下角,右击tomcat服务器图标,选择“start service”,这样tomcat服务器就启动了。打开IE浏览器,...

    基于JAVA的购物网站(毕业论文)

    2.8.4 Tomcat服务器的安装和配置 17 小结 18 第三章 系统需求分析和总体设计 19 3.1 系统功能需求 19 3.2 系统角色及其功能分析 19 3.2.1 系统的3个角色: 20 3.2.2 系统角色的功能 20 3.3 总体设计思想概述 20 3.4...

    基于JAVA的在线考试系统(毕业论文)

    2.8.4 Tomcat服务器的安装和配置 12 小结 13 第三章 系统需求分析和总体设计 14 3.1 系统功能需求 14 3.2 系统角色及其功能分析 14 3.2.1 系统的2个角色: 14 3.2.2 系统角色的功能 14 3.3 总体设计思想概述 15 3.4 ...

    javaweb详细笔记,绝对详细(内含代码)

    Http协议和Tomcat服务器 36 JavaWeb核心之Servlet 41 HttpServletResponse 46 HttpServletRequest 51 会话技术Cookie&Session; 55 动态页面技术(JSP/EL/JSTL) 59 javaEE的开发模式 65 事务(JDBC) 67 Json数据...

Global site tag (gtag.js) - Google Analytics