前言

最近刚刚实现的文件服务中心,记录一下,为没做过的人提供一下思路,由于本人技术有限,不足之处欢迎批评指正,共同学习,共同进步。

目录

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=falsegroup_name=group1bind_addr=client_bind=trueport=23002connect_timeout=30network_timeout=30heart_beat_interval=30stat_report_interval=60base_path=/data/fast_datamax_connections=256buff_size = 256KBaccept_threads=1work_threads=4disk_rw_separated = truedisk_reader_threads = 1disk_writer_threads = 1sync_wait_msec=50sync_interval=0sync_start_time=00:00sync_end_time=23:59write_mark_file_freq=500store_path_count=1store_path0=/data/fast_datasubdir_count_per_path=256tracker_server=198.168.1.121:22122tracker_server=198.168.1.122:22122log_level=debugrun_by_group=run_by_user=allow_hosts=*file_distribute_path_mode=0file_distribute_rotate_count=100fsync_after_written_bytes=0sync_log_buff_interval=10sync_binlog_buff_interval=10sync_stat_file_interval=300thread_stack_size=512KBupload_priority=10if_alias_prefix=check_file_duplicate=0file_signature_method=hashkey_namespace=FastDFSkeep_alive=0use_access_log = truerotate_access_log = falseaccess_log_rotate_time=00:00rotate_error_log = falseerror_log_rotate_time=00:00rotate_access_log_size = 0rotate_error_log_size = 0log_file_keep_days = 0file_sync_skip_invalid_record=falseuse_connection_pool = falseconnection_pool_max_idle_time = 3600http.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 addresstracker_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 {824772106@qq.com}notification_email_from sns-lvs@gmail.comsmtp_server smtp.hysec.comsmtp_connection_timeout 30router_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            # 优先级,数值越大,获取处理请求的优先级越高nopreemptadvert_int 1            # 检查间隔,默认为1s(vrrp组播周期秒数)authentication {auth_type PASSauth_pass 1111
}track_script {chk_http_port            #(调用检测脚本)}virtual_ipaddress {172.20.8.94            # 定义虚拟ip(VIP),可多设,每行一个}
}

2.4 backup配置

