Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)八(文件的上传FastDFS和校验)(Nginx的请求前缀配置,在发布项目的时候要注意)

一、品牌新增功能(图片上传)

1、新建一个微服务:文件的上传的微服务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、添加依赖

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-upload</artifactId>

    <dependencies>
        <!--引入注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--引入web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入Test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

    </dependencies>


</project>

3、编写配置文件

在这里插入图片描述
在这里插入图片描述

4、编写启动类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5、分析文件上传

现在的文件上传与Servlet的文件上传不同,现在的文件上传是单独的一个微服务,测试演示
当选择文件后就会触发文件上传
在这里插入图片描述

  • 完善一下提交的路径以及其他的参数
    在这里插入图片描述
<v-flex>
   <v-upload v-model="brand.image" url="/upload/image" :multiple="false" :pic-width="250" :pic-height="90"
    />
</v-flex>

在这里插入图片描述
在这里插入图片描述

  • 返回结果,上传文件后表单需要得到对应的的文件的路径,即表单提交的的时候需要知道对应文件的路径

6、编写上传功能(校验文件)

(1)controller

编写controller需要知道4个内容:

  • 请求方式:上传肯定是POST
  • 请求路径:/upload/image
  • 请求参数:文件,参教名是file,SpringMVvc会封装为一个接口:MultipleFile
  • 返回结果:上传成功后得到的文件的url路径
    代码如下:
    在这里插入图片描述
    在这里插入图片描述
package com.leyou.upload.web;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("upload")
public class UploadController {

    /*
    上传图片功能
     */
    @PostMapping("image")       //当做文件上传的时候SpringMVC会自动将上传的文件封装到MultipartFile当中
    public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){

    }

}

(2)service

在这里插入图片描述
在这里插入图片描述

package com.leyou.upload.service;

import org.springframework.stereotype.Service;

@Service
public class UploadService {


}

(3)在控制层当中注入Service

在这里插入图片描述

package com.leyou.upload.web;

import com.leyou.upload.service.UploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("upload")
public class UploadController {

    @Autowired
    private UploadService uploadService;
    /*
    上传图片功能
     */
    @PostMapping("image")       //当做文件上传的时候SpringMVC会自动将上传的文件封装到MultipartFile当中
    public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){
        String url = uploadService.uploadImage(file);
        return ResponseEntity.ok(url);
    }
}
(4)完善业务层

在这里插入图片描述
在这里插入图片描述

package com.leyou.upload.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;

@Service
public class UploadService {

    public String uploadImage(MultipartFile file) {

        //准备目标路径

        File dest = new File("");
        //保存文件到本地

        //返回图片路径

        return null;

    }
}

(5)创建一个文件夹用于上传文件

在当工程的目录傍边下创建对应的文件路径
在这里插入图片描述

(6)完善上传文件的业务层
  • 添加common的依赖
    在这里插入图片描述
     <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

  • 编写文件上传失败对应的枚举
    在这里插入图片描述
    UPLOAD_FILE_ERROR(500,"文件上传失败"),
  • 继续完善业务层,设置文件上传失败的时候抛出对应的异常信息
    在这里插入图片描述
package com.leyou.upload.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class UploadService {

    // Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
    private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");

    public String uploadImage(MultipartFile file) {


        try {
            //校验文件类型
            String contentType = file.getContentType();
            if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中

            }
            //准备目标路径
            
            File dest = new File("D:/IDEAWORK/upload/"+file.getOriginalFilename());
            //保存文件到本地
            file.transferTo(dest);
            return "http://image.leyou.com/" + file.getOriginalFilename();
        } catch (IOException e) {
           //如果上传失败,记录日志信息
            log.error("上传文件失败",e);
            //返回错误结果
            throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
        }
        //返回图片路径
    }
}

  • 设置抛出的异常信息
    在这里插入图片描述
 INVALID_FILE_TYPE(400,"无效的文件类型"),
  • 继续完善业务层,设置抛出异常信息
    在这里插入图片描述
			//校验文件类型
            String contentType = file.getContentType();
            if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }

(7)校验文件内容(继续完善业务层内容)

在这里插入图片描述

			 //校验文件的内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if(image == null){
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }

