Spring MVC 自定义静态资源下载

在 Spring MVC 中上传文件后把文件保存在本地,但是数据库保存了一份路径,所有需要实现下载文件,网上的教程一般都是自己写一个Controller 去下载,但是我这里直接使用Spring MVC的 ResourceHttpRequestHandler 实现动态下载静态资源,只需一点点代码然后加一段配置就可以实现下载附件功能。

第一步

自定义一个Handler,并重写 ResourceHttpRequestHandlerprocessPath 方法。

@Slf4j
public class CustomResourceHttpRequestHandler extends ResourceHttpRequestHandler {
    private final UploadRepository uploadRepository;
    public CustomResourceHttpRequestHandler(UploadRepository uploadRepository) {
        this.uploadRepository = uploadRepository;
    }
    // 重写该方法实现动态获取文件路径,而不是直接获取本地文件的路径
    @Override
    protected String processPath(String path) {
        Optional<Upload> uploadOption = uploadRepository.findById(path);
        return uploadOption.map(Upload::getPath)
                .orElseGet(() -> {
                    log.warn("文件获取path不存在。path={}", path);
                    return  null;
                });
    }
}

第二部配置

在 Spring Boot 中添加一下配置,注意LocationValues 的路径,必须以 / 结尾,访问本地文件必须有 file: ,不然会访问不到,报404

优雅开启和关闭Spring Cloud项目

第一种方式,使用脚本(不推荐)

使用命令行开启和关闭,直接 kill 掉Spring boot 进程,这样会导致Spring Cloud 项目不会去 注册中心把自己销毁掉,明明项目已经关闭,但是注册中心还是显示在线,而且这样还会有一个弊端,如果需 要监听Spring Boot 项目的生命周期钩子,比如项目启动和关闭,也会监听不到。 /home/dev/app.sh

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

#检查程序是否在运行
is_exist(){
  count=`ps -ef |grep java|grep $APP_NAME|grep -v grep|wc -l`
  #如果不存在返回1,存在返回0     
  if [ $count == 0 ]; then
   return 1
  else
    return 0
  fi
}

#启动方法
start(){
  is_exist
  if [ $? -eq "0" ]; then
    echo "${APP_NAME} is already running. pid=${pid} ."
  else
    SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
    JAR_PATH="$SHELL_FOLDER/../applications/$APP_NAME.jar"
    CONF_PATH="$SHELL_FOLDER/../conf/logback-spring.xml"
    nohup java -jar $JAR_PATH --logging.config=$CONF_PATH --spring.profiles.active=test > /dev/null 2>&1 &
   # java -jar $JAR_PATH --logging.config=$CONF_PATH
  fi
}

#停止方法
stop(){
  is_exist
  if [ $? -eq "0" ]; then
    pid=`ps -ef |grep java|grep $APP_NAME|grep -v grep|awk '{print $2}'`
    echo "Stop $APP_NAME, pid $pid"    
    kill -9 $pid
  else
    echo "${APP_NAME} is not running"
  fi  
}

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

#重启
restart(){
  stop
  start
}

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

使用

