Java Servlet(二)--- HttpServlet,HttpServletRequest,HttpServletResponse
文章目录
- Servlet
- HttpServlet
- HttpServletRequest
- 方法
- 使用方法
- HttpServletResponse
- 方法
- 方法的使用
- 写一个简单的网站
- 前端代码
- 前后端交互的部分
Servlet
Servlet是一组api,操作HTTP协议的,这组api是tomcat提供的
这组api,可以理解成事一个HTTP服务器框架
框架:我们自己写好的代码,让别人来帮咱们调用,一个程序的主体部分,都已经被其他大佬写完了,有些细节内容,允许我们自己插入咱们自己写的自定义的逻辑
如果不重写service,在父类(HttpServlet中)自己的service,就会根据请求的方法,来分别调用下面的doGet,doPost,doPut…(会通过if条件进行匹配是哪种请求)
HttpServlet
- 热加载和热部署
2. 带有异常调用栈(日志中)
3. 使用Postman发起一个请求,效果是在Postman这边会打印,在idea控制台这边也会打印
前端和后端,前端发送一个请求,后端这里接收请求,并做出响应
HttpServletRequest
- HttpServletRequest 表示了一个HTTP请求
- URL和URI,可以使用URL地址表示一个人的身份URI
方法
对方法的解释:
- 上述介绍的方法,都是get系列的方法(都是读的方法),没有set系列的(没有写的方法)
正是框架做出了限制,避免了我们不小心把发来的请求给改坏了的情况 - 当前拿到的HttpServletRequest,这里的数据都是客户端发来的。这些数据的内容已经确定下来了,我们是不应该修改的
使用方法
- StringBuilder 没加 synchronized
StringBuffer 加了 synchronized
加了synchronized就是线程安全的,也是不够严谨的,具体还是要看你的需求和代码的实际写法的 - html中,\n不能起到换行的效果,真正需要再网页上另起一行就需要用到 < br > 标签
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.util.Enumeration;@WebServlet("/show")
public class GetServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 调用上述api,把得到的结果构造成一个字符串,统一返回给客户端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.getQueryString());stringBuilder.append("<br>");// 获取所有的headerEnumeration<String> headNames = req.getHeaderNames();while(headNames.hasMoreElements()){String key = headNames.nextElement();String value = req.getHeader(key);stringBuilder.append(key + ":" + value + "<br>");}// 告诉浏览器,我们的数据是什么类型,任何一次服务器返回都应该做的事情resp.setContentType("text/html; charset=utf8");// 把上述内容整体返回到客户端中resp.getWriter().write(stringBuilder.toString());}
}
Postman中显示的内容
浏览器显示的内容
3. 在服务器这边获取到请求中的参数(Query String)
query string 中的键值对,都是我们自定义的。实际开发中会非常广泛地使用到query string 这样的机制。
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;@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 这里约定,程序中给出的query string 是usename=zhangsan & password=123// 上述query sting 会自动被tomcat解析为Map<String,String> 这样的结构// getParameter 就是在查询 Map<Sting,String> 里的内容String usename = req.getParameter("usename");String password = req.getParameter("password");// 就可以拿到这两内容做一些其他的处理了System.out.println("usename = " + usename);System.out.println("password = " + password);resp.getWriter().write("ok");}
}
结果:
最好不要写中文,最好使用urlencode,不然可能浏览器/服务器可能无法正确处理
4. 一个url中的query string,key,value,到底是谁负责定义的呢?到底定义成什么呢?
开会约定好,把开会的内容整理成一封邮件,大家都按照这里面的内容进行写请求和响应
- 除了 query string 之外,还可以通过http请求的body来传递参数(POST)
(1) 直接通过 form 表单
(body的格式就是 query string 的格式)
Content-Type:application/x-www-form-urlencoded
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;@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 约定,前端构造形如这样的请求// POST / postParameter// Content-Type: x-www-form-urlencoded// usename=zhangsan&password=123// 就需要再后端代码中,把 body中的值拿到// 获取值的方法,仍然是 getParameterString username = req.getParameter("usename");String password = req.getParameter("password");System.out.println("usename = " + username);System.out.println("password = " + password);resp.getWriter().write("ok");}
}
上面的query string 和 body的方式都是 Servlet天然支持的
(2) 直接使用json(现在特别流行这种写法)
(body的格式就是json)
Content-Type:application/json
手写json比较复杂,所以才引入了第三方库
json是Servlet自身不支持的,需要引入额外的第三方库
下载jackson
(1) 下载导入 jackson 到项目中,通过maven
类对象:
把json字符串转为java对象:
jackson从json字符串映射到java对象的过程:
举个例子:
上面也使用了反射,反射api属于非常规操作,除非万不得已,开发中不要随便使用反射。反射太灵活了,能做到很多事情,打破了很多现有的限制。
jackson对属性的处理:
反向操作的过程(将java对象转为json字符串的形式):
postman对于json的格式要求:
import com.fasterxml.jackson.databind.ObjectMapper;
// import org.omg.CORBA.Request;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;class Request{public String username;public String password;
}class Response{public boolean ok;
}@WebServlet("/json")
public class JsonParameterServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 此处约定格式如下:// POST /json//// {// usename:"zhangsan"// password:"123"// }// 此处也约定响应的格式,也按照json的格式来处理// {// ok:true// }// 把请求的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;// 把响应对象转成json字符串String respJson = objectMapper.writeValueAsString(response);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}
}
以上就是前后端交互的一部分
上面这三种方式,本质上是等价的。都是把键值对数据交给服务器。只不过具体用哪种方式,更多的是看个人习惯,或者是看公司产品既定的代码风格
(这些都是前后端交互的知识)
网站 = 前端 + 后端 + 前后端交互
-
post方法没有查询字符串的吗?
按照习惯用法,一般是没有的,但是也不是绝对的。post是可以有body并且同时有query string(但是正常开发不会这么用),这是反直觉的! -
如果url中query string和body中都传递了键值对,req.getParameter是优先获取哪个呢?
这次是用了query string中的键值对,**但是这种行为是Servlet没有规定的,Servlet并没有承诺谁更优先,**完全取决于内部的代码实现,说不定哪个版本的Servlet里面代码不一样,得到的结果就不一样的呢
比如:Mysql select查询的时候,如果不加order by得到的结果集合顺序,是不可预期的
HttpServletResponse
方法
对于方法的解释:
response 里的api都是set系列的方法
其实后面两个方法,说是get,但也是往body中写入数据
request 里的api都是get系列的方法
方法的使用
- 如何设置不同的状态码?
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;@WebServlet("/status")
public class StatusServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 不显示设置,默认也是200resp.setStatus(200);}
}
光返回一个状态码是不太好的(body是空的),浏览器上是不会直接显示状态码的,这时候就需要返回一个错误页面了
@WebServlet("/status")
public class StatusServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 不显示设置,默认也是200// resp.setStatus(404);resp.sendError(404,"这是一个错误页面");}
}
2. 通过setHeader 给响应中设置一些特殊的 header
比如,可以设置 refresh:1,让浏览器,每秒钟自动刷新一次
postman这里还观察不到,需要使用浏览器,
127.0.0.1:8080/java123456/refresh
把这个地址赋值到浏览器,就可以看到了
虽然是每秒刷新一次,但是也不是精确的 1000ms,会略多一点,浏览器法请求,到服务器返回响应,也需要时间
这个刷新有什么用呢?
比如说以前的文字直播,比如有一场球赛要看,就有人用文字,来描述当前比赛的情况,虽然无法看到画面,但是可以借助文字脑补,文字直播,大家就需要不停地按刷新,使用上述功能就可以达成自动刷新了
- 构造一个重定向响应
(1) 状态码是 3xx(比如302)
(2) header 需要有一个 Location 属性,描述要跳转到哪里
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setStatus(302);
// resp.setHeader("location","https://www.sogou.com");// 这一行代码和上面的代码是同样的作用resp.sendRedirect("https://www.sogou.com");}
}
写一个简单的网站
- 网站 = 前端 + 前后端交互 + 后端
(1)表白墙的前端的效果:当前这个页面已经可以实现把输入的数据进行提交的效果了
(2)如果只写了前端的话,会出现以下问题:
这里的数据都是在浏览器的内存中保存的,刷新页面/关闭页面,东西就无了
我们希望表白墙里的数据,能够长期存在,不同的浏览器/页面中,都能看到同一份数据
(3)这里就需要引入服务器了(引入后台代码)
这里服务器要实现的功能,主要有两个方面:
1.页面加载的时候,网页要从服务器这里获取到当前的表白数据
(让网页端给服务器发起http请求,服务器返回响应里就带着刚才的这些数据)
2. 点击提交的时候,网页就要把用户输入的信息,发送到服务器这边,服务器负责保存
(4)服务器的作用:
在一个网站中,服务器起到的最主要的效果,往往就是存储数据,因此服务器这边往往也就需要能够提供两种风格的接口。存数据,取数据
前端代码
- 一个html中,包含了html(页面的构成),css(页面样式),js(页面交互)
- js才能描述逻辑(js是前端的核心部分),通过这些逻辑,主要做两件事:
1.网页和用户的交互
2.网页和服务器的交互 - js代码所谓的交互,基本的流程,就是先找到html标签(体现成js中的对象)
进一步的通过api来操作对象的属性(获取值,修改值…)
api 具体是什么,我们也不必关注,但是可以看到,上面的一些变量定义,条件,循环,表达式,运算符,函数都要看懂
前后端交互的部分
对于表白墙程序来说,重点要实现的是 前后端交互 的部分
使用服务器,目的是为了能够在服务器这边存储用户提交的信息,
并且能够把信息获取下来。
服务器这边就需要给网页提供两个 http 的接口:
- 获取消息:网页加载的时候,浏览器给服务器发起一个 ajax请求
请求:
GET /message
响应:
HTTP/1.1 200 OK
Content-Type:application/json
例如:
[ ] 表示数组,{ } 表示json格式的字符串
[
{
from:‘张三’,
to:‘李四’,
message:‘我喜欢你’
},
{
from:‘黑猫’,
to:‘白猫’,
message:‘喵’
}
]
- 提交消息:用户点击提交按钮的时候,ajax 给服务器发一个请求。
目的是为了把用户在输入框输入的内容,给发送到服务器
这里的请求和响应的细节,都是可以自己随意设计的,只要达到效果即可
编写代码之前,需要进行的工作: