九万字的JavaWeb学习记录,从入门到入坟,更近一步
文章目录
- 推荐
- 推荐后学
- HTML
- html基本格式
- 常用文本标签:
- 特殊字符:
- 超链接标签:
- 列表标签
- 图像标签
- 表格标签
- 框架标签
- 表单标签
- 其他标签
- CSS
- 基本格式
- 基础语法
- 高级语法
- JS
- 基本格式
- 变量
- 关系运算
- 逻辑运算
- 数组
- 对象
- 函数
- 事件
- DOM模型
- **getElementById()**进行用户合法验证。
- 拓展
- jQuery
- 什么是jQuery?
- 入门
- jQuery核心函数
- 与DOM
- 本质
- 选择器
- 基础选择器
- 层级选择器
- 基本过滤选择器
- 内容选择器
- 属性过滤选择器
- 表单过滤选择器
- 元素筛选(遍历)
- 属性操作
- 练习
- 增删改
- 增
- 删除
- 改
- css基本操作
- 基本动画
- jQuery事件和原生事件的区别
- 其他常用事件
- 事件冒泡
- 事件对象
- 练习:图片跟随
- XML
- JavaWeb
- Tomcat
- 启动
- 停止
- 修改端口号
- 部署web
- 访问方式
- IDEA与Tomcat
- 创建动态web工程
- Tomcat运行web工程
- Servlet
- 手动实现Servlet
- 生命周期
- 获取请求方式
- 常用实现Servlet
- javax.servlet.http.HttpServlet
- 更加快捷方式
- Servlet继承体系
- ServletConfig 类
- ServletContext接口
- 作用
- 举例
- Htpp协议
- 请求
- 响应
- HttpServletRequest类
- 作用
- 常用方法
- 举例
- 获取参数
- 请求转发
- base标签
- / 的意义
- HttpServletResponse类
- 请求重定向
- jsp(快要过时)
- 重要参数
- 脚本
- 声明脚本
- 表达式脚本
- 代码脚本
- 注释
- 九大内置对象
- 四大域对象
- out输出和response.getWriter
- 原理
- out特点
- 常用标签
- 静态包含*
- 动态包含
- 请求转发
- 监听器
- EL表达式
- 基本
- 复杂
- 基本运算
- 十一大隐含变量(对象)
- 四大域数据
- pageContext
- 其他隐含变量
- JSTL
- 文件上传*
- 上传
- 解析
- 文件下载
- 举例
- 注意
- cookie
- session
- Filter过滤器
- 基本使用
- 完整使用
- 生命周期
- FilterConfig类
- FilterChain
- 匹配路径
- ThreadLocal
- JSON
- 基本入门
- 常用方法
- 与javaBean之间的转换
- JSON与List之间的转换
- jsonToMap
- AJAX
- 原生JS
- 特点
- JqueryAJAX
- AJAX请求
- GET请求
- POST请求
- getJSON
- 表单序列化
- i18n国际化(了解)
- 概念
- 三要素
- 入门
- jsp页面国际化
推荐
推荐后学
五万字的Spring5学习笔记,带你熟悉运用Spring5
HTML
- 超文本标记语言。
- 通过Web标准让不同浏览器的不同渲染引擎可以渲染出相同效果。
html基本格式
<!--标题头,最新的html5文件规范-->
<!DOCTYPE html>
<html lang="ch"><!--语言规定,可定义为ch,自然不写ch也行。-->
<head><meta charset="UTF-8"><!--规定字符集,才可以识别为中文--><title>Title</title>
</head>
<body></body>
</html>
<!--1.html为根标签,/+标签名为结束标签2.head为头部标签,封装css和js3.body为身体标签,使用css和js,同时也可以封装js,但是一般在head封装js4.以上统称为文件标签。
-->
常用文本标签:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!--换行标签-->我爱中国!<br>我爱中国!<!-- 我爱中国!--><!-- 我爱中国--><!--标题标签,h1-h6--><h1>1级标题</h1><h2>2级标题</h2><h3>3级标题</h3><h4>4级标题</h4><h5>5级标题</h5><h6>6级标题</h6><h7>7级标题</h7><!--没有七级标题--><!--段落标签p,使得可以在网页中显示不同的段落--><p>abcdefghijklmnopqrstuvwxyz</p><p>abcdefghijklmnopqrstuvwxyz</p>
<!-- hr自闭合标签,产生水平线--><hr/>
<!-- b字体加粗-->
<!-- i斜体标签-->
<!--font字体标签被淘汰,--></body>
</html>
注意:这些标签里,都可以加入html属性渲染颜色,但是不建议使用,一般都用css样式渲染颜色。
下面给出属性的定义方法:
color属性:
- color=“颜色英文/rgb((0-255),(0-255),(0-255))/#值1值2值3(00-FF)”
width=“数值/数值%”,数值单位默认为px像素。
align:居中,放置在窗体右,窗体左。
- center
- left
- right
特殊字符:
由于我们在网页显示内容需要各种标签,所以当我们使用想在网页上显示特殊字符的时候,需要特定的符号实体。
<!--这是一个特殊字符--><br><br> <!-- 网页输出<br>,因为这是一个标签,所以单纯写出网页会识别为换行,所以要用特殊字符--> <!--空格为 -->
关于特殊字符的使用,请查阅w3cshool相关文档。
超链接标签:
<!--a标签为超链接标签1.href设置超链接地址2.target进行当前跳转方式1._self表示当前页面2._blank表示新页面3.没有默认新页面
-->
<a href="https://www.baidu.com/" target="_self" >百度</a>
列表标签
无序列表
无序列表是一个项目的列表,此列项目使用粗体圆点(典型的小黑圆圈)进行标记。
无序列表始于
- 标签。每个列表项始于
- 。
有序列表
同样,有序列表也是一列项目,列表项目使用数字进行标记。
有序列表始于
- 标签。每个列表项始于
- 标签。
自定义列表不仅仅是一列项目,而是项目及其注释的组合。
自定义列表以
- 标签开始。每个自定义列表项以 开始。每个自定义列表项的定义以
- 开始。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--无序unordered list列表-->
<ul><li>a</li><li>b</li><li>c</li>
</ul>
<!--有序ordered list列表-->
<ol><li>a</li><li>b</li><li>c</li>
</ol>
<!--自定义列表-->
<dl><dt>Coffee</dt><dd>Black hot drink</dd><dt>Milk</dt><dd>White cold drink</dd>
</dl></body>
</html>
- 不同浏览器的兼容性不同,所以当你在标签里定义属性的时候,可能显示不出你想要的效果,例如
- ,这属性本来的意思是将列表的前置符号去掉,但是在一些比如谷歌,ie是不支持这样的写法的。
图像标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--img src="url" alt width height border /-->
<!--单标签 文件目录 错误警告 宽度设置 高度设置 边框设置 单标签结束-->
<!--在Java中,相对路径:当前工程下绝对路径:盘符\\路径-->
<!--在html里,相对路径:./当前目录下 ../上级目录绝对路径:http://地址//目录//文件名-->
<img src="../img/b.jpg" alt="找不到图片" width="200" height="200" border="1" />
</body>
</html>
表格标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--
table为表格标签,在标签里可添加width,height,border,align等属性
tr代表每一行,每一行里有n个单元格,td表示单元格,默认元素不居中,th也表示为单元格,默认元素居中
--><table width="100" border="1"><tr><td>a</td><td>a</td><td>a</td></tr><tr><td>b</td><td>b</td><td>b</td></tr><tr><td>c</td><td>c</td><td>c</td></tr>
</table>
</body>
</html>
下面演示表格的跨行跨列
<table width="100" border="1" cellspacing="10"><tr> <!-- colspan横跨两列,需要把第一行的第三列去掉--> <!-- rowspan横跨两行,需要把第三行的第一列去掉 --> <!-- 两个一起写,横跨两行两列,需要去掉第一行第三列,第二行地2,3列,第三行不删除任何--><td colspan="2" rowspan="2">a</td><td>a</td></tr><tr><td>b</td></tr><tr><td>c</td><td>c</td><td>c</td></tr> </table>
- 注意:跨行跨列非常简单,只需要每次写入跨行后,运行看看哪一个单元格突出便删去便可以。
框架标签
- 用于页面内镶嵌框架。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--双标签,通过name属性设置名字,其他标签可通过target属性访问该标签-->
<iframe name="a"></iframe>
<ol><li><a href="htmlListTest.html" target="a">点击这里可到达htmlListTest.html窗口</a></li>
</ol>
</body>
</html>
表单标签
- 用于注册和登录页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!-- input最重要元素,可请求用户输入,格式有多种(type=“ 1/2/3...”)1.text 定义常规文本输入。value可以设置默认值2.radio 定义单选按钮输入(选择多个选择之一)checked=“checked”为默认选中name属性可进行分组,每一组默认选中只有一个3.submit 定义提交按钮(提交表单4.password密码选框,浏览器显示不出输入值maxlength最大输入数量5.checkbox 复选框6.reset重置为默认值7.button为按钮value为按钮文字8.file为文件上传9.hidden为隐藏属性 为开发者参与发送给服务器的客户消息--><!-- select下拉列表选框option列表中每一项selected为默认选中--><!-- textarea多行文本输入rows设置行数cols行字符个数文本内容为默认值--><!-- button按钮按钮内容为默认值--><form>用户名称:<input type="text"/><br/>用户密码:<input type="password" maxlength="5" /><br/>
<!-- 以下可设置多个数据进行只能选其一-->性别:<input type="radio" name="sex"/>男<input type="radio" name="sex">女
<!-- 年龄默认20岁--><br/>年龄:<input value="20"/>
<!-- 国籍为下拉列表,默认为中国--><br/>国籍:<select><option>请选择国籍</option><option selected>中国</option><option>美国</option><option>小日本</option><option>英国</option></select><br/>
<!-- 兴趣爱好,设置行高喝行字符数,并显示默认值-->兴趣爱好:<textarea rows="20" cols="20">这是默认值</textarea>
<!-- 上传文件--><br/>上传文件:<input type="file"/><br/>
<!-- 重置按钮--><button type="reset">重置</button><br/><input type="reset" value="重置" />
<!-- 提交--><br/><input type="submit" value="提交"/>
</form>
</body>
</html>
- 运行上面这段程序就会知道,这样的表单是没有规则的,但我们可以运用表格去让他居中,并有规则。
<form><table align="center"><tr><td>用户名称:</td><td><input type="text"/></td></tr><tr><td>性别:</td><td><input type="radio" name="sex"/>男<input type="radio" name="sex"/>女</td></tr><tr><td>国籍:</td><td><select><option>请选择国籍</option><option selected>中国</option><option>美国</option><option>小日本</option><option>英国</option></select></td></tr></table>
</form>
说到这里,我们不得不说到form标签里的属性,既然我们得到了数据,又该如何发送给服务器去处理呢?
- Action属性:可设置发送给哪个服务器端。
- Method属性:可以指定以哪种方式发送。
- get属性,用于发送少量信息。
- 不安全,在浏览器地址栏可以查看获得的表单信息。
- 有长度限制。
- pos属性,用于发送大量数据,
- 长度限制较高。
- 安全性强。
- get属性,用于发送少量信息。
<form action="https://www.baidu.com/s?ie=UTF-8&wd=baidu" method="get">
其他标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div>默认在一行</div>
<div>默认在一行</div>
<span>默认不在一行</span>
<span>默认不在一行</span>
<p>默认上方空一行和在一行</p>
<p>默认上方空一行和在一行</p>
</body>
</html>
CSS
基本格式
选择器
{属性1:值;属性2:值;
}
/*css注释*/
基础语法
css样式通过style属性设置,定义在标签中,但这样定义难以让后续进行维护,工作量繁杂。称作内联样式。
<p style="color: sienna; margin-left: 20px"> This is a paragraph </p>
所以,css一般使用选择器+{}的形式放在head标签中,而body标签进行使用,这样大大提高了工作效率。称作内部样式表。
<head> <style type="text/css">hr {color: sienna;}p {margin-left: 20px;}body {background-image: url("images/back40.gif");}</style> </head>
为了更加加大工作效率,我们也可以将css样式定义为一个文件,在head标签中link该文件使用。称作外部样式表。
<head> <link rel="stylesheet" type="text/css" href="mystyle.css" /> </head>
/*css文件,只能是css代码*/ hr {color: sienna;} p {margin-left: 20px;} body {background-image: url("images/back40.gif");}
高级语法
选择器分组:当不同标签要使用相同样式的时候。
h1,h2,h3,h4,h5,h6 {color: green;}
样式继承:
在css中,会产生样式继承,即父类的样式会被子类继承。
比如有一个body标签样式
body {color: red;}
那么可以镶嵌在body标签中的样式诸如 p, td, ul, ol, ul, li, dl, dt,和 dd等都会继承这个样式。要想不被继承,只能另外起一个样式。
值得注意的是,在一些浏览器版本中,是不支持继承的,所以,如果要让这些浏览器支持继承效果,可进行冗杂操作。
body {color: red;}p, td, ul, ol, li, dl, dt, dd {color: red;}
派生选择器:请看下列例子。
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style type="text/css">table b{color:green;}</style> </head> <body> <!--我们定义一个表格--> <table border="1"><tr><td><b>1</b></td><td>2</td><td>3</td></tr><tr><td>4</td><td>5</td><td>6</td></tr> </table> </body> </html>
- 上面的样式中,我们要定义列表中b标签的样式,无需另外起一个选择器,只需li派生而出就可以了。
id选择器
#id1 {color:red;}
<p id="id1">这个段落是红色。</p>
id继承选择器:
#sidebar p {font-style: italic;}
这里将指定p段落为此样式,同样的,这个sidebar id选择器还未废除,可以重新指定其他样式。
#sidebar h2 {font-size: 1em;}
类选择器:
.center {text-align: center}
上面样式中,所以标签里有class="center"属性的,都居中。
类继承选择器:
同id继承选择器一样,不过新增一个继承写法。
td.fancy {color: #f60;}
<td class="fancy">
属性选择器:
<!DOCTYPE html> <html> <head> <style>a[target] {background-color: yellow; }</style> </head> <body><h1>CSS [attribute] 选择器</h1><p>带有 target 属性的链接获得颜色背景:target可以替换成target="_blank"指定那个选择为此样式</p><a href="https://www.w3school.com">w3school.com.cn</a> <a href="http://www.disney.com" target="_blank">disney.com</a> <a href="http://www.wikipedia.org" target="_top">wikipedia.org</a></body> </html>
指定属性选择器:
[attribute~=“value”] 选择器选取属性值包含指定词的元素。
[attribute|=“value”] 选择器用于选取指定属性以指定值开头的元素。
- 值必须是完整或单独的单词,比如 class=“top” 或者后跟连字符的,比如 class=“top-text”。
[attribute^=“value”] 选择器用于选取指定属性以指定值开头的元素。
- 值不必是完整单词!
[attribute$=“value”] 选择器用于选取指定属性以指定值结尾的元素。
下例选取 class 属性以 “test” 结尾的所有元素:
**提示:**值不必是完整单词!
[attribute*=“value”] 选择器选取属性值包含指定词的元素。
下例选取 class 属性包含 “te” 的所有元素:
**提示:**值不必是完整单词!
若需为不带 class 或 id 的表单设置样式,属性选择器会很有用
input[type="text"] {width: 150px;display: block;margin-bottom: 10px;background-color: yellow; }input[type="button"] {width: 120px;margin-left: 35px;display: block; }
JS
基本格式
在head标签或body标签中,采用script标签实现js。
为了实现代码复用,也可以另起一个文件专门编写js代码,此文件夹里只能出现js代码。
使用该文件时:
<script type="text/js" src="jsName.js"></script>
变量
这里与Java做对比,左Java,右js。
int number; string string ; 对象类型 object;boolean boolean ;
另外,js新增一个函数类型,与Java函数相似。
js里还有一些与Java一般的特殊值。
- undefined 没有定义
- null 空
- NAN 非number
js是一种若类型语言,所以定义变量只用var便可。
var i=100; var j="abc";
关系运算
- == 表示等于,只是字面的等于,比如123,和“123”若用==是true
- ===表示类型和值是否等于,123和“123” 为false。
逻辑运算
这里的逻辑运算与c类似,所有非空或非0的变量在js里都为true,其余为false,这里与java是不一样的。
且运算&&:
- 在js里,当全为真,返回最后一个值。
- 当有假的存在,返回第一个为假的值。
||或运算:
- js里,全为假,返回最后一个为假的值。
- 有一个为真,返回第一个为真的值。
当&&或||运算有了结果后,后面的运算不再执行,出现短路现象。
var i=10; var j=11; var z=20; alert(i||j||z);//这里只执行i||j alert(i&&j||z);//这里只执行i&&j,因为i&&j永远是true,所以后面无论是啥都不用执行,这式子就是true //但是如果前面的式子不能决定整个式子的值,那么要接着运行。
数组
var 数组=[] 长度由添加最后一个元素决定。
var cars=new Array();//利用其构造器赋值也行。 cars[0]="Audi"; cars[1]="BMW"; cars[2]="Volvo";
var cars=["Audi","BMW","Volvo"];
对象
var person={firstname:"Bill", lastname:"Gates", id:5566
var person = {firstName: "Bill",lastName : "Gates",id : 678,fullName : function() {return this.firstName + " " + this.lastName;} };
var person=new Object(); person.firstname="Bill"; person.lastname="Gates"; person.age=56; person.eyecolor="blue";
var myObject=new Object(); myObject.name="hyb"; myObject.age=20; myObject.myFunction=function(){alert(this.name+this.age); } alert(myObject.name); myObject.myFunction();
访问对象:对象名.访问变量。
对象名[“访问变量”]。
函数
function 函数名([变量1],[变量2]...)//注意:变量可以没有,有就一定不要强调变量类型
{
这里是要执行的代码
[return 变量] //返回值可以不要,要就一定要强调返回哪个变量。
}
var 函数名=function(若干变量){若干代码
}
myfunction();调用
以上都是强调在script中的,包括调用。
在body中,常用以下调用方式
<button onclick="myFunction('Harry Potter','Wizard')">点击这里</button> <button onclick="myFunction('Bob','Builder')">点击这里</button>
js中函数不允许函数重载,但不会报错,只是会完全覆盖掉原来的函数。
在js中,有如同java一样的可变参数(arguments),该参数是默认存在的,如下
var myfunction=function(){for(var i=0;i<arguments.length;i++){alert("这是隐形参数数组的第"+i+"值:"+arguments[i]);} } myfunction(1,2,3,4,5);
在js中,若果出现都是数值计算的函数里传入了一个字符型,那么尝尝需要用typeof关键字来辨认数值类型,
事件
电脑设备与页面进行交互的方式。
常用的事件有:
onload 加载完成事件,常用于js代码初始化。
onclick 单击事件
onblur 失去焦点事件,常用于输入框在失去焦点后,其内容是否合法的操作。
onchange 内容发生改变事件,常用于下拉列表和输入框内容发生改变后的操作。
onsubmit 表单提交事件,常用于在表单提交前验证数据正确等操作。
onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数。
onmousedown, onmouseup 以及 onclick 构成了鼠标点击事件的所有部分。首先当点击鼠标按钮时,会触发 onmousedown 事件,当释放鼠标按钮时,会触发 onmouseup 事件,最后,当完成鼠标点击时,会触发 onclick 事件。
使用事件之前,得学会事件注册(绑定),事件注册又分为静态注册和动态注册
就是要告诉浏览器在进行事件响应的时候要执行哪些代码。
静态注册:通过html标签属性直接注册。
动态注册:通过js代码获取标签的dom对象,然后通过dom对象.事件名=function(){}这种形式赋予事件响应后的代码,叫动态注册。
- 获取标签对象。
- 标签对象.对象名=function(){}
注册onload事件
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">//静态注册onload事件var myFunction=function(){alert("静态注册onload事件");}//动态注册onload事件,下面是固定写法,注册谁都一样,window.onload不变window.onload=function(){alert("动态注册onload事件");}</script> </head> <!--<body onload="myFunction()"> 你也可以直接在onload里写入代码--> <body> </body> </html>
注册onclick事件
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">//静态注册onclick事件var staticOnclick=function(){alert("静态注册onclick事件");}//动态注册onclick事件window.onload=function(){//1.获取标签对象//document为当前html页面//get获取//Element为元素,即标签//By 通过什么//Id为标签idvar obj=document.getElementById("id1");//返回一个对象//2.通过标签对象.事件名=function(){}obj.onclick=function(){alert("动态注册onclick事件");}}</script> </head> <body> <button onclick="staticOnclick()">静态注册</button> <button id="id1">动态注册</button> </body> </html>
onblur 失去焦点事件注册
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">//静态注册onblur事件var static=function(){alert("静态注册onclick事件");}//动态注册onclick事件window.onload=function(){//1.获取标签对象//document为当前html页面//get获取//Element为元素,即标签//By 通过什么//Id为标签idvar obj=document.getElementById("id1");//返回一个对象//2.通过标签对象.事件名=function(){}obj.onblur=function(){alert("动态注册onblur事件");}}</script> </head> <body> 账号:<input type="text" onblur="static()"/> 密码:<input type="text" id="id1"/> </body> </html>
onsubmit 表单提交事件
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">//静态注册onclick事件var static=function(){alert("出现错误,提交不成功!");return false;}//动态注册onclick事件window.onload=function(){//1.获取标签对象//document为当前html页面//get获取//Element为元素,即标签//By 通过什么//Id为标签idvar obj=document.getElementById("id1");//返回一个对象//2.通过标签对象.事件名=function(){}obj.onsubmit=function(){alert("动态提交失败--,不允许提交!");return false;}}</script> </head> <body> <!--<form action="https://www.baidu.com/" onsubmit="return static()">--> <!--<!– onsubmit不能放在button里,这是判断整个表单全部信息是否合理的请求–>--> <!-- <button type="submit">静态按钮</button>--> <!--</form>--> <!--<form action="https://www.baidu.com/" id="id1">--> <!--<!– 同样的,id也不能放在button里,道理一样–>--> <!-- <button type="submit">动态按钮</button>--> <!--</form>--> <form action="https://www.baidu.com/" onsubmit="return static()" id="id1"><button type="submit">静态按钮</button><button type="submit">动态按钮</button> </form> <!--以上两个form不能合并为一个,也就是一个form里不能同时出现两个提交按钮,若是出现,动态会将静态的覆盖掉。--> </body> </html>
DOM模型
在数据结构里,有一种结构叫树。
在java里,万物皆对象,甚至一个类都是对象,这个类里,有若干个属性,或者说元素。
类比:在网页中,一个html标签构成了一张网页,html里又包含了head标签和body标签,这两个标签里又分别包含了若干个标签,这万千的标签构成了一张网页。
所以,不如将html标签比如一个大类,也可以说对象,这个对象里包含了两个子对象head和body,这两个子对象又包含若干个子对象,p,h,form标签等,而且我们会发现,这些标签都是有规律的,大体一定要放在哪个位置,这也构成了一棵树。
所以,在HTML里,我们将各个标签按层次划分,成为DOM模型。
如图:https://www.w3school.com.cn/i/ct_htmltree.gif
为访问这些节点,我们提供了js,称为DOM方法,通过js,我们可以访问任何的节点信息。
常用的DOM方法有:
getElementById() 返回带有指定 ID 的元素。 getElementsByClassName() 返回包含带有指定类名的所有元素的节点列表。 getElementsByTagName() 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 getElementsByName 返回包含带有对应name属性的标签集合 appendChild() 把新的子节点添加到指定节点。 removeChild() 删除子节点。 replaceChild() 替换子节点。 insertBefore() 在指定的子节点前面插入新的子节点。 createAttribute() 创建属性节点。 createElement() 创建元素节点。 createTextNode() 创建文本节点。 getAttribute() 返回指定的属性值。 setAttribute() 把指定属性设置或修改为指定的值。 常见的DOM属性:
- innerHTML - 节点(元素)的内容,可以被赋值。
- innerText 节点文本值,也可以被赋值。
- parentNode - 节点(元素)的父节点
- childNodes - 节点(元素)的子节点
- attributes - 节点(元素)的属性节点
**getElementById()**进行用户合法验证。
- 在此之前,涉及正则表达式,不难,请去菜鸟教程查阅相关资料。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script>var static=function(){// ^\w$ \w代表包含字母数字下划线,^ $代表以\w开头和\w结尾var t=/^\w{5,15}$/;var s=document.getElementById("userName");var alt=document.getElementById("alert");if(t.test(s.value)){//记住这里一定要传他的value,因为s只是一个对象!alt.innerHTML="输入成功!";}else{alt.innerHTML="用户名必须是长度大于等于5小于等于15的字母数字或下划线!";}}</script>
</head>
<body>
<!--这里我们规定用户名必须是长度大于5小于15,且一定得是字母和数字或下划线组成-->
用户名:<input type="text" id="userName" onblur="static()"/>
<span style="color:red" id="alert"></span>
</body>
</html>
以上方法的优先级(简略),getId>getName>get(Class/Tag)Name。
并且一定要在页面加载的时候才能写入这些方法,所以这些方法只能封装在动态注册或静态注册里。
拓展
- 关于DOM的练习可进行下面的拓展,创建,添加,查询,删除。
jQuery
什么是jQuery?
- 是辅助js开发的一个类库,就如java里的类库。
- 核心思想:简化js操作。
入门
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="jquery-3.5.1.js"></script>//一定要另外导入,不能在下面的script导入<script type="text/javascript">window.onload=function(){//var s=document.getElementById("id1");//alert(s.value);$(function(){//获得指定id的对象,一般起$+字母的名字。var $s=$("#id1");$s.click(function(){alert("这是jQuery一个单击事件!");});});}</script>
</head>
<body><button id="id1">请点击</button>
</body>
</html
提出问题:
$是什么? 函数
click是什么?jQuery库里的一个单击函数。
如何引入jQuery?从官网上下载,直接放在本工程下任何文件夹,放入的文件一定得是js文件。注意导入的时候明确路径。
jQuery核心函数
- $为库中的核心函数,具有强大的功能。
- 页面加载完成,自动调用。
- 若要在jQuery创建标签,直接将标签的正常写法按照字符串拼接的方式生成便可。再利用apppend或者appendTo给body就可以了。
与DOM
- 只要通过JQuery调用,包装的,都是jQuery对象,包括jQuery包装的DOM对象。
- DOM和jQuery只能使用各自的属性和方法。
- 但是jQuery和DOM可以互相转换,当我们得到了jQuery时,可以用其核心函数$获得DOM对象,上面入门例子里var s=s=s=("#id1")就是一个例子,这个对象就是jQuery对象,由DOM对象转化而来,要想转换回去,只要在后面引用数组下标就可以了,var s=s=s=("#id1")[0]。为什么可以?这就涉及到jQuery的本质问题。
本质
- 既然jQuery可以获取一个个DOM对象,即一个个标签,所以在Jquery里,这些也被称作数组元素。
- 即jQuery的本质也是一个数组,装的都是一个个DOM对象。
选择器
基础选择器
选择器 | 实例 | 选取 |
---|---|---|
* | $("*") | 所有元素 |
#id | $("#lastname") | id=“lastname” 的元素 |
.class | $(".intro") | 所有 class=“intro” 的元素 |
element | $(“p”) |
所有
元素 |
.class.class | $(".intro.demo") | 所有 class=“intro” 且 class=“demo” 的元素 |
组合选择器 | $("#id1,div,p") | 所有id=id1,标签为div,p的元素 |
层级选择器
祖先 空格 后代 | $(“form input”) | 查找表单中,所有的后代标签input |
---|---|---|
祖先 > 后代 | $(“form input”) | 查找表单中,所有的直接子标签(元素),子的子不能被查找。 |
祖先 + 后代 | $(“label input”) | 查找label后,所有的input元素,假如label标签在form元素里的话,只能查form元素里的标签。 |
祖先 ~ 后代 | $(“form input”) | 查找表单后,所有的input元素。 |
基本过滤选择器
:first | $(“p:first”) |
第一个
元素 |
---|---|---|
:last | $(“p:last”) |
最后一个
元素 |
:even | $(“tr:even”) | 所有偶数 |
:odd | $(“tr:odd”) | 所有奇数 |
:eq(index) | $(“ul li:eq(3)”) | 列表中的第四个元素(index 从 0 开始) |
:gt(no) | $(“ul li:gt(3)”) | 列出 index 大于 3 的元素 |
:lt(no) | $(“ul li:lt(3)”) | 列出 index 小于 3 的元素 |
:not(selector) | $(“input:not(:empty)”) | 所有不为空的 input 元素 |
元素 元素
内容选择器
:contains(text) | $(":contains(‘W3School’)") | 包含指定字符串的所有元素 |
---|---|---|
:empty | $(":empty") | 无子(元素)节点的所有元素 |
:parent | $(“div:parent”) | 返回含有标签或内容的div标签 |
:hidden | $(“p:hidden”) |
所有隐藏的
元素 |
:visible | $(“table:visible”) | 所有可见的表格 |
:has | $(“div:has§”) | 返回含有p标签的div标签 |
属性过滤选择器
标签 [attribute]/[attribute](下似) | $(“div[href]”) $("[href]") | 所有带有href属性的div,所有带有 href 属性的元素(标签) |
---|---|---|
[attribute=value] | $("[href=’#’]") | 所有 href 属性的值等于 “#” 的元素 |
[attribute!=value] | $("[href!=’#’]") | 所有 href 属性的值不等于 “#” 的元素,或者没有此元素 |
[attribute$=value] | ("[href("[href("[href=’.jpg’]") | 所有 href 属性的值包含以 “.jpg” 结尾的元素 |
[attribute^=value] | $("[id^=‘u’]") | 所有id属性以u开头的元素 |
[attribute*=value] | $("[id*=‘m’]") | 所有id属性包含m内容的元素 |
组合 | 若干条件组合 | 所有若干条件的元素 |
表单过滤选择器
:input | $(":input") | 所有 元素 |
---|---|---|
:text | $(":text") | 所有 type=“text” 的 元素 |
:password | $(":password") | 所有 type=“password” 的 元素 |
:radio | $(":radio") | 所有 type=“radio” 的 元素 |
:checkbox | $(":checkbox") | 所有 type=“checkbox” 的 元素 |
:submit | $(":submit") | 所有 type=“submit” 的 元素 |
:reset | $(":reset") | 所有 type=“reset” 的 元素 |
:button | $(":button") | 所有 type=“button” 的 元素 |
:image | $(":image") | 所有 type=“image” 的 元素 |
:file | $(":file") | 所有 type=“file” 的 元素 |
:enabled | $(":enabled") | 所有激活的 input 元素 |
---|---|---|
:disabled | $(":disabled") | 所有禁用的 input 元素 |
:selected | $(":selected") | 所有被选取的 input 元素 |
:checked | $(":checked") | 所有被选中的 input 元素 |
- 第二个表格里,enabled和disabled表示选框是否可以,加入到标签里,成为是否有用属性。
元素筛选(遍历)
- 前面提到选择器的时候,比如has()便是一个筛选函数。
- 下面给出常用的遍历函数,其余的请到w3cshool查阅相关文档
.find() | 获得当前匹配元素集合中每个元素的后代,由选择器进行筛选。 |
---|---|
.first() | 将匹配元素集合缩减为集合中的第一个元素。 |
.has() | 将匹配元素集合缩减为包含特定元素的后代的集合。 |
.is() | 根据选择器检查当前匹配元素集合,如果存在至少一个匹配元素,则返回 true。 |
.last() | 将匹配元素集合缩减为集合中的最后一个元素。 |
.add() | 将元素添加到匹配元素的集合中。 |
.each() | 对 jQuery 对象进行迭代,为每个匹配元素执行函数。 |
.eq() | 将匹配元素集合缩减为位于指定索引的新元素。 |
.filter() | 将匹配元素集合缩减为匹配选择器或匹配函数返回值的新元素。 |
.not() | 与fileter相反,返回不匹配标准的所有元素。 |
属性操作
addClass() | 向匹配的元素添加指定的类名。 |
---|---|
attr() | 设置或返回匹配元素的属性和值。 |
hasClass() | 检查匹配的元素是否拥有指定的类。 |
html() | 设置(传参)或返回(不传参)匹配的元素集合中的 HTML 内容。 |
text() | 返回一个html内容,以文本形式,所以要设置html里的内容,不能传标签 |
removeAttr() | 从所有匹配的元素中移除指定的属性。 |
removeClass() | 从所有匹配的元素中删除全部或者指定的类。 |
toggleClass() | 从匹配的元素中添加或删除一个类。 |
val([value]) | 设置或返回(不传参数)匹配元素的值。 |
attr("…","…") | 设置或返回被选元素的属性值,不推荐操作checked,readOnly,selected,disabled(可以操作自定义设置的属性) |
prop("…","…") | 设置或返回被选元素的属性值,推荐操作attr不推荐操作的属性。 |
$("#btn1").click(function(){$("#test1").text("Hello world!");
});
$("#btn2").click(function(){$("#test2").html("<b>Hello world!</b>");
});
$("#btn3").click(function(){$("#test3").val("Dolly Duck");
});
练习
你最爱好的运动是?[选框]全选/全不选
足球[选框] ,篮球[选框] ,排球[选框],排球[选框]
全选[按钮] 全不选[按钮] 反选[按钮]
要求点击全选或全不选要全部选中或全不选中,并且要有总提示。反选是选中后反过来显示,也要求该有总提示也得有总提示。
要求点击总提示可进行选中或不选中。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="jquery-3.5.1.js"></script><script type="text/javascript">$(function(){//向全选框绑定单击事件$("#All").click(function(){$(":checkbox").prop("checked",true);});//全不选$("#No").click(function(){$(":checkbox").prop("checked",false);});//反选$("#Reversal").click(function(){$(":checkbox[name='habits']").each(function(){this.checked=!this.checked;});//获取全部的选项个数var count=$(":checkbox[name='habits']").length;//获取全部选中的选项个数var allCount=$(":checkbox[name='habits']:checked").length;//将你最爱好的运动是?的选择选上$("#sport").prop("checked",count==allCount);});//点击总提示,也可以进行选择$("#sport").click(function(){//this代表当前function的对象为#sport$(":checkbox").prop("checked",this.checked);});});</script>
</head>
<body>
<form action="" method="post">你最爱好的运动是?<input type="checkbox" id="sport"/>全选/全不选<br/>足球<input type="checkbox" name="habits" value="足球" ><br/>篮球<input type="checkbox" name="habits" value="篮球" ><br/>排球<input type="checkbox" name="habits" value="排球" ><br/>气球<input type="checkbox" name="habits" value="气球" ><br/><input id="All" type="button" value="全选" /><input id="No" type="button" value="全不选"/><input id="Reversal" type="button" value="反选"/>
</form></body>
</html>
- 做两个下拉列表,一个有几个选项,一个空选项。
- 要求左边有两个button,一个点击某个选项,可点击该button转移到右边;另一个按钮点击要求全部放在右边。
- 右边也有两个button,一样的功能。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style type="text/css">#left{width: 100px;height: 200px;text-align: left;}#right{width: 100px;height: 200px;text-align: center;}</style><script src="jquery-3.5.1.js"></script><script>$(function () {$("button:eq(0)").click(function () {$("select:eq(0) option:checked").appendTo($("select:eq(1)"))});$("button:eq(1)").click(function () {$("select:eq(0) option").appendTo($("select:eq(1)"))});$("button:eq(2)").click(function () {$("select:eq(1) option:checked").appendTo($("select:eq(0)"))});$("button:eq(3)").click(function () {$("select:eq(1) option").appendTo($("select:eq(0)"))});})</script>
</head>
<body><div id="left"><select multiple="multiple" name="sel1"><option value="op1">选项一</option><option value="op2">选项二</option><option value="op3">选项三</option><option value="op4">选项四</option></select>
<!-- 选中添加到右边--><button>选中添加到右边</button><br><button>全部选中添加到右边</button></div><div id="right" ><select multiple="multiple" name="sel2"></select><button>点击删除到左边</button><br><button>点击删除到右边</button></div>
</body>
</html>
增删改
增
- append() - 在被选元素的结尾插入内容
- prepend() - 在被选元素的开头插入内容
- after() - 在被选元素之后插入内容
- before() - 在被选元素之前插入内容
删除
- remove() - 删除被选元素(及其子元素)
- empty() - 从被选元素中删除子元素
改
- a.replaceWith(b) 用b替换掉所有的a,替换成一个
- a.replaceAll(b) 用a替换掉b,有多少个b就替换多少个。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="jquery-3.5.1.js"></script><script>$(function(){//在后面添加$("div[id='id1']").append("<h>这是添加的内容!</h>");$("<h1>这是添加的内容</h1>").appendTo("div[id='id1']");//在前面添加$("div[id='id1']").prepend("<h1>这是在id1前面添加的内容</h1>");//before$("div[id='id1']").before("这是before添加的内容");//after$("div[id='id1']").after("这是after添加的内容");//删除标签$("div[id='id1'] p").remove();//再创建p标签$("div[id='id1']").append("<p>这是创建的p标签</p>");//删除标签里的内容$("div[id='id1'] p").empty();$("div[id='id1'] p").before("删除p标签后追赠的内容!");//替换replaceWith,替换成一个$("div[id='id1'] p").replaceWith("<h1>替换掉p标签!</h1>");//replaceAll,一个一个替换$("<h1>一个一个替换div,出现两个替换</h1>").replaceAll("div");});</script>
</head>
<body><div id="id1"><p>这是第一个div</p></div><div><p></p></div></body>
</html>
- 现在有一个题目,要求有一个表格,表格有原始数据,表格下方有添加行按钮,点击按钮可添加行,并且有输入框,为表格里添加数据。要求表格具备删除功能。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="jquery-3.5.1.js"></script><style type="text/css">#t1,th,td{width: 200px;border: #000000 solid 1px;text-align: center;}</style><script>//这里我们定义一个删除函数var deleteFunction=function(){$("#delete").click(function () {// confirm提示是否删除let parent = $(this).parent().parent();// 当前对象为id=delete,其父元素为td,再父元素为tr,我们要删除tif (confirm("是否要删除?")){parent.remove();}return false;});}$(function () {$("#i2").click(function () {var value=$("#i1").val();var $1 = $("<tr>" +"<td>"+value+"</td>" +"<td>"+value+"</td>" +"<td>"+value+"</td>" +"<td><input type='button' id='delete' value='删除'/></td>"+"</tr>");$1.appendTo($("#t1"));// $("#delete").click(deleteFunction);这里不能直接这么写,因为我们要找的是具体添加的一行的一个子元素的delete$1.find("#delete").click(deleteFunction);});//删除函数乱用会有异常。//首先,下面的如何直接拥,这里的delete只能删除原有的数据,而你后面加入的数据,不能删除,//因为这里有两个绑定事件,都是在页面加载之后就绑定了,所以第一个单击事件,只是添加数据的,而//而第二个单击事件,只是用来删除的,并且因为在页面加载的时候已经绑定了,所以只能删除原有的数据,//对于后来加入的数据,这个delete时间压根就没有绑定上。所以要想绑定上,我们可以将这个删除事件弄成一个函数。// $("#delete").click(function () {// // confirm提示是否删除// let parent = $(this).parent().parent();// // 当前对象为id=delete,其父元素为td,再父元素为tr,我们要删除t// if (confirm("是否要删除?")){// parent.remove();// }// return false;// });$("#delete").click(deleteFunction);//函数调用,不加()这是原有数据的删除})</script>
</head>
<body><table id="t1"><tr><td>1</td><td>1</td><td>1</td><td><input type='button' id='delete' value='删除'/></td></tr></table>输入:<input id="i1" type="text" /><br><input id="i2" type="button" width="10" value="提交">
</body>
</html>
css基本操作
- addClass() - 向被选元素添加一个或多个类
- removeClass() - 从被选元素删除一个或多个类
- toggleClass() - 对被选元素进行添加/删除类的切换操作
- offset()- 获得并设置样式的坐标
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style type="text/css">.color{border-color: black;width: 100px;height: 200px;background: red;}</style><script type="text/javascript" src="jquery-3.5.1.js"></script><script type="text/javascript">$(function () {$("#add").click(function () {$("#div").addClass("color");});$("#del").click(function () {$("#div").removeClass("color");});$("#ad").click(function () {$("#div").toggleClass();});$("#getPos").click(function () {$("#div").offset({top:100,left:200});});});</script></head>
<body><div id="div"></div><input type="button" value="add" id="add"/><input type="button" value="delete" id="del"/><input type="button" value="add/Delete" id="ad"/><input type="button" value="getPos" id="getPos"/>
</body>
</html>
基本动画
- 具体功能和函数都放在代码里
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="jquery-3.5.1.js"></script><style type="text/css">.color{width: 100px;height: 100px;border:1px solid;border-color: black;background: red;}</style><script type="text/javascript">$(function () {$("#div").addClass("color");$("#show").click(function () {$("#div").show(1000,function () {alert("动画展示完成!")});//1000速度,下似});$("#hidden").click(function () {$("#div").hide(1000,function () {alert("动画隐藏完成!")});});$("#hiddenShow").click(function () {$("#div").toggle(function () {alert("隐藏或显示完成!")});})$("#in").click(function () {$("#div").fadeIn(1000,function () {alert("淡入完成")});});$("#out").click(function () {$("#div").fadeOut(1000,function () {alert("淡出完成")})});$("#inout").click(function () {$("#div").fadeToggle(function () {alert("淡入或淡出完成!")});})$("#fadeTo").click(function () {$("#div").fadeTo(1000,0.5,function () {alert("指定透明度0.5")})})});</script>
</head>
<body><div id="div">这里是一个动画</div><input type="button" value="展示动画" id="show"><input type="button" value="隐藏动画" id="hidden"><input type="button" value="隐藏/显示" id="hiddenShow"><input type="button" value="淡入" id="in"><input type="button" value="淡出" id="out"><input type="button" value="淡入/淡出" id="inout"><input type="button" value="指定透明度" id="fadeTo">
</body>
</html>
jQuery事件和原生事件的区别
- 他们分别在什么时候触发?
- jQuery在页面加载完成之后,且dom标签对象创建完后会立马执行
- 而原生事件(Windows.onclick)还要加载dom标签对象里的内容才会触发。
- 所以要是两个事件放在一起,那么总是jQuery先执行。
- 他们执行的次数?
- 若有多个原生事件,会执行最后一次。而有多个jQuery事件,会一个一个执行。
其他常用事件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="jquery-3.5.1.js"></script><script type="text/javascript">// click单击事件,有function为绑定,无function为触发// mouseover鼠标已入事件// mouseout鼠标移出事件// bind("绑定类别……",function(){})可以指定多个类别事件绑定,中间用空格隔开//one()跟bind一样,但是只能触发一次//unbind解除绑定//live为解决前面遇到插入后来数据却无法被之前的事件绑定的问题</script>
</head>
<body></body>
</html>
事件冒泡
- 假设一个div中有一个子元素标签h,那么我们可以给两个标签绑定相同的事件。
- 那么就会出现事件冒泡:触发子元素后会自动冒泡到父元素触发,不用手动触发父元素。
- 一般在开发中会避免事件冒泡,则在子元素的事件中加入return false即可。
事件对象
- 封装有触发信息的一个js对象。
- 只需要在绑定事件的时候,fuction函数中传入参数便可以了,这个参数通常写成event。
- 例如,前面的bind绑定事件方法,可以绑定多个事件,但是bind只有一个function,而传入event参数后,就可以在一个function函数分别实现不同事件(这里的不同事件只能是bind要绑定的事件)的功能,常利用if……else。
练习:图片跟随
- 类似于图片放大的功能,在鼠标移入移出的过程中,另一张图片跟随着鼠标进出原图片而显示和隐藏。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style type="text/css">#small{width: 100px;height: 100px;}#big{display: none;}</style><script type="text/javascript" src="jquery-3.5.1.js"></script><script type="text/javascript">//绑定多个事件$(function () {$("#small").bind("mouseover mouseout mousemove",function (event) {if(event.type==="mouseover"){$("#big").show();}else if(event.type==="mouseout"){$("#big").hide();}else if(event.type==="mousemove"){// 必须适当增加,不然两张图片会叠加一部分,造成闪烁$("#big").offset({top:event.pageY+10,left:event.pageX+10})}})})</script>
</head>
<body>
<!--两个标签的位置不能调换,必须大的放在最后,因为若是小的放在前面,那么会互相出现,出现闪烁,无论距离隔开多少,都无法解决。--><img src="../cpp.png" id="small"/><div id="big"><img src="../cpp.png" /></div>
</body>
</html>
XML
- xml的标签可以自定义,文件里要有基本格式。
<?xml version="1.0" encoding="utf-8" ?>
- 标签为自定义标签,习惯上一定要有根标签。
- 下面是一个自定义的xml文件。
<?xml version="1.0" encoding="utf-8" ?>
<books><book sn="1001"><name>不做大哥好多年</name><author>黄渝</author><price>20.0</price></book><book sn="1002"><name>做了大哥好多年</name><author>张宇</author><price>20.0</price></book>
</books>
- 在java自提供的解析xml文件方式已经过时,一般都用第三方jar包来解析。
- 下面以常用jar包,dom4j来举例,具体jar下载和导入请上网查阅。
package www.HYB.XML.src;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;import java.util.List;public class xmlTest {@Testpublic void test() throws Exception{SAXReader sr = new SAXReader();
// 读取文件Document read = sr.read("E:\\javaStudy\\BaseWeb\\src\\www\\HYB\\XML\\src\\book.xml");
// 获取根元素Element root = read.getRootElement();
// 获取多个元素elements或者元素elementList<Element> book = root.elements("book");
输出,转换成xml格式
for (Element e:book){
System.out.println(e.asXML());
}
获取元素
// for (Element e:book){
// System.out.println(e.element("name"));
// }
// 获取元素的内容,并放在javabean中for (Element e:book){String name = e.elementText("name");String author = e.elementText("author");String price = e.elementText("price");Book book1 = new Book(name, author, Double.parseDouble(price));System.out.println(book1);}}}
- javabean为一个具有基本功能的类。
JavaWeb
- 所有可以通过java语言来编写的可以被浏览器访问的程序叫做JavaWeb。
- 在这里主要有两个重要概念,请求和响应。
- 请求是客户端发送要求给服务端。
- 而服务端根据这些具体要求做出的一些回应叫响应。
- 请求和响应的关系是:
- 成对出现,有请求就有响应。
- 资源分类:
- 按照实现方式的不同分为静态资源和动态资源。
- 静态资源:图片,视频,html,css。
- 动态资源:js,jsp,Servlet,asp等。
- 常用服务器:
- Tomcat最常用的开源服务器。
- Jboss也开源,但学习曲线高,不建议使用。
- GlassFish,甲骨文公司开辟的企业级服务器。
- Resin 也是企业级服务器。
Tomcat
- 一个服务端。
- 上网下载压缩包,可直接解压,里面有多个文件包,下面介绍各文件包的主要作用。
- bin:存放可执行程序。
- conf:存放配置文件。
- lib:存放jar包
- logs:运放运行时日志。
- temp:存放临时数据。
- webapps:存放部署的web工程。
- work:工作目录,存放运行jsp翻译的Servlet源码和Session序列化目录。
启动
在bin目录下找到startup目录,双击,出现窗口,显示成功前提下不能关闭窗口。
随便一个浏览器,输入http://localhost:8080跳转出一个页面。
失败原因:
jdk版本问题,jdk8对应tomcat9,以此类推。
环境变量配置错误,比如:JAVA_HOME一定要大写,环境路径没有bin。
窗口出现乱码,找到conf目录下的logging.properies用记事本打开,找到java.util.logging.ConsoleHandler.encoding = GBK,将utf-8修改成GBK,解决问题。
若还不能解决问题,找到conf目录下的server.xml用记事本打开,修改一处地方,将端口号8080修改,随便修改,解决问题,当要访问浏览器,将8080修改成你修改的端口号,记住,端口号不能超过范围(1-65535)。
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />
下面是另一种启动服务器的方式:
- win+r打开dos窗口,输入cd Tomcat服务器路径,到达你要操作的文件夹。
- 然后输入catalina run可启动。
**记住,以上两种启动方式完成后都不能关闭窗口,不然访问页面还是不行。**命令行启动方式若是出现错误会给你报错,所以第一次使用建议使用命令行操作。
停止
- 直接关闭窗口。
- 在具体窗口 按住 Ctrl+c
- 在bin目录下找到shutdown.bat 双击
修改端口号
- 无法启动服务器可修改端口号。
- mysql默认端口号是3306,而Tomcat是8080。
部署web
直接将web工程相关文件放在Tomcat服务器下的webapps里,现在在网址里输入相关路径可访问具体工程文件。
不过上面会让我们创建工程的时候受到空间限制,那么有第二种部署web方法。
找到以下路径conf\Catalina\localhost,然后新建一个xml文件(没有xml格式打开器的,可用记事本打开),
在新建的xml文件写下一个标签。
<Context path="/访问路径" docBase="web项目路径"/>
访问方式
在访问web工程时,我们可以直接将源文件拖动至浏览器上,就可以直接访问具体页面。
但这种方式访问原理和Tomcat服务不同,它使用的是file协议,而Tomcat访问使用了http协议
比如一个访问a.html文件的地址为:
http://localhost:8080/访问路径/具体路径/a.html
这些都是具体数据,发送给Tomcat服务器,这服务器根据你的需求反馈在浏览器中。
注意:若访问地址没有工程名,系统默认访问ROOT工程,这个工程是Tomcat服务器提供的,是Tomcat页面。
若是有了工程名而没有具体的文件,那么默认访问index.html这也是Tomcat服务器里默认有。
IDEA与Tomcat
- 在IDEA配置多个或一个Tomcat
- 找到File | Settings | Build, Execution, Deployment | Application Servers
- 点击+号,选择Tomcat server,然后找到安装Tomcat具体路径,添加即可。
- 这样在你添加新工程的时候,Application Servers就会显示具体Tomcat版本号。
创建动态web工程
- 新建工程,然后新建模块,选择Java Enterprise,选择Application Servers具体版本,然后点击Web Application,默认4.0版本,之后写上工程名字便可。
- 或者直接点击file新建工程,然后点击Java Enterprise,剩下步骤一致。
Tomcat运行web工程
随着Tomcat web工程的部署,在运行图标坐标便可选择Tomcat运行,建议首先修改Tomcat名字。
点击Tomcat运行后,点击Deployment 然后左边+添加工程,-删除工程,下面的Application Context是工程路径。
那么,接下来就可以点击Server,里面可以选择浏览器和默认解析地址。可以修改。
基本功能修改页面都一样,这样我们便可以修改端口号和工程路径,默认浏览器。
修改热部署:在这里我们运行了一遍服务器后,浏览器访问网页,出现我们编辑的内容,可是当我们修改内容时,直接在浏览器中刷新是刷不出来了,要想做到实时刷新,需要进行热部署。
步骤一样,点击Server,点击On frame deactivation 选择Update classes and resourses。
Servlet
- javaEE的一个规范,即接口。
- 是javaWeb三大组件之一。
- 是运行在服务器上一个java小程序,可以接收客户端的请求并响应给客户端。
手动实现Servlet
Servlet接口最常用的重写方法伪service,用来处理客户端的请求和响应。
首先需要在sec目录下建立一个类,此类实现Servlet接口,然后重写里面的方法service,不妨写上一条输出语句,证明是否会被访问到此方法。
package www.hyb.myServlet;import javax.servlet.*; import java.io.IOException;public class myServlet implements Servlet {/*service主要用来处理请求和响应*/@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("这是一个Servlet程序!");} }
其次便是到web.xml文件里,添加两个标签
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"> <!-- 给Tomcat服务器配置一个servlet程序--><servlet> <!-- 为这个servlet起一个名字,一般是类名--><servlet-name>myServlet</servlet-name> <!-- 为servlet程序起一个全类名--><servlet-class>www.hyb.myServlet.myServlet</servlet-class></servlet><!-- 给servlet配置访问地址--><servlet-mapping> <!-- servlet名字--><servlet-name>myServlet</servlet-name> <!-- 自定义访问地址--><url-pattern>/firstServlet</url-pattern></servlet-mapping> </web-app>
之后便可以运行,运行出来网址页面为index.jsp的内容,要想访问到service方法,需要将自定义访问地址加上浏览器地址栏里,回车运行后,在IDEA控制台可见方法里的具体内容。
通过上面的编辑,我们得到的网址为:
【http://localhost:8081/HybWeb_war_exploded/firstServlet】
我们对这个网址进行分析:
- http:协议
- localhost:服务器ip,进行定位到哪个服务器之上。
- 8081:服务器端口号:具体定位到Tomcat服务器之上。
- HybWeb_war_exploded:定位到工程路径,默认为index.jsp
- /firstServlet:资源路径,定位到xml,先找到标签然后找到自定义访问地址,然后找到Servlet名字,通过Servlet名字找到标签中的姓名,然后找到其全类名,通过全类名找到相关类,相关方法,最后运行实现。
生命周期
- 我们都知道,一个类默认会有一个构造器,比如上面实现Servlet接口的类,有一个构造器。
- 那么我们加上这个构造器,就会得出Servlet程序运行的周期。
- 首先是构造器,被执行一次,然后是init初始化方法,被执行一次,之后就是service方法,每次访问都会被调用,最后就是当web工程停止的时候调用destroy销毁Servlet程序。
- 以上便是Servlet执行周期。
获取请求方式
我们新建一个html页面如下:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><form method="get"><input type="button" value="提交"></form> </body> </html>
可见method那里是get请求,但有时候也可能有post请求,而我们知道在实现Servlet接口的类中只有一个service方法。
所以我们需要判断是哪种请求方式。
首先我们看到service的方法是有一个参数,servletRequest ,ServletRequest 类型的。我们可以通过调用ServletRequest 子类HttpServletRequest的getmethod方法,去获取请求类型。
package www.hyb.myServlet;import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException;public class myServlet implements Servlet {/*service主要用来处理请求和响应*/@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {HttpServletRequest hsr=(HttpServletRequest) servletRequest;String method = hsr.getMethod();if ("get".equals(method)){System.out.println("get请求");}else if("post".equals(method)){System.out.println("post请求");}}}
常用实现Servlet
- 上面说的只是针对复杂手动的请求,在开发中,一般用Servlet接口的子类或者子接口来实现Servlet
javax.servlet.http.HttpServlet
这是一个接口实现类,我们可以直接创建一个类去继承该类,该类的特点是包含了get和post请求,不用我们重写service时判别。
package www.hyb.myServlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class HttpServlet extends javax.servlet.http.HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);} }
注意在用该方法时,其他步骤都一样,xml文件一定要编写。
更加快捷方式
直接在所需的包下,新建,create Servlet即可,但要将CreateJava EE6那里划去。
创建成功后,会出现一个类
package www.hyb.myServlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class Servlet2 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} }
还有一个xml文件
<servlet><servlet-name>Servlet2</servlet-name><servlet-class>www.hyb.myServlet.Servlet2</servlet-class> </servlet>
但这个xml不全,一定要补上
<servlet-mapping><servlet-name>Servlet2</servlet-name><url-pattern>/secondServlet</url-pattern> </servlet-mapping>
Servlet继承体系
- 首先是Servlet接口,它只做规范。
- 其次是GenericServlet为一个实现类,做了很多空实现,并持有对ServletConfig类的引用且实现其一些方法。
- HTTPServlet继承了GenericServlet类,并实现了service方法。
- 最后就是用户自定义的Servlet程序。
ServletConfig 类
该类主要应用在初始化中,下面介绍其中主要的方法
public void init(ServletConfig servletConfig) throws ServletException { // 获取Servlet别名System.out.println(servletConfig.getServletName()); // 获取参数System.out.println(servletConfig.getInitParameterNames()); // 根据参数获取参数值System.out.println(servletConfig.getInitParameter("参数名:")); // 获取对象System.out.println(servletConfig.getServletContext()); // myServlet // java.util.Collections$3@5d1b7065 // 参数值 // org.apache.catalina.core.ApplicationContextFacade@53dc85b6}
做上面之前我们要在web.xml中加入以下标签
<init-param><param-name>参数名:</param-name><param-value>参数值</param-value> </init-param>
关于ServletConfig类,还可以写在其他实现类中,但是若调用这个config一些方法,只能获取关于当前类编写的xml标签。
而且,若是当前类在重写init方法,一定要继承父类的init,比如我们新建一个实现类如下。
package www.hyb.myServlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class Servlet2 extends HttpServlet {@Overridepublic void init() throws ServletException {//一定要继承父类的init,不然本身什么也没有,当我们在其他地方使用config类的一些方法时,一片空白。super.init();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} }
ServletContext接口
- 它是一个接口,表示一个Servlet上下文对象,属于整个web工程。
- 一个web工程,只有一个ServletContext对象实例。
- 表示一个域对象,即可以像Map一样存储数据。但这里的域为存储数据的操作范围(整个web工程)。
- 下面解释和Map的一些方法区别。
存储 | 取出 | 删除 | |
---|---|---|---|
Map | put() | get() | remove() |
ServletContext | setAttribute() | getAttribute() | removeAttribute() |
作用
- 获取web.xml中配置的上下文参数context-param
- 获取当前的工程路径,格式:/工程名
- 获取工程部署在服务器磁盘上的绝对路径
- 像Map一样存储数据。
举例
为了举例上面的作用,首先,我们得在web.xml中加入上下文标签。
<!-- 整个web工程的上下文参数--><context-param><param-name>web</param-name><param-value>web-value</param-value></context-param>
其次,在src对应的包下,创建一个Servlet,名为ServletContext,那么web.xm会自动创建一对标签:
<servlet><servlet-name>ServletContext</servlet-name><servlet-class>www.hyb.myServlet.ServletContext</servlet-class> </servlet>
接下来我们在web.xml中给这个Servlet配置访问地址:
<servlet-mapping><servlet-name>ServletContext</servlet-name><url-pattern>/sc</url-pattern> </servlet-mapping>
其次便是在创建的Servlet中,随便一个方法中,用此接口。
package www.hyb.myServlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration;public class ServletContext extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取web.xml中的上下文参数javax.servlet.ServletContext sc = getServletConfig().getServletContext();System.out.println(sc.getInitParameter("web"));//web-value // 获取当前工程路径System.out.println(sc.getContextPath());// /HybWeb_war_exploded // 获取工程部署后在服务器硬盘上的绝对路径,用斜杠获取 // (在web.xml对应的<url-pattern>/sc</url-pattern>)sc前加/的由来/** 该绝对路径映射为IDEA中对应工程的模块中web包的路径* 我们可以将得到后路径去文件夹里搜一搜,会发现里面包含的数据是和在IDEA中的工程模块中的web包是一样的。* */System.out.println(sc.getRealPath("/"));//E:\javaStudy\BaseWeb\out\artifacts\HybWeb_war_exploded\/**/} }
我们可以看到,其绝对路径可以得到,即为web包的路径,那么我们是否用getRealPath()方法获取绝对路径中的一些数据文件呢?
答案肯定是可以的,这里我们先在web包中建一个Directory包为css,并在该包下创建一个样式单文件1.css。
// 获取绝对路径下一些文件System.out.println(sc.getRealPath("/css/1.css"));//E:\javaStudy\BaseWeb\out\artifacts\HybWeb_war_exploded\css\1.css
我们可以看到,绝对路径下的一些文件也是可以被访问到的。
注意:该接口只能获得上下文参数,初始化参数不能获取,初始化参数由ServletConfig类获取
最后,我们举例存储数据:
// 可以像web一样存储数据sc.setAttribute("key","value");System.out.println(sc.getAttribute("key"));//value
- 这里数据有一个特点:从web开始到web结束一直存在,也就是说,一旦存储了一个数据,在任何Servlet都可以访问到该value。
Htpp协议
请求
get请求分为请求行和请求头,post协议分为请求头,请求行和请求体。
我们创建一个Test.html文件,里面的数据为get请求,然后将其部署到我们的Tomcat服务器上,之后用谷歌浏览器打开。
然后按一下f12快捷键,进入调式控制台,勾选Preserve log ,然后重新加载网址,会看见调试台多出了一页,上面有个name标题,点击里面的内容,会出现里面的数据,Request Header便是基本协议内容。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br //Accept接收类型 Accept-Language: zh-CN,zh;q=0.9 //接收语言 Cache-Control: max-age=0 Connection: keep-alive //keep-alice结束后缓存一段时间,closed为直接结束 Cookie: Idea-ecc5f5ad=23d54301-a3d2-49bd-9a9d-79b5f9e33b9b; Idea-4c751249=7a30c2ba-c7d3-48c1-8f7d-a5b8ffb35ff7 Host: localhost:63342 //主机端口 If-Modified-Since: Thu, 22 Jul 2021 04:39:34 GMT sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92" sec-ch-ua-mobile: ?0 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 //用户代理,即为浏览器信息
关于post请求不过多赘述,通过以上我们便可以总结出一些常用的请求头:
- Accept:表示客户端可以接受的请求类型
- Accept-Language:表示客户端可以接受的语言类型。
- User-Agent:表示浏览器的信息
- Host:表示请求端口号。
get请求有哪些?
- form标签可以指定是否为get或者post请求
- a,link,Script,img,iframe标签都是get请求。
- 在浏览器地址栏敲入地址回车访问也是get请求。
post请求有哪些?
- form标签可以指定是否为post请求。
- 其他暂时是get请求。
响应
响应的请求格式有哪些?
还是老方法,不过这次我们查看Response Header:
accept-ranges: bytes cache-control: private, must-revalidate content-length: 215//内容长度 content-type: text/html//响应内容类型 date: Thu, 22 Jul 2021 11:10:04 GMT//响应的格林时间 last-modified: Thu, 22 Jul 2021 10:55:00 GMT server: IntelliJ IDEA 2020.1 X-Content-Type-Options: nosniff X-Frame-Options: SameOrigin x-xss-protection: 1; mode=block
同时,在General那一栏里,我们可以看到以下信息:
Request URL: http://localhost:63342/BaseWeb/HybWeb/web/WEB-INF/Test.html?_ijt=587bb802cn7n6sj8t7gpf39q35 Request Method: GET Status Code: 200 OK//这是响应状态:响应状态码为200,表示响应完成ok Remote Address: 127.0.0.1:63342 Referrer Policy: strict-origin-when-cross-origin
那么一些基本的响应状态码有哪些?
- 200 表示请求成功
- 302 表示请求重定向。
- 404 表示请求错误。
- 500 表示请求成功,但是内部出现了错误。
什么是响应体?
- 即源代码。
HttpServletRequest类
作用
- 我们可以看到在doPost()和doGet()方法中有此类类型的变量。
- 所以它是用来封装请求信息的。
常用方法
- getRequestURI 获取请求资源路径
- getRequestURL 获取请求的统一资源定位符,即是绝对路径。
- getRemoteHost() 获取客户端的ip地址
- getHeader() 获取请求头
- getParameter() 获取请求参数
- getParameterValues() 获取请求的多个参数值
- getMethod() 获取请求的方式
- setAttribute() 设置请求域数据
- getAttribute() 获取请求域数据
- getRequestDispatcher() 获取请求转发对象
举例
首先,我们创建一个模块,随便一个名字。
其次,便是创建一个Servlet,改模块下的web.xml中会自动配置该Servlet程序,我们需要手动为该Servlet程序配置访问地址。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>ServletData</servlet-name><servlet-class>www.hybweb.Servlet.ServletData</servlet-class></servlet><servlet-mapping><servlet-name>ServletData</servlet-name><url-pattern>/ServletData</url-pattern></servlet-mapping> </web-app>
在Servlet的doGet方法里,使用该类。
package www.hybweb.Servlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class ServletData extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // - getRequestURI 获取请求资源路径System.out.println(request.getRequestURI());// /_myNewWeb/ServletData // - getRequestURL 获取请求的统一资源定位符,即是绝对路径。System.out.println(request.getRequestURL());// http://localhost:8081/_myNewWeb/ServletData // - getRemoteHost() 获取客户端的ip地址System.out.println(request.getRemoteHost());// 0:0:0:0:0:0:0:1/*注意:0:0:0:0:0:0:0:1 此地址也表示本机地址,127.0.0.1 也是*/ // - getHeader() 获取请求头System.out.println(request.getHeader("User-Agent"));//Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 // - getMethod() 获取请求的方式System.out.println(request.getMethod());//GET} }
获取参数
- 首先我们在web目录下新建一个html文件如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="http://localhost:8081/_myNewWeb/ServletParameter" method="get">用户:<input type="text" name="user" ><br>密码:<input type="text" name="password"><br>提交:<input type="submit"></form>
</body>
</html>
然后新建一个Servlet,利用其get方法获取表格中的一些参数。
package www.hybweb.Servlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class ServletParameter extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println(request.getParameter("user"));System.out.println(request.getParameter("password"));} }
这样,在我们用这个表格填入一些信息并进行提交时,信息会被提交到action里的网址上,也就是本机的网址,那么用户名和密码就会在控制台上显示出来。
注意:post请求和get请求基本一样,但是post请求可能会出现中文乱码等问题,所以在doPost请求的方法里,加上
变量名.setCharacterEncoding("UTF-8");
请求转发
指服务器在接收到资源后跳转到另一个资源叫做请求转发。
举个例子:客户要求柜台一做事,柜台一做了一些事,但是也要让柜台二去确认一些事,并叫柜台二去做,自己才能做。
下面举个代码例子如何实现:
首先我们创建两个Servlet,分别为Servlet1和Servlet2,web.xml的一些参数先写好。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>Servlet1</servlet-name><servlet-class>www.hybweb.Servlet.Servlet1</servlet-class></servlet><servlet><servlet-name>Servlet2</servlet-name><servlet-class>www.hybweb.Servlet.Servlet2</servlet-class></servlet><servlet-mapping><servlet-name>Servlet1</servlet-name><url-pattern>/Servlet1</url-pattern></servlet-mapping><servlet-mapping><servlet-name>Servlet2</servlet-name><url-pattern>/Servlet2</url-pattern></servlet-mapping> </web-app>
然后请看Servlet1中的代码:
package www.hybweb.Servlet;import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class Servlet1 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 产生请求String user = request.getParameter("user");System.out.println("Servlet1已经为用户"+user+"做了一些事"); // 柜台一要求柜台二去做相同数据的事,那么就要采用域数据。request.setAttribute("key","value"); // 告诉柜台二,输入一定要和柜台二自定义的访问路径一致RequestDispatcher rd = request.getRequestDispatcher("/Servlet2"); // 去柜台二,带着请求和响应rd.forward(request,response);} }
下面Servlet2中的代码:
package www.hybweb.Servlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class Servlet2 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 来到柜台二,获取用户数据String user = request.getParameter("user");System.out.println("柜台二为用户"+user+"做了一些事"); // 获取域数据Object key = request.getAttribute("key"); // 回应柜台一的请求System.out.println("柜台二回应柜台一的请求"+key);} }
最后当我们跳转到网址的时候,在地址栏后写入:
Servlet1?user=hyb
最后我们按回车,如果不出现错误,那么在控制台上就会显示如下:
Servlet1已经为用户hyb做了一些事 柜台二为用户hyb做了一些事 柜台二回应柜台一的请求value
可见,当柜台一向客户做出了回应,同时请求柜台二做出回应时,是相通的,也即是说,两个柜台都可以统称为一个服务端。
base标签
当我们进行网页互相跳转的时候,最简单的方式是两张网页互相写上对方的地址。
但是学到这,我们一般用请求转发来跳转,但请求转发会有一个毛病:
- 比如有一张a网页,一张b网页,我们在a做请求跳转到b网页,这个时候b网页中写上a网页的地址。
- 我们会发现,当我们点击a网页的请求跳转,会跳转到b网页,而当我们点击b网页中的a网页地址,会发现不成功!
- 这是因为:在b网页中,我们采用了a网页的相对路径,而这个相对路径是基于地址栏的路径,我们可以在b网页中根据a网页的相对地址对比b网页地址栏的地址,然后一层层将…/缩减,最后会发现出现了一个错误地址,所以才会出现跳转不回去a网页的情况。
- 根本原因,因为我们用了请求转发,也就是说中间隔了一个Servlet,要是想跳转回来,可以利用base标签。
- 我们可以利用base标签在b网页中的head标签中,设置b网页中的a的相对路径工作时参照的地址。
- 这样,当我们利用请求转发时,在b网页中点击a网页的地址就会跳转回去。
这里我们也可以回顾一下在web中的相对路径和绝对路径的区别:
相对路径:./表示当前目录,…/表示上一级目录
绝对路径:http://ip:端口号/工程路径/资源路径
资源路径:就是一些js,css或者html等页面。
/ 的意义
- / 如何被浏览器解析,得到的地址是http://ip:端口号/
- / 如果被服务器解析,得到的地址是http://ip:端口号/工程路径
- 这就是为什么要在web.xml文件中的自定义路径要加上/的原因。
- 还有一些方法也要加上/
- 特殊情况:有可能会有一种方法发出请求给浏览器解析/,得到的地址还是http://ip:端口号/
HttpServletResponse类
与HttpServletRequest类作用相反,这个是响应。
通过响应流反馈给客户端
- getOutputStream()为字节流
- getwriter()为字符流
- 两个流不能同时存在。
问题:响应时,反馈在网页上会字符集乱码的问题。这是因为响应默认的字符集只支持英文,不支持中文,要想让他支持中文。
比如让服务器和浏览器都同时支持中文响应。
可以分别设置:(HttpServletResponse response)
- 设置服务端:response.setCharacterEncoding(“UTF-8”)
- 设置浏览器:response.setHeader(“Content-Type”,“text/html”,charset=UTF-8)
也可以一起设置:
- response.setContentType(“text/html;charset=UTF-8”)
注意:一定要先设置再相应。
请求重定向
当客户端请求了服务端的旧地址,服务端响应了一个新地址,客户端再次请求新地址,得到响应为新地址的内容。
二次响应定义为请求重定向。
下面举个例子
首先,我们创建两个ServletResponse1和ServletResponse2
其次,补全web.xml文件里的标签
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>ServletResponse1</servlet-name><servlet-class>www.hybweb.Servlet.ServletResponse1</servlet-class></servlet><servlet><servlet-name>ServletResponse2</servlet-name><servlet-class>www.hybweb.Servlet.ServletResponse2</servlet-class></servlet><servlet-mapping><servlet-name>ServletResponse1</servlet-name><url-pattern>/ServletResponse1</url-pattern></servlet-mapping><servlet-mapping><servlet-name>ServletResponse2</servlet-name><url-pattern>/ServletResponse2</url-pattern></servlet-mapping> </web-app>
最后,在ServletResponse1中,写入以下代码:
package www.hybweb.Servlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class ServletResponse1 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("response发生错误,现在给你response2的地址"); // 设置状态响应码response.setStatus(302); // 反馈新地址,设置响应头response.setHeader("Location","http://localhost:8081/_myNewWeb/ServletResponse2");} }
而后在ServletResponse2中写入:
package www.hybweb.Servlet;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class ServletResponse2 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");// 处理信息,写在网页里response.getWriter().write("response1出现错误,现在由我response2为你服务!");} }
这样,我们启动服务器,会自动跳转到网页上,这时,我们在地址栏输入ServletResponse1
便看到ServletResponse2的内容被写在了网页上。而且地址栏的地址也发生了变化。
通过以上例子,我们为请求重定向做出几点总结:
- 两次请求,两次回应。
- 访问请求一会自定跳转到请求二。
还有一些特点:
- 两次不共享request中的域数据。
- 不能访问WEB-INF下的资源。
- 可以访问工程外的资源。比如可以定位到:http://localhost:8081
更简洁的请求重定向方法:
我们可以用另一种方法直接将设置响应状态和定位地址包括在一个方法中
response.sendRedirect("具体地址")
jsp(快要过时)
前面我们在Servlet程序中,有这样一个方法。
response.getWriter().write("response1出现错误,现在由我response2为你服务!");
我们有提到过,这是写在网页上的,所以我们也可以将要写的html代码封装成字符串上,用此方法输出在网页上,就会显示对应的html页面。
也就是说,Servlet程序也可以写html页面。
但是,要写html页面需要将他们的各类标签封装成字符串,所以若是大的工程,这将会非常的繁琐。
因此,jsp就是对Servlet编写html页面的一种封装,在jsp文件里,我们可以直接写html页面,极大地方便了维护工作。
而jsp本质上也可以说是一个Servlet程序。
重要参数
我们新建一个javaEE模块,不难默认的index文件就是jsp格式,我们打开阅览,会发现以下标签。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
page标签就是用来设置一些jsp文件的重要标签。
language属性:表示jsp翻译后支持什么语言,目前只支持java
contenType属性:表示jsp返回的数据类型是什么,即Servlet程序中,response.setContentType()
pageEncoding属性:jsp文件本身的字符集
import :导入java程序包
autoFlush:设置缓冲区刷新机制,默认为true刷新。
buffer:设置缓冲区大小,默认是8kb
errorPage:设置jsp文件运行出错,跳转到哪一个页面。
这个页面的路径一般以/开头,它表示请求地址为http://ip:port/工程路径/映射到web包下。
isErrorPage:设置当前jsp页面是否为错误页面,默认是false,如果是true可以获取异常信息。
session:设置当前jsp页面,是否会创建HTTPSession属性,默认是true,会创建。
extends:当前jsp底层源码继承哪个类。
脚本
声明脚本
声明脚本赋予了jsp可以直接撰写java代码,在地层中,该代码可以被翻译成可以使用的java代码
但这些java代码只能是一些声明代码,比如:声明类属性,声明静态代码块,声明类方法,声明内部类
声明脚本格式为:
<%!java代码 %>
表达式脚本
可以在jsp页面上输出数据
基本格式为:
<%=表达式 %>
表达式脚本可以输出各种类型的数据,甚至是对象,但表达式只能是具体的数值,不要在里面声明类型,也不能给表达式以结束分号。
jsp页面写入表达式脚本,在源代码中,都被调用到_jspService()方法中,然后被调用到out.print()里输出。
代码脚本
格式:
<%java语句for循环,if,while,输出语句等。 %>
注释
- 在jsp里有三种注释:
- html注释,被_jspService调用,调用getWriter().writer()写出。
- java注释,只能在可以编写java的脚本中编写注释。
- jsp注释,可以注释jsp文件中任何一个。
九大内置对象
本质上是服务器将jsp文件翻译成Servlet时,内置提供的九大对象。
request:请求对象
response:响应对象
pageContext:jsp上下文对象
session:会话对象
application:ServletContext对象
config:Servletconfig对象
out:jsp输出流对象
page:指向当前jsp的对象
exception:异常错误对象
四大域对象
pageContext:jsp上下文对象,只对当前jsp页面有效
request:请求对象,不限于当前页面,但是只对一次请求有效
session:会话对象,一次会话有效,浏览器打开到浏览器结束。
application:ServletContext对象,整个web工程有效。
使用顺序为,按照存储数据内存范围从小到大使用。
out输出和response.getWriter
response.getWriter主要是给客户端输出使用
而out是给客户端的用户使用。
两个输出流都可调用writer()方法,将信息输出在网页上。
但要优先使用out输出,因为jsp底层源码用的便是out输出。
原理
- out和response各自有一个缓冲区,且out的每次刷新操作后,都会将数据转移到response缓冲区的最后面。
- 所以同时使用两种方法时,无论如何都是response先输出。
out特点
- out有两个方法,writer()和print().
- 两者都会可以将数字转化为字符串,有区别的是,writer()方法,会输出对应的ASCII码,也就当我们用writer输出整形不会得到真实的整形。
- 总结:writer()只适合输出字符串,而print()可以输出任何数据类型
常用标签
静态包含*
网页一般有三部分组成,页头,主体,页脚。
当页脚需要被包含到整个工程的所有网页中,我们可以将页脚部分编写成一个jsp文件,而主要的jsp文件便可将该文件包含进来。
极大地方便了代码的维护。
包含其他jsp文件的标签为
<%@ include file="/资源路径" %>
file的路径里的/表示http://ip:port/相当于一个javaEE模块里的web工程目录。
该标签的底层实现为:
其实就是将file的源代码拷贝过来,直接实现。
动态包含
动态包含也可以实现静态包含的一些内容
格式:
<jsp:include page="/资源路径"></jsp:include>
底层:
- 主文件里的有自己的输出,会传送给out缓冲区。
- 当检测到此标签的时候,会调用JspRuntimeLibrary.include(request,response,"/资源文件",out,false),该方法被调用后,附文件里的内容会直接传到主文件的缓冲区中,也被输出,效果和静态包含一样。
区别:主要可以完成静态包含完不成的功能。
主文件可以利用此标签(在标签里设置)设置参数,而附文件可以根据获取参数的方法来获取主文件的参数。
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 16:56To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><jsp:include page="b.jsp"><jsp:param name="hyb" value="123"/></jsp:include> </body> </html>
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 16:56To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body>b.jsp<%=request.getParameter("hyb")%> </body> </html>
请求转发
<jsp:forward page=""></jsp:forward>
- jsp里的请求转发主要用于解决Servlet程序中难以将数据打印到网页上的问题。
- 问题:
- 假如有一个搜索字面,要求输入某个姓,便可以将数据搜索出来,那么首先要经过Servlet获取请求参数然后去数据库中查询数据,最后反馈出来,jsp便是代替这一层反馈,我们可以让Servlet程序请求转发到jsp中去做。
- 要做到请求转发,先得让Servlet程序得到的数据保存到Request域中,然后jsp从Request中获取数据。
- 之后便在jsp里遍历出结果。
监听器
JavaWeb的三大组件之一,Listener。
javaEE的规范之一,接口。
监听某些事物的变化,然后通过回调函数,反馈给客户去做一些相应的处理。
主要使用ServletContextListener监听器,它可以监听ServletContext对象的创建和销毁,ServletContext对象在web工程创建时创建,在其销毁时销毁,而监听器一旦监听到了其创建和销毁,就会分别调用监听器的两个方法反馈。
使用监听器的步骤
- 编写一个类去实现ServletContextListener。
- 实现接口中的两个方法。
- 配置web.xml文件中标签
EL表达式
基本
- 主要为代替jsp中表达式脚本的输出。
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 20:12To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%request.setAttribute("key","value");%><%=request.getAttribute("key")%>${key}
</body>
</html>
- 我们可以看到,EL表达式明显比jsp脚本要简单的多。
- 而且EL表达式还有一些特点
- 加入两种方法都输出空值,EL表达式反馈给用户的感觉更加准确,是空白一片,而jsp表达式则给一个字符null
- 其次,便是加入四大域对象都设置了相同的key,那么用EL表达式去搜索,会其域对象的从小到大去搜索,但是这个搜索意思是要其中一个域对象真的结束了,才能搜索下一条。
复杂
下面是复杂javabean中,输出各类型属性的方法。
首先我们新建一个javabean,里面有各种复杂类型的属性。
package www.hyb.EL;import java.util.Arrays;
import java.util.List;
import java.util.Map;public class Person {private String name;private int age;private String[] phone;private List<String> cities;private Map<String,Object> map;public Person() {}public Person(String name, int age, String[] phone, List<String> cities, Map<String, Object> map) {this.name = name;this.age = age;this.phone = phone;this.cities = cities;this.map = map;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String[] getPhone() {return phone;}public void setPhone(String[] phone) {this.phone = phone;}public List<String> getCities() {return cities;}public void setCities(List<String> cities) {this.cities = cities;}public Map<String, Object> getMap() {return map;}public void setMap(Map<String, Object> map) {this.map = map;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", phone=" + Arrays.toString(phone) +", cities=" + cities +", map=" + map +'}';}
}
- 然后我们新建一个jsp文件,之后先利用jsp脚本设置一些信息,然后利用EL表达式将所需要的信息输出。
<%@ page import="www.hyb.EL.Person" %>
<%@ page import="com.sun.org.apache.xpath.internal.operations.String" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %><%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 20:35To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%Person person = new Person();person.setName("hyb");person.setAge(20);person.setPhone(new java.lang.String[]{"123","456","789"});List<java.lang.String> objects = new ArrayList<>();objects.add("北京");objects.add("上海");objects.add("深圳");person.setCities(objects);Map<java.lang.String, Object> map = new HashMap<>();map.put("key1","value1");map.put("key2","value2");map.put("key3","value3");person.setMap(map);// 放在域对象中pageContext.setAttribute("p",person);%>输出姓名:${p.name}<br>输出年龄:${p.age}<br/>输出某个电话:${p.phone[0]}<br/>输出某个城市:${p.cities[0]}<br/>输出某个map:${p.map.key1}
<%-- 输出姓名:hyb--%>
<%-- 输出年龄:20--%>
<%-- 输出某个电话:123--%>
<%-- 输出某个城市:北京--%>
<%-- 输出某个map:value1--%>
</body>
</html>
基本运算
关系运算
${1=1} //true
逻辑运算
${1=1 && 1<2} //true
算数运算
{1+1} //2
空运算
- 值为null:
- 值为空串
- Object数组,集合,map长度为0
<%@ page import="java.util.ArrayList" %> <%@ page import="java.util.List" %> <%@ page import="java.util.Map" %> <%@ page import="java.util.HashMap" %><%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 20:59To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><%request.setAttribute("key","");request.setAttribute("key1",null);Object o= new Object[]{};request.setAttribute("key2",o);List<String> list=new ArrayList<>();request.setAttribute("key3",list);Map<String,Object> map=new HashMap<>();request.setAttribute("key4",map);%>${empty key}<br/>${empty key1}<br/>${empty key2}<br/>${empty key3}<br/>${empty key4}<br/> <%-- true--%> <%-- true--%> <%-- true--%> <%-- true--%> <%-- true--%> </body> </html>
三元运算
表达式1?表达式2:表达式3
如果表达式1为真,返回表达式2,否则发挥表达式3
点运算和[]运算
点运算可以输出map或者某个javabean对象的一些属性值。
[] 可以输出集合或者数组里的某个值,也可以带有特殊字符的Map
${map['1.1.1']}
十一大隐含变量(对象)
变量 | 类型 | 作用 |
---|---|---|
pageContext | PageContextImpl | 获取jsp九大内置对象 |
pageScope | Map<String,Object> | 可以获取pageContext域数据 |
requestScope | Map<String,Object> | 获取request域数据 |
SessionScope | Map<String,Object> | 获取Session域数据 |
applicationScope | Map<String,Object> | 获取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中配置参数 |
四大域数据
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 21:57To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%pageContext.setAttribute("key","value1");request.setAttribute("key","value2");session.setAttribute("key","value3");application.setAttribute("key","value4");%>
<%--当我们需要获取各自的值时,不能直接拥${key},因为大伙的key都是相等的--%>${pageScope.key}${requestScope.key}${sessionScope.key}${applicationScope.key}
<%-- value1 value2 value3 value4--%>
</body>
</html>
pageContext
- 可以获取九大内置对象
- 下面介绍最常用的内置对象request的一些属性获取。
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 22:09To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%pageContext.setAttribute("r",request);%>协议:${r.scheme}<br/>服务ip:${r.serverName}<br/>端口:${r.serverPort}<br/>工程路径:${r.contextPath}<br/>请求方法:${r.method}<br/>ip:${r.remoteHost}<br/>
<%-- 会话id:${pageContext.session.id}--%>
<%-- 协议:http--%>
<%-- 服务ip:localhost--%>
<%-- 端口:8081--%>
<%-- 工程路径:/EL_JSTL--%>
<%-- 请求方法:GET--%>
<%-- ip:0:0:0:0:0:0:0:1--%>
<%-- 会话id:7F7721D2D8ED5FF71E6B8D88E5E6C2DA--%>
</body>
</html>
其他隐含变量
获取参数,首先,在演示之前,我们可以在地址栏上加入
http://localhost:8081/EL_JSTL/otherEL.jsp?username=hyb&username=zyl
这表示我们加入了两个属性一样但值不一样的参数,下面我们可以获取里面的参数,主要有两个隐含变量
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 22:21To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body>${param.username}${paramValues.username[1]} <%-- hyb zyl--%></body> </html>
下面演示获取请求头信息。
${header['User-Agent']}${headerValues['User-Agent'][0]} <%-- Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36--%> <%-- Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36--%>
cookie
获取cookie名字:${cookie.JSESSIONID.name} 获取cookie值:${cookie.JSESSIONID.value}
initParam
首先要配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><context-param><param-name>username</param-name><param-value>password</param-value></context-param> </web-app>
${initParam.username}
JSTL
是一个jsp标签库
在使用这些库之前,要导入JSTL的jar包
要使用这些库,必须引进该库的URI和前缀,使用taglib标签引入。
<%@ taglib prefix="前缀" uri="" %>
核心标签库:前缀c,URI:http://java.sun.com/jsp/jstl/core
其他用到再说。
下面是JSTL库里的一些常用标签示例
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/25Time: 23:02To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%--<c:ser scope="保存域数据类型" var="保存数据属性" value="保存域数据值">--%>保存之前:${requestScope.abc}<c:set scope="request" var="abc" value="123"/>保存之后:${requestScope.abc}<%--<c:if test="EL表达式"> 作if判断--%><c:if test="${1==1}" ><p>true</p></c:if><%--<c:choose> <c:when> <c:otherwise>如同java里的switch case一般要注意的是:choose里不能使用html注释,只能是jsp注释
--%><%request.setAttribute("key",180);%><c:choose>
<%-- 只要有一个条件成立,其他就不执行如果when里的所有条件都不执行,otherwise执行
--%><c:when test="${requestScope.key>200}"><p>该值小于200</p></c:when><c:when test="${requestScope.key<181}"><p>改值小于181</p></c:when><c:otherwise><p>改值为180</p></c:otherwise></c:choose><%--<c:froEach begin="开始标志" end="结束标志" var="中间变量">标签,可以遍历元素
在forEach标签里,你可以插入其他任何标签。--%><c:forEach begin="1" end="10" var="i"><table><tr>${i}</tr></table></c:forEach>
<%--forEach遍历数组,或者Map,List,对象<c:forEach items="${要遍历的数组}} var="自定义变量">
--%><%request.setAttribute("arr",new String[]{"123","456","789"});%><c:forEach items="${requestScope.arr}" var="i">${i}<br/></c:forEach>
<%--选择某个区间范围去遍历--%><c:forEach begin="1" end="2" items="${requestScope.arr}" var="i">${i}<br/></c:forEach>
</body>
</html>
文件上传*
- 一个form标签,必须是post请求。
- 里面必须有一个encType属性,属性值必须为multipart/form-data值
- 在form标签中使用input标签上传,type属性值为file。
- 最后编写服务器接收上传的数据。
上传
编写一个jsp文件,如下:
<%--Created by IntelliJ IDEA.User: 黄渝斌Date: 2021/7/26Time: 19:04To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><form action="http://localhost:8081/EL_JSTL/fileServlet" enctype="multipart/form-data" method="post"><input type="text" name="num">请上传图片:<input type="file" name="photo" value="上传图片"/> <%-- 以上的input标签,一定要加name属性,不然FileServlet里的isMultipartContent(HttpServletRequest request) 会被判断成false 也就是说isMultipartContent(HttpServletRequest request)会将这个标签判断不合法的标签,会变成false--%>提交:<input type="submit" value="提交"></form> </body> </html>
编写web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>FileServlet</servlet-name><servlet-class>www.hyb.File.FileServlet</servlet-class></servlet><servlet-mapping><servlet-name>FileServlet</servlet-name><url-pattern>/fileServlet</url-pattern></servlet-mapping> </web-app>
编写Servlet 程序
package www.hyb.File;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class FileServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("文件上传过来了!");} }
解析
前面我们做了一个基本的文件上传,但是仅仅是上传还不够,还需要解析。
首先,解析的第一步,就是要导入两个jar包,commons-fileupload-1.4.jar,commons-io-2.11.0.jar。
在这两个jar包中有,我们常用的类有哪些?
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request) 判断该表格是
public List parseRequest(HttpservletRequest request ) 用来解析上传的数据
FileItem表示每一个表单项
boolean FileItem.isFormField() 表示这个表单项是否为普通的表单项,还是含有上传的文件类型的表单项。
true 为普通的表单项,false为上传的文件类型的表单项。
String FileItem.getFileName()获取表单项的name属性。
String FIleItem.getString()获取表单项的值。
String FileItem.getName()获取上传的文件名。
void FileItem.Writer(file) 将上传的文件写到参数file 所指向的硬盘位置。
接着上个上传的例子,我们将其进行解析
package www.hyb.File;import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.List;public class FileServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判断上传的文件是否为多段数据if (ServletFileUpload.isMultipartContent(request)){ // 创建FileItemFactory工厂实现类FileItemFactory fileItemFactor=new DiskFileItemFactory(); // 然后用于解析的工具类ServletFileUpload sfu=new ServletFileUpload(fileItemFactor); // 解析上传的数据try {List<FileItem> fileItems = sfu.parseRequest(request); // 因为我们都是放在form表单里,所以这里获取的数据也有可能本来就是一个普通表单项,所以这里要多加判断for (FileItem f: fileItems ) {if(f.isFormField()){System.out.println("表单项的value属性"+f.getString("UTF-8"));}else{System.out.println("表单项的name属性"+f.getFieldName());}}} catch (Exception e) {e.printStackTrace();}}} } jav
文件下载
- 首先,客户端告知服务端要下载什么文件。
- 服务端获取要下载的文件名,读取要下载的文件内容,然后把下载的内容回传给客户端。
- 在回传前,通过响应头告诉客户端返回的数据类型和收到的数据用于下载使用。
举例
首先,我们创建一个Servlet程序,用doGet请求。
package www.hyb.File;import org.apache.commons.io.IOUtils; import sun.nio.ch.IOUtil;import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream;public class downloadFileServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 告诉服务端要下载的文件名字或路径String fileName="/file/1.jpg"; // 读取下载的文件内容ServletContext servletContext = getServletContext();InputStream resourceAsStream = servletContext.getResourceAsStream(fileName); // 下一步是回传数据,但是在回传之前,要告诉客户端返回的类型和用于下载使用 // 不然在浏览器解析的时候,会将这图片当成输出,输出在网页中 // 1.获取下载的文件类型String mimeType = servletContext.getMimeType(fileName); // 2.设置响应头,说明要下载的文件response.setHeader("Content-Disposition","attachment;filename=1.jpg"); // 下一步就是响应,获取响应的输出流ServletOutputStream outputStream = response.getOutputStream(); // 将输入流转换成输出流IOUtils.copy(resourceAsStream, outputStream); // 关闭流resourceAsStream.close();outputStream.close();} }
然后在web.xml配置响应的标签。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>downloadFileServlet</servlet-name><servlet-class>www.hyb.File.downloadFileServlet</servlet-class></servlet><servlet-mapping><servlet-name>downloadFileServlet</servlet-name><url-pattern>/downloadFileServlet</url-pattern></servlet-mapping> </web-app>
最后,我们重启服务器,然后输入我们的自定义地址就会发现图片进行下载。
注意
在Servlet程序里,告诉浏览器的要下载的文件名其实是我们自定义的,这并不是说,告诉浏览器文件名是让其对哪个文件进行下载,这是要对下载的文件进行命名,你也可自定义名字,但是要用到URL编码集,不然会报错。
"attachment;filename="+ URLEncoder.encode("中国.jpg","UTF-8")
但还需值得注意的一点是:老版本一些不同的浏览器,是不支持URL编码的,从最开始就支持的URL编码是IE和谷歌,像老版本的一些火狐就不支持。那么要想支持老版本的浏览器,就可以加个if判断。
// 如果有火狐就,否则谷歌,IEif (response.getHeader("User-Agent").contains("Firefox")){response.setHeader("Content-Disposition","attachment;filename=?UTF-8?B?"+ new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8")));}else{response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode("中国.jpg","UTF-8"));}
cookie
翻译过来是曲奇饼干的意思。
但在javaweb里,cookie是一个类,只有一个构造器,用来构造key-value。
客户端有了cooki后,每次请求都发送给客户端。
cookie大小不能超过4kb。
下面是简单的举例和创建:
package www.hyb.Cookie;import www.hyb.CookieUtils.CookieUtil;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class CookieServlet extends BaseServlet{protected void setCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建一个CookieCookie cookie = new Cookie("key1", "value1");Cookie cookie1 = new Cookie("key2", "value2");
// 发送给服务器response.addCookie(cookie);response.addCookie(cookie1);// 获取CookieCookie[] cookies = request.getCookies();
// 遍历cookiefor (Cookie cookie2 : cookies) {System.out.println(cookie2);
// 获取某一个cookieif ("key1".equals(cookie2.getName())){System.out.println(cookie2.getValue());}CookieUtil.getCookie("key1",cookies);break;}}
}
- 关于其自撰的工具类如下:
package www.hyb.CookieUtils;import javax.servlet.http.Cookie;public class CookieUtil {public static Cookie getCookie(String key,Cookie[] cookie){if (key==null||cookie==null||cookie.length==0){return null;}for (Cookie cookie1 : cookie) {if (key.equals(cookie1.getName())){return cookie1;}}return null;}
}
- 下面是修改Cookie的值
protected void updateCookie(HttpServletRequest request,HttpServletResponse response){
// 创建一个新的Cookie对象Cookie cookie = new Cookie("key1","newValue1");response.addCookie(cookie);// 或者是利用其setValue方法
// 1.获取一个CookieCookie key1 = CookieUtil.getCookie("key2", request.getCookies());key1.setValue("newValue2");}
下面是设置Cookie的存货设置。
- 主要是利用Cookie类的setMaxAge()方法来设置。
- 默认是-1,到浏览器关闭时关闭。
- 其次是0,立马关闭。
- 再者是整数,以秒为单位,60秒一个小时。
下面是Cookie路径的设置。
- 首先是利用其setPath路径进行设置。
- 方法里,必须传入工程路径,就是request.getContextPath() 其余自定义。
- 若是Cookie路径 里没有地址存在于总路径中,则不发送给服务器。
- 只要Cookie全部存在于总路径中,就发送给服务器。
Cookie免登陆,我们在平常的软件中都会给我们保存用户名和密码,用的便是Cookie,当我们登陆成功时,可以将用户名或者密码保存为Cookie,然后设置Cookie保存时间,这样浏览器就会在下次登陆的时候将Cookie对象发送给服务器。
在web页面,我们获取的cookie对象是一个Map对象。
session
会话,是一种用户维护客户端和服务端的技术,是一个接口,用来保存用户信息,但是保存在服务器中的。
获取一个session 和创建一个session的方法都是一样的,request.getSession() 第一次调用,创建session,第二次调用是获取。
isNew()方法可以判断是否创建过。
每次会话都有一个id值,通过getId获取,这个id是唯一的。
往request域中存储数据,用setAttribute()获取是getAttribute()
生命周期,超出为超时。
默认周期为1800秒,也就是三十分钟。
在Tomcat服务器里web.xml文件有这样一对标签来设置默认时常。
<session-config><session-timeout>30</session-timeout> </session-config>
所以我们要是想设置默认时长,也可以在本项目的web.xml文件中设置,单位是分钟。
session.setMaxInactiveInterval(int interval) 设置单个session时长。单位为秒
- 负数永不超时。
- 正数表示过了这段时间超时。
- 如同Cookie的0效果,马上超时不能传入0,要利用其一个方法,invaliate() 可以设置马上超时。
session.getMaInactiveInterval()来获取session时长。单位为秒
但是值得注意的是,该时长要解释为活跃时间,也就是说,若是在活跃时间内再次创建同一个session(两次请求的间隔时长),活跃时间会被重置。
session 底层是基于cookie的,其id值利用cookie的key-value去传送,即使我们session没有超时,但只要删除了,再创建都是新的session。
Filter过滤器
- 是javaWeb三大组件之一,三大组件有监听器,Servlet,Filter过滤器。
- 是javaEE的规范,即接口。主要作用是用来拦截请求,过滤响应,前者用的较多,后者较多出现在一些冷门的高级应用中。
- Filter过滤器常见的应用场景有:日志,事务,以及权限的检查。
基本使用
首先我们创建一个模块,让其有独立的web包,然后在web包下创建一个包,里面装一个a.html页面,和一个login.html页面。
然后我们创建一个Filter过滤器,在src包下创建。
package www.hyb.Filter;import javax.servlet.*; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException;public class MyFilter implements Filter {public void destroy() {}/** doFilter方法用来拦截请求,主要用于检查用户是否登录* */public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { // 获取session, // 1.先类型转换HttpServletRequest httpServletRequest= (HttpServletRequest) req; // 获取sessionHttpSession session = httpServletRequest.getSession(); // 查看session里是否有用户Object user = session.getAttribute("user"); // 判断if (user==null){req.getRequestDispatcher("/admin/login.html").forward(req,resp);}else{ // 如果不为空就继续访问后续地址chain.doFilter(req,resp);}}public void init(FilterConfig config) throws ServletException {}}
第三步便是像Servlet一样配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><filter><filter-name>MyFilter</filter-name><filter-class>www.hyb.Filter.MyFilter</filter-class></filter><filter-mapping><filter-name>MyFilter</filter-name> <!-- admin目录下的所有目录--><url-pattern>/admin/*</url-pattern></filter-mapping> </web-app>
之后我们便可以启动服务器,便会发现,当你访问a.html的时候,一定会先访问登录页面。
完整使用
- 上面的基本使用犹如监听,这里如果我们将login 的页面补全,并且按照正常的登录程序走过滤器就会启动,一旦登录成功,只要访问admin下的所有目录,就可以访问,若是登录页面这边没登录成功,就不能访问。
生命周期
- 在前面我们创建一个Filter并且实现接口的时候,会实现几个方法,在里面,还有一个隐藏方法,也就是构造器。
- 在其生命周期里,其构造器和init方法都是在创建的时候被调用的。
- 而doFilter方法是有拦截的时候就会调用。
- 最后便destory 方法,结束Filter的时候就会被调用。、
FilterConfig类
获取web.xml中filter-name的值
获取web.xml中的filter标签里的init-param标签的值。
获取ServletContext对象
举例子之前我们先配置web.xml文件
public void init(FilterConfig config) throws ServletException {
// - 获取web.xml中filter-name的值System.out.println(config.getFilterName());
// - 获取web.xml中的filter标签里的init-param标签的值。String key = config.getInitParameter("key");System.out.println(key);
// - 获取ServletContext对象System.out.println(config.getServletContext());}
FilterChain
- 过滤器链。
- 假设有两个过滤器,1,2,里面都分别有两个方法,chain.doFilter() 。那么要想访问目标资源,首先得经过1过滤器中的chain.diFilter前的代码,一旦执行到doFilter方法,立马转换到2过滤器,该方法剩下的语句先不执行。到了2过滤器,步骤也是一个样,直到2的doFilter方法,便会调用目标文件,调用完毕后,返回2过滤器,执行其中的doFilter剩余的方法,执行完便返回1过滤器中doFilter方法。
- 过滤器链一旦有一条断裂,剩下便不会执行,包括执行文件。
- 这些过滤器链默认在同一个线程中,都共用一个request域对象,执行顺序是按照web.xml的配置顺序。
匹配路径
- 前面配置web.xml文件中的匹配路径时候会看到,有/admin/* ,这表示目录匹配,模糊匹配,表示该目录下所有的资源文件都必须遵守。
- 还有一种叫精确匹配,/+目标文件。表示精确到某个资源文件的过滤器路径。
- 最后一种是后缀名匹配,该匹配不用加入/,而是直接*+.后缀名,表示有该后缀的文件都得遵守,该后缀名是自定义的,任何后缀都不会报错。
ThreadLocal
是一个解决线程安全问题的一个类。
可以为当前线程关联一个数据,只能关联一个,若是想关联另一个,必须开启另一个ThreadLocal。
每个ThreadLocal实例化的时候都是static 。
当ThreadLocal结束的时候,jvm虚拟机会自动释放保存的数据。
ThreadLocal像Map一样存储数据,key表示当前线程。
package www.hyb.Filter;import java.util.Random;public class ThreadLocalTest {// 创建一个ThreadLocalpublic static ThreadLocal<Object> data=new ThreadLocal<>();
// 以随机数表示一个数据的创建private static final Random random=new Random();
// 创建一个线程public static class Task implements Runnable{@Overridepublic void run() {// 每次进入一个线程,都创建出一个随机数int i = random.nextInt(1000);// 将数据放进ThreadLocal里data.set(i);// 可以考虑设置一下等待时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
// 为了演示,我们还可以在这里获取一个刚才设置的值System.out.println(data.get());/** 从这里可以获取,我们也可以在其他任何地方获取,在获取之前,我们可以先创建一个Order类* 在里面些一个方法来获取该线程关联的数据* */Order.print();}}public static void main(String[] args) {
// 开启三个线程,每个线程都会产生一个随机数,
// 前面我们在线程结束的时候都获取过设置的值,启动main方法后,控制台会显示。for (int i = 0; i < 3; i++) {new Thread(new Task()).start();}}
}
Order类
package www.hyb.Filter;public class Order {public static void print(){
// 获取当前线程名String name = Thread.currentThread().getName();System.out.println("当前线程"+name+"值为:"+ThreadLocalTest.data.get());}
}
JSON
- 一种轻量级数据交换格式,多种语言都支持,其中便包括java,js。
- 轻量级是指与xml文件做比较,解析xml的时间比json长。
- 交换格式是指客户端和服务器之间业务数据的传递格式。
基本入门
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">var jsonObj={"key1":1,"ky2":[1,"abc",false],"key3":{"key1":"key3_1"},"key4":[{"key4_1":"key_4_1"},{"key_4_2":"key_4_2"}]}alert(jsonObj.key1)for (var i=0;i<jsonObj.ky2.length;i++){alert(jsonObj.ky2[i])}alert(jsonObj.key3.key1)alert(jsonObj.key4[0].key4_1)alert(jsonObj.key4[1].key_4_2)</script>
</head>
<body></body>
</html>
常用方法
var jsonString=JSON.stringify(jsonObj);
//将对象转换成字符串格式,如java中的toString方法
alert(jsonString)
var json=JSON.parse(jsonString)
//将字符串格式转化为对象格式
alert(json)
与javaBean之间的转换
首先我们得创建一个javaBean
package www.hyb.Person;public class Person {private int id;private String name;private String sex;public Person() {}public Person(int id, String name, String sex) {this.id = id;this.name = name;this.sex = sex;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", sex='" + sex + '\'' +'}';} }
然后我们创建一个测试类
@Testpublic void jsonToJavaBean(){ // 获取一个Person对象1Person person = new Person(1,"hyb","男"); // 获取一个Gson对象Gson gson = new Gson(); // 将Person对象转换为Gson对象,利用toJson方法String s = gson.toJson(person);System.out.println(s); // 将Gson对象转换成一个Person对象,用fromJson方法Person person1 = gson.fromJson(s, Person.class);System.out.println(person1);}
JSON与List之间的转换
首先我们新建一个Java类
package www.hyb.Person;import com.google.gson.reflect.TypeToken;import java.util.List;public class PersonList extends TypeToken<List<Person>> { }
这个类什么也不写,只是继承一个类,并且输入集合的类型。
然后我们编写测试类,看看List集合如何互相转换json
@Testpublic void jsonToList(){Gson gson = new Gson();List<Person> list=new ArrayList<>();list.add(new Person(1,"hyb","男"));list.add(new Person(2,"zyl","女"));String s = gson.toJson(list);System.out.println(s); // 下面是将集合转换为json // 注意,以下写法是错误的,因为在json里,实际存放是一个Map,不是一个list集合 // gson.fromJson(list,list.getClass());List<Person> o = gson.fromJson(s, new PersonList().getType());System.out.println(o);System.out.println(o.get(0));}
jsonToMap
package www.hyb.Person;import com.google.gson.reflect.TypeToken;import java.util.Map;public class PersonMap extends TypeToken<Map<Integer,Person>> { }
@Testpublic void jsonToMap(){Gson gson = new Gson();Map<Integer,Person> map=new HashMap<>();map.put(1,new Person(1,"hyb","男"));map.put(2,new Person(2,"zyl","女"));String s = gson.toJson(map);System.out.println(s); // 将s转换成MapMap<Integer,Person> o = gson.fromJson(s, new PersonMap().getType());System.out.println(o);/** 为了解决每次从json转换成集合或者Map都要生成一个空类的问题,* 所以可以使用匿名类去解决每次都要新建一个类的问题* */Map<Integer,Person> p=gson.fromJson(s,new TypeToken<Map<Integer,Person>>(){}.getType());System.out.println(p);}
AJAX
- 是一种开发交互网页的技术。
- 是浏览器通过js异步请求,局部更新网页的一种技术。
原生JS
在原生js中,也可以发出AJAX请求,但会相对麻烦一点,首先,我们先创建一个html页面。
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>ajax请求页面</title><script type="text/javascript">function getAjax() {}</script> </head> <body><button onclick="getAjax()">ajax请求</button><div id="ajax" style="color: red"></div> </body> </html>
我们先绑定一个单击事件,但这个事件要发送请求到一个Servlet中,所以我们得先创建一个Servlet
但在创建Servlet之前,我们得先编写BaseServlet
package www.hyb.AJAX;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method;public abstract class BaseServlet extends HttpServlet {/** 注意:我们点击后台管理的a标签,不会直接跳到后台管理,因为a标签是get请求,而我们原先是post请求* 所以在这里我们要用get请求方法调用一次post请求才有效。* */protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");String action = request.getParameter("action");try {Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);method.invoke(this, request, response);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}} }
然后再编写请求的Servlet
package www.hyb.AJAX;import com.google.gson.Gson; import www.hyb.Person.Person;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class AjaxServlet extends BaseServlet{protected void getAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Gson gson = new Gson();Person person = new Person(1, "hyb", "男");String s = gson.toJson(person); // Servlet做出回应response.getWriter().write(s);}}
通过Servlet,我们存储到一些数据。下面是编写js里的单击请求事件。
function getAjax() { // 创建XMLHttpRequestlet xmlHttpRequest = new XMLHttpRequest(); // 调用open方法设置请求参数 // "请求方式","请求地址","是否是异步请求"xmlHttpRequest.open("GET","http://localhost:8081/JSON/ajaxServlet?action=getAjax",true); // 绑定onreadystatechange事件/** 这个事件理论上是在send之后的* 但这里最好是在send之前,不然会出一点小问题。* 但是会产生一个问题,若是放在send之前,我们还没发送请求,这里的代码会有效果吗?* 当然会有效果,因为ajax是异步请求,代码位置并不影响效果。* */xmlHttpRequest.onreadystatechange=function(){if (xmlHttpRequest.readyState===4 && xmlHttpRequest.status===200){//将数据放入div盒子里,但现在得到的是字符串,我们要转换成json,方便用户查看var json=JSON.parse(xmlHttpRequest.responseText);document.getElementById("ajax").innerHTML="编号:"+json.id+"姓名:"+json.name+"性别:"+json.sex;}} // 调用send方法发送请求xmlHttpRequest.send(); }
特点
局部更新:
前面可以看到,这个ajax是局部更新的,地址栏并不会发生变化,比如说,我修改的只是这个页面中的某个表格中的数据,但其他数据还是存在的。而非ajax请求,要想进行局部更新,地址栏肯定要发生变化,只不过是返回一次原来的页面而已。
异步请求:
解释异步请求之前,我们先理解一下同步请求,在open方法中,若布尔值之false便是同步请求,假设这里是false,我们在send方法后加入一个alert(),内容随便,开启服务器浏览网页之后你便会发现,我们加入的这个alert,只等等到前面的代码执行完毕才能执行,也就是说必须要先前的准备好。
而我们修改成true的话,加入的alert会先执行,因为前面的还没有准备好。
还比如说我们在body标签下加多几个ajax请求的按钮,若是用同步请求,你会发现只要你点击了第一个请求按钮,剩余的请求便不能再自动执行了。若使用异步请求,这些按钮都可以分别点击,都能请求成功,与其他按钮毫无相关。
JqueryAJAX
- 下面介绍JQuery对AJAX的封装,例子的html页面和Servlet程序都一样。下面只说明js部分。
AJAX请求
$(function () {$("#getAjax").click(function () {$.ajax({url:"http://localhost:8081/JSON/ajaxServlet",Type:"GET",data:"action=getJqueryAjax",success:function (data) {// var json=JSON.parse(data)$("#ajax").html("编号:"+data.id+"姓名:"+data.name+"性别:"+data.sex)},dataType:"json",})});
})
GET请求
$.get("http://localhost/8081/JSON/ajaxServlet","action=getJqueryAjax",function (data) {$("#ajax").html("编号:"+data.id+"姓名:"+data.name+"性别:"+data.sex)
});
POST请求
$.post("http://localhost/8081/JSON/ajaxServlet","action=getJqueryAjax",function (data) {$("#ajax").html("编号:"+data.id+"姓名:"+data.name+"性别:"+data.sex)
});
getJSON
- 请求固定,为get请求。
$.getJSON("http://localhost/8081/JSON/ajaxServlet","action=getJqueryAjax",function (data) {$("#ajax").html("编号:"+data.id+"姓名:"+data.name+"性别:"+data.sex)
});
表单序列化
在前面我们学过一个表单提交后是要刷新页面,传送数据到Servlet的,现在我们用AJAX请求的方法,将数据传给Servlet。
但是,我们也要将表单的数据项发送给Servlet,这个时候就需要表单序列化。
要将表单序列化,首先得使用一个函数,serialize()。
首先我们要编写好一个拥有表单的页面,记住,这个表单一定要规范:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>表单序列化</title></head> <body><form id="formSerialize"><label for="username">用户名:</label><input type="text" id="username" name="username" /><br><label for="password">密码:</label><input type="password" id="password" name="password"/><br><input type="submit" id="submit" value="提交"></form></body> </html>
为什么说这表单一定要规范,比如说,input标签一定要加入name属性,因为表单是靠key=value表示输入的值的,如果你不用那么属性,表单提交的时候并不会提交这些值上去。
其次,我们这个提交的input标签,要写一个id选择器或者其他选择器,方便JQuery识别。
下面是js代码,表示AJax的请求,将表单提交到一个Servlet中。
<script type="text/javascript">$(function () {$("#submit").click(function () {let jQuerySerialize = $("#formSerialize").serialize();$.getJSON("http://localhost:8081/JSON/ajaxServlet","action=getJquerySerializeAjax&"+jQuerySerialize,function (data) {});});}) </script>
上面要注意的点的是,地址一定要正确,和之前一样,是表单请求的一个Servlet地址,其次,action属性也一定要正确,并且最重要的时候action属性后要加上&符号,这表示后面紧跟表单提交上来的属性。function为回调函数,可以空着。
接下来我们在Servlet这边测试,表单提交的参数是否被传过来了。
protected void getJquerySerializeAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println(request.getParameter("username"));System.out.println(request.getParameter("password")); }
i18n国际化(了解)
概念
- 指的是一个网站支持多种不同的语言。
- 但目前多数公司都用苹果公司的标准,即一个网站在不同国家布局不一样,所以国际化只需了解。
三要素
- 准备不同国家语言的Locale对象
- 准备两个properties后缀的配置文件,这些个配置文件,key和值都要相同,只不过用不同的语言。且这个配置文件的命名,要有一些规范,例如:i18n_zh_CN.properties i18n开头,zh_CN代表中国汉字。
- 利用ResourcesBundle资源包获取配置文件信息。
入门
首先准备两个配置文件,一个英文,一个中文。
username=username password=password
username=用户名 password=密码
这两个配置文件必须放在src下。不能镶嵌在其他包里。
然后便是编写测试类测试。
@Testpublic void getI18nTest(){ // 获取Locale对象Locale locale= Locale.CHINA; // 利用ResourceBundle获取配置文件ResourceBundle i18n = ResourceBundle.getBundle("i18n", locale);System.out.println("username="+i18n.getString("username"));System.out.println("password="+i18n.getString("password"));}
乱码问题请点击file setting editer file-encoding,勾选……ascii converson
jsp页面国际化
首先我们准备两个properties文件,和之前的一样。
其次便是导入JSTL包。
然后编写一个jsp页面,里面有两个a标签
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>i18n国际化</title> </head> <body><fmt:setLocale value="${param.locale}"/><fmt:setBundle basename="i18n"/><a href="i18n.jsp?locale=zh_CN">中文</a><a href="i18n.jsp?locale=en_US">English</a><p><fmt:message key="username"/> </p><p><fmt:message key="password"/> </p> </body> </html>
可见,在这个jsp页面里,点击中文便能获取文件里的内容,点击英文便能获取文件里内容,以各自语言为基础。
九万字的JavaWeb学习记录,从入门到入坟,更近一步相关推荐
- 网络安全学习路线,入门到入坟,史上最全网络安全学习路线整理
很多小伙伴在网上搜索网络安全时,会出来网络安全工程师这样一个职位,它的范围很广,只要是与网络安全挂钩的技术人员都算网络安全工程师,一些小伙伴就有疑问了,网络安全现在真的很火吗? 那么寒哥就带大家看看, ...
- FHQ-Treap(非旋treap/平衡树)——从入门到入坟
作者:hsez_yyh 链接: FHQ-Treap--从入门到入坟_hsez_yyh的博客-CSDN博客 来源:湖北省黄石二中信息竞赛组 著作权归作者所有.商业转载请联系作者获得授权,非 ...
- 从入门到入坟搭建FreeNAS服务器并配置NextCloud_NAS存储
从入门到入坟搭建FreeNAS服务器并配置NextCloud 2021-01-06 23:15:38 173点赞 963收藏 100评论 创作立场声明:本文所有商品皆自费购入,第一次发表文章,若有不当 ...
- 【教程汇总+持续更新】Unity游戏开发从入门到入坟
新的一年,本该在年前整理的年终总结被拖到了年后开工.去年大量时间投入在Catlike教程的翻译上,截止目前位置,教程的进度已经完全追平原作者. 去年还有一部分是断断续续的更新SLG实战教程,但遗憾的是 ...
- canvas 从入门到入坟
文章目录 canvas 从入门到入坟 1. 概述 2. 使用场景 2.1 图表的绘制 2.2 canvas游戏 2.3 说明与作用 3. Canvas 入门 3.1 完成目标 3.2 初始化 3.3 ...
- 深聊MySQL,从入门到入坟之:MySQL竟然也有后悔药!!!
MySQL后悔药,防止看铁窗 1.引言 2.5种后悔药 2.1 limit 2.2 先测试后生产 2.3 删除前,先备份 2.4 删除前,先查询 2.5 修改时, begin+commit 3. 总结 ...
- 初阶指针---从入门到入坟
今天我们来见识一下c语言里让万千少年少女从入门到入坟的一道大门槛--指针 目录 1.指针是什么? 2.指针和指针类型 3.野指针 4. 指针运算 5. 指针和数组 6. 二级指针 7. 指针数组 1. ...
- MongoDB学习记录:入门(一)——五叶草
预热看我之前的文章Node学习记录: mongodb 这个系列旨在系统的学习Mongodb 部分图片来自慕课网mongodb入门截图 学习目标 MongoDB官网:https://www.mongod ...
- javaweb学习,快速入门
javaweb 1.基础概念 web开发 web网页的意思 静态web html css 提供给所有人看的数据始终不会发生变化 动态web 淘宝,几乎所有的网站 提供给所有人看的数据始终会发生变化,每 ...
- javaweb学习记录-qqzone项目-结构分析
回顾下之前学习的水果项目的mvc各层设计 qqzone项目结构 几个问题及分析 3. 系统启动时,我们访问的页面是: http://localhost:8080/pro23/page.do?opera ...
最新文章
- VTK:vtkBalloonWidget用法实战
- html的<input type='radio'/>change事件坑
- 转:使用 Tkprof 分析 ORACLE 跟踪文件
- weakhashmap_Java WeakHashMap get()方法与示例
- C#利用CDOSYS组件发邮件的一些小结
- rsyslog mysql ip_使用rsyslog+loganalzey收集日志显示客户端ip
- 通过银行卡号查询银行卡类型接口
- 不越狱破解A1528 iPhone5s移动联通4G网络
- Spring Cloud原理分析系列#Gateway#GlobalFilter vs GatewayFilter vs WebFilter
- 美女数码宝贝(天女兽、蔷薇兽、花仙兽、莉莉丝兽、维纳斯兽、仙女兽、人鱼兽、古代人鱼兽、丁香兽)
- 百融云创被传赴港IPO急辟谣 旗下信贷业务存众多质疑
- 2020 中信银行 软件开发中心 社招 8.23晚上在线笔试 进展讨论
- 我的世界服务器披风文件在哪,关于我的世界国际版披风导入方法与详解(联机可用...
- Texmaker+Miktex配置
- 如何获得指定进程的主窗口
- 普宁市中学高考成绩查询2021,2021年中山高考状元多少分是谁,中山高考状元名单资料...
- erp服务器安装虚拟打印机,ERP-U8,安装了打印机驱动,可是打印机与传真里面没有虚拟打印机,无法会话打印怎么办?...
- SECVISION智能楼宇视频监控防泄密解决方案
- 市场上有很多低代码开发平台,不懂编程的人可以用哪些?
- 思博伦收购octoScope