第2阶段 第11讲 Tomcat服务器与Servlet入门

Tomcat简介

如何实现动态网页技术,HTML包括JavaScript都是静态网页技术,就是不能与数据库交互,不是实现登录、注册、提交购物车、搜索。动态是根据不同的客户端、不同的时间、不同的偏好可以提供不同的内容;淘宝网千人千面,可以有针对性的推荐商品,提高成交率。

动态网页的实现:

  • JAVA技术: Servlet JSP 主流 淘宝、京东、当当网、美团、滴滴主流的互联网公司都是使用java平台
  • .NET技术: C# 一般网页的扩展名 .asp或者是 .aspx
  • PHP技术: 开源的、免费的;淘宝网最早是PHP修改的,论坛、政府网站、办公系统
  • CGI技术: 通用网关技术, 腾讯的邮件系统你注意一下扩展名

这些动态网页技术都要运行在服务器上,服务器接收用户的请求,找到请求的资源,再返回给客户端浏览器。我们网络上访问的网站taobao,jd 都是运行在服务器上的;主流服务器JAVA是Tomcat服务器,asp和aspx技术运行的服务器是IIS,在windows系统都自带该服务器;PHP apache服务器。

Tomcat是Apache开源社区维护的一个java的web服务器,并且得到Sun公司的大力支持,Oracle公司。

Tomcat官网

Tomcat官网

下载的Tomcat8.xx版本: 下载地址

  • tar.gz linux环境使用的, 可以直接解压 : tar -zxvf apache-tomcat-8.5.55.tar.gz
  • zip版本: windows系统,直接解压
  • exe版本: 直接安装的 apache-tomcat-8.5.55.exe

Tomcat目录结构

下载对应的版本之后,直接解压即可,

  • bin 主要是Tomcat启动和停止的脚本,以sh结尾的脚本是linux和mac使用,windows系统使用.bat脚本,startup,shutdow
  • conf: configuration 配置信息,server.xml文件配置端口号、线程池;tomcat-users.xml管理员账户信息
  • lib: library 库, jsp-api.jar servlet-api.jar tomcat-dbcp.jar连接池,所有的带i18n是国际化的语言信息,websocket是开发网页消息的发送和接收,可以开发一个网页版的聊天工具。特别网站的客服会用到。
  • logs: log4j.jar 记录服务器访问的日志信息,当系统出现问题通过日志查询
  • temp: 存储的临时文件,譬如: 文件上传先存到临时文件夹,上传结束再放大具体位置
  • webapps: web applications web应用,我们开发的web项目部署到该文件夹
  • work: 工作目录,存储jsp转换成servlet的java文件,包括编译后的字节码文件

启动、停止服务器

启动: startup.sh startup.bat

停止:shutdown.sh shutdown.bat, Ctrl + C 也可以停止DOS窗口

前台启动: 一直占用Dos窗口 Ctrl + C 结束运行

后台启动: Tomcat 以后台进程的方式运行,不占用Dos窗口

mac体系:

~/Downloads/apache-tomcat-8.5.51/bin » ./startup.sh            
Using CATALINA_BASE:   /Users/kongfanyu/Downloads/apache-tomcat-8.5.51
Using CATALINA_HOME:   /Users/kongfanyu/Downloads/apache-tomcat-8.5.51
Using CATALINA_TMPDIR: /Users/kongfanyu/Downloads/apache-tomcat-8.5.51/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home
Using CLASSPATH:       /Users/kongfanyu/Downloads/apache-tomcat-8.5.51/bin/bootstrap.jar:/Users/kongfanyu/Downloads/apache-tomcat-8.5.51/bin/tomcat-juli.jar
Tomcat started.
------------------------------------------------------------
~/Downloads/apache-tomcat-8.5.51/bin »                       

Tomcat服务器默认对外提供服务的端口: 8080; 访问地址:

本机: http://localhost:8080 http://127.0.0.1:8080 http://192.168.11.163:8080(局域网)

云服务器: http://119.34.5.89:8080
在这里插入图片描述
Server Status 查看服务器状态,此时提示登录;
在这里插入图片描述
修改tomcat-users.xml文件:

<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
  <role rolename="tomcat"/>
  <role rolename="manager-gui"/>
  <user username="tomcat" password="123456" roles="manager-gui"/>
  <user username="both" password="123456" roles="tomcat,role1"/>
  <user username="role1" password="123456" roles="role1"/>

</tomcat-users>

查看服务器的状态:
在这里插入图片描述
项目的启动和停止:
在这里插入图片描述

eclipse创建web项目

