一、Servlet-HTTP协议
1.什么是HTTP协议?
- 超文本传输协议
- 浏览器和服务器之间的一种通讯协议
- 该协议是W3C负责制定的,其实本质上就是数据传送格式提前制定好的。浏览器和服务器都必须按照这种数据格式进行接收和发送
2.HTTP协议包括几个部分?
-
1.请求协议:从浏览器发送到服务器的时候采用的数据传送格式
- 请求协议包括四个部分:
- (1)请求行:包括(请求方式、URI、协议版本号)
- (2)消息报头
- (3)空白行:专门用来分离消息报头和请求体
- (4)请求体
- 请求协议包括四个部分:
-
2.响应协议:从服务器发送到浏览器的时候采用的数据传送格式
- 响应协议包括四个部分:
- (1)状态行:包括(协议版本号、状态码、状态描述信息)【重点掌握状态码:200响应成功;404资源未找到;500服务器内部错误】
- (2)响应报头
- (3)空白行:专门用来分离响应报头和响应体
- (4)响应体
- 响应协议包括四个部分:
3.GET请求和POST请求的区别:
- 1.什么情况浏览器发送的请求是GET请求?什么情况浏览器发送的请求是POST请求?
- (1)只有当使用表单form,并且将form标签的method属性设置为method=“post”
才是POST请求,其余剩下所有的请求方式都是基于GET请求方式 - (2)如何判断当前请求是GET请求还是POST请求?
- 在浏览器地址栏上直接编写URL提交的请求一定是GET请求。
- 使用超链接向服务器发送的请求一定是GET请求。
- 使用form表单提交数据的时候,如果method属性没有编写,或者method属性值被指定是GET,这样发送的请求属于GET请求。
- 使用form表单提交数据的时候,如果method属性值被手动指定为POST,那么该请求属于POST请求。
- (1)只有当使用表单form,并且将form标签的method属性设置为method=“post”
<form action="/hcz8/system/login" method="post">
username<input type="text" name="username"/><br>
password<input type="password" name="password"/><br>
<input type="submit" value="提交">
</form>
- 2.GET请求在请求行上提交数据,格式:
uri?name=value&name=value…
这种提交方式最终提交的数据会显示到浏览器的地址栏上
因为是在请求行上提交数据,所以提交的数据长度有限制
- 3.POST请求在请求体上提交数据,相对安全,格式:
name=value&name=value…
这种提交方式最终不会显示到浏览器的地址栏上
因为是在请求体提交数据,所以提交的数据长度有限制
- 4.GET请求只能提交字符串数据,POST请求可以提交任何类型的数据,包括视频、文件…
4.GET请求和POST请求应当如何选择?
- POST请求: 当有敏感数据、传送数据不是普通字符串、传送数据非常多、请求数据是为了修改服务端资源,应该使用POST请求。
- GET请求:当多数情况下是从服务端读取资源,这个读取资源在短时间内不会发生变化的,所以GET请求最终的结果浏览器将其缓存起来了,这时应该用GET请求。
5.自定义一个适配器类来实现Servlet接口
- 每当我们定义一个类要去实现Servlet接口的时候都要去实现以下四个方法
@Override
public void init(ServletConfig config) throws ServletExcetion{
}
@Override
public void service(ServletRequest requeset, ServletResponse response) throws ServletException, IOException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo(){
return null;
}
@Override
public void destroy(){
}
- 所以这样代码会冗余,这时我们可以自己定义一个适配器类来继承Servlet接口,以后写的每一个类不需要直接实现Servlet接口,去继承这个适配器类即可,然后重写service方法;除了自己定义的适配器类之外,还可以直接实现SUN公司给我们提供的javax.servlet.GenericServlet接口。
//第一种形式:使用自定义适配器类
public abstract class GenericServlet implements Servlet{
//重写Servlet接口中的四个方法,这里省略不写了...
//除了重写的方法外,我们还可以扩展以下方法
public ServletContext getServletContext (){
return getServletConfig().getServletContext();
}
}
//第二种形式:自定义类直接继承SUN公司为我们提供的接口
public class LoginServlet extends javax.servlet.GenericServlet{
}
- 若子类在初始化时刻需要执行一段特殊的程序,但是又不能重写父类中的init类,这时我们可以在父类中定义一个无参数的init方法,以后子类可以重写无参数的init方法即可
public final void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init(){
}
6.这里我们来详细介绍一下ServletConfig接口和ServletContext 接口
1.ServletConfig
- 这里的ServletConfig是一个Servlet对象的配置信息对象,ServletConfig对象中封装了一个Servlet对象的配置信息,而Servlet对象的配置信息在web.xml文件中。一个Servlet对象对应一个ServletConfig对象,它们是一一对应关系的。
- 为了能够在service方法中也能使用ServletConfig,我们可以将init方法中的局部变量config 赋值给实例变量config
//定义私有的ServletConfig实例变量
private ServletConfig config;
//将init方法中的局部变量config 赋值给实例变量config
public void init(ServletConfig config) throws ServletExcetion{
this.config = config;
}
//如果子类想获取ServletConfig属性,可以调用重写的getServletConfig()方法
public ServletConfig getServletConfig(){
return config;
}
2.ServletContext
- SevletContext到底是什么?什么时候创建?什么时候销毁?创建几个?
- ServletContext一般被翻译为:Servlet上下文【Context一般都是翻译为上下文】
- 一个webapp只有一个web.xml文件,web.xml文件在服务器启动阶段被解析
- 一个webapp只有一个ServletContext对象,ServletContext在服务器启动阶段被实例化
- ServletContext在服务器关闭的时候会被销毁
- ServletContext对应的是web.xml文件的代表
- ServletContext是所有Servlet对象的周围环境的代表【在同一个webapp中,所有的Servlet对象共享一个“周围环境”,该对象就是ServletContext】
- 所有用户若想共享一个数据,可以将这个数据放到ServletContext对象中
- 一般放到ServletContext对象中的数据是不建议涉及到修改操作的,以为ServletContext是多线程共享的
的一个对象,修改的时候存在线程安全
- ServletContext接口中有哪些常用的方法?
- [1] void setAttribute(String name,Object object)//向ServletContext范围中添加数据(map.put(key,value;))
//创建User对象
User user = new User();
user.setUsercode("123");
user.setUsername("hcz");
//向ServletConfig中存储User数据
application.setAttribute("userObj", user);
application.setAttribute("time", new Date());
- [2] Object getAttribute(String name)//从ServletContext范围中取出数据(Object value = map.get(key); )
//取出time
application.getAttribute("time");
- [3] void removeAttribute(String name)//移除ServletContext范围中的数据(map.remove(key); )
//移除time
application.removeAttribute("time");
- [4] String getInitParameter(String name)
<!-- 初始化参数:被封装到ServletConfig对象中 -->
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/zgda</param-value>
</init-param>
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>hcz123</param-value>
</init-param>
</servlet>
//1.通过初始化参数的name获取value
String driver = config.getInitParameter("driver");
String url = config.getInitParameter("url");
String user = config.getInitParameter("user");
String password = config.getInitParameter("password");
- [5] Enumeration getInitParameterNames()
//2.获取所有初始化参数的name
Enumeration<String> names = config.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = config.getInitParameter(name);
out.print(name+"="+value);
out.print("<br>");
}
- [6] String getRealPath(String name)
//3.获取文件的绝对路径
String realPath = application.getRealPath("/index.html");
System.out.println(realPath);//D:\Tomcat9\tomcat9.0\webapps\hcz5\index.html
3.Servlet、ServletConfig、ServeltContext之间的关系
- 一个Servlet对应一个ServletConfig,多个Servlet对应多个ServletConfig
所有的Servlet共享一个ServletContext对象
二、前端页面和后台发送的请求方式
1.前端的页面发送请求方式应当和服务器端需要的请求方式一致
- 服务器要前端发送POST请求,那前端就应该发送POST请求,若发送GET请求,服务器应当提示错误信息
- 服务器要前端发送GET请求,那前端就应该发送GET请求,若发送POST请求,服务器应当提示错误信息
2.怎么样完成以上的需求?
- javaweb程序可以获取浏览器中的请求是什么类型的,POST还是GET?
- 当我们获取到请求方式之后,在javaweb程序中可以使用java语言中的if语句进行判断
if("POST".equals(method)){
}else if("GET".equals(method)){
}
3.怎么样在javaweb程序中获取请求方式?
- 重点: HTTP的请求协议全部信息会被自动封装到:
javax.servlet.http.HttpServletRequest对象中
- 在HttpServletRequset接口类型中有一个方法叫做:
String getMethod();可以获取请求方式
4.在每一个Servlet类中都编写以下程序,来保证前端的请求方式和后台需要的请求方式一致的
- 将ServletRequest,ServletResponse强制类型转换为带有Http的接口类型
HttpServletResponse response1 = (HttpServletResponse)response;
HttpServletRequest request1 = (HttpServletRequest)request;
- 设置编码格式和将其内容打印到浏览器中
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
- 获取浏览器发送的请求方式
String method = request1.getMethod();
- 通过 if 语句判断后台和前端发送的请求方式是否一致并将其输入到浏览器页面中
if("GET".equals(method)){
//前端错误
out.print("405-你应当发送POST请求");
//后台错误
throw new RuntimeException("405-你应当发送POST请求");
}
out.print("<html> ");
out.print("<head> ");
out.print(" <title>index page</title> ");
out.print("</head> ");
out.print("<body> ");
out.print(" 正在登录中 ");
out.print("</body> ");
out.print("</html> ");
每定义一个登录请求类都要将ServletRequest,ServletResponse强制类型转换为带有Http的接口类型,这时我们可以自定义封装一个HttpServlet类并继承GenericServlet接口。以后所有的登录请求类都可以继承该HttpServlet类
public class HttpServlet extends GenericServlet{
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
//将ServletRequest,ServletResponse强制类型转换为带有Http的接口类型
HttpServletResponse response = (HttpServletResponse)res;
HttpServletRequest request = (HttpServletRequest)req;
//将强制转换成Http接口类型的参数作为形式参数传给service方法
this.service(request,response);
}
public void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
//获取浏览器发送的请求方式
String method = request.getMethod();
try {
//LoginServlet是处理登录的,要求前端必须发送POST请求
if("GET".equals(method)){
doGet(request,response);
}else if("POST".equals(method)){
doPost(request,response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws Exception{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("405-你应该发送POST请求");
throw new RuntimeException("405-你应该发送POST请求");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws Exception{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("405-你应该发送GET请求");
throw new RuntimeException("405-你应该发送GET请求");
}
}
- if判断语句
- 如果浏览器发送的请求方式是GET,而后台的请求方式也是GET,则子类应该重写HttpServlet类中的doGet方法。
- 当重写的方法和前端页面中发送的请求方式不一致的时候,就会报错
- 当重写的方法和前端页面中发送的请求方式一致的时候,这里的重写方法就会覆盖父类中的这个方法
- 这里定义了一个登录请求类LoginServlet
/**
* LoginServlet是一个GET请求,不允许前端发送POST请求
* @author hcz
*
*/
pub
public class LoginServlet extends HttpServlet{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
try {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//response.getWriter().print("登录系统。。。。。");
out.print("登录系统。。。。。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 如果浏览器发送的请求方式是POST,而后台的请求方式也是POST,则子类应该重写HttpServlet类中的doPost方法。
- 当重写的方法和前端页面中发送的请求方式不一致的时候,就会报错
- 当重写的方法和前端页面中发送的请求方式一致的时候,这里的重写方法就会覆盖父类中的这个方法
- 这里定义了一个退出请求类LogoutServlet
/**
* LogoutServlet是一个POST请求,不允许前端发送GET请求
* @author hcz
*
*/
public class LogoutServlet extends HttpServlet{
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//response.getWriter().print("退出系统。。。。。");
out.print("退出系统。。。。。");
}
}
这里我们定义其前端页面为login.html
<html>
<head>
<title>login page</title>
</head>
<body>
GET方式:
<form action="/hcz9/system/login" method="get">
username<input type="text" name="username"/><br>
password<input type="password" name="password"/><br>
<input type="submit" value="提交">
</form>
<hr>
POST方式:
<form action="/hcz9/system/logout" method="post">
<input type="submit" value="退出系统">
</form>
</body>
</html>
配置文件为web.xml
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.javaweb.hcz9.servlet.math.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/system/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>com.javaweb.hcz9.servlet.math.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/system/logout</url-pattern>
</servlet-mapping>
注:以上是个人对这些知识点的片面理解,可能写的有点乱,请见谅!