JavaWeb随笔

JavaWeb

servlet

servlet(server applet):服务器端的Java小程序

关于系统架构

1.架构分类
  1. C/S架构
  2. B/S架构
2.C/S架构(client/server)
  • C/S架构的特点:需要安装特定的客户端软件
  • C/S架构系统的优点和缺点
    • 优点:
      • 速度快(因为大部分的数据都是集成在客户端软件当中的,有很少量的数据需要从服务端传递过来,因此速度快)
      • 体验好
      • 界面炫酷
      • 服务器压力小(大部分数据集成在客户端软件当中,需要从服务端请求的数据少)
      • 安全(客户端有很多个并且大量数据都是集成在客户端软件当中的,即使服务器受损了,数据也不会丢失)
    • 缺点:
      • 升级维护困难
3.B/S架构(browser/server)
  • B/S架构系统本质上还是一个C/S架构的系统,只是这个C比较特殊,是一个固定不变的浏览器软件
  • B/S架构的优缺点
    • 优点:
      • 升级维护容易,成本低
      • 不需要安装特定的客户端软件
    • 缺点:
      • 界面不美观
      • 服务器压力大
      • 不安全
      • 速度慢
      • 体验不好

B/S架构系统通信原理

JavaWeb随笔_第1张图片

  • web系统的访问过程
    • 第一步:打开浏览器
    • 第二步:找到地址栏
    • 第三步:输入一个合法的网址
    • 第四步:回车
    • 第五步:在浏览器上显示相应的结果
  • 关于域名
    • https://www.baidu.com/(网址)
    • www.baidu.com是一个域名
    • 在浏览器地址栏上输入域名,回车之后,域名解析器会将域名解析出来一个具体的IP地址和端口号
    • 解析结果也许是:https://14.215.177.39:80//index.html
  • 什么是IP地址
    • 计算机在网络当中的一个身份证号,在同一个网络中,ip地址是唯一的
    • A计算机想要和B计算机进行通信,首先需要知道B计算机的IP地址,有了IP地址才能建立连接
  • 什么是端口号
    • 一个端口号代表一个软件(一个端口号代表一个应用,一个端口仅代表一个服务)
    • 一个计算机中有很多软件,每一个软件启动之后都有一个端口号
    • 在同一个计算机上,端口号具有唯一性
  • 一个web系统的通信原理?通信步骤
    • 第一步:输入网址(URL)
    • 第二步:域名解析器进行域名解析:https://14.215.177.39:80//index.html
    • 第三步:浏览器软件在网络中搜索14.215.177.39这一台主机,知道找到这台主机
    • 第四步:定位14.215.177.39这台主机上的服务器软件,因为是80端口,可以很轻松定位到80端口对应的服务器软件
    • 第五步:80端口对应的服务器软件得知浏览器想要的资源名是:index.html
    • 第六步:服务器找到index.html文件,并且将index.html文件当中的内容直接输出相应到浏览器中
    • 第七步:浏览器接受到来自服务器的代码(html css js)
    • 第八步:浏览器渲染,执行html css js代码,展示效果
  • 什么是URL:
    • 统一资源定位符(http://www.baidu.com)

web服务器软件

  • web服务器软件都有哪些呢

    • Tomcat(web服务器)
    • jetty(web服务器)
    • JBOSS(应用服务器)
    • WebLogic(应用服务器)
    • WebSphere(应用服务器)
  • 应用服务器与web服务器的关系

    • 应用服务器实现了JavaEE所有规范
    • web服务器只实现了JavaEE中的servlet+JSP两个核心规范
    • 应用服务器是包含web服务器的
  • tomcat下载

    • apache官网地址:https://www.apache.org/
    • tomcat官方网址:https://tomcat.apache.org
    • tomcat是开源免费的web服务器
    • tomcat是Java语言编写的,因此tomcat要想在计算机上运行,必须有jre,因此需要配置运行环境
  • 关于tomcat服务器的目录

    • bin:是tomcat服务器的命令文件存放的目录,比如启动tomcat和关闭tomcat
    • conf:存放的是Tomcat的配置文件(server.xml文件中可以配置端口号,tomcat的默认端口号是8080)
    • lib:这个目录存放的是tomcat服务器的核心程序目录,因为tomcat是Java语言编写的,这里的jar包里面都是class文件
    • logs:tomcat服务器的日志目录
    • temp:存放临时文件的目录
    • webapps:这个目录中存放大量的webapp(web application:web 应用)
    • work:这个目录是用来存放jsp文件翻译之后的Java文件以及编译生成的class文件
  • 关于tomcat的环境配置的问题

    • tomcat服务器是用Java程序编写的,因此首先需要配置jre
    • 但是我们发现即使不用配置JAVA_HOME其实也可以运行Java程序
    • 通过分析tomcat服务器的源码发现,必须里面要求必须配置JAVA_HOME和CATALINA_HOME这两个环境变量
  • 访问tomcat服务器的步骤

    • 在cmd窗口输入startup.bat或者在tomcat的bin目录下双击startup.bat这个文件
      • startup.bat是在Windows操作系统下面的批处理文件,batch文件
      • startup.sh是在Linux操作系统下面的批处理文件,shell文件
      • 由此可见,tomcat服务器可以在Linux和Windows操作系统下面都可以运行
      • 启动startup.bat的时候实际上启动的是catalina.bat,这个文件执行的是org.apache.catalina.startup.Bootstrap这个类,因为tomcat是用Java语言编写的,所以说启动tomcat就是运行main方法
    • 打开浏览器
    • 输入网址:http://127.0.0.1(或者这里的IP地址改成localhost):8080看是否会相应tomcat的页面
  • 然后可以在webapps目录下面放一些静态资源文件,这样别人就可以通过浏览器访问这些静态资源

  • 在浏览器上直接输入一个url,然后回车就相当于点击一个超链接

    • 在使用超链接的时候,可以省略http://127.0.0.1:8080
    • 但是需要注意的是路径要以/开头

<a href="/oa/login.html">user logina>



<a herf="/oa/test/debug/a.html">a pagea>

开发一个web小程序

在开发一个web小程序的过程中涉及到多少个对象
  • 浏览器开发团队
  • web server开发团队
  • webapps开发团队
  • DB server开发团队

在开发一个web程序的过程中涉及到了四个对象,并且每两个对象之间遵循了一定的协议
JavaWeb随笔_第2张图片##### Servlet规范是一个什么规范?

  • 遵循Servlet规范的webapp,这个webapp就可以在不同的web服务器中运行(因为这个webapp是遵循Servlet规范的)
  • Servlet规范包括哪些内容呢
    • 规范了哪些接口,类,web应用中应该有哪些配置文件,配置文件的名字,存放路径,内容,合法的web应用应该有怎样的目录结构

开发一个servlet小程序的webapp(重点)

  • 开发步骤:
    • 第一步:在webapps目录下新建一个目录,起名为crm(crm是自己定义的,可以换成其他的名字,crm就是webapp的名字)
      • 注意:crm就是webapp的跟
    • 第二步:在webapp的根下面创建一个目录WEB-INF
      • 注意:这个目录的名字是servlet规范中规定的,必须全部大写并且名字必须一模一样
    • 第三步:在WEB-INF目录下创建一个目录classes
      • 注意:这个目录的名字必须是全部小写的classes,也是servlet规范中定义的,另外在这个目录下存放的是Java程序编译生成的class文件(也就是这里存放的是字节码文件)
    • 第四步:在WEB-INF目录下新建一个目录:lib
      • 注意:这个目录不是必须的,但如果一个webapp需要第三方jar包的话,这个jar包需要放在lib目录下,另外这个目录的名字也不能随意编写,必须是全部小写的lib,例如Java语言连接数据库需要的驱动jar包,那么这个jar包就必须放在lib目录下
    • 第五步:在WEB-INF目录下新建一个文件:web.xml
      • 注意:这个文件不是必须的,这个文件名必须叫做web.xml,这个文件必须放在这里,一个合法的webapp,web.xml文件是必须的,这个web.xml文件就是一个配置文件,在这个给配置文件中描述了请求路径和Servlet类之间的对照关系
      • 这个文件最好是从其他的webapp中拷贝的,不要手写


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">
web-app>
  • 第六步:编写一个Java程序,这个java程序也不能随意开发,这个小程序必须实现servlet接口
    • 注意:从JakartaEE9开始,Servlet接口的全名变了:jakarta.servlet.Servlet
    • 注意:在编写Java小程序的时候,java源代码愿意放在哪里就放在哪里,位置无所谓,只需要将编译之后的class文件放到classes目录下即可
  • 第七步:编译我们编写的HelloServlet程序
    • 怎样才能让这个程序编译通过呢?配置环境变量CLASSPATH
    • 思考问题:以上配置的CLASSPATH和tomcat的运行有没有关系呢?
      • 没有任何关系,以上配置只是为了让HelloServlet能够正常编译生成class文件
  • 第八步:将以上编译之后的HelloServlet.class文件拷贝到WEB-INF/classes目录下
  • 第九步:在web.xml文件中编写配置信息,让请求路径和Servlet类名关联在一起
    • 这一步用专业术语描述就是:在web.xml文件中注册Servlet类


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">
  <servlet>
	<servlet-name>HelloServletservlet-name>
	
	<servlet-class>src.HelloServletservlet-class>
  servlet>
  <servlet-mapping>
	<servlet-name>HelloServletservlet-name>
	
	<url-pattern>/hellourl-pattern>
  servlet-mapping>
web-app>
  • 第十步:启动tomcat服务器

  • 第十一步:打开浏览器,在浏览器地址栏中输入一个url,这个URL必须是

    • 在web.xml中url-pattern

    • 非常重要的一件事情就是浏览器上的请求路径不能随便写,这个请求路径必须和web.xml文件中的url-pattern一致

    • 注意:在浏览器上的请求路径和web.xml中的url-pattern唯一的区别就是:浏览器上的请求路径必须带上项目名称:/crm

    • 浏览器上编写的路径太复杂,可以使用超链接(非常重要:html页面只能放在WEB-INF目录外面

    • 以后不用编写main方法了,tomcat负责调用main方法,tomcat服务器启动的时候执行的就是main方法,我们Javaweb程序员只需要编写servlet接口的实现类,然后将其注册到web.xml文件中即可

      • 合法的webapp的目录结构
      webapproot
      	-----WEB-INF
      		-----classes
      		-----lib
      		-----web.xml
      	-----html
      	-----css
      	-----js
      	....
      
    • 浏览器发送请求,到最终服务器调用servlet中的方法,是怎样的一个过程?

      • 用户输入url,或者点击超链接http://127.0.0.1:8080/crm/test
      • 然后tomcat就受到请求,截取链接/crm/test
      • tomcat找到crm项目
      • 从crm项目下的web.xml中找到该路径对应的class文件
      • 通过反射机制创建TestServlet对象
      • 调用TestServlet对象的service方法处理用户请求
解决tomcat服务器启动时在doc窗口下乱码问题(控制台乱码)

将conf下的logging.properties中配置改成如下:

java.util.logging.ConsoleHandler.encoding = GBK

向浏览器响应一段html代码
public void service(ServletRequest request,ServletResponse response) throws ServletException,IOException{
	System.out.println("Test Servlet");
	//设置响应流的格式
	response.setContentType("text/html");//这样就可以向网页中响应文本内容或者html代码了,但是需要注意的是这个方法需要在获取流之前调用
	
	//通过PrintWriter向浏览器中响应信息给用户
	PrintWriter out = response.getWriter();
	out.print("Welcome to Servlet!!!");
	out.print("

Test

"
); }

通过jdbc技术向网页上响应数据库的内容

实现步骤:
  • 第一步:在Servlet实现类中编写连接数据库的代码
  • 第二步:将jdbc驱动的jar包放在WEB-INF下面的lib目录里面
  • 第三步:将该实现类注册到web.xml文件中
  • 第四步:启动tomcat服务器
  • 第五步:打开浏览器,输入正确的路径,就可以访问数据库中的数据了
package src;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
public class PlayerServlet implements Servlet{
	//重写五个方法
	public void init(ServletConfig config) throws ServletException{
		
	}
	public void service(ServletRequest request,ServletResponse response) throws ServletException,IOException{
		//设置文本流格式
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		//核心代码
		//连接数据库
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try{
			//注册驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			//获取连接信息
			String url = "jdbc:mysql://localhost:3306/mybatis";
			String username = "root";
			String password = "123456";
			conn = DriverManager.getConnection(url,username,password);
			//获取预编译的数据库对象
			String sql = "select number,name, team,position,salary from player";
			ps = conn.prepareStatement(sql);
			//执行sql语句
			rs = ps.executeQuery();
			//处理查询结果集
			while(rs.next()){
				int number = rs.getInt("number");
				String name = rs.getString("name");
				String team = rs.getString("team");
				String position = rs.getString("position");
				double salary = rs.getDouble("salary");

				//向用户界面输出查询结果
				out.print(number+","+name+","+team+","+position+","+salary+"
"
); } }catch(Exception e){ e.printStackTrace(); }finally{ //释放资源 if(rs != null){ try{ rs.close(); }catch(Exception e){ e.printStackTrace(); } } if(ps != null){ try{ ps.close(); }catch(Exception e){ e.printStackTrace(); } } if(conn != null){ try{ conn.close(); }catch(Exception e){ e.printStackTrace(); } } } } public void destroy(){ } public String getServletInfo(){ return ""; } public ServletConfig getServletConfig(){ return null; } }

在集成开发环境中开发一个Servlet小程序,连接数据库

开发步骤:
  • 第一步:新建一个空的project
  • 第二步:新建一个空的module
  • 第三步:右键新建的module,点击Add Framework support,勾选web application
  • 第四步:根据需要是否保留index.jsp,暂时还没学习,就删掉吧
  • 第五步:编写servlet程序
  • 第六步:导入jsp-api.jar(虽然暂时不需要但是最好也导进来)和servlet-api.jar,点击file—>project structure—>dependencies—>加号—>add jars……,将这两个jar包导入
  • 第七步:将servlet小程序注册到web.xml中
  • 第八步:编写html代码块,实现通过点击超链接来访问后台数据的功能,记住该html代码块只能写在WEB-INF外面,但是需要注意的是超链接的地址最前面要加上项目名称
  • 第九步:将servlet程序和tomcat服务器关联在一起,这里需要注意的一点是最好让servlet与tomcat关联在一起的时候项目名称改成前端超链接相同
  • 第十步:在WEB-INF下新建一个lib目录,将mysql的驱动jar包放到该目录下
  • 第十一步:启动tomcat服务器
  • 第十二步:打开浏览器,输入前端页面所在的位置
  • 第十三步:点击超链接访问后台数据

servlet的生命周期

  • 什么是servlet的生命周期?
    • servlet什么时候被创建
    • servlet什么时候被销毁
    • servlet对象创建了几个
    • servlet的生命周期表示:一个servlet对象从出生到死亡的整个过程
  • servlet的生命周期由谁来维护?
    • servlet对象的创建,对象上方法的调用,对象的销毁,javaweb程序员都是无权干预的
    • servlet对象的生命周期是由tomcat服务器(web server)全权负责
    • tomcat服务器我们通常又称为web容器
    • servlet的生命周期是由web容器来管理的
  • 我们自己创建的servlet对象收到web容器的管理吗?
    • 我们自己创建的对象不会受到web容器的管理
    • web容器创建的servlet对象,会放在一个hashmap集合当中,只有在这个集合当中的servlet才会被web容器管理,我们自己new出来的对象不会放到web容器中
  • 对于servlet对象的注意点
    • servlet对象在服务器启动的时候并不会被实例化,但是如果想让servlet对象在服务器启动的时候就实例化对象,可以在web.xml文件中的servlet标签中加一个这样的配置:,然后标签中加一个整数,整数越小,优先级越高,当一个web.xml文件中配置了多个映射关系的时候,会优先创建优先级高的servlet对象
    • servlet对象属于假单例(为什么说是假单例呢,因为servlet是由tomcat创建出来的,但是它的构造方法并不是私有的,真单例的对象构造方法是私有的),当有千万个用户同时请求一个资源的时候,还是只会创建一个servlet对象,这就属于多线程共享servlet,这时候就会出现问题
    • servlet被创建的时间,就是当有用户发送请求的时候才会实例化servlet对象,因为这样可以节省资源,并且显示调用servlet的无参构造方法,然后再调用servlet对象的init方法,最后再 调用service方法
    • 并且再用户多次发送请求的时候,无参构造和init方法只会调用一次,但是没发一次请求都会调用service方法
    • servlet的销毁时间是在服务器关闭之前会调用一次对象的destroy方法,destroy方法调用的时候对象没有被销毁,因为destroy方法是实例方法,对象如果被销毁了,就无法调用destroy方法了,在destroy方法调用结束之后,servlet对象才会被销毁,在destroy方法中可以将流的关闭写在这个方法里面
    • 为什么要使用init方法呢?
      • 我们思考一个问题,servlet的构造方法和init方法几乎是在同一时间执行,那么为什么还要init方法呢?很多在对象创建的时候就可以把代码写到无参构造方法中,那么为什么还需要init方法呢?
      • 因为不建议程序员手动写servlet的构造方法,并且容易出错,因此我们想到用init方法来代替构造方法,这样,很多只执行一次的代码就可以写在init方法中了

ServletConfig

抽象类GenericServlet
  • 什么是ServletConfig?
    • javax.servlet.ServletConfig,显然它是Servlet规范中的一员,ServletConfig是一个接口
  • 谁去实现这个接口呢?
    • tomcat服务器实现了ServletConfig接口
    • 如果把Tomcat服务器换成jetty或者其他服务器,输出ServletConfig对象的时候,结果可能不一样
  • 一个Servlet对象中就有一个ServletConfig对象(Servlet对象和ServletConfig对象是一对一的),有多少个Servlet对象就会有多少个ServletConfig对象
  • ServletConfig对象是由谁创建的?在什么时候创建?
    • Tomcat服务器(WEB服务器)创建的ServletConfig对象
    • 在创建Servlet对象的时候,同时还创建了ServletConfig对象
  • ServletConfig接口有什么作用?
    • ServletConfig对象的翻译是:Servlet对象的配置信息对象
    • 有多少个Servlet对象就会有多少个ServletConfig对象与之对应
  • ServletConfig对象包含了什么信息呢?
<servlet>
        <servlet-name>Studentservlet-name>
        <servlet-class>com.lkw.servlet01.StudentServletservlet-class>
servlet>
  • ServletConfig对象中包含的信息是:web.xml中servlet标签中的配置信息
    • Tomcat在启动的时候会解析web.xml文件,然后将servlet标签中的配置信息包装到ServletConfig对象中
  • ServletConfig接口中有哪些方法?
<servlet>
        <servlet-name>Studentservlet-name>
        <servlet-class>com.lkw.servlet01.StudentServletservlet-class>
        
        <init-param>
            <param-name>driverparam-name>
            <param-value>com.mysql.cj.jdbc.Driverparam-value>
        init-param>
        <init-param>
            <param-name>urlparam-name>
            <param-value>jdbc:mysql://localhost:3306:mybatisparam-value>
        init-param>
        <init-param>
            <param-name>usernameparam-name>
            <param-value>rootparam-value>
        init-param>
        <init-param>
            <param-name>passwordparam-name>
            <param-value>123456param-value>
        init-param>
    servlet>

    • 以上servlet标签中的init-parameter是初始化参数,然后在配置好这些初始化参数之后,当tomcat启动的时候,会解析web.xml文件,然后将这些初始化信息封装到ServletConfig对象当中,那么就可以获取ServletConfig对象,然后通过调用ServletConfig对象中的方法获得这些在web.xml文件中配置的信息
    • 获取servlet-name:config.getServletName();
    • 通过ServletConfig对象中的两个方法可以获取到web.xml文件中的初始化配置信息
      • 获取所有的初始化参数的name,返回的是一个集合:config.getInitParameterNames(),返回的是一个Enumeration集合
      • 获取name对应的参数的值,返回的是一个String:config.getInitParameter();
      • 然后可以将这两个方法结合起来使用,然后通过遍历上面的集合,然后再通过key,获取value
    • 实际上,要想获取Servlet对象的初始化参数,可以不用获取ServletConfig对象,通过this也是可以获取的
public class TestServletConfig extends GenericServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        //获取ServletConfig对象
        ServletConfig config = this.getServletConfig();
        //获取初始化参数的所有name
        Enumeration<String> initParameterNames = config.getInitParameterNames();
        //遍历集合
        while(initParameterNames.hasMoreElements()){
            String name = initParameterNames.nextElement();//获取name值
            //通过name获取name对应的值
            String parameter = config.getInitParameter(name);
            //向页面中响应获取到的key和value
            out.print(name+"="+parameter);
            out.print("
"
); } } }

ServletConfig接口中有四个方法
JavaWeb随笔_第3张图片### ServletContext

  • 什么是ServletContext?
    • ServletContext是接口,是Servlet规范中的一员
  • ServletContext是谁实现的?
    • Tomcat服务器(WEB服务器)实现了ServletContext接口
  • ServletContext是由谁创建的?在什么时候创建?
    • ServletContext对象是由WEB服务器创建的,在服务器启动的时候创建
    • 对于一个webapp来说,ServletContext对象只有一个,只要是在一个webapp下,如果有多个servlet,那么所有的servlet对象共享同一个ServletContext对象
    • ServletContext对象在服务器关闭的时候销毁
  • ServletContext怎么理解?
    • Servlet的环境对象(Servlet的上下文对象)
    • Servlet Context对象可以理解为整个web.xml文件
    • Tomcat是一个容器,一个容器中可以有多个webapp,那么一个webapp就对应了一个ServletContext对象
  • ServletContext接口中的常用方法:
public String getInitParameter(String name);//通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames();//获取所有初始化参数的name

    <context-param>
        <param-name>context pageparam-name>
        <param-value>10param-value>
    context-param>
    <context-param>
        <param-name>context indexparam-name>
        <param-value>100param-value>
    context-param>


//获取应用的根路径(非常重要)因为在java源代码中有一些地方可能会应用到应用的根路径,这个方法可以获取动态获取应用的根路径
public String getContextPath();
//获取某个文件的绝对路径,方法的参数中传递一个文件名,但是要注意的地方是文件名要带上文件夹的名称,如果该文件在webapp的根目录下的话就不用带上文件夹名,但是该文件在根目录下的一个目录下的话,需要带上前面的目录名称
public String getRealPath(String name);
public class TestServletContext extends GenericServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        //获取ServletContext对象
        //有两种方式可以获取该对象
        //第一种:通过ServletConfig对象来获取
        //ServletContext application = this.getServletConfig().getServletContext();
        //第二种:通过this直接获取
        ServletContext application = this.getServletContext();
        //获取初始化参数参数的所有name
        Enumeration<String> initParameterNames = application.getInitParameterNames();
        //遍历集合
        while(initParameterNames.hasMoreElements()){
            String name = initParameterNames.nextElement();
            String value = application.getInitParameter(name);
            //向页面中响应获取到的初始化参数
            out.print(name+"="+value+"
"
); } //获取该webapp的根路径 String contextPath = application.getContextPath(); out.print(contextPath+"
"
); //获取某个应用的绝对路径,这个应用此时正在项目的根路径下,注意在写路径的时候最好是在最前面加上一个”/“ String path1 = application.getRealPath("/index1.html"); out.print("这个应用此时正在项目的根路径下:"+path1+"
"
); //获取某个应用,该应用在一个根目录下的另一个文件夹下 String path2 = application.getRealPath("/realpath/index.html"); out.print("该应用在一个根目录下的另一个文件夹下:"+path2+"
"
); } }
//通过ServletContext对象也是可以记录日志的
public void log(String name);
public void log(String name,Throable t);
//这些日志记录到哪里了?
//我们要知道的一件事情是如果使用的是idea工具启动tomcat服务器的话,那么这个tomcat只是我们在电
//脑上下载的tomcat的副本,算不上真正的tomcat,所以它的日志文件肯定是保存在tomcat副本保存的文
//件夹下面
  • ServletContext对象还有另一个名字:应用域(后面还有其他域,请求域,会话域)

  • 如果所有用户共享一份数据,并且这个数据很少被修改,并且这个数据量很少,可以将这些数据放到ServletContext这个应用域当中

  • 为什么是所有用户共享的数据?不是共享的没有意义,因为一个webapp只有一个ServletContext对象,只有将数据放进去才有意义

  • 为什么数据量要小?因为数据量比较大的话,太占用内存,并且这个对象的生命周期比较长,从服务器启动直到服务器关闭

  • 为什么这些共享数据很少被修改,或者说几乎不修改?所有共享数据如果涉及到修改操作必然会涉及到线程并发带来的安全问题,所以在ServletContext对象中共享的数据一般都是只读的

  • 数据量小,被所有用户共享,又不修改,这样的数据放到ServletContext对象中,会大大提升效率,因为应用域相当于一个缓存,放到缓存中的数据,下次在使用的时候,不需要从数据库中再次获取,会大大提升效率

  • //向ServletContext应用域中存放数据
    public void setAttribute(String name,Object value);
    //向ServletContext应用域中获取数据
    public Object getAttribute(String name);
    //删除ServletContext应用域中存放的数据
    public void removeAttribute(String name);
    

