Http协议及web开发部分的基础内容

来源:互联网 发布:淘宝几天会自动收货 编辑:程序博客网 时间:2024/06/05 04:42
1、web的目录结构:
所谓的web服务就是就是将本地的资源共享给其他的客户端。在web的开发中有如下的目录结构:(这里是以myeclipse为准的,如果是eclipse,则将WebRoot改成WebContent)
WebRoot
   |---这一级目录主要的存放的是一些静态的文件(html+js+css+img)等 。  
   |---WEB-INF          WEB-INF这一级目录浏览器是不能直接的访问的,只能通过servlet来访问
          |---class     主要存放编译后的class文件
 |---lib       主要存放的是项目中的jar文件
  web.xml       这里主要的是配置servlet的(配置文件)
  
当需要部署项目的时候只需要将WebRoot目录下的静态文件和web-inf目录拷贝到服务器就可以了,将这两个文件放到一个文件夹中,这个文件夹就是项目的上下文路径
2、http协议理解:
简单的理解所谓的http协议就是一个客户端和服务器端通信(数据交换)的一种规范。如果没有这种规范的话服务器端要根据不同的浏览器发送的请求做不同的处理,并且浏览器端还要根据不同的服务器端返回的数据做不同的处理。有了http协议这种规范就不会出现这种问题。
##1、http请求:http请求包括三部分,分别为请求行,请求头,和请求实体,其中请求头和请求实体之间有空行分隔开。具体格式如下:
GET /test/hello HTTP/1.1               -请求行
Host: localhost:8080                    --请求头(多个key-value对象)
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
                                    --一个空行
name=eric&password=123456             --(可选)实体内容
1)请求行:请求行有三部分内容分别为请求的方法,请求的URI,请求的协议,其中请求方法有get和post两种,这两者的区别主要是请求的参数所在请求的位置不一样,get请求的参数在请求行中,而post请求的参数是在请求的实体中的;get请求对传递的参数长度有限制的,只能为1K,而post的请求是没有长度的限制的。
2)请求的URI(同一资源标识符)URL是URI的一个子集,简单的理解上例中的/test/hello就是一个URI,如果是加了通信协议和ip,端口及时URL了,这里的区别主要是URI可以请求任何的资源(局域网,ftp等),而URL只能请求互联网中的资源。
3)请求协议:现在使用的都是http/1.1了,之前是1.0版本的,这两者的区别主要是1.0是一个请求了之后马上就断开连接的一种方式,这种方式效率很低,因为http是一种基于TCP/IP的协议的,要首先的要建立连接(三次握手),这样的话就需要每次请求都需要建立连接的,但是1.1是一种一旦建立了连接之后在一定的时间内可以不断的发送请求的一种协议。
实例:在一个页面中于三张图片,总共发送了几次请求?
四次,分别为页面一次(HTML标签),三张图片三次(如果是三张一样的图片其实还是发送了四次请求,不过浏览器的缓存技术处理这样看起来只是发送了两次请求)

表单提交数据模板

<form action="/text/hello" method = "post">name:<input type ="text" name = "username"><br>password:<input type ="password" name = "password"><br><input type ="submit" value ="提交"></form>

3、客户端和服务器端的交互
客户端和服务器端是通过服务器端创建的对象HttpServletRequest对象来实现的,这个对象中分装了请求的内容,包括请求行,请求头,请求的实体等信息,这些信息可以通过服务器提供的API来获取得到:(这里得到的内容都是字符串类型的)
获取请求行的内容:
request.getMethod();   //请求方式
request.getRequetURI()   //request.getRequetURL()   请求资源
request.getProtocol()   //请求http协议版本
获取请求头的内容:
request.getHeader("名称")   //根据请求头获取请求值
request.getHeaderNames()    //获取所有的请求头名称,这个方法返回的是一个枚举类型,得到的全部是请求头的名称,然后可以遍历得到具体的内容。
获取请求实体:
request.getInputStream()   //获取实体内容数据
具体的实例代码如下:

1)请求行内容获取

private void t1(HttpServletRequest request) {/** * 请求行   格式:(GET /day09/hello HTTP/1.1) */System.out.println("请求方式:"+request.getMethod());//请求方式System.out.println("URI:"+request.getRequestURI());//请求资源System.out.println("URL:"+request.getRequestURL());System.out.println("http协议版本:"+request.getProtocol());//http协议}

2)请求头内容的获取

private void t2(HttpServletRequest request) {/** * 请求头 */String host = request.getHeader("Host"); //根据头名称的到头的内容System.out.println(host);//遍历所有请求头Enumeration<String> enums = request.getHeaderNames(); //得到所有的请求头名称列表while(enums.hasMoreElements()){//判断是否有下一个元素String headerName = enums.nextElement(); //取出下一个元素String headerValue = request.getHeader(headerName);System.out.println(headerName+":"+headerValue);}}


3、请求实体获取

private void doPost(HttpServletRequest request, HttpServletResponse resp)throws ServletException, IOException {/** * 请求的实体内容 */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);}}

