Practical case——[St. Regis Takeaway Project]

  • This project is based on the current popular takeaway ordering, and the business is real, practical and extensive. Develop based on popular technical frameworks such as Spring Boot and mybatis plus, and experience the real project development process, requirements analysis process and code implementation process. In order to exercise demand analysis ability, coding ability, bug debugging ability, and increase development experience. ——Excerpt from Dark Horse Programmer

1. Development environment construction

(1) Database environment construction

  • Start Navicat, create a mysql connection
  • Create the database required by the project - reggie, the character set usesutf8mb4

insert image description here

  • Import database script:db_reggie.sql
  • View the tables in the database
    insert image description here

(2) Maven project creation

1. Create Maven

  • Create a Maven project and configure project information
    insert image description here
  • Click the [Finish] button to create a successful
    insert image description here

2. Check and check the project code, maven warehouse configuration and jdk configuration

insert image description here

  • Verify that the maven environment variables are configured correctly
    insert image description here
  • Add Ali mirror source in the maven configuration file
    insert image description here
  • Check the configuration of the maven repository in IntelliJ IDEA
    insert image description here
  • Check the jdk configuration
    insert image description here
    insert image description here
    insert image description here

3. Add project-related dependencies and plugins

  • Add relevant dependencies and build plugins in the pom.xml file
    insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/>
    </parent>
    <groupId>net.hw</groupId>
    <artifactId>ReggieTakeOut</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.4</version>
            </plugin>
        </plugins>
    </build>
</project>

4. Create an application properties file

  • Create application properties file under resources directory −application.yml
    insert image description here
#配置服务器
server:
  port: 8080  #端口号

#配置Spring框架
spring:
  application: ReggiedTakeOut #应用名称
  datasource: #数据源
    druid: #druid数据源
      driver-class-name: com.mysql.cj.jdbc.Driver #数据库驱动程序
      url: jdbc:mysql://localhost:3306/reggie #数据源地址
      username: root #用户名
      password: 123456 #密码

#配置mybatis-plus插件
mybatis-plus:
  configuration: #配置
    map-underscore-to-camel-case: true #将字段名映射成实体属性时,转换下划线,按照驼峰命名法映射
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志实现类
  global-config: #全局配置
    db-config: #数据库配置
      id-type: auto #数据库ID自增

5. Install the lombok plugin

  • In the settings dialog, find plugins, search lombok, and click the green Installbutton
    insert image description here

6. Create a startup main class

  • Create net.xxxa package, and then create ReggieTakeOutApplication classes in the package
    insert image description here
package net.xjx;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class ReggieTakeOutApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ReggieTakeOutApplication.class, args);
        log.info("瑞吉外卖项目启动成功~");
    }
}
  • Run the program to see the effect

insert image description here

7. Copy static resources and template pages

  • Find the directory in the front-end resource backendand frontendcopy it to resourcesthe directory
    insert image description here

  • Test whether the template page can be accessed - the home page of the backend -index.html
    insert image description here

  • Start the application and visit http://localhost:8080/backend/index.html in the browser

insert image description here

  • At this time, 404 will be displayed, that is, the page cannot be found

8. Create an MVC configuration class for static resource mapping

  • Create configa subpackage and create a WebMvcConfig class in the package
    insert image description here
  • Test whether you can access the home page of the backend - /backend/index.html
    insert image description here

2. Background login function development

1. Demand analysis

(1) Page prototype display

  • Find project resources - product prototype > St. Regis takeaway background (management terminal) - login.html
    insert image description here
  • Click Login.html page
    insert image description here
  • The front-end page of the login page calls the ajax function and passes the user name and password to the background when the user name and password are entered and the login is clicked. The background controller needs to write a corresponding processing function to perform business processing on the submitted data, and then return the processing result to the front-end .
  • View login.html page code
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>瑞吉外卖管理端</title>
  <link rel="shortcut icon" href="../../favicon.ico">
  <!-- 引入样式 -->
  <link rel="stylesheet" href="../../plugins/element-ui/index.css" />
  <link rel="stylesheet" href="../../styles/common.css">
  <link rel="stylesheet" href="../../styles/login.css">
  <link rel="stylesheet" href="../../styles/icon/iconfont.css" />
  <style>
    .body{
      
      
      min-width: 1366px;
    }
  </style>
</head> 