注意:以后我们在编写Servlet类的时候,实际上是不会直接去继承GenericServlet类的,而因为我们使用的是B/S架构,这种架构是基于HTTP超文本传输协议的,在Servlet规范当中,提供了一个叫做HttpServlet的类,这个类是专门为HTTP协议准备的一个Servlet类

继承链
Servlet(接口)
----GenericServlet(抽象类)
----HttpServlet(抽象类)

      • 目前接触过的缓存机制
        • 堆内存当中的字符串池
          • ”abc“先在字符串常量池中去查找,如果有,直接拿来用,如果没有则新建,然后放入到字符串常量池中
        • 堆内存中的整数型常量池
          • [-128~127]一共256个integer类型的引用,放在整数型常量池中,如果没有超出这个范围,就会从常量池中去取
        • 连接池(Connection Cache)
          • 这里所说的连接池中的连接是java语言连接数据库对象:java.sql.Connection对象
          • JVM是一个进程,MySQL数据库是一个进程,进程和进程之间建立连接,打开通道是很费劲的,是很耗费资源的,怎么办呢?可以提前先创建好N个Connection连接对象,将连接对象放到一个集合当中去,我们把这个放油Connection对象的集合称为连接池,每一次用户连接的时候不需要再创建新的对象,省去了新建的环节,直接从连接池中获取连接对象,大大提升了访问效率
          • 连接池:
            • 最小连接数
            • 最大连接数
            • 连接池可以提高用户的访问效率,当然也可以保证数据库的安全
          • 线程池
            • tomcat服务器本身就是支持多线程的
            • tomcat服务器是在用户发送一个请求,就新建一个Thread对象的吗?
              • 不是这样的,实际上是在tomcat启动的时候,会先创建好N多个Thread对象,然后将线程对象放到集合当中去,称为线程池,用户发送请求过来之后,需要有一个对应的线程来处理这个请求,这个时候线程对象就会直接从线程池中拿,效率比较高
              • 所有的WEB服务器,或者应用服务器,都是支持多线程的,都有多线程机制
          • redis
            • NoSQL数据库,非关系型数据库,缓存数据库
          • 向ServletContext应用域中存储数据,也等于是将数据存放到缓存cache中了

