JavaWeb知识总结
HTML是什么:
Hyper Text Marker Language
超文本标记语言
超文本:超级文本 例如流媒体、声音、图片等
标签:这种语言有大量的标签组成
任何一个标签都有开始标签和结束标签
开始标签:<标签>
结束标签:</标签> 结束标签有一个斜杠
HTML运行在浏览器上
HTML的拓展名为 .html或者 .htm
有前端和后台组成的系统架构叫做:B/S结构系统
B :Browser(浏览器)
S:Server (服务器)
<p> </p>段落标签,可以用来给文字分段
<h1> </h1>可以用来设置字体的大小(这个最大)
<h2></h2>
<h3></h3>
<h4></h4>
<h5></h5>
<h6></h6>(这个最小)
<br>换行,放在需要换行的后面是独目标签
<hr>横线 是独目标签
<hr color=”red”>划出一条红色的横线
<pre></pre> 保留格式,在源码上是什么样的,网页上就是什么样的
<b> </b>粗体字
<i> </i>斜体字
<ins>插入字</ins> 插入字
<del>删除字<del>删除字
10<sup>2</sup> 10的平方
M<sub>2</sub> m2 二在m的右下角
<font color=”red” size=”12”>文字</font> 字体标签
B/S架构的原理(初略):
第一步:用户在浏览器地址栏输出url
第二步:回车(这一步相当于浏览器向服务器发送一个请求)
请求:request
Browser🡪Server
第三步:服务器会给浏览器一个响应,最总会将一段html代码发送给服务器
浏览器对html代码进行执行,展示其结果
相应:response
Server🡪Browser
目前有两种方式让浏览器向服务器发送请求:
第一种:通过手动在浏览器的地址栏输入URL,回车
第二种方式:通过点击网页中的超链接
以上两种方式实质上没有任何区别,但第二种会更简单
CSS是html的化妆品,CSS是建立在html之上的,html是主体,CSS起修饰
Html怎样嵌入CSS样式:
第一种方式:内联定义
第二种方式:定义内部样式块对象
第三种方式:链入外部样式表文件(是最常用的方式)
JavaScript:简称JS
Javascript是一种脚本语言
java是一种非脚本语言,属于编译型语言
脚本语言的特点是 目标程序都是以普通文本的形式保存的(可以用记事本直接打开)浏览器打开就直接执行了
JavaScript是运行在浏览器中,Java是运行在JVM虚拟机中的,两者之间没有任何关系
JavaScript也是一门编程语言,作用于html文件中的节点,存在变量等
JavaScript分为三块:
ECMAScript、DOM(document Object Model 操作网页中的节点)、BOM(Browser Object model 操作浏览器本身)
Javascript是一种事件驱动型编程语言,通常在每个事件发生之后去执行某段代码 例如鼠标单击事件click,鼠标经过事件 mouseover等,在Java Script中,每一个事件都具有对应的事件句柄,例如:click的事件句柄是onclick mouseover的事件句柄是onmouseover
所有的事件句柄都是以标签的属性形式进行存在的,例如input button就有一个onclick属性,当用户单击以下按钮对象的时候,此时按钮上发生了鼠标单击事件,那么注册在onclick中的JS代码就会被浏览器调用执行
事件发生三要素:
- 事件源
- 事件
- 事件监听器 (在浏览器中)
BoM:Browser Object Model(浏览器对象模型),通过BOM的对象和方法,可以对浏览器窗口进行操作,例如:关闭浏览器、前进、后退、修改地址栏地址等,这些都属于BOM,BOM的顶级内置对象是window
DOM:Document Object Model(文档对象模型),通过DOM的对象和方法,可以对网页中的元素进行增删改,让网页产生动态效果,DOM的顶级内置对象是document对象
Jsp:
什么是jsp,它的作用是什么?
Jsp全称叫做java service pages ,java服务器的页面,jsp页面的主要作用是替代Servlet程序回传html页面的数据(代码)
Jsp页面和html页面一样,都需要将jsp文件放到web目录下,访问也和html一样
在webapp下有一个a.html和b.jsp文件
访问html文件: http://ip:port/工程路径/a.html
访问jsp文件:http://ip:port/工程路径/b.jsp
Jsp页面的本质;
jsp页面其实是一个Servlet程序
这是一个jsp被翻译成java程序的地址:
C:\Users\小鲨鱼\AppData\Local\JetBrains\IntelliJIdea2021.3\tomcat\181a779e-c5ea-4ce2-ae6e-8216580f2f49\work\Catalina\localhost\jspTest\org\apache\jsp
当第一次访问jsp文件的时候,tomcat服务器会先把jsp文件解析成一个java源文件,并且将其进行编译生成class字节码文件,查看这个java源文件,发现他继承了HttpServlet类,
Jsp的page属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Language属性:表示jsp文件翻译后是什么语言文件,暂时只支持java
ContenType属性:就相当于Servlet程序中的response.setContentType()这个方法,表示jsp的返回类型
PageEncoding属性:表示当前jsp页面本身的字符集
Import属性:用于导入包和类
===================以下两个属性是给out输出流进行使用的===============
第一个是:autoFlush属性:设置out输出缓冲区满了之后是否自动刷新,默认是true
第二个是:buffer属性:设置out缓冲区的大小,默认是8kb
ErrorPage属性: 设置当jsp运行时出错自动跳转到错误页面的路径
IsErrorPage属性:设置出当前jsp页面是否是错误页面信息,默认是false,如果是true,可以获取到异常信息。
Session属性:设置当前jsp是否能够创建HttpSession对象。默认是true
Extends属性:设置jsp文件翻译成java类之后,默认继承谁。
Jsp中的常用脚本:
第一种:
声明脚本:(不太常使用)
格式:<%! 这里放的是java语言 %>
申明脚本中可以放什么类容:
第一种:可以在jsp对应的类中添加属性
第二种:可以在jsp对应的类中添加方法
第三种:可以在jsp对应的类中添加静态代码块
第四种:可以在jsp对应的类中添加内部类
第二种:
表达式脚本:(常用)
格式:<%= 表达式 %>
表达式脚本的作用是在jsp页面上显示输出数据
表达式脚本的特点:
第一:所有的表达式脚本都会被翻译到_jspService方法中
第二:表达式脚本都会被翻译成out.print(表达式)输出到页面上
第三:由于表达式脚本翻译的内容都在_jspService方法中,所以,_jspService方法中的所有对象都可以直接使用
第四:表达式脚本中的语句不能以分号结尾
第三种:
代码脚本:
格式:<% java语句 %>
代码脚本的作用是可以在jsp页面中编写我们自己需要的功能(java语句,不是方法)
代码脚本的特点:
1、代码脚本翻译之后都是在_jspService这个方法中的
- 代码脚本由于翻译到_jspService方法中,所以我们可以使用在_jspService方法中的对象
- 我们可以有多个代码脚本块组合完成一个java语句(可以进行拼接)
- 代码脚本可以和表达式脚本一起使用,在jsp页面上输出数据
Jsp中的三种注释:
第一种:html注释
<!--这是一个html注释--> 被翻译到java文件中是以out.print(<!--这是一个html注释-->)的形式存在的
第二种:java注释
//单行注释 /*多行注释*/ 被翻译到java文件中的时候会将注释一并翻译进去,也就是在java文件中,还是以//单行注释 /*多行注释*/的形式存在。
第三种:jsp注释:
<%--这时jsp注释--%> 他可以注释掉jsp中的所有东西,jsp文件中正真的注释,在翻译后的java文件中不会存在注释掉的信息
Jsp中的九大内置对象:
什么是内置对象:内置对象是指Tomcat翻译jsp页面的时候,内部提供的对象叫做内置对象。
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
JspWriter out = null;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
第一个是:request 请求对象
第二个是:response 响应对象
第三个是:pageContext jsp上下文对象
第四个是:sesssion 会话对象
第五个是:application SerlvetContext对象
第六个是:config ServletConfig对象
第七个是:out 输出流对象
第八个是:page 指向当前页面的对象
第九个是:exception 这个需要在page配置中将isErrorpage属性为true的时候才出现的对象
Jsp中的四个域对象:
- request (HttpServletRequest类) 作用范围:一次请求内有效
- Session (HttpSession类) 作用范围:一次会话内有效(打开浏览器访问服务器,直到关闭浏览器这就是一个会话)(浏览器关闭后失效)
- Application (ServletContext类) 作用范围:整个web工程内都有效,只要服务器没有停止,就一直存在数据可以访问(服务器关闭后失效)
- PageContext (PageContext类) 作用范围:当前的jsp页面内有效
域对象是可以像map集合一样进行存取数据的对象,四个域对象的功能相同,但是他们的作用范围不相同。
虽然这四个域对象的功能都是一样的,那我们在使用的时候应该如何选择?
原则:从小到大的原则
先使用pageContext ==> requset ==>session ==>application
为什么要这样选择呢?
因为数据都是需要内存空间的,范围较小的域对象在出域之后就可以将存入的数据进行删除,释放资源,减轻服务器的压力。
Jsp中的out和response.getWriter输出的区别:
Response中表示响应,常用于设置返回给客户端的内容(输出)
Out也是给用户输出使用的
Out输出流和response输出流都有一个对应的缓冲区,一个叫做out缓冲区,另一个叫做response缓冲区,再将对应的输出流的东西加载(使用write()方法)到缓冲区之后,out缓冲区会执行out.flush()操作,会将out缓冲区中的数据加载到response缓冲区的末尾,最后,response缓冲区会执行flush()操作,将response缓冲区中的数据进行写到客户端。
因为jsp文件在被翻译成java源文件后,都是使用的out进行输出的,因此,建议都使用out进行输出,避免打乱输出的顺序。
Out.write()方法只能输出字符串类型(如果输出的内容是int类型,输出结果会将int类型转化为ASCLL中对应的char)
Out.print()方法可以输出任意类型(因为底层将传入的参数转化成了字符串类型,再将字符串类型的参数通过调用write()方法进行输出)
在jsp文件中可以统一通过out.print()方法进行输出。
Jsp中常用的标签
- jsp静态包含
实例:
<%@include file="/include/footInfo.jsp"%>
格式:
通过<%@ include file=”需要的jsp路径 ”%>
静态包含的好处是只需要将include file中的文件中的代码进行修改,就能将使用了所有这个页面的内容进行修改(只需要改动一个地方就行了)。
静态包含的特点:
- 静态包含不会被翻译到jsp页面中
- 静态包含其实是把被包含的jsp页面的代码拷贝到包含的位置进行执行和输出
- 不会讲包含的jsp文件进行翻译
- 动态包含
动态包含可以实现和静态包含相同的效果
动态包含的格式:
<jsp:include page="footInfo.jsp"></jsp:include>
<jsp:include page=”jsp文件的路径”></jsp:include>
使用动态包含在jsp文件进行翻译之后会被翻译成以下内容:
并且将被包含的jsp文件也进行翻译
JspRuntimeLibrary.include(request, response, "footInfo.jsp", out, false);
如何理解动态包含的底层逻辑:(这里通过main.jsp和foot.jsp进行分析)
首先,先将main中的需要输出的数据写入到out缓冲区中,然后通过JspRuntimLibrary.include(requset,response,”footInfo”,out,false)这段代码将main程序中的request对象response对象out对象都传入了footInfo程序中,也就是说,在传入这些对象之后,footInfo程序中的request、response、out对象和main中的是同一个对象,并且out缓冲区也是同一个,接着footInfo程序会将自己需要进行输出的内容写入out缓冲区中,最后通过out.flush()方法将out缓冲区中的所有内容进行写入response缓冲区中,将其写入客户端。
动态包含的特点:
- 会将被包含的jsp文件进行翻译成class文件
- 使用动态包含,底层会调用以下代码进行调用jsp页面并执行:
JspRuntimeLibrary.include(request, response, "footInfo.jsp", out, false);
- 被包含的文件的request、response、out、out缓冲区等对象和执行JspRuntimLibrary.include(requset,response,”footInfo”,out,false)这段代码的jsp文件相同。
- 动态包含可以传递参数(通过)
- 请求转发
格式:
<jsp:forword page=”请求转发的地址”></jsp:forword>
他的功能就是实现请求的转发。
Listener监听器:
什么是Listener监听器?
- Listener监听器他是javaWeb的三大组件之一(Javaweb中 的三大组件:Servlet程序,Filter过滤器,Listener监听器)
- Listener监听器他是一个规范,规范就是接口
- 监听器的作用是监听某种事物的变化,通过回调函数,反馈给用户或者程序去做一些相应的处理。
ServletContextListener监听器:
ServletContextListener监听器可以监听ServletContext对象的创建和销毁。
ServletContextListener对象在web工程启动的时候创建,在web工程关闭的时候销毁。
一旦监听器监听到ServletContext对象的创建和销毁的时候,都会调用ServletContextListner监听器的方法进行反馈
两种方法,分别是:
default public void contextInitialized(ServletContextEvent sce) {}
这个方法的作用是:
在创建ServletContext对象之后,马上进行初始化
default public void contextDestroyed(ServletContextEvent sce) {}
这个方法的作用是:
在ServletContext对象被销毁的时候马上进行调用。
如何使用ServletContextListener监听器监听ServletContext对象:
使用步骤:
- 编写一个类实现ServletContextListener接口
- 实现接口中的两个方法
- 在web.xml文件中进行配置监听器
El表达式:
什么是El表达式:
El表达式的全称是:Expression Language,是表达式语言
El表达式的作用:
El表达式主要是代替jsp页面中的表达式脚本,在jsp页面中进行数据的输出。
为什么要使用El表达式进行输出呢?
因为使用El表达式进行输出数据会比使用jsp中的表达式脚本更加简洁
El表达式的格式:
${表达式}
当使用El表达式输出的时候,如果输出结果是null,会在页面上展示为空串,如果使用JSp表达式脚本进行输出,如果输出结果为null的时候,会在页面上显示null字符串。
El表达式搜索域数据的顺序:
首先,El表达式主要是使用在jsp页面是进行数据的输出。主要输出的数据是域对象中的数据。
El表达式的搜索域数据的顺序是 从域对象的作用域从小到大
也就是:
PageContext ==> request ==>session ==>application
El表达式中特殊的运算符的作用:
- empty运算符:作用:判断数据是否为空,如果为空,就返回true,如果不为空就返回false
在那些情况下会将其判断为空:
- 值为null的时候
- 值为空串的时候(这个空串中不能去添加空格)
- Object类型数组的长度是0的时候
- List集合中的元素个数为0的时候
- Map集合中的元素个数为0的时候
- El表达式中可以使用三元运算符
- “ . ”点运算和 [ ] 中括号运算:
. 点运算可以输出javaBean对象中的某个属性
[ ] 中括号运算可以输出数组或有序集合中的某一个元素的值,并且可以输出map集合 中含有特俗符号的key的值
实例:
使用 [ ] 中括号查找map集合中的数据。
Map<String> map=new HashMap<>();
Map.put(“a.a.a”,”a.a.avalue”);
Map.put(“b.b.b”,”b.b.bvalue”);
Map.put(“c.c.c”,”c.c.cvalue”);
Map.put(“aaa”,”aaavalue”)
Request.setAttribute(“map”,map);
取出key为aaa的元素的value
${ map.aaa } 这样就可以将key为aaa的元素的value进行取出
如果想要取出key中含有特殊字符的value的话需要将key用 [ ] 方括号进行括起来,再将key用单引号或者双引号进行引起来
${ map [ “a.a.a“ ] } 这样就可以将key为a.a.a 的元素中的value进行取出
通过jstl中的foreach标签进行输出map集合中的value:
<c:foreach var=”entry” items=”map”>
${entry.value.key} 输出key为可以的value
</c:foreach>
El表达式中的11个隐含的变量:
变量 类型 作用
PageContext PageContextImpl 可以获取jsp中的九大内置对象
PageScope Map<String,Object> 可以获取pageContext域中的数据
RequestScope Map<String,Obejct> 可以获取request域中的数据
SessionScope Map<String,Obejct> 可以获取session域中的对象
applicationScope Map<String,Obejct> 可以获取ServletContext域中的数据
Param Map<String,String> 可以获取请求的参数的值
ParamValues Map<String,String[]> 可以获取请求的参数的值,获取多个值的时候使用(例如在获取多选框的选项的时候)
Header Map<String,String> 可以获取请求头的信息
HeaderValues Map<String,String[]> 可以获取请求头的信息,在获取请求头中有多个值的情况
Cookie Map<String,cookie> 可以获取当前请求的Cookie信息
InitParam Map<String,String> 可以获取在web.xml文件中的Context-param标签中的上下文参数
El表达式中的四个特点域中的属性:
PageScope ==== pageContext域
RequestScope ==== requset域
SessionScope ==== session域
ApplicationScope ==== ServletContext域
作用:因为如果我们直接在El表达式中直接写key的话,value的结果是会通过El中的检索顺序进行输出的,这是我们可以通过指定某一个域对象进行输出,例如:pageScope.key就可以输出pageContext域中key为key的键值对的value
El表达式中的PageContext的作用:
首先需要明确,El表达式中的PageContext对象和jsp中的PageContext不是同一个对象,El表达式中的PageContext对象是PageContextImpl类型,而jsp中的PageContext就是PageContext类型的对象。
El表达式中pageContext的作用:
- 协议
- 服务器ip
- 服务器端口号
- 获取工程路径
- 获取请求方法
- 获取客户端的ip地址
- 获取会话的id编号
JSTL标签库(次重点)
JSTL标签库的全称叫做JSP Standard Tag Library JSP标准标签库。是一个不管完善的开源代码的jsp标签库
El表达式主要是为了替换jsp中的表达式脚本,而JSTL标签库的作用是为了替换jsp中的代码脚本,这样使整个jsp页面变得更加整洁。
JSTL由五个不同功能的标签库组成。
功能范围: |
URL |
前缀 |
核心标签库-重点 |
http://java.sun.com/jsp/jstl/core |
c |
格式化 |
http://java.sun.com/jsp/jstl/fmt |
fmt |
函数 |
http://java.sun.com/jsp/jstl/functions |
fn |
数据库(不使用) |
http://java.sun.com/jsp/jstl/sql |
sql |
XML(不使用) |
http://java.sun.com/jsp/jstl/xml |
x |
JSTL标签库的使用步骤:
- 第一步先将jstl的jar包进行导入(这两个包)
- 使用taglib指令将标签库进行引入
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Core核心库的使用:
<c:set/>
作用:set标签的作用是可以往域中保存数据
实例:
<%--
需要向一个域中添加数据需要由三个东西:
1、第一个域对象 通过scope属性进行设置 默认是page也就是pageContext域对象
2、key 通过var属性进行添加
3、value 通过value属性进行添加
--%>
<c:set scope="page" var="abc" value="page"/>
<c:if/>
If标签的作用是进行if判断
判断的依据是通过if中的test属性进行判断的,test属性中应该添加的是需要进行判断的EL表达式。如果为true,在if标签中的内容就会执行,如果为false,在if标签中的内容就不会执行。
实例:
<c:if test="${12==12}">
<h1>12==12</h1>
</c:if>
<%--运行结果:
<c:if>标签
12==12
if标签的作用:
将test中的El表达式进行判断,如果结果为true,就会执行在if标签中的代码,如果为false,就不会执行if标签中的代码
test属性中传入的应该是EL表达式,可以是jsp的表达式脚本
--%>
<c:choose><c:when><c:otherwise>标签
作用:多路判断。跟java中的switch ... case... default非常接近(区别就在于switch...case...default需要手动使用break进行跳出,这个标签不需要,只有一个满足情况,就会直接跳出这个标签)
使用这个标签需要主义的情况:
- 在标签中间不能使用html页面的注释,只能使用jsp中的注释
- 在标签中的<c:when>标签只能是在<c:choose>标签中。
实例:
<%
pageContext.setAttribute("abcd",198);
%>
${pageScope.abcd}
<c:choose>
<c:when test="${pageScope.adcd > 180}">
<h2>超过了180</h2>
</c:when>
<c:when test="${pageScope.adcd>170}">
<h2>超过了170</h2>
</c:when>
<c:otherwise><h2>其他</h2></c:otherwise>
</c:choose>
<c:forEach/>
作用:进行遍历输出使用。
几个实例进行运用
1、通过forEach输出1到10:
代码实例:
<%--从1遍历到10 输出--%>
<c:forEach begin="1" end="10" var="i">
<%--
forEach标签的属性说明:begin属性表示开始 end属性表示结束 var属性表示循环变量(也是当前正在遍历到的数据)
--%>
${i}
</c:forEach>
2、遍历数组:
代码实例:
<%--遍历Object数组--%>
<%
/*创建一个Object数组*/
Object[] objects=new Object[10];
for (int i = 0; i < 10; i++) {
objects[i]=i;
}
pageContext.setAttribute("obj",objects);
/*pageContext.setAttribute("length",objects.length);*/
%>
<%--
foreach标签属性解释:
var 表示当前遍历到的数据
items 表示遍历的数据源(集合或者数组)
--%>
<c:forEach var="i" items="${pageScope.obj}">
${i}<br>
</c:forEach>
- 遍历map集合
代码实例:
<%
Map<String,String> map=new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put(""+i,"空格"+i);
}
pageContext.setAttribute("map",map.entrySet());
%>
<c:forEach items="${pageScope.map}" var="i">
输出键值对${i}<br>
输出key:${i.key}<br><%--通过使用i.key可以调用Map.Entry这个接口中的getKey方法--%>
输出value:${i.value}<br><%--通过使用i.value可以调用Map.Entry这个接口中的getValue方法--%>
<%--也就是说,这里的i的类型其实就是一个Map.Entry类型,通过使用foreach标签,等同于Java中使用
for(Map.Entry<String,Object> i: map.entrySet()){
System.out.println(i);
}
是将map先调用entrySet方法,在使用Map.Entry这个接口引用进行输出的
--%>
</c:forEach>
在java中的getXXX方法,在EL表达式中都需要将get方法进行省略。
- 使用forEach标签将List集合进行遍历:
实例代码:
实例代码:
<%
List<Person> personList=new ArrayList<>();
for (int i = 0; i < 10; i++) {
personList.add(new Person("name"+i,i));
}
pageContext.setAttribute("list",personList);
%>
<c:forEach items="${pageScope.list}" var="i">
list元素的toString方法输出结果:${i}<br>
list元素中的name属性:${i.name}<br>
list元素中的age属性:${i.age}<br>
</c:forEach>
Foreach标签中其他的一些属性的作用:
1、step表示步长值:默认为一(何为步长值?步长值就是每一个元素在遍历的时候两个元素之间的间隔,默认是一个位置的间隔。)
- varstatus属性表示当前遍历到的数据的状态
Foreach标签中的varstatus属性:
- 直接输出varstatus中自定义的变量可以发现这是一个对象这个对象是实现了接口LoopTagStatus这个接口的,也就是说,这个变量可以调用在这个接口中的方法。
这个接口中有哪些方法呢?
Public interface LoopTagStatus{
Public Object getCurrent() ==>获取当前的遍历到的对象
Public int getIndex() ==>获取遍历的索引
Public int getCount() ==>获取遍历到元素的个数
Public boolean isFirst() ==>判断当前遍历到的元素是否为第一个元素
Public boolean isLast() ==>判断当前遍历到的元素是否为最后一个元素
Public Integer getBegin() ==>获取在foreach标签中的begin的属性值
Pubilc Integer getEnd() ==>获取在foreach标签中的end的属性值
Public Integer getStep ==>获取在foreach标签中的step的属性值
}
Foreach标签中,可以将foreach标签中的所有属性都用在遍历通过以及集合中,达到指定开头和结尾,自定义步长值的操作。
文件的上传和下载:
文件的上传:(重点)
- 要先有一个form标签,method=post请求
- Form标签中的encType的属性值必须是multipart/form-data值
- 在form标签中使用input type=file添加上传的文件
- 编写服务器代码接收(暂时使用servlet程序进行接收),处理上传的数据文件
代码演示:
//因为客户端是通过流的方式进行上传的,我们也只能通过流的方法进行接收,否则无法接收到数据
//SyStem.out.println(request.getParameter("username")) null
//1、先进行判断上传的文件是否通过多段数据的类型进行上传的(只有通过多段的数据才是上传的文件)
if (ServletFileUpload.isMultipartContent(request)){
//返回true表示是以多段的形式,反之则不是
//创建FileItemFactory工厂实现类
FileItemFactory fileItemFactory=new DiskFileItemFactory();
//创建用于解析上传数据的工具类ServletFileUpload类
ServletFileUpload servletFileUpload=new ServletFileUpload(fileItemFactory);
try {
List<FileItem> list = servletFileUpload.parseRequest(request);
for (FileItem fileItem : list
) {
if (fileItem.isFormField()) {//判断每一个表单项是普通项还是上传文件
//这里为普通项
System.out.println("普通表单项的name属性值:" + fileItem.getFieldName());
System.out.println("普通表单项的value值:" + fileItem.getString("UTF-8"));//为了防止出现乱码,可以传入参数
} else {
//上传的文件
System.out.println("上传的文件的name属性:" + fileItem.getFieldName());
System.out.println("上传文件的文件名称:" + fileItem.getName());
//写入本地计算机的路径
fileItem.write(new File("D:\\uploadTest\\"+fileItem.getName()));
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Enctype=Multipart/form-data解释:
表示提交的数据通过多段(每一个表单项,每一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器
因为我们设置的表单的提交方式是通过流的方法进行提交的,所以我们在服务器中也需要使用流的方式进行获取数据
Commons-fileupload.jar 常用的API介绍:
Commons-fileupload.jar需要依赖于commons-io.jar这个包,我们需要将两个jar包进行导入。
Commons-fileupload.jar和commons-io.jar这两个包中常用的类:
- ServletFileUpload类 用于解析上传的数据
- Fileitem类 表示每一个表单项
常用的方法:
1、boolean ServletFileUpload.isMultipartipartContent(HttpServletRequset request)
作用:判断当前上传的数据格式是否是多端的格式
2、public List<Fileitem> parseRequest(HttpServletRequest request)
作用:解析上传的数据
3、boolean FileItem.isFormField()
作用:判断当前表单项是否是一个普通的表单项
True表示是一个普通的表单项 false表示上传的文件
4、String FileItem.getFieldName()
作用:获取当前表单项的name属性
5、String FIleItem.getString()
作用:获取当前表单项的值(也就是value)
6、String FileItem.getName()
作用:获取上传的文件名
7、void FIleItem.wirte(file);
作用:将上传的文件写到参数file所指向的磁盘位置
对应的文件上传的Servlet程序查看UploadServlet.java
2、文件的下载:
在文件进行下载的时候,服务器应该干什么:
- 获取要下载的文件名
- 读取要下载的文件内容
- 把下载的文件内容回传给客户端
- 再回传前,通过响应头告诉客户端返回的数据类型
- 告诉客户端收到的数据是用于下载使用的(还是通过响应头)
下载的代码演示:
// 1、获取要下载的文件名
String download="kk.jpg";
// 2、读取要下载的文件内容(通过ServletContext.getResourceAsStream()方法以流的方式进行读取
ServletContext servletContext = getServletContext();
// 4、再回传前,通过响应头告诉客户端返回的数据类型
//获取当前文件的类型 Mime是服务器里的类型,格式为 大类型/小类型
实例:text/html
String mimeType = servletContext.getMimeType("/file/" + download);
System.out.println("下载的文件类型:"+mimeType);
response.setContentType(mimeType);
// 5、告诉客户端收到的数据是用于下载使用的(还是通过响应头)
Attachment表示附件的意思,可以理解成下载,file表示为在客户端页面上显示的下载文件的名字
response.setHeader("Content-Disposition","attachment;file="+download);
//在服务器中 / 斜杠会被解析为http:ip:port/工程路径
InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + download);
// 3、把下载的文件内容回传给客户端
//获取相应的输出流
ServletOutputStream outputStream = response.getOutputStream();
//通过commons-io.jar包中的IoUtils工具类将读取到的数据,复制给输出流,输出到客户端
IOUtils.copy(resourceAsStream,outputStream);
谷歌、IE:
如果在file命名的时候出现了中文,就需要进行url编码:
Response.setHeader(“Content-Disposition”,”attachment;file=”+URLEncoder.encode(“中文.jpg”,”UTF-8”));
谷歌浏览器和IE浏览器都是使用URL进行编码的,只需要进行上述操作就可以出现中文,但是火狐浏览器是使用的base64编码器,需要使用base64编码器进行操作。示例查看El_JSTL中的Base64Test01.
火狐:
Response.setHeader(“Content-Disposition”,”attrachment;file==?Charset?B?xxxx?=”)
”attrachment;file==?Charset?B?xxxx?= 解释:
=?表示编码内容的开始
Charset表示字符集
B表示BASE64编码
Xxxx表示文件名在BASE64编码之后的内容
?=表示编码内容的结束
将html文件修改成jsp文件步骤:
- 在html顶部添加page指令
- i将后缀名修改为jsp
在一般的企业中,一个Servlet程序对应一个模块,在book这个项目中,我们需要将login这个功能和register功能进行结合,将他们合成一个Servlet程序,怎么判断在什么时候实现什么功能呢?第一种方式:可以通过网页的url进行判断,第二种方法:可以在login表单中和register的表单中添加一个隐藏域,例如:<input type=”hidden” name=”action” value=”login”> <input type=”hidden” name=”action” value=”register”>(需要注意,没有name属性的表单项不会被提交),在进行功能的实现之前,可以进行判断需要实现什么功能。
在需要通过大量的if...else进行判断调用方法的时候,可以使用反射机制通过字符串进行获取相应的方法,再通过method类中的invoke方法进行调用获取到的方法。这样可以实现不通过if...else实现调用相应方法的结果。
数据的封装和抽取BeanUtils的使用:
BeanUtils工具类,它可以一次性的把所有的请求参数注入到一个javaBean对象中,也就是抽取数据,将其封装成一个javaBean对象。
BeanUtils包的使用:
1、这是一个第三放提供的功能,需要进行导入jar包一个是
第一个是commons-beanutils.jar,第二个是:commons-logging.jar两个jar包
- 使用BeanUtils类中的方法实现注入。(值得注意的是,注入的信息是通过当前信息中的key的名字和javabean对象的属性进行确定的,当key的值等于javabean对象中的某一个属性名的值是,就会将key对应的参数赋值给javabean对象的这个属性。)
MVC概念:
Mvc全称:Model模板、view视图、Controller控制器。
Mvc可以指导web层的代码如何有效的分离,单独工作
View视图:只负责数据和界面的显示,不接受任何的显示数据无关的代码,便于程序员和美工的分工合作——jsp/html
Controller控制器:只负责接受请求,调用业务层的代码处理请求,然后派发页面,是一个”调度者“的角色——Servlet程序转到某一个页面或者重定向到某一个页面
Model模型:将与业务逻辑相关的数据进行封装成具体的javabean对象,其中不参杂任何与数据处理相关的代码——javaBean/domain/entity/pojo。
MVC是一种思想:
Mvc的理念是将软件代码进行拆分成组件,单独开发,组合使用(目的还是为了进行解耦合)
表单的重复提交:
当用户提交完请求,浏览器会记录下最后一次请求的全部信息,当用户点击F5进行刷新操作的时候,就又会将之前的数据进行再一次提交。
如何进行解决:
因为使用一次请求在请求执行完之后如果使用请求转发的话,在这一次请求中的数据都还存在,因此会导致表单的重复提交,如果使用重定向的方法进行跳转页面,就可以将上一次请求中的数据进行删除,不会出现重复提交的操作。
数据库中进行分页的代码结构:
Select * from表名 limit 每一页开始的位置(数字),每一页的最大显示条数;
每一页开始的位置的公式:
(当前的页数-1)*每一页的最大显示条数
分页操作的分析:
显示页面的序号,这里显示五个页面的序号为例:
需要分为以下四种情况:
第一种情况:
当总的页数小于等于5的时候,就只需要显示 1~最大页面
第二种情况:
当总的页数大于5的时候,这时候又分为三种情况:
第一种情况:
当当前的页面是1,2,3这几个页面中的一个的时候,只需要显示 1~5
第二种情况:
当当前的页面大于等于 最后的页面-2的时候,只需要显示 最大页面-4~最大页面
第三种情况:
就是不属于前面两种情况,需要显示 当前页面-2~当前页面+2。
Cookie:
什么是cookie:(保存在浏览器中)
- cookie是服务器通知客户端保存键值对的一种技术
- 客户端有了cookie对象之后,每次请求都会发送给服务器
- 每一个cookie对象的大小不能超过4kb
Cookie中保存的值需要注意什么:
保存的值不能含有空格、方括号、圆括号、等号、逗号、双引号、斜杠、问号、@符号、冒号、分号、和空值、也不要使用中文。(如果需要使用上述的符号,需要使用BASE64进行编码之后,再将编码之后的值进行填入value)
客户端是如何保存cookie对象的:
- 服务器先创建cookie对象
- 通过response对象的addCookie()方法通知服务器保存cookie对象
- 当客户端收到从服务器传来的信息后,发现响应头中有一个set-cookie,告诉客户端需要将cookie对象进行保存起来,这是浏览器就会将服务器中传来的cookie进行保存。
服务器如何获取客户端保存的cookie对象:
步骤比较简单,只需要执行一行代码即可。
通过request请求对象进行获取cookie对象
Request.getCookies() 返回的类型是一个cookie[ ] 数组
Cookie值的修改:
方案一:(类似于HashMap集合中不可重复的操作)
- 先创建一个要修改的同名的cookie对象
- 在构造器同时赋予新的cookie值
- 调用response.addCookie(Cookie);
方案二:
- 先找到需要修改的cookie对象
- 通过这个cookie对象中的setValue()进行修改
- 调用response中的addCookie()告诉服务器保存cookie对象
Cookie的生命控制:
Cookie的生命控制指的是如何管理cookie什么时候进行销毁(删除)
主要通过 cookie对象中的setMaxAge()方法(单位是秒)进行设置
SetMaxAge()方法中填入的参数的含义:(默认是-1)
- 正数:表示在该秒之后将cookie对象进行删除
- 负数:表示在浏览器关闭之后,将cookie对象进行删除(默认值为-1)
- 零:表示马上将cookie对象进行删除
如果是负数的话就是和session的等级相同的,session对象就是在浏览器关闭之后 就进行删除的。
值得注意的是,如果参数为正数,在cookie存活期间,如果将浏览器进行关闭之后,参数在存活时间内的cookie对象依然存在,只有当时间到了才会进行销毁。
Cookie对象中的path属性的作用:
Cookie对象中的path属性的作用可以有效的过滤哪些cookie是发送给服务器的,哪些不进行发送。
Path属性是通过请求的地址来进行有效的过滤。
例子如下:
Cookie A path=/工程路径
Cookie B path=/工程路径/abc
请求地址如下:
在请求地址如下的情况
Cookie A 会将Cookie发送到服务器
Cookie B 不会将Cookie发送到服务器
当请求地址为:
在这时候:
CookieA 会发送Cookie到服务器
CookieB 会发送Cookie到服务器
也就是说,只要URL中的地址包含了Cookie 中的path,这个Cookie就会将Cookie发送到服务器。
如何通过cookie达到用户登录成功之后,在退出浏览器之后,也可以将用户名进行回显出来:
首先进行判断,如果用户名和密码都验证成功了,就可以在成功的条件的代码中添加一个cookie对象,设置最大生存期,告诉客户端保存这个cookie对象,然后在jsp页面中使用El表达式将cookie中的value进行显示( ${cookie.name.value} )就可以了。
通过El表达式获取到cookie 对象的value属性:
${ cookie . cookie中key的名字 . value}
举个例子
Cookie cookie=new Cookie(“name”,”value”);
如果通过El表达式进行获取就是这样的:
${ cookie. name . value}
Session:
在了解之前,需要明白超时的概念:
超时是指在一定时间如果没有和服务器进行交互,就会将这个session对象进行销毁,如果有和服务器进行交互的工作,就会重置超时的时间。(也就是客户端向服务器两次放松请求的最大时间长度)
举个例子:
假如我们设置了一个timeOut为3秒的session对象,如果,在三秒中我们没有像服务器发送请求的话,三秒之后,这个session对象就会被删除,如果在三秒期间,我们发送了请求,与服务器之间有交互的操作,就会重置timeOut的时间,也就是从现在开始,重新数三秒。
什么是session会话:(保存在服务器中)
- session就是一个接口(HttpSession)
- Session就是会话,它是用来维护客户端和服务器之间的关联的一种技术
- 每一个客户端都有自己的一个session会话
- Session会话中,通常用来保存用户登录之后的信息
如何创建和获取session对象:
如何获取和创建session,通过request进行获取
Request.getSession()方法进行获取和创建session对象
第一次调用这个方法是创建session对象
以后进行调用这个方法就是获取之前创建好的session对象
如何判断是否为刚创建的session对象:
通过session对象中的isNew()方法进行判断
isNew() true表示是刚创建的 false表示是之前创建的现在为获取
每个session对象都是唯一的,如何进行区分每一个session对象:
通过id值进行区分,如何获取session对象的id值?
通过session对象的 getId()方法进行获取session对象的id值
Session对象的生命周期控制:
通过使用以下方法进行设置session对象的超时时间
Public void setMaxInactiveInterval(int interval) 通过这个方法进行设置session对象的超时时间,一旦session对象超过了超时时间,session对象就会被销毁。(单位为秒)
Public int getMaxInactiveInterval() 获取session对象的超时时间
Session对象的默认超时时长:
session对象的默认超时时长:1800秒 也就是30分钟
因为在Tomcat服务器中的配置文件中默认有以下配置信息:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
所以默认是30分钟
如果要进行修改session对象的默认超时时间,可以有以下操作:
第一种方法:在tomcat服务器中的web.xml文件中将上述的配置进行修改
导致的结果:整个tomcat服务器中的所有session的默认超时时间都是你修改的时间,这种方法不推荐。
第二种方法:在你自己的工程中的web.xml文件中进行添加session的默认超时配置,也就是上述的那种格式。
导致的结果:只有你的工程中的session对象的超时时间是你修改后的时间,推荐这种方法。
如果你想要只设置某一个session对象的超时时间,就学要使用Public void setMaxInactiveInterval(int interval) 进行设置超时时间。
setMaxInactiveInterval(int interval)方法中的参数的几种情况:
第一种情况:参数为正数的时候,表示在该秒之后将session进行销毁
第二种情况:参数为负数的时候,表示该session对象永不过时(极少使用)
注意:setMaxInactiveInterval方法中的参数不能是0.
如何将session对象进行马上超时:
调用invalidate()方法
Session.invalidate() 将当前调用此方法的session对象进行马上超时,马上销毁。
浏览器和session之间的关联的技术内幕:
Session技术,底层是基于Cookie技术进行实现的。
如果在客户端中没有cookie信息,然后向服务器进行发送请求,服务器通过request.getSession()方法创建一个session对象,将session会话放到服务器内存中,服务器在每一次创建了session对象之后,也会同时创建一个cookie对象,这个cookie对象的key永远都是JSEEIONID,这个cookie的value就是创建好的session会话的id值。
再通过响应头将新创建出的session的id值通过cookie的形式传向客户端。
Cookie: JSESSIONID=35236DB7799B2B980C7205A25F506A53
传向服务器之后,服务器会闯将一个cookie对象,将传入的信息进行写入刚创建好的cookie对象中,在此之后,客户端每次向服务器进行发送请求的时候,都会将这个cookie对象进行发送到服务器,服务器通过request.getSession()方法获取到cookie对象中保存的session会话的id值,然后在服务器内存中将所有的session的id进行比较(因为所有的session对象的id值都是唯一的),如果有相同的session就直接放回这个session对象,如果没有就直接创建一个session对象。
如果在session会话没有超时的情况下,在客户端将session对象进行删除,在向服务器发送请求,这个时候,尽管session对象没有超时,但是客户端在发送请求的时候没有cookie对象,服务器无法获取到session会话的id值,就会重新创建一个session会话发送给客户端。
注销账号需要做的工作:
- 将保存了用户信息的session对象进行销毁或只销毁session对象中的用户信息
- 重定向到登录界面。
表单的重复提交之------验证码:
表单重复提交的三种常见的情况:
第一种:提交完表单后,服务器使用请求转发进行跳转,客户端点击刷新之后,就又会发起一次请求,造成表单重复提交的问题。解决方法:通过使用请求重定向进行跳转。
第二种:用户正常提交服务器,但是由于网络延迟等原因,未收到服务器的相应,这时候如果用户反复点击提交,可能也会造成表单的重复提交。
第三种:用户正常提交服务器,服务器也没有延迟,在是提交完成之后,用户回退浏览器(返回)。重新提交,也会造成表单的重复提交。
第一种情况可以使用请求重定向的方式进行解决,第二三种情况就需要使用验证码的方式进行解决。
谷歌kaptcha 图片验证码的使用:
谷歌验证码kaptcha使用步骤如下:
- 导入谷歌验证码的jar包
- 在web.xml文件种去配置用于验证码生成的Servlet程序
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jsp</url-pattern>
</servlet-mapping>
- 在表单中使用img标签去显示验证码图片,并使用他。
<img alt="" src="kaptcha.jsp" style="float: right; margin-right: 40px;width: 80px;height: 37px">
- 在服务器种获取谷歌生成的验证码和客户端发送过来的验证码进行比较使用。
谷歌生成的验证码如何在session域对象中进行取出:
通过session域对象,存放验证码的key为
public static final String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";
也就是KAPTCHA_SESSION_KEY作为key进行取出value验证码
Request.getSession().getAttribute(“KAPTCHA_SESSION_KEY”)进行获取。
关于浏览器中的缓存机制:
为了提高请求的执行速度,在每一次请求完毕之后,浏览器都会将请求的内容保存到浏览器端(要么是硬盘上,要么是内存中),当你第二次发送请求的时候,浏览器发现你之前发送的一个请求和请求的参数和这个请求和这个请求的参数是相同的,就会直接从硬盘上或者内存中将请求的内容进行返回。
举个例子:(使用跟换验证码进行举例)
http://localhost:8080/Book/kaptcha.jsp 进行切换验证码,浏览器就会生成以下缓存kaptcha.jap=验证码的图片,当再次通过 http://localhost:8080/Book/kaptcha.jsp 获取验证码图片的时候,浏览器发现两次请求和请求的参数都是一样的,所以就会直接从缓存将对应的内容进行读取出来。
如何解决浏览器的缓存机制:
可以在请求的后面添加一个参数,参数的值为当前的时间,这样就可以解决。
this.src="kaptcha.jsp?time="+new Date();
HTTP协议中的Referer请求头的作用:
Http协议中有一个请求头叫做Referer,它的作用将当前客户端的访问的地址发送到服务器,服务器通过request.getHeader(“Referer”)进行获取客户端发来的地址。
Filter:
什么是过滤器:
- filter过滤器他是javaweb的三大组件之一,三大组件:servlet程序 Listenter监听器 Filter过滤器
- Filter过滤器就是一个规范,就是一个接口
- Filter的作用是:拦截请求,过滤相应
拦截请求常用的应用场景:
- 权限检查
- 日记操作
- 事务管理
..........等等
Filter的初体验
要求:在web工程下,有一个admin的目录,这个admin目录下的所有资源都只有在进行登录之后在进行访问
如何判断用户是否进行登录:
之前我们说过,如果用户进行了登录,就将用户的登录信息保存的session域中,所以,我们只需要判断在session域中是否含有用户的信息即可
Filter过滤器的使用:
- 先编写一个类实现 javax.servlet.Filter这个接口
public class AdminFilter implements Filter {
- 在doFilter方法中编写代码进行拦截(doFilter方法就是进行拦截的方法)
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//将ServletRequest对象转化为HttpServletRequest对象
HttpServletRequest requ= (HttpServletRequest) request;
//通过HttpServletRequest对象获取在session对象,进行判断session对象中是否存有用户的信息
HttpSession session = requ.getSession();
if (session.getAttribute("user")==null){
//如果session对象中没有用户的信息,将页面跳转到登录页面
System.out.println("session域中没有用户信息!");
requ.getRequestDispatcher("/login.jsp").forward(request, response);
}else {
//说明session域对象中存有用户的信息,进行默认操作就可以了
System.out.println("session域中有用户信息!");
chain.doFilter(request, response);//这段代码就是进行默认操作
}
}
- 在web.xml文件中进行配置Filter过滤器,包括配置别名、配置类全名、配置过滤路径、配置那个Filter过滤器的过滤路径
一个Filter中可以有多个路径
<!--进行配置Filter过滤器需要起作用的地址,Filter在web.xml文件中配置和Servlet程序配置区别不大-->
<filter>
<!--给过滤器起一个别名-->
<filter-name>AdminFilter</filter-name>
<!--配置过滤器的全类名-->
<filter-class>com.littleshark.AdminFilter</filter-class>
</filter>
<!--配置Filter的拦截路径-->
<filter-mapping>
<!--filter-name表示当前是当前路径是给那个Filter过滤器进行使用的-->
<filter-name>AdminFilter</filter-name>
<!--进行配置拦截路径
/ 斜杠表示请求路径为:http://ip:port/工程路径/
*表示全部 /admin/* 表示拦截工程路径下的admin文件夹中的所有文件 也就是 http://ip:port/工程路径/admin/*
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
注意:
在客户端访问到页面的时候,如果路径是使用了过滤器的路径,就会先经过过滤器,如果满足条件之后,才会进行相应的操作。
4、Filter的生命周期:
1、构造方法 在工程开启之后就会马上执行
2、init初始化 在工程开启之后就会马上执行
3、doFilter过滤 在客户端访问对应有过滤器的地址的时候,就会执行
4、destroy销毁 在关闭工程的时候,就会执行
实例: Filter的public AdminFilter()构造方法
Filter的public void init(FilterConfig filterConfig)厨师化方法
Filter的public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)过滤方法
Filter的public void destroy()销毁方法
5、FilterConfig类:
FilterConfig类:他就是Filter过滤器的配置文件类
Tomcat每次创建Filter的时候,也会同时创建一个FilterConfig类,这里包含了Filter配置文件的信息。
FilterConfig类的作用是:获取Filter过滤器的内容
1·、获取Filter的名称(也就是 filter-name中的内容)
2、获取filter中配置的init-param初始化参数(在filter标签中进行配置,可以配置多组)
<filter-name>AdminFilter</filter-name>
<!--配置过滤器的全类名-->
<filter-class>com.littleshark.Filter.AdminFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>LittleShark</param-value>
</init-param>
</filter>
3、获取ServletContext对象
6、FilterChain过滤器链:
Filter:过滤
Chain:链条、链
FilterChain:就是过滤器链(多个过滤器如何一起工作)
每一个Filter中都会有同一行代码:
FilterChain.doFilter()方法,它的作用是:(只有两个作用)
- 如果有下一个过滤器的话,就执行下一个过滤器
- 如果没有下一个过滤器就执行包含的目标资源。
(将资源进行取出的特点和Static栈类似,目标的资源就是最后放进栈中的对象,在将栈中的对象进行一一取出)
7、什么决定Filter执行的顺序:
是Filter在web.xml文件中配置的先后顺序进行决定的。
8、多个Filter过滤器执行的特点:
1、所有的Filter过滤器和目标资源默认都是执行在同一个线程中的(可通过Thread.currentThread().getName() 进行查看线程)
2、多个Filter构造器共同执行的时候,他们都是使用的同一个Request对象(因为在调用filterChain.Dofilter()方法的时候,需要将当前的ServletRequest和ServletResponse对象进行传入,可以将ServletRequest转化为HttpServletRequest对象,所以他们是使用的是同一个Request对象)
9、Filter的拦截路径:
1、精确匹配:
<url-pattern>/login.jsp</url-pattern>
只要满足 http://ip:port/工程路径/login.jsp 就会进行拦截
2、目录匹配:
<url-pattern>/admin/*</url-pattern>
这个就是目录匹配,只要满足 http://ip:port/工程路径/admin/* 就会进行拦截
3、后缀名匹配:(不要斜杠 / )
<url-pattern>*.html</url-pattern>
这个就是后缀名进行匹配,表示请求地址如果是通过.html进行结尾就会进行拦截
Filter只关心地址是否匹配,不关心资源是否存在。
ThreadLocal的使用:
- ThreadLocal的作用:他可以解决多线程的数据安全问题
- ThreadLocal它可以给当前线程关联一个数据(可以是一个变量、可以是一个对象、也可以是一个数组、集合)
- ThreadLocal的特点:
- ThreadLoacl可以当作当前线程关联一个数据(它可以像map集合那样存取数据,key为当前线程)
- 每一个ThreadLocal对象,都只能为当前线程关联一个数据,如果要为当前线程关联多个数据,需要使用多个ThreadLocal对象实例
- 每一个ThreadLocal对象的实例定义的时候,一般都是static类型
- ThreadLocal中保存的数据,当当前线程销毁之后,数据有JVM的GC垃圾回收器进行自动释放。
Filter和ThreadLocal的联合管理事务:
使用ThreadLocal进行获取同一个Connection对象
如何保证一连串事件是通过成功和同时失败的,这个就是一个事务,如何确保这是通过一个事务,就要保证这是同一个Connection数据据库连接池对象,如果可以获取到同一个数据库连接对象,可以将数据库连接对象放到ThreadLocal对象中,但是,需要确保,需要进行执行的代码都是在同一个线程中进行执行的,注意,在这个事务进行提交或者回滚之后,需要将这个连接对象通过remove方法将这个连接对象从数据库连接池中进行移除,原因在于TomCat使用了数据库连接池技术。
使用Filter过滤器进行批量添加try catch语句:
Filter过滤器中总是会有一个doFilter方法,这个方法的作用就是执行下一个过滤器或者加载资源,这里的资源包含很多,类也是一个资源,也就是说,doFilter方法可以间接调用网址参数中的方法,如果我们在doFilter方法中添加try catch,就可以同时将多个资源进行添加try catch语句块
将所有的异常都统一交给TomCat服务器,让他进行展示友好的错误信息界面:
怎么做:
在web.xml文件中通过错误页面配置来进行管理
<!--配置出错页面-->
<error-page>
<!--出错的代码-->
<error-code>500</error-code>
<!--出错页面的地址-->
<location>/pages/errorPage/errorPage.jsp</location>
</error-page>
JSON、AJAX、i18n:
1、什么是JSON:
Json(javaScript Object Notaton)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,Json采用完全独立的语言文本格式,而且很多语言都提供了对json的支持(包括c、Java、c++、c#、python等),这样是的json成为理想的数据交换格式。
Json是一种轻量级的数据交换格式,轻量级是和xml文件进行比较。
数据交换指的是客户端和服务器之江的业务数据的传递格式
2、Json在javaScript中的使用:
1、json的定义:(Json本身是一个对象(Object))
Json是由键值对进行组成的,并且由花括号(大括号)包围,每一个键由引号引起来,键和值之间使用冒号进行分割,多组键值对使用逗号进行分割。
// json的定义
var jsonObject={ /*json中可以保存任意类型例如:number类型,字符串类型、json类型、布尔类型,数组、json数组等等*/
"key1":12,
"key2":"value2",
"key3":true,
"kye4":[11,"abc",false],
"key5":{
"key5_1":"abc"
}
}
2、json的访问:
// json的访问
alert("json对象中的第一个值为:"+jsonObject.key1)
3、json的常见的两种常用方法:
Json的存在有两种形式:
第一种是通过对象的形式存在 我们叫做json对象
第二种是通过字符串的形式存在 我们叫做json字符串
一般我们要操作json中的数据的时候,使用json对象
在客户端和服务器之间进行交换数据的时候,使用json字符串
如何进行转化:
JSON.stringify() 将json对象转化为json字符串
JSON.parse() 将json字符串转化为json对象。
// json对象转字符串
alert(typeof (jsonObject))/*Object*/
alert(typeof (JSON.stringify(jsonObject)))/* string */
// json字符串转json对象
alert(typeof (JSON.parse(JSON.stringify(jsonObject))))
3、Json在java中的使用:
需要将json的jar包进行添加到目录。
3.1、javabean和json的互转:
@Test
public void test01(){
Person person=new Person(12,"小王");
//通过Gson的jar将javabean对象转化为json字符串形式
//1、先要创建Gson对象
Gson gson=new Gson();
//2、通过Gson中的toJson方法将传入的参数转化为Json中的字符串形式
String javaBeanToJsonString = gson.toJson(person);
System.out.println(javaBeanToJsonString);//{"id":12,"name":"小王"}
//将字符串类型的json转为为对象
Person person1 = gson.fromJson(javaBeanToJsonString, Person.class);
System.out.println(person1);
}
3.2、List集合和json的互转
@Test
public void test02(){
//将List集合转化为json字符串形式
List<Person> list=new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(new Person(i+1,"name"+i+1));
}
Gson gson=new Gson();
String listToJsonString = gson.toJson(list);
System.out.println(listToJsonString);
/*[{"id":1,"name":"name01"},{"id":2,"name":"name11"},{"id":3,"name":"name21"},
{"id":4,"name":"name31"},{"id":5,"name":"name41"},{"id":6,"name":"name51"},
{"id":7,"name":"name61"},{"id":8,"name":"name71"},{"id":9,"name":"name81"},
{"id":10,"name":"name91"}]*/
//总结:通过Gson的toJson方法,会将List集合的信息保存为一个数组的形式
//将Json为字符串类型的List集合转化为List对象,值得注意的是,如果是集合的话,第二个参数就应该填写type,如果不这么填写,得到的List集合中的对象会与先前保存的对象不相同。
List<Person> list1 = gson.fromJson(listToJsonString, new PersonType().getType());
System.out.println(list1.get(0) instanceof Person);//true
}
class PersonType extends TypeToken<ArrayList<Person>>{
}
3.3、Map集合和json的互转
@Test
public void test03(){
Map<Integer,Person> map=new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put(i,new Person(i+1,"name"+i+1));
}
Gson gson=new Gson();
String mapToJsonString = gson.toJson(map);
System.out.println(mapToJsonString);
/*{"0":{"id":1,"name":"name01"},"1":{"id":2,"name":"name11"},"2":{"id":3,"name":"name21"},
"3":{"id":4,"name":"name31"},"4":{"id":5,"name":"name41"},"5":{"id":6,"name":"name51"},
"6":{"id":7,"name":"name61"},"7":{"id":8,"name":"name71"},"8":{"id":9,"name":"name81"},
"9":{"id":10,"name":"name91"}}*/
//总结:通过Gson中的toJson方法可以将map集合中的信息保存为Json的形式
//将Json为字符串类型的Map集合转化为Map对象,同样,Map是一个集合,如果需要将Json字符串形式转化为Map集合之后,保存的依然是之前的类型,就需要传入Type
Map map1 = gson.fromJson(mapToJsonString, new PersonTypeOfMap().getType());
System.out.println(map1.get(1) instanceof Person);//true
}
class PersonTypeOfMap extends TypeToken<HashMap<Integer,Person>>{}
//也可以将他们全部写成匿名内部类的形式
Map map1 = gson.fromJson(mapToJsonString, new TypeToken<HashMap<Integer,Person>>(){}.getType());
AJAX请求:
- AJAX(Asynchronous Javascript And XML) 异步JavaScript和XML,指的是一种创建交互式网页应用的网页开发技术。
- Ajax是一种浏览器通过js异步发起请求,局部更新页面的技术。
异步请求:在没有收到服务端的响应的时候,代码会继续往下进行,一旦相应返回了,就执行响应中的代码,用户有更优的体验。
同步请求:在没有收到服务器的响应之间,就不会往下进行执行代码,只有收到了响应才会继续往下执行代码
Ajax的局部更新:浏览器地址栏不会发生变化,局部更新不会舍弃原来页面上的内容。
原生的AJAX请求实例:
<script type="text/javascript">
function ajaxRequest() {
// 1、我们首先要创建XMLHttpRequest
var xmlHttpRequest=new XMLHttpRequest();
// 2、调用open方法设置请求参数 请求类型、请求的地址、是否为异步
xmlHttpRequest.open("GET","http://localhost:8080/JSON_AJAX_i18n/ajaxServlet?action=javaScriptAjax",true)
// 4、在send方法前绑定onreadystatechange事件,处理请求完成后的操作。
xmlHttpRequest.onreadystatechange=function () {
if (xmlHttpRequest.status==200&&xmlHttpRequest.readyState==4){
/*将相应的数据显示到页面上*/
document.getElementById("div01").innerHTML=xmlHttpRequest.responseText
}
}
// 3、调用send方法发送请求
xmlHttpRequest.send()
}
</script>
</head>
<body>
<button onclick="ajaxRequest()">ajax request</button>
<div id="div01">
</div>
protected void javaScriptAjax(HttpServletRequest request,HttpServletResponse response){
System.out.println("Ajax请求过来了!");
Person person=new Person(1,"小王");
//将需要对客户端的相应person转化成json的字符串形式
Gson gson=new Gson();
String personJson = gson.toJson(person);
try {
response.getWriter().write(personJson);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
2、Jquery中的AJAX请求:
$.ajax方法
Url 表示请求的地址
Type 表示请求的方式 get post
Data 表示发送给服务器的数据
两种格式:
一:name=value&name=value
二:{key : value , key:value}
Success 请求成功,响应的回调函数
Datatype 响应的数据类型
常用的数据类型有:
- Text 表示纯文本
- Xml 表示xml数据(现在不怎么使用了)
- Json 表示json对象
$.ajax({
url:"http://localhost:8080/JSON_AJAX_i18n/ajaxServlet",
data:"action=jqueryAjax",
/*data:{action:"jqueryAjax"},*/
type:"GET",
success:function (data) {
$("#msg").text("id:"+data.id+" 姓名:"+data.name);
},
dataType:"json"
});
$.get方法
Url 请求的url地址
Data 发送的数据
Callback 成功的回调函数
Type 返回的数据类型
// ajax--get请求
$("#getBtn").click(function(){
alert("kkk")
$.get("http://localhost:8080/JSON_AJAX_i18n/ajaxServlet","action=jqueryGet",function (data){
alert(data)
},"json")
});
$.post方法
Url 请求的url地址
Data 发送的数据
Callback 成功的回调函数
Type 返回的数据类型
// ajax--post请求
$("#postBtn").click(function(){
// post请求
$.post("http://localhost:8080/JSON_AJAX_i18n/ajaxServlet","action=jqueryPost",function (data) {
alert("post中的返回值:"+data)
},"json")
});
$.getJSON方法 需要注意:请求方式为固定的get请求,返回的类型也是固定的为json
Url 请求的url地址
Data 发送的数据
Callback 成功的回调函数
$("#getJSONBtn").click(function(){
// 调用
$.getJSON("http://localhost:8080/JSON_AJAX_i18n/ajaxServlet","action=jqueryGetJson",function (date) {
alert("jqueryGetJson中的data:"+date)
})
});
表单序列化 serialize()方法:(使用方法:$(“#id值”).serialize()就可以获取到客户端在表单中填写的信息)
他的作用是可以将表单中的所有表单项的内容进行获取到,并以name=value&name=value的方式进行拼接
// ajax请求
$("#submit").click(function(){
alert($("#form01").serialize())
});