HTML:负责网页的结构
(页面元素和内容)。
CSS:负责网页的表现
(页面元素的外观、位置等页面样式,如:颜色、大小等)。
JavaScript:负责网页的行为
(交互效果)。
Vue:一套用于构建用户界面的渐进式JavaScript框架
。
Ajax:与服务器进行数据交换,网页实现布局更新。
Axios:基于promise的网络请求库,通过promise实现对ajax技术的一种封装。
YApi:可视化接口管理平台,YApi
Element Plus:基于Vue3的桌面端组件库,Element UI是基于Vue2的。
Nginx:Nginx是一款轻量级的Web服务器、反向代理服务器。
前端开发软件:Visual Studio Code。安装插件Chinese (Simplified)、Code Spell Checker、HTML CSS Support、JavaScript (ES6) code snippets、Mithril Emmet、Path Intellisense、vue3-snippets、VueHelper、Auto Close Tag、Auto Rename Tag、open in browser、Vetur、IntelliJ IDEA Keybindings。
HTML(HyperText Markup Language):超文本标记语言。w3school查看更多HTML5标签
(1)超文本:超越了文本的限制,比普通文本更强大。除了文字信息,还可以定义图片、音频、视频等。
(2)标记语言:由标签构成的语言。HTML标签都是预定义
好的,HTML代码直接在浏览器中运行,HTML标签由浏览器解析。
img标签
<img src="规定显示图像的URL" alt="规定图像的替代文本" />
alt: 如果无法显示图像(如由于网速太慢),浏览器将显示替代文本
width: 宽度(px ,像素;% ,相对于父元素的百分比)
height: 高度
h1到h6标签
<h1> 最大的标题 h1>
<h2> 次最大标题 h2>
...
<h6> 最小的标题 h6>
hr水平线标签、br换行标签
style样式标签
<style>
标签名1 {
属性名1: 属性值1;
属性名2: 属性值2;
...
}
...
style>
link标签
<link rel="stylesheet" href="css样式表文件名.css">
布局标签div与span
<div> 一行只显示一个(独占一行);宽度默认是父元素的宽度,高度默认由内容撑开;可以设置宽和高 div>
<span> 一行可以显示多个;宽度和高度默认由内容撑开;不可以设置宽和高;span和div都是没有语义的布局标签 span>
超链接标签
<a href="指定资源访问的url" target="指定在何处打开资源链接"> 网页中显示的链接描述 a>
target: 非必填属性
_self: 默认值,在当前页面打开
_blank: 在空白页面打开
视频、音频标签
<video src="规定视频的url" controls width="宽度(可选)" height="高度(可选)">video>
controls: 显示播放控件,controls="controls" 属性名=属性值可以省略为属性名
<audio src="规定音频的url" controls>audio>
段落标签
<p> 段落的内容 p>
文本加粗标签
<b> 要加粗的文本 b>
<strong> 要强调的文本(同样可以实现加粗的效果,但具有强调语义) strong>
表格标签
<table border="表格边框的宽度" width="表格的宽度" cellspacing="单元之间的空间">
<tr>
<td> 该行的第一个单元格内容 td>
<td> 该行的第二个单元格内容 td>
<th> 对于表头单元格可用th标签 th>
tr>
table>
表单标签
<form action="表单数据提交的url地址" method="表单提交方式"> 表单项标签(必须有name属性才能提交) form>
method:
get: 表单数据拼接在url后面,如url?age=18,大小有限制
post: 表单数据在请求体(消息体)中携带,没有大小限制
表单项标签
(1) 表单项
<input type="表单项的输入形式" name="元素的名称,必须存在才能提交" >
value: 指定元素的值
对于单选框或复选框(name属性必须一致),且需用<label for="应与相关元素的id属性相同">标签为input元素定义标注(标记),这样在点击标签时才会聚焦到相关的表单控件上。
(2) 下拉列表
<select name="下拉列表的名称">
<option value="值1"> 第1个下拉列表元素 option>
<option value="值2"> 第2个下拉列表元素 option>
select>
(3) 文本域
<textarea name="文本域的名称" cols="列数" rows="行数">textarea>
CSS(Cascading Style Sheet):层叠样式表,用于控制页面的样式(表现)。w3school查看更多CSS3样式
写在head标签
中)。.css
文件中(需要通过link标签
在网页中引入,同样)。标签名
选择要设置样式的标签。优先级最低。#id属性值
选择要设置样式的标签。优先级最高。.class属性值
选择要设置样式的标签。优先级中间。box-sizing
:指定宽和高是针对哪块区域的。如content-box(css属性的width和height就指定了内容区域的大小);border-box(指定的是边框区域的宽和高)。padding
:指定内边距(顺序上、右、下、左),若都相同,可只写一个。值为auto就会自动计算对应内边距大小。border
:指定边框属性border-width(边框的宽度,都是按上右下左顺序分别指定)、border-style(边框样式,必须指定的,dotted(点状)、solid(实线)、double(双线)、dashed(虚线))和border-color(边框颜色)。margin
:指定外边距,和内边距类似,都可设置某一个方位的外边距(margin_top、margin_right、margin_bottom、margin_left)。常用属性:
JavaScript(简称:JS)是一门跨平台、面向对象的脚本语言(解释性语言),是用来控制网页行为的,它能使网页进行交互。ES6是最新的JavaScript版本。w3school查看更多JS用法
JavaScript引入方式
(1)内部脚本:将JS代码定义在HTML页面中,必须位于标签之间,在HTML文档中,可以在任意地方,放置任意数量的script标签,一般会把脚本置于body元素的底部,可改善显示速度。
(2)外部脚本:将JS代码定义在外部JS文件中,然后引入到HTML页面中。外部JS文件中,只包含JS代码,不包含script标签。引入时script标签不能自闭合,应。
书写语法
区分大小写;结尾分号可有可无;注释//和/**/;大括号表示代码块。
(1) window.alert() //写入警告框,window可省略
(2) document.write() //写入HTML输出
(3) console.log() //写入浏览器控制台
变量
(1)var
:JavaScript是一门弱类型语言,变量可以存放不同类型的值,作用域比较大,全局变量;可以重复声明。
(2)let
:ES6新增,只在所在的代码块内有效,且不允许重复声明。
(3)const
:ES6新增,用来声明一个只读的常量(一旦声明,常量的值就不能改变)。
数据类型、操作符和流程控制语句
(1)原始类型(使用typeof 变量名
可获取数据类型)
(2)引用类型
(3)数据转换
(4)运算符
(5)流程控制语句
函数
(1) 函数定义方式一
function 函数名(参数1, 参数2...) { //形式参数不需要指定类型
//要执行的代码
//return 返回值;
}
(2) 函数定义方式二
var 函数名 = function(参数1, 参数2...) { //在JS中,函数调用可以传递任意个数的参数
}
(3) 箭头函数
var 函数名 = (参数1, 参数2...) => { 要执行的代码 } //ES6新特性
(1) var 数组名 = new Array(元素列表);
(2) var 数组名 = [元素列表];
(3) 数组名.length //返回数组中元素的数量
(4) 数组名.forEach(函数) //遍历数组中的每个有值的元素(for循环没值的也会遍历),并调用一次传入的函数
(5) 数组名.push(元素列表) //将新元素添加到数组的末尾,并返回新的长度
(6) 数组名.splice(起始索引, 删除个数) //从数组中删除元素
(1) var 字符串名 = new String("字符串");
(2) var 字符串名 = "字符串";
(3) 字符串名.length //求字符串的长度
(4) 字符串名.charAt(索引值) //返回在指定位置的字符
(5) 字符串名.indexOf("子串") //检索字符串的位置
(6) 字符串名.trim() //去除字符串两边的空格
(7) 字符串名.substring(起始索引, 结束索引) //求子串,左闭右开
var 对象名 = {
属性名1: 属性值1,
属性名2: 属性值2,
...
函数名1: function(形参列表) {},
函数名2(形参列表) {}
};
(1) 定义JSON字符串
var json字符串 = '{"key1": value1, "key2": value2...}'; //key值必须用双引号括住
value:
数字:整数或浮点数
字符串:在双引号中
逻辑值:true或false
数组:在方括号中
对象:在花括号中
null
(2) JSON字符串转为JS对象
var jsObject = JSON.parse(json字符串);
(3) JS对象转为JSON字符串
var jsonStr = JSON.stringify(js对象);
window.history //对History对象的只读引用
window.location //对于窗口或框架的Location对象
window.navigator //对Navigator对象的只读引用
window.alert("消息") //显示带有一段消息和一个确认按钮的警告框
window.confirm("消息") //显示带有一段消息以及确认按钮和取消按钮的对话框
window.setInterval(函数, 时间) //按照指定的周期(以毫秒计)来调用函数或计算表达式
window.setTimeout(函数,时间) //在指定的毫秒数后调用函数或计算表达式,只执行一次
(2)Location对象location.href //获取当前页面完整的URL
location.href = "url"; //设置url值,会自动跳转到对应的网址
(1) 根据id获取Element对象
var element对象名 = document.getElementById('id值');
(2) 根据标签名获取Element对象数组
var element对象数组名 = document.getElementsByTagName('标签名');
(3) 根据name获取Element对象数组
var element对象数组名 = document.getElementsByName('name值');
(4) 根据class获取Element对象数组
var element对象数组名 = document.getElementsByClassName('class值');
(5) 获取或更改Element对象的内容
var content = Element对象.innerHTML;
Element对象.innerHTML = "内容";
Vue是一套渐进式前端框架,免除原生JavaScript中的DOM操作,简化书写。它是基于MVVM
(Model-View-ViewModel)思想,实现数据的双向绑定
,将编程的关注点放在数据上。Vue官网
安装:
(1)下载安装node.js(JS运行环境)node.js,命令node -v检查版本,在以管理员身份情况下命令npm config set prefix “安装路径” 来配置npm的全局安装路径(通过npm命令install的文件存放的路径),命令npm config get prefix获取路径,命令npm config set registry https://registry.npm.taobao.org配置淘宝镜像。
(2)安装vue-cli(vue开发工具),命令npm install -g @vue/cli,命令vue -V检查版本,命令vue create my-project创建项目(项目名全小写,可用-连接),也可以用vue ui可视化创建项目,命令cd my-project转到项目目录,命令npm run serve运行。
(3)安装vue3高亮插件volar。
{{ 绑定变量名 }}
绑定普通文本,一般配合JS中的data()设置数据。v-html="绑定变量名"
指令可以识别HTML元素(标签)。v-bind:属性名="绑定变量名"
绑定标签属性,v-bind:可简写为:。@
) 来监听DOM事件,事件处理方法写在methods:{ }中,且方法可以接收传递的参数。<template> HTML标签 </template>
<script>
export default {
name: '组件名',
data() { }, //数据区域,v-bind和v-model绑定的数据必须在此处声明
methods: { }, //方法区
components: { }, //挂载组件
props:{ }, //父组件向子组件传递信息
mounted() { } //渲染完成后进行网络请求
}
</script>
<style scoped> CSS样式 </style> //scoped:指的是样式只在该组件中生效,不加则全局都共享该样式
$emit
this.$emit("事件名", this.要传递的数据)
,其中,事件名:父组件在调用子组件时要用@事件名
这一事件指定对应的事件方法,在方法中有参数,接收处理该参数即可。通过vue-router路由管理页面之间的关系,Vue Router是Vue.js的官方路由,它与Vue.js核心深度集成,让用Vue.js构建单页应用变得轻而易举。Vue Router
() => import('对应组件的路径')
))$route.params.
id获取参数Vuex是一个专为Vue.js应用程序开发的状态管理模式+库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。能够在vue中管理公共的数据,便于开发和维护;在整个项目中可以实现组件之间的数据共享;储存在vuex中的数据都是响应式的,能够保持数据与页面上的数据保持同步。Vuex官网
(1) this.$store.state.状态变量名
(2) import { mapState } from 'vuex'; //mapState辅助函数
computed: {
...mapState(["状态变量名"]) //这样就可以直接用状态变量名了,...为展开运算符
}
this.$store.getters
,mapGetters辅助函数。this.$store.commit('方法名')
提交,或在methods属性中引入...mapMutations([方法名列表])
,再直接通过this.方法名()
即可调用。(1) 注册action1
actions: {
action名1 (context) { //context相当于this.$store
context.commit('对应的mutation名')
}
}
(2) 注册action2
actions: {
action名2({ commit }) { //也可以传递其它参数
commit('对应的mutation名') //若mutation中有除state其它参数,这里同样需要额外的参数
}
}
(3) 分发Action
this.$store.dispatch('action名') //同样可以传递参数进去
...mapActions([方法名列表]) //就直接用this.action名()调用了
(5)Module:将store分割成模块,每个模块里都有state,mutation,active,getter,当项目比较大时,可以分成很多的模块,甚至是嵌套子模块,这样的话就解决了多人写作开发中同名数据发生冲突导致被修改。
组合API
Vue3新增了一个setup
生命周期函数,在组合API中,使用setup()方法替换了beforeCreate和created,那么在这两个生命周期中的方法将放在setup中执行,因此setup无this。组合式API
setup(){ } 中声明变量(vue2在data中声明)、声明方法(vue2在methods中声明)、props传递数据、context获取上下文对象
(代替了this), 所有变量和方法都必须return出去才能被外部调用。
(1)ref与reactive声明变量:const 变量名=ref(变量值);const 变量名=reactive({ 属性名:属性值 });
(2)声明方法:在方法中改变变量的值的时候,需用其value属性来更改,如变量名.value=更改后的值。
(3)props:接收父组件传递的参数,setup(props) { props:{ 参数名:参数类型} props.参数名即可使用 }
(4)context:setup(props, context) { }
(5)在setup()中调用生命周期钩子,如onMounted(()=>{ }),且同一个生命周期函数可以存在多个。
(6)provide()和inject()可以实现嵌套组件之间的数据传递,只能在setup()中使用,父级组件使用provide()向下传递数据,子级组件使用inject()获取上层传递过来的数据,且不限层级。
(1) 父组件,先从vue中导入provide
provide("参数名", 值);
(2) 子组件,先从vue中导入inject
const 参数名 = inject("参数名");
Ajax(Asynchronous JavaScript And XML),异步的JavaScript和XML。如使用XMLHttpRequest是一种Ajax的实现方式。
(1)数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。
(2)异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。
Axios是一个基于promise的网络请求库,命令npm install --save axios安装axios。
this.$axios
使用)import axios from "axios"
const app = createApp(App);
app.config.globalProperties.$axios = axios;
app.mount('#app');
(1) axios的普通get请求
this.$axios({
method: "get",
url: "请求访问的url"
}).then(res => {
console.log(res.data);
})
(2) axios的简写get请求
this.$axios.get("请求访问的url")
.then(res => {
console.log(res.data);
})
(1) axios的普通post请求
this.$axios({
method: "post",
url: "请求访问的url",
data: querystring.stringify(数据对象) //需要安装并引用npm install --save querystring
}).then(res => {
console.log(res.data);
})
(2) axios的简写post请求
this.$axios.post("请求访问的url", querystring.stringify({数据对象}))
.then(res => { console.log(res.data); })
(1) 封装axios的get和post到request.js文件
import axios from "axios"
import querystring from "querystring"
const instance = axios.create({
//网络请求的公共配置
timeout: 5000
})
const errorHandle = (status, info) => {
switch (status) {
case 400:
console.log("语义有误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器拒绝访问");
break;
case 404:
console.log("地址错误");
break;
case 500:
console.log("服务器遇到意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
//拦截器最常用的
//1. 发送数据之前
instance.interceptors.request.use(
config => {
if (config.method === "post") { //post需要对数据进行特殊处理:字符化
config.data = querystring.stringify(config.data)
}
//config:包含网络请求的所有信息
return config;
},
error => Promise.reject(error)
)
//2. 获取数据之前
instance.interceptors.response.use(
response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
error => {
const { response } = error;
errorHandle(response.status, response.info);
}
)
export default instance; //导出网络请求
(2) 定义存放url的path.js文件夹
const base = {
baseUrl: "http://iwenwiki.com",
chengpin: "/api/blueberrypai/getChengpinDetails.php"
}
export default base;
(3) 定义处理具体请求的index.js
import axios from "../utils/request"
import path from "./path"
const api = {
getChengpin(){
return axios.get(path.baseUrl + path.chengpin);
}
}
export default api
(4) 在需要进行网络请求的vue中使用
import api from "./api/index"
api.getChengpin().then(res => {
console.log(res.data);
})
Access-Control-Allow-Origin
。devServer: { //在vue.config.js中添加这一配置,且需重启vue-cli
//port: 7000, //可以设置端口号为7000
proxy: {
'/api': {
target: '跨域的域名,如http://iwenwiki.com', //指定后其它url就可直接在这个基础上添加url
changeOrigin: true
}
}
}
Element Plus是基于Vue3的组件库,Element Plus组件库
const { defineConfig } = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
})
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
export default {
install: (app) => {
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
}
};
Nginx (engine x) 是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。
Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具。它基于项目对象模型(Project Object Model,POM)的概念,通过一小段描述信息来管理项目的构建。
(1)依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题。
(2)统一项目结构:提供标准、统一的项目结构。
(3)项目构建:标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式。
Maven安装与配置
(1)解压下载的Maven压缩包。Maven下载
(2)配置本地仓库:修改conf文件夹下的settings.xml中的
为一个指定目录(该标签是被注释的,需要拿出来配置)。
(3)配置阿里云私服:修改conf文件夹下的settings.xml中的
标签,更改mirror子标签为:
<mirror>
<id>alimavenid>
<name>aliyun mavenname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<mirrorOf>centralmirrorOf>
mirror>
(4)配置环境变量:新建MAVEN_HOME环境变量为解压目录,并将其bin目录加入Path环境变量。在cmd中使用命令mvn -v检验是否配置成功。
坐标
Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置,使用坐标来定义项目或引入项目中需要的依赖。
(1)groupId:定义当前Maven项目隶属组织名称(通常是域名反写)。
(2)artifactId:定义当前Maven项目名称(通常是模块名称)。
(3)version:定义当前项目版本号。
依赖配置
依赖是指当前项目运行所需要的jar包,一个项目中可以引入多个依赖。在dependency标签中声明依赖并刷新加入依赖即可。Maven仓库
依赖传递
依赖具有传递性。可以右键选择Diagrams中的Show Dependencies可视化查看依赖关系。
(1)直接依赖:在当前项目中通过依赖配置建立的依赖关系;
(2)间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源。
(3)排除依赖:主动断开依赖的资源,被排除的资源无需指定版本,在exclusions标签下声明子标签。
(4)循环依赖:重构代码,消除循环依赖(改成单向依赖);使用适当的依赖范围和排除依赖(provided或test范围)
依赖范围
依赖的jar包,默认情况下,可以在任何地方使用。可以通过scope标签设置其作用范围:
(1)compile(默认):主程序,测试程序,打包(运行)。如log4j
(2)test:测试程序。如junit
(3)provided:主程序,测试程序。如servlet-api
(4)runtime:测试程序,打包(运行)。如jdbc驱动
HTTP协议
HTTP(超文本传输协议),规定了浏览器和服务器之间数据传输的规则。基于TCP协议:面向连接,安全;基于请求-响应模型:一起请求对应一次响应;HTTP协议是无状态的协议:对于事物处理没有记忆能力,每次请求-响应都是独立的,因此速度快,但是多次请求间不能共享数据。
(1)请求数据格式
请求行:请求数据第一行(请求方式、资源路径、协议)。
请求头:第二行开始,格式key:value。
请求体:POST请求,存放请求参数。
请求方式-GET
:请求参数在请求行中,没有请求体,GET请求大小是有限制的。
请求方式-POST
:请求参数在请求体中,POST请求大小是没有限制的。
(2)响应数据格式
响应行:响应数据第一行(协议、状态码、描述)。
响应头:第二行开始,格式key:value。
响应体:最后一部分,存放响应数据。
Tomact
Web服务器是一个软件程序,对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷,主要功能是“提供网上信息浏览服务”。如Tomcat、WebLogic、WebSphere等。
Tomcat是一个开源免费的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范,Tomcat官网
下载Tomcat压缩包并解压,打开bin文件夹下的startup.bat启动(若控制台乱码,修改conf文件夹下的logging.properties的java.util.logging.ConsoleHandler.encoding = GBK),输入http://localhost:8080验证是否安装成功。若端口冲突,可以在conf文件夹下的server.xml中更改端口号。
在IDEA中部署Tomcat:File->Settings->Build,Execution,Deployment->Application Servers->+;Run->Edit Configurations…->Tomcat Server->Local
Postman
Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。作用:常用于进行接口测试。
请求
(1)原始方式:在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取。
(2)SpringBoot方式
简单参数:参数名与形参变量名相同,定义形参即可接收参数。
简单实体对象:请求参数名与形参对象属性名相同,定义POJO接受即可。
复杂实体对象:按照对象层次结构关系即可嵌套POJO属性参数。
数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数。
集合参数:请求参数名与形参中集合变量名相同,通过@RequestParam
绑定参数关系。
日期参数:使用@DateTimeFormat
注解完成日期参数格式转换。
JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要用@RequestBody
注解标识。
路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用@PathVariable
注解获取路径参数。
响应
(1)@ResponseBody
:位于Controller方法上/类上,作用:将方法返回值直接响应,如果返回值是实体对象/集合,将会转换为json格式响应。@RestController=@Controller+@ResponseBody
。
(2)统一响应结果:定义一个Result实体类,包含响应码code(整形,1代表成功,0代表失败);提示信息msg(String类型);返回的数据data(Object类型)。并创建3个静态方法(返回对象都是Result对象):只传data的success方法;无参success方法;只传msg的error方法。
静态资源目录
SpringBoot项目的静态资源默认存放目录为:classpath:/static;classpath:/public;classpath:/resources;
三层架构
(1)controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
(2)service:业务逻辑层,处理具体的业务逻辑。
(3)dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增删改查。
分层解耦
(1)内聚:模块内部的功能联系。高内聚
(2)耦合:各个模块之间的依赖、关联程度。低耦合
IOC与DI
(1)控制反转
(Inversion Of Control):简称IOC
,对象的创建控制权由程序自身转移到容器(这种思想称为控制反转)。
(2)依赖注入
(Dependency Injection):简称DI
,容器为应用程序提供运行时所依赖的资源。
@Resource与@Autowired区别
:@Autowired是Spring框架提供的注解,@Resource是JDK提供的注解;@Autowired默认是按照类型注入,而@Resource默认是按照名称注入。
(3)Bean对象:IOC容器中创建、管理的对象。注解生效必须用@ComponentScan
扫描,启动类上声明注解@SpringBootApplication
中已经包含,默认扫描范围是启动类所在的包及其子包。
Mybatis快速入门
(1)创建SpringBoot项目时,选择SQL下的MyBatis Framework和MySQL Driver依赖。
(2)创建基本表和对应的pojo实体类(对于基本数据类型,最好使用包装类,不会有默认值的干扰)。
(3)在SpringBoot配置文件application.properties中配置数据库连接信息。
# 驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/test
# 连接数据库的用户名
spring.datasource.username=root
# 连接数据库的密码
spring.datasource.password=123456
(4)定义mapper类,并在类上用@Mapper
注解:在运行时,会自动生成该接口的实现类对象(代理对象),并将该对象交给IOC容器管理;编写接口并使用@Select
等注解标明对应的SQL语句。配置SQL提示:选中写的SQL语句,右键->Show Context Actions->Inject language or reference->MySQL即可,若对于基本表还是没提示,则需连接MySQL数据库。
JDBC、数据库连接池、Lombok
JDBC(Java DataBase Connectivity),使用Java语言操作关系型数据库的规范(API接口),各数据库厂商去实现这套接口,提供数据库驱动jar包,真正执行的代码是驱动jar包中的实现类。
数据库连接池
是个容器,负责分配、管理数据库连接(Connection);它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。优点:资源重用;提升系统响应速度;避免数据库连接遗漏。
所有的数据库连接池都必须实现官方(Sun)提供的数据库连接池接口DataSource,再通过getConnection()方法来获取连接对象Connection,目前最好的两个连接池:
(1)HikariCP:光连接池,SpringBoot默认的数据库连接池。(若需更改为别的连接池,则需导入对应的依赖)
(2)Druid(德鲁伊):功能比较全面,且扩展性较好的数据库连接池,比较方便对jdbc接口进行监控跟踪等。
Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发、提高效率。需要导入lombok依赖。同时还提供@Slf4j
注解来记录日志。
预编译SQL
(1)开启Mybatis日志到控制台,在SpringBoot配置文件application.properties中进行设置:
# 指定Mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
(2)预编译SQL性能更高
:在带有参数的SQL语句中,会先用占位符?
来代替,然后对该SQL语句进行SQL语法解析检查、优化SQL、编译SQL并将编译的SQL放入缓存,最后执行SQL(执行的同时会将参数对占位符?进行替换)。如此一来,对于不同的参数但SQL语句相同,只需编译一次,之后从缓存中取,最后执行时赋予不同的参数即可,进而提升了性能。
(3)预编译SQL更安全(防止SQL注入)
:SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。例如:通过输入数据' or '1'='1
就可以使得SQL条件永远成立。
#{}与${}
(1)#{}:执行SQL时,会将#{}替换为?,生成预编译SQL,会自动设置参数值(参数值会自动加上引号)。使用时机:参数传递,都使用#{},可以防止SQL注入。
(2)${}:拼接SQL,直接将参数拼接在SQL语句中,存在SQL注入问题。使用时机:对表名、字段名进行动态设置时使用。
基础操作的注意点
(1)插入时的主键返回,可以在接口方法上使用@Options(keyProperty = "实体的主键属性", useGeneratedKeys = true)
,这样就会自动将生成的主键值,赋值给实体对象的主键属性。
(2)数据封装:实体类属性名和数据库表查询返回的字段名一致时,Mybatis会自动封装,反之则不会自动封装。
方法一:给字段起别名,让别名与实体类属性名一致。
方法二:通过@Results,@Result(配合column指定字段名、property指定属性名)注解手动映射封装。
方法三:开启Mybatis的驼峰命名自动映射开关(在SpringBoot配置文件application.properties中)。
# 开启Mybatis的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true
(3)模糊查询时,要用concat函数对占位符和通配符进行拼接。
(4)在Springbot1.X版本/单独使用Mybatis时,接口的形参是不会保留的,因此需要使用@Param
注解来进行指定。
XML映射文件
(1)XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
(2)XML映射文件的namespace属性与Mapper接口全限定名一致。
(3)XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率而生。XML映射文件的约束:XML约束
使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。
动态SQL
动态SQL:随着用户的输入或外部条件的变化而变化的SQL语句。
(1)where标签:如果包含的if标签都不成立则where条件判断不生效。
(2)if标签:用于判断条件是否成立,使用test属性进行条件判断,如果条件为true,则拼接SQL。
(3)set标签:动态的在行首插入set关键字,并会删掉额外的逗号。(用在update语句中)
(4)foreach标签:用于一些批量操作,如批量删除,属性如下所示:
(5)sql标签与include标签:sql标签将公共sql语句抽取并指定id属性;include标签通过refid属性对sql标签引用。
分页插件PageHelper
导入依赖pagehelper-spring-boot-starter。
PageHelper.startPage(page,pageSize); //传入当前页码和每页条数
//执行相关查询业务(该插件会自动加上对应的分页需要的SQL语句,计算总条数等信息)
//将查询的列表强转成Page<实体>对象
//通过上一步的对象可获取所有信息,如getTotal()获取总条数,getResult()获取查询结果,getPages()获取总页数等
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
//获取文件的原始的文件名
String originalFilename = multipartFile.getOriginalFilename();
//UUID构造唯一的识别码
int index = originalFilename.lastIndexOf(".");
String extName = originalFilename.substring(index);
String newFileName = UUID.randomUUID() + extName;
//将文件存储在服务器的磁盘目录中
multipartFile.transferTo(new File("E:\\" + newFileName));
MultipartFile常用方法:# 配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
# 配置一次可上传文件的总大小
spring.servlet.multipart.max-request-size=100MB
参数配置化
对于一写配置参数,需要提取在配置文件中,便于修改和维护,如自定义阿里云OSS配置信息:可以在Springboot的配置文件application.properties中采用key=value的形式来定义,然后需用到的时候通过@Value
注解来注入外部配置的属性(位置:定义变量的上方),具体用法为@Value("${key}")
。
yml配置文件
SpringBoot项目中除了application.properties配置文件,还可以有application.yml配置文件(或application.yaml),不同之处在于,yml配置文件是分级的(推荐使用)。
(1)大小写敏感
(2)数值前边必须有空格,作为分隔符
(3)使用缩进标识层级关系,缩进时,不允许使用Tab键,只能使用空格(Idea会自动将Tab准换为空格)。
(4)缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
(5)#标识注释,从这个字符一直到行尾,都会被解析器忽略。
(6)yml常用的数据格式如下所示:
@ConfigurationProperties
可以将同前缀的配置批量的封装到一个实体类中,通过Lombok的注解@Data构建set/get方法;通过@Component注解将其交给Spring容器进行管理;通过@ConfigurationProperties(prefix = “”)注解自动为对应的属性注入配置的值;最后通过将该实体类依赖注入即可使用。需要导入spring-boot-configuration-processor依赖
会话技术
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束,在一次会话中可以包含多次请求和响应。
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。
(1)Cookie
:客户端会话跟踪技术,服务器通过响应头Set-Cookie来设置Cookie数据,客户端通过请求头Cookie来携带Cookie数据。跨域(协议、域名/IP、端口任何一个不同就是跨域)。
(2)Session
:服务端会话跟踪技术,通过在服务器建立Session,同时借助Cookie会话技术存储Session的ID进而对不同的会话进行判断。
(3)令牌技术
JWT令牌
JWT(JSON Web Token):定义了一种简洁的(字符串)、自包含的格式,用于在通信双方以json数据格式安全的传输信息,由于数字签名的存在,这些信息是可靠的。JWT官网
组成:
(1)第一部分:Header(头),记录令牌类型、签名算法等。
(2)第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。前两部分都会通过Base64对json数据进行编码(Base64是一种基于64个可打印字符(A-Z a-z 0-9 + /)来表示二进制数据的编码方式)。
(3)第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定密钥,通过指定签名算法计算而来。
登录认证
:登录成功后,生成令牌;后续的每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理。
(1)导入依赖jjwt
(2)登录后下发令牌(通过自定义工具类对生成和解析JWT令牌进行封装)
public class JwtUtils {
private static String signKey = "superm";
private static Long expire = 43200000L;
//生成JWT令牌(参数为有效荷载)
public static String generateJwt(Map<String, Object> claims) {
String jwt = Jwts.builder()
.addClaims(claims) //有效荷载
.signWith(SignatureAlgorithm.HS256, signKey) //签名算法和密钥
.setExpiration(new Date(System.currentTimeMillis() + expire)) //有效期
.compact();
return jwt;
}
//解析JWT令牌(返回值为有效荷载的内容)
public static Claims parseJWT(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
(3)对请求进行拦截验证解析令牌。
过滤器Filter
Filter过滤器是JavaWeb三大组件(Servlet、Filter、Listener)之一;过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能,例如一些通用的操作(登录校验、统一编码处理、敏感字符处理等)。
Filter过滤器的使用方法:
(1)定义Filter:定义一个类,实现Filter接口(jakarta.servlet.Filter),并重写其方法doFilter进行过滤操作(还有init初始化和destory销毁方法,有默认实现),在doFilter方法中先执行放行前逻辑,再通过filterChain.doFilter(servletRequest, servletResponse);
对拦截的请求进行放行,最后执行放行后的逻辑。
(2)配置Filter:定义的Filter类上加@WebFilter("/*")
注解来配置拦截资源的路径,并在启动类上加@ServletComponentScan
注解开启对Servlet组件的支持。
过滤器链:
一个Web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。执行顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然顺序。
登录校验
@Slf4j
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest; //向下转型,HttpServletRequest具有Http协议的方法,如getHeader
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//1. 获取请求的url
String url = req.getRequestURL().toString();
log.info("请求的url:{}", url);
//2. 判断是否是登录url
if (url.contains("login")) {
log.info("登录操作,放行...");
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//3. 获取请求头中的JWT令牌
String jwt = req.getHeader("token");
//4. 判断令牌是否存在,不存在,则返回错误结果(未登录)
if(jwt==null){
log.info("请求头token为空,返回未登录的信息");
resp.getWriter().write(JSONObject.toJSONString(Result.error("NOT_LOGIN"))); //需导入fastjson2依赖
return;
}
//5. 令牌存在,则解析JWT令牌,若解析失败,则返回错误结果(未登录)
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
log.info("token解析失败,返回未登录的信息");
resp.getWriter().write(JSONObject.toJSONString(Result.error("NOT_LOGIN"))); //前端需对改信息判断跳转到登录页面
return;
}
//6. 放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest, servletResponse);
}
}
拦截器Interceptor
拦截器是一种动态拦截方法调用的机制,类似于过滤器,由Spring框架提供,用来动态拦截控制器方法的执行。作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
拦截器Interceptor的使用方法:
(1)定义拦截器:自定义拦截器类实现HandlerInterceptor接口,用@Component
注解将拦截器交由Spring容器,重写其三个方法:preHandle(目标资源方法运行前运行,若为true就放行,返回false则不放行);postHandle(请求处理后运行);afterCompletion(视图渲染完之后运行)。
(2)配置拦截器:定义一个配置类实现WebMvcConfigurer接口,用@Configuration
注解表明该类是配置类,重写addInterceptors方法,通过注入依赖获取拦截器对象,最后通过registry.addInterceptor(拦截器对象).addPathPatterns("/**").excludePathPatterns("/login");
来添加拦截器并指定拦截路径(还可以指定不拦截的路径)。
拦截路径:
执行流程:
异常处理
将Dao、Service、Controller的异常都通过throws Exception向上抛出,然后定义一个全局异常处理器类使用@RestControllerAdvice
注解标记,@RestControllerAdvice=@ResponseBody+@ControllerAdvice,对于不同的异常定义不同的方法并用@ExceptionHandler(异常类.class)
标注,可以是自定义的异常,也可以是系统异常,方法中的参数就是那个异常类的类型。
在业务层(Service)层的方法上、类上、接口上使用@Transactional
注解,将当前方法(一般对包含多个对数据库操作的增删改的方法)交给Spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务。
# 开启事务管理日志
logging.level.org.springframework.jdbc.support.JdbcTransactionManager=debug
Spring事务失效
AOP(Aspect Oriented Programming)(面向切面编程、面向方法编程),其实就是面向特定方法编程,需导入spring-boot-starter-aop依赖。应用场景:记录操作日志、权限控制、事务管理等。优点:代码无侵入、减少重复代码、提高开发效率、维护方便。
核心概念
(1)连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)。
(2)通知:Advice,指哪些重复的逻辑,也就是共享功能(最终体现为一个方法)。
(3)切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用。
(4)切面:Aspect,描述通知与切入点的对应关系(通知+切入点)。@Aspect
+@Component
注解指定切面类
(5)目标对象:Targer,通知所应用的对象。
通知类型
@Around
环绕通知需要自己调用ProceedingJoinPoint.proceed()
来让原始方法执行,且必须指定返回值Object类型来接收原始方法的返回值。
通知的执行顺序默认是按照切面类的类名字母顺序执行的;也可以通过@Order(数字)
注解在切面类上来控制顺序,数字越小,越先执行。
切入点表达式-execution
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
:多个切入点表达式可以通过且(&&)、或(||)、非(!)
来组合。
(1)访问修饰符可以省略。
(2)返回值类型、包名、类名、方法名可以使用星号*代表任意。
(3)包名和类名之间一个点.代表当前包下的类,两个点..
代表当前包及其子包下的类。
(4)参数列表可以使用两个点..
表示任意个数,任意类型的参数列表。
抽取公共切点表达式:使用@Pointcut
注解在某方法上进行抽取,调用时使用方法名()即可。
切入点表达式-annotation
自定义注解类,并使用@Retention()
和@Target()
注解指定自定义注解什么时候生效和注解的位置,然后在切入点方法上使用自定义的注解,最后在切面类的通知类型中使用@annotation(自定义注解全限定包名)
来指定切入点。
连接点JoinPoint
在Spring中用JoinPoint
抽象了连接点,用它可以获得方法执行时的相关信息,ProceedingJoinPoint
是其子类,对@Around通知只能用ProceedingJoinPoint,而其它四种通知,获取连接点信息只能使用JoinPoint对象。
(1)获取目标对象的类名:JoinPoint.getTarget().getClass().getName();
(2)获取目标方法的方法名:JoinPoint.getSignature().getName();
(3)获取目标方法运行时传入的参数:Object[] args = JoinPoint.getArgs();
(4)目标方法执行并返回值:Object result = ProceedingJoinPoint.proceed();
AOP-记录操作日志
日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长等。通过自定义注解对Controller层中需要记录日志的方法实现@Around通知的日志切入即可。
@Retention
:指定注解的生命周期。@Taget
:指定注解的使用位置。@Inherited
:指定被标注的类型是可以继承的。@Documented
:将注解信息添加在Javadoc中。@intertface
:用于声明注解的注解(并非是元注解)。配置文件的优先级
命令行参数配置:-Dxxx = xxx(优先级最高,越往下优先级越低)
Java系统属性配置:--
xxx = xxx
application.properties > application.yml(主流) > application.yaml
SpringBoot多环境配置
(1)application-dev.properties:开发环境
(2)application-test.properties:测试环境
(3)application-prod.properties:生产环境
在application.properties文件中通过spring.profiles.active属性来指定哪个具体的配置文件会被加载,如spring.profiles.active=dev对应加载开发环境的配置。
获取Bean
默认情况下,Spring项目启动时,会把Bean都创建好放在IOC容器中(仅限单例且没有延迟的Bean),如果想要主动获取这些Bean,先通过依赖注入获取Spring容器ApplicationContext对象,再通过如下方式获取即可:
(1) 根据name获取Bean:Object getBean(String name) //需要强制转换
(2) 根据类型获取Bean:<T> T getBean(Class<T> requiredType)
(3) 根据name获取Bean(带类型转换):<T> T getBean(String name, Class<T> requiredType)
Bean的作用域
可以通过@Scope
注解来指定Bean的作用域,通过@Lazy
注解延迟Bean的初始化(延迟到第一次使用)。
第三方Bean
通过在配置类中(@Configuration
注解的类)声明方法,并返回第三方对象,同时用@Bean
注解进行标记,此时方法名就是默认的Bean的名称(建议方法名就是第三方对象类的首字母小写)。如果第三方Bean需要依赖其它Bean对象,直接在Bean定义方法中设置形参即可,容器会根据类型自动装配。
Spring框架比较繁琐(依赖和配置),SpringBoot底层的起步依赖
和自动配置
大大简化了Spring Framework中依赖和配置的繁琐。
自动配置
:SpringBoot的自动配置就是当Spring容器启动后,一些配置类、Bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。@ComponentScan
开启组件扫描,指定扫描的包(会将全部的Bean加载到IOC容器)。使用繁琐,性能低。@Import({})
导入,导入的类会被Spring加载到IOC容器中,可以导入:普通类,配置类,ImportSelector接口实现类(可以将要交给Spring容器管理的全限定类名封装成数组),第三方依赖一般会使用自定义的@EnableXxxx注解
来封装@Import
注解进而完成对想要交由Spring容器管理的Bean对象的配置。@EnableAutoConfiguration
注解使用@Import
注解,导入了实现ImportSelector接口的实现类AutoConfigurationImportSelector。selectImports()
方法,用于确定将什么类交由Spring的IOC容器。getAutoConfigurationEntry()
方法,获取可自动配置的配置类信息集合。getCandidateConfigurations()
方法获取在配置文件中配置的所有自动配置类的集合。spring.factories
文件、META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件中配置类的集合。@Conditional
注解条件装配。parent标签
实现。打包方式为pom
(默认是jar)。dependencyManagement
标签来统一管理依赖的版本(只是管理,在父工程并没有引入这些依赖)。子工程在引入依赖时,无需指定version版本号,父工程统一管理。若变更依赖版本,只需在父工程中统一变更,父工程还可以通过在properties标签中自定义属性(xxx.version标签
来指定版本),最后在依赖的version标签中通过${xxx.version}
引用属性。modules标签
设置当前聚合工程所包含的子模块名称,通过module标签设置子模块的相对路径。聚合工程中所包含的模块,在构建时,会自动根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关。<server>
<id>maven-releasesid>
<username>adminusername>
<password>adminpassword>
server>
<server>
<id>maven-snapshotsid>
<username>adminusername>
<password>adminpassword>
server>
(2)设置私服的连接地址(在settings.xml中的mirrors中配置)<mirror>
<id>maven-publicid>
<mirrorOf>*mirrorOf>
<url>http://192.168.150.101:8081/repository/maven-public/url>
mirror>
(3)指定从私服下载的依赖无论是RELEASE还是SNAPSHOT版本都可以使用(在settings.xml中的profiles中配置)<profile>
<id>allow-snapshotsid>
<activation>
<activeByDefault>trueactiveByDefault>
activation>
<repositories>
<repository>
<id>maven-publicid>
<url>http://192.168.150.101:8081/repository/maven-public/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>trueenabled>
snapshots>
repository>
repositories>
profile>
(4)在IDEA的Maven工程的pom文件中配置上传(发布)地址<distributionManagement>
<repository>
<id>maven-releasesid>
<url>http://192.168.150.101:8081/repository/maven-releases/url>
repository>
<snapshotRepository>
<id>maven-snapshotsid>
<url>http://192.168.150.101:8081/repository/maven-snapshots/url>
snapshotRepository>
distributionManagement>
(5)发布项目,直接运行deploy生命周期即可