深入理解Servlet原理

Servlet介绍:

1. 如何返回一个网页:

 a. 静态网页

    >新闻页、百度百科

    >服务器保存一份HTML,直接返回给浏览器即可

 b. 动态网页

    >淘宝、QQ空间、微博

    >服务器保存一个组件,通过它动态拼一个HTML

    >在Java中这个组件就是Servlet

2. Servlet特征:

  a. Servlet是服务器端组件,必须保存在服务器上。

  b. Servlet可以动态拼资源(HTML/IMG等),即处理HTTP协议。

  c. Servlet必须满足Sun的规范。

  d. Servlet是什么:Servlet是Sun推出的,用来在服务器端处理HTTP协议的组件。

服务器:

1. 名称:Java 服务器、Java Web 服务器、Servlet 容器;

2. 本质:是一个软件,需要安装在硬件上才能用和浏览器是平级的关系;

3. 举例:Tomcat(Apache)、JBOSS、WebLogic、WebSphere。

Tomcat使用:

1. 启动Tomcat:

   -Linux:打开/tomcat/bin,终端输入命令./startup.sh

   -Windows:打开/tomcat/bin,双击startup.bat

2. 关闭Tomcat:

   -Linux:打开/tomcat/bin,终端输入命名./shutdown.sh

   -Windows:打开/tomcat/bin,双击shutdown.bat

Servlet开发步骤:

1.创建WEB项目

  >目录:webapp/WEB-INF/web.xml

2.导入jar包

  >通过maven导入jar包,搜javaee

  >使用服务器自带的jar包,右键项目->target runtime->勾选tomcat

3.创建Servlet

  >实现Servlet接口

  >也可以继承HttpSevlet,此类已实现了Servlet接口

  >实现/重写service(),在此方法内动态拼HTML

4.注册Servlet

  >注册Servlet,并声明别名

  >通过别名,给此Servlet注册网名(以/开头)

5.部署项目

  >在Servers下选择Tomcat,右键Add and Remove

  >在弹出框内左侧选中项目,双击移动到右侧

  >部署:就是拷贝

6.访问Servlet

  >启动Tomcat

  >浏览器输入地址 http://ip:port/项目名/Servlet网名

7.重新部署

  >修改代码后,需要重新部署并重启Tomcat才有效

  >点击Servers下面的Tomcat7,右键publish

  >可以手动关闭Tomcat,再启动它

  >也可以等待Eclipse自动重启Tomcat(Reloading...)

Servlet执行原理:

HTTP协议:

1. 什么是HTTP协议:它规定了浏览器和服务器如何通信,以及通信时的数据格式。

2. 如何通信:

  >建立连接

  >发送请求

  >接收响应

  >关闭连接

3. 数据格式:

 a. 请求数据包

   >请求行:请求方式、Servlet网名、协议类型

   >消息头:数据的描述信息

   >实体内容:浏览器发送给服务器的数据

 b. 响应数据包

   >状态行:协议类型、状态码、状态

   >消息头:数据的描述信息

   >实体内容:服务器给浏览器发送的数据

4. 对开发的要求

  -通信的方式已经由浏览器和服务器完成;

  -请求数据的打包由浏览器实现;

  -响应数据的打包由服务器实现;

  -开发需要提供浏览器发送给服务器的数据,以及服务器返回的数据;

  -服务器通过request对象接收请求数据;

  -服务器通过response对象向浏览器发送数据;

注册案例:

1. form的action属性要写上Servlet的访问路径(网名);

2. 在表单空间上,使用name属性给该控件的数据命名,可以调用request的getParameter("name的指")来获取值;

3. radio和checkbox需要设置value属性的值,就是要传递给服务器的具体的值;

Servlet原理图:

请求方式:

1. 介绍:浏览器向服务器发送数据的方式;

2. GET:

  >默认情况下所有的请求都是GET请求

  >采用路径传参,即通过路径携带参数

  >传参过程中参数可见,隐私性差

  >因为路径大小有限制,所以能够传递的参数很小

3. POST:

  >method="post"

  >采用实体内容传参

  >在传参的过程中,路径上看不到参数,隐私性好

  >实体内容专门用于传递数据,因此大小不受限制

4. 使用场景:

  >浏览器向服务器索取(查询)数据用GET请求

  >浏览器向服务器提交(保存)数据用POST请求

解决乱码问题:

重定向:

 1. 格式:res.sendRedirect("findEmp");//findEmp是网名

 2. 原理图如下:

项目路径:

URI和URL:

1. 狭义(Java):

   - URI:绝对路径;

   - URL:完整路径;

   - URL包含了URI;

2. 广义(Java/.net/php):

   - URI:资源的名称;

   - URL:资源的真名;

   - URI包含了URL;  

Servlet路径的配置方式及用途:

1. 精确匹配(/test):

    - 只有这唯一的路径可以可以访问此Servlet

    - 该Servlet只能处理一个请求 

