Maison > interface Web > js tutoriel > le corps du texte

node+koa2+mysql+bootstrap crée un forum frontal

不言
Libérer: 2018-05-07 15:02:54
original
1555 Les gens l'ont consulté

Cet article partage avec vous les étapes pour créer un forum front-end en utilisant node+koa2+mysql+bootstrap à travers des exemples. Les amis dans le besoin peuvent s'y référer.

Avant-propos

Après avoir appris koa2 et exprimé et écrit quelques démos, je prévois d'écrire un projet pour mettre en pratique mes compétences. Puisque je suis étudiant, là-bas. n'a rien à faire. Ce projet vise à développer un forum front-end. Les exigences fonctionnelles sont formulées en référence à certaines communautés. Les principales sont :

Connexion et inscription
.

Maintenance des informations personnelles, avatar et autres informations de base

Publiez des articles, l'éditeur de texte enrichi utilise le plug-in wangEditor pour modifier, supprimer des articles, classer les articles, etc.

Commentaires d'articles, collections d'articles, likes, etc.

Prend en charge le chargement paginé d'articles et de commentaires

Suivre et ne plus suivre les utilisateurs

Télécharger, partager, télécharger et afficher des ressources (fichiers)

Ressources d'apprentissage recommandées....

Journal personnel de l'auteur

mais. . . . 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/home

Application de la pile technologique du projet : 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 suivre ~~ encouragez mon front -fin salaud.

Environnement de développement

nœud : v8.3.0

koa : ^2.4.1

mysql : 5.7. 1

npm : 5.3.0 et supérieur

Comment exécuter le projet

Cloner le projet en local git clone git@github .com :Jay214/myblog-koa2.git

Installer le module middleware npm install

Installer mysql

mysql Il est recommandé d'utiliser la version inférieure à 5.7, il y a un bug dans 5.7 Pour l'interface graphique, il est recommandé d'utiliser navicat pour MySQL Enregistrez simplement le fichier, 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ême

Si le projet existe Si vous avez des bugs ou de meilleures suggestions, n'hésitez pas pour commenter 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 le parcourir d'abord Après avoir lu le document, la construction de la base de données en arrière-plan est la clé, veuillez donc d'abord installer MySQL. Il est recommandé d'installer MySQL en dessous de la version 5.7, car la version 5.7.0 a un bug et le fichier de configuration doit le faire. être modifié. Vous connaîtrez les détails lorsque vous l’installerez.

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 les fichiers de base de données

3.middlewares stocke le middleware qui détermine s'il faut se connecter et s'inscrire ou non

4.public stocke les fichiers statiques, js, les fichiers qui référence au framework bootstrap et à d'autres fichiers

5.routers stocke les fichiers de routage

6.views stocke les fichiers modèles

7.index est le fichier principal du programme, définissant les interfaces et les interfaces de base de données, référençant les modules, etc.

8.package.json fichier de configuration du projet, comprenant le nom du projet, l'auteur, les dépendances, les modules, etc.

Le projet est développé avec vscode et est très confortable à utiliser. Amis qui ne l'ont pas encore essayé, n'hésitez pas à l'essayer maintenant.

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
Copier après la connexion

Utilisation de chaque module

koa node framework

middleware d'analyse de formulaire koa-bodyparser

koa-mysql-session, koa-session-minimal middleware 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

chiffrement de mot de passe md5

middleware momentané

base de données mysql

Middleware de rendu de modèles koa-views

Cache de fichiers koa-static-cache

Construire le cadre de base du projet

Configurer la base de données connexion

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;
Copier après la connexion
Puis dans le dossier du fichier lib nouveau mysql .js :

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用来操作数据库表
  })
  } 
  }) 
 })}
Copier après la connexion
Ici, un pool de connexions à la base de données est établi et une fonction qui exploite la table de la base de données est encapsulée s'il n'est pas nécessaire de se connecter à la base de données. Si vous comprenez, veuillez le rechercher vous-même.

Créez un fichier d'entrée

Créez un nouvel index.js dans le répertoire principal, c'est-à-dire 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}`)
Copier après la connexion
Les codes ci-dessus sont tous commentés, je ne les expliquerai donc pas un par un puisque le partage des ressources et le journal personnel n'ont pas encore été rédigés, je les partagerai temporairement. les ensemble... à la place.

Ensuite, ajoutez des instructions d'opération de base de données à mysql.js, créez des tables, ajoutez, supprimez, modifiez et interrogez.

总共六张表:用户表、文章表、文章评论表、文章收藏表、文章点赞表、用户关注表。