HTTP协议

  • 什么是HTTP协议:由W3C之定义一种超文本传输协议
    • 什么是超文本:
      • 超文本就是:不是普通文本,比如流媒体:声音,视频,图片等
      • HTTP协议支持:不仅可以传输普通字符串还可以传输超文本
    • 这种协议游走在B和S之间,B向S发送请求需要遵循该协议,S向B响应数据需要遵循该协议,这样B和S才能解耦合
      • 什么是解耦合?
        • 就是B不依赖S
        • S也不依赖B
  • Http协议包括:
    • 请求协议:浏览器向WEB服务器发送数据的时候,这些数据需要遵循的一套规定
    • 响应协议:WEB服务器向浏览器响应数据的时候,数据在发送的时候需要遵循的一套规定
  • Http协议就是提前制定好的一种消息模板
    • 不管你是哪个品牌的浏览器,WEB服务器,都必须遵守的规定
    • 同一个品牌的比如Chrome浏览器可以向Tomcat发送请求,也可以向Jetty发送数据
    • WEB服务器也不依赖具体品牌的浏览器,可以是FF,IE,Chrome
  • HTTP的请求协议
    • HTTP请求协议包含4部分:
      • 请求行
        • 包括三部分
          • 第一部分:请求方式(7种)
            • get(常用)
            • post(常用)
            • delete
            • put
            • head
            • options
            • trace
          • 第二部分:URI
            • 什么是URI?统一资源标识符。代表网络中某个资源的名字,通过URI无法定位资源
            • 什么是URL?统一资源定位符。代表网络中某个资源,可以通过URL来定位到该资源
            • URI和URL有什么区别,有什么关系
              • URL包括URI
                • 比如有这样的一个URL:http://127.0.0:8080/servlet05/index.html
                • 然后这个资源的URI就是:/servlet05/index.html
          • 第三部分:协议版本号
      • 请求头
        • 请求的主机
        • 主机的端口号
        • 浏览器信息
        • 平台信息
        • cookie等信息
        • ……
      • 空白行
        • 用来分隔请求头和请求体的
      • 请求体
        • 是浏览器向服务器发送的数据
    • HTTP请求的具体报文(GET)
