[Jingtao e-commerce] user module

1, User login

thinking
The front end transmits the user name and password entered by the user to the back end, and the back end queries the database based on this condition. If the data is found, it indicates that the user exists, otherwise the user does not exist and will not log in.

MD5 encryption

In general, the password we enter cannot be stored in the database. This is very unsafe. In case some hackers are powerful and get the database, it is not very dangerous. Therefore, when saving data, we must encrypt the password in advance and then store the data. Here, MD5 encryption is generally used. This encryption method is irreversible, There is no decryption operation; However, you can now Baidu MD5, which is arrogant. There must be a website for online MD5 decryption. The principle is that you use the computer to calculate all the splicing possibilities for those letters, and then find the same and crack it. In this way, it is actually very dangerous. Therefore, you need "salt value" and a character behind your password, The general salt value is specified by the company. The password cracked in this way must be wrong. In the springboot project, there is such an encryption method
Similarly, if you search for data, you only need to encrypt the password in the same encryption method to query the database.

String md5 = DigestUtils.md5DigestAsHex(password.getBytes());

No salt value is added to the above code
In fact, if hackers really know your database, they will know what your salt value is by cracking a few, so you can add the field "salt value" to the data, and then the salt value is randomly generated by UUID, which is absolutely safe!!!

UUID

Concept:
UUID is a concept proposed by the international organization for Standardization (ISO). UUID is a 128 bit value, which can be calculated by a certain algorithm. In order to improve efficiency, the commonly used UUID can be shortened to 16 bits. UUID is used to identify the attribute type and is regarded as a unique identifier in all space and time. Generally speaking, this value can be guaranteed to be truly unique, and any UUID generated anywhere will not have the same value. One benefit of using UUIDs is that new identifiers can be created for new services. In this way, when searching for a service, the client only needs to indicate the UUID related to a certain type of service (or a specific service) in its service search request. If the service provider can match the available service with this UUID, it will return a response.
During the login process, you must transfer the unique ID. springboot also has a special method. Because the UUID is generally in the style of xxx xxx xxx..., you usually take "-"

//6. Use UUID to dynamically generate TOKEN, which is generated according to the number of milliseconds + random number + hash algorithm of the current time, which can almost ensure no repetition
String token = UUID.randomUUID().toString()
                .replace("-", "");

token
1. Since the server needs to identify the logged in user, the server dynamically generates a unique token and returns it to the user
2. The user saves the token locally, which is convenient to carry during the next visit
Therefore, it is only necessary to determine whether the user can log in according to whether the non null token value is transmitted
Business layer service:

	@Override
    @Transactional
    public String login(User user) {
        //1. Get plaintext
        String password = user.getPassword();
        //2. Encryption processing
        String md5 = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(md5);
        //Query the database and obtain the database object
        User userDB = userMapper.selectOne(new QueryWrapper<User>(user));
        //5. Judge whether the login is correct
        if (userDB == null) {
            return null;
        }
        //6. Use UUID to dynamically generate TOKEN, which is generated according to the number of milliseconds + random number + hash algorithm of the current time, which can almost ensure no repetition
        String token = UUID.randomUUID().toString()
                .replace("-", "");
        return token;
    }

Control layer controller:

	@PostMapping("/login")
    public SysResult login(@RequestBody User user) {
        //Requirement: after successful login, return value identifier information
        String token = userService.login(user);
        //If the token is null, the login fails
        if (token == null || token.length() == 0) {
            return SysResult.fail();
        }
        //Otherwise, return correctly
        return SysResult.success(token);
    }

Session and Cookie

In the page, when you jump to the page, you need to know whether there is a user login, otherwise you can't jump to the page, so you need to store the token value in a container. The page gets the value in the container and knows that you have logged in, so jump is allowed. The container here uses the session. Of course, when you mention the session and the cookie.

1.Session Introduction

Session: in computers, especially in network applications, it is called "session control". The session object stores the properties and configuration information required for a specific user session. In this way, when the user jumps between the Web pages of the application, the variables stored in the session object will not be lost, but will exist throughout the user session. When a user requests a Web page from an application, if the user does not have a session, the Web server will automatically create a session object. When a session expires or is abandoned, the server terminates the session. One of the most common uses of the session object is to store user preferences. For example, if you indicate that you don't like viewing drawings, you can store this information in the session object. For more information about using session objects, see "managing sessions" in the ASP applications section. Note that session state is reserved only in browsers that support cookie s.

Summary:
1) Session is called "session mechanism"
2) Opening a web page in a browser is a conversation
3) The user's data can be saved to the session, but there is a life cycle. When the session is closed, the data disappears

2.Cookie mechanism

Cookie s, sometimes in the plural. The type is "small text file", which is the data (usually encrypted) stored on the user's local terminal by some websites in order to identify the user's identity and track the Session, and is temporarily or permanently saved by the user's client computer.
explain:
1) A cookie is a small text file
2) The data stored in cookie s is usually ciphertext
3) The life cycle of the data in the cookie is controllable. A few days. A few years!!!

3. Difference between session and cookie