这里引用了外键,但是现在的开发不推荐使用外键了,所以你们可以自行修改,这里在项目第一次启动时会出现数据库创建失败(由于外键原因),只要重新启动就ok了,如果对mysql还不了解的,这里附送大家一个传送门:mysql入门视频教程 密码:c2q7 。

前端页面开发

项目基本结构搭建好后,就可以进行前端页面的编写了。用node开发web时我们一般会配合模板引擎,这个项目我采用的是ejs,除了ejs之外较为常用的还有jade,但是jade相对ejs来说的话代码结构不够清晰。关于ejs语法,这里做个简单的介绍:

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>
Copier après la connexion

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(&#39;img-title&#39;)[0],
  
    menu = document.getElementsByClassName(&#39;menu&#39;)[0];
    imgTitle.onclick = function (event) {
    showTap();
    event.stopPropagation();
    }
    
    document.body.addEventListener(&#39;click&#39;,function (event) { 
    menu.style.display = &#39;none&#39;;
    // event.stopPropagation();
    },true)
 
    function showTap(){
    if(menu.style.display == &#39;block&#39;){
     menu.style.display = &#39;none&#39;;
    }else {
     menu.style.display = &#39;block&#39;;
    }
    }
    //退出登录
    var signOut = document.getElementsByClassName(&#39;out&#39;)[0];
   /* signOut.onclick = function(){
    ajax(&#39;get&#39;,&#39;/signout&#39;,null);
    xhr.onreadystatechange = function () {
    if(xhr.readyState==4&&xhr.status>=200&&xhr.status<300){
    let text = xhr.responseText; //服务器返回的对象
    if(text){
    window.location.reload = &#39;localhost:8080/home&#39;;
    }
    
    }
   }

    }*/
   </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(&#39;search&#39;)[0];
 searchInput.onfocus = function () {
  this.style.width = "300px";
 }
 searchInput.onblur = function () {
  this.style.width = "180px";
 }
 
 </script>
Copier après la connexion

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 = $(&#39;.login-close&#39;);
 var $sign = $(&#39;.sign&#39;);
 $close.click(function () {
  $sign.css("display","none");
 })

 var $register = $(&#39;.register&#39;), //login/loginup切换
  $span = $(&#39;.form-tips span&#39;),
  $signup = $(&#39;.signup&#39;),
  $signTitle = $(&#39;.sign-title h1&#39;),
  $signin = $(&#39;.signin&#39;);

 $register.click(function () {
  if($span.html() == "已有账号?"){

  $signin.css(&#39;display&#39;,&#39;block&#39;);
  $signup.css(&#39;display&#39;,&#39;none&#39;);
  $(this).html(&#39;注册&#39;);
  $span.html("没有账号?");
  $signTitle.html("欢迎登录");

  }else{

  $signin.css(&#39;display&#39;,&#39;none&#39;);
  $signup.css(&#39;display&#39;,&#39;block&#39;);
  $(this).html(&#39;登录&#39;);
  $span.html("已有账号?");
  $signTitle.html("欢迎注册");
  }
 })

 var $loginup = $(&#39;.loginup&#39;); //点击登录/注册,阻止事件冒泡
 $loginup.click(function () {
  $mask.fadeIn(100);
  $sign.slideDown(200);
  return false;
 })

 var $close = $(&#39;.login-close&#39;),
  $mask = $(&#39;.login-form-mask&#39;),
  $sign = $(&#39;.sign&#39;);

 $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(&#39;login-up&#39;)[0],
 loginIn = document.getElementsByClassName(&#39;login-in&#39;)[0],
 signUp = document.getElementsByClassName(&#39;signup&#39;)[0],
 signIn = document.getElementsByClassName(&#39;signin&#39;)[0];

 
 
 loginUp.onclick = function () { //注册
 var data1 = &#39;username=&#39; + signUp["username"].value + &#39;&&#39; + &#39;pass=&#39;+ signUp["pass"].value + &#39;&&#39; + &#39;repeatpass=&#39; + signUp["repeatpass"].value;
 var reg = /^[\u4E00-\u9FA5]{2,5}$/;
 /* if(!reg.test(signUp["username"].value)){
  signUp["username"].classList.add("tips");
  signUp[&#39;username&#39;].value()
 } */
 ajax(&#39;post&#39;,&#39;/signup&#39;,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(&#39;login&#39;)[0].outerHTML = "<li class=&#39;users&#39;><a href=&#39;/&#39;>"+signUp["username"].value+ "(=^ ^=)" +"</a></li>"
  }else{
  fadeOut();
  alert("用户已存在")
  }
  
  }
 }

 }

 loginIn.onclick = function () { //登录
 var data2 = &#39;username=&#39; + signIn["username"].value + &#39;&&#39; + &#39;pass=&#39; + signIn["pass"].value;
 ajax(&#39;post&#39;,&#39;/signin&#39;,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(&#39;login&#39;)[0].outerHTML = "<li class=&#39;users&#39;><a href=&#39;/&#39;>"+signUp["username"].value+ "(=^ ^=)" +"</a></li>"
  if(text===1){
  fadeOut();
  // let imgTitle = document.getElementsByClassName(&#39;img-title&#39;)[0];
  // imgTitle.setAttribute(&#39;src&#39;,&#39;/images/&#39; + JSON.parse(xhr.responseText).avator)
  setTimeout(()=>{
   window.location.reload();
  },1000)
  }else if(text === 2){
   alert(&#39;密码错误&#39;)
  }else{
   alert(&#39;账号不存在&#39;)
  }
  
  }
 }
 
 }
</script>
Copier après la connexion

footer.ejs

 </body>
 </html>
Copier après la connexion

header为页面头部结构,nav为页面导航条,login为登录、注册内容、footer为页面顶部结构。可以看到我在ejs文件里有很多的if else 判断语句,这是根据session来判断用户是否登录渲染不同的内容。现在我们需要我们的页面编写样式:分别是home.css和index.css

为了增强对原生js的理解,在项目里我用了大量的原生ajax(显然jquery封装的ajax比较好哈哈),因此这里先编写一个原生ajax请求:

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(&#39;你的浏览器不支持ajax&#39;);
  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",&#39;application/json&#39;"application/x-www-form-urlencoded")
 }
 try{
  setTimeout(()=>{
  xhr.send(data);
 },0);
 }catch(err) {
  alert("some error have hapened in font:",err);
 }
 return xhr;
 }
Copier après la connexion

实现登录注册

前端基本页面开发好后,我们就可以写后台登录接口了:

注册:signup.js

var router = require(&#39;koa-router&#39;)();
var userModel = require(&#39;../lib/mysql.js&#39;);
var md5 = require(&#39;md5&#39;)

 // 注册页面
 
 // post 注册
router.post(&#39;/signup&#39;, 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(&#39;用户已存在&#39;)
   ctx.body = {
   code: 1
   };  
  
  } else if (user.pass !== user.repeatpass || user.pass == &#39;&#39;) {
  ctx.body = { //应把这个逻辑放到前端
   code: 2
  };

  } else {
  flag = 1;  
  
  }
 })
 if(flag==1){
 let res = await userModel.insertData([user.name, md5(user.pass + &#39;asd&$BH&*&#39;) ])
 console.log(res.insertId)
 await userModel.findDataByName(user.name)
 .then((result)=>{
  
  // var res = JSON.parse(JSON.stringify(result))
  console.log(result[0][&#39;avator&#39;])
  ctx.session.id = res.insertId;
  ctx.session.user=user.name;
  ctx.session.avator = &#39;default.jpg&#39;;
  ctx.body = {
  code: 3
  };
  console.log(&#39;注册成功&#39;)
  })
 }

})

module.exports = router
Copier après la connexion

密码采用md5加密,注册后为用户创建session并将其添加到数据库,写完别忘了在最后加上module.exports = router将接口暴露出来。

登录:signin.js

var router = require(&#39;koa-router&#39;)();
var userModel = require(&#39;../lib/mysql.js&#39;)
var md5 = require(&#39;md5&#39;)

router.post(&#39;/signin&#39;, 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][&#39;name&#39;]&&(md5(pass + &#39;asd&$BH&*&#39;) === res[0][&#39;pass&#39;])) {
   console.log(&#39;登录成功&#39;)
   ctx.body = {
   code: 1,
   }
 
   ctx.session.user = res[0][&#39;name&#39;]
   ctx.session.id = res[0][&#39;id&#39;]
   ctx.session.avator = res[0][&#39;avator&#39;] 

  }else if(md5(pass + &#39;asd&$BH&*&#39;) != res[0][&#39;pass&#39;]){
  ctx.body = {
   code: 2 //密码错误
  }
  }
 }).catch(err => {
  ctx.body = {
  code: 3 //账号不存在+
  }
  console.log(&#39;用户名或密码错误!&#39;)

 })

})

module.exports = router
Copier après la connexion

退出登录:signout.js

//使用新建的路由文件
//登录
app.use(require(&#39;./routers/signin.js&#39;).routes())
//注册
app.use(require(&#39;./routers/signup.js&#39;).routes())
//退出登录
app.use(require(&#39;./routers/signout.js&#39;).routes())
Copier après la connexion

登录注册完成,由于学习繁忙,内容只能一点一点写了,后续内容持续更新。

相关推荐:

node+express实现聊天室

node+express+jade制作简单网站指南_node.js

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!