Tomcat和servlet

Tomcat
            个人理解就是部署服务端,相当于封装了socketServer,也是遵守了tcp协议,tomcat有如下目录:
      

bin:脚本目录 *****
    启动脚本(启动服务器):startup.bat
    停止脚本(停止服务器):shutdown.bat

conf:配置文件目录 (config /configuration) *****
    核心配置文件:server.xml
    用户权限配置文件:tomcat-users.xml
    所有web项目默认配置文件:web.xml

lib:依赖库,tomcat和web项目中需要使用的jar包 *****

logs:日志文件.
    localhost_access_log.txt tomcat记录用户访问信息,..表示时间。
    例如:localhost_access_log.2017-04-28.txt
    
temp:临时文件目录,文件夹内内容可以任意删除。

webapps:默认情况下发布WEB项目所存放的目录。 *****

work:tomcat处理JSP的工作目录。

其中部署的代码就是放到webapps这个我文件中,而且他的包是war包,java的包是jar包,然后如果将war包放到这里面就会自动给这个解压

创建web工程:在idea中创建web工程有两种方式,第一个方式就是使用骨架,第二个方式就是不适用骨架,具体流程如下
      1:使用骨架:
       1):  
       2):
 

 3):
    

 然后将缺失的resource和Java文件手动创建出来就完事儿了

第二种:不使用骨架:
 1):
     

2):
   

 3):
 

 各个目录功能:
     

 然后他会有一个虚拟路径,比如本来是loclhost.8080/路径                    但是刚创建的时候会有一个虚拟路径也会到这里面所以这里要删除一下
 

 这里的运行的四个选项框分别为:
         

 
Servlet
     Servlet是一个接口(既规范),他是顶级父接口,如果一个类实现了Servlet的接口就必须实现它里面的所有的方法,但是一般就用service这个接口然而却要实现那么多没用的方法,所以他就有个子类,实现了他的子类也就是只需要实现一个service方法就可以了,servlet的子类就是GenericServlet这个class文件,在GenericServlet的还有一个子类HttpServlet,一般都用HttpServlet重写他的doget和dopost即可。tomcat默认是get请求

      域名是怎么找到这个配置的如下图:
      

在核心文件上配置号好这个想要映射的文件,其中有一个servlet-class这个标签里面是一个路径,他在tomcat中使用的是反色技术
Class clazz = Class.forName("全限定名");
Servlet servlet = clazz.newInstance();//实际上HelloServlet对象,向上转型
servlet.service();

然后再调用service这就是为什么上边说的实现了一个Servlet只用service的原因,因为底层只调用了service这个时候,上边代码也说明了被反射的那个类需要有一个无参构造。

原理:
 

1.当我们点击run运行的时候,tomcat之所以会启动,是因为程序入口(main方法)在tomcat中

2.tomcat开始运行,会加载web项目里面的配置文件web.xml(xml解析,读取数据)

​ 主要是根据url-pattern 找到对应的servlet-class

3.然后tomcat进入等待状态(永不停止,除非手动关闭)

4.当用户在浏览器中输入地址:http://localhost:8080/hello就会定位到tomcat的访问的项目下面的某个servlet中

5.tomcat会根据 /hello 的servlet的虚拟路径 找到HelloServlet的全限定名

6.tomcat底层通过反射创建HelloServlet的对象,并调用HelloServlet的service方法:


Servlet的生命周期:是指一个对象从出生到销毁的过程
        当使用实现顶级父类的时候会重写了好多方法,其中就有init方法还有service还有destroy方法,其中init是初始化,也就是说游览器第一次访问的时候会执行这个方法,当游览器第二次来执行的时候就不会再执行这个方法了,他是在无参构造执行以后来执行init这个方法,然后就是执行service方法,如果关闭这个服务就会执行destroy这个方法。


 

继承HttpServlet方式的执行流程

当访问自定义类的servlet的时候先访问HttpServlet类实现的Servlet接口的service方法,在service方法中调用重载的service,里面两个service,采用了重载,然后根据不同的请求方式执行对应的方法

网页报错问题:
 

1.500错误

​ 服务器异常

2.404错误

​ 找不到资源

3.405错误

