我的javaweb学习笔记

假期学习笔记

day 00

localhost:127.0.0.1

java反射机制基础应用

JDBC中所有的下标从1开始

乐观锁与悲观锁

乐观锁:允许并发,不过需要一个 提前的检查。如果事务二在更新后发现需要修改的数据已经先被更改,那么就需要去事务回滚。

悲观锁:不允许并发(也称为行级锁,就是在select后面加上for update)说白了就是要排队来执行SQL语句。

day01

java的各版本对应

Java8到java13的版本号分别为1.8,1.9,1.10,10,11,12,13。

使用模板创建java模块

(1)maven-archetype-quickstart:普通的java项目

(2)maven-archetype-webapp: web项目

Maven中依赖的范围(scope):

Maven的resource文件的作用:

day02

Http请求协议包内部空间【背】

1.按照自上而下来划分,分为四个空间

2.空间划分:

请求行:{

URL属性(请求地址)

method:请求方式(POST//GET)

}

请求头:{

请求参数信息(GET)

}

空白行:{

没有任何内容,起到隔离的作用

}

请求体:{

请求参数信息(POST)

}

Http响应协议包内部空间【背】

1.按照自上而下来划分,分为四个空间

2.空间划分:

状态行:{

Http状态码

}

响应头:{

content-type:制定浏览器采用相应的编译器来对二进制内容进行编译

空白行:{

没有任何内容,起到简单的 隔离的作用

}

响应体:{

可能被访问的静态资源文件内容

可能被访问的静态资源文件命令

可能被访问的静态资源文件的运行结果

都以二进制的形式存在

}

各种概念的区别(重点理解)

1.重写与重载的区别

定义不同---重载是定义相同的方法名,参数不同;重写是子类重写父类的方法

范围不同---重载是在一个类中,重写是子类与父类之间的

多态不同---重载是编译时的多态性,重写是运行时的多态性

返回不同---重载对返回类型没有要求,而重写要求返回类型,有兼容的返回类型

参数不同---重载的参数个数、参数类型、参数顺序可以不同,而重写父子方法参数必须相同

修饰不同---重载对访问修饰没有特殊要求,重写访问修饰符的限制一定要大于被重写方法的访问修饰符

2.throws和throw的关系

throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。

throws:用于声明异常,例如,如果一个方法里面不想有任何的异常处理,则在没有任何代码进行异常处理的时候,必须对这个方法进行声明有可能产生的所有异常(其实就是,不想自己处理,那就交给别人吧,告诉别人我会出现什么异常,报自己的错,让别人处理去吧)。

throw:就是自己进行异常处理,处理的时候有两种方式,要么自己捕获异常(也就是try catch进行捕捉),要么声明抛出一个异常(就是throws 异常~~)。

注意:throw一旦进入被执行,程序立即会转入异常处理阶段,后面的语句就不再执行,而且所在的方法不再返回有意义的值!

3.抽象类与接口的区别与联系

抽象类要被子类继承,接口要被类实现。

接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。

接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

接口是设计的结果,抽象类是重构的结果。

抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。

抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。

抽象类主要用来抽象类别,接口主要用来抽象功能。

day03

TomCat的文件结构

1.bin:

开启服务器或是关闭服务器的操作就在里面;

2.conf

里面是一些服务器本身的配置文件

3.lib

其实就是一些TomCat本身用到的jar包

4.logs

里面都是些日志信息

5.temp

存放一些服务器运行时的临时文件,在服务器关闭后会自动清理

6.webapps

里面就是部署的一些网站源资源

7.work

是tomcat的工作目录,也就是tomcat把jsp转换为class文件的工作目录,这也正是为什么它叫work目录而不是cache目录的原因。

serverlet的规范

一 . serverlet规范介绍

1.serverlet规范是一种JavaEE中的一种规范。

2.作用:

(1)指定了【动态资源文件】开发步骤(在java的世界中,class文件才是真正的动态资源文件)

(2)指定Http服务器调用动态资源文件的规则

(3)指定Http服务器管理动态资源文件实例对象的规则

二 . servlet接口实现类

1.servlet接口来自于servlet规范下一个接口,这个接口存在Http服务器提供jar包

2.在TomCat服务器下lib文件有一个servlet-api.jar包存放的Servlet接口(javax.servlet.Servlet接口)

3.servlet规范中的任务,Http服务器调用的【动态资源文件】必须是一个Servelet接口实现类

例如:

class Student {
    //不是动态资源文件,TomCat无权限调用
}
class Teacher implements Servlet{
    //合法的动态资源文件,TomCat有权限调用
    Servlet obj = new Teacher();
    obj.doGet();
}

三 . servlet接口实现类的开发步骤

第一步:创建一个java类,来继承与servlet父类,使它成为一个servlet接口的实现类

第二步:重写Httpservlet父类的了两个方法。doGet()或者doPost()

第三步:将Servlet接口实现类的信息【注册】到Tomcat服务器

【网站】--->【web】--->【web-INF】--->web.xml

//将Servlet接口实现类类路径地址交给TomCat

<servlet>
    <servlet-name>self</servlet-name>//声明一个变量存储servlet接口实现类的类路径
    <servlet-class>com.huazai.TFWIL.HelloServlet</servlet-class>//接口实现类路径
</servlet>

Tomcat String self = "com.huazai.controller.OneServlet"

//同样的,因为如果按普通方法来配置的话,会因为太长而不好输入,所以需要给他来起个别名
​
<servlet-mapping>
​
    <servlet-name>self</servlet-name>
​
    <url-pattern>/one</url-pattern>
​
    //设置简短的请求别名,别名在书写的时候必须以“/”来开头
​
</servlet-mapping>

在当前配置下,如果浏览器向Tomcat索要OneServlet时,地址就为http://localhost:8080/myweb/one

抽象类的作用

降低接口实现类对接口实现过程难度,将接口中不需要使用抽象方法教给抽象类进行完成,这样接口实现类只需要对接口需要方法进行重写。

day04

关于get方式提交中文乱码问题的解决方式

关于get方式提交中文乱码问题的解决方式_追梦2013xxxx的博客-优快云博客_get请求中文乱码

day05

html中写超链接的方法

  <a href="login.html">login</a>

html中简要的写一个登录界面

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>user login page</title>
    </head>
    <body>
        <form>
            <h2>user login</h2>
            username:<input type="text" name="username"/><br>
            password:<input type="password" name="userpwd"/><br>
        </form>
    </body>
</html>
​
<br>

http500(Servlet实例化异常)

在部署工件后,访问时出现了http500,那么就可以把tomcat的版本降到9,具体原因是因为位置变化,也可以在项目中手动导入tomcat安装目录下lib中的servlet-api包。

Servlet的规范中严格的规定意义

实际上在servlet的规范中,并不仅仅只是实现了一个借口。

一个合格的webapp,应该有一个严格的文件目录结构,应该具有怎样的配置文件,这个配置文件应该放到哪里,都是提前由Servlet规范规定好的。TomCat服务器需要遵循这个Servlet规范,JavaWeb程序员也需要遵循这个规范。这样子webapp才能够解耦合。

JavaEE中各个部分的通信关系

各组别之间分别用各自的协议或是规范来连接起来。

关于JavaEE的版本

JavaEE目前最高的版本是JavaEE,JavaEE被Oracle将JavaEE规范捐赠给了Apache。Apache吧JavaEE换名了,以后不叫JavaEE了,更名为jakarta EE。JavaEE8升级过后的版本,本应为“JavaEE”,但是现在叫做,JakartaEE9。

JavaEE8的时候对应的Servlet包名是:javax.servlet.Servlet

JakartaEE9的时候Servlet包名是:Jakarta.servlet.Servlet(包名已经被更改)

也就是说TomCat10及以后不能使用javax。

day06

注解的用法和写注解的方法与注意事项

import java.lang.annotation.*;
​
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//表示我们的注解可以用在什么地方
@Retention(value = RetentionPolicy.RUNTIME)
//retention表示这个注解在什么地方可以被识别到.分别有三个级别,即source < class < runtime
@Documented
//表示我们的注解是否生成在JavaDOC当中
@Inherited
//代表子类可以继承父类的注解
public @interface MyAnnotation {
}
​
@MyAnnotation
class TestAnnotation {
    @MyAnnotation
    public void testMethod() {
​
    }
}

自定义一个较为复杂的注解

import java.lang.annotation.*;
​
@MyAnnotation02(name = "zzh",school = {"CUIT"})
public class kuangAnnotation {
    @MyAnnotation02(name = "zzh",school = {"CUIT"})
    public static void main(String[] args) {
​
    }
}
​
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation02 {
    //注解的参数 : 参数类型 + 参数名()
    String name() default "";
    int age() default 0;
    int id() default -1;
​
    String[] school();
}

反射概述及应用Java.Reflection

一个类在内存中只有一个Class对象,当一个类被加载之后,就仅仅是唯一的。

比如有如下的使用反射机制来创建对象

            Class c1 = Class.forName("com.huazai.study.User");
            System.out.println(c1.hashCode());
//通过包名来创建
            Class c2 = testUser.getClass();
            System.out.println(c2.hashCode());
//通过已有实例,使用getClass()来创建
            Class<User> c3 = User.class;
            System.out.println(c3.hashCode());
//知道类名,直接使用类名创建
            Class<Integer> type = Integer.TYPE;
            System.out.println(type.hashCode());
//内部类独有的通过TYPE来进行创建
​
//需要注意的是四个的hashcode都是相等的

大体上有上述几种方式(创建的对象都是同一个)

获取类的各种结构

try {
    A a = new A();
    Class<? extends A> c1 = a.getClass();
    //获取类名
    System.out.println(c1.getName());
    System.out.println(c1.getSimpleName());
    System.out.println("==========================================");
    //获得该类中全部的属性,getFields()只能找到public范围的属性
    Field[] fields = c1.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field);
    }
    //获得指定的类中属性
    Field declaredField = c1.getDeclaredField("m");
    System.out.println(declaredField);
    //获得本类及其父类的所有public方法
    Method[] methods = c1.getMethods();
    for (Method method : methods) {
        System.out.println(method);
    }
    //获得本类的所有方法
    System.out.println("==========================================");
    Method[] methods1 = c1.getDeclaredMethods();
    for (Method method : methods1) {
        System.out.println(method);
    }
    /**
     * 获得指定的方法,需要注意的是private权限的方法是不能被获取到的
     * 之所以需要getMethod的第二个parameterTypes参数
     *  是因为有方法的重载,所以需要参数来确定具体的某个方法
     */
    Method test2 = c1.getMethod("test2", String.class);
    System.out.println(test2);
    Method test = c1.getMethod("test",null);
    System.out.println(test);
    //获取指定的构造方法
    System.out.println("==========================================");
    Constructor<?>[] constructors = c1.getConstructors();
    for (Constructor<?> constructor : constructors) {
        System.out.println(constructor);
    }//仅获得public方法
    Constructor<?>[] constructors2 = c1.getDeclaredConstructors();
    for (Constructor<?> constructor : constructors2) {
        System.out.println(constructor);
    }//获取所有方法
    //同理,可以获得指定的构造器

} catch (Exception e) {
    e.printStackTrace();
}

