什么是Servlet?
Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。
Servlet接口及其实现类
在Servlet接口中定义了5个抽象方法,具体如下表所示:
方法声明 | 功能描述 |
---|---|
void init(ServletConfig config) | 容器在创建好Servlet对象后,就会调用此方法。该方法接受一个ServletConfig类型的参数,Servlet容器通过这个参数向Servlet传递初始化配置信息 |
ServletConfig getServletConfig() | 用于获取Servlet对象的配置信息,返回Serclet的ServletConfig对象 |
String getServletInfo | 返回一个字符串,其中包含关于Servlet的信息,例如,作者、版本和版权等信息 |
void service(ServletRequest request,ServletResponse response) | 负责响应用户的请求,当容器接收到客户端访问Servlet对象的请求时,就会调用此方法。容器会构造一个表示客户端请求信息的ServletRequest对象和一个响应客户端的ServletResponse对象作为参数传递给service()方法 。在service()方法中,可以通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息 |
void destory | 负责释放Servlet对象占用的资源。当服务器关闭或者Servlet对象被移除时,Servlet对象会被销毁,容器会调用此方法 |
其中init()、service()、destory()方法可以表现Servlet的生命周期。
HttpServlet的常用方法
方法声明 | 功能描述 |
---|---|
protected void doGet(HttpServletRequest req,HttpServletResponse resp) | 用于处理GET类型的HTTP请求方法 |
protected void doPost(HttpServletRequest req,HttpServletResponse resp) | 用于处理POST类型的HTTP请求方法 |
protected void doPut(HttpServletRequest req,HttpServletResponse resp) | 用于处理PUT类型的HTTP请求方法 |
Servlet的生命周期
实例化阶段 容器调用Servlet的构造器,创建一个Servlet对象
初始化阶段 执行 init 初始化方法
运行阶段 执行 service 方法
销毁阶段 执行 destroy 销毁方法
请求方式
请求方式是客户端对话服务器的意向说明,是区分请求种类的关键。 不同的请求方式不仅在数据传输时有所不同,在表单提交服务器端处理时都会采用不同的方式,而区分不同种类的请求方式也会使得浏览器采用不同的缓冲方式处理后续请求,从而提升响应速度。
请求方式的种类
请求方式 | 作用 |
---|---|
GET | 请求指定的资源 |
POST | 向指定的资源提交需要处理的数据 |
HEAD | 要求响应与响应的GET一样,但没有响应体 |
PUT | 上传指定资源 |
DELETE | 删除指定资源 |
GET请求方式
当需要向服务器请求指定的资源时使用的方法,在地址栏输入一个地址、点击链接、表单默认提交都会向浏览器发送Get请求
Get请求的特点:会将请求数据添加到请求资源路径的后面,所以只能提交少量的数据给Web服务器,请求参数会显示在浏览器地址栏上,相对来说不安全。
POST请求
向服务器提交需要处理的数据,这些数据在请求的内容里,可以导致新资源的产生和已有资源的更新。设置表单method属性为POST会向浏览器发送POST请求。
Post请求的特点:请求参数添加到实体内容中,可以提交大量的数据,不会将请求参数显示在浏览器地址栏,相对来说安全。
小练习
设计一个页面,addEmp.html添加员工。三个表单域,姓名,薪水,年龄,点击提交后到达addEmpServlet,Servlet只做一件事情读取与员工信息并显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/addEmp" method="get">
姓名:<input type="text" name="xm"></br>
薪水:<input type="text" name="xs"></br>
年龄:<input type="text" name="nl"></br>
<input type="submit" value="提交">
</form>
</body>
</html>
public class AddEmpServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String xm = req.getParameter("xm");
String xs = req.getParameter("xs");
String nl = req.getParameter("nl");
PrintWriter out = resp.getWriter();
out.println("<html><body>");
out.println("<h1>"+ xm + "</h1>");
out.println("<h1>"+ xs + "</h1>");
out.println("<h1>"+ nl + "</h1>");
out.println("</body></html>");
}
}
Servlet虚拟路径映射
匹配Servlet规则-精确匹配
通过将请求资源路径中的具体资源名称与web.xml文件中的"url-pattern"进行对比,严格匹配相对后找到对应资源并执行
匹配Servlet规则-通配符匹配
使用“”来匹配0个或多个字符
匹配Servlet规则-后缀匹配
不能使用斜杠开头,使用“.”开头的任意多个字符。例如*.do匹配以“.do”结尾的请求。
ServletConfig 接口
ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。
ServletConfig 类的三大作用
1、可以获取 Servlet 程序的别名 servlet-name 的值
2、获取初始化参数 init-param
3、获取 ServletContext 对象
web.xml代码
<!-- servlet 标签给 Tomcat 配置 Servlet 程序 -->
<servlet> <!--servlet-name 标签 Servlet 程序起一个别名(一般是类名) -->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class 是 Servlet 程序的全类名-->
<servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
<!--init-param 是初始化参数-->
<init-param>
<!--是参数名-->
<param-name>username</param-name>
<!--是参数值-->
<param-value>root</param-value>
</init-param>
<!--init-param 是初始化参数-->
<init-param>
<!--是参数名-->
<param-name>url</param-name>
<!--是参数值-->
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</servlet>
<!--servlet-mapping 标签给 servlet 程序配置访问地址-->
<servlet-mapping>
<!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!--url-pattern 标签配置访问地址 <br/> / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径 <br/> /hello 表示地址为:http://ip:port/工程路径/hello <br/> -->
<url-pattern>/hello</url-pattern> </servlet-mapping>
Servlet 代码:
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2 init 初始化方法");
// 1、可以获取 Servlet 程序的别名 servlet-name 的值
System.out.println("HelloServlet 程序的别名是:" + servletConfig.getServletName());
// 2、获取初始化参数 init-param
System.out.println("初始化参数 username 的值是;" + servletConfig.getInitParameter("username"));
System.out.println("初始化参数 url 的值是;" + servletConfig.getInitParameter("url"));
// 3、获取 ServletContext 对象
System.out.println(servletConfig.getServletContext()); }
ServletContext接口
1、获取 web.xml 中配置的上下文参数 context-param
2、获取当前的工程路径,格式: /工程路径
3、获取工程部署后在服务器硬盘上的绝对路径
4、像 Map 一样存取数据
ServletContext接口分别定义了增加、删除、设置ServletContext域属性的方法
方法说明 | 功能描述 |
---|---|
Enumeration getAttributeNames() | 返回一个Enumeration 对象,该对象包含了所有存放在ServletContext中所有域属性名 |
Object getAttibute(String name) | 根据参数指定的属性名返回一个与之匹配的属性值 |
void removeAttribute(String name) | 根据参数指定的属性名,从ServletContext中删除匹配的属性值 |
void setAttribute(String name,Object obj) | 设置ServletContext的域属性,name为域属性名,obj为域属性值 |
ServletContext用于获取资源路径的方法
方法说明 | 功能描述 |
---|---|
Set getResourcePaths(String path) | 返回一个Set集合,集合中包含资源目录中子目录和文件的路径名称。参数path必须以正斜线开始,指定匹配资源的部分路径 |
String getRealPath(String path) | 返回资源文件在服务器文件系统的真实路径(文件的绝对路径)。参数path代表文件的虚拟路径,以正斜线开始,“/”表示当前Web的根路径 |
URL getRecource(String path) | 返回映射到某个资源文件的URL对象。参数path必须以正斜线开始,“/”表示当前Web的根路径 |
InputStream getRecourceAsStream(String path) | 返回映射到某个资源文件的InputStream输入流对象。参数path传递域getRecource()方法一致 |
ServletContext代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获取 web.xml 中配置的上下文参数 context-param
ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
System.out.println("context-param 参数 username 的值是:" + username); System.out.println("context-param 参数 password 的值是:"+context.getInitParameter("password"));
// 2、获取当前的工程路径,格式: /工程路径
System.out.println( "当前工程路径:" + context.getContextPath() );
// 3、获取工程部署后在服务器硬盘上的绝对路径 /*** / 斜杠被服务器解析地址为:http://ip:port/工程名/ 映射到 IDEA 代码的 web 目录<br/> */
System.out.println("工程部署的路径是:" + context.getRealPath("/"));
System.out.println("工程下 css 目录的绝对路径是:" + context.getRealPath("/css")); System.out.println("工程下 imgs 目录 1.jpg 的绝对路径是:" + context.getRealPath("/imgs/1.jpg")); }
HttpServletRequest类
获取请求参数的常用方法
方法说明 | 功能描述 |
---|---|
getRequestURI() 获取请求的资源路径 | |
getRequestURL() | 获取请求的统一资源定位符(绝对路径) |
getRemoteHost() | 获取客户端的 ip 地址 |
getHeader() | 获取请求头 |
getParameter() | 获取请求的参数 |
getParameterValues() | 获取请求的参数(多个值的时候使用) |
getMethod() | 获取请求的方式 GET 或 POST |
setAttribute(key, value) | 设置域数据 |
getAttribute(key) | 获取域数据 |
getRequestDispatcher() | 获取请求转发对象 |
小练习:编一个表单,,其中包含用户名,密码,爱好,并在浏览器显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/RequestParamServlet" method="get">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
爱 好:<input type="checkbox" name="hobby" value="唱歌">唱歌
<input type="checkbox" name="hobby" value="跳舞">跳舞
<input type="checkbox" name="hobby" value="玩">玩</br>
<input type="submit" value="提交">
</form>
</body>
</html>
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String [] hobbys = req.getParameterValues("hobby");
PrintWriter out = resp.getWriter();
out.println("<html><body>");
out.println("<h1>"+ username + "</h1>");
out.println("<h1>"+ password + "</h1>");
for(int i=0;i<hobbys.length;i++){
out.print("<h1>"+ hobbys[i] + "</h1>");
}
out.println("</body></html>");
}
关于HttpServletRequest请求中文乱码的解决方法:
req.setCharacterEncoding("utf-8");
HttpServletResponse类
字节流 getOutputStream(); 常用于下载(传递二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
两个流同时只能使用一个。
关于HttpServletResponse请求中文乱码的两种解决方法:一般用第二种
resp.setCharacterEncoding("utf-8");
resp.setHeader("Content-Type","text/html;charset=utf-8")
resp.setContentType("text/html;charset=utf-8");
请求的重定向
resp.sendRedirect("http://localhost:8080");
练习:输入用户名sa,密码123,跳转登录成功页面。
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/LoginServlet" method="post">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit" value="提交">
</form>
</body>
</html>
success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
欢迎欢迎,热烈欢迎。
</body>
</html>
LoginServlet.java
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if("sa".equals(username)&&"123".equals(password)){
resp.sendRedirect("success.html");
}else{
resp.sendRedirect("login.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
请求的转发
请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。
练习:从一个Servlet转发到另一个Servlet,输出你好,呆瓜
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
req.setAttribute("name","你好呆瓜");
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/Servlet2");
requestDispatcher.forward(req,resp);
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
String name=(String)req.getAttribute("name");
out.println("<html><body>");
out.println("<h1>"+ name + "</h1>");
out.println("</body></html>");