servlet

Posted lomon6

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了servlet相关的知识,希望对你有一定的参考价值。

---恢复内容开始---

初始HTTP

Web交互流程

客户端是根据用户输入的地址信息请求服务器,服务器在接收到用户的请求进行处理并将结果响应给客户端,客户端在将响应的结果显示给用户


Http协议

问题:由于浏览器和服务器的版本都有很多种,不同版本之间的它们有事怎样进行数据传输呢?

解决:http协议就是用来规范浏览器和服务器之间的数据交互格式

特点:

  1. 简单快捷:客户向服务器请求服务,只需要传送请求方法和路径即可。(请求方法:GET 、POST、HEAD方法不同的请求方法代表客户与服务器之间的联系类型不同)
  2. 灵活:可以允许任意类型的数据传输
  3. 无连接:即限制每次链接只处理一个请求,服务器处理完客户请求并且收到客户的应答后会自动断开连接(采用这用方式可以节省传输时间)
  4. 无状态:即协议对于事物的处理没有记忆能力。也就是在后续处理是不用在重传前面用到的信息

Http交互流程

客户端和服务器端建立连接 ---> 客户端发送请求数据到服务器端 (HTTP协议)---> 服务器端接收客户请求并处理将结果响应给客户端 (HTTP协议)---> 关闭客户端和服务器端 的连接(HTTP1.1不会马上关闭)


Http协议请求格式

  1. 请求行:包含请求方式、请求地址、HTTP协议版本
  2. 请求头:消息报头(一般用于通知服务器有关于客户端需要使用到的一些附加信息)
  3. 空行:位于请求头和请求数据之间(是必须要有的),通知服务器一下不会有请求头
  4. 请求包体:非必须

注意:由于一张网页的内容是非常丰富的因此浏览器会遵循HTTP的请求格式将一些有效的数据发送给服务器


Http的请求方式

  • 在HTTP1.0中定义了三种请求方法:HEAD POST GET
  • 在HTTP1.1中又新增加了五种请求方法:DELETE CONNECT OPTIONS PUT TRACK

注意:这里需要注意get和post的请求方法的区别:get请求方法:请求数据会以问号的形式隔开拼接在请求头中也没有请求实体,因此不安全同时也不能携带大量的数据;post请求方法:数据在请求实体中进行发送,因此在URL中看不到具体的请求数据,所以相对较安全同时也适合大量数据的传送


Http协议的响应格式

  1. 状态行:HTTP版本、状态码、状态信息
  2. 响应头:消息报头(客户端需要使用到的一些附加信息)
  3. 空行:是必须的;位于响应头和响应包体之间;同时服务器以下不会有响应头(相应实体)
  4. 响应包体:正文,也就是服务器要返回给浏览器的信息

服务器初识

问题:众所周知,java代码一个重要的功能就是进行数据处理的功能。但是目前我们运行所编写的代码是具有一次性。也就是代码运行完后如果想再次执行就需要再次启动代码的执行。此时便需要一种容器可以根据用户的请求实时进行启动代码的执行,而不是手动的启动。

解决:服务器

服务器的概念

服务器其实就是一个用代码编写的容器,这个容器可以根据用户的请求实时调用需要执行的逻辑代码

注:在普通用户看来服务器其实就是一个安装程序,用户只需要将服务器安装在操作系统上,然后将事先编写好的逻辑代码根据规则放到服务器的指定位置,那么服务器就自动的会根据接收到请求调并执行对象的逻辑代码进行处理。


创建Web程序流程

1、 打开 Myeclipse 并创建工作空间

2、 点击 file 选择—>new—>web project—>输入项目名,点击 finish

3、 在 src 下创建包 com.bjsxt.servlet.

4、 在包下创建一个普通 java 类 MyServlet,并承 HttpServlet

5、 在 MyServlet 类中覆写 service 方法

6、 在 webRoot 下的 WEB-INF 下找到 web.xml文件并配

7、 打开 tomcat 的安装目录,在 webapps 目录下新建文件夹,文件夹名为 project,并将项目源码 webRoot 下的内容全部复制到该文件夹下。
8、 启动 tomcat 服务器,并在地址栏中输入:localhost:8080/project/my


服务器的具体运行细节

问题:都知道服务器是在接收到浏览器的请求后,会调用相应的逻辑代码来进行请求处理,而逻辑代码是由程序员编写并放到服务器中,那么此时服务器又是怎么知道要调用相应的逻辑代码呢?

