HTML
一、html结构
<!DOCTYPE html> h5默认的文档声明
<html> html根标签
<head> 头标签
<meta charset="utf-8"> 页面编码格式
所有的现代浏览器:谷歌/火狐/IE8+以上的/欧鹏浏览器/洋葱浏览器/
windows自带的edge 浏览器识别的编码:utf-8
<title>窗口标题</title> 指定的页面的窗口标题
</head>
<body>
内容标签等
<body>
</html>
二、文本标签
1、标题标签: h1-h6:从大到小。<h1> 文本 </h1>
2、<hr/> :水平线标签,效果为分割线,分割前后两端内容
3、段落标签:<p> 内容</p>。内容前后两端内容自动换行
4、换行标签<br/>
5、字体滚动标签: marquee。<marquee behavior=“xx” />属性如下:
(1) behavior=“xx” 滚动方式。slide:滚动到某一边停止。scroll:穿梭滚动。alternate:来回滚动
(2)scrollamount="xx" 滚动速度。正整数值,值越大,速度越快
(3)direction="xx" 方向。默认值 left :从右到左、right:从左到右、down:上到下、up:下到上
6、bgcolor="xx" 设置背景色
7、 <blockquote> 文本内容</blockquote> 文本内容进行首行缩进
8、上标标签:<sup>XX</sup>
9、下标标签:<sub>XX</sub>
10、特殊转义字符:
©--- "©" 版权所有
&re----"®" 注册商标
代表一个空格
 代表两个空格