​ 如果我们不重写doGet/doPost方法, 那么父类的doGet/doPost方法会执行(继承),给浏览器响应一个错误: 状态码405 (http1.1)。


使用注解不用web.xml来哦欸之路径:
      

 这个注解其实可以@WebServlet("/路径"),然后网址就能localhost:8080/路径
注解如果都有默认值就可以直接写一个值就可以,就是给里面的value赋值,这里面还有一个值:urlPatterns和value是一样的作用,两个不可一起使用

servlet映射路径一共有四种
1:完全路径配置:个人理解就是,写的路径就必须是这个路径,写的比较死,例如 <url-pattern>/user/one</url-pattern>,那么网址就必须http://localhost:8080/hello/one这个路径,
2:目录配置:个人理解,就是写将这个名字目录的子目录都可以匹配到这个映射配置,例如<url-pattern>/user/*</url-pattern>,这样http://localhost:8080/hello/user/*  路径随便只要前边一样就行
3:后缀名匹配:*.do *.action 注意这里不能书写/ 访问以.do或者.action结尾的资源路径,后缀名都属于标识 符      <url-pattern>*.do</url-pattern>  这样然后就可以使用网站http://localhost:8080/....*.do   这样就可以使用,只要是结尾是.do的都可以访问这个配置
4:缺省路径:/ 如果上述三种路径都不满足就访问缺省路径。 <url-pattern>/</url-pattern>,然后就可以随便写
上述访问路径的优先级: 完全路径匹配 > 目录匹配 > 后缀名匹配 > 缺省路径

   

在使用tomcat经常使用的是继承HttpServlet,而重写他的service还是doget还是dopost都会带着两个参数
     

//携带HttpServletRequest req, HttpServletResponse resp参数
@WebServlet("/hello")
public class SendRedirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Content-type", "text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.write("<a href='www.baidu.com'>中国</a>");

        writer.flush();
    }


//携带ServletRequest servletRequest, ServletResponse servletResponse这个参数
public class Test extends GenericServlet {
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        
    }
}

而上边连个方法中,ServletRequest是HttpServletRequest这个参数的父类,HttpServletRequest是ServletRequest的扩展,主要是说HttpServletRequest有什么用呢?


1. service方法的两个参数request和response是由tomcat创建的
    void service(ServletRequest var1, ServletResponse var2)
2. request 表示请求数据, tomcat将浏览器发送过来的请求数据解析并封装到request对象中
        servlet开发者可以通过request对象获得请求数据
3. response 表示响应数据,服务器发送给浏览器的数据
        servlet开发者可以通过response对象设置响应数据

Request是游览器将请求发送到后台服务器也就是tomcat,然后tomcat根据请求的数据(请求行+请求头+请求体)处理然后解析保存到一个Resquest对象中

Request是请求对象,Response是响应对象,他的请求继承关系如下

所以ServletRequest和HttpServletRequest是继承关系,并且两个都是接口,接口是无法创建对象,这个时候,我们就需要用到Request继承体系中的RequestFacade

  • 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。

  • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建

  • 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法

对于上述结论,要想验证,可以编写一个Servlet,在方法中把request对象打印下,就能看到最终的对象是不是RequestFacade
 

@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

输出的就是org.apache.catalina.connector.RequstFacade@xxxx;说明这是一个多态
Request的继承体系为ServletRequest(最大父接口)-->HttpServletRequest(可以处理http协议的请求接口)-->RequestFacade(tomcat定义的实现类)
Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法
而对于Request室友很多API,例如:
获取请求方式(get,post这种):String getMethod()
获取虚拟目录(项目访问路径): String getContextPath()    
获取URL(统一资源定位符): StringBuffer getRequestURL()     
获取URI(统一资源标识符,也就是url后面的地址个人理解): String getRequestURI()   

获取请求体的数据:get和post中get没有请求体,所以他们分别都有可以读取到数据的方法
GET:  String getQueryString()
POST:BufferedReader getReader();
实例代码:
 

@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String result = req.getQueryString();
        System.out.println(result);

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedReader br = req.getReader();
        String result = br.readLine();
        System.out.println(result);
    }
}

使用request的getMethod()来获取请求方式,根据请求方式的不同分别获取请求参数值,这样就可以解决上述问题,但是以后每个Servlet都需要这样写代码,实现起来比较麻烦,这种方案我们不采用
request对象已经将上述获取请求参数的方法进行了封装,并且request提供的方法实现的功能更强大,以后只需要调用request提供的方法即可,在request的方法中都实现了哪些操作?

解决方案二:
1:获取所有参数Map集合:Map<String,String[]> getParameterMap()    第一个为key第二个value集合,因为可能会一个key携带多个value
 

/**
 * request 通用方式获取请求参数
 */
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //GET请求逻辑
        System.out.println("get....");
        //1. 获取所有参数的Map集合
        Map<String, String[]> map = req.getParameterMap();
        for (String key : map.keySet()) {  //也可以用map.foreach(key,value->{..})
            // username:zhangsan lisi
            System.out.print(key+":");

            //获取值
            String[] values = map.get(key);
            for (String value : values) {   
                System.out.print(value + " ");
            }

            System.out.println();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}