4、获取表单提交的参数:
1)在开发中通过request.getParameter("参数名"); 来获取单个值得请求参数,如果是多个值则使用request.getParameterValues("参数名");(常见的就是获取前台传递的checkbox的值)request.getParameterNames();   获取所有参数名称列表。
2)传递中文的问题:当请求的方式是post方式提交的,则可以使用request.setCharacterEncoding("utf-8");将请求的参数转化为utf-8的编码形式,但是如果请求的方式是get方式的话就不能用这个方法了,就只能一个个的转了,方式使用前台使用字符串类型的,传递到服务器端就是字节形式,然后服务器会自动的采用iso-8859-1的编码的方式来编码,所以这样就会出错,就要采用utf-8的形式来编码eg:String name = new String(name.getBytes("iso-8859-1"),"utf-8");上面代码的理解:首先将得到的参数转化为字节码的形式,然后在转化成字符串的形式。还有一种就是在tomcat的配置文件中修改默认的编码的方式(server.xml)。
##2、http响应信息:
http协议中的响应信息有响应行,响应头,响应的实体内容。其中响应行有相应的协议,响应的状态码,响应描述,响应头是一些的键值对形式,响应实体简单的理解就是可以在浏览器中看得到的内容。服务器端提供了一个HttpServletRespose对象来提供具体的响应信息的。其对应的方法如下:
响应行:一般只会这时响应的状态码:response.setStatus()  设置状态码,当设置为404的时候就会返回的信息是404,但是这个404并不是真的404.
响应头:response.setHeader("name","value")  设置响应头

响应实体:这个使用的最多的方法,response.getWriter().writer()//发送的是字符串实体的内容。response.getOutputStream().writer()//发送的是字符串实体的内容

1)、响应头的设置
1>response.setStatus(302);//发送一个302状态码
response.setHeader("location", "/test/hello.html"); //location的响应头,上面的代码中就会是浏览器发送两次请求,在浏览器中可以看到的地址是hello.html的地址(这里的专业术语就叫做重定向)。response.sendRedirect("/test/hello.html");这句代码和上面的两行代码是等价的。在实际的开发中用的最多就是这个。
2>response.setHeader("content-type", "text/html");表示的就是根据服务器给浏览器返回的信息是什么,这里返回的是html的形式,返回的数据的形式可以在tomcat的
web.xml中去设置。因为这个响应头比较常用所以有一个方法response.setContentType("text/html");这里和上面的代码也是等价的。
3>response.setHeader("Content-Disposition", "attachment; filename=aaa.zip");这个头设置的就是以下载的方式打开文件(如果不设置这个头的话,当浏览器能识别
具体的格式话,就会直接的打开的)
下载图片的实例程序:

