Vue 编码基础
2.1.1. 组件规范
2.1.2. 模板中使用简单的表达式
2.1.3 指令都使用缩写形式
2.1.4 标签顺序保持一致
2.1.5 必须为 v-for 设置键值 key
2.1.6 v-show 与 v-if 选择
2.1.7 script 标签内部结构顺序
2.1.8 Vue Router 规范
Vue 项目目录规范
2.2.1 基础
2.2.2 使用 Vue-cli 脚手架
2.2.3 目录说明
2.2.4注释说明
2.2.5 其他
开源分享:docs.qq.com/doc/DSmRnRG…
const val = await updateBlog(ctx.query.id, ctx.request.body)
if (val) {
ctx.body = new SuccessModel()
} else {
ctx.body = new ErrorModel('更新博客失败')
}
})
router.post('/del', loginCheck, async function (ctx, next) {
const author = ctx.session.username
const val = await delBlog(ctx.query.id, author)
if (val) {
ctx.body = new SuccessModel()
} else {
ctx.body = new ErrorModel('删除博客失败')
}
})
module.exports = router
3. 新建模型
首先解释一下SuccessModel和ErrorModel , 作用主要是供全局返回信息使用的。如登陆成功或者失败返回的标志位及提示信息
class BaseModel{
constructor(data,message){
if(typeof data === 'string'){
this.message = data
data = null
message = null
}
if(data){
this.data = data
}
if(message){
this.message = message
}
}
}
class SuccessModel extends BaseModel{
constructor(data,message){
super(data,message)
this.errno = 0
}
}
class ErrorModel extends BaseModel{
constructor(data,message){
super(data,message)
this.errno = -1
}
}
module.exports = {
SuccessModel,
ErrorModel
}
4. 中间件开发
登陆校验的中间件 loginCheck
其实就是检查 session 中是否存有用户名的信息(信息在登陆成功时写进 session)
const { ErrorModel } = require('../model/resModel')
module.exports = async (ctx, next) => {
if (ctx.session.username) {
await next()
return
}
ctx.body = new ErrorModel('未登录')
}
5. 控制层开发
接下来就讲一下控制层的实现,主要是连接数据库的sql语句来实现数据的交互
const xss = require('xss')
const { exec } = require('../db/mysql')
const getList = async (author, keyword) => {
let sql = select * from blogs where 1=1
if (author) {
sql += and author='${author}'
}
if (keyword) {
sql += and title like '%${keyword}%'
}
sql += order by createtime desc;
return await exec(sql)
}
const getDetail = async (id) => {
const sql = select * from blogs where id='${id}'
const rows = await exec(sql)
return rows[0]
}
const newBlog = async (blogData = {}) => {
// blogData 是一个博客对象,包含 title content author 属性
const title = xss(blogData.title)
const content = xss(blogData.content)
const author = blogData.author
const createTime = Date.now()
const sql = `
insert into blogs (title, content, createtime, author)
values ('{content}', {author}');
`
const insertData = await exec(sql)
return {
id: insertData.insertId
}
}
const updateBlog = async (id, blogData = {}) => {
// id 就是要更新博客的 id
// blogData 是一个博客对象,包含 title content 属性
const title = xss(blogData.title)
const content = xss(blogData.content)
const sql = `
update blogs set title='{content}' where id=${id}
`
const updateData = await exec(sql)
if (updateData.affectedRows > 0) {
return true
}
return false
}
const delBlog = async (id, author) => {
// id 就是要删除博客的 id
const sql = delete from blogs where id='${id}' and author='${author}';
const delData = await exec(sql)
if (delData.affectedRows > 0) {
return true
}
return false
}
module.exports = {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
}
5. 连接数据库
说明一下 exec函数其实就是数据库查询的函数
const mysql = require('mysql')
const { MYSQL_CONF } = require('../conf/db')
//创建链接对象
const con = mysql.createConnection(MYSQL_CONF)
//开始连接
con.connect()
//统一执行sql函数
function exec(sql) {
const promise = new Promise((resolve, reject) => {
con.query(sql, (err, result) => {
if (err) {
reject(err)
return
}
resolve(result);
})
})
return promise
}
module.exports = {
exec,
escape:mysql.escape
}
连接 mysql 的具体配置,分为生产环境和开发环境
const env = process.env.NODE_ENV //获取环境变量
let MYSQL_CONF
if (env === 'dev') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
port: 3306,
password: 'password',
database: 'myblog'
}
}
if (env === 'production') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
port: 3306,
password: 'password',
database: 'myblog'
}
}
module.exports = {
MYSQL_CONF
}
1. sql 注入
const sql = select username,realname from users where username=${username} andpassword=${password};
首先我们看一下 sql 的数据库查询,要是用户名输入 zhangsan' --就会把后面的密码注释了(也就是说不用密码就可以登陆)
解决方式是使用 mysql:escape进行转义
2. xss攻击
比如新建博客的时候可能会输入 <script>alert(1)</script>的形式,就会造成xss攻击,解决方式就是转义字符(如<,>等基本可以避免攻击)
const newBlog = async (blogData = {}) => {
// blogData 是一个博客对象,包含 title content author 属性
const title = xss(blogData.title)
const content = xss(blogData.content)
const author = blogData.author
const createTime = Date.now()
const sql = `
insert into blogs (title, content, createtime, author)
values ('{content}', {author}');
`
const insertData = await exec(sql)
return {
id: insertData.insertId
}
}
利用node的文件流,创建一个写文件流,并把它记录到本地文件当中
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(${ctx.method} ${ctx.url} - ${ms}ms)
})
const ENV = process.env.NODE_ENV
//记录日志
if (ENV !== 'production') {
app.use(morgan('dev'));
} else {
const logFileName = path.resolve(__dirname, 'logs', 'access.log')
const writeStream = fs.createWriteStream(logFileName, {
flags: 'a'
})
app.use(morgan('combined', {
stream: writeStream
}));
}
const http = require('http')
// 组合中间件
function compose(middlewareList) {
return function (ctx) {
// 中间件调用
function dispatch(i) {
const fn = middlewareList[i]
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i+1)))
} catch(err) {
return Promise.reject(err)
}
}
return dispatch(0)
}
}
class LikeKoa2 {
constructor() {
this.middlewareList = []
}
use(fn) {
this.middlewareList.push(fn)
return this
}
createCtx(req, res) {
const ctx = {
req,
res
}
return ctx
}
handleRequest(ctx, fn) {
return fn(ctx)
}
callback() {
const fn = compose(this.middlewareList)
return (req, res) => {
const ctx = this.createCtx(req, res)
return this.handleRequest(ctx, fn)
}
}
lsiten(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】