1.简单servlet程序示例
1)创建一个servlet,重写service()方法,会自动调用doGet()方法或者doPost()方法
package com.huawei.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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;
public class HelloServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String name = req.getParameter("name");
PrintWriter out = res.getWriter();
out.println("<span style='color:red;font-size:30px;'>你好 "+name+"</span>");
}
}
2)配置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">
<!--配置Servlet,tomcat服务器会读取其中的内容-->
<servlet>
<!--Servlet内部名称,可以自定义,但是最好不要乱写,尽量保证有意义-->
<servlet-name>helloServlet</servlet-name>
<!--Servlet类全名,包名+简单类名-->
<servlet-class>com.huawei.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet映射配置-->
<servlet-mapping>
<!--Servlet内部名称,可以自定义,但是最好不要乱写,尽量保证有意义,一定要和上面的servlet-name保持一致-->
<servlet-name>helloServlet</servlet-name>
<!--Servlet映射路径,也称为访问Servlet的名称-->
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
3)注解方式实现上面的内容——免于web.xml中servlet配置
package com.huawei.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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(name = "helloServlet", urlPatterns = "/test2")
public class HelloServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String name = req.getParameter("name");
PrintWriter out = res.getWriter();
out.println("<span style='color:red;font-size:30px;'>你好 "+name+"</span>");
}
}
4)IntelliJ IDEA 2017部署普通web项目(非maven)
3)启动Tomcat
5)@WebServlet注解
//具体可以按住Ctrl单击注解查看所有参数
@WebServlet(name = "helloServlet", //对应servletname
urlPatterns = "/test2", //对应url-pattern
loadOnStartup = 1) //对应load-on-startup
public class HelloServlet extends HttpServlet {
//省略一千字
}
如果希望应用程序启动时,就先将Servlet类载入、实例化并做好初始化动作,则可以使用loadOnStartup设置。设置大于0的值(默认值为-1),表示启动应用程序后就要初始化Servlet(而不是实例化几个Servlet)。数字代表了Servlet的初始顺序,容器必须保证有较小数字的Servlet先初始化,在使用标注的情况下,如果有多个Servlet在设置loadOnStartup时使用了相同的数字,则容器实现厂商可以自行决定要如何载入哪个Servlet。
2.servlet执行流程
- 按上述方法启动服务器
- 在浏览器输入http://localhost:8080/start/test?name=亚索
- 根据ip:端口号与服务器建立连接
- 根据应用名(idea可以自己随便写,如start,eclipse则只能是工程名)去服务器上查找对应的应用(HelloJavaEE),每一个应用都有一个web.xml文件
- 根据/test去web.xml文件中查找对应的url-pattern, 找到之后,根据servlet-name查找到对应的HelloServlet
- 调用HelloServlet的service方法处理数据
3.servlet映射路径
Servlet的映射路径由<servlet-mapping>中的<url-pattern>(注意<url-pattern>要么要以/开头,要么要以*开头)决定,那么<url-pattern>究竟怎么写,怎么去匹配呢?有两种匹配方案:
- 精确匹配
<url-pattern>/test/login</url-pattern>
精确匹配的要点是:<url-pattern>以/开始,并且必须将<url-pattern>中的内容精确的写上。在精确匹配时要注意坚决不能漏掉/,否则会报错,一定要带有/ - 模糊匹配,下面三种方式,但是在一个url-pattern中不能组合下面的模糊匹配方式
- <url-pattern>/*</url-pattern>
- <url-pattern>/test/*</url-pattern>
- <url-pattern>*.do</url-pattern>
注意模糊匹配不能组合起来用,只能单个使用
- 如果在浏览器中输入的url有多个Servlet同时被匹配,也就是说模糊匹配和精确匹配都能找到对应的Servlet资源,精确匹配的优先级高(长得最像的优先被匹配),但是要尽量避免这种情况的发生。当以后缀名结尾的模糊匹配,优先级最低。
4.servlet运行原理
1)建立连接
浏览器根据ip地址及端口号与服务器建立连接
2)打包
浏览器根据http协议将数据打包
数据包中包含请求资源路径(/start/test)
3)发送请求
浏览器向服务器发送请求
4)拆包
服务器根据http协议拆包,获取浏览器发送过来的请求数据
5)创建Request
可以通过请求对象获取请求数据
6)创建Response
可以通过响应对象获取输出流,向页面输出数据
7)创建HelloServlet
服务器通过反射实例化HelloServlet
8)调用service方法
在service方法中处理数据
9)服务器端的通讯模块将数据打包
10)服务器向浏览器发送响应
11)浏览器拆包,获取服务器响应回来的数据
12)浏览器生成新的页面,响应给用户
5.servlet映射练习
- Servlet1 映射到/abc/*
- Servlet2 映射到/*
- Servlet3 映射到/abc
- Servlet4 映射到*.do
Question:
①/abc/a.html:Servlet1
②/abc:Servlet3
③/abc/a.do:Servlet1
④/a.do:Servlet2
⑤/xxx/yyy/a.do:Servlet4
解析URL的顺序:当输入一个URL时,首先会到web.xml文件中查找是否与偶匹配的url-pattern,如果能匹配到url-pattern,则处理,如果不能匹配到,则交给tomcat的default-servlet处理,也就是会去加载静态资源文件。
结论:先找动态资源,后找静态资源。
6.get请求与post请求
- get请求:
☆在浏览器地址栏直接传参
☆超链接
☆表单默认提交方式 - post请求:
☆将表单的默认提交方式改成post, <form method = “post”></form>
7.HTTP协议简述
- 什么是http协议
hypertext transport protocal 超文本传输协议
是一种应用协议,包含了浏览器与服务器的通讯过程及数据格式。 - 通讯过程
step1.建立连接,浏览器根据ip及端口号与服务器建立连接
step2.打包,发送请求,浏览器将数据打包向服务器发送请求
step3.打包,发送响应,服务器将数据打包向浏览器发送响应
step4.服务器关闭连接
特点:一次请求,一次连接
优点:效率高,可以用有限的资源为更多的用户服务 - 数据格式
●请求数据包
请求行
请求方式(get/post)
请求资源路径(/应用名/….)
协议类型及版本
若干消息头
是一些键值对,由w3c制定,具有特定的含义。
规定了浏览器与服务器之间,可以通过发送消息头的方式来传递一些信息。
比如user-agent,它包含了浏览器的相关信息,比如类型及版本号。
实体内容
如果是post请求,浏览器会将参数名=参数值放在该处。
如果是get请求,参数名=参数值跟在请求资源路径后面。
● 响应数据包
响应行
协议类型及版本号
响应的状态码
状态码描述信息
若干消息头
由w3c制定的一些键值对,比如
content-type:告诉浏览器,服务器返回的数据类型及编码格式
实体内容
服务器处理之后的数据 - get请求与post请求区别
1)如果是get请求,请求参数是放在请求资源路径后面,不能够提交大量的数据(不同的浏览器对数据量大小的限制不一样, 一般是2k-8k,为了保证浏览器的兼容性,最好不要超过2k), 而post请求的请求参数是放在实体内容里面,理论上没有限制。
2)post相对于get更安全。post也不是绝对的安全,因为服务器不会对数据加密,可以通过代理服务抓取数据包,所以对于敏感的数据建议加密。
8.servlet获取请求参数
- 参数名唯一
String request.getParameter(参数名);
注:
a.如果参数名写错,返回的是null
b.如果用户在输入框没有输入数据,返回的是 “” - 参数名有多个相同
String[] request.getParameterValues(参数名);
9.转发与重定向
- 重定向
- 服务器向浏览器发送一个302的状态码以及一个location消息头(值就是一个url地址),当浏览器检测到302状态码之后,会立即向location的地址发送请求
- 如何重定向
response.sendRedirect(String url); - 重定向的特点
- 重定向之后,浏览器地址栏的地址会发生改变
- 重定向的地址是任意的
- 转发
- 一个web组件(servlet/jsp)将未完成的事情交给另外一个组件继续完成。通常情况是servlet将未做完的事情交给jsp继续处理。比如:servlet负责取数据,jsp负责展示数据
- 如何转发
- step1.绑定数据
//name:绑定名 obj:绑定值
request.setAttribute(String name,Object obj);
//根据绑定名获取绑定值
Object request.getAttribute(String name) - step2.获得转发器
//url:转发的目的地
RequestDispatcher dispatcher = request.getRequestDispatcher(String url); - step3.转发
dispatcher.forward(req,res);
- step1.绑定数据
- 转发的特点
- 转发之后,浏览器地址的地址不会发生改变
- 转发的地址只能是同一应用内部的地址
- 转发之间的组件共享同一个request和response
10.servlet 生命周期
1)为什么要学习Servlet生命周期
Servlet程序由tomcat服务器调用,所以有必要去知道究竟怎么去调用,Servlet生命周期就是要去搞明白Servlet对象什么时候去创建?调用什么方法?什么时候Servlet对象被销毁?销毁调用什么方法做了什么事情?Servlet程序的生命周期是由tomcat服务器去控制的。
2)servlet分为几个阶段
- 阶段一:实例化
- 情况一(默认):
- 当请求到达容器时,容器会先检查是否有该对象,如果没有,创建该servlet对象,servlet生命周期整个过程当中,只会被实例化一次。
- 情况二:
- 当容器启动时创建servlet对象因为有一些servlet实例化之后需要做大量的初始化工作,比如读取配置文件信息,这些操作需要花费 一定的时间,如果当请求到达容器时才实例化,那么服务器响应的时间会较长,影响用户体验度。
- 方式:
在web.xml文件中配置<load-on-startup>1</load-on-startup>配置的参数>=0的整数,数值越小,优先级越高
- 情况一(默认):
- 阶段二:初始化
- 容器为servlet分配资源,调用init(ServletConfig)方法,ServletConfig对象由容器在调用init方法之前创建好,可以通过getServetConfig()方法获取到config对象,config.getInitParameter(key)通过该方法可以获取初始化参数值
可以在web.xml中配置初始化参数,或者通过注解方式
<init-param>
<param-name>city</param-name>
<param-value>南京</param-value>
</init-param>
String value = getServletConfig().getInitParameter(“key”); - 注:可以重写init方法,建议重写无参的init()
- 容器为servlet分配资源,调用init(ServletConfig)方法,ServletConfig对象由容器在调用init方法之前创建好,可以通过getServetConfig()方法获取到config对象,config.getInitParameter(key)通过该方法可以获取初始化参数值
- 阶段三:就绪
- 在servlet对象实例化完,并且初始化工作已结束,容器会调用service方法,会根据请求方式决定调用doGet()还是doPost();可以重写service()方法 (建议),也可以重写doGet()或者doPost()方法
- 注:service方法在请求到达容器时被调用,而且每发送一次请求,就会被调用一次
- 阶段四:销毁
- 容器会根据自身的算法,调用destroy方法
- 总结:在servlet生命周期的整个过程中,实例化/初始化/销毁只会被执行一次,而就绪会被调用多次。
3)servlet相关的接口与类
- servlet接口
init(ServletConfig config);
ServletConfig是一个接口
service(ServletRequest req,ServletResponse res);
ServletRequest接口
ServletResponse接口
destroy(); - GenericServlet抽象类实现了servlet接口
init();
destroy(); - HttpServlet抽象类继承了GenericeServlet
service()方法