2:根据名称获取参数值(数组):String[] getParameterValues(String name)
 

/**
 * request 通用方式获取请求参数
 */
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //GET请求逻辑
        //...
        System.out.println("------------");
        String[] hobbies = req.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}


3:根据名称获取参数值(单个值):String getParameter(String name)
       这个和第二种差不多只是这个是获取一个,如果一个key有好几个value那么久获取第一个value的值

解决post请求的问题,因为tomcat默认是ISO-8859-1编码,而游览器是UTF-8,所以会乱码,解决乱码有三种,如下代码:

package com.itheima.sh.web;

import com.itheima.sh.pojo.User;
import com.itheima.sh.service.UserServcie;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;

@WebServlet("/httpServletRequestDemo04Servlet")
public class LoginServlet 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 {
        //1.获取浏览器的请求数据
//        String username = request.getParameter("username");

        /*
            解决post乱码问题有三种方式:
            【1】方式一
                使用URLEncoder类进行编码:static String encode(String s, String enc)
                                参数:
                                    s:编码的字符串
                                    enc:使用编码表
                使用URLDecoder进行解码:static String decode(String s, String enc)
                                参数:
                                    s:解码的字符串
                                    enc:使用编码表
         */
        //1)编码 : 使用URLEncoder类进行编码:static String encode(String s, String enc)
//        String encodeUsername = URLEncoder.encode(username, "ISO-8859-1");
//        //2)解码:使用URLDecoder进行解码:static String decode(String s, String enc)
//        username = URLDecoder.decode(encodeUsername, "UTF-8");

        /*
             解决post乱码问题有三种方式:
            【2】方式二:
                使用String类中的方法进行编码:    byte[] getBytes(String charsetName)
                                                  参数表示指定的编码表,返回值表示编码后的字节数组
                使用String类中的构造方法进行解码:String(byte[] bytes, String charsetName)
                                                参数:
                                                    bytes:字节数组
                                                    charsetName:表示指定的编码表
                                                返回值:解码后的字符串

         */
        //1)编码 : 使用String类中的方法进行编码:    byte[] getBytes(String charsetName)
//        byte[] bytes = username.getBytes("ISO-8859-1");
//        //2)解码:使用String类中的构造方法进行解码:String(byte[] bytes, String charsetName)
//        username = new String(bytes, "UTF-8");

        //username = new String(username.getBytes("ISO-8859-1"), "UTF-8");

        /*
            解决post乱码问题有三种方式:
            【3】方式三:
                如果是get请求,tomcat8底层已经帮助我们解决完了,我们只需要解决post乱码即可,但是上述
                两种方式对于post请求可以解决乱码,对于get请求本身获取到的已经是正确的数据,处理
                后又乱码了。
                我们的想法是:get请求不用我们自己书写代码处理乱码,只需要我们书写代码处理post乱码。
                我们接下来学习第三种解决方案:
                只解决来自于请求体数据的乱码。而get请求体没有数据,post请求体含有数据,所以我们可以理解为第三种处理方案只是用来解决
                post乱码的。使用的api是ServletRequest接口中的:
                    void setCharacterEncoding(String env)
                        参数:指定的编码表
                注意:该方式的代码必须书写在获取请求数据之前
         */
        request.setCharacterEncoding("utf-8");//告知tomcat使用UTF-8解码页面请求数据