解决:要想让服务器调用相应的逻辑代码那么就要求程序员按照服务区能够识别的规则来进行编写代码。当浏览器按照指定的规则发送请求,那么服务器就可以调用相应的逻辑代码来进行请求处理

实现:Servlet技术

Servle技术

概念:即一个类这个类实现了Servlet接口

Servlet技术的特点

(1)运行在支持java的应用服务器上

(2)Servlet的实现遵循了服务器可以识别的规则,也就是服务器可以根据请求自动调用相应的Servlet类进行请求处理

(3)简单快捷,可移植性强

Servlet技术的使用

1、创建普通的java类并继承HttpServlet

2、覆写service方法并在service方法书写逻辑代码

4、在WebRoot下的WEB-INF文件夹下的web.xml文件中配置servlet

Servlet运行流程

访问方式:http://localhost:8080/Demon/demon

组成:“服务器地址:端口号/webapps目录下的文件夹的名称(虚拟项目名)/要执行的servlet的url-pattern”

? 或 “服务器地址:端口号/虚拟项目名/servlet的别名”

注1::虚拟项目名:Myeclipse中的项目名 别名:web.xml中标签中的内容)

注2:服务器地址+端口号 ”可以定位到一个应用程序(即服务器所在的位置)

注3:"服务器地址:端口号/webapps目录下文件"--->即此时服务器已经找到要执行的具体项目

注4:唯一可以标识一个java类的是:包名+类名

注5:为了安全考虑,我们要在web.xml中配置servlet的别名用于让服务器辨别。当服务器根据输入的地址可以找到想要运行的具体项目-->根据servlet的别名在web.xml查找对应的类名和对应的包名(因此web.xml的作用就是保护servlet更加保密性和安全性)


Servlet的生命周期

  1. 从Servlet第一次调用被加载到内存到服务器关闭(期间一直存在)
  2. 如果Servlet中在web.xml中配置了1那么它的生命周期是:从服务器启动到服务器关闭。

注1:当用户第一发起请求是servlet会被加载到内存,此时如果删除tomcat服务器目录下的webapps文件夹下的项目下的servlet文件进行删除后在进行请求操作仍然不会出错,因为当类被调用的时候已经被加载到内存中了,那么什么时候发起调用会报错呢?(当servlet被销毁时即此时内存中不存在这个文件).servlet第一次加载进了Tomcat内存只要服务器不关闭它就必须一直存在(不可以被销毁),因为我们不确定用户什么时候会发起请求,只有当服务器关闭之后才可以对其进行销毁。

注2:当服务器启动的时候web.xml会被加载到内存,但是只有浏览器发起servlet请求的时候Tomcat服务器才会拿着请求去使用web.xml中的内容:即通过web.xml里面的找到对应的从而找到对应的(有上可知:当第一次对servlet进行调用的时候响应的类才会被加载到内存)。

注3:init()方法是对servlet进行初始化的一个方法,会在servlet第一次被调用加载到内存时调用(调用一次);destory()方法是在servlet被销毁的时候被调用,也就是服务器被关闭的时候调用。


service和doGet和doPost方法

  1. Service方法:不管是 get 方式还是 post 方式的请求,如果 Servlet 类中有service 方法,则优先调用 Service 方法。
  2. doPost方法:在没有service方法的情况下,如果是post方式的请求则调用doPost方法
  3. doGet方法:在没有service方法的情况下,如果是get方式的请求则调用doGet方法

注:由servlet的生命周期可知,只要发起请求对应的servlet的class文件就会被加载到内存,此时即使把它删除(指的是从服务中删除,内存中不会被删除除非是服务器被关闭即对其进行销毁)只要在myeclipse对其进行保存,它就会帮我们把这个文件复制到Tomcat服务器的webapps目录下,但是服务器加载的却是上一次在内存中保存的servlet的class文件;因此每次对servlet进行修改时需要重启服务器


servlet常见错误

404错误:资源未找到错误

原因一:在请求地址中的servlet的别名书写错误。

原因二:虚拟项目名称拼写错误

500错误:内部服务器错误

错误一:java.lang.ClassNotFoundException:com.bjsxt.servlet.ServletMothod

解决:在web.xml中校验servlet类的全限定路径(包和类路径是否正确)是否拼写错误。

错误二:因为service方法体的代码执行错误导致

解决:根据错误提示对service方法体中的代码进行错误更改。