通过反射来对类的各个部分进行操作

try {
    Class<?> c1 = Class.forName("com.huazai.study.User");

    //构造一个对象,本质上会调用无参构造器
    User lyt = (User) c1.getDeclaredConstructor().newInstance();
    System.out.println(lyt);

    //通过构造器创建对象
    Constructor<?> constructor = c1.getDeclaredConstructor(int.class, String.class);
    User zzh = (User) constructor.newInstance(18, "zzh");
    System.out.println(zzh);

    //通过反射来调用方法,使用invoke()来使用反射获取的方法
    //假如说有一个需求是用字符串来调用对应的方法,就可以用反射来对应方法
    User zzj = (User) c1.getDeclaredConstructor().newInstance();
    Method test2 = c1.getDeclaredMethod("test2", String.class);
    test2.invoke(zzj,"渣渣辉");

    System.out.println("========================================================");
    //通过反射来操作属性
    User user4 = (User) c1.getDeclaredConstructor().newInstance();
    Field name = c1.getDeclaredField("name");

    name.setAccessible(true);
    //不能直接操作私有属性,但是可以通过serAccessible()该方法可以让java去访问private权限的变量
    name.set(user4,"另一个zzh");
    System.out.println(user4.getName());

} catch (Exception e) {
    e.printStackTrace();
}

