文章目录
一、Servlet的API
1.HttpServlet
- 写一个Servlet代码,往往要继承这个类,重写里面的方法。目的就是为了把写好的代码,“插入到”Tomcat中。
Servlet代码,只需要继承HttpServlet就行,不需要写一个main方法。因为写的程序是放在Tomcat上面运行的。在Tomcat程序里有main方法。
Tomcat通过反射,在代码中new一个我们自己写的子类对象,这个子类对象在执行doGet的时候,会执行重写的doGet代码。相当于把自己写的代码业务,镶嵌进Tomcat的程序中运行。相当于自定义了Tomcat的行为。
1.HttpServlet类中的方法
都可以在子类中进行重写
- init方法:在实例化之后自动执行一次。借住这个方法完成一些数据的初始化操作。
- destroy方法:不再使用的时候执行一次。往往用来释放资源
- service方法:每次收到HTTP请求的时候调用执行
子类重写了这三个方法之后,都不需要手动调用。而是通过Tomcat在合适的时机自动调用。
这三个方法调用的时机,就被成为Servlet的生命周期(面试题)。
生命周期就是什么时间点,该做什么事。
service一般会被doGet、doPost代替。
如果不重写service,在父类(HttpServlet)中,自己的service就会根据请求的方法,来分别调用doGet、doPost、doPut…
destroy大概率执行不到,因为一个Servlet不用了,说明Tomcat要关闭了。
Tomcat的关闭方式有两种:
1.直接结束Tomcat的进程。这种情况来不及调用destroy
2.通过8005管理端口,给Tomcat发送一个“停机”指令,这种时候是能够执行destroy的。但在实际开发中,第一种更常见。
doPost方法:
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
resp.getWriter().write("doPost ");
}
}
使用postman来构造Post请求。
返回了doPost内容
2.HttpServletRequest
- 表示一个HTTP请求
Tomcat通过Socket API来读取HTTP请求(字符串),并且按照HTTP协议的格式把字符串解析成HttpServletRequest对象
- getProtocol() : 获取版本号 HTTP/1.1
- getMethod() : 获取请求的方法名 (GET、POST…)
- getRequestURI() :获取到URL的一部分
URL:唯一资源定位(地址)符,(相当于住址)
URI:唯一资源标识符 ,(相当于身份证号)
都具有唯一性,经常会拿URL来作为URI
- getContextPath() : 得到请求的一级路径
- getQueryString () : 返回URL中?后的查询字符串
query string本质上是键值对,根据key获取value
- getParameterNames : 获取到query string中所有的key
- getParameter(String name) : 根据key来获取值
- getParameterValues(String name) : 根据key来获取值, 存在重复的key,一个key有多个值。
- getHeaderNames : 获取请求头(header)键值对中所有的key
- getHeader :在herder中,根据key获取value
- 对getHeader的进一步封装
- getInputStream() : 得到一个流对象,读取这个流对象,得到整个请求的body。
都是获取请求对象的数据,只需要进行读取,不应该进行修改
@WebServlet("/show")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(req.getProtocol());
stringBuilder.append("<br>");
stringBuilder.append(req.getMethod());
stringBuilder.append("<br>");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("<br>");
stringBuilder.append(req.getContextPath());
stringBuilder.append("<br>");
stringBuilder.append(req.getContextPath());
stringBuilder.append("<br>");
stringBuilder.append(req.getQueryString());
stringBuilder.append("<br>");
//获取所有的header
Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()){
String key = headers.nextElement();
String value = req.getHeader(key);
stringBuilder.append("key = :"+key+ " value = :"+value);
stringBuilder.append("<br>");
}
resp.setContentType("text/html;charset=utf-8 ");
resp.getWriter().write(stringBuilder.toString());
}
}
1.直接通过query string传参
在服务器这边获取到请求的参数(Query String)。query string中的键值对都是程序员自定义的
@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//username=zhang&password = 123
String username = req.getParameter("username");
String password = req.getParameter("password");
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("username="+username+" password="+password);
resp.getWriter().write(stringBuilder.toString());
}
}
%E5%BC%A0%E4%B8%89%0A
如果是中文要记得,进行urlencode操作。
2.通过http请求的body来传递参数(POST)
@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//前端会构造 :POST /postParameter
//Content-Type:x-www-form-urlencoded
//username=zhan&password=1234
//不管参数是在querystring中还是在body中,都是通过getParameter()获取到
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username="+username+" password="+password);
resp.getWriter().write("OK");
}
}
1.直接通过form表单(body的格式就是query string 的格式)
Content-Type:application/x-www-form-urlencoded
2.直接使用json.(body的格式就是json的格式)
jackson
上面两种方式Servlet天然支持。而针对json格式的数据进行解析和构造,需要引入第三方库(jackson)
1.下载导入jackson到项目目录
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
2.使用jackson
一个类,两个方法
ObjectMapper类
对象- 映射。把json字符串,映射成一个Java对象<=>把Java对象映射成字符串
收到json字符串后,先映射成Java对象,进行业务处理。处理完成后再把Java对象映射成json字符串,通过响应返回
readValue方法:把json字符串,映射成一个Java对象
writeValueAsString方法:把Java对象映射成字符串
class Request{
public String username;//如果写成private,需要提供对应的getter和setter方法
public String password;
}
//1.把请求的body中的json字符串解析成java对称
ObjectMapper objectMapper = new ObjectMapper();
Request request = objectMapper.readValue(req.getInputStream(), Request.class);
1.把json字符串,映射成Java对象。
1.由于json字符串在Http请求的body中,所以要通过HttpServletRequest调用getInputStream方法来获取到body中的内容。
2.把获取到的流对象,直接传给readValue,内部就会进行读取,按照json的格式解析成Map(键值对),
3.把Map转换成一个Java对象。第二个参数来明确要转成什么对象,把“图纸”传进去,得到具体的java对象。readValue内部通过反射api创建出Request.class的实例。并且根据Request.class提供的属性名字,查询Map。把得到的结果赋值给对应的属性。
.class类对象:
写的java代码,要被javac编译成.class文件(二进制文件)。这个文件包含了.java源代码的核心信息(名字、属性、类型、方法、参数、访问限定符、继承关系、实现接口、注解等一系列信息)。当java进程启动时,就会读取.class文件,把这些二进制内容,读到内存中进行解析(这个过程叫做“类加载”)。类加载完毕后,就会在内存中得到一个类对象。类对象中,就包含了.class文件中的信息。这个类对象就相当于一个类的图纸,后续要构造这个类的实例,都是基于类对象来进行的。
2.把Java对象映射成Json字符串
Response response = new Response();
response.ok=true;
//2.把响应对象,转换成json字符串
String respJson = objectMapper.writeValueAsString(response);
1.通过传入的参数,获取到类对象。通过反射拿到都有哪些属性 ok
2.根据属性的名字拿到属性的值 true
3.把上述属性名和值按照json的格式构造成字符串。{ ok:true }
class Request{
public String username;
public String password;
}
class Response{
public boolean ok;
}
@WebServlet("/json")
public class JsonParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//约定请求格式如下:
//POST/json
//Content-Type:application/json
/**
* {
* username:"zhang",
* password:12345
* }
*/
/**约定响应的格式(也按照json组织)
* {
* ok:true
* }
*
*/
//1.把请求的body中的json字符串解析成java对称
ObjectMapper objectMapper = new ObjectMapper();
Request request = objectMapper.readValue(req.getInputStream(), Request.class);
System.out.println("username="+request.username);
System.out.println("password="+request.password);
Response response = new Response();
response.ok=true;
//2.把响应对象,转换成json字符串
String respJson = objectMapper.writeValueAsString(response);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
Content-Type :application/json
3.HttpServletResponse
- Servlet中doXXX方法的目的,就是根据请求计算出响应,把响应的数据放到HttpServletResponse对象中。Tomcat会自动的把这个对象按照HTTP协议的格式转换成字符串,通过Socket返回给客户端。
-
setStatus() :设置状态码
200成功 302重定向 403没有权限 404找不到 405方法没实现 500服务器出错
resp.setStatus(404); resp.sendError(404,"发送错误,返回自定义的出错信息");
-
setHeader():如果name已经存在,会覆盖旧值
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("refresh","1");
resp.getWriter().write(""+System.currentTimeMillis());
}
}
浏览器每秒钟自动刷新一次. 并显示当前的时间戳
- addHeader():不覆盖旧值,允许出现多个相同的key
resp.setContentType("application/json;charset=utf8");
设置类型和编码格式
- sendRedirect() : 直接构造重定向的响应
1.状态码是3开头的,比如302
2.header需要有一个Location属性,描述要跳转的哪里
resp.setStatus(302);
resp.setHeader("Location","https://www.baidu.com");
resp.sendRedirect("https://www.sogou.com");
- getWriter() : 向body中写入文本格式数据
- getOutputStream() : 向body中写入二进制格式数据
响应的body也是通过流对象的形式体现。写入就是输出流
request里的api都是get类型的方法
response里的api都是set类型的方法