Notes on node blog project development

Time:2021-8-2

Nodejs development personal blog project

Preview address:http://baijiawei.top

GitHub address:https://github.com/bjw1234/blog

Modules to be installed

  • Body parser parses post requests
  • Cookies read / write cookies
  • Express build server
  • Markdown syntax parsing generator
  • Mongoose operation mongodb database
  • Swig template parsing engine

directory structure

  • DB database storage directory
  • Models database model file directory
  • Public public file directory (CSS, JS, IMG)
  • Routers routing file directory
  • Schema database structure file
  • Views template view file directory
  • App.js startup file
  • package.json

App.js file

1. Create application and listening ports

const app = express();

app.get('/',(req,res,next) => {
    res.send("Hello World !");
});
app.listen(3000,(req,res,next) => {
    console.log("app is running at port 3000");
});

2. Configure application template

  • Define the template engine to use app.engine(‘html’,swig.renderFile) Parameter 1: the name of the template engine, which is also the suffix of the template file. Parameter 2: represents the method used to parse and process the template content
  • Set the directory where template files are stored app.set(‘views’,’./views’)
  • Register the template engine used app.set(‘view engine’,’html’)

3. Use the template engine to parse the file

/**
 *Read the specified file in the views directory, parse it and return it to the client 
 *Parameter 1: template file
 *Parameter 2: parameters passed to the template 
 */
 
res.render('index',{
    Title: 'home page',
    content: 'hello swig'
});

4. It is necessary to cancel the restriction of template cache during development

swig.setDefaults({
  cache: false
});

app.set('view cache', false);

5. Set static file hosting

//When the user accesses a file under the / public path, it returns directly
app.use('/public',express.static(__dirname + '/public'));

Partition module

  • Foreground module
  • Background module
  • API module
//Divide modules according to different functions
app.use('/',require('./routers/main'));
app.use('/admin',require('./routers/admin'));
app.use('/api',require('./routers/api'));

For the administrator module admin.js

var express = require('express');
var router = express.Router();

//For example, visit / admin / user
router.get('/user',function(req,res,next) {
    res.send('User');
});

module.exports = router;

Foreground routing + template

  • Main module
    /Front page
    /View content page
  • API module
    /Front page
    /Register user registration
    /Login user login
    /Comment comment get
    /Comment / post comment submission

Background (admin) routing + template

  • home page
    /Background home page
  • user management
    /User user list
  • Classification management
    /Category classification list
    /Category / Add Category addition
    /Category / edit category modification
    /Category / delete category deletion
  • Article content management
    /Article Nei content list
    /Article / add content addition
    /Article / edit content modification
    /Article / delete content deletion
  • Comment content management
    /Comment comment list
    /Comment / delete

Function development sequence

Functional module development sequence

  • user
  • column
  • content
  • comment

Coding order

  • Design data storage structure through schema definition
  • Functional logic
  • Page display

Connect to database (mongodb)

Start mongodb server:
mongod –dbpath=G:\data\db –port=27017
Start the service and set the storage address and port of the database

var mongoose = require('mongoose');
//Linked database
mongoose.connect("mongodb://localhost:27017/blog",(err) => {
    if(err){
        Console.log ("database connection failed");
    }else{
        Console.log ("database connection succeeded");
      //Start the server and listen on the port  
      app.listen(3000,(req,res,next) => {
            console.log("app is running at port 3000");
        });
    }
});

Define data table structure and model

For the user data table (users. JS), under the schema folder:

var mongoose = require('mongoose');
module.exports = new mongoose.Schema({
    //User name
   username:String,
   //Code
   password:String
});

Create the user.js model class in the models directory

var mongoose = require('mongoose');
var userSchema = require('../schemas/users');

module.exports = mongoose.model('User',userSchema);

Process user registration

  • The front end submits the user name and password through Ajax

url: /api/register

  • Back end data parsing for front end submission (post)
var bodyParser = require('body-parser');
//Bodyparser configuration
//By using this method, you can add a body attribute to the req object
app.use( bodyParser.urlencoded({extended:true}));

//In the API module:
//1. A middleware can be defined to unify the return format
var responseData;
Router. Use (function (req, res, next) {// the default path is' / '. This middleware is called when accessing this directory
    responseData = {
         code:0,
       message:''
    };
    next();
});

router.post('/register',(req,res,next) => {
    console.log(req.body);
   //To determine whether the user name and password are legal
   //Determine whether the user name has been registered
   //Return JSON data to the client through res.json (responsedata)
   
   //Query database
   User. Findone ({// returns a promise object
           username: username
   }).then(function( userInfo ) {
           If (userinfo) {// this record exists in the database
            ...
          res.json(responseData);
          return;
       }
       //Add this information to the database
       var user = new User({ username:username,password:password });
       return user.save(); //  Return promise object
   }).then(function( newUserInfo ){
            console.log(newUserInfo);
       res.json(responseData);  //  Data saved successfully  
   });
});

Use of cookies module

  • Global (app. JS) registration
//Set cookies
//As long as the client sends a request, it will pass through this middleware
app.use((req, res, next) => {
    req.cookies = new cookies(req, res);

    /**
     *Parsing user's cookie information
     *Whether to query the database as isadmin
     *Note: querying the database is an asynchronous operation, and next should be placed in the callback
     */
    req.userInfo = {};
    if (req.cookies.get("userInfo")) {
        try {
            req.userInfo = JSON.parse(req.cookies.get("userInfo"));
            //Query the database to determine whether it is an administrator
            User.findById(req.userInfo._id).then(function (result) {
                req.userInfo.isAdmin = Boolean(result.isAdmin);
                next();
            });
        } catch (e) {
            next();
        }
    } else {
        next();
    }
});

