Interface for user information

  • Obtaining database resources
  • The databaseupdateupdate
  • EggFile resource processing

I. Access to user information

Let’s cut to the chase. First open /app/controller/user.js and add the getUserInfo method as follows:

// Get user information
async getUserInfo() {
 const { ctx, app } = this;
 // Use app.jwt.verify to parse the user information inside the token
 const token = ctx.request.header.authorization;
 const decode = app.jwt.verify(token, app.config.jwt.secret);
 // use the getUserByName method to obtain information about the username from the database using the username decode
 const userInfo = await ctx.service.user.getUserByName(decode.username);
 // userInfo should have password information, so specify the following four items to return to the client
 ctx.body = {
   code: 200.msg: 'Request successful'.username: userInfo.username,
   signtrue: userInfo.signtrue,
   avatar: userInfo.avatar || defaultAvatar,
 };
}
Copy the code

Detailed comment information has already been added to the code, so I won’t go over it.

The interface is then thrown and authentication middleware is added as follows:

//router.js
router.get('/api/user/get_userinfo', _jwt, controller.user.getUserInfo); // Get user information
Copy the code

Verify the feasibility of the structure directly through Postman, as shown below:

Note that you need to add the authorization attribute to Headers with the token information returned by the previous login interface.

/controller/user.js, create a new editUserInfo method and add the following code:

// Modify the signature
async editUserInfo() {
  const { ctx, app } = this;
  // Obtain the signature field in the request body by post request
  const { signature = ' ' } = ctx.request.body;

  try {
    let user_id;
    const token = ctx.request.header.authorization;
    // Decrypt the user name in the token
    const decode = app.jwt.verify(token, app.config.jwt.secret);
    if(! decode)return;
    // eslint-disable-next-line prefer-const
    user_id = decode.id;
    // Find the full information of userInfo by username
    const userInfo = await ctx.service.user.getUserByName(decode.username);
    // Use the service method editUserInfo to modify signature information.
    const result = awaitctx.service.user.editUserInfo({ ... userInfo, signature, }); ctx.body = {code: 200.msg: 'Request successful'.data: {
        id: user_id,
        signature,
        username: userInfo.username,
      },
    };
  } catch (error) {
    console.log(error); }}Copy the code

Open /service/user.js and create a new editUserInfo to modify user information in the database.

// Modify user information
async editUserInfo() {
  const { app } = this;
  try {
    // Use app.mysql.update to specify the user table
    return await app.mysql.update('user', {
      // To modify the parameters, directly through... Expand operator expansion. params, }, {// Select a user whose ID is equal to params.id
      id: params.id,
    });
  } catch (error) {
    console.log(error);
    return null; }}Copy the code

At this point, in the router.js script, the interface is modified to throw:

router.post('/api/user/edit_userinfo', _jwt, controller.user.editUserInfo); // Modify the user signature
Copy the code

Open Postman to verify the interface is correct:

The database is successfully modified:

2. Modify the user profile picture

When it comes to changing users’ avatars, this is how it normally works on the front end. First, click on the user’s profile picture; Next, pop up a popup window or enter the mobile phone album, choose a picture you like, then upload the picture, and finally replace your own picture with the modified picture.

The above process involves one step, which is “upload picture”. Therefore, before writing and modifying the profile picture information interface, it is necessary to implement a “upload picture” interface. The function of uploading pictures is relatively broad, not only the profile picture needs to upload pictures, but also many other operations, such as moments, commodity pictures and so on. So create a new script in the Controller folder called upload.js as follows:

Next, analyze the logic of uploading a wave of images to the server.

  1. First of all, we need to call the upload interface in the front end, and bring the picture parameters. The specific how to bring them will be explained in the following code part.
  2. Receives the picture information from the front end of the server, which contains the picture path information and passes through the serverfs.readFileSyncMethod to read the image content and put it in a variable.
  3. Find a public place to store your picturesapp/public/uploadThe uploaded resources are stored here.
  4. throughfs.writeFileSyncMethod, write the image content to the folder created in step 3.
  5. Finally returns the picture address, basically the picture address structure isHost + IP + image name + suffixThe return path will be explained in detail in the following code.

Currently, there is no front-end project to upload images, so here is a simple HTML upload page, as shown below:

<! doctypehtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<input type="file" id="upload"/>
<script>
    // Get the DOM of the input tag
    const input = document.getElementById('upload')
    // Listen for his changes
    input.addEventListener('change'.(e) = >{
      // Get the uploaded file object
      let file = input.files[0]
      // Declare the FormData instance
      let formData = new FormData()
      // Add the instance attribute file
      formData.append('file', file)
      console.log('formData',formData);
      // Invoke the server upload interface
      fetch('http://localhost:7001/api/upload', {method: 'POST'.body: formData
      }).then(res= >{
        if (res.ok) {
          console.log('Upload successful')
          return res.json()
        }  else {
          console.log('Upload failed');
        }
      }).then(res= >{
        console.log('res is', res);
      }).catch(error= > console.log(error))
    })
</script>
</body>
</html>
Copy the code

The HTML function is very simple, is to upload the resource through the FormData instance encapsulation, sent to the server. Next, go to the server to receive the data, open upload.js and add the following code:

'use strict';

const fs = require('fs');
const moment = require('moment');
const mkdirp = require('mkdirp');
const path = require('path');

const Controller = require('egg').Controller;

