2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > JavaWeb加强之JSON jQuery Ajax Java正则表达式 过滤器 监听器 模板引擎FreeMarker

JavaWeb加强之JSON jQuery Ajax Java正则表达式 过滤器 监听器 模板引擎FreeMarker

时间:2019-02-23 11:06:45

相关推荐

JavaWeb加强之JSON jQuery Ajax Java正则表达式 过滤器 监听器 模板引擎FreeMarker

过滤器、监听器,以及JSON、Ajax和正则表达式等开发必备技能,并学习文件上传和验证码等功能开发。

2.4.1 JSON基础

JSON的基础语法,以及流行JSON框架FastJSON的使用。

内容:

JSON语法规则:

JSON数据是以key/value的形式描述,key和value中间使用冒号分隔开;多组key/value值使用逗号分隔开,例如:{ “firstName”:“John” , “lastName”:“Doe” }。

JSON的作用主要就是数据的存储与传输,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。使用这种方式可以更快的进行前后台数据的传输。在存储数据方面逐渐替代了xml的功能。从实际的使用看,他们的用途不一样,xml主要用作配置文件和一些简单数据的存储,从后面的学习中可以看到xml作为配置文件是非常常见的。而json更多得用在数据的请求处理中,如通过请求服务器得到json数据,然后在前端或移动端页面中进行显示。

console.log(json);在浏览器控制台中对json内容进行输出。console是浏览器内置对象,log()方法是向控制台输出日志。

JavaScript对JSON有天然的支持特性。

在 JavaScript 中,document.write() 可用于直接向 HTML 输出流写内容。内容中的符合html结构的内容可被直接解析为对应的html标签。用于动态补充或展示页面内容。

Ctrl+Shift+F快捷键格式化代码。

JSON与字符串互相转换:

JSON是浏览器(IE8以下不支持JSON对象)内置对象。

在javascript的字符串中出现多对””,要使用转义符号\,避免混淆。JSON以[ ]开头表示这是一个json数组的含义,里面含有多个json对象。而只编写{ }则表示的是一个json对象。

JSON对象书写的另一种方式,类似对象。

每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。document.write()表示向文档写 HTML 表达式 或 JavaScript 代码。除此之外常用的还有document.getElementById(“id值”)返回对拥有指定 id 值的第一个标签对象的引用。

console.log()、console.info()的作用都是在浏览器控制台打印信息的,可理解它们两个其实就是同一个,只不过名字不一样,其中console.info()打印出的信息,在控制显示的时候信息前面会出现一个小图标。

Java是开源的全世界的工程师都在为Java添砖增瓦。

JSON与Java交互:

JSON工具包是用来JAVA与JSON之间序列号与反序列化。

github全世界最著名的开源软件平台()。搜索fastjson下载alibaba开发的,可在github下载也可在/maven2/com/alibaba/fastjson/。下载。

JavaBean简单笼统的说是一种符合一定规范编写的Java类,不是一种技术,而是一种规范 , 表达实体和信息的规范。大家针对这种规范,总结了很多开发技巧、工具函数。符合这种规范的类,可以被其它的程序员或者框架使用。它的方法命名,构造及行为必须符合特定的约定:1、这个类必须具有一个公共的(public)无参构造函数;2、所有属性私有化(private);

2、私有化的属性必须通过public类型的方法(getter和setter)暴露给其他程序,并且方法的命名也必须遵循一定的命名规范。4、这个类应是可序列化的。(比如可以实现Serializable 接口)。这些特点使它们有更好的封装性和可重用性。并且可以被序列化(持久化),保存在硬盘或者在网络上传输。

Bean译过来是“豆子”的意思,我们是不是只能看到豆子硬硬的外皮,而看不到内部的东西。

通常我们说的API是API文档的简称。API文档就像字典或使用说明书 一样的存在,对某样技术用到的接口、类、方法等具体的解释。就像字典一样,在使用时,可以在API中的方法时能够快速找到,学会使用这个方法。

FastJson序列化与JSON注解:

日历类Calendar:月份是从0开始的,这是java中约定俗成的规定,其余的是从1开始的。

JSON序列化:格式:JSON.toJSONString(需要序列化的JAVA对象/对象数组/对象集合),将JAVA对象转换成JSON字符串。

JSON注解:格式:@JSONField(属性=属性值),放在JAVA对象中需要设置序列化JSON字符串格式的属性上面。如图:

@JSONField(format=“yyyy-MM-dd HH:mm:ss”)对(下面代码所示时间属性)属性序列化注解,@JSONField(serialize=false)不对(下面代码所示属性)属性进行序列化。

JSON反序列:格式:JSON.parseObject(需要转换成JAVA对象的JSON字符串,需要转换成JAVA对象的类型),将需要转换成JAVA对象的JSON字符串转换成JAVA对象的类型。

这里指Employee类编译好的字节码文件,表示将json转换为Employee对象。其他类加不加.class看是否将json转换具体对象。

序列化 (Serialization)是指将对象的状态信息转换为可以存储或传输的形式的过程。可以将其保存到磁盘文件中或通过网络发送到任何其他程序;反序列化是相反的过程(将流转换为对象)。而序列化的一种选择,就是使用json来当作临时存储的方式。JSON又称JavaScript 对象表示法(JavaScript Object Notation),但是它本身是和平台与语言无关的,具有自我描述性,易于理解。json是能直接转换为js对象的一种格式,使用它来存储对象,更加方便。

JSON序列化是把对象包装成JSON字符串传输。Json的优点:明文结构一目了然,可以跨语言,属性的增加减少对解析端影响较小。缺点:字节数过多,无法处理对象方法等数据,依赖于不同的第三方类库。

导入项目后需要配置自己的jdk。项目右击,选择Build Path,Configure Build Path。在右侧Libraies中选择JRE System Library,点击Edit,选择Alternate JER,点击下箭头,选择自己的jdk,点击Finish,Apply and Close。

json反序列化话需要对应实体类有无参构造器。

对于FastJson来说如果JAVA对象的某个属性为null,则序列化不输出此属性的JSON字符串。

JSON.parseArray(JSON字符串,转换成的JAVA对象类型),JSON字符串(多个JSON对象的数组)转换成JAVA对象List集合:

2.4.2 jQuery与Ajax基础

介绍JQuery的常用语法规则及如何使用Ajax进行页面局部刷新。

jQuery与Ajax:

内容:

JavaScript库:

jQuery介绍:

jQuery下载与安装:

EL 表达式是从域中取出之前存好的属性,是 ${},而jQuery 是$() 并且是获取页面的元素,虽然写法比较类似,但是其实还是没有太大关联的。

jQuery选择器实验室:

js里addClass()和className 的区别:1、addclass()是JQuery的函数。JavaScript中没有。className 属性可以用来设置或返回元素的 class 属性。2、 addClass() 方法向被选元素添加一个或多个类,该方法不会移除已存在的 class 属性,仅仅添加一个或多个 class 属性–>就是说addClass方法只会向当前被选中的元素添加属性,而不会移除原有属性。className将其赋值为"“可以达到清空元素的class的目的.

选择器的用途:选择需要的元素 $(“a”) (选择器表达式(字符串形式))。//移除指定的css类,移除所有具有该css类的处理。(选择器表达式(字符串形式))。//移除指定的css类,移除所有具有该css类的处理。(选择器表达式(字符串形式))。//移除指定的css类,移除所有具有该css类的处理。(”*").removeClass(“highlight”);在css样式表中书写时,ID选择符前面应该加前缀符号‘#’,标签选择器直接写标签名,类选择器应该加前缀符号‘.’。

Web页面开发的两个要素:

jQuery选择器:

基本选择器:

层叠选择器:

注:兄弟选择器只能选择在该元素后边并且平级的元素。

属性选择器:

