简单宿舍管理系统(springboot+vue)
- 1.创建项目
- 1.前端
- 2.数据库
- 3.后端
- 2.登陆
- 1.前端
- 1.准备工作
- 2.登陆组件
- 3.配置
- 2.后端
- 1.链接数据库
- 2.创建用户实体类
- 3.数据操作持久层
- 1.配置
- 2.内容
- 3.测试
- 4.中间业务层
- 1.异常
- 2.业务实现
- 3.测试
- 5.响应前端控制层
- 3.前后对接
- 4.效果
- 3.后台管理
最近看了springboot和vue,为了练一下把前后端打通就自己手动写个简单的系统,测试一下,把代码放在仓库。
1.创建项目
1.前端
我的前端项目名叫Dormitory,然后添加插件element-plus(页面设计)和axios(后端交互)。
npm init vue@latest#这里插件下载我都选no,之后自己会手动下载使用
cd Dormitory
npm install
npm install element-plus
npm install axios
npm run dev
2.数据库
首先创建库,第一个是登陆功能,我就顺便创建一个简单的用户表t_user。
mysql -u root -p
create database dormitory;
use dormitory;
use store
CREATE TABLE t_user (uid INT AUTO_INCREMENT COMMENT '用户id',username VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',password CHAR(32) NOT NULL COMMENT '密码',role INT COMMENT '角色',name VARCHAR(20) NOT NULL UNIQUE COMMENT '姓名',gender INT COMMENT '性别:0-女,1-男',telephone VARCHAR(50) COMMENT '手机号',PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.后端
创建项目名叫dormitory_b,依赖库我用了三个(spring web,mybatis framework,mysql driver),然后配置一下jdk和maven环境和xml即可。
2.登陆
登陆这里我把uid和role保存到后端session中,username保存到前端cookie中,而且密码啥的我也没加密,就怎么简单怎么来。
1.前端
1.准备工作
这里我用到element-plus和icon,而且我是按需引入,所以首先下载插件:
npm install -D unplugin-vue-components unplugin-auto-import
npm install @element-plus/icons-vue
然后在vite.config.ts按需引入element-plus:
import { fileURLToPath, URL } from 'node:url'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
});
在main.ts里将icon全局注册到App上:
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}
就可以使用svg方式使用:
<el-icon><Menu /></el-icon>
然后配置路由用到了router,所以先下载:
npm install vue-router
然后在src里面建一个router文件夹,里面建一个index.js写路由配置文件,然后在main.js里面挂载一下:
import router from './router';
app.use(router)
2.登陆组件
这里登陆页面我写在了LoginView里面,后面我会配置路由和组件。
<template><div class="login-container"><div class="login-form"><el-form ref="login-form" :model="loginForm" label-width="80px" :rules="rules"><el-form-item label="用户名" prop="username"><el-input v-model="loginForm.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input type="password" v-model="loginForm.password"></el-input></el-form-item><el-form-item label="角色" prop="role"><el-radio-group v-model="loginForm.role"><el-radio label="admin">系统管理员</el-radio><el-radio label="dorm">宿舍管理员</el-radio></el-radio-group></el-form-item><el-form-item size="large"><el-button type="primary" @click="toLogin">登录</el-button></el-form-item></el-form></div></div></template><script>import { ref } from 'vue';import axios from 'axios';export default {setup() {const loginForm = ref({username: '',password: '',role: 'admin',});const rules = {username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],password: [{ required: true, message: '请输入密码', trigger: 'blur' }],role: [{ required: true, message: '请选择角色', trigger: 'change' }],};const performLogin = async () => {try {const formData = new FormData();//axios默认是json格式发送数据,但我后端接受的是user,所以将数据放到表单formData.append('username', loginForm.value.username);formData.append('password', loginForm.value.password);formData.append('role',loginForm.value.role=='admin'?0:1);const response = await axios.post('http://localhost:8080/users/login', formData);const data = response.data;if (data.state === 200) {// 登录成功后,保存用户名到cookiedocument.cookie = `username=${loginForm.value.username}; expires=; path=/`;alert('登录成功');} else if (data.state === 400) {alert('用户名错误');} else if (data.state === 401) {alert('密码错误');}else if (data.state === 402) {alert('角色错误');}} catch (error) {console.error('An error occurred:', error);}};const toLogin = () => {performLogin();};return {loginForm,rules,toLogin,};},};</script><style scoped>.login-container {display: flex;align-items: center;justify-content: center;height: 100vh;}.login-form {padding: 80px;border-radius: 10px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);}</style>
3.配置
首先是在router/index.js里面写路由配置,将这个页面路由配置一下:
import { createRouter, createWebHistory } from 'vue-router'
import LoginView from '@/components/LoginView.vue'
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/login',component: LoginView}]
})
export default router
然后在App.vue里面写一下这个路由出口
<template><RouterView></RouterView>
</template>
此时就可以通过http://localhost:5173/login/
访问到这个页面。
2.后端
1.链接数据库
在application.properties中配置数据库。
spring.datasource.url=jdbc:mysql://localhost:3306/dormitory?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
2.创建用户实体类
在entity/User类里面创建用户实体类,和getset,equal,tostring方法(mac的快捷键是command+n)。
public class User {private Integer uid;private String username;private String password;private Integer role;private String name;private Integer gender;private String phone;
}
3.数据操作持久层
1.配置
首先是配置一下mapper层,在启动类里面添加项目的mapper路径,让自动扫包。
@MapperScan("com.hckj.dormitory_b.mapper")
在application.properties中配置mapper地址。
mybatis.mapper-locations=classpath:mapper/*.xml
2.内容
在mapper/UserMapper接口里面写SQL语句的抽象方法(类添加@Mapper
注解),然后resources/mapper/UserMapper.xml里面写抽象方法的映射文件(这里放在resource是因为xml是静态文件)。
User findByUsername(String username);//接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hckj.dormitory_b.mapper.UserMapper"><select id="findByUsername" resultType="com.hckj.dormitory_b.entity.User">select * from t_user where username=#{username}</select>
</mapper>
3.测试
为了登陆测试,这里先给数据库里面插入一条数据:
INSERT INTO t_user (username, password, name,role, gender, telephone)
VALUES ('zoe', '111', 'dz', 0, 0,'188');
然后测试(测试类加注解:@SpringBootTest和@RunWith(SpringRunner.class)
)
@Autowiredprivate UserMapper userMapper;@Testpublic void findByUsername(){System.out.println(userMapper.findByUsername("zoe"));}
4.中间业务层
1.异常
在登录这个业务里会出现用户没有查询到和密码不匹配,所以在service的ex包里面创建UsernameNotFoundException和PasswordNotMatchException异常类,还有一个是角色不匹配RoleNotMatchException,并都继承RuntimeException,然后生成抛出异常的5种构造方法。
2.业务实现
然后写业务层的接口(加@Service
注解)并写类实现这个接口。
User login(String username, String password,Integer role);//接口
@Service
public class UserServiceImpl implements IUserService{@Autowiredprivate UserMapper userMapper;@Overridepublic User login(String username, String password,Integer role) {User result = userMapper.findByUsername(username);if (result == null) {throw new UsernameNotFoundException("用户数据不存在");}String password_ = result.getPassword();if (!password_.equals(password)) {throw new PasswordNotMatchException("用户密码错误");}Integer role_=result.getRole();if (!role_.equals(role)) {throw new RoleNotMatchException("用户角色错误");}User user = new User();user.setUid(result.getUid());user.setUsername(result.getUsername());user.setRole(result.getRole());return user;}
}
3.测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTests {@Autowiredprivate IUserService userService;@Testpublic void login(){User user= userService.login("zoe","111",0);System.out.println(user);}
}
5.响应前端控制层
package com.hckj.dormitory_b.controller;import com.hckj.dormitory_b.entity.User;
import com.hckj.dormitory_b.service.IUserService;
import com.hckj.dormitory_b.service.ex.PasswordNotMatchException;
import com.hckj.dormitory_b.service.ex.RoleNotMatchException;
import com.hckj.dormitory_b.service.ex.UsernameNotFoundException;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("users")
public class UserController {@Autowiredprivate IUserService userService;@PostMapping("login")public Map<String, Object> login(User user, HttpSession session) {String username = user.getUsername();String password = user.getPassword();Integer role=user.getRole();Map<String, Object> response = new HashMap<>();try {User loggedInUser = userService.login(username, password,role);session.setAttribute("uid",loggedInUser.getUid());//将用户的uid和role保存到sessionsession.setAttribute("role",loggedInUser.getRole());response.put("state", 200);response.put("message", "登陆成功");response.put("data", loggedInUser);} catch (UsernameNotFoundException e) {response.put("state", 400);response.put("message", "用户名未找到");response.put("data", null);} catch (PasswordNotMatchException e) {response.put("state", 401);response.put("message", "密码不正确");response.put("data", null);} catch (RoleNotMatchException e){response.put("state",402);response.put("message","角色不正确");response.put("data",null);}return response;}
}
3.前后对接
对接这里其实就只是一个跨域问题,这个就是在后端工程的config/WebMvcConfig类里面加入设置,这里我前端的地址是http://localhost:5173
package com.hckj.dormitory_b.config;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 WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:5173").allowedMethods("GET", "POST", "PUT", "DELETE").allowCredentials(true);}
}