<body>
  <div class="login" id="login-app">
    <div class="login-box">
      <img src="../../images/login/login-l.png" alt="">
      <div class="login-form">
        <el-form ref="loginForm" :model="loginForm" :rules="loginRules" >
          <div class="login-form-title">
            <img src="../../images/login/logo.png" style="width:139px;height:42px;" alt="" />
          </div>
          <el-form-item prop="username">
            <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号" maxlength="20"
              prefix-icon="iconfont icon-user" />
          </el-form-item>
          <el-form-item prop="password">
            <el-input v-model="loginForm.password" type="password" placeholder="密码" prefix-icon="iconfont icon-lock" maxlength="20"
              @keyup.enter.native="handleLogin" />
          </el-form-item>
          <el-form-item style="width:100%;">
            <el-button :loading="loading" class="login-btn" size="medium" type="primary" style="width:100%;"
              @click.native.prevent="handleLogin">
              <span v-if="!loading">登录</span>
              <span v-else>登录中...</span>
            </el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
  </div>

  <!-- 开发环境版本,包含了有帮助的命令行警告 -->
  <script src="../../plugins/vue/vue.js"></script>
  <!-- 引入组件库 -->
  <script src="../../plugins/element-ui/index.js"></script>
  <!-- 引入axios -->
  <script src="../../plugins/axios/axios.min.js"></script>
  <script src="../../js/request.js"></script>
  <script src="../../js/validate.js"></script>
  <script src="../../api/login.js"></script>

  <script>
    new Vue({
      
      
      el: '#login-app',
      data() {
      
      
        return {
      
      
          loginForm:{
      
      
            username: 'admin',
            password: '123456'
          },
          loading: false
        }
      },
      computed: {
      
      
        loginRules() {
      
      
          const validateUsername = (rule, value, callback) => {
      
      
            if (value.length < 1 ) {
      
      
              callback(new Error('请输入用户名'))
            } else {
      
      
              callback()
            }
          }
          const validatePassword = (rule, value, callback) => {
      
      
            if (value.length < 6) {
      
      
              callback(new Error('密码必须在6位以上'))
            } else {
      
      
              callback()
            }
          }
          return {
      
      
            'username': [{
      
       'validator': validateUsername, 'trigger': 'blur' }],
            'password': [{
      
       'validator': validatePassword, 'trigger': 'blur' }]
          }
        }
      },
      created() {
      
      
      },
      methods: {
      
      
        async handleLogin() {
      
      
          this.$refs.loginForm.validate(async (valid) => {
      
      
            if (valid) {
      
      
              this.loading = true
              let res = await loginApi(this.loginForm)
              if (String(res.code) === '1') {
      
      
                localStorage.setItem('userInfo',JSON.stringify(res.data))
                window.location.href= '/backend/index.html'
              } else {
      
      
                this.$message.error(res.msg)
                this.loading = false
              }
            }
          })
        }
      }
    })
  </script>
</body>

</html>

  • The Vue object binds the div element whose id attribute is login-app through the el attribute
    insert image description here
  • The Vue object binds the JSON data loginForm through the data() method, and binds the verification rules loginRules through computed
    insert image description here
  • A one-step method handleLogin for Vue objects to process login form data through methods binding
    insert image description here
  • In the front-end processing function, there is the result returned by the back-end processing function, which is stored in resa variable, and there are three data in it: res.code, res.data, res.msg, which requires that the JSON data returned by the back-end processing function must contain these three items

(2) Login page display

  • Page location: at resource/backend/page/login/login.html
    insert image description here
  • Why should the user login data be bound in the Vue object?
  • Because there is a piece of data in the employee table employee: adminand 123456(after MD5 encryption, it becomes e10adc3949ba59abbe56e057f20f883e)
    insert image description here
  • Click the [Login] button to first verify, if the verification is passed, the button title will become Login..., if the verification fails, the button title will still be Login
    insert image description here

(3) View login request information

  • Press the keyF12 to enter the browser's debug mode
    insert image description here
  • Description After clicking the login button to pass the client verification, the requested URL:
    http://localhost:8080/employee/login
  • Later we will write the corresponding processing function login() in the employee controller
@RestController // 交给Spring容器管理
@RequestMapping("/employee")
public class EmployeeController {
    
    
   
    @PostMapping("/login")
    public R<Employee> login(HttpRequest request, @RequestBody Employee employee) {
    
    
        return null;
    }
}

