Bootstrap

Spring Boot + vue-element 开发个人博客项目实战教程(十九、日志中心页面接口对接)

⭐ 作者简介:码上言


⭐ 代表教程:Spring Boot + vue-element 开发个人博客项目实战教程


⭐专栏内容:零基础学Java个人博客系统

👦 学习讨论群:530826149

项目部署视频

https://www.bilibili.com/video/BV1sg4y1A7Kv/?vd_source=dc7bf298d3c608d281c16239b3f5167b

前言

接下来,我们主要还剩下前端页面的编写工作,对于vue不了解的同学到这基本上后端的东西说完了,下面的可以选学,学一学vue再来看,其实也没什么,希望大家一鼓作气学习完。

一、修改

1、修改错误信息

我们之前写的登录的代码,现在可能大家会发现登录进来还有错误信息的提示,我们先暂时把那个提示去掉。
打开views/login/index.vue文件,修改handleLogin()方法,去掉以下代码。

this.$notify.error({
    title: '登录失败',
    message: '请输入正确的用户名或密码!'
})

完整代码:

  handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('Login', this.loginForm).then(() => {
            this.loading = false
            this.$router.push({ path: this.redirect || '/' })
          }).catch(() => {
            this.loading = false
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }

如果你点击登录控制台出现302错误,请检查一下前端的代码中headers是否正确。

在这里插入图片描述

2、主页页面修改

我们修改完,然后运行项目打开页面,会看到如下页面。
在这里插入图片描述
我们可以看一下vue-element-admin框架的页面,首页为控制台,我们可以放一些大的标题、图表等信息,美化一下我们的后台网站。
打开src/router/index.js文件,然后我们配置一下路由,将以下的代码注释掉。

{
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: 'Dashboard',
    hidden: true,
    children: [{
      path: 'dashboard',
      component: () => import('@/views/dashboard/index')
    }]
  },

然后我们自己添加dashboard路由,其中icon的图表可以从https://www.iconfont.cn/进行下载,或者我是下载的vue-element-admin的src/icons/svg中找的。

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: 'Dashboard',
    children: [{
      path: 'dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: 'Dashboard', icon: 'dashboard' }
    }]
  },

然后我们再打开项目,就会看到我们一进来就是项目的控制台首页了。
在这里插入图片描述
这时我们会注意到左侧的导航栏都是英文,我们如何改成自己的导航的文字呢,也是在src/router/index.js这个文件中,我们会看到meta属性,然后修改title的名称即可。
在这里插入图片描述
在这里插入图片描述

二、导航栏改造

现在我们开始改造一下左侧的导航栏,我们将原来的导航栏都删除掉,只留下dashboard控制台。
如何删除呢?我们先把src/router/index.js里面的删除掉,然后再去views里面找到对应的文件删除掉,如果你不会,可以去https://gitee.com/xyhwh/personal_vue下载。
搭建一个新的页面导航要做以下操作。

1、添加路由

首先我们还是打开src/router/index.js文件,然后我们新添加一个导航的路由。其中icon的图标可以在https://www.iconfont.cn/下载,格式为svg。下载完放到src/icons/svg文件中。

 {
    path: '/operation',
    component: Layout,
    redirect: '/operation/list',
    name: 'Operation',
    meta: { title: '日志中心', icon: 'operationlog' },
    children: [
      {
        path: 'list',
        name: 'OperationList',
        component: () => import('@/views/operation/index'),
        meta: { title: '操作日志', icon: '' }
      },
      {
        path: 'loginlog',
        name: 'LoginLogList',
        component: () => import('@/views/operation/loginlog'),
        meta: { title: '登录日志', icon: '' }
      }
    ]
  },

这里我要说一下,路由和侧边栏是组织起一个后台应用的关键骨架。这个框架项目的侧边栏和路由是绑定在一起的,所以你只有在 @/router/index.js 下面配置对应的路由,侧边栏就能动态的生成了。大大减轻了手动重复编辑侧边栏的工作量。当然这样就需要在配置路由的时候遵循一些约定的规则。
例如:

