假期学习笔记
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是什么关系?
-
URL包括URI。
-
URI:/School/login
-
-
-
第三部分: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仓库的官网地址
-
repository来跟我念:瑞帕斯托瑞
-
[rɪˈpɒzətri]
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域中把这个类绑定或者解绑时,就会触发监听事件。
-
-
思考一个业务场景
-
编写一个功能,记录当前网站在线(已经登录)的人的人数。
-