第一节 Tomcat的配置
第一章 Web应用的演变
1.1 C/S模式和B/S模式
C/S:Client/Server或客户端/服务器模式 C/S的优点是能充分发挥客户端PC的处理能力 缺点是对用户的电脑配置要求较高,更新升级比较麻烦 常见的CS程序:QQ、微信、播放器等
B/S:Browser/Server或浏览器/服务器模式 优点是用户使用简单,只要有浏览器和网络即可 常见的程序:淘宝网、京东网等
第二章 Tomcat服务器搭建
2.1 Tomcat服务器介绍
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用[服务器],在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选,目前Tomcat最新版本为9.0。
2.2 Tomcat安装
Tomcat压缩版,安装特别方便,只需要右键解压即可!
Tomcat服务器的安装
-
官网下载(http://tomcat.apache.org/),Tomcat8.0|8.5解压缩版本
-
解压到一个没有特殊符号的目录中(一般纯英文即可)
-
进入到解压的目录下找到bin\startup.bat双击启动即可
注意:不建议将服务器软件放在磁盘层次很多的文件夹中!
不建议放在中文路径下!
tomcat安装需要配置JAVA_HOME环境变量
第一次启动服务器建议使用命名行打开,因为可以提示错误信息!
2.3 Tomcat目录的介绍
1、bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个exe文件:tomcat9.exe、tomcat9w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要JDK的配置,shutdawn.bat用来停止Tomcat; 2、conf:这是一个非常非常重要的目录,这个目录下有四个最为重要的文件: server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等; tomcatusers.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面了; web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗口才对。MIME就是用来说明文档的内容是什么类型的! context.xml:对所有应用的统一配置,通常我们不会去配置它。 3、lib:Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的Jar包放到这个目录下; 4、logs:这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。 5、temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除! 6、webapps:存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。 7、work:运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。 8、LICENSE:许可证。 9、NOTICE:说明文件。
2.4 启动tomcat服务器
tomcat安装文件/bin/startup.bat 启动程序
测试
打开浏览器!输入 http://localhost:8080
Tomcat其他配置:
1 修改端口号
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
2 如何把资源放在tomcat中访问
(1)再webapps中建立文件夹:aaa (2)把网页hello.html复制到aaa文件夹中, (3)访问http://localhost:8080/aaa/hello.html
第二节 Servlet的使用
1.1 什么是Servlet
Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
1.2 Servlet入门
-
在src创建package
-
选中刚刚创建的包,右键-->New-->Servlet
-
发布右键-->Run As-->Run On Server
-
浏览器输入网址访问:http://localhost:8080/项目名称/HelloServlet
1.3 常见错误解决方法
(1)HTTP Status 404 资源找不到 解决方法:查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件 如果有,重新启动Tomcat 如果没有,在Eclipse中选择Project-->clean让Eclipse清空缓存并重新构建项目,再次运行 idea中,把out目录的内容删除,然后重新运行。 (2)serlvet地址配置重复 (3)serlvet地址配置错误,比如没有写/ Invalid <url-pattern>
1.4 HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。
1.4.2 Http协议的通信
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1、 建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更高层协议的连接。因此,首先要建立TCP连接,一般TCP连接的端口号是80 2、 浏览器向Web服务器发送请求命令 一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令 例如:GET /sample/hello.html HTTP/1.1 3、 浏览器发送请求头信息 浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。 4、 Web服务器应答 客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK 应答的第一部分是协议的版本号和应答状态码 5、 Web服务器发送应答头信息 正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。 6、 Web服务器向浏览器发送数据 Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据 7、 Web服务器关闭TCP连接 一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码 Connection:keep-alive TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽
1.4.3 请求和响应数据格式
HTTP请求报文 :
当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),HTTP请求信息由4部分组成:
1 请求行 请求方法/地址 URI协议/版本
2 请求头(Request Header)
3 空行
4 请求正文
HTTP响应报文 :
HTTP应答与HTTP请求相似,HTTP响应也由4个部分构成,分别是:
1、状态行
2、响应头(Response Header)
3、空行
4、响应正文
2.1 Servlet核心接口和类
Servlet接口
在ServletAPI中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。 该接口包括以下五个方法: init(ServletConfig config) ServletConfig getServletConfig() service(ServletRequest req,ServletResponse res) String getServletInfo() destroy( ) 处理方式: (1)第一次访问Servlet时,服务器会创建Servlet对象,并调用init方法,再调用service方法 (2)第二次再访问时,Servlet对象已经存在,不再创建,执行service方法 (3)当服务器停止,会释放Servlet,调用destroy方法。
2.2 Servlet的两种创建方式
Servlet的第一种创建方式:继承HttpServlet 。
Servlet创建的第二种方式:实现接口Servlet 。
2.3 Servlet的两种配置方式
第一种注解式配置 Servlet3.0及以后 :
使用注解方式:
注解类 WebServlet
name:serlvet名字 (可选)
value: 配置url路径
urlPatterns:配置url路径 ,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建的时机, 如果是0或者正数 启动程序时创建,如果是负数,则访问时创建。
数子越小优先级越高。
initParams:配置Servlet的初始化参数
第二种web.xml配置 Servlet所有版本都支持:
2.4 Servlet生命周期
2.4.1 生命周期的四个阶段
阶段一、实例化(调用构造方法) 实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建 <load-on-startup>1</load-on-startup>
阶段二、初始化(init方法) Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过<init-param>节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。 一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。 注:init方法只被执行一次
阶段三、就绪/服务 Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现 HttpServlet将service方法拆分了。doGet和doPost
阶段四、销毁 Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预
2.9 Servlet线程安全问题
2.9.1 线程安全问题
因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。
2.9.2 如何保证线程安全
1、synchronized 将存在线程安全问题的代码放到同步代码块中 2、实现SingleThreadModel接口 servlet实现SingleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。 3、尽可能只使用局部变量
案例:实现用户注册功能
注册页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
<style type="text/css">
div{
width: 300px;
height: 200px;
background-color: #00FFFF;
position: relative;
margin: 0 auto;
}
</style>
</head>
<body>
<div>
<form action="/0830web1/registservlet" method="post" enctype="application/x-www-form-urlencoded">
<table align="center">
<tr>
<td>用户名:</td>
<td>
<input type="text" name="username" placeholder="请输入用户名"/>
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="password" placeholder="请输入密码"/>
</td>
</tr>
<tr>
<td>确认密码:</td>
<td>
<input type="password" name="password1" placeholder="请确认密码"/>
</td>
</tr>
<tr>
<td>邮箱:</td>
<td>
<input type="email" name="email" />
</td>
</tr>
<tr>
<td>性别:</td>
<td>
<input type="radio" name="sex" value="男" checked="checked" />男
<input type="radio" name="sex" value="女" />女
</td>
</tr>
<tr align="center">
<td colspan="2">
<input type="submit" value="提交" />
<input type="reset" value="重置" />
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
Servlet代码:
package com.vince.servlet;
import com.vince.dao.UserDao;
import com.vince.dao.impl.UserDaoimpl;
import com.vince.domain.User;
import com.vince.utiles.ActiveCodeUtiles;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "RegistServlet" ,value="/registservlet")
public class RegistServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取表单数据
String username = request.getParameter("username");
String password = request.getParameter("password");
String password1 = request.getParameter("password1");
String email = request.getParameter("email");
String sex = request.getParameter("sex");
if (username==null||username.trim().length()==0){
response.getWriter().write("用户名不能为空");
return;
}
if (password==null||password.trim().length()==0){
response.getWriter().write("密码不能为空");
return;
}
if (!password.equals(password1)){
response.getWriter().write("两次输入密码不一致");
return;
}
//访问数据库
User user=new User(null, username, password, email, sex, 0, 1, ActiveCodeUtiles.createActiveCode());
UserDao userDao=new UserDaoimpl();
try {
userDao.add(user);
response.getWriter().write("恭喜你注册成功~");
//转发
request.getRequestDispatcher("/login.html").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
response.getWriter().write("注册失败!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}