日升时奋斗,日落时自省
目录
1、HttpServlet
2、HttpServletRequest
2.1、GET请求中的参数
2.2、获取POST请求中的参数(FORM)
2.3、获取POST请求中的参数(JSON)
3、HttpServletResponse
3.1、设置状态码
3.2、页面跳转
3.3、页面刷新
我们写Servlet代码的时候,首先第一步就是先创建类,继承自HttpServlet,重写其中要紧的方法
核心方法:
方法名称 | 调用时机 |
init | 在HttpServlet实例化后只调用了一次 |
destroy | 在HttpServlet实例不再使用的时候调用一次 |
service | 收到HTTP请求的时候用 |
doGet | 收到GET请求的调用(由service调用) |
doPost | 收到POST请求的调用(由service调用) |
doPut/doDelete/.... | 收到其他请求的时候调用(由service调用) |
此处方法来演示一帆:
首先先看一下service方法,看一下对应的jidea提供的service的源码
剩下的就是init和destroy方法
那我们这里就创建一个Maven项目此处就叫做(hello_servlet3),以下直接写出这两个方法,使用idea中smart tomcat插件直接运行(附代码)
@WebServlet("/hello3")
public class Hello_Servlet3 extends HttpServlet {
@Override
public void init() throws ServletException {
//可以在这里重写 init 方法
//输入 一些咱们自己的 “初始化” 相关的逻辑
System.out.println("init ");
}
@Override
public void destroy() {
System.out.println("destroy ");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//把数据显示到服务器控制台
System.out.println("hello3");
//把数据写回浏览器
resp.getWriter().write("hello world3");
}
}
HttpServlet类中主要也就是针对请求和响应来,所以以下就是针对HttpServletRequest和HttpServletResponse类来进行细致化了解
当Tomcat通过Socket API读取HTTP请求(字符串),并且按照HTTP协议的格式把字符串解析成HttpServletRequest对象
接收HTTP的请求来的req,能做到调用基本的方法,完成我们的后端操作(以下是常用API)
方法 | 描述 |
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 getHeader(String name) |
以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() |
返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长 度未知则返回 -1。 |
InputStream getInputStream() |
用于读取请求的 body 内容. 返回一个 InputStream 对象 |
创建一个ShowRequestServlet类来演示对应的方法(以下附加代码 ,注释比较详细,一下还有图解)
如果一直是按照我们这里创建的目录和注解,直接输入路径 :127.0.0.1:8080/hello_servlet3/showRequest
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//这里是设置响应的 content-type 告诉浏览器 显影就body 里的数据格式是啥样的
//setContentType 调用的第一个参数 是数据类型此处是text/html 第二个参数 是设计字符集
resp.setContentType("text/html; charset=utf8");
// 这个 StringBuilder 把这些 api 的结果拼起来 ,统一写响应中
StringBuilder stringBuilder=new StringBuilder();
//协议名称 和 版本号 getProtocol 反馈出来的是 协议名称 和 版本号
stringBuilder.append(req.getProtocol());
stringBuilder.append("
");
//方法 此处的getMethod http请求时使用的方法 是什么 基本常见的就是 GET POST
stringBuilder.append(req.getMethod());
stringBuilder.append("
");
//字符串 getRequestURI 从请求中得到一个地址
stringBuilder.append(req.getRequestURI());
stringBuilder.append("
");
//getQueryString 针对网址后面 查询字符串
stringBuilder.append(req.getQueryString());
stringBuilder.append("
");
//获取到 header 中所有的键值对 getHeaderNames方法 返回的是一个枚举类型
Enumeration headerNames=req.getHeaderNames();
//此处采用类似于迭代的方式 将所有的剪键值对 打印出来
while(headerNames.hasMoreElements()){
//每次都会提取下一个元素 key值
String headername=headerNames.nextElement();
//此处getHeader 表示的请求头的对应值 也就是 value值
stringBuilder.append(headername+":"+req.getHeader(headername));
stringBuilder.append("
");
}
//前面使用了 StringBuild 来接收这些字符串 此处就是将这些字符串 响应给页面
resp.getWriter().write(stringBuilder.toString());
}
}
上面介绍了基本的操作,查看一些HTTP发送来的信息(其实把这些抓个包也能看到,可以作为对比)
剩下的还有很多方法,
这里在罗列两个刚刚没有提到的方法,getCharacterEncoding()直接传入字符集就可以了,也是设定字符集的方法,但是我们上面已经提及到了一个可以设置字符集的:getContentType(),里面就可以带着设置了字符集,如果两个都在同一个类里面出现的时候getContentType()更加强制,所以这个功能也更强,这里也就算是提一下,认识就行,不能见了不认识,也比较常见
还有一个就是:getContentLength(),以字节为单位返回请求主体的长度,如果长度未知则返回-1
GET请求中的参数一般都是通过query string 传递给服务器的也就是刚刚演示到的查询字符串
127.0.0.1:8080/hello_servlet3/showRequest?studentId=10&classId=20
此时浏览器通过query string 给服务器传递里两个参数一个是studentId 还有一个就是classId对应值就是 10 和 20 其实一个键值对表示的
这里创建一个GetParameter类来演示这个效果,这个类仍然在这个项目当中(代码附加详细注释)
@WebServlet("/getparameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//预测一个浏览器会发一个形如 /getParameter?student=10&classId=20请求
//借助req 里的getParameter 方法就能拿到query string 中的键值对内容
String student=req.getParameter("studentId");
String classId=req.getParameter("classId");
resp.setContentType("text/html");
//这里就使用 以下这设置字符集的操作 这里设置,上面就不需要设置了
resp.setCharacterEncoding("utf8");
//上面 setContentType 可以同时设置两个 也可以分开设置同时 设置下面的字符集
//resp.setCharacterEncoding("utf-8");
//设置字符集这些都要写在write上面 ,不能写在下面的 要不就不会生效了
//响应在程序内部
System.out.println("学生 ="+student+"序号 ="+classId);
//下面直接响应给页面显示出来
resp.getWriter().write("学生 ="+student+"序号 ="+classId);
}
}
POST请求的参数一般通过body传递给服务器,body中的数据格式有很多种类,form表单也是一种形式,仍然可以操作类获取参数值,创建一个的类,叫做POSTParameterServlet,其实和上一个代码是一样的,只是为了区分开form表单和query string
Servlet 的java代码:
@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String student=req.getParameter("studentId");
String classId=req.getParameter("classId");
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("studentId ="+student+"classId ="+classId);
}
}
form表单的代码:
Document
如何操作?
如果POST请求中的body是按照JSON的格式来传递,获取参数此处代码有所变动
此处新创建一个类,来接收JSON形式的,该类叫做:PostParameter2Servlet
JSON是以body的形式来传输数据的,需要对这个body进行处理
body里面存放的也是键值对,但是这里取值就不同了,java代码中需要创建一个类,定义并且与body相同的属性(前后端就会先约定好,需要的属性,下面图解操作)
Servlet代码:
class Student{
public int studentId;
public int classId;
}
@WebServlet("/postParameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过这个方法处理 body 为 json 格式的数据
//直接把 req 对象里 body 完整读取出来
//getInputStream
// 在流对象中读多少个字节 取决于 content - type
//getContentLength 获取字节的长度
int length=req.getContentLength();
//创建一个缓存 大小就是 获取字节大小的缓存大小
byte[] buffer=new byte[length];
//此处就 需要获取body字节数
InputStream inputStream= req.getInputStream();
//将这个字节流 读入缓存中
inputStream.read(buffer);
//把这个字节数组 构造成 String 打印出来 String中的第一个参数就是 缓存数组 第二个参数就是从第几个开始 从0 开始
//第三个参数就是 缓存数组的长度 第四个参数就是 设定字符集
String body=new String(buffer,0,length,"utf8");
//打印 在控制台
System.out.println(body);
//响应到页面
resp.getWriter().write(body);
}
}
JSON代码:
此处使用的就是postman构造一个post请求进行发送
当然了这里提及到JSON格式的传输使用字节流读取并响应的,看着有点繁琐,能不能一步到位,当然可以,只需要改动后端代码就可以
更改后的后端代码:(但是这里需要导入Jackson的依赖,需要去中央仓库找 和前面提到的Servlet依赖是一样的方法 输入网址的地方输入nvm)
附后端改后的代码:
class Student{
public int studentId;
public int classId;
}
@WebServlet("/postParameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建一个 ObjectMapper 能够将JSON格式转换为 java
ObjectMapper objectMapper=new ObjectMapper();
//readValue 将一个 json 格式的字符串转换成 java 对象
/*
* 1、 从body 中读取 json 格式 字符串
* 2、根据第二个参数对象, 创建 Student 实例
* 3、解析上述json 格式的字符串 处理成 map 键值对结构
* 4、变量所有键值对 看键的名字 和 Student那个实例属性名字匹配 就把value值赋值上去
* 5、返回Student实例
* */
Student student=objectMapper.readValue(req.getInputStream(),Student.class);
System.out.println(student.studentId+","+student.classId);
resp.getWriter().write(student.studentId+","+student.classId);
}
}
操作:启动服务器 然后 postman向服务器发送消息
演示:
总结:
<1>此处使用的自定义了Student类 ,这个类用来表示解析之后生成的JSON对象,这个类的属性和名字和类型要和JSON字符串的key相对应
<2>Jackson依赖的核心类就是ObjectMapper,其中的readValue方法把一个JSON字符串转换成Java对象,其中的writeValueAsString方法把一个java对象转成JSON格式字符串
<3>readValue的第二个参数为Student类型(也就是我们自定义的类型),通过这个类对象,在readValue1的内部就可以借助反射机制来构造出Student对象,并且根据JSON中key,把对应的value赋值给Student的对应字段
以上操作基本已经全部演示了一下(有想法的友友们,可以自己尝试自己试一下)
Servlet中的方法接收到请求后计算出响应,把响应的数据设置到HttpServletResponse对象中
后来Tomcat就会把这个HttpServletResponse对象按照HTTP协议的格式,转换成一个字符串,并通过socket写回给浏览器
此处也会演示HttpServletResponse相关的一些API
方法 | 描述 |
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 getWriter() | 用于往 body 中写入文本格式数据. |
OutputStream getOutputStream() |
用于往 body 中写入二进制格式数据. |
此处创建一个StatusServlet类,注解设置为@WebServlet("/status")
附代码(加详细注释):
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//这里就不再演示接收请求了进行请求处理了, 此处直接响应一个 404
//其实这个响应不一有啥反应 空白页
resp.setStatus(404);
// 但是这里不设置 body 设置一下 响应数据类型
resp.setContentType("text/html;charset=utf8");
//响应的一个html的语句 仅仅只是为了演示效果
resp.getWriter().write("404 没有找到");
}
}
这里代码写好以后,直接在idea中启动程序
以上最后提到了针对响应报错的一个方法sendError,我个人感觉挺好用,其实可以尝试一下,毕竟只需要一行代码;
这里创建一个RedirectServlet类 注解设置为 @WebServlet("/Redirect")
附代码(加详细注释):
@WebServlet("/Redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//sendRedirect方法能直接将页面跳转到 参数的 url 中
resp.sendRedirect("https://www.sogou.com");
//下面这两行 其实表达的是和上面一行代码 的意思是一样的 setStatus设置状态码 302表示重定向
// resp.setStatus(302);
//setHeader 第一个参数写 Location 就是我们在HTTP 抓包的时候看见的 重定向 key 第二个参数就是 url
// resp.setHeader("Location","https://www.sogou.com");
}
}
创建一个AutoRefreshServlet类 ,注解设置为@WebServlet("/autoRefreshServlet")
附代码(加详细注释):
@WebServlet("/autoRefreshServlet")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//执行操作刷新操作 第二个参数是一秒 也就是每一秒刷新一次
resp.setHeader("Refresh","1");
//获取时间 但是这里获取的是一个时间戳 还需要转换一下时间格式
long timeStamp=new Date().getTime();
//下面使用SimpleDateFormat类 进行java的时间格式转换 ,这个可以去查看一下
//因为不好记 而且语言与语言之间不一样
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//调用SimpleDateFormat中的format方法 转换时间格式
String date = format.format(timeStamp);
//响应到页面上
resp.getWriter().write("timeStamp:"+date);
}
}