HTTP协议和Servlet编程

    xiaoxiao2025-07-28  15

    HTTP协议

    本文是基于Windows 10系统环境,学习和使用HTTP协议:

    Windows 10MyEclipse 10

    一、 HTTP协议的基本概念

    (1) HTTP协议的定义

    对浏览器客户端和服务器端之间数据传输的格式规范

    (2) request的内容

    request请求(浏览器->服务器) GET /day09/hello HTTP/1.1 # 请求行(请求方式:URI:版本号) # 请求头(多个key-value键值对) Accept: text/html,image/* # 浏览器接受的数据类型 Accept-Charset: ISO-8859-1 # 浏览器接受的编码格式 Accept-Encoding: gzip,compress # 浏览器接受的数据压缩格式 Accept-Language: en-us,zh- # 浏览器接受的语言 Host: www.it315.org:80 # (必须的)当前请求访问的目标地址(主机:端口) If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT # 浏览器最后的缓存时间 Referer: http://www.it315.org/index.jsp # 当前请求来自于哪里 User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) # 浏览器类型 Cookie:name=eric # 浏览器保存的cookie信息 Connection: close/Keep-Alive # 浏览器跟服务器连接状态。close: 连接关闭 keep-alive:保存连接。 Date: Tue, 11 Jul 2000 18:23:51 GMT # 请求发出的时间 name=eric&password=123456 # 请求实体内容 request请求相关API代码 // HttpServletRequest对象作用是用于获取请求数据。 // 核心的API: // 请求行: request.getMethod(); //请求方式 request.getRequetURI() request.getRequetURL() //请求资源 request.getProtocol() //请求http协议版本 // 请求头: request.getHeader("名称") //根据请求头获取请求值 request.getHeaderNames() //获取所有的请求头名称 // 打印所有的请求头内容 Enumeration<String> enums = request.getHeaderNames(); while(enums.hasMoreElements()){ String headerName = enums.nextElement(); String headerValue = request.getHeader(headerName); } // 实体内容: request.getInputStream() //获取实体内容数据 // 打印实体内容 InputStream in = request.getInputStream(); byte[] buf = new byte[1024]; int len = 0; while((len=in.read(buf))!=-1){ String str = new String(buf, 0, len); System.out.println(str); } request获取GET与POST提交的参数 request.getParameter("参数名"); //根据参数名获取参数值(单值) request.getParameterValues("参数名"); //根据参数名获取参数值(多值) // 打印所有的参数 Enumeration<String> enums = request.getParameterNames(); while(enums.hasMoreElements()){ String paraName = enums.nextElement(); String paraValue = request.getParameter(paraName); System.out.println(paraName+"="+paraValue); } 请求参数编码问题 // 修改post方式参数编码 request.setCharacterEncoding("utf-8"); // 修改get方式参数编码 String name = new String(name.getBytes("ISO-8859-1"),"utf-8");

    (2) response的内容

    response响应(服务器->浏览器) HTTP/1.1 200 OK # 响应行(版本号:状态码:状态描述) # 响应头(多个key-value键值对) Location: http://www.it315.org/index.jsp # 表示重定向的地址,该头和302的状态码一起使用。 Server:apache tomcat # 表示服务器的类型 Content-Encoding: gzip # 表示服务器发送给浏览器的数据压缩类型 Content-Length: 80 # 表示服务器发送给浏览器的数据长度 Content-Language: zh-cn # 表示服务器支持的语言 Content-Type: text/html; charset=GB2312 # 表示服务器发送给浏览器的数据类型及内容编码 Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT # 表示服务器资源的最后修改时间 Refresh: 1;url=http://www.it315.org # 表示定时刷新 Content-Disposition: attachment; filename=aaa.zip # 表示告诉浏览器以下载方式打开资源(下载文件时用到) Transfer-Encoding: chunked Set-Cookie:SS=Q0=5Lb_nQ; path=/search # 表示服务器发送给浏览器的cookie信息(会话管理用到) Expires: -1 # 表示通知浏览器不进行缓存 Cache-Control: no-cache Pragma: no-cache Connection: close/Keep-Alive # 表示服务器和浏览器的连接状态。close:关闭连接 keep-alive:保存连接 this is hello servlet!!! # 响应实体内容 response请求相关API代码 // HttpServletResponse对象 // 响应行: response.setStatus(404) //设置状态码 // 响应头: response.setHeader("name","value") //设置响应头 response.setHeader("Server","JBoss") //设置响应头 // 实体内容: response.getWriter().writer("hello"); //发送字符实体内容 response.getOutputStream().writer("hello".getBytes()); //发送字节实体内容 响应参数编码问题 // 修改post方式参数编码 response.setCharacterEncoding("utf-8");

    (3) 案例

    重定向 response.setStatus(302) //设置状态码 response.setHeader("location","/day09/adv.html") //设置URI //简化版 response.sendRedirect("/day09/adv.html") //重定向至adv.html 隔3秒后,跳转至新页面 response.setHeader("refresh","3;/day09/adv.html") //隔3秒后,跳转至新页面 发送图片 response.setContentType("image/jpg"); /tomcat/conf/web.xml FileInputStream in = new FileInputStream(new File("e:/mm.jpg")); byte[] buf = new byte[1024]; int len = 0; while(len(in.read(buf))!=-1){ response.getOutputStream().write(buf,0,len); }

    二、 Servlet编程

    (1) Servlet映射问题

    web.xml配置文件 <servlet-mapping> <!-- servlet的内部名称,一定要和上面的内部名称保持一致!! --> <servlet-name>FirstServlet</servlet-name> <!-- servlet的映射路径(访问servlet的名称) --> <url-pattern>/first</url-pattern> </servlet-mapping> 精确匹配 url-pattern 浏览器输入 /first http://localhost:8080/day10/first /itcast/demo1 http://localhost:8080/day10/itcast/demo1 模糊匹配 url-pattern 浏览器输入 /* http://localhost:8080/day10/任意路径 /itcast/* http://localhost:8080/day10/itcast/任意路径 *.后缀名 http://localhost:8080/day10/任意路径.后缀名 *.do http://localhost:8080/day10/任意路径.do *.action http://localhost:8080/day10/任意路径.action *.html(伪静态) http://localhost:8080/day10/任意路径.html 注意事项 1. url-pattern要么以 / 开头,要么以*开头。 例如, itcast是非法路径。 2. 不能同时使用两种模糊匹配,例如 /itcast/*.do是非法路径 3. 当有输入的URL有多个servlet同时被匹配的情况下: 3.1 精确匹配优先。(长的最像优先被匹配) 3.2 以后缀名结尾的模糊url-pattern优先级最低!!!

    (2) Servlet的自动加载

    默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。 改变servlet创建对象的时机: 提前到加载web应用的时候!!! 在servlet的配置信息中,加上一个即可!!

    web.xml配置文件 <servlet> <servlet-name>LifeDemo</servlet-name> <servlet-class>gz.itcast.c_life.LifeDemo</servlet-class> <!-- 让servlet对象自动加载 --> <load-on-startup>1</load-on-startup> <!--注意: 整数值越大,创建优先级越低!!--> </servlet>

    (3) Servlet的多线程并发问题

    servlet对象在tomcat服务器是单实例多线程的 因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。解决方案 1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步) 2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

    (4) ServletConfig对象

    作用 ServletConfig对象: 主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)对象创建和得到 创建时机: 在创建完servlet对象之后,在调用init方法之前创建。 得到对象: 直接从有参数的init方法中得到!!!核心API String getInitParameter(String name) // 根据参数名获取参数值 Enumeration getInitParameterNames() // 获取所有参数 ServletContext getServletContext() // 得到servlet上下文对象 String getServletName() // 得到servlet的名称 servlet的初始化参数配置web.xml <servlet> <servlet-name>ConfigDemo</servlet-name> <servlet-class>gz.itcast.f_config.ConfigDemo</servlet-class> <!-- 初始参数:这些参数会在加载web应用的时候,封装到ServletConfig对象中 --> <init-param> <param-name>path</param-name> <param-value>e:/b.txt</param-value> </init-param> <init-param> <param-name>path2</param-name> <param-value>e:/a.txt</param-value> </init-param> </servlet> public class ConfigDemo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 读取servlet的初始参数 */ String path = this.getServletConfig().getInitParameter("path"); File file = new File(path); //读取内容 BufferedReader br = new BufferedReader(new FileReader(file)); String str = null; while( (str=br.readLine())!=null ){ System.out.println(str); } //查询当前servlet的所有初始化参数 Enumeration<String> enums = this.getServletConfig().getInitParameterNames(); while(enums.hasMoreElements()){ String paramName = enums.nextElement(); String paramValue = this.getServletConfig().getInitParameter(paramName); System.out.println(paramName+"="+paramValue); } //得到servlet的名称 String servletName = this.getServletConfig().getServletName(); System.out.println(servletName); } }

    (5) ServletContext对象

    基本概念 ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。核心API // 得到当前web应用的路径 String getContextPath() // 得到web应用的初始化参数 String getInitParameter(String name) Enumeration getInitParameterNames() // 域对象有关的方法 void setAttribute(String name, Object object) Object getAttribute(String name) void removeAttribute(String name) // 转发(类似于重定向) RequestDispatcher getRequestDispatcher(String path) // 得到web应用的资源文件 String getRealPath(String path) InputStream getResourceAsStream(String path) 获取ServletContext对象 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); } 得到当前web应用的路径—重定向 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.得到ServletContext对象 ServletContext context = this.getServletContext(); //2.得到web应用路径 /day10 /** * web应用路径:部署到tomcat服务器上运行的web应用名称 */ String contextPath = context.getContextPath(); System.out.println(contextPath); /** * 案例:应用到请求重定向 */ response.sendRedirect(contextPath+"/index.html"); } 得到web应用的初始化参数(全局) public class ContextDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //得到SErvletContext对象 ServletContext context = this.getServletContext(); System.out.println("参数"+context.getInitParameter("AAA")); Enumeration<String> enums = context.getInitParameterNames(); while(enums.hasMoreElements()){ String paramName = enums.nextElement(); String paramValue =context.getInitParameter(paramName); System.out.println(paramName+"="+paramValue); } //尝试得到ConfigDemo中的servlet参数 String path = this.getServletConfig().getInitParameter("path"); //会打印path=null,因为ServletConfig属于servlet,而不是全局的 System.out.println("path="+path); } } 域对象有关的方法 域对象:作用是用于保存数据,获取数据。可以在不同的动态资源之间共享数据。所有域对象 HttpServletRequet 域对象 ServletContext域对象 HttpSession 域对象 PageContext域对象 // 保存数据 void setAttribute(String name, Object object) // 获取数据 Object getAttribute(String name) // 删除数据 void removeAttribute(String name) 转发(类似于重定向) public class ForwardDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //转发 /** * 注意:不能转发当前web应用以外的资源。 */ RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/GetDataServlet"); rd.forward(request, response); } } 携带数据的转发 public class ForwardDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 保存数据到request域对象 */ request.setAttribute("name", "rose"); RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/GetDataServlet"); rd.forward(request, response); } } 接收数据 public class GetDataServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 从request域对象中获取数据 */ String name = (String)request.getAttribute("name"); System.out.println("name=" + name); } }

    (6) 转发和重定向的区别

    转发 a)地址栏不会改变 b)转发只能转发到当前web应用内的资源 c)可以在转发过程中,可以把数据保存到request域对象中重定向 a)地址栏会改变,变成重定向到地址。 b)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。 c)不能再重定向的过程,把数据保存到request中。结论 如果要使用request域对象进行数据共享,只能用转发技术!!!
    最新回复(0)