一、概念
1.1 servlet概念:
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。 简单来说,Servlet是服务器端的一段程序(代码、功能实现),可交互式的处理客户端发送到服务器的请求,并完成操作响应。并支持动态网页技术。JavaWeb程序开发的基础,JavaEE规范(一套接口)的一个组成部分。它是由服务器厂商实现的。
1.2 Servlet的核心作用
1. 接收客服端请,完成操作任务
2. 动态生成网页,网页数据可以改变
3. 将包含操作结果的动态网页响应给客服端
1.3 Servlet的核心目录结构
—web :存放需要部署的网站项目
——WEB-INF :核心内容,分别是以下内容
———classes :存放.class文件(XxxServlet.class)
———lib :储存所需jar包
———web.xml :web配置文件
——index.html/index.jsp.index.css/images等
见idea目录结构如下图: (因为idea会自动处理部署的文件并打包成war包的形式储存在out文件中,所以我们在使用IDEA时不用自己创建classes文件)
1.4 IDEA工具内创建核心目录结构
因为我们使用的是idea,如果去项目目录创建该Servlet目录结构过于繁琐,所以我们可以使用idea在工具内创建目录结构(可以在配置tomact时提前创建好都是OK的!)
1.5 Servlet的开发步骤
1.5.1 开发环境
1、搭建开发环境,并创建Servlet核心目录结构
2、实现javax.serlvet.Servlet接口,覆盖5个方法
3、在核心的servlet()方法中书写输出语句,验证访问结果/
4、将编译后的.class文件放置在WEB-INF/classes中
5、web.xml文件中添加配置信息
二、实现Servlet
2.1 创建servlet的三种方法
1.实现servlet接口,重写和接口中的init(),service(),destory()等方法
2.继承GenericServlet,重写父类中的service()方法
3.继承HTTPServlet,重写父类中的doGET()doPost()方法 ->目前用的方法
2.2 doGET与doPost()方法的区别
doGet是处理客户端发来的Get请求,doPost是处理客户端发来的Post请求,它们的区别可以从以下几个方面来说明:
1、客户端(一般指浏览器)生成的方式
get:form中method属性为get时;或者直接在URL地址栏中输入URL,需要传递参数时,直接在URL后面拼接?name=张三&age=18这样的查询参数字符串;
post:form中method属性为post。
2、客户端数据传送方式
get:表单数据存放在URL地址后面。所有get方式提交时HTTP中没有消息体;
post:表单数据存放在HTTP协议的消息体中以实体的方式传送到服务器。
3、服务器获取数据方式
get:服务器采用Servlet中的doGet来获取变量的值;
post:服务器采用Servlet中的doPost来获取数据。
4、传输的数据量
get:数据量长度有限制,一般不超过2kb。因为是参数传递,且在地址栏中,故数据量有限制;
post:适合大规模的数据传送。因为是以实体的方式传送的。
5、安全性
get:安全性差。因为是直接将数据显示在地址栏中,浏览器有缓冲,可记录用户信息。所以安全性低;
post:安全性高。因为post方式提交数据时是采用的HTTP post机制,是将表单中的字段与值放置在HTTP HEADER内一起传送到ACTION所指的URL中,用户是看不见的。
6、传输速度上的差别
doget传输速度高于dopost传输速度。
2.3 继承HTTPServlet
HttpServlet抽象类的内部继承了GenericServlet抽象类(证明HttpServlet有了上面我们说到的那四个方法),并扩展提供了适用于Web站点的HTTP协议的几个方法,也就是说HttpServlet的子类至少必须重写一个方法,该方法通常是如下这几个方法:
doGet,如果 servlet 支持 HTTP GET 请求 ---->用于查找
doPost,用于 HTTP POST 请求 ----->增加
doPut,用于 HTTP PUT 请求 ----->修改 -----------restful风格
doDelete,用于 HTTP DELETE 请求 ---->删除
init 和 destroy,用于管理 servlet 的生命周期内保存的资源
getServletInfo,servlet 使用它提供有关其自身的信息
注意:因为我们是继承了GenericServlet抽象类,所以没有理由再去重写 service 方法。service 通过将标准 HTTP 请求分发给每个 HTTP 请求类型的处理程序方法(上面列出的 doXXX 方法)来处理它们。(只需要使用扩展的Http的所需方法即可)
java代码:
public class ServletResourceCode extends HttpServlet {
@Override
public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
/*
* 获取前端request传进来的参数
* */
System.out.println("接收到通过GET方式传输的参数,用户名:"+
httpServletRequest.getParameter("username")+
"密码:"+
httpServletRequest.getParameter("password"));
}
public void doPost(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
System.out.println("接收到通过POST方式传输的参数,用户名:"+
httpServletRequest.getParameter("username")+
"密码:"+
httpServletRequest.getParameter("password"));
}
}
index,jsp配置表单
web.xml配置
2.4 HttpServletRequest对象详解
2.4.1 1 HttpServletRequest常用方法
2.4.1 获得客户机信息:
2.4.2 获得客户机请求头
2.4.3 获得客户机请求参数(客户端提交的数据)
package com.request_reponse;
/**
* @author zyh
* @version 1.0
* @items
* @Date:on 2021/8/10 at 19:59
*/
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.util.Arrays;
import java.util.Map;
/**
* 1.HttpServletRequest:是servlet中操作请求和响应报文,只不过操作报文的形式是通过这个对象来修改的
*/
public class Request extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
* 因为servlet容器调用这个servlet的时候会将request这个对象传进来,所以我们直接用这个对象就可以了
* 为什么servlet的doGet方法或者service()方法不需要返回值?
* 因为servlet容器会去实例化这一个HttpServletRequest对象,当servlet容器调用这个doGet()方法的时候,传的形参是这个对象的地址,
* 在doGet()中对这个对象做的修改会实际修改到内存中,所以在doGet()调用完成以后,servlet容器拿到的这个对象就已经是修改好了的了
* 说白了就是引用类型传参
*
* */
/**
* 设置请求的编码格式为:UTF-8
*/
req.setCharacterEncoding("UTF-8");
/**
*获取请求的URL和URI ,URI是servlet在项目中的映射地址 URL是http请求的完整地址
*/
System.out.println("请求的URL是+"+req.getRequestURL());
System.out.println("请求的URI是+"+req.getRequestURI());
//把参数列表打印出来
System.out.println("请求参数是:"+req.getQueryString());
/**
* 浏览器的一些信息
*/
System.out.println("请求的主机明是:"+req.getRemoteHost());
System.out.println("请求的主机IP是:"+req.getRemoteAddr());
System.out.println("请求端口号是:"+req.getRemotePort());
/**
* getHead可以根据请求头部的键俩获取相应的值
*/
System.out.println(req.getHeader("user-agent"));
/**
* 获取客服端的请求参数:
* 1.request.getParameter() -> 原生的servlet用的最多的方法
* 2.request.getParameterValues() -> 当同一个键有多个值的时候用这个方法
* 3.request.getParameterName() -> 获取所用的参数名,返回值是一个枚举类
* 4.request.getParameterMap() -> 以Map的形式获取参数,获得所有的参数键值对
*/
System.out.println("客服端参数:"+req.getParameter("localhost"));
Map<String, String[]> map = req.getParameterMap();
System.out.println(Arrays.toString(map.get("a")));
System.out.println(Arrays.toString(map.get("b")));
}
}
2.4.4 请求时中文产生乱码解决思路
直接使用request.setCharacterEncoding("UTF-8")来处理即可
2.5 HttpServletResponse对象详解
2.5.1 负责向客户端(浏览器)发送数据的相关方法:
2.5.2 负责向客户端(浏览器)发送响应头的相关方法
2.5.3 负责向客户端(浏览器)发送响应状态码的相关方法
2.5.4 设置http响应头控制浏览器定时刷新网页(refresh)
package com.request_reponse;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zyh
* @version 1.0
* @items
* @Date:on 2021/8/10 at 21:37
*/
public class Response extends HttpServlet {
/**
* 发送数据的方式:
* 1.response.getOutStream() -->可以向浏览器返回一个二进制文件
* 2.response.getWriter() -->这个方PrintWriter对象,可以向浏览器写入HTML文件,
* 也可以写JSON等其他文件,print和write都能向前端返回数据,但是print的功能要多一点
*
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 一般来说,我们去写servlet的时候,为了避免乱起,我们都会在前面写上:
* 1.request.setCharacterEncoding("UTF-8")
* 2.response.setContentType("MIME类型;charset=utf-8")
*/
req.setCharacterEncoding("UTF-8");
/**
* 设置了返回资源的MIME类型,并且设置了资源的编码为UTF-8
*/
resp.setContentType("text/html;charset=utf-8");
/**
* 设置相应的状态码
* 可以做一些异常处理的时候,设置响应码
*/
resp.setStatus(404);
/**
* 设置响应头来控制浏览器的行为:
* response.setHeader();
* 1.控制浏览器刷新的页面
* 2.控制浏览器重定向 -->重定向后 Http状态码会修改为302
*/
//resp.setHeader("Refresh","5;url=/request");
resp.sendRedirect("/request");
}
}
三、 重定向和转发
3.1 转发
案例
实现从OneServlet中转发到TwoServlet
- OneServlet向请求域中添加了一个键和值,转发给TwoServlet
- TwoServlet就从请求域中取出键和值,打印到浏览器上。
代码:
oneservlet
package com.itheima.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(name = "Demo6OneServlet", urlPatterns = "/one")
public class Demo6OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("这是One<br/>");
//向请求域中添加键和值
request.setAttribute("name","Jack");
request.setAttribute("age", 20); //整数类型
String name = (String) request.getAttribute("name");
int age = (int) request.getAttribute("age");
//从请求域中取出值
out.print("名字:" + name + "<br/>");
out.print("年龄:" + age );
out.print("<hr/>");
//删除其中一个
request.removeAttribute("age");
//从请求域中取出值,直接输出Object对象
out.print("名字:" + request.getAttribute("name") + "<br/>");
out.print("年龄:" + request.getAttribute("age") );
System.out.println("这是one");
//开始转发,参数是:要跳转到的地址
request.getRequestDispatcher("/two").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
TowServlet
package com.itheima.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(name = "Demo7TwoServlet", urlPatterns = "/two")
public class Demo7TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("这是Two,从请求域中取出one中的值:" + request.getAttribute("name"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
转发的特点
地址栏不发生变化,显示的是上一个页面的地址
请求次数:只有1次请求
根目录:http://localhost:8080/项目地址/,包含了项目的访问地址
请求域中数据不会丢失
转发使用哪个方法?
request.getRequestDispatcher("/地址").forward(request, response);
3.1 请求重定向指:
重定向案例
从OneServlet重定向到TwoServlet
- 在OneServlet中向请求域中添加键和值
- 使用重定向到TwoServlet,在TwoServlet中看能否取出请求域的值
代码:
oneservlet
package com.itheima.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(name = "Demo6OneServlet", urlPatterns = "/one")
public class Demo6OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("这是One<br/>");
//向请求域中添加键和值
request.setAttribute("name","Jack");
request.setAttribute("age", 20); //整数类型
String name = (String) request.getAttribute("name");
int age = (int) request.getAttribute("age");
//从请求域中取出值
out.print("名字:" + name + "<br/>");
out.print("年龄:" + age );
out.print("<hr/>");
//删除其中一个
request.removeAttribute("age");
//从请求域中取出值,直接输出Object对象
out.print("名字:" + request.getAttribute("name") + "<br/>");
out.print("年龄:" + request.getAttribute("age") );
System.out.println("这是one");
//开始转发,参数是:要跳转到的地址
//request.getRequestDispatcher("/two").forward(request, response);
//使用重定向
response.sendRedirect("two");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
twoservlet
package com.itheima.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(name = "Demo7TwoServlet", urlPatterns = "/two")
public class Demo7TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("这是Two,从请求域中取出one中的值:" + request.getAttribute("name"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
重定向的特点
地址栏:显示新的地址
请求次数:2次
根目录:http://localhost:8080/ 没有项目的名字
请求域中的数据会丢失,因为是2次请求
疑问 问:什么时候使用转发,什么时候使用重定向?
如果要保留请求域中的数据,使用转发,否则使用重定向。
以后访问数据库,增删改使用重定向,查询使用转发。
问:转发或重定向后续的代码是否还会运行?
无论转发或重定向后续的代码都会执行
小结:重定向和转发的区别