HTML
HTML 语义化
使用语义化标签而不是div, span
作用:
1.使人更易理解
2.SEO 使机器(搜索引擎 爬虫)能够理解
行级块级元素(块状,内联)
display:block/table
有div h1 h2 table ul ol p等
display: inline/inline-block
有 span img input button等
script 标签中 defer 和 async
普通的sript:阻止HTML解析,下载并加载完后才会继续解析HTML
defer:异步下载,同步加载(HTML加载完后才会加载)
async:异步下载和加载,可能会阻碍HTML解析
CSS
盒模型宽度计算
width+padding*2+boder*2
使宽度计算方式包括内边距和边框:box-sizing: border-box;
margin
重叠
相邻元素的margin-top和margin-bottom会重叠
空白内容也会发生重叠
负值
margin-top和margin-left负值,元素向上、向左移动
margin-right和margin-bottom负值,右侧元素左移,下方元素上移,自身不受影响
BFC
Block format context ,块级格式化上下文
一块独立渲染区域,内部元素的渲染不会影响边界以外的元素
形成BFC的常见条件
float不是none
position 是 absolute 或 fixed
overflow不是visible
display 是 flex inline-block等
float
两栏布局
(左侧固定 + 右侧自适应布局)
现在有以下 DOM 结构:
<div class="outer">
<div class="left">左侧</div>
<div class="right">右侧</div>
</div>
利用浮动,左边元素宽度固定 ,设置向左浮动。将右边元素的 margin-left 设为固定宽度 。注意,因为右边元素的 width 默认为 auto ,所以会自动撑满父元素。
.outer {
height: 100px;
}
.left {
float: left;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
margin-left: 200px;
height: 100%;
background: lightseagreen;
}
同样利用浮动,左边元素宽度固定 ,设置向左浮动。右侧元素设置 overflow: hidden; 这样右边就触发了 BFC ,BFC 的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。
.outer {
height: 100px;
}
.left {
float: left;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
overflow: auto;
height: 100%;
background: lightseagreen;
}
利用 flex 布局,左边元素固定宽度,右边的元素设置 flex: 1 。
.outer {
display: flex;
height: 100px;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
flex: 1;
height: 100%;
background: lightseagreen;
}
利用绝对定位,父级元素设为相对定位。左边元素 absolute 定位,宽度固定。右边元素的 margin-left 的值设为左边元素的宽度值。
.outer {
position: relative;
height: 100px;
}
.left {
position: absolute;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
margin-left: 200px;
height: 100%;
background: lightseagreen;
}
利用绝对定位,父级元素设为相对定位。左边元素宽度固定,右边元素 absolute 定位, left 为宽度大小,其余方向定位为 0 。
.outer {
position: relative;
height: 100px;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
position: absolute;
left: 200px;
top: 0;
right: 0;
bottom: 0;
height: 100%;
background: lightseagreen;
}
三栏布局
圣杯:
<header style="background-color: rgb(233, 233, 233);">header</header>
<container class="container">
<div class="center">center</div>
<div class="left">left</div>
<div class="right">right</div>
</container>
<footer style="background-color: rgb(233, 233, 233);">footer</footer>
.container {
display: block;
padding-left: 200px;
padding-right: 300px;
}
.center {
float: left;
background-color: bisque;
width: 100%;
}
.left {
position: relative;
float: left;
background-color: aqua;
width: 200px;
margin-left: -100%;
right: 200px;
}
.right {
float: left;
background-color: aquamarine;
width: 300px;
margin-right: -300px;
}
footer {
clear: both;
}
双飞翼:
<div id="main">
<div id="main-wrap">
main
</div>
</div>
<div id="left">
left
</div>
<div id="right">
right
</div>
#main {
width: 100%;
height: 200px;
background-color: greenyellow;
float: left;
}
#main-wrap {
margin-left: 200px;
margin-right: 250px;
}
#left {
width: 200px;
height: 200px;
background-color: aqua;
float: left;
margin-left: -100%;
}
#right {
width: 250px;
height: 200px;
background-color: lightgreen;
float: left;
margin-left: -250px;
}
clear fix:
.clearfix:after {
content: '' ;
display:table;
clear:both;
}
.clearfix {
*zoom:1;/*兼容IE低版本*/
}
flex
flex-direction 主轴方向
justify-content 主轴对齐方式
align-items 交叉轴对齐方式
flex-wrap 换行
align-self 子元素交叉轴对齐
画个色子
<div class="box">
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
</div>
.box {
width: 200px;
height: 200px;
border: 2px solid #ccc;
border-radius: 10px;
padding: 20px;
display: flex;
justify-content: space-between;
}
.item {
display: block;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: palevioletred;
}
.item:nth-child(2) {
align-self: center;
}
.item:nth-child(3) {
align-self: flex-end;
}
position
absolute和relative分别依据什么定位?
relative依据自身定位
自身位移并作为子元素(如果有)的定位基准
absolute依据最近一层的定位元素定位
定位元素
absolute relative fixed
body(找不到absolute时)
居中对齐实现方式
水平居中
inline元素:text-align:center
block元素:margin:auto
absolute元素:left:50%+margin-left负值(必须知道子元素尺寸) -宽度/2
垂直居中
inline元素:line-height的值等于height值
absolute元素:top:50%+margin-top负值
absolute元素:transform(-50%,-50%)
absolute元素:top,left,bottom,right=0+margin:auto
line-height 继承方式:
具体数值,如30px,则继承该值
比例,如2/1.5,则继承该比例
百分比,如200%,则继承计算出来的值
响应式(rem/vw/vh)
px,绝对长度单位,最常用
em,相对长度单位,相对于父元素,不常用
root em rem,相对长度单位,相对于根元素,常用于响应式布局
vh网页视口高度的1/100
vw网页视口宽度的1/100
vmax 取两者最大值;vmin取两者最小值
响应式布局的常用方案
media-query,根据不同的屏幕宽度设置根元素 font-size
rem,基于根元素的相对单位
网页视口尺寸
window.screen.height//屏幕高度
window.innerHeight//网页视口高度
document.body.clientHeight//body高度
JS
变量类型和计算
值类型和引用类型的区别
引用类型vs值类型
引用:储存内存地址(对象,数组,函数等)
typeof 能判断哪些类型
识别所有值类型
识别函数
判断是否是引用类型(object)(不可再细分)
变量计算-类型转换
字符串拼接: 拼接时有字符串则会转换为字符串 如 a = true + 'wdnmd' //'truewdnmd'
何时使用===何时使用==
除==null,用===
==: '' == false -> true; 0 == false -> true; null == undifined -> true
if 语句和逻辑运算 : !!(0/NaN/''/null/undefined/false) 为falsely变量,其他为truly
深拷贝
handle\1-深拷贝.ts
原型原型链
class 和继承
类型判断 instanceof
原型和原型链
如何准确判断一个变量是不是数组?
val instanceof Array // true/false
手写一个简易的jQuery,考虑插件和扩展性
class jQuery {}
jQuery.prototype.chajian = function(args){}
class jjQuery extends jQuery {}
class 的原型本质,怎么理解?
每个class都有显示原型prototype
每个实例都有隐式原型__proto__
实例的__proto__指向对应class的prototype
作用域和闭包
作用域和自由变量
全局作用域
函数作用域
块级作用域(ES6新增)
一个变量在当前作用域没有定义,但被使用了
向上级作用域,一层一层依次寻找,直至找到为止
如果到全局作用域都没找到,则报错xx is not defined
闭包
函数中自由变量的查找在函数定义的地方而不是执行的地方
在函数定义的时候,如果当前作用域有被引用的变量,则会形成闭包
this
取值是在函数执行时确定的,而不是定义时确定的
作为对象方法执行作用域为上级对象
setTimeout的this指向window
箭头函数this的取值始终为上级作用域
this 的不同应用场景,如何取值?
当做普通函数被调用: 执行时作用域
使用call apply bind: 指定作用域
作为对象方法调用: 上级对象
在class的方法中调用: 对象本身
箭头函数: 上级作用域
手写 bind 函数
handle\2-bind.ts
实际开发中闭包的应用场景,举例说明
隐藏数据,只提供api
异步
单线程和异步
JS是单线程语言,只能同时做一件事儿
浏览器和 nodejs 已支持JS启动进程,如Web Worker
JS和DOM渲染共用同一个线程,因为JS可修改DOM结构
应用场景
网络请求,如ajax图片加载
定时任务,如 setTimeout
callback hell 和 Promise
同步和异步的区别是什么?
基于JS是单线程语言
异步不会阻塞代码执行
同步会阻塞代码执行
手写用 Promise 加载一张图片
promise.ts
前端使用异步的场景有哪些?
网络请求,如ajax图片加载
定时任务,如setTimeout
event loop 事件循环
JS如何执行?
从前到后,一行一行执行
如果某一行执行报错,则停止下面代码的执行
先把同步代码执行完,再执行异步
event loop
同步代码,一行一行放在Call Stack执行
遇到异步,会先“记录”下,等待时机(定时、网络请求等)
时机到了,就移动到 Callback Queue
如 Call Stack为空(即同步代码执行完)Event Loop开始工
轮询查找 Callback Queue,如有则移动到 Call Stack 执行
然后继续轮询查找(永动机一样)
DOM 事件和 event loop
JS是单线程的
异步(setTimeout,ajax等)使用回调,基于event loop
DOM 事件也使用回调,基于 event loop
Promise
三种状态
pending resolved rejected
pending -> resolved 或 pending -> rejected
变化不可逆
状态的表现和变化
pending状态,不会触发then和catch
resolved 状态,会触发后续的 then 回调函数
rejected状态,会触发后续的catch回调函数
then 和 catch 对状态的影响
then 正常返回 resolved,里面有报错则返回 rejected
catch 正常返回 resolved,里面有报错则返回 rejected
async/await
异步回调 callback hell
Promise then catch 链式调用,但也是基于回调函数
async/await是同步语法,彻底消灭回调函数
async/await和Promise的关系
执行async函数,返回的是Promise对象 (值封装为Promise对象,Promise直接返回)
await 相当于 Promise 的 then
try...catch 可捕获异常,代替了 Promise 的 catch
for ... of
for...in(以及forEach for)是常规的同步遍历
for...of 常用于异步的遍历
宏任务 macroTask和微任务 microTask
什么是宏任务,什么是微任务
宏任务:setTimeout,setInterval,Ajax,DOM事件
微任务:Promise async/await
微任务执行时机比宏任务要早
event loop 和 DOM 渲染
每次Call Stack清空(即每次轮询结束),即同步任务执行完
都是DOM重新渲染的机会,DOM结构如有改变则重新渲染
然后再去触发下一次 Event Loop
微任务和宏任务的区别
宏任务:DOM渲染后触发,如setTimeout
微任务:DOM渲染前触发,如Promise
微任务是ES6语法规定的
宏任务是由浏览器规定的
宏任务有哪些?微任务有哪些?微任务触发时机更早
微任务、宏任务和DOM渲染的关系
微任务、宏任务和DOM渲染,在eventloop的过程
手写promise
3-promise.ts
JS Web API
DOM
DOM 本质
从HTML解析出来的一棵树
DOM 节点操作
获取DOM节点
const div1 = document.getElementById('div1')//元素
const divList = document.getElementsByTagName('div')//集合
const containerList = document.getElementsByClassName('.container')//集合
const pList = document.querySelectorAll('p')//集合
const p = pList[0]
property:修改对象属性,不会体现到html结构中
console.log(p.style.width)//获取样式
p.style.width='100px'//修改样式
console.log(p.className)//获取class
p.className='p1'//修改 class
//获取 nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)
attribute:修改html属性,会改变html结构
p.setAttribute('data-name','imooc')
o.setAttribute('style','font-size:30px;')
p.getAttribute('data-name')//imooc
p.getAttribute('style')//font-size:30px;
两者都有可能引起DOM重新渲染
DOM 结构操作
新增/插入节点
//新建节点
const newP = document.createElement('p')
newP.innerHTML='this is newp'
//插入节点
div1.appendChild(newP)
//移动节点(已在DOM中的节点appendChild不会复制)
const oldp = document.getElementById('oldp')
div2.appendChild(oldp)
获取父元素,子元素列表
//获取父元素
const divl = document.getElementById('div1')
const parent = divl. parentNode
//获取子元素列表
const divl = document.getElementById('divl')
const child = div1.childNodes
const child=Array.prototype.slice.call(div1.childNodes).filter(child => {
if(child.nodeType === 1) return true;
return false;
})
删除子元素
div1.removeChild(child[0])
DOM 性能
DOM操作非常“昂贵”,避免频繁的DOM操作
对DOM查询做缓存
将频繁操作改为一次性操作
BOM
navigator
如何识别浏览器的类型
navigator.userAgent
screen
screen.width
screen.height
location
网址:location.href
协议:location.protocol
域名:location.host
协议+ 域名:location.origin
路径:location.pathname
参数:location.search
锚点:location.hash
history
后退:history.back
前进:history.forward
事件
事件绑定
const btn = doucument.getElementById('btn');
btn.setEventListener('click',e => {alert('click')})
// console.log(e.target)//获取触发的元素
// event.preventDefault()//阻止默认行为
事件冒泡
事件会传递给父元素
// e.stopPropagation() //阻止冒泡
事件代理
代码简洁
减少浏览器内存占用
但是,不要滥用
div.addEventListener('click', e => {
event.preventDefault();
const target = event.target
if(target.nodeName === 'A'){
alert(target.innerHTML)
}
})
编写一个通用的事件监听函数
// function bindEvent(ele, type, fn){
// ele.addEventListener(type,fn)
// }
function bindEvent(ele, type, selector, fn){
if(!fn){
fn = selector
selector = null
}
ele.addEventListener(type,e => {
const target = e.target
if(selector){
if(target.matches(selector)){
fn.call(target, e)
}
} else {
fn.call(target, e)
}
})
}
//普通绑定
bindEvent(btn, 'click', function(e) {
e.preventDefault();
alert(this.innerHTML)
})
//代理绑定
bindEvent(div, 'click', 'a', function(e) {
e.preventDefault();
alert(this.innerHTML)
})
描述事件冒泡的流程
基于DOM树形结构
事件会顺着触发元素往上冒泡
应用场景:代理
无限下拉的图片列表,如何监听每个图片的点击?
事件代理
用 e.target获取触发元素
用matches来判断是否是触发元素
ajax
XMLHttpRequest
xhr.readyState
0-UNSET尚未调用open方法
1-OPENED open方法已被调用
2-HEADERS_RECEIVED send方法已被调用,header已被接收
3-LOADING 下载中,responseText已有部分内容
4-DONE 下载完成
状态码
xhr.status
·2xx - 表示成功处理请求,如200
·3xx - 需要重定向,浏览器直接跳转,如301 302 304
·4xx - 客户端请求错误,如404 403
·5xx - 服务器端错误
手写一个简易的 ajax
function ajax(url: string) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText)
} else if (xhr.status === 404) {
reject(new Error('404NotFound'))
}
}
}
xhr.send(null)
})
}
跨域:同源策略,跨域解决方案
什么是跨域(同源策略)
ajax请求时,浏览器要求当前网页和server必须同源(安全)
同源:协议、域名、端口,三者必须一致
前端:http://a.com:8080/ server:https://b.com/api/xxx
**<img/>**可用于统计打点,可使用第三方统计服务
**<link/><script>**可使用CDN,CDN一般都是外域
**<script>**可实现JSONP
所有的跨域,都必须经过 server 端允许和配合
未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
JSONP
服务器可以返回任何内容
<script>可绕过跨域限制
服务器可以任意动态拼接数据返回
所以,<script>就可以获得跨域的数据,只要服务端愿意返回
CORS(服务端支持)
存储
cookie
本身用于浏览器和 server 通讯
被“借用”到本地存储来
可用 document.cookie = ... 来修改
cookie 的缺点
存储大小,最大4KB
http请求时需要发送到服务端,增加请求数据量
只能用 document.cookie = …来修改,太过简陋
localStorage 和 sessionStorage
HTML5专门为存储而设计,最大可存5M
API简单易用 setItem getItem
不会随着http请求被发送出去
localStorage 数据会永久存储,除非代码或手动删除
sessionStorage 数据只存在于当前会话,浏览器关闭则清空
一般用localStorage会更多一些
描述cookie localStorage sessionStorage 区别
容量
API易用性
是否跟随http请求发送出去
HTTP
前端工程师开发界面
需要调用后端的接口,提交/获取数据——http协议
要求事先掌握好ajax
http 状态码
状态码分类
1xx服务器收到请求
2xx请求成功,如200
3xx重定向,如302
4xx客户端错误,如404
5xx服务端错误,如500
常见状态码
200成功
301永久重定向(配合location,浏览器自动处理
302临时重定向(配合location,浏览器自动处理)
304资源未被修改
404资源未找到
403没有权限
500服务器错误
504网关超时
关于协议和规范
就是一个约定
要求大家都跟着执行
不要违反规范,例如IE浏览器
http methods
传统的methods
get获取服务器的数据
post像服务器提交数据
简单的网页功能,就这两个操作
现在的methods
get 获取数据
post 新建数据
patch/put更新数据
delete删除数据
Restful API
一种新的API设计方法(早已推广使用)
传统API设计:把每个url当做一个功能
Restful API设计:把每个url当做一个唯一的资源
如何设计成一个资源?
不用url参数
传统API设计:/api/list?pageIndex=2
Restful API设计:/api/list/2
用method表示操作类型
传统API设计
post请求/api/create-blog
post请求/api/update-blog?id=100
get请求/api/get-blog?id=100
Restful API设计
post请求/api/blog
patch 请求 /api/blog/100
get 请求 /api/blog/100
http headers
常见的 Request Headers
Accept 浏览器可接收的数据格式
Accept-Encoding浏览器可接收的压缩算法,如gzip
Accept-Languange 浏览器可接收的语言,如 zh-CN
Connection:keep-alive一次TCP连接重复使用
cookie
Host
User-Agent(简称UA)浏览器信息
Content-type 发送数据的格式,如 application/json
常见的 Response Headers
Content-type 返回数据的格式,如 application/json
Content-length 返回数据的大小,多少字节
Content-Encoding 返回数据的压缩算法,如 gzip
Set-Cookie
缓存相关的headers
Cache-Control Expires
Last-Modified If-Modified-Since
If-None-Match
Etag
http缓存
什么是缓存?
为什么需要缓存?
哪些资源可以被缓存?一静态资源(js css img)
强缓存与协商缓存
强缓存:
如果没有过期,浏览器可以直接使用该缓存而不需要重新向服务器请求
Expires 存在于响应头,为缓存过期时间点
Cache-Control 存在于响应头和请求头,为缓存过期时常
Cache-Control
Response Headers 中
控制强制缓存的逻辑
例如 Cache-Control:max-age=31536000(单位是秒)
max-age 过期时长
no-cache 不用强制缓存
no-store 不用任何缓存
private 只允许最终用户缓存
public 允许路由/代理缓存
Expires
同在 Response Headers 中
同为控制缓存过期
已被 Cache-Control 代替
协商缓存:
不能直接使用该缓存,始终向服务器询问是否需要更新
服务器端缓存策略
服务器判断客户端资源,是否和服务端资源一样
一致则返回304,否则返回200和最新的资源
在Response Headers中,有两种
Last-Modified 资源的最后修改时间
Etag 资源的唯一标识(一个字符串,类似人类的指纹)
版本
HTTP/0.9
只有一个命令GET
响应类型: 仅超文本
没有header等描述数据的信息
服务器发送完毕,就关闭TCP连接
HTTP/1.0
增加了很多命令(post HESD )
增加status code 和 header
多字符集支持、多部分发送、权限、缓存等
响应:不再只限于超文本 (Content-Type 头部提供了传输 HTML 之外文件的能力 — 如脚本、样式或媒体文件)
HTTP/1.1
持久连接。TCP三次握手会在任何连接被建立之前发生一次。最终,当发送了所有数据之后,服务器发送一个消息,表示不会再有更多数据向客户端发送了;则客户端才会关闭连接(断开 TCP)
支持的方法: GET , HEAD , POST , PUT ,DELETE , TRACE , OPTIONS
进行了重大的性能优化和特性增强,分块传输、压缩/解压、内容缓存磋商、虚拟主机(有单个IP地址的主机具有多个域名)、更快的响应,以及通过增加缓存节省了更多的带宽
HTTP2
所有数据以二进制传输。HTTP1.x是基于文本的,无法保证健壮性,HTTP2.0绝对使用新的二进制格式,方便且健壮
同一个连接里面发送多个请求不再需要按照顺序来
头信息压缩以及推送等提高效率的功能
HTTP3
QUIC“快速UDP互联网连接”(Quick UDP Internet Connections)
HTTP3 的主要改进在传输层上。传输层不会再有我前面提到的那些繁重的 TCP 连接了。现在,一切都会走 UDP。
HSTS
HTTP Strict Transport Security,简单说就是强制客户端使用 HTTPS 访问页面
原理:
在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age
用户访问时,服务器种下这个头
下次如果使用 http 访问,只要 max-age 未过期,客户端会进行内部跳转,可以看到 307 Redirect Internel 的响应码
变成 https 访问源服务器
HTTP协议特点
支持客户/服务器模式。
简单快速客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于 HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
TCP
TCP(Transmission Control Protocol)传输控制协议
TCP/IP协议将应用层、表示层、会话层合并为应用层,物理层和数据链路层合并为网络接口层
连接三次握手
第一次握手:主机A发送位码为SYN=1,随机产生Seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;(第一次握手,由浏览器发起,告诉服务器我要发送请求了)
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),SUN=1,ACK=1234567 + 1,随机产生Seq=7654321的包;(第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧)
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码SYN是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=7654321 + 1,主机B收到后确认Seq值与ACK=7654321+ 1则连接建立成功;(第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧)
断开四次分手
刚开始双方都处于established状态,假如是客户端先发起关闭请求
第一次挥手:客户端发送一个FIN报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态
第二次挥手:服务端收到FIN之后,会发送ACK报文,且把客户端的序列号值+1作为ACK报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT状态
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送FIN报文,且指定一个序列号。此时服务端处于LAST_ACK的状态
需要过一阵子以确保服务端收到自己的ACK报文之后才会进入CLOSED状态,服务端收到ACK报文之后,就处于关闭连接了,处于CLOSED状态。
开发环境
git
常用git命令
git add . 添加
git checkout xxx 还原
git commit - m " xxx " 提交
git push origin master 推送
git pull origin master 拉去
git branch 分支
git checkout -b xxx 新建分支 / git checkout XXX 切换分支
git merge xxx 合并分支
git stash 暂存 git stash pop 恢复暂存
抓包
移动端h5页,查看网络请求,需要用工具抓包
windows 一般用 fiddler
Mac OS 一般用 charles
webpack babel
ES6模块化,浏览器暂不支持
ES6语法,浏览器并不完全支持
压缩代码,整合代码,以让网页加载更快
运行环境
运行环境即浏览器(server端有nodejs)
下载网页代码,渲染出页面,期间会执行若干JS
要保证代码在浏览器中:稳定且高效
网页加载过程
加载资源的形式
html代码
媒体文件,如图片、视频等
javascript css
加载过程
DNS解析:域名->IP地址
浏览器根据IP地址向服务器发起http请求
服务器处理http请求,并返回给浏览器
渲染过程
根据HTML代码生成DOM Tree
根据CSS代码生成CSSOM
将DOM Tree和CSSOM整合行程Render Tree
根据Render Tree 渲染页面
遇到<script>则暂停渲染,优先加载并执行JS代码,完成再继续
直至把 Render Tree 渲染完成
页面渲染
HTML生成DOM树,CSS生成对象模型(CSSDOM)
DOM树与CSSDOM合并生成渲染树
浏览器根据渲染树计算后生成布局树Layout Tree
最后将画面绘制到屏幕上
window.onload 和 DOMContentLoaded 区别
window.onload资源全部加载完才能执行,包括图片
DOMContentLoaded DOM 渲染完成即可,图片可能尚未下载
性能优化
是一个综合性问题,没有标准答案,但要求尽量全面
某些细节问题可能会单独提问:手写防抖、节流
性能优化原则
多使用内存、缓存或其他方法
减少CPU计算量,减少网络加载耗时
(适用于所有编程的性能优化——空间换时间)
让加载更快
减少资源体积:压缩代码
减少访问次数:合并代码,SSR服务器端渲染,缓存
使用更快的网络:CDN
缓存
静态资源加 hash 后缀,根据文件内容计算 hash
文件内容不变,则hash不变,则url不变
url和文件不变,则会自动触发http缓存机制,返回304
SSR
服务器端渲染:将网页和数据一起加载,一起渲染
非SSR(前后端分离):先加载网页,再加载数据,再渲染数据
早先的JSP ASP PHP,现在的vue React SSR
让渲染更快
CSS 放在 head ,JS 放在 body 最下面
尽早开始执行JS,用DOMContentLoaded触发
懒加载(图片懒加载,上滑加载更多)
对DOM查询进行缓存
频繁DOM操作,合并到一起插入DOM结构
节流 throttle 防抖 debounce
const p = document.getElementsByTagName('p');
防抖 debounce
监听一个输入框的,文字变化后触发change事件
直接用keyup事件,则会频发触发change事件
防抖:用户输入结束或暂停时,才会触发change事件
const debounce = (fn: Function, delay: number = 500): EventListener => {
let timer: NodeJS.Timeout;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
//@ts-ignore
fn.apply(this, arguments);
}, delay)
}
}
p[0].addEventListener('click', debounce(function () {
console.log(p[0]);
}, 600))
节流 throttle
拖拽一个元素时,要随时拿到该元素被拖拽的位置
直接用drag事件,则会频发触发,很容易导致卡顿
节流:无论拖拽速度多快,都会每隔100ms触发一次
const throttle = (fn: Function, delay: number = 100): EventListener => {
let timer: NodeJS.Timeout | null = null;
return function () {
if (timer) return;
timer = setTimeout(() => {
//@ts-ignore
fn.apply(this, arguments);
timer = null;
}, delay)
}
}
p[0].addEventListener('drag', throttle(
function (e: any) {
console.log(e.offsetX, e.offsetY)
}, 500)
);
浏览器
URL
协议://主(ex.com)机:端口/路(a/b)径 ?查询(k=v&k=v)参数#锚点
DNS
从域名获取IP地址
根域名服务器,顶级域名服务器,主域名服务器
递归查询
客户端只发一次请求,要求对方给出最终结果。
浏览器缓存,系统缓存,路由器缓存,ISP(运营商)DNS缓存:统称为DNS高速缓存
若当前DNS服务器没有,则服务器会继续向其他DNS服务器查询
迭代查询
客户端发出一次请求,对方如果没有授权回答,它就会返回一个能解答这个查询的其它名称服务器列表,客户端会再向返回的列表中发出请求,直到找到最终负责所查域名的名称服务器,从它得到最终结果。
当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:“你下一步应当向哪一个域名服务器进行查询”。
安全
XSS跨站请求攻击
一个博客网站,我发表一篇博客,其中嵌入<script>脚本
脚本内容:获取cookie,发送到我的服务器(服务器配合跨域)
发布这篇博客,有人查看它,窃取访问者的cookie
XSS 预防(xss 工具)
替换特殊字符,如<变为<>变为>
<script>变为 &lt;script&gt;,直接显示,而不会作为脚本执行
前端要替换,后端也要替换,都做总不会有错
XSRF跨站请求伪造
你正在购物,看中了某个商品,商品id是100
付费接口是xxx.com/pay?id=100,但没有任何验证
我是攻击者,我看中了一个商品,id是200
我向你发送一封电子邮件,邮件标题很吸引人
但邮件正文隐藏着<img src=xxx.com/pay?id=200/>
你一查看邮件,就帮我购买了id是200的商品
XSRF 预防
使用post接口
增加验证,例如密码、短信验证码、指纹等
Read More ~
JAVA+WindowBuilder+MySQL实现饭店管理系统
本项目为我的大二课程设计项目,仅供学习使用!
目 录
1 项目概述... 1
2 需求分析... 2
2.1 总体目标... 2
2.2 具体目标... 2
2.3 系统功能建模... 2
2.3.1 系统数据流程图... 2
2.3.2 数据字典... 3
2.4 系统数据模型... 4
3 概要设计... 6
3.1 体系结构设计... 6
3.2 数据库设计... 6
3.2.1 关系模式设计... 6
3.2.2 物理表结构设计... 7
4 详细设计... 10
4.1 登录模块... 10
4.2 点餐模块... 11
5 系统实现... 12
5.1 实现技术... 12
5.2 应用程序配置... 12
5.3 业务逻辑代码... 12
5.4 数据库代码... 23
6 结束语... 29
7 参考文献... 30
1 项目概述
本项目是一个饭店管理系统。
主要实现了用户的登录,开台,点餐,结算等功能。
管理端实现了订单管理,餐台管理,用户管理和菜品管理。
可以利用本系统对餐厅,饭店的点餐,订单和菜品进行系统的管理,提升饭店餐厅的管理效率。
主程序和GUI:使用IDEA开发的JAVA程序
数据库:使用Navicat管理的MySQL数据库
连接:使用JDBC驱动进行数据库与Java程序连接
2 需求分析
2.1 总体目标
系统目标:
1.窗体界面设计友好、美观
2.基本信息管理方便、快捷
3.具有良好的数据查询功能,方便管理员和用户的操作
4.系统运行稳定、系统数据安全可靠
5.最大限度地实现系统的易维护性和易操作性
2.2 具体目标
具体目标:
1.登录:输入账户名和密码,进行登录。
2.基本信息管理:用户管理,餐台管理,菜品分类管理,菜品管理。
3.点餐管理:点餐(开台点餐,点餐信息增删改查)
4.结算管理:结算,结算后餐台空闲
5.统计查询:菜品销售查询,收入统计
2.3 系统功能建模
2.3.1 系统数据流程图
详细数据流图如图2-1所示。
图 2‑1
此DFD图有两个接口,分别是用户和管理员
用户输出:订座信息,点餐信息,付款信息
管理员输出:用户管理信息,菜品变动信息,餐台管理信息,订单管理信息
用户收到:餐台信息,菜品信息,发票信息,用户状态信息
管理员收到:销售数据
2.3.2 数据字典
数据字典如图 2-2所示。
图 2‑2
主要数据有:用户信息、管理员信息,菜品信息,餐台信息,菜单信息
这些数据分别存储于用户数据库、管理员数据库、菜品数据库、餐台数据库、菜单数据库
2.4 系统数据模型
系统数据模型,即E-R图,如图 2-3所示。
图 2‑3
实体有:用户,订单,菜单,菜品,餐台,管理员
实体关系:
用户-点餐-订单:一对多
订单-占用-餐台:一对一
订单-关联-菜单:一对多
菜单-包含-菜品:多对多
管理员-处理-餐台/菜单:三实体多对多
3 概要设计
3.1 体系结构设计
系统功能模块图如图 3-1所示。
图 3‑1
饭店管理系统分用户和管理员两个模块。
用户模块中又包含订座、点餐、结账三个模块;
前两个对应了餐台选择和菜品选择模块。
管理员模块中包含用户管理,菜品管理和订单管理模块
分别包含注册、删除;菜品、库存增删;订单取消、删除模块。
3.2 数据库设计
3.2.1 关系模式设计
User (UID, UName, Password, Tele, Point)
Admin (AID, AName, Password, Tele)
Order (OID, SID, OMID, Note, Price, isPay)
OrderMenu (OMID, OID, FID)
Seat (SID, Anum,State)
Food (FID, FName, Class, Price, Inventory)
3.2.2 物理表结构设计
管理员设计参数见表 3-1所示。
表 3‑1 管理员表
列含义
列标示
类型
长度
完整性约束
管理员ID
AID
Int
2
主键
管理员名
AName
Varchar
20
非空
密码
Password
Varchar
30
非空
电话
Tele
Char
11
用户设计参数见表 3-2所示。
表 3‑2 用户表
列含义
列标示
类型
长度
完整性约束
用户ID
UID
Int
10
主键
用户名
UName
Varchar
20
非空
密码
Password
Varchar
30
非空
电话
Tele
Char
11
积分
Point
Int
225
餐台设计参数见表 3-3所示。
表 3‑3 餐台表
列含义
列标示
类型
长度
完整性约束
餐台号
SID
Int
3
主键
座位数
Anum
Int
2
非空
是否空闲
State
Int
1
非空
菜品设计参数见表 3-4所示。
表 3‑4 菜品表
列含义
列标示
类型
长度
完整性约束
菜品ID
FID
Int
4
主键
菜品名
FName
Varchar
20
非空
类别
Class
Varchar
20
价格
Price
Decimal
5-2
库存
Inventory
Int
5
订单设计参数见表 3-5所示。
表 3‑5 订单表
列含义
列标示
类型
长度
完整性约束
订单号
OID
Int
10
主键
备注
Note
Varchar
225
价格
Price
Decimal
10-2
付款状态
isPay
Int
1
非空
座位号
SID
Int
3
外键
菜单设计参数见表 3-6所示。
表 3‑6 菜单表
列含义
列标示
类型
长度
完整性约束
菜号
OMID
Int
10
主键
订单号
OID
Int
10
外键
菜品号
FID
Int
4
外键
4 详细设计
4.1 登录模块
登录模块如图 4-1所示。
图 4‑1
在登录时,先判断是否为管理员,若为管理员,直接进行登录验证,否则调用用户管理系统操作。输入账号密码时,先后判断是否为空,账号是否存在,密码是否对应。当都通过时,登录成功,否则重新输入。
4.2 点餐模块
点餐模块如图 4-2所示。
图 4‑2
点餐时,先查看并选择数据库中的菜品,然后将菜品添加到清单中,进行确认订单后,将清单信息更新到订单数据库
5 系统实现
5.1 实现技术
使用Ecilpse + WindowBuilder进行GUI和JAVA程序的开发
使用Navicat对MYSQL数据库进行管理
5.2 应用程序配置
JAVASE 1.7的开发及运行环境
MYSQL数据库版本为5.7.33
5.1.47的JDBC驱动进行JAVA程序和数据库的连接
5.3 业务逻辑代码
Hms.model:
*LoginContrl.Java*
//登录控制
package hms.model;
import java.sql.*;
import hms.util.DBUtil;
public class LoginControl {
public static boolean isAdmin;
public static int id;
//验证密码
public static boolean LoginCheck(boolean isAdmin, int id, String password) throws ClassNotFoundException, SQLException {
String SQL = "SELECT password FROM ";
if (!isAdmin) {
SQL = SQL + "user where uid = " + id;
} else {
isAdmin = true;
SQL = SQL + "admin where aid = " + id;
}
ResultSet resultSet = DBUtil.query(SQL);
if (!resultSet.next()) {
try {
DBUtil.closeConnection();
} catch (Exception e) {
e.printStackTrace();
}
return false;
} else if (!resultSet.getObject("password").equals(password)) {
try {
DBUtil.closeConnection();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
try {
DBUtil.closeConnection();
} catch (Exception e) {
e.printStackTrace();
}
LoginControl.id = id;
try {
ReadInformation();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("\nSucesss!\nisAdmin:" + isAdmin + "\nid:" + LoginControl.id);
return true;
}
//信息读入
public static void ReadInformation() throws Exception {
if (isAdmin) {
} else {
User.userInformationRead(id);
}
}
}
*Seat.Java*
//餐台管理
package hms.model;
import java.sql.*;
import hms.util.DBUtil;
public class Seat {
public static int[] SID = new int[100];
public static int[] Anum = new int[100];
public static int[] State = new int[100];
public static int USID;
public static int UAnum;
//座位获取
public static void getSeats() throws Exception {
String SQL = "SELECT * FROM seat";
ResultSet resultSet = DBUtil.query(SQL);
for (int i = 1; resultSet.next(); i++) {
SID[i] = resultSet.getInt("SID");
Anum[i] = resultSet.getInt("Anum");
State[i] = resultSet.getInt("State");
}
DBUtil.closeConnection();
}
//剩余座位量获取
public static int remainingSeats(int Anum) throws Exception {
int num = 0;
String SQL = "SELECT * FROM seat where Anum =";
SQL = SQL + " " + Anum;
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
if(resultSet.getInt("State") == 0) {
num++;
}
}
DBUtil.closeConnection();
return num;
}
//确认座位
public static boolean SeatConfirm() throws Exception {
String SQL = "SELECT * FROM seat WHERE Anum = ";
SQL = SQL + UAnum + " AND State = 0";
ResultSet resultSet = DBUtil.query(SQL);
resultSet.next();
try {
USID = resultSet.getInt("SID");
} catch (Exception e) {
return false;
}
String SQL2 = "UPDATE seat SET State = 1 WHERE SID = ";
SQL2 = SQL2 + USID;
DBUtil.update(SQL2);
DBUtil.closeConnection();
return true;
}
//座位状态更改
public static void StateChange(int State,int SID) throws Exception {
String SQL = "UPDATE seat SET State = ";
SQL = SQL + State +" WHERE SID = "+ SID;
DBUtil.update(SQL);
DBUtil.closeConnection();
}
}
*Food.Java*
//菜品管理
package hms.model;
import java.sql.ResultSet;
import javax.swing.ImageIcon;
import hms.util.DBUtil;
import hms.view.OrderFrame;
public class Food {
//菜名获取
public static String[] getFoodsName(String Class) throws Exception {
String[] list = new String[20];
String SQL = "SELECT FName FROM Food WHERE Class like '";
SQL = SQL + Class +"'";
ResultSet resultSet = DBUtil.query(SQL);
for (int i = 0; resultSet.next(); i++) {
list[i] = resultSet.getString("FName");
}
DBUtil.closeConnection();
return list;
}
//菜品图片读入
public static ImageIcon getIcon(int FID) {
try {
ImageIcon testtt = new ImageIcon(OrderFrame.class.getResource("/img/" + FID + ".jpg"));
} catch (Exception e) {
return null;
}
ImageIcon icon = new ImageIcon(OrderFrame.class.getResource("/img/" + FID + ".jpg"));
return icon;
}
public static int CFid = 1;
public static String CFName = "红烧肉";
public static float CFPrice = (float) 18.00;
public static int CFInventory = 35;
public static int allPrice = 0;
//菜品选择
public static void foodChoose(String FName) throws Exception {
String SQL = "SELECT * FROM Food WHERE FName like '";
SQL = SQL + FName +"'";
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
CFid = resultSet.getInt("FID");
CFName = resultSet.getString("FName");
CFPrice = resultSet.getInt("Price");
CFInventory = resultSet.getInt("Inventory");
}
DBUtil.closeConnection();
}
public static String[] orderStrings = new String[20];
public static int listNum = 0;
//菜单添加菜品
public static void addFood() {
orderStrings[listNum] = CFName;
listNum++;
allPrice += CFPrice;
}
}
*Order.Java*
//订单管理
package hms.model;
import java.sql.ResultSet;
import hms.util.DBUtil;
public class Order {
public static int OID;
//创建订单
public static void creatOrder() throws Exception {
int lastOID = 0;
String SQL = "SELECT OID FROM order ORDER BY OID";
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
lastOID = resultSet.getInt(1);
}
DBUtil.closeConnection();
System.out.println(lastOID);
OID = lastOID + 1;
String SQL2 = "INSERT INTO order (OID,isPay,SID) VALUES ('";
SQL2 = SQL2 + OID + "','0','" + Seat.USID + "')";
DBUtil.update(SQL2);
DBUtil.closeConnection();
}
public static int OMID;
//上传订单和菜单
public static void updateOrder() throws Exception {
int lastOMID = 0;
String SQL = "SELECT OMID FROM ordermenu ORDER BY OMID";
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
lastOMID = resultSet.getInt(1);
}
DBUtil.closeConnection();
System.out.println(lastOMID);
OMID = lastOMID + 1;
for (int i = 0; Food.orderStrings[i] != null; i++) {
int FID = 0;
String SQL3 = "SELECT FID FROM Food WHERE FName like '";
SQL3 = SQL3 + Food.orderStrings[i] + "'";
ResultSet resultSet2 = DBUtil.query(SQL3);
while (resultSet2.next()) {
FID = resultSet2.getInt("FID");
}
String SQL2 = "INSERT INTO ordermenu (OMID,FID,OID) VALUES ('";
SQL2 = SQL2 + OMID + "','" + FID + "','" + OID + "')";
DBUtil.update(SQL2);
OMID++;
DBUtil.closeConnection();
}
String SQL4 = "UPDATE order SET Price =";
SQL4 = SQL4 + Food.allPrice + " WHERE OID = " + OID;
DBUtil.update(SQL4);
DBUtil.closeConnection();
}
//结算处理
public static void payDeal() throws Exception {
String SQL = "UPDATE order SET isPay = 1 WHERE OID = ";
SQL = SQL + OID;
DBUtil.update(SQL);
DBUtil.closeConnection();
String SQL2 = "UPDATE user SET Point = Point + ";
SQL2 = SQL2 + Food.allPrice + " WHERE UID = " + User.UID;
DBUtil.update(SQL2);
DBUtil.closeConnection();
}
//根据订单号获取座位号
public static int getSID(int OID) throws Exception {
int SID = 0;
String SQL = "SELECT SID FROM order where OID = ";
SQL = SQL + OID;
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
SID = resultSet.getInt(1);
}
return SID;
}
//订单删除
public static void OrderDelet(int OID) throws Exception {
String SQL = "DELETE FROM order WHERE OID = ";
SQL = SQL + OID;
DBUtil.update(SQL);
DBUtil.closeConnection();
}
//获取总营业额
public static float getTotalTurnover() throws Exception {
float TotalTurnover = 0;
String SQL = "SELECT Price From order";
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
TotalTurnover += resultSet.getFloat(1);
}
return TotalTurnover;
}
//获取总销量
public static int getTotalSales() throws Exception {
int TotalSales = 0;
String SQL = "SELECT OMID From ordermenu";
ResultSet resultSet = DBUtil.query(SQL);
while (resultSet.next()) {
TotalSales++;
}
return TotalSales;
}
}
5.4 数据库代码
Hms.util
*DBUtil.Java*
//数据库连接与操作的抽象
package hms.util;
import java.sql.*;
public class DBUtil {
public static final String DBDRIVER = "com.mysql.jdbc.Driver";
public static final String DBURL = "jdbc:mysql://localhost:3306/resmsc?useSSL=false&useUnicode=true&characterEncoding=UTF-8";
public static final String DBUSER = "LNTU_DDC";
public static final String DBPASS = "jtcsm";
public static Connection connection = null;
//获取并返回连接
public static Connection getConnection() throws ClassNotFoundException, SQLException {
Connection con = null;
try {
Class.forName(DBDRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("connect to db");
return con;
}
//数据库查找
public static ResultSet query(String sql) throws ClassNotFoundException, SQLException {
connection = getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
return resultSet;
}
//数据库更新
public static int update(String sql) throws ClassNotFoundException, SQLException {
connection = getConnection();
Statement statement = connection.createStatement();
int UpdateLine = statement.executeUpdate(sql);
return UpdateLine;
}
//关闭连接
public static void closeConnection() throws Exception {
connection.close();
}
}
SQL****建表语句
Admin
DROP TABLE IF EXISTS admin;
CREATE TABLE admin (
AID int(2) NOT NULL,
AName varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
Password varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
Tele char(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (AID) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Food
DROP TABLE IF EXISTS food;
CREATE TABLE food (
FID int(4) NOT NULL,
FName varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
Class varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
Price decimal(5, 2) NULL DEFAULT NULL,
Inventory int(5) NULL DEFAULT NULL,
PRIMARY KEY (FID) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Order
DROP TABLE IF EXISTS order;
CREATE TABLE order (
OID int(10) NOT NULL,
Note varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
Price decimal(10, 2) NULL DEFAULT NULL,
isPay int(1) NOT NULL,
SID int(3) NULL DEFAULT NULL,
PRIMARY KEY (OID) USING BTREE,
INDEX SID(SID) USING BTREE,
CONSTRAINT SID FOREIGN KEY (SID) REFERENCES seat (SID) ON DELETE SET NULL ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Ordermenu
DROP TABLE IF EXISTS ordermenu;
CREATE TABLE ordermenu (
OMID int(10) NOT NULL,
FID int(4) NULL DEFAULT NULL,
OID int(10) NULL DEFAULT NULL,
PRIMARY KEY (OMID) USING BTREE,
INDEX FID(FID) USING BTREE,
INDEX OID(OID) USING BTREE,
CONSTRAINT FID FOREIGN KEY (FID) REFERENCES food (FID) ON DELETE SET NULL ON UPDATE RESTRICT,
CONSTRAINT OID FOREIGN KEY (OID) REFERENCES order (OID) ON DELETE SET NULL ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Seat
DROP TABLE IF EXISTS seat;
CREATE TABLE seat (
SID int(3) NOT NULL,
Anum int(2) NOT NULL,
State int(1) NOT NULL,
PRIMARY KEY (SID) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
User
DROP TABLE IF EXISTS user;
CREATE TABLE user (
UID int(10) NOT NULL,
UName varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
Password varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
Tele char(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
Point int(20) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (UID) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
6 结束语
此次开发使我能够熟练的使用WindowBuilder进行GUI窗口设计,能够熟练的使用面向对象的思想进行Java程序的开发,并且学会了JDBC能够使用JAVA程序对数据库进行增删改查,还加强了对SQL语句的熟练程度,能够快速的对数据库进行操作。
我所开发的饭店管理系统以对用户端的体验为开发方向着重开发,当用户进行点餐时,仅仅进行单击操作就可以完整的进行选座,选餐,支付这一整套就餐步骤,极大的提升了用户体验;但由于时间关系在管理端还存在未开发完毕的功能,在时间充沛的情况下我会进行改进,并且以后提高自己的开发速度以避免再次出现这种情况。
7 参考文献
[1]张海藩,牟永敏. 软件工程导论[M] .北京.清华大学出版社. 2013(06)
[2]耿祥义,张跃平. Java程序设计精编教程[M] .北京.清华大学出版社. 2017(03)
[3]王珊,萨师煊. 数据库系统概论[M].北京.高等教育出版社. 2014(05)
[4] 张英,杜炜. JDBC数据库连接池技术简介及设计[J]. 电脑知识与技术. 2010 (08)
[6] 赵海龙,戴玉刚. JDBC驱动程序及其选择分析[J]. 福建电脑. 2008 (02)
[7] 罗荣,唐学兵. 基于JDBC的数据库连接池的设计与实现[J]. 计算机工程. 2004 (09)
[8] 何明,戴钢,葛正义. 基于JDBC语句分享的数据库连接池[J]. 铁路计算机应用. 2002 (11)
[9] 张廷玉,石伟伟. 基于JDBC的WebGIS异构数据库存取技术[J]. 测绘通报. 2000 (01)
[10] 谢人强. 选用合适的JDBC驱动程序[J]. 电脑知识与技术(学术交流). 2007 (02)
[11] 孙国志. 面向软件工程的工作流管理系统研究[J]. 企业技术开发. 2014 (11)
Read More ~
在deepin中使用code::blocks
记一次无用的折腾
记一次西西批西区域赛
封装一张纸条->ac一道题
什么嘛,我还是蛮不错的嘛
Read More ~
针不戳
住在山里针不戳
Read More ~