从0到1做一个spring boot小项目

931 阅读6分钟

最终效果

这个项目能收获什么

  • 搭建一个spring boot项目

  • 与mybatis整合实现基本的CRUD

  • 前后端联动

  • 缓存基本的应用(redis)

  • 负载均衡的使用(nginx)

  • 对Linux和shell文件有个基本了解

  • 麻雀虽小,相信能收获颇多

这个项目干什么的

**计算Linux虚拟机指标。**包括内存使用率,cpu使用率,实时网速。获取hdfs的健康信息,包括配置容量,现有容量,DFS余量,非DFS使用量。并进行可视化展示

涉及技术

【必用】spring boot + Echarts + thymeleaf+【选用】Redis+Vue+Bootstrap

怎么去看

核心基本的看1-3部分,美化拓展的看4-5部分。每个模块都是可以拆分的,取你所需。只要其中有涉及到你想看的,那就值得一看。

源码地址

github.com/bigli97/com…

程序流程图

集群部署架构图

项目技术栈

负载均衡实现效果

目录

Java连接Linux

进行Linux指标展现

整合mybatis

获取hdfs数据

整合redis

整合nginx

第一部分【Java连接Linux】

本篇实现思路

利用Java去读取Linux中的文件,读出其中的信息,并将获得的字符串加以计算,通过控制层传给前端,利用前端进行展示。

本篇效果展示

实现步骤

  1. Java利用ssh连接Linux

  2. 数据准备

  3. 提供一个可视化模型

  4. 进行前后端联动,异步将数据传输到页面上

1、Java利用ssh连接Linux

2、数据准备

(1)CPU使用率获取

command:top -b -n 1 | head -3

第三行为cpu状态: 依次对应: us:user 用户空间占用cpu的百分比 sy:system 内核空间占用cpu的百分比 ni:niced 改变过优先级的进程占用cpu的百分比 id:空闲cpu百分比 wa:IO wait IO等待占用cpu的百分比 hi:Hardware IRQ 硬中断 占用cpu的百分比 si:software 软中断 占用cpu的百分比 st:被hypervisor偷去的时间

计算方式:100-cpu空闲百分比

(2)内存使用率获取

command:cat /proc/meminfo

红框代表含义:总内存,空闲内存

计算方式:(总内存-空闲内存)/总内存

(3)实时网速获取

command:cat /proc/net/dev(记录了不同网络接口(interface)上的各种包的记录)

最左边的表示接口的名字,Receive表示收包(下载量),Transmit表示发送包(上传量)

需要一个脚本文件(获取实时网速和实时上传率,我只做了第一个)

简单介绍以下脚本含义:sed将:替换为空格全局匹配, awk读第二个,grep 按什么匹配,echo代表输出什么,剩下的有点语言底子的都应该可以看懂

计算方式:根据前后一秒网络下载量所产生的差值作为数据

3、可视化模板

我们需要一个可视化前端模板,我找了一个官方案例,效果如下

echarts.apache.org/examples/zh…

4、进行前后端数据交互

前端部分

后端部分

本部分小结

对学习了spring boot或者Echarts想要一个练手项目的时候,那么这个项目就适合你。我为什么没有直接利用Java去实现本机(windows)一些性能指标的监控呢,比如下图。因为Java并不能直接获取本机的一些数据,应该是操作系统层面的权限问题吧,这些都是我踩过的坑,我也只获取到了jvm层面

win10指标监控

第二部分【整合mybatis】

步骤

  1. 增加pom依赖
  2. 修改application配置文件
  3. 增加mapper配置文件
  4. 创建entity(存放实体类),dao(进行数据操作),service(业务层)的包

1、增加pom依赖

2、修改application配置文件

被注释的那一行代表输出sql语句

3、增加mapper配置文件

在这里说一下为什么使用mapper而不适用注解的方式,比如说下面这段代码

注解方式只适合简单sql语句,而mapper.xml是通用的

@Select("select * from user ")

结构图

4、创建entity(存放实体类),dao(进行数据操作),service(业务层)的包

结构图

entity的类(这里用了lombok,没有的话还需要补充get、set方法)

dao下的类

service下的类

service.impl下的类

红框外的表示与redis整合,先不看

controller下的类

一个返回页面,一个异步访问

本部分结果截图

第三部分【获取hdfs数据】

思路

第一部分获取了Linux指标的一些信息,这篇文章是获取hdfs的数据,也是为了与大数据挂钩,实现思路也和第一篇类似,举一反三,还可以获取别的信息,比如一些znone节点健康信息之类的,重要不是获取什么,而是怎么获取

