試著回想18歲的自己,未來的人脈往往成為促使我們選擇台大電機的原因,然而曾經我們引以為傲的人脈資產,現在卻如此凋零。
一瞥世界上知名大學,他們都擁有一個共通點:人脈網絡。哈佛大學的老爺爺願意為了甫錄取的學弟妹提點長談,史丹佛大學的前輩也不遺餘力提拔後進。相比之下,我們認為系上一直缺乏專屬平台供系友建立緊密的網路,遂使人脈日益薄弱。
近年創立的NTUEE Chain已經輔導眾多學生申請上國外一流大學,我們更希望延續EE Chain的初衷,讓這份互相傳承聯絡的心拓展到所有系友。繼承著B03~B06學長姐們的意志,我們希望這個聯絡網能成為一個整合式的社群網路,讓NTUEErs聚在一起;秉持著恢復人脈網的精神,讓NTUEE能在世界上有更大的影響力;建立一個連結電機系的共同回憶,讓系友們有專屬的家!
這並不是一個網頁養成班,沒辦法讓所有人把寫網頁的所有技能練習套精熟,主要學習內容是依照本網站的需求進行延伸,會從最基本的寫起,並漸漸加深加廣,目標寫出一個完整、讓人驚艷的網頁^_^
如果有漏掉的隨時回報
$ git clone https://github.com/chinyi0523/NTUEE_Plus_website.git
$ cd NTUEE_Plus_website
$ npm install
$ npm run install-client
$ npm start
一樣在vscode的terminal即可
# 輸入使用者名稱
$ git config --global user.name "YourName"
# 輸入帳號email
$ git config --global user.email "YourMail@gmail.com"
# 查看使用者名稱
$ cat ~/.gitconfig
# 暫存所有檔案(我都是用這個)
$ git add . 或 git add -a 或 git add --all
# 暫存特定檔案(善用*,例如*.txt)
$ git add <filename>
# 暫存所有modified的檔案(無視untrack),但建議用.gitignore
$ git add -u
git add .
無視# 存檔,'commit message'換成你的簡述
$ git commit -m 'commit message'
#如果覺得commit -m太長,可以在config設定縮寫cm
$ git config --global alias.cm 'commit -m' #以後打git cm取代git commmit -m
# 變成untrack file(建議)
$ git rm <filename> --cached
# 直接從電腦刪除
$ git rm <filename>
# 改檔名(不用重新add)
$ git mv <oldname> <newname>
# 從origin更新程式
$ git pull
# 把local的更動上傳到origin
$ git push
分支branch
善用分支讓大家的程式不打架
#看目前所在的branch和local所有的branch
$ git branch
$ git branch -a #茶和local+remote所有分支
$ git checkout <branchname> #切換到其他branch
#新增branch並切換過去,注意!他會以當前branch為根源
$ git checkout -b <branchname>
# 抓遠端master
$ git pull origin master
#把local當前的branch發到remote的branch上
$ git push -u origin <branch name>
# 之後在這個branch pull、push都是對origin branch做事
# 如果後端完成事情要要merge
$ git checkout Recruitment
$ git merge Recruitment-backend
# 如果前端想要拿後端merge到Recruitment的資料
$ git checkout Recruitment-frontend
$ git merge Recruitment
方法2:rebase
通常用在自己的branch上,特點是保持分支樹乾淨(最終會merge成一條),
例如Recruitment-backend開了個子branch <testAwait>
$ git checkout Recruitment-backend
$ git rebase testAwait
├── backend/routes/
├── api.js
### doc相關 ###
├── apidoc.json #生成readme的rule
├── README.MD #在/backend跑yarn doc生成
├── docTemplate/ #README的template
### middleware相關 ###
├── error/
├── index.js
├── ErrorHandler #throw它可以指定狀態碼(404,500,...)
├── handleError #api.js最底下呼叫,處理所有error
├── dbCatch #mongoose相關的error handling
├── middleware/
├── mail/ #寄信
├── validation/ #判斷req格式
├── fileProcess.js #把formdata塞進req.body
### 主要程式碼 ###
├── Schemas #資料庫相關
### 特殊 ###
├── db.js #與資料庫連線的基本設定
├── preload.js #docker建好後在/跑yarn reset-db
├── query.js #把req變成mongoose的query
### collections ###
├── ...
├── srcs #api相關
├── in/
├── abroadinfo #留學資訊
├── account
├── auth/ #管理員相關的帳號設定
├── ...
├── auth #用session檢查權限
├── isAuth.js
├── isUser.js
├── career #就是recruitment
├── column
├── profile_new
├── recommendation
├── study #留學配對
├── out/
├── account #註冊登入那些的
├── dashboard
├── forget #忘記密碼
obj小教學:
const obj1 = {a:1,b:2}
const {a,b} = obj1//a=1,b=2
const c = 3
const d=4
//{c:3,d:4}
const obj2 = {c,d}
Express.js是後端Node.js的開發框架之一,框架有點像是一個工具包,開發者能夠使用 npm(Node Package Manager) 安裝所需要的工具包到專案資料夾,輕鬆完成專案的使用環境設定,讓你專注在程式碼的撰寫與實際運行上。
//index.js
//開啟app應用程式,套用express框架
const express = require('express');
const app = express();
...
//設定前後端路由(下面介紹)
app.use("/api", require("./backend/routes/api"));
app.use(express.static('./client/dist'));
...
//在http://localhost:1993監聽此應用程式
app.listen(process.env.PORT||1993,function(){
console.log('server connect');
console.log('port name: ',process.env.PORT||1993);
})
路由是指判斷應用程式如何回應用戶端對特定端點的要求,而這個特定端點是一個 URI(或路徑)與一個特定的 HTTP 要求方法(GET、POST 等)。
每一個路由可以有一或多個處理程式函式,當路由相符時,就會執行這些函式。
路由定義的結構如下:
app.METHOD(PATH, HANDLER);
//METHOD 是 HTTP 要求方法。
//PATH 是伺服器上的路徑。
//HANDLER 是當路由相符時要執行的函數,或稱中介軟體
如果想要用一個path管理很多個路由,可以用express.Router,可以想成是迷你應用程式。
例如後端的程式由api.js控管,並輸出成一個router在/api下運作。
//routes/api.js
const express = require("express");
const router = express.Router();
router.post(url1,function1);
router.post(url2,function2);
...
module.exports = router;
//index.js
...
app.use("/api", require("./routes/api"));
...
中介軟體函數是寫在route中的函式,他的input固定為「要求物件 (req)」、「回應物件 (res)」 和「執行下一個中介軟體(next)」,常見的形式為:
router.post(url,function(req, res, next){
//do something
next()
},function(req,res,next){})
//client
axios.post(url,{account:"b07901029",username:"huho"},config)
->
//backend
req.body.account //"b07901029"
//client
GET /url?account=b07901029&username=均府
->
//backend
req.query.account //"b07901029"
router.METHOD(url,
function(req,res,next){},
function(req,res,next){},...)
router.post('/login',function(req,res,next){
next('route');
},function(req,res,next){
console.log('我不會被執行')
})
router.post('/login',function(req,res,next){
console.log('我會被執行')
})
一些express常見的應用
router.use(function)
強制執行所有路由都要經過他(好像要注意priority?)
通常會用來設定參數(例如index.js中的session或urlencoded或res header),或執行一些大家統一要用的參數。
Auth
驗證使用者是否有登入
//api.js
const Auth = require('/in/Auth');
axios.post(url,Auth,...);
//Auth.js
module.export = funciton(req,res,next){
if(req.session){
next()
}else{
//開發階段這裡呼叫next();
res.status(403).send({description:"請登入"});
}
}
multer
專門處理檔案上傳,在/register、/chVisual、/getImg有應用在照片處理
不想深入研究的話就直接套用:
//client
let data = new FormData();
data.append('avatar',this.state.file);
//用append設定其他要post的資料,下面介紹更多關於formData的注意事項
const config = {headers:
{'content-type':'multipart/form-data'}
};
axios.post(url,data,config);
->
//backend
const parseFile = require('./middleware/multer.js');
router.post(url,parseFile('avatar'),...);
//ImgGet裡輸入要讀取的檔案的key
//之後的function就可以在req.file裡拿到{buffer,mimetype(img/png之類的)}
//frontend
//要傳object時請用json
let data = new FormData();
const obj = {data:"b07901029",show:true}
data.append("account",JSON.stringify(obj))
//要傳array key請加[]
const arr = ["a","b","c"]
arr.forEach(item=>{
//如果item是obj請參考上面解法
data.append("fakeArr[]",item)
})
->
//backend
const {data,show} = req.body["account"] //{"b07901029",true}
//用forEach拿array
req.body["fakeArr"].forEach(item=>{
console.log(item);
//"a"\n"b"\n"c"
})
//backend
//這裡req.file應該變成我們存放mimetype和buffer的地方
const prefix="data:"+req.file.mimetype+";base64,"
const img = new Buffer(req.file.buffer, 'binary').toString('base64');
const userimage = prefix+img;
res.send({userimage})
->
//client
//拿到的userimage用this.setState({userimage}),然後可直接設成<img>的value:
<img value={this.state.userimage}>
validation
在執行主程式前用express-validator驗證資料格式,目的是不要讓使用者傳奇怪的資料到後端
//基本架構:
const {check} = require('express-validator')
router.post(url,[check(key1),check(key2),...],authController,function,...)
express-validator中有三種常用函式:body、cookie、check,分別會檢驗req.body、req.cookies、req.{body,cookies,header,param,query}下指定key對應的value有沒有符合格式。
若沒有符合格式,消息會被存在req中並呼叫下一個函式:authController,express-validator下還有validationResult這個函式,用validationResult(req)可以抓到錯誤並回傳res.status(400)。
以下是我們的版本(以login為例),require validation,然後指定要檢查的欄位
const valid = require('../../../middleware/validation')
const rules = ['account', 'password']
module.exports = [valid(rules), asyncHandler(login)]
mongoDB是一個文件導向的資料庫(database),一個資料庫底下可以有多個集合(collections),每個集合下有多個文檔(documentions)。
以我們的專案為例,我們的database存放在mongoDB online上,名叫eeplus。當中有以下collections:
user_logins
user_visuals
columns
...
而user_logins有數個documentation,格式類似json
{_id:ObjectID(b6e5rb48e6), account:"b07901029", userpsw:"f2hoifpew"},
{_id:ObjectID(ber561r65b), account:"b07901014", userpsw:"vewoivnro"},
...
mongoose是nodejs中用來與mongoDB溝通的套件。
//routes/Schema/db.js
const mongoose = require('mongoose');
mongoose.connect(DB_URL);
//form like mongodb://<user>:<psw>@host:port/dbname
const db = mongoose.connection(); //背景監聽
db.on('disconnected', function(){
console.log('disconnected!');
});
const mongoose = require("./db")
const Schema = mongoose.Schema;
//在此設定model的type、驗證、虛擬屬性(我沒用過,感覺很好玩!)
const User_login_Schema = new Schema({
//透過:TYPE設定類型
username: String,
//也可以規定資料的內容,例如enum:['dog','cat']限定內容選項
account: {type:String, require:True},
...,
//可以設定多層的資料,也可以設定[]
img: {
data: { type: Buffer },
contentType: { type: String }
}
});
//把schema編譯成model,之後就可以對model進行操作
//之後save的檔案會存在user_logins(好像會自動加s)這個collection中
module.exports = mongoose.model("User_login", User_login_Schema);
// define a schema
const animalSchema = new Schema({ name: String, type: String });
// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
return mongoose.model('Animal').find({ type: this.type }, cb);
};
animalSchema.statics.findByName = function(name) {
return this.find({ name: new RegExp(name, 'i') });
};
const doc = await new Login({
account:"b07901029"
}).save().catch(dbCatch)//throw error if error occur
//只找一個
const doc = await Login
.findOne(query, selector)
.catch(err=>{})
//找多個
const docs = await Login
.find(query,selector)
.catch(err=>{})
const {updateQuery} = require(../Schemas/query)
//updateQuery會把特定的object轉成mongoose看得懂的格式
//簡單說就是依據value是不是空字串,把value塞進{$set,$unset}
const {title} = req.body
const update = updateQuery({'title.title':title})
//update = {$set:{'title.title':title}}
const {n,nModified} = await Recruitment
.updateOne(query,update,option)
.catch(err=>{})
/*{
n, //number of matched doc
nModified //number of modified doc
}*/
loginModel.deleteMany(query,function(err){});
Learn Coding Websites
codecadamy(HTML, CSS, JS)
freeCodeCamp youtube channel
Ric's Course
link
Node.js & Express.js & Mongo.js
w3school
express_Ric
Node.js full module list
Express.js MDN tutorial
Express.js & Node.js video
Ric's ppt