        //  1.获取浏览器的请求数据
        String username = request.getParameter("username");
        System.out.println("username = " + username);
    }
}

第三种必须要调用参数之前将编码改为utf-8.

request的转发: request.getRequestDispatcher("/req6").forward(request,response);
这个是将游览器的请求转发到指定的路径,getRequestDispatcher的参数是指定的路径,forward是请求和响应参数。而且这个转发也可以携带数据例如:void setAttribute(String name,Object o);这个是写入数据然后一起转到指定的位置,在那个位置也可以调用Object getAttribute(String name);,这个也可以删除:void removeAttribute(String name);,而且转发在游览器的路径还是原本的路径只不过转发给了指定的路径。因为他是重新来一次请求
 

还有一个重定向:他是游览器访问一个路径,然后再返回给游览器比关切状态码是302,然后再去重新访问指定的路径,这个想到与是重新访问了一次路径,所以request的setAtribute的参数携带不过去并且游览器的路径也会变化,调用方法resp.sendRedirect("/指定的路径");注意:这个是响应调用的response,并且需要加虚拟地址

常见的MIME类型:就是文件在tomcat服务器中的文件类型:



超文本标记语言文本 .html      text/html ***
xml文档 .xml                 text/xml
XHTML文档 .xhtml             application/xhtml+xml
普通文本         .txt        text/plain ***
PDF文档 .pdf                 application/pdf
Microsoft Word文件 .word     application/msword
PNG图像 .png              image/png **
GIF图形 .gif                 image/gif
JPEG图形 .jpeg,.jpg         image/jpeg **
 

request生命周期:

1.何时创建?

浏览器第一次访问tomcat服务器的时候

2.谁创建?

tomcat创建

3.创建对象做什么?

浏览器第一次访问tomcat服务器的时候,tomcat创建request对象和response对象,传递给servlet中的service方法,然后我们可以在servlet中使用request对象调用方法获取请求数据(请求行 头 体),然后处理业务逻辑,处理完毕,然后tomcat将响应数据给浏览器,浏览器接收到响应之后,tomcat立刻销毁request和response对象。





Response是后端处理完以后需要返回结果给游览器,后端将这些数据封装到response对象中,tomcat解析response对象返回给游览器
reponse响应字节数据:

/**
 * 响应字节数据:设置字节数据的响应体
 */
@WebServlet("/resp4")
public class ResponseDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 读取文件
        FileInputStream fis = new FileInputStream("d://a.jpg");
        //2. 获取response字节输出流
        ServletOutputStream os = response.getOutputStream();
        //3. 完成流的copy
        byte[] buff = new byte[1024];
        int len = 0;
        while ((len = fis.read(buff))!= -1){
            os.write(buff,0,len);
        }
        fis.close();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

 这个和io流一样的
处理字节流也可以使用common-io这个里面的copy

  //1. 读取文件
        FileInputStream fis = new FileInputStream("d://a.jpg");
        //2. 获取response字节输出流
        ServletOutputStream os = response.getOutputStream();
        //3. 完成流的copy
      	IOUtils.copy(fis,os);
        fis.close();

Session和Cookie
         cookie:就是比如一个游览器访问那个游览器,然后游览器会返回一个cookie值返回出来,给游览器,游览器会保存一个cookie,比如这次访问的localhost:8080这个域名,然后游览器会把cookie和这个域名保存下来,然后如果下次再访问的时候,如果还是这个域名那么游览器就会将这个cookie带过去,而且cookie也有两种,一种是会话级别cookie-就是游览器关闭以后cookie就会消失,一种是持久性cookie-就是有固定,不管游览器怎么关闭都没事但是服务器不能关闭。具体代码如下:
            发送Cookie到游览器:
                             

@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //发送Cookie
        //1. 创建Cookie对象
        Cookie cookie = new Cookie("username","zs");
        //2. 发送Cookie,response
        response.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

然后比如访问localhost:8080/aServlet就会游览器获得到一个cookie,这样是一个会话级别,然后下次只要还是localhost:8080/...就可以得到这个cookie,获得cookie的具体代码如下:
  