普通方法,反射方法(开启/关闭检测)的性能比较

public class 普通方法_反射方法的性能比较 {
    public static void main(String[] args) throws Exception {
        test01();
        test02();
        test03();
    }

    public static void test01() {
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.printf("普通方法,This program had cost %d ms",endTime - startTime);
        System.out.println();

    }
    public static void test02() throws Exception {

        Class<?> c1 = Class.forName("com.huazai.study.User");
        User user = (User) c1.getDeclaredConstructor().newInstance();
        Method getName = c1.getMethod("getName");

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long endTime = System.currentTimeMillis();

        System.out.printf("反射机制,This program had cost %d ms",endTime - startTime);
        System.out.println();
    }
    public static void test03() throws Exception {
        User preUser = new User();
        Class<? extends User> c1 = preUser.getClass();
        User user = (User) c1.getDeclaredConstructor().newInstance();
        Method getName = c1.getMethod("getName");
        getName.setAccessible(true);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long endTime = System.currentTimeMillis();

        System.out.printf("反射机制(关闭安全性检查),This program had cost %d ms",endTime - startTime);
        System.out.println();
    }

}

运行结果:

普通方法,This program had cost 4 ms 反射机制,This program had cost 1712 ms 反射机制(关闭安全性检查),This program had cost 1066 ms

反射操作注解

public class 反射操作注解 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.huazai.study.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获取注解中的value值
        tableHuazai Huazai = c1.getAnnotation(tableHuazai.class);
        String HuazaiValue = Huazai.value();
        System.out.println(HuazaiValue);

        //获得类指定的注解
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);
        fieldHuazai huazaiName = name.getAnnotation(fieldHuazai.class);
        
        System.out.println(huazaiName.columnName() + "  " +
                huazaiName.type() + "  " + huazaiName.length() );
        
    }

}