(4) Data model - employee table

  • View employee table structure
    insert image description here

2. Code development

(1) Create an employee entity class

  • ORM (Object Relation Mapping) Object Relational Mapping
  • Employee Entity Class (Employee) — Employee Table (employee)
serial number Entity attribute name relation field name
1 id id
2 name name
3 username username
4 password password
5 phone phone
6 sex sex
7 idNumber id_number
8 status a hundred
9 createTime create_time
10 status status
11 createUser create_user
12 updateUser update_user
  • Create entitya subpackage to create an employee entity class - Employee
    insert image description here
package net.cch.reggie.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 功能: 员工实体类
 * 作者: 陈春宏
 * 时间: 2022/10/27 11:16
 */

@Data //Lombok注解,注在类上,提供类的get、set、equals、hashCode、CanEqual、toString方法
public class Employee implements Serializable {
    
    

    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String name;

    private String password;

    private String phone;

    private String sex;

    private String idNumber; //对应id_number

    private Integer status;

    private LocalDateTime createTime;

    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT) //mybatis-plus注解,填充策略
    private Long createUser;//对应字段 -create_user

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;//对应字段 -update_user


}

(2) Create an employee mapper interface

  • Create a mapper subpackage, and create an employee mapper interface in the mapper subpackage - EmployeeMapper
    insert image description here
  • With the mybatis-plus plug-in, there is no need to create the corresponding mapper configuration file (EmployeeMapper.xml)

insert image description here

package net.cch.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.cch.reggie.entity.Employee;
import org.apache.ibatis.annotations.Mapper;

/**
 * 功能:EmployeeMapper接口
 * 作者: 陈春宏
 * 时间: 2022/10/27 21:20
 */
@Mapper //交给spring容器来管理
public interface EmployeeMapper extends BaseMapper<Employee> {
    
    

}

(3) Create employee services

1. Create an employee service interface

  • Create servicea subpackage and create an employee service interface in the service package - EmployeeService
    insert image description here
  • Using the mybatis-plus plug-in, the code is extremely simple, only need to inherit IService<Employee>the interface
package net.cch.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import net.cch.reggie.entity.Employee;


/**
 * 功能: EmployeeService接口
 * 作者: 陈春宏
 * 时间: 2022/10/27 21:21
 */

public interface EmployeeService extends IService<Employee> {
    
    
}

2. Create an employee service interface entity class

net.cch.serviceCreate an impl subpackage in the package, and create an employee service interface entity class in the subpackage-EmployeeServiceImpl
insert image description here

package net.cch.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.cch.reggie.entity.Employee;
import net.cch.reggie.mapper.EmployeeMapper;
import net.cch.reggie.service.EmployeeService;
import org.springframework.stereotype.Service;

/**
 * 功能: EmployeeService实现类
 * 作者: 陈春宏
 * 时间: 2022/10/27 21:26
 */
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
    
    

}

(4) Create a return result class

  • The return results of all processing methods on the server side are encapsulated in this general class
  • Create a common subpackage, and create a return result class in it -R
    insert image description here
package net.cch.reggie.common;

import lombok.Data;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用返回结果,服务器响应的数据最终会封装成此对象
 * @param <T>
 */

@Data
public class R<T> {
    
    

    private Integer code; //编码:1成功,0和其它数字为失败

    private String msg; //错误信息

    private T data; //数据

    private Map map = new HashMap(); //动态数据

    public static <T> R<T> success(T object) {
    
    
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
    
    
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
    
    
        this.map.put(key, value);
        return this;
    }

}

(5) Create an employee controller

  • Create a controller subpackage and create it under the subpackage -EmployeeController
    insert image description here
package net.cch.reggie.controller;

import 
import lombok.extern.slf4j.Slf4j;
import net.cch.reggie.common.R;
import net.cch.reggie.entity.Employee;
import net.cch.reggie.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;