全部代码

package com.leyou.upload.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class UploadService {

    // Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
    private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");

    public String uploadImage(MultipartFile file) {


        try {
            //校验文件类型
            String contentType = file.getContentType();
            if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //校验文件的内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if(image == null){
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //准备目标路径
           
            File dest = new File("D:/IDEAWORK/upload/"+file.getOriginalFilename());
            //保存文件到本地
            file.transferTo(dest);
            return "http://image.leyou.com/" + file.getOriginalFilename();
        } catch (IOException e) {
           //如果上传失败,记录日志信息
            log.error("上传文件失败",e);
            //返回错误结果
            throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
        }
        //返回图片路径
    }
}

7、运行测试

重新启动项目
在这里插入图片描述
启动文件上传的微服务项目
在这里插入图片描述

打开测试工具
http://localhost:8084/upload/image
在这里插入图片描述
在这里插入图片描述
请求成功并返回对应的图片路径
在这里插入图片描述
并在对应的文件夹下找到对应上传的图片
在这里插入图片描述
上传其他错误文件
在这里插入图片描述
发送
在这里插入图片描述

8、完善网页文件上传功能(忽略路由前缀)

当点击图片的时候报404
在这里插入图片描述

(1)在网关当中配置文件上传微服务的路由(文件上传当中配置的前缀是)