GET /servlet05/getServlet?username=lkw&userpwd=123 HTTP/1.1	请求行	
Host: 127.0.0.1:8080																请求头
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8											
																					空白行
																					请求体

POST请求的具体报文

POST /servlet05/postServlet HTTP/1.1												请求行
Host: 127.0.0.1:8080																          请求头
Connection: keep-alive
Content-Length: 24
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8					
																					空白行
username=lkw&userpwd=123															请求体

HTTP的响应协议

  • HTTP响应协议包含4部分
    • 状态行
      • 三部分组成
        • 第一部分:版本协议号(HTTP/1.1)
        • 第二部分:状态码(HTTP协议中规定的响应状态号,不同的响应结果对应不同的号码)
          • 200表示请求成功,正常结束
          • 404表示访问的资源不存在,通常是因为要么是你的路径写错了,要么就是路径写对了,但是服务器中对应的资源没有启动成功,总之404错误是前端错误
          • 405表示前端发送的请求方式与后端请求处理的方式不一致造成的
            • 比如:前端是POST请求,后端的处理方式是get方式进行处理的时候,就会发生405
            • 比如:前端是GET请求,后端的处理方式是post方式进行处理的时候,就会发生405
          • 500表示服务器端的程序出了异常,一般认为是服务器端的错误导致的
          • 以4开始的一般认为是浏览器端造成的错误
          • 以5开始的一般认为是服务器端造成的错误
    • 响应头
      • 响应的内容类型,长度,时间。。。
    • 空白行
      • 用来分隔响应头和响应体的
    • 响应体
      • 响应体就是响应正文,这些内容是一个长的字符串,这个字符串被浏览器渲染,解释并执行,最终展现效果
  • HTTP响应的具体报文
HTTP/1.1 200  ok												状态行
Content-Type: text/html;charset=ISO-8859-1					响应头
Content-Length: 122
Date: Tue, 01 Mar 2022 15:48:19 GMT
Keep-Alive: timeout=20
Connection: keep-alive
															空白行
												响应体

	
		
		post
	
	
		

post Page

  • GET和POST的区别

    • get请求发送数据的时候,数据会挂在URI后面,并且在URI后面加上一个”?“,”?“后面是数据,这样会导致发送的数据回显在浏览器的地址栏上(get请求在请求行上发送数据)

      • http://127.0.0.1:8080/servlet05/getServlet?username=lkw&userpwd=123
    • post请求发送数据的时候,在请求体当中发送,不会回显到浏览器的地址栏上(post请求在请求体上发送数据)

    • get请求无法发送大数据量,post请求可以发送大数据量,并且而理论上没有长度限制

    • get请求只能发送普通的字符串,并且长度有限,不同浏览器限制不同,post请求可以发送任何类型的数据,包括普通字符串和超文本

    • get请求在W3C中是这样说的:get请求适合于从服务器端获取数据

    • post请求在W3C中是这样说的:post请求适合于向服务器端传送数据

    • get请求是绝对安全的,因为get请求只是为了从服务器山峰获取数据,不会对服务器造成威胁

    • post请求是为危险的,因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器中,就会对服务器造成威胁,另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会拦截post请求

    • get请求支持缓存

      • http://127.0.0.1:8080/servlet/cc.jpg
      • 任何一个get请求的”响应结果“都会被浏览器缓存起来,在浏览器当中,一个get请求的路径对应一个资源,路径不同,对应的资源也不同
      • 实际上,只要发送get请求,浏览器做的第一件事情就是先从本地浏览器缓存中找,找不到的时候就会从服务器上获取,这种缓存机制是为了提升用户体验
      • 但是当我们想每次在发送get请求的时候都不走缓存,应该怎样做呢?
        • 可以在路径的后面添加一个每时每刻都在变化的时间戳,这样每次请求的路径就不一样,那么浏览器就会从服务器上去获取资源,不会走缓存了
          • http://127.0.0.1:8080/servlet/cc.jpg?t=11111111
          • http://127.0.0.1:8080/servlet/cc.jpg?t=11111112
          • http://127.0.0.1:8080/servlet/cc.jpg?t=系统的毫秒数
          • 以上两个路径就不会走缓存了
    • post请求不支持缓存(post请求是用来修改服务器端的资源的)

      • post请求之后,服务器的”响应结果”不会被浏览器缓存起来
    • GET和POST请求应该如何选择,什么时候选择GET请求,什么时候选择POST请求

      • 如果是想从服务器上获取资源,建议使用get请求,如果是想向服务器提交数据,建议使用post请求
      • 大部分的表单提交,都是post方式,因为form表单中要填写大量数据,这些数据都是收集用户的信息,一般是需要传给服务器,服务器都这些数据进行修改/保存等
      • 如果表单上有敏感信息,建议使用post请求,因为get请求会回显到浏览器的地址栏上
      • 做文件上传,一定是post请求,因为要传的数据不是普通文本
      • 其他情况都可以使用get请求
    • 怎么向服务器发送GET请求,怎么向服务器发送POST请求

      • 到目前为止,只有一种情况可以发送POST请求:就是使用form表单的时候,并且form表单中的method属性为post时候才是post请求
      • 其他情况下一律都是get请求
        • 在浏览器上输入URL,回车
        • 在浏览器上直接点击超链接
        • 使用form表单提交数据的时候,form表单的method属性的值为get的时候
        • 或者在使用表单的时候,,method没有写,默认还是method = “get”
        • ……
    • 在发送数据的时候无论是get还是post,发送数据的格式都是一致的,都是用&分隔一对键和值,键和值之间使用=分隔,只是位置不同而已

模板方法设计模式

  • 什么是模板方法设计模式:
    • 在模板类当中定义了核心算法骨架,具体的实现步骤可以延伸到子类中去
  • 模板类通常是一个抽象类,模板当中的模板方法定义核心算法,这个方法通常是final修饰的(但不是必须的)
  • 模板类当中的抽象方法是不确定实现的方法,这个不确定怎么实现的事情,交给子类去处理
  • 模板类
public abstract class Person {
    //定义核心算法
    //添加了final之后,这个方法无法被覆盖,这样核心算法也就得到了保护
    public final void day(){
        eat();
        sleep();
        doSomething();
    }
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
    //可以将这个方法延伸到子类当中去
    public abstract void doSomething();
}
  • 子类1

    public class Student extends Person{
        @Override
        public void doSomething() {
            System.out.println("学生学习");
        }
    }
    
  • 子类2

    public class Teacher extends Person{
        @Override
        public void doSomething() {
            System.out.println("老师教学");
        }
    }
    

HttpServlet

  • HTTP Servlet的作用是HTTP协议专用的类,抽象类
  • HttpServletRequest对象中封装了请求协议的全部内容
    • tomcat服务器(WEB服务器)将“请求协议”中的全部数据解析出来,然后将这些数据全部封装到request对象当中
    • 也就是说,通过HttpServlet可以获取请求协议中的全部内容
  • HttpServletResponse对象是专门用来响应http协议到浏览器的
  • HttpServlet源码分析
//继承链
Servlet
	----GenericServlet
		----HttpServlet
		
		
GenericServlet实现了Servlet接口,在GenericServlet中有有两个service方法

源码分析结果

public class HelloServlet extends HttpServlet {
    //这里重写了service方法,可以可以重写其中请求之一
    /*@Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.print("

Hello

"); }*/ //重写doGet方法 @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print("

Get

"); //我们发现,当重写了doGet方法,并且提交的是get请求的时候,这个方法可以处理get请求 //这个时候我试一下提交post请求 //这时候发现不能处理该请求,并且给了错误提示,同样重写doPost方法之后使用get方式提交也会出现这种错误 //出现上面的情况的原因是我只在子类中重写了doPost方法,但是你在前端提交的是get方法,但是我在子类中没有重写 //HttpServlet的 //doGet方法,那么服务器就会调用HttpServlet的doGet方法,然后就会出现错误,服务器接收到何种请求就会调用该请求 //对应的处理方法 } }

因此我们发现,在HttpServlet中,有service方法,并且这个service方法语序被子类重写,但是被子类重写之后就不能享受网页错误提示

关于web站点的欢迎页面

