【超详细前后端项目搭建】前端vue3+ts项目(引入ElementPlus、Axios)、后端springboot搭建(创建接口操作mysql数据库)实现前后端联调

avatar
作者
猴君
阅读量:143

目录


前言

本项目为简易的全栈项目,其中前端项目使用到了vue3、ts、Element Plus、axios等技术栈;后端项目使用到了springboot、jdbc、mysql、maven等技术


附上开源代码gitee地址:
前端代码:https://gitee.com/smileagain-lg/vue3-element-demo.git
后端代码:https://gitee.com/smileagain-lg/spring-boot-demo.git

一、前端项目

1、使用vue脚手架创建项目

1.1检查vue版本

输入命令vue -V(V要大写),版本需要在4.5.1之后

1

1.2 使用vue脚手架创建项目

1、使用命令vue create vue3-element-demo 创建Vue项目。
2、通过上下键选择,选择 Manually select features,按回车,手动进行配置。
在这里插入图片描述
3、通过上下键选择,通过空格键选中(使用Babel,TypeScript,Router、Vuex、CSS Pre-processors、Linter / Formatter),按回车
在这里插入图片描述

4、选择vue3按回车
在这里插入图片描述
5、是否使用 Class 风格装饰器,此处输入【y】,然后回车确认;
在这里插入图片描述
6、Babel 和 TS 是否一起使用,用于现代模式、自动检测的 polyfills 和转译 JSX,此处输入【y】,然后回车确认;
在这里插入图片描述
7、是否使用history路由模式,此处输入【n】,即使用默认的 hash 模式,然后回车确认;
在这里插入图片描述
8、选择 CSS 预处理器,按上下方向键来选择,笔者习惯了 Less,然后回车确认;
在这里插入图片描述
9、选择第一个ESLint with error prevention only(仅具有错误预防功能的ESLint)
在这里插入图片描述
在这里插入图片描述
10、Babel、ESLint 等插件的配置是单独的文件进行配置,还是都在 package.json 文件里面?此处输选择 package.json 咯,并不想太多零散的配置文件,然后回车确认;
在这里插入图片描述
11、是否保存当前创建 Vue3 项目的特性配置,下次再创建 Vue 项目的时候,可以选择该特性,然后回车确认即可创建完成。这个可以不用保存,输入【n】,然后回车确认;
在这里插入图片描述12、项目创建中;
在这里插入图片描述
项目创建成功:
在这里插入图片描述
在这里插入图片描述
运行项目
在这里插入图片描述
在这里插入图片描述

2、删除项目多余文件,修改配置项目

2.1、删除以下文件

在这里插入图片描述

2.1、在views下创建index文件

在这里插入图片描述

<template>     <div>我的首页</div> </template>    <script lang="ts">   export default {     name: 'Index'   } </script>  <style scoped></style> 

2.2、修改router/index.ts路由文件:

在这里插入图片描述
编译时会有报错:
vue eslint报错:Component name “index“ should always be multi-word.eslintvue/multi-word-component-names
在这里插入图片描述
原因:除了根组件(App.vue)外,自定义组件名称应该由多单词组成,防止和html标签冲突。
解决方法,关闭eslint校验,重新编译就正常了
lintOnSave: false

在这里插入图片描述

2.3、修改App.vue文件:

在这里插入图片描述

<template>   <div id="app">     <router-view/>   </div> </template>  <style lang="less"> html, body, #app {   width: 100%;   height: 100%; } </style> 

运行效果:
在这里插入图片描述

2.4、初始化页面样式以及清除浮动

新建css/resset.css文件,并在index.html文件中引入,初始化样式
在这里插入图片描述

