所需技术
web标准组成
html:负责网页的结构(页面元素和内容)
css:负责网页的表现(页面元素的外观,位置等页面样式,如:颜色,大小等)
javasc:负责网页行为(交互效果)
web前端开发
html,css学习
html:超文本标记语言
超文本:超越了文本的限制,比普通文本根强大
标记语言:由标签构成的语言
css
层叠样式表,用于控制页面布局
css标签可进入w3school官方文档查看
html快速入门
HTML结构(Hypertext Markup Language)是一种用于创建网页和其他信息展示的标记语言。它由HTML标签和文本组成,标签用于定义文档的结构和内容,文本则是实际内容的主体。
HTML结构由以下几个部分组成:
-
文件声明:
<!DOCTYPE html>
,用于告诉浏览器使用哪个HTML版本。 -
html 标签:
<html>
,用于定义文档的根元素。 -
head 标签:
<head>
,用于定义文档的头部,包含元数据和其他信息。 -
title 标签:
<title>
,用于定义文档的标题。 -
body 标签:
<body>
,用于定义文档的主体,包含文档显示的所有内容。 -
header 标签:
<header>
,用于定义文档的页眉,通常包含网站的logo和导航菜单等。 -
nav 标签:
<nav>
,用于定义文档的导航菜单。 -
section 标签:
<section>
,用于定义文档中的节或段落。 -
article 标签:
<article>
,用于定义独立的文章或故事。 -
aside 标签:
<aside>
,用于定义文档的侧边栏。 -
footer 标签:
<footer>
,用于定义文档的页脚。 -
div 标签:
<div>
,用于定义文档中的区块,通常用于布局。
HTML结构可以根据需要添加其他标签和属性来实现不同的功能和样式。
vs code安装使用
安装:
-
下载Visual Studio Code安装程序:https://code.visualstudio.com/Download
-
运行安装程序,按照提示完成安装即可。
使用:
-
打开Visual Studio Code,可以直接从开始菜单中打开。
-
在打开的界面中,可以选择打开文件夹或者文件。也可以通过终端(Terminal)命令行进入到指定文件夹,输入“code . ”命令打开Visual Studio Code。
-
编写代码:支持多种编程语言的代码编写,如C、C++、Java、Python、JavaScript等等。
-
调试代码:Visual Studio Code支持多种语言的调试,可以通过调试工具检查代码逻辑、变量的值等。
-
安装插件:Visual Studio Code支持自定义插件,用户可以根据自己的需要安装相应的插件。可以通过菜单栏中的“扩展(Extensions)”查看和安装插件。
-
快捷键:Visual Studio Code支持多种快捷键,可以通过菜单栏中的“帮助(Help)”查看快捷键列表。
-
其他功能:Visual Studio Code还提供了很多其他的功能,如代码折叠、代码格式化、自动补全等等。用户可以根据自己的需要使用这些功能。
html基础标签&样式
标题样式
- 行内样式:<h1 style="color: brown;">旅游热点</h1>
- 内嵌样式:
<style>
h1{
color: red;
}
</style>
- 外联样式
h1{
color: red;
}
<link rel="stylesheet" href="标题样式.css">
选择器
HTML选择器是CSS中用来选择HTML元素的方法。HTML选择器可以通过元素的标签名、类名、ID、属性、伪类和伪元素等多种方式来匹配元素。
HTML选择器分类如下:
-
标签选择器:使用HTML标签名作为选择器,可以匹配所有该标签的元素,如p、div等。
-
类别选择器:使用CSS类名作为选择器,只匹配具有指定类名的元素,如.class。
-
ID选择器:使用CSS ID作为选择器,只匹配具有指定ID的元素,如#id。(id名称不能重复,优先级最高)
-
属性选择器:匹配具有指定属性的元素,如[type="text"]。
-
伪类选择器:匹配一些特定状态下的元素,如:hover、:active等。
-
伪元素选择器:匹配元素的特定部分,如::before、::after等。
颜色表示形式
- 关键字:预定义的颜色名,如red...
- rgb表示法:红绿蓝三原色。每项取值范围:0-255,如:rgb(0,0,0)
- 十六进制表示法:#开头,将数字转换成十六进制表示。如:#000000...
文本标签
HTML(HyperText Markup Language)是一种用于创建网页的标记语言,它使用标签来描述网页内容的各个部分。
以下是一些常见的HTML标签及其用途:
<html>
:定义HTML文档的根元素<head>
:定义文档头部,其中包含了一些元数据信息,如文档标题、字符集等<title>
:定义文档的标题,通常会显示在浏览器的标签栏中<body>
:定义文档的主体部分,包含了页面的内容<h1>
~<h6>
:定义标题,<h1>
最大,<h6>
最小<p>
:定义段落,可以包含文本、图像、链接等<img>
:定义图像,需要指定图像的源文件(src)、替代文本(alt)等属性<a>
:定义链接,需要指定链接的目标(href)、链接文本等属性<ul>
、<ol>
、<li>
:定义无序列表、有序列表和列表项<table>
:定义表格,需要使用<tr>
、<td>
等标签来指定表格的行、列和单元格<form>
:定义表单,可以包含输入控件,如文本框、单选框、复选框等<input>
:定义输入控件,在<form>
中使用,需要指定类型(type)和名称(name)等属性<textarea>
:定义文本域,用于输入大段文本,如评论、简介等<button>
:定义按钮,通常与 JavaScript 一起使用来实现交互功能<div>
:定义文档中的一个区块,通常用来分组其他元素<span>
:定义文档中的一个内联区块,通常用来修饰文本(组合行内元素,没有语义)
以上仅是 HTML 中的一部分标签,完整列表可以在 W3Schools 中查看。
字体标签
HTML字体标签是一种用来定义文本字体、大小、颜色等样式的标签。以下是常用的HTML字体标签:
-
<font>:用于定义文本字体、大小、颜色等样式。可以通过属性指定字体、大小、颜色等样式。
-
<strong>:用于定义加粗效果。默认字体为粗体。
-
<em>:用于定义强调效果。默认字体为斜体。
-
<u>:用于定义下划线效果。
-
<strike>:用于定义删除线效果。
-
<sup>和<sub>:分别用于定义上标和下标效果。
-
<h1>-<h6>:用于定义标题。h1最大,h6最小,依次递减。
示例:
<p style="font-family:Arial;font-size:18px;color:red;">这是一段红色、Arial字体大小为18px的文本。</p>
<strong>这是加粗的文本</strong>
<em>这是斜体的文本</em>
<u>这是下划线的文本</u>
<strike>这是删除线的文本</strike>
2<sup>10</sup>等于1024
H1标签:这是一级标题
H2标签:这是二级标题
超链接
HTML超链接标签是<a>标签,用于创建一个超链接。它的语法如下:
<a href="链接地址">链接文本</a>
其中,href
属性指定了链接的地址,链接文本
则是用户点击链接时看到的文本内容。
示例:
创建一个指向百度首页的链接:
<a href="https://www.baidu.com/">百度首页</a>
点击「百度首页」,会跳转到百度首页。
视频标签和音频标签
HTML中的视频标签和音频标签分别为<video>
和<audio>
标签。
视频标签(<video>
)
语法:
<video src="视频文件地址" width="宽度" height="高度" controls="controls">
您的浏览器不支持 video 标签。
</video>
其中,src
属性指定了视频文件的地址,width
和height
属性指定了视频播放器的宽度和高度,controls
属性用于显示视频控制按钮。
示例:
<video src="video.mp4" width="640" height="480" controls="controls">
您的浏览器不支持 video 标签。
</video>
音频标签(<audio>
)
语法:
<audio src="音频文件地址" controls="controls">
您的浏览器不支持 audio 标签。
</audio>
其中,src
属性指定了音频文件的地址,controls
属性用于显示音频控制按钮。
示例:
<audio src="audio.mp3" controls="controls">
您的浏览器不支持 audio 标签。
</audio>
需要注意的是,视频和音频文件格式有很多种,不同的格式支持情况也有所不同。在实际使用中,最好提供多种格式的文件,以便于不同浏览器和设备能够正常播放。
换行标签
HTML换行标签是 <br>
。在 HTML 中,<br>
表示换行符,可以在段落中插入一个简单的换行符,而不是分段。
例如:
<p>这是第一行。<br>这是第二行。</p>
上面的代码将生成一个段落,其中一行包含两个句子,这两个句子之间用换行符分隔。
需要注意的是,<br>
标签是一个单标签,不需要闭合标签。
空格
在 HTML 中,空格占位符可以使用
实现。实际上,HTML 中默认是忽略连续的空格的,可以使用空格占位符来强制浏览器显示空格。这对于需要在 HTML 中控制布局的情况特别有用。
例如,如果您希望在段落中有一些额外的间距而不想使用 CSS,请使用空格占位符:
<p>这是一些 额外的间距。</p>
在上面的例子中,我们在“一些”和“额外的间距”之间插入了七个空格占位符,以便在这些单词之间添加一些额外的间距。
需要注意的是,
是一个实体名称,而不是一个标签,因此不能使用  
或其他类似的形式。
div标签
<div>是HTML中最基本的容器标签,其作用是为一组相关的元素提供容器,用于组织页面内容的布局结构。同时,<div>标签也可以用作CSS样式的容器,方便开发者为其内部元素应用相同的样式。
<div>标签没有特定的语义含义,具有很强的通用性和灵活性。HTML中的大部分元素都可以放置在<div>标签内部,如文本、图片、视频、音频等。
<div>标签的使用范例:
<div>
<h1>这是一个标题</h1>
<p>这是一段文字</p>
<img src="image.jpg" alt="图片">
</div>
上述代码中,<div>标签作为一个容器,包含了一个标题、一段文字和一张图片。开发者可以为这个<div>容器设置样式,例如设置其宽度、背景颜色、边框等。
span标签
<span>标签是HTML中用于标记短小文本片段的标签,相较于<div>标签,<span>标签更为精细和细致,其通常用来对文本进行局部样式设置、添加超链接、标记颜色、标记语义等操作。
<span>标签可用于内联文本,例如,在一段文本中用于标记一个词或一个短语。与<div>标签不同,<span>标签不会自动换行,而是将内嵌的内容作为一整个行内元素展示出来。
例如:
<p>这是一段包含<span>重要信息</span>的文本。</p>
上述代码中,<span>标签用于对“重要信息”一词进行标记,可以方便地为其设置样式,例如加粗、变色、添加下划线等效果。
表格标签
HTML中用于创建表格的主要标签有以下几个:
-
<table>:定义一个表格。
-
<tr>:定义表格中的一行。
-
<td>:定义行中的一个单元格。
-
<th>:定义行中的一个表头单元格。
-
<caption>:定义表格的标题。
-
<thead>:定义表格的头部。
-
<tbody>:定义表格的主体部分。
-
<tfoot>:定义表格的脚注部分。
<table>标签是创建表格的基础标签,其内部必须包含至少一个<tr>标签,每个<tr>标签必须包含至少一个<td>或<th>标签,而<th>标签用于定义表格的表头,会自动加粗并居中显示。
例如,下面是一个包含表头、主体和脚注部分的简单表格:
<table>
<caption>2019年度休假情况</caption>
<thead>
<tr>
<th>姓名</th>
<th>职位</th>
<th>年假</th>
<th>事假</th>
</tr>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>经理</td>
<td>15天</td>
<td>2天</td>
</tr>
<tr>
<td>李四</td>
<td>主管</td>
<td>12天</td>
<td>3天</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2">总计</th>
<td>27天</td>
<td>5天</td>
</tr>
</tfoot>
</table>
表单标签
HTML中用于创建表单的主要标签有以下几个:
-
<form>:定义一个表单,用于向服务器发送用户输入的数据。
-
<input>:定义表单中的输入控件,可以输入文本、选项、按钮等。
-
<label>:定义表单控件的标签。
-
<select>:定义一个下拉菜单,供用户选择其中一个选项。
-
<option>:定义下拉菜单的选项。
-
<textarea>:定义一个文本输入区域。
-
<button>:定义一个按钮。
-
<fieldset>:定义一个表单的一组相关控件。
-
<legend>:定义<fieldset>标签的标题。
<body>
<!-- form表单属性:
action:表单提交的url,往何处提交数据,如果不指定,默认提交到当前页面
method:表单的提交方式
get:在url后面凭借表单数据,比如:?username=tom&password=123& age=22,
url长度有限制,默认值
post:在消息体(请求体)中传递,参数大小无限制-->
<form action="" method="get">
用户名:<input type="text" name="username"></input>
密码:<input type="password" name="password"></input>
年龄:<input type="text" name="age"></input>
<input type="submit" value="提交">
<form action="" method="post">
用户名:<input type="text" name="username"></input>
密码:<input type="password" name="password"></input>
年龄:<input type="text" name="age"></input>
<input type="submit" value="提交">
</form>
</body>
例如,下面是一个包含文本输入框、密码输入框、单选框、多选框、下拉菜单、文本输入区域、按钮等控件的表单:
<form action="/submit-form" method="post">
<fieldset>
<legend>个人信息</legend>
<label for="name">姓名:</label>
<input type="text" id="name" name="name" required>
<br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
<br>
<label>性别:</label>
<input type="radio" name="gender" value="male" checked>男
<input type="radio" name="gender" value="female">女
<br>
<label>爱好:</label>
<input type="checkbox" name="hobby" value="reading">阅读
<input type="checkbox" name="hobby" value="music">音乐
<input type="checkbox" name="hobby" value="travel">旅游
<br>
<label for="city">城市:</label>
<select id="city" name="city" required>
<option value="">请选择城市</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
</select>
<br>
<label for="message">留言:</label>
<textarea id="message" name="message" rows="5"></textarea>
</fieldset>
<br>
<button type="submit">提交</button>
</form>
表单标签-表单项
<body>
<form action="">
姓名:<input type="text" name="username"><br>
密码:<input type="password" name="password"></input><br>
性别<label><input type="radio" name="gender" value="1">男</input></label>
<label><input type="radio" name="gender" value="2">女</input> </label><br>
Java <label> <input type="checkbox" name="学科" id=""></label>
python<label><input type="checkbox" name="学科" id=""></label><br>
邮箱:<input type="email" name="e-mal" id=""><br>
数字输入框<input type="number" name="number" id=""><br>
定义文件上传 <input type="file" name="file" id=""><br>
学历 <select name="degree">
<option value="">请选择</option>
<option value="1">大专</option>
<option value="2">本科</option>
<option value="3">博士</option>
<option value="4">硕士</option>
</select>
</form>
</body>
css样式-首行缩进
在 CSS 中实现首行缩进的方法有两种:使用 text-indent
属性和使用 padding-left
属性。
使用 text-indent
属性:
语法:
selector {
text-indent: length;
}
其中,selector
为要应用样式的元素选择器,length
为缩进距离,可以是像素值、百分比、em 等长度单位。如果缩进距离为负数,则表示向左侧缩进。
示例:
p {
text-indent: 2em;
}
上面的样式将会使 <p>
元素的首行缩进 2 个字符的宽度。
使用 padding-left
属性:
语法:
selector {
padding-left: length;
text-indent: -length;
}
其中,selector
为要应用样式的元素选择器,length
为缩进距离,可以是像素值、百分比、em 等长度单位。如果缩进距离为负数,则表示向左侧缩进。需要注意的是,为了使首行缩进生效,需要将 text-indent
属性设置为负数的同等距离。
示例:
p {
padding-left: 2em;
text-indent: -2em;
}
上面的样式将会使 <p>
元素的首行缩进 2 个字符的宽度。这种方法还可以通过设置不同的 padding-left
值来实现不同级别的缩进。
盒子模型
CSS盒子模型是指在网页中每个元素都是一个矩形的盒子,由四条边和四个角组成。CSS盒子模型包括以下几个部分:
- 内容区(Content):元素的内容,比如文本、图片等,属于内容的展示部分。
- 填充区(Padding):紧贴内容区的区域,属于元素内部的空白区域。
- 边框(Border):包围着填充区的边框线,可以设置边框的样式、宽度和颜色等属性。
- 外边距(Margin):位于填充区和周围元素之间的空白区域。
上述四个部分形成了一个完整的盒子模型,可以通过CSS设置它们的各种属性,包括宽度、高度、边框样式、内外边距等等。盒子模型的尺寸计算方式为:元素的宽度 = 左右内边距 + 左右边框 + 左右外边距 + 内容区宽度,元素的高度则是上下内边距 + 上下边框 + 上下外边距 + 内容区高度。
CSS盒子模型的标准模型和IE盒子模型的区别在于,标准模型的宽高只包括内容区,而IE盒子模型的宽高包括了填充和边框。在CSS中采用标准盒子模型,可以通过box-sizing属性控制。
JavaScript
跨平台面向对象的脚本语言
js的引入方式
JavaScript可以通过以下方式引入:
-
内联方式:直接在网页中嵌入JavaScript代码,例如:
<script> // JavaScript代码 </script>
-
外部引用方式:将JavaScript代码写入一个单独的文件中,然后在HTML文件中通过
<script>
标签引用该文件,例如:<script src="path/to/javascript.js"></script>
这里的
path/to/javascript.js
是JavaScript代码所在的路径。 -
模块导入方式:通过
<script type="module">
标签引入JavaScript模块,例如:<script type="module" src="path/to/javascript.js"></script>
此时,
javascript.js
文件必须是符合ES6模块标准的JavaScript代码。
JS基础语法
书写语法
1.区分大小写
2.每行结尾的分号可有可无
注释:
单行注释://注释内容
多行注释:/*注释内容*/
大括号表示代码块
//判断
if(count==3){
alert(count);
}
输出语句
<script>
window.alert("hello js");//浏览器弹出警告框
document.write("hello js");//写入HTML。在浏览器展示
console.log("hello js")//写入浏览器控制台
</script>
变量
用var来声明变量,js是一门弱类型语言,变量可以存放不同类型的值。
var a = 20;
a ="张三";
变量名需要遵循如下规则:
组成字符可以是任何字母,数字,下划线(_)或者美元符号($)
数字不能开头
建议使用驼峰命名
注意:1.ES6新增了let关键字来定义变量,它的用法类似于var,但是所声明的变量,只在let关键字所在的代码块内有效,且不允许重复声明。
2.ES6新增const关键字,用来声明一个只读的变量,一旦声明,常量的值就不能改变。
<script>
// var定义变量
// var a=10;
// a="张三";
// alert(a);
//var定义变量 特点:1.作用域比较大,全局变量
// 2.可以重复定义
// {
// var x=1;
// var x=A;
// // alert(x);
// }
// alert(x);
// let:局部变量,不能重复定义
{
let x=1;
// let x=0;
alert(x);
}
// const:常量,不能改变
const p=666;
// p1=555;
alert(p);
</script>
数据类型,运算符,流程控制语句
原始类型和引用数据类型
原始类型:
number:数字(整数,小数,Nat(Not a Number))
string:字符串,单双引皆可
boolean:布尔,true,false
null:对象为空
undefined:当声明的变量未初始化时,该变量的默认值是undefined
使用typeof运算符可以获取数据类型:
<script>
// 原始数据类型
alert(typeof 3);//number
alert(typeof 3.14);//number
alert(typeof "A");//string
alert(typeof 'HELLO');//string
alert(typeof true);//boolean
alert(typeof false);//boolean
alert(typeof null);//object:一个对象
var a;
alert(typeof a);//undefined
</script>
运算符
js函数
执行特定任务的代码块
定义需通过function关键字来定义,语法为:
<script>
function functionName(参数1,参数2){
//要执行的代码
}
</script>
例如:
function functionName(a,b){
//要执行的代码
return a+b;
}
注意:形式参数不需要类型,因为js是弱类型语言。返回值也不需要定义类型,可以在函数内部直接使用return返回即可
调用:函数名称(实际参数列表)
<script>
//调用函数
var result= add(10,30);
return result;
//定义函数
function add(a,b){
//要执行的代码
return a+b;
}
定义函数2:
// 定义函数-2
var add=function (参数1,参数2){
//执行代码块
}
例如:
<script>
//调用函数
var result= add(10,30);
return result;
// 定义函数-2
var add=function (a,b){
return a+b;
}
注意:JS函数调用可以传递任意参数
js对象
Array
<script>
//定义数组
// var arr= new Array(1,2,3,4,5,6);
// var arr = [1, 2, 3, 4];
// console.log(arr[0]);
// console.log(arr[1]);
//特点:长度可变类型可变
// var arr = [1, 2, 3, 4];
// arr[10] = 50;
// console.log(arr[10]);
// console.log(arr[9]);
// arr[9]="A";
// arr[8]=true;
// console.log(arr);
var arr = [1, 2, 3, 4];
arr[10]=50;
// for (let i = 0; i < array.length; i++) {
// console.log(arr[i]);
// }
// forEach:遍历数组中有值的函数
// arr.forEach(function(e){
// console.log(e);
// })
//ES6箭头函数:{...} => {....} 简化函数定义
// arr.forEach((e) => {
// console.log(e);
// })
//push:添加元素到数组末尾
// arr.push(7,8,9);
// console.log(arr);
//splice:删除元素
arr.splice(2,2);
console.log(arr);
</script>
String
<!-- 创建字符串 -->
<script>
var str="我爱学Java";
alert(str);
console.log(str);
//length获取字符串长度
console.log(str.length);
//charAt获取指定位置的字符
console.log(str.charAt(3));
//indexof检索字符串
console.log(str.indexOf("Java"));
//trim去除字符串左右两侧空格
var s=str.trim();
console.log(s);
//substring(start,end)---start开始索引,end结束索引(含头不含尾)
console.log(s.substring(0,7));
</script>
JSON
自定义对象
<script>
//自定义对象
var user={
name:"TOM",
age:10,
gender:"男",
// eat:function(){
// alert("吃饭")
// }
eat(){
alert("吃饭");
}
}
alert(user.name);
alert.eat();
</script>
JSON介绍
JSON基础语法
<script>
//定义JSON
var str='{"name":"TOM","age":18,"addr":["日本","亚洲"]}';
//json字符串==>js对象
var k=JSON.parse(str);
alert(k.name);
//js对象转为json字符串
var str1= JSON.stringify(k);
alert(str1)
</script>
BOM
Window
<script>
//获取Window
window.alert("你好BOM")
alert("你好,星期天")
//方法
//confirm 对话框 确认:true 取消:false
// confirm("确认打开星期天?")
var k=confirm("确认打开星期天?");
alert(k);
//定时器 setInterval---周期性的执行某一个函数
// var i=0;
// setInterval(function(){
// i++;
// console.log("执行了"+i+"次");
// },1000);
//定时器 setTimeout 延迟指定时间执行一次
setTimeout(function(){
alert("hello")
},2000)
</script>
location
<script>
//location 获取当前域名
alert(location.href)
//设置指定域名
location.href="http://www.baidu.com"
</script>
DOM
获取对象
js事件监听
事件:发生在HTML上的事情;如:按钮被点击了,鼠标移动到元素上,按下键盘
事件监听:JavaScript可以在事件被侦测到时执行代码
事件绑定
<body>
<input type="button" value="事件绑定1" id="but1" onclick="on()">
<input type="button" value="事件绑定2" id="but2">
<script>
function on(){
alert("按钮1被点击了")
}
document.getElementById("but2").onclick=function(){
alert("按钮2被点击了")
}
</script>
</body>
常见事件
Vue
是一套前端框架,免除原生JS中的DOM操作,简化书写。基于MVVM思想,实现数据双向绑定
官网:https://v2.cn.vuejs.org/
MVVM
MVVM是一种软件架构模式,包括三个核心组件:Model、View、ViewModel。
- Model:即数据模型,是应用程序中处理数据和业务逻辑的部分。它从数据源获取数据、验证数据并对其进行修改。
- View:即用户界面,是应用程序中处理交互的部分,它负责向用户展示数据并响应用户的操作。
- ViewModel:是连接 Model 和 View 的核心组件,它负责将 Model 中的数据转换成View可以使用的数据,并将用户的操作转换成Model可以理解的操作。同时,ViewModel还负责将数据变更通知给View,从而保证View与Model保持同步。
MVVM的核心思想是数据绑定,即通过数据绑定,将ViewModel中的数据与View中的UI元素进行绑定,实现数据的自动更新。这样,当ViewModel中的数据发生变化时,相应的UI元素也会自动更新,无需手动操作。
MVVM的优点有:
- 分离关注点:通过将数据处理、业务逻辑和UI元素分离,MVVM能够使得应用程序的不同部分之间关注点更加清晰,代码更容易维护和扩展。
- 可测试性:ViewModel中的数据和业务逻辑可以进行单元测试,View中的UI元素也可以进行UI测试,从而保证应用程序的质量。
- 可重用性:由于MVVM将数据和UI元素分离,因此可以更加容易地将ViewModel重用于不同的View上。
MVVM是目前较为流行的前端框架(如Vue.js、Angular.js等)所使用的架构模式,也逐渐受到后端开发者的青睐并应用于后端开发中。
快速入门
1.新建HTML页面,引入Vue.jswenjian
2.在JS代码区域,创建Vue核心对象,定义数据模型
3.编写视图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue快速入门</title>
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
{{
message
}}
</div>
</body>
<script>
new Vue({
el:'#app',//vue接管区域
data:{
message:'hello vue!'
}
})
</script>
</html>
插值表达式
形式:{{表达式}}
内容可以是:
变量,三元运算符,函数调用,算数运算
Vue常用指令
v-bind和v-model
v-bind
为HTML标签绑定属性值,如设置href,css样式等
书写格式:
<标签 v-bind:属性名="元素">
例如:
<a v-bind:href="url">星期天</a>
也可简写为:
<a :href="url">星期天</a>
v-model
在表单元素上创建双向绑定数据
书写格式
<input type=""text" v-model="url">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<!-- <a v-bind:href="url">点一下</a> -->
<a :href="url">点一下</a>
<input type="text" v-model="url">
</div>
<script>
new Vue({
el:"#app",
data:{
url:'https://www.baidu.com'
}
})
</script>
</body>
</html>
注意:通过v-bind或者v-model绑定的变量,必需在数据模型中声明
v-on
为HTML标签绑定事件
<input type="button" value="按钮" v-on:click="h">
<input type="button" value="按钮" @click="h">
methods:{
h:function(){
alert('我被点击了')
}
}
<body>
<div id="app">
<!-- <input type="button" value="点我一下" v-on:click="handle()"> -->
<input type="button" value="点我一下" @click="handle()">
</div>
<script>
new Vue({
el:"#app",
data:{
},
methods:{
handle:function(){
alert("我被点击了");
}
}
})
</script>
</body>
v-if,v-show,v-else和v-else-if
<div id="app">
年龄<input type="text" v-model="age">经判定,为:
<span v-if="age<=35">年轻人(35岁以下)</span>
<span v-else-if="age>=36&&age<=60">中年人(35-60)</span>
<span v-else="age>=60"</span>>老年人(60及以上)</span>
<br>
年龄<input type="text" v-model="age">经判定,为:
<span v-show="age<=35">年轻人(35岁以下)</span>
<span v-show="age>=36&&age<=60">中年人(35-60)</span>
<span v-show="age>=60"</span>>老年人(60及以上)</span>
</div>
<script src="../lib/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
age:20
},
methods:{
}
})
</script>
v-for
列表渲染,便案例容器的元素或者对象的属性
Vue的生命周期
<script src="../lib/vue-2.4.0.js"></script>
<script>
new Vue({
el: '#app',
data: {
},
methods:{
},
mounted(){
alert("vue挂载完成,发送请求到服务器")
}
})
</script>
Ajax
同异步请求
原生Ajax
- 准备数据地址
- 创建XMLHttpRequest对象:用于和服务器交换数据
- 向服务器发送请求
- 获取服务器相应数据
具体可以去W3c查看
Axios
介绍:Axios对原生的Ajax进行了封装,简化书写,快速开发
官网:https://www.axios-http.cn/
快速入门
可简化为:
前后端分离开发
YAPI
YAPI是高效,易用,功能强大的api管理平台,旨在为开发,产品,测试人员提供更优雅的接口管理服务
地址:http://yapi.smart-xwork.cn/
前端开发工程化
环境准备
vue-cli
安装NodeJS
官网下载
配置
完成
v-cli安装
配置淘宝镜像全局配置
下载vue-cli脚手架
安装完成
Vue项目简介
vue项目创建
图形化界面打不开解决方案:关于Vue ui 的没反应、报错问题解决总结_vue.js_脚本之家
npm install -g @vue/cli 常见问题_我是PHP小白的博客-CSDN博客
npm 下载vue-cli出错npm安装报错(npm ERR! code EPERM npm ERR! syscall mkdir npm ERR! path C:\Program Files\nodejs\node_ca...)_晴雷的博客-CSDN博客
继承终端下载
1.
vue create vue-test
2.
创建完成
结构
项目启动
端口号配置
开发流程
异常处理
原因node.js版本过低,解决方法npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! [email protected] dev: `vite` npm ERR! Exit statu_礼貌而已的博客-CSDN博客
Element
Vue的组件库Element
快速入门
<template>
<div>
<!-- 按钮 -->
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
常见组件
<template>
<div>
<!-- 按钮 -->
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
<br>
<!-- table -->
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
<!-- 分页 -->
<!-- layout组件布局: -->
<el-pagination background layout="prev, pager, next"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="1000"
></el-pagination>
<br>
<!-- Table -->
<el-button type="text" @click="dialogTableVisible = true">打开嵌套表格的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogTableVisible">
<el-table :data="gridData">
<el-table-column property="date" label="日期" width="150"></el-table-column>
<el-table-column property="name" label="姓名" width="200"></el-table-column>
<el-table-column property="address" label="地址"></el-table-column>
</el-table>
</el-dialog>
<!-- Dilog打开Form表单 -->
<el-button type="text" @click="dialogFormVisible = true">打开嵌套Form的 Dialog</el-button>
<el-dialog title="打开Form表单" :visible.sync="dialogFormVisible">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
},
gridData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}],
dialogTableVisible: false,
dialogFormVisible:false,
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
},
methods:{
handleSizeChange:function(val){
alert("每页记录数变化"+val)
},
handleCurrentChange:function(val){
alert("每页展示记录数"+val)
},
onSubmit: function() {
alert(JSON.stringify(this.form))
}
}
}
</script>
<style>
</style>
Vue路由
介绍
安装
打包部署
打包
集成终端打包命令:
生成一个dist文件夹即可
部署
异常
端口被占用
查看80端口被谁占用
解决方案:
修改nginx端口
访问
web后端开发
基础技术
Maven
什么是maven?
是一款用于管理和构建Java项目的工具
maven的作用
依赖管理
管理Java相关的jar包
统一项目结构
项目构建
Maven概述
介绍
安装
IDEA集成Maven
配置Maven环境
创建Maven项目
导入Maven
依赖管理
依赖配置
依赖传递
依赖范围
Maven生命周期
springBoot web后端开发
spring提供了若干个子项目,每个项目用于完成特定的功能,spring boot可以帮助我们非常快速的构架应用程序,简化开发,提高效率
spring boot web入门
案例:
HTTP协议
HHTP-概述
HTTP协议-请求协议
HTTP响应协议
状态码
Web服务器-Tomcat
简介
Tomcat基本是使用
spring bootWeb-入门程序解析
请求响应
概述
请求
请求响应——Postman
简单参数
实体参数
数组集合参数
日期参数
JSON 参数
路径参数
小结
响应数据
统一响应结果
小结
分层解耦
三层架构
分成解耦
IOC&DI入门
@Conponent
将当前类交给IOC容器管理,成为IOC容器中的bean
@Autowired
运行时,IOC容器会提供该类型的bean对像,并取值给该变量---依赖注入
IOC详解
Bean的声明
Bean组件扫描
DI详解
小结
数据库
MySQL概述
安装,配置
数据模型
关系型数据库
SQL简介
SQL分类
数据库设计-DDL
数据库
创建数据库
create database javawebtest;
切换使用数据库
use javawebtest;
查看当前使用数据库
select datdabase();
查看所有数据库
show databases;
查看数据库中所有表
show tables;
删除数据库
drop database javawebtest;
图形化工具
表结构操作-DDL
创建
-- 创建数据库
create database javawebtest;
-- 创建表结构
create table tb_user(
-- 唯一标识 auto_increment:自增长
id int primary key auto_increment comment 'ID,唯一标识',
-- 非空且唯一
username varchar(20) not null unique comment '用户名',
-- 非空
name varchar(10) not null comment '姓名',
age int comment '年龄',
-- 默认值为男
gender char(1) default '男' comment '性别'
)comment '用户表';
常见的数据类型
查询
修改
删除
表结构操作-DML
添加insert
更新update
删除delete
表结构操作-DQL
基本查询
条件查询
分组查询-聚合函数
分组查询
排序查询
分页查询
多表设计
一对多
一对一
多对多
多表查询
内连接
外连接
子查询
标量子查询
列子查询
行子查询
表子查询
事务
四大特性
索引
结构
B+树
语法
Mybatis
入门
配置SQL提示
JDBC
数据库连接池
切换数据库连接池
lombok
<!-- lombok插件引入-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
MyBatis基本操作
环境准备
删除
@Mapper
public interface EmpMapper{
//根据ID 删除数据 #{}:mybatis占位符
@Delete("delete from emp where id="#{id}")
public void delete(Integer id);
// public int delete(Integer id);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
//声明接口
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete(){
//int delete=empMapper.delete(1);
//System.out.println(delete);
empMapper.delete(1);
}
}
日志输出
SQL执行流程
预编译流程
SQL注入
参数占位符
添加
@Mapper
public interface EmpMapper{
//新增员工
//@Insert(insert into emp(username,name,gender,job) values("Tom","汤姆",1,1)
@Insert(insert into emp(username,name,gender,job) values(#{username},#{name},#{gender},#{job})
public void insert(Emp emp);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
//构造员工对象
Emp emp=new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setGender((short)1);
emp.setJob((short)1);
//执行添加员工信息操作
empMapper.insert(emp);
}
主键返回
在添加成功后,需要获取数据库数据的主键
@Options(userGeneratedKeya=true,keyProperty="id")
@Mapper
public interface EmpMapper{
//新增员工
//@Insert(insert into emp(username,name,gender,job) values("Tom","汤姆",1,1)
@Insert(insert into emp(username,name,gender,job) values(#{username},#{name},#{gender},#{job})
public void insert(Emp emp);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
//构造员工对象
Emp emp=new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setGender((short)1);
emp.setJob((short)1);
//执行添加员工信息操作
empMapper.insert(emp);
System.out.println(emp.getId);
}
修改
@Mapper
public interface EmpMapper{
//修改员工信息
@Update("update emp set username=#{username},name=#{name},gender=#{gender},job=#{job}")
public void update(Emp emp);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
//构造员工对象
Emp emp=new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setGender((short)1);
emp.setJob((short)1);
//修改员工信息
empMapper.update(emp);
}
查询
@Mapper
public interface EmpMapper{
//根据ID查询
@Select("select * from emp where id=#{id} ")
public Emp getById(Integer id);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
@Test
public void testGetById(){
Emp emp = empMapper.getById(20);
System.out.println(emp);
}
}
数据封装
解决方案
@Mapper
public interface EmpMapper{
//根据ID查询
//方案一:给字段起别名,让别名与实体类属性一致
@Select("select id ,username ,name, gender ,job,create_time createTime,update_time updateTime,dept_id deptId from emp where id=#{1} ")
public Emp getById(Integer id);
//方案二:通过@Results,@Result注解手动映射封装
@Results({
@Result(column="dept_id",property="deptId"),
@Result(column="create_time",property="updateTime"),
@Result(column="update_time",property="updateTime"),
})
@Select("select * from emp where id=#{id} ")
public Emp getById(Integer id);
}
在配置文件application.properties中
#方案三:开启Mybatis的驼峰命名自动映射开关------a_cloumn--------->aCloumn
mybatis.configuration.map-underscore-to-camel-case=true
在mapper中
@Mapper
public interface EmpMapper{
//根据ID查询
@Select("select * from emp where id=#{id} ")
public Emp getById(Integer id);
}
测试类
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
@Test
public void testGetById(){
Emp emp = empMapper.getById(20);
System.out.println(emp);
}
}
条件查询
@Mapper
public interface EmpMapper{
//条件查询员工
/* @Select("select * from emp where name=like '%${name}%' and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name,short gender,LocalData begin,LocalDate end);
*/
//concat:字符串拼接函数
@Select("select * from emp where name=like concat('%',#{name},'%') and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name,short gender,LocalData begin,LocalDate end);
}
@SpringBootTest
class SpringbootMybatisCrudApplicationTest{
@Test
public void List(){
empMapper.list("张",(short)1,LocalDate.of(2000,1,1),LocalDate.of(2001,2,2))
System.out.println(empList)
}
}
XML映射文件
<!--约束 mybatis中文网直接复制-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespase:命名空间-->
<mapper namespase="">
<!--resultType:单条记录所封装的类型-->
<select id="list" resultType="com.pojo.emp">
sql语句
</select>
</mapper>
Mybatis动态SQL
<if>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.pojo.Emp">
<select id="list" resultTypr="com.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender=#{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>
</select>
</mapper>
<foreach>
//批量删除员工
public void deleteByIds(List<Integer> ids){
}
<!--批量员工 (18,19,20)-->
<!--
collection:遍历的集合
item:遍历出来的元素
aeparator:分隔符
open:遍历开始前拼接的SQL片段
close:遍历结束后拼接的SQL片段
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" aeparator="," open="(" close=")">
#{id}
</foreach>
</delete>
@Test
public void deleteByTds(){
List<Integer> ids=Arrays.asList(18,19,20);
empMapper.deleteByIds(ids);
}
<sql><include>
案例
环境搭建
统一结果封装类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应信息 描述字符串
private Object data; //返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
查询
EmpController
@Slf4j//日志输出管理
@RestController
public class EmpController{
@Autowired
privater EmpService empservice;
//查询所有数据
@GetMapping("/emps")
public Result select(){
//调用service里面的delete方法,并用一个list集合接收
List<Emp> slectList= empservice.select();
return Result.succes(selectList);
}
}
EmpService
public interface EmpService(){
//查询所有
List<Emp> select();
}
EmpServiceImpl
@Service
public class EmpSerViceImpl implements EmpService(){
@Autorwide
private EmpMapper empmapper
//查询所有
@Override
public Result select(){
return empmapper.select();
}
}
EmpMapper
@Mapper
publuc interface EmpMapper(){
//查询所有
@Select("select * from emp")
List<Emp> select();
}
EmpController
//根据ID删除信息
@DeleteMapping("/emps/{id}")
public Result delete(@PathVariable Integer id){
empservice.delete(id);
renturn Result.success();
}
Service
void delete(Integer id);
EmpServiceImpl
@Override
public Result delete(Integer id){
empmapper.deleteById(id);
}
EmpMapper
@Delete("delete from emp where id=#{id}")
void deleteById(id);
新增
分页查询
分页查询插件
分页带条件查询
删除
新增员工
目录
介绍:Axios对原生的Ajax进行了封装,简化书写,快速开发
文件上传
本地存储
@RestController
@Slf4j
public class UploadController {
@PostMapping("/upload")
public Result upload(String name, Integer age, MultipartFile image) throws Exception {
log.info("上传文件:"+name+age+image);
//获取上传文件名
String originalFilename = image.getOriginalFilename();
//构造唯一的文件名(不能重复)-uuid(通用唯一识别码)
int index = originalFilename.lastIndexOf(".");
String extname = originalFilename.substring(index);
String newFileName= UUID.randomUUID().toString()+extname;
//将上传文件保存到本地
image.transferTo(new File("D:\\项目\\MavneTest\\imager"+newFileName));
return Result.success();
}
}
#配置单个文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
#单个请求最大大小限制(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
阿里云存储oss
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
log.info("文件上传");
//获取对象存储OSS文件上传
String upload = aliOSSUtils.upload(image);
log.info("文件上传,请求url为"+upload);
return Result.success(upload);
}
package com.example.tlias.utils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;
/**
* 阿里云 OSS 工具类
*/
@Component
public class AliOSSUtils {
private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private String accessKeyId = "自己的ID";
private String accessKeySecret = "自己的Secret";
private String bucketName = "bucketName";
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
修改员工
查询,实现数据回显
修改员工
配置文件
yml配置文件
常见的yml格式
@ConfigurationProperties
登录认证
登录功能
package com.example.tlias.controller;
import com.example.tlias.pojo.Emp;
import com.example.tlias.pojo.Result;
import com.example.tlias.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class loginController {
@Autowired
private EmpService empService;
/**
* 登录功能
*/
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("登录功能");
Emp e =empService.login(emp);
return e!=null ? Result.success():Result.error("用户名或密码不正确");
}
}
/**
* 登录
* @param emp
* @return
*/
Emp login(Emp emp);
/**
* 登录
* @param emp
* @return
*/
@Override
public Emp login(Emp emp) {
return empMapper.getByUserNameAndPwd(emp);
}
/**
* 根据用户名和密码实现登录
* @param emp
* @return
*/
@Select("select * from emp where username=#{username} and password=#{password}")
Emp getByUserNameAndPwd(Emp emp);
登录校验
会话技术
跨域
会话技术对比
JWT令牌
生成JWT令牌
依赖导入
<!--JWT令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
/**
* 生成JWT令牌
*/
@Test
public void testGenJWT(){
Map<String, Object> claims=new HashMap<>();
claims.put("id",1);
claims.put("name","TOM");
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, "wsulg")//设置签名算法
.setClaims(claims)//自定义内容
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为一个小时
.compact();
System.out.println(jwt);
}
/**
* 解析JWT
*/
@Test
public void testParserJwt(){
Claims claims = Jwts.parser()
.setSigningKey("wsulg")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVE9NIiwiaWQiOjEsImV4cCI6MTY5MzI4OTY3Nn0.7kVfYCEzIseN4OWStIohc-ZIjrJGG-onb_7Xo7-xgA4")
.getBody();
System.out.println(claims);
}
JWT令牌跟踪会话
/**
* 登录功能
*/
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("登录功能");
Emp e =empService.login(emp);
//登录成功,下发JWT令牌
if (e !=null){
Map<String, Object> claims= new HashMap<>();
claims.put("id",e.getId());
claims.put("username",e.getUsername());
claims.put("name",e.getName());
//生成JWT令牌
String jwt = JwtUtils.generateJwt(claims);
return Result.success(jwt);
}
//登陆失败返回错误信息
return Result.error("用户名或密码不正确");
}
过滤器Filter
package com.example.tlias.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class FilterDemo implements Filter {
@Override//初始化
public void init(FilterConfig filterConfig) throws ServletException {
//Filter.super.init(filterConfig);
System.out.println("实现了init方法");
}
@Override//拦截所有请求,可调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截请求");
//方行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override//销毁方法,只调用一次
public void destroy() {
//Filter.super.destroy();
System.out.println("调用了destroy方法");
}
}
package com.example.tlias;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.web.bind.annotation.RestController;
@ServletComponentScan//支持serclet
@SpringBootApplication
public class TliasApplication {
public static void main(String[] args) {
SpringApplication.run(TliasApplication.class, args);
}
}
登录过滤器
package com.example.tlias.filter;
import com.alibaba.fastjson.JSONObject;
import com.example.tlias.pojo.Result;
import com.example.tlias.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.Request;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginChexkFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req= (HttpServletRequest) servletRequest;
HttpServletResponse reqs= (HttpServletResponse) servletResponse;
//1.获取请求url
String url = req.getRequestURL().toString();
log.info("获取到的url为"+url);
//2.判断请求url中是否包含login,如果包含,说明登录操作,放行
if (url.contains("login")){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
//3.获取请求头中的令牌(token)
String jwt = req.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
if (!StringUtils.hasLength(jwt)){
log.info("请求token为空,返回登录信息");
Result error = Result.error("NOT_LOGIN");
//将错误返回结果输出为json
//手动转换 对象---json------>阿里巴巴fastJSON
String notLogin= JSONObject.toJSONString(error);
reqs.getWriter().write(notLogin);
return;
}
//5.解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.parseJWT(jwt);//校验令牌
}catch (Exception e){//解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//将错误返回结果输出为json
//手动转换 对象---json------>阿里巴巴fastJSON
String notLogin= JSONObject.toJSONString(error);
reqs.getWriter().write(notLogin);
return;
}
//6.放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest,servletResponse);
}
}
拦截器interceptor
package com.example.tlias.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override//目标哦资源方法运行前运行,返回true 放行,返回false,不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle....");
return true;
}
@Override//目标哦资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
System.out.println("postHandle.....");
}
@Override//视图渲染后执行,最后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
System.out.println("afterCompletion....");
}
}
package com.example.tlias.config;
import com.example.tlias.interceptor.LoginCheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration//配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
拦截路径
执行流程
拦截器完成登录校验
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override//目标哦资源方法运行前运行,返回true 放行,返回false,不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取请求url
String url = request.getRequestURL().toString();
log.info("获取到的url为"+url);
//2.判断请求url中是否包含login,如果包含,说明登录操作,放行
if (url.contains("login")){
return true;
}
//3.获取请求头中的令牌(token)
String jwt = request.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
if (!StringUtils.hasLength(jwt)){
log.info("请求token为空,返回登录信息");
Result error = Result.error("NOT_LOGIN");
//将错误返回结果输出为json
//手动转换 对象---json------>阿里巴巴fastJSON
String notLogin= JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
//5.解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.parseJWT(jwt);//校验令牌
}catch (Exception e){//解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//将错误返回结果输出为json
//手动转换 对象---json------>阿里巴巴fastJSON
String notLogin= JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
//6.放行
log.info("令牌合法,放行");
return true;
}
@Override//目标哦资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
System.out.println("postHandle.....");
}
@Override//视图渲染后执行,最后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
System.out.println("afterCompletion....");
}
}
异常处理
/**
* 全局统一异常处理类
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)//捕获所有异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}
}
spring事务管理&AOP
事务管理
日志开关配置
事物进阶
rollbackFor
propagation
AOP基础
AOP核心概念
AOP进阶
通知类型通知顺序
切入点表达式
execution
@annotation
连接点
web后端开发——原理篇
配置优先级
Bean管理
获取Bean
Bean的作用域
第三方Bean
spring boot原理
自动配置
@Conditional
案例
总结
Maven高级
分模块设计与开发
分模块设计
继承与聚合
继承
版本锁定
聚合
私服
介绍
资源上传与下载
学习结束了,将继续跟随黑马老师啃编程!