40萬(wàn)用戶自助建站seo根據(jù)什么具體優(yōu)化
簡(jiǎn)單宿舍管理系統(tǒng)(springboot+vue)
- 1.創(chuàng)建項(xiàng)目
- 1.前端
- 2.數(shù)據(jù)庫(kù)
- 3.后端
- 2.登陸
- 1.前端
- 1.準(zhǔn)備工作
- 2.登陸組件
- 3.配置
- 2.后端
- 1.鏈接數(shù)據(jù)庫(kù)
- 2.創(chuàng)建用戶實(shí)體類
- 3.數(shù)據(jù)操作持久層
- 1.配置
- 2.內(nèi)容
- 3.測(cè)試
- 4.中間業(yè)務(wù)層
- 1.異常
- 2.業(yè)務(wù)實(shí)現(xiàn)
- 3.測(cè)試
- 5.響應(yīng)前端控制層
- 3.前后對(duì)接
- 4.效果
- 3.后臺(tái)管理
最近看了springboot和vue,為了練一下把前后端打通就自己手動(dòng)寫個(gè)簡(jiǎn)單的系統(tǒng),測(cè)試一下,把代碼放在倉(cāng)庫(kù)。
1.創(chuàng)建項(xiàng)目
1.前端
我的前端項(xiàng)目名叫Dormitory,然后添加插件element-plus(頁(yè)面設(shè)計(jì))和axios(后端交互)。
npm init vue@latest#這里插件下載我都選no,之后自己會(huì)手動(dòng)下載使用
cd Dormitory
npm install
npm install element-plus
npm install axios
npm run dev
2.數(shù)據(jù)庫(kù)
首先創(chuàng)建庫(kù),第一個(gè)是登陸功能,我就順便創(chuàng)建一個(gè)簡(jiǎn)單的用戶表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 '手機(jī)號(hào)',PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.后端
創(chuàng)建項(xiàng)目名叫dormitory_b,依賴庫(kù)我用了三個(gè)(spring web,mybatis framework,mysql driver),然后配置一下jdk和maven環(huán)境和xml即可。
2.登陸
登陸這里我把uid和role保存到后端session中,username保存到前端cookie中,而且密碼啥的我也沒(méi)加密,就怎么簡(jiǎn)單怎么來(lái)。
1.前端
1.準(zhǔn)備工作
這里我用到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全局注冊(cè)到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里面建一個(gè)router文件夾,里面建一個(gè)index.js寫路由配置文件,然后在main.js里面掛載一下:
import router from './router';
app.use(router)
2.登陸組件
這里登陸頁(yè)面我寫在了LoginView里面,后面我會(huì)配置路由和組件。
<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">系統(tǒng)管理員</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: '請(qǐng)輸入用戶名', trigger: 'blur' }],password: [{ required: true, message: '請(qǐng)輸入密碼', trigger: 'blur' }],role: [{ required: true, message: '請(qǐng)選擇角色', trigger: 'change' }],};const performLogin = async () => {try {const formData = new FormData();//axios默認(rèn)是json格式發(fā)送數(shù)據(jù),但我后端接受的是user,所以將數(shù)據(jù)放到表單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('用戶名錯(cuò)誤');} else if (data.state === 401) {alert('密碼錯(cuò)誤');}else if (data.state === 402) {alert('角色錯(cuò)誤');}} 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里面寫路由配置,將這個(gè)頁(yè)面路由配置一下:
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里面寫一下這個(gè)路由出口
<template><RouterView></RouterView>
</template>
此時(shí)就可以通過(guò)http://localhost:5173/login/
訪問(wèn)到這個(gè)頁(yè)面。
2.后端
1.鏈接數(shù)據(jù)庫(kù)
在application.properties中配置數(shù)據(jù)庫(kù)。
spring.datasource.url=jdbc:mysql://localhost:3306/dormitory?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
2.創(chuàng)建用戶實(shí)體類
在entity/User類里面創(chuàng)建用戶實(shí)體類,和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.數(shù)據(jù)操作持久層
1.配置
首先是配置一下mapper層,在啟動(dòng)類里面添加項(xiàng)目的mapper路徑,讓自動(dòng)掃包。
@MapperScan("com.hckj.dormitory_b.mapper")
在application.properties中配置mapper地址。
mybatis.mapper-locations=classpath:mapper/*.xml
2.內(nèi)容
在mapper/UserMapper接口里面寫SQL語(yǔ)句的抽象方法(類添加@Mapper
注解),然后resources/mapper/UserMapper.xml里面寫抽象方法的映射文件(這里放在resource是因?yàn)閤ml是靜態(tài)文件)。
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.測(cè)試
為了登陸測(cè)試,這里先給數(shù)據(jù)庫(kù)里面插入一條數(shù)據(jù):
INSERT INTO t_user (username, password, name,role, gender, telephone)
VALUES ('zoe', '111', 'dz', 0, 0,'188');
然后測(cè)試(測(cè)試類加注解:@SpringBootTest和@RunWith(SpringRunner.class)
)
@Autowiredprivate UserMapper userMapper;@Testpublic void findByUsername(){System.out.println(userMapper.findByUsername("zoe"));}
4.中間業(yè)務(wù)層
1.異常
在登錄這個(gè)業(yè)務(wù)里會(huì)出現(xiàn)用戶沒(méi)有查詢到和密碼不匹配,所以在service的ex包里面創(chuàng)建UsernameNotFoundException和PasswordNotMatchException異常類,還有一個(gè)是角色不匹配RoleNotMatchException,并都繼承RuntimeException,然后生成拋出異常的5種構(gòu)造方法。
2.業(yè)務(wù)實(shí)現(xiàn)
然后寫業(yè)務(wù)層的接口(加@Service
注解)并寫類實(shí)現(xiàn)這個(gè)接口。
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("用戶數(shù)據(jù)不存在");}String password_ = result.getPassword();if (!password_.equals(password)) {throw new PasswordNotMatchException("用戶密碼錯(cuò)誤");}Integer role_=result.getRole();if (!role_.equals(role)) {throw new RoleNotMatchException("用戶角色錯(cuò)誤");}User user = new User();user.setUid(result.getUid());user.setUsername(result.getUsername());user.setRole(result.getRole());return user;}
}
3.測(cè)試
@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.響應(yīng)前端控制層
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.前后對(duì)接
對(duì)接這里其實(shí)就只是一個(gè)跨域問(wèn)題,這個(gè)就是在后端工程的config/WebMvcConfig類里面加入設(shè)置,這里我前端的地址是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);}
}