global_defs {notification_email {XXXXXXXX@qq.com}notification_email_from sns-lvs@gmail.comsmtp_server smtp.hysec.comsmtp_connection_timeout 30router_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 PASSauth_pass 1111
}
track_script {chk_http_port                   #(调用检测脚本)}virtual_ipaddress {172.20.8.94                   # 定义虚拟ip(VIP),可多设,每行一个}
}```
### 2.5 添加检查nginx状态的脚本#!/bin/bash#version 0.0.1A=`ps -C nginx --no-header | wc -l`if [ $A -eq 0 ];thensystemctl restart dockersleep 3if [ ps -C nginx --no-header |wc -l -eq 0 ];thensystemctl stop keepalivedfifi脚本说明:检查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 {@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Beanpublic 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());}@Overridepublic 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;}//创建连接@Overridepublic 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);}}@Overridepublic PooledObject<OpenOfficeConnection> wrap(OpenOfficeConnection openOfficeConnection) {return new DefaultPooledObject<>(openOfficeConnection);}//初始化连接  在此做一些链接初始化工作/*   @Overridepublic void activateObject(PooledObject<OpenOfficeConnection> pooledObject) throws Exception {OpenOfficeConnection ftpClient = pooledObject.getObject();}*/// 销毁对象@Overridepublic void destroyObject(PooledObject<OpenOfficeConnection> p) {OpenOfficeConnection connetion = p.getObject();connetion.disconnect();}//链接状态检查@Overridepublic 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/libexport LUAJIT_INC=/usr/local/luajit/include/luajit-2.0export 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)dolocal e = string.find(uri,v);if(type(e) ~= "nil" and tonumber(e) > 0) thenngx.exec("@fastDFS");break;endendngx.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) thenif token1 == token2 thenngx.exec("@fastDFS");endend';}}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 {@Testpublic 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();}
}

fastdfs+nginx+keepalived+openoffice+lua 实现文件上传、下载、水印、预览(word、excel、ppt、txt),feign文件上传相关推荐

  1. Vue 预览word,excel,ppt等office文档-内网访问(基于onlyoffice,后端返回文件流)

    Vue 预览word,excel等office 先看效果!! 需求背景:在前端页面中预览office文件且是内网访问,服务器不可访问外网的前提. 因此微软的接口就废掉了,因为他接口的条件是可以访问外网 ...

  2. struts上传word和excel文件到oracle,Struts文件上传,下载,重传,预览

    [Struts2]☆★之文件上传,下载,重传,预览 今日群里一兄弟问我能否给一份struts文件上传下载的例子,因为自己项目比较紧所以想在网上找 些源码给他,但是纵观全网,写的都不是太全,这让新手使用 ...

  3. php word excel转pdf文件怎么打开,php office文件(word/excel/ppt)转pdf文件,pptpdf

    php office文件(word/excel/ppt)转pdf文件,pptpdf 把代码放到了github上,点击进入 前阶段有个项目用到了线上预览功能, 关于预览office文件实现核心就是,把o ...

  4. Word,Excel,PPT等Office文件Web浏览器在线预览

    博主联系方式   https://fizzz.blog.csdn.net/article/details/113049879 前两天接到一个需求:需要在线预览用户上传的Word,Excel,PPT文档 ...

  5. vue预览word,excel,pptx,pdf文件

    vue预览word,excel,pptx,pdf文件 1.做word,excel,pptx的预览,要先确定文件路径访问是通过域名的url来预览,不可以通过IP的url来访问 先把文件路径的url进行u ...

  6. h5页面如何预览excel文件_移动端页面,如何解析预览 word/excel/PDF文件?

    展开全部 利用Office2007以上版本的一个PDF插件SaveAsPDFandXPS.exe可以导出PDF文件,然后再利用免费的swftools.exe工具生成swf格式的Flash文件,网页中加 ...

  7. office2016安装后新建图标(word\excel\ppt)等文件图标均显示白色

    虽然激活的2016打开也可以输入文件,但是图标看着很不舒服! 找了找 Excel文件不显示图标的第一种方式:图标未知 如下面的截图,一个Excel文档,在桌面上预览,可以看到excel文件不显示图标. ...

  8. 小程序下载、预览word,pdf文件

    onLoad: function(res){var url = '文件地址';wx.downloadFile({ //下载url: url,success: function(e){const fil ...

  9. 前端-vue-文件上传(图片、word,ppt,pdf,excel,txt等文件流)

    1. 文件上传(图片.word,ppt,pdf,excel,txt等文件流) 总结一下上传组件的思路 input标签的@change事件 通过input标签的@change事件的绑定,进行文件的选择上 ...

最新文章

  1. DrawText函数
  2. spring,springmvc,mybatis基本整合(一)--xml文件配置方式(1)
  3. Oracle11g 修改数据库编码(UTF-8修改为GBK)
  4. pymysql的安装
  5. 牛客网剑指offer编程实践51-66题
  6. jQuery.sap.getModulePath(cus.crm.opportunity.css.Opportunity, .css)
  7. python基础教程(十一)
  8. openfire+elipse的导入配置
  9. java用cookie最新浏览商品_jQuery.cookie.js实现记录最近浏览过的商品功能示例
  10. 印花材料使用过程中的三个常见问题及解决方案
  11. primefaces教程_PrimeFaces教程
  12. java wait() notify_Java的wait(), notify()和notifyAll()使用小结
  13. 大龄程序员的成长之路
  14. 【Unity入门计划】Unity2D动画(2)-脚本与混合树实现玩家角色动画过渡
  15. 图形学中4x4矩阵的理解
  16. Occupancy Flow: 4D Reconstruction by Learning Particle Dynamics(1)
  17. Word目录制作,添加目录自动跳转
  18. diy nas配置推荐2019_打造家用NAS之一(2019年版)
  19. [JMeter]java.net.URISyntaxException: Malformed escape pair at index 83
  20. 搭建Redis服务器: 设置变量school,值为tarena 查看变量school的值

热门文章

  1. Plotly:最强Python可视化库,没有之一
  2. 来自北大算法课的Leetcode题解:696. 计算二进制子串
  3. 多商品评价页面对用户评价信息的处理
  4. 小啊呜产品读书笔记001:《邱岳的产品手记-13》第24讲 产品案例分析:PathSource的混乱与直观 25讲 产品世界的暗黑模式:操纵的诱惑
  5. 一文了解 Go time 包的时间常用操作
  6. Golang-beego安装
  7. Theta*: 连续环境下平滑的任意角度的路径规划
  8. 「Adobe国际认证」6 种配色方案,让一切设计都能完美无瑕?
  9. NO.007-2018.02.12《白头吟》两汉:卓文君
  10. ABI 与 API 的区别