fastdfs+nginx+keepalived+openoffice+lua 實現文件上傳、下載、水印、預覽(word、excel、ppt、txt),feign文件上傳

前言

最近剛剛實現的文件服務中心,記錄一下,爲沒做過的人提供一下思路,由於本人技術有限,不足之處歡迎批評指正,共同學習,共同進步。

目錄

Fastdfs集羣搭建
搭建keepalived 實現ngxin熱備高可用
遠程訪問 實現上傳下載
圖片添加水印
feign遠程調用解決MultipartFile爲null的問題
搭建openoffice-實現文件預覽
自定義openoffice連接池
nginx整合lua實現文件安全url

1.文件服務器 搭建

我是基於docker鏡像安裝的fastdfs,較以前的安裝實現是太便捷了,特別推薦。

1.1 拉取鏡像

docker pull morunchang/fastdfs

1.2 在node01和node02上安裝tracker

在node01和node02上分別執行以下操作
注意:以下操作指令在node01中執行,在node02操作時,將tracker1改爲tracker2

1)創建文件夾

mkdir -p /apps/fastdfs/tracker1/data /apps/fastdfs/tracker1/conf

2)寫入/apps/fastdfs/tracker1/conf/tracker.conf

disabled=false
bind_addr=
port=22122
connect_timeout=30
network_timeout=30
base_path=/data/fast_data
max_connections=256
accept_threads=1
work_threads=4
store_lookup=2
store_group=group1
store_server=0
store_path=0
download_server=0
reserved_storage_space = 10%
log_level=info
run_by_group=
run_by_user=
allow_hosts=*
sync_log_buff_interval = 10
check_active_interval = 120
thread_stack_size = 64KB
storage_ip_changed_auto_adjust = true
storage_sync_file_max_delay = 86400
storage_sync_file_max_time = 300
use_trunk_file = false 
slot_min_size = 256
slot_max_size = 16MB
trunk_file_size = 64MB
trunk_create_file_advance = false
trunk_create_file_time_base = 02:00
trunk_create_file_interval = 86400
trunk_create_file_space_threshold = 20G
trunk_init_check_occupying = false
trunk_init_reload_from_binlog = false
trunk_compress_binlog_min_interval = 0
use_storage_id = false
storage_ids_filename = storage_ids.conf
id_type_in_filename = ip
store_slave_file_use_link = false
rotate_error_log = false
error_log_rotate_time=00:00
rotate_error_log_size = 0
log_file_keep_days = 0
use_connection_pool = false
connection_pool_max_idle_time = 3600
http.server_port=8080
http.check_alive_interval=30
http.check_alive_type=tcp
http.check_alive_uri=/status.html

3)運行tracker1的docker容器

docker run -d --name tracker1 --net=host --restart always \
-v /etc/localtime:/etc/localtime \
-v /apps/fastdfs/tracker1/data:/data/fast_data/ \
-v /apps/fastdfs/tracker1/conf/tracker.conf:/etc/fdfs/tracker.conf \
morunchang/fastdfs sh tracker.sh

4)查看docker日誌是否啓動正常

docker logs tracker1

5)開啓防火牆端口:22122

firewall-cmd --zone=public --add-port=22122/tcp --permanent
firewall-cmd --reload

1.3 在node01和node02上安裝storage

在node01和node02上分別執行以下操作
注意:以下操作指令在node01中執行,在node02操作時,將storage1改爲storage2
1)創建文件夾

mkdir -p /apps/fastdfs/storage1/data /apps/fastdfs/storage1/conf

2)寫入/apps/fastdfs/storage1/conf/storage.conf

   disabled=false
    group_name=group1
    bind_addr=
    client_bind=true
    port=23002
    connect_timeout=30
    network_timeout=30
    heart_beat_interval=30
    stat_report_interval=60
    base_path=/data/fast_data
    max_connections=256
    buff_size = 256KB
    accept_threads=1
    work_threads=4
    disk_rw_separated = true
    disk_reader_threads = 1
    disk_writer_threads = 1
    sync_wait_msec=50
    sync_interval=0
    sync_start_time=00:00
    sync_end_time=23:59
    write_mark_file_freq=500
    store_path_count=1
    store_path0=/data/fast_data
    subdir_count_per_path=256
    tracker_server=198.168.1.121:22122
    tracker_server=198.168.1.122:22122
    log_level=debug
    run_by_group=
    run_by_user=
    allow_hosts=*
    file_distribute_path_mode=0
    file_distribute_rotate_count=100
    fsync_after_written_bytes=0
    sync_log_buff_interval=10
    sync_binlog_buff_interval=10
    sync_stat_file_interval=300
    thread_stack_size=512KB
    upload_priority=10
    if_alias_prefix=
    check_file_duplicate=0
    file_signature_method=hash
    key_namespace=FastDFS
    keep_alive=0
    use_access_log = true
    rotate_access_log = false
    access_log_rotate_time=00:00
    rotate_error_log = false
    error_log_rotate_time=00:00
    rotate_access_log_size = 0
    rotate_error_log_size = 0
    log_file_keep_days = 0
    file_sync_skip_invalid_record=false
    use_connection_pool = false
    connection_pool_max_idle_time = 3600
    http.domain_name=
    http.server_port=9101