405错误:请求方式不支持

原因:请求方式和servlet中的方法不匹配所造成的。

解决:尽量使用 service 方法进行请求处理,并且不要再 service 方法中调用父类的
service。


Servlet对请求的处理

问题:当浏览器对服务器发起请求时(当然此时是遵守http协议将请求数据发送给服务器),服务器接收到数据后要怎么对数据进行存储呢?(在存储的时候还要保证数据的完整性)

解决:在java中存储数据一般都是使用变量或者对象。显然这里请求数据都是以键值对的形式存在,并且数据量多,因而这里使用对象来对数据进行存储。(服务器每接收一个请求,就会创建一个对象来专门对这次的数据进行存储。)

要知道的:我们将保存到数据对象(request)作为实参传到service方法中;即此时service方法已经拿到了浏览器请求的数据。也就是Tomcat服务器的作用是调用service方法并将请求对象作为实参传递到此方法中,而我们所要做的就是拿到请求对象然后获取里面的数据并使用。

request对象

解释:request对象存储了此次请求相关的请求数据

使用:

  1. 获取请求头数据

    //获取请求方式
    req.getMethod();
    //获取请求URL
    req.getRequestURI();
    //获取URI
     req.getRequestURI();   
    //获取协议
    req.getScheme();
  2. 获取请求行数据

    //获取指定请求行的信息:返回指定请求头的信息eg:User-Agent、Host
    req.getHeader("键名");
    //获取请求行的所有的键的信息:返回请求头的键名的枚举集合获取用户数
    req.getHeaderNames();
     //获取请求行所有键的信息(枚举类型)
     Enumeration e = req.getHeaderNames();
             while(e.hasMoreElements()){
                String name = (String) e.nextElement();
                String value = req.getHeader(name);
                System.out.println(name+" : "+value);
            }
  3. 获取用户数据

    // 返回指定的用户数据
     req.getParameter("键名");
    //返回同键不同值的请求数据
     req.getParameterValues("键名"); 
    //返回所有用户请求数据的枚举集合(注意:如果请求数据不存在则返回null)
     req.getParameterNames(); 

response对象

问题;我们使用request对象保存请求数据并进行相相应的处理后,处理的结果又是怎样显示到浏览器中呢?

解决:使用response对象

解释:服务器在调用指定的servlet对请求进行处理的时候,会给service传递两个实参reqeust和response。其中request对象中封存了请求相关的信息;而response对象封存了对请求做出处理响应的结果

使用:

  1. 设置响应头

    resp.setHeader(String name, String value);
    resp.addHeader(String name, String value);
  2. 设置响应状态

    //自定义响应状态码
    sendError(int num, String meg)
  3. 设置响应实体

    //响应具体的数据给浏览器 
    resp.getWrite().write(String str);
  4. 设置编码格式

    //告诉浏览器以"text/html"的形式;"utf-8"编码来读取此文件
    resp.setContentType("text/html;charset=utf-8");

servlet流程总结

  1. 浏览器向服务器发送求信息

  2. 服务器接收到请求进行解析,创建request对象用来存储数据,并调用响应的servlet进行请求处理,同时将request对象作为service方法的实参

  3. servlet方法的执行来进行请求处理(这也正是程序员所要做的工作)

    • 设置请求编码格式和响应编码格式
    • 获取请求信息
    • 处理请求信息
    • 响应处理结果

    注1:处理请求信息:(MVC思想):创建业务层对象、调用业务层对象的方法

    注2:数据的流转

    浏览器——>服务器——>数据库

    浏览器<——服务器<——数据库

请求乱码的解决

  1. 使用String进行重新编码

    String name = req.getParameter("name");
    //将数据再次进行编码(先以“iso8859-1”的形式拆分成二进制形式,然后在以“utf-8”的形式编码)
    name = new String(name.getBytes("iso8859-1"),"utf-8");
  2. Get请求方式

    步骤一:在 service 方法中使用:

    req.setCharacterEncoding(''utf-8'');

    步骤二:在 tomcat 服务器目录下的 conf 文件下找到 server.xml 文件,打开进行如下配置:

    <connector port="8080" protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443" useBodyEncodingForURL="true"/>
    
  3. Post请求方式

     // 在service方法中使用从而设置对客户端请求进行重新编码的编码
     req.setCharacterEncoding(“utf-8”);
    

Servlet请求转发和重定向