/**  * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)  * http://cssreset.com  */    html, body, div, span, applet, object, iframe,  h1, h2, h3, h4, h5, h6, p, blockquote, pre,  a, abbr, acronym, address, big, cite, code,  del, dfn, em, img, ins, kbd, q, s, samp,  small, strike, strong, sub, sup, tt, var,  b, u, i, center,  dl, dt, dd, ol, ul, li,  fieldset, form, label, legend,  table, caption, tbody, tfoot, thead, tr, th, td,  article, aside, canvas, details, embed,   figure, figcaption, footer, header, hgroup,   menu, nav, output, ruby, section, summary,  time, mark, audio, video{    margin: 0;    padding: 0;    border: 0;    font-size: 100%;    font: inherit;    font-weight: normal;    vertical-align: baseline;  }  /* HTML5 display-role reset for older browsers */  article, aside, details, figcaption, figure,   footer, header, hgroup, menu, nav, section{    display: block;  }  ol, ul, li{    list-style: none;  }  blockquote, q{    quotes: none;  }  blockquote:before, blockquote:after,  q:before, q:after{    content: '';    content: none;  }  table{    border-collapse: collapse;    border-spacing: 0;  }     /* custom */  a{    color: #7e8c8d;    text-decoration: none;    -webkit-backface-visibility: hidden;  }  ::-webkit-scrollbar{    width: 5px;    height: 5px;  }  ::-webkit-scrollbar-track-piece{    background-color: rgba(0, 0, 0, 0.2);    -webkit-border-radius: 6px;  }  ::-webkit-scrollbar-thumb:vertical{    height: 5px;    background-color: rgba(125, 125, 125, 0.7);    -webkit-border-radius: 6px;  }  ::-webkit-scrollbar-thumb:horizontal{    width: 5px;    background-color: rgba(125, 125, 125, 0.7);    -webkit-border-radius: 6px;  }  html, body{    width: 100%;    font-family: "Arial", "Microsoft YaHei", "黑体", "宋体", "微软雅黑", sans-serif;  }  body{    line-height: 1;    -webkit-text-size-adjust: none;    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);  }  html{    overflow-y: scroll;  }     /*清除浮动*/  .clearfix:before,  .clearfix:after{    content: " ";    display: inline-block;    height: 0;    clear: both;    visibility: hidden;  }  .clearfix{    *zoom: 1;  }     /*隐藏*/  .dn{    display: none;  } 

index.html中引用:
在这里插入图片描述

3、引入ElementPlus 组件库

3.1、导入依赖包

npm i element-plus -D
在这里插入图片描述

第一种:全局挂载ElementPlus,在main.js中添加

在这里插入图片描述

第一种:按需导入组件

vue.config.js中引入(按需导入方式),添加如下配置
在这里插入图片描述

const { defineConfig } = require('@vue/cli-service'); const AutoImport = require('unplugin-auto-import/webpack'); const Components = require('unplugin-vue-components/webpack'); const { ElementPlusResolver } = require('unplugin-vue-components/resolvers'); module.exports = defineConfig({   transpileDependencies: true,   //关闭eslint校验   lintOnSave: false,   configureWebpack: {     plugins: [       AutoImport({         resolvers: [ElementPlusResolver()],       }),       Components({         resolvers: [ElementPlusResolver()],       }),     ],   } }) 

在页面中使用ElementPlus组件

在这里插入图片描述
效果:
在这里插入图片描述

3、创建登录页面

在view下新建Login.vue文件

在这里插入图片描述

<template>     <div class="container" :class="{ 'sign-up-mode': signUpMode }">       <!-- form表单容器 -->       <div class="form-container">         <div class="signin-signup">           <!-- 登录 -->             <el-form             ref="ruleFormRef"             :model="loginUser"             :rules="rules"             label-width="100px"             class="login-form sign-in-form"             >             <el-form-item label="邮箱" prop="email">                 <el-input v-model="loginUser.email" placeholder="Enter Email..." />             </el-form-item>             <el-form-item label="密码" prop="password">                 <el-input                 v-model="loginUser.password"                 type="password"                 placeholder="Enter Password..."                 />             </el-form-item>             <el-form-item>                 <el-button type="primary" class="submit-btn" @click="submitForm(ruleFormRef)">提交</el-button>             </el-form-item>             <!-- 找回密码 -->             <el-form-item>                 <p class="tiparea">忘记密码<a>立即找回</a></p>             </el-form-item>             </el-form>         </div>       </div>       <!-- 左右切换动画 -->       <div class="panels-container">         <div class="panel left-panel">           <div class="content">             <h3>Row,row,row your boat</h3>             <p>Gentlely down the stream</p>             <button @click="signUpMode = !signUpMode" class="btn transparent">               注册             </button>           </div>         </div>         <div class="panel right-panel">           <div class="content">             <h3>Merrily,merrily,merrily,merrily,</h3>             <p>Life is but a dream</p>             <button @click="signUpMode = !signUpMode" class="btn transparent">               登录             </button>           </div>         </div>       </div>     </div>   </template>    <script lang="ts" setup>   import { ref, reactive, toRefs, getCurrentInstance } from 'vue'   import type { FormInstance, FormRules } from 'element-plus'   // Vue3语法糖   // 通过解构getCurrentInstance,获取this,这里的this就是ctx   // const { ctx } = getCurrentInstance()   const { proxy } = getCurrentInstance()   // 登录/注册模式   const signUpMode = ref(false)   const ruleFormRef = ref<FormInstance>()   // 登录表单   const loginUser = reactive({     email: '',     password: ''   })   // 校验规则   const rules = reactive({     email: [           {             required: true,             type: 'email',             message: 'email格式错误',             trigger: 'blur'           }         ],         password: [           { required: true, message: '密码不得为空', trigger: 'blur' },           { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }         ]       })       // 触发登录方法       const submitForm  = (formEl: FormInstance | undefined) => {         if(!formEl!) return         formEl.validate((valid) => {           if (valid) {             console.log('submit!')             const data = proxy.$http.getUserPassword(loginUser)             console.log('data', data)           } else {             console.log('error submit!')             return false           }         })       }   </script>   <style scoped>   .container {     position: relative;     width: 100%;     min-height: 100vh;     background-color: #fff;     overflow: hidden;   }   .form-container {     position: absolute;     left: 0;     top: 0;     width: 100%;     height: 100%;   }   .signin-signup {     position: relative;     top: 50%;     left: 75%;     transform: translate(-50%, -50%);     width: 44%;     transition: 1s 0.7s ease-in-out;     display: grid;     grid-template-columns: 1fr;     z-index: 5;   }    /* 左右切换动画 */   .social-text {     padding: 0.7rem 0;     font-size: 1rem;   }    .social-media {     display: flex;     justify-content: center;   }    .social-icon {     height: 46px;     width: 46px;     display: flex;     justify-content: center;     align-items: center;     margin: 0 0.45rem;     color: #333;     border-radius: 50%;     border: 1px solid #333;     text-decoration: none;     font-size: 1.1rem;     transition: 0.3s;   }    .social-icon:hover {     color: #4481eb;     border-color: #4481eb;   }    .btn {     width: 150px;     background-color: #5995fd;     border: none;     outline: none;     height: 49px;     border-radius: 49px;     color: #fff;     text-transform: uppercase;     font-weight: 600;     margin: 10px 0;     cursor: pointer;     transition: 0.5s;   }    .btn:hover {     background-color: #4d84e2;   }   .panels-container {     position: absolute;     height: 100%;     width: 100%;     top: 0;     left: 0;     display: grid;     grid-template-columns: repeat(2, 1fr);   }    .container:before {     content: '';     position: absolute;     height: 2000px;     width: 2000px;     top: -10%;     right: 48%;     transform: translateY(-50%);     background-image: linear-gradient(-45deg, #4481eb 0%, #04befe 100%);     transition: 1.8s ease-in-out;     border-radius: 50%;     z-index: 6;   }    .image {     width: 100%;     transition: transform 1.1s ease-in-out;     transition-delay: 0.4s;   }    .panel {     display: flex;     flex-direction: column;     align-items: flex-end;     justify-content: space-around;     text-align: center;     z-index: 6;   }    .left-panel {     pointer-events: all;     padding: 3rem 17% 2rem 12%;   }    .right-panel {     pointer-events: none;     padding: 3rem 12% 2rem 17%;   }    .panel .content {     color: #fff;     transition: transform 0.9s ease-in-out;     transition-delay: 0.6s;   }    .panel h3 {     font-weight: 600;     line-height: 1;     font-size: 1.5rem;   }    .panel p {     font-size: 0.95rem;     padding: 0.7rem 0;   }    .btn.transparent {     margin: 0;     background: none;     border: 2px solid #fff;     width: 130px;     height: 41px;     font-weight: 600;     font-size: 0.8rem;   }    .right-panel .image,   .right-panel .content {     transform: translateX(800px);   }    /* ANIMATION */    .container.sign-up-mode:before {     transform: translate(100%, -50%);     right: 52%;   }    .container.sign-up-mode .left-panel .image,   .container.sign-up-mode .left-panel .content {     transform: translateX(-800px);   }    .container.sign-up-mode .signin-signup {     left: 25%;   }    .container.sign-up-mode form.sign-up-form {     opacity: 1;     z-index: 2;   }    .container.sign-up-mode form.sign-in-form {     opacity: 0;     z-index: 1;   }    .container.sign-up-mode .right-panel .image,   .container.sign-up-mode .right-panel .content {     transform: translateX(0%);   }    .container.sign-up-mode .left-panel {     pointer-events: none;   }    .container.sign-up-mode .right-panel {     pointer-events: all;   }    @media (max-width: 870px) {     .container {       min-height: 800px;       height: 100vh;     }     .signin-signup {       width: 100%;       top: 95%;       transform: translate(-50%, -100%);       transition: 1s 0.8s ease-in-out;     }      .signin-signup,     .container.sign-up-mode .signin-signup {       left: 50%;     }      .panels-container {       grid-template-columns: 1fr;       grid-template-rows: 1fr 2fr 1fr;     }      .panel {       flex-direction: row;       justify-content: space-around;       align-items: center;       padding: 2.5rem 8%;       grid-column: 1 / 2;     }      .right-panel {       grid-row: 3 / 4;     }      .left-panel {       grid-row: 1 / 2;     }      .image {       width: 200px;       transition: transform 0.9s ease-in-out;       transition-delay: 0.6s;     }      .panel .content {       padding-right: 15%;       transition: transform 0.9s ease-in-out;       transition-delay: 0.8s;     }      .panel h3 {       font-size: 1.2rem;     }      .panel p {       font-size: 0.7rem;       padding: 0.5rem 0;     }      .btn.transparent {       width: 110px;       height: 35px;       font-size: 0.7rem;     }      .container:before {       width: 1500px;       height: 1500px;       transform: translateX(-50%);       left: 30%;       bottom: 68%;       right: initial;       top: initial;       transition: 2s ease-in-out;     }      .container.sign-up-mode:before {       transform: translate(-50%, 100%);       bottom: 32%;       right: initial;     }      .container.sign-up-mode .left-panel .image,     .container.sign-up-mode .left-panel .content {       transform: translateY(-300px);     }      .container.sign-up-mode .right-panel .image,     .container.sign-up-mode .right-panel .content {       transform: translateY(0px);     }      .right-panel .image,     .right-panel .content {       transform: translateY(300px);     }      .container.sign-up-mode .signin-signup {       top: 5%;       transform: translate(-50%, 0);     }   }    @media (max-width: 570px) {     form {       padding: 0 1.5rem;     }      .image {       display: none;     }     .panel .content {       padding: 0.5rem 1rem;     }     .container {       padding: 1.5rem;     }      .container:before {       bottom: 72%;       left: 50%;     }      .container.sign-up-mode:before {       bottom: 28%;       left: 50%;     }   }    /* 控制login & register显示 */   form {     padding: 0rem 5rem;     transition: all 0.2s 0.7s;     overflow: hidden;   }    form.sign-in-form {     z-index: 2;   }    form.sign-up-form {     opacity: 0;     z-index: 1;   }    /* register */   .loginForm,   .registerForm {     margin-top: 20px;     background-color: #fff;     padding: 20px 40px 20px 20px;     border-radius: 5px;     box-shadow: 0px 5px 10px #cccc;   }    .submit-btn {     width: 100%;   }   .tiparea {     text-align: right;     font-size: 12px;     color: #333;     width: 100%;   }   .tiparea a {     color: #409eff;   }   </style>   

在这里插入图片描述
在这里插入图片描述

4、封装并使用 Axios

4.1、安装Axios

npm i axios
在这里插入图片描述

4.2、安装NProgress顶部进度条

npm i --save-dev @types/nprogress
在这里插入图片描述

4.3、封装请求拦截

在 src 目录新建 utils 文件夹,再新建 requestUtil.ts 文件,写上以下代码
在这里插入图片描述

import axios from 'axios' import Nprogress from 'nprogress' import 'nprogress/nprogress.css' import { ElMessage } from 'element-plus'  const http = axios.create({   baseURL: 'http://localhost:9000',   timeout: 300 * 1000, // 请求超时时间设置为300秒 })  const NETWORK_ERROR = '网络错误,请联系开发人员'  /**  * 请求拦截器  */ http.interceptors.request.use((req) => {   console.log('请求拦截器 =>', req)   Nprogress.start()   return req; }, (error) => {   Nprogress.done()   return Promise.reject(error); });  /**  * 响应拦截器  */ http.interceptors.response.use(function (res) {   console.log('响应拦截器 =>', res)   Nprogress.done()   if (res.status == 200) {     return res.data   } else {     ElMessage.error((NETWORK_ERROR))     return Promise.reject(NETWORK_ERROR)   } });  export default http  

4.4、前端设置跨域

在vue.config.js中配置如下代码:
在这里插入图片描述

const { defineConfig } = require('@vue/cli-service'); // const AutoImport = require('unplugin-auto-import/webpack'); // const Components = require('unplugin-vue-components/webpack'); // const { ElementPlusResolver } = require('unplugin-vue-components/resolvers'); module.exports = defineConfig({   transpileDependencies: true,   //关闭eslint校验   lintOnSave: false,   // ElementPlus按需导入方式   // configureWebpack: {   //   plugins: [   //     AutoImport({   //       resolvers: [ElementPlusResolver()],   //     }),   //     Components({   //       resolvers: [ElementPlusResolver()],   //     }),   //   ],   // }   devServer: {     open: true,     host: 'localhost',     port: 8080,     https: false,     // 设置跨域     proxy: {       '/api': {         target: 'http://localhost:9000',         ws: true,         changeOrigin: true,         pathRewrite: {           '^api': ''         }       }     }   } }) 

4.5、配置接口api

在src目录下创建api文件夹,里面创建index.ts
在这里插入图片描述

import http from '@/utils/requestUtils'    export default {   /**    * 根据用户邮箱、密码查询用户信息    */   getUserPassword(data: any) {     return http.post(       '/api/getUserPassword',       data,       {         headers: {           'Content-Type': 'application/json'         },       }     )   },     /**    * 保存用户信息    */   saveUser(data: any) {     return http.post(       '/api/saveUser',       data,       {         headers: {           'Content-Type': 'application/json'         },       }     )   }, } 

4.6、将http请求全局封装

在 main.ts 文件引入HTTP请求工具并配置为全局方法
在这里插入图片描述

import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import axios from 'axios' import apiServe from '@/api'   const app = createApp(App)  app.use(store) app.use(router) app.use(ElementPlus) app.mount('#app')  app.config.globalProperties.$http = apiServe app.config.globalProperties.$axios = axios 

二、后端项目

1、检查JDK和maven的安装版本

在cmd输入 java -version
和mvn -v检查对应的安装情况
在这里插入图片描述

2、创建springboot项目

通过idea的spring initializr创建工程,不选择maven而是选择spring initializr快捷创建。然后去勾选相关依赖。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3、创建springboot项目成功

项目创建成功

在这里插入图片描述

4、配置maven和maven库

配置本地maven库
在这里插入图片描述

5、加载maven库

在这里插入图片描述

6、创建application.yml

在resources下面新建application.yml,并配置数据库名,密码,以及端口,端口尽量不要使用8080,避免和前端端口相同了

在这里插入图片描述
注释掉另外一个配置
在这里插入图片描述

# mysql spring:   datasource:     #MySQL配置     driverClassName:  com.mysql.cj.jdbc.Driver     url: jdbc:mysql://localhost:3306/easyproject?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC     #数据库名和密码     username: root     password: 920724  mybatis:   mapper-locations: classpath:mapper/*.xml   type-aliases-package: com.example.demo.model server:   port: 9000 

7、运行项目

在这里插入图片描述
项目运行成功,端口9000
在这里插入图片描述
在这里插入图片描述

8、新建WebConfig文件处理跨域

创建utils文件夹,在utils文件夹下创建WebConfig,并添加以下配置
在这里插入图片描述

package com.springboot.userlogin.springbootdemo.utils;  import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  // 使用注解说明是全局配置类 @Configuration public class WebConfig extends WebMvcConfigurerAdapter { // 继承跨域请求的类      @Override     public void addCorsMappings(CorsRegistry registry) { // 跨域处理的方法         registry.addMapping("/**") // 任意访问都允许跨域                 .allowedOrigins("http://localhost:8080", "null") // 跨域来源                 .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") // 跨域请求类型                 .maxAge(3600) // 超时时间                 .allowCredentials(true); // 允许携带信息     } } 

alt+insert快捷键可以弹出
在这里插入图片描述

9、使用idea连接mysql

mysql安装配置方法可以参照我写的另外一个文档:
https://blog.csdn.net/m0_47791238/article/details/134811414?spm=1001.2014.3001.5501

在这里插入图片描述
在这里插入图片描述
输入mysql用户名和密码:
在这里插入图片描述
在这里插入图片描述

10、在pom文件添加lombok依赖

目的:为了使用@Data注解
在这里插入图片描述

<dependency>       <groupId>org.projectlombok</groupId>       <artifactId>lombok</artifactId>       <version>1.18.24</version>  </dependency> 

11、创建bean文件夹,用于放置实体对象

在项目中创建bean文件夹,新建user实体类,使用Data注解,创建构造方法和get\set方法
在这里插入图片描述

package com.springboot.userlogin.springbootdemo.bean;  import lombok.Data;  @Data public class User {     private int id;     private String username;     private String password;     private String email;     private String role;     private boolean state;  //    public User() { //    }  //    public User(String username, String password, String email, String role, boolean state) { //        this.username = username; //        this.password = password; //        this.email = email; //        this.role = role; //        this.state = state; //    } // //    public int getId() { //        return id; //    } // //    public String getUsername() { //        return username; //    } // //    public String getPassword() { //        return password; //    } // //    public String getEmail() { //        return email; //    } // //    public String getRole() { //        return role; //    } // //    public boolean getState() { //        return state; //    } // //    public void setId(int id) { //        this.id = id; //    } // //    public void setUsername(String username) { //        this.username = username; //    } // //    public void setPassword(String password) { //        this.password = password; //    } // //    public void setEmail(String email) { //        this.email = email; //    } // //    public void setRole(String role) { //        this.role = role; //    } // //    public void setState(boolean state) { //        this.state = state; //    } } 

12、查看构造成功成功的实体对象

快捷键 alt + 7
在这里插入图片描述

13、创建controller接口

在这里插入图片描述

import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;  @RestController public class LoginController {     @Autowired     UserDao userDao;      @PostMapping("/api/getUserPassword") // @RequestMapping注解创建接口     public String userLogin(@RequestBody User user) { // @RequestBody注解方便找到user实体          System.out.println("User : " + user);         String str = "error";         int count = userDao.getUserByMassage(user.getEmail(), user.getPassword());         if (count > 0) {             str = "ok";         }         return str;     } } 

14、创建dao接口

在这里插入图片描述

package com.springboot.userlogin.springbootdemo.dao;  import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository;  @Repository @Mapper public interface UserDao {      int getUserByMassage(@Param("email") String email, @Param("password") String password); } 

15、创建mapper映射文件

在resources下面创建mapper文件夹,用于存放数据库的映射文件
在mapper文件夹下新建UserMapper.xml
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  <!--对应dao层接口文件的目录--> <mapper namespace="com.springboot.userlogin.springbootdemo.dao.UserDao">     <!--  id值为UserDao接口方法名; -->     <select id="getUserByMassage" resultType="java.lang.Integer">        	SELECT count(id) FROM easyUser        	WHERE email=#{email} AND password=#{password}     </select> </mapper> 

三、测试前后端功能

1、前端页面接口请求

在这里插入图片描述

2、后端控制台日志打印

在这里插入图片描述

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!