GitHub地址:https://github.com/saysky/springboot-vue-example/ 前几天一个朋友找我帮她做项目,功能比较简单,后台只需要设计3张表,但是要求前端必须使用 Vue,且使用 Element UI。正好最近准备学习 Vue,就把这个活接下来了,给自己压力去 learn and do. 功能很简单,服务器信息管理系统,后台可以添加服务器,然后可以对其申请、释放、删除。 先看一下效果图
一、部分效果图
1.服务器管理页面,服务器信息分页显示,添加服务器,申请服务器,释放服务器,删除服务器,查询服务器 2.新增服务器弹出对话框 3.申请服务器,使用datepicker选择时间
二、代码结构
1、后端,典型 SpringBoot+MyBatis 框架,后端控制器使用 @RestController,全部返还JSON格式数据 2、前端
三、主要代码介绍
通过服务器信息管理,其实本质上就是一张表的 CRUD,来介绍后端代码和前端代码 1.后端代码,这里只贴 Controller 里的代码
- package com.example.sens.controller;
- import com.baomidou.mybatisplus.plugins.Page;
- import com.example.sens.entity.Server;
- import com.example.sens.entity.User;
- import com.example.sens.enums.ServerStatus;
- import com.example.sens.service.ServerService;
- import com.example.sens.utils.Response;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
- import javax.servlet.http.HttpSession;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Objects;
- /**
- * @author 言曌
- * @date 2019-05-08 13:10
- */
- @RestController
- @RequestMapping("/api/server")
- public class ServerController {
- @Autowired
- private ServerService serverService;
- /**
- * 分页展示服务器
- * @param pageNo
- * @param pageSize
- * @param queryType
- * @param queryKeyword
- * @return
- */
- @GetMapping("/paging")
- public Response<Page<Server>> paging(@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
- @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
- @RequestParam(value = "queryType", required = false) String queryType,
- @RequestParam(value = "queryKeyword", required = false) String queryKeyword) {
- Page pageable = new Page(pageNo, pageSize);
- Page<Server> page = null;
- try {
- page = serverService.findAll(queryType, queryKeyword, pageable);
- } catch (Exception e) {
- return Response.no();
- }
- return Response.yes(page);
- }
- /**
- * 申请服务器
- * @param server
- * @param session
- * @return
- */
- @PostMapping("/apply")
- public Response applyServer(@RequestBody Server server, HttpSession session) {
- User user = (User) session.getAttribute("user");
- try {
- Long now = System.currentTimeMillis();
- //1.判断项目名称是否存在
- Server checkProjectName = serverService.findByProjectName(server.getProjectName());
- if(checkProjectName != null && !Objects.equals(checkProjectName.getId(), server.getId())) {
- return Response.no("项目名已存在!");
- }
- //2.添加
- if ((Objects.equals(server.getServerStatus(), ServerStatus.FREE.getDesc())) || (now > (server.getReleaseTime() != null ? server.getReleaseTime() : 0))) {
- server.setApplyUserName(user.getUserName());
- server.setApplyTime(now);
- server.setServerStatus(ServerStatus.USED.getDesc());
- serverService.saveByServer(server);
- } else {
- return Response.no("服务器在使用中,不能申请!");
- }
- } catch (Exception e) {
- e.printStackTrace();
- return Response.no("申请失败!");
- }
- return Response.yes();
- }
- /**
- * 释放服务器
- * @param id
- * @return
- */
- @PostMapping("/release")
- public Response releaseServer(@RequestParam("id") Long id) {
- try {
- Server server = serverService.findByServerId(id);
- if (server != null) {
- Long now = System.currentTimeMillis();
- if (!(Objects.equals(server.getServerStatus(), ServerStatus.FREE.getDesc()))) {
- server.setReleaseTime(now);
- server.setServerStatus(ServerStatus.FREE.getDesc());
- serverService.saveByServer(server);
- } else {
- return Response.no("服务器已经释放!");
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- return Response.no("申请失败!");
- }
- return Response.yes();
- }
- /**
- * 创建服务器
- * @param server
- * @return
- */
- @PostMapping("/create")
- public Response createServer(@RequestBody Server server) {
- try {
- serverService.saveByServer(server);
- } catch (Exception e) {
- e.printStackTrace();
- return Response.no("保存失败!");
- }
- return Response.yes();
- }
- /**
- * 删除服务器
- * @param id
- * @return
- */
- @PostMapping("/delete")
- public Response<Boolean> delete(@RequestParam("id") Long id) {
- try {
- serverService.removeServer(id);
- } catch (Exception e) {
- e.printStackTrace();
- return Response.no();
- }
- return Response.yes();
- }
- /**
- * 批量删除服务器
- * @param ids
- * @return
- */
- @PostMapping(value = "/batchRemove")
- @ResponseBody
- public Response<Boolean> batchRemove(@RequestParam("ids") String ids) {
- if("".equals(ids)) {
- return Response.no("请至少选择一项!");
- }
- String[] arr = ids.split(",");
- List<Long> list = new ArrayList<>();
- for (int i = 0; i < arr.length; i++) {
- list.add(Long.valueOf(arr[i]));
- }
- try {
- serverService.batchRemove(list);
- } catch (Exception e) {
- e.printStackTrace();
- return Response.no();
- }
- return Response.yes();
- }
- }
2.前端代码,主要贴vue文件代码
- <template>
- <div class="main-login">
- <lyz-layout
- :pagination="pagination"
- :label="label"
- @handleSizeChange="handleSizeChange"
- @handleCurrentChange="handleCurrentChange">
- <div slot="banner" class="top-right">
- <el-button type="primary" size="small" @click="createServer" slot="reference">新增</el-button>
- <el-select v-model="queryType" placeholder="请选择查询类型" class="right-select" @change="queryTypeChange"
- clearable @clear="queryList">
- <el-option label="服务器名称" value="server_name">服务器名称</el-option>
- <el-option label="项目名称" value="project_name">项目名称</el-option>
- </el-select>
- <el-input placeholder="请输入搜索内容" v-model="queryKeyword" class="input-with-select" clearable>
- <el-button slot="append" icon="el-icon-search" @click="queryList"></el-button>
- </el-input>
- <el-button type="danger" size="small" @click="batchRemove" slot="reference">批量删除</el-button>
- </div>
- <div slot="main" class="main-body">
- <el-table
- :data="tableData"
- stripe
- v-loading="loginLoading"
- tooltip-effect="light"
- height="100%"
- style="width: 100%"
- @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55"></el-table-column>
- <el-table-column
- v-for="(data,index) in tableHeader"
- :show-overflow-tooltip="true"
- :key="index"
- :prop="data.prop"
- :label="data.label"
- :min-width="data['min-width']"
- :align="data.align">
- </el-table-column>
- <el-table-column
- fixed="right"
- label="操作"
- min-width="120">
- <template slot-scope="scope">
- <el-button type="text" size="mini"
- :disabled="scope.row.serverStatus === '使用中'"
- @click="applyServer(scope.row)">申请
- </el-button>
- <el-button type="text" size="mini"
- :disabled="scope.row.serverStatus === '空闲'"
- @click="releaseServer(scope.row.id)">释放
- </el-button>
- <el-button type="text" size="mini" class="danger-text"
- @click="deleteServer(scope.row.id)">删除
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </lyz-layout>
- <el-dialog :title="operate==='apply'?'申请服务器':'添加服务器信息'" :visible.sync="messageVisible" width="33%" center
- class="user-dialog">
- <el-form :model="messageForm" :label-width="messageLabelWidth" ref="messageForm" :rules="messageRule"
- :validate-on-rule-change=false>
- <el-form-item label="名称" v-if="operate==='create'" prop="serverName">
- <el-input v-model="messageForm.serverName" placeholder="请输入服务器名称"></el-input>
- </el-form-item>
- <el-form-item label="状态" v-if="operate==='create'" pop="serverStatus">
- <el-radio-group v-model="messageForm.serverStatus">
- <el-radio label="free" checked>空闲</el-radio>
- <el-radio lebel="used">使用中</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="项目名称" v-if="operate==='apply'" prop="projectName">
- <el-input v-model="messageForm.projectName" placeholder="请输入项目名称"></el-input>
- </el-form-item>
- <el-form-item label="申请时间" v-if="operate==='apply'" prop="applyTime">
- <el-date-picker
- v-model="messageForm.applyTime"
- type="datetime"
- value-format="timestamp"
- placeholder="选择申请时间"
- align="right"
- :picker-options="pickerOptions">
- </el-date-picker>
- </el-form-item>
- <el-form-item label="释放时间" v-if="operate==='apply'" prop="releaseTime">
- <el-date-picker
- v-model="messageForm.releaseTime"
- type="datetime"
- value-format="timestamp"
- placeholder="选择释放时间"
- align="right"
- :picker-options="pickerOptions">
- </el-date-picker>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button @click="messageVisible = false">取 消</el-button>
- <el-button type="primary" @click=saveServer>确 定</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import lyzLayout from '@/components/lyzLayout';
- import manage from '../manage.component';
- import {formatDateTime, responseText, debounce} from '../../../config/utils.js';
- export default {
- name: "server",
- data() {
- return {
- queryType: '',
- queryKeyword: '',
- pagination: {
- pageIndex: 1,
- pageSize: 10,
- total: 0,
- },
- label: '服务器信息管理',
- messageForm: {},
- messageVisible: false,
- messageLabelWidth: '90px',
- messageRule: {
- serverName: [
- {required: true, message: '请输入服务器名称', trigger: 'blur'}
- ],
- serverStatus: [
- {required: true, message: '请选择服务器状态', trigger: 'blur'}
- ],
- projectName: [
- {required: true, message: '请输入项目名称', trigger: 'blur'}
- ],
- applyTime: [
- {required: true, message: '请输入申请时间', trigger: 'blur'}
- ],
- releaseTime: [
- {required: true, message: '请输入释放时间', trigger: 'blur'}
- ]
- },
- operate: '',
- multipleSelection: [],//多选的数据
- pickerOptions: {
- shortcuts: [{
- text: '今天',
- onClick(picker) {
- picker.$emit('pick', new Date());
- }
- }, {
- text: '一天后',
- onClick(picker) {
- const date = new Date();
- date.setTime(date.getTime() + 3600 * 1000 * 24);
- picker.$emit('pick', date);
- }
- }, {
- text: '一周后',
- onClick(picker) {
- const date = new Date();
- date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
- picker.$emit('pick', date);
- }
- }, {
- text: '一月后',
- onClick(picker) {
- const date = new Date();
- date.setTime(date.getTime() + 3600 * 1000 * 24 * 30);
- picker.$emit('pick', date);
- }
- }],
- disabledDate: function (now) {
- if (now < new Date())
- return true;
- return false
- }
- },
- tableData: [],
- loginLoading: false,
- tableHeader: [
- {
- prop: 'id',
- label: 'ID',
- 'min-width': 40,
- align: 'center',
- },
- {
- prop: 'applyUserName',
- label: '使用人',
- 'min-width': 80,
- align: 'center',
- },
- {
- prop: 'serverName',
- label: '服务器名称',
- 'min-width': 120,
- align: 'center',
- },
- {
- prop: 'serverStatus',
- label: '服务器状态',
- 'min-width': 100,
- align: 'center',
- },
- {
- prop: 'applyTime',
- label: '申请时间',
- 'min-width': 120,
- align: 'center',
- },
- {
- prop: 'releaseTime',
- label: '释放时间',
- 'min-width': 120,
- align: 'center',
- },
- {
- prop: 'projectName',
- label: '项目名称',
- 'min-width': 120,
- align: 'center',
- },
- ]
- };
- },
- components: {
- lyzLayout,
- },
- mixins: [manage],
- created() {
- this.queryList();
- },
- mounted() {
- this.$watch('queryKeyword', debounce(() => {
- this.pagination.pageIndex = 1;
- this.queryList();
- }, 1000));
- },
- methods: {
- queryTypeChange(val) {
- if (val !== '') {
- this.queryType = val;
- this.queryList();
- }
- },
- queryList() {
- this.loginLoading = true;
- let params = {
- queryType: this.queryType,
- queryKeyword: this.queryKeyword,
- pageNo: this.pagination.pageIndex,
- pageSize: this.pagination.pageSize
- };
- this.$http.get('/server/paging', {params: params}).then(({body}) => {
- if (body.success === true) {
- responseText(body.data.records).forEach((item) => {
- itemitem.serverStatus = item.serverStatus == 'free' ? '空闲' : '使用中';
- if (item.releaseTime != null) {
- item.releaseTime = new Date(item.releaseTime).toLocaleString().replace(/:\d{1,2}$/, ' ');
- }
- if (item.applyTime != null) {
- item.applyTime = new Date(item.applyTime).toLocaleString().replace(/:\d{1,2}$/, ' ');
- }
- })
- this.tableData = responseText(body.data.records);
- this.pagination.total = body.data.records ? body.data.total : 0;
- } else {
- this.$message.error(body.message);
- }
- }).finally(() => {
- this.loginLoading = false;
- })
- },
- handleSelectionChange(val) {
- this.multipleSelection = val;
- },
- batchRemove() {
- let ids = '';
- this.multipleSelection.forEach(selectedItem => {
- // 删除请求
- ids += selectedItem.id + ',';
- });
- let params = {
- ids: ids
- };
- this.$http.post("/server/batchRemove", {}, {params: params}).then(({body}) => {
- if (body.success === true) {
- this.queryList();
- this.$message.success(body.message);
- } else {
- this.$message.error(body.message);
- }
- }).catch(() => {
- this.$message.error('删除失败');
- })
- },
- deleteServer(id) {
- let params = {
- id: id,
- };
- this.delete('/server/delete', params);
- },
- createServer(row) {
- console.log(row);
- this.messageVisible = true;
- this.operate = 'create';
- let _form = Object.assign({}, row);
- this.messageForm = _form;
- },
- applyServer(row) {
- console.log(row);
- this.messageVisible = true;
- this.operate = 'apply';
- let _form = Object.assign({}, row);
- this.messageForm = _form;
- },
- saveServer() {
- console.log('save');
- let params = {
- applyUserName: this.messageForm.applyUserName,
- serverName: this.messageForm.serverName,
- projectName: this.messageForm.projectName,
- applyTime: this.messageForm.applyTime,
- releaseTime: this.messageForm.releaseTime,
- };
- this.$refs['messageForm'].validate((valid) => {
- if (valid) {
- if (params.applyTime > params.releaseTime) {
- this.$message.error('释放时间必须大于申请时间!');
- } else {
- if (this.messageForm.id) {
- params.serverStatus = this.messageForm.serverStatus == '空闲' ? 'free' : 'used';
- params.id = this.messageForm.id;
- this.save('/server/apply', params, 'messageVisible');
- } else {
- params.serverStatus = this.messageForm.serverStatus;
- this.save('/server/create', params, 'messageVisible');
- }
- }
- }
- })
- },
- releaseServer(id) {
- this.$http.post('/server/release?id=' + id, {}, {}).then(({body}) => {
- if (body.success === true) {
- this.$message.success(body.message);
- this.queryList();
- } else {
- this.$message.error(body.message);
- }
- }).catch(() => {
- this.$message.error('释放失败');
- })
- }
- }
- }
- </script>
- <style scoped>
- .main-login {
- height: 100%;
- }
- .danger-text {
- color: #F56C6C;
- }
- </style>
其他代码就不贴了,见GitHub 该项目实现了前后端分离,后面的开发只需要在原有的基础上复制粘贴就行了 GitHub地址:https://github.com/saysky/springboot-vue-example/
2020年04月18日 18:58:15
兄弟,我clone你的项目,打开前端还是vue的主页面
2020年04月10日 13:28:46
没有进入登录页面,登录页面进去也是空白,是什么原因呢
2020年05月02日 13:07:33
检查一下后台请求
2019年10月29日 10:55:36
你好,请问为什么我加了菜单,但是显示不出来,左侧菜单是在哪里配置的
2019年06月11日 11:24:00
请求发一下github链接谢谢
2019年05月30日 15:27:10
能发送下git地址吗? 谢谢!
2019年05月24日 11:30:28
请大佬发送下git地址。
2019年05月12日 16:48:21
步骤很详细,谢谢