@tableHuazai("DB_Stu")
class Student {
    @fieldHuazai(columnName = "id",type = "int",length = 18)
    private int id;
    @fieldHuazai(columnName = "age",type = "int",length = 18)
    private int age;
    @fieldHuazai(columnName = "name",type = "String",length = 18)
    private String name;
    
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface tableHuazai {
    String value() default "";
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface fieldHuazai {
    String columnName() default "";
    String type() default "";
    int length() default 0;
}

泛型中的super和extends

super代表下界(基类),extends代表上界(父类)

有关于newInstance()

newInstance()方法在Java9 之后 不再推荐使用,取而代之的是class.getDeclaredConstructor.newInstance()

day07

关于JavaBean的一种约定

1、所有属性为private

2、提供默认构造方法

3、提供getter和setter

4、实现serializable接口

day08

Servlet是由谁来进行控制的?

  • Servlet对象的创建,对象上的方法的调用,以及对象最终的销毁,Javaweb程序员是无权限去干预的。

  • Servlet对象的生命周期是有Tomcat服务器(Web Server)来全权负责的。

  • Tomcat服务器通常又称为:WEB容器(即WEB Container)

同样的,我们自己new出来的Servlet对象受WEB容器的影响吗?

  • 注意我们自己的Servlet是不受控制的。

  • WEB容器创建的Servlet对象,应该会被放入HashMap中。来处理关系。

day09

ServletConfig中总共有四个方法:

  • 第一个方法:public String getInitParameter(String name);

  • 第二个方法:public Enumeration<String> getInitParmeterNames();

  • 第三个方法:public ServletContext getServleContext();

  • 第四个方法:public String getServletName();

    要注意以上四个方法,也可用使用this来进行调用(这个Servlet继承了GenericServlet)

ServletContext

  • 这个东西是什么?

    • ServletContext是接口,是Servlet规范中的一员

  • 由谁来实现?

    • ServletContext由Tomcat来实现此接口

    • 即为org.apache.catalina.core.ApplicationContextFacade implement ServletContext {}

  • ServletContext对象是谁创建的?在什么时候创建的?

    • ServletContext是在服务器启动时来创建的

    • 对于一个webapp来讲,ServletContext对象仅有一个

  • ServletContext是什么意思?

    • Context意为上下文,环境的意思。Servlet的上下文对象。

    • 其实ServletContext对象对象的就是整个web.xml文件。

  • Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。

ServletConfig和ServletContext的一些区别

  • 一个Servlet对应一个ServletConfig,一百个Servlet对象对应一百个ServletConfig对象。而对于ServletContext来讲,在同一个webapp中,它是很多个Servlet对象所共有的。

  • ServletContext是一个应用级的对象。

ServletContext的配置信息举例

<context-param>
    <param-name>pageSize</param-name>
    <param-value>100</param-value>
</context-param>
<context-param>
    <param-name>startIndex</param-name>
    <param-value>0</param-value>
</context-param>
<!--注意以上的配置信息是ServletContext的初始化参数配置信息,属于应用级配置信息。会放到所有的Servlet标签外面。使用ServletConfig来获取-->
  • 如下述代码来获取ServletContext中的信息

ServletContext application = this.getServletContext();
Enumeration<String> names = application.getInitParameterNames();
while( names.hasMoreElements() ) {
    String name = names.nextElement();
    String value = application.getInitParameter(name);
    pw.print(" 属性名 " + name);
    pw.print(" 属性值 " + value);
    pw.print("<br>");
}
  • 获取根路径(相对路径)

//获取应用的根路径(非常重要),因为java源代码中有一些地方可能会使用应用的根路径,这个方法可以动态的获取应用的根路径
//在Java源码中,不要将应用的根路径写死,因为并不知道在最终部署的时候,起一个什么样的名字。
//public String getContextPath();
ServletContext application = this.getServletContext();
Enumeration<String> names = application.getInitParameterNames();
String path = application.getContextPath();
pw.print(path);

今日学习的小插曲:startsWith()

  • 该函数是用于检测字符串是否以固定前缀开始,同样还有endsWith()

//public boolean startsWith(String prefix, int toffset);
//public boolean endsWith(String suffix) {
//        return startsWith(suffix, length() - suffix.length());
//    }
//实现方式属实牛逼啊!
String Str = new String("www.runoob.com");
System.out.print("返回值 :" );
System.out.println(Str.startsWith("www") );
System.out.print("返回值 :" );
System.out.println(Str.startsWith("runoob") );
System.out.print("返回值 :" );
System.out.println(Str.startsWith("runoob", 3) );

System.out.println("Str.endsWith(\"com\") = " + Str.endsWith("com"));

Tomcat的log日志相关

//log
//这个日志会记录到CATALINA_HOME/logs 的目录下
public void log(String message);
	application.log("你们好,我想跟lyt在一起!!!为此,我要努力");
public void log(String message, Throwable t);
    int age = 17;
    if ( age < 18) {
        application.log("对不起,未成年,请不要进来。",new RuntimeException("小屁孩,快离开!"));
    }
//日志的分类
//catalina.2022-02-12.log 服务器端的java运行程序的控制台信息。
//localhost.2022-02-12.log ServletContext对象的log方法记录的信息将存到这个文件中。
//localhost_access_log.2022-02-12.log 访问日志。

day10

有关于ServletContext的一些补充

  • Servlet还有一个名字叫做应用域(后续还会有请求域,会话域)

  • 如果说数据量较小,并且修改较少,那么就可以放入到ServletContext中去。

  • 为什么数据量要小?

    • 因为数据量较大的话,过于占用堆内存,并且这个对象的生命周期较长,服务器关闭的时候,这个对象才会被销毁。(大数据量会影响服务器的性能)。

  • 为什么这些数据很少的修改,或者说几乎不修改?

    • 因为所有用户共享的数据,如果涉及到修改操作,必然会涉及到线程安全的问题(线程并发)。所以一般ServletContext对象中的数据一般都是只读的。

  • 而对于符合上述要求的数据,将它们都放入到ServletContext当中,会大大的提升效率。因为应用域相当于一个缓存,放到缓存中的数据,下次在用的时候,不需要再从数据库中再次获取,大大的提升了执行效率。

  • 那么怎么存数据,取数据,删除数据呢?

    • //存
      public void setAttribute(String name, Object value);
      //map.put(k,v);
      //取
      public Object getAttribute(String name);
      //map.get(k);
      //删除
      public void removeAttribute(String name);
      //map.remove(k);

day11

什么是协议 ?

  • 协议实质上是某些人,或者某些组织提前指定好的一套规范,大家都按照这个规范来,就可以做到沟通无障碍。

  • 协议就是一套规范,就是一台标准,有其他人或其他组织来负责制定的。

HTTP协议 ?!

  • HTTP协议:是W3C制定的一种超文本传输协议。

  • W3C:

    • 万维网联盟组织

    • 负责制定标准:HTTP HTML4.0 HTML5 XML DOM标准等规范都是万维网所制定的。

    • 万维网之父:蒂姆·伯纳斯·李

  • 什么是超文本?

    • 超文本就是不是普通文本,比如流媒体:声音,视频,图片等。

    • HTTP协议支持:不但可以传输普通字符串,同样支持流媒体信息。

  • 这种协议游走在B和S之间。这样子B和S才能够解耦合。

  • 那么,什么是解耦合呢?

    • B不依赖于S。

    • S也不依赖于B。

  • HTTP协议的具体响应报(response)

    • HTTP/1.1 200  //请求头
      Content-Type: text/html;charset=UTF-8  //请求体
      Content-Length: 1117
      Date: Tue, 15 Feb 2022 15:09:07 GMT
      Keep-Alive: timeout=20
      Connection: keep-alive
      								//空白行
      <html>    						 //响应体
      <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
          <title>用户登录</title>
      </head>
      <body>
      </body>
      </html>
    • 状态行

      • 三部分组成

        • 第一部分:协议版本号(HTTP/1.1)

        • 第二部分:状态码

          • 200 表示访问成功

          • 404 表示访问的资源不存在,通常要么是路径写错了,要么是路径写错了。要么就是对应的资源并没有启动。总之404错误是前端的错误。

          • 405 表示前端发送的请求方式与后端处理的方式不一致。

          • 500 表示服务器端的程序出现了异常,一般认为是服务器端的错误导致的。

          • 以4开始的,一般是浏览器端的错误导致的。

          • 以5开始的,一般是服务器端的错误导致的。

        • 第三部分:状态的描述信息。

          • ok表示成功。

          • not found表示资源找不到。

      • 请求行

        • 也是三部分组成

          • 请求方式(7种)

            • get,post,delete,put,head,options,trace

          • URI

            • 什么是URI?统一资源标识符。代表网络中某个资源的名字,但是通过URI是无法定位的。

            • 什么是URL?统一资源定位符。代表网络中某个资源的名字,但是通过URL是可以定位到的。

            • URl和URI是什么关系?

          • 第三部分:HTTP协议版本号

GET请求和POST请求有什么区别?

  • get请求发送请求的时候,数据会挂在URL的后面,然后跟一个?,然后在跟数据。这样子会导致数据会显示在地址栏里面。会泄露数据。

  • post会在请求体中装填数据。所以看不到。

  • 发送的请求数据格式一律是:name=value&name=value&name=value......

    • <input type="text" name="userid" id="userid" value=""/>
    • name是什么?

      • 以form表单为例:form表单中input标签的name

    • value是什么?

      • 以form表单为例:form表单中input标签的value

GET和POST该怎么来选择?

  • get请求只能发送普通的字符串。并且发送的字符串长度有限制,不同的浏览器限制不同。这个没有明确的规定。所以说get无法发送大数据量。

  • post请求可以发送大数据,流媒体。理论上没有长度限制。

  • W3C中是这样说的:get比较适合从服务器来获取数据,post比较适合向服务器发送数据。正好印证了get与post的单词之意。

day12

续上文,GET和POST该怎么来选择?

  • get请求是安全的,因为是从服务器上获取数据。post请求是危险的,因为是往服务器上发送请求。一般情况下拦截请求的时候,大部分会拦截(监听)post的请求。

  • get请求支持缓存,post请求不支持。

    • 任何一个get请求对应的响应结果都会被缓存下来。

    • 实际上,只要发送get请求,浏览器做得第一件事就是先去本地找缓存,找不到的时候才回去服务器上获取。这种缓存的机制是为了提高用户的体验。

    • 或许会有这样的一种请求:我们并不希望get请求走缓存,怎么办?怎么避免走缓存?希望每一次的资源都是在服务器上新获取的。

      • 只要每一次的路径不一样就好了,可以在请求路径后面加入时间戳。

  • 大部分的form表单提交,都是post方式来提交的。因为post表单中要填写大量的数据,这些数据是收集用户的信息。

  • 如果信息中包含了敏感信息,还是建议用post来进行发送。因为get会回显到地址栏上面。(如密码信息等)

  • 大文件的上传,一定是post上传,要传的数据不是普通的文本。

  • 其他的要求可以使用get请求。

模板方法设计模式

  • 什么是设计模式?

    • 解决某个问题的固定的解决方案。(即可以被重复利用)

  • 你知道哪些设计模式?

    • GoF设计模式:

      • 通常我们所说的23种设计模式。(Gang of Four四人组设计模式)

    • JavaEE设计模式:

      • ......

day13

一个webapp如何设置欢迎页(默认是为index命名的文件)

  •     <welcome-file-list>
            <welcome-file>/login.jsp</welcome-file>
            <welcome-file>/test/test.html</welcome-file>
        </welcome-file-list>

    经过测试,此处加不加“/”都是可以的。同时还需要注意一点,文件的路径是从webapp为根路径开始向下找的。

    同样的,欢迎页的设置是有优先级的。如上所示,如果第一个找不到的话,就再去找侠一个文件地址。

  • 一共有两个地方可以配置:

    • 一个是在webapp内置的web.xml文件当中。(这个地方配置就属于是局部配置)

    • 一个是在CATALINA_HOME/conf/web.xml文件中进行配置。(在这个地方就属于是全局配置)

    • 注意原则:局部优先原则。(就近原则)

    • 以下就是CATALINA_HOME/conf/web.xml中的全局配置。(index!!!)

    • <welcome-file-list>
          <welcome-file>index.html</welcome-file>
          <welcome-file>index.htm</welcome-file>
          <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
  • 欢迎页可以是一个Servlet吗?答案是肯定的。

day14

HttpServletRequest接口详解

  • HttpServletRequest是一个接口,全限定名称:jakarta.servlet.http.HttpServletRequest

  • HttpServletRequest接口是Servlet规范中的一员。

  • HttpServletRequest接口的父接口:ServletRequest

    • public interface HttpServletRequest extends ServletRequest {}
  • HttpServletRequest接口的实现类谁写的? HttpServletRequest对象是谁给创建的?

    • 通过测试:org.apache.catalina.connector.RequestFacade 实现了 HttpServletRequest接口

      • public class RequestFacade implements HttpServletRequest {}
    • 测试结果说明:Tomcat服务器(WEB服务器、WEB容器)实现了HttpServletRequest接口,还是说明了Tomcat服务器实现了Servlet规范。而对于我们javaweb程序员来说,实际上不需要关心这个,我们只需要面向接口编程即可。我们关心的是HttpServletRequest接口中有哪些方法,这些方法可以完成什么功能!!!!

  • HttpServletRequest对象中都有什么信息?都包装了什么信息?

    • HttpServletRequest对象是Tomcat服务器负责创建的。这个对象中封装了什么信息?封装了HTTP的请求协议。

    • 实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP的请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServletRequest对象当中,传给了我们javaweb程序员。

    • javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。

  • request和response对象的生命周期?

    • request对象和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。

    • 一次请求对应一个request。

    • 两次请求则对应两个request。

    • .....

  • HttpServletRequest接口中有哪些常用的方法?

    • 怎么获取前端浏览器用户提交的数据?

      • Map<String,String[]> getParameterMap() 这个是获取Map
        Enumeration<String> getParameterNames() 这个是获取Map集合中所有的key
        String[] getParameterValues(String name) 根据key获取Map集合的value
        String getParameter(String name)  获取value这个一维数组当中的第一个元素。这个方法最常用。
        // 以上的4个方法,和获取用户提交的数据有关系。
      • 思考:如果是你,前端的form表单提交了数据之后,你准备怎么存储这些数据,你准备采用什么样的数据结构去存储这些数据呢?

        • 前端提交的数据格式:username=abc&userpwd=111&aihao=s&aihao=d&aihao=tt

        • 我会采用Map集合来存储:

          • Map<String,String>
                key存储String
                value存储String
                这种想法对吗?不对。
                如果采用以上的数据结构存储会发现key重复的时候value覆盖。
                key         value
                ---------------------
                username    abc
                userpwd     111
                aihao       s
                aihao       d
                aihao       tt
                这样是不行的,因为map的key不能重复。
            Map<String, String[]>
                key存储String
                value存储String[]
                key				value
                -------------------------------
                username		{"abc"}
                userpwd			{"111"}
                aihao			{"s","d","tt"}
        • 注意:前端表单提交数据的时候,假设提交了120这样的“数字”,其实是以字符串"120"的方式提交的,所以服务器端获取到的一定是一个字符串的"120",而不是一个数字。(前端永远提交的是字符串,后端获取的也永远是字符串。)

    • 手工开发一个webapp。测试HttpServletRequest接口中的相关方法。

      • 先测试了4个常用的方法,获取请求参数的四个方法。

        • 	Map<String,String[]> parameterMap = request.getParameterMap();
          	Enumeration<String> names = request.getParameterNames();
          	String[] values = request.getParameterValues("name");
          	String value = request.getParameter("name");

      • request对象实际上又称为“请求域”对象。

        • 应用域对象是什么?

          • ServletContext (Servlet上下文对象。)

          • 什么情况下会考虑向ServletContext这个应用域当中绑定数据呢?

            • 第一:所有用户共享的数据。

            • 第二:这个共享的数据量很小。

            • 第三:这个共享的数据很少的修改操作。

            • 在以上三个条件都满足的情况下,使用这个应用域对象,可以大大提高我们程序执行效率。

            • 实际上向应用域当中绑定数据,就相当于把数据放到了缓存(Cache)当中,然后用户访问的时候直接从缓存中取,减少IO的操作,大大提升系统的性能,所以缓存技术是提高系统性能的重要手段。

          • 你见过哪些缓存技术呢?

            • 字符串常量池

            • 整数型常量池 [-128~127],但凡是在这个范围当中的Integer对象不再创建新对象,直接从这个整数型常量池中获取。大大提升系统性能。

            • 数据库连接池(提前创建好N个连接对象,将连接对象放到集合当中,使用连接对象的时候,直接从缓存中拿。省去了连接对象的创建过程。效率提升。)

            • 线程池(Tomcat服务器就是支持多线程的。所谓的线程池就是提前先创建好N个线程对象,将线程对象存储到集合中,然后用户请求过来之后,直接从线程池中获取线程对象,直接拿来用。提升系统性能)

            • 后期你还会学习更多的缓存技术,例如:redis、mongoDB.....

          • ServletContext当中有三个操作域的方法:

            • void setAttribute(String name, Object obj); // 向域当中绑定数据。
              Object getAttribute(String name); // 从域当中根据name获取数据。
              void removeAttribute(String name); // 将域当中绑定的数据移除
              
              // 以上的操作类似于Map集合的操作。
              Map<String, Object> map;
              map.put("name", obj); // 向map集合中放key和value
              Object obj = map.get("name"); // 通过map集合的key获取value
              map.remove("name"); // 通过Map集合的key删除key和value这个键值对。
        • “请求域”对象

          • “请求域”对象要比“应用域”对象范围小很多。生命周期短很多。请求域只在一次请求内有效。

          • 一个请求对象request对应一个请求域对象。一次请求结束之后,这个请求域就销毁了。

          • 请求域对象也有这三个方法:

            • void setAttribute(String name, Object obj); // 向域当中绑定数据。
              Object getAttribute(String name); // 从域当中根据name获取数据。
              void removeAttribute(String name); // 将域当中绑定的数据移除
          • 请求域和应用域的选用原则?

            • 尽量使用小的域对象,因为小的域对象占用的资源较少。

关于Servlet中的不同Servlet的转发问题。

request.getRequestDispacther("/应填写的路径名").forword(request.response);
//例如:request.getRequestDispacther("/register").forword(request.response);
//即是跳转致注册界面
  • 需要注意的一点是:转发的资源就必须是一个Servlet吗?

    • 不一定是,只要是在Tomcat服务器中的一个合法的资源即可。例如html。

    • 注意,转发的时候的路径名必须以“/”来开始。(不需要加上项目名)

关于resquest对象中两个非常容易混淆的方法:

String username = request.getParameter("username");

//之前一定是执行过request.setAttribute("name",new Object());
Object obj = request.getAttribute("name");
//第一个方法:获取的是前端提交的数据。
//第二个方法:获取的是请求域中绑定的数据。

request中其他一些较为常用的方法

public String request.getRemoteAddr();//获取客户端的IP地址。
public void setCharacterEncoding();//设置post请求的编码字符集。(如果一次修改不成功,那就重启一下服务器。)
//切记,get请求在请求头上传数据,post在请求体重传数据。
//但是,在Tomcat10之后,默认请求的字符编码集就已经是UTF-8了。
public String request.getContextPath();//获取应用的根路径
public String request.getRequestURI();//获取请求的URI
public String request.getServletPath();//获取Servlet的Path

day15

关于前端页面的一些写法

<input type="button" value="后退" οnclick="window.history,back()"/>//后退按钮
//οnclick="window.confirm()"是验证方法(确定,取消)

ResourceBundle相关

    private static ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
    private static final String URL = bundle.getString("url");
    private static final String user = bundle.getString("user");
    private static final String password = bundle.getString("password");
    private static final String driver = bundle.getString("driver");
//配置文件绑定式的jdbc写法。可以有利于后期的更改。
//注意要将.properties文件放到MAVEN创建的resources目录下。(resources与java目录,webapp目录同级)

有关于出校管理系统项目开发时所遇上的问题。

  • <td><label for='sdf'>预出校时间:</label></td>
    <td><input type='datetime-local' name='sdf' id='sdf' /></td>
  • for绑定的input的id!

day16

有关于重定向和转发的联系与区别

  • 转发是服务器内部的一次转发,在浏览器端的请求栏地址上是没有变化的。

  • 重定向是会直接给浏览器发送一次全新的请求。以此来跳转到新的页面。具体代码如下所示;

  • response.sendRedirect("/School/login");
    //注意:路径需要加上一个项目名。为什么?
    //浏览器发送请求,请求路径上是需要加上项目名的。
    //以上的代码会直接发送一次全新的请求。
    //也可以写为相对路径,比如"Demo01"
  • 那么,转发和重定向应该怎么来选择呢?

    • 在一个Servlet当中如果想向另外一个页面跳转,并且想要将request中的attribute数据传递下去,那么就使用转发。

    • 剩下的所有情况均使用重定向。(重定向使用较多)

  • 但是要注意的一点是:转发会存在着浏览器的刷新问题。所以如无上述要求,那就使用重定向来做事。

day17

有关于@WebServlet注解在开发时的使用

  • name:指定的是Servlet的name属性,等同于xml文件中的<servlet-name>

  • values:此属性等价于urlPatterns属性。两个属性不能同时使用。

  • urlPatterns:指定一组的URL匹配模式。等价于<url-pattern>的标签。

  • loadOnStartup:指定Servlet的顺序,等价于<load-on-startup>标签。

  • 注意:当注解的属性名是value的时候,那么连属性名都是可以干掉不写的。比如@WebServlet("welcome")。

MANEN仓库的官网地址

JSP相关

  • JSP实际上就是一个Servlet,index.jsp访问的时候,会自动生成index_jsp.java,然后自动编译生成index_jsp.class的文件。

  • index_jsp继承了HttpJspBase,而HttpJspBase继承的是HttpServlet.所以index_jsp实际上就是一个Servlet。

  • 所以说,同样的,它和Servlet的生命周期是相同的。没有任何的区别。

  • 并且jsp和Servlet一样,都是单例的。(假单例)

  • 所以说JSP是什么?

    • jsp是java程序。(jsp本质上还是一个Servlet)。

    • jsp是:JavaServer Pages的缩写。

    • jsp是一套规范。所有的web容器/web服务器都要遵循这套规范的。都是按照这套规范来对 .jsp 翻译为 .java。

    • 所以说,每一个web容器都会内置一个jsp的翻译引擎。

  • 如果说jsp出现了错误,那么最应该去对应的 .java 文件中去寻找错误。

  • jsp的基础语法

    • jsp的page指令。(使用UTF-8的编码方式来进行编码,避免乱码。)

      • <%@page contentType="text/html;charset=UTF-8"%>
  • 怎么在jsp中写java程序?

    • <% java程序 %>在这个标签里面写的java代码,被翻译到jsp的servlet的内部。在这个符号里面写java代码的时候,要记住自己再方法体当中写代码。所以说public,private之类访问权限不能写,static静态代码块。以及方法的内部不能再写方法。

    • jsp的专业注释方法<%----%>(注意这么写的注释,其中的的东西是不会被翻译到jspServlet当中的。)

    • 注意不要jsp的程序内写HTML的注释方法,(即<!---->)这么写的注释仍然会被翻译到jsp的Servlet的 .java程序当中。

    • <%! Service外的代码 %>这个语法很少使用。为什么呢?

      • 因为写在外面的静态变量或者是实例变量,因为这个jspServlet是单例的,肯定就会引发线程安全的问题,到时候可能又会为了安全而去使用锁,从而影响服务器的性能。

    • <%=%>这个写法在jsp当中会被翻译成什么呢?

      • 比如<%= 1000 + 4200 %>会被翻译为out.print(1000 + 4200);

      • 位置在哪里呢?还是在我们的老地方:Service方法当中。

      • 那么,在什么时候来使用呢?在需要动态的内容展示的时候,如果只是“Hello world”的话,那么直接写到jsp中就可以了。

  • JSP的九大内置对象

    • javax.servlet.jsp.PageContext pageContext;

    • javax.servlet.http.HttpSession session;

    • javax.servlet.ServletConfig config;

    • javax.servlet.jsp.JspWriter out;

    • java.lang.Object page;

    • javax.servlet.http.HttpServletRequest request;

    • javax.servlet.http.HttpServletResponse reponse;

    • 还有一个Exception(异常处理,需要开启才能看得到);

  • JspWriter与PrinterWriter的关系:

    • 都是继承自java.io.Writer类.

    • JspWriter可以在JSP页面中直接用out对象输出.可以用pageContext.getOut();得到JspWriter对象.PrintWrietr在JSP页面中必须用response.getWriter();方法得到其对象.二者作用域不同.

    • 在JSP页面中同时调用两种方法向页面输出数据时,PrintWriter中的数据会输出在JspWriter前面.

day18

既然说jsp的本质是一个Servlet,那么jsp和Servlet到底有神马区别呢?

  • 职责不同

    • Servlet的职责是什么?

      • 收集数据。(业务逻辑的处理,连接数据库等操作)

    • jsp的职责是什么?

      • 做数据的展示。

开始将出校管理系统由一个纯Servlet改造为一个Servlet+jsp的项目。

  • 已经完成了。

day19

cookie相关:

  • 关于cookie的有效时间:

    • cookie.setMaxAge(60 * 60);设置cookie在一个小时后失效。

    • 没有设置有效时间:默认保存在浏览器的运行内存当中,浏览器关闭则cookie一起消失。

    • 只要设置coolie的时间 > 0,则这个cookie一定会存储到硬盘文件当中。

    • 那么,如果设置有效时间为0呢?

      • coolie被删除,同名cookie被删除。

    • 设置cookie的时间 = 0呢?

      • cookie被删除,同名的cookie也会被删除。

    • 设置时间为负数呢?

      • 保存在运行内存中,和不设置一模一样。

  • 关于cookie的path,cookie关联的路径是:

    • 生成cookie 的父路径,以及父路径的所有以下子路径。

    • 手动来设置cookie的path

      • cookie.setPath("/Manager"); 表示只要是这个Manager项目的请求路径,都会提交这个cookie给服务器。

  • 浏览器发送cookie,服务器中的java怎样子接收?

    • Cookie[] cookies = request.getCookies();
      if (cookies != null) {
          for (Cookie cookie : cookies) {
              String name = cookie.getName();
              System.out.println(name);
          }
      }
      //这个cookie的数组长度一定大于零的,如果里面没有数据的话,则一定会返回null。

使用cookie来是实现一个十天免登录的功能:

  • 修改前端页面

  • 在登录的时候添加cookie

  • 修改登录时的Servlet

day20

EL表达式的使用

  • EL表达式默认从小的范围取数据。pageContext < request < seesion < applicatoin

EL表达式中的隐含对象

  • pageContext

  • param

  • paramValues

  • initParam

  • 其他

  • <%=request.getParameter("username")%>
        ==
    ${param.username}

关于EL表达式中的运算符

  • 在EL表达式里面的+只会被作为算数运算符。如果是“123”则会调用Integer.parseInt()。

  • empty则是与java中的empty()函数用法一致。

maven中来引入JSTL

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-impl</artifactId>
            <version>1.2.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-spec</artifactId>
            <version>1.2.5</version>
        </dependency>

关于JSTL使用的一些小问题

  • <%--<%@taglib prefix="c" uri="http://java.sun.com/jstl/core" %>--%>
    //不可用的,会出现forEach页面空白
    <%--<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>--%>
    //可用的,forEach正常使用
  • 然后是在forEach中给序号

    • <c:forEach items="${requestScope.MessageList}" var="message" varStatus="Counter">
          <td align="center">${Counter.count}</td>
    • 其中,Counter.count是从一开始。

    • Counter.index是从零开始。

day21

关于EL表达式在<base>标签中的使用

  • <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}"/>

day22

有关于Filter的使用

