Servlet的API就是一组类和方法
其中主要的三个类有
HttpServlet
HttpServletRequest
HttpServletResponse
HttpServlet
这是编写Servlet代码用到的核心类
通过继承这个类 并重新写其中的方法 让tomcat去调用到这里的逻辑
方法名称 | 调用时机 |
---|---|
init | 在HttpServlet实例化之后被调用一次 |
destroy | 在HttpServlet示例不再使用的时候调用一次 |
service | 收到HTTP请求的时候调用 |
doGet | 收到GET请求的时候调用(由service方法调用) |
doPost | 收到POST请求的时候调用(由service方法调用) |
doPut/doDelete/doOptions | 收到其他请求的时候调用(由service方法调用) |
webapp被加载的时候 执行init 使用这个方法进行一些初始化操作
webapp在被销毁的时候(tomcat结束) 执行destroy 使用这个方法进行一些收尾工作 但是这个方法不保证能够调用到 所以关闭tomcat还可以通过 8005端口给tomcat发起特殊请求(可以执行destroy) tomcat就关闭了 或者直接杀死tomcat进程(无法执行destroy)
每次收到请求都会执行service 处理每个请求
Servlet的生命周期(什么阶段 做什么事)
- webapp刚被加载的时候 调用servlet的init方法
- 每次收到请求的时候 调用service方法
- webapp要结束的时候 调用destroy方法
对于上述的方法 浏览器只能方便构造get请求 不方便构造其他的方法 所以可以使用postman
创建一个MethodServlet类
public class MethodServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("doPost");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("doPut");
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("doDelete");
}
}
启动tomcat
然后我们使用postman软件使用上述的各种方法发出请求
HttpServletRequest
Tomcat收到HTTP请求 就会被解析成下面对象
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本 |
String getMethod() | 返回请求的HTTP方法的名称 例如GET POST 或者 PUT |
String getRequestURI() | 从协议名称直到HTTP请求的第一行的查询字符串中 返回该请求的URL的一部分 |
String getContextPath() | 返回指示请求上下文的请求URI部分 |
String getQueryString() | 返回包含在路径后的请求URL中的查询字符串 |
Enumeration getParameterNames() | 返回一个String对象的枚举 包含在该请求中包含的参数的名称 |
String getParameter(String name) | 以字符串形式返回请求参数的值 或者如果参数不存在则返回null |
String[] getParameterValues(String name) | 返回一个字符串对象的数组 包含所有给定的请求参数的值 如果参数不存在则返回null |
Enumeration getHeaderNames(String name) | 返回一个枚举 包含该请求中包含的所有头名 |
String getHeader(String name) | 以字符串形式返回指定请求头的值 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称 |
String getContentType() | 返回请求主体的MIME类型 如果不知道类型则返回null |
int getContentLength() | 以字节为单位返回请求主体的长度 并提供输入流 或者如果长度未知则返回-1 |
InputStream getInputStream() | 用于读取请求的body内容 返回一个InputStream对象 |
注意:URI 唯一资源标识符 URL 唯一资源定位符
Enumeration getParameterNames()
String getParameter(String name)
可以通过一些方式 给服务器传递自定义的数据(query string、body(键值对格式))
Enumeration getHeaderNames(String name)
String getHeader(String name)
获取到请求头里的键值对Tomcat收到请求之后也会把请求头解析成Map
示例:
@WebServlet("/Reques")
public class RequesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将调用req的各种方法汇总到一个字符串中
StringBuilder respBody = new StringBuilder();
respBody.append(req.getProtocol());
respBody.append(req.getMethod());
respBody.append(req.getRequestURI());
respBody.append(req.getContextPath());
respBody.append(req.getQueryString());
//拼接header
Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()){
String header = headers.nextElement();
respBody.append(header+":"+req.getHeader(header));
}
//统一返回结果
resp.getWriter().write(respBody.toString());
}
}
让网页换行显示
@WebServlet("/Reques")
public class RequesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
//将调用req的各种方法汇总到一个字符串中
StringBuilder respBody = new StringBuilder();
respBody.append(req.getProtocol());
respBody.append("<br>");
respBody.append(req.getMethod());
respBody.append("<br>");
respBody.append(req.getRequestURI());
respBody.append("<br>");
respBody.append(req.getContextPath());
respBody.append("<br>");
respBody.append(req.getQueryString());
respBody.append("<br>");
//拼接header
Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()){
String header = headers.nextElement();
respBody.append(header+":"+req.getHeader(header));
respBody.append("<br>");
}
//统一返回结果
resp.getWriter().write(respBody.toString());
}
}
相当于把http请求详情打印出来
String getParameter(String name)
如何获取到query string 和 body的数据?
示例:
获取query string
@WebServlet("/Pameter")
public class PameterServlet extends HttpServlet {
//约定 客户端使用query string传递数据
//例如 username=zhangsan&password=123456
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
resp.getWriter().write("ok!");
}
}
获取body(只考虑form表单格式)
@WebServlet("/Pameter2")
public class Pameter2Servlet extends HttpServlet {
//预期让客户端发出一个POST请求 同时使用form格式的数据 在body中把数据传递过来
//body 形如:
//username=张三&password=123
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username =req.getParameter("username");
String password =req.getParameter("password");
System.out.println("username="+username);
System.out.println("password="+password);
resp.getWriter().write("ok!");
}
}
body为json的格式
我们要使用这种格式要用jackson jackson也是第三方库需要通过maven从中央仓库把这个库下载并导入到项目中
maven地址: https://mvnrepository.com/
我们在2.14版本之中选择一个
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
添加到pom.xml文件后下载依赖
如果报红可以点击右侧的maven然后重新下载
然后我们可以使用一个ObiectMapper类的方法
把一个对象映射到JSON字符串 也可以把JSON字符串映射到对象
创建一个JsonServlet类
我们使用了objectMapper.readValue()这个方法将json字符串给解析成了Java对象
其中第一个参数是一个对象流 表示了json是从请求的body使用通过getInputStream得到对象 进一步的读取出来的
第二个参数 则是指定的类型 当前得到的json字符串需要转换成一个Java对象需要指定对象的类型就和上面的User类一个类型(定义一个类 让这个类里的属性的名字和类型和json字符串相匹配)
通过上面的方法就把json字符串映射成一个Java对象的过程
我们打开psotman测试
可以看到我们可以将一个json格式的body请求转换成了一个java对象
服务器已经顺利的把客户端发来的json格式数据给进行解析
readValue就把req的body的字符串给解析 然后构造了User对象
HttpServletResponse
同样也是和HTTP响应数据相匹配(状态码 各种header body)针对这些属性就可以进行"设置"
请求对象 拿到之后的目的 是为了获取里面的属性(读)
响应对象 拿到之后的目的 是为了设置里面的属性(写)
对于doXXX这样的方法 就是要根据请求计算响应
请求对象 是Tomcat收到请求之后 对http协议解析得到的对象
响应对象 是Tomcat创建空的对象 我们在代码中把响应对象的属性设置好返回给客户端
方法 | 描述 |
---|---|
void setStatus(int sc) | 设置状态码 |
void setHeader(String name,String value) | 设置一个带有给定名称的值的header 如果name已存在 则覆盖旧的值 |
void addHeader(String name,String value) | 添加一个带有给定名称和值的header 如果name已存在 不覆盖旧的值 并添加新的键值对 |
void setContentType(String type) | 设置被发送到客户端的响应的内容类型 |
void setCharacterEncoding(String charset) | 设置被发送到客户端的字符编码(MIME字符集)例如 UTF-8 |
void sendRedirect(String location) | 使用指定的重定向位置URL 发送临时响应到客户端 |
PrintWriter() | 用于往body中写入文本格式数据 |
OutputStream getOutputStream() | 用于往body中写入二进制格式数据 |
注意:
使用了addHeader haeder中就可能出现key相同的两个键值对
设置状态码示例:
将状态码设置成200
设置成500
设置成404
设置响应报头示例:
此处通过refresh属性设置浏览器自动刷新(每隔两秒返回一个时间戳)
让页面重定义到百度主页
我们打开抓包工具八爪鱼
然后浏览器输入
就会自动跳转到百度网页
从八爪鱼可以看出我们的浏览器先访问了这一个url然后才跳转百度网页
浏览器看到开头请求的两个字段就知道要跳转到百度了
301是永久重定向
302是临时重定向
或者使用 resp.sendRedirect(“https://www.baidu.com”);一次性把两个步骤合到一起
让服务器返回一个html数据
浏览器看到的是
这是因为在IDEA里的中文字符串一般都是utf8的编码
浏览器会跟随系统的编码windows简体中文版本默认的编码是gbk 使用要按照gbk的方式匹配
我们就可以使用
resp.setContentType("text/html;charset=utf8");