在这里插入图片描述

    upload-service :
       path: /upload/**  #设置对应微服务映射的路径的前缀upload不去除
       serviceId : upload-service  #upload-service对应微服务的名称代替了ip地址  10010地址映射到8084
       strip-prefix: false
      #由于网关捕获到upload之后页面的url只剩下/image,
      #但是controller里面是/upload/image,所以不能去除upload的前缀
(2)重新启动运行测试项目

在这里插入图片描述
再次测试发送请求成功
在这里插入图片描述

9、绕过网关缓存

默认情况下,所有的请求经过Zuul网关的代理,默认会通过SpringMVC 预先对请求进行处理,缀存。

普通请求井不会有什么影响,但是对于文件上传,.就会造成遗成不必要的网络负担。

在高井发时,可能导致网络阻塞,Zuul网关不可用这拌我们的整个系统就瘫换了

所以,我们上传文件的请求需要绕过请求的缓存,直接通过路由到达目标微服务:

Zuul is implemented as a Servlet. For the general cases, 

Zuul is embedded into the Spring Dispatch mechanism.

This lets Spring MVC be in control of the routing. 

In this case, Zuul buffers requests. 

If there is a need to go throughZuul without buffering requests 
(for example, for large file uploads), 

the Servlet is also installed outside of the

Spring Dispatcher. By default, the servlet has an address of /zuul . 

This path can be changed with the zuul.servletpath property.

Zuul实现为一个Servlet。对于一般情况,Zuul被嵌入到Spring调度机制中,这使得Spring MVC能够控制路由。在这种情况下,Zuul缓冲请求。如果需要在不缓冲请求的情况下通过ZUUL(例如,对于大型文件上载),Servlet也会安装在

Spring 调度员。默认情况下,servlet的地址为/zuul。
可以使用zuul.servletpath属性更改此路径。

也就是说在请求路径的前面加上/zuul,就会跳过Zuul的缓存,不是不去网关,只是跳过了请求缓存

(1)现在修改页面的访问路径(需要在api前面加Zuul)修改Nginx的配置文件

但是不可以直接改变请求访问页面的路径

我们需要修改到以/zuul为前缀,

可以通过nginx的rewrite指令实现这一需求:

Nginx提供了rewrite指令,用于对地址进行重写,语法规则:

rewrite“用来匹配路径的正则”重写后的路径[指令];

通过cd linux指令找到对应nginx的配置文件当中conf当中的nginx.conf文件

vim 命令打开文件添加以下内容

在这里插入图片描述

		location /api/upload {
			rewrite "^/(.*)$" /zuul/$1;
		}

重写reload nginx
在这里插入图片描述

nginx -s reload
(2)再次运行访问

在这里插入图片描述
看不出区别,但是在文件上传的时候,效率会提升
在这里插入图片描述

10、FastDFS(完善文件上传的保存功能以及显示图片)

(1)什么是分布式文件系统

分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。
通俗来讲;

  • 传统文件系统管理的文件就存储在本机。
  • 分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文
    件,都需要通过管理中心来访问
(2)什么是FastDFS

FastDFS是由淘宝的余庆先生所开发的一个轻量级、高性能的开源分布式文件系统。用纯c语言开发,功能丰富:

  • 文件存储
  • 文件同步
  • 文件访问(上传、下载)
  • 存取负载均衡
  • 在线扩容

适合有大容量存储需求的应用或系统。同类的分布式文件系统有谷歌的GFS、HDFS (Hadoop)、TFS(淘宝〉等。

(3)FastDFS的结构

在这里插入图片描述
FastDFS两个主要的角色:Tracker Server和Storage Server .

  • Tracker Server:跟踪服务器,主要负责调度storage节点与client通信,在访问上起负载均衡的作用,和记录storage节点的运行状态,是连接client和storage节点的枢纽。

  • Storage Server:存储服务器,保存文件和文件的meta data (元数据),每个storage server会启动一个单独的线程主动向Tracker cluster中每个tracker server报告其状态信息,包括磁盘使用情况,文件同步情况及文件上传下载次数统计等信息

  • Group:文件组,多台Storage Server的集群。上传一个文件到同组内的一台机器上后,FastDFs会将该文件即时同步到同组内的其它所有机器上,起到备份的作用。不同组的服务器,保存的数据不同,而且相互独立,不进行通信。

  • Tracker Cluster:跟踪服务器的集群,有一组Tracker Server(跟踪服务器)组成。

  • Storage Cluster :存储集群,有多个Group组成。

(4)上传和下载的流程

在这里插入图片描述
最小化部署图
在这里插入图片描述
文件上传原理:
1.Client通过Tracker server查找可用的Storage server。
2.Tracker server向client返回一台可用的Storage server的IP地址和端口号。
3. Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并进行文件上传。
4.上传完成,Storage server返回Client一个文件ID,文件上传结束。

文件下载原理:

1.Client通过Tracker server查找要下载文件所在的的Storage server。
2. Tracker server向Client返回包含指定文件的某个Storage server的IP地址和端口号。
3. Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并指定要下载文件。4.下载文件成功。

(5)安装和使用(Centos下安装FastDFS)
1)上传

将以下内容上传到linux下的/home/leyou/fdfs目录:
https://download.csdn.net/download/qq_44757034/20901739

在这里插入图片描述
在这里插入图片描述

2)安装依赖

FastDFS运行需要一些依赖,在课前资料提供的虚拟中已经安装好了这些依赖,如果大家想要从头学习,可以按下面方式安装:

a、安装GCC依赖

GCC用来对C语言代码进行编译运行,使用yum命令安装:
GCC用来对C语言代码进行编译运行,使用yum命令安装:

sudo yum -y install gcc
b、 安装unzip工具

unzip工具可以帮我们对压缩包进行解压

sudo yum install -y unzip zip

在这里插入图片描述

c、 安装libevent
sudo yum -y install libevent

在这里插入图片描述

d、 安装Nginx所需依赖
sudo yum -y install pcre pcre-devel zlib zlib-devel openssl openssl-devel

在这里插入图片描述

d、 安装libfastcommon-master

这个没有yum包,只能通过编译安装:

  • 解压刚刚上传的libfastcommon-master.zip

      unzip  libfastcommon-master.zip
    

在这里插入图片描述

  • 进入解压完成的目录:

    cd libfastcommon-master
    
  • 编译并且安装:

    sudo ./make.sh 
    sudo ./make.sh install
    

在这里插入图片描述
在这里插入图片描述

到这里为止,所有依赖都已经安装完毕,接下来我们安装FastDFS:

3)安装FastDFS
a、 编译安装

这里我们也采用编译安装,步骤与刚才的编译安装方式一样:
发回上一级别目录

cd ../
  • 解压

    tar -xvf FastDFS_v5.08.tar.gz
    

在这里插入图片描述

  • 进入目录

    cd FastDFS
    
  • 编译并安装

    sudo ./make.sh 
    sudo ./make.sh install
    

在这里插入图片描述
在这里插入图片描述

  • 校验安装结果

1)安装完成,我们应该能在/etc/init.d/目录,通过命令ll /etc/init.d/ | grep fdfs看到FastDFS提供的启动脚本:
在这里插入图片描述
在这里插入图片描述
2)我们可以在 /etc/fdfs目录,通过命令查看到以下配置文件模板:
在这里插入图片描述
其中:

  • tarcker.conf.sample 是tracker的配置文件模板
  • storage.conf.sample 是storage的配置文件模板
  • client.conf.sample 是客户端的配置文件模板
b、 启动tracker

FastDFS的tracker和storage在刚刚的安装过程中,都已经被安装了,因此我们安装这两种角色的方式是一样的。不同的是,两种需要不同的配置文件。

我们要启动tracker,就修改刚刚看到的tarcker.conf,并且启动fdfs_trackerd脚本即可。

  • 编辑tracker配置

首先我们将模板文件进行赋值和重命名:

sudo cp tracker.conf.sample tracker.conf
sudo vim tracker.conf

打开tracker.conf,修改base_path配置:

base_path=/leyou/fdfs/tracker # tracker的数据和日志存放目录

在这里插入图片描述

  • 创建目录

刚刚配置的目录可能不存在,我们创建出来

sudo mkdir -p /leyou/fdfs/tracker

在这里插入图片描述

  • 启动tracker

    我们可以使用 sh /etc/init.d/fdfs_trackerd 启动,不过安装过程中,fdfs已经被设置为系统服务,我们可以采用熟悉的服务启动方式:

sudo service fdfs_trackerd start # 启动fdfs_trackerd服务,停止用stop

在这里插入图片描述

另外,我们可以通过以下命令,设置tracker开机启动:

sudo chkconfig fdfs_trackerd on

在这里插入图片描述

c、启动storage

我们要启动tracker,就修改刚刚看到的tarcker.conf,并且启动fdfs_trackerd脚本即可。

  • 编辑storage配置

首先我们将模板文件进行赋值和重命名:

sudo cp storage.conf.sample storage.conf
sudo vim storage.conf

打开storage.conf,修改base_path配置:

base_path=/leyou/fdfs/storage # storage的数据和日志存放目录
store_path0=/leyou/fdfs/storage # storage的上传文件存放路径
tracker_server=192.168.56.101:22122 # tracker的地址
  • 创建目录

刚刚配置的目录可能不存在,我们创建出来

sudo mkdir -p /leyou/fdfs/storage
  • 启动storage

    我们可以使用 sh /etc/init.d/fdfs_storaged 启动,同样我们可以用服务启动方式:

sudo service fdfs_storaged start  # 启动fdfs_storaged服务,停止用stop

另外,我们可以通过以下命令,设置tracker开机启动:

sudo chkconfig fdfs_storaged on

最后,通过ps -ef | grep fdfs 查看进程:

在这里插入图片描述
测试上传
将一张图片上传到/var/333.png

/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /var/333.png 

得到返回数据:group1/M00/00/00/rBEACmEPpcyAcBNZAAFkkXlaVjk629.png

4)安装Nginx及FastDFS模块
a、 FastDFS的Nginx模块

切换到

cd /home/leyou/fdfs
  • 解压

    tar -xvf fastdfs-nginx-module_v1.16.tar.gz
    

    在这里插入图片描述

  • 配置config文件

    # 进入配置目录
    cd /home/leyou/fdfs/fastdfs-nginx-module/src/
    # 修改配置
    vim config
    # 执行下面命令(将配置中的/usr/local改为/usr):
    :%s+/usr/local/+/usr/+g
    

    保存退出
    在这里插入图片描述

  • 配置mod_fastdfs.conf

    # 将src目录下的mod_fastdfs.conf复制到 /etc/fdfs目录:
    sudo cp mod_fastdfs.conf /etc/fdfs/
    # 编辑该文件
    sudo vim /etc/fdfs/mod_fastdfs.conf
    
  • 修改一下配置:

    connect_timeout=10                  		# 客户端访问文件连接超时时长(单位:秒)
    tracker_server=192.168.56.101:22122  	# tracker服务IP和端口
    url_have_group_name=true            		# 访问链接前缀加上组名
    store_path0=/leyou/fdfs/storage        		# 文件存储路径
    
  • 复制 FastDFS的部分配置文件到/etc/fdfs目录

  cd /home/leyou/fdfs/FastDFS/conf/
  cp http.conf mime.types /etc/fdfs/
b、 安装Nginx

切换回fdfs目录下

  • 解压

    tar -xvf nginx-1.10.0.tar.gz
    
  • 配置
    切换到

cd nginx-1.10.0
  sudo ./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx --add-module=/home/leyou/fdfs/fastdfs-nginx-module/src

在这里插入图片描述

  • 编译安装
 sudo make && sudo make install
  • 配置nginx整合fastdfs-module模块

    我们需要修改nginx配置文件,在/opt/nginx/config/nginx.conf文件中:

  sudo vim  /opt/nginx/conf/nginx.conf

将文件中,原来的server 80{ ...} 部分代码替换为如下代码:

      server {
          listen       80;
          server_name  image.leyou.com;
  
      	# 监听域名中带有group的,交给FastDFS模块处理
          location ~/group([0-9])/ {
              ngx_fastdfs_module;
          }
  
          location / {
              root   html;
              index  index.html index.htm;
          }
  
          error_page   500 502 503 504  /50x.html;
          location = /50x.html {
              root   html;
          }
          
      }
  • 启动
  nginx # 启动
  nginx -s stop # 停止
  nginx -s reload # 重新加载配置
  • 设置nginx开机启动

    创建一个开机启动的脚本:

    vim /etc/init.d/nginx
    

    添加以下内容:

  #!/bin/sh
  #
  # nginx - this script starts and stops the nginx daemon
  #
  # chkconfig:   - 85 15
  # description:  NGINX is an HTTP(S) server, HTTP(S) reverse \
  #               proxy and IMAP/POP3 proxy server
  # processname: nginx
  # config:      /etc/nginx/nginx.conf
  # config:      /etc/sysconfig/nginx
  # pidfile:     /var/run/nginx.pid
  
  # Source function library.
  . /etc/rc.d/init.d/functions
  
  # Source networking configuration.
  . /etc/sysconfig/network
  
  # Check that networking is up.
  [ "$NETWORKING" = "no" ] && exit 0
  
  nginx="/usr/bin/nginx"
  prog=$(basename $nginx)
  
  NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf"
  
  [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
  
  lockfile=/var/lock/subsys/nginx
  
  make_dirs() {
     # make required directories
     user=`$nginx -V 2>&1 | grep "configure arguments:.*--user=" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
     if [ -n "$user" ]; then
        if [ -z "`grep $user /etc/passwd`" ]; then
           useradd -M -s /bin/nologin $user
        fi
        options=`$nginx -V 2>&1 | grep 'configure arguments:'`
        for opt in $options; do
            if [ `echo $opt | grep '.*-temp-path'` ]; then
                value=`echo $opt | cut -d "=" -f 2`
                if [ ! -d "$value" ]; then
                    # echo "creating" $value
                    mkdir -p $value && chown -R $user $value
                fi
            fi
         done
      fi
  }
  
  start() {
      [ -x $nginx ] || exit 5
      [ -f $NGINX_CONF_FILE ] || exit 6
      make_dirs
      echo -n $"Starting $prog: "
      daemon $nginx -c $NGINX_CONF_FILE
      retval=$?
      echo
      [ $retval -eq 0 ] && touch $lockfile
      return $retval
  }
  
  stop() {
      echo -n $"Stopping $prog: "
      killproc $prog -QUIT
      retval=$?
      echo
      [ $retval -eq 0 ] && rm -f $lockfile
      return $retval
  }
  
  restart() {
      configtest || return $?
      stop
      sleep 1
      start
  }
  
  reload() {
      configtest || return $?
      echo -n $"Reloading $prog: "
      killproc $nginx -HUP
      RETVAL=$?
      echo
  }
  
  force_reload() {
      restart
  }
  
  configtest() {
    $nginx -t -c $NGINX_CONF_FILE
  }
  
  rh_status() {
      status $prog
  }
  
  rh_status_q() {
      rh_status >/dev/null 2>&1
  }
  
  case "$1" in
      start)
          rh_status_q && exit 0
          $1
          ;;
      stop)
          rh_status_q || exit 0
          $1
          ;;
      restart|configtest)
          $1
          ;;
      reload)
          rh_status_q || exit 7
          $1
          ;;
      force-reload)
          force_reload
          ;;
      status)
          rh_status
          ;;
      condrestart|try-restart)
          rh_status_q || exit 0
              ;;
      *)
          echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
          exit 2
  esac
  
  • 修改文件权限,并加入服务列表

    # 修改权限
    chmod 777 /etc/init.d/nginx 
    # 添加到服务列表
    chkconfig --add /etc/init.d/nginx 
    
  • 设置开机启动

 chkconfig nginx on

访问浏览器对应的地址可以看到刚刚上传的图片

http://image.leyou.com/group1/M00/00/00/rBEACmEPpcyAcBNZAAFkkXlaVjk629.png

下面这是是刚刚上传的图片
在这里插入图片描述

11、文件上传Java代码的实现

余庆先生提供了一个Java客户端,但是作为一个c程序员,写的java代码可想而知。而且已经很久不维护了。这里推荐一个开源的FastDFS客户端,支持最新的SpringBoot2.0。
配置使用极为简单,支持连接池,支持自动生成缩略图,狂拽酷炫吊炸天啊,有木有。

https://github.com/tobato/FastDFS_Client

在这里插入图片描述

(1)在项目当中使用FastDFS-Client
1)引入依赖:修改ly-upload当中的pom.xml文件

在这里插入图片描述

		<dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
        </dependency>
2)引入Java的配置类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

package com.leyou.upload.config;

import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;

@Configuration
@Import(FdfsClientConfig.class)
//解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FastClientImporter {


}

3)编写FastDFS属性,即编写FastDFS的配置文件

在这里插入图片描述

fdfs:
  so-timeout: 1501
  connect-timeout: 601
  thumb-image: #设置图片的缩略图
    width: 60
    height: 60
  tracker-list: #tracker地址
    - 192.168.58.101:22122
4)编写测试类(实现上传文件的测试以及其对应上传缩略图)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

package com.leyou.upload;

import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.domain.ThumbImageConfig;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.upload.service.UploadService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

@RunWith(SpringRunner.class)  //测试启动器,可以加载Springboot测试注解。
@SpringBootTest  //单元测试
public class FdfsTest {

    @Autowired
    private FastFileStorageClient storageClient;

    @Autowired
    private ThumbImageConfig thumbImageConfig;

    @Test
    public void testUpload() throws FileNotFoundException {
        File file = new File("D:\\test\\1.png");
        // 上传并且生成缩略图
        StorePath storePath = this.storageClient.uploadFile(
                new FileInputStream(file), file.length(), "png", null);
        // 带分组的路径
        System.out.println(storePath.getFullPath());
        // 不带分组的路径
        System.out.println(storePath.getPath());
    }

    @Test
    public void testUploadAndCreateThumb() throws FileNotFoundException {
        File file = new File("D:\\test\\baby.png");
        // 上传并且生成缩略图
        StorePath storePath = this.storageClient.uploadImageAndCrtThumbImage(
                new FileInputStream(file), file.length(), "png", null);
        // 带分组的路径
        System.out.println(storePath.getFullPath());
        // 不带分组的路径
        System.out.println(storePath.getPath());
        // 获取缩略图路径
        String path = thumbImageConfig.getThumbImagePath(storePath.getPath());
        System.out.println(path);
    }
}

在D盘的test文件夹当中准备一张图片
在这里插入图片描述

运行测试类当中的测试方法

在这里插入图片描述
返回结果
在这里插入图片描述
用这个地址了浏览器当中访问

http://image.leyou.com/group1/M00/00/00/rBEACmEQz1iAJkXSAAiysGYAir4636.png

访问成功代表上传成功
在这里插入图片描述
运行第二个测试方法:上传并且生成缩略图
在这里插入图片描述
在这里插入图片描述
访问第三个图片的路径

http://image.leyou.com/group1/M00/00/00/rBEACmEQ0bCAJREiAAiysGYAir4857_60x60.png

图片已经被压缩
在这里插入图片描述

(2)改造:UploadService
1)UploadService完成文件的上传

在这里插入图片描述

package com.leyou.upload.service;

import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class UploadService {

    @Autowired
    private FastFileStorageClient storageClient;
    // Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
    private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
    public String uploadImage(MultipartFile file) {
        try {
            //校验文件类型
            String contentType = file.getContentType();
            if(!ALLOW_TYPES.contains(contentType)){//校验当前文件的后缀是否在上述集合当中
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //校验文件的内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if(image == null){
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //上传到FastDFS
            //获取后缀名,通过文件名称截取字符串的方式获取后缀名称
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(),".");
            StorePath storePath =  storageClient.uploadFile(file.getInputStream(),file.getSize(), extension,null);
            return "http://image.leyou.com/" + storePath.getFullPath();
        } catch (IOException e) {
           //如果上传失败,记录日志信息
            log.error("上传文件失败",e);
            //返回错误结果
            throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
        }
        //返回图片路径
    }
}
2)继续完善上述代码:(在配置文件当中配置相关属性)

UploadService当中的返回的路径是的地址是写死的地址因此我们需要将其抽取出来 ,需要配置一下允许访问数据的类型

在这里插入图片描述

ly:
  upload:
    baseUrl: http://image.leyou.com/
    allowTypes:
      - image/jpeg
      - image/png
      - image/jpg
3)读取上述的配置文件当中定义的数据

在这里插入图片描述
在这里插入图片描述

package com.leyou.upload.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

@ConfigurationProperties(prefix = "ly.upload")
public class UploadProperties {
    private String baseUrl;
    private List<String> allowTypes;


}

在这里插入图片描述
在这里插入图片描述
继续完善
在这里插入图片描述

package com.leyou.upload.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

@Data
@ConfigurationProperties(prefix = "ly.upload")
public class UploadProperties {
    private String baseUrl;
    private List<String> allowTypes;

}

4)在UploadService当中使用

在这里插入图片描述

@EnableConfigurationProperties(UploadProperties.class)

@EnableConfigurationProperties注解的作用是:
使用 @ConfigurationProperties注解的类生效。读取配置信息的类的注解生效
在这里插入图片描述
全部代码

package com.leyou.upload.service;

import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.upload.config.UploadProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
@EnableConfigurationProperties(UploadProperties.class)
public class UploadService {

    @Autowired
    private FastFileStorageClient storageClient;
    // Arrays.asList可以将任意数据封装为集合(这里将文件的后缀分装为一个集合方便在文件上传时候进行校验)
    @Autowired
    private UploadProperties prop;
   // private static final List<String> ALLOW_TYPES = Arrays.asList("image/jpeg","image/png","image/jpg");
    public String uploadImage(MultipartFile file) {
        try {
            //校验文件类型
            String contentType = file.getContentType();
            if(!prop.getAllowTypes().contains(contentType)){//校验当前文件的后缀是否在上述集合当中
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //校验文件的内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if(image == null){
                throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
            }
            //上传到FastDFS
            //获取后缀名,通过文件名称截取字符串的方式获取后缀名称
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(),".");
            StorePath storePath =  storageClient.uploadFile(file.getInputStream(),file.getSize(), extension,null);
            return prop.getBaseUrl() + storePath.getFullPath();
        } catch (IOException e) {
           //如果上传失败,记录日志信息
            log.error("上传文件失败",e);
            //返回错误结果
            throw new LyException(ExceptionEnum.UPLOAD_FILE_ERROR);
        }
        //返回图片路径
    }
}
(3)文件上传运行测试

在这里插入图片描述
http://manage.leyou.com/#/item/brand

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上传成功
在这里插入图片描述
在这里插入图片描述
搜索以后发现显示太大
在这里插入图片描述
设置一下图片的大小
在这里插入图片描述
在这里插入图片描述

12、设置nginx上传文件大小的限制

vim /opt/nginx/ conf/nginx.con

在这里插入图片描述

client_max_body_size 100m

在这里插入图片描述
退出保存
从新加载nginx
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员猫爪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值