1) session data is temporarily stored. cookie data can be permanently saved. (different life cycles)
2) Session is a memory object in the browser! A cookie is an actual local file
3) session generally stores some secret related data. Cookies generally store relatively public data (secret free login). (Security)

//Get user token information
let token = result.data
window.sessionStorage.setItem("token",token)

Full code:

login(){
      //Perform data verification after obtaining the form object
      //valid indicates the result of verification. true indicates passing. false indicates failure
      this.$refs.loginFormRef.validate(async valid => {
         //If the verification is not completed, return directly
         if(!valid) return

        //If the verification is successful, an ajax request is initiated
        const {data: result} = await this.$http.post('/user/login',this.loginForm)
        if(result.status !== 200) return this.$message.error("User login failed")
        this.$message.success("User login succeeded")

        //Get user token information
        let token = result.data
        window.sessionStorage.setItem("token",token)

        //After the user logs in successfully, jump to the home page
        this.$router.push("/home")
      })
    }

4. Route navigation guard

When talking about the jump page, you need to verify whether the user logs in. Here, you need to define the route navigation guard in the front-end index.js

/**
 * Define route navigation guard
 * Valuepoint 1 to the URL of the route jump
 * Parameter 2 where does the route from come from
 * Parameter 3 next is a function that indicates release or redirection
 *            next() Release
 *            next("/login") redirect
 * Business realization:
 *    Core logic: check whether there is a token
 *        A token indicates that you have logged in and released the request
 *        No token indicates that the user is not logged in and redirects to the login page
 *        If you visit the login page, you can release it directly
 */
router.beforeEach((to,from,next) => {
    if (to.path === "/login") {
      return next()
    }
    //It indicates that the page visited by the user is not a login request and needs to be verified
    //Get token data
    let token = window.sessionStorage.getItem("token")
    //The following if judgment is interpreted as: if the token is not null
    if (token) {
      return next()
    }
    next("/login")
})

2, Left menu page

Because it is nested, some small algorithms are used. Level is a level. Level 3 can only be nested to level 2, and so on_ The id attribute must use an id attribute with a level of 2, so we can first query in reverse order according to the level when obtaining data, and then start inserting the level of 3 into the level of 2

 	@Override
    public List<Rights> getRightsList() {
//        //Query level 1 list information
//        QueryWrapper<Rights> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("level", 1);
//        List<Rights> rightsList = rightsMapper.selectList(queryWrapper);
//        //Traverse the first level list
//        for (Rights rights : rightsList) {
//            queryWrapper.clear();
//            queryWrapper.eq("parent_id", rights.getId());
//            //Encapsulate the secondary query results into the primary object
//            rights.setChildren(rightsMapper.selectList(queryWrapper));
//        }
        QueryWrapper<Rights> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("level");
        List<Rights> rightsList = rightsMapper.selectList(queryWrapper);
        for (int i = 0; i < rightsList.size();i++) {
            Rights r = rightsList.get(i);
            String name = r.getName();
            String[] nameArr = name.split("-");
            r.setName(nameArr[nameArr.length-1]);
            if (r.getLevel() != 1) {
                for (int j = i + 1; j < rightsList.size(); j++) {
                    Rights r1 = rightsList.get(j);
                    if (r.getParentId() == r1.getId()) {
                        List<Rights> list = new ArrayList<>();
                        if (r1.getChildren() != null) {
                            list = r1.getChildren();
                        }
                        list.add(r);
                        r1.setChildren(list);
                        break;
                    }
                }
            }
        }
        List<Rights> rightsList1 = new ArrayList<>();
        for (Rights r : rightsList) {
            if (r.getLevel() == 1) {
                rightsList1.add(r);
            }
        }
        return rightsList1;
    }

3, User list display and CRUD operation

1. User list

Note the router here, because the user list is only a sub component of home. If a route is added between them, the user list will cover the whole page, so it needs to be nested. The children attribute of the route is used here
Add components in index.js

import User from '../components/user/user.vue'

nesting

The user's information must be paged

<!-- User data table presentation  border Border line properties  -->
       <el-table :data="userList" border stripe>
           <el-table-column type="index" label="Serial number"></el-table-column>
           <el-table-column prop="username" label="user name"></el-table-column>
           <el-table-column prop="phone" label="Telephone"></el-table-column>
           <el-table-column prop="email" label="mailbox"></el-table-column>
           <el-table-column prop="status" label="state">
             <!--Defines the scope slot to get the current row element-->
             <template slot-scope="scope">
                <el-switch v-model="scope.row.status" @change="updateStatus(scope.row)"
                  active-color="#13ce66" inactive-color="#ff4949">
                </el-switch>
             </template>
           </el-table-column>
           <el-table-column label="operation">
             <template slot-scope="scope">
                <el-button type="primary" icon="el-icon-edit" size="small" @click="updateUserBtn(scope.row)"></el-button>
                <el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
             </template>

           </el-table-column>
       </el-table>

       <!-- Define the property description of the paging component about the paging plug-in
            1.@size-change This event will be triggered if the number of implemented entries per page in paging changes
            2.@current-change When the number of pages changes,Trigger the function
            3.current-page Currently selected page
            4.page-sizes   Options for page data presentation
            5.page-size    Number of pages selected by default
            6.layout    Type of data displayed in paging
            7.total     Total records
       -->
        <el-pagination
             @size-change="handleSizeChange"
             @current-change="handleCurrentChange"
             :current-page="queryInfo.pageNum"
             :page-sizes="[5, 10, 20, 40]"
             :page-size="queryInfo.pageSize"
             layout="total, sizes, prev, pager, next, jumper"
             :total="total">
        </el-pagination>