问题:服务器在接收到浏览器的请求后,如果只是用一个servlet进行请求处理,会造成不同的servlet逻辑代码冗余。servlet职责不明确

解决:使用请求转发

特点:

  1. 一次请求地址栏的信息不改变
  2. 可以实现多个servlet联动操作处理请求,避免了代码的冗余,同时也让servlet的职责更加明确

使用:

//地址指的是相对路径,这里指servlet的别名
req.getRequestDispatcher("要转发的地址").forward(req,resp);

注1:请求转发厚直接return结束(也就是转发后就已经对请求做出了响应,此时请求已经可以结束了)

Request对象作用域

问题:由于不同的servlet可以进行请求转发,那么这时它们之间请求转发后又是怎么进行数据共享呢?或者说数据是怎样通过一个servlet流向另一个servlet呢?

解决:使用servlet的作用域

使用:

request.setAttribute(Object name, Object value);
request.getAttribute(Object name);

作用:解决了一次请求中不同servlet之间的数据(请求数据+其它数据)共享问题

作用域:基于请求转发,可以被一次请求中的所有servlet共享

特点:服务器创建且每次请求都会创建request对象,生命周期是一次请求

注:使用Request对象进行数据流转,数据只在一次请求内有效

重定向

问题:在使用请求转发是可能会造成数据的重复提交或者如果请求的servlet无法进行处理又该怎么办呢?

解决:使用重定向

使用:

//本地路径为:uri;网络路径为:定向资源的URL
response.sendRedirect("路径");

特点:两次请求,地址栏的信息改变;避免了表单的重复提交。

Cookie技术

问题:HTTP协议是没有记忆功能的,一次请求结束后,相关的数据会被销毁。如果第二次请求还需要相同的数据又该怎么样处理呢?

解决:使用Cookie技术

解释:Cookie技术其实就是浏览器端的数据存储技术,解决了不同请求需要使用相同请求数据的问题。我们把需要共享的数据存储在浏览器端,从而避免了用户重复书写请求数据。至于哪些数据需要使用Cookie技术存储这个需要在后台进行响应的时候告诉浏览器。

特点:

  1. Cookie技术是浏览器端的存储技术
  2. 适合存储少量数据
  3. 属于键值存储不安全
  4. 数据的声明在服务器端
  5. 默认Cookie信息存储好了之后每次请求都会携带存储的数据。除非设置有效路径。

使用:

Cookie数据的存储分为:临时存储和定位存储

  • 临时存储:不设置Cookie信息的存储时间,周期为一次会话。存储在浏览器内存(当浏览器关闭的时候就失效)
  • 定时存储:设置Cookie信息的存储时间,周期为设置的时间。存储在用户电脑中(在有效期内符合路径要求的请求都会附带该信息)
//创建Cookie对象
Cookie c = new Cookie(String name, String value);
//设置Cookie对象(可选操作)
c.setMaxAge(int seconds);//设置有效期
c.setPath(String uri);//设置有效路径
resp.addCookie(c);//响应Cookie对象给客户端
//Cookie数据的获取
Cookie[] cks = req.getCookiess();//获取Cookie信息数组
//遍历Cookie数组区的信息
for(Cookie c : cks){
    String name = c.getName();
    String value = c.getValue();
    System.out.print(name + value);
}

注:一个Cookie对象只能存储一条数据,多条数据可以多创建几个Cookie对象

总结:Cookie技术解决了不同请求之间的数据共享问题。

Cookie小尾巴


Session对象

问题:Request对象解决了一次请求不同Servlet内的数据共享问题;那么同一个用户的不同请求要处理相同的数据又该怎么处理呢?

解决:使用session对象(解决了一个用户的不同请求之间数据共享的问题)

原理:

用户使用浏览器向服务器第一次发送请求的时候,服务器在接收到请求后会调用相应的Servlet进行处理同时在处理的过程中会给用户创建一个Session对象用来存储用户请求处理相关的公共数据。并将此 session 对象的 JSESSIONID 以 Cookie 的形式存储在浏览器中(临时存储,浏览器关闭即失效)。用户在发起第二次请求及后续请求时,请求信息中会附带 JSESSIONID,服务器在接收到请求后,调用对应的 Servlet 进行请求处理,同时根据 JSESSIONID 返回其对应的 session 对象