  • 什么是web站点的欢迎页面
    • 对于一个webapp来说是可以设置欢迎页面的,就是说当我们在访问某个站点的时候,如果没有指定任何“资源路径”,就会默认访问欢迎页面
    • 设置方法,在web.xml中配置如下标签即可
<welcome-file-list>
	<welcome-file>login.htmlwelcome-file>
welcome-file-list>
    • 这样就会在输入站点的时候,就是没有指定资源也会访问该网页
    • 注意:在设置欢迎页面的时候,这个路径不需要以“/”开始,因为这个路径默认是从webapp的根下开始查找的
    • 如果文件放在了webapp根下的文件夹中,那么应该在文件的前面加上上级目录的名称,但是还是不需要以“/”开头
    • 当web.xml文件中配置了多个欢迎页面的时候,越靠上的优先级越高
    • 其实在tomcat服务器中conf/web.xml文件中也配置了,但是这相当于全局配置文件,而在webapp下配置的文件属于局部配置文件,优先加载局部配置文件,就近原则
    • 注意:欢迎页面除了可以可以配置静态网页资源之外,还可以配置一个Servlet,因为欢迎页面就是一个资源,那么Servlet小程序也是一个资源,只不过这个资源是动态资源而已

HttpServletRequest接口详解

  • HttpServletRequest是一个接口,是Servlet规范中的一员,它的父接口是ServletRequest
  • Tomcat服务器(WEB服务器)实现了HttpServlet接口
  • HttpServlet对象是Tomcat服务器创建的
  • 实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServlet对象当中
  • request和response对象的生命周期
    • request和response对象,一个是请求对象,一个是响应对象,这两个对象只在当前请求中有效
    • 一次请求对应一个request对象,一次响应对应一个response对象
  • HttpServletRequest对象中的常用方法
String getParameter(String name);//使用最多的
Map<String,String[]> getParameterMap();//获取map
Enumeration<String> getParameterNames();//获取map集合中的所有key
String[] getParameterValues(String name);//根据key获取map集合的value

请求域对象

  • 请求域对象要比应用域对象要范围要小很多,生命周期短很多,请求域只在一次请求内有效
  • 一个请求对象request对应一个请求域对象,一次请求结束之后,这个请求就销毁了
  • 请求域对象也有三个方法
void setAttribute(String name,Object obj);//向域当中绑定数据
Object getAttribute(String name);//从域当中根据name获取数据
void removeAttribute(String name);//将域当中绑定的数据移除
  • 请求域和应用域的选用原则:
    • 尽量使用小的域对象,因为小的域对象占用的资源较少
  • 跳转
    • 转发(一次请求)
//第一步:获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
//第二步:调用转发器的forward方法完成跳转
dispatcher.getRequestDispatcher(request,response);
//当然也可以使用一行代码实现请求转发
request.getRequestDispatcher("/b").forward(request,response);
  • 两个Servlet怎么实现数据共享
    • 将数据放到ServletContext应用域当中,但是应用域范围太大,占用资源太多,不建议使用
    • 可以将数据放到request域当中,然后AServlet转发到BServlet,保证AServlet和BServlet在同一次请求当中,这样就可以做到两个Servlet,或者多个Servlet共享同一份数据
  • 转发的下一个资源一定是一个Servlet吗?
    • 不一定,只要是Tomcat服务器中的合法资源都可以转发,例如html
    • 注意:转发的时候,路径的写法需要注意,转发的路径以“/”开始,不加项目名
  • 关于request对象中非常容易混淆的方法:
//url?username=lkw&password=123456
String username = request.getParameter("username");
Object obj = request.getAttribute("name");
//以上两个方法的区别:
//第一个方法:获取的是用户在浏览器上提交的数据
//第二个方法:获取的是请求域当中绑定的数据,就是先向请求域中设置一个数据,然后可以通过get方法获取数据

HttpServletRequest接口中的其他常用方法

//获取客户端的IP地址
String remoteAddr = request.getRemoteAddr();
//get请求在请求行上提交数据
//post请求在请求体中提交数据
//设置请求体的字符集(显然这个方法是用来处理POST请求的乱码问题的,这种方法并不适用于get请求的乱码问题)
//tomcat10之后,request请求体当中的字符集默认是UTF-8,不需要设置字符集,不会出现乱码问题
//Tomcat9之前(包括9),如果前端提交的是中文,后端获取之后出现乱码,可以执行如下代码:
request.setCharacterEncoding("UTF-8");
//Tomcat9(包括9)响应中文的时候也会出现乱码问题,可以执行如下代码:
response.setContentType("text/html;charset=UTF-8");
//在tomcat10之后,包括10在内,响应中文将不会出现乱码问题,就不需要设置charset=UTF-8了

//get请求的的乱码问题怎么解决?
//get请求在发送的时候,数据是在请求行上提交的,不是在请求体上提交的
//get乱码的解决方法:在CATALINA_HOME/cong/server.xml中,在Connector标签中设置如下:
<Connector URIEcoding="UTF-8" />
//注意响应的乱码问题,在tomcat8之后,URIEcoding默认即使UTF-8编码,所以GET请求也就不会出现乱码问题了

//获取应用的根路径:
    String contextPath = request.getContextPath();
//获取请求方式
	String method = request.getMethod();
//获取请求的URI
String uri = request.getRequestURI();//   /servlet09/testrequest
//获取servlet path
String servletPath = request.getServletPath();    //testRequest

使用纯粹的Servlet实现对一张单表的CRUD操作

  • 使用servlet技术对一张【部门表进行增删改查操作】

    • 第一步:准备一张数据库表(sql脚本)

      • DROP TABLE IF EXISTS player;
        CREATE TABLE player(
        	number INT,
        	pname  VARCHAR(255),
        	pteam VARCHAR(255)
        );
        INSERT INTO player VALUES(30,'Stephen Curry','GS');
        INSERT INTO player VALUES(24,'Kobe Bryant','LAL');
        INSERT INTO player VALUES(7,'Kevin Druant','Net');
        SELECT * FROM player;
        
    • 第二步:准备前端页面

      • 详情页面:detail.html(单个球员)
      • 添加页面:add.html
      • 修改页面:edit.html
      • 球员列表页面:playerlist.html(所有球员)
      • 欢迎页面:welcome.html
    • 一个困扰了我一个下午的问题就是项目的包结构,就是如果以后还想开发类似的项目,那么properties配置文件应该在src下面创建一个resources文件夹,然后使用ResourceBundle类取这个配置文件中的数据的时候应该传入这样的路径:resources.jdbc(这里的jdbc是我的配置文件的名字,但是不需要加文件后缀名.properties)

在一个web应用中如何实现资源的跳转

  • 在一个web应用中,有两种方式可以实现资源的跳转:

    • 第一种:转发
    • 第二种:重定向
  • 转发和重定向的区别:

    • 代码上的区别:

      //转发
      request.getDispatcherServlet("/list").forward(request,response);
      //转发的时候不管转发多少次都是一次请求
      //重定向
      response.sendRedirect("/项目名/list");
      //重定向的原理是,当浏览器发送一个请求的时候,这时候目标服务器没有该资源的时候,服务器就会向浏览器发送一个路径,让浏览器主动去访问这个路径上的资源
      //所以就是为什么在写路径的时候需要加上项目名,因为是浏览器是主动访问资源的
      
    • 形式上的区别:

      • 转发:(一次请求)
        • 在浏览器上访问例如:http://127.0.0.1:8080/servlet08/a,当请求结束的时候,地址栏上还是这个地址
      • 请求(多次请求)
        • 当在浏览器上访问:http://127.0.0.1:8080/servlet08/a,当请求结束的时候,如果转发给了b,那么地址栏上就变成了http://127.0.0.1:8080/servlet08/b
    • 转发和重定向的本质区别

      • 转发是在服务器内部完成的
      • 重定向是浏览器完成的
    • 转发和重定向应该如何选择

      • 如果希望将上一个Servlet中的数据传到下一个Servlet中就是用转发机制
      • 其他情况都使用重定向
    • 跳转的下一个资源没有要求:

      • 可以是一个Servlet,也可以是一个静态的html,只要是服务器内部的合法资源就可以
    • 转发存在刷新页面的问题:

      • 就是说,当向数据库中插入一条数据的时候,如果反复刷新页面,会在数据库中反复插入该数据,刷新几次插入几次,但是重定向不存在刷新页面的问题

通过注解简化Servlet

  • 在Servlet类上使用@WebServlet注解
    • name属性:用来指定Servlet的名字,等同于
    • urlPattern属性:用来指定Servley的映射路径,可以指定多个字符串。
    • loadOnStartUp属性:用来指定服务器启动阶段是否加载该Servlet。等同于
    • value属性:当注解的名字是value的时候,value可以省略
    • 注意:不是必须将所有属性都写上,只是需要提供什么写什么
    • 注意:属性是一个数组,如果数组中只有一个元素,使用该注解的时候,属性值的大括号可以省略
  • 注解对象使用格式:
    • @注解名称(属性名=属性值,属性名=属性值……)

JSP

  • 纯粹使用servlet编写的程序,存在很多的缺点,只要一修改代码,就需要重新编译,生成新的class问津,打一个war包,重新发布,很麻烦