/**
 * 功能: 员工管理控制层
 * 作者: 陈春宏
 * 时间: 2022/10/27 21:28
 */
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
    
    

    @Autowired
    private EmployeeService employeeService;

    /**
     * 员工登录
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {
    
    
       return null;
    }
}
  • Login method processing logic

1. Encrypt the password password submitted by the page with md5
2. Query the database according to the user name username submitted by the page
3. If no query is found, the login failure result will be returned
4. Password comparison, if they are inconsistent, the login failure result will be returned
5. View Employee status, if it is disabled, return the employee disabled result
6. Login is successful, save the employee id into the Session and return the successful login result

  • Perform md5 processing on the password password submitted by the page
    insert image description here
 //1、将页面提交的密码进行md5加密处理
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());
  • Query the database according to the username username submitted by the page
  • In general, querying by user name returns a record set, but the employee table has a unique constraint on the short name of the user. Therefore, there are only two cases for querying the employee table by user name: either it is not found, or one is found.
    insert image description here
    insert image description here
//2、根据页面提交的用户名username查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername,employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);
  • If there is no query, return the result of login failure
    insert image description here
 //3、如果没有查询到则返回登录失败的结果
        if(emp == null){
    
    
            return R.error("登录失败[用户名错误]");
        }
  • Password comparison, if inconsistent, return the result of wrong password
    insert image description here
//4、密码比对,如果不一致则返回密码错误的结果
        if(!emp.getPassword().equals(password)){
    
    
            return R.error("登录失败[密码错误]");
        }

  • Check the status of the employee, if it is disabled, return the result that the employee is disabled
    insert image description here
  //5、查看员工状态,如果为禁用状态,则返回员工已禁用结果

        if(emp.getStatus() == 0){
    
    
            return  R.error("账号已禁用!");
        }
  • If the login is successful, save the employee id to the Session and return the login result
    insert image description here
//6、登录成功,将员工id存入到Session并返回登录结果

        request.getSession().setAttribute("Employee",emp.getId());
        return R.success(emp);

3. Function test

(1) Modify the timeout configuration

  • Set the timeout to 1000000 milliseconds in resources/backend/js/request.jsthe file to facilitate breakpoint debugging laterinsert image description here

(2) Set breakpoints

  • EmployeeControllerset a breakpoint in
    insert image description here
  • View console information
    insert image description here

(4) Test Login - [Successful]

  • browser accesshttp://localhost:8080/backend/page/login/login.html
    insert image description here

  • Press the keyF12 to open the developer tools
    insert image description here

  • Login with username and password, admin : 123456,click 登录the button
    insert image description here

  • View breakpoint debugging information
    insert image description here

  • Single 击[Step Over]button 3 times, judge whether the user is wrong
    insert image description here

  • Click the [Step Over] button to determine whether the password is wrong
    insert image description here

  • Click the [Step Over] button to determine whether the employee status is disabled
    insert image description here

  • Click the [Step Over] button 3 times to return the successful login resultinsert image description here

  • At this point, view the login page, the login is successful, and the user information will be stored locallyinsert image description here

(5) Test Login - [Failed]

  • browser accesshttp://localhost:8080/backend/page/login/login.html
    insert image description here
  • Test username login failed
    insert image description here
    insert image description here
  • Test password comparison failed
    insert image description here
  • The test employee status is disabled, and the field employeeof the table statusis changed to 0
    insert image description here
    insert image description here

3. Background exit function development

1. Demand analysis

  • After the employee logs in successfully, the page jumps to the backend system homepage (backend/index.html), and the name of the currently logged-in user will be displayed at this time. If the employee needs to log out of the system, just click the logout button on the right to log out of the system. The system back page should jump back to the login page.

  • Jump to the homepage of the system after the employee logs in successfully
    insert image description here

  • Show current user login
    insert image description here

  • Get user login information through localStorage method
    insert image description here

  • View stored userinfo information
    insert image description here

2. Code development

  • The user clicks the logout button on the page to send a request, the request address is /employee/logout, and the request method is POST.insert image description here

(1) Clean up the user id in the Session

insert image description here

    /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request){
    
    
        //清理Session中保存的当前员工的id
        request.getSession().removeAttribute("employee");

        return null;

    }

(2) Return results

insert image description here

   /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request){
    
    
        //清理Session中保存的当前员工的id
        request.getSession().removeAttribute("employee");
        return R.success("退出成功");
    }

3. Function test

(1) Restart the service

insert image description here

(2) Test exit

  • Press and hold F12 to enter the debug page
    insert image description here
  • Click Exit to jump back to the login page, and the userinfo of LocalStorage is gone.
    insert image description here

Guess you like

Origin blog.csdn.net/qq_56238454/article/details/128353822