步骤

  1. Java利用ssh连接Linux

  2. 将命令得出的字符信息进行处理

  3. 提供一个可视化模板

  4. 进行前后端联动,异步将数据传输到页面上

重复的步骤我就不写了,可以看第一部分

实现方式

通过Linux的命令去返回字符串

获取hdfs健康信息的命令是:dfs dfsadmin -report

这里需要注意的是,此命令耗时3秒左右,所以做工具类方法的时候需要在一个方法中处理,不然一个用3秒,多了就吃不消了。还有这个命令本身并不提供,这里说的是即使你/etc/profile下面配了也不行。如下图

原因简单的说一下吧,不想了解的跳过

jsch方式通过SSH2连接的。而SSH直接执行远程命令和脚本,会使用Bash的non-interactive + non-login shell模式,它会创建一个shell,执行完脚本之后便退出,不再需要与用户交互。 non-interactive shell 执行它创建的脚本,默认情况下这个环境变量并没有设置。 no-login shell 他代表不会去执行/etc/profile文件,而会去用户的HOME目录检查.bashrc并加载。 那怎么解决?通过原因我们可以知道需要在当前用户下.bashrc文件末添加环境变量,也就是说如果当前你使用的是root用户,那么修改的就是/root/.bashrc这个文件。第二种方式就是运行的时候命令前加一句环境变量,如下

export PATH=$PATH:/opt/hadoop-2.7.1/bin:/opt/hadoop-2.7.1/sbin;hdfs dfsadmin -report

该命令的结果为下图,我想要的数据为红框中的信息

获取方式

字符串的subString方法,通过找到"("的下标+1,"GB"的下标-1来获取。这提一下+1,-1的意思,不+1的话你获取到的是"(",而不是后面的内容。indexOf这个就是获取下标的方法,但只能获取到第一个返回的下标,那我要获取第二行红框的数据怎么办?通过indexOf("\n")来获取一行的下标,我要找第二行将这个x2就可以了,第三行x3。具体代码实现如下

实现结果

第四部分【整合redis】

项目只实现了单机版整合

步骤

  1. 增加pom依赖
  2. 修改application.properties
  3. 编写PortUtil工具类
  4. 编写RedisConfig类
  5. 编写redis工具类
  6. 对业务层进行修改

1、增加pom依赖

2、修改application.properties

3、编写PortUtil工具类

作用:在运行项目的时候需要判断redis服务启动没有。启动走redis,没启动走数据库。

4、编写RedisConfig类

作用:当添加Redis依赖后,SpringBoot会自动帮我们在容器中生成一个RedisTemplate和一个StringRedisTemplate,但是,这个RedisTemplate的泛型是<Object,Object>,在代码中会不可避免的需要类型转换,这样不够安全,也过于麻烦,而且RedisTemplate没有设置序列化方式,所以,需要配置Redis。一句话:防止乱码。

5、编写redis工具类

作用:对redis进行操作,比如增删改一个对象,方法太多了,只写了常用的。

放个代表性的图,我比较喜欢将工具类写为静态的,这样方便调用。而需要的一个redis模板类,不能够直接进行@Resource注入,所以需要set注入。hasKey是其中的一个方法,其他方法也都大差不差的。

6、对业务层进行修改

一般redis加在业务层。

create方法

get方法

可以利用redis可视化工具去查看运行情况,也可以通过在application配置文件中加入

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

这句作用是打印程序所运行产生的sql语句

本部分结果截图

控制台

第五部分【整合nginx】

对于只学过理论的人来说,这或许是一个练手机会。

不用我这个项目,任意一个spring boot项目都是可以的,我的每一部分都是独立的。最后效果是通过访问一个网址或者ip达到访问不同端口的目的。负载可以负载端口也可以负载IP,在于你怎么配置。

实现效果图

首先就是打包

将你的项目打成jar包

下面是关于idea如何打包的,会打包的自行跳过

打包步骤

  1. pom文件中添加打包插件

  2. 增加所打的包的方式,jar就写jar,war就写war

  3. 利用maven自带插件打包(建议先clean)

1、pom文件中添加打包插件

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

不加这个插件的的后果,都是亲身试验过的坑啊

2、增加所打的包的方式,jar就写jar,war就写war

<packaging>jar</packaging>

3、利用maven自带插件打包(建议先clean)

4、jar包所在位置

