今回は、フォーラムのフロントエンドとバックエンドを構築するためのnode+koa2+mysql+bootstrapについて説明します。node+koa2+mysql+を使用してフォーラムのフロントエンドとバックエンドを構築するための注意事項とは何ですか。ここで実際のケースを見てみましょう。
おすすめの mysql ビデオ チュートリアル: "mysql チュートリアル"
前書き
koa2 を学習し、いくつかのデモを作成してから、スキルを練習するプロジェクトを作成する予定です。このプロジェクトは、いくつかのコミュニティを参考にしてフロントエンド フォーラムを開発することを目的としています。主な機能要件は、
ログインと登録
個人情報の保守、アバターおよびその他の基本情報
です。記事、リッチテキストエディターはwangEditorプラグインを採用し、記事の編集、削除、記事分類など
記事コメント、記事コレクション、いいねなど
記事ページング、コメントページング読み込みをサポート
ユーザーのフォローとフォロー解除
リソース(ファイル)アップロード共有、ダウンロード、表示
推奨学習リソース...
著者の個人日記
しかし。 。 。 。諸事情により、現時点では一部の機能しか実装されておらず、プロジェクト運用効果: http://120.77.211.212/home
プロジェクト技術スタックアプリケーション: node-koa2-ejs-bootstrap3 はまだ書かれていません。 —jquery、github アドレス :https://github.com/Jay214/myblog-koa2、役に立ったと思われる場合、またはまだ読むことができる場合は、フロントエンドのクソ野郎である私にスターを付けてください〜〜励ましてください。
開発環境node: v8.3.0
koa: ^2.4.1
mysql: 5.7.1
npm: 5.3.0以降
プロジェクトの実行方法のプロジェクトをローカル git clone git@github.com:Jay214/myblog-koa2.git
モジュールミドルウェアをインストールする npm install
mysql をインストールするmysql バージョンは 5.7 未満であることが推奨されます。5.7 にはバグがあり、グラフィカルインターフェースが推奨されます navicat for MySQL
を使用してスーパーバイザーをインストールします (npm install スーパーバイザープロジェクト実行ツール。開いた後は監視モードになります。ファイルを変更して保存するだけです。プロジェクトを再度開始する必要はありません) ノードインデックスまたは npmスーパーバイザインデックス
localhost:8080/home ポート番号は自分で変更できます
プロジェクトにバグを見つけた場合、またはより良い提案がある場合は、お気軽に提案を送ってください、qq: 2752402930。
準備koa2 は es6 の Promise と es7 の await/async 構文に基づいているため、es6/es7 を理解していない場合は、最初にドキュメントを読んでください。バックグラウンドでのデータベースの構築が重要です。 , そのため、まず mysql をインストールしてください。バージョン 5.7.0 にはバグがあり、設定ファイルを変更する必要があるため、MySQL は 5.7 より前のバージョンをインストールすることをお勧めします。インストールすると詳細がわかります。
ノード環境をインストールし、node -v を使用してノードのバージョンを確認します。ノードには、es6 の Promise と es7 の await/async 構文をサポートするための新しいバージョンが必要です。 npmをインストールする必要があります。
プロジェクト構造
1.configにはデフォルトファイル(データベース接続設定)が格納されます
2.libにはデータベースファイルが格納されます
3.middlewaresにはログインおよび登録するかどうかを決定するミドルウェアが格納されます
4 .public は静的ファイル、js、参照ブートストラップ フレームワークおよびその他のファイルを保存します
5.routers はルーティング ファイルを保存します
6.views はテンプレート ファイルを保存します
7.index はプログラムのメイン ファイルであり、インターフェイス、データベース インターフェイス、参照を定義します
8.package。プロジェクト名、作成者、依存関係、モジュールなどを含む json プロジェクトの構成ファイル。プロジェクトは vscode で開発されました。まだ試したことがないので、ぜひ行ってみてください。
プロジェクトの初期化: cd myblog1 -> npm init この時点で package.json ファイルが作成されています。
koa2 は小さくてコンパクトな軽量フレームワークであるため、開発効率と利便性を高めるために、いくつかの 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
各モジュールの使い方
koaノードフレームワーク
koa-bodyparserフォーム解析ミドルウェア
koa-mysql-session, koa-session-minimalデータベース処理ミドルウェア
koa-routerルーティングミドルウェア
koa -static静的リソース読み込みミドルウェア
ejsテンプレートエンジン
md5パスワード暗号化
瞬間ミドルウェア
mysqlデータベース
koa-viewsテンプレートレンダリングミドルウェア
koa-static-cacheファイルキャッシュ
プロジェクトの基本フレームワーク
データベース接続を設定します
configフォルダーに新しいdefault.jsを作成します:
const config = { //启动端口 port: 8080, //数据库配置 database: { DATABASE: 'nodesql', USERNAME: 'root', PASSWORD: '123456', PORT: '3306', HOST: 'localhost' } } module.exports = config;
次に、libフォルダーに新しい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用来操作数据库表 }) } }) })}
ここでデータベース接続プールが確立され、データベーステーブルを操作するための関数が作成されます。データベース接続がわからない場合は、自分で調べてください。
エントリファイルを作成します
メインディレクトリに新しいindex.js、つまりプロジェクトエントリファイルを作成します:
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}`)
上記のコードはすべてコメント化されているため、1つずつ説明しません。リソース共有と個人日記がまだ書かれていないので、一時的に共有を統一…差し替え。
次に、テーブルの作成、追加、削除、変更、クエリを行うためのデータベース操作ステートメントをmysql.jsに追加します。
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); } .......
ユーザーテーブル、記事テーブル、記事コメントテーブル、記事コレクションテーブル、記事いいねテーブル、ユーザーフォローテーブルの合計6つのテーブルがあります。
ここでは外部キーが参照されていますが、現在の開発では外部キーの使用は推奨されていないため、自分で変更できます。プロジェクトの初回起動時にデータベースの作成に失敗します (外部キーが原因)。 ) 再起動さえすれば大丈夫です。mysql についてまだ知らない場合は、mysql 入門ビデオ チュートリアルのポータルを参照してください。パスワード: c2q7。
フロントエンド ページの開発
プロジェクトの基本構造が確立されたら、フロントエンド ページを作成できます。ノードを使用して Web を開発する場合、このプロジェクトでは ejs に加えて、jade もよく使用されますが、ejs と比較すると、jade のコード構造は十分に明確ではありません。 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>
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はページヘッダー構造、navはページナビゲーションバーです、login はログインと登録のコンテンツ、footer はページの最上部の構造です。 ejs ファイルには、セッションに基づいてユーザーがログインしているかどうかを判断し、さまざまなコンテンツを表示する if else 判定ステートメントが含まれていることがわかります。ここで、ページ スタイル: 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('你的浏览器不支持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; }
ログイン登録を実装するには
フロントエンドの基本ページが開発された後、バックエンドのログインインターフェイスを書くことができます:
Registration: 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
パスワードはmd5で暗号化されています。登録後、ユーザーのセッションを作成しデータベースに追加します。最後に module.exports = router を追加してインターフェイスを公開することを忘れないでください。
ログイン: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
ログアウト:signout.js
//使用新建的路由文件 //登录 app.use(require('./routers/signin.js').routes()) //注册 app.use(require('./routers/signup.js').routes()) //退出登录 app.use(require('./routers/signout.js').routes())
この記事の事例を読んだ後は、この方法を習得したと思います。さらに興味深い情報については、PHP 中国語 Web サイトの他の関連記事に注目してください。 !
推奨読書:
音楽プレーヤー関数を作成するための vue 要素 (コード付き)
vue を使用して個人情報を表示し、パスワードを変更する方法
以上がnode+koa2+mysql+bootstrap はフォーラムのフロントエンドとバックエンドを構築しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。