Web项目简介:

  • src 文件夹: source code 源代码文件夹: 实体类,JdbcUtil,Dao接口,Dao实现类
  • WebContent web内容
    • META-INF 元信息 information
    • WEB-INF web 信息
      • lib 各种jar包存储的位置
      • web.xml web项目的核心配置文件
    • HTML页面写在WebContent目录下面,包括images、js、css
  • JRE System Library java运行环境 系统库
  • Apache Tomcat v8.5 服务器运行jar包

部署web项目

部署项目到Tomcat的webapps目录下, 需要做的修改:
在这里插入图片描述

上图的位置是wtpwebapps,还不是tomcat的默认的webapps目录, 做如下修改:
在这里插入图片描述

Servlet技术入门

Servlet概念

Servlet是一个java类,部署在服务器端的程序,用来接收用户请求,并做出响应的一个web组件。

Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

如何编写Servlet

编写Servlet的规范:

  • 继承HttpServlet
  • 重写doGet方法和doPost方法
package com.ujiuye.web;

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 HelloServlet extends HttpServlet {
	private static final long serialVersionUID = -6600072285720004089L;
	
	/**
	 * 处理Get请求
	 * request表示的是请求对象
	 * response表示的响应对象
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out= response.getWriter();
		out.println("<h1>一个人幸运的前提是他有改变自己的能力。</h1>");
		out.close();
	}
	/**
	 * 处理Post请求
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

配置Servlet

注册Servlet, 注册该web应用的配置文件中; 相当于新入职一个员工,到人事注册,提交身份证信息等等。

配置的位置: web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>chapter11</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <!--配置Servlet的实现类信息  -->
  <servlet>
  	<servlet-name>helloServlet</servlet-name>
  	<servlet-class>com.ujiuye.web.HelloServlet</servlet-class>
  </servlet>
  <!--配置映射信息: 访问的路径  -->
  <servlet-mapping>
  		<servlet-name>helloServlet</servlet-name>
  		<url-pattern>/hello</url-pattern>
  </servlet-mapping>
</web-app>

配置完成,要重启Tomcat服务器的。

访问Servlet

http://localhost:8080/chapter11/hello
在这里插入图片描述

url的配置:

/* 匹配任何字符: http://localhost:8080/chapter11/asdasd

/hello/abc : http://localhost:8080/chapter11/hello/abc

*.action 类似 *.do http://localhost:8080/chapter11/xxx.action http://localhost:8080/chapter11/xxx.do

Tomcat执行Servlet的过程:
在这里插入图片描述

Servlet生命周期

Servlet生命周期: 一个Servlet组件从被Tomcat加载、产生对象、服务(处理请求)、销毁的过程。

package com.ujiuye.web;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LifeCycleServlet extends HttpServlet{
	
	static {
		System.out.println("LifeCycleServlet被加载到服务器了....");
	}
	
	public LifeCycleServlet() {
		System.out.println("LifeCycleServlet构造方法被执行了...创建对象");
	}
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("LifeCycleServlet初始化方法被调用....");
	}
	

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("LifeCycleServlet执行服务的方法.....doGet....");
		resp.getWriter().println("<h1>欢迎访问我的web</h1>");
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
	
	@Override
	public void destroy() {
		System.out.println("LifeCycleServlet销毁方法执行.....");
	}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>chapter11</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <!--配置Servlet的实现类信息  -->
  <servlet>
  	<servlet-name>helloServlet</servlet-name>
  	<servlet-class>com.ujiuye.web.HelloServlet</servlet-class>
  </servlet>
  <servlet>
  	<servlet-name>life</servlet-name>
  	<servlet-class>com.ujiuye.web.LifeCycleServlet</servlet-class>
  </servlet>
  
  <!--配置映射信息: 访问的路径  -->
  <servlet-mapping>
  		<servlet-name>helloServlet</servlet-name>
  		<url-pattern>*.action</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>
  	<servlet-name>life</servlet-name>
  	<url-pattern>/life</url-pattern>
  </servlet-mapping>
</web-app>

执行过程:

信息: Server startup in 646 ms
五月 30, 2020 3:52:36 下午 org.apache.tomcat.util.http.parser.Cookie logInvalidHeader
信息: A cookie header was received [1585184331] that contained an invalid cookie. That cookie will be ignored.
 Note: further occurrences of this error will be logged at DEBUG level.
LifeCycleServlet被加载到服务器了....
LifeCycleServlet构造方法被执行了...创建对象
LifeCycleServlet初始化方法被调用....
LifeCycleServlet执行服务的方法.....doGet....
LifeCycleServlet执行服务的方法.....doGet....
LifeCycleServlet执行服务的方法.....doGet....
LifeCycleServlet执行服务的方法.....doGet....
五月 30, 2020 3:53:54 下午 org.apache.catalina.core.StandardServer await
信息: A valid shutdown command was received via the shutdown port. Stopping the Server instance.
五月 30, 2020 3:53:54 下午 org.apache.coyote.AbstractProtocol pause
信息: Pausing ProtocolHandler ["http-nio-8080"]
五月 30, 2020 3:53:54 下午 org.apache.catalina.core.StandardService stopInternal
信息: 正在停止服务[Catalina]
LifeCycleServlet销毁方法执行.....
五月 30, 2020 3:53:54 下午 org.apache.catalina.core.ApplicationContext log
信息: SessionListener: contextDestroyed()
五月 30, 2020 3:53:54 下午 org.apache.catalina.core.ApplicationContext log
信息: ContextListener: contextDestroyed()
五月 30, 2020 3:53:54 下午 org.apache.coyote.AbstractProtocol stop
信息: 正在停止ProtocolHandler ["http-nio-8080"]
五月 30, 2020 3:53:54 下午 org.apache.coyote.AbstractProtocol destroy
信息: 正在摧毁协议处理器 ["http-nio-8080"]

从执行的结果可以看出; Servlet是单实例、多线程;不是线程安全的对象。

总结:

  • 加载
  • 实例化
  • 初始化
  • 服务
  • 销毁

加载是由Tocmat实现的的类加载器完成的,类似我们在学习java基础的时候JVM的类加载器。
在这里插入图片描述

Servlet处理登录请求

登录页面: login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录系统</title>
<style type="text/css">
#username,#pwd{
	border:1px solid #000;
	width: 150px;
}
</style>
<script type="text/javascript">
function subForm(){
	var name = document.getElementById("username").value;
	if(name == "" || name.length==0){
		alert("请输入用户账号.");
		return false;
	}
	return true;
}

</script>
</head>
<body>


<h1>用户登录</h1>

<form action="login" method="post" onsubmit="return subForm()">
 用户账号: <input type="text" name="username" id="username"/><br/>
用户密码:  <input type="password" name="password" id="pwd"/><br/>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
</form>

</body>
</html>

登录处理的Servlet: LoginServlet.java

package com.ujiuye.web;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//获取登录的用户名称
		String username = request.getParameter("username");
		//获取登录的用户密码
		String password  = request.getParameter("password");
		//假设正确的用户名和密码 admin 123456
		if( "admin".equals(username) && "123456".equals(password) ) {
			response.sendRedirect("a.jsp");//重定向的一个页面
		}else {
			response.sendRedirect("login.html");
		}
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

配置Servlet: 注解配置

@WebServlet("/login")

get请求和post请求的参数传递:
在这里插入图片描述
在这里插入图片描述
Servlet处理过程:
在这里插入图片描述

GET请求和POST请求区别

项目GETPOST
后退按钮/刷新无害数据会被重复提交(浏览器应该告诉用户数据会被重新提交)
书签可收藏不可收藏
缓存可缓存不可缓存
编码application/x-www-form-urlencodedapplication/x-www-form-urlencoded或multipart/form-data为二级制数据使用多重编码
历史参数保留在浏览器历史中不会保存
数据长度发送数据GET方法向URL添加数据: 最大2048个字符无限制
数据类型只允许ASCII字符无限制,也允许二进制数据
安全性差,数据是URL的一部分,可以看到更安全
可见性数据在URL中对所有人可见的数据不会显示在URL中

Servlet源码分析

查看父类HTTPServlet源码:

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod(); //获取请求提交的方法 get或post或delete

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

可以看出父类根据请求提交的方法转而调用子类的相关实现方法。

面试题

servlet生命周期

见上面讲义

Servlet是单例吗?

不一定是,在一个ServeltName情况下是的。在多个ServletName匹配到一个Servlet类时,该Servlet不是单例。

Servlet是线程安全的吗?

不是,一个servlet实现类只会有一个实例对象,多个线程是可能会访问同一个servlet实例对象的,线程安全问题都是由全局变量及静态变量引起的。解决线程安全的方法如下:

1、实现 SingleThreadModel 接口

Servlet2.4 已经提出不提倡使用。实现此接口,Servlet容器为每个新的请求创建一个单独的Servlet实例。这会有严重性能问题。

2、同步锁

使用synchronized关键字,虽然可以保证只有一个线程可以访问被保护区段,已达到保证线程安全。但是系统性能及并发量大大降低。不可取~

3、避免使用实例变量,即Servlet中全局变量。使用局部变量 (推荐)

方法中的局部变量分配在栈空间,每个线程有私有的栈空间。因此访问是线程安全的。

参考资料

Java Web(一) Servlet详解

图解HTTP协议

深入浅出JavaWeb

JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值