@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取Cookie
        //1. 获取Cookie数组
        Cookie[] cookies = request.getCookies();
        //2. 遍历数组
        for (Cookie cookie : cookies) {
            //3. 获取数据
            String name = cookie.getName();
            if("username".equals(name)){
                String value = cookie.getValue();
                System.out.println(name+":"+value);
                break;
            }
        }

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

localhost:8080/bServlet这样就可以将localhost:8080这个域名的cookie的值取出来
也可以设置持久层:setMaxAge(int seconds),其中那个seconds就是秒,比如30分钟就是60*30

如果遇到特殊符号 Cookie cookie = new Cookie("msg", "12 34");的那个有空格所以就会出错,这个时候就可以先进行编码然后再去储存到cookie中
 

package com.itheima.sh.b_cookie_02;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

@WebServlet("/specialCookie01Servlet")
public class SpecialCookie01Servlet 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 {
        /*
            向cookie中存储特殊字符问题演示
         */
        //1.创建Cookie类的对象
//        Cookie cookie = new Cookie("msg", "12 34");报错
        String str = "12 34";
        //编码
        String encode = URLEncoder.encode(str, "utf-8");
        Cookie cookie = new Cookie("msg", encode);
        //2.将cookie存储到浏览器端
        response.addCookie(cookie);
    }
}

然后可以得到了就可以String decode = URLDecoder.decode(value, "utf-8");进行解码。

cookie的小结

cookie:创建服务器端,存在浏览器端。减轻服务器压力,但是不安全
 

cookie能够在多次请求的时候实现数据共享的原因:
一次请求服务器的时候,tomcat服务器将cookie响应给浏览器的时候会设置响应头:set-cookie:name=value.

下次再次向服务器发送请求的时候浏览器会设置请求头:cookie:name=value 将cookie携带到服务器端既可以实现数据的共享

cookie的使用:
1.创建cookie对象: new Cookie(name,value)
2.设置cookie为持久化cookie:cookie对象.setMaxAge(秒); 默认是会话级别的,会话结束cookie消失‘
3.响应cookie给浏览器:response.addCookie(cookie);
4.从请求中获取cookie:Cookie[] cookies = request.getCookies();
5.获取cookie的name:cookie对象.getName()
6.获取cookie的value:cookie对象.getValue()
7.向cookie中存储特殊符号:多含有特殊符号的字符串进行编码和解码使用

Session:session和cookie都是会话技术,也是多次请求之间可以数据共享。
session是储存到服务端,cookie是储存到游览器,所以session就会给服务端造成压力但是他会很安全,第一次请求会判断有没有session,如果没有那么就是会创建一个如果有数据就会再次创建这个对象,然后再给里面添加值;
代码实现:

//HttpSession session = request.getSession(); 如果是第一次执行那么就是创建session对象,如果不是第一次执行就是获取session
//HttpSession getSession(boolean create) ; 参数是true用法和无参用法一样的,如果参数是false表示如果存在session就获取session,不存在则返回null;

//void setAttribute(String name, Object o)   存储数据到 session 域中
//Object getAttribute(String name)    根据 key,获取值
//void removeAttribute(String name)    根据 key,删除该键值对

//储存Session
@WebServlet("/demo1")
public class SessionDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	//存储到Session中
        //1. 获取Session对象
        HttpSession session = request.getSession();
        //2. 存储数据
        session.setAttribute("username","zs");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

//取出session
@WebServlet("/demo2")
public class SessionDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据,从session中
        //1. 获取Session对象
        HttpSession session = request.getSession();
        //2. 获取数据
        Object username = session.getAttribute("username");
        System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}



下面是原理:

个人理解原理:就是每个游览器每次第一次访问tomcat底层会创建一个会话级别的cookie,然后这个游览器是第一次游览会创建一个JSESSIONID的session容器的id标识符,然后会将这个值储存到cookie,然后下次访问的时候会根据这个tomcat生成的这个cookie的值然后取出来SESSIONID的值然后就会去找服务器内存中的session容器中的对应的id。这样就可以来识别session容器,但是他是会话级别的,所以就会再游览器关闭了以后失去cookie,但是这个cookie如果想要变成持久的,就可以
 

 //1.创建session
        HttpSession session = request.getSession();
        //2.获取session的JSESSIOID的值
        String sessionId = session.getId();
        System.out.println(sessionId);
        //3.创建Cookie ,Cookie("JSESSIOID",值)
        Cookie cookie = new Cookie("JSESSIONID", sessionId);
        //4.使用cookie对象调用方法setMaxAge()进行cookie的持久化,存活时间建议30min
        cookie.setMaxAge(60*30);
        //5.将cookie响应给浏览器
        response.addCookie(cookie);

