1. 环境说明,此教程代码运行环境如下:

JDK:JDK1.8+,
JclamAV Server:1.1.0-rc,
Server:CentOS8

2. 代码编辑
  1. jClamAV客户端依赖导入
<!--JClamAV客户端依赖-->
<dependency>
    <groupId>xyz.capybara</groupId>
    <artifactId>clamav-client</artifactId>
    <version>2.1.2</version>
</dependency>
<!--hutool工具包依赖-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.4</version>
</dependency>
  1. 编写配置类 JClamAVConfig用于初始化ClamAV的客户端, 以及配置文件 application.properties,

application.properties如下:

#web服务端口
server.port=8080
#JclamAV服务端配置
env.clamav.uri=192.168.217.142:3310

JclamAVConfig类如下:

package com.darlingrin.jclamavdemo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import xyz.capybara.clamav.ClamavClient;
import xyz.capybara.clamav.Platform;

/**
 * @ClassName FileValidate
 * @Description TODO
 * @Author Rin
 * @Date 2023/12/29 14:38
 * @Version 1.0
 **/
@Configuration
public class JClamAVConfig {
    //日志记录
    private static final Logger log = LoggerFactory.getLogger(JClamAVConfig.class);
    //定义clamav相关配置的key(此项用于对application.properties或者application.yml配置文件中的key进行配置)
    private final static String CLAMAV_URI = "env.clamav.uri";
    //实例化Clamav客户端
    public static ClamavClient client;

    //注入Spring的环境配置管理对象
    @Autowired
    Environment environment;

    /**
     * 初始化客户端
     * @return clamav客户端对象
     */
    @Bean(name = "clamavClient")
    public ClamavClient getClamavClient(){
        try{
            //获取application.properties中的jclamAV服务端配置
            String uri = environment.getProperty(CLAMAV_URI);
            //拆分端口ip(当然如果定义配置的时候ip和端口分开配置的直接分开获取即可)
            String serverHost = uri.split(":")[0];
            Integer serverPort = Integer.valueOf(uri.split(":")[1]);
            //初始化ClamavClenet对象
            client = new ClamavClient(serverHost,serverPort, Platform.UNIX);
            log.info("Clamav Server Connected Successfully ..... in {}:{}",serverHost,serverPort);
            //输出jclamav的版本
            log.info(client.version());
            return client;
        }catch (Exception e){
            log.error("Clamav Server Connect Failed,Caused By >>>>>>> ",e);
        }
        return null;
    }
}
  1. 编写文件扫描工具类FileScannerHelper用于将对文件进行预处理以及参数处理

FileScannerHelper.java代码如下:

package com.darlingrin.jclamavdemo.tools;

import cn.hutool.core.io.IoUtil;
import com.darlingrin.jclamavdemo.config.JClamAVConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.capybara.clamav.ClamavClient;
import xyz.capybara.clamav.ClamavException;
import xyz.capybara.clamav.commands.scan.result.ScanResult;

import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;

/**
 * @ClassName FileScanner
 * @Description TODO
 * @Author Rin
 * @Date 2023/12/29 14:51
 * @Version 1.0
 **/
public class FileScannerHelper {
    //日志记录
    private static final Logger log = LoggerFactory.getLogger(FileScannerHelper.class);
    private static ClamavClient client = JClamAVConfig.client;

    /**
     * 文件扫描走文件流的方式
     * @param fileStream 传入文件流
     * @return 0安全文件,1危险文件
     * @throws ClamavException
     */
    public static Integer FileScanner(InputStream fileStream) throws ClamavException {
        try{
            ScanResult scres = client.scan(fileStream);
            if(scres instanceof ScanResult.OK){
                //验证通过
                return 0;
            } else if (scres instanceof ScanResult.VirusFound) {
                Map<String, Collection<String>> foundViruses = ((ScanResult.VirusFound) scres).getFoundViruses();
                log.warn("Virus Found >>>> {}",foundViruses);
                return -1;
            }
        }catch (ClamavException e){
            log.error("ClamAV Scanned Error Caused By >>>>> {}",e);
            throw e;
        }
        return 0;
    }


    /**
     * 危险文件扫描走文件地址的方式*这个文件地址是指文件扫描服务器所在的文件地址
     * @param file 文件对象
     * @return 0安全,1危险
     * @throws ClamavException
     */
    public static Integer FileScanner(File file) throws ClamavException {
        try{
            ScanResult scres = client.scan(file.toPath());
            if(scres instanceof ScanResult.OK){
                //验证通过
                return 0;
            } else if (scres instanceof ScanResult.VirusFound) {
                Map<String, Collection<String>> foundViruses = ((ScanResult.VirusFound) scres).getFoundViruses();
                log.warn("Virus Found >>>> {}",foundViruses);
                return -1;
            }
        }catch (ClamavException e){
            log.error("ClamAV Scanned Error Caused By >>>>> {}",e);
            //IoUtil走的hutool工具包里面的Io工具类
            return FileScanner(IoUtil.toStream(file));
        }
        return 0;
    }
}

  1. 接下来编写测试类,先放一个安全的文件进行处理,示例代码走的是文件流的方式进行操作,示例代码在test包下面进行测试,当然也可以导入spring-web的依赖写一个controller进行测试
    注意:因为在进行环境配置的时候有用到spring的环境管理,因此测试代码也必须依赖spring环境,故不能以执行main方法的方式测试

测试类代码如下:

//读取文件
File file = new File("D:\\软件安装包分区\\dm8_20231113_x86_win_64.zip");
System.out.println("=============================File Scanner Start==============================");
System.out.println("File Name: "+file.getName());
//计算文件大小(单位为KB)
System.out.println("File Size: "+(file.length()/8/1024)+"KB");
Date st = new Date();
System.out.println("File Scaner StartTime: "+sdf.format(st));
//将文件转为文件流
InputStream ips = IoUtil.toStream(file);
//调用服务,进行文件扫描(核心调用就这一行代码)
Integer status = FileScannerHelper.FileScanner(ips);
//获取文件扫描结果
System.out.println("File Scaner Consequence: "+(status==0? "It's Safety":"Tt's Dangerous"));
//结束扫描
Date ed = new Date();
System.out.println("File Scaner EndTime: "+sdf.format(ed));
System.out.println("Scanner Time : "+(ed.getTime() - st.getTime())+"ms");
System.out.println("==============================File Scanner End===============================");

测试结果如下:

文件安全扫描结果截图

在进行病毒文件或者风险文件操作的时候,请在独立的容器中进行测试,禁止在本机进行测试,建议在虚拟机中进行测试,防止误操作导致系统崩溃


危险文件扫描结果截图