In the back end, our traditional method is to use limit to limit

	@Override
    public PageResult getUserList(PageResult pageResult) {
        //1. Get total pages Integer -- long automatic conversion
        long total = userMapper.selectCount(null);
        //2. Get paging results
        int size = pageResult.getPageSize();
        int start = (pageResult.getPageNum() - 1) * size;
        List<User> userList = userMapper.findListByPage(start,size);
        pageResult.setTotal(total)
                .setRows(userList);
        return pageResult;
    }

MP paging usage

However, because MP is used here, there is a special paging method, but the IPage class needs to be encapsulated first

/**
     * Business description: query database by MP
     * Step description:
     *      1.Build paging objects for MP
     *      2.Query data according to paging object
     *      3.Get data from paging object
     *      4.Encapsulates the PageResult object
     *      5.Edit the configuration class to encapsulate the paging interceptor
     */
    @Override
    @Transactional
    public PageResult getUserList(PageResult pageResult) {
        //1. Define paging objects
        IPage<User>  page = new Page<>(pageResult.getPageNum(), pageResult.getPageSize());
        //2. Define condition constructor
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //boolean flag = pageResult.getQuery() == null? false : true;
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username",pageResult.getQuery());
        //3. Perform paging query
        page = userMapper.selectPage(page,queryWrapper); //Interceptors must be added, otherwise the condition constructor will not take effect
        //Get data from the encapsulated paging object
        pageResult.setTotal(page.getTotal())
                .setRows(page.getRecords());
        System.out.println(page.getTotal());
        return pageResult;
    }

It turns out that it doesn't work. Why?

MP paging interceptor

After careful inspection, it is found that MP has no splicing where conditions at all. Check the official website and find that interceptors need to be set
Location: under config package

@Configuration
public class MybatisPlusConfig {
    //When MybatisPlus performs paging operations, it will be intercepted by this interceptor
    //Action of interceptor dynamic splicing where condition
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

2. Modify user status

Front end code:

<el-table-column prop="status" label="state">
	<!--Defines the scope slot to get the current row element-->
	<template slot-scope="scope">
		<el-switch v-model="scope.row.status" @change="updateStatus(scope.row)"
		active-color="#13ce66" inactive-color="#ff4949">
		</el-switch>
	</template>
</el-table-column>

Here is the switch in Element. When the data is true, execute active color, and when it is false, execute inactive color. Click @ change here to change the state immediately. After clicking, change the original true to false and pass it to js, and vice versa. It is worth mentioning that int type 1,0 in the database can correspond to Boolean type true and false in java

	//Rule: treat non null elements in the object as set conditions,
    //      Id as unique where condition
    @Override
    @Transactional
    public void updateStatus(User user) {
        userMapper.updateById(user);
    }

3. User add

The front end remembers to call the method of displaying the user list to update the data in time

	/**
     * explain:
     *      1.User warehousing operation
     *      Add status / creation time / update time
     *      2.Password encryption processing
     * @param user
     */
    @Override
    @Transactional
    public void addUser(User user) {
        String password = user.getPassword();
        //Encryption processing
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setStatus(true)
                .setPassword(password);
        userMapper.insert(user);
    }

4. Update user data

Query data by id

	@Override
    @Transactional
    public Object getUserById(Integer id) {
        return userMapper.selectById(id);
    }

Update user data according to id

//Non null elements are treated as set conditions, id unique and where conditions
    @Override
    @Transactional
    public void updateUser(User user) {
        userMapper.updateById(user);
    }

5. Delete data

Delete the data according to the id, but if the program makes an error, the user information cannot be deleted, but because the deletion operation is executed before the error, isn't it an accident?

@Transactional rollback

Here we will talk about the transaction function of SQL. Before execution, start the transaction, the whole program is executed successfully, and the transaction commits the transaction. Otherwise, rollback. @ Transactional here plays such a role. At the same time, its parameters can specify which exceptions are encountered and which exceptions do not need to be rolled back.

	/**
     * @Transactional Rule Description:
     *      1.If a runtime exception occurs, the transaction is rolled back
     *      2.If a compilation exception (check exception) occurs, the default rule is that the transaction is not rolled back
     *      3.Attribute description:
     *          noRollbackFor = {} Do not roll back when an exception is encountered
     *          rollbackFor = {} Encountered some kind of exception rollback
     * @param id
     */
    @Override
    @Transactional
    public void deleteUser(Integer id) {
        userMapper.deleteById(id);
    }
}

4, Partial complete code

front end

User login – login.vue