* 开启
```bash
./app start myapp.jar
  • 关闭
./app stop myapp.jar
  • 重启
./app.sh restart myapp.jar 

第二种方式,打包可执行jar(推荐)

打包可执行的jar可以支持 systemctl 启动,也可以支持脚本启动,并且执行关闭后会冲注册中心销毁掉服务,并且会在启动和关闭会调用Spring Boot 的生命周期事件。

expect 的用法

!/usr/bin/expect

    告诉操作系统脚本里的代码使用那一个shell来执行。

注意:这段代码必须在第一行。

set timeout

设置超时时间,计时单位是:秒 ,timeout -1 为永不超时。

spawn

spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 which spawn 之类的命令去找spawn命令。

它主要的功能是给ssh运行进程加个壳,用来传递交互指令。

expect “str”

这个命令的意思是判断上次输出结果里是否包含“str”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是 set timeout

send ""

这里就是执行交互动作,

命令字符串结尾别忘记加上“\r”,如果出现异常等待的状态可以核查一下。

interact

执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行

$argv 参数数组

expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个….参数

示例

expect 调用 ssh 密码登陆

#!/usr/bin/expect

set timeout 5
set password "1234"
spawn ssh [email protected]
expect {
	"yes/no" { send "yes\r"; exp_continue }
	"Password:" { send "$password\r" }
	}
interact

Linux 各个目录的说明

根文件系统

/bin

    这一目录中存放了供所有用户使用的完成基本维护任务的命令。其中bin是binary的缩写,表示二进制文件,通常为可执行文件。     一些常用的系统命令,如cpls等保存在该目录中。

/boot

    这里存放的是启动Linux时使用的一些核心文件。如操作系统内核、引导程序Grub等。

/dev

    在此目录中包含所有的系统设备文件。从此目录可以访问各种系统设备。如CD-ROM,磁盘驱动器,调制解调器和内存等。     在该目录中还包含有各种实用功能,如用于创建设备文件的MAKEDEV。

/etc

    该目录中包含系统和应用软件的配置文件。

/etc/passwd

    该目录中包含了系统中的用户描述信息,每行记录一个用户的信息。

/home

    存储普通用户的个人文件。每个用户的主目录均在/home下以自己的用户名命名。

/lib

    这个目录里存放着系统最基本的共享链接库和内核模块。共享链接库在功能上类似于Windows里的.dll文件。

/lib64

    64位系统有这个文件夹,64位程序的库。

/lost+found

    这并不是Linux目录结构的组成部分,而是ext3文件系统用于保存丢失文件的地方。     不恰当的关机操作和磁盘错误均会导致文件丢失,这意味着这些被标注为“在使用”,但却并未列于磁盘上的数据结构上。     正常情况下,引导进程会运行fsck程序,该程序能发现这些文件。除了“/”分区上的这个目录外,在每个分区上均有一个lost+found目录。

/media

    可移动设备的挂载点,当前的操作系统通常会把U盘等设备自动挂载到该文件夹下。

/mnt

    临时用于挂载文件系统的地方。一般情况下这个目录是空的,而在我们将要挂载分区时在这个目录下建立目录,再将我们将要访问的设备挂载在这个目录上,这样我们就可访问文件了。(注意在GNOME中,只有挂载到/media的文件夹才会显示在“计算机”中,挂载到/mnt不会做为特殊设备显示,详见自动挂载分区)

/opt

    多数第三方软件默认安装到此位置,如Adobe Reader、google-earth等。并不是每个系统都会创建这个目录。

/proc

    它是存在于内存中的虚拟文件系统。里面保存了内核和进程的状态信息。多为文本文件,可以直接查看。如/proc/cpuinfo保存了有关CPU的信息。

/root

    这是根用户的主目录。与保留给个人用户的/home下的目录很相似,该目录中还包含仅与根用户有关的条目。

/sbin

    供超级用户使用的可执行文件,里面多是系统管理命令,如fsck, reboot, shutdown, ifconfig等。

/tmp

    该目录用以保存临时文件。该目录具有Sticky特殊权限,所有用户都可以在这个目录中创建、编辑文件。但只有文件拥有者才能删除文件。为了加快临时文件的访问速度,有的实现把/tmp放在内存中。

/usr

    静态的用户级应用程序等,见下。

/var

    动态的程序数据等,见下文。

/usr目录结构


    /usr通常是一个庞大的文件夹,其下的目录结构与根目录相似,但根目录中的文件多是系统级的文件,而/usr中是用户级的文件,一般与具体的系统无关。     应注意,程序的配置文件、动态的数据文件等都不会存放到/usr,所以除了安装、卸载软件外,一般无需修改/usr中的内容。说在系统正常运行时,/usr甚至可以被只读挂载。由于这一特性,/usr常被划分在单独的分区,甚至有时多台计算机可以共享一个/usr。

提示:     usr最早是user的缩写,/usr的作用与现在的/home相同。而目前其通常被认为是 User System Resources 的缩写,其中通常是用户级的软件等,与存放系统级文件的根目录形成对比。

/usr/bin

    多数日常应用程序存放的位置。如果/usr被放在单独的分区中,Linux的单用户模式不能访问/usr/bin,所以对系统至关重要的程序不应放在此文件夹中。

/usr/include

    存放C/C++头文件的目录

/usr/lib

    系统的库文件

/usr/local

    新装的系统中这个文件夹是空的,可以用于存放个人安装的软件。安装了本地软件的/usr/local里的目录结构与/usr相似

/usr/sbin

    在单用户模式中不用的系统管理程序,如apache2等。

/usr/share

    与架构无关的数据。多数软件安装在此。

/usr/X11R6

    该目录用于保存运行X-Window所需的所有文件。该目录中还包含用于运行GUI要的配置文件和二进制文件。 ###/usr/src     源代码

Ubuntu16.04.5 安装 Docker

使用 apt-get 安装

卸载掉旧版本

命令:

sudo apt remove docker docker-engine docker.io

安装

  1. 更新软件包
sudo apt update
  1. 添加使用 HTTPS 传输的软件包以及 CA 证书
sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
  1. 添加Docker的官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

验证秘钥

mysql允许用户远程连接的方式

mysql允许用户远程连接的方式。

  • 第一步(修改配置文件) vim /etc/mysql/my.cnf 找到 bind-address = 127.0.0.1

    注释掉这行,如:#bind-address = 127.0.0.1

    或者改为: bind-address = 0.0.0.0

    允许任意IP访问;

    或者自己指定一个IP地址。

    重启 MySQL:sudo /etc/init.d/mysql restart

  • 第二步(授权用户能进行远程连接)

    grant all privileges on *.* to root@"%" identified by "password" with grant option; flush privileges;

    第一行命令解释如下,. :第一个代表数据库名;第二个代表表名。这里的意思是所有数据库里的所有表都授权给用户。root:授予root账号。 “%”:表示授权的用户IP可以指定,这里代表任意的IP地址都能访问MySQL数据库。“password”:分配账号对应的密码,这里密码自己替换成 你的mysql root帐号密码。

    第二行命令是刷新权限信息,也即是让我们所作的设置马上生效。