Tomcat 与 Servelet概述
软件结构发展史
- 桌面应用时代
- 联机时代(Client-Server 模式)
- 互联网时代(Browser-Server 模式)
桌面应用时代
桌面应用俗称单机应用,软件以及所有数据都保存在电脑本地硬盘中;优点为易于使用,结构简单;缺点为数据难以共享,安全性差,更新不及时
联机时代
C/S架构,指的是客户端和服务器架构;数据保存在服务器上,不需要保存在本机电脑;优点是数据方便共享并且安全性高;缺点是必须要安装客户端,升级与维护比较困难。C/S结构的典型应用例如:QQ。
互联网时代
B/S架构,即:浏览器和服务器的架构模式。通过浏览器加载服务端上面的内容,以网页的形式显示给用户,B/S架构的优点为:开发简单,无需安装客户端,数据易于共享;缺点为:相较于C/S模式,B/S模式的执行速度与用户体验较弱。B/S的典型应用有很多,浏览器能浏览到的各个网站都是B/S模式应用。
B/S模式执行流程
关于B/S模式执行流程,可以看我的文章 浅谈HTTP
请求与响应
客户端即是访问者,服务器即是被访问的对象。
或者可以简单地理解为,一个是浏览网页的,一个是提供网页服务给浏览者浏览的。
那么客户端从输入URL 到 页面的呈现 到底发生了什么呢?
这个问题在本文不会给出详细的解答。但是我们可以知道客户端和服务器之间一定存在着某种"沟通"。
这种沟通就是请求(Request)和 响应(Response)
在我们输入了URL之后,浏览器给服务器发送了一个request,web服务器接收到request后进行处理,然后返回给浏览器一个response,浏览器通过解析response中的HTML,我们就看到网页了。关于请求与相应的具体部分,依然可以参照我的文章 浅谈HTTP 。
Servlet
- Servlet是什么
Servlet是服务器程序,主要功能是用于生成动态Web内容。它担当Web浏览器或其他HTTP客户程序发出请求,与HTTP服务器上的数据库或者应用程序之间的中间层。
Apache Tomcat
- Tomcat是什么
Tomcat 是 Apache软件基金会旗下一款免费的开源的Servlet容器,由Apache基金会,Sun和一些其他公司及个人共同开发完成。Tomcat是一个服务器,如果你要将自己的电脑当作一个服务器使用,就需要开启Tomcat。 - Tomcat与Servlet的关系
Tomcat是J2EE Web(Servlet与JSP)标准的实现,Servlet是建立动态网站的程序代码,可以说是在Tomcat上运行的程序,简单说:Tomcat是运行平台,Servlet是运行程序
安装 Apache Tomcat
下载链接
进入官网,下载自己电脑系统匹配的版本即可,要确保安装了匹配的jdk,下载完毕后,进入下载目录的bin目录下,运行startup命令,如果出现
The CATALINA_HOME environment variable is not defined correctly
这样的报错信息,说明没有设置好JAVA_HOME
如果出现
command is not defined
那么就要看你的startup命令是否是在bin目录下运行的,在没有设置好CATALINA_HOME之前,startup命令只能在bin目录下运行。
命令运行成功后,会弹出一个黑色窗口,最后显示:
在浏览器上输入http://localhost:8080/
会显示Apache Tomcat的页面。
如果需要关闭服务器,只需要敲入CTRL + C
即可退出
IntelliJ IDEA 整合Tomcat
关于怎样使用idea整合Tomcat的教程在网上一大堆
例如:
Kudō Shin-ichi 这位同学的文章 IntelliJ IDEA整合Tomcat服务器
这里就不再赘述。
Servlet创建与生命周期
第一个Servlet程序
在idea整合好Tomcat,创建一个web项目后,开始写第一个Servlet程序:
FirstServlet 类
package servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class FirstServlet extends HttpServlet {
// idea 快捷键 快速生成 ctrl + O
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String html = "<h1 style='color:red'>hi, " + name + "</h1><hr/>";
PrintWriter out = resp.getWriter();
out.println(html);
}
}
在web.xml里的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<!--servlet的别名 -->
<servlet-name>firstServlet</servlet-name>
<servlet-class>servlet.FirstServlet</servlet-class>
</servlet>
<!--servlet的映射-->
<servlet-mapping>
<servlet-name>firstServlet</servlet-name>
<url-pattern>/hi</url-pattern>
</servlet-mapping>
</web-app>
运行程序,输入URL:http://localhost:8080/first_servlet/hi?name=dobbykim
页面显示如下:
该程序的执行流程如下:
当我们输入url:
http://localhost:8080/first_servlet/hi?name=dobbykim
的时候,浏览器向Tomcat服务器发起了"请求"。在Servlet程序内部,首先会在配置文件web.xml中去找servlet-mapping,找到了对应的跳转地址,通过servlet-name找到了对应的servlet-class。通过servlet-class,服务器找到了FirstServlet类;在FirstServlet类中,一个请求获取到的参数,也就是本示例中的name=dobbykim会被写好的页面一同由PrintWriter对象响应回浏览器,返还给客户,呈现出页面。
Java Web标准工程结构
组织结构 | 描述 |
---|---|
tocat 安装目录/webapps/ | Tomcat应用根目录 |
/web应用目录/ | Java Web应用目录 |
/web应用目录/index.html or .jsp | 默认首页 |
/WEB-INF | WEB应用的安全目录,用于存放配置文件 |
/WEB-INF/web.xml | web.xml是"部署描述符文件",是该web项目核心配置文件 |
/WEB-INF/classes | 存放编译后的classes文件 |
/WEB-INF/lib | 用于存放web应用依赖的jar文件 |
/META-INF/MANIFEST.MF | 包含Web应用的版本等信息 |
Servlet开发与基本配置
Servlet开发步骤
- 创建Servlet类,继承HttpServlet
- 重写service方法,编写程序代码
- 配置web.xml,绑定URL
示例:使用Servlet计算n以内自然数的累加和,并输出,参数n通过url地址进行传递,示例程序如下:
ComputerServlet类
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ComputerServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String nString = req.getParameter("n");
int n = Integer.parseInt(nString);
int sum = ((n + 1) * n) / 2;
String html = "<p>" + sum + "</p>";
PrintWriter out = resp.getWriter();
out.println(html);
}
}
web.xml中的配置如下:
<servlet>
<servlet-name>ComputerServlet</servlet-name>
<servlet-class>ComputerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ComputerServlet</servlet-name>
<url-pattern>/ComputerServlet</url-pattern>
</servlet-mapping>
通过在URL中传参即可动态改变网页中显示的内容:
请求参数的发送与接收
请求参数
- 请求参数是指浏览器通过请求向Tomcat提交的数据
- 请求参数通常是用户输入的数据,待Servlet进行处理
- 请求参数的格式 :参数名1=值1&参数名2=值2&...参数名n=值n
Servlet接收请求参数
- request.getParameter() 接收单个参数
- request.getParameterValues() 接收多个同名参数
示例如下:
在web目录下,student.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>学员信息登记表</title>
</head>
<body>
<h1>学员信息登记表</h1>
<form action="/FirstServlet/sample" method="get" >
姓名:<input name="name"/>
<br/>
电话:<input name="mobile"/>
<br/>
性别:
<select name="sex" style="width:100px;padding:5px;">
<option value="male" >男</option>
<option value="female">女</option>
</select>
<br/>
特长:
<input type="checkbox" name="spec" value="English"/>英语
<input type="checkbox" name="spec" value="Program"/>编程
<input type="checkbox" name="spec" value="Speech"/>演讲
<input type="checkbox" name="spec" value="Swimming"/>游泳
<br/>
<input type="submit" value="提交">
<br/>
</form>
</body>
</html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>SampleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sample</servlet-name>
<url-pattern>/sample</url-pattern>
</servlet-mapping>
</web-app>
SampleServlet 类:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class SampleServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String mobile = req.getParameter("mobile");
String sex = req.getParameter("sex");
String[] specs = req.getParameterValues("spec");
PrintWriter out = resp.getWriter();
out.println("<h1>name:" + name + "</h1>");
out.println("<h1>mobile:" + mobile + "</h1>");
out.println("<h1>sex:" + sex + "</h1>");
for (int i = 0; i < specs.length; i++) {
out.println("<h2>spec:" + specs[i] + "</h2>");
}
}
}
表单填写如下:
submit后,跳转页面如下:
Get与Post请求
- get方式是将数据通过在URL附加数据显性向服务器发送数据
例如:http://localhost:8080/FirstServlet/sample?name=zhangsan
- post方式会将数据存放在请求体中隐性向服务器发送数据
url中不会显示参数:http://localhost:8080/FirstServlet/sample
请求体的内容:name=zhangsan
Get与Post处理方式
- 所有请求 service()方法
- Get请求 doGet()方法
- Post请求 doPost()方法
Get与Post应用场景
- Get常用于不包含敏感信息的查询功能
- Post用于安全性要求比较高的功能或者服务器的"写"操作
例如:用户登录,用户注册,更新公司账目等等
Get与Post示例程序:
RequestMethodServlet类:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RequestMethodServlet extends HttpServlet {
// 处理 get 请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
resp.getWriter().println("<h1 style='color:green'>" + name + "</h1>");
}
// 处理 post 请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
resp.getWriter().println("<h1 style='color:red'>" + name + "</h1>");
}
}
使用get方式提交表单时:
使用post方式提交表单:
并且可以看到提交的请求体中有用户的信息:
Servlet的生命周期
- 装载 : 解析web.xml
- 创建:构造函数
- 初始化:init()
- 提供服务 service()
- 销毁 destroy()
示例程序如下:
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class FirstServlet extends HttpServlet {
public FirstServlet() {
System.out.println("正在创建FirstServlet对象");
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("正在初始化FirstServlet对象");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String html = "<h1 style='color:red'>" + name + "</h1>";
PrintWriter out = resp.getWriter();
System.out.println("service提供服务");
out.println(html);
}
@Override
public void destroy() {
System.out.println("正在销毁FirstServlet对象");
}
}
输入URL:
可以看到输出发生了变化:
改变URL中的Parameter:
控制台输出为:
可以看到,并没有重新创建Servlet对象,而是一直由一个Servlet对象提供service服务;当我们重启Servlet时候,Servlet销毁:
使用注解配置Servlet
注解简化配置
- Servlet 3.x之后引入了注解
- 注解用于简化Web应用程序的配置过程
- Servlet核心注解: @WebServlet
示例程序如下:
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("/annotation")
public class AnnotationServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("I'am AnnotationServlet");
}
}
在Servlet类前面添加@WebServlet注解,括号里面是映射地址,这样就可以通过注解简化在web.xml里面的配置
启动时加载Servlet
- web.xml使用
<load-on-startup>
设置启动加载 - 推荐的使用范围
<load-on-startup>0~9999</load-on-startup>
;0的优先级最高 - 启动时加载在工作中常用于系统的预处理
对于启动时加载Servlet同样可以使用两种方式
- web.xml中配置
- 使用注解
示例程序:
Process1:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class Process1 extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("执行process1");
}
}
Process1在web.xml中配置:
<servlet>
<servlet-name>process1</servlet-name>
<servlet-class>Process1</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>process1</servlet-name>
<url-pattern>/process1</url-pattern>
</servlet-mapping>
Process2:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@WebServlet(urlPatterns = "/process2",loadOnStartup = 1)
public class Process2 extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("执行process2");
}
}
在控制台输出结果如下:
通过在web.xml中设置load-on-startup或者通过注解进行配置可以在启动时加载在工作中常用于系统的预处理,例如示例程序中,process1和process2是预处理需要执行的程序,我们可以在启动Tomcat时,加载Servlet类。
网友评论