<!-- Define template objects -->
<template>
    <div class="login_container">
      <div class="login_box">
        <!-- Avatar area-->
        <div class="avatar_box">
          <img src="../assets/logo.png" alt="VUE picture" />
        </div>

        <!-- Login form area
              ref Represents the reference object of the current form
             :model Is an object encapsulated in a table
        -->
        <el-form ref="loginFormRef" label-width="0" class="login_form" :model="loginForm" :rules="rules" >
          <el-form-item prop="username">
            <el-input  prefix-icon="iconfont iconuser" v-model="loginForm.username"></el-input>
          </el-form-item>
          <el-form-item prop="password">
            <el-input  prefix-icon="iconfont iconsuo" type="password" v-model="loginForm.password"></el-input>
          </el-form-item>
          <el-form-item class="btns">
             <el-button type="primary" @click="login">Sign in</el-button>
              <el-button type="info" @click="resetBtn">Reset</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
</template>

<!-- definition JS variable -->
<script>
export default {
  data(){
    return {
      loginForm: {
        username: '',
        password: ''
      },
      //Define validation rules for forms
      rules: {
         //Define verification user name
         username: [
          { required: true, message: 'enter one user name', trigger: 'blur' },
          { min: 3, max:30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
         ],
         //Define verification password
         password: [
          { required: true, message: 'Please input a password', trigger: 'blur' },
          { min: 3, max:30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
         ]
      }
    }
  },
  methods: {
    resetBtn(){
      //this object represents the current component object
      //console.log(this)
      //Realize data reset
      this.$refs.loginFormRef.resetFields()
    },
    login(){
      //Perform data verification after obtaining the form object
      //valid indicates the result of verification. true indicates passing. false indicates failure
      this.$refs.loginFormRef.validate(async valid => {
         //If the verification is not completed, return directly
         if(!valid) return

         //If the verification is successful, an ajax request is initiated
        const {data: result} = await this.$http.post('/user/login',this.loginForm)
        if(result.status !== 200) return this.$message.error("User login failed")
        this.$message.success("User login succeeded")
        console.log(result)
        //Get user token information
        let token = result.data
        window.sessionStorage.setItem("token",token)

        //After the user logs in successfully, jump to the home page
        this.$router.push("/home")
      })
    }
  }
}
</script>

<!-- Prevent component conflicts -->
<style lang="less" scoped>
.login_container{
  background-color: #2b4b6b;
  height: 100%;
}

.login_box {
  width: 450px;
  height: 300px;
  background-color: #FFFFFF;
  /* Set arc angle*/
  border-radius: 10px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  .avatar_box {
    height: 130px;
    width: 130px;
    border: 1px solid #EEEEEE;
    border-radius: 50%;
    padding: 10px;
    box-shadow: 0 0 10px #DDDDDD; /*  Add shadow*/
    position: absolute;           /* Absolute positioning*/
    left: 50%;                    /* 50% to the left*/
    transform: translate(-50%,-50%);   /*Callback 50%*/
    background-color: #FFFFFF;
    img {
      height: 100%;
      width: 100%;
      border-radius: 50%;
      background-color: #EEEEEE;
    }
  }

  .btns {
    display: flex;
    justify-content: flex-end;

  }

  .login_form {
    position: absolute;
    bottom: 0;
    width: 100%;
    padding: 0 20px;
    box-sizing: border-box;
  }
}
</style>

Left menu bar – Home.vue

<!-- Define template objects -->
<template>
    <div class="login_container">
      <div class="login_box">
        <!-- Avatar area-->
        <div class="avatar_box">
          <img src="../assets/logo.png" alt="VUE picture" />
        </div>

        <!-- Login form area
              ref Represents the reference object of the current form
             :model Is an object encapsulated in a table
        -->
        <el-form ref="loginFormRef" label-width="0" class="login_form" :model="loginForm" :rules="rules" >
          <el-form-item prop="username">
            <el-input  prefix-icon="iconfont iconuser" v-model="loginForm.username"></el-input>
          </el-form-item>
          <el-form-item prop="password">
            <el-input  prefix-icon="iconfont iconsuo" type="password" v-model="loginForm.password"></el-input>
          </el-form-item>
          <el-form-item class="btns">
             <el-button type="primary" @click="login">Sign in</el-button>
              <el-button type="info" @click="resetBtn">Reset</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
</template>

<!-- definition JS variable -->
<script>
export default {
  data(){
    return {
      loginForm: {
        username: '',
        password: ''
      },
      //Define validation rules for forms
      rules: {
         //Define verification user name
         username: [
          { required: true, message: 'enter one user name', trigger: 'blur' },
          { min: 3, max:30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
         ],
         //Define verification password
         password: [
          { required: true, message: 'Please input a password', trigger: 'blur' },
          { min: 3, max:30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
         ]
      }
    }
  },
  methods: {
    resetBtn(){
      //this object represents the current component object
      //console.log(this)
      //Realize data reset
      this.$refs.loginFormRef.resetFields()
    },
    login(){
      //Perform data verification after obtaining the form object
      //valid indicates the result of verification. true indicates passing. false indicates failure
      this.$refs.loginFormRef.validate(async valid => {
         //If the verification is not completed, return directly
         if(!valid) return

         //If the verification is successful, an ajax request is initiated
        const {data: result} = await this.$http.post('/user/login',this.loginForm)
        if(result.status !== 200) return this.$message.error("User login failed")
        this.$message.success("User login succeeded")
        console.log(result)
        //Get user token information
        let token = result.data
        window.sessionStorage.setItem("token",token)

        //After the user logs in successfully, jump to the home page
        this.$router.push("/home")
      })
    }
  }
}
</script>

<!-- Prevent component conflicts -->
<style lang="less" scoped>
.login_container{
  background-color: #2b4b6b;
  height: 100%;
}

.login_box {
  width: 450px;
  height: 300px;
  background-color: #FFFFFF;
  /* Set arc angle*/
  border-radius: 10px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  .avatar_box {
    height: 130px;
    width: 130px;
    border: 1px solid #EEEEEE;
    border-radius: 50%;
    padding: 10px;
    box-shadow: 0 0 10px #DDDDDD; /*  Add shadow*/
    position: absolute;           /* Absolute positioning*/
    left: 50%;                    /* 50% to the left*/
    transform: translate(-50%,-50%);   /*Callback 50%*/
    background-color: #FFFFFF;
    img {
      height: 100%;
      width: 100%;
      border-radius: 50%;
      background-color: #EEEEEE;
    }
  }

  .btns {
    display: flex;
    justify-content: flex-end;

  }

  .login_form {
    position: absolute;
    bottom: 0;
    width: 100%;
    padding: 0 20px;
    box-sizing: border-box;
  }
}
</style>

User component page – user.vue

<template>
  <div>
    <!-- 1.Define breadcrumb navigation -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">home page</el-breadcrumb-item>
      <el-breadcrumb-item>user management </el-breadcrumb-item>
      <el-breadcrumb-item>User list</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 2.Define card view -->
    <el-card class="box-card">

       <!-- 3.Defines a row of the grid :gutter="20"Define row spacing   :span="9" placeholder   -->
       <el-row :gutter="20">
         <el-col :span="9">
            <!-- 3.Define search box -->
            <el-input placeholder="Please enter the content" v-model="queryInfo.query" clearable  @clear="getUserList">
                <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
            </el-input>
         </el-col>
         <el-col :span="4">
            <!-- Define add button-->
            <el-button type="primary" @click="dialogVisible = true">Add user</el-button>
         </el-col>
       </el-row>

       <!-- User data table presentation  border Border line properties  -->
       <el-table :data="userList" border stripe>
           <el-table-column type="index" label="Serial number"></el-table-column>
           <el-table-column prop="username" label="user name"></el-table-column>
           <el-table-column prop="phone" label="Telephone"></el-table-column>
           <el-table-column prop="email" label="mailbox"></el-table-column>
           <el-table-column prop="status" label="state">
             <!--Defines the scope slot to get the current row element-->
             <template slot-scope="scope">
                <el-switch v-model="scope.row.status" @change="updateStatus(scope.row)"
                  active-color="#13ce66" inactive-color="#ff4949">
                </el-switch>
             </template>
           </el-table-column>
           <el-table-column label="operation">
             <template slot-scope="scope">
                <el-button type="primary" icon="el-icon-edit" size="small" @click="updateUserBtn(scope.row)"></el-button>
                <el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
             </template>

           </el-table-column>
       </el-table>

       <!-- Define the property description of the paging component about the paging plug-in
            1.@size-change This event will be triggered if the number of implemented entries per page in paging changes
            2.@current-change When the number of pages changes,Trigger the function
            3.current-page Currently selected page
            4.page-sizes   Options for page data presentation
            5.page-size    Number of pages selected by default
            6.layout    Type of data displayed in paging
            7.total     Total records
       -->
        <el-pagination
             @size-change="handleSizeChange"
             @current-change="handleCurrentChange"
             :current-page="queryInfo.pageNum"
             :page-sizes="[5, 10, 20, 40]"
             :page-size="queryInfo.pageSize"
             layout="total, sizes, prev, pager, next, jumper"
             :total="total">
        </el-pagination>
    </el-card>

    <!-- Edit user new dialog box visible.sync Controls the display of dialog boxes-->
    <el-dialog title="Add user" :visible.sync="dialogVisible" width="50%" @close="closeDialog">

      <!-- Define user submitted form data
          UI Tool act ID attribute
      -->
      <el-form :model="addUserModel" :rules="rules" ref="addUserRef" label-width="100px" class="demo-ruleForm">
        <el-form-item label="user name" prop="username">
          <el-input v-model="addUserModel.username"></el-input>
        </el-form-item>
        <el-form-item label="password" prop="password">
          <el-input v-model="addUserModel.password" type="password"></el-input>
        </el-form-item>
        <el-form-item label="Password confirmation" prop="password2">
          <el-input v-model="addUserModel.password2" type="password"></el-input>
        </el-form-item>
        <el-form-item label="Telephone" prop="phone">
          <el-input v-model="addUserModel.phone"></el-input>
        </el-form-item>
        <el-form-item label="mailbox" prop="email">
          <el-input v-model="addUserModel.email"></el-input>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="addUserBtn">determine</el-button>
      </span>
    </el-dialog>

    <!-- Define modify page when dialog box closes,Reset table data-->
    <el-dialog title="Modify user" :visible.sync="updateDialogVisible" width="50%" @close="closeUpdateDialog">
      <!-- Define user submitted form data-->
      <el-form :model="updateUserModel" :rules="rules" ref="updateUserRef" label-width="100px">
        <el-form-item label="user name" prop="username">
          <el-input v-model="updateUserModel.username"  disabled ></el-input>
        </el-form-item>
        <el-form-item label="Telephone" prop="phone">
          <el-input v-model="updateUserModel.phone"></el-input>
        </el-form-item>
        <el-form-item label="mailbox" prop="email">
          <el-input v-model="updateUserModel.email"></el-input>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="updateDialogVisible = false" >Cancel</el-button>
        <el-button type="primary" @click="updateUser">determine</el-button>
      </span>
    </el-dialog>


  </div>
</template>

<script>

  export default {
    data(){
      //Data callback callback function for verifying mailbox rule rule value verification
      const checkEmail = (rule, value, callback) => {
        //The regular expression defining the mailbox uses / in JS to represent the beginning and end of the regular expression
        const emailRege = /^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$/
        //Regular expression syntax verification test(xx) returns true if the verification is successful and false if the verification fails
        if (emailRege.test(value)) {
          //Indicates that the mailbox is returned legally and correctly
          return callback()
        }
        callback(new Error('Please fill in the correct email address'))
      }

      //Mailbox rules for verifying mobile phone numbers
      const checkPhone = (rule, value, callback) => {

        //Defines the regular syntax for checking mobile phone numbers
        const phoneRege = /^1[34578][0-9]{9}$/
        if (phoneRege.test(value)) {

          return callback()
        }
        callback(new Error('Please fill in the correct mobile phone number'))

      }

      const checkPassword = (rule, value, callback) => {
        if(this.addUserModel.password !== value) return callback(new Error('2 Inconsistent password input'))
        //Otherwise, the verification is successful
        callback()
      }

      return {
        queryInfo: {
          query: '',
          pageNum: 1,
          pageSize: 5
        },
        userList: [],
        //The total number of records is a numeric type
        total: 0,
        dialogVisible: false,
        addUserModel: {
          username: '',
          password: '',
          password2: '',
          email:  '',
          phone:  ''
        },
        //Data verification rules
        rules: {
          username: [
                  { required: true, message: 'enter one user name', trigger: 'blur' },
                  { min: 3, max: 30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
                ],
          password: [
                  { required: true, message: 'Please input a password', trigger: 'blur' },
                  { min: 3, max: 30, message: 'The length is between 3 and 30 characters', trigger: 'blur' }
                ],
          password2: [
                  { required: true, message: 'Please input a password', trigger: 'blur' },
                  { min: 3, max: 30, message: 'The length is between 3 and 30 characters', trigger: 'blur' },
                  { validator: checkPassword , trigger: 'blur' }
                ],
          phone: [
                  { required: true, message: 'Please enter your mobile phone number', trigger: 'blur' },
                  { min: 3, max: 30, message: 'The length is between 3 and 30 characters', trigger: 'blur' },
                  { validator: checkPhone , trigger: 'blur' }
                ],
          email: [
                  { required: true, message: 'Please enter email address', trigger: 'blur' },
                  { min: 3, max: 30, message: 'The length is between 3 and 30 characters', trigger: 'blur' },
                  { validator: checkEmail , trigger: 'blur' }
                ]
        },
        updateDialogVisible: false,
        //Define and modify user data encapsulation
        updateUserModel: {
        }
      }

    },
    methods: {
      async getUserList(){
        const {data: result} = await this.$http.get('/user/list',{
           params: this.queryInfo
        })
        if(result.status !== 200) return this.$message.error("User list query failed")
        this.userList = result.data.rows
        this.total = result.data.total
        console.log("Total records:"+this.total)
      },
      async updateStatus(user){
         //To implement user state modification, pay attention to the new usage ${key} proposed in template string ES6
        //const {data: result} = await this.$http.put('/user/status/'+user.id+'/'+user.status)
        const {data: result} = await this.$http.put(`/user/status/${user.id}/${user.status}`)
        if(result.status !== 200) return this.$message.error("User status modification failed!")
        this.$message.success("User status modified successfully!")
      },
      handleSizeChange(pageSize){
        //console.log("number of pieces per page" + pageSize)
        this.queryInfo.pageSize = pageSize
        this.getUserList()
      },
      handleCurrentChange(pageNum){
        //console.log("pages:" + pageNum)
        this.queryInfo.pageNum = pageNum
        this.getUserList()
      },
      closeDialog(){
        //Reset table data
        this.$refs.addUserRef.resetFields()
      },
      //Verify user data
      addUserBtn(){
        this.$refs.addUserRef.validate(async valid => {
          //If the verification fails, stop the data
          if(!valid) return
          //console.log(this.addUserModel)
          const {data: result} = await this.$http.post('/user/addUser',this.addUserModel)
          if(result.status !== 200) return this.$message.error("Failed to add user")
          this.$message.success("User added successfully")
          //close dialog boxes
          this.dialogVisible = false
          //Retrieve user list
          this.getUserList()

        })
      },
      async updateUserBtn(user){
        this.updateDialogVisible = true
        const {data: result} = await this.$http.get("/user/"+user.id)
        if(result.status !== 200) return this.$message.error("User query failed")
        this.updateUserModel = result.data
      },
      closeUpdateDialog(){
        //Reset table data
        this.$refs.updateUserRef.resetFields()
      },
      updateUser(){
        //1. Pre check data
        this.$refs.updateUserRef.validate(async valid => {
           if(!valid)  return this.$message.error("Form validation failed")
           //Encapsulate data according to interface document requirements
           let user = {}
           user.id = this.updateUserModel.id
           user.phone = this.updateUserModel.phone
           user.email = this.updateUserModel.email
           const {data: result} = await this.$http.put(`/user/updateUser`,user)
           if(result.status !== 200) return this.$message.error("User modification failed")
           this.$message.success("User update succeeded")
           this.updateDialogVisible = false
           this.getUserList()
        })
      },
      async deleteUser(user){
         //1. Message confirmation box
         const result =  await this.$confirm('This operation will be permanently deleted '+user.username+', Continue?', 'Tips', {
                   confirmButtonText: 'determine',
                   cancelButtonText: 'cancel',
                   type: 'warning'
                 }).catch(error => error)

         //If confirm is confirmed, if cancel is cancelled
         if(result !== 'confirm'){
            this.$message.info("Delete cancel")
            return
         }
         const {data: result2} = await this.$http.delete(`/user/${user.id}`)
         if(result2.status !== 200) return this.$message.error("Deletion failed")
         this.$message.success("Delete succeeded")
         //Reload data
         this.getUserList()
      }
    },
    //Using hook function to realize data query
    mounted(){
      this.getUserList()
    }
  }
</script>


<style lang="less" scoped>

</style>

Component, route setting – index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import ElementUI from '../components/ElementUI.vue'
import Home from '../components/Home.vue'
import User from '../components/user/user.vue'
import ItemCat from '../components/items/ItemCat.vue'
//Using routing mechanism
Vue.use(VueRouter)
const routes = [
  {path: '/', redirect: '/login'},
  {path: '/login', component: Login},
  {path: '/elementUI', component: ElementUI},
  //Implement parent-child component nesting
  {path: '/home',component: Home,
    children:[
      {path: '/user',component: User},
      {path: '/itemCat',component: ItemCat}
    ]
  }
]


const router = new VueRouter({
  routes
})

/**
 * Define route navigation guard
 * Valuepoint 1 to the URL of the route jump
 * Parameter 2 where does the route from come from
 * Parameter 3 next is a function that indicates release or redirection
 *            next() Release
 *            next("/login") redirect
 * Business realization:
 *    Core logic: check whether there is a token
 *        A token indicates that you have logged in and released the request
 *        No token indicates that the user is not logged in and redirects to the login page
 *        If you visit the login page, you can release it directly
 */
router.beforeEach((to,from,next) => {
    if (to.path === "/login") {
      return next()
    }
    //It indicates that the page visited by the user is not a login request and needs to be verified
    //Get token data
    let token = window.sessionStorage.getItem("token")
    //The following if judgment is interpreted as: if the token is not null
    if (token) {
      return next()
    }
    next("/login")
})
export default router

back-end

Business layer service:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public List<User> findAll() {
        return userMapper.selectList(null);
    }

    /**
     * Idea:
     *      1.Encrypt the password
     *      2.Query the database according to username/password
     *      3.Value:
     *          Login succeeded, return the secret key
     *      4.No value:
     *          Login failed, null returned
     * @param user
     * @return
     */
    @Override
    @Transactional
    public String login(User user) {
        //1. Get plaintext
        String password = user.getPassword();
        //2. Encryption processing
        String md5 = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(md5);
        //Query the database and obtain the database object
        User userDB = userMapper.selectOne(new QueryWrapper<User>(user));
        //5. Judge whether the login is correct
        if (userDB == null) {
            return null;
        }
        //6. Use UUID to dynamically generate TOKEN, which is generated according to the number of milliseconds + random number + hash algorithm of the current time, which can almost ensure no repetition
        String token = UUID.randomUUID().toString()
                .replace("-", "");
        return token;
    }

    /**
     * Paging Sql
     *    Syntax: select * from user limit starting position, number of entries per page
     *    Rule: array with header and no tail
     *    Query page 1:
     *          select * from user limit 0,10
     *    Query page 2:
     *          select * from user limit 10,10
     *    Query page N:
     *          select * from user limit (Number of pages - 1) number of articles, number of articles
     * @param pageResult
     * @return
     */
//    @Override
//    public PageResult getUserList(PageResult pageResult) {
//        //1. Get total pages Integer -- long automatic conversion
//        long total = userMapper.selectCount(null);
//        //2. Get paging results
//        int size = pageResult.getPageSize();
//        int start = (pageResult.getPageNum() - 1) * size;
//        List<User> userList = userMapper.findListByPage(start,size);
//        pageResult.setTotal(total)
//                .setRows(userList);
//        return pageResult;
//    }
    /**
     * Business description: query database by MP
     * Step description:
     *      1.Build paging objects for MP
     *      2.Query data according to paging object
     *      3.Get data from paging object
     *      4.Encapsulates the PageResult object
     *      5.Edit the configuration class to encapsulate the paging interceptor
     */
    @Override
    @Transactional
    public PageResult getUserList(PageResult pageResult) {
        //1. Define paging objects
        IPage<User>  page = new Page<>(pageResult.getPageNum(), pageResult.getPageSize());
        //2. Define condition constructor
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //boolean flag = pageResult.getQuery() == null? false : true;
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username",pageResult.getQuery());
        //3. Perform paging query
        page = userMapper.selectPage(page,queryWrapper); //Interceptors must be added, otherwise the condition constructor will not take effect
        //Get data from the encapsulated paging object
        pageResult.setTotal(page.getTotal())
                .setRows(page.getRecords());
        System.out.println(page.getTotal());
        return pageResult;
    }
    //Rule: treat non null elements in the object as set conditions,
    //      Id as unique where condition
    @Override
    @Transactional
    public void updateStatus(User user) {
        userMapper.updateById(user);
    }

    /**
     * explain:
     *      1.User warehousing operation
     *      Add status / creation time / update time
     *      2.Password encryption processing
     * @param user
     */
    @Override
    @Transactional
    public void addUser(User user) {
        String password = user.getPassword();
        //Encryption processing
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setStatus(true)
                .setPassword(password);
        userMapper.insert(user);
    }

    @Override
    @Transactional
    public Object getUserById(Integer id) {
        return userMapper.selectById(id);
    }
    //Non null elements are treated as set conditions, id unique and where conditions
    @Override
    @Transactional
    public void updateUser(User user) {
        userMapper.updateById(user);
    }

    /**
     * @Transactional Rule Description:
     *      1.If a runtime exception occurs, the transaction is rolled back
     *      2.If a compilation exception (check exception) occurs, the default rule is that the transaction is not rolled back
     *      3.Attribute description:
     *          noRollbackFor = {} Do not roll back when an exception is encountered
     *          rollbackFor = {} Encountered some kind of exception rollback
     * @param id
     */
    @Override
    @Transactional
    public void deleteUser(Integer id) {
        userMapper.deleteById(id);
    }
}

Control layer controller:

@RestController
//@CrossOrigin({"http://localhost:8081"})
@CrossOrigin
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/hello")
    public List<User> hello(){

        return userService.findAll();
    }
    /**
     * Business description: realize user login
     * Idea: query the database according to the parameters
     *      Value: the user name and password are correct
     *      No value: the user name does not exist or the password is incorrect
     * URL: /user/login
     * Parameter: username/password
     * Type: post
     * Return value: SysResult object (token)
     */
    @PostMapping("/login")
    public SysResult login(@RequestBody User user) {
        //Requirement: after successful login, return value identifier information
        String token = userService.login(user);
        //If the token is null, the login fails
        if (token == null || token.length() == 0) {
            return SysResult.fail();
        }
        //Otherwise, return correctly
        return SysResult.success(token);
    }
    /**
     * Business description: realize paging query of user list
     * URL Address: http://localhost:8091/user/list?query= Keywords for query & pagenum = 1 & PageSize = 10
     * Return value: SysResult object
     */
    @GetMapping("/list")
    public SysResult getUserList(PageResult pageResult) { //3
        pageResult = userService.getUserList(pageResult);
        return SysResult.success(pageResult); //5
    }
    /**
     * Business description: modify status information
     * URL: /user/status/{id}/{status}
     * Parameter: id/status
     * Return value: SysResult
     */
    @PutMapping("/status/{id}/{status}")
    public SysResult updateStatus(User user) {
        userService.updateStatus(user);
        return SysResult.success();
    }
    /**
     * Business: add users
     * URL: /user/addUser
     * Parameter: json of the whole form object
     * Return value: SysResult object
     */
    @PostMapping("/addUser")
    public SysResult addUser(@RequestBody User user) {
        userService.addUser(user);
        return SysResult.success();
    }
    /**
     * Business: query database by id
     * URL: /user/{id}
     * Parameter: primary key id
     * Return value: SysResult(User object)
     */
    @GetMapping("/{id}")
    public SysResult getUserById(@PathVariable Integer id) {
        return SysResult.success(userService.getUserById(id));
    }
    /**
     * Business requirements: implement user update operation
     * URL: /user/updateUser
     * Parameter: object submission JSON object annotation acceptance
     * Return value: SysResult
     */
    @PutMapping("/updateUser")
    public SysResult updateUser(@RequestBody User user) {
        userService.updateUser(user);
        return SysResult.success();
    }
    /**
     * Business requirement: delete data
     * URL: /user/{id}
     * Parameter: id
     * Return value: SysResult
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUser(@PathVariable Integer id) {
        userService.deleteUser(id);
        return SysResult.success();
    }
}

Tags: Java Vue

Posted on Mon, 06 Sep 2021 00:20:09 -0400 by chingwaah