{
  path: '/permission',
  component: Layout,
  redirect: '/permission/index', //重定向地址,在面包屑中点击会重定向去的地址
  hidden: true, // 不在侧边栏显示
  alwaysShow: true, //一直显示根路由
  meta: { roles: ['admin','editor'] }, //你可以在根路由设置权限,这样它下面所有的子路由都继承了这个权限
  children: [{
    path: 'index',
    component: ()=>import('permission/index'),
    name: 'permission',
    meta: {
      title: 'permission',
      icon: 'lock', //图标
      roles: ['admin','editor'], //或者你可以给每一个子路由设置自己的权限
      noCache: true // 不会被 <keep-alive> 缓存
    }
  }]
}

前端这个东西要多自己动手看效果,不行就修改,不要记忆,大脑是用来思考的,不是用来记忆的。

2、添加页面

rcs/views文件下,我们新建一个operation文件夹,然后再里面新建index.vueloginlog.vue两个文件,我们先创建一些模板。
index.vue文件:

<template>
  <div class="operationlog">
    <q>这是操作日志页面</q>
  </div>
</template>

<script>

export default {
  name: 'Operationlog',
  computed: {

  }
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>

</style>

loginlog.vue文件:

<template>
  <div class="operationlog">
    <q>这是登录日志页面</q>
  </div>
</template>

<script>

export default {
  name: 'Operationlog',
  computed: {

  }
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>

</style>

在这里插入图片描述
然后我们再运行项目,打开浏览器看一下。然后我们可以在右侧开发我们的功能了。
在这里插入图片描述
看下我们的后台系统,是不是看着也挺好看的,还是开始的目标,我们知道开发的流程和具体的操作即可,有些安全性的东西和页面美化就不太多的描述,作为毕设系统和初学的项目完全足够了。

三、操作日志页面开发

在开发的过程中,这个前端框架使用了eslint校验代码,虽然是限制我们规范化写代码,但是特别的烦,动不动就报红色,所以我们先不用这个了,我设置一下就不让它检验src目录下的文件了。打开项目的这个文件,然后加入/src保存即可。
在这里插入图片描述
现在开始写页面,我们先加一下操作日志的接口,也就是我们后端写的Controller的api接口,首先打开src/api,然后创建一个operation.js文件,然后写入我们的api接口,和原来的login登录一样,可以参考登录的api。

import request from '@/utils/request'

export function fetchLogList(query) {
	return request({
	url: '/log/operationLog/list',
	method: 'post',
	data: query
	})
}

1、接口请求

首先打开views/operation/index.vue文件进行编写页面。
我们先写接口,我们首先在script里引入接口

import { fetchLogList } from '@/api/operation'

然后写获取接口里面的数据,在methods方法里面写。还记得我们封装的返回类,返回的参数是什么嘛,不记得可以去看后端的JsonResult类,我们将数据都封装到了result里面了,我们前端只要去result里面去拿数据即可。数据的请求为JSON格式

 getList() {
      this.listLoading = true
      var body = this.listQuery;
      fetchLogList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
    },

由于我们这里使用的是JSON格式请求,我们的后端也是接收的JSON,所以我们在传递参数的时候,以现在后端的写法是接收不到参数的(你可以自己实验一下,后端的代码可以先不改动,看看参数是否可以接收到),我们现在先去后端改一下Controller接口的接收参数。(注意其余的接口只要是前端传递参数都要按照以下写)。

我们先写一个公共的类,把接口的接收的参数外边再包一层,和controller包同级下新建一个common包,然后里面添加一个PageRequestApi.java类,用于封装请求的参数,也就是参数外边再包一层大括号。

package com.blog.personalblog.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import javax.validation.Valid;

/**
 * @author: SuperMan
 * @create: 2022-04-26
 **/

@JsonIgnoreProperties(
        ignoreUnknown = true
)
public class PageRequestApi<T> {

    @Valid
    private T body = null;

    public PageRequestApi() {
    }

    public PageRequestApi(T body) {
        this.body = body;
    }

    public static <T> PageRequestApi<T> instance(T body) {
        return new PageRequestApi(body);
    }

    public T getBody() {
        return this.body;
    }

    public void setBody(final T body) {
        this.body = body;
    }

}

写完之后,然后打开OperationLogController.java类,然后将操作日志的接口进行修改,以下代码就是将PageRequest包起来,当做一个泛型。

public JsonResult<Object> OperationLogListPage(@RequestBody @Valid PageRequestApi<PageRequest> pageRequest) {
}

我们包起来之后,如何拿到前端传来的参数呢,别着急,我们只需要将PageRequestApi对象下的body获取到就可以拿到传来的参数。

    @ApiOperation(value = "操作日志列表")
    @PostMapping("/operationLog/list")
    public JsonResult<Object> OperationLogListPage(@RequestBody @Valid PageRequestApi<PageRequest> pageRequest) {
        List<OperationLog> operationLogPage = operationLogService.getOperationLogPage(pageRequest.getBody());
        PageInfo pageInfo = new PageInfo(operationLogPage);
        PageResult pageResult = PageUtil.getPageResult(pageRequest.getBody(), pageInfo);
        return JsonResult.success(pageResult);
    }

上边代码看到了吧,只要pageRequest.getBody()就可以获取到了,就比之前深了一层。好了,需要改的就那么多,下面还是进行页面编写。

2、页面编写

页面的编写没什么难度,主要是将我们拿到的数据进行遍历然后展示,我们基本上都是拿表格进行展示数据,这个都是element封装好的,我们直接拿来使用即可。

<template>
  <el-card class="main-card">
    
    <!-- 设置标题操作日志 -->
    <div class="title">操作日志</div>
    <div class="operation-container"></div>
    <el-table v-loading="listLoading" :data="list" fit highlight-current-row style="width: 90%; margin-top:30px;">
      <el-table-column align="center" label="ID" >
        <template slot-scope="scope">
          <span>{{ scope.row.id }}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作IP">
        <template slot-scope="scope">
          <span>{{ scope.row.operationIp}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作IP地址">
        <template slot-scope="scope">
          <span>{{ scope.row.operaLocation}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="方法名">
        <template slot-scope="scope">
          <span>{{ scope.row.methods}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="请求参数">
        <template slot-scope="scope">
          <span>{{ scope.row.args}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作人员">
        <template slot-scope="scope">
          <span>{{ scope.row.operationName}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="请求方式">
        <template slot-scope="scope">
          <el-tag :type="tagType(scope.row.operationType)">
            {{ scope.row.operationType }}
          </el-tag>
        </template>
      </el-table-column>

      <el-table-column align="center" label="返回结果">
        <template slot-scope="scope">
          <span>{{ scope.row.returnValue}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作日期">
        <template slot-scope="scope">
          <span>{{ scope.row.createTime}}</span>
        </template>
      </el-table-column>

    </el-table>

  </el-card>
</template>

这里我在请求方式上面优化了一下页面效果,需要我们在export default中添加个方法。也就是个switch判断,根据后端返回来的数据,来判断是加什么颜色。

  computed: {
    tagType() {
      return function(type) {
        switch (type) {
          case "SYSTEM":
            return "";
          case "LOGIN":
            return "success";
          case "INSERT":
            return "warning";
          case "SELECT":
            return "warning";
          case "UPDATE":
            return "warning";
          case "DELETE":
            return "danger";
        }
      };
    }
  }

在这里插入图片描述

3、分页

然后就是分页。分页作为数据列表的很重要的一部分,总不能把所有的数据全部放到页面上展示出来,显然不是我们想要的,我们上边修改的传参的请求主要是为了分页进行修改的。
我们在el-card标签中添加分页效果。
在这里插入图片描述

    <!-- 分页 -->
    <el-pagination
      class="pagination-container"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="this.listQuery.pageNum"
      :page-size="this.listQuery.pageSize"
      :total="count"
      :page-sizes="[10, 20, 30]"
      layout="total, sizes, prev, pager, next, jumper"
    />

添加返回的数据

data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10
      }
    }
  },

根据官方文档,我们还要写两个方法用来传递页码数。

 handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
 },
 handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
 }

基本上到这里页面全部写完了,也没啥好说的,多看几遍就可以了,做过html的都差不多还可以,我将这个全部的代码贴出来。看看自己还遗漏了哪些,自行补充。

<template>
  <el-card class="main-card">
    
    <!-- 设置标题操作日志 -->
    <div class="title">操作日志</div>
    <div class="operation-container"></div>
    <el-table v-loading="listLoading" :data="list" fit highlight-current-row style="width: 90%; margin-top:30px;">
      <el-table-column align="center" label="ID" >
        <template slot-scope="scope">
          <span>{{ scope.row.id }}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作IP">
        <template slot-scope="scope">
          <span>{{ scope.row.operationIp}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作IP地址">
        <template slot-scope="scope">
          <span>{{ scope.row.operaLocation}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="方法名">
        <template slot-scope="scope">
          <span>{{ scope.row.methods}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="请求参数">
        <template slot-scope="scope">
          <span>{{ scope.row.args}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作人员">
        <template slot-scope="scope">
          <span>{{ scope.row.operationName}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="请求方式">
        <template slot-scope="scope">
          <el-tag :type="tagType(scope.row.operationType)">
            {{ scope.row.operationType }}
          </el-tag>
        </template>
      </el-table-column>

      <el-table-column align="center" label="返回结果">
        <template slot-scope="scope">
          <span>{{ scope.row.returnValue}}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="操作日期">
        <template slot-scope="scope">
          <span>{{ scope.row.createTime}}</span>
        </template>
      </el-table-column>

    </el-table>

 <!-- 分页 -->
    <el-pagination
      class="pagination-container"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="this.listQuery.pageNum"
      :page-size="this.listQuery.pageSize"
      :total="count"
      :page-sizes="[10, 20, 30]"
      layout="total, sizes, prev, pager, next, jumper"
    />

  </el-card>
</template>

<script>
import { fetchLogList } from '@/api/operation'

export default {
  name: 'operationLogList',
  created() {
    this.getList()
  },
 
  data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10
      }
    }
  },

  methods: {

    getList() {
      this.listLoading = true
      var body = this.listQuery;
      fetchLogList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
    },

    handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
    },
    handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
    }

  },

  computed: {
    tagType() {
      return function(type) {
        switch (type) {
          case "SYSTEM":
            return "";
          case "LOGIN":
            return "success";
          case "INSERT":
            return "warning";
          case "SELECT":
            return "warning";
          case "UPDATE":
            return "warning";
          case "DELETE":
            return "danger";
        }
      };
    }
  }
  
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
 .pagination-container {
    float: right;
    margin-top: 1.25rem;
    margin-bottom: 1.25rem;
 }
 .title {
    position: absolute;
    left: 0;
    font-size: 16px;
    font-weight: 700;
    color: #202a34;
  }
</style>

好啦,到这里,我们基本上把操作日志的页面搞完了,可能页面有点丑,后期在优化吧,我们启动后端项目,别忘了启动redis,然后再将前端项目启动起来,登录进入,打开日志中心下的操作日志,看一下是否有数据展示,然后还有分页的效果。
在这里插入图片描述

4、中文化

我们看到页面的分页,页数,共多少条之类的都是英文,我们要将这些进行汉化,所以我们打开前端项目,找到src/main.js,然后注释掉以下这一句:

//import locale from 'element-ui/lib/locale/lang/en' // lang i18n

然后添加以下这一句即可。

import locale from 'element-ui/lib/locale/lang/zh-CN' 

修改完,保存看一下页面是不是出现了汉字,如果是的,说明已经汉化了。
在这里插入图片描述

四、总结

好啦,这一篇我们先写到这里吧,我们的操作日志的页面完成了,有想学习java或者技术交流的可以加入我的群:626974338,大家一起学习。还有一个下面的登录日志的页面,我就在这一篇不写了,大家自己先仿照着操作日志的写,下一篇我们再说。

上一篇:Spring Boot + vue-element 开发个人博客项目实战教程(十八、操作日志功能实现)
下一篇:Spring Boot + vue-element 开发个人博客项目实战教程(二十、登录日志、用户、分类管理页面开发)

;