一、后端
1.数据库
创建用户表
drop table sys_user;
CREATE TABLE IF NOT EXISTS sys_user (
id INT NOT NULL AUTO_INCREMENT comment '主键',
name VARCHAR ( 50 ) comment '名称',
user_name VARCHAR ( 50 ) NOT NULL comment '用户名',
pass_word VARCHAR ( 50 ) NOT NULL comment '密码',
phone VARCHAR ( 11 ) comment '手机号',
e_mail VARCHAR ( 50 ) comment '邮箱',
level int NOT NULL comment '级别,0用户,1管理员',
is_delete int NOT NULL comment '逻辑删除标志,0未删除,1已删除',
create_time CHAR ( 19 ) NOT NULL comment '创建时间',
PRIMARY KEY ( id )
) ENGINE=INNODB DEFAULT CHARSET=utf8;
添加管理员账号
INSERT INTO `sys_user` VALUES (1, '管理员', 'admin', '123456', NULL, NULL, 1, 0, '2023-07-06 16:56:00');
2.使用Mybatis-plus
用idea打开在第二节创建的spring项目
2.1 添加mybatis-plus依赖
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 模板引擎-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
刷新maven,就会自动下载依赖
2.2 编写代码生成器
创建utils/MybatisPlusGenerator.java
package com.msp.system.utils;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.util.Collections;
/**
* MybatisPlus代码生成器
*/
public class MybatisPlusGenerator {
public static void main(String[] args) {
//1.配置数据源
FastAutoGenerator.create("jdbc:mysql://localhost:3306/msp","root","123456")
// 2.全局配置
.globalConfig(builder -> {
builder.author("初bai") // 设置作者
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 设置输出路径
.commentDate("yyyy-MM-dd hh:mm:ss") // 注释日期
.dateType(DateType.ONLY_DATE) // 定义生成实体类日期的类型
// .enableSwagger() // 开启 swagger 模式
.fileOverride()
.disableOpenDir(); // 禁止打开输出目录,默认打开
})
// 3.包配置
.packageConfig(builder -> {
builder.parent("com.msp") // 设置父包名
.moduleName("system") // 设置模块包名
.entity("entity") // 实体类包名
.service("service") // service 包名
.serviceImpl("service.impl") // serviceImpl包名
.mapper("mapper") // mapper包名
.xml("xml") // xml包名
.controller("controller") // controller包名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml
,System.getProperty("user.dir") + "/src/main/java/com/msp/system/mapper/xml")); // 配置 **Mapper.xml 路径信息:项目的 mapper 目录下
})
// 4.策略配置
.strategyConfig(builder -> {
builder.addInclude("sys_user") //设置需要生成的数据表名
.addTablePrefix("") //设置需要过滤的前缀
//4.1实体类配置
.entityBuilder()
.enableLombok() //开启lombok
.disableSerialVersionUID() //不实现序列化接口
.logicDeleteColumnName("is_delete") //逻辑删除字段
.naming(NamingStrategy.underline_to_camel) //数据库表映射到实体的命名策略,下划线转驼峰
.columnNaming(NamingStrategy.underline_to_camel) //数据库表字段映射到实体的命名策略,下划线转驼峰
.addTableFills(
new Column("create_time", FieldFill.INSERT),
new Column("is_delete", FieldFill.INSERT)
) //添加表字段填充,“create_time”自动填充入插入时间,"is_delete"自动填充逻辑删除标识
.enableTableFieldAnnotation() //开启生成实体类是生成字段注解
//4.2service配置
.serviceBuilder()
.formatServiceFileName("%sService") //格式化service接口文件名
.formatServiceImplFileName("%sServiceImpl") //格式化serviceImpl接口文件名
//4.3Mapper配置
.mapperBuilder()
.superClass(BaseMapper.class) //设置父类
.formatMapperFileName("%sMapper") //格式化mapper文件名
.enableMapperAnnotation() //开启@Mapper注解
.formatXmlFileName("%sXml") //格式化Xml 文件名
//4.4Controller配置
.controllerBuilder()
.formatFileName("%sController") //格式化controller文件名
.enableRestStyle(); //开启生成@RestController
})
// 5.模板引擎配置
.templateEngine(new FreemarkerTemplateEngine())
// 6.执行
.execute();
}
}
执行结果
2.3 添加mybatis-plus配置类
创建utils/MybatisplusConfig.java
package com.msp.system.utils;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Mybatis-Plus配置类
* 自动添加逻辑删除和创建时间
*/
@Component
public class MybatisPlusConfig implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),metaObject);
this.setFieldValByName("isDelete","0",metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),metaObject);
}
}
启动项目,试运行,看看有没有错误..........
3.修改application.properties
3.1 设置端口号访问地址
在 src/main/resources/application.properties 中添加
server.port=8951
server.servlet.context-path=/api
3.2 打印sql日志
在 src/main/resources/application.properties 中添加
logging.level.com.idmc.sscp.mapper=debug
4.跨域配置类
创建 utils/CorsConfig.java
package com.msp.system.utils;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 前后端跨域请求配置类
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**") // 设置允许跨域的路径
.allowedOriginPatterns("*") // 设置允许跨域请求的域名
.allowCredentials(true) // 是否允许证书
.allowedMethods("GET","POST") // 设置允许证书的方法
.allowedHeaders("*") // 设置允许报头的属性
.maxAge(3600); //跨域时间
}
}
5.编写注册登录后端代码
src/main/java/com/msp/system/controller/SysUserController.java
package com.msp.system.controller;
import com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.msp.system.entity.SysUser;
import com.msp.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 前端控制器
* </p>
*
* @author 初bai
* @since 2023-07-07 08:52:14
*/
@RestController
@RequestMapping("/sysUs")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
/**
* 注册
*/
@PostMapping("/register")
public int register(@RequestBody SysUser user){
if (sysUserService.save(user)){
return 0;
}
return 1;
}
/**
* 登录
*/
@PostMapping("/login")
public int login(@RequestBody SysUser user){
if (user.getUserName().trim()!="" && user.getPassWord()!=""){
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
wrapper.eq("user_name",user.getUserName()).eq("pass_word",user.getPassWord());
if (sysUserService.count(wrapper)==1){
return 0;
}
}
return 1;
}
}
二、前端
1.启动项目
使用webStorm打开第二节时创建的前端项目,在Terminal中输入npm run start启动项目
打开网站 http://localhost:8080 可以看到搭建的vue项目
2.引入关键组件
2.1 axios
npm i axios --save
在main.js中添加
import axios from 'axios'
Vue.prototype.$http = axios
2.2 element-UI
npm i element-ui --save
在main.js中添加
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
3.使用el-标签
选择项目下nodemodules/element-ui包
点击apply,等加载完就可以用了el标签了;如果不好用,请检查elment-ui版本,2.15.10以上版本官方更新了更新优化了,element-ui最好用2.15.10,否则写代码的时候没有提示,会很难受!!!!
4.添加背景图片
首先,在网上下载个背景图片,放到static文件夹下,修改名字为login
修改App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/*text-align: center;*/
color: #2c3e50;
/*margin-top: 60px;*/
width: 100%;
height: 100%;
position: fixed;
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url('../static/login.jpg');
}
</style>
保存,查看页面,会发生变化
5.编辑页面
5.1 注册页面
在src/components下,创建Register.vue
<template>
<el-form :model="regForm" :rules="regRules" ref="regFormRef" class="reg_container" label-width="18%"
v-loading="loading">
<h3 class="reg_title">系统注册</h3>
<el-form-item label="昵称" prop="name" class="item">
<el-input v-model="regForm.name" style="width: 80%;"></el-input>
</el-form-item>
<el-form-item label="账户" prop="userName" class="item">
<el-input v-model="regForm.userName" style="width: 80%;"></el-input>
</el-form-item>
<el-form-item label="密码" prop="passWord" class="item">
<el-input v-model="regForm.passWord" show-password style="width: 80%;" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="passWordTwo" class="item">
<el-input v-model="regForm.passWordTwo" show-password style="width: 80%;" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone" class="item">
<el-input v-model="regForm.phone" style="width: 80%;" maxLength="11"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email" class="item">
<el-input v-model="regForm.email" style="width: 80%;"></el-input>
</el-form-item>
<el-form-item label="启用" prop="level" class="item">
<el-switch
v-model="regForm.level"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="1"
inactive-value="0">
</el-switch>
</el-form-item>
<el-form-item>
<el-button @click="login" style="width: 20%">去登录</el-button>
<el-button type="primary" @click="regSubmit" style="width: 60%">立即注册</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: 'Register',
data () {
let validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'))
} else {
if (this.regForm.passWord !== '') {
this.$refs.regFormRef.validateField('passWordTwo')
}
callback()
}
}
let validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== this.regForm.passWord) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
return {
loading: false,
regForm: {
userName: '',
passWord: '',
passWordTwo: '',
phone: '',
email: '',
name: '',
level: ''
},
regRules: {
name: [
{required: true, message: '请输入昵称', trigger: 'blur'},
{min: 2, max: 8, message: '长度是2到8个字符', trigger: 'blur'},
{pattern: /^(?!\s+).*(?<!\s)$/, message: '开头和结尾不能有空格', trigger: 'blur'}
],
userName: [
{required: true, message: '请输入用户名', trigger: 'blur'},
{min: 5, max: 15, message: '长度是5到15个字符', trigger: 'blur'},
{pattern: /^(?!\s+).*(?<!\s)$/, message: '开头和结尾不能有空格', trigger: 'blur'}
],
passWord: [
{required: true, message: '请输入密码', trigger: 'blur'},
{ validator: validatePass, trigger: 'blur' },
{min: 6, max: 30, message: '长度是6到30个字符', trigger: 'blur'}
],
passWordTwo: [
{required: true, message: '请再次输入密码', trigger: 'blur'},
{ validator: validatePass2, trigger: 'blur' },
{min: 6, max: 30, message: '长度是6到30个字符', trigger: 'blur'}
],
phone: [
// {required: true, message: '请输入手机号', trigger: 'blur'},
{min: 11, max: 11, message: '长度是11个字符', trigger: 'blur'},
{pattern: /^(?!\s+).*(?<!\s)$/, message: '开头和结尾不能有空格', trigger: 'blur'}
],
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur'] },
{ min: 5, max: 30, message: '长度是5到30个字符', trigger: 'blur' },
{ pattern: /^(?!\s+).*(?<!\s)$/, message: '开头和结尾不能有空格', trigger: 'blur' }
]
}
}
},
methods: {
regSubmit () {
this.$refs.regFormRef.validate((valid) => {
if (valid) {
this.loading = true
this.$http.post('/sysUs/register', this.regForm).then(res => {
if (res.data === 0) {
this.$alert('注册成功', '成功')
this.$router.replace({path: '/log'})
} else {
this.$alert('注册失败', '失败')
}
this.loading = false
})
}
})
},
login () {
this.$router.replace({path: '/log'})
}
}
}
</script>
<style>
.reg_container {
border-radius: 15px;
background-clip: padding-box;
margin: 50px auto;
width: 480px;
padding: 15px 45px 25px 45px;
/*半透明*/
background: rgba(255, 255, 255, 0.3);
box-shadow: 0 0 25px #cac6c6;
}
.reg_title {
margin: 0px auto 40px auto;
text-align: center;
color: #1e1c1c;
}
.item .el-form-item__label{
color: #1a1a1a;
}
</style>
5.2 登录页面
在src/components下,创建Login.vue
<template>
<el-form :rules="loginRules" ref="loginFormRef" :model="loginForm" class="login_container" label-position="left" label-width="0px"
v-loading="loading">
<h3 class="login_title">系统登录</h3>
<el-form-item prop="userName">
<el-input v-model="loginForm.userName" auto-complete="off" placeholder="账户"></el-input>
</el-form-item>
<el-form-item prop="passWord>">
<el-input type="password" v-model="loginForm.passWord" auto-complete="off" placeholder="密码"></el-input>
</el-form-item>
<el-form-item style="width: 100%">
<el-button @click="regSubmit" style="width: 20%">注册</el-button>
<el-button type="primary" @click="loginSubmit" style="width: 60%">登录</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: 'Login',
data () {
return {
loading: false,
loginRules: {
userName: [
{required: true, message: '请输入用户名', trigger: 'blur'},
{min: 5, max: 15, message: '长度是5到15个字符', trigger: 'blur'},
{pattern: /^(?!\s+).*(?<!\s)$/, message: '开头和结尾不能有空格', trigger: 'blur'}
],
passWord: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 30, message: '长度是6到30个字符', trigger: 'blur'}
]
},
loginForm: {
userName: '',
passWord: ''
}
}
},
methods: {
loginSubmit () {
this.$refs.loginFormRef.validate((valid) => {
if (valid) {
this.loading = true
this.$http.post('/sysUs/login', this.loginForm).then(res => {
if (res.data === 0) {
this.$alert('登录成功', '成功')
this.$router.replace({path: '/home'})
} else {
this.$alert('登录失败', '失败')
}
this.loading = false
})
.catch(failRes => {})
}
})
},
regSubmit () {
this.$router.replace({path: '/reg'})
}
}
}
</script>
<style>
.login_container {
border-radius: 15px;
background-clip: padding-box;
margin: 130px auto;
width: 320px;
padding: 35px 45px 25px 45px;
background: rgba(255,255,255,0.3); // 半透明
box-shadow: 0 0 25px #cac6c6;
}
.login_title {
margin: 0px auto 40px auto;
text-align: center;
color: #1e1c1c;
}
</style>
5.3 中心组件
在src/components下,创建Container.vue
<template>
<el-container class="home-container">
<!-- 头部-->
<el-header>
<div>
<span>管理中心</span>
</div>
<el-button type="info" round @click="logout">退出</el-button>
</el-header>
<!-- 主体-->
<el-container>
<!-- 侧边栏-->
<el-aside>
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:router="true"
@open="handleOpen"
@close="handleClose"
style="text-align: left">
<el-menu-item index="/home">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
<el-menu-item index="/user">
<i class="el-icon-user-solid"></i>
<span slot="title">用户管理</span>
</el-menu-item>
<el-menu-item index="/bomb">
<i class="el-icon-message-solid"></i>
<span slot="title">短信群发</span>
</el-menu-item>
<el-menu-item index="/dd">
<i class="el-icon-s-platform"></i>
<span slot="title">待定</span>
</el-menu-item>
<el-menu-item index="/dd">
<i class="el-icon-s-order"></i>
<span slot="title">待定</span>
</el-menu-item>
</el-menu>
</el-aside>
<!-- 主体内容-->
<el-main>
<router-view/>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
}
},
methods: {
logout () {
window.sessionStorage.clear()
this.$router.push('/log')
},
handleOpen (key, keyPath) {
console.log(key, keyPath)
},
handleClose (key, keyPath) {
console.log(key, keyPath)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.home-container{
height: 100%;
}
.el-header{
background-color: #33383f;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #ffffff;
font-size: 20px;
> div{
display: flex;
align-items: center;
span{
margin-left: 15px;
}
}
}
.el-aside{
background-color: #545c64;
}
.el-main{
background-color: #a4bedb;
}
</style>
5.4 主页面
在src/components下,创建Home.vue
<template>
<div>
11111111111
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style>
</style>
6.添加路由
修改router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Register from "../components/Register";
import Login from "../components/Login";
import Container from "../components/Container";
import Home from "../components/Home";
Vue.use(Router)
export default new Router({
routes: [
// 系统公用
{
path: '/log', // 登陆界面
name: 'Login',
component: Login
},
{
path: '/reg', // 注册
name: 'Register',
component: Register
},
// 管理端
{
path: '/home',
name: 'home_adm',
component: Container,
redirect: '/home', // 管理端首页
children: [
{path: '/home', component: Home} // 首页
// {path: '/us', component: User}, // 用户管理
// {path: '/lya', component: LyApplyFor}, // 领养申请管理
// {path: '/mcs', component: McSafeguard}, // 萌宠信息维护
// {path: '/ycs', component: YcSafeguard}, // 养宠经验维护
// {path: '/tms', component: TeamSafeguard} // 团队介绍维护
]
}
]
})
7. 页面样式
登录界面样式
注册页面样式
管理中心主页面样式
8.修改配置文件
8.1 修改前端端口为8952
修改config/index.js
8.2 设置访问地址
在main.js中添加
// 设置反向代理,前端默认发送到 http://localhost:8951/api
axios.defaults.baseURL = 'http://localhost:8951/api'
三、前后端联调测试
1.启动后端项目
正常启动,端口是8951,额外访问地址是/api
2.启动后端项目
正常启动,启动地址是 http://localhost:8952
3.注册测试
进入注册界面,http://localhost:8952/#/reg ,输入测试数据
点击立即注册,会自动跳转到登录界面。打开开发人员工具,发现请求的端口是后端设置的端口,post请求
打开本地数据库,会发现数据已经录入进去了
以上结果表明,注册成功!!!!通过
4.登录测试
在 http://localhost:8952/#/log 登录界面内,输入刚刚测试注册的数据进行登录测试
点击登录,登录成功会跳转到功能界面