  • 于是就出现了JSP技术,就是我们程序员只需要写Servlet中的前端代码,然后让我们写的前端代码自动编译生成Servlet这种java程序,然后机器再自动将java程序编译生成class文件,然后让JVM调用这个class文件

  • JSP实际上是一个Servlet

    • index.jsp访问的时候,会自动编译生成index_jsp.java,会自动编译生成index_jsp.class,那么index.jsp这就是一个类
    • index.jsp类继承HttpJspBase,而HttpJspBase类继承的是HttpJspServlet,所以index_jsp类就是一个Servlet类
    • jsp的生命周期和Servlet的生命周期完全相同,完全是一个东西,没有任何区别
    • jsp和Servlet一样,都是单例的(假单例)
    • JSP本质上是一个Servlet,但是JSP和Servlet是有区别的
      • 职责不同:
        • servlet的职责:收集数据(Servlet的强项是逻辑处理,业务处理,连接数据库,收集/获取数据等)
        • JSP的职责:展示数据(JSP的强项是做数据的)
  • jsp文件第一次访问的时候比较慢,为什么?

    • 大部分运维人员在向客户展示项目的时候,会先把所有的jsp文件先访问一遍

    • 第一次比较麻烦

      • 要把jsp文件编译生成java文件
      • java源文件要编译生成class字节码文件
      • 然后通过class去创建servlet对象
      • 然后调用init方法
      • 最后调用servlet的service方法
    • 第二次比较快

      • 因为第二次直接调用servlet的service方法就行了
    • JSP是什么

      • JSP是java程序
      • JSP:javaServer Pages(基于java语言实现的服务器端的页面)
      • servlet是javaee的13个子规范之一,jsp也是
      • jsp是一套规范,所有的web容器都需要遵循这套规范的,是按照这套规范进行翻译的
      • 每一个web容器都会内置一个jsp翻译引擎
    • 对jsp进行错误调试的时候,还是要直接打开JSP文件相对应的java文件,检查java代码

    • jsp的page指令,解决响应的时候中文乱码的问题:

      • 通过page指令来设置响应的内容类型,在内容类型的后面加上:charset=UTF-8
      • <%@page contentType=“text/html;charset=UTF-8”%>
    • 怎么在JSP中编写java程序

      • <%java语句;%>
      • 在这个符号里面编写的称为java程序,被翻译到的servlet类的service方法内部
      • 在<%%>这个符号里面写java代码的时候,要时刻记住在方法体内部应该写哪些内容,不应该写哪些内容
      • 在service方法当中编写的代码是有顺序的,方法体中的代码要遵循自上而下的顺序依次执行
      • 在service方法当中不应该出现静态代码块,不能写方法,不能定义成员变量
      • 在同一个jsp中<%%>这个符号可以多次出现
    • <%!%>

      • 在这个符号当中编写的java程序会自动翻译到service方法之外,就相当于静态变量
      • 这个语法很少使用,因为service方法当中是不允许出现静态变量和实例变量的,因为tomcat服务器是支持多线程的,静态变量和实例变量是会存在线程安全问题
    • JSP的输出语句

      • 向浏览器上输出一个java变量
      • <%String name = “lkw”;out.print(“name=”+name);%>
      • 注意:以上代码中out是jsp的九大内置对象之一,可以拿来直接使用,因为在源码中可以发现,service方法的里面定义了八大实例变量,因此这些变量可以直接在service方法当中直接使用,但是在service
      • 方法之外就不能使用,因此在<%!%>标签之内就不能使用service方法中的内置对象
    • JSP基础语法总结:

      • JSP中直接编写普通字符串
        • 翻译到service方法的out.print();里面
      • <%%>
        • 翻译到service方法的内部,里面是一条条的java语句
      • <%!%>
        • 翻译到service方法的外部
      • <%=%>
        • 翻译到service方法的内部,翻译为:out.print();
        • 使用时机:如果输出的内容中含有java变量,输出的内容是一个动态的内容,不是一个死的字符串串的时候,使用,如果输出的是一个固定的字符串,直接写在jsp文件中即可
      • <%@ page contentType=“text/html;charset=UTF-8”%>
        • page指令,通过contentType属性来设置响应内容类型
    • 使用servlet+jsp完成项目的改造

      • 使用servlet处理业务,收集数据
      • 使用jsp进行数据的展示
      • 将之前编写的html文件全部改成jsp,在jsp文件的头部添加page指令<%@page contentType=“text/html;charset=UTF-8”%>
      • 完成所有页面的跳转,保证页面可以正常流转(修改超链的路径)
        • <%=request.getContextPath()%>,可动态获取项目的根路径,将页面中的项目根路径都改成这种格式
    • jsp指令

      • 指令的作用:指导jsp的翻译引擎如何工作(指导当前的jsp翻译引擎如何翻译jsp文件)

      • jsp指令包括:

        • include指令:包含指令,在jsp中完成静态包含,很少使用
        • taglib指令:引入标签库的指令
        • page指令
      • 指令的用法:

        • <%@指令名 属性名=属性值 属性名=属性值 ……%>
      • 关于page指令的常用属性

        • <%@page session="true|false"%>
          true表示启用jsp的内置对象session,表示一定启动session对象,没有session对象的时候会创建
          如果没有设置,默认是session=“true”
          session="false"表示不启动内置对象,当前的jsp页面无法使用内置对象session
          
        • <%@page contentType="text/html"%>contentType属性用来设置响应的内容类型
          
        • <%@page pageEncoding="UTF-8"%>
          pageEncoding="UTF-8"表示响应时采用的字符集
          
        • <%@page errorPage="/error.jsp"%>
          当前页面出现异常之后,跳转到error.jsp页面
          errorPage属性用来指定出现错误之后跳转的位置
          
        • <%@page isError="true"%>
          表示启用jsp九大内置对象的exception,默认是false
          这个指令最好结合上面的errorPage使用,errorPage指令可以保证当用户的请求出错的时候,前端响应错误页面,后端出现异常,同时利于用户的体验和开发者纠错
          
    • jsp的九大内置对象

      • jakarta.servlet.jsp.PageContext pageContext; (页面作用域)
      • jakarta.servlet.http.HttpServletRequest request, 请求作用域
      • jakarta.servlet.http.HttpSession session 会话作用域
      • jakarta.servlet.ServletContext application; 应用作用域
        • pageContext
        • 以上四个作用域都有:setAttribute,getAttribute,removeAttribute方法
        • 以上作用域的使用规则:尽可能使用小的域
      • jakarta.servlet.jsp.JspWriter out;负责输出
      • jakarta.servlet.http.HttpServletResponse 负责响应
      • jakarta.servlet.ServletConfig config;
      • java.lang.Object page = this;(this指的就是当前的servlet对象)
      • java.lang.Throwable.exception;

EL表达式

  • EL表达式是干什么的

    • Expression Language(表达式语言)
    • EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起开更加整洁,美观
    • JSP中夹杂着各种java代码,例如<%@ java代码%>,<%=%>等,导致jsp文件很混乱
    • EL表达式可以算是JSP语法的一部分,EL表达式归属于JSP
  • EL表达式在JSP中主要是:

    • 从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器,这就是EL表达式的作用

      • 作用一:从某个域中取数据
      • 作用二:将取出来的数据转换成字符串
      • 作用三:将字符串输出到浏览器上
    • EL表达式的语法格式:

      • ${表达式}
    • EL表达式的使用

      • <%
        	//创建user对象
        	User user = new User();
        	user.setName("lkw");
        	user.setAge(20);
        	user.setSex("男");
        	//将User对象存储到某个域当中,一定要存,因为EL表达式只能从某个范围中取数据
        	//数据必须存储到四大范围之一
        	request.setAttribute("userObj",user);
        %>
        <%--使用EL表达式取--%>
        ${这个位置写的一定是存储到域对象中的name}
        应该这样写
        ${userObj}
        等同于java代码:<%=request.getAttribute("userObj")%>
        不可以这样写:${"userObj"},这样写只能输出字符串,不能获得存在域中的数据
        
        面试题:
        ${abc}和${"abc"}的区别
        	${abc}表示从某个域当中取出数据,并且被取的这个数据的name是“abc”,之前一定有这样的代码:域.setAttribute("abc",对象)
        	${"abc"}表示直接将“abc”当作普通字符串输出到浏览器,不会从某个域中取数据
        	
        ${userObj}底层的实现原理:从域中取出数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器
        <%--如果输出对象的属性值,怎么办--%>
        ${userObj.username}使用这个语法的前提是:User对象中有getUsername()方法
        EL表达式的这个语法中,实际调用了底层的getXxx()方法
        如果没有取到数据,会报500异常
        <%
        	//四个域中存储了数据,并且name相同
        	pageContext("data","pageContext");
        	request.setAttribute("data","request");
        	session.setAttribute("data","session");
        	application.setAttribute("data","application");
        	//在没有指定范围的情况下,在EL表达式中取数据优先从小范围中取数据
        	pageContext
        
      • EL表达式优先从小范围中取数据

        • pageContext
      • EL表达式中有四个隐含的范围

        • pageScope对应的是pageContext范围
        • requestScope对应的是request范围
        • sessionScope对应的是session范围
        • applicationScope对应的是application范围
      • EL表达式对null进行了预处理,如果是null,则向浏览器输出一个空字符串,因为设计EL表达式的初衷就是向浏览器展示数据,底层原理是先默认从最小的范围取数据,如果没有取到数据的话,会向范围大的域中依次取数据,都没有的话,不会输出任何内容

      • EL表达式取数据有两种形式