class UploadController extends Controller {
  async upload() {
    const { ctx } = this;
    // You need to go to config/config.default.js to set the mode property of config.multipart to file
    const file = ctx.request.files[0];

    // Declare the path to the resource
    let uploadDir = ' ';

    try {
      // ctx.request.files[0] retrieves the first file. If the front end uploads multiple files, the array object can be traversed
      const f = fs.readFileSync(file.filepath);
      // Get the current time
      const day = moment(new Date()).format('YYYYMMDD');
      // Create a path to save the image
      const dir = path.join(this.config.uploadDir, day);
      / / the number of milliseconds
      const date = Date.now();
      // Create a directory if it does not exist
      await mkdirp(dir);
      // Return the path where the image is saved
      uploadDir = path.join(dir, date + path.extname(file.filename));
      // Write to folder
      fs.writeFileSync(uploadDir, f);
    } finally {
      // Clear temporary files
      await ctx.cleanupRequestFiles();
    }
    ctx.body = {
      code: 200.msg: 'Upload successful'.data: uploadDir.replace(/app/g.' '),}; }}module.exports = UploadController;
Copy the code

Analyze the resource upload interface logic from scratch. The first step is to install moment and mkdirp for timestamp conversion and new folder, respectively.

npm i moment mkdirp -S
Copy the code

Second, egg provides two modes for receiving files: file and stream. Use the familiar form file. So you need to go to config/config.default.js to configure the receiving mode:

config.multipart = { 
    mode: 'file' 
};
Copy the code

The multipart configuration item has many options, such as whitelist upload format customization and fileSize fileSize limits, which can be found in the documentation.

After the configuration is complete, you can obtain the file resources uploaded by the front-end in the form of CTx.request. files.

Read the file from fs.readfilesync (file.filepath) and save it in the f variable for future use.

Create an image save file path:

let dir = path.join(this.config.uploadDir, day);
Copy the code

This.config. uploadDir requires a global declaration for subsequent general use. The following declaration can be made in config/config.default.js:

// add your user config here
const userConfig = {
  // myAppName: 'egg',
  uploadDir: 'app/public/upload'
};
Copy the code

Create a directory with await mkdirp(dir). If it already exists, it will not be created again. The mkdirp method is already implemented internally.

Build the path to the file as follows:

// Finally, write the contents of the file to the above path as follows:
fs.writeFileSync(uploadDir, f)
Copy the code

Return path on success:

ctx.body = {
  code: 200.msg: 'Upload successful'.data: uploadDir.replace(/app/g.' '),}Copy the code

The important thing to note here is that app needs to be removed, because app is not needed when the front-end accesses the path, such as port 7001 when the project is started. Finally access to the file path is http://localhost:7001/public/upload/20220114/1642175834885.png.

Once you have done that, you need to take the final step to resolve cross-domain. NPM I egg-cors install the egg-cors plugin. Once installed, go to config/plugins.js and add the following attributes:

cors: {
  enable: true.package: 'egg-cors',}Copy the code

Then configure config.default.js as follows:

config.cors = {
  origin: The '*'.// Allow all cross-domain access
  credentials: true.// Allow cookies to cross domains
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'};Copy the code

After the above logic is complete, open the front-end page written before and click upload picture as follows:

App /public folder on the server:

When you access the image path through the browser, the following indicates that the image has been successfully uploaded to the server:

Once you have the address of the image returned by the server, you can submit it to the editUserInfo method. Add the following parameters to the editUserInfo method:

// Modify user information
async editUserInfo() {
  const { ctx, app } = this;
  // Obtain the signature field in the request body by post request
  const { signature = ' ', avatar = ' ' } = ctx.request.body;

  try {
    let user_id;
    const token = ctx.request.header.authorization;
    // Decrypt the user name in the token
    const decode = app.jwt.verify(token, app.config.jwt.secret);
    if(! decode)return;
    // eslint-disable-next-line prefer-const
    user_id = decode.id;
    // Find the full information of userInfo by username
    const userInfo = await ctx.service.user.getUserByName(decode.username);
    // Use the service method editUserInfo to modify signature information.
    const result = awaitctx.service.user.editUserInfo({ ... userInfo, signature, avatar, }); ctx.body = {code: 200.msg: 'Request successful'.data: {
        id: user_id,
        signature,
        username: userInfo.username,
        avatar,
      },
    };
  } catch (error) {
    console.log(error); }}Copy the code

The above code, in the add avatar parameters, and the incoming CTX. Service. User. Save editUserInfo method.

Third, upload resources to expand knowledge

The above methods are used when there is no OSS service. At present, more methods in the market are to purchase OSS service, upload static resources such as pictures to THE CDN, and let users access online resources in the form of content distribution. This is a way to optimize the site’s performance by reducing the number of resource requests under the main domain name, thus reducing the latency of web page loading.

Qiuniuyun provides 10GB storage space for free. If you have a domain name and have recorded it, you can use it to realize a CDN service and store file resources in Qiuniuyun, so as to reduce the storage pressure of your server.

4. To summarize

Now that you’ve written three more interfaces, you’ll feel much easier writing the server than the front end.

No, every job has its own difficulties. The front end is more oriented to the browser, and the browser and the user is a one-to-one relationship, the front end is more focused on the visual and interactive experience, so that users in the most easy-to-use way to complete their demands.

On the other hand, the server is a piece of server code that serves multiple terminals, so the server is more of a one-to-many relationship. This is a test of server-side code, as well as database efficiency. When the traffic peak can respond well to each user’s request, the extreme case is the request level of Tmall Double 11, the pressure on the server is unimaginable.

This project is for learning and practicing, not concurrency or security.