File file = new File("F:\\hello.jpg");response.setHeader("Content-Disposition", "attachment; filename="+file.getName());byte [] buff = new byte[1024];int len = 0;FileInputStream in = new FileInputStream(file);//用一个输入流读取文件while((len = in.read(buff,0,len))!=-1){response.getOutputStream().writer(buff,0,len);//这里读取的是图片所以就要使用字节流}
在开发中要注意response.setCharacterEncoding("utf-8")和request.setCharacterEncoding("utf-8")的区别,前者是服务器返回给浏览器的编码信息,后者是服务器接收
浏览器请求的编码信息,有一个要注意在浏览器还是服务器相互传递数据的时候要进行编码和解码的过程,当浏览器向服务器发送字符数据的时候,就首先的要编码将字符数据
编码成字节数据传递,然后字服务器端在解码,解码成字符数据,默认的都是采用的iso的编码的方式,所以这样就不会的看到实际的传递的数据,要是通过上面的方法里确定
编码的具体方式。当以response.getOutputStream().write()方式写入的时候是不存在编码的,如果要在这里传递数据的话,在浏览器端就需要使用gbk的方式来解码getBytes("utf-8")方法这里可以指定具体的编码的方式.
在配置servlet的时候只能以/或者*开始,如果以其他的开始的话就会报错,其中*一般用于匹配具体的后缀名的,常用的有*.do等。在tomcat中也有一个web.xml文件,这个文件中也有一个servlet的配置,是DefaultServlet其中映射的url是/(和/*作用一样)这个servlet的作用就是加载webRoot下的静态文件的

servlet的生命周期:
第一次访问servlet首先的会调用自己的构造方法,然后实例创建成功之后就会调用父类的init方法,然后就会调用service方法,当再次访问的时候就只会调用service方法了
不会再调用其他的两个方法(这就说明servlet是一个单实例的,单利的),当一个servlet销毁的时候就会调用destory方法。response对象的理解,当servlet处理了请求之后
会返回一个response对象,服务器会处理这个对象,将其处理为响应的数据格式,返回给浏览器,这样浏览器就会识别里面的数据,就会显示到浏览器中的。
在servlet中有两个init方法,其中一个是带参数的,一个是不带参数的,带参数的是tomcat负责调用的,在这个方法中会调用不带参数的init方法,所以如果要有什么初始化
的就写在不带参数的方法中,如果写在了带参数的init方法中了就不会去调用没有带参数的初始化的方法了
web.xml配置
当写了一个servlet的时候,第一次访问的时候会比较慢(若果构造函数和init方法里面有复杂的逻辑的话,那么就会访问比较慢)这时候就可以在配置文件中具体的servlet
中加入一个标签<load-on-startup>就行了(放在servlet-class的标签的后面),这个标签中的数字越大,优先级就越低。这种就是可以在启动服务的时候自动加载这个servlet了简单的理解就是在启动的时候就会初始化这个servlet,就相当于访问过一次了
servlet的运行模式:
servlet是一个单实例的,在服务器端运行的模式是单实例,多线程的运行模式,多线程的运行模式的话就存在线程安全的问题,在servlet中常用的功能统计当前的用户是第
几位的访问用户,这里可以放到成员变量中,但是在成员变量中就会出现多线程的问题,这时候就要给用到成员变量的代码加上锁,这里的锁对象必须是同一个对象,不能使用response,因为不同的用户这个对象是不相同的,可以使用当前servlet的class文件,这个是唯一的一个对象。
实例代码

public class Demo1Servlet extends HttpServlet{int count = 1;public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{response.setContentType("text/html;chartset=utf-8");synchronized(Demo1Servlet.class){response.getWriter().writer("你是本网站的第"+count+"位访问者");//------------------1count++;}}}

如果上面的代码没有同步锁的话,就会出现线程的安全问题,比如一个线程进入到get方法执行到1处的时候,没有了执行权,有其他的线程来执行了,此时就会出现两个访问者是同一位访问者所以就要在访问到成员变量的代码上加上锁,但不能为了方便在全部的代码上加锁,这样就失去了多线程的作用。上面的代码中writer方法中使用了count和下面的count++使用了成员变量,所以就要在这两行代码中加上锁

servlet另外的两个对象:
ServletConfig对象:
在servlet中总共有四个对象,分别为HttpServletRequest,HttpServletResponse,ServletConfig,ServletContext对象,其中前面的章节主要是介绍前两个,后面主要学习
后面的两个,其中ServletConfig对象主要的作用就是servlet级别的一个对象,每一个servlet都会有一个ServletConfig对象的,这个对象的主要的作用就是加载Servlet的初始化参数的,这里要注意是Servlet的,在Servlet的配置文件中可以添加<init-param>,这个标签就是用于给指定的servlet参数的。在Servlet的方法中可以通过对象的getServletConfig()方法来获取这个对象,然后就可以通过方法 getInitParameter(java.lang.String name) 来获取指定的参数的值了,这个对象是在Servlet的init方法中的一个参数,所以其创建的时间是在创建一个servlet之后,调用init方法之前初始化的
ServletContext对象:
这个对象是web级别的对象,一个web项目只会有一个ServletContext对象,简单的理解就是加载这个项目的时候就可以得到ServletContext对象了,要想使用这个对象就可以通过ServletConfig对象的getServletContext得到常用的ServletContext的API:
1、getContextPath();表示的就是得到当前web的上下文路径,可以在get或者Post方法中ServletContext context = this.getServletContext();  context.getgetContextPath()
2、java.lang.String getInitParameter(java.lang.String name);  --得到web应用的初始化参数,这里的和ServletConfig对象的方法是一样的,但是作用的范围是不一样的,配置
java.util.Enumeration getInitParameterNames();的位置也是不一样的,这里的配置是在servlet同一级的标签下配置的使用的是<context-param>标签,而Servlet使用的是<init-parm>
3、void setAttribute(java.lang.String name, java.lang.Object object); --域对象有关的方法
java.lang.Object getAttribute(java.lang.String name);
void removeAttribute(java.lang.String name);
所谓的域对象指的就是可以保存数据,获取数据,达到共享数据的一个效果。ServletContext是一个基于web应用的对象,所以讲信息保存到这里面可以在当前项目中的任何的servlet中都是可以访问到的,这里面可以添加对象,不仅是字符串。在一个Servlet对象中setAttribute(保存数据),然后就可以在其他的servlet中通过getAttribute来访问。在后续的开发中会接触到的域对象有HttpServletRequest,HttpSession,ServletContext,PageContext。

4、RequestDispatcher getRequestDispatcher(java.lang.String path);作用是请求转发的
注意请求转发和重定向的区别:两者发送的请求的个数不一样,前者只发送一次请求,后者发送两次请求,两者所属的对象不一样,请求转发是属于ServletContext的,重定向是属于HttpServletResponse的。请求转发:this.getServletContext().getRequestDispatcher("/GetDateServlet").forward(request, response);重定向:response.sendRedirect("/index,jsp");

0 0