3)寫入/apps/fastdfs/storage1/conf/nginx.conf

worker_processes  1;
error_log  /data/fast_data/logs/nginx-error.log;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /data/fast_data/logs/nginx-access.log  main;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       9101;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location ~ /group1/M00 {
                    root /data/fast_data/data;
                    ngx_fastdfs_module;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

4)寫入/apps/fastdfs/storage1/conf/mod_fastdfs.conf

connect_timeout=30
network_timeout=30
base_path=/data/fast_data
load_fdfs_parameters_from_tracker=true
storage_sync_file_max_delay = 86400
use_storage_id = false
storage_ids_filename = storage_ids.conf
tracker_server=198.168.1.121:22122
tracker_server=198.168.1.122:22122
storage_server_port=23002
group_name=group1
url_have_group_name = true
store_path_count=1
log_level=info
log_filename=
response_mode=proxy
if_alias_prefix=
flv_support = true
flv_extension = flv
group_count = 0

5)寫入/apps/fastdfs/storage1/conf/storage.sh

#!/bin/sh
/data/fastdfs/storage/fdfs_storaged /etc/fdfs/storage.conf
/etc/nginx/sbin/nginx
tail -f /data/fast_data/logs/storaged.log

6)寫入/apps/fastdfs/storage1/conf/client.conf

# connect timeout in seconds
# default value is 30s
connect_timeout=30

# network timeout in seconds
# default value is 30s
network_timeout=30

# the base path to store log files
base_path=/data/fastdfs/test

# tracker_server can ocur more than once, and tracker_server format is
#  "host:port", host can be hostname or ip address

tracker_server=198.168.1.122:22122

#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
log_level=info

# if use connection pool
# default value is false
# since V4.05
use_connection_pool = false

# connections whose the idle time exceeds this time will be closed
# unit: second
# default value is 3600
# since V4.05
connection_pool_max_idle_time = 3600

# if load FastDFS parameters from tracker server
# since V4.05
# default value is false
load_fdfs_parameters_from_tracker=false

# if use storage ID instead of IP address
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# default value is false
# since V4.05
use_storage_id = false

# specify storage ids filename, can use relative or absolute path
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# since V4.05
storage_ids_filename = storage_ids.conf

#HTTP settings
http.tracker_server_port=80

#use "#include" directive to include HTTP other settiongs
##include http.conf

7)運行docker容器

docker run -d --name storage1 --net=host --restart always \
-v /etc/localtime:/etc/localtime \
-v /apps/fastdfs/storage1/data:/data/fast_data/ \
-v /apps/fastdfs/storage1/conf/storage.sh:/storage.sh \
-v /apps/fastdfs/storage1/conf/storage.conf:/etc/fdfs/storage.conf \
-v /apps/fastdfs/storage1/conf/nginx.conf:/etc/nginx/conf/nginx.conf  \
-v /apps/fastdfs/storage1/conf/mod_fastdfs.conf:/etc/fdfs/mod_fastdfs.conf \
-v /apps/fastdfs/storage1/conf/client.conf:/data/fastdfs/conf/client.conf \
morunchang/fastdfs sh storage.sh

8)查看docker日誌是否正常

docker logs storage1

9)開啓防火牆端口:23002、9101

firewall-cmd --zone=public --add-port=23002/tcp --add-port=9101/tcp --permanent
firewall-cmd --reload

1.4 驗證fastdfs是否安裝成功

說明:以下操作在node01中進行。

1.4.1查看FastDFS監控狀態

docker exec -it storage1 fdfs_monitor /data/fastdfs/conf/client.conf

參數說明:

tracker_server_count:2 --表示2個Tracker Server
tracker server is 198.168.1.121:22122 --表示Leader Tracker
group count: 1	--表示有1個group
group name = group1	--組名稱是group1
storage server count = 2	--組內有2個storage
active server count = 2	--活動的storage有2個
storage server port = 23002	--storage的端口
storage HTTP port = 9101	--storage的文件訪問端口
store path count = 1	--storage只掛了一個存儲目錄
total_upload_count = 11	--總共上傳了多少個文件
total_upload_bytes = 691405	--總共上傳了多少字節
success_upload_bytes = 691405 --成功上傳了多少字節
total_download_count = 2	--總共下載了多少文件(使用java客戶端)

1.4.2 上傳文件到FastDFS

docker exec -it storage1 bash
cd /data/fastdfs/conf
fdfs_test client.conf upload anti-steal.jpg

文件上傳成功後,會提示文件訪問地址,同時會自動同步到storage2,因此也可以通過storage2的IP,訪問文件。

由於storage1的http端口配置爲9101,所以真正的訪問地址是:
(示例地址)http://198.168.1.001:9101/group1/M00/00/00/rBQIe11swBOAPaazAABdrZgsqUU480_big.jpg
storage2的訪問地址是:
(示例地址)http://198.168.1.002:9101/group1/M00/00/00/rBQIe11swBOAPaazAABdrZgsqUU480_big.jpg

到此 ,雙機fastdfs集羣搭建完成,不過每臺鏡像上的nginx都是訪問本地的fastdfs,接下來搭建keepavlived實現nginx高可用,和fastdfs服務器負載。

2 搭建keepalived 實現ngxin熱備高可用

首先說明一下keepalived提供了什麼:首先,keepalived提供了虛擬ip,客戶真正訪問的也是虛擬ip。本例中有兩臺節點,但同一時間有且僅有一臺服務器提供虛擬ip,另一臺處於備用狀態,當提供虛擬ip服務的keepalived宕機時,備用機器會馬上提供虛擬ip。第二,用戶對虛擬ip的訪問請求會被轉發到keepalived所在服務器的nginx上,第三,當nginx掛掉時,本機keepalived會重啓nginx或立刻停止服務(腳本配置)。

2.1 安裝

yum install wget make gcc gcc-c++ openssl-devel 
wget http://www.keepalived.org/software/keepalived-2.0.7.tar.gz 
tar zxvf keepalived-2.0.7.tar.gz 
cd keepalived-2.0.7 
./configure --prefix=/data/keepalived
make 
make install

如果報以下警告:
WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
不用擔心,我們只需要用到VRRP功能,不需要用IPVS功能,所以請確保以下三項是yes就行了。

在這裏插入圖片描述

2.2 將keepalived 以服務方式啓動

mkdir /etc/keepalived 
cp /data/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ 
systemctl enable keepalived

2.3 master配置

Keepalived分爲主從(主機與備用機),下面是主master機器(172.20.8.90)的配置
global_defs {
    notification_email {
        [email protected]
    }
    notification_email_from [email protected]
    smtp_server smtp.hysec.com
    smtp_connection_timeout 30
    router_id nginx_master        # 設置nginx master的id,在一個網絡應該是唯一的
}
vrrp_script chk_http_port {
    script "/etc/keepalived/check_nginx.sh"    #最後手動執行下此腳本,以確保此腳本能夠正常執行
    interval 2                          #(檢測腳本執行的間隔,單位是秒)
    weight 2
}
vrrp_instance VI_1 {
    state BACKUP            # 指定keepalived的角色,MASTER爲主,BACKUP爲備
    interface eno16780032            # 當前進行vrrp通訊的網絡接口卡(當前centos的網卡
    virtual_router_id 66        # 虛擬路由編號,主從要一直
    priority 100            # 優先級,數值越大,獲取處理請求的優先級越高
    nopreempt
    advert_int 1            # 檢查間隔,默認爲1s(vrrp組播週期秒數)
    authentication {
        auth_type PASS
        auth_pass 1111
}
    track_script {
        chk_http_port            #(調用檢測腳本)
    }
    virtual_ipaddress {
        172.20.8.94            # 定義虛擬ip(VIP),可多設,每行一個
    }
}

2.4 backup配置

