SpringBoot + Vue Element UI 实现前后端分离

avatar 2019年05月11日21:18:28 14 32880 views
博主分享免费Java教学视频,B站账号:Java刘哥

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 里的代码

 
  1. package com.example.sens.controller;
  2.  
  3. import com.baomidou.mybatisplus.plugins.Page;
  4. import com.example.sens.entity.Server;
  5. import com.example.sens.entity.User;
  6. import com.example.sens.enums.ServerStatus;
  7. import com.example.sens.service.ServerService;
  8. import com.example.sens.utils.Response;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.web.bind.annotation.*;
  11.  
  12. import javax.servlet.http.HttpSession;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import java.util.Objects;
  16.  
  17. /**
  18.  * @author 言曌
  19.  * @date 2019-05-08 13:10
  20.  */
  21.  
  22. @RestController
  23. @RequestMapping("/api/server")
  24. public class ServerController {
  25.  
  26.  
  27.     @Autowired
  28.     private ServerService serverService;
  29.  
  30.     /**
  31.      * 分页展示服务器
  32.      * @param pageNo
  33.      * @param pageSize
  34.      * @param queryType
  35.      * @param queryKeyword
  36.      * @return
  37.      */
  38.     @GetMapping("/paging")
  39.     public Response<Page<Server>> paging(@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
  40.                                          @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
  41.                                          @RequestParam(value = "queryType", required = false) String queryType,
  42.                                          @RequestParam(value = "queryKeyword", required = false) String queryKeyword) {
  43.         Page pageable = new Page(pageNo, pageSize);
  44.         Page<Server> page = null;
  45.         try {
  46.             page = serverService.findAll(queryType, queryKeyword, pageable);
  47.         } catch (Exception e) {
  48.             return Response.no();
  49.         }
  50.         return Response.yes(page);
  51.     }
  52.  
  53.  
  54.     /**
  55.      * 申请服务器
  56.      * @param server
  57.      * @param session
  58.      * @return
  59.      */
  60.     @PostMapping("/apply")
  61.     public Response applyServer(@RequestBody Server server, HttpSession session) {
  62.         User user = (User) session.getAttribute("user");
  63.         try {
  64.             Long now = System.currentTimeMillis();
  65.             //1.判断项目名称是否存在
  66.             Server checkProjectName = serverService.findByProjectName(server.getProjectName());
  67.             if(checkProjectName != null && !Objects.equals(checkProjectName.getId(), server.getId())) {
  68.                 return Response.no("项目名已存在!");
  69.             }
  70.  
  71.             //2.添加
  72.             if ((Objects.equals(server.getServerStatus(), ServerStatus.FREE.getDesc())) || (now > (server.getReleaseTime() != null ? server.getReleaseTime() : 0))) {
  73.                 server.setApplyUserName(user.getUserName());
  74.                 server.setApplyTime(now);
  75.                 server.setServerStatus(ServerStatus.USED.getDesc());
  76.                 serverService.saveByServer(server);
  77.             } else {
  78.                 return Response.no("服务器在使用中,不能申请!");
  79.             }
  80.  
  81.         } catch (Exception e) {
  82.             e.printStackTrace();
  83.             return Response.no("申请失败!");
  84.         }
  85.         return Response.yes();
  86.     }
  87.  
  88.     /**
  89.      * 释放服务器
  90.      * @param id
  91.      * @return
  92.      */
  93.     @PostMapping("/release")
  94.     public Response releaseServer(@RequestParam("id") Long id) {
  95.         try {
  96.             Server server = serverService.findByServerId(id);
  97.             if (server != null) {
  98.                 Long now = System.currentTimeMillis();
  99.                 if (!(Objects.equals(server.getServerStatus(), ServerStatus.FREE.getDesc()))) {
  100.                     server.setReleaseTime(now);
  101.                     server.setServerStatus(ServerStatus.FREE.getDesc());
  102.                     serverService.saveByServer(server);
  103.                 } else {
  104.                     return Response.no("服务器已经释放!");
  105.                 }
  106.             }
  107.         } catch (Exception e) {
  108.             e.printStackTrace();
  109.             return Response.no("申请失败!");
  110.         }
  111.         return Response.yes();
  112.     }
  113.  
  114.     /**
  115.      * 创建服务器
  116.      * @param server
  117.      * @return
  118.      */
  119.     @PostMapping("/create")
  120.     public Response createServer(@RequestBody Server server) {
  121.         try {
  122.             serverService.saveByServer(server);
  123.         } catch (Exception e) {
  124.             e.printStackTrace();
  125.             return Response.no("保存失败!");
  126.         }
  127.         return Response.yes();
  128.     }
  129.  
  130.  
  131.     /**
  132.      * 删除服务器
  133.      * @param id
  134.      * @return
  135.      */
  136.     @PostMapping("/delete")
  137.     public Response<Boolean> delete(@RequestParam("id") Long id) {
  138.         try {
  139.             serverService.removeServer(id);
  140.         } catch (Exception e) {
  141.             e.printStackTrace();
  142.             return Response.no();
  143.         }
  144.         return Response.yes();
  145.     }
  146.  
  147.     /**
  148.      * 批量删除服务器
  149.      * @param ids
  150.      * @return
  151.      */
  152.     @PostMapping(value = "/batchRemove")
  153.     @ResponseBody
  154.     public Response<Boolean> batchRemove(@RequestParam("ids") String ids) {
  155.         if("".equals(ids)) {
  156.             return Response.no("请至少选择一项!");
  157.         }
  158.         String[] arr = ids.split(",");
  159.         List<Long> list = new ArrayList<>();
  160.         for (int i = 0; i < arr.length; i++) {
  161.             list.add(Long.valueOf(arr[i]));
  162.         }
  163.         try {
  164.             serverService.batchRemove(list);
  165.         } catch (Exception e) {
  166.             e.printStackTrace();
  167.             return Response.no();
  168.         }
  169.         return Response.yes();
  170.     }
  171.  
  172.  
  173. }

  2.前端代码,主要贴vue文件代码

 
  1. <template>
  2.     <div class="main-login">
  3.         <lyz-layout
  4.                 :pagination="pagination"
  5.                 :label="label"
  6.                 @handleSizeChange="handleSizeChange"
  7.                 @handleCurrentChange="handleCurrentChange">
  8.             <div slot="banner" class="top-right">
  9.                 <el-button type="primary" size="small" @click="createServer" slot="reference">新增</el-button> &nbsp;
  10.  
  11.                 <el-select v-model="queryType" placeholder="请选择查询类型" class="right-select" @change="queryTypeChange"
  12.                            clearable @clear="queryList">
  13.                     <el-option label="服务器名称" value="server_name">服务器名称</el-option>
  14.                     <el-option label="项目名称" value="project_name">项目名称</el-option>
  15.                 </el-select>
  16.  
  17.                 <el-input placeholder="请输入搜索内容" v-model="queryKeyword" class="input-with-select" clearable>
  18.                     <el-button slot="append" icon="el-icon-search" @click="queryList"></el-button>
  19.                 </el-input>
  20.                 <el-button type="danger" size="small" @click="batchRemove" slot="reference">批量删除</el-button> &nbsp;
  21.  
  22.             </div>
  23.             <div slot="main" class="main-body">
  24.                 <el-table
  25.                         :data="tableData"
  26.                         stripe
  27.                         v-loading="loginLoading"
  28.                         tooltip-effect="light"
  29.                         height="100%"
  30.                         style="width: 100%"
  31.                         @selection-change="handleSelectionChange">
  32.                     <el-table-column type="selection" width="55"></el-table-column>
  33.                     <el-table-column
  34.                             v-for="(data,index) in tableHeader"
  35.                             :show-overflow-tooltip="true"
  36.                             :key="index"
  37.                             :prop="data.prop"
  38.                             :label="data.label"
  39.                             :min-width="data['min-width']"
  40.                             :align="data.align">
  41.                     </el-table-column>
  42.                     <el-table-column
  43.                             fixed="right"
  44.                             label="操作"
  45.                             min-width="120">
  46.                         <template slot-scope="scope">
  47.                             <el-button type="text" size="mini"
  48.                                        :disabled="scope.row.serverStatus === '使用中'"
  49.                                        @click="applyServer(scope.row)">申请
  50.                             </el-button>
  51.                             <el-button type="text" size="mini"
  52.                                        :disabled="scope.row.serverStatus === '空闲'"
  53.                                        @click="releaseServer(scope.row.id)">释放
  54.                             </el-button>
  55.                             <el-button type="text" size="mini" class="danger-text"
  56.                                        @click="deleteServer(scope.row.id)">删除
  57.                             </el-button>
  58.                         </template>
  59.                     </el-table-column>
  60.                 </el-table>
  61.             </div>
  62.  
  63.         </lyz-layout>
  64.         <el-dialog :title="operate==='apply'?'申请服务器':'添加服务器信息'" :visible.sync="messageVisible" width="33%" center
  65.                    class="user-dialog">
  66.             <el-form :model="messageForm" :label-width="messageLabelWidth" ref="messageForm" :rules="messageRule"
  67.                      :validate-on-rule-change=false>
  68.  
  69.                 <el-form-item label="名称" v-if="operate==='create'" prop="serverName">
  70.                     <el-input v-model="messageForm.serverName" placeholder="请输入服务器名称"></el-input>
  71.                 </el-form-item>
  72.  
  73.                 <el-form-item label="状态" v-if="operate==='create'" pop="serverStatus">
  74.                     <el-radio-group v-model="messageForm.serverStatus">
  75.                         <el-radio label="free" checked>空闲</el-radio>
  76.                         <el-radio lebel="used">使用中</el-radio>
  77.                     </el-radio-group>
  78.                 </el-form-item>
  79.  
  80.                 <el-form-item label="项目名称" v-if="operate==='apply'" prop="projectName">
  81.                     <el-input v-model="messageForm.projectName" placeholder="请输入项目名称"></el-input>
  82.                 </el-form-item>
  83.  
  84.                 <el-form-item label="申请时间" v-if="operate==='apply'" prop="applyTime">
  85.                     <el-date-picker
  86.                             v-model="messageForm.applyTime"
  87.                             type="datetime"
  88.                             value-format="timestamp"
  89.                             placeholder="选择申请时间"
  90.                             align="right"
  91.                             :picker-options="pickerOptions">
  92.                     </el-date-picker>
  93.                 </el-form-item>
  94.  
  95.                 <el-form-item label="释放时间" v-if="operate==='apply'" prop="releaseTime">
  96.                     <el-date-picker
  97.                             v-model="messageForm.releaseTime"
  98.                             type="datetime"
  99.                             value-format="timestamp"
  100.                             placeholder="选择释放时间"
  101.                             align="right"
  102.                             :picker-options="pickerOptions">
  103.                     </el-date-picker>
  104.                 </el-form-item>
  105.  
  106.             </el-form>
  107.             <div slot="footer" class="dialog-footer">
  108.                 <el-button @click="messageVisible = false">取 消</el-button>
  109.                 <el-button type="primary" @click=saveServer>确 定</el-button>
  110.             </div>
  111.         </el-dialog>
  112.     </div>
  113. </template>
  114.  
  115. <script>
  116.     import lyzLayout from '@/components/lyzLayout';
  117.     import manage from '../manage.component';
  118.     import {formatDateTime, responseText, debounce} from '../../../config/utils.js';
  119.  
  120.     export default {
  121.         name: "server",
  122.         data() {
  123.             return {
  124.                 queryType: '',
  125.                 queryKeyword: '',
  126.                 pagination: {
  127.                     pageIndex: 1,
  128.                     pageSize: 10,
  129.                     total: 0,
  130.                 },
  131.                 label: '服务器信息管理',
  132.                 messageForm: {},
  133.                 messageVisible: false,
  134.                 messageLabelWidth: '90px',
  135.                 messageRule: {
  136.                     serverName: [
  137.                         {required: true, message: '请输入服务器名称', trigger: 'blur'}
  138.                     ],
  139.                     serverStatus: [
  140.                         {required: true, message: '请选择服务器状态', trigger: 'blur'}
  141.                     ],
  142.                     projectName: [
  143.                         {required: true, message: '请输入项目名称', trigger: 'blur'}
  144.                     ],
  145.                     applyTime: [
  146.                         {required: true, message: '请输入申请时间', trigger: 'blur'}
  147.                     ],
  148.                     releaseTime: [
  149.                         {required: true, message: '请输入释放时间', trigger: 'blur'}
  150.                     ]
  151.                 },
  152.                 operate: '',
  153.                 multipleSelection: [],//多选的数据
  154.                 pickerOptions: {
  155.                     shortcuts: [{
  156.                         text: '今天',
  157.                         onClick(picker) {
  158.                             picker.$emit('pick', new Date());
  159.                         }
  160.                     }, {
  161.                         text: '一天后',
  162.                         onClick(picker) {
  163.                             const date = new Date();
  164.                             date.setTime(date.getTime() + 3600 * 1000 * 24);
  165.                             picker.$emit('pick', date);
  166.                         }
  167.                     }, {
  168.                         text: '一周后',
  169.                         onClick(picker) {
  170.                             const date = new Date();
  171.                             date.setTime(date.getTime() + 3600 * 1000 * 24 * 7);
  172.                             picker.$emit('pick', date);
  173.                         }
  174.                     }, {
  175.                         text: '一月后',
  176.                         onClick(picker) {
  177.                             const date = new Date();
  178.                             date.setTime(date.getTime() + 3600 * 1000 * 24 * 30);
  179.                             picker.$emit('pick', date);
  180.                         }
  181.                     }],
  182.                     disabledDate: function (now) {
  183.                         if (now < new Date())
  184.                             return true;
  185.                         return false
  186.                     }
  187.                 },
  188.                 tableData: [],
  189.                 loginLoading: false,
  190.                 tableHeader: [
  191.                     {
  192.                         prop: 'id',
  193.                         label: 'ID',
  194.                         'min-width': 40,
  195.                         align: 'center',
  196.                     },
  197.                     {
  198.                         prop: 'applyUserName',
  199.                         label: '使用人',
  200.                         'min-width': 80,
  201.                         align: 'center',
  202.                     },
  203.                     {
  204.                         prop: 'serverName',
  205.                         label: '服务器名称',
  206.                         'min-width': 120,
  207.                         align: 'center',
  208.                     },
  209.                     {
  210.                         prop: 'serverStatus',
  211.                         label: '服务器状态',
  212.                         'min-width': 100,
  213.                         align: 'center',
  214.                     },
  215.                     {
  216.                         prop: 'applyTime',
  217.                         label: '申请时间',
  218.                         'min-width': 120,
  219.                         align: 'center',
  220.                     },
  221.                     {
  222.                         prop: 'releaseTime',
  223.                         label: '释放时间',
  224.                         'min-width': 120,
  225.                         align: 'center',
  226.                     },
  227.                     {
  228.                         prop: 'projectName',
  229.                         label: '项目名称',
  230.                         'min-width': 120,
  231.                         align: 'center',
  232.                     },
  233.                 ]
  234.             };
  235.         },
  236.         components: {
  237.             lyzLayout,
  238.         },
  239.         mixins: [manage],
  240.         created() {
  241.             this.queryList();
  242.         },
  243.         mounted() {
  244.             this.$watch('queryKeyword', debounce(() => {
  245.                 this.pagination.pageIndex = 1;
  246.                 this.queryList();
  247.             }, 1000));
  248.         },
  249.         methods: {
  250.             queryTypeChange(val) {
  251.                 if (val !== '') {
  252.                     this.queryType = val;
  253.                     this.queryList();
  254.                 }
  255.             },
  256.             queryList() {
  257.                 this.loginLoading = true;
  258.                 let params = {
  259.                     queryType: this.queryType,
  260.                     queryKeyword: this.queryKeyword,
  261.                     pageNo: this.pagination.pageIndex,
  262.                     pageSize: this.pagination.pageSize
  263.                 };
  264.                 this.$http.get('/server/paging', {params: params}).then(({body}) => {
  265.                     if (body.success === true) {
  266.                         responseText(body.data.records).forEach((item) => {
  267.                             itemitem.serverStatus = item.serverStatus == 'free' ? '空闲' : '使用中';
  268.                             if (item.releaseTime != null) {
  269.                                 item.releaseTime = new Date(item.releaseTime).toLocaleString().replace(/:\d{1,2}$/, ' ');
  270.                             }
  271.                             if (item.applyTime != null) {
  272.                                 item.applyTime = new Date(item.applyTime).toLocaleString().replace(/:\d{1,2}$/, ' ');
  273.                             }
  274.                         })
  275.                         this.tableData = responseText(body.data.records);
  276.                         this.pagination.total = body.data.records ? body.data.total : 0;
  277.                     } else {
  278.                         this.$message.error(body.message);
  279.                     }
  280.                 }).finally(() => {
  281.                     this.loginLoading = false;
  282.                 })
  283.             },
  284.  
  285.             handleSelectionChange(val) {
  286.                 this.multipleSelection = val;
  287.             },
  288.             batchRemove() {
  289.                 let ids = '';
  290.                 this.multipleSelection.forEach(selectedItem => {
  291.                     // 删除请求
  292.                     ids += selectedItem.id + ',';
  293.                 });
  294.                 let params = {
  295.                     ids: ids
  296.                 };
  297.                 this.$http.post("/server/batchRemove", {}, {params: params}).then(({body}) => {
  298.                     if (body.success === true) {
  299.                         this.queryList();
  300.                         this.$message.success(body.message);
  301.                     } else {
  302.                         this.$message.error(body.message);
  303.                     }
  304.                 }).catch(() => {
  305.                     this.$message.error('删除失败');
  306.                 })
  307.             },
  308.             deleteServer(id) {
  309.                 let params = {
  310.                     id: id,
  311.                 };
  312.                 this.delete('/server/delete', params);
  313.             },
  314.             createServer(row) {
  315.                 console.log(row);
  316.                 this.messageVisible = true;
  317.                 this.operate = 'create';
  318.                 let _form = Object.assign({}, row);
  319.                 this.messageForm = _form;
  320.             },
  321.             applyServer(row) {
  322.                 console.log(row);
  323.                 this.messageVisible = true;
  324.                 this.operate = 'apply';
  325.                 let _form = Object.assign({}, row);
  326.                 this.messageForm = _form;
  327.             },
  328.             saveServer() {
  329.                 console.log('save');
  330.                 let params = {
  331.                     applyUserName: this.messageForm.applyUserName,
  332.                     serverName: this.messageForm.serverName,
  333.                     projectName: this.messageForm.projectName,
  334.                     applyTime: this.messageForm.applyTime,
  335.                     releaseTime: this.messageForm.releaseTime,
  336.                 };
  337.                 this.$refs['messageForm'].validate((valid) => {
  338.                     if (valid) {
  339.                         if (params.applyTime > params.releaseTime) {
  340.                             this.$message.error('释放时间必须大于申请时间!');
  341.                         } else {
  342.                             if (this.messageForm.id) {
  343.                                 params.serverStatus = this.messageForm.serverStatus == '空闲' ? 'free' : 'used';
  344.                                 params.id = this.messageForm.id;
  345.                                 this.save('/server/apply', params, 'messageVisible');
  346.                             } else {
  347.                                 params.serverStatus = this.messageForm.serverStatus;
  348.                                 this.save('/server/create', params, 'messageVisible');
  349.                             }
  350.                         }
  351.                     }
  352.                 })
  353.             },
  354.             releaseServer(id) {
  355.                 this.$http.post('/server/release?id=' + id, {}, {}).then(({body}) => {
  356.                     if (body.success === true) {
  357.                         this.$message.success(body.message);
  358.                         this.queryList();
  359.                     } else {
  360.                         this.$message.error(body.message);
  361.                     }
  362.                 }).catch(() => {
  363.                     this.$message.error('释放失败');
  364.                 })
  365.             }
  366.  
  367.         }
  368.     }
  369. </script>
  370.  
  371. <style scoped>
  372.     .main-login {
  373.         height: 100%;
  374.     }
  375.  
  376.     .danger-text {
  377.         color: #F56C6C;
  378.     }
  379. </style>

  其他代码就不贴了,见GitHub 该项目实现了前后端分离,后面的开发只需要在原有的基础上复制粘贴就行了   GitHub地址:https://github.com/saysky/springboot-vue-example/

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
avatar

发表评论

avatar 登录者:匿名
匿名评论,评论回复后会有邮件通知

  

已通过评论:7   待审核评论数:0
  1. avatar

    兄弟,我clone你的项目,打开前端还是vue的主页面

  2. avatar jin

    没有进入登录页面,登录页面进去也是空白,是什么原因呢

  3. avatar 蓦然,未见

    你好,请问为什么我加了菜单,但是显示不出来,左侧菜单是在哪里配置的

  4. avatar m_xy

    请求发一下github链接谢谢

  5. avatar Iohags

    能发送下git地址吗? 谢谢!

  6. avatar 郑州

    请大佬发送下git地址。

  7. avatar 楚狂人博客

    步骤很详细,谢谢