简单宿舍管理系统(springboot+vue)
最近看了springboot和vue,为了练一下把前后端打通就自己手动写个简单的系统,测试一下,把代码放在仓库。
1.创建项目
1.前端
我的前端项目名叫Dormitory,然后添加插件element-plus(页面设计)和axios(后端交互)。
python
npm init vue@latest#这里插件下载我都选no,之后自己会手动下载使用
cd Dormitory
npm install
npm install element-plus
npm install axios
npm run dev
2.数据库
首先创建库,第一个是登陆功能,我就顺便创建一个简单的用户表t_user。
python
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,而且我是按需引入,所以首先下载插件:
python
npm install -D unplugin-vue-components unplugin-auto-import
npm install @element-plus/icons-vue
然后在vite.config.ts按需引入element-plus:
python
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上:
python
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
就可以使用svg方式使用:
python
<el-icon><Menu /></el-icon>
然后配置路由用到了router,所以先下载:
python
npm install vue-router
然后在src里面建一个router文件夹,里面建一个index.js写路由配置文件,然后在main.js里面挂载一下:
python
import router from './router';
app.use(router)
2.登陆组件
这里登陆页面我写在了LoginView里面,后面我会配置路由和组件。
python
<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) {
// 登录成功后,保存用户名到cookie
document.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里面写路由配置,将这个页面路由配置一下:
python
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里面写一下这个路由出口
python
<template>
<RouterView></RouterView>
</template>
此时就可以通过http://localhost:5173/login/
访问到这个页面。
2.后端
1.链接数据库
在application.properties中配置数据库。
python
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)。
python
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路径,让自动扫包。
python
@MapperScan("com.hckj.dormitory_b.mapper")
在application.properties中配置mapper地址。
python
mybatis.mapper-locations=classpath:mapper/*.xml
2.内容
在mapper/UserMapper接口里面写SQL语句的抽象方法(类添加@Mapper
注解),然后resources/mapper/UserMapper.xml里面写抽象方法的映射文件(这里放在resource是因为xml是静态文件)。
python
User findByUsername(String username);//接口
<?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">
<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.测试
为了登陆测试,这里先给数据库里面插入一条数据:
python
INSERT INTO t_user (username, password, name,role, gender, telephone)
VALUES ('zoe', '111', 'dz', 0, 0,'188');
然后测试(测试类加注解:@SpringBootTest和@RunWith(SpringRunner.class)
)
python
@Autowired
private UserMapper userMapper;
@Test
public void findByUsername(){
System.out.println(userMapper.findByUsername("zoe"));
}
4.中间业务层
1.异常
在登录这个业务里会出现用户没有查询到和密码不匹配,所以在service的ex包里面创建UsernameNotFoundException和PasswordNotMatchException异常类,还有一个是角色不匹配RoleNotMatchException,并都继承RuntimeException,然后生成抛出异常的5种构造方法。
2.业务实现
然后写业务层的接口(加@Service
注解)并写类实现这个接口。
python
User login(String username, String password,Integer role);//接口
@Service
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
@Override
public 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.测试
python
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTests {
@Autowired
private IUserService userService;
@Test
public void login(){
User user= userService.login("zoe","111",0);
System.out.println(user);
}
}
5.响应前端控制层
python
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 {
@Autowired
private 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保存到session
session.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
python
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 {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true);
}
}