详解HttpServlet从需求到实现
1.HTTP协议
-超文本传输协议
-浏览器和服务器之间的一种通讯协议
-W3C制定,本质是提前制定好的数据传送格式。
包括:
-请求协议:从Browser发送到Server的时候采用的数据传送格式
请求行:请求方式 URI 协议版本号
消息报头
空白行:用来分离消息报头和请求体
请求体
-响应协议:从Server发送到Browser的时候采用的数据传送格式。
状态行:协议版本号
响应报头
空白行:分离响应报头和响应体的。
响应体
状态码:
200:一切正常
300/301:页面重定向(跳转)
404:资源不存在(请求的资源路径写错了)
403:权限不足(如果要访问的目录设置为不可见)
500:服务器内部错误(代码有误)
2.GET请求和POST请求
--GET请求:除了PSOT请求,都是GET请求
POST请求:只有当使用from表单,并且将form表单的method属性设置为method="post",才是post请求。
--GET请求和POST请求的区别
-GET请求在请求行上提交数据:格式uri?name=value&name=value&name=value...
这种提交方式最终会在浏览器地址栏上显示
-POST请求在请求体中提交数据,相对安全:提交格式:name=value&name=value&name=value..
这种提交方式最终不会在浏览器地址栏上显示
-POST请求在请求体中提交数据,所以POST请求提交的数据没有长度的限制
-GET请求在请求行上提交数据,所以GET请求提交的数据长度有限制。
-GET请求只能提交字符串数据,POST请求可以提交任何类型数据,所以文件上传使用POST请求。
-GET请求最终的结果会被浏览器缓存,POST请求最终的结果不会被浏览器缓存。
--选择使用POST请求的情况(其余的选择GET)
-有敏感数据。
-传送数据不是字符串。
-传送数据非常多
-这个请求是为了修改服务器端的数据
-GET请求多数情况下是从服务器中读取资源,这个读取的资源在短时间内不会变化,所以浏览器把结果缓存起来了
-POST请求是为了修改服务器端的资源,而每次修改的结果是不同的,结果没必要缓存。
--浏览器缓存资源,缓存的资源是和某个特定的路径绑定在一起的,只要浏览器再发送中这个相同的路径,
会去缓存中获取资源,不再访问服务器,提高用户体验。
如果不希望走缓存,可以在请求路经后添加时间戳,例如:http://ip:port/oa/system/logout?times=5351351435
3.需求:要求前端页面发送的请求方式和服务器端需要的请求方式一致
解决:
1.在javaweb程序中获取请求方式
-重点:HTTP的请求协议全部信息被自动封装到javax.servlet.http.HttpServletRequest对象中
-在HttpServletRequest接口类型中有一个方法:String getMethod();可以获取请求方式
-public interface javax.servlet.http.HttpServletRequest extends ServletRequest{ }
2.在javaweb程序中进行判断
if("POST".equals(method)){
}elseif("GET".equals(method)){
}
4.总结: 在每一个Servlet程序中都编写了以下的程序,来保证前端页面发送的请求方式和服务器端需要的请求方式一致
//将servletRequest,servletResponse强制类型转换成带有http的接口类型
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//获取浏览器发送请求的方式
String method = request.getMethod();
if ("GET".equals(method)){
//前台报错
out.print("405-应该发送POST请求");
//后台报错
throw new RuntimeException("405-应该发送POST请求");
}else if ("POST".equals(method)){
out.print("正在登陆");
}
5.封装:HttpServlet
public class HttpServlet extends GenericServlet
{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
service(request,response);
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String method = request.getMethod();
if ("GET".equals(method)){
doGet(request,response);
}else if ("POST".equals(method)){
doPost(request,response);
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
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 ServletException, IOException{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("405-应该发送GET请求");
throw new RuntimeException("405-应该发送GET请求");
}
}
6.使用HttpServlet重点
-编写一个Servlet类应该继承javax.servlet.http.HttpServlet,get请求重写doGet方法,post请求重写doPost方法
-doPost/doGet方法可以等同看作main方法。
当前端请求方式和后台的处理方式不同的话,会出现405错误。
继承HttpServlet的实现子类
import javax.*;
import java.io.IOException;
import java.io.PrintWriter;
public class LoginServlet extends javax.servlet.http.HttpServlet
{
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("login......");
}
//复写doPost方法,如果前段发送的doGet请求,会调用父类中的doGet方法,报错。
}
7.HttpServletRequest接口:
1.javax.servlet.http.HttpServletRequest 是一个接口,Servlet规范重要接口之一。
2.继承关系:
public interface HttpServletRequest extends ServletRequest;
3.HttpServletRequest接口的实现类是Web容器实现的,面向接口调用方法即可。
4.封装了HTTP请求协议的全部内容:
-请求方式
-URI
-版本协议号
-表单提交的数据
...
5.HttpServletRequest一般变量叫做:request,一次请求对应一个request对象。
所以request对象的生命周期是短暂的。
一次请求:网页上点击超链接,到页面停下来,看作是一次完整的请求。
举例:点击A连接,执行向request范围中存入一个对象,点击B连接从request范围中获取这个对象,是获取不到的。
6.HttpServletRequest中常用的方法
-表单提交的数据会被自动封装到request对象中,request对象中有map集合存储请求数据
- Map<String,String[]>
-String getParameter(String name) //通过key获取value一维数组中的首元素(最常用)
-Map getParameterMap() //获取整个Map集合
-Enumeration getParameterNames() //获取整个map集合的所有key
-String[] getParameterValues(String name) //通过Map集合的key获取value
-String getContextPath() //获取webapp的根路径【上下文路径】
-String getMethod() //获取浏览器的请求方式
-String getRequestURI() //获取请求的URI
-StringBuffer getRequestURL() //获取请求的URL
-String getServletPath() //获取Servlet Path 【url-pattern】
-String getRemoteAddr() //获取客户端IP地址
-void setAttribute(String name,Object o) //向request范围中存储数据
-Object getAttribute(String name) //从request范围中读取数据
-void removeAttribute(String name) //移除request范围中的数据
//request范围代表同一次完整的请求。
-Cookie[] getCppkies() //获取Cookie对象
-HttpSession getSession() //获取Session对象
如何将AServlet和BServlet执行放在同一个请求中
-RequestDispatcher getRequestDispatcher(String path) //获取请求转发器,指向转发的路径
//使用转发技术 forward【转发是一次请求】
//1.获取请求转发器对象
//RequestDispathcer dispathcher = request.getRequestDispatcher("/b");//指向BServlet
//2.调用转发器的forward方法即可完成转发
//dispathcher.forward(request,response);
//合并: request.getRequestDispatcher("/b").forward(request,response);
-void setCharacterEncoding(String env)
7.关于范围对象的选择:
ServletContext 应用范围,可以跨用户传递数据
ServletRequest 请求范围,只能在同一个请求中传递数据【可以跨Servlet传递数据,但是Servlet必须在同一个请求中】
优先选择request范围。
使用HttpServletRequest中的方法实现获取前台用户输入的数据
项目结构
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>register</title>
</head>
<body>
<form action="/prj_servlet_09_war_exploded/user/save" method="post">
用户名<input type="text" name="username">
<br>
密码<input type="text" name="password">
<br>
性别
男<input type="radio" name="sex" value="m">
女<input type="radio" name="sex" value="f">
<br>
爱好
<input type="checkbox" name="interset" value="sport">运动
<input type="checkbox" name="interset" value="music">音乐
<input type="checkbox" name="interset" value="dance">跳舞
<input type="checkbox" name="interset" value="study">学习
<input type="checkbox" name="interset" value="read">阅读
<br>
学历
<select name="grade">
<option value="gz" >高中</option>
<option value="dz" >专科</option>
<option value="db" >本科</option>
</select>
<br>
简介
<textarea rows="10" cols="60" name="introduce"></textarea>
<br>
<input type="submit" value="注册">
<input type="reset" value="重置">
</form>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>register.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>save</servlet-name>
<servlet-class>com.chif.SaveUserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>save</servlet-name>
<url-pattern>/user/save</url-pattern>
</servlet-mapping>
</web-app>
SaveUserServlet.java
package com.chif;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Set;
public class SaveUserServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取用户信息、
//从request中获取
String username = req.getParameter("username");
String password=req.getParameter("password");
String sex = req.getParameter("sex");
//String interset = req.getParameter("interset");
String grade = req.getParameter("grade");
String introduce = req.getParameter("introduce");
//获取所有的兴趣爱好
String[] intersets = req.getParameterValues("interset");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
System.out.println(username);
System.out.println(password);
System.out.println(sex);
for (String in:intersets){
System.out.println(in);
}
System.out.println(grade);
System.out.println(introduce);
//第二种方法:获取整个map集合
Map<String, String[]> parameterMap = req.getParameterMap();
Set<String> names = parameterMap.keySet();
for (String name:names){
String[] values = parameterMap.get(name);
System.out.print(name+"=");
for (String value:values){
System.out.println(value);
}
}
}
}
运行截图:
前台
后台输出获取结果
username=zhangsan
password=123
sex=m
intersets=sport music dance study read
grade=db
introduce=I like somkeing!
15.模版方法设计模式
。。。。。。。
典型应用:Servlet规范中的HttpServlet
HttpServlet是一个模版类
其中的service(HttpServletRequest,HttpServletResponse)方法是典型的模板方法
doGet,doPost...具体的实现步骤延迟到子类中去完成.
模版方法设计模式的特点:
doXXX
doYYY
doZZZ
模版方法设计模式的主要作用
1.核心算法得到保护
2.核心算法得到复用
3.在不改变算法的前提下,可以重新定义算法步骤的具体实现。