注:属性选择器只会选择明确写了属性的选择器,eg:对于<input>标签默认type=”text”,当不写type时,属性选择器${“input[type=’text’]”不会选择这个<input>。

位置选择器:

表单选择器:

表单选择器的”:”后边是表单包含的元素的type属性值。注:对于<input>标签默认type=”text”,当不写type时,表单选择器”:text”会选择这个<input>,刚好补充了属性选择器${“input[type=’text’]”不会选择这个<input>。$("selector:input")----------所有输入框。$("form:text")是选择form表单中的type=’text’元素,而$("selector:text")(写法$(“:text”))是选择页面中所有type=’text’元素;如果是获取写在form表单中的type=’text’就可以使用$("form:input")。浏览器输入URL中http:// 这个加与不加没区别的,浏览器解析时会默认用这个协议的。

操作元素属性:

attr()方法中参数只有一个时,是获取这个参数对应的属性值,参数是两个时是设置第一个参数对应的属性的值为第二个参数。

注:获取元素属性时,当拥有此属性的元素为多个时,获取的是第一个元素的属性。

在input的标签中,对于不同的输入类型,value 属性的用法也不同:当type=“button”, “reset”,“submit” -时,value只是为了定义按钮上的显示的文本,所以这里value值并不会清空。

操作元素的CSS样式:

操作元素的css样式中css()方法中参数只有一个时,是获取这个参数对应的样式属性值,参数是两个时是设置第一个参数对应的样式属性的值为第二个参数。当需要设置多个样式属性可用JSON对象表示法。

注:获取元素样式属性时,当拥有此样式属性的元素为多个时,获取的是第一个元素的样式属性。

操作元素的css样式中addClass()方法为选择器选中的元素添加多个指定类名需添加空格。

设置元素内容:

val()----获取或设置输入项的值,设置参数,表示更改匹配元素的值;不设置参数,表示获取匹配元素的值。text()—获取或设置元素的纯文本,设置参数,表示更改匹配元素的值;不设置参数,表示获取匹配元素的值。如果文本内容出现标签,不进行转义,输出标签。html()—获取或设置元素内部的html,设置参数,表示更改匹配元素的值;不设置参数,表示获取匹配元素的值。如果文本内容出现标签,进行转义,浏览器会解析标签。

当文本内容不含标签建议使用text()方法,text()和html()方法最大的区别是对于文本中的html标签是否进行转义。

b标签是加粗文本。

("span.myclass")−−>这个是一个组合的选择器,表示选择class为myclass的span标签。jQuery事件处理方法:![在这里插入图片描述](https://img−/2029002056578.png)jQuery常用事件:![在这里插入图片描述](https://img−/20290021036.png?x−oss−process=image/watermark,typeZmFuZ3poZW5naGVpdGk,shadow10,textaHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size16,colorFFFFFF,t70)load()方法是从服务器加载数据,并把返回的数据放入被选元素中,需要传入url等参数。当页面初始化后,执行("span.myclass")--> 这个是一个组合的选择器,表示选择class为myclass的span标签。 jQuery事件处理方法: ![在这里插入图片描述](https://img-/2029002056578.png) jQuery常用事件: ![在这里插入图片描述](https://img-/20290021036.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size_16,color_FFFFFF,t_70) load()方法是从服务器加载数据,并把返回的数据放入被选元素中,需要传入url等参数。当页面初始化后,执行("span.myclass")−−>这个是一个组合的选择器,表示选择class为myclass的span标签。jQuery事件处理方法:![在这里插入图片描述](https://img−/2029002056578.png)jQuery常用事件:![在这里插入图片描述](https://img−/20290021036.png?x−oss−process=image/watermark,typeZ​mFuZ3poZW5naGVpdGk,shadow1​0,texta​HR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size1​6,colorF​FFFFF,t7​0)load()方法是从服务器加载数据,并把返回的数据放入被选元素中,需要传入url等参数。当页面初始化后,执行(function(){})。使用()选中元素需要使用引号引起来。()选中元素需要使用引号引起来。()选中元素需要使用引号引起来。(function(){

alert(“欢迎来到设置颜色的页面”)😉;

(this)是指当前事件产生的对象。按下空格匹配元素的样式属性color为red。![在这里插入图片描述](https://img−/202900212268.png)处理方法中的event参数不是一个固定参数名,可以写成其他名,但最好见名知意还是event好。键盘按键分字符键,非字符键(功能键和特殊按键),keypress是用户摁下按键,并且产生一个字符时发生,所以退格键就只能触发onkeydown和onkeyup事件。Ajax介绍:![在这里插入图片描述](https://img−/2029002130916.png)ajax是前端完成的,可通过ajax访问后台,然后通过后台返回的数据,展示到前端页面中。Ajax的使用流程:![在这里插入图片描述](https://img−/2029002140773.png)创建XMLHttpRequest对象:![在这里插入图片描述](https://img−/202900214841.png)![在这里插入图片描述](https://img−/2029002150989.png?x−oss−process=image/watermark,typeZmFuZ3poZW5naGVpdGk,shadow10,textaHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size16,colorFFFFFF,t70)在JS里,window是最顶级对象,它代表了一个窗体,表示浏览器的初始网页的时候会自动创建一个window对象。IE5IE6版本以上的浏览器的XMLHttpRequest是window的子对象,所以如果是高版本的浏览器可以直接创建这个XMLHttpRequest,但是IE6.0,5.5都是没有的,它们是使用window.ActiveXObject替代,所以这里需要添加一个判断。发送Ajax请求:![在这里插入图片描述](https://img−/202900292.png)![在这里插入图片描述](https://img−/2029002204371.png)open()方法参数:第一个是请求方式,第二个是请求的URL,第三个是同步(false)或异步(true).处理服务器响应:![在这里插入图片描述](https://img−/2029002211714.png)![在这里插入图片描述](https://img−/2029002214900.png)![在这里插入图片描述](https://img−/2029002217541.png?x−oss−process=image/watermark,typeZmFuZ3poZW5naGVpdGk,shadow10,textaHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size16,colorFFFFFF,t70)![在这里插入图片描述](https://img−/2029002221449.png)innerHTML是js的一个属性,设置元素内部的HTML。使用ajax进行前后台数据的交互,html进行静态界面的展示,而jsp文件,是动态网页,可以直接可以进行前后台数据的交互,可以不需使用ajax,所以这里使用html+ajax的方式进行数据的交互和展示。但是也可以使用jsp和ajax的使用。这就可以实现页面局部刷新了,页面完全无需重新加载,大大的提升了页面的效率及速度。在实际的开发中,都是可以的,具体根据要求做。在Servlet中要注意,如果前面是Ajax请求发送的话,就不用页面跳转,而是直接返回我们需要返回的数据,通常这种数据格式通过json来传去客户端。很少回传html。js中的JSON和Servlet里面的JSON有别。这个JSON是JavaScript内置对象,而Servlet中的JSON是FastJson提供给java的一个对象。不加斜杠的参考路径是当前访问的路径;加上斜杠的参考路径是我们访问的根路径,加载文件是从根路径开始加载。js中在初始化变量时,如果不设置初始值,默认为undefined,在拼接时会将其加上。因此在初始化时要给其初始值,如:varhtml=“”;利用Ajax实现新闻列表。同步和异步的区别:同步状态:代码进入等待状态,响应不返回,程序不会继续向下执行,就是前面代码没执行完后面的代码就会一直等待。异步状态:程序不会处于阻塞状态,程序依旧向下执行,数据返回时,是通过触发onreadystatechange事件进行数据的获取和处理。通常Ajax设置为异步状态。使用了同步,xmlhttp.onereadystatechange=function()...,该事件失效..(将function()代码取出来放在send()后面就行了)。因为JavaScript本身是不支持多线程技术的,Ajax属于JavaScript范畴,因此Ajax是单线程的。在浏览器中发送请求是:1、在浏览器任务就被分成两种,一种是同步任务,一种是异步任务。同步任务:只有前一个任务执行完成后,才可执行下一个任务,在主线程中。异步任务:这个队列的所有任务都是不进入主线程执行,而是被浏览提供的线程执行。当执行完毕后就会产生一个回调函数,并且通知主线程,在主线程执行完当前所执行的任务后,就会调取最早通知自己的回调函数,使其进入主线程中执行,比如ajax请求,在主线程中呈现的就是请求结果。2、如上所述,浏览器中请求的执行顺序就是:(1)所有同步任务都在主线程上执行,形成一个执行栈(executioncontextstack)。(2)主线程之外,还存在一个"任务队列"(taskqueue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件(回调函数callback)。(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",查看里面有哪些事件,结束等待状态,进入执行栈,开始执行对应的异步任务。(4)最后主线程就是不断重复上面的第三步。如上所述就是−−>异步请求在浏览器中的执行过程,所以说异步请求都是在同步请求执行完成后,再去发送请求访问服务器,所以这些请求都是按照顺序来依次执行的,并不会出现"先处理了后台数据A,这时候异步读取后台数据A"这样的情况。Thread.sleep(5000)代表将当前的线程执行休眠,也就是现在页面发送过来的请求的这个线程。Thread是一个类,sleep是一个静态方法,可以通过Thread类名直接调用sleep方法,不用创建对象。同步是发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待的过程;异步是发送一个请求,不需要等待返回,随时可以再发送下一个请求,不需要等待。jQuery对Ajax的支持:1.jQuery对Ajax进行封装,提供了(this)是指当前事件产生的对象。 按下空格匹配元素的样式属性color为red。 ![在这里插入图片描述](https://img-/202900212268.png) 处理方法中的event参数不是一个固定参数名,可以写成其他名,但最好见名知意还是event好。 键盘按键分字符键,非字符键(功能键和特殊按键),keypress是用户摁下按键,并且产生一个字符时发生,所以退格键就只能触发onkeydown和onkeyup事件。 Ajax介绍: ![在这里插入图片描述](https://img-/2029002130916.png) ajax是前端完成的,可通过ajax访问后台,然后通过后台返回的数据,展示到前端页面中。 Ajax的使用流程: ![在这里插入图片描述](https://img-/2029002140773.png) 创建XMLHttpRequest对象: ![在这里插入图片描述](https://img-/202900214841.png) ![在这里插入图片描述](https://img-/2029002150989.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size_16,color_FFFFFF,t_70) 在JS里,window是最顶级对象,它代表了一个窗体,表示浏览器的初始网页的时候会自动创建一个window对象。IE5 IE6 版本以上的浏览器的XMLHttpRequest是window的子对象,所以如果是高版本的浏览器可以直接创建这个XMLHttpRequest,但是IE6.0,5.5都是没有的,它们是使用window.ActiveXObject替代,所以这里需要添加一个判断。 发送Ajax请求: ![在这里插入图片描述](https://img-/202900292.png) ![在这里插入图片描述](https://img-/2029002204371.png) open()方法参数:第一个是请求方式,第二个是请求的URL,第三个是同步(false)或异步(true). 处理服务器响应: ![在这里插入图片描述](https://img-/2029002211714.png) ![在这里插入图片描述](https://img-/2029002214900.png) ![在这里插入图片描述](https://img-/2029002217541.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-/2029002221449.png) innerHTML是js的一个属性,设置元素内部的HTML。 使用ajax进行前后台数据的交互,html进行静态界面的展示,而jsp文件,是动态网页,可以直接可以进行前后台数据的交互,可以不需使用ajax,所以这里使用html+ajax的方式进行数据的交互和展示。但是也可以使用jsp和ajax的使用。这就可以实现页面局部刷新了,页面完全无需重新加载,大大的提升了页面的效率及速度。在实际的开发中,都是可以的,具体根据要求做。 在Servlet中要注意,如果前面是Ajax请求发送的话,就不用页面跳转,而是直接返回我们需要返回的数据,通常这种数据格式通过json来传去客户端。很少回传html。 js中的JSON和Servlet里面的JSON有别。这个JSON是JavaScript内置对象,而Servlet中的JSON是FastJson提供给java的一个对象。 不加斜杠的参考路径是当前访问的路径;加上斜杠的参考路径是我们访问的根路径,加载文件是从根路径开始加载。 js中在初始化变量时,如果不设置初始值,默认为undefined,在拼接时会将其加上。因此在初始化时要给其初始值,如:var html=“”; 利用Ajax实现新闻列表。 同步和异步的区别: 同步状态:代码进入等待状态,响应不返回,程序不会继续向下执行,就是前面代码没执行完后面的代码就会一直等待。异步状态:程序不会处于阻塞状态,程序依旧向下执行,数据返回时,是通过触发onreadystatechange事件进行数据的获取和处理。通常Ajax设置为异步状态。使用了同步,xmlhttp.onereadystatechange=function(){...},该事件失效..(将function()代码取出来放在send()后面就行了)。 因为JavaScript本身是不支持多线程技术的,Ajax属于JavaScript范畴,因此Ajax是单线程的。 在浏览器中发送请求是:1、在浏览器任务就被分成两种,一种是同步任务,一种是异步任务。同步任务:只有前一个任务执行完成后,才可执行下一个任务,在主线程中。异步任务:这个队列的所有任务都是不进入主线程执行,而是被浏览提供的线程执行。当执行完毕后就会产生一个回调函数,并且通知主线程,在主线程执行完当前所执行的任务后,就会调取最早通知自己的回调函数,使其进入主线程中执行,比如ajax请求,在主线程中呈现的就是请求结果。2、如上所述,浏览器中请求的执行顺序就是:(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件(回调函数callback)。(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",查看里面有哪些事件,结束等待状态,进入执行栈,开始执行对应的异步任务。(4)最后主线程就是不断重复上面的第三步。 如上所述就是-->异步请求在浏览器中的执行过程,所以说异步请求都是在同步请求执行完成后,再去发送请求访问服务器,所以这些请求都是按照顺序来依次执行的,并不会出现"先处理了后台数据A,这时候异步读取后台数据A" 这样的情况。 Thread.sleep(5000)代表将当前的线程执行休眠,也就是现在页面发送过来的请求的这个线程。Thread是一个类,sleep是一个静态方法,可以通过Thread类名直接调用sleep方法,不用创建对象。 同步是发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待的过程;异步是发送一个请求,不需要等待返回,随时可以再发送下一个请求,不需要等待。 jQuery对Ajax的支持: 1.jQuery对Ajax进行封装,提供了(this)是指当前事件产生的对象。按下空格匹配元素的样式属性color为red。![在这里插入图片描述](https://img−/202900212268.png)处理方法中的event参数不是一个固定参数名,可以写成其他名,但最好见名知意还是event好。键盘按键分字符键,非字符键(功能键和特殊按键),keypress是用户摁下按键,并且产生一个字符时发生,所以退格键就只能触发onkeydown和onkeyup事件。Ajax介绍:![在这里插入图片描述](https://img−/2029002130916.png)ajax是前端完成的,可通过ajax访问后台,然后通过后台返回的数据,展示到前端页面中。Ajax的使用流程:![在这里插入图片描述](https://img−/2029002140773.png)创建XMLHttpRequest对象:![在这里插入图片描述](https://img−/202900214841.png)![在这里插入图片描述](https://img−/2029002150989.png?x−oss−process=image/watermark,typeZ​mFuZ3poZW5naGVpdGk,shadow1​0,texta​HR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size1​6,colorF​FFFFF,t7​0)在JS里,window是最顶级对象,它代表了一个窗体,表示浏览器的初始网页的时候会自动创建一个window对象。IE5IE6版本以上的浏览器的XMLHttpRequest是window的子对象,所以如果是高版本的浏览器可以直接创建这个XMLHttpRequest,但是IE6.0,5.5都是没有的,它们是使用window.ActiveXObject替代,所以这里需要添加一个判断。发送Ajax请求:![在这里插入图片描述](https://img−/202900292.png)![在这里插入图片描述](https://img−/2029002204371.png)open()方法参数:第一个是请求方式,第二个是请求的URL,第三个是同步(false)或异步(true).处理服务器响应:![在这里插入图片描述](https://img−/2029002211714.png)![在这里插入图片描述](https://img−/2029002214900.png)![在这里插入图片描述](https://img−/2029002217541.png?x−oss−process=image/watermark,typeZ​mFuZ3poZW5naGVpdGk,shadow1​0,texta​HR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzI2MTA3,size1​6,colorF​FFFFF,t7​0)![在这里插入图片描述](https://img−/2029002221449.png)innerHTML是js的一个属性,设置元素内部的HTML。使用ajax进行前后台数据的交互,html进行静态界面的展示,而jsp文件,是动态网页,可以直接可以进行前后台数据的交互,可以不需使用ajax,所以这里使用html+ajax的方式进行数据的交互和展示。但是也可以使用jsp和ajax的使用。这就可以实现页面局部刷新了,页面完全无需重新加载,大大的提升了页面的效率及速度。在实际的开发中,都是可以的,具体根据要求做。在Servlet中要注意,如果前面是Ajax请求发送的话,就不用页面跳转,而是直接返回我们需要返回的数据,通常这种数据格式通过json来传去客户端。很少回传html。js中的JSON和Servlet里面的JSON有别。这个JSON是JavaScript内置对象,而Servlet中的JSON是FastJson提供给java的一个对象。不加斜杠的参考路径是当前访问的路径;加上斜杠的参考路径是我们访问的根路径,加载文件是从根路径开始加载。js中在初始化变量时,如果不设置初始值,默认为undefined,在拼接时会将其加上。因此在初始化时要给其初始值,如:varhtml=“”;利用Ajax实现新闻列表。同步和异步的区别:同步状态:代码进入等待状态,响应不返回,程序不会继续向下执行,就是前面代码没执行完后面的代码就会一直等待。异步状态:程序不会处于阻塞状态,程序依旧向下执行,数据返回时,是通过触发onreadystatechange事件进行数据的获取和处理。通常Ajax设置为异步状态。使用了同步,xmlhttp.onereadystatechange=function()...,该事件失效..(将function()代码取出来放在send()后面就行了)。因为JavaScript本身是不支持多线程技术的,Ajax属于JavaScript范畴,因此Ajax是单线程的。在浏览器中发送请求是:1、在浏览器任务就被分成两种,一种是同步任务,一种是异步任务。同步任务:只有前一个任务执行完成后,才可执行下一个任务,在主线程中。异步任务:这个队列的所有任务都是不进入主线程执行,而是被浏览提供的线程执行。当执行完毕后就会产生一个回调函数,并且通知主线程,在主线程执行完当前所执行的任务后,就会调取最早通知自己的回调函数,使其进入主线程中执行,比如ajax请求,在主线程中呈现的就是请求结果。2、如上所述,浏览器中请求的执行顺序就是:(1)所有同步任务都在主线程上执行,形成一个执行栈(executioncontextstack)。(2)主线程之外,还存在一个"任务队列"(taskqueue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件(回调函数callback)。(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",查看里面有哪些事件,结束等待状态,进入执行栈,开始执行对应的异步任务。(4)最后主线程就是不断重复上面的第三步。如上所述就是−−>异步请求在浏览器中的执行过程,所以说异步请求都是在同步请求执行完成后,再去发送请求访问服务器,所以这些请求都是按照顺序来依次执行的,并不会出现"先处理了后台数据A,这时候异步读取后台数据A"这样的情况。Thread.sleep(5000)代表将当前的线程执行休眠,也就是现在页面发送过来的请求的这个线程。Thread是一个类,sleep是一个静态方法,可以通过Thread类名直接调用sleep方法,不用创建对象。同步是发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待的过程;异步是发送一个请求,不需要等待返回,随时可以再发送下一个请求,不需要等待。jQuery对Ajax的支持:1.jQuery对Ajax进行封装,提供了.ajax()方法。2.语法:$ajax(option)。

function(json)中的json表示把从服务器返回的json字符串存储到json对象中。然后JavaScript将json字符串解析为json对象,然后在function中执行调用等操作。ajax请求成功得到响应内容,js将得到的json字符串自动解析为json对象。JavaScript的语法与Java的语法格式有些不同,在JavaScript中,方法中的参数是形参,不需要定义,可以直接使用,而这里function中的json就是形参,可以作为一个变量在方法里直接使用。

$ 就是 jQuery 对象的引用,可以实现以 jQuery 对象为入口的操作。$(function() {…}) 是 jQuery 中的经典用法,等同于 $(document).ready(function() {…}),即在页面加载完成后才执行某个函数。

参数"error":function(xmlhttp,errorText){xmlhttp.status 错误状态码}

jQuery中的append()方法是追加,$("#container").append("<h1>"+title+"</h1>");JQuery append() 方法在被选元素的结尾(仍然在内部)插入指定内容。

向服务器传递的参数”data”有两种书写方式,一种是URL参数方式,一种是JSON格式,建议使用json方式书写,可读性、分割较好,同时是在发送请求时,参数却会转换URL参数方式在URL后面(get请求)/请求体中(post请求)。在后台获取data中的key值和value值,可直接通过request.getParameter(“t”);进行获取传过来的参数value值。而key值是我们自己设置的名字,用来获取value的,是无法被获取的。

ajax的本质就是在不刷新整体页面的情况下更新部分页面。

XMLHttpRequest、xmlhttp.responseText返回值 等内容都是是原生JS的书写方式;而JQuery是对原生JS的封装,所以在JQuery中就可以直接使用了。

实现二级联动菜单:

2.4.3 Java正则表达式

介绍正则表达式的语法规则,以及常见的校验规则。

什么是正则表达式:英文缩写regex。

应用:

正则表达式的分隔符可以有多种如:// {} ()等。

字符范围匹配:

/regex是开源中国提供的开源的正则表达式在线测试工具。

元字符:

注意:”.”是匹配任意单个字符(换行符除外),”.”只匹配特殊字符”.”。”-”可以进行原义匹配,所以不加\也是可以的。

X|Y是匹配 x 或 y,匹配的X或者Y的整个内容,也就是输入要匹配的字符串中要么匹配X(eg:0571),要么匹配Y(eg:4-\d\d\d\d\d\d\d\d)。[XY]则是匹配所包含的单个字符,表示字符串中要匹配X(eg:1),要么匹配Y(eg:4)。

\d匹配单个数字,d应该代表digitization n.数字化。\n 匹配单个换行符, n应该代表newline character换行符。\s匹配单个空格 ,s应该代表space n.空间。w是Word单词的缩写,\w匹配包括下划线的任何单词字符,等价于’[A-Za-z0-9_]’。

多次重复匹配:

1、正则表达式是用来检查一个字符串是否含有符合规则的子串。即只要字符串中有可以匹配到的就算找到,无论它在字符串中的哪个位置。2、如果正则表达式是^\d{3,4}-\d{7,8},规定了字符串的开始和字符串的结尾,规定了字符串的开始^和字符串的结尾,规定了字符串的开始和字符串的结尾,那么1234-123456789就不能匹配到了。

定位匹配:

^www.com中www表示必须以www开头,必须以com结尾。在进行全字匹配时添加上和中^www表示必须以www开头,必须以com结尾。 在进行全字匹配时添加上^和中www表示必须以www开头,必须以com结尾。在进行全字匹配时添加上和,因为^匹配输入字符串的开始位置。$匹配输入字符串的结束位置,这样可以保证在某些场景时,防止造成子串匹配的问题。

贪婪模式:

非贪婪模式:?要在描述数量的后边。

表达式分组:

小括号的优先级是最高的,也就是说用小括号括起来的内容会作为一个整体,然后再和其他内容组合。

正则表达式中字符集charset为UTF-8(Unicode)的中文字符编码的范围是\u4e00-\u9fa5,Unicode编码,是一种全世界语言都包括的一种编码。

(?:)表示非捕获分组,和捕获分组唯一的区别在于,非捕获分组匹配的值不会保存起来。加号(+)进行拼接。

字符串“fdgdgawwwrwoijjko”用正则表达式“w”匹配共找到16处匹配,用替换文本“88”的替换结果是:“88f88d88g88d88g88a8888r8888o88i88j88j88k88o88”。

JavaScript表单验证:

对表单姓名和身份证进行校验:

在JS中定义正则表达式对象只需要在/正则表达式/。

onsubmit是表单的提交事件,返回true表示成功提交(不写return true也会提交的),返回false不提交。

在JS中定义正则表达式对象只需要在“/”和“/”之间写正则表达式就可以返回一个正则表达式对象,正则表达式对象的test()方法可以校验数据是否符合表达式,返回true代表匹配成功,返回false代表匹配失败。

innerHTML 属性,设置或返回表格行的开始和结束标签之间的 HTML,意思就是innerHTML可以为元素对象插入内容。append()是js中的函数表示在被选元素的结尾插入指定内容。

Java中Web页面信息提取:

String字符串的拼接会产生一个新的字符串,而不是更新之前的字符串,这样每次拼接都会产生多余的String,尤其当多次拼接的时候非常浪费内存。而StringBulider则不会,每次拼接都是在原来的字符串上进行拼接。所以这里建议使用StringBulider而不要替换成String。StringBuilder是一个可变的字符序列。

FileInputStream 从文件系统中的某个文件中获得输入字节。InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。BufferedReader : 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。当关闭bufferedReader 后,底层会自动关闭fis和isr。这里无需手动关闭。eclipse是一个编译器,当编译器关闭时流不会自动关闭。

java中创建正则表达式的对象:Pattern p=pile("(正则表达式)");

匹配正则表达式:Matcher m = p.matcher(content);

当find()方法找到一个正则表达式成功匹配的字符串,可以通过group(0)得到该子串,group(1)得到该子串的第一个表达式分组,依此类推。再次查询时,之前对该方法的调用成功,并且匹配器此后没有重置,则从上一个匹配器未匹配的第一个字符开始。

2.4.4 过滤器

介绍过滤器的创建过程、生命周期和过滤器链等内容,及过滤器的应用场景。

内容:

过滤器-Filter:

过滤链:

开发过滤器三要素:

过滤器的生命周期:

初始化- Filter.init() //对当前过滤器进行初始化,执行时机tomcat启动后会自动创建Filter这个过滤器对象,一旦对象创建完,马上执行Filter.init()方法。提供服务-Filter.doilter(),当有请求进来时,会先执行Filter.doilter()方法。销毁- Filter.destroy()//执行时机应用(tomcat服务器)关闭或者重启时。

过滤器的特性:

唯一的过滤器对象在并发环境中采用”单例多线程”提供服务。单例:对象只有一个,多线程:一个项目可能会又多个人同时访问,就会出现多线程。虽然全局只有一个过滤器对象,但是如果是在并发环节中,每一个请求进来的时候,过滤器都会为其创建一个独立的线程来提供服务,线程和线程之间他们是彼此不受影响的,正是因为叫单例多线程的这么一种设计,既保证了过滤器不会因为频繁创建对象消耗系统资源,同时又采用多线程方式,有效提高了多用户在访问同一个过滤器时的执行速度。

请求转发的链接路径是不会被过滤器拦截,而重定向会被过滤器拦截。

过滤器两种开发方式:

1.过滤器的配置形式:

2.过滤器的注解形式:

配置与注解如何选择:

Tomcat是如何发现注解形式的过滤器并启动过滤器的?Servlet3.0版本之后,默认对注解有了支持。每次应用程序启动时,Tomcat会对项目内的所有.class字节码文件(java编译后的文件)进行扫描,当扫描到WebFilter注解时,则启用这个过滤器。同时存在配置形式和注解形式的过滤器时,会先执行配置形式过滤器。一般来说,整个项目只需要采用一种形式的过滤器,尽可能避免使用两种形式。

doFilter()的含义是调用过滤器链中的过滤器,过滤器链是将请求的内容,与过滤器链中的过滤内容一一匹配,匹配成功,filter(过滤器)在doFilter里做完自己的过滤逻辑,交给下一个过滤器···循环执行,过滤器走到链的末尾,filterChain执行收尾工作,过滤器执行完毕。

注解形式配置的过滤器适用于短平快的中小型项目,开发更加快速,但不便于修改,不便于统一配置,所以不适用于中大型项目。

开发字符集过滤器:

Web中文乱码的解决:

res.setContentType()指定 HTTP 响应的编码,同时指定了浏览器显示的编码。

ServletRequest接口:

oracle公司制定标准,第三方厂商提供具体实现(.jar包),eg:Apache的tomcat服务器提供的.jar包,如RequestFacade实现类是tomcat所特有。

过滤器的开发技巧:

过滤器参数化:过滤器参数初始化有两种方式:1.在web.xml中书写<init-param>标签。2.在过滤器类中写注解。

优化字符集过滤器:

基于注解的初始参数是在java文件中写的,如果java文件修改了,只有重新编译再上线才会生效。而基于web.xml文本的初始参数重新启动tomcat服务器就会生效不需要编译再上线。

url-pattern设置过滤范围:

url-pattern常用写法:

还可组合使用:/servlet/*.jsp表示过滤以/servlet/开头以.jsp结尾的匹配。

/映射的问题:

在web.xml中默认配置了<welcome-file-list></welcome-file-list>标签,则表示当路径映射为/时,会从上至下查找所访问的页面是否存在,然后将其映射。如果含有index.jsp文件,则在路径中输入/index.jsp和/效果是一致的,也可以将<welcome-file-list></welcome-file-list>标签这部分进行删除,会直接访问index.jsp/html。当没有默认文件时(index.jsp)就会跳转到映射地址中。

过滤器的映射地址设置为/,只对servlet生效 的意思是 :/ 只拦截后台的地址,不会拦截页面。也就是只拦截servlet,不拦截jsp/html。context root设置/,过滤器映射地址设置/,过滤器只对Servlet生效的意思是此过滤器只会拦截映射地址为/的Servlet类(一个项目映射地址为/的Servlet类只有一个),而不能拦截其他映射地址为/xxServlet的Servlet类。

Web.xml中配置过滤器filter对多个URL的作用范围。

过滤器类中配置过滤器filter多个URL的作用范围。

getClass().getSimpleName()跟getName()区别:this.getClass()获取当前类的字节码对象。this.getClass().getSimpleName(),获取当前类的的简写名。this.getName()获取当前类的字节码对象名。

在servlet-2.3中,Filter会过滤一切请求,到了servlet-2.4之后Filter默认下只拦截外部提交的请求,不会过滤内部转发的求情。

过滤链:

过滤链开发注意事项:

调用chain.doFiiter()将请求向后传递。过滤器的执行顺序以XML配置中的<filter-mapping>从上到下执行。

浏览器发送的请求中,与过滤器链中的过滤内容匹配成功的请求只有通过过滤链doFilter()中的chain.doFilter(),传递到达Servlet、html和jsp等,然后再通过doFilter()中的chain.doFilter()逆序传递最后响应给浏览器,若过滤链某个过滤类没有执行doFilter()中的chain.doFilter(),那么匹配成功的请求不会到达Servlet、html和jsp等,直接通过之前的doFilter()中的chain.doFilter()逆序执行过滤链,最后响应给浏览器(没有执行Servlet、html和jsp等代码)。若在过滤链中某个过滤类的doFilter()中的chain.doFilter()还有其他请求,那么这些请求会冲突导致异常,注销doFilter()中的chain.doFilter()方法,其他请求会到达Servlet、html和jsp等,然后逆序执行过滤链最后响应浏览器。

过滤链是双向的,响应返回时按逆序通过过滤链。一个来回实际上是以“doFilter”分割的,doFilter其实就是调用过滤器链的下一个过滤器,这个调用是个递归调用,执行完最后匹配的Filter或者Servlet之后,会再返回到调用处。过滤链执行顺序为FilterA>FilterB>FilterC这种配置顺序下:FilterA(doFilter之前的部分)执行->doFilter调用FilterB(同样执行doFilter之前的部分)->调用FilterC->Hello World!->返回执行FilterC(doFilter之后的部分)->返回FilterB(doFilter之后的部分)->返回FilterA之后的部分。

Chain.doFilter()常用做“防火墙功能”的函数体,比如一个应用不希望海外IP访问,判断条件为是否是本地IP,是才执行Chain.doFilter()调用过滤链的下一个过滤器,不是就不执行Chain.doFilter(),此时不会调用下一个过滤器,而是执行完Chain.doFilter()前面的代码后结束应用。

以注解型过滤器时,过滤器执行顺序按过滤器类名(不是注解中的filterName)的大小顺序(升序执行)进行,如:filterA filterZ filterV三个过滤器执行顺序为AVZ(不合理)类名有独特含义,不能特地为了过滤链的执行顺序而修改过滤器类名。所以建议项目中最好写配置型过滤器。

项目中过滤器的应用场景:

多端设备自动匹配:

request.getHeader(“user-agent”)来获取访问页面的设备类型。

在新建项目中Context root(上下文路径) 设置为“/”,大型项目中,每个tomcat对应一个应用,当大型项目需要多个应用时,可安装多个tomcat并设置不同端口,通过请求不同的端口来访问不同的应用。这样做的话每个应用都有独立的tomcat进程,一个应用崩溃了不会影响其他的应用。

2.4.5 监听器

介绍监听器,常见应用场景及在Java Web中实现监听器。

内容:

监听器-Listener:

三种监听对象:

过滤器与监听器的区别:

开发监听器三要素:

监听器的配置方式:1.在web.xml当中配置

<listener><listener-class>com.imooc.listener.FirstListener</listener-class></listener>

2.注解方式:@WebListener。优先选择配置型监听器。

stop是停止服务器的服务,Terminate是非正常关闭,是代表中断。

六种常用监听接口:

内置对象监听接口:

属性监听接口:

一个请求tomcat时 处理的过程:Web应用启动时,ServletContext对象被初始化,启动成功后访问地址时,一个HttpServletRequest对象被创建。同时因为是一个新的浏览器窗口发来的请求,所以tomcat会创建一个session对象,网页处理完成后HttpServletRequest被销毁。2. 第二次请求(当浏览器窗口刷新后),session 并没有被创建,因为session id 已存在,通过确认session id 的存在,所以并不会创建新的session。此时,HttpServletRequest 又经历了一次创建与销毁的过程。3. 当浏览器关闭重新打开一个新的窗口,再次访问这个网址,这时一个新的session被创建。原因是新的浏览器并没有包含任何session id,所以由新的浏览器窗口向tomcat发送请求后,会为其创建一个对应的session,原有的sessionid并不会消失,原因是sessionid的凭证不存在了,30分钟后自然过期,或程序代码人为关闭。当(servlet)关闭应用时,ServletContext 才被销毁。

session对象的销毁:1、手动调用销毁 2、30分过期自动销毁。3.手动调用session的invalidate方法session.invalidate();也可以销毁session。Tomcat关闭后,seesion的处理:Tomcat下发布的web应用程序,如果涉及session的操作,在Tomcat关闭或undeploy的时候,将会在work 目录下相应的路径下创建 SESSION.ser 文件存储该webapp的 session 数据进行序列化,当服务器再次启动的时候会加载此文件,进行反序列化,重新恢复之前的session们。即在 session有效时间内重启Tomcat 或re-deploy,将会加载该文件中的数据,恢复用户原来的 session运行环境。所以关闭Tomcat后seesion并不会马上被销毁,仍然还是要等待seesion的有效期过去。

属性监听接口:

实际开发对属性监听接口的实现类非常少(可能会监听属性的新增)。

监听器的应用场景:

请求流量分析:

请求流量分析统计的统计功能实现:1、利用全局对象监听器在启动应用创建全局对象时往对象添加两个属性,分别是初始化的时间记录表和初始化的次数统计表集合,两者一一对应(存放时间的位置在次数统计表中对应的是该时间的请求次数)。2、利用请求对象监听器在请求到来时对全局对象里的两个属性进行修改。

关于当前时间如何转化为指定格式的String字符串:

1、获取当前时间:Date date=new Date();2、设置时间格式:SimpleDateFormat sdf=new SimpleDateFormat(“HH:mm”);//知识点回顾:JSP中利用JSTL里的fmt格式化标签库对时间进行格式化的方式?3、利用sdf里的format()方法表示将当前时间袼式化为指定的格式。返回String对象: String time=sdf.format(date);

List list=new List();list.indexOf()返回的是查询的值在列表中的位置,若无返回-1;list.get(index)返回的是列表中该位置对应的值;list.set(index,value):将list中index位置的值修改为value。

监听器类中contextInitialized()方法表示在web应用启动时,将最原始的数据进行初始化,getServletContext()方法的作用就是获取ServletContext的上下文对象。ServletContext对象是程序全局变量,对每个用户每个页面都有效。存放在ServletContext对象中。它的存活时间是最长的,只要服务器没有停下,它们就一直可以使用。所以即便是关掉当前窗口甚至是在另一个浏览器中访问,得到的结果是相同的。

1、request对象就是用来保存请求信息的。在第一次发送请求到服务器的时候,无论是匹配到了Servlet还是Filter等,在doFilter或Service之类的方法执行之前,request就被初始化了。如果在服务器进行转发,那么request不会丢失,使用的是同一个。当进行重定向,或者浏览器重新发起请求的时候,request就不再是同一个了。2、session是在第一次使用session时初始化的。在第一次使用request.getSession的时候,就被初始化了。

一般将script放在body之后,避免长时间执行script脚本而延迟阻塞。有一些页面的效果的实现,是需要预先动态的加载一些js脚本,所以这些脚本应该放在<body>之前。

入门百度Echarts组件:

百度ECharts世界上最强大的图表js组件:.里面有许多实例和教程。

需要引入的js文件是dist目录下的echarts.min.js文件(echarts.js的最小压缩文件)。

setInterval(必需:要调用的函数或要执行的代码串,必需:周期性执行或调用函数或要执行的代码串之间的时间间隔,以毫秒计) 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。而第一个参数,以字符串形式传入,是语法。

toString()是返回对象的文本表示形式。(String)是强转。如果某个对象不能用另一个对象表示时就会报错。

监听器常见用途:1) 统计在线人数,利用HttpSessionLisener;2) 加载初始化信息:利用ServletContextListener;3) 统计网站访问量,实现访问监控:利用RequestListener;

过滤器常用应用场景:统一编码,统一用户认证,屏蔽非法文字,进行响应数据压缩等操作,便于代码重用,不必每个servlet中还要进行相应的操作。

静态数据预处理:

对于长期不会改变的静态数据,可以创建一个全局监听对象,服务器启动后在全局监听对象创建初始化时从数据库中提取数据写入全局属性中,然后直接在页面获取需要的全局属性,可以避免每次加载页面时都要从数据库获取数据。

2.4.6 FreeMarker

介绍模板引擎FreeMarker的基本使用以及与Servlet进行整合

内容:

Freemarker模板引擎:

主流模板引擎:

Freemarker:

JSP与Freemarker:

脚本是一种批处理文件的延伸,是一种纯文本保存的程序,简单地说就是一条条的文字命令,这些文字命令是可以看到的(如可以用记事本打开查看、编辑),脚本程序在执行时,是由系统的一个解释器,将其一条条的翻译成机器可识别的指令,并按程序顺序执行。

Freemarker安装:。

FreeMarker的执行步骤:1、加载模板。Configuration config=new Configurarion(Configuration.VERSION_2_3_28(FreeMarker的版本号));(创建核心配置对象)//设置加载目录

config.setClassForTemplateLoading(FreemarkerSample1.class,"")(在类FreemarkerSample1所在的包中加载指定文件,“”代表当前包)//得到模板对象Template t=config.getTemplate("sample1.ftl");2、创建数据。Map<String,Object> data=new HashMap<>();data.put("site","百度");

data.put(“url”,“”);3、产生输出。t.process(data,new OutputStreamWriter(System.out)(将System.out从字节流转换为字符流));

config.setClassForTemplateLoading(FreemarkerSample1.class,"");的第二个参数的含义是表示加载当前包下的模板,而config.getTemplate()方法表示要加载的模板名称。所以想要加载FreemarkerSample1.class的所在包中的sample2.ftl模板,只需要修改如下代码:config.getTemplate(“sample2.ftl”);就可以获取sample2.ftl的模板对象了。如果模板与加载的类不在一个包下,第二个参数可以直接编写所在路径就可以了。例如:sample2.ftl在com.imooc.freemarker.entity包下,则第二个参数的路径就需要编写为,/com/imooc/freemarker/entity/的路径。具体如下:

FTL取值:

freemarker中<#-- -->注释。

对象里map的提取computer.info["cpu"]。因为通过{computer.info["cpu"]}。 因为通过computer.info["cpu"]。因为通过{对象名.属性名}这种方式来获取属性名,所以get方法是必须的,set方法对于获取属性没有影响,但set方法一般也会写上。

分支判断:1.if分支判断。2.switch分支判断。

</#if>作为结束<#if 条件>的闭合。

??判断对象是否为空,true不为空,false为空。

字符串的比较用“==”,不是equals()方法。

使用大于号时要加上用括号。

list迭代列表:

<#list students(被迭代的集合) as(关键字) stu(迭代变量)><li>${stu_index(获取当前循环的索引值,从0开始)}-${stu.name}</li>

list迭代Map:

LinkedHashMap可以保证数据按存放的顺序进行提取,Map map=new LinkedHashMap();。

内建函数:

是freemarker中文参考手册。

比如对于1.5,上取整(ceiling)的意思是取大于他的最小整数,也就是2,下取整(floor)是 取小于他的最大整数,也就是1。

freemarkter的数据、放在List、实体类、json中都是可以的,但在实际的开发中通常后台返回给前端的数据都是key,value的形式,因此实例类以及Map形式应用很广泛一点。

freemarker三目运算符<#-- 利用?string实现三目运算符的操作 -->${(words?index_of("blood") != -1) ? string("包含敏感词汇","不包含敏感词汇")}。//sort_by函数(升序排列)返回新集合<#list computers?sort_by("price") as c>${c.sn}-${c.price}</#list>//对集合进行逆序<#list computers?sort_by("price")?reverse as c>${c.sn}-${c.price}</#list>//对集合进行逆序<#list computers?reverse('price') as c>${c.sn}-${c.price}</#list>。常用内置函数:${name?cap_first} ${brand?upper_case}${brand?length} ${words?replace("blood","*****")}${words?index_of("blood")}<#-- 四舍五入 -->${n?round}<#-- 向下取整 -->${n?floor}<#-- 向上取整 -->${n?ceiling}。公司共有${computers?size}台电脑,第一台:${computers?first.model},最后一台:${computers?last.model}。

Freemarker内建函数写法与java类似,属性名?函数(小括号可有可无)>对象.方法(),Freemarker中函数名由多个单词组成时用”_”分开且都是小写,java中方法名由多个单词组成时第一个单词小写后面每个单词首字母大写。

Freemarker与Servlet整合:

Freemarker对Java Web有良好的支持,下载的freemarker.jar包中有一个Servlet是FreemarkerServlet(在freemarker中路径为:freemarker.ext.servlet.FreemarkerServlet),将Freemarker与Servlet整合只需在web.xml文件中配置FreemarkerServlet的映射地址以及.ftl文件在项目中的路径(一般设置为/WEB-INF/ftl)即可。

按住Ctrl,鼠标移到路径名,路径名下方出现链接横线说明路径名书写正确。

<init-param>是配置初始化参数。TemplatePath是模板路径的意思,是Freemarker的中的设置路径的参数名称,不能修改,这个是固定的参数,直接使用就可以。

ftl文件放在WEB-INF目录下,WEB-INF下的文件是不能通过浏览器直接访问的。web.xml中配置之后,对于ftl结尾的请求,全都会交给FreemarkerServlet处理,它会将TemplatePath模板路径追加到当前这个以ftl结尾的请求路径前,如request.getRequestDispatcher("/employee.ftl").forward(request, response);会正常的去Web根目录的/WEB-INF/ftl下寻找employee.ftl。所以url中不用写这些文件夹。

init-param和context-param区别?相同:init-param与context-param都是在web.xml里以键值对形式定义的变量。不同:init-param是定义在servlet标签里,而context-param是定义在web-app标签里。

配置freemarker后,可以将保存数据的集合或列表放在context、session、request的属性里,在 . ftl文件里使用时直接写集合或列表的属性名,freemarker引擎作用域对象的作用域从小到大寻找要迭代的列表。

jsp等文件和eclipse工具设置的字符集:在jsp中头部中,pageEncoding是jsp文件本身的编码。contentType的charset是指服务器发送给客户端时的内容编码。在<head>标签中,<meta>标签charset属性用于规定HTML文档的字符编码。

eclipse的Text file encoding是Eclipse工作空间编码。这些都需要设置为统一的编码,如都是UTF-8或GBK编码。

复制完全限定名:选中工程上的java文件,右键选择Copy Qualified Name,复制的是带斜杠的项目工程路径地址。打开java文件,在java文件中,将光标放到类名上,右键选择Copy Qualified Name,复制的是用"."分隔的包名+类名。

2.4.7 项目:登录注册

登录注册功能的编写,包括头像上传和验证码等内容。

内容:

知识点:

MVC设计模式:

Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

Java Web开发历程:

本项目开发流程(MVC的流程):

用户注册功能的实现:

用户信息的保存:用户列表的初始化,1.建立用户java类,将所需属性封装起来。2.创建一个监听器,设置全局对象初始化用于保存数据:(1)创建list集合,用于放置用户信息。(2)将list集合保存在ServletContext域中。

servlet(controller)1. 接收数据。2. 封装数据(调用javaBean)。3. 处理数据(调用javaBean)。4. 作出响应(显示处理结果)。

用户头像的上传:

文件上传需要post提交,GET请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,并且提交的数据是有限的,因为它是在地址栏中拼接参数,受浏览器地址栏长度的限制。POST的安全性要比GET的安全性高。POST提交的数据内容更多,也就是没有大小长度限制。

文件上传原理:

没有设置enctype属性的情况:

设置了enctype属性的情况:

以下两个包主要是用来进行文件上传的:

在jsp页面写jstl和el表达式:

生成验证码使用的jar:

commons-fileupload和commons-io的jar包可以参考Apache官网进行下载。kaptcha的jar包,可以参考官网地址:/p/kaptcha/ 但国外的网站,国内访问不到。

前端一些模板参考:/sinat_40770656/article/details/95058150。

如果from表单没有设置enctype=“multipart/form-data"这个属性,那么上传的只是文件的名字,没有文件的内容,加上属性后才能上传文件中的内容(firefox浏览器能解析看到,chrome浏览器不解析看不到)。

smartUpload是第一代jsp+javabean的设计模式经常使用的,一般嵌入到jsp中。

在form表单添加enctype=“multipart/form-data"属性后,表单中的信息都会以二进制的方式传递。因此通过request是没有办法获取其它参数的,而FileUpload正好可以解决这一问题。

虚拟路径的意思是,并不是磁盘中的真实路径。getRealPath(”/upload”)是获取这个项目的根目录下这个upload文件夹在磁盘中的真实路径。项目发布后,WebContent下就是项目的根路径。项目发布后是没有WebContent这个文件夹的,代表的就是根路径。

从输入流中读取数据并写入文件。byte[] b=new byte[1024];定义一个byte数组。is.read(b)是从输入流中读取数据存放到b数组中。while((len=is.read(b))!=-1)判断是否读取完成,如果没有,则循环读取。os.write(b, 0, len)从0开始,从b字节数组写入len字节到该文件输出流。read每次读取完成后会清空数组。len = is.read(b)做到了边读取,边把这次读取的字节赋值给len,前几次循环时数组被写满,所以len=1024,当读到流的末尾时,数组没有被写满,len就是剩余的字节数。

idea支持项目的热部署,也就是在Tomcat启动后,改变jsp或html等信息后,不需要再次进行服务器的关闭重启,直接update即可,更加适合开发。

如果使用的是IDEA需要手动在upload中先添加一个文件。项目部署到tomcat后到编译后到target文件夹中可以看到对应到图片文件。idea的文件不能为空,空文件夹不会被编译。

String path=request.getServletContext().getRealPath("/upload");和String path=getServletContext().getRealPath("/upload");是一样的。request.getServletContext()是调用HttpServletRequest类中的getServletContext方法。Servlet类继承了HttpServlet,HttpServlet继承了GenericServlet,所以在Servlet类中直接调用了getServletContext方法。

解决上传文件重名的问题:

UUID.randomUUID().toString()生成随机字符串。

写为静态方法可以在使用时,直接通过类名就可以直接调用,不需要进行实例化,例如:

用户登录功能的实现:

用户信息的查询:

更改包的显示方式:

登录servlet类。

header.jsp显示用户登录成功/失败的页面。

验证码的生成和校验:

验证码生成的流程:

Graphics类提供了基本的几何图形绘制方法,主要有:画线段、画矩形、画圆、画带颜色的图形、画椭圆、画圆弧、画多边形、画字符串等

在绘制任意图形之前都需要直接指定绘制时使用的颜色。

Graphics2D类ratate()方法旋转图片,第一个参数是弧度。rotate()方法使用的特点,第二次进行旋转时,会在之前旋转的基础上进行。

Graphics类中的drawLine(int x1, int y1, int x2, int y2) 方法是用来画线的。两点确定一条直线,而在坐标中由横(X)、纵坐标(y)确定一个点,这四参数实际就是确定两个点,是要画的直线的起始点横纵坐标和终点的横纵坐标。X1,Y1是确定直线的起始点,即横坐标为x1,纵坐标为y1的点。同理x2,y2确定直线的终点。例A(x1,y1) B(x2,y2) 就可以画出直线AB了。

验证码的代码实现:在servlet中生成验证码,通过BufferedImage 在内存中生成一张图片,new BufferedImage(宽,高,类型(RGB));绘制背景色和边框,需要一个画笔通过BufferedImage.getGraphics() 获得一个画笔对象Graphics. 通过setColor(Color);设置背景色然后进行填充fillReact(0,0,width,height);

ImageIO.writer(xx,“jpg”,response.getOutputStream()); xx是图片对象,response.getOutputStream()是在浏览器上显示的输出流。

在CheckImgServlet中ImageIO.write(); write方法的含义是以响应对象的输出流将内存中的图片以jpg的形式输出。此时它输出的是一个具体的图片,所以在页面中通过访问${pageContext.request.contextPath }/CheckImgServlet就可以得到这个图片。

fillRect方法是填充指定的矩形。drawRect方法是绘制指定矩形的边框。

实现点击刷新图片(验证码),就是从后台重新获取图片,在点击的时候浏览器会优先获取缓存中的数据,所以要让每次的url不一样才能实现点击刷新,只需要在url后面加一个参数,可以是以时间戳为参数。new Date().getTime();(这是js里面获得系统当前时间的毫秒值)。

return是表示结束方法的运行,使用return就不会再执行下面的语句了。这里的转发只是对请求的转发,按照代码的执行循序,如果没有return,代码会根据顺序依次向下执行(因为request和response是对应的,直到代码块执行完或执行到response),而当验证码不正确时,用户名密码的判断不需要再执行,所以可以直接添加return结束当前方法。

假设不加code2null,如果code2为null,直接执行后面的code2.equalsIgnoreCase(code1),由于code2为null,所以会报空指针异常。所以前面添加了code2null,这里利用了||的短路性质,如果code2==null则整个表达式为true,因此不会在执行后面的code2.equalsIgnoreCase(code1)了。也就避免了空指针问题。

Kaptcha验证码的使用(第三方验证码生成的工具):

Web.xml文件中配置Kaptcha第三方工具包提供的KaptchaServlet的映射地址、参数等。

Kaptcha验证码配置参数的介绍:Conifg.class–>Comstans.class中选择需要配置的参数,在Web.xml中进行参数的配置。.class文件需要关联Kaptcha的source.jar才能看代码。

Kaptcha会在初始化时读取web.xml中配置的初始化参数,所以可以通过配置参数改变this.sessionKeyValue的值。

Kaptcha验证码的校验:

输错验证码后不让输入的用户名和密码重新输入,用局部刷新,通过form表单提交无法实现。需要使用ajax。思路如下:ajax发送请求给后台。后台进行验证,然后向前台返回信息。ajax根据返回的信息。决定做什么操作。如果验证失败。调用changeImg(),改变验证码。如果验证成功跳转至登录成功页面。

kaptcha的session的key也可以在web.xml的init-param中来修改。不修改就直接使用默认的com.google.code.kaptcha.Contans.KAPTCHA_SESSION_KEY。

项目中一共有如下几个包:

1、com.imooc.domain的作用是存放项目的实体类。2、com.imooc.service的作用是存放项目的业务层代码的接口。3、com.imooc.service.impl的作用是存放项目的业务层代码的实现类。

4、com.imooc.utils的作用是存放项目的工具类。5、com.imooc.web.listener的作用是存放项目的监听器的类。6、com.imooc.web.servlet的作用是存放项目的Servlet类,用于后台控制的一些类就放在这里。

HttpServletRequest是一个接口,在该接口中有getContextPath方法,EL表达式${pageContext.request.contextPath}在底层实质上是调用对应get方法完成的。

“/”是绝对路径,在web项目中绝对路径是相对于http://localhost:8080,所以前面会自动拼接 http://localhost:8080。

在form表单中,写一个οnsubmit="return validate form()用于检验用户名密码重置密码的函数。

疫情实时动态,里面的大量数据的需获取:数据获取一般有三种方式:1 , 手动录入,一般用于比较少的数据 。2 , 从网站爬取或者是授权可用的。3 , 调用第三方接口,一般会专门有供应商做好接口提供给其他网站使用。实时更新一般都是定时发送请求更新数据。

接口定义的是一系列规范,是java多态的一种形式,在开发过程中可以快速分离工作内容,增强了程序的层次感。同一个接口可以有多个实现类,实现类的不同,其要执行的操作也不同。一个类可以实现多个接口,如Service接口中可以定义service层中常用的增删改查方法,其他service实现类都可以实现该接口,避免了代码冗余。

jar包是类的归档文件,里面可以封装类库,也就是把很多类封装到jar包中,其他类可以使用。而war包是Java web程序打的包。关于jar包的使用,此案例已经使用jar包了,比如支持文件上传的jar包,里面有很多的类。项目使用jar包的时候,只要引入jar包,然后使用import语句导入类就可以了,不用新建项目。Java web程序除了tomcat去部署,也可以通过其他服务器去部署,比如WebLogic,不过tomcat比较常用。java web的开发主要通过eclipse和IntelliJ IDEA等开发工具完成,一个一个文件建立是比较原始的方式,开发效率低。

Java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。框架又叫做开发中的半成品,它不能提供整个WEB应用程序的所有东西,但是有了框架,我们就可以集中精力进行业务逻辑的开发而不用去关心它的技术实现以及一些辅助的业务逻辑。说白了Java框架就是封装好方便程序员操作的类,使项目的开发更简单,维护起来也更容易。

pageContext对象 这个对象代表页面上下文,该对象主要用于访问JSP之间的共享数据。使用pageContext可以访问page、request、session、application范围的变量。

jsp九大内置对象和EL表达式十一大内置对象:

并且pageContext:可以获取JSP九大内置对象,相当于使用该对象调用getxxx()方法,因此${pageContext.request.contextPath }的意思就是:pageContext.getRequest().getContextPath ();el表达式${pageContext.request.contextPath }中的pageContext是el内置对象,代表该页面的pageContext对象,不是jsp内置对象,pageContext开头el表达式有快捷提示,其他的el表达式就没有,是因为EL表达式其他内置对象如pageScope,requestScope是从作用域中获取值的,由于不知道往这些作用域中放的键是什么,所以就没有提示。1,requestScope是获取request域属性值,而pageContext对象可以获取JSP九大内置对象。2,pageContext.request获取的是HttpServletRequest对象,而requestScope只是一个概念, 表示request的作用域,是EL的内置对象之一,只有放了才能取,所以通过requestScope获取的数据,必须在之前已经通过set方法set进了request才能获取。3,${pageContext.request.contextPath}意思就是取出部署的应用程序名或者是当前的项目名称。requestScope只是用于获取request范围内的属性值,所以${requestScope.contextPath}获取不到上下文路径。Servlet类请求转发到HTML/JSP页面,1.如果是ajax请求返回的可以直接在js中使用属性名.属性值 这样的方式。2.如果是直接返回的页面。通常使用jstl+el表达式处理。或者直接使用<%%>java 代码块。3.直接返回页面不会使用js操作。使用 2 中的方法操作数据很简单。java.util包提供了java中的基础工具类。包括基本的集合框架等基础类以及通用的工具类。java.awt是一个软件包,包含用于创建用户界面和绘制图形图像的所有分类。javaweb的开发中几乎不会用到这个包。

java中常用的包有很多,此处列举一些:

小结及FAQ:

Java过滤器常用场景。其中三个选项课程中都有提到,权限访问控制,压缩响应信息,字符编码处理为过滤器的常用场景。<%@ taglib uri="/jsp/jstl/core" prefix="c"%>,prefix属性的值是可以改变的,可用c、d、e等,只不过我们一般习惯用c表示。JSTL常用标签的认识。与Java中的for循环对应的是<c:forEach>标签,jstl中没有<c:for>标签;<c:if>与Java的if语句是对应的,<c:when>对应的是switch语句中的case语句。

初始化参数的获取和设置:在初始化方法中应该是先获取初识化参数,即使用getInitParameter方法,随后是设置属性setAttribute方法,在销毁方法中应该是获取属性而非初始化参数了,即使用getAttribute方法。

Servlet将后台数据对象object,回写给dataType是json的Ajax。Servlet回写数据时的核心代码:json=JSON.toJSONString(object);:输出的数据需要转换为JSON。response.setContentType(“text/html;charset=UTF-8”);:在回写时需要设置写回的数据的输出格式。以防中文乱码问题。response.getWriter().println(json);:需要从Response中获取输出流,将需要输出的数据输出。

task2.4.7图书系统管理问题:

①为了便于web.xml中登录过滤器对Servlet过滤(映射地址书写/servlet/*),给所有Servlet的映射地址如loginServlet改为/servlet/login后,Servlet处理请求响应转发到jsp,发现所有jsp文件路径都隐性在/servlet目录下,因此所有jsp页面对资源的引用和地址的跳转的相对路径写法都需要通过…/跳到上级目\n录,如css引用,js引用,图片引用,超链接等,为什么?明明工程文件目录结构就不需要跳到上级目录

答:这里不是用的工程文件目录,而是发布后中的文件目录。例如如果访问路径是localhot:8080/servlet/addCategory,而css,js文件等是在locahost:8080/目录下,这时如果想正确访问,应该使用…/返回上一级目录。

这里建议使用绝对路径加载css,js等,在路径前加上${pageContext.request.contextPath }。

②Context root bug :eclipse开发环境下设置应用context root为/,过滤器映射地址为/,eclipse版本 -03 (4.15.0),tomcat8.5,jdk1.8.0_231。具体问题:

context root设置为/,过滤器设置/,问题1:项目启动后,为什么ContextListener监听器contextInitialized()方法会执行两次?方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())第一次打印contextPath:,第二次打印contextPath:“项目名(eg:test)”。问题2:项目启动后浏览器没有请求,为什么过滤器中的doFilter(…)方法会执行一次?问题3:过滤器只对Servlet生效是只会拦截映射地址为/的Servlet类(一个项目映射地址为/的Servlet类只有一个)还是拦截其他所有映射地址为/xxServlet的Servlet类?

问题1原因;jdk、tomcat等运行环境和各种版本等开发环境问题,正常开发环境在项目启动后ContextListener监听器contextInitialized()方法只会执行一次,所以方法中的syso(sce.getServletContext().getContextPath())只会输出打印一次正确的contextPath。问题2原因:eclipse开发工具原因,idea开发工具不会出现此问题。问题3原因:从知识点上context root设置/,过滤器映射地址设置/,过滤器只对Servlet生效的意思是此过滤器只会拦截映射地址为/的Servlet类(一个项目映射地址为/的Servlet类只有一个),而不能拦截其他映射地址为/xxServlet的Servlet类?

如果使用eclipse应该经常遇到问题2吧,是实际开发中eclipse应用很少吗?都采用idea等其他开发工具?

Tomcat 启动两次的问题(ServletContextListener的contextInitialized被执行两次的问题):相关博客回答/shaokai132333/article/details/53328258。

它的解释是放到Tomcat的webapps中的Web应用被启动了两次,自己理解这个启动两次是针对项目的context root设置/,在项目发布到tomcat后,会执行一次项目,然后为了达到在浏览器url不输入项目名就访问项目的目的,会再访问在Tomcat的server.xml文件中的Context标签中的docBase属性值,一般就是项目的绝对路径,将这个项目的绝对路径作为根(访问ip可直接访问该应用),path属性是context root设置的context path上下文路径。web应用执行两次这样好像就解释了问题1和问题2,对于问题1:contextInitialized()方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())执行两次,tomcat服务器启动后,web应用第一次启动,contextInitialized()方法中syso(“contextPath:”+sce.getServletContext().getContextPath())打印的contextPath为空;为了访问ip可直接访问该应用根据tomcat的server.xml配置就将web应用名做为根再次启动web应用,web应用第二次启动,syso打印contextPath为项目名了。对于问题2:因为web应用启动两次,第二次将webapps中的web应用名做为根再次启动web应用会被过滤器拦截,所以doFilter()在项目启动后执行一次。

部署到webapps的项目出现上述问题可能的两种原因是:第一种原因:部署到webapps的项目的contextPath不会被改变,始终是项目名作为根路径,所以当更改项目的contextPath不为/项目名时,为将这个项目名作为根(访问ip可直接访问该应用),tomcat服务器中会有两个内容相同而url不同(一个含/或/其他用户命名的名,另一个含/项目名)项目,所以会生成两个ServletContext对象(所以ContextListener监听器contextInitialized()方法会执行两次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())第一次打印contextPath:,第二次打印contextPath:“项目名(eg:test)”。),为将这个项目名作为根(访问ip可直接访问该应用),第二次url含/项目名的应用部署相当于访问第一次应用部署的url(所以只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。)。第二种原因:部署到webapps的项目的contextPath不会被改变,始终是项目名作为根路径,所以当更改项目的contextPath不为/项目名时,为将这个项目名作为根(访问ip可直接访问该应用),tomcat服务器中会有两个内容相同而url不同(一个含/或/其他用户命名的名,另一个含/项目名)项目,所以会生成两个ServletContext对象(所以ContextListener监听器contextInitialized()方法会执行两次?方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())第一次打印contextPath:,第二次打印contextPath:“项目名(eg:test)”。),由于eclipse开发工具的bug导致只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。

部署到webapps同级的其他目录:当把tomcat 的deploy path改为与webapps同级的其他目录后,出现ContextListener监听器contextInitialized()方法执行一次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())打印context root设置的值,浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。出现上述问题可能的两种原因:第一种原因:部署到与webapps同级的其他目录的项目的contextPath会被改变,所以当更改项目的contextPath不为/项目名时,为将这个项目名作为根(访问ip可直接访问该应用),tomcat服务器中会有两个内容相同并且url相同(都是context root设置值)项目,所以只会生成一个ServletContext对象(所以ContextListener监听器contextInitialized()方法只会执行一次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())打印context root设置值。),为将这个项目名作为根(访问ip可直接访问该应用),第二次应用部署相当于访问第一次应用部署的url(所以只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。)。第二种原因:部署到与webapps同级的其他目录的项目contextPath会被改变,所以当更改项目的contextPath是否为/项目名时,tomcat服务器中只有一个项目,所以只会生成一个ServletContext对象(所以ContextListener监听器contextInitialized()方法只会执行一次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())打印context root设置值。),由于eclipse开发工具的bug导致只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。

总结最可能的原因:部署到webapps的项目的contextPath不会被改变,始终是项目名作为根路径,所以当更改项目的contextPath不为/项目名时,为将这个项目名作为根(访问ip可直接访问该应用),tomcat服务器中会有两个内容相同而url不同(一个含/或/其他用户命名的名,另一个含/项目名)项目,所以会生成两个ServletContext对象(所以ContextListener监听器contextInitialized()方法会执行两次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())第一次打印contextPath:,第二次打印contextPath:“项目名(eg:test)”。),由于eclipse开发工具的bug导致只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。部署到与webapps同级的其他目录的项目contextPath会被改变,所以当更改项目的contextPath是否为/项目名时,tomcat服务器中只有一个项目,所以只会生成一个ServletContext对象(所以ContextListener监听器contextInitialized()方法只会执行一次,方法中的syso(“contextPath:”+sce.getServletContext().getContextPath())打印context root设置值。),由于eclipse开发工具的bug导致只有一个项目的服务器启动后浏览器没有请求,过滤器中的doFilter(…)方法会执行一次。

问题2最可能的原因:在启动项目后,就会访问localhost:8080/项目的context root,一般是项目名/,所以启动项目后请求被映射地址为/的LoginFilter过滤器拦截就会直接执行LoginFilter的doFilter()方法。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。