Servlet基础
一、Servlet概述
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
即是:
- Servlet是一个Java程序
- 是运行在服务器上
- 处理客户端请求并作出响应
1.回顾JSP如何编写服务器动态网页
就像其他普通的网页一样,您的浏览器发送一个HTTP请求给服务器。
Web服务器识别出这是一个对JSP网页的请求,并且将该请求传递给JSP引擎。通过使用URL或者.jsp文件来完成。
JSP引擎从磁盘中载入JSP文件,然后将它们转化为servlet。这种转化只是简单地将所有模板文本改用println()语句,并且将所有的JSP元素转化成Java代码。
JSP引擎将servlet编译成可执行类,并且将原始请求传递给servlet引擎。
Web服务器的某组件将会调用servlet引擎,然后载入并执行servlet类。在执行过程中,servlet产生HTML格式的输出并将其内嵌于HTTP response中上交给Web服务器。
Web服务器以静态HTML网页的形式将HTTP response返回到您的浏览器中。
最终,Web浏览器处理HTTP response中动态产生的HTML网页,就好像在处理静态网页一样。
二、Servlet与JSP的关系
1.疑问
发起疑问:先有JSP还是先有Servlet?(当然是先有Servlet了-手动滑稽)
回忆JSP 执行过程,然后说明JSP被翻译成.JAVA,这个.JAVA到底是什么样子呢?
打开环境,新建一个JSP,运行后,再观看此.java文件上,如Test.jsp在运行时首先解析成一个Java类Test_jsp.java,
而这个Test_jsp.java继承于org.apache.jasper.runtime.HttpJspBase类,
而HttpJspBase又是继承自HttpServlet的类,
由此可以得出一个结论,就是JSP在运行时会被Web容器翻译为一个Servlet
三、Servlet的声明周期
1.Servlet声明周期
2.生命周期的各个阶段
请求处理:当有请求到达容器时,容器会调用servlet对象的service方法。HttpServlet的service方法,它会根据用户的请求方式来调用doGet()或doPost().
但是,这两个do方法默认情况下会抛出异常,所以需要子类去重写(override)
3.Servlet构造方法
- 构造方法只有首次调用Servlet时,会被执行,后续请求不在执行
- 例如:
public HelloServlet() {
//1.只有首次会执行
System.out.println("创建HelloServlet对象");
}
4.init()方法
- init方法被设计成只调用一次
- 它在第一次创建Servelt时,被调用,在后续每次用户请求时,不再调用。因此,它是用于一次性初始化。
@Override
public void init(ServletConfig config) throws ServletException {
//2.只有首次会执行
System.out.println("开始初始化");
super.init(config);
}
5.service方法
- service()方法是执行实际任务的主要方法
- Servlet容器(即Web服务器)调用service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//3.每次刷新都执行
System.out.println("service方法执行");
super.service(req, resp);
}
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。
service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
6.doGet()方法
- get请求来自于一个URL的正常请求,或者来自于一个未指定Method的HTML表单,它由doGet()方法处理。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//4.由service方法决定是调用doGet方法还是doPost等方法
System.out.println("doGet方法执行");
}
7.doPost()方法
- post请求来自于一个特别指定了Method为POST的HTML表单,它由doPost()方法处理。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
8.destroy()方法
- destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
- 在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
@Override
public void destroy() {
//销毁时,执行
System.out.println("destroy方法执行");
super.destroy();
}
9.GET和POST的区别
GET和POST的区别
GET | POST |
---|---|
从服务器上获取数据 | 向服务器传送数据 |
把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一 一对应,在URL中可以看到 | 通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程 |
传送的数据量较小,不能大于2KB | 传送的数据量较大,一般被默认不受限制(但跟服务器有关) |
安全性非常低,但执行效率高 | 安全性较高,但执行效率低 |
建议:
get方式的安全性较Post方式要差些,包含机密信息的话,建议用post数据提交方式。
在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式。
四、Servlet的配置、实例
实例1:简单的xml配置,带上下文参数和初始化参数
Servlet代码:
package cn.ebuy.servlet;
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 HelloServlet extends HttpServlet {
public HelloServlet() {
//1.只有首次会执行
System.out.println("创建HelloServlet对象");
}
@Override
public void init(ServletConfig config) throws ServletException {
//2.只有首次会执行
System.out.println("开始初始化");
//获取上下文参数
System.out.println(config.getServletContext().getInitParameter("deltools"));
//获取初始化参数
System.out.println(config.getInitParameter("dbtype"));
System.out.println(config.getInitParameter("className"));
super.init(config);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//3.每次刷新都执行
System.out.println("service方法执行");
super.service(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//4.由service方法决定是调用doGet方法还是doPost方法
System.out.println("doGet方法执行");
PrintWriter out=resp.getWriter();
out.println("HelloServlet");
//打印上下文参数
out.println(this.getServletContext().getInitParameter("deltools"));
//打印初始化参数
out.println(this.getInitParameter("dbtype"));
}
@Override
public void destroy() {
//销毁时,执行
System.out.println("destroy方法执行");
super.destroy();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
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_3_1.xsd"
version="3.1">
<context-param>
<param-name>deltools</param-name>
<param-value>idea</param-value>
</context-param>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>cn.ebuy.servlet.HelloServlet</servlet-class>
<!--配置初始化参数-->
<init-param>
<param-name>dbtype</param-name>
<param-value>mysql</param-value>
</init-param>
<init-param>
<param-name>className</param-name>
<param-value>HelloServlet</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
</web-app>
怎么启动时,就自动实例并初始化Servlet,而不是第一次访问时再创建呢?
在xml文件中<servlet>
标签内加上 <load-on-startup>0</load-on-startup>
(注意位置,不能在<init-param>
前面)
在servlet的配置当中,1的含义是:
标记容器是否在启动的时候就加载这个servlet。
当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
正数的值越小,启动该servlet的优先级越高。
如果我们在web.xml中设置了多个servlet的时候,可以使用load-on-startup来指定servlet的加载顺序,服务器会根据load-on-startup的大小依次对servlet进行初始化。不过即使我们将load-on-startup设置重复也不会出现异常,服务器会自己决定初始化顺序。
版权声明:本文为CSDN博主「xuke6677」的原创文章
原文链接
实例2:使用WebServlet注解配置Servlet
首先有可能你不能使用WebServlet这个注解,接下来有解决方法:
类代码:
package cn.ebuy.servlet;
import javax.servlet.ServletException;
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;
import java.io.PrintWriter;
/**
* 测试注解配置Servlet
*/
//配置注解属性
@WebServlet(name = "roleServlet",urlPatterns = {"/roleServlet","/role"},loadOnStartup = 1,initParams = {@WebInitParam(name = "deltool",value = "idea"),
@WebInitParam(name = "dbtype",value = "mysql")
} )
public class RoleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out= resp.getWriter();
//获取初始化属性deltool
out.println(this.getInitParameter("deltool"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
实例3:测试Servlet是线程不安全
测试1 单例:
package cn.ebuy.servlet;
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.io.PrintWriter;
@WebServlet("/testServlet1")
public class TestServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out= resp.getWriter();
out.println(this);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
页面显示:
测试2:
类代码:
package cn.ebuy.servlet;
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.io.PrintWriter;
@WebServlet("/testServlet1")
public class TestServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out= resp.getWriter();
String op= req.getParameter("op");
if (op.equals("read")){
out.println(i);
}else if (op.equals("add")){
this.add();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
int i;
public void add(){
this.i++;
}
}
效果:
之后
由此得出结论:Servlet慎用全局变量
至此便结束了