global_defs {
    notification_email {
       [email protected]
    }
    notification_email_from [email protected]
    smtp_server smtp.hysec.com
    smtp_connection_timeout 30
    router_id nginx_backup              # 設置nginx backup的id,在一個網絡應該是唯一的
}
vrrp_script chk_http_port {
    script "/etc/keepalived/check_nginx.sh"
    interval 2                          #(檢測腳本執行的間隔)
    weight 2
}
vrrp_instance VI_1 {
    state BACKUP                        # 指定keepalived的角色,MASTER爲主,BACKUP爲備
    interface eno16780032                      # 當前進行vrrp通訊的網絡接口卡(當前centos的網卡)
    virtual_router_id 66                # 虛擬路由編號,主從要一直
    priority 50                         # 優先級,數值越大,獲取處理請求的優先級越高
    advert_int 1                        # 檢查間隔,默認爲1s(vrrp組播週期秒數)
    authentication {
        auth_type PASS
        auth_pass 1111
}
track_script {
        chk_http_port                   #(調用檢測腳本)
    }
    virtual_ipaddress {
        172.20.8.94                   # 定義虛擬ip(VIP),可多設,每行一個
    }
}```
### 2.5 添加檢查nginx狀態的腳本

    #!/bin/bash
    #version 0.0.1
    A=`ps -C nginx --no-header | wc -l`
    
    if [ $A -eq 0 ];then
    systemctl restart docker
    sleep 3
    if [ ps -C nginx --no-header |wc -l -eq 0 ];then
    systemctl stop keepalived
    fi
    fi

腳本說明:檢查nginx進程數 如果爲0 重啓docker(容器會同步重啓),睡3秒 nginx進程還是0 則停止keepalived

賦權:chmod +x /etc/keepalived/nginx_pid.sh

2.6 配置master和backup時間同步

在NGINX_MASTER和NGINX_BACKUP上安裝ntp

yum -y install ntp

在NGINX_MASTER上修改ntp配置文件
添加以下兩行

vim /etc/ntp.conf
server 127.127.1.0 iburst local clock #添加使用本地時間 restrict 192.168.8.0 mask 255.255.255.0 nomodify #允許更新的IP地址段

在這裏插入圖片描述
在NGINX_MASTER上啓動ntp服務,並加入開機啓動

systemctl start ntpd systemctl enable ntpd

在NGINX_BACKUP上同步NGINX_MASTER的時間

ntpdate 172.20.8.123

在NGINX_BACKUP上設置計劃任務
每天凌晨5點01分同步時間。

crontab -e 1 5 * /usr/sbin/ntpdate 172.20.8.123 >> /var/log/upClock.log

測試:
關閉一臺服務,vip能自動切換 可以通過vip正常訪問服務 則成功。

3. 遠程訪問 實現上傳下載

3.1 引入開源工具包

<dependency>
 		 <groupId>com.github.tobato</groupId>
 		   <artifactId>fastdfs-client</artifactId>
 		   <version>1.26.3</version>
 </dependency>		   

該包已經封裝好了各種方法,可以直接調用。這裏着重說一下水印、feign遠程調用圖片上傳下載和預覽的問題

3.2 圖片添加水印


	/**
	* 加圖片水印  
	*
	* @param bufImg  --BufferedImage  用來畫圖的寬高跟需要加水印的圖片一樣的空白圖
	* @param srcImg --需要加水印的圖片
	* @param degree --旋轉角度
	* @param logoText	--水印內容
	* 
	 */
	public static void markPic(BufferedImage buffImg, Image srcImg, Integer degree,String logoText) {
	 
		 // 2、得到畫筆對象
        Graphics2D g = buffImg.createGraphics();
        
        // 3、設置對線段的鋸齒狀邊緣處理
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(
                srcImg.getScaledInstance(srcImg.getWidth(null),
                        srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0,
                null);
        
        // 4、設置水印旋轉
        if (null != degree) {
            g.rotate(Math.toRadians(degree),
                    (double) buffImg.getWidth() / 2,
                    (double) buffImg.getHeight() / 2);
        }
       
        // 5、設置水印文字顏色
        g.setColor(fileWatermark.getColor());
        
        // 6、設置水印文字Font
     //   g.setFont(fileWatermark.getFont());
        
        // 7、設置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
        		fileWatermark.getAlpha()));
        
        // 8、第一參數->設置的內容,後面兩個參數->文字在圖片上的座標位置(x,y)
     //   g.drawString(logoText, fileWatermark.getPositionWidth(), fileWatermark.getPositionHeight());
        
        // 9、釋放資源
        g.dispose();

	}
	
	/**
     * 給圖片添加水印文字
     *
     * @param logoText
     *            水印文字
     * @param srcImgPath
     *            源圖片路徑
     * @param targerPath
     *            目標圖片路徑
	 * @throws IOException 
     */
    public static void markImageByText(MultipartFile multipartFile,String logoText) throws Exception {
       markImageByText(multipartFile,logoText, null);
    }
 
    /**
     * 給圖片添加水印文字、可設置水印文字的旋轉角度
     *
     * @param logoText
     * @param srcImgPath
     * @param targerPath
     * @param degree 水印旋轉角度
     */
    public  static MultipartFile markImageByText(MultipartFile multipartFile,String logoText,Integer degree) throws Exception {
    	
    	OutputStream os = null;
    	InputStream input =null;
    	
    	try {
		    	// 1、源圖片
		        Image srcImg = ImageIO.read(multipartFile.getInputStream());
		        BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),
		                srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
		        
		        markPic(buffImg,srcImg,degree,logoText);
		      
		        
		        String suffix = CommonUtil.getFileExtension(multipartFile);
		        
		        ByteArrayOutputStream bs = new ByteArrayOutputStream();
				ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
				ImageIO.write(buffImg, suffix, imOut);
				//InputStream is = new ByteArrayInputStream(bs.toByteArray());

				// 加水印後的文件上傳
				//multipartFile = new MockMultipartFile(multipartFile.getOriginalFilename(),is);
				String originalFilename = multipartFile.getOriginalFilename();
				
				File file = new File("/tmp/"+ new Date().getTime() + "/" + originalFilename);
				
				// 判斷目標文件所在的目錄是否存在
				if (!file.getParentFile().exists()) {
					// 如果目標文件所在的文件夾不存在,則創建父文件夾
					log.info("目標文件所在目錄不存在,準備創建它!");
					if (!file.getParentFile().mkdirs()) {
						log.error("創建目標文件所在的目錄失敗!");
						throw new NotFoundException("目錄不存在");
					}
				}
				
				// 創建目標文件
				if (file.createNewFile()) {
					
					log.info("創建單個文件" + originalFilename + "成功!");
					 
				} else {
					
					log.error("創建單個文件" + originalFilename + "失敗!");
					throw new IOException("創建單個文件" + originalFilename + "失敗!");
					
				}
				
				FileItem fileItem = new DiskFileItem(originalFilename, Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());
				 
				try {
				    input = new FileInputStream(file);
				    os = fileItem.getOutputStream();
				    IOUtils.copy(input, os);
				    
				} catch (IOException ex) {
				   ex.printStackTrace();
				}
				 
				multipartFile = new CommonsMultipartFile(fileItem);
				
				//返回加了水印的上傳對象
				log.error("圖片:[]成添加水印文字,filename=[{}]",originalFilename);
				

	    } finally {
	        try {
	            if (null != input)
	            	input.close();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	        try {
	            if (null != os)
	                os.close();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
    	
    	return multipartFile;
	 }

3.3 feign遠程調用解決MultipartFile爲null的問題

服務消費方增加兩個配置類:
FeignMultipartSupportConfig

@Configuration
public class FeignMultipartSupportConfig {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;
	
    @Bean
    public Encoder multipartFormEncoder() {
    	return new FeignSpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

FeignSpringFormEncoder

public class FeignSpringFormEncoder extends FormEncoder {
	  /**
	   * Constructor with the default Feign's encoder as a delegate.
	   */
	  public FeignSpringFormEncoder() {
	    this(new Default());
	  }	  
	  /**
	   * Constructor with specified delegate encoder.
	   *
	   * @param delegate delegate encoder, if this encoder couldn't encode object.
	   */
	  public FeignSpringFormEncoder(Encoder delegate) {
	    super(delegate);
	    
	    MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(ContentType.MULTIPART);
	    processor.addWriter(new SpringSingleMultipartFileWriter());
	    processor.addWriter(new SpringManyMultipartFilesWriter());
	  }
	  
	  
	  @Override
	  public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
	    if (bodyType.equals(MultipartFile.class)) {
	    	MultipartFile file = (MultipartFile) object;
	      Map data = Collections.singletonMap(file.getName(), object);
	      super.encode(data, MAP_STRING_WILDCARD, template);
	      return;
	    } else if (bodyType.equals(MultipartFile[].class)) {
	    	MultipartFile[] file = (MultipartFile[]) object;
	      if(file != null) {
	        Map data = Collections.singletonMap(file.length == 0 ? "" : file[0].getName(), object);
	        super.encode(data, MAP_STRING_WILDCARD, template);
	        return;
	      }
	    } else if(bodyType.equals(CommonsMultipartFile[].class) ) {
	    	CommonsMultipartFile[] file = (CommonsMultipartFile[]) object;
	        Map data = Collections.singletonMap(file.length == 0 ? "" : file[0].getName(), object);
	        super.encode(data, MAP_STRING_WILDCARD, template);
	        return;
	    }else if(bodyType.equals(CommonsMultipartFile.class)) {
	    	  CommonsMultipartFile file = (CommonsMultipartFile) object;
		      Map data = Collections.singletonMap(file.getName(), object);
		      super.encode(data, MAP_STRING_WILDCARD, template);
		      return;
	    }
	    super.encode(object, bodyType, template);
	  }
	}

4. 文件預覽

思路:搭建openoffice服務器,word、ppt轉pdf,txt文本轉碼後轉pdf,excel轉html再轉pdf

4.1 搭建openoffice

需要先安裝jdk
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

下載openoffice

wget https://jaist.dl.sourceforge.net/project/openofficeorg.mirror/4.1.5/binaries/zh-CN/Apache_OpenOffice_4.1.5_Linux_x86-64_install-rpm_zh-CN.tar.gz  

解壓後會在當前目錄裏生成一個zh-CN目錄

cd /usr/local/src/ openoffice /zh-CN/RPMS/
yum localinstall *.rpm

裝完後會在當前目錄下生成一個desktop-integration目錄

cd /usr/local/src/zh-CN/RPMS/desktop-integration/
yum localinstall openoffice4.1.5-redhat-menus-4.1.5-9789.noarch.rpm

啓動
臨時啓動

/opt/openoffice4/program/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard

放入後臺永久運行

nohup /opt/openoffice4/program/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard &

加入到開機自啓動
//遠程連接設置host爲0.0.0.0

vim /etc/rc.local
nohup /opt/openoffice4/program/soffice -headless -accept="socket,host=0.0.0.0,port=8100;urp;" -nofirststartwizard &

啓動如果報錯
error while loading shared libraries: libXext.so.6: cannot open shared object file: No such file or directory

原因是缺少相關包,執行命令:

yum install libXext libSM libXrender
在啓動OpenOffice時,將host=的ip地址寫爲0.0.0.0就可以通過java遠程連接了

字體庫安裝
涉及到文件中的字體裝換,如果沒有字體庫,中文會亂碼。

yum -y install fontconfig            --安裝字體庫

這時在/usr/shared目錄就可以看到fonts和fontconfig目錄了

打開c盤下的Windows/Fonts目錄: 找到我們想要的字體,

首先在/usr/shared/fonts目錄下新建一個目錄chinese: 然後上傳字體

chmod -R 755 /usr/share/fonts/chinese             --修改新增字體庫文件夾權限

接下來需要安裝ttmkfdir來搜索目錄中所有的字體信息,並彙總生成fonts.scale文件,輸入命令:

yum -y install ttmkfdir

然後執行ttmkfdir命令即可:

ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir

最後一步就是修改字體配置文件了,首先通過編輯器打開配置文件:

vi /etc/fonts/fonts.conf

可以看到一個Font list,即字體列表,在這裏需要把我們添加的中文字體位置加進去:
在這裏插入圖片描述
然後輸入:wq保存退出,最後別忘了刷新內存中的字體緩存,這樣就不用reboot重啓了

fc-cache

這樣所有的步驟就算完成了,最後再次通過fc-list,進行檢查。
示例代碼

  File word = new File("G:\\XXXXXX.doc");
  File pdf = new File("G:\\XXXXXX.pdf");
  OpenOfficeConnection connection=new SocketOpenOfficeConnection("172.20.8.123",8100);
        try {
            System.err.println("開啓連接");
            connection.connect();
            System.err.println("連接成功"); 
           DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);
           converter.convert(word, pdf);       
           connection.disconnect();   
        } catch (Exception e) {
            String string=e.getMessage();
            System.err.println(string);
        }

4.2 自定義openoffice連接池

maven 引入依賴

<dependency>
  <groupId>com.artofsolving</groupId>
  <artifactId>jodconverter</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
   <version>1.3.2</version>
</dependency>

OpenOfficeFactory

@Data
@Slf4j
public class OpenOfficeFactory extends BasePooledObjectFactory<OpenOfficeConnection>{

	private FilePreviewProperties properties;
	
	 public OpenOfficeFactory(FilePreviewProperties properties) {
	        this.properties = properties;
	}
	 
	//創建連接
	@Override
    public OpenOfficeConnection create() throws Exception {
        try {
            OpenOfficeConnection connection=new SocketOpenOfficeConnection(properties.getHost(),properties.getPort());
            connection.connect();
            return connection;
        } catch (Exception e) {
        	 throw new  Exception("連接OpenOffice失敗", e);
        }
    }
	
    @Override
    public PooledObject<OpenOfficeConnection> wrap(OpenOfficeConnection openOfficeConnection) {
        return new DefaultPooledObject<>(openOfficeConnection);
    }
    
    //初始化連接  在此做一些鏈接初始化工作
 /*   @Override
    public void activateObject(PooledObject<OpenOfficeConnection> pooledObject) throws Exception {
    	OpenOfficeConnection ftpClient = pooledObject.getObject();
        
    }*/
    
    // 銷燬對象
    @Override
    public void destroyObject(PooledObject<OpenOfficeConnection> p) {
    	OpenOfficeConnection connetion = p.getObject();
    	connetion.disconnect();
    }

    //鏈接狀態檢查
    @Override
    public boolean validateObject(PooledObject<OpenOfficeConnection> pooledObject) {
    	OpenOfficeConnection connetion = pooledObject.getObject();
        try {
            return connetion.isConnected();
        } catch (Exception e) {
            return false;
        }
    }
}

OpenOfficePool

@Data
public class OpenOfficePool {

	  private GenericObjectPool<OpenOfficeConnection> pool;

	  public OpenOfficePool(OpenOfficeFactory factory) {
	        this.pool = new GenericObjectPool<>(factory, factory.getProperties().getPool());
	       /* GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
	        poolConfig.setMaxTotal(10);
	        poolConfig.setMinIdle(10);
	        poolConfig.setMaxIdle(10);
	        poolConfig.setMaxWaitMillis(10);
	        this.pool = new GenericObjectPool<OpenOfficeConnection>(factory,poolConfig);*/
	  }

	  /**
	   * 獲取一個OpenOfficeConnection連接對象
	   * @return OpenOfficeConnection連接對象
	 * @throws Exception 
	   */
	  public OpenOfficeConnection borrowObject() throws Exception {
	      try {
	            return pool.borrowObject();
	      } catch (Exception e) {
	            throw new Exception("獲取OpenOffice連接失敗", e);
	      }
	  }

    /**
     * 歸還一個OpenOffice連接對象
     * @param OpenOffice連接對象
     */
    public void returnObject(OpenOfficeConnection channelSftp) {
        if (channelSftp!=null) {
            pool.returnObject(channelSftp);
        }
    }
    
    /**
     * 銷燬池子
     */
    public  void destroy() {
        try {
        	pool.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
    }
}

4.3 nginx整合lua

4.3.1 下載 安裝
LuaJIT-2.0.5.tar.gz (下載地址:http://luajit.org/download.html)
lua-nginx-module-0.10.13.tar.gz (下載地址:https://github.com/openresty/lua-nginx-module/releases)

由於虛擬機上nginx是yum安裝的,只有二進制文件,所以下載統一版本nginx

tar-zxvf LuaJIT
tar-zxvf  lua-nginx-module
cd LuaJIT-2.0.4
make PREFIX=/usr/local/luajit
make install PREFIX=/usr/local/luajit

#設置環境變量

 export LUAJIT_LIB=/usr/local/luajit/lib
 export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
 export LD_LIBRARY_PATH=/usr/local/luajit/lib:$LD_LIBRARY_PATH

解壓nginx
make
make install

#查看之前的編譯參數

nginx -V

==示例
./configure --prefix=/etc/nginx
–add-module=/data/fastdfs-nginx-module/src
–add-module=/usr/local/src/lua/lua-nginx-module-0.10.15/
==示例
4.3.2 如果之前安裝過nginx,只需要在最後加上lua-nginx-module-0.10.15重新make即可

nginx -t 如果報錯
nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory
解決:
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/

4.3.3 如果docker重啓 環境變量失效的話:

vim /etc/ld.so.conf.d/libc.conf 

在這裏插入圖片描述
再次運行ldconfig即可

4.3.4 配置nginx 實現 訪問控制:

nginx配置

worker_processes  4;

error_log  /data/fast_data/logs/nginx-error.log debug;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /data/fast_data/logs/nginx-access.log  main;
    sendfile        on;
    keepalive_timeout  65;

    upstream imageserver {
	ip_hash;
	server 172.20.8.123:9101 weight=5;
	server 172.20.8.124:9101 weight=5;
    }

    server{
        listen    80;
		server_name 172.20.8.123;


	location @fastDFS {
	    charset utf-8;
	    proxy_pass http://imageserver;
	}

	location @error {
				default_type 'text/plain';
				content_by_lua '
					ngx.say("lua error");
				';
        }

	location /getTime {
       		default_type text/html;
	       	content_by_lua '
				ngx.say(ngx.time() * 1000);
    		';
	}

	location ~ /group1/M00 {
      	access_by_lua '
			local uri = ngx.var.uri;

			array = {"jpg","png","jpeg","gif"};

			for i,v in ipairs(array)do
				local e = string.find(uri,v);
				if(type(e) ~= "nil" and tonumber(e) > 0) then
				  ngx.exec("@fastDFS");
				  break;
				end
			end
			ngx.update_time();

			local args = ngx.req.get_uri_args();
			local ts  = args["ts"];
			local token1 = args["token"];

    		local getTime = ngx.time() * 1000;

			local diffTime = tonumber(ts) - getTime;

			local token2 = ngx.md5(tostring(uri) .. "salt" .. tostring(ts));

			if (tonumber(diffTime) > 0) then

				if token1 == token2 then

					ngx.exec("@fastDFS");
				end
			 end

 		';
	}
   }

    server {
        listen       9101;
        server_name  172.20.8.123;

        location ~/group1/M00 {
                    root /data/fast_data/data;
                    ngx_fastdfs_module;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

java配置

java代碼
public class NginxTest {
    @Test
    public void test() {
        // 獲取 Nginx 服務器上的系統時間
        String requestUrl = "http://192.168.229.165/getTime";
        long systemTime = Long.parseLong(getURLContent(requestUrl));
        System.out.println("Nginx 服務器上系統時間:" + systemTime);

        // 請求的資源路徑
        String requestResources = "/group1/M00/00/00/wKjlpltF-K-AZQQsAABhhboA1Kk469.png";
        String url = getUrl(requestResources, systemTime);
        System.out.println("請求的 url 爲:");
        System.out.println("192.168.229.165" + url);
    }

    /**
     * 獲取帶時間戳與 token 的 url
     * @param requestResources 請求的資源路徑,不包括 IP 地址與端口,開頭有 /,例如 /group1/M00/00/00/wKjlpltF-K-AZQQsAABhhboA1Kk469.png
     * @param systemTime 系統時間
     * @return 返回請求的 url 地址,包括有效期與 token
     */
    public static String getUrl(String requestResources, long systemTime) {
        // 添加有效期時間,假設該鏈接有效期爲 1 天,即 86400000
        // 計算毫秒時,切記轉換爲 Long 類型進行運算,避免超出 int 類型的範圍
        // 有效期,單位:毫秒
        // 自己測試時,爲了方便,可以設置爲 1 分鐘之類的
        long milliseconds = systemTime + 1L * 24 * 60 * 60 * 1000;
        // long milliseconds = systemTime + 60L * 1000;

        // 計算 token 信息
        // “鹽” 值,和 Nginx 服務器上的保持一致即可
        String salt = "salt";
        // 加密前的字符串:請求的資源路徑 + “鹽” 值 + 時間戳
        String beforeEncryptionString = requestResources + salt + milliseconds;
        // 這裏使用 Spring 提供的 md5 加密工具進行 md5 加密
        String token = DigestUtils.md5DigestAsHex(beforeEncryptionString.getBytes());
        String url = requestResources + "?ts=" + milliseconds + "&token=" + token;

        return url;
    }

    /**
     * 獲取請求 url 返回的文本
     * @param requestUrl 請求的 url
     * @return
     */
    public static String getURLContent(String requestUrl) {
        URL url = null;
        BufferedReader in = null;
        StringBuffer sb = new StringBuffer(); 

        try {
            url = new URL(requestUrl);     
            in = new BufferedReader(new InputStreamReader(url.openStream())); 
            String str = null;  
            while ((str = in.readLine()) != null) {
                sb.append(str);     
            } 
        } catch (Exception e) {
            e.printStackTrace();
        } finally{   
            // 關閉資源
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

發佈了17 篇原創文章 · 獲贊 41 · 訪問量 6277
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章