        • 第一种:.(大部分使用这种形式)
        • 第二种:[](如果存储到域的时候,这个name中含有特殊字符,可以使用[ ])
          • request.setAttribute(“abc.def”,“zhangsan”);
          • ${requestScope.abc.def}这样是无法获取到数据的
          • 应该这样:${requestScope[“abc.def”]}
      • 掌握使用EL表达式,怎么从Map集合中取数据

        • ${map.key}
      • 掌握使用EL表达式,从数组和List中取数据,使用下标的形式

        • ${数组[0]}
        • ${list[0]}
      • page指令当中,有一个属性,可以忽略EL表达式

        • <%@page contentType="text/html;charset=UTF-8" isELIgnored="true"%>
          isELIgnored="true",表示忽略EL表达式
          isELIgnored="false",表示不忽略EL表达式(默认就是不忽略)
          isELIgnored="true",这个是全局控制,就是写了这个指令,页面中的所有EL表达式都会失效
          可以使用反斜杠\进行局部的控制,\${username},这样可以在想要忽略的地方忽略表达式
          
          
      • 通过表达式获取应用的根:

        • ${pageContext.request.contextPath}:因为在EL表达式中隐含了pageContext对象,并没有隐含request对象,然后可以通过pageContext获取九大内置对象,然后这个表达式翻译成java代码就是:<%pageContext.getRequest().getPageContextPath()%>
      • EL表达式中的其他隐含对象

JavaWeb随笔_第4张图片- - param(获取请求路径中指定的参数)

- 底层实际上调用的是request.getParameter()

- ```
  username:
password:
//EL表达式获取表单上提交的用户名和密码 ${param.username}:实际上调用的是request.getParameter("username"); ${param.password}:实际上调用的是request.getParameter("password"); ```
  • paramValue(获取请求路径中指定参数的索引值)

    • 其底层实际上调用的是request.getParameterValues();

    • 这个方法一般用在复选框上面,因为复选框上有多个name值相同的属性

    • 爱好:
              <input type="checkbox" name="hobby" value="sleep">睡觉
              <input type="checkbox" name="hobby" value="play"><input type="checkbox" name="hobby" value="eat"><input type="submit" value="点击">
      ${paramValue.hobby[0]}//获取的是复选框上属性值为hobby的数组的第一个下标对应的值
      
  • initParam(获取初始化参数)

    • 其底层调用的是ServletContext.getInitParameter()

    • 
        ![在这里插入图片描述](https://img-blog.csdnimg.cn/d342499700ab49b682d158ffa7d21ebb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5piv5bCP5YiY5ZGAfg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
      
          name
          刘凯武
        
      //获取初始化参数值为name的value
      ${initParam.name}---->刘凯武
      
  • EL表达式的运算符

    • 算术运算符:+ - * / %
    • JavaWeb随笔_第5张图片EL表达式的+号运算符可以处理字符串变量
  • 关系运算符:==、!=、> 、 < 、 >= 、<=
    -JavaWeb随笔_第6张图片逻辑运算符:!、&&、||、not、and、or
    在这里插入图片描述- - - - 条件运算符:? :就是三元运算符

    • 取值运算符:[], .

    • empty运算符

      • 用法:${empty 变量},结果为布尔值

      • <%
                String name1=null;
                String name2="";
                List name3=new ArrayList();
        
                pageContext.setAttribute("name1", name1);
                pageContext.setAttribute("name2", name2);
                pageContext.setAttribute("name3", name3);
            %>
            empty对于没有定义的变量,运算结果为true:
          empty namex=${empty namex }
        empty对于null的引用,运算结果为true: empty name1=${empty name1 }
        empty对于为空串的String引用,运算结果为true: empty name2=${empty name2 }
        empty对于没有元素的数组或集合,运算结果为true: empty name3=${empty name3 }
      • empty运算可以判断一个数据是否为空,若为空,输出true,不为空,输出false
        以下几种情况为空(在原本的key之前加empty关键字):
        (1)值为null、空串
        (2)值为Object类型的数组且长度为0 (注:其他类型的长度为0的数组值为非空)
        (3)List、Map集合元素个数为0

    • 自定义EL函数

      • 因为EL本身具有处理字符串的能力,所以可以自定义EL函数
        • 定义函数
        • 注册:

关于B/S架构系统的会话机制(session机制)

  • 会话:
    • 用户打开浏览器,进行一系列操作,最终将浏览器关闭,这整个过程叫做一次会话。会话在服务器端也有一个对应的java对象,这个java对象叫做session
    • 一个会话对象中包含一个或多个请求
    • 在java的servlet规范当中,session对应的类名:HttpSession
  • session机制属于B/S结构的一部分,如果使用php语言开发web项目,同样也存在session机制,这种机制实际上是一个规范,然后对不同的语言对这种会话机制都有实现
  • session对象的主要作用:保存会话状态(用户登陆成功了,这是一种登陆成功的状态,但是要想把这种状态保存下来就需要使用会话机制保存会话状态)
  • 为什么session对象用来保存会话状态呢
    • 因为http协议是一种无状态协议
    • 无状态就是:请求的时候,B和S是连接的,但是请求结束之后,连接就断开了,http协议设计成这样的原因是因为这种无状态协议,可以降低服务器的压力,请求是瞬间完成的,请求结束之后,连接断开,这样服务器的压力小
    • B和S断开了,对于关闭浏览器这个动作,服务器是不知道的
    • 不同的用户打开浏览器使用的是不同的session对象
  • 为什么不使用request和ServletContext对象保存会话状态?
    • request是请求对象,作用域太小
    • ServletContext是服务器启动的时候创建,服务器关闭的时候销毁,使用这个对象来保存会话状态,如果一个用户登陆成功,那么其他的用户就不需要登陆就可以访问数据,作用域太大
  • 关于session对象
    • session对象是存储在服务器端的
    • 一个session对象对应一个会话
    • 一次会话当中包含了多次请求
    • session的获取方式:
      • HttpSession session = request.getSession();
      • 表示从服务器获取当前的session对象,如果没有获取到任何session对象,则新建
      • HttpSession session = request.getSession(false);
      • 从服务器当中获取当前session对象,如果获取不到session,不会新建,返回null
    • session的实现原理:
      • 在web服务器中有一个session列表,类似于map集合,这个map集合中的key保存的是sessionid,value保存的是对应的session对象
      • 用户发送一个请求的时候,服务器会创建一个新的session对象,同时给session对象生成一个id,然后web服务器会将session的id发送给浏览器,浏览器将session的id保存在浏览器的缓存当中
      • 用户发送第二次请求的时候,会自动将浏览器缓存中的sessionid自动发送给服务器,服务器获取到sessionid,然后从session列表中查到对应的session对象
      • jssesion=xxxxx这个是以cookie的形式保存在浏览器的内存当中的,浏览器只要关闭,这个cookie就没有了
      • 浏览器关闭,内存消失,cookie消失,sessionid消失,等同于会话消失
    • 为什么浏览器关闭,session结束
      • 关闭浏览器之后,浏览器中保存的sessionid消失,下次重新打开浏览器的之后,浏览器的缓存中并没有保存这个sessionid,自然找不到服务器中对应的session对象,session对象找不到等同于会话结束
    • session对象什么时候被销毁
      • 两种销毁方式:
        • 第一种:超时销毁
          • 可以设置session的失效时间,在这段时间内如果发现用户没有进行任何操作,那么就会被销毁
        • 第二种:手动销毁
          • 手动销毁就是清除浏览器中的缓存,当用户下一次发送请求的时候,发现从浏览器中找不到响应的sessionid,既然sessionid找不到了,那么就相当于在服务器中找不到相应的session对象,那么就等同于session失效
    • cookie禁用了,session还是可以找到的
      • cookie禁用:服务器正常发送cookie给浏览器,但是浏览器不接受,因此在浏览器的缓存中就找不到sessionid,那么浏览器在向服务器发送请求的时候,都会重新创建新的session对象
      • 即便是cookie被禁用了,仍然可以实现session机制,可以使用URL重写机制,就是在URL后面加一个英文分号,然后在分号的后面加上jsessionid=xxxxxx就可以了
      • 但是url重写机制会提高开发这个成本,开发人员在编写任何请求路径的时候,后面都要添加一个sessionid,给开发带来了很大的难度,很高的成本,大部分网站在仅用了cookie的时候,网站就不能为用户提供服务

Cookie

  • session的实现原理中,每一个session都会关联一个sessionid,
    • 例如:JSESSIONID=224B0760EB9CCD4CF0B104408629E198
    • 以上的这个键值对数据其实就是cookie对象
    • 对于session关联的cookie来说,这个cookie是被保存在浏览器的“运行内存”当中
    • 只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存中的cookie发送到服务器
    • 例如,上面这个cookie:JSESSIONID=224B0760EB9CCD4CF0B104408629E198,当用户再次发送请求的时候,就会将这个cookie发送到服务器
    • 服务器就是根据224B0760EB9CCD4CF0B104408629E198这个值来找到对应的session对象的,就相当于cookie当中保存的是键值对,键名为自定义的,值表示的是sessionid,然后当用户发送请求的时候,会将这个cookie发送到服务端,然后服务端获得这个cookie之后,然后会获取到sessionid,然后根据sessionid查询对应的session对象
  • cookie的生成过程,保存位置,作用,浏览器发送cookie的时机,发送哪些cookie给服务器
    • cookie最终是保存在浏览器客户端的
    • 存储位置:
      • 可以保存在运行内存当中(浏览器关闭cookie就会消失)
      • 也可以保存在硬盘文件中(永久保存)
    • cookie的作用
      • cookie和session机制其实就是为了保存会话状态,因为http协议是面向无连接和无状态的协议
      • cookie是将会话状态保存在浏览器客户端的(cookie数据存储在浏览器客户端的)
      • session是将会话状态保存到服务器端的(session对象是存储在服务器上的)
    • cookie机制和session机制其实都不是javayuyan特有的机制,实际上cookie和session都是http协议的一部分,使用其他编程语言只要是做web开发都会存在cookiehesession机制
    • http协议中规定:任何一个cookie都是由name和value组成的,name和value都是字符串类型的
    • 在java的servlet类中,对cookie提供了哪些支持呢?
      • 提供了一个Cookie类专门表示cookie数据
      • java怎么将cookie数据发送到浏览器呢?response.addCookie(cookie);
    • 在http协议中,当浏览器发送请求的时候,会自动携带该path下的cookie数据给服务器
    • 关于cookie的有效时间
      • 设置cookie的有效时间
        • cookie.setMaxAge(60);表示cookie将在60秒之后失效
      • 没有设置有效时间,默认保存在浏览器的运行内存当中,浏览器关闭则cookie失效
      • 只要设置cookie的有效时间>0,这个cookie就会一直存在硬盘文件中
      • 设置cookie<0,表示该cookie不会被存储在硬盘文件上
      • 设置cookie=0,表示将该cookie删除,主要应用在:使用这种方式删除浏览器上的同名cookie
    • 关于cookie的path,cookie关联的路径:
      • 假设现在发送的请求路径是http://localhost:8080:/servlet09/cookie/generate生成的cookie,如果cookie、没有设置path,默认是http://localhost:8080/servlet09/cookie以及它的子路径
      • 也就是说,以后只要浏览器的请求路径是http://localhost:8080/servlet09/cookie这个路径以及其子路径,cookie都会被发送到服务器
    • 手动设置cookie的path
      • cookie.setPath("/servlet09");,表示只要是servlet09羡慕的请求路径,都会将cookie提交到服务器
    • 浏览器发送cookie给服务器,服务器中的Java程序怎么接收?
//这个方法如果没有查到数据,就会返回null,并不会返回一个长度为0的数组
Cookie[] cookies = request.getCookies();
if(cookie != null){
	//获取cookie的name
	String name = cookie.getName();
	//获取cookie的value
	String value = cookie.getValue();
}
    • 使用cookie实现十天免登录功能
      • 先实现登录功能
        • 登陆成功
          • 跳转到部门列表页面
        • 登陆失败
          • 跳转到登录失败界面
      • 修改前端页面
        • 在登陆页面给一个复选框,
        • 用户选择了复选框:表示要支持十天内免登录
        • 用户没有选择复选框:表示用户不想使用十天内免登录
      • 修改Servlet中的login方法
        • 如果用户登陆成功了,并且用户登陆时选择了十天内免登录,这个时候应该在servlet的login方法中创建cookie,用来存储用户名和密码,并且设置路径,设置有效期,将cookie响应给浏览器(浏览器将其自动保存在硬盘文件中10天)
      • 用户再次访问该网站的时候,访问这个网站的首页的时候,有两个走向:
        • 要么跳转到部门列表页面
        • 要么跳转到登陆界面
        • 以上分别有两个走向,这显然是需要编写java程序进行控制的

JSTL

1.jstl简介
  • 什么是jstl:(java server pages standard tag library),jsp标案标签库
  • 作用:和el表达式一样,都是用来简化jsp页面,尽量做到jsp页面上零java代码
2.jstl标签库
  • 核心标签库:

    • http://java.sun.com/jsp/jstl/core
    • 包含Web应用的常见工作,比如循环,表达式赋值,基本输入输出等
  • 格式化标签库:

    • http://java.sun.com/jsp/jstl/fmt
    • 用来格式化显示数据的工作,比如:对不同区域的日期格式化
  • 引入标签库:

    • <%@ taglib url="http://java.sun.com/jsp/jstl/core" prefix="c"%>
      
3.基本标签的使用
  • c:if标签的使用

    • 常用属性:
      • test:条件判断,就类似于if后面的括号中的内容,接收结果是boolean类型的值的表达式(必要属性)
      • var:限域变量名(存放在作用域中的变量名),用来接收判断结果的值(可选属性)
      • scope:限于变量名的范围:(page,request,session,application),小范围作用域可以取大范围作用域中保存的数据,反之则不然,设置var变量保存的域
  • choose,when,otherwise标签

    • 相当于switch语句

    • choose   -----switch
      when     -----case
      otherwise-----default
      
    • choose标签和otherwise标签没有属性,when标签必须有一个test属性

    • choose标签中必须包含至少一个when标签,可以没有otherwise标签

    • otherwise标签必须设置在最后一个when标签之后

    • choose标签只能设置when标签和otherwise标签

    • when标签和otherwise标签中可以嵌套其他标签

    • otherwisee标签会在所有when标签不执行时才会执行

  • foreach标签

    • //循环状态,可以通过循环状态获取到数组元素的下标,第几次循环,数组的首索引,尾索引
      
      
  • formatNumber标签

    • formatNumber用于格式化数字,货币,百分比,该标签用指定的格式或精度来格式化数字(将数值型数据转换成指定格式字符串类型)

    • 语法格式

      • 
        
    • 属性

      • value:要显示的数字(必要属性)
      • type:NUMBER,CURRENCY,或PERCENT类型(非必要属性)
      • var:存储格式化数字的变量(非必需属性)
      • scope:var属性的作用域(非必要属性)
        JavaWeb随笔_第7张图片formatDate标签
  • formatDate标签用于使用不同的方式将日期格式化(将Date类型转换成指定格式的字符串类型)

  • 语法格式:

    • 
      

JavaWeb随笔_第8张图片### 过滤器

  • 什么是过滤器:

    • 就是介于客户端和服务器之间的一个程序,每次用户请求都会先经过过滤器,然后再到服务器,每次服务器响应给客户端的数据都会先经过过滤器,然后再响应到客户端
  • 过滤器的作用:

    • 用于在servlet之外对request和response进行修改
      • 对用户的请求进行预处理,也可以对response进行后处理
  • 使用过滤器的完整流程

    • Filter对用户请求进行预处理,接着将请求交给servlet进行处理并生成响应,最后filter在对服务器响应进行后处理,在一个web应用中,可以开发编写多个filter,这些filter组合起来形成一个filter链
  • 过滤器的实现

    • 第一步:实现jarkata.servlet.Filter接口

    • 第二步:重写三个方法

      • init:初始化过滤器

      • dofilter方法:这个方法是过滤器的核心方法

        •     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
                  //处理用户请求
                  System.out.println("filter01正在处理请求.....");
                  //放行资源
                  filterChain.doFilter(request, response);
                  //这里是处理服务器的响应
                  System.out.println("filter01正在处理响应.....");
              }
          