这样就会储存下来规定的时间了

 

Session钝化与活化(了解)

(1)服务器端AServlet和BServlet共用的session对象应该是存储在服务器的内存中

(2)服务器重新启动后,内存中的数据应该是已经被释放,对象也应该都销毁了

所以session数据应该也已经不存在了。但是如果session不存在会引发什么问题呢?

举个例子说明下,

(1)用户把需要购买的商品添加到购物车,因为要实现同一个会话多次请求数据共享,所以假设把数据存入Session对象中

(2)用户正要付钱的时候接到一个电话,付钱的动作就搁浅了

(3)正在用户打电话的时候,购物网站因为某些原因需要重启

(4)重启后session数据被销毁,购物车中的商品信息也就会随之而消失

(5)用户想再次发起支付,就会出为问题

所以说对于session的数据,我们应该做到就算服务器重启了,也应该能把数据保存下来才对。

分析了这么多,那么Tomcat服务器在重启的时候,session数据到底会不会保存?

答案是肯定的。

钝化:就是正常关闭tomcat服务器,会将session容器中的数据长久保存到硬盘上。底层原理是序列化。

活化:就是启动tomcat服务器,将之前钝化的session容器读取到内存中。底层原理是反序列化。

由于钝化和活化的原理是序列化和反序列,所以要求存储在session容器中的对象所属类必须实现序列化接口Serializable。**

代码实现:
序列化:
 

package com.itheima.sh.f_session_06;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/setSessionServlet")
public class SetSessionServlet 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 {
        response.setContentType("text/html;charset=utf-8");
        //1.创建session
        HttpSession session = request.getSession();
        //2.获取session的id
        String sessionId = session.getId();
        //3.创建商品对象
        Product p = new Product("笔记本", 9999);
        //4.将商品对象存储到session中
        session.setAttribute("p",p);
        //5.响应数据
        response.getWriter().print("setSessionServlet.....当前JSESSIONID="+sessionId);
    }
}

反序列化:
 

package com.itheima.sh.f_session_06;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/getSessionServlet")
public class GetSessionServlet 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 {
        response.setContentType("text/html;charset=utf-8");
        //1.获取session
        HttpSession session = request.getSession();
        //2.获取session的id
        String sessionId = session.getId();
        //3.从session中取出商品
        Product p = (Product) session.getAttribute("p");
        //4.响应数据
        response.getWriter().print("getSessionServlet.....当前JSESSIONID="+sessionId+",p="+p.toString());
    }
}

Session销毁
1:session销毁有两种方式:默认情况下就是30分钟自动销毁,如果没有配置,默认是30分钟,默认值是在Tomcat的web.xml配置文件中写死的。
2:调用Session对象的invalidate()进行销毁
 

@WebServlet("/demo2")
public class SessionDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据,从session中

        //1. 获取Session对象
        HttpSession session = request.getSession();
        System.out.println(session);

        // 销毁
        session.invalidate();
        //2. 获取数据
        Object username = session.getAttribute("username");
        System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}


Cookie和Session小结
      

Cookie 和 Session 都是来完成一次会话内多次请求间==数据共享==的。所需两个对象放在一块,就需要思考:

区别:

存储位置:Cookie 是将数据存储在客户端,Session 将数据存储在服务端

安全性:Cookie不安全,Session安全

数据大小:Cookie最大3KB,Session无大小限制

存储时间:Cookie可以通过setMaxAge()长期存储,Session默认30分钟

服务器性能:Cookie不占服务器资源,Session占用服务器资源

应用场景:

购物车:使用Cookie来存储

以登录用户的名称展示:使用Session来存储

记住我功能:使用Cookie来存储

验证码:使用session来存储

  • Cookie是用来保证用户在未登录情况下的身份识别

  • Session是用来保存用户登录后的数据

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值