//When a user logs in or registers successfully, cookies can be set for him / her
req.cookies.set("userInfo",JSON.stringify({
     _id:result._id,
    username:result.username 
}));

Swig template engine

1. Variables
{{ name }}

2. Properties
{{ student.name }}

3. If judgment
{% if name = = = ‘Guo Jing’%}
Hello, brother Jing
{ % endif % }

4. For loop
// arr = [1, 2, 3]
{ % for key, val in arr % }
<p>{ { key } } — { { val } }</p>
{ % endfor % }

5. Set command
Used to set a variable for reuse in the current context

{% set foo = [0, 1, 2, 3, 4, 5] %}

  • {% extends ‘layout.html’ %} //Inherit an HTML template
  • {% include ‘page.html’ %} //Contains a template to the current location
  • {% block main %} xxx {% endblock %} //Rewrite a block

6. Autoscape automatic coding
When you want to display the HTML code generated by the back end in a div, the template will be automatically encoded when rendering,
Displayed as a string. This can be avoided by:

 <div id="article-content" class="content">
    {% autoescape false %}
    {{ data.article_content_html }}
    {% endautoescape %}
</div>

User management and paging

  • Crud user data
const User = require('../models/user');

//Query all user data
User.find().then(function(users){

});

//Query data according to a field
User.findOne({
    username:username
}).then(function(result){

});

//Query data according to user ID
User.findById(id).then(function(user){

});

//Delete data by ID
User.remove({
    _id: id
}).then(function(){

});

//Modify data
User.update({
    _id: id
},{
    username: name
}).then(function(){
    
});
  • Data paging management

Two important methods
Limit (number): limit the number of data pieces obtained
Skip (number): ignores the first number of data

Number of ignored entries: (current page – 1) * number of entries displayed per page

//Receive the transmitted page
let query_page = Number(req.query.page) || 1;
query_ page = Math.max(query_ page, 1);  //  The minimum limit is 1
query_ page = Math.min(Math.ceil(count / limit), query_ page); //  Limit Max count / limit rounded up


var cur_ page = query_ page;  //  Current page
var limit = 10; //  Number of items displayed per page
var skip = (cur_ page - 1) * limit; // Number of ignored entries

User.find().limit(limit).skip(skip).then(function(users){
    ...
  //Pass current page to page
  //Pass Max page number maxpage to page
});

Table structure of article

//For content.js
var mongoose = require('mongoose');
var contentSch = require('../schemas/contentSch');

module.exports = mongoose.model('Content',contentSch);


// contentSch.js
module.exports = new mongoose.Schema({
    
   //Associated field - ID of the classification
   category:{
        //Type
        type:mongoose.Schema.Types.ObjectId,
        //Quote
        ref:'Category'  
    },
    
    //Content title
    title: String,
    
    //Introduction
    description:{
        type: String,
        default: ''  
    },
    
    //Content
    content:{
        type:String,
        default:''
    }
});

//Associated category field during article query
Content.find().populate('category').then(contents => {
    //In this way, we can find the content in the content table
   //Associated information content.category.category_ name 
});

Markdown syntax highlighting

  • Use directly in HTML
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
<script></script>

<script></script>

//Marked related configuration
marked.setOptions({
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
    highlight: function (code) {
        return hljs.highlightAuto(code).value;
    }
});

//Markdown syntax parsing content preview
$('#bjw-content').on('keyup blur', function () {
    $('#bjw-previous').html(marked($('#bjw-content').val()));
});
  • Used in node environment
//Introducing default styles in template pages
<!-- Syntax highlighting -- >
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">

const marked = require('marked');
const hljs = require('highlight.js');

//Marked related configuration
marked.setOptions({
    renderer: new marked.Renderer(),
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false,
    highlight: function (code) {
        return hljs.highlightAuto(code).value;
    }
});

//Mark down syntax conversion for content
data.article_content_html = marked(article.content);

Enables text fields to support tab indentation

$('#bjw-content').on('keydown',function(e){
    If (e.keycode = = = 9) {// tab
         var position = this.selectionStart + 2; //  Tab = = = two spaces
       this.value = this.value.substr(0,this.selectionStart) + "  " + this.value.substr(this.selectionStart);
       this.selectionStart = position;
       this.selectionEnd = position;
       this.focus();
       e.preventDefault();
    }
});

Layer bullet

//Show pop ups
function showDialog(text, icon, callback) {
    layer.open({
        time: 1500,
        anim: 4,
        offset: 't',
        icon: icon,
        content: text,
        btn: false,
        title: false,
        closeBtn: 0,
        end: function () {
            callback && callback();
        }
    });
});

Random user avatar generation

//Import corresponding library
const crypto = require('crypto');
const identicon = require('identicon.js');

//When a user registers, a random avatar is generated according to the user's user name
let hash = crypto.createHash('md5');
hash.update(username);
let imgData = new identicon(hash.digest('hex').toString());
let imgUrl = 'data:/image/png;base64,'+imgData;

Small problems in form submission

When using the form to submit some code, the browser will intercept it. The reason is that the browser mistakenly thinks that the customer is carrying out XSS attack. Therefore, it is also very simple to solve this problem, that is, to encode the submitted content in Base64 or other forms and decode it on the server.

Project address:https://github.com/bjw1234/blog

Finish scattering flowers ^ ^ ^ ^~

Recommended Today

Implementation example of go operation etcd

etcdIt is an open-source, distributed key value pair data storage system, which provides shared configuration, service registration and discovery. This paper mainly introduces the installation and use of etcd. Etcdetcd introduction etcdIt is an open source and highly available distributed key value storage system developed with go language, which can be used to configure sharing […]