        • 先处理用户请求,然后处理完请求之后需要放行资源,因为不放行资源的话,请求用于都不能到达服务器,放行资源:filterChain.doFilter(request,response);放行资源之后是处理服务器响应

      • destroy方法:销毁filter对象

    • 第三步:在FIlter是实现类上面加一个@WebFilter(“路径”)

    • 第四步:编写相应的servlet类接受用户请求

    • 注意事项:关于Filter链的问题,Filter处理请求的顺序是根据项目中Filter的顺序来处理请求的,然后处理响应的时候是反过来的顺序:

      在这里插入图片描述

      • 因此这里的过滤器处理请求的顺序是先执行AFilter02,然后执行Filter01,处理响应的顺序是先到达Filter01然后再经过AFilter02

JavaWeb随笔_第9张图片

监听器

  • 什么是监听器:
    • 来自于servlet规范(一组接口,8个)
    • 专门用于监听域对象的生命周期以及域对象共享数据的变化情况
    • 监听器接口实现类,只能由开发人员负责实现,tomcat不会自动实现
  • 域对象:
    • 分类:
      • ServletContext application:全局作用域对象,在tomcat运行期间,可以为工程中所有的servlet提供共享数据
      • HttpSession session:会话作用域对象,在一次会话过程中,为参与本次会话的所有servlet提供共享数据
      • HttpServletRequest request:请求作用域对象,再一次请求处理过程中,把比如请求转发,为参与本次请求的所有servlet提供共享资源
  • 监听共享数据的变化:ServletContextAttributeListener对象,是专门用于监听共享数据的变化的对象,见名知义
    • 测试全局作用的共享数据的变化
      • application.setAttribute(“key”,100) 新增共享数据
      • application.setAttribute(“key”,200) 相同的key,后一个覆盖前一个
      • application.removeAttrnite(“key”) 删除共享数据
  • 监听器应用介绍:----数据库连接池
    • jdbc操作数据库消耗时间最多的地方
      • Connection的创建
      • Connection的销毁
    • jdbc运行时提升数据库解决方案
      • jdbc运行时,既不创建Connection,也不销毁Connection
    • 数据库连接池管理方案
      • 在项目启动的时候,预先创建一定数量的Connection
      • 在用户来访的时候,将一个空闲的Coonection交给JDBC来使用
      • 在使用完毕之后,将本次使用的Connection置于空闲状态,以备下一个用户的使用
      • 在项目关闭的时候,将所有的Connection集中销毁

你可能感兴趣的:(服务器,java,网络)