特点:

  • Ssession技术是依赖Cookie技术的浏览器端的数据存储技术
  • 是由服务器创建的
  • 每个用户独立拥有一个Session
  • 默认存储时间为30分钟 (也可以设置session对象在服务器端的有效时间 hts.setMaxInterval(int seconds);在指定的时间内session没有被使用则失效,如果在此期间使用则重新记时。

使用:

使用时机:一般用户在登录web项目是会将用户的个人信息存储在session对象中以供其他请求使用。

//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置响应编码格式
resp.setContentTyep("text/html;charset=utf-8")
//获取请求数据
String name = "张三";
//处理请求数据
//响应处理结果
//创建 Session 对象
HttpSession hts = req.getSession();
//存储数据到 session 对象 hts.setAttribute(String name, Object value);
hts.setAttribute("name","张三")
//获取 session 对象 hts.getAttribute(String name);
//获取数据从 session 对象(如果获取 session 中不存在的数据返回 null)

作用域:一次会话。(JSESEESIONID在浏览器端不失效并且session对象在服务器端不失效,同一个用户的任意请求在项目的任意个servlet页面内获取的都是同一个session对象

要知道的1:注意在创建(获取)session对象的时候如果请求中拥有session的标识符(JSESESSIONID),则返回其对应的session对象;如果没有的话就创建一个新的session对象并将它的JSESESSIONID作为Cookie数据存储在浏览器端

要知道的2:session对象的JSESESSIONID是存储在了Cookie的临时存储空间

判断session是否失效的标准:

  1. 情况一:用户把浏览器关闭(session对象失效,JSESESSIONID不失效):不作处理,用户下次访问此网站是会重新登录,此时会在创建一个session,并将数据存储其中
  2. 情况二:浏览器没有关闭(JSESESSIONID不失效),session对象失效:要知道虽然JSESESSIONID不失效的话也会执行 "HttpSession hts = req.getSession();"此代码,即又创建了一个新的session对象,此时Cookie中也有了信息的JSESESSIONID;通过比较请求中JSESESSIONID和后台获取到的session对象的JSESESSIONID是否相同:相同则不失效;不相同则是失效了。

三天免登陆


ServletContext对象

问题:request解决了一个用户一次请求之间的的数据共享问题;session解决了一个用户多次请求之间的数据共享问题;那么针对不同用户之间的数据共享有是怎么处理的呢?

解决:使用ServletContext对象(解决了不同用户之间的数据共享问题)

原理:

ServletContext对象是有服务器创建的并且一个项目只有一个对象。因此在项目的任意一个页面获取的ServletContext对象都是同一个,因而不同的用户获取的ServletContext对象也是同一个了。(换句话说该对象被所有用户所共享)

特点:

  1. 由服务器所创建,一个项目只有一个因此被所有用户共享
  2. 生命周期:服务器启动到服务器关闭
  3. 作用域:整个项目内

使用:

//获取 ServletContext 对象(有三种方法,获取的都是同一个对象)
ServletContext sc1 = this.getServletContext();
ServletContext sc2 = this.getServletConfig().getServletContext();
ServletContext sc3 = req.getSession().getServletContext();
//使用作用域进行共享数据流转
sc1.setAttribute("name","张三");
sc1.getAttribute("name");


//获取 web.xml 中的全局配置
    //在web.xml中配置如下属性
        <context-param>
            <param-name>name</param-name>
            <param-value>zhangSan</param-value>
         </context-param>
     //全局数据的获取
    String webName = sc1.getInitParameter("name");//根据键名返回值
    Enumeration s = sc1.getInitParameterNames();//返回键名的枚举
//获取webRoot(MyEclipse)或者webContent(Eclipse)资源的绝对路径
        String ProjectPath =  sc1.getRealPath(String path);
        //获取的路径为项目跟目录:在Tomcat服务器中webapps中的所运行的项目里
        //(即:E:Java workspace.metadata.me_tcatwebappsWebProjec)
        //path:指的是项目根目录中的路径(即项目webRoot下的文件夹下的文件的路径)
//获取webRoot下资源的流对象  
        InputStream s1 = sc1.getResourceAsStream("/contextPath/1.txt");
    //注:只能获得项目根目录中下资源的流对象,class文件的流对象需要类加载器

网站计数器

---恢复内容结束---

以上是关于servlet的主要内容,如果未能解决你的问题,请参考以下文章

servlet和filter的区别

Java基础——JSP

java---servlet与filter的联系与区别

servlet,filter,listener,intercepter区别

Tomcat根据JSP生成Servlet机制解析

servlet,过滤器,监听器,拦截器的区别