最后提一下,我用过idea自带的打包工具就是那个build,然后运行的时候报的信息一大堆看不懂的,当然项目最后启动不了,可能是我方式不对,但我还是极力的不推荐,一是麻烦,二是需要注意的地方太多,用我上面这种就可以了。

这个是idea的自带打包方式

这个是自带打包方式出现的报错信息

打包跳过的来这里,步骤如下

  1. 设置一个方法返回各自的端口
  2. 定义不同的端口
  3. 将打好的包用名字进行区分
  4. 修改nginx.conf
  5. 依次启动jar包
  6. 访问路径验证效果
  7. 启动nginx

1、为了观察效果,可以控制器中设置一个方法返回各自的端口(就是我演示中的效果)

2、将项目打包,分别定义不同的端口8080,8081,8082

3、将打好的包用名字进行区分,放入Linux中

4、进入nginx的conf目录下修改nginx.conf

5、启动nginx.

./nginx

6、依次启动jar包(也可以使用一键启动脚本,后面说)

nohup java -jar xxx(nohup表示后台运行)

7、访问路径验证效果,一直刷新会观察到端口的变化

http://192.168.11.130/port

一键启动tomcat脚本(偷个懒,每次太麻烦)

#!/bin/bash
#@author dali
#统一启动3个jar包文件
#这里定义你的jar包名称
APP_NAME1=computer8080.jar
APP_NAME2=computer8081.jar
APP_NAME3=computer8082.jar

#使用说明,用来提示输入参数
usage() {
    echo "Usage: sh 执行脚本.sh [start|stop|restart|status]"
    exit 1
}

#检查8080是否在运行
is_exist1(){
  pid1=`ps -ef|grep $APP_NAME1|grep -v grep|awk '{print $2}' `
  #如果不存在返回1,存在返回0
  if [ -z "${pid1}" ]; then
   return 1
  else
    return 0
  fi
}

#检查8081是否在运行
is_exist2(){
  pid2=`ps -ef|grep $APP_NAME2|grep -v grep|awk '{print $2}' `
  #如果不存在返回1,存在返回0
  if [ -z "${pid2}" ]; then
   return 1
  else
    return 0
  fi
}

#检查8082是否在运行
is_exist3(){
  pid3=`ps -ef|grep $APP_NAME3|grep -v grep|awk '{print $2}' `
  #如果不存在返回1,存在返回0
  if [ -z "${pid3}" ]; then
   return 1
  else
    return 0
  fi
}

#启动方法
start(){
  is_exist1
  if [ $? -eq "0" ]; then
    echo "${APP_NAME1} is already running. pid=${pid1} ."
  else
    nohup java -jar $APP_NAME1 > /dev/null 2>&1 &
  fi

  is_exist2
  if [ $? -eq "0" ]; then
    echo "${APP_NAME2} is already running. pid=${pid2} ."
  else
    nohup java -jar $APP_NAME2 > /dev/null 2>&1 &
  fi

  is_exist3
  if [ $? -eq "0" ]; then
    echo "${APP_NAME3} is already running. pid=${pid3} ."
  else
    nohup java -jar $APP_NAME3 > /dev/null 2>&1 &
  fi
}

#停止方法
stop(){
  is_exist1
  if [ $? -eq "0" ]; then
    kill -9 $pid1
  else
    echo "${APP_NAME1} is not running"
  fi

  is_exist2
  if [ $? -eq "0" ]; then
    kill -9 $pid2
  else
    echo "${APP_NAME2} is not running"
  fi

  is_exist3
  if [ $? -eq "0" ]; then
    kill -9 $pid3
  else
    echo "${APP_NAME3} is not running"
  fi
}

#输出运行状态
status(){
  is_exist1
  if [ $? -eq "0" ]; then
    echo "${APP_NAME1} is running. Pid is ${pid1}"
  else
    echo "${APP_NAME1} is NOT running."
  fi

  is_exist2
  if [ $? -eq "0" ]; then
    echo "${APP_NAME2} is running. Pid is ${pid2}"
  else
    echo "${APP_NAME2} is NOT running."
  fi

  is_exist3
  if [ $? -eq "0" ]; then
    echo "${APP_NAME3} is running. Pid is ${pid3}"
  else
    echo "${APP_NAME3} is NOT running."
  fi
}

#重启
restart(){
  stop
  start
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
  "start")
    start
    ;;
  "stop")
    stop
    ;;
  "status")
    status
    ;;
  "restart")
    restart
    ;;
  *)
    usage
    ;;
esac