day05_HTTP_Servlet
HTTP
1. HTTP简介
- HTTP全称:Hyper Text Transfer Protocol【超文本传输协议】
- HTTP作用:约束报文格式
- 报文:浏览器与服务器通信时传输的数据,称之为报文
- 浏览器与服务器通信方式
- 浏览器向服务器发出:请求
- 服务器向浏览器做出:响应
2. 报文种类
2.1 请求报文
- 浏览器向服务器发送请求时,携带数据,称之为请求报文
- 请求报文格式
- 请求行
- 请求方式【get|post】 请求URI 协议版本【HTTP1.1】
- 请求头
- User-Agent:包含浏览器端信息,如:操作系统、浏览器版本等信息
- Referer:存储请求上一个【前一个】URL
- Cookie:存储Cookie信息
- 请求体【GET请求,没有请求体】
- 请求数据【参数】
- 请求行
2.2 响应报文
- 服务器向浏览器做出响应时,携带数据,称之为响应报文
- 响应报文格式
- 响应行
- 协议版本 状态码【 响应码】 提示文本
- 响应头
- Content-Type:设置响应类型,如:text/html;charset=UTF-8
- 响应体
- 响应数据
- 响应行
2.3 GET请求和POST请求区别
- 参数区别
- GET请求参数,在URL后使用?拼接参数
- POST请求参数,存储请求体中
- 安全性
- GET相对不安全
- POST相对安全
- 数据大小
- GET请求,参数在URL后使用?拼接参数,参数有大小限制
- POST请求,参数在请求体中,参数无大小限制
2.4 响应码
- 200:请求响应成功
- 404:请求失败,请求资源未找到【url地址不正确】
- 500:请求失败,请求资源找到了,但服务器内部有错误【代码写错了】
- 302:请求重定向
- 等等…
Servlet
1. Servlet简介
1.1 为什么使用Servlet
- 原因:以实现注册功能为例,需要将html中数据最终插入数据库中,所以此时需要将html中数据先提交java代码,再使用JDBC技术插入数据库。但html无法直接请求xxx.java文件,所以此时需要servlet技术。
1.2 什么是Servlet
- 理解层面:Servlet就是具有URL属性【特性】的java程序
- 定义层面:Servlet 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范
- 代码层面:Servlet就是一个接口,或javax.servlet.Servlet接口的实现类
2. Servlet之Helloworld
- 创建动态工程
- javax.servlet.Servlet这个包在servlet-api.jar包下
- 需要为web.xml【注解】中为Servlet实现注册
- 准备html发送请求
- 创建HelloworldServlet类
- HelloworldServlet实现javax.servlet.Servlet
- 重写接口中相应方法【接口中方法,默认抽象方法】
- 在web.xml中注册HelloworldServlet
- 设置全类名【类的全限定名】,通知Servlet容器【web容器、服务器】创建当前Servlet
- 为当前Servlet设置URL特性
3. Servlet工作原理【执行流程】
- 浏览器向服务器端组件Servlet发送请求【HelloworldServlet】
- 通过指定URL去web.xml中检索注册URL【/HelloWorldServlet】
- 通过servlet-mapping中的servlet-name与servlet中的servlet-name进行匹配
- 匹配成功,会找到指定servlet-class
- 执行Servlet中的相应方法【service()】
4. Servlet生命周期【面试题】
- 构造器:Servlet创建时,调用构造器方法【单例】
- 执行时机:第一次请求Servlet时,触发构造器,创建Servlet对象
- 执行次数:在整个生命周期中,执行一次
- init():初始化Servlet时,调用init()方法
- 执行时机:第一次请求Servlet时,构造器之后,执行init()
- 执行次数:在整个生命周期中,执行一次
- service():处理请求,做出响应时, 调用service()方法
- 执行时机:每次请求Servlet时,均调用service(),处理请求做出响应
- 执行次数:在整个生命周期中,执行多次
- destroy():销毁Servlet对象时,调用destroy()方法
- 执行时机:在关闭服务器时,调用destroy()方法,销毁Servlet对象
- 执行次数:在整个生命周期中,执行一次
第一次请求Servlet时,服务器创建Servlet对象【执行构造器】,之后执行init()方法进行初始化操作,最后执行service()方法,处理请求做出响应。以后再次请求Servlet,只执行service()方法,当关闭服务器时,调用destroy()方法,销毁Servlet对象
Servlet生命周期进阶版
要求:注册Servlet时,设置Servlet优先级
启动服务器时,服务器创能Servlet对象【执行构造器】,调用init()方法进行初始化操作;每次请求Servlet时调用service()方法,处理请求做出响应。当关闭服务器时,调用destroy()方法,销毁Servlet对象
5. ServletConfig与ServletContext
5.1 ServletConfig
- 概念:ServletConfig对象封装Servlet配置信息,每个Servlet都有唯一对应ServletConfig对象,该对象由服务器创建,最终以参数的形式传入到init()方法中
- 作用:
- 获取servlet名称:servletConfig.getServletName()
- 获取servlet初始化参数值:servletConfig.getInitParameter()
- 获取ServletContext对象:servletConfig.getServletContext()
5.2 ServletContext【重要】
- 概念:ServletContext对象是Servlet上下文对象,每个web应用对应唯一ServletContext,该对象由服务器创建,获取方式如下:
- servletConfig.getServletContext()
- request.getServletContext()
- 作用:
- 获取指定资源的真实路径【d:/】:servletContext.getRealPath()
- 获取上下文路径:servletContext.getContextPath()
- 上下文路径:通过上下文路径,访问当前项目
- 获取上下文初始化参数:servletContext.getInitParameter()
- 配置上下文初始化参数
jdbcurl
jdbc:mysql://localhost:3306/dbname
- ServletContext是域对象
- 一共四个域【聚齐再讲】
- servletContext.setAttibute()
- servletContext.getAttibute()
- servletContext.removeAttibute()
6. 最终创建Servlet方式
目前创建Servlet方式不足
- 最好只留下service()方法,处理请求做出响应
- 最好提示注册Servlet
6.1 继承HttpServlet
- EndServlet : HttpServlet : GenericServlet : javax.servlet.Servlet
6.2 GenericServlet与HttpServlet作用
- GenericServlet作用
- 提供获取对象方法【getServletConfig()和getServletContext】
- @Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
} - 将service()方法,抽象化
- @Override
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
- HttpServlet作用
- 重写service():类型转换
- @Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException(lStrings.getString(“http.non_http”));
}
service(request, response);
} - 重载service():通过请求方式不同,调用不同处理方法
- protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求方式
String method = req.getMethod();
if(“GET”.eq(method)){
doGet(req,resp);
}else if(“POST”.eq(method)){
doPost(req,resp);
}else if()…
} - Servlet中提供7种请求方式
- GET POST PUT DELETE
7. request对象和response对象【最重要】
7.1 request请求对象
- 类型:HttpServletRequest
- 概念:request对象封装浏览器向服务器发送请求时请求报文【请求行,请求头,请求体】,该对象由服务器创建,以参数形式传入到service()中,最终传入doGet()或doPost()方法中
- 作用:
- 获取请求行
- 获取请求方式:request.getMethod()
- 获取URI:request.getRequestURI()
- 获取URL:request.getRequestURL()
- 获取协议:request.getScheme()
- 获取服务器名称:request.getServerName()
- 获取服务器端口号:request.getServerPort()
- 获取上下路径:request.getContextPath()
- 获取请求头:request.getHeader()
- 获取请求参数
- 常见请求参数
- 1.测试请求参数
- 2.
- request.getParameter():获取请求参数,单个参数,单个值
- request.getParameterValues():获取请求参数,单个参数,多个值【多选框】
- request.getParameterMap():获取请求参数,多个参数,多个值【获取所有请求参数】
- 请求转发【路径跳转】
- //1. 获取转发器
RequestDispatcher requestDispatcher = request.getRequestDispatcher(“target.html”);
//2. 执行转发
requestDispatcher.forward(request,response);
- request是域对象
- request.setAttibute()
- request.getAttibute()
- request.removeAttribute()
- 获取请求行
7.2 response响应对象
- 类型:HttpServletResponse
- 概念:response对象封装服务器向浏览器做出响应时的响应报文【响应行、响应头、响应体】,该对象由服务器创建,以参数形式传入到service()中,最终传入doGet()或doPost()方法中
- 作用:
- 设置响应行
- 设置状态码: response.setStatus(404);
- 设置响应头
- 设置文本类型及字符集:response.setHeader(“Content-Type”,”text/html;charset=UTF-8”);
- 响应数据
- 获取响应流,响应数据
- PrintWriter writer = response.getWriter();
writer.write(“xxx成功啦!”); - 重定向【路径跳转】
- response.sendRedirect(“target.html”);
- 设置响应行
7.3 转发与重定向区别【面试题】
- 转发地址栏不变,重定向地址栏改变
- 转发携带request对象,重定向未携带request对象
- 转发浏览器只发送一次请求,重定向浏览器发送两次请求
- 转发可以访问WEB-INF下资源,重定向不能直接访问WEB-INF下资源
- WEB-INF目录属于web应用私有目录,服务器内部可以访问,浏览器不能直接访问
8. 练习
8.1 需求
- 使用request&response对象,实现伪登录&伪注册功能【不使用JDBC】
- 假设数据库只有一条数据,username=guoqiang &pwd=123456
- 登录业务
- 登录成功:使用转发跳转login_success.html
- 登录失败:使用重定向跳转回login.html
- 注册业务
- 注册成功:使用转发跳转regist_success.html
- 注册失败:使用重定向跳转回regist.html
8.2 示例代码
登录页面
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
/**<br /> * 处理登录请求<br /> *<br /> * 登录业务<br /> * //假设数据库只有一条数据,username=guoqiang &pwd=123456<br /> * - 登录成功:使用转发跳转login_success.html<br /> * - 登录失败:使用重定向跳转回login.html<br /> * @param request<br /> * @param response<br /> * @throws ServletException<br /> * @throws IOException<br /> */<br /> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br /> //获取请求参数【uname&pwd】<br /> String uname = request.getParameter("uname");<br /> String pwd = request.getParameter("pwd");<br /> if("guoqiang".equals(uname) && "123456".equals(pwd)){<br /> //登录成功:使用转发跳转login_success.html<br /> request.getRequestDispatcher("page/login_success.html").forward(request,response);<br /> }else{<br /> //登录失败:使用重定向跳转回login.html<br /> response.sendRedirect("page/login.html");<br /> }
}<br />
9. web应用中乱码问题
乱码情况
请求乱码:
POST方式发送请求时,出现乱码
GET方式发送请求时,未出现乱码
响应乱码
响应过程中,默认出现乱码
9.1 基本概念
- 字符集:所有字符集合,包括【中文、英文字符、各个国家字符、及标点符号等】
- 常用字符集:UTF-8【支持较大量中文字符】、GBK【GB2312:支持少量中文字符】、ISO-8859-1【不支持中文字符】等
- 编码与解码
- 编码:将字符转换为二进制过程,称之为编码
- 解码:将二进制转换为字符过程,称之为解码
- 乱码:编码与解码使用字符集不一致时,出现乱码现象
9.2 浏览器与服务器默认编码与解码情况
- 服务器默认编码与解码一致为:ISO-8859-1【不支持中文】
- 浏览器
- 默认编码:
- 默认解码:GBK
9.3 默认请求与响应乱码情况
- 乱码种类
- 浏览器向服务器发送请求时,出现乱码:请求乱码
- 浏览器编码与服务器解码不一致
- 服务器向浏览器做出响应时,出现乱码:响应乱码
- 服务器编码与浏览器解码不一致
- 浏览器向服务器发送请求时,出现乱码:请求乱码
- Tomcat8.5及以后版本,解决GET请求乱码问题
9.4 解决乱码
- 解决请求乱码
- 解决GET请求乱码
- Tomcat8.5及以后版本,不用解决【服务器默认解决GET请求乱码问题】
- Tomcat7解决方案
- 思路:找到修改8080位置,设置字符集问题
- 代码:tomcat->conf->server.xml
connectionTimeout=”20000”
redirectPort=”8443” />
- 解决POST请求乱码
- 思路:浏览器编码【UTF-8】与服务器解码【ISO-8859-1】不一致
- 将服务器解码设置为:UTF-8
- 代码:request.setCharacterEncoding(“UTF-8”);
- 思路:浏览器编码【UTF-8】与服务器解码【ISO-8859-1】不一致
- 解决GET请求乱码
- 解决响应乱码
- 思路及代码:服务器编码【ISO-8859-1】与浏览器解码【GBK】不一致
- 将服务器编码设置为:GBK
- response.setCharacterEncoding(“GBK”);
- 将服务器编码与浏览器解码均设置为:UTF-8【推荐使用】
- response.setContentType(“text/html;charset=UTF-8”);
- 将服务器编码设置为:GBK
- 思路及代码:服务器编码【ISO-8859-1】与浏览器解码【GBK】不一致
- 总结:三行代码解决请求与响应乱码问题
10. web应用中绝对路径
web应用中路径问题:由于使用转发跳转路径时,转发地址栏不变,此时使用相对路径不可靠【../】,可能出现404。所以建议使用绝对路径
10.1 什么是绝对路径
- 以【/】开头路径,称之为绝对路径
10.2 【/】代表意义
- 服务器解析【/】,代表当前上下文路径,即为:http://localhost:8080/day06_Servlet
- 以下两种情况由服务器解析【/】
- 注册中的【/】,web.xml中【/】或注解
- 转发中【/】
- 以下两种情况由服务器解析【/】
- 浏览器解析【/】,代表当前服务器路径,即为:http://localhost:8080
- 以下两种情况由浏览器解析【/】
- html代码中使用【/】,如:等
- 重定向中【/】
- 以下两种情况由浏览器解析【/】
10.3 Servlet注册路径问题
- Servlet默认路径注册在当前上下文路径下
/RegistServlet - 运行期间的【上下文】路径,相当于编写代码期间的【web】路径
10.4 示例代码
- html代码
登录成功!
回首页- Servlet代码
- //登录成功:使用转发跳转login_success.html
request.getRequestDispatcher(“/page/login_success.html”).forward(request,response);
//登录失败:使用重定向跳转回login.html
response.sendRedirect(request.getContextPath()+”/page/login.html”);
11. 基于注解【JavaEE6(web3.0)】注册Servlet
//@WebServlet(name = “Servlet30”,value={“/Servlet30”,”/Servlet3”})
@WebServlet(name = “Servlet30”,value=”/Servlet30”)
public class Servlet30 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br /> System.out.println("Servlet30");<br /> }<br />}