Project introduction
Some time ago led the interim gave a small demand, to do a simple meeting report, to meet conference form content to add and delete, file uploads and downloads and user login validation, so taking advantage of the stroke to write, watch online for this tutorial is not a lot, so I write this article, is a basic article introduction to the whole development of the stack, Don’t spray big guy.
The following is the project address, hope to give a STAR, encourage:
Making the address
Effect preview:
Technology stack
The front end of the project is based on Vue, the back end is based on NodeJS-Express, and the database is Mongodb.
The front end
It is mainly based on VUe-CLI
The UI framework is: element-UI
CSS using SCSS
The login page uses the Element-UI form component, not a separate page, forgive me for being lazy…
The front end is more than described, that is, the same old, specific can see the code.
The project structure is (roughly) as follows:
├ ─ ─ pulic │ └ ─ ─ index. The HTML ├ ─ ─ the SRC │ ├ ─ ─ assets │ ├ ─ ─ the components / / main component │ └ ─ ─ the plugin / / element plug-in │ └ ─ ─ App. Vue │ ├─ ├─ ├─ └─ ├─ environment variablesCopy the code
Tip: Simple structure, mainly axios package, component Element +bootstrap.
The back-end
The backend uses Nodejs, the framework uses Express, this can be based on personal interest, Koa, NestJS, Hapi can be. Don’t judge too much.
Third party libraries used in back-end projects are listed as the most important.
< span style = "max-width: 100%; clear: both; min-height: 1em; "Bcryptjs" : "^ 2.4.3", / / solve the cross-domain "cors" : "^ 2.8.5", / / here is to express the next version of the "express" : "^ 5.0.0 - alpha. 7", / / "HTTP - assert" : ^1.4.1", // The most popular cross-domain authentication "jsonWebToken ": "^8.5.1", // a mongoose object modeling tool for asynchronous working environment: "^5.7.13"," Morgan ": "^" 1.9.1, / / express middleware download upload document "multer" : "^ 1.4.2",}Copy the code
The project structure of the back end is as follows, which is self-built and is best followed by specifications.
│ ├ ─ ─ middleware / / custom middleware │ ├ ─ ─ models / / definition of the table structure │ ├ ─ ─ the plugin / / database configuration file │ │ │ ├ ─ ─ routes / / routing file │ │ │ └ ─ ─ uploads / / │ ├─ index.js // Project entry fileCopy the code
The database
The database is used here is mongodb, specific but more introduction.
The table structure is as follows:
Form data model
const mongoose = require('mongoose')
// Create the model
const schema = new mongoose.Schema({
date: { type: Date },
iteminfo: [{road_name: { type: String },
road_lat: { type: Number },
road_lng: { type: Number },
ys_state: { type: String },
ws_state: { type: String },
issus_list: { type: String },
list_before_url: [{ name: { type: String }, url: { type: String}}].list_after_url: [{ name: { type: String }, url: { type: String}}].remark: { type: String}}}])// Export the model
module.exports = mongoose.model('FightInfo', schema)
Copy the code
The user model
const mongoose = require('mongoose')
const schema = new mongoose.Schema({
username: { type: String },
password: {
type: String,
set(val) {
return require('bcryptjs').hashSync(val, 10)}}})module.exports = mongoose.model('User', schema)
Copy the code
Tip: The table structure is simple. Both table structure models are under the Model folder
Front end separation
The project is developed in a separate front and back end way. Express provides AN API interface for access filtering (routing), validation (JSON-Web-token) and some knowledge and skills of Mongoose operating mongooDB database.
-
Start the Express master file as follows
const express = require('express') const logger = require('morgan') const app = express() // Request logger for easy debugging app.use(logger('dev')) / / support json app.use(express.json()) // Resolve cross-domain app.use(require('cors') ())// Static folder upload and download files app.use('/uploads', express.static(__dirname + '/uploads')) // Static folder app.use('/json', express.static(__dirname + '/plugin/json')) // Connect to the database file require('./plugin/db/config')(app) // How to operate the form require('./routes/fightinfo')(app) // User login authentication require('./routes/user')(app) app.use(async (err, req, res, next) => { res.status(err.statusCode || 500).send({ message: err.message }) }) app.listen(3001, () = > {console.log('http://127.0.0.1:3001/')})Copy the code
-
Database connection
//mongodb database configuration connections module.exports = app= > { const mongoose = require('mongoose') mongoose.connect('mongodb://localhost/vue-fight-direct', { useNewUrlParser: true.useUnifiedTopology: true.useFindAndModify: false})}Copy the code
-
Write routes for user authentication
Tip: Here is the route for the user to log in and register, since there is no registration page (I’m just doing an interactive feature here, like an excuse for my laziness). , you can use the third-party tool PostMan for registration verification, the field can be based on the user model, that is (username, password). If you do not register the data to add, delete, change and check, the need for login verification.
module.exports = app= > { const express = require('express') const router = express.Router() const jwt = require('jsonwebtoken') const bcryptjs = require('bcryptjs') // Import the user model file const User = require('.. /.. /models/User') app.set('secret'.'ashjhdjhasjdidh') // User login router.post('/login'.async (req, res) => { const { username, password } = req.body // Check whether the user exists const user = await User.findOne({ username }) if(! user) {return res.status(422).send({ message: 'User does not exist'})}// Check whether the password is correct const isValid = bcryptjs.compareSync(password, user.password) if(! isValid) {return res.status(422).send({ message: 'Password error'})}/ / send the token const token = jwt.sign({ id: user._id }, app.get('secret')) res.send({ token: token, message: 'Successful landing'})})// User registration router.post('/register'.async (req, res) => { const model = await User.create(req.body) res.send(model) }) app.use('/api/rest/user', router) } Copy the code
-
Write form-specific Action (CRUD) routes
module.exports = app= > { const express = require('express') const multer = require('multer') const FightInfo = require('.. /.. /models/FightInfo') const router = express.Router({ mergeParams: true }) const storage = multer.diskStorage({ destination: (req, file, cb) = > { cb(null.'./uploads')},filename: (req, file, cb) = > { cb(null, file.originalname) } }) const upload = multer({ storage: storage }) // User authentication middleware const authMiddleWare = require('.. /.. /middleware/auth') // Add the form router.post('/', authMiddleWare(), async (req, res) => { await FightInfo.create(req.body) res.send({ message: 'Form added successfully'})})// Modify the form information router.put('/:id', authMiddleWare(), async (req, res) => { await FightInfo.findByIdAndUpdate(req.params.id, req.body) res.send({ message: 'Saved successfully'})})// Get a single form router.get('/:id'.async (req, res) => { const items = await FightInfo.findById(req.params.id) res.send(items) }) // Get all the forms router.get('/'.async (req, res) => { const items = await FightInfo.find().sort({ date: - 1 }) res.send(items) }) // File upload app.post('/api/rest/upload', upload.single('file'), async (req, res) => { req.file.url = `http://localhost:3001/uploads/${req.file.filename}` await res.send(req.file) }) app.use('/api/rest/fightinfo', router) } Copy the code
-
User authentication middleware
module.exports = options= > { return async (req, res, next) => { const jwt = require('jsonwebtoken') const token = String(req.headers.authorization || ' ').split(' ').pop() // Check whether there is a token if(! token) {return res.status(401).send({ message: 'Invalid token'})}// Check whether the user exists const userid = jwt.verify(token, req.app.get('secret')).id if(! userid) {return res.status(401).send({ message: 'User does not exist' }) } next() } } Copy the code
Project details
The new form
Users can select a new form to record a meeting, but only after logging in can they have the permission.
When the user logs in for the first time, there is no form information, so he can select a new form to add content.
New combat object
Users can select to add a single object in the form to record the meeting. Login is not required, but permission authentication is required to save the meeting.
The login
Authentication is required for user login. The front-end login returns a token to the background and saves the token into the session. Authentication is required for saving and adding tokens.
Other features
You can edit the content in the form, save it into the library after each edit, and upload files and download.
insufficient
Upload files and download files. There is no permission authentication, so you can upload files without logging in. Of course, you can add specific permission authentication by referring to the component upload in Element-UI.
conclusion
In fact, the whole project is very simple, nothing more than add, delete, change and check, but this is also a complete full stack of actual combat, including user login registration, interface authority verification, etc.. Technology stacks (Vue, Express, mongodb) are also popular and meaningful for beginners.
Hope you don’t hesitate to give advice, if possible, give a star to encourage:
Making the address