2. 通配符(/*):

    - 所有的路径都是可以访问此Servlet

    - 该Servlet可以处理所有请求

3. 后缀匹配(*.test):

    - 所有以.test为后缀的路径都可以访问此Servlet

    - 该Servlet可以处理很多请求

注:

  a. 必须先通过规范约定正确的路径;

  b. 按照规范判断路径,处理请求。对于不满足规范的路径,认为是用户输入的错误路径,统一报错;

Servlet生命周期:

1. 第1、2、4步只能执行一次,第3步可以执行多次;

2. 因为Servlet被Tomcat自动创建一次,因此它在Tomcat内是单例的(只有1个实例),即Servlet满足单例模式;

3. 默认情况下,首次访问Servlet时,Tomcat会创建它,也可以修改配置文件web.xml,使得Tomcat启动时就直接创建Servlet;

4. 启动时创建Servlet,数字1代表创建的次序:<load-on-startup>1</load-on-startup>;

ServletConfig和ServletContext:

1. Context:上下文,理解为环境。环境可以给其内部的个体提供资源。从编程的角度来说可以给内部的对象提供数据;
2. ServletConfig:它是Servlet的私有环境,可以为某一个Servlet提供数据;
3. ServletContext:它是Servlet的公有环境,可以为所有Servlet提供数据;
4. 使用ServletConfig和ServletContext给Servlet预置数据,不用写单独的配置文件,直接使用web.xml即可;另外这两个对象可以在初始化Servlet之前自动读取web.xml中的预置数据;
5. Servlet特殊用法:
    - 可以使用此对象存取一些变量;
    - 即在程序运行阶段随时向此对象存取数据;
    - 获取对象:ServletContext ctx = getServletContext();
    - 取:ctx.getAttribute("user");
    - 存:ctx.setAttribute("user","admin");
 6. 通常在Tomcat启动时,都要调用某Servlet重写init(ServletConfig config)方法,专门用来在此阶段初始化项目所需要的一些变量。

使用案例:

1. ServletConfig案例:
  a. 配置文件web.xml 

<servlet>

<servlet-name>login</servlet-name>
<servlet-class>web.LoginServlet</servlet-class>

<!-- 给当前Servlet预置一个数据 -->

<init-param>

<param-name>maxOnline</param-name>

<param-value>2000</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>login</servlet-name>

<url-pattern>/login</url-pattern>

</servlet-mapping>

  b. 在Servlet类中读取参数
 

/**

* 1.Tomcat在创建此Servlet后,会自动创建ServletConfig对象。

* 2.Tomcat会调用此对象,读取web.xml中给当前Servlet所配置的参数。

* 3.Tomcat会自动调用init方法,并传入已创建好的ServletConfig对象。

* 归纳:调用init方法前,创建config并读取数据。在init及其后面的方法内可以使用config。

*/

@Override

public void init(ServletConfig config) throws ServletException {

super.init(config);

String mo = config.getInitParameter("maxOnline");

System.out.println(mo);

}

@Override

protected void service(

HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

//从web.xml中读取参数

ServletConfig cfg = getServletConfig();

String mo = cfg.getInitParameter("maxOnline");

System.out.println(mo);

}

2. ServletContext案例:

  a. 配置文件web.xml

 

<!--

给所有的Servlet预置一个数据。
1.Tomcat启动时会自动创建ServletContext对象。

2.Tomcat调用context读取此参数。

由于这件事是在调用Servlet之前完成的,所以在service()中可以通过context读取参数。

-->

<context-param>

<param-name>size</param-name>

<param-value>10</param-value>

</context-param>

<servlet>

<servlet-name>findDept</servlet-name>

<servlet-class>web.FindDeptServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>findDept</servlet-name>

<url-pattern>/findDept</url-pattern>

</servlet-mapping>

  b. 在Servlet类中读取参数

 

@Override

protected void service(
HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

//从web.xml中读取分页条件

ServletContext ctx = getServletContext();

String size = ctx.getInitParameter("size");

//分页查询

System.out.println(size);

}

线程安全:

1. 成员变量:

    - 成员变量存于堆内;

    - 堆内数据只有一份;

    - 多线程共用一份数据;

    - 存在并发问题;

2. 局部变量:

    - 成员变量存于栈内;

    - 栈内数据是多份;

    - 每个线程都有一份自己的数据;

    - 没有并发问题;

3. 解决方案:

   - 不用成员;

   - 枷锁synchronized (this) {//TODO};

HttpServlet:

1. 自定义的类继承HttpServlet类,重写service方法,Tomcat将HttpServletRequest,HttpServletResponse传入此方法:

public class TestServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

super.service(req, res);

}

//...

}

2. 调用父类,并将HttpServletRequest、HttpServletResponse两个参数传入:

public class HttpServlet {

public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res= (HttpServletResponse) response;
this.service(req, res);
}
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String m = req.getMethod();
if(m.equals("GET")) {
doGet(req, res);
}else if(m.equals("POST")) {
doPost(req, res);
}
}
private void doPost(HttpServletRequest req, HttpServletResponse res) {
// TODO
}
private void doGet(HttpServletRequest req, HttpServletResponse res) {
// TODO
}
//...
}
3. doGet()和doPost()默认的代码直接抛出了异常,为了强制开发者去重写他们。若要调用它们,就必须重写;

4. service()内去掉super.service()的目的就是不掉用它们,从而避免异常;

原文地址:https://www.cnblogs.com/shoshana-kong/p/10583886.html