Cette fois, je vais vous apporter node+koa2+mysql+bootstrap pour construire le front et le back end du forum. Quelles sont les précautions pour construire le front et le back end. du forum avec node+koa2+mysql+bootstrap, comme suit C'est un cas pratique, jetons-y un œil.
Tutoriels vidéo mysql recommandés : "tutoriel mysql"
Avant-propos
Après avoir appris koa2 et express Après avoir écrit quelques démos, je prévois d'écrire moi-même un projet pour mettre en pratique mes compétences. Comme je suis étudiant, je n'ai pas de bons projets à faire, j'ai donc pour objectif de développer un forum front-end. Les exigences fonctionnelles sont formulées avec référence. à certaines communautés. Les principales sont :
Se connecter et s'inscrire
Maintenance des informations personnelles, avatar et autres informations de base
Publier des articles, le L'éditeur de texte enrichi utilise le plug-in wangEditor, modifie, supprime des articles, la classification des articles, etc. 🎜>
Suivez et ne plus suivre les utilisateursTéléchargez et partagez des ressources (fichiers), Téléchargez et consultez Ressources d'apprentissage recommandées...Journal personnel de l'auteurmais. . . . Pour diverses raisons, seules certaines fonctions ont été implémentées jusqu'à présent et le partage des ressources n'a pas encore été écrit Effet de fonctionnement du projet : http://120.77.211.212/homePile technologique du projet application : node-koa2- ejs-bootstrap3—jquery, adresse github : https://github.com/Jay214/myblog-koa2 Si vous le trouvez utile ou si vous pouvez toujours le lire, veuillez mettre une étoile ~~ pour encourager mon front-. fin salaud.
Environnement de développement
nœud : v8.3.0koa : ^2.4.1
mysql : 5.7.1npm : 5.3.0 et supérieurComment exécuter le projet
Cloner le projet sur un clone git local git@github.com:Jay214/myblog -koa2 .gitInstaller le module middleware npm install
Installer mysql
Il est recommandé que la version mysql soit inférieure à 5.7, 5.7 a un bug, graphique L'interface recommande d'utiliser navicat pour MySQLpour exécuter et installer le superviseur (outil d'exécution du projet npm install superviseur, il sera en mode surveillance après ouverture, modifiez simplement le fichier et enregistrez-le, pas besoin de redémarrer le projet ) index de nœud ou index de superviseur npm
localhost:8080/home Le numéro de port peut être modifié par vous-mêmeSi vous trouvez des bugs dans le projet ou avez de meilleures suggestions, n'hésitez pas à faire suggestions, qq: 2752402930.Préparation
Puisque koa2 est basé sur la promesse d'es6 et la syntaxe wait/async d'es7, si vous ne comprenez pas es6/es7, veuillez d'abord lire le document Building. la base de données en arrière-plan est la clé, veuillez donc d'abord installer MySQL. Il est recommandé d'installer MySQL sous la version 5.7, car la version 5.7.0 a un bogue et le fichier de configuration doit être modifié. Vous connaîtrez les détails lors de l'installation. il.Installez l'environnement de nœud et utilisez node -v pour vérifier la version du nœud. Node a besoin d'une version plus récente pour prendre en charge la promesse d'es6 et la syntaxe wait/async d'es7. Désormais, la version du nœud sera livrée avec npm, il n'est donc pas nécessaire d'y aller.
Structure du projet
1.config stocke le fichier par défaut (configuration de la connexion à la base de données)
2.lib stocke le fichier de base de données
3.middlewares stocke le middleware qui détermine s'il faut se connecter et s'inscrire ou non4.public stocke les fichiers statiques, js, les références au framework bootstrap et d'autres fichiers5.routers stocke le fichier d'itinéraires6.views stocke les fichiers modèles7.index est le fichier principal du programme, définissant les interfaces, les interfaces de base de données, les modules de référence, etc.Fichiers de configuration du projet 8.package.json, y compris le nom du projet, l'auteur, les dépendances, les modules, etc. Le projet est développé avec vscode Il est très confortable à utiliser si vous l'avez. Je ne l'ai pas encore essayé, allez-y et essayez-le. Initialisation du projet : cd myblog1 -> npm init Le fichier package.json a été créé à ce moment. Étant donné que koa2 est un framework léger, petit et compact, afin de favoriser l'efficacité et la commodité de notre développement, nous devons installer un middleware de module koa2 :
npm install i koa koa-bodyparser koa-mysql-session koa-router koa-session-minimal koa-static koa-views md5 moment mysql ejs koa-static-cache --save-dev
Utilisation de chaque module
koa node framework
koa-bodyparser form parsing middleware
koa-mysql-session, koa -Middleware minimal de session pour le traitement des bases de données
Middleware de routage koa-router
Middleware de chargement de ressources statiques koa-static
Moteur de modèles ejs
Cryptage de mot de passe md5
middleware momentané
base de données mysql
middleware de rendu de modèle koa-views
cache de fichiers koa-static-cache
Construire le framework de base du projet
Configuration de la connexion à la base de données
Créez un nouveau default.js dans le dossier config :
const config = { //启动端口 port: 8080, //数据库配置 database: { DATABASE: 'nodesql', USERNAME: 'root', PASSWORD: '123456', PORT: '3306', HOST: 'localhost' } } module.exports = config;
Créez ensuite un nouveau mysql.js dans le dossier lib :
var mysql = require('mysql'); var config = require('../config/default.js') //建立数据库连接池 var pool = mysql.createPool({ host: config.database.HOST, user: config.database.USERNAME, password: config.database.PASSWORD, database: config.database.DATABASE }); let query = function(sql, values) { return new Promise((resolve, reject)=>{ pool.getConnection(function (err,connection) { if(err){ reject(err); }else{ connection.query(sql,values,(err,rows)=>{ if(err){ reject(err); }else{ resolve(rows); } connection.release(); //为每一个请求都建立一个connection使用完后调用connection.release(); 直接释放资源。 //query用来操作数据库表 }) } }) })}
Un pool de connexions à la base de données est établi ici et une fonction permettant de faire fonctionner la table de la base de données est encapsulée. Si vous ne comprenez pas la connexion à la base de données, veuillez la rechercher vous-même.
Créez un fichier d'entrée
Créez un nouvel index.js dans le répertoire principal, qui est le fichier d'entrée du projet :
const koa = require("koa"); //node框架 const path = require("path"); const bodyParser = require("koa-bodyparser"); //表单解析中间件 const ejs = require("ejs"); //模板引擎 const session = require("koa-session-minimal"); //处理数据库的中间件 const MysqlStore = require("koa-mysql-session"); //处理数据库的中间件 const router = require("koa-router"); //路由中间件 const config = require('./config/default.js'); //引入默认文件 const views = require("koa-views"); //模板呈现中间件 const koaStatic = require("koa-static"); //静态资源加载中间件 const staticCache = require('koa-static-cache') const app = new koa(); //session存储配置,将session存储至数据库 const sessionMysqlConfig = { user: config.database.USERNAME, password: config.database.PASSWORD, database: config.database.DATABASE, host: config.database.HOST, } //配置session中间件 app.use(session({ key: 'USER_SID', store: new MysqlStore(sessionMysqlConfig) })) //配置静态资源加载中间件 app.use(koaStatic( path.join(dirname , './public') )) //配置服务端模板渲染引擎中间件 app.use(views(path.join(dirname, './views'),{ extension: 'ejs' })) //使用表单解析中间件 app.use(bodyParser({ "formLimit":"5mb", "jsonLimit":"5mb", "textLimit":"5mb" })); //使用新建的路由文件 //登录 app.use(require('./routers/signin.js').routes()) //注册 app.use(require('./routers/signup.js').routes()) //退出登录 app.use(require('./routers/signout.js').routes()) //首页 app.use(require('./routers/home.js').routes()) //个人主页 app.use(require('./routers/personal').routes()) //文章页 app.use(require('./routers/articles').routes()) //资源分享 app.use(require('./routers/share').routes()) //个人日记 app.use(require('./routers/selfNote').routes()) //监听在8080端口 app.listen(8080) console.log(`listening on port ${config.port}`)
Le Le code ci-dessus contient des commentaires, je ne les expliquerai pas un par un, puisque le partage des ressources et le journal personnel n'ont pas encore été rédigés, je vais les partager temporairement ensemble... à la place.
Ensuite, ajoutez des instructions opération de base de données à mysql.js pour créer des tables, ajouter, supprimer, modifier et interroger.
var users = `create table if not exists users( id INT(200) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, pass VARCHAR(40) NOT NULL, avator VARCHAR(100) DEFAULT 'default.jpg', job VARCHAR(40), company VARCHAR(40), introdu VARCHAR(255), userhome VARCHAR(100), github VARCHAR(100), PRIMARY KEY (id) );` var posts = `create table if not exists posts( id INT(200) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, title VARCHAR(100) NOT NULL, content TEXT NOT NULL, uid INT(200) NOT NULL, moment VARCHAR(40) NOT NULL, comments VARCHAR(255) NOT NULL DEFAULT '0', pv VARCHAR(40) NOT NULL DEFAULT '0', likes INT(200) NOT NULL DEFAULT '0', type VARCHAR(20) NOT NULL, avator VARCHAR(100), collection INT(200) NOT NULL DEFAULT '0', PRIMARY KEY (id) , FOREIGN KEY (uid) REFERENCES users(id) ON DELETE CASCADE );` var comment= `create table if not exists comment( id INT(200) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, content TEXT NOT NULL, moment VARCHAR(40) NOT NULL, postid INT(200) NOT NULL, avator VARCHAR(100), PRIMARY KEY ( id ), FOREIGN KEY (postid) REFERENCES posts(id) ON DELETE CASCADE );` var likes = `create table if not exists likes( id INT(200) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, postid INT(200) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (postid) REFERENCES posts(id) ON DELETE CASCADE );` var collection = `create table if not exists collection( id INT(200) NOT NULL AUTO_INCREMENT, uid VARCHAR(100) NOT NULL, postid INT(200) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (postid) REFERENCES posts(id) ON DELETE CASCADE );` var follow = `create table if not exists follow( id INT(200) NOT NULL AUTO_INCREMENT, uid INT(200) NOT NULL, fwid INT(200) NOT NULL DEFAULT '0', PRIMARY KEY (id), FOREIGN KEY (uid) REFERENCES users(id) ON DELETE CASCADE ) ` let createTable = function(sql){ return query(sql, []); } //建表 createTable(users); createTable(posts); createTable(comment); createTable(likes); createTable(collection); createTable(follow); //createTable(follower); //注册用户 let insertData = function(value){ let _sql = "insert into users(name,pass) values(?,?);" return query(_sql,value); } //更新头像 let updateUserImg = function(value){ let _sql = "update users set avator=? where id=?" return query(_sql,value); } //更新用户信息 let updateUser = function(value){ let _sql = "update users set name=?,job=?,company=?,introdu=?,userhome=?,github=? where id=?" return query(_sql,value); } //发表文章 let insertPost = function(value){ let _sql = "insert into posts(name,title,content,uid,moment,type,avator) values(?,?,?,?,?,?,?);" return query(_sql,value); } //更新文章评论数 let updatePostComment = function(value){ let _sql = "update posts set comments=? where id=?" return query(_sql,value); } .......
Il y a six tables au total : table des utilisateurs, table des articles, table des commentaires d'articles, table de collecte d'articles, table des articles similaires, table de suivi des utilisateurs.
Les clés étrangères sont référencées ici, mais l'utilisation de clés étrangères n'est pas recommandée dans le développement actuel, vous pouvez donc la modifier vous-même. Ici, l'échec de la création de la base de données se produira au premier démarrage du projet (en raison d'une clé étrangère). clés), tant que le redémarrage se déroulera correctement. Si vous ne connaissez pas encore MySQL, voici un portail pour vous : Mot de passe du didacticiel vidéo d'introduction à MySQL : c2q7.
Développement de la page front-end
Une fois la structure de base du projet établie, vous pouvez rédiger la page front-end. Lorsque nous utilisons node pour développer du Web, nous utilisons généralement un moteur de modèles. Pour ce projet, j'ai utilisé des ejs, mais jade est également plus couramment utilisé, mais par rapport aux ejs, la structure du code de jade n'est pas assez claire. Concernant la syntaxe ejs, voici une brève introduction :
header.ejs
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Myblog</title> <link rel="stylesheet" href="/css/bootstrap.min.css" rel="external nofollow" > <link rel="stylesheet" href="/css/index.css" rel="external nofollow" > <script src="/js/jquery-3.2.1.min.js" type="text/javascript"></script> <script src="/js/bootstrap.min.js" type="text/javascript"></script>
nav.ejs
</head> <body> <header class="nav-head"> <p class="nav container"> <ul> <li><a href="/home" rel="external nofollow" >首页</a></li> <li> <a href="/share" rel="external nofollow" rel="external nofollow" rel="external nofollow" >资源分享</a></li> <li> <a href="/share" rel="external nofollow" rel="external nofollow" rel="external nofollow" >推荐</a></li> <li> <a href="/share" rel="external nofollow" rel="external nofollow" rel="external nofollow" >个人日记</a></li> <li><a href="/about" rel="external nofollow" >关于作者</a></li> <li><input type="text" placeholder="搜索" class="input-sm search"></li> <% if(session.user){ %> <li> <img src="/images/<%= session.avator %>" alt="" class="img-circle img-title"> <ul class="menu"> <li class="personal menulist"><a href="/personal/<%= session.user %>" rel="external nofollow" >主页</a></li> <!-- <li class="collection menulist"><a href="#" rel="external nofollow" >收藏集</a></li> --> <li class="menulist"><a href="/articles" rel="external nofollow" >写文章</a></li> <li class="out"><a href="/signout" rel="external nofollow" >登出</a></li> </ul> </li> <script> var imgTitle = document.getElementsByClassName('img-title')[0], menu = document.getElementsByClassName('menu')[0]; imgTitle.onclick = function (event) { showTap(); event.stopPropagation(); } document.body.addEventListener('click',function (event) { menu.style.display = 'none'; // event.stopPropagation(); },true) function showTap(){ if(menu.style.display == 'block'){ menu.style.display = 'none'; }else { menu.style.display = 'block'; } } //退出登录 var signOut = document.getElementsByClassName('out')[0]; /* signOut.onclick = function(){ ajax('get','/signout',null); xhr.onreadystatechange = function () { if(xhr.readyState==4&&xhr.status>=200&&xhr.status<300){ let text = xhr.responseText; //服务器返回的对象 if(text){ window.location.reload = 'localhost:8080/home'; } } } }*/ </script> <% }else{ %> <li class="login"> <a class="loginup" href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><span class="glyphicon glyphicon-user"></span> 注册 | 登录</a> </li> <% } %> </ul> </p> </header> <script> var searchInput = document.getElementsByClassName('search')[0]; searchInput.onfocus = function () { this.style.width = "300px"; } searchInput.onblur = function () { this.style.width = "180px"; } </script>
login.ejs
<p class="sign"> <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="关闭" class="login-close close">×</a> <p class="sign-title"> <h1>用户注册</h1> <h3>来吧骚年们!</h3> </p> <form class="form signup" role="form"> <p class="form-group"> <input type="text" name="username" placeholder="账号不少于两个字符" class="form-control"> </p> <p class="form-group"> <input type="password" name="pass" class="pass form-control" placeholder="密码"> </p> <p class="form-group"> <input type="password" name="repeatpass" id="repeat" placeholder="重复密码" class="form-control"> </p> <p class="form-group"> <input type="button" value="注册" class="btn btn-primary login-up"> </p> </form> <form class="form signin" role="form"> <p class="form-group"> <input type="text" name="username" placeholder="请输入用户名" class="form-control"> </p> <p class="form-group"> <input type="password" name="pass" class="pass form-control" placeholder="请输入密码"> </p> <p class="form-group"> <input type="button" value="登录" class="btn btn-primary login-in"> </p> </form> <p class="form-tips"> <span>已有账号?</span> <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="register">登录</a> </p> </p> <p class="login-form-mask"></p> <script> // $(document).ready(function () { var $close = $('.login-close'); var $sign = $('.sign'); $close.click(function () { $sign.css("display","none"); }) var $register = $('.register'), //login/loginup切换 $span = $('.form-tips span'), $signup = $('.signup'), $signTitle = $('.sign-title h1'), $signin = $('.signin'); $register.click(function () { if($span.html() == "已有账号?"){ $signin.css('display','block'); $signup.css('display','none'); $(this).html('注册'); $span.html("没有账号?"); $signTitle.html("欢迎登录"); }else{ $signin.css('display','none'); $signup.css('display','block'); $(this).html('登录'); $span.html("已有账号?"); $signTitle.html("欢迎注册"); } }) var $loginup = $('.loginup'); //点击登录/注册,阻止事件冒泡 $loginup.click(function () { $mask.fadeIn(100); $sign.slideDown(200); return false; }) var $close = $('.login-close'), $mask = $('.login-form-mask'), $sign = $('.sign'); $sign.click(function () { return false; }) $close.click(function (e) { // e.stopPropagation(); fadeOut(); }) $(document).click(function (e) { //点击任意位置取消登录框 //e.stopPropagation(); fadeOut(); }) function fadeOut(){ $mask.fadeOut(100); $sign.slideUp(200); } var loginUp = document.getElementsByClassName('login-up')[0], loginIn = document.getElementsByClassName('login-in')[0], signUp = document.getElementsByClassName('signup')[0], signIn = document.getElementsByClassName('signin')[0]; loginUp.onclick = function () { //注册 var data1 = 'username=' + signUp["username"].value + '&' + 'pass='+ signUp["pass"].value + '&' + 'repeatpass=' + signUp["repeatpass"].value; var reg = /^[\u4E00-\u9FA5]{2,5}$/; /* if(!reg.test(signUp["username"].value)){ signUp["username"].classList.add("tips"); signUp['username'].value() } */ ajax('post','/signup',data1,"application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if(xhr.readyState==4&&xhr.status>=200&&xhr.status<300){ let text = JSON.parse(xhr.responseText).code; console.log(text) //服务器返回的对象 if(text == 3){ fadeOut(); alert("注册成功") setTimeout(()=>{ window.location.reload(); },1000) // document.getElementsByClassName('login')[0].outerHTML = "<li class='users'><a href='/'>"+signUp["username"].value+ "(=^ ^=)" +"</a></li>" }else{ fadeOut(); alert("用户已存在") } } } } loginIn.onclick = function () { //登录 var data2 = 'username=' + signIn["username"].value + '&' + 'pass=' + signIn["pass"].value; ajax('post','/signin',data2,"application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if(xhr.readyState==4&&xhr.status>=200&&xhr.status<300){ let text = JSON.parse(xhr.responseText).code; //服务器返回的对象 console.log(text); // document.getElementsByClassName('login')[0].outerHTML = "<li class='users'><a href='/'>"+signUp["username"].value+ "(=^ ^=)" +"</a></li>" if(text===1){ fadeOut(); // let imgTitle = document.getElementsByClassName('img-title')[0]; // imgTitle.setAttribute('src','/images/' + JSON.parse(xhr.responseText).avator) setTimeout(()=>{ window.location.reload(); },1000) }else if(text === 2){ alert('密码错误') }else{ alert('账号不存在') } } } } </script>
footer.ejs
</body> </html>
header est la structure d'en-tête de la page, nav est la barre de navigation de la page, login est le contenu de connexion et d'inscription, et footer est la structure du haut de la page. Vous pouvez voir que j'ai beaucoup d'instructions de jugement if else dans le fichier ejs. Ceci est basé sur la session pour juger si l'utilisateur est connecté et afficher un contenu différent. Nous devons maintenant écrire nos styles de page : home.css et index.css respectivement
Afin d'améliorer la compréhension du js natif, j'ai utilisé beaucoup d'ajax natif dans le projet (évidemment jquery encapsulé ajax c'est mieux haha), donc ici nous écrivons d'abord une requête ajax native :
ajax.js
var xhr = null; function ajax(method,url,data,types) { //封装一个ajax方法 // var text; if(window.XMLHttpRequest){ xhr = new XMLHttpRequest(); }else if(window.ActiveXObject){ xhr = new ActiveXObject("Microsoft.XMLHTTP"); }else { alert('你的浏览器不支持ajax'); return false; } xhr.onerror = function (err) { alert("some err have hapened:",err); } xhr.open(method,url,true); if(method=="post"){ xhr.setRequestHeader("Content-type",types); // xhr.setRequestHeader("Conent-Type",'application/json'"application/x-www-form-urlencoded") } try{ setTimeout(()=>{ xhr.send(data); },0); }catch(err) { alert("some error have hapened in font:",err); } return xhr; }
implémenter l'enregistrement de connexion
Une fois la page de base front-end développée, nous pouvons écrire l'interface de connexion back-end :
Inscription : signup.js
var router = require('koa-router')(); var userModel = require('../lib/mysql.js'); var md5 = require('md5') // 注册页面 // post 注册 router.post('/signup', async(ctx, next) => { console.log(ctx.request.body) var user = { name: ctx.request.body.username, pass: ctx.request.body.pass, repeatpass: ctx.request.body.repeatpass } let flag = 0; await userModel.findDataByName(user.name) .then(result => { console.log(result) if (result.length) { //处理err console.log('用户已存在') ctx.body = { code: 1 }; } else if (user.pass !== user.repeatpass || user.pass == '') { ctx.body = { //应把这个逻辑放到前端 code: 2 }; } else { flag = 1; } }) if(flag==1){ let res = await userModel.insertData([user.name, md5(user.pass + 'asd&$BH&*') ]) console.log(res.insertId) await userModel.findDataByName(user.name) .then((result)=>{ // var res = JSON.parse(JSON.stringify(result)) console.log(result[0]['avator']) ctx.session.id = res.insertId; ctx.session.user=user.name; ctx.session.avator = 'default.jpg'; ctx.body = { code: 3 }; console.log('注册成功') }) } }) module.exports = router
Le mot de passe est crypté avec md5 Après. Lors de l'enregistrement, une session est créée pour l'utilisateur et ajoutez-la à la base de données. Après l'écriture, n'oubliez pas d'ajouter module.exports = router à la fin pour exposer l'interface.
Connexion : signin.js
var router = require('koa-router')(); var userModel = require('../lib/mysql.js') var md5 = require('md5') router.post('/signin', async(ctx, next) => { console.log(ctx.request.body) var name = ctx.request.body.username; var pass = ctx.request.body.pass; await userModel.findDataByName(name) .then(result => { var res = JSON.parse(JSON.stringify(result)) if (name === res[0]['name']&&(md5(pass + 'asd&$BH&*') === res[0]['pass'])) { console.log('登录成功') ctx.body = { code: 1, } ctx.session.user = res[0]['name'] ctx.session.id = res[0]['id'] ctx.session.avator = res[0]['avator'] }else if(md5(pass + 'asd&$BH&*') != res[0]['pass']){ ctx.body = { code: 2 //密码错误 } } }).catch(err => { ctx.body = { code: 3 //账号不存在+ } console.log('用户名或密码错误!') }) }) module.exports = router
Déconnexion : signout.js
//使用新建的路由文件 //登录 app.use(require('./routers/signin.js').routes()) //注册 app.use(require('./routers/signup.js').routes()) //退出登录 app.use(require('./routers/signout.js').routes())
Je crois que vous maîtrisez la méthode après avoir lu le cas dans cet article , veuillez venir pour des informations plus intéressantes. Faites attention aux autres articles connexes sur le site Web chinois de php !
Lecture recommandée :
vue-element fait fonctionner le lecteur de musique (avec code)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!