zoukankan      html  css  js  c++  java
  • JavaWeb(一)——web会话/Tomcat/JDBC

    iwehdio的博客园:https://www.cnblogs.com/iwehdio/

    学习自:

    1、Cookie和Session

    • 会话机制最主要的目的是帮助服务器记住客户端状态(标识用户,跟踪状态)。

      • 目前,客户端与服务器的通讯都是通过HTTP协议。而HTTP是一种无状态协议。
      • 当服务器无法断定客户端时,一次会话就结束了!
      • 服务器什么情况下无法断定一个客户端?无非两种情况:服务器不行了(session失效)或客户端不行了(cookie失效)。
      • 会话的基本原则:双方共存(cookie与session同在)。
    • Cookie:

      • Cookie其实是一份小数据,是服务器响应给客户端,并且存储在客户端的一份小数据。下次客户端访问服务器时,会自动带上这个Cookie。服务器通过Cookie就可以区分客户端。
      • 服务器端发给客户端的Cookie最终以HTTP响应形式发送,也就是Set-Cookie响应头。
      • 浏览器接收到这些响应头后,会把它们作为Cookie文件存在客户端。当我们第二次请求同一个服务器(也可以具体设置Cookie的作用域),浏览器在发送HTTP请求时,会带上这些Cookie。

      image-20210120195514144

    • 其实Cookie可以分为两种:

      • 会话Cookie (Session Cookie):会话Cookie被保存在浏览器的内存中,当浏览器关闭时,内存被释放,内存中的Cookie自然也就烟消云散。
      • 持久性Cookie (Persistent Cookie):向客户端响应持久性Cookie,要设置Cookie的持久化时间!
      • 不设置MaxAge,默认响应会话Cookie(MaxAge<0),存在浏览器内存。Cookie随浏览器关闭而消失
      • 设置MaxAge>0,响应持久性Cookie,会存在电脑硬盘的特定文件夹下(浏览器自定义的)
      • 设置特定Cookie的MaxAge=0,则会删除已经存在客户端的此Cookie
    • Session:

      • Session是服务端的东西。其本质上类似于一个大Map,里面的内容,以键值对的形式存储。
      • 不再把数据作为Cookie放在请求头/响应头里传来传去了,而是只给客户端传一个JSESSIONID(其实也是一个Cookie)。
      • 真正的数据存在服务器端的Session中,Cookie中只是存了Session的id,即JSESSIONID。下次访问该网站时,把JSESSIONID带上,即可在服务器端找到对应的Session,也相当于“带去”了用户信息。
      • Session有个默认最大不活动时间:30分钟。
      • 只要你在服务器端创建了Session,即使不写addCookie("JSESSIONID", id),JSESSIONID仍会被作为Cookie返回。
      • 钝化:如果一个Session长时间无人访问,为了减少内存占用,会被钝化(序列化)到磁盘上。当该Session再次被访问时,才会被活化(反序列化)。
    • Cookie细节:

      • Cookie不可跨域名性。
        • 浏览器判断⼀个⽹站是否能操作另⼀个⽹站的Cookie的依据是域名。所以⼀般来说,当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,⽽不会带上google的Cookie。
        • 但是也可以通过修改作用的域名实现跨域名。
      • Cookie保存中⽂。需要进行URLEncode和Decode。
      • Cookie的有效期是通过setMaxAge()来设置的。
        • 如果MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆⽹站时该
          Cookie就有效【不论关闭了浏览器还是电脑】
        • 如果MaxAge为负数,Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,
          Cookie不会写到硬盘中。Cookie默认值就是-1。
        • 如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的⽅法,把
          MaxAge设置为0等同于删除Cookie。
      • Cookie也没有提供修改Cookie的⽅法。
        • Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie。
        • 注意:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败
    • 浏览器禁⽤了Cookie,Session还能⽤吗?

      • Session好像不能⽤了。但是Java Web提供了解决⽅法:URL地址重写
      • HttpServletResponse类提供了两个URL地址重写的⽅法:
        • encodeURL(String url)
        • encodeRedirectURL(String url)
      • 这两个⽅法会⾃动判断该浏览器是否⽀持Cookie,如果⽀持Cookie,重写后的URL地址就不会带有jsessionid了。
      • URL地址重写的原理:将Session的id信息重写到URL地址中。服务器解析重写后URL,获取Session的
        id。
    • Session和Cookie的区别:

      • 从存储内容上⽐较
        • Cookie只能存储字符串,如果要存储⾮ASCII字符串还要对其编码。
        • Session可以存储任何类型的数据,可以把Session看成是⼀个容器
      • 从隐私安全上⽐较
        • Cookie存储在浏览器中,对客户端是可⻅的。信息容易泄露出去。如果使⽤Cookie,最好将
          Cookie加密
        • Session存储在服务器上,对客户端是透明的。不存在敏感信息泄露问题。
      • 从有效期上⽐较
        • Cookie保存在硬盘中,只需要设置maxAge属性为⽐较⼤的正整数,即使关闭浏览器,
          Cookie还是存在的
        • Session的保存在服务器中,设置maxInactiveInterval属性值来确定Session的有效期。并且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。
      • 从对服务器的负担⽐较
        • Session是保存在服务器的,每个⽤户都会产⽣⼀个Session,如果是并发访问的⽤户⾮常
          多,是不能使⽤Session的,Session会消耗⼤量的内存。
        • Cookie是保存在客户端的。不占⽤服务器的资源。⼤型⽹站,⼀般都
          是使⽤Cookie来进⾏会话跟踪。
      • 从浏览器的⽀持上⽐较
        • 如果浏览器禁⽤了Cookie,那么Cookie是⽆⽤的了!
        • 如果浏览器禁⽤了Cookie,Session可以通过URL地址重写来进⾏会话跟踪。
      • 从跨域名上⽐较
        • Cookie可以设置domain属性来实现跨域名
        • Session只在当前的域名内有效,不可跨域名

    2、Tomcat

    • 服务器最本质的作用有两个:

      • 将资源对外暴露
      • 配合各种传输协议进行响应输出
    • 什么是Tomcat?

      • Tomcat简单的说就是⼀个运⾏JAVA的⽹络服务器,底层是Socket的⼀个程序,它也是JSP和Serlvet的⼀
        个容器。
    • 为什么需要Tomcat?

      • Tomcat就是提供能够让别⼈访问⾃⼰写的⻚⾯的⼀个程序。
    • Tomcat目录结构:

      image-20210120201221113

    • Tomcat架构:

      image-20210120201311516

      • 应该结合配置文件conf/server.xml看,其中与server中的结构对应。

      image-20210120201421679

      • Server.xml文件中的配置结构和Tomcat的架构是一一对应的。根目录是<Server>,代表服务器,<Server>下面有且仅有1个<Service>,代表服务。
      • Service>下有两个<Connector>,代表连接(需要的话可以再加)。
      • 其实这个Connector就是服务器的端口。可以看到Tomcat默认配置了两个端口,一个是HTTP/1.1协议的,一个是AJP/1.3协议。
      • 我们在浏览器输入"http://localhost:8080/demo/index.html"时,浏览器是以HTTP协议发送的,当这个请求到了服务器后,会被识别为HTTP类型,于是服务器就找来专门处理HTTP的Connector,它的默认端口正是上面Server.xml配置的8080。
      • 与Connector平级的还有个<Engine>(Tomcat引擎)。Connector的作用说穿了就是监听端口,不处理实际业务,它只负责把请求带到Engine那,然后Engine会处理。
      • <Engine>下面有个Host,代表主机。主机中就部署了Web项目。
    • web站点目录:

      • 在webapps中建⽴了web1⽬录,下⾯放置我们的html⽂件,jsp⽂件,图⽚等等,则web1就被当做
        web应⽤管理起来(tomcat6.0以后的版本才⽀持)。

      image-20210129152828602

      • web.xml中可以用<welcome-file>指定首页。
    • 配置虚拟目录:

      • 为什么需要配置虚拟⽬录?

        • 如果把所有web站点的⽬录都放在webapps下,可能导致磁盘空间不够⽤,也不利于对web站点
          ⽬录的管理【如果存在⾮常多的web站点⽬录】
        • 把web站点的⽬录分散到其他磁盘管理就需要配置虚拟⽬录【默认情况下,只有webapps下的⽬
          录才能被Tomcat⾃动管理成⼀个web站点】
        • 把web应⽤所在⽬录交给web服务器管理,这个过程称之为虚拟⽬录的映射
      • 配置方法1:

        • 在server.xml中的<Host> 节点下添加如下代码。path表示的是访问时输⼊的web项⽬名,docBase表示的是站点⽬录的绝对路径。
        <Context path="/web1" docBase="D:web1"/>
        
      • 配置方法2:

        • 进⼊到confCatalinalocalhost⽂件下,创建⼀个xml⽂件,该⽂件的名字就是站点的名字。xml⽂件的代码如下,docBase是你web站点的绝对路径。
        <Context
            docBase="D:web1"
            reloadable="true">
        </Context>
        
    • 虚拟主机:

      • 什么是虚拟主机?

        • 多个不同域名的⽹站共存于⼀个Tomcat中
      • 为什么要用到虚拟主机?

        • 开发了4个⽹站,有4个域名。如果我不配置虚拟主机,⼀个Tomcat服务器运⾏⼀个⽹站,我就需要4台电脑才能把4个⽹站运⾏起来。
      • 配置虚拟主机:

        • 在tomcat的server.xml⽂件中添加主机名
        <Host name="zhongfucheng" appBase="D:web1">
        	<Context path="/web1" docBase="D:web1"/>
        </Host>
        
    • 浏览器访问WEB资源的流程图:

      image-20210129153553721

    3、JDBC

    • JDBC就是一组API(包括少量类),为访问不同数据库提供了统一的途径,为开发者屏蔽了一些细节问题。

    • 使用JDBC有三个大步骤:

      • 连接数据库
      • 执行SQL语句
      • 获得结果
    • 获取数据库连接:

      public class DriverDemo {
      	@Test
      	public void testDriver() throws SQLException {
      		//1. 创建一个 Driver 实现类的对象
      		Driver driver = new com.mysql.jdbc.Driver();
      
      		//2. 准备连接数据库的基本信息: url, user, password
      		String url = "jdbc:mysql://192.168.136.128:3306/test";
      		Properties info = new Properties();
      		info.put("user", "root");
      		info.put("password", "root");
      
      		//3. 调用 Driver 接口的 connect(url, info) 获取数据库连接
      		Connection connection = driver.connect(url, info);
      		System.out.println(connection);
      	}
      }
      
    • MySQL的Driver实现类:

      • 只有一个静态代码块和无参构造。

      image-20210120212312981

      • MySQL的Driver类继承了NonRegisteringDriver,NonRegisteringDriver实现了Driver接口的全部方法。

      • connect()的核心代码就一句:总之,就是根据给定的url和用户名密码,返回一个与数据库关联的Connection。

        Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(host(props), port(props), props, database(props), url);
        
      • 由于com.mysql.jdbc.Driver继承了NonRegisteringDriver,所以它也可以调用connect方法(继承父类方法)。

      • 空参构造的作用,仅仅是为了能够new com.mysql.jdbc.Driver()。但重点不在于new本身,而是new这个Driver的时候,JVM会去加载这个Driver实现类。此时会自动执行静态代码块中的代码,就是把这个Driver注册到DriverManager。

        java.sql.DriverManager.registerDriver(new Driver());
        
    • 使用Driver获取连接的整体逻辑是:

      • new com.mysql.jdbc.Driver()
      • 类被加载进内存
      • 静态代码块执行:java.sql.DriverManager.registerDriver(newDriver());
      • com.mysql.jdbc.driver实例被注册进DriverManager
      • 调用com.mysql.jdbc.driver实例的connect()方法获得Connection
    • 获取Connection通常有两种办法:

      • 根据具体的Driver实现类直接获取
      • 通过驱动管理器获取
      • 通常后者更常用。而所谓的驱动管理器,就是DriverManager。通过DriverManager.getConnection()即可获取。
    • DriverManager如何获得Connection。

      @Test
      public void testDriverManager() throws Exception{
          //1. 驱动的全类名
          String driverClass = "com.mysql.jdbc.Driver";
          //2. 准备连接数据库的基本信息: url, user, password
          String url = "jdbc:mysql://192.168.136.128:3306/test";
          String user = "root";
          String password = "root";
      
          //2. 加载数据库驱动程序(,JVM主动加载类到内存,对应的 Driver 实现类中有注册驱动的静态代码块)
          Class.forName(driverClass);
      
          //3. 通过 DriverManager 的 getConnection() 方法获取数据库连接
          Connection connection =
              DriverManager.getConnection(url, user, password);
          System.out.println(connection);
      
      }
      
    • driver.connect()和DriverManager.getConnection()都可以获得连接,它们之间有什么联系吗?

      • DriverManager内部维护一个容器,该容器存储所有已注册的Driver
      • DriverManager是java.sql包下的一个类,内部维护着一个CopyOnWriteArrayList用于存放已经注册的驱动实例。之所以能getConnection(),是因为底层会循环遍历所有驱动,找到当前注册的驱动后调用driver.connect()获得Connection。
      • 静态代码块注册驱动到DriverManager对于Driver方式获取Connection是多余的,但是对于DriverManager获取Connection是必须的。
      • 设计DriverManager的初衷就是为了支持注册多个(多种)驱动,通过DriverManager可以管理多个驱动程序。所以它叫“驱动管理器”(DriverManager)。
    • Connection对象:

      • 客户端与数据库所有的交互都是通过Connection来完成的。
      //创建向数据库发送sql的statement对象。
      createStatement()
      //创建向数据库发送预编译sql的PrepareSatement对象。
      prepareStatement(sql)
      //创建执⾏存储过程的callableStatement对象
      prepareCall(sql)
      //设置事务⾃动提交
      setAutoCommit(boolean autoCommit)
      //提交事务
      commit()
      //回滚事务
      rollback()
      
    • Statement对象:

      • 用于向数据库发送Sql语句,对数据库的增删改查都可以通过此对象发送sql语句完成。
      //查询
      executeQuery(String sql)
      //增删改
      executeUpdate(String sql)
      //任意sql语句都可以,但是⽬标不明确,很少⽤
      execute(String sql)
      //把多条的sql语句放进同⼀个批处理中
      addBatch(String sql)
      //向数据库发送⼀批sql语句执⾏
      executeBatch()
      
    • ResultSet对象:

      • 代表Sql语句的执⾏结果,当Statement对象执⾏executeQuery()时,会返回⼀个ResultSet对象。
      • ResultSet对象维护了⼀个数据⾏的游标【简单理解成指针】,调⽤ResultSet.next()⽅法,可以让游标指向具体的数据⾏,进⾏获取该⾏的数据。
      //获取任意类型的数据
      getObject(String columnName)
      //获取指定类型的数据【各种类型,查看API】
      getString(String columnName)
      //对结果集进⾏滚动查看的⽅法
      next()
      Previous()
      absolute(int row)
      beforeFirst()
      afterLast()
      
    • PreparedStatement对象:

      • 继承Statement对象,它⽐Statement对象更强⼤,使⽤起来更简单
      • Statement对象编译SQL语句时,如果SQL语句有变量,就需要使⽤分隔符来隔开,如果变量⾮常
        多,就会使SQL变得⾮常复杂。PreparedStatement可以使⽤占位符,简化sql的编写
      • Statement会频繁编译SQL。PreparedStatement可对SQL进⾏预编译,提⾼效率,预编译的SQL存储在PreparedStatement对象中
      • PreparedStatement防⽌SQL注⼊。【Statement通过分隔符'++',编写永等式,可以不需要密码就进⼊数据库】
    • 批处理:

      • 当需要向数据库发送⼀批SQL语句执⾏时,应避免向数据库⼀条条发送执⾏,采⽤批处理以提升执⾏效率
      • 批处理有两种⽅式:
        1. Statement
        2. PreparedStatement
      • 通过addBatch()方法添加到批处理中,
      • 通过executeBath()⽅法批量处理执⾏SQL语句,返回⼀个int[]数组,该数组代表各句SQL的返回值
    • MySQL存储⼤⽂本是⽤Test,Test⼜分为4类:

      • TINYTEXT
      • TEXT
      • MEDIUMTEXT
      • LONGTEXT
    • ⽤JDBC操作MySQL数据库去操作大文本数据:

      • 插入:preparedStatement.setCharacterStream(int parameterIndex,Reader reader,long length):第⼆个参数接收的是⼀个流对象,因为⼤⽂本不应该⽤String来接收,String太⼤会导致内存溢出。第三个参数接收的是⽂件的⼤⼩。
      • 查询:resultSet.getCharacterStream(String filename):返回一个该文件路径的Reader对象。

    iwehdio的博客园:https://www.cnblogs.com/iwehdio/
    来源与结束于否定之否定。
  • 相关阅读:
    当当网首页——JS代码
    当当网首页——CSS代码
    离散与连续 分度值
    timepicker php strtotime 8hours
    w[wi].disabled = true;
    Browser Cookie Limits
    FROM_UNIXTIME(unix_timestamp), FROM_UNIXTIME(unix_timestamp,format)
    递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
    从交集角度考虑订房系统的时间连续性
    glup 压缩图片
  • 原文地址:https://www.cnblogs.com/iwehdio/p/14305275.html
Copyright © 2011-2022 走看看