  • 关于Filter的配置路径:

    • /a.do, /b.do, /dept/save.这些配置方法都是精确匹配。

    • /*匹配所有的路径。

    • *.do后缀匹配。不要以/开始。

    • /dept/*前缀匹配。

  • 使用@WebFilter来进行注解式开发的话,相同注解的执行顺序是什么样的呢?

    • 执行顺序遵从类名的字典顺序。

  • Filter的生命周期

    • 和Servlet生命周期一致性。

    • 会在服务器启动就开始实例化,而Servelt不会。

  • Filter这里有一个责任链设计模式。

    • 开闭原则:对扩展开放,对修改关闭。

    • 责任链设计模式最大的核心思想,是可以在程序运行的时候动态的来进行调换。所以在Filter中.xml文件的写法反而要比注解的方式要好。

day23

之前一直在想的一个关于前端代码为什么会没有的原因:

  • 因为在MessageList取不到数据的时候,返回值并不是null,而是一个空的括号"[]"!!!

  • 所以在jstl的if标签里面判断的时候这样写即可

  • <c:if test="${requestScope.MessageList == '[]'}">
    	<%--你的业务代码--%>
    </c:if>

day24

Listener监听器

  • 什么是监听器?

    • 监听器是Servlet规范中的一员,就像Filter一样。Filter也是Servlet中的一员。

    • 在Servlet中,所有的监听器借口都是以"Listener"来结尾的。

  • 监听器有什么用?

    • 监听器实际上是Servlet规范里面给我们JavaWeb程序员留下的特殊时机。

    • 特殊的时机如果想执行这段代码,则需要使用到相应的监听器。

  • Servlet规范中给我们留下了那些监听器呢?

    • jakarta.servlet包如下:

      • ServletContextListener

      • ServletContextAttributeListener

      • ServletRequestListener

      • ServletRequestAttributeListener

    • jakarta.servlet.http包如下:

      • HttpSessionListener

      • HttpSessionAttributeListener

      • HttpSessionBindingListener

      • HttpSessionIdListener

        • sessionid改变的时候,就会调用里面的唯一一个方法。

      • HttpSessionActivationListener

        • 在session钝化和活化的时候就会被调用。

  • 接下来来讲讲怎么使用HttpSessionBindingListener

    • 这是一个比较特殊的监听器,并不是一个web的监听器,而是基于Session的监听器。本质上可以用来监听一个java类。当session域中把这个类绑定或者解绑时,就会触发监听事件。

  • 思考一个业务场景

    • 编写一个功能,记录当前网站在线(已经登录)的人的人数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值