Java EE day13学习总结
今天主要学习Tomcat和Servlet
思维导图:
一.Tomcat
我们一直说,自己的电脑也可以是一台服务器,那么也就意味我们的电脑也可以提供外部访问的能力,可以的,只不过我需要依靠一个服务器软件进行帮助。
1.WEB服务器:
(1)IIS:Windows电脑自带的,一般用于微软开发的系列软件或者服务会使用IIS(特别是微软提供Windows Server)
(2)Weblogic:这个是BEA公司公司开发的,支持了javaee的所有规范(接口)。不过这个几乎没人用,因为收费。
(3)Tomcat:是Apache公司开发的一个完全基于java的服务器软件,支持sevlet、jsp等相关规范(但是不支持ejb),开源且免费的玩意
(4)JBoss:是Radhat公司开发的一个中间件,支持所有的JAVAEE规范,软件免费 但是呢,服务收费,而且只支持Linux.
2.下载安装Tomcat:
官网地址:https://tomcat.apache.org/
因为Tomcat本身是一个基于java开发的程序,所以他是一个完全跨平台的软件;下载的时候不需要指定Windows、linux、mac os等平台分别下载,直接下载zip就可以了;下载后也不需要进行安装,直接解压即可,但是一定要保证你的JAVA_HOME相关的环境变量是设置正确的,因为tomcat强烈依赖于jre运行。
3.Tomcat的目录分析:
bin:存放脚本的目录,所有的启动(startup)、停止(shutdown)、监控等脚本都在这个目录当中
conf:是tomcat的核心配置目录(server.xml/web.xml)
lib:存放是tomcat运行的依赖的jar包(其实也包括servlet和jsp的实现)
logs:存放的是日志文件(tomcat的运行状态、异常状态的日志都是存在这个目录)
temp:存放的是临时文件
webapps:存放我们的web项目的位置
work:处理我们的class和jsp文件的
4.如何启动Tomcat
(1)所有的启动相关的操作全部是在bin目录
开启:
startup.bat(Windows)
startup.sh(Linux)
关闭:
shutdown.bat
shutdown.sh
(2)注意:
Tomcat的启动会默认占用一个8080的端口,在启动之前一定要先确保这个端口
不要被其他程序占用(一般被占用无非也就是同时开启了两个同端口的tomcat)
5.Tomcat的常见异常:
java.net.BindException: Address already in use (Bind failed):因为端口被占用
6.Tomcat的server.xml(Tomcat的核心配置)
端口号的修改:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
为何tomcat会默认的运行webapps的项目呢?
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
7.Tomcat的web.xml(项目的配置)
为什么不输入文件名就能直接方法index的文件?
welcome-file-list:默认加载指定的页面
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
8.为何能找到webapps的ROOT项目
(1)先加载mapping,决定运行那个servlet
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(2)找到servlet后,servlet决定执行和加载哪一些文件
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
9.Tomcat的手动部署方式:
(1)默认部署
其实所谓的默认部署就是将我们的web资源存放到webapps下面,在不修改 server.xml下面的Connector的配置的情况下,默认就是访问webapps。我们只需要将项目存在这个目录下面就可以进行访问,并且输入对应的项目名(目录名)就可以进行访问。
特点:
将我们的项目和tomcat进行了紧密的关联
(2)通过server.xml进行虚拟配置(新增一个指定路径)
在Host配置项里面新增一个Context的配置项
docBase:是存放你web资源的具体目录位置(绝对路径)
path:这个path不是真正的路径,只是一个虚拟路径 可以任意写
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/Users/toobug/Documents/HBuilderProjects/day03" path="/hello/"/>
</Host>
特点:
<1>可以自定义任何目录,就实现了tomcat和项目的完全分离
<2>但是需要频繁的去修改server.xml,一般不太建议 因为server.xml是核心配置项
能少动则少动。
(3)通过conf/Catalina/localhost/的目录进行配置
<1>在这个目录创建一个xml文件
<2>在这个文件里面编写代码
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="/Users/toobug/Documents/HBuilderProjects/day03" />
<3>这种方式不用去指定一个path的虚拟路径,xml的名字其实就是路径名
特点:
<1>可以自定义任何目录,就实现了tomcat和项目的完全分离
<2>无需修改server.xml 保证了业务的安全性
10.JAVAEE的项目结构
项目名称
|-- src (存放的是所有的java代码)
|-- web
|-- WEB-INF(这里的所有内容,用户是不能通过浏览器访问的,一般放配置文件)
|-- web.xml(当前项目的配置文件,servlet的配置、访问页配置、拦截器等等等)
|-- lib(当前项目的所需的一些jar包)
|-- classes(存放是其实就是java编译后的class文件,这个文件需要给项目运行)
|-- static(存放是一些静态资源文件,比如图片、css、js)
11.Web概述:
12.Tomcat生命周期:
Lifecycle接口统一管理Tomcat生命周期。一共做了4件事:
- 定义13个string类型常量,用于LifecycleEvent时间的type属性中,用于区分组件发出的LifecycleEvent事件时的状态。
- 定义三个管理监听器的方法,addLifecycleListener、findLifecycleListeners、removeLifecycleListener。
- 定义4个生命周期的方法,init、start、stop、destory,用于执行生命周期的各个阶段的操作。
- 定义了获取当前状态的两个方法,getState、getStateName、用于获取当前的状态。
二.Servlet
1.概念:
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
2.Servlet 的优势:
Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:
(1)性能明显更好。
(2)Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
(3)Servlet 是独立于平台的,因为它们是用 Java 编写的。
(4)服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
(5)Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。
3.Servlet 执行以下主要任务:
(1)读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
(2)读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
(3)处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
(4)发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
(5)发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
4.Servlet有三种创建方式:
(1)实现 Servlet 接口
(2)继承 GenericServlet 类
(3)继承 HttpServlet 方法
5.Servlet 生命周期:(可被定义为从创建直到毁灭的整个过程)
(1)Servlet 通过调用 init () 方法进行初始化。
(2)Servlet 调用 service() 方法来处理客户端的请求。
(3)Servlet 通过调用 destroy() 方法终止(结束)。
(4)最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的
6.关于servlet的路径映射的问题:
(1)精确匹配
<url-pattern>/demo</url-pattern>
<url-pattern>/demo/mp4</url-pattern>
(2)模糊匹配
<1> /* (http://localhost:8080/servlet/任意映射路径)
<2>/demo/* (http://localhost:8080/servlet/demo/任意映射路径)
<3> *.do (http://localhost:8080/servlet/任意映射路径.do)
<4> *.* (http://localhost:8080/servlet/任意路径.任意后缀)
<5> /demo/*/*.do (http://localhost:8080/servlet/demo/任意路径/任意路径.do)[不要用]
<6>注意:
在任何情况下,精确匹配的优先级永远大于模糊匹配
(/demo = /demo) > (/* = /demo)
在任何情况下,动态资源的优先级永远大于静态资源
(*.html = reg.html) > (web/reg.html)
在url-pattern当中,* 和 / 在一定程度上是冲突的(一般要么/开头,要么是*开头,最好不要两着冲突)
比如一下都是错误的:
*/.html
*/
/*/*
7.我们在实际的开发当中,从前端请求过来的参数,肯定不是用户手动的写在url里面的
所以需要准备一个表单,这个表单就可以让用户直接输入数据(这个界面一般也不是我们处理,一般是前端);
(1)前端提交数据的方式无非也就两个:get/post (这个提交方式也是前端决定)
(2)tomcat本质上就会根据前端提交的参数类型,从而决定调用哪个一个方法(doGet、doPost)
举例:
package com.servlet.demo02;
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 RegServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doget----");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("账号:"+username+"--密码:"+password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("dopost----");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("账号:"+username+"--密码:"+password);
}
}
8.在servlet3.0的版本提供了一个注解的方式,其中就一个注解是可以快速和简化配置Servlet
@WebServlet:(这个注解必须写在类名上面)
(1)可以完全省略web.xml的配置
(2)可以完全的支持多线程
(3)可以支持可插性的特性(你编写的代码,生成的class 文件可以实现自动部署,自动加载,自动执行)
name = "ServletDemo"(就是一个servlet类的名称:<servlet-name>ServletDemo</servlet-name> )
urlPatterns = "/zhujie" (就是一个用户范围servlet的一个名称 <url-pattern>/hello</url-pattern>)
举例:
package com.servlet.demo02;
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 = "ServletDemo",urlPatterns = "/zhujie")
public class ZhuJieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我被访问了");
}
}
9.配置环境变量:
(1)将所有需要的配置文件存放到src的根目录当中
(2)在web目录下面创建一个lib目录,将所有需要的jar存入到这个目录
(3)在lib目录下面选中所有的jar包,右键选中add as lib..
(4)将所有的jar包关联到项目之后,确保你的代码不存在问题但是现在这个步骤仅仅只是将jar包和项目进行关联,并没有和tomcat的部署进行关联,在开发阶段正常(jre),在运行阶段失败(tomcat)project Structure -- > Problem -- > fix 进行lib和tomcat的关联修复,lib包就和我们的web项目完全关联了。
举例:
package com.servlet.demo04;
import com.servlet.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
public class TestMysql {
public static void main(String[] args) throws SQLException {
//创建一个QueryRunner的核心类
QueryRunner qr = new QueryRunner( JdbcUtils.getDataSource());
//编写一个sql
String sql = "select * from account";
//查询所有记录
List<User> query = qr.query(sql, new BeanListHandler<User>(User.class));
//测试数据的取出
for(User user :query){
System.out.println(user.getId()+"--"+user.getUsername()+"---"+user.getPassword());
}
}
}
10.获取前端参数的几种方式:
(1)获取单个key请求参数的value
request.getParameter("username"); //返回的是一个String的变量(前端提交的任何数据都认为是一个String,如果需要操作这些数据 请自己转换)
(2)获取多个相同key的请求参数的value
request.getParameterValues("ck"); //返回的是这个key对应的多个值,使用一个String的数组进行变量
(3)获取多个key和对应的value
request.getParameterMap();//返回的是前端请求过来的key和value,使用是一个map集合接受,因为value可能存在多个,所有使用的是一个String[]来接受value
注意:
前端的name属性其实就是对应了我们后端的key
前端的value属性其实就是对应了我们后端的value
举例:
package com.servlet.demo05;
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;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet(name = "CheckboxServlet",urlPatterns = "/checkbox")
public class CheckboxServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取前端的请求参数的值
String username = request.getParameter("username");
String password = request.getParameter("password");
//获取多选框的数据
// String java = request.getParameter("java");
// String php = request.getParameter("php");
// String python = request.getParameter("python");
//解决多个复选框选中的问题
String[] cks = request.getParameterValues("ck");
for (String ck : cks) {
System.out.println(ck);
}
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
System.out.println("name:"+key+"--- values:"+ Arrays.toString(entry.getValue()));
}
System.out.println(username);
System.out.println(password);
}
}
11.回想下我们之前说的一些问题
(1)一个方法不调用不执行
(2)方法的调用除了static修饰的,除此之外都需要依靠对象进行调用
看下我们现在的
(3)我们有去调用Servlet的方法吗?
没有,谁去调用?之前main方法我们也没有调用,是JVM调用 但是因为main方法是一个static方法,所以JVM不需要创建对象就可以调用;但是,现在我们用过的servlet的方法并没有任何的static,是谁调用的?怎么调用的?
Tomcat进行调用的,Tomcat根据反射的newInstance()来进行了对象的创建
(4)那么Tomcat这个运行的流程又是如何的?(其实就是Tomcat生命周期)如果要了解Servlet就需要知道JAVAEE的Servlet标准是什么,因为我们之前就说过,JAVAEE只提供接口(标准跟规范,跟JDBC是一个道理)接口的实现是由各个接口的使用者进行操作,比如说Tomcat就需要操作Servlet的标准。所以我们就需要去了解Servlet究竟提供了一些什么东西?
(5)Servlet主要的三个核心(生命周期)
<1>void init(ServletConfig var1)【只在启动的时候执行一次】Servlet的初始(出生)时机,这个时机会初始化Servlet的所有配置。
<2>void service(ServletRequest var1, ServletResponse var2)【每一次访问Servlet都需要执行】Servlet的生存时机,servlet在生存的时候需要干什么事,我们的doGet和doPost方法的请求和响应其实就是他完成的。
<3>void destroy()【Tomcat停止或者结束部署的时候执行一次】Servlet的死亡时机,就是Servlet某种原因中断,操作了Servlet死亡的时候需要干什么事情
(6)注意:
<1>一个Tomcat的项目启动,不会立即创建对象
<2>只有在首次访问项目的servlet的时候,才会创建对象 并且只初始化一次,即便你下次继续访问对象不会继续创建也不会在执行初始化
<3>综上所述,也就可以证明Servlet使用是单例设计模式(保证的内存当中且能存在一个相同对象),因为是要访问Servlet后才会创建对象,在项目启动的时候不会创建,所以我们可以知道这个单例设计模式采用的懒汉式的设计模式。因为Servlet采用的是单例设计,那么也就意味这所有的Servlet成员变量之间的数据是可以进行共享的。这种情况就有可能造成线程安全(并发)的问题,针对针对这种情况,我们一般句建议不再在任何的servlet类上面写成员变量。如果非得写,最好给成员的位置加上代码锁,但是锁的范围控制好一点,因为怕造成同步代码产生效率低的问题。
//@WebServlet(name = "LifeServlet",urlPatterns = "/life",loadOnStartup = 1,initParams = {@WebInitParam(name = "toobug",value = "18"),@WebInitParam(name = "toobug",value = "18")})
举例:
package com.servlet.demo06;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LifeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("hello");
}
public LifeServlet(){
System.out.println("我是构造");
}
//初始化时机
public void init(ServletConfig config) throws ServletException {
String name = config.getInitParameter("name");
String age = config.getInitParameter("age");
String servletName = config.getServletName();
System.out.println(servletName);
System.out.println(name+"---"+age);
System.out.println("hello init开始出生了");
}
//生存时机
public void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException{
System.out.println("hello service开始工作了");
}
//销毁时机
public void destroy(){
System.out.println("hello destroy死亡了");
}
}
12.servler的运行步骤