> 代表>
< 代表<
< br/> 原文输出<br/> ,不输出换行
11、原样输出标签: <pre>XX </pre> 按照文本内容原样输出
12、设置字体加粗标签:
<strong>XX</strong>---对字体加粗,没有语义的强调
<b>XX</b>---有语义的强调
13、斜体标签:
<em>XX</em>:斜体,没有语义的强调
<i>XX</i>:斜体,没有语义的强调
14、字体标签:<font color="XX" >文本</font>。属性如下:
1)color="XX":字体颜色
2)size="XX" 字体大小
3)center: 居中
<center>
<font color="blue" size="7">字体标签</font>
</center>
三、列表标签
1、无序列表
<ul >
<li>内容</li>
</ul>
无序列表type属性:<ul type="XX">
type="disc" :小黑圆圈
type="circle":空心原点
type="square":小正方形
2、有序列表
<ol >
<li>内容</li>
</ol>
有序列表type属性: <ol type="XX">
type="1":数字顺序排列
type="A":字母顺序排列
3、列表分类
<dl> ---定义列表
<dt>列表项的分类</dt>
<dd>具体列表内容1</dd>
<dd>具体列表内容2</dd>
<dd>具体列表内容3</dd>
</dl>
四、超链接标签
超链接a标签
第一种用法:跳转到指定的另一个链接地址url(统一资源定位符)
属性1)url:
访问的外部资源地址
协议://域名:端口号/具体访问页面地址
跳转到百度的注册页面 端口号:如果是80端口,可以省略不写
访问当前项目下的01_html常用基础标签.html页面,url地址不带协议
属性2)target:打开资源文件的方式
_blank:新建窗口打开
_self:当前窗口直接打开(默认值)
第二种用法:
锚连接:在同一个页面或者不同页面上进行"书签"的一种标记
同一个面下:
1)创建跳转标记---相当于打一个"书签"
<a name="锚点名称"></a>
2)创建跳转链接---跳转到"书签上"
<a href="#锚点名称">跳转指定位置</a>
不同页面跳转指定的锚点(标记)
1)创建跳转标记---在另一个页面的某个位置打标记--相当于打一个"书签"
<a name="锚点名称"></a>
2)创建跳转链接---跳转到"书签上"
<a href="url地址#锚点名称">跳转指定位置</a>
五、图像标签
一、图片
<img src="图像地址" /> ---一般存放在img文件中,使用相对路径
属性: <img width="XX" />
1、width = "10px" / height= "10px" ---照片宽度、高度。 width = "100%" ---铺满
2、title="文本" ---鼠标悬停在图片上时提示的文本文字
3、alt="文本" ---图片加载失败时提示的文字
4、align="xx" ---图片在浏览器中对其方式
(1)align="left" ---左对齐,默认
(2)align="center" ---居中
(3)align="left" ---右对齐
链接式图像:使用超链接将图像标签包起来,点击图像跳转到指定页面上
<a href="06_商品详情页.html" target="_self">
<img src="/day38_HTML_CSS/img/2.jpg" width="1000px" height="500px" alt="这是一个红米的手机图片" title="红米" /> </a>
二、背景图片
<body background="图片地址"> ---一般存放在img文件中,使用相对路径
注意事项:超链接标签的href属性以及图像标签的src属性="url地址"都会进行加载(加载url地址,如果是服务器地址,就需要向服务器再次发送请求)
六、表格标签
格式:
<body>
<table >
<caption>文本</caption> ---表格上标题
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr >
<td>张三</td>
<td>19</td>
</tr>
</table>
</body>
1、table:列表标签
table属性:
(1)<table border="1px">:表格边框线粗细
(2)<table align="left">:表格在浏览器中对齐的位置,或者在行标签指定align:每一行单元格都居中
left ---浏览器上方左对齐,默认
center ---浏览器上方居中对齐
right ---浏览器上方右对齐
(3)<table cellspacing="0">:表格边框线和单元格间的空隙
(4)<table cellpading="0">:控制单元格的内容和边框之间的间距
(5)<table bgcolor="red">:表格的背景颜色
(6)<table width/height="10px">:表格宽度、高度
2、<caption>文本</caption>:表格上方的标题
3、tr:行标签。<tr align="center"> ---行内容居中
4、th:行中的第一行表头内容,自动加粗居中
5、td:行中单元格具体内容
td属性:
(1)<td rowspanspan="5">内容</td>:5行进行合并
(2)<td colspan="5">内容</td> 5列进行合并
6、子标签 caption:给表格设置标题元素
七、表单标签
用户录入"用户信息",通过"表单"将用户的数据提交给服务器,服务器去接收数据
录入的时候,表单中表单元素必须指定name属性,给后端进行标记用户输入实际内容
1、表单标签form格式
<body>
<form action="server.html" method="post">
用户名:<input type="text" placeholder="请您输入用户名" name="username" />
<input type="submit"value="注册">
</form>
</body>
2、form属性
(1)action:<form action="提交到的服务器地址url">
(2)<form method="post"> 提交方式post/gest
(3)<input type="submit" value="注册">:注册按钮
3、表单项
(1)type="hidden":隐藏域,(页面中没有任何效果,可以提交数据)
<input type="hidden" name="id" value="id01" />
(2)type="text" :文本输入框
用户名:<input type="text" name="username" placeholder="请输入用户名" />
(3)type="password" :密码输入框
密码:<input type="password" name="pwd" placeholder="请输入密码" />
placheoder:文本框提示信息
(4)type="radio" :单选按钮,指定同一个name,必须只能选一个
<input type="radio" name="sex" value = "0"/>男
<input type="radio" name="sex" value = "1"/>女
(5)type="checkbox":复选框,选择多个内容,必须指定相同的name属性
<input type="checkbox" name="hobby" value = "0"/>游泳
<input type="checkbox" name="hobby" value = "1"/>健身
(6)type="date" : 日期组件,2023/2/18
<input type="date" name="birthday" />
(7)type="email":邮箱组件,必须满足邮箱格式,XXX@XXX
<input type="email" name="Email" />
(8)type="file":文件上传组件,form表单必须加一个属性 enctype="multipart/form-data"
<input type="file" name="txt" />
(9)type="botton":按钮组件,必须结合value使用
<input type="botton" name="按钮名称" />
(10)type="reset":重置按钮,将前面已输入的内容清空重置
<input type="reset" name="清空" />
(11)下拉菜单
<select name="籍贯">
<option>陕西省</option>
<option>广东省</option>
</select>
(12)文本域
<textarea rows="5" cols="30">
文本内容文本内容
</textarea>
属性:rows,文本域能够写几行。cols:一行能书写的字符个数
(13)超链接嵌套按钮
<a href="跳转地址"> <input type="botton" value="登录">
八、iframe画中画
<iframe src="URL" width="指定内联框架宽度" height="高度"></iframe>
url:连接点页面或者资源文件的统一资源定位符号
<iframe src="01_框架标签/table_data.html" width="1000px" height="500px"></iframe>
九、value属性和placeholder属性的区别
value:
在html表单元素中(文本输入框/密码输入框/复习框/单项按钮/下拉菜单....),这些元素的默认值;
结合js事件(获取焦点事件,输入的时候,就将这个默认值删除)
placeholder:
表单元素的新增属性, 字体灰色,当键入内容之后,就自动删除(效果)
十、get方式和post方式提交区别
(1)是否提交在地址栏上
get方式将数据提交到地址栏上的, action提交的地址url?key1=value1&key2=value2....(浏览器默认get提交)
post提交方式,不会将数据提交到地址栏上,在浏览器(F12--进入调试器)--->"网络"里面的负载 可以看到表单提交的数据 (post提交针对中文会出现乱码)
(2)是否适合私密数据提交
get提交方式,相对post来说不安全,地址栏是可以直接看到明文的敏感数据
post提交方式,相对get来说安全,地址栏不会直接看到具体内容;针对隐私数据,post提交的数据也需要加密
get/post提交的数据(密码等等)----加密的! md5加密(信息摘要算法) "123456" + 加盐 "qianfeng" 保证不会被破解
3)提交数据大小是否有限制
get提交方式,在地址栏上提交数据,提交数据大小有限制
post提交方式,是在浏览器中 网络中的请求头后面的负载里面可以直接不断去提交数据,没有大小限制
CSS
一、css概念
CSS:层叠样式表 Cascading Style Sheet。通过CSS给页面添加修饰效果
二、给标签添加样式使用方式
1、行内样式
<body>
<a href="XXX" style="color: red; font-size: 25px; text-decoration: none;">超链接</a>
</body>
style="样式属性名称1:样式值1;样式属性名称2:样式值2;..."
每一个html标签都有属性style(样式),一次只能控制一个标签。适用于在局部位置设置某个标签样式
2、内联样式(css内部方式)
<head>
<meta charset="utf-8">
<title>XXX</title>
<style>
常用标签名称(a){
样式属性名称1:值1;
样式属性名称2:值2;
...
(color:orange)
}
</style>
</head>
<body>
<a href="#">超链接</a>
</body>
弊端:html标签和css代码混合使用,不利于后期项目维护
3、外联方式(CSS外部样式)
(1)<head>
xxx
<link href="css文件地址" rel="stylesheet" />
</head>
(2)<head>
<style>
@import url("css文件路径");
</style>
</head>
1)在css文件夹中新建一个.calss文件
2)使用 css选择器{
样式属性名称1:值1;
样式属性名称2:值2;
...
}
3)在当前页面导入css文件
rel="stylesheet" ---固定格式,必须写,"关联样式库中样式"
4、在当前html页面中导入css样式, 在head标题体中
(1) <link href="css/xx.css文件" rel="stylesheet" />
(2) <style>
@import url("css/xx.css文件")
</style>
三、CSS选择器
优先级: id选择器 > class类选择器 > 标签名称选择器
1、标签名称选择器
标签名称{
样式名称1:值1 ;
样式名称2:值2 ;
}
<style>
div{
color: skyblue;
font-size: 20px;
}
</style>
2、class(类)选择器
.class属性值{
样式名称1:值1 ;
样式名称2:值2 ;
}
<style>
.class01{
color: orange;
font-size: 30px;
}
</style>
3、id选择器
#id属性值{
样式名称1:值1 ;
样式名称2:值2 ;
}
<style>
#id01{
color: green;
font-size: 35px;
}
</style>
在标签中指定id属性="id值"(不能以数字开头,字母开头)
id属性值在同一个html页面中,必须是 "唯一的"
4、子元素选择器
选择器1 选择器2{
样式名称1:值1 ;
样式名称2:值2 ;
}
选择器2选中的标签是选择器1选中标签的子标签
5、并集选择器
选择器1,选择器2,选择器3....{
样式名称1:值1 ;
样式名称2:值2 ;
}
6、伪类选择器
1、标签的四种状态:
(1)、 link:鼠标没有访问标签的状态
(2)、 hover:鼠标经过这个标签的状态
(3)、 active:鼠标点击且没有松开的状态
(4)、 visited:鼠标已经点击访问过的状态
visited升到放在link之后才能循环使用
伪类名称对大小写不敏感
2、伪类选择器格式
选择器名称(标签名称/class/id):状态名称{
样式名称:值;
...
...
}
<style>
a:link{
color: red;
font-size: 20px;
}
<body>
<a href="XXX">文本</a>
</body>
四、CSS背景样式
1、CSS背景格式
<head>
<style>
body(标签选择){
background(背景属性): 背景颜色 图片文件地址 背景图片是否重复 背景图片起始位置 ;
}
</style>
</head>
背景的简写属性:
background:background-color background-image background-repeat backgound-position;
示范 background: darkgray url(img/index_right.jpg) no-repeat top center;
必须严格按照顺序
2、CSS背景属性
1、background-color:背景颜色
2、background-image: url(图片文件地址)
3、background-repeat:背景图片是否重复,如何重复
(1)background-repeat,默认,图片尺寸达不到当前屏幕分辨率,x轴/y轴都重复
(2)background-repeat-x:x轴重复
(3)background-repeat-y:y轴重复
(4)background-no-repeat:不重复
4、background-attachment:背景附着: 设置fixed 固定,图片不会随着页面滚动而滚动
5、background-position:设置背景图像的起始位置,默认左上对齐
top left
center center
bottom right
background: red url(xxx) no-repeat top center
五、CSS文本样式
<head>
<style>
选择器{
样式1:值1;
样式2:值2;
}
</style>
</head>
1、文本颜色:color
2、文本对齐方式:text-align
(1)tetx-align:left---左对齐,默认
(2)text-align:center---居中
(3)text-align:right---右对齐
3、文本装饰:text-decoration
text-decoration:onoe---删除链接的下划线
text-decoration:underline---设置下划线
text-decoration:voerline---上划线
text-decoration:line-through---中划线
4、文本字符间距
(1)letter-spacing:10px
(2)word-spacing:20px 两个字组成一个词
5、大小写转换:text-transform
text-transform:uppercase ---转换成大写字母
text-transform:lowercase ---转换成小写字母
6、文本缩进 textt-indent:10px ---指定文本第一行缩进
7、行高 text-height:20px
六、CSS字体样式
<head>
<style>
选择器{
样式1:值1;
样式2:值2;
}
</style>
</head>
1、字体格式 font-family=“黑体”
2、字体类型 font-style
(1)font-style:normal 默认字体类型
(2)font-style:italic 斜体
(3)font-style:oblique 斜体
3、字体粗细 font-weight:10px bold:等价于700
4、字体大小 font-size:20px
font的简写
font:字体类型 字体粗细 字体大小 字体格式 ---按顺序
font:italic bold 20px “仿宋”
七、CSS边框样式
1、边框颜色
(1)border-top-color:上边框颜色
(2)border-bottom-color:底边框颜色
(3)border-left-color:左边框颜色
(4)border-right-color:右边框颜色
2、边框宽度
(1)border-top-width:上边框宽度
(2)border-bottom-width:底边框宽度
(3)border-left-width:左边框宽度
(4)border-right-width:右边框宽度
3、边框样式
(1)border-top-style:上边框样式
(2)border-bottom-style:底边框样式
(3)border-left-style:左边框样式
(4)border-right-style:右边框样式
边框样式值:solid(单实线)、double(双实线)、dashed(虚线)、dotted(点)
border的简写属性
border:边框宽度 边框样式(必须有) 边框颜色 ---按顺序
border:10px solid red
八、CCS列表样式
一、无序列表
<style>
ul{
}
ul li{
}
</style>
1、列表标记类型
(1)list-style-type:none ---去掉列表项前面的标记
(2)list-style-type:square ---小黑正方形
(3)list-style-type:circle ---空心圆点
(4)list-style-type:disc ---小黑圆圈,默认
2、将图片指定为列表标记项 list-style-image
list-style-image;url(图片地址)
3、display-inline 设置到同一行上
li {
display: inline;
}
浮动列表项
创建水平导航栏的另一种方法是浮动 <li> 元素,并为导航链接规定布局:
li {
float: left;
}
a {
display: block;
padding: 8px;
background-color: #dddddd;
}
4、border-collapse 属性设置是否将表格边框折叠为单一边框: collapse:合并
九、浮动
浮动和清除
CSS float 属性规定元素如何浮动
CSS clear 属性规定哪些元素可以在清除的元素旁边以及在哪一侧浮动
float 属性用于定位和格式化内容,例如让图像向左浮动到容器中的文本那里。
float 属性可以设置以下值之一:
left - 元素浮动到其容器的左侧
right - 元素浮动在其容器的右侧
none - 元素不会浮动(将显示在文本中刚出现的位置)。默认值。
inherit - 元素继承其父级的 float 值
clear 属性可设置以下值之一:
none - 允许两侧都有浮动元素。默认值
left - 左侧不允许浮动元素
right- 右侧不允许浮动元素
both - 左侧或右侧均不允许浮动元素
inherit - 元素继承其父级的 clear 值
十、CSS定位
定位属性:position 也可以进行部分内容的布局
position:绝对定位 absolute:根据当前元素的父元素进行移动的
相对定位 relative:根据之前元素的位置进行移动的方式
固定定位 :fixed:永远在页面中指定位置,不会随着滚动而滚动
top:整个元素向下移动
left:整个元素向右移动
盒子模型
概念:
(1)将任何标签都看成盒子,整个页面布局大体方向先使用div将内容包裹起来,形成 "层级" ,一个页面分成了很多块。给div加入id/class等选择器,通过css样式属性精准控制
(2块级元素:
div 占一行标签
h1-h6 占一行内容
(3行级元素:
<br/> <span>
(4)将html页面中任何标签 看成一个"盒子"
容量:width/height
厚度: 边框 border
内边距:padding 盒子的内边距: 边框和内容之间的距离(上右下左)
外边距:margin 盒子和盒子之间的距离:通过外边距让整个盒子进行移动!
<head>
<link href="css文件" rel="stylesheet" /> ---导入外部css样式
</head>
<body>
<div id="formDiv">
<form>
<div id="userDiv">
<label for="username">用户名</label>
<input type="text" id="username" placeholder="请输入用户名" />
/* label元素和input输入元素是一个表单组,
able里面for必须和input标签中id一致*/
</div>
<div id="btnDiv">
<input id="register" type="submit" value="注册" />
</div>
</div>
</body>
框架标签
概念:
框架标签:frame,一个frame包含一个html页面
<frame src="链接到的html页面地址" name="当前框架名称" />
如果整个页面结构并非一个html组成,而是两个或者两个以上的html页面组成,需要使用框架集frameset
一、框架
frame:框架标签。
src="链接到html页面地址"
name="给框架标签起名称"
frameset框架集。不能和body共存
<frameset rows="20%,*"> *:代表剩下的百分比 20%就是头部页面
rows属性:由上而下划分,每一个部分所占的权重百分比
<frame src="01_header.html" /> ---链接头部html页面地址
<frameset cols="15%,*"> *:代表剩下的百分比 15%是左边菜单页,剩下为中间主页
cols属性:由左而右划分,每一个部分所占的权重百分比
<frame src="02_menu.html" /> ---链接菜单html页面地址
<frame src="03_main.html" name="main" />
超链接的target打开方式。如果在框架标签中使用,target也可以指定在哪个一个frame中打开,需要和frame标签中name属性值一致!
</frameset>
</frameset>
二、菜单页面-menu
<body>
<ul>
<li>
<a href="student_table.html" target="main">查询所有学生</a>
超链接的target打开方式,如果在框架标签中使用,target也可以指定在哪个一个frame中打开需要和frame标签中name属性值一致!
</li>
<li>
<a href="../01_格式优雅的表单.html" target="main">教师管理</a>
</li>
</ul>
</body>
三、中间主页面-main
四、头部页面-header
font、boostrap框架引入
一、使用方式
1)将font图标库的css文件夹和font文件夹放在前端项目下
2)将boostrap前端框架这里面所有css文件夹的内容以及font文件夹的放在当前项目下
3)首先页面中导入boostrap全局样式boostraom. min.css(压缩版)
4)在head标题体中导入第三方提供的 font-awesome.min.css图标样式
二、样例
(1)
<head>
导入css样式
<link href="../css/bootstrap.min.css" rel="stylesheet" />
<link href="../css/font-awesome.min.css" rel="stylesheet" />
</head>
<body>
<div>
<a href="../01_个人中心.html" target="_top"> ---top弹出
<i class="icon-user icon-large"></i>
图标库提供标签 i标签 里面使用class属性="icon-user"
</a>
</div>
</body>
(2)
<head>
<title>学生信息表</title>
<style>
@import url("../css/bootstrap.min.css");
----导入前端框架boostrap提供css样式库 import引入----
</style>
</head>
<body>
<table class="table table-striped table-bordered table-hover">
<tr>
<th>姓名</th>
<th>操作</th>
</tr>
<tr>
<td>高圆圆</td
<td>
<input type="button" class="btn btn-primary" value="修改" />
<input type="button" class="btn btn-danger" value="删除" />
boostrap提供按钮样式
class="btn btn-primary" 深蓝色(首选项效果)
class="btn btn-danger" 危险图标
</td
</tr>
</table>
</body>
boostrap
jsp中导入boostrap样式
//导入bootstrap的css样式
<link href="css/bootstrap.min.css" rel="stylesheet"/>
//导入js库,需用用到boostrap框架js插件,在导入boostrap.min.js之前,先导入Jquery
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
boostrap格栅
1)布局容器
class="container":容器:是固定宽度并且支持响应式布局
class="container-fluid":容器:是支持width,100%(占整个视口宽度)
2)行 class="row"
3)行定义列 column class="col-设备编号-所占的列数量"
设备编号:
xs :超小桐木 手机 <768px
sm :小屏幕 平板>=768px
md :中等屏幕 桌面显示器 (≥992px
lg :大屏幕 大桌面显示器 (≥1200px)
class ="table-bordere" 设置边框
<div class="container-fluid">
<!--定义行 class="row"-->
<div class="row">
<!--列 column:-->
<div class="col-md-4 table-bordered">col</div>
<div class="col-md-4 table-bordered">col</div>
<div class="col-md-4 table-bordered">col</div>
</div>
<!--第二行-->
<div class="row">
<div class="col-md-8 table-bordered">
<a href="#">笔记本专区</a>
<a href="#">手机专区</a>
<a href="#">户外设备专区</a>
</div>
<div class="col-md-4 table-bordered">
<input type="text" />
</div>
</div>
</div>
boostrap表格样式
class="table"基本表格样式
class="table-striped" 斑马条纹样式
class="table-bordere" 为单元格增加边框
class="table-hover " 鼠标悬浮在上面有样式效果
class="table-condensed" 紧缩表格
class="table-responsive" 响应式表格,视口尺寸小于768像素开始出现水平滚动条,大于768px水平滚动条消失
给tr行上加入的的样式
class="active": 鼠标悬停在行或单元格上时所设置的颜色
class="success"成功标识的颜色
class="danger"成功标识的颜色
<table class="table table-responsive table-striped table-condensed table-bordered table-hover">
<tr>
<th>商品编号</th>
<th>商品名称</th>
</tr>
<tr class="active">
<td>1</td>
<td>小米p10</td>
</tr>
<tr class="success">
<td>2</td>
<td>小米p10</td>
</tr>
boostrap表单样式
class="form-horizontal" 设置表单水平排列表单
laber元素和input组件在一行上
class="form-group" 包含laber和input或者select下拉菜单
class ="form-control" :将input元素或者select或者textarea设置为100%宽度
boostrap按钮样式
class="btn btn-default" 默认样式按钮
<input type="button" class="btn btn-default" value="按钮" />
<input type="button" class="btn btn-primary" value="修改" />
<input type="button" class="btn btn-danger" value="删除" />
<input type="button" class="btn btn-warning" value="警告按钮" />
class = "btn-group"按钮组,将所有的按钮放在 同一行上
boostrap导航条
nav:导航组件:水平导航条
class="navbar navbar-default":导航条样式
boostrap分页
<nav aria-label="Page navigation">
<ul class="pagination">
<!--上一页-->
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<!--分页页码-->
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<!--下一页-->
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
URL和URI
url:统一资源定位符 是URI的子集
http://localhost:8080/day38_HTML_CSS/01_html%E5%B8%B8%E7%94%A8%E5%9F%BA%E7%A1%80%E6%A0%87%E7%AD%BE.html
URI:定位符: 前面没有带协议
/day38_HTML_CSS/01_html%E5%B8%B8%E7%94%A8%E5%9F%BA%E7%A1%80%E6%A0%87%E7%AD%BE.html
URI的范围大于url
URI--->/web项目名称/资源文件名称
/day38_HTML_CSS/---->web项目的上下文路径(Application Context)
web项目一般都需要带上 "上下文路径名称",防止前端请求会出现404:一般页面地址找不到
JavaScript
JavaScript的变量定义及类型划分
javascript(js):属于弱类型语言 (语法不严谨)
1)定义变量使用var定义 ,可以重复定义变量
2)var可以定义任何类型,而且可以省略
js类型划分:
基本类型 引用类型
(整数/小数)number 数值类型 提升为 内置对象:Number:数值对象
(双引号括起来的/单引号括起来的)String 提升为 内置对象:String:字符串对象
boolean类型 提升为 内置对象:Boolean
object类型 创建对象 提升为 内置对象Object:所有js对象的模板
undefined 未定义类型 (没有意义)
js内置的常用函数:
给浏览器输出内容
document.write(输出内容) ;
console.log(输出内容):在浏览器-f12---控制台里面的日志信息
查看变量的数据类型
typeof(变量名)
js经常测试:是否能够获取数据通过弹框的方式
window.alert(对话提示框)
JavaScript运算符及流程控制
与java不同点:
1、switch(表达式){ //switch中case语句,在js可以跟变量,而java中只能是常量
case 变量/常量:
语句1;
break;
case 变量名2/常量名2:
语句2;
break ;
....
default:
语句n;
break ;
}
2、for-in语句: 遍历数组或者性
for(var 变量名 in 数组对象名称或者对象名称){
使用这个变量名即可;
}
for(var i in strArray){
document.write(strArray[i]+" ") ;
}
3、 var a = 3 ;
var b = 4 ;
//不取整
document.write("(a/b):" + (a/b)) ;
4、
//定义字符串数组
创建数组格式
arrayObj = new Array() ; 不给数组长度
arrayObj = new Array([size]) 给定长度
arrayObj = new Array([element0[, element1[, ...[, elementN]]]])
简写
arrayObj = [element0[, element1[, ...[, elementN]]]] ;
var strArray = ["JavaEE","MySql","Redis","JavaScript","Jdbc"] ;
与java相同点
算术运算符 :+,-,*,/,%
赋值运算符: =,+=,-=.....
逻辑运算符
&,|,^,逻辑非!
&&:连接的表达式左边为false,右边不执行
||:连接表达式左边为true,右边不执行
比较运算符<=,>=,==,<,>....
三元(三目运算符)
(条件表达式)?执行成立的结果:执行不成立的结果;
流程语句
顺序结构语句
选择结构:
if()
if()...else{}...
if()...else if()... else{}
循环结构语句
for(var 变量名= 值;条件表达式;步长语句){
循环体语句
}
var 变量名 = 值;
while(条件表达式){
循环体语句;
步长语句;
}
do{
循环体语句;
步长语句;
}while(条件表达式) ;
for-in语句: 遍历数组或者性
for(var 变量名 in 数组对象名称或者对象名称){
使用这个变量名即可;
}
Person对象---name属性和age属性
var 数组名称= new Array([元素1,元素2....]) ;
等价于
var 数组清除 = [元素1,元素2....] ; 静态初始化
JavaScript比较运算符(不同点)
a==b
a===b
=== 和 == 的区别
===:比较两个引用,==比较两个值
比较两个值的时候不考虑数据类型
JavaScript函数
js定义函数的格式固定的写法:
function 函数名称(形参名称1,形参名称2...){
//方法体内容
1.可以直接return 结果; 带有返回值;
2.可以直接输出document.write(xxx)
}
调用函数
var 结果 = 函数名称(实际参数列表) ; 有返回值的直接接收,使用它
定义函数注意事项:
1)定义函数的时候,形式参数不能携带var,直接参数名称即可
2)js弱类型语言,没有函数重载的概念,后面定义的函数将前面的函数覆盖
3)当实际参数个数小于形式参数个数,结果就是NaN(没值),但是依然会调用
4)实际参数个数大于形式参数个数,结果将前面的实际参数进行赋值计算
5)函数里面数组---arguments,将实际的值绑定给形式参数
JavaScript常见弹窗函数
window均可以省略
window.alert("信息") 只有一个确定的弹窗
window.confirm("你好");
他的返回值是boolean,当点击“确定”时,返回true,无论点击“取消”还是右上角的那个“X“关闭,都返回false
prompt弹窗
window.prompt("你爱学习吗?","爱");
第一个参数是提示信息,第二个参数是用户输入的默认值。
当你点击确定的时候,返回用户输入的内容。当你点击取消或者关闭的时候,返回null
JavaScript事件
事件编程的三要素
1、事件源--特定的html标签 如:button按钮具备点击事件
2、事件监听器--编写一个函数
3、绑定事件监听器到事件源上
通过标签一些特定的属性将上面的函数进行绑定
一、和点击相关的事件
1、单击 onclick
方式1:<input type="button" id="btn" value="点我试试" οnclick="click()"/>
function click(){
alert(“触发单击事件”);
}
方式2:
<input type="button" id="btn" value="点我试试" />
dom操作,获取id=“btn”的input标签对象
var inputObject = document.getElementById(“btn”);
使用对象名.onclick属性
inpuitObj.οnclick=function(){
alert(“触发单击事件”);
}
2、双击ondblclick
<input type="button" οndblclick="mydbllclick() " value="双击">;
定义触发函数
function.mydbllclick(){
alert(“触发双击事件”);
}
二、和焦点相关事件
3、获取焦点 onfocus(输入数据)
用户名:<intput type="text" id="username" οnfοcus="myFous" value="请输入用户名"/>
//定义函数
function myFocus(){
var input=document.getElementById("username") ;
//改变value属性,输入内容时,默认属性值变为空
input.value="";
}
4、失去焦点onblur(输入数据完毕,到输入框外面)
用户名:<input type="text" id="username" οnblur="myBlur()"value="请输入用户名" />
<span id="spanTip"></span>
//定义函数
function myBlur(){
//获取文本输入框的内容
var username = document.getElementById("username") ;
var span = document.getElementById("spanTip") ;
if(username!= “张三”){
//匹配失败,给span标签设置标签文本innerHTML属性
span.innerHTML = “不符合格式”.fontcolor(“red”);
}else{
//匹配成功
span.innerHTML="<strong>√</strong>".fontcolor("green") ;
}
}
普通纯文本 innerText :不能渲染html标签,原样输入内容
标签文本 innerHTML:可用渲染html标签
三、选项卡发生变化事件onchange
onchange:下拉菜单,选择的时候。元素就会改变 onchange
籍贯:
<select οnchange="myChange()" id="province">
<option>请选择</option>
<option value="陕西省">陕西省</option>
<option value="山西省">山西省</option>
<option value="广东省">广东省</option>
<option value="湖南省">湖南省</option>
</select>
<select id="city"></select>
//定义函数,html元素改变,就会触发onchange指定的函数
function myChange(){
//通过id=“province” 获得select标签对象
var pro = document.getElementById("province") ;
//获取选择的内容的value属性
var province = pro.value ;
//获取当前id=“city”的select的标签对象
var city = document.getElementById("city") ;
//每一次选项卡变化之前,清空掉上一次内容
city.innerHTML=“”;
if("陕西省"==province){
//创建城市数组--陕西省城市
var cityArr = ["西安市","咸阳市","宝鸡市","渭南市"] ;
//遍历
for(var i = 0 ; i < arr.length ; i ++){
//设置city所在的select标签对象的option标签--- 作为select的innerHTML
city.innerHTML+= "<option value='"+arr[i]+"'>"+arr[i]+"</option>" ;
}
}
//创建城市数组--山西省城市
if("山西省"==province){
//js创建数组
var arr = ["太原市","运城市","大同市","晋中市"] ;
//遍历
for(var i = 0 ; i < arr.length ; i ++){
//arr[i]每一个城市
//设置city所在的select标签对象的option标签--- 作为select的innerHTML
city.innerHTML += "<option value='"+arr[i]+"'>"+arr[i]+"</option>" ;
}
}
四、鼠标相关事件
6、鼠标经过onmouseover / 移出 onmoueout
<div id="adv_div" οnmοuseοut="myMouseOut()">
经过这个区域,打开一个页面
</div>
var myTaskId ;
<input type="button" value="取消定时任务" οnclick="clearMyTask()" />
<input type="button" value="开启定时器" οnclick="openInterVal()" />
//定义函数新建窗口打开02_函数的应用.html
function opennewUrl(){
window.open("02_函数的应用.html","_blank") ;
}
//定义函数每隔5秒执行一次函数opennewUrl()
function openInterVal(){
myTaskId = window.setInterval("opennewUrl()",5000) ;
}
//定义函数取消定时任务
function clearMyTask(){
//window对象---clearInteval(任务id) ; 取消定时任务
window.clearInterval(myTaskId) ;
}
//鼠标经过,打开链接
function myMouseOver(){
top.location.href="01_js事件变成三要素.html" ;
}
//鼠标移出,每隔3秒打开一个页面
function myMouseOut(){
myTaskId = window.setInterval("opennewUrl()",3000) ;
}
js完成 页面跳转(打开url)
1)window.open("url","打开资源文件方式")
window.open("02_函数的应用.html","_blank") ;
2)window.location.href="重新载入url地址" 新的窗口
top.location.href 在当前页面中直接将当前页码覆盖,打开一个新的页面
top.location.href="01_js事件变成三要素.html" ;
五、页面载入事件onload
浏览器将body内容加载完毕就会触发 onload事件
<body οnlοad="myInit()">
function myInit(){
alert("载入事件触发了")
}
JavaScript自定义对象
<script>
1、js自定义对象方式1:类似java的有参构造
定义一个Persopn对象 function对象(属性1,属性2){ //不需要加类型
追加属性/追加方法
}
function Person(name,age){
this.age = age;
this.name = name;
this.palyGame(gameName){
alert("超会玩"+gameName);
}
}
//创建对象
//var 对象名 = new 对象();
var person = new Person("高圆圆",32);
2.自定义对象方式2:类似于java的无参构造
function Person(){}
//创建对象
//var 对象名 = new 对象();
var person = new Person();
//使用对象名.属性名= xx; 赋值
person.name = "张三";
//使用对象名.方法名=function(参数列表){} 定义方法
person.palyGame = function(gameName){
alert("超会玩"+gameName);
}
3.创建对象方式3:利用Object:在js代表所有对象
var p = new Object() ;
//追加属性/追加功能
p.name = "张蒋杰" ;
p.age = 23 ;
p.playGame = function(gameName){
alert("会玩"+gameName)
}
4.创建对象方式4,json:字面量值的方式----js简谱 (web交互是一种轻量级的交互格式)
//{"key":value,"key2":value2....}
//创建一个学生信息:id,姓名,年龄,地址
var student =
{"id":"1","name":"张三丰","age":23,"address":"西安市"} ;
//jons对象.key=获取value ;
console.log("学生的id是:"+student.id) ;
console.log("学生的name是:"+student.name) ;
//创建学生集合类似数组格式
//[{"key1":vaue1,"key":value2},{..},{...}]
var students = [
{"id":"1","name":"张三丰","age":23,"address":"西安市"},
{"id":"2","name":"高圆圆","age":44,"address":"北京市"},
{"id":"3","name":"赵又廷","age":43,"address":"上海市"}
];
//json对象[索引值].key=获取vlaue
console.log("第一学生的id是:"+students[0].id) ;
console.log("第一学生的name是:"+students[0].name) ;
//json对象[索引值]['key属性']
console.log("第三学生的name是:"+students[2]['name']) ;
</script>
打开窗口
1.新页面弹出一个窗口
top.location.href="01_js事件变成三要素.html" ;
2.当前页面打开一个窗口
window.location.href="01_js事件变成三要素.html" ;
确认提示框 window.confirm("str"),返回一个boolean型的值
function deleUser(uid){
var flag = window.confirm("是否要删除");
if(flag){
window.location.href="${pageContext.request.contextPath}/delUser?uid="+uid ;
}
}
var–let–const的区别
let和const是ES6新增的声明变量的关键词,之前声明变量的关键词是var。
let:
1.var定义的变量,可以预解析提前调用的结果是undefined,let定义的变量不能预解析,提前调用的结果是 报错。
2.var定义的变量,变量名称可以重复,效果是重复赋值,let定义的变量不能重复,否则执行报错。
3.var定义的变量作用域是全局/局部作用域。let定义的变量如果在{}中只能在{}中调用。
4.在循环语句中var定义的循环变量和使用let定义的循环变量。执行原理和执行效果不同。
const:
1.var定义的变量,可以预解析提前调用的结果是undefined,const定义的变量不能预解析,提前调用的结果是 报错。
2.var定义的变量,变量名称可以重复,效果是重复赋值,const定义的变量不能重复,否则执行报错。
3.var定义的变量作用域是全局/局部作用域。const定义的变量如果在{}中只能在{}中调用。
4.const 定义的变量存储的数据数值不能改变,也就是const定义的变量,不能重复赋值。
使用const声明常量,一旦声明,就必须立即初始化,const声明常量,允许在不重新赋值的情况下修改它的值(基本数据类型不可,只有引用数据类型可以,引用类型引用的是地址不是值)
DOM编程
基于Document Object Model:文档对象模型编程
将html文档每一个封装"标签对象",自己的属性,自己的函数,完成表单校验
dom核心:
1)获取指定的标签对象
2)改变标签对象的属性
一、获取标签对象
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="#"></a><input type="text" />
</body>
//document集合属性:
//links:获取带有href的a标签对象 以及area标签(热点域)
//获取第一个a标签对象
var aNode = document.links[0] ; //集合属性
//获取它的父节点
var bodyNode = aNode.parentNode ;
//childNodes:所有子节点
var nodes = bodyNode.childNodes ;
for(var i = 0 ; i < nodes.length ; i ++){
alert(nodes[i].nodeName) ;
}
var first = bodyNode.firstChild ;//第一个子节点
通过id获取标签对象
var 对象名= document.getElementById(“id”);
//添加文本内容
对象名.span.innerHTML =“xxx“;
获取通过标签对象获得标签属性
var 对象名= document.getElementById(“id”).value;
通过标签名找到 HTML 元素
方法:getElementsByTagName("合法的元素名");
通过类名找到HTML 元素
方法:getElementsByClassName("class属性的值")
<img id="image" src="1.gif">
<script>
document.getElementById("image").src="2.jpg";
</script>
修改css属性
<p id="p2">Hello World!</p>
<script>
document.getElementById("p2").style.color="blue";
document.getElementById("p2").style.fontFamily="Arial";
document.getElementById("p2").style.fontSize="larger";
JavaScript内置对象Date
获取时间方法
获取年份:getFullYear()
获取月份:getMOnth() 0-11之间的整数
获取日期:getDate()
获取时:getHours()
获取分:getMinutes()
获取秒:getSeconds()
<body>
<marquee scrollamount="20">
当前系统时间是:<span id="tip"></span>
</marquee>
</body>
<script>
//定义函数
function getDateTime(){
//创建日期对象
var date = new Date();
var span = document.getElementById("tip") ;
var dateStr = date.getFullYear()+"年"+(date.getMonth()+1)+"月" +date.getDate()+"日"+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds()
span.innerHTML = dateStr ;
}
</script>
定时器
JavaScript定时器
定义定时器:
setInterval('调用函数',毫秒时间):每间隔固定毫秒值就执行一次函数
setTimeout('调用函数',毫秒时间):在固定时间之后执行一次调用函数
关闭定时器:
clearInterval(定时器名称)
clearTimeout(定时器名称)
window.setInterval()
setInterval("generateTime()",1000) ;//每隔1秒执行这个函数一次
JavaScript 内置对象字符串
字符串定义方式
var str1 = new String("hello");
var str2 = "jack";
字符串比较
==:默认比较地址值
str1==str2
valueOf():返回指定对象的原始值
str1.valueOf() == str2.valueOf()
正则表达式
js的正则表达式基本语法;
x后面带上符号:x代表任意字符
数量词
x+:x字符出现1次或者多次
X?:x字符出现0次或1次
X*:x字符出现0次或者多次
范围
x{n}:x恰好出现n次
x{n,}:x字符至少出现n次
x{n,m}:x字符至少出现n次,不超过m次
x[a-z]:x字符为a-z的小写字母
\d :0-9的数字字符
\w : 匹配下划线的任意单词字符。等价于[A-Za-z0-9_]
创建一个正则规则:基本语法
不完全匹配
var 正则对象名 = /基本语法/; 不完全匹配
完全匹配
var 正则对象名 = /^正则语法$/; 精确匹配
^:输入匹配规则的开始位置:以指定的字符开头
$:输入匹配的结束位置:以指定的字符结尾
内置的方法:
var 结果变量 = 正则对象名.test(字符串);true匹配成功,false匹配失败
var str = “waha123”;
var reg = /^[a-z0-9]+$/ 代表:a-z0-9的字符出现1次或者多次
if(reg.test(str)){
//匹配成功
}else{
alter("匹配失败")
}
修饰符:
i 执行对大小写不敏感的匹配
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
m 执行多行匹配
方法:
exec() 方法:检索字符串中的指定值。返回值是被找到的值。如果没有发现匹配,则返回
null
var patt1=new RegExp("e");
document.write(patt1.test("The best things in life a
正则表达式表单校验-onsubmit事件
<form action="提交地址" method=“提交方法” οnsubmit=“return checkall()”
// checAkll() 函数,用来判断每一个表单是否均校验成功,若有一个表单校验没有成功则不能跳转页面
<label for="username">用户 名</label>
<input type="text" name="username" οnblur="checkUsername()" placeholder="请输入用户名"
id="username" /><span id="userTip"></span>
</div>
<div class="pwdDiv">
<label for="pwd">密   码</label>
<input type="password" name="password" οnblur="checkPwd()"
placeholder="请输入密码" id="pwd" /><span id="pwdTip"></span>
</div>
<div class="repwdDiv">
<label for="repwd">确认密码</label>
<input type="password" name="repassword" οnblur="checkRepwd()" placeholder="两次密码一致" id="repwd" />
<span id="repwdTip"></span>
</div>
//调用所有校验的函数,并提交返回值true或false给 onsubmit
function checkAll(){
if(checkUsername() && checkPwd() && checkRepwd() && checkEmail())
return ture;
}else{
returen false;
}
//校验用户名是否符合正则表达式
function checkUsername(){
//获取id="username"的input标签对象同时获取内容
var username = document.getElementById("username").value ;
//获取id="userTip"的span标签对象
var span = document.getElementById("userTip") ;
//创建正则规则
//用户名:6-16位数字或者字母组成
var reg = /^[A-Za-z0-9_]{6,16}$/ ;
/* if(username==""){
span.innerHTML ="用户名不能为空".fontcolor("red") ;
}*/
if(reg.test(username)){
//成立,给span标签设置标签文本
span.innerHTML = "恭喜您".fontcolor("green") ;
return true ;
}else{
span.innerHTML = "不可用".fontcolor("red") ;
return false ;
}
}
//校验密码
function checkPwd(){
//获取密码框的内容
var pwd = document.getElementById("pwd").value;
//获取id="pwdTip" 的span标签对象
var span = document.getElementById("pwdTip") ;
//创建正则规则:校验密码
//密码:6-10位的数字或者字母组成
var reg = /^\w{6,10}$/ ;
//校验
if(reg.test(pwd)){
span.innerHTML ="√".fontcolor("green") ;
return true ;
}else{
span.innerHTML ="X".fontcolor("red") ;
return false ;
}
}
//校验确认密码
function checkRepwd(){
//获取密码框的内容
var pwd = document.getElementById("pwd").value;
//获取确认密码框的内容
var repwd = document.getElementById("repwd").value ;
//获取id="repwdTip"的span标签对象
var span = document.getElementById("repwdTip") ;
//两次内容一致
if(pwd.valueOf() == repwd.valueOf()){
span.innerHTML = "一致".fontcolor("green") ;
return true ;
}else{
span.innerHTML = "两次信息不一致".fontcolor("red") ;
return false ;
}
}
function checkEmail(){
//获取邮箱的内容
var email = document.getElementById("email").value ;
//id="emailTip"的span标签对象
var span = document.getElementById("emailTip") ;
//创建邮箱正则规则:
var reg = /^\w+@\w+(\.[a-z]{2,3}){1,2}$/ ;// \w -- [A-Za-z0-9_]+
if(reg.test(email)){
span.innerHTML = "邮箱格式满足".fontcolor("green") ;
return true ;
}else{
span.innerHTML = "不满足格式".fontcolor("red") ;
return false ;
}
}
Servlet
Servlet概念
Servlet:Server Applet:服务器连接器(java语言编写的服务端程序)
必须应用在应用服务器(web容器,tomcat/jetty/apache Http服务器...)
Servlet的本质:
习惯称为:一个能够实现javax.servlet.Servlet接口的类
servlet作用
1、接收前端的发送的请求
2、解析请求,完成服务端程序的登录/注册等并响应给客户
使用Servlet步骤
1)需要导入servlet的核心jar包
javax.servlet-api-4.0.1.jar
javax.servlet-api-3.1.0.jar
或者tomcat的解压目录lib---servlet-api.jar包
2)创建一个类(具体类),继承Servlet接口的抽象的子实现类(HttpServlet)
3)重写HttpServlet里面的两个方法
doGet(请求对象,响应对象):接收前端的get请求
doPost(请求对象,响应对象):接收前端的post请求
4)配置Servlet: 在WEB-INF的web.xml文件(网站全局配置文件)
<!--servet的基本配置-->
<servlet>
<!--serlvet的名称:可以自定义名字或则和你定义的Servlet的类名一致-->
<servlet-name>MyFirstServlet</servlet-name>
<!--当前servlet的全限定名称-->
<servlet-class>com.qf.servlet_01.MyFirstServlet</servlet-class>
</servlet>
<!--servlet的映射配置-->
<servlet-mapping>
<!--必须和上面的serlvet-name一致-->
<servlet-name>MyFirstServlet</servlet-name>
<!--前端请求服务器的路径
必须以"/开头"
精确匹配,具体前端请求的路径, /名称 -->
<url-pattern>/first</url-pattern>
</servlet-mapping>
5)默认get接收前端请求:
@Override
//HttpServletRequest\HttpServletResponse http底层网络协议创建HttpServletResponse/HttpServletRequest对象
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//本质就是设置一个响应头:content-type:text/html;charset=utf-8
resp.setContentType("text/html;charset=utf-8");
//浏览器中输入地址:http://localhost:8080/day41_Servlet_Jsp_Web_exploded/first
System.out.println("进入到了MyFirstServlet") ;
//服务器端给浏览器响应一句话:HttpServletResponse
resp.getWriter().write("响应成功了!"); //有中文,解决响应的中文乱码
}
tomcat 怎么将请求精确转发给 servlet
web项目通过压缩成war部署到Tomcat服务器上 Serv实现子类对应out中xx.class文件
tomcat 怎么将请求精确转发给 servlet ?
一个 tomcat 下有好多个 servlet,那 tomcat 是怎么请求精确转发给 servlet 的呢?
tomcat 根据 URL 先确定转发给 webapps 下的哪个项目,再确定转发给项目中的哪个 servlet。
RL:http://localhost:8080/ch06-cookies/checkcookie.do
通信协议:http://(使用 http 通信协议)。
服务器IP:localhost (本地)。
端口号:8080 (tomcat 对应的 socket 的端口号默认是8080,大家常说的 tomcat “监听” 8080 端口)。
uri:/ch06-cookies/checkcookie.do (tomcat 用这部分判断是要将请求转发给哪个 servlet)。
webapps 下的项目名字:ch06-cookies
项目中的 servlet:checkcookie.do
在 tomcat 的 webapps 目录下,存放的项目文件结构是有要求的。
(1)webapps 目录下,每一个文件夹就是一个单独的 web 项目,文件夹的名字会作为 uri 的起始
确定了项目,接下来就是确定请求该转发给哪个 servlet
day41_Servlet_Jsp_Web_exploded 项目内部文件结构:
day41_Servlet_Jsp_Web_exploded
├── WEB-INF
│ ├── classes
│ │ └── com
│ │ └── qf
│ │ ├── CheckCookie.class
│ │ └── CookieTest.class
│ └── web.xml
├── cookieresult.jsp
└── form.html
web项目通过压缩成war部署到Tomcat服务器上 Serv实现子类对应out中xx.class文件
每个项目下都必须有有个 web.xml 文件,它被叫做(Deployment Descriptor,DD),里面定义了路径和 servlet 的对应关系
web.xml:
<servlet></servlet>、<servlet-mapping></servlet-mapping> 这样的一对元素定义一个对应关系,这里定义了两个对应关系:
<servlet>
<servlet-name>Ch6_Check_Cookie</servlet-name>
<servlet-class>com.example.CheckCookie</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Ch6_Check_Cookie</servlet-name>
<url-pattern>/checkcookie.do</url-pattern>
</servlet-mapping>
http://localhost:8080/ch06-cookies/checkcookie.do 请求会被转发给 CheckCookie servlet 来处理。
Servlet执行流程
Servelt的生命周期
Servelt接口有关生命周期的方法:
1、 初始化init
public void init(ServletConfig config) throws ServletException;
初始化参数ServletConfig,可以直接获取到web.xml的配置文件信息
Servelt的抽象子类:GenericsServlet未做任何实现(private transient ServletConfig config;定义ServletConfig不可序列化)
GenericsServlet的抽象子类HttpServlet未做任何实现
2、服务端应用程序的入口 service
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
被抽象子类HttpServlet做了具体实现,里面实现了doxx方法
子类需重写该方法
3、销毁destroy
public void destroy();
自定义类可以实现这个方法
servlet销毁:服务器(web容器)正常关闭,就会标记当前这个servlet,被jvm进行对象回收
Servelt的初始化加载
服务器启动时不创建实现子类对象,前端发送请求给服务器时才创建
该类加载只执行一次,只有一个实例,单例。
初始化方法init(ServletConfig)以及构造方法都执行一次:
Servlet-->单例设计模式(线程不安全的,可以被多个浏览器同时访问) :在内存中始终只有一个对象
1、第一次访问 当前端访问时:
inti方法被调用:初始化该类, service方法被调用
2、第二次访问
只调用service方法 service方法不断被调用
底层方法:获取前端提交方式,判断前端是GET,还是Post请求,执行不同
doXXX()方法;直接覆盖doXXX方法,完成自己的逻辑
初始化时机:在访问Servlet的时候创建
想要服务器一启动就进行初始化该类(Servlet),需要在配置文件中进行设置
<!--load-on-startup:配置servlet的初始化时机
web容器(Tomcat)一启动的时候就会立即当前类对象
值越大,优先级越小,默认1
-->
<load-on-startup>1</load-on-startup>
web.xml文件配置参数说明
1、全局参数
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
2、servet的基本配置
<servlet>
//serlvet的名称:可以自定义名字或则和你定义的Servlet的类名一致
<servlet-name>MyFirstServlet</servlet-name>
//当前servlet的全限定名称,用于Tomcat通过反射获得当前类的字节码文件并调用方法
<servlet-class>com.qf.servlet_01.MyFirstServlet</servlet-class>
</servlet>
3、servlet的映射配置mapping
<servlet-mapping>
//必须和上面的serlvet-name一致
<servlet-name>MyFirstServlet</servlet-name>
/*前端请求服务器的路径
必须以"/开头"
精确匹配,具体前端请求的路径, /名称
*/
<url-pattern>/first</url-pattern>
</servlet-mapping>
4、初始化配置参数:放在load-on-startup上面
<init-param> 类一加载,立马就会加载上下文的地址,地址中加载资源文件
<param-name>path</param-name> 上下文地址
<param-value>D:\EE_2302\day41\hello.java</param-value> 资源文件
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
5、配置servlet的初始化时机参数,一启动web容器就加载(原先web容器启动时不初始化,客户端访问时才初始化)
<!--load-on-startup:配置servlet的初始化时机
web容器一启动的时候就会立即当前类对象
值越大,优先级越小,默认1
-->
<load-on-startup>1</load-on-startup>
ServletConfig配置对象
web.xml文件
初始化配置参数:类一加载,立马就会加载上下文的地址,地址中加载资源文件
<init-param>
<param-name>path</param-name> 上下文地址
<param-value>D:\EE_2302\day41\hello.java</param-value> 资源文件
</init-param>
可以有多个初始化参数
ServletConfig接口:servlet配置对象,可以获得web.xml文件里面的配置系信息
作用:可以获取Servlet配置信息中init-param:初始化参数
获取ServletConfig
GenericsServlet中个方法可以直接拿到ServletConfig,
浏览器发请求--解析servlet--->顶层父类可以直接获取到Servletconfig
被自定义类继承
public ServletConfig getServletConfig() {
return config;
}
private transient ServletConfig config;
ServletConfig config = this.getServletConfig();
方法1:一次获取一个配置信息
可以获取Servlet配置信息中初始化参数:init-param
ServletConfig中方法 public String getInitParameter(String name)
可以获取Servlet配置信息中init-param:初始化参数
param-name :初始化名称
param-value :初始化值
String pathValue = config.getInitParameter("path");
方法2:一次获获取所有初始化参数名称
ServletConfig接口中方法,被自定义类继承(servlet)
//Enumeration迭代器
public Enumeration<String> getInitParameterNames();
//获取所有初始化参数名称,遍历参数名称,通过参数名称获取参数值
Enumeration<String> en = config.getInitParameterNames();
while(en.hasMoreElements()){
String paramName = en.nextElement();
//public String getInitParameter(String name)
String paramValue = config.getInitParameter(paramName);
}
用于框架中读取配置文件
<init-param> 类一加载,立马就会加载上下文的地址,地址中加载资源文件
<param-name>path</param-name> 上下文地址
<param-value>D:\EE_2302\day41\hello.java</param-value> 资源文件
</init-param>
方法3:String servletName = config.getServletName();
获取servlet的名称,及当前的类
ServletContext接口
ServletContext接口:代表整个web Application :全局对象 无实现子类,唯一父类Object
作用:
获取ServletContext对象
GenericsServlet中getServletContext()方法
public ServletContext getServletContext() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletContext();
}
ServletContext context = this.getServletContext();
1)获取全局参数--开发中 使用context-param获取全局参数读取核心配置文件
<context-param>
<param-name>xxx</param-name>
<param-value>xxx.properties/xx.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF / root-context.xml</param-value>
</context-param>
2)获取上下文路径 String getContextPath()
String contextPath = request.getContextPath();
//接收get请求
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//统一这块处理post乱码
//请求服务器的时候,服务器端将请求过来的中文解决
//1)获取ServletContext对象:
ServletContext context = this.getServletContext();
// public String getInitParameter(String name);
String encoding = context.getInitParameter("encoding");//全局参数
request.setCharacterEncoding(encoding);
//获取到用户名登录的信息 用户名和密码
//HttpServletRequest--->public String getParameter(String name);
//参数:表单提交的表单元素的里面的name属性值
// http://localhost:8080/day41_Servlet_Jsp_Web_exploded/context1?username=hello&password=123
//get请求,提交数据有中文,不会乱码
String username = request.getParameter("username");
String password = request.getParameter("password");
//2)ServletContext获取上下文路径
//public String getContextPath();
String contextPath = context.getContextPath();
//简写格式:请求对象HttpSevletRequest里面-->public String getContextPath(); 动态获取上下文路径
String contextPath = request.getContextPath();
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("<a href='http://localhost:8080"+request.getContextPath()+"/login.html'>用户未登录</a>");
}
//接收post请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端提交的数据的方式通用的
//post提交的是,中文有乱码的
/*String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("登录的用户名是:"+username+",密码是:"+password);*/
//get请求或者post请求获取前端提交数据都是一样,直接复用
doGet(req,resp);
3)请求转发
4)域对象:在不同servelt之间进行数据传输
请求/响应解决中文乱码
请求解决中文乱码
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
ServletContext context = this.getServletContext();
String encoding = context.getInitParameter("encoding");//获取全局参数
request.setCharacterEncoding(encoding);
1. request.setCharacterEncoding("utf-8");
同时设置服务端的编码格式和客户端响应的文件类型及响应时的编码格式
响应解决中文乱码
2. response.setContentType("text/html;charset=utf-8");
域对象
域对象:在不同servlet之间进行"数据传输"(数据共享)
Servlet+jsp :jsp本质就是Servlet
1、PageContext page域 在某一个jsp(java server Page)有效
2、HttpServletRequest :请求对象: 在一次请求有效 (请求对象) 使用居多
3、HttpSession session会话 : 在一次"会话"中有效(存储服务器端),关闭浏览器失效
4、ServletContext : 全局对象:代表整个web application,服务器重启或关闭失效
通用方法:public void setAttribute(String name,Object obj) :
给域对象中属性名称中添加任意类型数据
public Object getAttribute(String name):通过属性名称获取内容
HttpServletRequest请求对象
//所有的请求信息都封装在HttpServletRequest,获取请求信息
1、获取请求行中的请求方式 String getMethod()
String method = request.getMethod();
2、获取请求行的中uri(范围大),getRequestURI()
String requestURI = request.getRequestURI();
3、获取请求行的中url(范围小),getRequestURL()
StringBuffer requestURL = request.getRequestURL();
4、获取请求行中的协议版本String getProtocol()
String protocol = request.getProtocol();
5、获取请求头中的具体内容
String getHeader(String var1);通过指定的请求头获取请求的内容
//请求头:User-Agent:客户端的浏览器类型
String header = request.getHeader("user-agent");
header.contains("Chrome") //客户端的浏览器类型
6、通过参数名称获取参数值String getParameter(String var1)
String username = request.getParameter("username");
7、获取所有参数名称Enumeration<String> getParameterNames()
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement(); //参数名称
//通过参数名称获取参数值
String value = request.getParameter(name);
}
8、后端通过Map集合的方法获取参数
//Map<String, String[]> getParameterMap();获取前端提交的所有参数的参数名和参数值都封装Map中,遍历map取出来
Map<String, String[]> parameterMap = request.getParameterMap();
//遍历Map---Set<Key> keySet()获取所有键 + V get(K key) (推荐)
//要么entryset--Map.entry<K,V>键值对对象
Set<String> set = parameterMap.keySet();
for(String key:set){
//通过键获取值
String[] array = parameterMap.get(key);
for(String s:array){
System.out.println(key+"---"+s);
}
}
9、request域对象存一个数据
request.setAttribute("name",object) ;
HttpServletResponse响应对象
HttpServletRequest处理请求信息
1、设置响应的内容 void setContentType(String var1)
//设置响应的字符编码格式
response.setContentType("text/html;charset=utf-8");
2、设置给浏览器响应头
//void setHeader(String var1, String var2);设置响应头
response.setHeader("content-type","text/html;charset=utf-8");
3、添加响应头
//refresh,定时刷新或者定时跳转页面
//每秒刷新访问的这个地址
response.setHeader("refresh","1");
//定时跳转指定的页面,3秒后跳转登录页
response.setHeader("refresh","3;/Servlet_Jsp_02_Web_exploded/login.jsp");
请求转发
请求转发:属于"服务器行为"进行操作,不需要带上下文路径
前端发送请求,后端的Servlet,接收参数,查询数据库,获取到数据库的信息,将判断结果返回前端,从后端跳转前端 , 用户名或者密码输入错误,给页面提示"错误信息"
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
一、通过ServletContext请求转发,是域对象
//获取SevletContext对象
ServletContext servletContext = this.getServletContext();
1)获取分发器:RequesDispatcher
//public RequestDispatcher getRequestDispatcher(String path);
//参数:是转发到前端页面地址或者后端的另一个地址
RequestDispatcher rd = servletContext.getRequestDispatcher("/getValue.jsp”)属于"服务器行为"进行操作,不需要带上下文路径
//2)RequestDispatcher分发器--->进行转发
//public void forward(ServletRequest request, ServletResponse response)
rd.forward(request,response);
二、 //简写格式,通过域对象HttpServlet请求转发
request.getRequestDispatcher("/getValue.jsp").forward(request,response);
//request对象---类型:HttpServletRequest:本身是域对象,域对象可以存数据
}
//直接后端/context2地址,请求转发到一个jsp页面上,并且jsp页面还能获取到里面存储数据
//域对象方法:通用方法:public void setAttribute(String name,Object obj) :
给域对象属性名称中添加任意类型数据
servletContext.setAttribute("name","李国栋");
request.setAttribute("name2","高圆圆");
web容器里面内部进行跳转,当前目录下面的xx.jsp
请求转发的特点:
1)地址栏没有变化
2)整个过程request对象一致
request对象---类型:HttpServletRequest:本身是域对象,域对象可以存数据
在jsp页面中,可以取数据
3)请求转发可以访问WEB—INF资源文件(WEB—INF的资源文件不能直接访问)
重定向
后端直接完成页面跳转---重定向方式也可以跳转页面,用于页面跳转
原理:
1)设置响应头名称location 以及跳转地址 "/web上下文路径/资源页面"
response.setHeader("location",request.getContextPath()+"/login.jsp");
2)设置响应状态 302 :进一步请求
response.setStatus(302);
浏览器第一次请求原界面,返回给浏览器信息,浏览器看到响应信息302将第二次请求login.jsp
重定向简写格式
// void sendRedirect(String var1) throws IOException;
response.sendRedirect(request.getContextPath()+"/login.jsp");
请求转发和重定向的区别
1.地址栏是否有变化
请求转发:地址栏没有变化
重定向:地址栏有变化
2.是否能够访问WEB-INF下的资源文件
请求转发:可以访问WEB-INF下的资源文件
重定向:不能访问WEB-INF下的资源文件
3.整个过程请求对象是否一致
请求转发:request对象一致,所以使用请求转发,在servlet存数据,请求转发jsp从request中获取数据
重定向:request对象不一致
4.是否能够访问外部项目资源文件(一个tomcat可以部署多个web项目)
请求转发:只能访问当前项目下的资源文件包括wEB-INE下面的资源文件
重定向:可以访问当项目下的资源文件以及访问其他项目下的资源文件
JSP—Java server Pages
jsp注释
<%-- 注释 --%> JSP注释,注释内容不会被发送至浏览器甚至不会被编译
< !--注释-- > HTML注释,通过浏览器查看网页源代码时可以看见注释内容
jsp的三大指令/九大内置对象
三大指令<%@page%>\<%@include%>\<%@taglib prefix="c" uri="xxx" %>
<%@page
contentType="text/html;charset=UTF-8" language="java"
isErrorPage="false"
errorPage="指定错误页面的路径" //errorPage="404.jsp"
%>
contentType:页面编码格式(默认的)
language:支持的语言格式java(默认)
isErrorPage:是否是错误页面:默认值是false()默认的
errorPage:如果当前页码存在问题(异常等),直接跳转错误页面上
buffer="8kb":jsp页面存储缓冲区大小 8kb(默认的)
isELIgnored:是否能够使用EL表达式 ${},默认为true可以使用
自定义:404页面
<%@ page
contentType="text/html;charset=UTF-8"
language="java"
isErrorPage="true" //这个页面是错误页面
%>
<h4>亲,您访问的资源找不到了</h4>
静态包含指令include
<body>
<%--静态包含指令
特点:不会将被导入进来的jsp文件(03_导航.jsp)单独进行翻译和编译:节省jsp内存
拼接到该文件(jsp)中
--%>
<%@include file="03_导航.jsp"%> //导入其他页面
<%--主页信息--%>
<div>
<%--taglib指令
导入jstl的核心库,指定前缀名称"c" c标签
uri:指定jsp/jstl/core地址
--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
9大内置对象:前面4个域对象:从小到大
PageContext page域:仅仅是当前某个jsp页面中有效,范围最小,页面跳转后无效
HttpServletRequest request域:在请求中有效,
HttpSession session域:一次会话中有效,浏览器关闭无效
ServletContext application域:在整个web程序中有效
//给request域中存储数据
pageContext.setAttribute("name","王宝强");
request.setAttribute("name","高圆圆"); //类似于Map结合<String,Object>
session.setAttribute("name","李国栋"); //session存储的服务器端的
application.setAttribute("name","赵又廷");
//取数据
<%=(String)request.getAttribute("name")%><br/>
<%--el表达式默认在jsp是可以启用的 代替上面的输出表达式
${pageScope.属性名} page域中取数据 // ${pageScope.name3}
${requestScope.属性名} request域中取数据 //${requestScope.name}
${sessionScope.属性名} session域中取数据 //${sessionScope.name2}
${applicationScope.属性名} application域取数据 //${applicationScope.name4}
简写 ${name}
当属性明相同时:
${属性名}--必须从域对象搜索(从小到大搜索),里面是否存在数据,有的数据直接获取
EL表达式,OGNL对象图导航语言
<%--使用jsp的角标模拟服务器端代码--%>
<%
//存储User实体到request域中
User user = new User() ;
user.setUsername("高圆圆") ;
user.setGender("女");
user.setAge(44);
user.setAddress("西安市") ;
request.setAttribute("user",user);
%>
OGNL对象图导航语言:
<%=((User)request.getAttribute("user")).getName()%> //原书写方式
<%--el表达式可以操作javabean(javabean导航)
${存储的属性名称}--->类似于Map<Key,Value>
${Key}--->获取到value
${Key.javabean实体的bean属性}
Object Graph Navigation Language ---OGNL 对象图导航语言:jsp支持/开源框架Spring家族/mybatis
${user} 就等价于(User)request.getAttribute("user") 获取到user对象
${user}访问getUsername():get()去掉,第一个字母小写:username
user对象实例.getUsername()方法
${user.username}
--%>
<br/>
${user.name} - ${user.gender} - ${user.age} - ${user.address}
Servlet+jsp:实践
Servlet--->接收前端页面提交数据,调用service获取业务数据,在控制台视图以及数据(存储域对象中)
Jsp----->里面通过jsp内置对象:其中四个域对象:request域和Session域,从servlet取数据,展示数据:渲染视图
jstl标签库:里面核心标签:展示数据
<%
//频繁书写java代码(不推荐)
%>
Jsp:
1)翻译 :将jsp文件翻译成.java文件
2)编译 :将.java文件 编译.class文件
<%
jsp脚本书写,java代码
%>
jstl标签库
<%--使用jsp的角标模拟服务器端代码--%>
<%
//存储User实体到request域中
User user = new User() ;
user.setUsername("高圆圆") ;
user.setGender("女");
user.setAge(44);
user.setAddress("西安市") ;
request.setAttribute("user",user);
User user2 = new User() ;
user2.setUsername("王五") ;
user2.setGender("男");
user2.setAge(23);
user2.setAddress("渭南市") ;
List<User> list = new ArrayList<>() ;
list.add(user) ;
list.add(user2) ;
request.setAttribute("list",list);
//jsp页面上遍历List集合获取里面每一个实体,需要jstl:jsp的标签库(导入jar包)
%>
<%--taglib指令
导入jstl的核心库,指定前缀名称"c" c标签
uri:指定jsp/jstl/core地址
--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
1、遍历集合标签foreach
<%--遍历集合数据
c:foreach标签的属性
items="从域对象获取的数据"
var ="循环中变量名"
--%>
<c:forEach items="${list}" var="u">
<tr>
<%--${循环中的变量}
${u}---就是每一个user实体
--%>
<td>${u.name}</td>
<td>${u.gender}</td>
<td>${u.age}</td>
<td>${u.address}</td>
</tr>
</c:forEach>
<c:froeach beggin="1" end="10" step="1" var="i" varStatus="status">
<%-- varStatus="循环中状态属性">
它的属性值.ixdex:索引值,根据begin的值开始计算
--%>
${status.index}helloword${i}
2、<%--c:if:判断存储的数据内容是否满足要求
test属性=${域对象获取的数据}
empty:空
empty 对象名:表示对象是否为空
--%>
<c:if test="${empty list}">
<h3>list集合是空的</h3>
</c:if>
<c:if test="${not empty list}">
<h3>list集合对象不为空</h3>
</c:if>
3、<%--c:choose
c:when test="${域对象获取数据}"
c:otherwise:类似java语言中选择结构语句
--%>
request.setAttribute("number",2);
<c:choose>
<c:when test="${number==1}">
<h4>星期一</h4>
</c:when>
<c:when test="${number==2}">
<h4>星期二</h4>
</c:when>
<c:otherwise>
<h4>非法数据</h4>
</c:otherwise>
</c:choose>
jstl函数库
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
${fn:substring(<string>, <beginIndex>, <endIndex>)}
参数1:获取指定的字符串名称
参数2:指定开始截取的索引位置 从0开始
参数3:最终索引,包含endIndex-1处
<a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}" style='color:#666'>${fn:substring(p.pname, 0, 6)}...</a>
信息摘要算法的工具:MessageDigest
//jdk提供:信息摘要算法的工具:MessageDigest
//public sattic MessageDigest getIntstance 创建当前类的实例
// String字符串内容---byte[] digest() :转换成字节数组
password = MD5Utils.md5(password) ;
HttpSession清除会话
//public void invalidate()
//1)从request对象中获取HttpSession
HttpSession session = request.getSession();
//2)判断
if(session!=null){
//将session清除了,使用会话无效
//public void invalidate()
session.invalidate();
}
//public void removeAttribute(String name);
从此会话中移除与指定名称绑定在一起的对象。如果会话没有与指定名称绑定在一起的对象,则此方法不执行任何操作。
超链接失效与js事件
<c:if test="${ empty admin}">
<a href="javascript:void(0)" οnclick="btn_login()" >请登录</a>
</c:if>
<c:if test="${not empty admin}">
恭喜,${admin.username}
<%-- <a href="${pageContext.request.contextPath}/logOut">【退出】</a>--%>
超链接失效:javascript:void(0)
<a href="javascript:void(0)" οnclick="btn_logOut()">【退出】</a>
</c:if>
function btn_logOut(){
//window:代表窗口对象
//window.loaction.href="加载地址":窗口打开一个页面
//top.laction.href="从顶部弹出一个页面"
top.location.href ="${pageContext.request.contextPath}/logOut" ;
}
function btn_login(){
//点击登录,打开登录页面
top.location.href="${pageContext.request.contextPath}/admin/admin_login.jsp"}
//修改
<a href="javascript:void(0)" οnclick="update('${u.uid}')" style="color: blue">修改</a>
<script>
function update(uid){
alert(uid) ;
}
//删除
<input type="button" style="color: darkseagreen;" value="添加用户" οnclick="addUser()" />
function addUser(){ window.location.href="${pageContext.request.contextPath}/admin/user/add_user.jsp";
}
jsp动作标签
<%--jsp动作标签
jsp:forward 请求转发
--%>
<%--<jsp:forward page="/jsp/index.jsp"></jsp:forward>--%>
上下文路径后无内容,直接访问/index主页
<jsp:forward page="/index"></jsp:forward>
Maven
Maven:项目管理"工具",可以管理所有的jar包的版本/测试/打war包/部署 一套的流程都可以很简单通过maven完成
maven---Apache提供的工具: maven.apache.org : 下载工具 :
respository:仓库 --存储项目中使用的各种jar包
本地仓库:(自己玩就本地)
中央仓库:
国外网站---->配置国内公共库 "阿里云仓库"
远程仓库:搭建私服(企业中)
优点:
1)更好的管理jar包版本
2)maven项目占用空间小
3)测试代码和源代码分离
4)集成一些内置tomcat和各种插件
clean清除/编译compile/测试test/打包package/部署deploy
maven执行流程
Jquery
Jqeury是一个丰富js库,提供大量API可以操作Ajax/动画/事件/dom操作等等
下载:jquery-xxx.min.js/jquery-xxx.js
前者压缩版:部署上线,必须使用压缩版(占用空间内存小)
后者非压缩版:自己用的时候使用后者,部署上线不能用这个非压缩版
使用步骤:
1)导入js库
2)Jquery的函数入口就是页面载事件---当body内容加载完毕就会触发页面载入事件
//原生Js页面载入事件
function init(){
alert("原生Js页面载入事件!") ; }
//Jquery页面载入事件
语法$(function() {
xxx;
});
//程序入口
$(function(){
//body内容加载完了
}
Jquery对象和Js对象的相互转换
<input type="button" id="input_button" οnclick="changeSpanInnerHTML()" value="按钮"/><br/><br/>
<span id="span">helloworld</span>
导入jquery的js库
<script src="js/jquery-3.4.1.min.js"></script>
1.原生js对象转为Jqery对象
function changeSpanInnerHTML(){
//使用Jquery对象方式:改变span的内容
//获取id="span"标签对象
var span = document.getElementById("span") ;
// span.innerHTML :原生js访问它的innerHTML:设置标签文本 (推荐)
// span.innerText :原生Js访问它的innerText:设置普通文本
var $span = $(span) ;
//设置它的文本方法:text(xx):等价于之前的innerText
// html("<标签名称>xxx</标签名称>"):等价于innerHTML属性
$span.html("<strong>将span内容切换为了JavaEE</strong>") ;
}
2.jquery对象转js对象 $("#xx").get(0) 0,1,2...依次获取
//页面载入事件
$(function (){
//逻辑
//给id="btn" 设置点击(Jquery的写法)
$("#btn").click(function(){
//$("#btn"):将它(Jq对象)转换成原生js对象
//Jq提供对象的方法:Jq对象.get(index):匹配第几个index的元素
var spanObj = $("#spanTip").get(0) ; //id="spanTip"
//原生Js改变它的文本
spanObj.innerHTML = "<strong>使用Jq对象转换Js改变为:Filter</strong>" ;
}) ;
}) ;
Jquery基本选择器
常用三个基本选择器
id选择器:$("#id属性值") :id必须唯一
1. class选择器:$(".class属性值"):class可以同名
2. element选择器:$("标签名称");
3. $(selector1,selector2,...):jquery并集选择器
//页面载入事件
$(function(){
//获取id="b1"标签对象,并设置点击
$("#b1").click(function (){
//改变 id 为 one 的元素的背景色为 红色
//Jquery对象设置样式:css("样式名称","样式样式")
//或者多个样式css({"样式名称1":"值1","样式名称2":"值2"}...)
$("#one").css("background-color","red") ;
}) ;
Jquery层级选择器/子元素选择器
层级选择器
$("selector1 selector2"):Jquery的后代选择器:匹配父标签下所有的子元素
//页面载入事件
$(function(){
//id="b1"设置点击
$("#b1").click(function(){
//改变 <body> 内所有 <div> 的背景色为红色
$("body div").css("background-color","red") ;
}) ;
子元素选择器
$("selector1 > selector2"):Jquery的子元素选择器,第二个选择器中的元素一定是第一个选择器中元素的子元素
//id="b2"设置点击
$("#b2").click(function(){
//改变 <body> 内子 <div> 的背景色为 红色
$("body>div").css("background-color","orange") ;
}) ;
Jquery属性选择器
Jquery属性选择器
$("元素名称[attribute]"):带有指定属性的元素
$("元素名称:[attribute=value]"):匹配给定元素具有特定值的元素
$("[attribute!=value]") :匹配给定元素不具备特定的值
$("[attribute^=value]"):匹配给定的属性以某些值开始的元素
$("[attribute$=value]"):匹配给定的属性以某些特定值结尾的元素
$("[attribute*=value]"):匹配给定的属性包含value值的元素
$("[selector1][selector2][selectorN]"):符合属性选择器,同时有多个属性满足条件
//含有属性title 的div元素背景色为红色
$("div[title]").css("background-color","red") ;
//属性title值等于test的div元素背景色为红色
$("div[title='test']").css("background-color","red") ;
//属性title值不等于test的div元素(没有属性title的也将被选中)背景色为红色
$("div[title!='test']").css("background-color","red") ;
//属性title值 以te开始 的div元素背景色为红色
$("div[title^='te']").css("background-color","red ") ;
//属性title值 以est结束 的div元素背景色为红色
$("div[title$='est']").css("background-color","red ") ;
//属性title值 含有es的div元素背景色为红色
$("div[title*='es']").css("background-color","red ") ;
//选取有属性id的div元素,然后在结果中选取属性title值含有“es”的 div 元素背景色为红色
$("div[id][title*='es']").css("background-color","red ") ;
Jquery文档处理
Jq对象.append("xx"):在文档内部追加指定内容
$("#ul").append("<li>宝鸡</li>")
Jq对象.appednTo("xx"):将XX内容添加到Jq对象指定元素的后面
$("#gz").appendTo($("#xa")) ;
Jq对象.prepend(content):在文档内容指定的元素的前面追加内容
$("#ul").prepend("<li>神木</li>");
Jq对象.prependTo(content):在文档内容指定的元素的前面追加内容
$("#sm").prependTo($("#xa")) ;
Jquery对象.after("xx"):在文档外部插入
$("#ul").after("<li>宝鸡</li>")
Jquery方式表单校验
//页面载入事件
$(function(){
//获取到id="formSubmit"的form标签对象
//Jquery里面的函数submit ---->类似form表单给了属性on submit
$("#formSubmit").submit(function(){
//验证表单元素
//用户名 密码 确认密码 邮箱
if(checkUsername() && checkPwd() && checkRepwd() && checkEmail()){
return true ;//表单提交
}
return false ;//禁用提交
}) ;
})
//校验用户名
function checkUsername(){
//获取id="username"的input标签对象同时获取内容
//var username = document.getElementById("username").value ;
//Jq方式获取用户名的内容
var username = $("#username").val() ;
alert(username) ;
//获取id="userTip"的span标签对象
//var span = document.getElementById("userTip") ;
var span = $("#userTip") ;
//创建正则规则
//用户名:6-16位数字或者字母组成
var reg = /^[A-Za-z0-9_]{6,16}$/ ;
/* if(username==""){
span.innerHTML ="用户名不能为空".fontcolor("red") ;
}*/
var flag = reg.test(username) ;
if(flag){
//成立,给span标签设置标签文本
// span.innerHTML = "恭喜您".fontcolor("green") ;
//给input标签对象css样式
$("#username").css("border","") ;
//满足正则规则提示
span.html("恭喜") ;
span.css("color","green") ;
}else{
//span.innerHTML = "不可用".fontcolor("red") ;
//给输入框的input对象设置边框样式
$("#username").css("border","1px solid red") ;
span.html("不可用") ;
span.css("color","red") ;
}
return flag ;
}
//校验确认密码
function checkRepwd(){
//获取密码框的内容
// var pwd = document.getElementById("pwd").value;
var pwd = $("#pwd").val() ;
//获取确认密码框的内容
//var repwd = document.getElementById("repwd").value ;
var repwd = $("#repwd").val() ;
//获取id="repwdTip"的span标签对象
// var span = document.getElementById("repwdTip") ;
var span =$("#repwdTip") ;
//两次内容一致
if(pwd.valueOf() == repwd.valueOf()){
// span.innerHTML = "一致".fontcolor("green") ;
$("#repwd").css("border","") ;
span.html("<strong>√</strong>") ;
span.css("color","green") ;
return true ;
}else{
// span.innerHTML = "两次信息不一致".fontcolor("red") ;
$("#repwd").css("border","1px solid red") ;
span.html("<strong>×</strong>") ;
span.css("color","red") ;
return false ;
}
}
原生ajax的操作步骤
1)创建xmlHttpRequest
2)建立连接open(method,url,是否异步);
3)发送请求
4)等待响应
function mySendAjax() {
//1)创建xmlHttpRequest:浏览器代理对象
var xmlHttp;
if (window.XMLHttpRequest) {
//所有现代浏览器使用这个XMLHttpRequest
xmlHttp = new XMLHttpRequest();
} else {
// code for IE6, IE5 //很低版本的浏览器
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2)建立连接open
//open(method, url, async)
//参数1:请求方式: get/post
//如果get请求,可以地址栏携带参 url?key1=value1&key2=value2....
//参数2:和服务器端建立连接的地址 后端服务器接口地址
//参数3:默认true:表示异步,false,表示同步
xmlHttp.open("get", "/Jquery_boostrap_war/my?username=zhangsan", true);
//3)发送器请求到服务器地址
//send()
xmlHttp.send();
//4)异步交互:等待响应
//代理对象:监听服务器的状态的改变,会触发函数:
//onreadystatechange
xmlHttp.onreadystatechange = function () {
//等待响应状态 readyState是4并且状态码200响应成功
if (this.readyState == 4 && this.status == 200) {
//获取数据
//响应文本属性 responseText
//将服务器端响应过来的内容存储在这个代理对象中
alert(this.responseText);
}
}
}
jquery的ajax代替原生写法
//jquery的ajax发送异步请求
$.ajax(
type: 请求方式:GET/POST,(默认get)
url: 请求后端地址,
data: 请求的参数:如果get,还在url?key1=value1&key2=value2,
success:function(data){
//响应成功的回调函数,data:服务器响应的数据
},
error:function(data){
//失败的回调函数:data服务器响应过来的数据
},
dataType:服务器响应过来的数据格式 :jsonjson/text文本格式/html格式,
contentType:浏览器请求的服务器内容格式(可以不写)
//方式2:
$.get(url,参数,function(data),"服务器响应的格式");get提交
//方式3
$.post(url,参数,function(data),"服务器响应的格式"); post提交
$(function(){
//给用户名文本输入框添加失去焦点事件
$("#username").blur(function(){
//获取用户名的内容
var username = $(this).val() ;
$.ajax({
type:"get",
url:"/Jquery_boostrap_war/my?username="+username+"",
success:function(data){
//data服务器响应过来的数据
//{"code":1,"msg":"用户名太受欢迎了,请更换!"}
//{"code":0,"msg":"共享,可用"}
if(data.code==0){
alert(data.msg) ;
}
if(data.code==1){
alert(data.msg) ;
}
},
dataType:"json" //服务器响应来的数据格式
}) ;
}) ;
}) ;
JSON接收与发送数据
发送数据:
如果数据存储在JavaScript对象中,可以把该对象转换为JSON,然后将其发送到服务器。
var myJSON = JSON.strirlgify(myobj);
接收数据:
如果以]JSON格式接收到数据,能够将其转换为JavaScript对象
var myobj =JSON.parse(myJSON);
jsp的el表达式
jsp的el表达式
内置对象
${sessionScope.属性名} session域中取数据
${requestScope.属性名} request域域中取数据
${pageScope.属性名} page域中获取数据
${applicationScope.属性名} 全局(servletContext)获取数据
${cookie}:---Map<String,Cookie> ${cookie.名称} 获取cookie 对象
${param} --- Map<String,String> 获取url地址栏上?后面的所有的参数名称以及参数值
${param.key}获取value
<script>
//$(function (){
//获取地址栏所有参数名称以及参数值的内容 url? key1=value1&key2=value2
//alert('${param.cid}') ; //{pSize=12, curPage=1, methodName=getProductByPage, cid=1}
//}) ;
</script>
jstl: substring方法
${fn:substring(<string>, <beginIndex>, <endIndex>)}
参数1:获取指定的字符串名称
参数2:指定开始截取的索引位置 从0开始
参数3:最终索引,包含endIndex-1处
注解
注解是一种标记,是可用Java程序解析;
公共接口---本质就是一个接口:public interface Annotation---里面方法名在注解中,称为"属性"
@Annotation
注解分为:---底层都依赖"元注解":@Target:正在使用的注解它使用的范围(类上/方法/参数...)
@Retention:正在使用的直接它的保留阶段: SORUCE/CLASS/RUNTIME
1)jdk内置注解
@Override:标记这个方法是否实现接口或者重写父类的
@Deprecated //标记这个方法已经过时的,但是可以用
@SuppressWarnings//压制警告
@FunctionalInterface:函数式接口:当前接口中有且仅仅有一个抽象的方法,加入注解标记
@Override注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Target
@Target--->public @interface Target { //当前标记的这个注解能够在什么类型上用(方法用/类上用/参数上用...)
ElementType[] value();//value属性--返回值类型:枚举类型
---public enum ElementType{
TYPE, //当前这个注解可以用在类上
FIELD,//当前这个注解可以用在成员变量上
METHOD,//这个注解可以用在成员方法上
PARAMETER,//这注解可以用在形式参数上
CONSTRUCTOR,//能够用在构造函数上
LOCAL_VARIABLE,//能够用在局部变量上
ANNOTATION_TYPE,//能够注解类型上
PACKAGE,//能够用在包上
TYPE_PARAMETER, //能够使用在参数类型上
TYPE_USE //使用标记类型
}}
@Retention(RetentionPolicy.SOURCE):标记当前正在使用的注解的保留范围(标记当前这个在原码阶段)
@Retention(RetentionPolicy.RUNTIME) 标记当前这个注解的保留范围在运行阶段
//Java代码经历三个阶段
public enum RetentionPolicy {
SOURCE,//Java源代码阶段
CLASS,//Java编译阶段(类的加载-获取字节码文件对象,创建对象...)
RUNTIME//运行阶段 (一般自己用 Runtime)
}
自定义注解
自定义注解
@自定义名称 ---指定的属性
自定义注解 MySelfAnno
@Target(ElementType.TYPE) //能够在类上
@Retention(RetentionPolicy.RUNTIME) //保留在运行阶段上
public @interface MySelfAnno {
String value() ;
String name() ;
}
在类上加入刚才自定义的注解MySelfAnno
@MySelfAnno(value = "com.qf.ann.Fateher",name = "show")
public class ParseAnno {
public static void main(String[] args) {
//如何解析这里MySelfAnno的value和name?
//public <A extends Annotation> A getAnnotation(类<A> annotationClass)
// 就可以直接获取"注解"(接口)的实现类
Class c = ParseAnno.class ;
}
}
1.
//自定义了一个注解:本质是接口 public @interface MyAnno{}
//标记MyAnno能够在类上使用,加入元注解
@Target(ElementType.TYPE)
//标记MyAnno保留在运行阶段上使用
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
//注解中的属性----也就是接口的方法名
//属性的返回值只有5中类型:
int myId() ; //myId属性的返回值int类型
String value() ; //value属性,返回值String类型
MyEnum my() ; //my属性返回值,枚举类型
MyAnn2 anno() ;//anno属性的返回值 注解类型
//以上四种类型的数组
String[] strs() ;//数组格式
}
2.
public enum MyEnum {
LEFT, //传统定义的类的时候自定义常量 :public static final 数据类型 变量名 = 初始化值;
RIGHT,
BEHIND,
FRONT ;
}
3.
//使用这个自定义注解:注解里面只有五种类型
@MyAnno(myId = 1,
value = "高圆圆",
my=MyEnum.BEHIND,
anno = @MyAnn2(value = "helloword"),
strs = {"servlet","hello"})
public class MyTest {
//@MyAnno() :只能在类上用
public void method(){
}
}
实际开发中:
大量使用第三方提供的注解:
现在使用Servlet---->@WebServlet:标记在类上使用,里面有很多的属性---代替了xml配置
//给MyTest2加入刚才自定义的注解
@MySelfAnno(className = "com.qf.demo.Worker",name = "love")
public class MyTest2 {
public static void main(String[] args) throws Exception {
//解析自定义注解
//1)获取当前类的字节码文件对象 MyTest2.class
Class c = MyTest2.class ;
//2)public <A extends Annotation> A getAnnotation(类<A> annotationClass)
//参数是:当前注解类型的Class对象
MySelfAnno mySelfAnno = (MySelfAnno) c.getAnnotation(MySelfAnno.class);
//返回值是Annotation公共接口,需要强转为自己的注解类型
//上面操作:获取到了注解(接口)它的实现类,就可以调用方法(注解中的属性名)
String s1 = mySelfAnno.className();
//System.out.println(s1);
String name = mySelfAnno.name();
//System.out.println(name);
//反射代码
Class clazz = Class.forName(s1) ; //正在使用的类对象
//创建实例
Object obj = clazz.newInstance();
//获取这个类的方法Method类对象
Method method = clazz.getDeclaredMethod(name);
//取消Java语言访问检查
method.setAccessible(true) ;
//调用方法
method.invoke(obj) ;
}
}
Servlet启用注解方式
//@WebServlet(name="默认当前类名MyServlet",value="/my(可以配置多个路径,只有一个value则可以省略)",loadOnStartup=1(初始化时机,类一加载就创建实例),initParams=@WebInitParam(name="初始化参数",value="初始化值"))
@WebServlet("/my") //必须"/开头"
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("访问到了Servlet了");
response.getWriter().write("hello,Servlet,,,");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
Servlet启用注解方式---代替xml配置方式
@WebServlet
String name():name属性---等价于xml配置的时候 (不写,默认当前类名)
<servlet>
<servlet-name>默认当前类名/可以自己定义名称</servlet-name>
<servlet-class></servlet-class>
<load-on-statrup>1</load-on-statrup> //web容器一启动,创建当前类实例
</servlet>
String[] value() default {};
int loadOnStartup() default -1; 等价于<load-on-statrup>1</load-on-statrup>
String[] urlPatterns() default {};
value属性和urlPatterns他们意义一样的,指定后端服务器请求地址 等价
<servlet-mapping>
<servlet-name></servlet-name>
<url-pattern>/映射路径</url-pattern>
</servlet-mapping>
WebInitParam[] initParams() default {} -->等价于
<init-param>初始化参数
<param-value></param-value>
</init-param>
用户登录
1.jsp中设置登录的表单页面
//action:提交的服务器地址
<form action="${pageContext.request.contextPath}/admin_Login" method="post">
<div class="userDiv">
<label for="username">用户 名</label>
<input type="text" name="username" placeholder="请输入用户名"
id="username" /><span id="userTip"></span>
......
<div class="btnDiv">
<!--submit:表单提交:将表单中所有数据提交服务器服务器上-->
<input type="submit" value="登录">
</div>
2.登录的servlet设置
//解决post提交乱码
request.setCharacterEncoding("utf-8");
//1)接收管理员登录用户密码
//2)密码需要加密 :get提交/post提交 都可以看到密码信息
String username = request.getParameter("username");
String password = request.getParameter("password");
//jdk提供:信息摘要算法的工具:MessageDigest-->
// public static MessageDigest getInstance :创建当前类的实例
// String字符串内容---byte[] digest() :转换成字节数组
//加密工具类
password = MD5Utils.md5(password) ;
//调用管理员业务接口,返回管理员用户实体
AdminService adminService = new AdminServiceImpl() ;
Admin admin = adminService.getAdminByName(username, password);
//进行判断,数据库中存在用户就将管理员实体存储在HttpSession中,否则请求转发到登录页面
if(admin!=null){
//从请求对象中获取HttpSession
HttpSession session = request.getSession() ;
session.setAttribute("admin",admin) ;
//重定向到admin/admin_index.jsp :后台主页
response.sendRedirect(request.getContextPath()+"/admin/admin_index.jsp");
}else{
//没找到用户请求转发到登录页面
request.setAttribute("msg","用户名或者密码输入错误") ;
request.getRequestDispatcher("/admin/admin_login.jsp").forward(request,response);
}
3.登录的用户业务接口实现
public Admin getAdminByName(String username,String password) {
try {
//调用dao :管理员的数据访问接口
AdminDao ad = new AdminDaoImpl() ;
Admin admin = ad.selectAdmin( username) ;
if(admin!=null){
//判断密码是否一致
if(admin.getPassword().equals(password)){
return admin ;
}
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
4.访问数据库
public Admin selectAdmin(String username) throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
String sql = "select * from admin where username = ?" ;
Admin admin = qr.query(sql, new BeanHandler<>(Admin.class), username);
return admin;
}
用户登录成功-查询所有商品-图解
用户注销
判断当前是否在session中存在用户,存在则显示(XX已登录,注销),不存在(用户未登录)则显示请登录
//1)pom.xml中导入jstl包
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
//2)当如jstl核心标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
//3)判断是否存在用户登录
<c:if test="${ empty admin}">
<a href="javascript:void(0)" οnclick="btn_login()" >请登录</a>
</c:if>
<c:if test="${not empty admin}">
恭喜,${admin.username}
<%-- <a href="${pageContext.request.contextPath}/logOut">【退出】</a>--%>
<%--超链接失效--%>
<a href="javascript:void(0)" οnclick="btn_logOut()">【退出】</a>
</c:if>
//4)设置点击事件
<script>
function btn_login(){
//点击登录,打开登录页面
top.location.href="${pageContext.request.contextPath}/admin/admin_login.jsp"
}
function btn_logOut(){
alert("点击退出了") ;
//window:代表窗口对象
//window.loaction.href="加载地址":窗口打开一个页面
//top.laction.href="从顶部弹出一个页面"
top.location.href ="${pageContext.request.contextPath}/logOut" ;
}
</script>
//5)设置注销的servlet
//1)从request对象中获取HttpSession
HttpSession session = request.getSession();
//2)判断
if(session!=null){
//将session清除了,使用会话无效
//public void invalidate()
session.invalidate();
}
//重定向到管理员主页
response.sendRedirect(request.getContextPath()+"/admin/admin_index.jsp");
window打开窗口
window:代表窗口对象
window.location.href="地址" 窗口打开一个页面
top.location.href="地址" 从顶部弹开一个页面
新的请求对象,存储在request中的信息会没有,分页查询页码数据须在地址后重新接默认值
MVC架构思想
Model:业务模型
pojo里面存储存放的实体类(JavaBean)
service:业务层----完成的业务逻辑功能(登录/注册/获取某个实体/获取列表...)
dao:持久层 ----操作数据库db,获取数据---返回service层
View:视图
html / 模板引擎 :
jsp (el表达式/核心库jstl)/freemarker网页静态化技术...
/vue框架 +elementUI(组件/布局容器...)
Controller:控制器
通过服务连接器: 处于前端和业务接口中间层---servlet 获取service层的数据,
控制视图(后端请求转发/重定向),或者响应json串
前台用户管理
一.查询所有用户
查询所有用户1:定义jsp展示数据
<table border="1px" align="center" width="100%" height="500px">
<tr>
<th>用户编号</th>
<th>用户昵称</th>
<th>真实姓名</th>
<th>用户邮箱</th>
<th>用户性别</th>
<th>用户操作</th>
</tr>
<c:forEach items="${users}" var="u">
<tr>
<td>${u.uid}</td>
<td>${u.username}</td>
<td>${u.name}</td>
<td>${u.email}</td>
<td>${u.sex}</td>
<td>
<a href="javascript:void(0)" onclick="update('${u.uid}')" style="color: blue">修改</a>
<a href="#" style="color: red;">删除</a>
</td>
</tr>
</c:forEach>
</table>
查询所有用户2:定义servlet
管理员获取所有用户的后端服务地址
*/
public class AdminGetAllUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//调用业务接口
AdminService adminService = new AdminServiceImpl() ;
List<User> users = adminService.allUsers() ;
if(users!=null){
//将users存储在request域中
request.setAttribute("users",users) ;
//请求转发到管理员里面用户列表页面
request.getRequestDispatcher("/admin/user/user_list.jsp").forward(request,response);
}else{
request.setAttribute("msg","未获取到数据");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
}
查询所有用户3:service实现
/**
* 查询所有前台用户
* @return 返回用户列表
*/
@Override
public List<User> allUsers() {
try {
//调用AdminDao:数据库中获取用户列表
AdminDao adminDao = new AdminDaoImpl() ;
List<User> users = adminDao.selectAllUsers() ;
if(users!=null || users.size()>0){
//有数据
//返回
return users;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
查询所有用户4:dao实现
/**
* 管理员数据访问接口查询所有前台用户
* @return 返回用户列表
*/
@Override
public List<User> selectAllUsers() throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from user" ;
//查询
List<User> list = qr.query(sql, new BeanListHandler<>(User.class));
return list;
}
二:添加用户
添加用户1:定义jsp
<!--action:提交的服务器地址-->
<form action="${pageContext.request.contextPath}/adminAddUser" method="post">
<div class="uidDiv">
<label for="uid">用户ID</label>
<%--表单中的所有name属性和实体的属性名称一致--%>
<input type="text" name="uid" style="margin-left: 30px;" placeholder="请输入用户ID"
id="uid" />
</div>
<div class="userDiv">
<label for="username">用户昵称</label>
<input type="text" name="username" placeholder="请输入用户昵称"
id="username" />
</div>
<div class="relNameDiv">
<label for="name">真实姓名</label>
<input type="text" name="name"
placeholder="请输入真实姓名" style="margin-left: 30px;" id="name" />
</div>
<div class="emailDiv">
<label for="email">用户邮箱</label>
<input type="text" name="email"
placeholder="请输入邮箱" id="email" />
</div>
<div class="sexDiv">
<label for="sex">用户性别</label>
<input type="text" name="sex"
placeholder="请输入用户性别" style="margin-left: 30px;" id="sex" />
</div>
<div class="btnDiv">
<!--submit:表单提交:将表单中所有数据提交服务器服务器上-->
<input type="submit" value="保存用户">
</div>
添加用户2:定义servlet后端地址
管理员添加用户后端地址
*/
public class AdminAddUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决添加用户的中文乱码(post提交)
request.setCharacterEncoding("utf-8") ;
//接收参数
String uid = request.getParameter("uid");
String username = request.getParameter("username");
String name = request.getParameter("name");
String eamil = request.getParameter("email");
String sex = request.getParameter("sex");
//封装User对象
User user = new User() ;
user.setUid(uid) ;
user.setUsername(username) ;
user.setEmail(eamil) ;
user.setName(name);
user.setSex(sex);
//调用AdminService业务接口
AdminService adminService = new AdminServiceImpl() ;
adminService.add(user) ;
//请求转发到查询所有的后台地址上
request.getRequestDispatcher("/getAllUser").forward(request,response);
System.out.println("添加成功");
}
添加用户3:定义service
/**
* 添加前台用户
* @param user 用户实体
*/
@Override
public void add(User user) {
try {
//访问管理员的数据访问接口
AdminDao adminDao = new AdminDaoImpl() ;
adminDao.insertUser(user) ;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
添加用户4:dao实现
/**
* 添加前台用户
* @param user 用户实体
*/
@Override
public void add(User user) {
try {
//访问管理员的数据访问接口
AdminDao adminDao = new AdminDaoImpl() ;
adminDao.insertUser(user) ;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
三:修改用户
修改用户1:先查询用户,展示数据
function update(uid){
// alert(uid) ;
window.location.href="${pageContext.request.contextPath}/adminGetUser?uid="+uid ;
}
public class AdminGetUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 前端发送的请求:window.loaction.href="${pageContext.request.contextPath}/adminGetUser?uid="+uid ;
String uid = request.getParameter("uid");
System.out.println(uid);
//调用管理员的业务接口
AdminService adminService = new AdminServiceImpl() ;
User user = adminService.getUser(uid) ;
//将user对象存在request域中
request.setAttribute("user",user) ;
//请求转发到admin/user/update_user.jsp
request.getRequestDispatcher("/admin/user/update_user.jsp").forward(request,response);
}
<!--action:提交的服务器地址-->
<form action="${pageContext.request.contextPath}/updateUser" method="post">
<%--隐藏域 :没有效果,但是可以携带数据--%>
<input type="hidden" name="uid" value="${user.uid}" /> <%--uid=xxxx值--%>
<%--<div class="uidDiv">
<label for="uid">用户ID</label>
<%–表单中的所有name属性和实体的属性名称一致–%>
<input type="text" name="uid" style="margin-left: 30px;" placeholder="请输入用户ID"
id="uid" />
</div>--%>
<div class="userDiv">
<label for="username">用户昵称</label>
<input type="text" name="username" value="${user.username}" placeholder="请输入用户昵称"
id="username" />
</div>
<div class="relNameDiv">
<label for="name">真实姓名</label>
<input type="text" name="name"
placeholder="请输入真实姓名" style="margin-left: 30px;" value="${user.name}" id="name" />
</div>
<div class="emailDiv">
<label for="email">用户邮箱</label>
<input type="text" name="email"
placeholder="请输入邮箱" id="email" value="${user.email}" />
</div>
<div class="sexDiv">
<label for="sex">用户性别</label>
<input type="text" name="sex"
placeholder="请输入用户性别" style="margin-left: 30px;" id="sex" value="${user.sex}" />
</div>
<div class="btnDiv">
<!--submit:表单提交:将表单中所有数据提交服务器服务器上-->
<input type="submit" value="修改">
</div>
修改用户2:查询到的用户数据界面,显示用户数据,并按修改后提交到修改的后端地址
//解决post提交中文乱码
request.setCharacterEncoding("utf-8") ;
//获取修改的参数
String uid = request.getParameter("uid");
String username = request.getParameter("username");
String name = request.getParameter("name");
String email = request.getParameter("email");
String sex = request.getParameter("sex");
//System.out.println(uid+"---"+username+"---"+name+"---"+email+"----"+sex);
//封装User对象
User user = new User() ;
user.setUid(uid) ;
user.setUsername(username) ;
user.setName(name) ;
user.setEmail(email) ;
user.setSex(sex); ;
//调用管理员的业务接口
AdminService adminService = new AdminServiceImpl() ;
adminService.updateUser(user) ;
//请求转发到查询所有的服务端地址
request.getRequestDispatcher("/getAllUser").forward(request,response);
}
/**
* 更新用户
* @param user 用户实体
*/
@Override
public void updateUser(User user) {
try {
//调用AdminDao更新数据库
AdminDao adminDao = new AdminDaoImpl() ;
adminDao.updateUser(user) ;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
/**
* dao层数据访问接口操作数据库---更新用户
* @param user 用户实体
*/
@Override
public void updateUser(User user) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "update user set username=?,name=?,email=?,sex=? where uid= ?" ;
qr.update(sql,
user.getUsername(),
user.getName(),
user.getEmail(),
user.getSex(),
user.getUid()) ;
}
删除用户
<a href="javascript:void(0)" onclick="delUser('${u.uid}')" style="color: red;">删除</a>
<script>
function delUser(uid){
// alert(uid) ;
//友情提示,确认提示框
var flag = window.confirm("您忍心删除吗?") ;
if(flag){
//alert("要删除了") ;
window.location.href="${pageContext.request.contextPath}/delUser?uid="+uid ;
}}
</script>
/**
* 管理员删除用户的服务端地址
*/
public class AdminDelUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//前端请求: window.location.href="${pageContext.request.contextPath}/delUser?uid="+uid ;
//接收参数
String uid = request.getParameter("uid");
//调用业务接口
AdminService adminService = new AdminServiceImpl() ;
adminService.deleteUser(uid) ;
//请求撞到查询后端地址上
request.getRequestDispatcher("/getAllUser").forward(request,response);
}
分页查询
增加\修改\删除数据后若想跳转到分页查询页面,需传入当前页码及每页显示条数参数
//请求转发到查询所有的服务端地址
request.getRequestDispatcher("/getAllUser?curPage=1&pSize=4").forward(request,response);
分页查询步骤1:自定义分页实体PageBean
自定义分页实体
public class PageBean<T> {
//5个属性
private int currentPage ; //当前页码
private int pageSize ; //每页显示的条数
private int totalPage ; //总页数 //计算出来的,查询到总记录数 除以 pageSize
private int totalCount ; // 总记录数
private List<T> pageList ; //分页查询的列表数据
public PageBean() {
}
public PageBean(int currentPage, int pageSize, int totalCount, List<T> pageList) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.pageList = pageList;
}
//总页数计算出来
public int getTotalPage() {
return ((totalCount % pageSize == 0)?(totalCount/pageSize):(totalCount/pageSize)+1);
}
/* public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}*/ 不提供
分页查询步骤2:jsp设置默认页码/每页显示数量
<li><a href="${pageContext.request.contextPath}/getAllUser?curPage=1&pSize=4" target="main" class="btn btn-primary">查询所有用户</a></li>
//默认当前页码为第一页,每页显示4条信息 ,提交到/getAllUser服务器地址上
分页查询步骤3:定义服务器地址/getAllUser
页面链接请求次服务器地址
携带参数当前页码,每页显示条数curPage=1&pSize=4,类型为字符串类型
//管理员获取所有用户的后端服务地址
@WebServlet("/getAllUser")
public class AdminGetAllUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//${pageContext.request.contextPath}/getAllUser?curPage=1&pSize=4
//1)获取curPage/psize:String类型
String curPage = request.getParameter("curPage");
String pSize = request.getParameter("pSize");
//2)将curPage/pSize--->int
int currentPage = Integer.parseInt(curPage) ; //当前页码
int pageSize = Integer.parseInt(pSize) ; //每页显示的条数
//3)调用AdminService
AdminService adminService = new AdminServiceImpl() ;
PageBean<User> pb = adminService.getUserByPage(currentPage, pageSize);
//查询到的分页实体存储泛型为User类型,包含当前页码数 currentPage,每页显示的条数totalPage,总页数totalPage计算出来的,总记录数totalCount,分页查询的列表数据pageList
//4)将pb对象存储在request域对象中,将数据请求转发的jsp页面中
request.setAttribute("pb",pb) ;
//5)请求转发到 admin/user/user_list.jsp,列表集合中,jsp进行展示分页查询的数据
request.getRequestDispatcher("/admin/user/user_list.jsp").forward(request,response);
分页查询步骤4:AdminService业务层实现
业务层通过代用dao层获取分页列表数据list,总记录数totalCount,封装分页实体返回给servlet
/**
* 分页查询用户数据
* @param currentPage 当前页码
* @param pageSize 每页显示的条数
* @return 返回分页实体,包含了分页列表数据,当前页码,每页显示的条数,总记录数
*/
@Override
public PageBean<User> getUserByPage(int currentPage,
int pageSize) {
try {
//调用AdminDao:获取数据:分页列表数据
AdminDao adminDao = new AdminDaoImpl() ;
//获取分页用户数据
List<User> list = adminDao.selectUserByPage(currentPage, pageSize);
//调用AdminDao:获取总记录数
int totalCount = adminDao.getTotalCount();
if(list!=null || list.size()>0){
//用户列表数据不为空,则通过PageBean
return new PageBean<>(currentPage,pageSize,
totalCount,list);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null ;
}
分页查询步骤5:dao层实现
1.分页查询数据库数据
2.查询总数
/**
* 数据访问接口分页查询用户数据
* @param currentPage 当前页码
* @param pageSize 每页显示的条数
* @return 返回用户列表
*/
@Override
public List<User> selectUserByPage(int currentPage, int pageSize) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from user limit ?,?" ;
List<User> users = qr.query(sql, new BeanListHandler<>(User.class), (currentPage - 1) * pageSize, pageSize);
return users;
}
/**
* 获取用户的总记录数
* @return 返回总条数
*/
@Override
public int getTotalCount() throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select count(uid) from user" ;
//查询
Object obj = qr.query(sql, new ScalarHandler<>()) ;
//String万能方法valueOf(obj)--->Integer.parseInt(数字字符串)
int totalCount = Integer.parseInt(String.valueOf(obj));
return totalCount;
}
分页查询步骤6:jsp列表定义展示数据
接收servlet传过来的分页实体PageBean,"pb"
包含当前页码数 currentPage,每页显示的条数totalPage,总页数totalPage计算出来的,总记录数totalCount,分页查询的列表数据pageList
1.导入样式及jquery
<link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet"/>
<script src="${pageContext.request.contextPath}/js/jquery-3.4.1.min.js"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
2.使用boostrap样式定义列表表格
<table class="table table-hover table-bordered table-striped table-responsive">
<tr>
<th>用户编号</th>
<th>用户昵称</th>
<th>真实姓名</th>
<th>用户邮箱</th>
<th>用户性别</th>
<th>用户操作</th>
</tr>
//遍历分页查询到的数据
<c:forEach items="${pb.pageList}" var="u">
<tr>
<td>${u.uid}</td>
<td>${u.username}</td>
<td>${u.name}</td>
<td>${u.email}</td>
<td>${u.sex}</td>
<td>
//操作列,获取可获取当前用户实体的id值
<a href="javascript:void(0)" class="btn btn-warning" οnclick="update('${u.uid}')" >修改</a>
<a href="javascript:void(0)" class="btn btn-danger" οnclick="delUser('${u.uid}')">删除</a>
</td>
</tr>
</c:forEach>
</table>
3.表格右下角显示总数
<div style="float: right;margin-right: 10px;">
共有<span>${pb.totalPage}</span>页
共有<span>${pb.totalCount}</span>记录
</div>
4.boostrap分页组件,定义页码的按钮,传入页码数及页面记录总数,跳转再次进入servlet进行查询
<nav style="margin-left: 350px;" aria-label="Page navigation">
<ul class="pagination">
1)
<!--向上一页查询箭头(<)-->
<%--判断是第一页,禁用(<),使失效--%>
<c:if test="${pb.currentPage==1}">
<%--bootstarp提供样式 class="disabled" 禁用状态--%>
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
2)
<%--判断不是第一页,则向上一页查询箭头(<)可用,传入参数当前页码-1,每页显示条数4,传参给servlet再次执行查询,然后再返回pagebean实体,展示数据--%>
<c:if test="${pb.currentPage!=1}">
<li>
<a href="${pageContext.request.contextPath}/getAllUser?curPage=${pb.currentPage-1}&pSize=4" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
3)<!--遍历分页页码-->1,2,3,4,5....进行判断
<c:forEach begin="1" end="${pb.totalPage}" var="n"> (1,2,3,4,5...)
<%--判断如果是当前页,使链接失效,设置激活样式--%>
<c:if test="${pb.currentPage==n}">
<%--bootstrap 样式 :class="active"激活状态--%>
<li class="active">
<a href="#">${n}</a>
</li>
<%--判断如果不是当前页,获得跳转查询的页码,设置分页查询每页显示的数据,传参给servlet进行查询,返回pagebean数据,再进行展示--%>
<c:if test="${pb.currentPage!=n}">
<li>
<a href="${pageContext.request.contextPath}/getAllUser?curPage=${n}&pSize=4">${n}</a>
</li>
</c:if>
</c:forEach>
4)
<!--向下一页查询箭头(>)-->
<%--判断如果是最后一页,禁用--%>
<c:if test="${pb.currentPage==pb.totalPage}">
<li class="disabled">
<a href="javascript:void(0)" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<%--判断如果不是最后一页,当前页码数-1,传参给serlvet查询,返回pagebean分页实体,展示数据--%>
<c:if test="${pb.currentPage!=pb.totalPage}">
<li>
<a href="${pageContext.request.contextPath}/getAllUser?curPage=${pb.currentPage+1}&pSize=4" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
</ul>
</nav>
数据增删改设置提醒弹窗
script>
function delUser(uid){
// alert(uid) ;
//友情提示,确认提示框
var flag = window.confirm("您忍心删除吗?") ;//确认返回ture,取消或x返回false
if(flag){
//alert("要删除了") ;
window.location.href="${pageContext.request.contextPath}/delUser?uid="+uid ; xxx
}
}
function update(uid){
// alert(uid) ;
window.location.href="${pageContext.request.contextPath}/adminGetUser?uid="+uid ;
}
function addUser(){
window.location.href="${pageContext.request.contextPath}/admin/user/add_user.jsp";
xxx
}
</script>
ajax校验用户名是否可用
1.jsp页面+ajax校验
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名">
<span id="tip"></span>
</div>
//用户名输入之后,鼠标移出之后触发失去焦点事件
$("#username").blur(function(){
//异步校验用户名(昵称)是否可用
//获取用户名的内容
var username = $("#username").val() ;
alert(username) ;
//获取id="tip"标签对象
var div = $("#tip");
//发送ajax
$.ajax({
type:"get",
url :"${pageContext.request.contextPath}/checkUser?username="+username+"",
success:function(data){
//服务器响应成功的回调函数
//获取数据
if(data.code==0){
//可用
//给$span设置标签文本
div.html(data.msg) ;
//设置样式
div.css("color","green") ;
}
if(data.code==1){
//不可用
//给$span设置标签文本
div.html(data.msg) ;
//设置样式
div.css("color","red") ;
$("#username").css("border","1px solid red") ;
}
},
dataType:"json"
}) ;
2.响应实体定义
public class ResponseResult {
private Object data ; //任意java对象
private int code ; //0,没有数据 1,有数据
private String msg ; //消息字符串
public ResponseResult() {
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
3.定义后端servlet地址
@WebServlet("/checkUser")
public class CheckUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//设置响应中文乱码
response.setContentType("text/html;charset=utf-8");
//${pageContext.request.contextPath}/checkUser?username="+username+""
//1)接收参数
String username = request.getParameter("username");
//2)调用用户的业务接口
UserService userService = new UserServiceImpl() ;
ResponseResult responseResult = userService.getUser(username);
//3)将responseResult转换成json
String jsonStr = JsonUtils.object2json(responseResult) ;
//4)将jsonStr字符串响应给前端
response.getWriter().write(jsonStr) ;
}
4.定义Service
/**
* 通过用户名查询用户是否存在
* @param username 用户名
* @return 如果数据存在或者不存在,返回自定义实体对象,设置对应的属性值
*/
@Override
public ResponseResult getUser(String username) {
ResponseResult rr = null ;
try {
//访问数据库:调用UserDao
UserDao ud = new UserDaoImpl() ;
User user = ud.selectUserByUsername(username);
//创建自定义响应实体对象
rr = new ResponseResult() ;
//如果user是null,没有查到,可以注册
if(user==null){
//封装数据
rr.setCode(0) ;
rr.setData(null);
rr.setMsg("恭喜您,可用");
}else{
rr.setCode(1);
rr.setData(null);
rr.setMsg("用户名太受欢迎了,请更换!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return rr;
}
5.dao实现
/**
* 数据库访问接口 通过用户名查询指定的用户
* @param registerUsername 注册的用户名
* @return 返回用户实体
*/
@Override
public User selectUserByUsername(String registerUsername) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from user where username = ?" ;
//执行查询
User user = qr.query(sql, new BeanHandler<>(User.class), registerUsername);
return user;
}
注册/登录图片验证码使用
一:验证码工具类:ImgUtils
public class ImgUtils extends HttpServlet {....}
//继承HttpServlet,需在web.xml中进行配置,
工具类核心代码:
//产生4个随机验证码
String checkCode = getCheckCode();
//将验证码放入HttpSession中 //存储在服务器端
request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
二:登录主页先进行设置
//验证码通过工具类ImgUtils存储在HttpSession中
//1) 接表单输入的验证码内容
String code = request.getParameter("code");
//2) 获取HttpSession
HttpSession session = request.getSession();
//3) 从session取出服务器端存储的验证码
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//4) 验证码一次验证,如果当前这次输入出错了,将上一次的信息从session中删除
session.removeAttribute("CHECKCODE_SERVER");
//5) 验证表单提交的验证码是否和服务器端存储的验证码内容是否一致,不区分大小写
if(code==null || !checkcode_server.equalsIgnoreCase(code)){
request.setAttribute("msg","验证码输入错误") ;
//请求转发到登录界面
request.getRequestDispatcher("/admin/admin_login.jsp").forward(request,response);
return;
}
三:jsp中
<label for="Code" >验证码</label>
<input type="text" name="Code" id="Code" style="margin-left: 20px;" placeholder="请输入验证码">
<img src="${pageContext.request.contextPath}/checkCode" οnclick="checkCode()" id="img1">
//点击图片刷新
function checkCode(){
//获取id="img1"的标签对象
var img = document.getElementById("img1");
//一点击就改变img的src属性,产生一个新的图片验证码
img.src="${pageContext.request.contextPath}/checkCode?newDate=" +new Date();
}
前台用户注册-同步提交
前台用户注册1:jsp页面
<div class="col-md-8" style="background:#fff;padding:40px 80px;margin:30px;border:7px solid #ccc;">
<font>注册</font>REGISTER
<span style="color: red;margin-left: 100px;">${msg}</span>
<form action="${pageContext.request.contextPath}/registerUser" method="post" id="registerForm" class="form-horizontal" style="margin-top:5px;">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名">
</div>
<script>
//页面载入事件
$(function(){
//点击图片--刷新图片
//Jq方式获取标签对象,同时添加点击事件
$("#img1").click(function(){
//改变它的src属性,Jquery方式给标签对象设置属性
$(this).attr(
"src", "${pageContext.request.contextPath}/checkCode?time="+new Date().getTime()) ;
}) ;
//用户名输入之后,鼠标移出之后触发失去焦点事件
$("#username").blur(function(){
//异步校验用户名(昵称)是否可用
//获取用户名的内容
var username = $("#username").val() ;
alert(username) ;
//获取id="tip"标签对象
var div = $("#tip");
//发送ajax
$.ajax({
type:"get",
url :"${pageContext.request.contextPath}/checkUser?username="+username+"",
success:function(data){
//服务器响应成功的回调函数
//获取数据
if(data.code==0){
//可用
//给$span设置标签文本
div.html(data.msg) ;
//设置样式
div.css("color","green") ;
}
if(data.code==1){
//不可用
//给$span设置标签文本
div.html(data.msg) ;
//设置样式
div.css("color","red") ;
$("#username").css("border","1px solid red") ;
}
},
dataType:"json"
}) ;
<div class="form-group">
<label for="code" class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="code" name="code" placeholder="请输入验证码">
</div>
<div class="col-sm-3">
<img src="${pageContext.request.contextPath}/checkCode" id="btn_img"/>
</div>
</div>
<script>
//点击图片刷新
$("#btn_img").click(btnImg) ;
function btnImg(){
//alert("触发") ;
var img = $("#btn_img") ; $(img).attr("src","${pageContext.request.contextPath}/checkCode?time="+new Date().getTime());
}
</script>
前台用户注册2:响应实体定义
public class ResponseResult {
private Object data ; //任意java对象
private int code ; //0,没有数据 1,有数据
private String msg ; //消息字符串
public ResponseResult() {
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
前台用户注册3:自定义转换器:日期转换器
public interface Constant {
public static final int USER_ACTIVE = 1 ;
}
//自定义转换器:日期转换器
//自定义类实现org.apache.commons.beanutils.Converter接口
public class MyDateConverter implements Converter {
//转换方法
@Override
public <T> T convert(Class<T> aClass, Object source) {
try {
//字符串日期文本---java.util.Date ---> Date parse(String日期文本)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
Date date = sdf.parse((String) source);
return (T) date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
前台用户注册4:服务器地址servlet定义+BeanUtils封装用户实体+邮箱验证
@WebServlet("/registerUser")
public class RegisterUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决post乱码
request.setCharacterEncoding("utf-8") ;
//1)校验注册的验证码
//获取前台输入的用户的验证码的内容 name="code"
String code = request.getParameter("code") ;
// 从request请求对象获取HttpSession,获取服务器端存储的验证码
HttpSession session = request.getSession();
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//一次性验证
session.removeAttribute("CHECKCODE_SERVER");
if(code == null || !checkcode_server.equalsIgnoreCase(code)){
request.setAttribute("msg","验证码错误") ;
request.getRequestDispatcher("/jsp/register.jsp").forward(request,response);
return;
}
//接收用户其他 ,将用户的数据存储在Map中
Map<String, String[]> parameterMap = request.getParameterMap(); //参数名称=参数值...
//commons-beanUtils.jar包 针对实体类进行封装---BeanUtils---populate(Object bean,Map<String,String[]>)
//创建User对象
User user = new User() ;
//必须针对birthday这个参数处理----String类型的 ---java.util,Date
//使用ConvertUtils---->转换器工具----日期转换
// public static void register(Converter converter, Class<?> clazz)
// 注册指定的转换: 参数1:转换器接口参数2:最终类型格式
ConvertUtils.register( new MyDateConverter(), Date.class); //MyDateConverter(),自定义
try {
BeanUtils.populate(user,parameterMap); // 将每一个参数都封装到user对象中,pom.xml中需导入BeanUtils工具类
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//封装用户的uid---UUID生成的
user.setUid(UUIDUtils.getId());
//密码需要处理:加密
String password = user.getPassword();
password = MD5Utils.md5(password);
user.setPassword(password) ;
//用户的code随机码,存储邮件激活码
user.setCode(UUIDUtils.getCode());
//调用UserService
UserService userService = new UserServiceImpl() ;
userService.addUser(user) ;
//请求转发
request.setAttribute("msg","注册成功,请在注册邮箱进行激活!");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
前台用户注册5:业务层sercvice实现添加用户\发送激活邮件
添加用户
/**
* 添加用户
* @param user 用户实体
*/
@Override
public void addUser(User user) {
try {
//调用UserDao
UserDao userDao = new UserDaoImpl() ;
userDao.insertUser(user) ;//插入数据
//给注册邮箱上发送一份邮件:需要正文---超链接
String content = "欢迎注册,请<a href='http://localhost:8080/Maven_2302_war_exploded/activeUser?code="+user.getCode()+"'>点击激活</a>" ;//邮件正文
MailUtils.sendMail(user.getEmail(),content,"用户邮件激活") ;
//sendMail(目标邮件,邮件内容超链接,邮件标题),需导入支持邮件技术的jar包,自定义邮件工具类
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
ajax异步校验查询用户是否存在
/**
* 通过用户名查询用户是否存在
* @param username 用户名
* @return 如果数据存在或者不存在,返回自定义实体对象,设置对应的属性值
*/
@Override
public ResponseResult getUser(String username) {
ResponseResult rr = null ;
try {
//访问数据库:调用UserDao
UserDao ud = new UserDaoImpl() ;
User user = ud.selectUserByUsername(username);
//创建自定义响应实体对象
rr = new ResponseResult() ;
//如果user是null,没有查到,可以注册
if(user==null){
//封装数据
rr.setCode(0) ;
rr.setData(null);
rr.setMsg("恭喜您,可用");
}else{
rr.setCode(1);
rr.setData(null);
rr.setMsg("用户名太受欢迎了,请更换!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return rr;
}
前台用户注册6:Dao层实现添加用户
/**
* 用户的数据访问接口添加用户
* @param user 用户实体
*/
@Override
public void insertUser(User user) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "insert into user values(?,?,?,?,?,?,?,?,?,?)" ;
int count = qr.update(sql,
user.getUid(),
user.getUsername(),
user.getPassword(),
user.getName(),
user.getEmail(),
user.getTelephone(), //这个数据暂时没有
user.getBirthday(),
user.getSex(),
user.getState(),
user.getCode());
}
前台用户注册7:点击邮箱验证
1.pom.xml导入
<!--支持邮件技术 jar包 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
2.邮件工具类
private static final String USER = "919081924@qq.com"; // 发件人称号,同邮箱地址
private static final String PASSWORD = "csobpqlwmowybfcc"; // 如果是qq邮箱/其他邮箱等可以使户端授权码,或者登录密码
邮箱接收的地址
String content = "欢迎注册,请<a href='http://localhost:8080/Maven_2302_war_exploded/activeUser?code="+user.getCode()+"'>点击激活</a>" ;
前台用户注册7:点击邮箱验证-servle后端地址定义
邮箱显示数据
邮箱接收的地址
String content = "欢迎注册,请<a href='http://localhost:8080/Maven_2302_war_exploded/activeUser?code="+user.getCode()+"'>点击激活</a>" ;
@WebServlet( "/activeUser")
public class ActiveUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//http://localhost:8080/Maven_2302_war_exploded/activeUser?code=477D3B9AFEA4474B8B044E7DDBAD199D
//接收参数
String code = request.getParameter("code");
//调用UserService
UserService userService = new UserServiceImpl() ;
User user = userService.getUserByCode(code);
if(user!=null){
request.setAttribute("msg","用户激活成功,请<a href='"+request.getContextPath()+"/jsp/login.jsp'>登录</a>");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
}
前台用户注册7:点击邮箱验证-service定义,State设为1,已激活
/**
* 通过激活码获取用户
* @param code 用户的激活码
* @return 返回用户实体
*/
@Override
public User getUserByCode(String code) {
try {
//访问数据接口
UserDao userDao = new UserDaoImpl() ;
User user = userDao.selectUserByCode(code) ;
//逻辑判断
if(user==null){
return null ;
}else{
//存在
//更新用户的激活状态
user.setState(1) ;
//更新数据库---调用数据访问接口
userDao.updateUserState(user) ;
return user ;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
前台用户注册7:点击邮箱验证-Dao实现-根据激活码查询用户,修改用户的激活状态
/**
* 数据访问接口根据激活查询指定用户
* @param code 激活码
* @return 返回用户实体
*/
@Override
public User selectUserByCode(String code) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from user where code = ?" ;
//查询
User user = qr.query(sql, new BeanHandler<>(User.class), code);
return user;
}
/**
* 更新用户的激活状态
* @param user 用户实体
*/
@Override
public void updateUserState(User user) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "update user set state = ? where uid = ?" ;
int count = qr.update(sql,
user.getState(),
user.getUid());
}
}
用户实体
private String uid ;//用户编号 (UUID工具生成随机字符串)
private String username ;//昵称
private String password ;//用户密码
private String name ; //前台用户的真实姓名
private String email ; //邮箱
private String telephone ;//电话号码
private Date birthday ;//用户出生日期
private String sex ; //性别
private int state ;//用户激活状态: 默认值0,未激活(前台用户不能登录),1表示登录
private String code ;//用户的激活码 (jdk提供工具:UUID参数随机字符串)
前台用户注册-异步提交
//如果写js表单校验,每一个表单元素---都满足正则条件,然后表单提交
//表单提交---jquery的ajax提交表单
$("#registerForm").submit(function(){
$.ajax({
type:"get", url:"${pageContext.request.contextPath}/registerUser" ,//前台用户注册的服务地址
data:$("#registerForm").serialize(), //获取$("#registerForm")的表单,进行序列化操作
//"key1=vaue1&key2=value2"
success:function(data){
/*if(data.code ==0){
alert(data.msg) ;
}*/
//服务器响应成功的回调函数
//获取到的自定义数据里json串key-->data如果是true,
//window.location.href = "" ;//跳转消息提示页,注册成功,请登录
},
dataType:"json"
}) ;
前台用户登录
前台用户登录步骤1:jsp页面
<div class="col-md-5">
<div style="width:440px;border:1px solid #E7E7E7;padding:20px 0 20px 30px;border-radius:5px;margin-top:60px;background:#fff;">
<font>Rice mall登录</font>LOGIN
<div style="margin-left: 50px;font-size: 15px;color: red;">${msg}</div>
<form class="form-horizontal" action="${pageContext.request.contextPath}/userLogin" method="post">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">密码</label>
<div class="col-sm-6">
<input type="password" class="form-control" name="password" id="inputPassword3" placeholder="请输入密码">
</div>
</div>
<div class="form-group">
<label for="code" class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="code" name="code" placeholder="请输入验证码">
</div>
<div class="col-sm-3">
<img src="${pageContext.request.contextPath}/checkCode" id="btn_img"/>
</div>
<script>
//点击图片刷新
$("#btn_img").click(btnImg) ;
function btnImg(){
//alert("触发") ;
var img = $("#btn_img") ;
$(img).attr("src","${pageContext.request.contextPath}/checkCode?time="+new Date().getTime());
}
</script>
前台用户登录步骤2:servlet定义页面(验证用户是否激活)
@WebServlet("/userLogin")
public class UserLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//0)解决post中文乱码
request.setCharacterEncoding("utf-8");
//1)校验验证码 ,因为验证码存储在服务器端的
HttpSession session = request.getSession();
//接收name="code"这个验证码数据
String code = request.getParameter("code");
//获取服务器端的存储验证码
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//一次性验证
session.removeAttribute("CHECKCODE_SERVER");
if(code==null || !checkcode_server.equalsIgnoreCase(code)){
request.setAttribute("msg","验证码错误!"); request.getRequestDispatcher("/jsp/login.jsp").forward(request,response);
return;
}
//接收用户名和密码
String username = request.getParameter("username") ;
String password = request.getParameter("password") ;
//将密码加密
password = MD5Utils.md5(password);
//调用UserService
UserService userService = new UserServiceImpl() ;
User user = userService.getUseByUserNameAndPwd(username,password) ;
System.out.println(user);
if(user == null){
//提示错误信息
request.setAttribute("msg","用户名或者密码输入错误!") ;
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response);
return;
}
//用户不为null
//判断用户激活状态不是1
if(user.getState() != Constant.USER_ACTIVE) {
request.setAttribute("msg","用户状态未激活,请到邮箱先激活") ;
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response) ;
return;
}
//将用户实体存储在HttpSession中
session.setAttribute("user",user) ;
//重定向到/jsp/index.jsp,前台主页
response.sendRedirect(request.getContextPath()+"/jsp/index.jsp") ;
}
前台用户登录步骤3:service业务实现
/**
* 获取用户实体 ,通过用户名和密码
* @param username 用户名
* @param password 密码
* @return 返回用户实体
*/
@Override
public User getUseByUserNameAndPwd(String username, String password) {
try {
//访问数据接口
UserDao userDao = new UserDaoImpl() ;
User user = userDao.selectUserByUsername(username) ;
if(user!=null){
//判断
if(user.getPassword().equals(password)){
return user ;
}
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
前台用户登录步骤4:dao业务实现
/**
* 数据库访问接口 通过用户名查询指定的用户
* @param registerUsername 注册的用户名
* @return 返回用户实体
*/
@Override
public User selectUserByUsername(String registerUsername) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from user where username = ?" ;
//执行查询
User user = qr.query(sql, new BeanHandler<>(User.class), registerUsername);
return user;
}
主页头部显示登录人信息
<c:if test="${empty user}">
<li><a href="${pageContext.request.contextPath}/jsp/login.jsp">登录</a></li>
<li><a href="${pageContext.request.contextPath}/jsp/register.jsp">注册</a></li>
</c:if>
<c:if test="${not empty user}">
<strong>欢迎${user.name}登录,</strong><a href="#">【退出】</a>
</c:if>
用户登出
@WebServlet("/logOut")
public class AdminLogOutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1)从request对象中获取HttpSession
HttpSession session = request.getSession();
//2)判断
if(session!=null){
//将session清除了,使用会话无效
//public void invalidate()
session.invalidate();
}
//重定向到管理员主页 response.sendRedirect(request.getContextPath()+"/admin/admin_index.jsp");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
Cookie
Cookie的使用步骤
@WebServlet("/myCookie")
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//http://localhost:8080/Cookie_Filter_war_exploded/myCookie:第一次请求
//1)服务器端创建Cookie对象
//Cookie(String name, String value)
Cookie cookie = new Cookie("name","李国栋") ;
Cookie cookie2 = new Cookie("name2","王宝强") ;
//2)设置cookie的有效路径以及它的存活时间 (有效路径默认就是当前web application上下文路径)
// cookie.setPath(request.getContextPath());
//public void setMaxAge(int expiry) :设置最大生存时间,时间为秒
cookie.setMaxAge(3600) ;
cookie2.setMaxAge(3600) ;
//3)HttpSevletResponse--->添加cookie到响应头中 (将cookie内容响应浏览器,浏览器就储存起来)
// public void addCookie(Cookie cookie)
//给浏览器添加响应头
//set-Cookie:cookie的名称=cookie的内容 存活时间 日期格式
response.addCookie(cookie) ;
response.addCookie(cookie2) ;
//4)当前浏览器再次请求:http://localhost:8080/Cookie_Filter_war_exploded/myCookie
//HttpServletRequest中,请求对象获取浏览器携带cookie
/public Cookie[] getCookies()
Cookie[] cookies = request.getCookies();
if(cookies!=null){
//遍历cookie.getName()和cookie.getValue()方法
for(Cookie c : cookies){
//获取cookie的名称和值
//public String getName()
//public String getValue()
String name = c.getName();
String value = c.getValue();
}
}else{
System.out.println("浏览器第一次访问,没有cookie数据!");
}
}
Cookie和HttpSession的区别?
1)存储数据类型的区别
cookie:只能存储String类型
HttpSession:存储任意Java类型,因为它是域对象 setAttribute(String name,Object obj)
2)存储位置的区别
cookie:存储在浏览器端,是有服务器携带给浏览器
HttpSession:是存在服务器端的,但是HttpSession依赖于Cookie的
cookie的名称:"JSESSIONID" "随机的ID字符串(标识)"
是一种持久存储"持久化",在setAttribute(String name,Object obj),"钝化"
给SESSION.ser文件写入内容,即使服务器关闭了,文件还在;
再次启动服务器,HttpSession对象.getAttribute(String name)--->"活化",从本地磁盘桑
SESSION.ser文件读取内容;
3)是否有限限制
Cookie是有限制,浏览器 可以存储20-30站点,每一个站点理论300个cookie
HttpSession无限制,不断的进行"钝化",setAttribute(String name,Object obj)写数据到文件中
过滤器Filter
过滤器的使用及生命周期
自定义一个类,让这个类实现Filter接口,重写里面的三个方法
过滤器:
1.默认是web容器启动的时候创建当前类实例,而且进行初始化: 就一次
2.过滤任务DoFilter:过滤器的入口,不断的反复调用
3.销毁:服务器正常关闭,web容器需要将过滤器实例进行销毁(标记,清除!)
@WebFiler替代xml配置方式
String[] value();
String[] urlPatterns(); //过滤的路径:一般就使用 value,
DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
// dispatcherTypes属性就是过滤器的过滤规则:直接访问还是请求转发/还是地址栏上包含某个路径等等
@WebFilter(value = "/login.jsp",dispatcherTypes = {DispatcherType.REQUEST})
public class MyFilter implements Filter {
// value = "/login.jsp" 拦截的地址 value = "/*" 拦截所有
//无参构造方法
public MyFilter(){
System.out.println("MyFilter对象被创建了...web容器一启动就创建");
}
/**
* 过滤器的初始化
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//FilterConfig过滤器的配置对象
System.out.println("init方法被调用了...." );
//过滤器配置对象FilterConfig
String filterName = filterConfig.getFilterName();
System.out.println(filterName ) ;
}
//过滤任务:过滤的逻辑
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//请求来了,过滤任务里面获取请求相关的信息
HttpServletRequest request = (HttpServletRequest) servletRequest;
//获取浏览器携带的所有cookie
Cookie[] cookies = request.getCookies() ;
if(cookies!=null){
for(Cookie c: cookies){
System.out.println(c.getName()+"---"+c.getValue());
}
}else{
System.out.println("没有cookie");
}
//服务器响应,可以处理响应相关的信息
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取前端提交的方式
String method = request.getMethod();
System.out.println("过滤任务中获取到了前端提交方式:"+method);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("hello,响应成功了!");
//放行
//参数3:过滤链
filterChain.doFilter(request,response) ;
}
//销毁
@Override
public void destroy() {
System.out.println("MyFilter.destory执行了...");
}
}
全局过滤器,解决请求及响应乱码
解决全局中文乱码的过滤器
* 解决post提交中文乱码,解决响应的中文的乱码
*/
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
System.out.println("CharacterEncodingFilter初始化了");
}
public void destroy() {
}
//过滤任务
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将req,resp强转为子接口HttpServetlRequest/HttpServletResponse
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//获取前端提交方式
String method = request.getMethod();
if("POST".equals(method)){ //POST提交
//解决POST提交中文乱码
request.setCharacterEncoding("utf-8") ;
}
//处理响应的中文乱码
response.setContentType("text/html;charset=utf-8") ;
//放行
chain.doFilter(request, response);
}
}
前台用户登录,勾选自动登录,用户信息存储在Cookie中,实现自动登录
步骤1:jsp中设置自动登录
<label>
<input type="checkbox" name="autoUser" value="auto_user"> 自动登录
</label>
<label>
<input type="checkbox"> 记住用户名
</label>
步骤2:Servlet实现
@WebServlet("/userLogin")
public class UserLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//0)解决post中文乱码
//request.setCharacterEncoding("utf-8");
//1)校验验证码 ,因为验证码存储在服务器端的
HttpSession session = request.getSession();
//接收name="code"这个验证码数据
String code = request.getParameter("code");
//获取服务器端的存储验证码
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//一次性验证
session.removeAttribute("CHECKCODE_SERVER");
if("".equals(code) || !checkcode_server.equalsIgnoreCase(code)){
request.setAttribute("msg","验证码错误!");
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response);
return;
}
//接收用户名和密码
String username = request.getParameter("username") ;
String password = request.getParameter("password") ;
//将密码加密
password = MD5Utils.md5(password);
System.out.println(username+"---"+password);
//调用UserService
UserService userService = new UserServiceImpl() ;
User user = userService.getUseByUserNameAndPwd(username,password) ;
System.out.println(user);
if(user == null){
//提示错误信息
request.setAttribute("msg","用户名或者密码输入错误!") ;
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response);
return;
}
//用户不为null
//判断用户激活状态不是1
if(user.getState() != Constant.USER_ACTIVE) {
request.setAttribute("msg","用户状态未激活,请到邮箱先激活") ;
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response) ;
return;
}
//判断用户是否勾选了自动登录
//获取name="atuoUser"参数
String autoUser = request.getParameter("autoUser");
//复选框的默认值auto_user和autoUser进行比较
if(!"auto_user".equals(autoUser)){
//没有勾选
//创建Cookie
Cookie cookie = new Cookie("autouser","") ;
//设置最大存活时间 0 ---自动删除cookie
cookie.setMaxAge(0) ;
//响应给浏览器
response.addCookie(cookie) ;
}else{
//勾选了
//存储Cookie
//定义一个cookie的内容-就是"用户名=密码",
String content = user.getUsername() +"="+user.getPassword() ;
//使用jdk工具: 编码器- URLEncoder--->public static String encode(String s, String enc)
//import java.net.URLEncoder;
//参数1:字符串内容
//参数2:字符集
content = URLEncoder.encode(content, "utf-8");
Cookie cookie = new Cookie("autouser",content) ;
//设置最大存活时间
cookie.setMaxAge(60*60*24*30) ;
//响应给浏览器
response.addCookie(cookie) ;
}
//将用户实体存储在HttpSession中
session.setAttribute("user",user) ;
//重定向到/jsp/index.jsp,前台主页
response.sendRedirect(request.getContextPath()+"/jsp/index.jsp") ;
}
步骤3:前台用户自动登录,过滤器实现自动登录
自动登录的过滤器
@WebFilter(value = "/jsp/login.jsp",dispatcherTypes = DispatcherType.REQUEST) //默认直接访问这个地址进行过滤
public class AutoLoginFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
System.out.println("AutoLoginFilter初始化了");
}
//销毁
public void destroy() {
}
/**
* 过滤任务
* @param req 请求对象
* @param resp 响应对象
* @param chain 过滤链
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1)req,resp---强转为HttpServletRequest/HttpServletResponse
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//2)获取所有的cookie(当浏览器再次请求服务器的时候 "/jsp/login.jsp")
Cookie[] cookies = request.getCookies();
//声明cookie的内容
String content = null ;
if(cookies!=null){
//浏览器中有cookie
//遍历cookie
for(Cookie cookie :cookies){
//获取到每一个Cookie ,判断如果当前cookie的名称是"autouser",获取它的内容
if("autouser".equals(cookie.getName())){
content = cookie.getValue() ;
}
}
//判断如果当前获取到的content不为null,
if(content!=null){
//加密的内容----Jdk解码器URLDecoder--->public static String decode(String s, String enc)
//参数1:字符串内容
//参数2:字符集格式
content = URLDecoder.decode(content, "utf-8");
//"用户名=密码"---通过"="拆分内容
String[] strs = content.split("=");
System.out.println("过滤器中获取到用户信息--->"+strs[0]+"---"+strs[1]);
//strs[0] :用户名
//strs[1] :密码
//调用UserService业务接口
UserService userService = new UserServiceImpl() ;
User user = userService.getUseByUserNameAndPwd(strs[0], strs[1]) ;
//获取HttpSession
HttpSession session = request.getSession();
if(user!=null){
session.setAttribute("user" ,user) ;
//重定向到首页
response.sendRedirect(request.getContextPath()+"/jsp/index.jsp");
}else{
//user没有找到
//放行
chain.doFilter(request,response);
}
}else{
//放行
chain.doFilter(request,response) ;
}
}else{
//没有cookie
//放行
chain.doFilter(request,response);
}
}
}
jdk工具: 编码器- URLEncoder
编码 public static String encode(String s, String encoing)
String content = user.getUsername() +"="+user.getPassword() ;
content = URLEncoder.encode(content, "utf-8");
Cookie cookie = new Cookie("autouser",content) ;
解码
加密的内容----Jdk解码器URLDecoder--->public static String decode(String s, String enc)
//参数1:字符串内容
//参数2:字符集格式
content = URLDecoder.decode(content, "utf-8");
项目优化,抽取一个公共的BaseServlet
ublic class BaseServlet extends HttpServlet {//所有子类servlet都继承该servlet
//程序入口,覆盖service方法,参数带的HttpServletRequest/HttpServletResponse
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取正在运行的类的字节码文件对象
Class clazz= this.getClass();//具体子类
try {
//创建子类实例
Object object = clazz.newInstance();
//自定义浏览器访问后端地址servlet的一种格式
//http://localhost:8080/Maven_2302_war/模块名称?methodName=子类的方法名(子类不同的方法)
//举例:http://localhost:8080/Maven_2302_war/user?methodName=add
String methodName = request.getParameter("methodName");
if(methodName==null){
//为空则表示访问时没有携带参数,:http://localhost:8080/Maven_2302_war/
//地址栏没有约定这个格式
methodName="index"; //此时访问主页http://localhost:8080/Maven_2302_war/
}
//通过字节码文件对象获取成员方法Method类对象
Method method = clazz.getDeclaredMethod(methodName,
HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);
method.invoke(object,request,response);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
多个servlet写成一个方法
表单提交,必须为post方法
get方式提交会覆盖xxx../user?methodName=add
xxx../user?username=xx&pasword=XX...
1.//自定义浏览器访问后端地址servlet的一种格式
//http://localhost:8080/Maven_2302_war/模块名称?methodName=子类的方法名(子类不同的方法)
修改页面访问的地址
<form method="post" action="${pageContext.request.contextPath}/user?methodName=register" id="formID">
2.子类继承Baseservlet
访问后端地址时http://localhost:8080/Maven_2302_war/user?methodName=add
创建当前类实例,在baseservlet中完成,访问谁,就创建哪个子类对象
3.注解方式配置地址值@WebServlet("/user")
4.将该模块的业务改为方法
* 前台用户模块
*/
@WebServlet("/user")
public class UserServlet extends BaseServlet{
/**
* 查询所有用户
* @param request 请求对象
* @param response 响应对象
* @throws ServletException
* @throws IOException
*/
public void getAllUsers(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String cuPage = request.getParameter("currentPage");
String pSize = request.getParameter("pageSize");
int currentPage = Integer.parseInt(cuPage);
int pageSize = Integer.parseInt(pSize);
AdminService adminService = new AdminServiceImpl();
PageBean<User> pageBean = adminService.getUserByPage(currentPage, pageSize);
request.setAttribute("pb", pageBean);
request.getRequestDispatcher("/user/uesr_list.jsp").forward(request,response);
}
jsp动作标签
<%--jsp动作标签
jsp:forward 请求转发
--%>
<%--<jsp:forward page="/jsp/index.jsp"></jsp:forward>--%>
上下文路径后无内容,直接访问后端地址/index主页
<jsp:forward page="/index"></jsp:forward
电商前台首页导航条获取分类信息
1.1ajax异步获取导航条信息
<ul id="ulDaoHang" class="nav navbar-nav">
$(function (){
//Jquery的页面载入事件
//alert("页面载入事件触发") ;
//通过id="ulDaoHang"获取Jquery的标签对象
var $ul = $("#ulDaoHang") ;
//alert($ul) ;
//发送ajax
$.ajax({
url:"${pageContext.request.contextPath}/category?methodName=getAllCategory",
type: "get",
success:function(data){
//服务器响应成功的回调函数 :date----服务器响应过来的数据json数据
//[{"cname":"手机数码","cid":"1"},{"cname":"运动户外","cid":"172934bd636d485c98fd2d3d9cccd409"},{"cname":"电脑办公","cid":"2"},{"cname":"家具家居","cid":"3"},{"cname":"鞋靴箱包","cid":"4"},{"cname":"图书音像","cid":"5"},
// {"cname":"aaaa","cid":"59f56ba6ccb84cb591c66298766b83b5"},{"cname":"母婴孕婴","cid"
//将data遍历出来
//Jquery对象访问的方法each(...){}
//var $data = $(data) ;
//alert($data) ;
//data:后端响应过来的数据---解析js对象----将js对象 通过$(js对象),转换成Jq
var data = JSON.parse(data) ;
//alert($(data)) ;
$(data).each(function(){ //转换成$(data)Jquery对象
// alert(this.cname) ;
$ul.append("<li><a href='${pageContext.request.contextPath}/product?methodName=getProductByPage&curPage=1&pSize=12&cid="+this.cid+"'>"+this.cname+"</a><span class='sr-only'>(current)</span><li>");
})
} ,
dateType:"json"
})
})
1.2异步获取导航条信息servlet
/**
* 分类信息的后端访问地址
*/
@WebServlet("/category")
public class CategoryServlet extends BaseServlet {
/**
* 获取商品分类信息
* @param request 请求对象
* @param response 响应对象
*/
public void getAllCategory(HttpServletRequest request,HttpServletResponse response) throws IOException {
//直接访问分类业务接口
CategoryService categoryService = new CategoryServiceImpl() ;
List<Category> allCaregorys = categoryService.getAllCaregorys();
//response.setContentType("application/json;charset=utf-8");
//将集合对象转换成json,响应给前端
String jsonStr = JsonUtils.list2json(allCaregorys);
//[{},{}]
//响应
response.getWriter().write(jsonStr);
}
}
1.3异步获取导航条信息servlce
public class CategoryServiceImpl implements CategoryService {
/**
* 获取所有分类信息
* @return 返回分类列表
*/
@Override
public List<Category> getAllCaregorys() {
try {
//访问数据
CategoryDao categoryDao = new CategoryDaoImpl() ;
List<Category> categories = categoryDao.selectAllCategorys();
if(categories!=null || categories.size()>0){
return categories ;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
}
1.3异步获取导航条信息dao
public class CategoryDaoImpl implements CategoryDao {
/**
* 数据访问接口获取所有分类
* @return 返回分类列表
*/
@Override
public List<Category> selectAllCategorys() throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from category" ;
//查询
List<Category> categories = qr.query(sql, new BeanListHandler<>(Category.class)) ;
return categories;
}
}
点击导航条分类信息,展示商品分页信息
1.1点击链接跳转
var data = JSON.parse(data) ;
//alert($(data)) ;
$(data).each(function(){ //转换成$(data)Jquery对象
// alert(this.cname) ;
$ul.append("<li><a href='${pageContext.request.contextPath}/product?methodName=getProductByPage&curPage=1&pSize=12&cid="+this.cid+"'>"+this.cname+"</a><span class='sr-only'>(current)</span><li>");
})
} ,
dateType:"json"
1.2根据分类,展示商品分页信息servlet
/**
* 点击分类信息获取商品分页数据
* @param request 请求对象
* @param response 响应对象
*/
public void getProductByPage(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//${pageContext.request.contextPath}/product?methodName=getProductByPage&curPage=1&pSize=12&cid="+this.cid+"'
//1)接收参数
String curPage = request.getParameter("curPage");
String pSize = request.getParameter("pSize");
String cid = request.getParameter("cid") ;
//2)将curPage/pSize转换成int
int currentPage = Integer.parseInt(curPage);
int pageSize = Integer.parseInt(pSize);
//3)调用商品业务接口
ProductService productService = new ProductServiceImpl() ;
PageBean<Product> pb = productService.getProductsByPage(currentPage, pageSize, cid);
System.out.println(pb) ;
//4)存储在request域中
request.setAttribute("pb",pb) ;
//5)请求转发到jsp/product_list.jsp
request.getRequestDispatcher("/jsp/product_list.jsp").forward(request,response);
}
1.3根据分类,展示商品分页信息service
@Override
public PageBean<Product> getProductsByPage(int currentPage, int pageSize, String cid) {
List<Product> list = null;
try {
//访问数据接口
ProductDao productDao = new ProductDaoImpl() ;
//起始索引
int start = (currentPage-1)*pageSize ;
list = productDao.selectProductByPage(start, pageSize, cid);
//以后将list第一次查询出来----存储在"redis" (no sql数据库) key:value键值对
int totalCount = productDao.totalCount(cid);
if(list!=null || list.size()>0){
return new PageBean<>(currentPage,pageSize,totalCount,list);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null ;
}
1.4根据分类,展示商品分页信息dao
/**
* 数据访问接口查询商品分页数据
* @param start 起始索引=(当前页码-1)*每页显示的条数
* @param pageSize 每页显示的条数
* @param cid 分类id
* @return 返回商品列表数据
*/
@Override
public List<Product> selectProductByPage(int start, int pageSize, String cid) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from product where cid = ? limit ?,?" ;
//查询
List<Product> productList = qr.query(sql, new BeanListHandler<>(Product.class), cid, start, pageSize);
return productList;
}
/**
* 根据商品分类id获取商品的总记录数
* @param cid 分类id
* @return 返回总记录数
*/
@Override
public int totalCount(String cid) throws SQLException {
//执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select count(pid) from product where cid = ?" ;
Object obj = qr.query(sql, new ScalarHandler<>(), cid);
int totalCount = Integer.parseInt(String.valueOf(obj)) ;
return totalCount;
}
1.5展示数据jsp
<c:forEach items="${pb.pageList}" var="p">
<div class="col-md-2">
<a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}">
<img src="${pageContext.request.contextPath}/${p.pimage}" width="170" height="170" style="display: inline-block;">
</a>
<p><a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}" style='color:green'>${fn:substring(p.pname,0 ,6 )}...</a></p>
<p><font color="#FF0000">商城价:¥${p.shop_price}</font></p>
</div>
</c:forEach>
<!--分页 -->
<div style="width:380px;margin:0 auto;margin-top:50px;">
<ul class="pagination" style="text-align:center; margin-top:10px;">
<%--
判断如果是第一页
--%>
<c:if test="${pb.currentPage==1}">
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
</c:if>
<%--判断如果不是第一页--%>
<c:if test="${pb.currentPage!=1}">
<li>
<a href="${pageContext.request.contextPath}/product?methodName=getProductByPage&curPage=${pb.currentPage-1}&pSize=12&cid=${param.cid}" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
</c:if>
<%--遍历页码--%>
<c:forEach begin="1" end="${pb.totalPage}" var="n">
<%--是否是当前页--%>
<c:if test="${pb.currentPage==n}">
<%--是当前页--%>
<li class="active">
<a href="#">${n}</a>
</li>
</c:if>
<%--不是当前页--%>
<c:if test="${pb.currentPage!=n}">
<%--不是当前页--%>
<li>
<a href="${pageContext.request.contextPath}/product?methodName=getProductByPage&curPage=${n}&pSize=12&cid=${param.cid}">${n}</a>
</li>
</c:if>
</c:forEach>
电商前台首页获取最新商品和热门商品
获取数据
@WebServlet("/index")
public class IndexServlet extends BaseServlet{
public void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ProductService productService = new ProductServiceImpl();
List<Product> newProducts = productService.getNewProducts();
List<Product> hostProducts = productService.getHostProducts();
if(newProducts!=null && hostProducts!=null){
request.setAttribute("newProducts",newProducts);
request.setAttribute("hostProducts",hostProducts);
}
request.getRequestDispatcher("/jsp/index.jsp").forward(request, response);
}
service层
/**
* 获取最新商品
* @return 返回商品列表
*/
@Override
public List<Product> getNewProducts() {
List<Product> productList = null;
try {
ProductDao productDao = new ProductDaoImpl();
productList = productDao.selectNewProducts();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return productList;
}
/**
* 获取热门商品
* @return 返回商品列表
*/
@Override
public List<Product> getHostProducts() {
List<Product> productsList = null;
try {
ProductDao productDao = new ProductDaoImpl();
productsList = productDao.selectNewProducts();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return productsList;
}
dao层
/**
* 数据访问接口,根据商品的上架日期查询最新的商品
* @return 商品列表,日期降序排序,获得10条数据
*/
@Override
public List<Product> selectNewProducts() throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
String sql = "select * from product order by pdate asc limit 10;";
List<Product> list = qr.query(sql, new BeanListHandler<>(Product.class));
return list;
}
/**
* 数据访问接口,根据商品的属性is_host查询热门商品
* @return 商品列表,10条数据
*/
@Override
public List<Product> selectHostProducts() throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
String sql = "select * from product where is_host=1 limit 10;";
List<Product> list = qr.query(sql, new BeanListHandler<>(Product.class));
return list;
}
展示数据
<%--遍历数据--%>
<c:forEach items="${newProducts}" var="p">
<div class="col-md-2" style="text-align:center;height:200px;padding:10px 0px;">
<a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}">
<%--商品图片--%>
<img src="${pageContext.request.contextPath}/${p.pimage}" width="130" height="130" style="display: inline-block;">
</a>
<%--商品名称--%>
<p><a href="{pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}" style='color:#666'>${fn:substring(p.pname, 0, 6)}...</a></p>
<%--商城价格--%>
<p><font color="#E4393C" style="font-size:16px">¥${p.shop_price}</font></p>
</div>
</c:forEach>
jstl函数库:fn
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
${fn:substring(<string>, <beginIndex>, <endIndex>)}
参数1:获取指定的字符串名称
参数2:指定开始截取的索引位置 从0开始
参数3:最终索引,包含endIndex-1处
<a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}" style='color:#666'>${fn:substring(p.pname, 0, 6)}...</a>
公共导航条抽取
创建header.jsp
其他页面导入,静态包含指令include,导入的jsp页面不会被单独编译和翻译
<%@include file="header.jsp"%>
电商展示商品详情
点击商品名称或图片超链接跳转商品服务器地址
<a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}">
<img src="${pageContext.request.contextPath}/${p.pimage}" width="130" height="130" style="display: inline-block;"> </a>
<p><a href="${pageContext.request.contextPath}/product?methodName=getProduct&pid=${p.pid}" style='color:#666'>${fn:substring(p.pname, 0, 6)}...</a></p>
1.1展示商品详情,servlet层
/**
* 查询商品详情
* @param request 请求对象
* @param response 响应对象
*/
public void getProduct(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pid = request.getParameter("pid");
ProductService productService = new ProductServiceImpl();
Product product = productService.getProduct(pid);
if(product!=null){
request.setAttribute("product", product);
}
request.getRequestDispatcher("/jsp/product_info.jsp").forward(request, response);
}
1.2展示商品详情service层
/**
* 通过商品id获取商品信息
* @param pid 商品id
* @return 商品实体
*/
@Override
public Product getProduct(String pid) {
try {
ProductDao productDao = new ProductDaoImpl();
Product product = productDao.getProduct(pid);
if (product != null) {
return product;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
1.3展示商品详情dao层
/**
* 通过商品id查询数据库获取商品信息
* @param pid 商品id
* @return 商品实体
*/
@Override
public Product getProduct(String pid) throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
String sql = "select * from product where pid=?";
Product product = qr.query(sql, new BeanHandler<>(Product.class), pid);
return product;
}
1.4展示商品详情jsp
<div><strong>${product.pname}</strong></div>
<div style="border-bottom: 1px dotted #dddddd;width:350px;margin:10px 0 10px 0;">
<div>编号:${product.pid}</div>
</div>
<div style="margin:10px 0 10px 0;">商城价: <strong style="color:#ef0101;">¥:${product.shop_price}</strong> 市场价: <del>¥${product.market_price}</del>
</div>
购物车
1.1商品详情页表单提交购物车
<form id="form" action="${pageContext.request.contextPath}/cart?methodName=addCartItem2Cart" method="post">
<%--隐藏域--%>
<input type="hidden" name="pid" value="${product.pid}"/>
<div class="col-md-6">
<div><strong>${product.pname}</strong></div>
<div style="border-bottom: 1px dotted #dddddd;width:350px;margin:10px 0 10px 0;">
<div>编号:${product.pid}</div>
</div>
<div style="margin:10px 0 10px 0;">商城价: <strong style="color:#ef0101;">¥:${product.shop_price}</strong> 市场价: <del>¥${product.market_price}</del>
</div>
<div style="margin:10px 0 10px 0;">促销: <a target="_blank" title="限时抢购 (2014-07-30 ~ 2015-01-01)" style="background-color: #f07373;">限时抢购</a> </div>
<div style="padding:10px;border:1px solid #e7dbb1;width:330px;margin:15px 0 10px 0;;background-color: #fffee6;">
<div style="margin:5px 0 10px 0;">白色</div>
<div style="border-bottom: 1px solid #faeac7;margin-top:20px;padding-left: 10px;">购买数量:
<input id="quantity" readonly name="count" value="1" maxlength="4" size="10" type="text"> </div>
<div style="margin:20px 0 10px 0;;text-align: center;">
<a href="javascript:void(0)">
<input onclick="addCartItem()" style="background-color: #ffd002" value="加入购物车" type="button">
</a> </div>
</div>
<script>
function addCartItem(){
//触发表单提交
//通过id="form" 获取form标签对象
var $form = $("#form") ;
//submit事件
$form.submit() ;
}
</script>
1.2购物车实体
/**
* @author 嘟嘟噜
* @version 1.0
* @date 2023/4/24 23:18
* 购物车实体
*/
public class Cart {
//Map集合实例--代表存储的多个购物车项
//Key:代表商品id
//Value:购物车项CartItem
private Map<String ,CartItem> map = new LinkedHashMap<>() ;//保证迭代次序有序
private double totalMoney = 0.0 ;//购物车总金额
/**
* 向购物车中添加购物项
* @param cartItem 购物项
*/
public void addCartItem2Cart(CartItem cartItem){
//获取新添加的购物车的商品id
String pid = cartItem.getProduct().getPid();
//在Map中判断键是否重复,是否已经添加过该商品
if (map.containsKey(pid)){//如果重复
CartItem oldCartItem = map.get(pid);//通过key获取value,pid--->购物项实体
oldCartItem.setCount(oldCartItem.getCount() + 1);//原来的购物车项的数量+1
}else {
//如果不重复,没有添加过该购物车项
map.put(pid,cartItem);
}
totalMoney+=cartItem.getSubTotal();//小计金额累计加
}
/**
* 通过商品pid从购物车中删除购物项
* @param pid 商品pid
*/
public void removeCartItemFormCart(String pid){
CartItem cartItem = map.remove(pid);//删除方法,通过key删除,返回删除的value对象
totalMoney -= cartItem.getSubTotal();// 总金额减少购物项中的对应的小计金额
}
public void clearCart(){
map.clear(); //map方法,清空集合内容,将购物车内全部清空
totalMoney = 0.0;
}
//获取所有值---集合Collection<V> values()
public Collection<CartItem> getCartItems(){ //cartItems 购物车的bean属性
return map.values() ;
}
public Cart() {
}
public Map<String, CartItem> getMap() {
return map;
}
public void setMap(Map<String, CartItem> map) {
this.map = map;
}
public double getTotalMoney() {
return totalMoney;
}
public void setTotalMoney(double totalMoney) {
this.totalMoney = totalMoney;
}
}
1.3购物车项实体
/**
* @author 嘟嘟噜
* @version 1.0
* @date 2023/4/24 23:05
* 购物项实体
*/
public class CartItem {
private Product product;//商品
private int count;//数量
private double subTotal;//小计金额
public CartItem() {
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getSubTotal() {
return product.getShop_price() * count;
}
}
1.4购物车servlet
package com.ddl.controller;
/**
* @author 嘟嘟噜
* @version 1.0
* @date 2023/4/24 23:49
*/
import com.ddl.pojo.Cart;
import com.ddl.pojo.CartItem;
import com.ddl.pojo.Product;
import com.ddl.pojo.User;
import com.ddl.service.ProductService;
import com.ddl.service.impl.ProductServiceImpl;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet( "/cart")
public class CartServlet extends BaseServlet {
//将购物车存储到HttpSession中,添加/删除/清空,都需要获取Cart购物车
public Cart getCartFromHttpSession(HttpServletRequest request){
//获取session
HttpSession session = request.getSession();
//从session中获取购物车
Cart cart = (Cart) session.getAttribute("cart");
if (cart==null){
//如果购物车为空,则创建一个购物车,存储到HttpSession中
cart= new Cart();
session.setAttribute("cart",cart);
}
return cart;
}
public void addCartItem2Cart(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
//判断用户是否登录
User user = (User) session.getAttribute("user");
if (user==null){
response.sendRedirect(request.getContextPath()+"/jsp/login.jsp");
return;
}
String pid = request.getParameter("pid"); //购物车表单提交,添加购物车项
String getCount = request.getParameter("count");//购物车表单提交,获取商品数量
ProductService productService = new ProductServiceImpl();
Product product = productService.getProduct(pid);//通过编号获取商品实体
//封装购物车项
CartItem cartItem = new CartItem();
int count = Integer.parseInt(getCount);
cartItem.setCount(count);
cartItem.setProduct(product);
//从上面的getCartFromHttpSession获取购物车
Cart cart = getCartFromHttpSession(request);
//购物车方法,添加购物车项
cart.addCartItem2Cart(cartItem) ;
//重定向到 购物车页面
response.sendRedirect(request.getContextPath()+"/jsp/cart.jsp");
}
public void ClearCart(HttpServletRequest request, HttpServletResponse response) throws IOException {
//获取购物车
Cart cart = getCartFromHttpSession(request);
//清空购物车
cart.clearCart();
//从HttpSession中删除购物车
request.getSession().removeAttribute("cart");
response.sendRedirect(request.getContextPath()+"/jsp/cart.jsp");
}
public void delCartItem(HttpServletRequest request, HttpServletResponse response) throws IOException {
String pid = request.getParameter("pid");
Cart cart = getCartFromHttpSession(request);
cart.removeCartItemFormCart(pid);
response.sendRedirect(request.getContextPath()+"/jsp/cart.jsp");
}
}
1.5购物车jsp展示数据
<c:if test="${ empty cart}">
<h2>亲,空空如也~~~,请<a href="${pageContext.request.contextPath}/index">购物</a>></h2>
</c:if>
<c:if test="${not empty cart}">
<div style="margin:0 auto; margin-top:10px;width:950px;">
<strong style="font-size:16px;margin:5px 0;">购物车信息</strong>
<table class="table table-bordered">
<tbody>
<tr class="warning">
<th>图片</th>
<th>商品</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
<th>操作</th>
</tr>
<%--遍历每一个购物车项
el表达式 可以操作javaBean
快速ognl对象图导航语言操作bean属性
${域中的属性名.实体的bean属性} ---域对象.getAttribute("属性名").getXXX()
访问getXXX()方法
--%>
<c:forEach items="${cart.cartItems}" var="bean"> <%--bean代表每一个购物车项--%>
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="id" value="22">
<img src="${pageContext.request.contextPath}/${bean.product.pimage}" width="70" height="60">
</td>
<td width="30%">
<a target="_blank">${bean.product.pname}</a>
</td>
<td width="20%">
¥${bean.product.shop_price}
</td>
<td width="10%">
<input type="text" value="${bean.count}" maxlength="4" size="10">
</td>
<td width="15%">
<span class="subtotal">¥${bean.subTotal}</span>
</td>
<td>
<a href="javascript:void(0)" onclick="delCartItem('${bean.product.pid}')" class="delete">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div style="margin-right:130px;">
<div style="text-align:right;">
<em style="color:#ff6600;">
登录后确认是否享有优惠
</em> 赠送积分: <em style="color:#ff6600;">${cart.totalMoney}</em> 商品金额: <strong style="color:#ff6600;">¥${cart.totalMoney}元</strong>
</div>
</c:if>
</div>
<div style="text-align:right;margin-top:10px;margin-bottom:10px;">
<a href="${pageContext.request.contextPath}/cart?methodName=ClearCart" id="clear" class="clear">清空购物车</a>
<a href="${pageContext.request.contextPath}/order?methodName=submitOrder">
<input type="submit" width="100" value="提交订单" name="submit" border="0" style="background-color:#E66B1A" />
</a>
</div>
</div>
</div>
购物车中提交订单—产生订单数据–展示订单
1.1 点击提交订单超链接–发送请求
${pageContext.request.contextPath}/order?methodName=generateOrder"
展示order_info的数据
<%--遍历每一个订单项
Order实体里面---List<OrderItem> getList()
el表达式 操作list属性
--%>
<c:forEach items="${order.list}" var="bean">
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="id" value="22">
<img src="${pageContext.request.contextPath}/${bean.product.pimage}" width="70" height="60">
</td>
<td width="30%">
<a target="_blank">${bean.product.pname}</a>
</td>
<td width="20%">
¥${bean.product.shop_price}
</td>
<td width="10%">
${bean.count}
</td>
<td width="15%">
<span class="subtotal">¥${bean.subtotal}</span>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div style="text-align:right;margin-right:120px;">
商品金额: <strong style="color:#ff6600;">¥${order.total}</strong>
</div>
</div>
1.2 OrderServlet 订单后端访问地址
/**
* 订单的后端访问地址
*/
@WebServlet("/order")
public class OrderServlet extends BaseServlet {
/**
*生成订单信息和订单项信息
* @param request 请求对象
* @param response 响应对象
*/
public void generateOrder(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
//封装订单数据之前,从request域中获取HttpSession,是否有用户信息;如果没有,继续登录
User user = (User) request.getSession().getAttribute("user");
if(user==null){
//重定向登录页面中
response.sendRedirect(request.getContextPath()+"/jsp/login.jsp");
return;
}
//封装订单
Order order = new Order() ;
//订单编号
order.setOid(UUIDUtils.getId()) ;
//下订单时间
order.setOrdertime(new Date()) ;
//从HttpSession获取购物车
Cart cart = (Cart) request.getSession().getAttribute("cart") ;
//获取购物车中的总金额
order.setTotal(cart.getTotalMoney()) ;
//收货地址/电话/收货人
//封装订单项----包含的商品/数量/小计--都来自于购物车CartItem
OrderItem orderItem = null ;
for(CartItem cartItem:cart.getCartItems()){
//获取到每一个购物车项
orderItem = new OrderItem() ;
//订单项itemid
orderItem.setItemid(UUIDUtils.getId()) ;
orderItem.setCount(cartItem.getCount()) ;
orderItem.setSubtotal(cartItem.getSubTotal()) ;
orderItem.setProduct(cartItem.getProduct()) ;
orderItem.setOrder(order) ; //属于哪个订单
//订单里面添加多个订单项数据
List<OrderItem> list = order.getList();
list.add(orderItem) ;
}
//这个订单属于哪个用户的
order.setUser(user) ;
//调用订单业务接口
OrderService orderService = new OrderServiceImpl() ;
orderService.addOrder(order) ;
//将购物车里面的数据删除了
request.getSession().removeAttribute("cart") ;
//将Order实体存储在request域中
request.setAttribute("order",order) ;
//请求转发到/jsp/order_info.jsp
request.getRequestDispatcher("/jsp/order_info.jsp").forward(request,response);
}
}
1.3 OrderService订单业务接口实现
/**
* @author 高圆圆
* @date 2023/4/25 14:14
* 订单业务接口实现
*/
public class OrderServiceImpl implements OrderService {
/**
* 添加订单信息
* @param order 订单实体
*/
@Override
public void addOrder(Order order) {
try {
//调用订单数据访问接口
OrderDao orderDao = new OrderDaoImpl() ;
//控制事务:产生订单这个业务需要同时给订单项和订单添加数据,要么同时执行成功,要么同时失败
//获取连接对象---封装到自定义工具类中
DruidJdbcUtils.setAutoCommit();
//插入订单
orderDao.insertOrder(order) ;
//有一个异常
// int i = 1 / 0 ;
for(OrderItem orderItem:order.getList()){
//插入订单项
orderDao.insertOrderItem(orderItem);
}
//提交事务
DruidJdbcUtils.commitAndClose();
} catch (SQLException throwables) {
//事务回滚
try {
DruidJdbcUtils.rollbackAndClose();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}
}
}
1.4 Orderdao:订单数据访问接口层实现
/**
* @author 高圆圆
* @date 2023/4/25 14:17
* 订单数据访问接口实现
*/
public class OrderDaoImpl implements OrderDao {
/**
* 插入订单
* @param order 订单实体
*/
@Override
public void insertOrder(Order order) throws SQLException {
//自动提交
/* //执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "insert into orders values(?,?,?,?,?,?,?,?)" ;
int count = qr.update(sql,
order.getOid(),
order.getOrdertime(),
order.getTotal(),
order.getState(),
order.getAddress(),
order.getUser().getName(),
order.getTelephone(),
order.getUser().getUid());*/
//Commons-dbutils使用这个工具---自动提交---需要执行对象QueryRunner无参构造方法
QueryRunner qr = new QueryRunner() ;
String sql = "insert into orders values(?,?,?,?,?,?,?,?)" ;
//添加/删除/修改 ----update(Connection conn,String sql,Object[] params...)
int count = qr.update(
DruidJdbcUtils.getConnection(),
sql, order.getOid(),
order.getOrdertime(),
order.getTotal(),
order.getState(),
order.getAddress(),
order.getUser().getName(),
order.getTelephone(),
order.getUser().getUid());
}
/**
* 插入订单项实体
* @param orderItem 订单项实体
*/
@Override
public void insertOrderItem(OrderItem orderItem) throws SQLException {
/* //执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "insert into orderitem values(?,?,?,?,?)" ;
int count = qr.update(sql,
orderItem.getItemid(),
orderItem.getCount(),
orderItem.getSubtotal(),
orderItem.getProduct().getPid(),
orderItem.getOrder().getOid());*/
QueryRunner qr = new QueryRunner() ;
String sql = "insert into orderitem values(?,?,?,?,?)" ;
int count = qr.update(
DruidJdbcUtils.getConnection(),
sql,
orderItem.getItemid(),
orderItem.getCount(),
orderItem.getSubtotal(),
orderItem.getProduct().getPid(),
orderItem.getOrder().getOid());
}
}
1.5订单实体
/**
* @author 嘟嘟噜
* @version 1.0
* @date 2023/4/25 19:14
* 订单实体
*/
public class Order {
private String oid; //订单编号,UUID生成
private Date ordertime; //下订单时间
private double total; //总金额,来自购物车的总金额
private int state; //订单状态,默认为0未支付,1为已支付
private String address ; //订单收货地址
private String name; // 收货人
private String telephone; //电话号码
private User user ;//订单属于的用户,包含uid等信息
private List<OrderItem> list = new LinkedList<>(); //订单中的订单项
public Order() {
}
public String getOid() {
return oid;
}
public List<OrderItem> getList() {
return list;
}
public void setList(List<OrderItem> list) {
this.list = list;
}
public void setOid(String oid) {
this.oid = oid;
}
public Date getOrdertime() {
return ordertime;
}
public void setOrdertime(Date ordertime) {
this.ordertime = ordertime;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
1.6订单项实体
/**
* 订单项实体
* @author 嘟嘟噜
* @version 1.0
* @date 2023/4/25 19:09
*/
public class OrderItem {
private String itemid; //订单编号,UUID工具生成
private int count; //商品数量,可从购物车数据中取出
private double subtotal; //订单项的小计金额,可从购物车数据中取出
private Product product; //包含的商品,可从购物车数据中取出
private Order order; // 属于哪个订单
public OrderItem() {
}
public String getItemid() {
return itemid;
}
public void setItemid(String itemid) {
this.itemid = itemid;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getSubtotal() {
return subtotal;
}
public void setSubtotal(double subtotal) {
this.subtotal = subtotal;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
查询用户订单列表-分页展示
1.1点击链接跳转后端地址
<a href="${pageContext.request.contextPath}/order?methodName=getOrderListByPage¤tPage=1&pageSize=3">订单列表</a>
1.2查询用户订单列表servlet
public void getOrderListByPage(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
User user = (User) request.getSession().getAttribute("user");
if (user == null){
response.sendRedirect(request.getContextPath()+"/jsp/login.jsp");
return;
}
String cPage = request.getParameter("currentPage");
String pPage = request.getParameter("pageSize");
int currentPage = Integer.parseInt(cPage);
int pageSize = Integer.parseInt(pPage);
OrderService orderService = new OrderServiceImpl();
PageBean<Order> pageBean = orderService.getOrderByPage(currentPage, pageSize, user);
request.setAttribute("pb",pageBean);
for (Order order : pageBean.getPageList()) {
System.out.println( order.getOid());
}
request.getRequestDispatcher("/jsp/order_list.jsp").forward(request,response);
}
1.3查询用户订单列表servlce层
/**
* 分页查询订单列表接口
* @param currentPage 当前页码
* @param pageSize 每页显示的数量
* @param user 用户实体
* @return 分页信息实体
*/
@Override
public PageBean<Order> getOrderByPage(int currentPage, int pageSize, User user) {
try {
OrderDao orderDao = new OrderDaoImpl();
List<Order> list = orderDao.getOrderByPage(currentPage, pageSize, user);
int count = orderDao.getTotalCount(user);
System.out.println(list);
PageBean<Order> pageBean= new PageBean<>(currentPage,pageSize,list,count);
System.out.println(pageBean);
if (list!=null || list.size()>0){
return pageBean;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
1.4查询用户订单列表dao层
/**
* 数据库访问接口,分页查询订单
*
* @param currentPage 当前页码
* @param pageSize 每页显示条数
* @param user 用户实体
* @return 订单集合
*/
@Override
public List<Order> getOrderByPage(int currentPage, int pageSize, User user) throws SQLException, InvocationTargetException, IllegalAccessException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
//分页查询用户的订单列表
String sql = "select * from orders where uid =? order by ordertime desc limit ?,?";
List<Order> orderList = qr.query(sql, new BeanListHandler<>(Order.class),
user.getUid(),
(currentPage - 1) * pageSize,
pageSize);
//订单项,商品表内联接查询页
sql = "select * from orderitem oi,product po where oi.pid=po.pid and oid=?";
//遍历每一个订单
for (Order order : orderList) {
//key为订单项和商品的属性,value为对应的属性值
List<Map<String, Object>> mapOfOrderItem = qr.query(sql, new MapListHandler(), order.getOid());
//遍历每一个订单项,封装每个订单中的订单项,加入到每一个订单下
for (Map<String, Object> map : mapOfOrderItem) {
OrderItem orderItem = new OrderItem();
Product product = new Product();
//工具类将map中的信息,商品的值封装进商品中
BeanUtils.populate(product, map);
//工具类将map中的信息,订单项的值封装进订单项中
BeanUtils.populate(orderItem, map);
//将商品封装进订单项中
orderItem.setProduct(product);
//获得每一个订单的集合
List<OrderItem> list = order.getList();
//将每一个订单项加入到对应的订单中
list.add(orderItem);
}
}
return orderList;
}
/**
* 数据访问接口,通过用户实体的id查询用户的订单总数
*
* @param user 用户实体
* @return 订单总数
*/
@Override
public int getTotalCount(User user) throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource());
//查询用户的订单总数
String sql = "select count(oid) from orders where uid=?";
Object obj = qr.query(sql, new ScalarHandler<>(), user.getUid());
int count = Integer.parseInt(String.valueOf(obj));
return count;
}
支付宝支付
1.1配置
public class AlipayConfig {
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数
public static String return_url = "http://yuqx65.natappfree.cc/test08_war_exploded/aliPayReturnUrlServlet"; // 此处使用外网ip(使用免费的花生壳或者netapp产生的外网域名)
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://yuqx65.natappfree.cc/test08_war_exploded/notify";
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String app_id = "2021000122685092";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String alipay_public_key ="xxx";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String merchant_private_key="xxx";
// 签名方式
public static String sign_type = "RSA2";
// 字符编码格式
public static String charset = "utf-8";
// 支付宝网关
public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do" ;
}
<!--加入支付宝的SDK-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.12.4.ALL</version>
</dependency>
@WebServlet("/aliPayReturnUrlServlet")
public class AliPayReturnUrlServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//支付宝回调 : 外网必须访问:
//支付宝响应get请求
PrintWriter out = response.getWriter();
//输入支付密码--->确认支付--->通过内网穿透工具产生的外链(公网域名)去访问本地web服务
//获取支付宝GET过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
//tomcat7.0 get提交中文的乱码
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
//System.out.println("转码后:"+valueStr);
params.put(name, valueStr);
//订单账号/订单总金额/订单中的信息主题("数码产品....")
}
try {
//调用SDK验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params,
//支付宝应用公钥
AlipayConfig.alipay_public_key, //否则验签失败
//编码格式 utf-8
AlipayConfig.charset,
//验签方式
AlipayConfig.sign_type);
//——请在这里编写您的程序(以下代码仅作参考)——
if(signVerified) {
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金额
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
//调用OrderService业务接口,将支付的状态变成1(完成业务)
OrderService orderService = new OrderServiceImpl() ;
//通过订单编号获取订单 out_trade_no
Order order = orderService.getOrderByOid(out_trade_no);
order.setState(1) ;
orderService.updateOrderState(order) ;
//设置成功的页面
request.setAttribute("order",order) ;
//请求转发到/success.jsp
request.getRequestDispatcher("/jsp/success.jsp").forward(request,response);
}else {
//启用的支付宝的公钥模式---没有使用支付宝公钥
out.println("验签失败");
}
//——请在这里编写您的程序(以上代码仅作参考)——
} catch (AlipayApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
1.2jsp
<form id="payForm" action="${pageContext.request.contextPath}/order?methodName=pay" method="post">
<%--隐藏域--%>
<input type="hidden" name="oid" value="${order.oid}" />
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="id" value="22">
<img src="${pageContext.request.contextPath}/${bean.product.pimage}" width="70" height="60">
</td>
<td width="30%">
<a target="_blank">${bean.product.pname}</a>
</td>
<td width="20%">
¥${bean.product.shop_price}
</td>
<td width="10%">
${bean.count}
</td>
<td width="15%">
<span class="subtotal">¥${bean.subtotal}</span>
</td>
</tr>
</form>
<script>
function btn_pay(){
//获取id="payForm"的jquery标签对象,触发表单提交事件
var form = $("#payForm");
form.submit() ;
}
</script>
1.3订单支付servlet
/**
* 订单支付的功能---调用支付宝接口
* @param request 请求对象
* @param response 响应对象
*/
public void pay(HttpServletRequest request, HttpServletResponse response){
String oid = request.getParameter("oid");
//System.out.println(oid);
//调用订单业务接口---通过订单编号获取订单实体
OrderService orderService = new OrderServiceImpl() ;
Order order = orderService.getOrderByOid(oid);
try {
//获得初始化的AlipayClient (创建支付宝客户端对象)
AlipayClient alipayClient = new DefaultAlipayClient(
AlipayConfig.gatewayUrl,
AlipayConfig.app_id,
AlipayConfig.merchant_private_key,
"json",
AlipayConfig.charset,
AlipayConfig.alipay_public_key,
AlipayConfig.sign_type);
//设置请求参数---设置支付宝回调的参数
AlipayTradePagePayRequest alipayRequest =
new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//设置发送请求的时候,里面的具体的参数:
//1)out_trade_no:订单编号
//2)subject:主题信息
//3)product_code:产品码名称,支付宝默认值:FAST_INSTANT_TRADE_PAY
//4)total_amount:总金额
alipayRequest.setBizContent("{\"out_trade_no\":\""+ order.getOid() +"\","
+ "\"total_amount\":\""+ order.getTotal() +"\","
+ "\"subject\":\""+ "数码产品" +"\","
+ "\"body\":\""+ "手机和电脑相关"+"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//若想给BizContent增加其他可选请求参数,以增加自定义超时时间参数timeout_express来举例说明
//alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
// + "\"total_amount\":\""+ total_amount +"\","
// + "\"subject\":\""+ subject +"\","
// + "\"body\":\""+ body +"\","
// + "\"timeout_express\":\"10m\","
// + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节
//请求
//将设置表单信息全部以form表单方式发送支付宝
String result = alipayClient.pageExecute(alipayRequest).getBody();
//输出
//响应给浏览器---->用户看到支付宝的登录页面
response.getWriter().write(result) ;
response.getWriter().flush();
response.getWriter().close();
} catch (AlipayApiException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
1.4订单支付service dao
/**
* 修改订单支付状态
* @param order 订单实体
*/
@Override
public void updateOrderState(Order order) {
try {
OrderDao orderDao = new OrderDaoImpl() ;
orderDao.updateOrderFroState(order);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 数据访问接口,修改订单支付状态
* @param order 订单实体
*/
@Override
public void updateOrderFroState(Order order) throws SQLException {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
String sql = "update orders set state =? where oid =?";
qr.update(sql,order.getState(),order.getOid());
}
文件上传
1.前端-文件上传的表单
<form action="访问后端地址" method="post" enctype="multipart/form-data" >
上传图片:<input type="file" name="file" />
</form>
enctype="multipart/form-data" 支持多文件上传
必须设置为post提交
上传组件:input type="file"
2. 后端访问接口地址中—>Servlet提供的@MultipartConfig
@MulipartConfig--->会前端文件上传组件 input type="file"获取到文件流对象
@WebServlet("/upload")
@MultipartConfig
public class UploadFileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收其他的表单数据
//String pname = request.getParameter("pname");
//System.out.println(pname) ;
//接收 前端enctype="multipart/form-data"--->支持post
//1)通过请求对象Part对象----它可以解析文件名称
Part part = request.getPart("file") ;//参数--->文件上传组件的name属性值
//2)获取上传文件的名称
String fileName = part.getSubmittedFileName() ;
// System.out.println("上传文件的名称是:"+fileName) ;
//3)获取文件的存储路径---项目部署路径
String realPath = request.getServletContext().getRealPath("/myImage");
// System.out.println("文件存储路径是:"+realPath) ;
// D:\EE_2302\day43\code\Maven_2302\src\main\webapp\myImage
//4)通过part对象将写入磁盘上--->realpath地址里面
part.write(realPath+"/"+fileName);
// part.write("") ; //绝对路径
//数据库图片地址,/myImage/图片名称
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
Git 分布式版本控制系统
命令行方式使用:
初始化本地库
git init //在指定的文件中出生本地库 ---->文件夹中产生 .git文件
将指定一些文件添加在暂存区中
git add 文件名称.后缀名
git commit 文件 -m '注释:标名当前代码更新的内容是什么'
将本地库的代码推送远程仓库上----新建仓库完成
设置个人签名信息---用户名/邮箱 (设置一次即可,以后不用设置了)---c://users/用户名目录//.gitconfig文件---记录签名信息
需要给当前https远程仓库请求地址,设置别名
git remote add origin(别名名称) http地址
git push origin 主分支名称(默认master) --->第一次使用:弹出一个窗口,设置gitee码云的账户和密码
git log 查看日志
git工作流
git命令
1.git init 初始化本地库
2.git status 查看当前本地库文件的状态:
3.git add 文件名称: 将指定文件添加到暂存区
4.git commit 文件名称 -m '注释' 将暂存区中的文件提交到本地库中
5.git log 查看日志
6.git remote add origin 仓库地址 给远程仓库设置别名origin
7.git push 别名 分支名称(默认master 主分支) :将本地库的代码---推送到远程仓库上
8.git clone 仓库地址: 就是下载远程仓库 的代码