CentOS7設置靜態IP、搭建單機版FastDFS圖片服務器、使用FastDFS-Client客戶端進行簡單測試、實現圖片上傳、實現商品添加修改刪除

CentOS7設置靜態IP、搭建單機版FastDFS圖片服務器、使用FastDFS-Client客戶端進行簡單測試、實現圖片上傳、實現商品添加修改刪除

CentOS7設置靜態IP而且還可以上網

192.168.173.148
但是用mac的終端遠程連接到CentOS的時候,由於家裏和學校IP不同,虛擬機的IP也會變化,每次還要重新查看,並且之後配置集羣什麼的也會出現問題,所以需要CentOS設置爲固定IP。如果虛擬機使用橋接的方式,那麼很多與ip相關的服務都會出現問題,所以我們希望使用nat模式,爲了防止再次啓動系統的時候網絡IP發生變化,因此設置靜態IP和DNS。

網上查閱了一番資料之後,發現這個問題在windows下很好解決,因爲vmware workstation中有虛擬網絡編輯器,可以直接把VMnet8,也就是NAT模式的DHCP關掉並設置子網IP。但vmware fusion不行,需要其他操作。

1.把網絡配置nat模式

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.在mac終端到這個目錄下

cd /Library/Preferences/VMware\ Fusion/vmnet8
cat nat.conf
在這裏插入圖片描述
這裏的ip就是虛擬機的網關地址,netmask就是子網掩碼

cat dhcpd.conf
在這裏插入圖片描述
range就是靜態ip的範圍,是虛擬機可分配的地址範圍
netmask 255.255.255.0是子網掩碼
option broadcast-address 192.168.173.255;是廣播地址
option routers 192.168.173.2是網關

獲取DNS(在mac系統偏好設置—>網絡—>)

在這裏插入圖片描述
在這裏插入圖片描述
fe8O::262e:2ff:fe3e:72ad

3.設置虛擬機固定ip

cd /etc/sysconfig/network-scripts
vi ifcfg-ens33

進去後輸入’i’,進入編輯模式,增加IPADDR,NETMASK,GATEWAY,HWADDR,DNS等信息,ONBOOT=no改爲‘yes’。

dhcp
BOOTPROTO=“static”
ONBOOT=“yes”

IPADDR=192.168.173.148
GATEWAY=192.168.173.2
NETMASK=255.255.250.0
DNS1=192.168.3.1注:DNS要和mac的DNS保持一致
DNS2=fe8O::262e:2ff:fe3e:72ad

#後面的這些可以選擇性添加
PREFIX=24
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_PRIVACY=no

4.重啓網卡

service network restart

ping baidu.com 試試

在這裏插入圖片描述

pin

接下來我們就可以通過SecureCRT等工具遠程連接了,有一點請記住,如果你換了一個地方上網的話,可能會發現你的虛擬機有不通了,那是因爲DNS地址發生了變化,此時只需要再次編輯ifcfg-enxxx文件,然後加上你現在網絡的DNS地址即可

如:
DNS1=192.168.0.1
DNS2=114.114.114.114

在這裏插入圖片描述

又弄了一次終於設置成功了!
在這裏插入圖片描述

給Mac上的Fusion虛擬主機設置固定的IP地址2

因爲最近需要安裝k8s的本地測試環境,所以使用Mac上的Vmware Fusion安裝了幾臺ubuntu系統的虛擬機,某次重啓的時候發現ssh登錄不上去了,打開虛擬機看了一下,發現是ip地址發生了變化,研究了半天,找到了解決的方法如下:

在Mac的Terminal上編輯下面這個文件:

sudo vi /Library/Preferences/VMware\ Fusion/vmnet8/dhcpd.conf

最後一行是下面的內容:

####### VMNET DHCP Configuration. End of “DO NOT MODIFY SECTION” #######

在這行的下面,添加虛擬機的ip信息如下:

host host1 {
hardware ethernet 00:0c:29:dd:a5:67;
fixed-address 192.168.32.131;
}

其中:

host1是在Vmware Fusion中看到的虛擬機列表裏的名稱;
00:0c:29:dd:a5:67是這臺虛擬機的網卡MAC地址,進入虛擬機的terminal裏執行ifconfig就可以找到

192.168.32.131是你要設置的固定ip的地址。

如果有多個虛擬主機,順序填寫就可以了。

設置好之後,執行下面的刷新操作:

sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --configure

然後,重新啓動你的Mac,就可以生效了。

在這裏插入圖片描述

00:0C:29:8C:9F:AA

在這裏插入圖片描述

CentOS-7-x86_64-DVD-1810

host CentOS-7-x86_64-DVD-1810 {
hareware ethernet 00:0C:29:8C:9F:AA;
fixed-address 192.168.173.131
}

搭建單機版FastDFS圖片服務器

一、背景描述
之前公司的圖片服務器已經不能勝任了(直接使用tomcat),需要重新搭建圖片服務器,這兩天研究了下FastDFS,感覺挺好用記錄下來以供日後參考。

二、FastDFS官方介紹
FastDFS是一款類Google FS的開源分佈式文件系統,它用純C語言實現,支持Linux、FreeBSD、AIX等UNIX系統。它只能通過 專有API對文件進行存取訪問,不支持POSIX接口方式,不能mount使用。準確地講,Google FS以及FastDFS、mogileFS、 HDFS、TFS等類Google FS都不是系統級的分佈式文件系統,而是應用級的分佈式文件存儲服務。

FastDFS架構圖
1)Tracker cluster中各個tracker server相互獨立,不進行相互通信。
2)Storage cluster中各個storage組(Volume1,Volume2…)相互獨立,不進行相互通信,也就是說各個組之間保存的數據是不相同的。但是各個組中的storage server之間是屬於互相備份的關係,也就是說storage server之間保存相同的數據。
3)每個storage server會啓動一個單獨的線程主動向Tracker cluster中每個tracker server報告其狀態信息,包括磁盤使用情況,文件同步情況及文件上傳下載次數統計等信息。

文件上傳和下載的時序圖
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組中某個Storage server上的某個文件(文件名包括Storage組名稱)。
2)Tracker server向Client返回一臺可用的Storage server的IP地址和端口號。
3)Client直接通過Tracker server返回的IP地址和端口與其中一臺Storage server建立連接並進行文件下載。

1、運行環境及相關軟件

CentOS 7
FastDFS_v5.05.tar.gz
nginx-1.7.8.tar.gz
fastdfs-nginx-module_v1.16.tar.gz
libfastcommonV1.0.7.tar.gz

解壓後:
FastDFS
nginx-1.7.8
fastdfs-nginx-module
libfastcommon-1.0.7
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.安裝libfastcommon

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

3.FastDFS主程序設置的目錄爲/usr/lib

把/usr/lib64/libfastcommon.so文件向/usr/lib/下複製一份
在這裏插入圖片描述
或者!!!先把上面/usr/lib下面複製的這個文件刪除掉!再進行下列操作

創建軟鏈接
FastDFS主程序設置的目錄爲/usr/local/lib/,所以我們需要創建/ usr/lib64/下的一些核心執行程序的軟連接文件。如下所示。
在這裏插入圖片描述

4.安裝FastDFS

./make.sh
在這裏插入圖片描述
./make.sh install
在這裏插入圖片描述

安裝完後,服務腳本位置如下:cd /etc/init.d/ && ls | grep fdfs
在這裏插入圖片描述

配置文件位置如下:cd /etc/fdfs/
在這裏插入圖片描述
在這裏插入圖片描述

FastDFS一系列執行腳本如下,可以看到有上傳文件腳本、下載文件腳本等等:cd /usr/bin/ && ls | grep fdfs

在這裏插入圖片描述

【另一個版本,還做了複製到/etc/fdfs
安裝後在/usr/bin/目錄下有以fdfs開頭的文件都是編譯出來的。
配置文件都放到/etc/fdfs文件夾
在這裏插入圖片描述
把FastDFS conf目錄下的配置文件都複製到/etc/fdfs下
在這裏插入圖片描述

5.因爲FastDFS服務腳本設置的bin目錄爲/usr/local/bin/下,但是實際我們安裝在了/usr/bin/下面。所以我們需要修改FastDFS配置文件中的路徑,也就是需要修改兩個配置文件

使用命令vim /etc/init.d/fdfs_storaged進入編輯模式,然後直接輸入":",光標會定位到最後一行,在":“後輸入”%s+/usr/local/bin+/usr/bin",如下圖所示。輸入完之後回車,會提示修改了7處。爲了確保所有的/usr/local/bin都被替換了,我們可以再打開文件確認一下。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

接着修改第二個配置文件,我們使用命令vim /etc/init.d/fdfs_trackerd進入編輯模式,接着按照上面那樣輸入":%s+/usr/local/bin+/usr/bin "並按回車,同樣會提醒我們修改了7處。

6.配置跟蹤器

1、進入到/etc/fdfs目錄並且複製一份tracker.conf.sample並命名爲tracker.conf,如下所示。【上述另外一個版本進行復制了,所以這裏省略這一步】

2、配置tracker服務,修改/etc/fdfs/tracker.conf文件

此路徑爲儲存文件的路徑.自己設置,修改
在這裏插入圖片描述
在這裏插入圖片描述

3、我們在上圖配置文件中配置的/fastdfs/tracker目前是不存在的,因此我們需要創建一下該目錄

在這裏插入圖片描述

4、配置防火牆,放開tracker使用的端口22122,使用命令vim /etc/sysconfig/iptables進入編輯模式,添加一行內容-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT,如下圖所示。

在這裏插入圖片描述

5、重啓防火牆

[root@fastdfs fdfs]# service iptables restart
iptables:將鏈設置爲政策 ACCEPT:filter [確定]
iptables:清除防火牆規則: [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火牆規則: [確定]
[root@fastdfs fdfs]#

這裏的四五兩步在centos7中和以上有所不同

6、在啓動tracker之前,/fastdfs/tracker目錄下是沒有任何文件的,如下所示

在這裏插入圖片描述
啓動tracker,啓動完之後,可以看到這個目錄下多了兩個目錄data和logs。如下所示。

在這裏插入圖片描述

【另一個版本啓動時說是找不到文件
啓動tracker
在這裏插入圖片描述

7、設置開機自啓動,在rc.local文件中添加/etc/init.d/fdfs_trackerd start,如下所示。

在這裏插入圖片描述
在這裏插入圖片描述

7.配置FastDFS存儲

1、進入/etc/fdfs目錄,複製一份storage.conf.sample文件並命名爲storage.conf,如下所示。

這一步可以省略,因爲在執行另一個版本時我已經進行了拷貝

2、修改storage.conf文件 ,我們使用命令vim /etc/fdfs/storage.conf進入編輯模式,對以下四項進行修改,192.168.156.13是我的虛擬機的IP,大家根據自己虛擬機的IP自行設置。

base_path=/fastdfs/storage
store_path0=/fastdfs/storage
tracker_server=192.168.156.13:22122
http.server_port=8888

路徑爲/usr/local/fastdfs/storage

3、創建存儲目錄,如下所示。

在這裏插入圖片描述

4、配置防火牆,允許外界訪問storage的默認端口23000,如下所示。

[root@fastdfs fdfs]# vim /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
   添加完之後,重啓防火牆,如下所示。
[root@fastdfs fdfs]# service iptables restart
iptables:將鏈設置爲政策 ACCEPT:filter [確定]
iptables:清除防火牆規則: [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火牆規則: [確定]
[root@fastdfs fdfs]#

5、在啓動storage之前,/fastdbf/storage目錄下是沒有任何文件的

啓動storage,啓動後再看/fastdfs/storage目錄,可以看到多了data和logs。
在這裏插入圖片描述

6、查看FastDFS tracker和storage 是否啓動成功,當看到如下所示信息時說明都啓動成功了。

在這裏插入圖片描述

7、我們進入到 /fastdfs/storage/data/目錄下,可以看到兩級共256*256個目錄,每級都是從00到FF,如下只是列出了第一級的目錄,點進去每個目錄都還有00到FF共256個目錄。

在這裏插入圖片描述

8、設置storage開機自啓動,添加一行/etc/init.d/fdfs_storaged start,如下所示。

在這裏插入圖片描述

8.測試圖片上傳

1、進入到/etc/fdfs目錄下並複製一份client.conf.sample並更名爲client.conf,如下所示。

這步可以省略,因爲另一個版本中進行了拷貝

2、使用命令vim /etc/fdfs/client.conf進入編輯模式並修改如下兩項內容,如下所示。

base_path=/fastdfs/tracker
tracker_server=192.168.156.13:22122

3、我們找到命令的腳本位置,並且使用命令,進行文件的上傳。

下面使用fdfs_upload_file腳本進行文件上傳操作,如下所示。可以看到已經上傳成功了,返回的是圖片的保存位置:group1/M00/00/00/wKicDVjr_ayAE4VVAAHk-VzqZ6w020.jpg在這裏插入圖片描述
group1/M00/00/00/wKit1F1jS0uAUVZ-AAOLZ96tasM153.png

9.FastDFS與nginx相結合

注:FastDFS通過Tracker服務器,將文件放在Storage服務器存儲,但是同組存儲服務器之間需要進入文件複製,有同步延遲的問題。假設Tracker服務器將文件上傳到了192.168.4.125,上傳成功後文件ID已經返回給客戶端。此時FastDFS存儲集羣機制會將這個文件同步到同組存儲192.168.4.126,在文件還沒有複製完成的情況下,客戶端如果用這個文件ID在192.168.4.126上取文件,就會出現文件無法訪問的錯誤。而fastdfs-nginx-module可以重定向文件連接到源服務器取文件,避免客戶端由於複製延遲導致的文件無法訪問錯誤。

1、先安裝nginx,大家可以參考http://blog.csdn.net/u012453843/article/details/69396434這篇博客的第四步Nginx安裝

一、Nginx概念
Nginx是一款輕量級的Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器,並在一個BSD-like 協議下發行。由俄羅斯的程序設計師Igor Sysoev所開發,供俄國大型的入口網站及搜索引擎Rambler(俄文:Рамблер)使用。其特點是佔有內存少,併發能力強,事實上nginx的併發能力確實在同類型的網頁服務器中表現較好,中國大陸使用nginx網站用戶有:百度、京東、新浪、網易、騰訊、淘寶等。
二、負載均衡策略
1、使用硬件複雜均衡策略實現,如使用F5、Array等負載均衡器
2、使用軟件進行負載均衡
2.1 使用阿里雲服務器均衡負載SLB
2.2 使用Nginx+Keepalived
2.3 其它軟件負載均衡如LVS(Linux Virtual Server)、haproxy等技術。
三、Nginx的優點
1、Nginx 可以在大多數 UnixLinux OS 上編譯運行,並有 Windows 移植版。 Nginx 的1.4.0穩定版已經於2013年4月24日發佈,一般情況下,對於新建站點,建議使用最新穩定版作爲生產版本,已有站點的升級急迫性不高。Nginx 的源代碼使用 2-clause BSD-like license。
2、Nginx 是一個很強大的高性能Web和反向代理服務器,它具有很多非常優越的特性:
在連接高併發的情況下,Nginx是Apache服務器不錯的替代品:Nginx在美國是做虛擬主機生意的老闆們經常選擇的軟件平臺之一。能夠支持高達 50,000 個併發連接數的響應,感謝Nginx爲我們選擇了 epoll and kqueue作爲開發模型。
四、Nginx安裝
如果大家是剛新建的虛擬機並且最小化安裝的話,需要先配置靜態IP並且要能上網,大家可以參考:http://blog.csdn.net/u012453843/article/details/52839105這篇博客進行學習,編輯文章用vi即可。配置好靜態IP並且能上網之後需要先安裝wget、vim和gcc。
yum install wget
yum install vim-enhanced
yum install make cmake gcc gcc-c++

1、下載nginx安裝包
[root@nginx1 ~]# wget http://nginx.org/download/nginx-1.6.2.tar.gz
–2017-04-07 01:44:55-- http://nginx.org/download/nginx-1.6.2.tar.gz
正在解析主機 nginx.org… 206.251.255.63, 95.211.80.227, 2606:7100:1:69::3f, …
正在連接 nginx.org|206.251.255.63|:80… 已連接。
已發出 HTTP 請求,正在等待迴應… 200 OK
長度:804164 (785K) [application/octet-stream]
正在保存至: “nginx-1.6.2.tar.gz”
在這裏插入圖片描述
2、安裝依賴,其中pcre(perl compatible regular expressions)是一個pert庫,包括perl兼容的正則表達式庫。nginx的http模塊使用pcre來解析正則表達式,所以需要在linux上安裝pcre庫。pcre-devel是使用pcre開發的一個二次庫,nginx也需要此庫。zlib庫提供了很多種壓縮的方式,nginx使用zlib對http包的內容進行gzip,所以需要在linux上安裝zlib庫。openssl是一個強大的安全套接字層密碼庫,囊括主要的密碼算法、常用的祕鑰和證書封裝管理功能及SSL協議,並提供豐富的應用程序提供測試或其它目的的使用。nginx不僅支持http協議,還支持https(即在ssl協議上傳輸http),所以需要在linux安裝openssl庫。

yum install -y pcre pcre-devel
在這裏插入圖片描述
yum install -y zlib zlib-devel
在這裏插入圖片描述
yum install -y openssl openssl-devel
在這裏插入圖片描述
3、解壓nginx-1.6.2.tar.gz到/usr/local/目錄下
[root@nginx1 ~]# tar -zxvf nginx-1.6.2.tar.gz -C /usr/local/
在這裏插入圖片描述
4、進入到/usr/local目錄下,可以看到我們解壓後的nginx-1.6.2文件夾了,然後我們進行configure配置,命令:cd nginx-1.6.2 && ./configure --prefix=/usr/local/nginx。可以看出,這條命令是組合命令,先進入nginx-1.6.2目錄然後在執行./configure命令。如下圖所示。

5、編譯安裝
[root@nginx1 nginx-1.6.2]# make && make install

6、啓動Nginx,啓動完之後檢查nginx是否已經正常啓動,看到如下信息說明正常啓動。
[root@nginx1 nginx-1.6.2]# /usr/local/nginx/sbin/nginx
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
突然想起來,tomcat服務器配置的就是80端口。

[root@nginx1 nginx-1.6.2]# ps -ef | grep nginx
root 3640 1 0 04:40 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody 3641 3640 0 04:40 ? 00:00:00 nginx: worker process
root 3643 1368 0 04:40 pts/0 00:00:00 grep nginx
[root@nginx1 nginx-1.6.2]#
如果要關閉nginx,我們可以使用如下命令:
[root@nginx1 nginx-1.6.2]# /usr/local/nginx/sbin/nginx -s stop
如果想要重新熱啓動nginx,則使用如下命令:
[root@nginx1 nginx-1.6.2]# /usr/local/nginx/sbin/nginx -s reload

配置nginx,如下所示:
在這裏插入圖片描述
說明:
a、"user root"是解決下載操作時報404的問題
b、8888端口號與/etc/fdfs/storage.conf中的http.server_port=8888相對應
c、storage對應有多個group的情況下,訪問路徑帶group名稱,例如:/group1/M00/00/00/**,對應nginx配置:
location ~/group[0-9]/ {
ngx_fastdfs_module;
}
在這裏插入圖片描述
然後再啓動
在這裏插入圖片描述
在這裏插入圖片描述

7、nginx默認的端口是80,我們需要在防火牆配置中添加80端口:"-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT"從而可以讓外界訪問80端口,否則防火牆將禁止外界訪問80端口。如下所示。
[root@nginx1 nginx-1.6.2]# vim /etc/sysconfig/iptables

#Firewall configuration written by system-config-firewall
#Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
添加完80端口之後,我們重啓防火牆,如下所示。
[root@nginx1 nginx-1.6.2]# service iptables restart
iptables:將鏈設置爲政策 ACCEPT:filter [確定]
iptables:清除防火牆規則: [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火牆規則: [確定]

8、通過瀏覽器訪問nginx歡迎頁,我們在地址欄輸入:http://192.168.156.11/(80端口不用輸也可以)或http://192.168.156.11:80/,如下圖所示。

2、安裝fastdfs-nginxmodule_v1.16.tar.gz(fast與nginx相結合的模塊安裝包)

看到解壓的fastdfs-nginx-module目錄,然後進入到fastdfs-nginx-module/src/目錄下,可以看到config文件。
在這裏插入圖片描述

3、修改該conf文件,我們把文件的第四行配置中的/usr/local/include都改爲/usr/include,共兩處。

在這裏插入圖片描述

4、fastdfs與nginx進行結合,由於我們剛纔安裝過nginx了,因此在/usr/local目錄下已經生成了一個nginx目錄了,如下圖所示。

爲了將nginx與fastdfs相結合,我們先把這個nginx目錄刪除掉,如下圖所示,可以看到已經沒有nginx目錄了。
進入到nginx-1.6.2/目錄下並執行配置和編譯安裝,如下所示。
在這裏插入圖片描述
[root@fastdfs local]# cd nginx-1.6.2/
[root@fastdfs nginx-1.6.2]# ./configure --add-module=/usr/local/fast/fastdfs-nginx-module/src/
[root@fastdfs nginx-1.6.2]# make && make install

複製fastdfs-nginx-module中的配置文件,到/etc/fdfs目錄中,如下所示。
[root@fastdfs fdfs]# cd /usr/local/fast/fastdfs-nginx-module/src/
[root@fastdfs src]# cp /usr/local/fast/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/
在這裏插入圖片描述
我們到 /etc/fdfs/ 目錄下,修改我們剛copy過來的mod_fastdfs.conf 文件,需要修改的項如下,其中第一項是超時時長,第三項是允許外界通過http方式訪問資源。
connect_timeout=10
tracker_server=192.168.156.13:22122
url_have_group_name = true
store_path0=/fastdfs/storage

在這裏插入圖片描述

複製FastDFS裏的2個文件,到/etc/fdfs目錄中,如下所示。

[root@fastdfs fdfs]# cd /usr/local/fast/FastDFS/conf/
[root@fastdfs conf]# ll
總用量 84
-rw-r--r--. 1 8980 users 23981 12月 2 2014 anti-steal.jpg
-rw-r--r--. 1 8980 users 1461 12月 2 2014 client.conf
-rw-r--r--. 1 8980 users 858 12月 2 2014 http.conf
-rw-r--r--. 1 8980 users 31172 12月 2 2014 mime.types
-rw-r--r--. 1 8980 users 7829 12月 2 2014 storage.conf
-rw-r--r--. 1 8980 users 105 12月 2 2014 storage_ids.conf
-rw-r--r--. 1 8980 users 7102 12月 2 2014 tracker.conf
[root@fastdfs conf]# cp http.conf mime.types /etc/fdfs/
[root@fastdfs conf]#

在這裏插入圖片描述

  創建一個軟連接,在/fastdfs/storage文件存儲目錄下創建軟連接,將其鏈接到實際存放數據 的目錄,如下所示。
  [root@fastdfs conf]# ln -s /fastdfs/storage/data/ /fastdfs/storage/data/M00

在這裏插入圖片描述
進入到/usr/local/nginx/conf/目錄下,修改nginx.conf文件,如下圖所示。
在這裏插入圖片描述
修改的內容如下圖示
在這裏插入圖片描述
listen 8888;
location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}

在這裏插入圖片描述

設置nginx開機自啓動,這樣下次重啓設備之後,tracker、storage、nginx都自動啓動了,直接就可以使用服務,如下所示。

 [root@fastdfs ~]# vim /etc/rc.d/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
/etc/init.d/fdfs_trackerd start
/etc/init.d/fdfs_storaged start
/usr/local/nginx/sbin/nginx

在這裏插入圖片描述
啓動nginx,如下所示。
在這裏插入圖片描述
在這裏插入圖片描述
這是因爲之前安裝單獨的nginx的時候設置了8888端口號
殺掉這個進程,重新啓動
在這裏插入圖片描述

5、在通過8888端口訪問圖片之前先配置下防火牆,允許外界訪問8888端口,添加的一行是-A INPUT -m state --state NEW -m tcp -p tcp --dport 8888 -j ACCEPT,如下圖所示。

在這裏插入圖片描述
配置完防火牆後重啓防火牆

[root@fastdfs conf]# service iptables restart
iptables:將鏈設置爲政策 ACCEPT:filter [確定]
iptables:清除防火牆規則: [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火牆規則: [確定]
[root@fastdfs conf]#

6、現在我們便可以通過http的方式訪問我們剛纔上傳的圖片了(我們剛纔上傳圖片返回的地址是group1/M00/00/00/wKicDVjr_ayAE4VVAAHk-VzqZ6w020.jpg),如下圖所示。

group1/M00/00/00/wKit1F1jS0uAUVZ-AAOLZ96tasM153.png
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
http://192.168.173.148:8888/group1/M00/00/00/wKitlF1jS0uAUVZ-AAOLZ96tasM153.png
至此,一個單機版的FastDFS便搭建完畢了!!

使用FastDFS-Client客戶端進行簡單測試

第一件事:由於中央倉庫並沒有fastdfs-client的包,因此需要我們自己整,大家可以參考:http://blog.csdn.net/u012453843/article/details/70135826這篇博客學習怎樣使用Eclipse從Github官網下載fastdfs-client源碼並轉化爲maven工程以及如何打包到本地maven倉庫。

FastDFS Client目前在中央倉庫是沒有座標的
1,首先去我的github上下載下來fastdfs的壓縮包
直接下載地址:https://github.com/wangwei216/fastdfs-client-java-master
然後直接解壓出來

2,使用cmd命令行 使用cd命令走到到你自己下載到的目錄下,然後使用mvn clean install 直接打包到本地的maven倉庫(注意:本機必須安裝Maven,並配置Maven環境變量,並且盤符要切換到fastdfs-client-java解壓的目錄下)
在這裏插入圖片描述
當上述操作完成時,我們會看到Maven本地倉庫有了fastdfs-client-java-1.27-SNAPSHOT.jar。
此時我們就可以在我們需要的項目中添加對它的依賴,就可以使用fastdfs-client-java此開發工具包。
FastDFS有兩個角色:跟蹤服務器和存儲服務器。跟蹤服務器負責文件訪問的調度和負載均衡,存儲文件服務器負責文件的存儲、文件同步、提供文件訪問接口,管理元數據(文件相關屬性,鍵值對方式),例如:width = 1024,鍵爲“width”,值爲“1024”。
在這裏插入圖片描述
在這裏插入圖片描述

3,然後添加到pom.xml文件中就不會報錯了


org.csource
fastdfs-client-java
1.27-SNAPSHOT

寫的不錯比較細緻,但是有一點需要注意一下,在生成JAR包的時候,要看下fastdfs-client-java項目中pom文件的版本,我使用的時候,並不是1.25而是1.27-SNAPSHOT,這個很重要

總結:
這種方式不僅適用於fastdfs的打包到本地的方法,而且還可以運用到所有中央倉庫中沒有jar包的方法,只要是中央倉庫中沒有的,都可以適用這中方式
例如dubbo的jar包也可以適用這種,先把需要的jar包下載下來,然後使用cmd命令到本地文件,然後安裝到本地maven倉庫

第二件事:在taotao-manager-web工程的resources目錄下新建一個resource文件夾並在它下面創建client.conf文件,client.conf文件中輸入tracker所在的設備的IP及端口,由於我的tracker是在192.168.156.13上,因此我這裏寫的是"tracker_server=192.168.156.13:22122",如下圖所示。
在這裏插入圖片描述
下面我們新建一個測試類來進行測試,我們在src/test/java目錄下新建一個包com.taotao.fastdfs,在該包下新建一個測試類TestFastDFS.java,如下圖所示。
在這裏插入圖片描述
爲方便複製,現把測試類代碼粘貼如下:

package com.taotao.fastdfs;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.junit.Test;

public class TestFastDFS {
   
	@Test
	public void testUploadFile() throws Exception{
		//1.向工程添加jar包
		//2.創建一個配置文件,配置tracker服務器地址
		//3.加載配置文件
		ClientGlobal.init("E:/workspace/taotao-manager-web/src/main/resources/resource/client.conf");
		//4.創建一個TrackerClient對象
		TrackerClient trackerClient = new TrackerClient();
		//5.使用TrackerClient對象獲得trackerserver對象。
		TrackerServer trackerServer = trackerClient.getConnection();
		//6.創建一個StorageServer的引用,我們用null就可以
		StorageServer storageServer = null;
		//7.創建一個StorageClient對象。trackerserver、StorageServer兩個參數
		StorageClient storageClient = new StorageClient(trackerServer, storageServer);
		//8.使用StorageClient對象上傳文件
		NameValuePair[] metaList = new NameValuePair[3];
		metaList[0] = new NameValuePair("fileName", "2");
		metaList[1] = new NameValuePair("createTime", "2017-04-13 16:01:00");
		metaList[2] = new NameValuePair("createUser", "zhangsan");
		String[] upload_files = storageClient.upload_file("E:/images/2.jpg", "jpg", metaList);
		for(String file : upload_files){
			System.out.println(file);
		}
	}
}

上面的代碼有三點需要注意:

第一、taotao-manager-web工程還未添加junit的依賴,因此需要在pom.xml文件中添加junit的依賴,如下所示,這裏之所以不用寫版本是因爲在taotao-parent工程中已經統一定義好版本了。

junit junit

第二、NameValuePair是給圖片添加附加信息的,包括圖片原文件名、大小、作者等等,導包時會發現有多個選項,我們選擇"import org.csource.common.NameValuePair"

第三、我們在複製粘貼win10系統的本地文件絕對路徑(E:/images/2.jpg)時,Eclipse是識別不了的,運行會報如下錯誤。解決方法是手動輸入,而且要注意把包括雙引號在內的這個路徑串刪除(“E:/images/2.jpg”),然後手動輸入一遍。

注意上面三點後,我們再執行這個測試方法便成功了,如下圖所示。回顯信息的第一行是該圖片被保存到哪個組了,由於我們現在只是用的單機FastDFS服務器,因此現在都是group1。第二行是存放的具體位置。
在這裏插入圖片描述
在這裏插入圖片描述
group1
M00/00/00/wKitlF1lD_OAci8OAAHApE3lJzA14.jpeg

帶有附加信息的圖片上傳後,會生成一個以"-m"結尾的文件,如下圖所示。這個文件中保存了我們附加的圖片信息。
在這裏插入圖片描述
在這裏插入圖片描述

既然上傳上去了,現在我們試着用http的方式來訪問下該圖片,我們需要把group1和M00/00/00/wKicDVjvjkqAISg-AAGDL8Ay0xY563.jpg拼接到一塊來訪問。端口8888是我在Nginx配置的對外暴露的訪問接口。這樣我們便可以查看到我們剛纔上傳的照片了,如下圖所示。
在這裏插入圖片描述
在這裏插入圖片描述

經過上面的操作,說明我們搭建的圖片服務器沒問題,但有個問題是,上傳操作步驟繁瑣,因此我們迫切需要對其進行封裝,現在我把封裝好的類FastDFSClient.java文件的內容粘貼如下。

構造方法中的conf = conf.replace(“classpath:”, this.getClass().getResource("/").getPath());這句話的意思是,如果用戶傳入的文件路徑是相對路徑(相對路徑 以resources目錄爲根目錄,比如用戶傳入的文件路徑是"classpath:applications.properties",那麼需要轉爲絕對路徑,因此需要把"classpath:"給替換掉,改爲E:/workspace/taotao-manager-web/src/main/resources)。

封裝類中使用的Storage客戶端是StorageClient1而不是StorageClient,這個客戶端的好處是能夠幫我們自動把文件所在的組以及存放位置拼接到一塊。

package cn.itcast.fastdfs.cliennt;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;

public class FastDFSClient {

	private TrackerClient trackerClient = null;
	private TrackerServer trackerServer = null;
	private StorageServer storageServer = null;
	private StorageClient1 storageClient = null;
	
	public FastDFSClient(String conf) throws Exception {
		if (conf.contains("classpath:")) {
			conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
		}
		ClientGlobal.init(conf);
		trackerClient = new TrackerClient();
		trackerServer = trackerClient.getConnection();
		storageServer = null;
		storageClient = new StorageClient1(trackerServer, storageServer);
	}
	
	/**
	 * 上傳文件方法
	 * <p>Title: uploadFile</p>
	 * <p>Description: </p>
	 * @param fileName 文件全路徑
	 * @param extName 文件擴展名,不包含(.)
	 * @param metas 文件擴展信息
	 * @return
	 * @throws Exception
	 */
	public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
		String result = storageClient.upload_file1(fileName, extName, metas);
		return result;
	}
	
	public String uploadFile(String fileName) throws Exception {
		return uploadFile(fileName, null, null);
	}
	
	public String uploadFile(String fileName, String extName) throws Exception {
		return uploadFile(fileName, extName, null);
	}
	
	/**
	 * 上傳文件方法
	 * <p>Title: uploadFile</p>
	 * <p>Description: </p>
	 * @param fileContent 文件的內容,字節數組
	 * @param extName 文件擴展名
	 * @param metas 文件擴展信息
	 * @return
	 * @throws Exception
	 */
	public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {
		
		String result = storageClient.upload_file1(fileContent, extName, metas);
		return result;
	}
	
	public String uploadFile(byte[] fileContent) throws Exception {
		return uploadFile(fileContent, null, null);
	}
	
	public String uploadFile(byte[] fileContent, String extName) throws Exception {
		return uploadFile(fileContent, extName, null);
	}

我們新建一個工具包com.taotao.utils,然後把我們的封裝類FastDFSClient.java放到下面。我們來測測這個工具類是否好使,我們再新建個測試方法testFastDFSClient,如下圖所示。
在這裏插入圖片描述
代碼如下

@Test
	public void testFastDFSClient() throws Exception{
        FastDFSClient fastDFSClient = new FastDFSClient("E:/workspace/taotao-manager-web/src/main/resources/resource/client.conf");
        String imgPath = fastDFSClient.uploadFile("E:/images/2.jpg");
        System.out.println(imgPath);
	}

我們運行testFastDFSClient方法,返回的結果如下圖所示。
在這裏插入圖片描述
在這裏插入圖片描述
我們來訪問這個圖片,如下圖所示。
在這裏插入圖片描述
在這裏插入圖片描述

Cannot resolve symbol ‘Test’ 解決辦法 Intellij Idea 的maven工程在sources目錄中使用 @Test

Cannot resolve symbol ‘Test’ 解決辦法

問題:
intellij的maven工程,在sources目錄中的一個java文件中,使用junit的@Test 註釋類,但是intellij提示找不到類 cannot resolve symbol ‘Test’。而查看自己的pom文件,已經引入了junit包,該註釋類在maven的依賴包中是存在的。

方法一:
將pom文件中 junit的引用設置scope爲compile

junit
junit
4.10
compile

這裏還有個問題,一般jar包的默認作用域都是compile。難道junit這個包的默認作用域是test。

原理:
在使用idea中遇到在maven項目裏能引入類提示 cannot resolve symbol XXX,但項目組已經存在jar包,就是無法引用,清理項目緩存依然不管用。後來發現idea中libray是可以設置範圍的,Project structure->Modules->Dependencies 在此可對jar包設置範圍,共有如下值 Compile ,Test, Runtime ,Provided , 翻譯如下:

Scope Use this drop-down to affect the classpath for the various build phases.
Compile: This is the default option. If it is selected, the dependency is resolved and is available in classpath during the compilation and run phases.
Test: Select this option, if this dependency is only required for tests, and should not be available in normal application use. If this scope is selected, the dependency is resolved and is available in classpath during the test compilation and run phases.
Runtime: This scope indicates that the dependency is only required when running the application, and should not be available in classpath during the compilation.
Provided: If this option is selected, the dependency is resolved and is available in classpath during the compilation, but is not included in classpath at runtime. This dependency scope is useful, when you have some container that provides the dependency at runtime.

範圍 使用此下拉菜單來影響各個構建階段的類路徑。
編譯:這是默認選項。如果選中,依賴關係將在編譯和運行階段解析並在類路徑中可用。
測試:選擇此選項,如果此依賴關係僅用於測試,並且在正常的應用程序使用中不可用。如果選擇了此作用域,則在測試編譯和運行階段期間,將解析依賴關係,並在classpath中可用。
運行時:這個範圍表示只在運行應用程序時需要依賴關係,在編譯過程中不應該在classpath中使用依賴關係。
提供的:如果選擇了這個選項,依賴被解析並在編譯期間在類路徑中可用,但在運行時不包含在類路徑中。這個依賴範圍是有用的,當你有一些容器在運行時提供依賴。

將有問題的jar包改爲Compile 問題解決!

圖片上傳功能

上節課我們一起學習了搭建一個單機版的FastDFS圖片服務器以及使用FastDFS-Client進行簡單的文件上傳操作測試,這節我們一起學習項目中添加商品時上傳圖片的問題,目前上傳圖片還沒有實現,如下圖所示。
在這裏插入圖片描述

我們看下list-add.jsp頁面,可以看到上傳圖片觸發方法picFileUpload是通過class來處理的,在標籤的下方是一個隱藏域,是用來接收上傳到圖片服務器的回顯地址的,當我們提交表單的時候,可以把這些圖片地址保存到數據庫中。
在這裏插入圖片描述

流程是這樣的,頁面加載完之後,會自動調用TAOTAO.init進行初始化,如下圖所示。
在這裏插入圖片描述
TAOTAO在common.js中定義,我們來看下common.js,可以看到TAOTAO=TT都是在這裏定義的,在init方法中this.initPicUpload(data);用來初始化上傳組件。

初始化上傳組件中就有我們在jsp頁面中定義的類picFileUpload,由於上傳操作可能不只一個地方調用,因此$(".picFileUpload").each(function(i,e){來對所有調用上傳的頁面的組件進行初始化。

如果已經上傳過圖片,現在處於編輯狀態的話,那麼就使用_ele.siblings(".pics").find(“ul”).append來加載原來已經添加過的圖片。

點擊上傳圖片按鈕後,就會加載富文本編輯的上傳圖片界面,富文本編輯器的參數是在上面var TT=TAOTAO={的下面,指定了上傳文件參數的名稱,請求的url是/pic/upload,上傳類型是image、flash、media、file四種。
在這裏插入圖片描述

下面我們來實現圖片上傳功能

第一步:導包
上傳圖片需要依賴commons-io和commons-fileupload開發包,我們需要在taotao-manger-web工程的Maven依賴中查一下是否有這兩個包,目前是有commons-io-1.3.2.jar這個包的(它是在taotao-manager-common中依賴的,而taotao-manager-web依賴了taotao-manager-common,因此它也有這個包了),但目前沒有commons-fileupload,因此我們需要在taotao-manager-web的pom.xml文件中添加對commons-fileupload的依賴。
在這裏插入圖片描述

添加的依賴如下,由於在taotao-parent當中統一定義了版本號,因此這裏不用指定版本號。

<dependency>
		<groupId>commons-fileupload</groupId>
		<artifactId>commons-fileupload</artifactId>
	</dependency>

第二步:配置文件上傳解析器
我們需要在taotao-manager-web工程的springmvc.xml文件當中配置一下文件上傳解析器。如下所示。

<!-- 配置文件上傳解析器 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 設定默認編碼 -->
		<property name="defaultEncoding" value="UTF-8"></property>
		<!-- 設定文件上傳的最大值5MB,5*1024*1024 -->
		<property name="maxUploadSize" value="5242880"></property>
	</bean>

第三步:配置訪問圖片前綴
我們在訪問圖片時是以http的方式訪問的,例如http://192.168.156.13:8888/group1/M00/00/00/wKicDVjxPn2AOBiGAAHk-VzqZ6w952.jpg,從上節課我們知道圖片服務器返回的圖片路徑是group1/M00/00/00/wKicDVjxPn2AOBiGAAHk-VzqZ6w952.jpg,也就是說沒有前面那部分路徑,我們不能在代碼中寫死前綴,因爲IP及端口號都有可能更改,因此最好是放到配置文件當中,我們在resource目錄下新建一個resource.properties文件,配置文件中輸入IMAGE_SERVER_URL=http://192.168.156.13:8888/,這裏輸入端口8888是因爲我在圖片服務器的nginx當中配置的訪問端口是8888,如果端口是默認的80端口的話,可以直接輸入IMAGE_SERVER_URL=http://192.168.156.13/即可,下圖所示。
在這裏插入圖片描述

第四步:加載配置文件
我們在第三步新建了resource.properties,在spring中我們需要加載該配置文件,因此我們在springmvc.xml中加入<context:property-placeholder location=“classpath:resource/resource.properties”/>,如下圖所示。
在這裏插入圖片描述

當前springmvc.xml文件的完整內容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
       
    <!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:resource/resource.properties"/>    
	<!-- 配置註解驅動 -->
	<mvc:annotation-driven />
	<!-- 視圖解析器 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean>
	<!-- 配置包掃描器,掃描@Controller註解的類 -->
	<context:component-scan base-package="com.taotao.controller"/>
	
	<!-- 配置資源映射 -->
	<mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
	<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
	
	<!-- 多媒體解析器 -->
	<!-- 配置文件上傳解析器 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 設定默認編碼 -->
		<property name="defaultEncoding" value="UTF-8"></property>
		<!-- 設定文件上傳的最大值5MB,5*1024*1024 -->
		<property name="maxUploadSize" value="5242880"></property>
	</bean>
	
	<!-- 引用dubbo服務 -->
	<dubbo:application name="taotao-manager-web"/>
	<dubbo:registry protocol="zookeeper" address="192.168.156.14:2181"/>	
	<dubbo:reference interface="com.taotao.service.ItemService" id="itemService" />
	<dubbo:reference interface="com.taotao.service.ItemCatService" id="itemCatService" />
</beans>

第五步:創建Controller
我們需要新建一個PictureController類來處理上傳操作,如下圖所示。
在這裏插入圖片描述
上圖中@Value("${IMAGE_SERVER_URL}")是爲了注入我們在配置文件resource.properties中配置的圖片訪問前綴。@RequestMapping("/pic/upload")指定上傳文件請求的url,與下圖指定url一樣,上圖的public Map uploadFile(MultipartFile uploadFile) 參數"uploadFile"與下圖的上傳文件的方法參數名稱是要求一樣的。
在這裏插入圖片描述

那麼方法uploadFile應該返回什麼樣的格式呢,我們可以從kindeditor官網http://kindeditor.net/docs/upload.html查看一下,如下圖所示,可以看到返回值格式是json串,那麼我們便有三種實現方式。

第一種是直接返回Map格式的數據,json和Map數據都是key和value的形式,因此返回Map是沒問題的。
第二種是創建一個POJO類,該類有三個屬性,分別是error、url、message,然後將該類轉換爲json之後返回。
第三種是將Map轉變爲json字符串返回。這裏我們暫且使用第一種方式。

在這裏插入圖片描述

現把Controller類代碼粘貼如下

package com.taotao.controller;
 
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
 
import com.taotao.utils.FastDFSClient;
 
@Controller
public class PictureController {
 
	@Value("${IMAGE_SERVER_URL}")
	private String IMAGE_SERVER_URL;
	
	@RequestMapping("/pic/upload")
	@ResponseBody
	public Map uploadFile(MultipartFile uploadFile) {
		Map result  = new HashMap<>();
		try {
			//1.接收上傳的文件
			//2.獲取擴展名
			String orignalName = uploadFile.getOriginalFilename();
			String extName = orignalName.substring(orignalName.lastIndexOf(".")+1);
			//3.上傳到圖片服務器
			FastDFSClient fastDFSClient = new FastDFSClient("classpath:resource/client.conf");
			String url = fastDFSClient.uploadFile(uploadFile.getBytes(), extName);
			url = IMAGE_SERVER_URL + url;
			result.put("error", 0);
			result.put("url", url);
			return result;
		}  catch (Exception e) {
			e.printStackTrace();
			result.put("error", 0);
			result.put("message", "上傳圖片失敗!");
			return result;
		}
	}
}

這樣我們便配置完了,現在我們試試圖片上傳功能,如下圖所示,發現點擊"開始上傳"之後圖片正常回顯了。我們點擊"全部插入"按鈕。
在這裏插入圖片描述

點擊"全部插入"按鈕之後可以看到在"上傳圖片"按鈕的下方有我們剛纔上傳的三張圖片,我們是可以點擊任何一張圖片在瀏覽器中瀏覽的,比如我們點擊第三張圖片。

在這裏插入圖片描述

在瀏覽器中訪問的效果如下圖所示。這樣我們的圖片上傳功能便實現了。
在這裏插入圖片描述

解決KindEditor上傳圖片不兼容的問題

在上節課我們實現了圖片上傳功能,但是有個問題,那就是對瀏覽器兼容性不夠,因爲Map類型的返回值在火狐瀏覽器無法識別,Controller代碼如下圖所示。爲了解決這個兼容問題,我們需要修改下返回值類型,將Map類型變爲String類型(也就是json串)。我們至少可以使用以下兩種方案來解決。

第一種:使用fastjson來實現轉換
在taoao-common工程的maven依賴中添加對fastjson的依賴,之所以把這個放到taotao-common工程下是因爲這樣的操作可能在多個工程都用得着,因此放到taotao-common工程更合適。我們可以從中央倉庫複製fastjson的依賴座標,如下所示(版本有很多,我只是隨便選了個)。

com.alibaba fastjson 1.2.25

由於我們是在taotao-parent工程統一定義maven依賴版本,因此我們便在taotao-parent的pom.xml文件中添加如下圖所示的內容。注意,這裏只定義版本,不實際依賴。

在這裏插入圖片描述

下面我在taotao-common工程添加對fastjson的實際依賴,如下圖所示。
在這裏插入圖片描述
注意:由於我們剛纔修改了taotao-parent和taotao-common工程,因此需要對這兩個工程打下包,依次在taotao-parent和taotao-common工程上右鍵-------->Run As-------->Maven install進行打包。

我們的taotao-manager-web工程是依賴taotao-common工程的,因此自動就會把fastjson給加到taotao-manager-web工程的maven依賴當中了。我們便可以直接使用fastjson的功能了。如下圖所示。
在這裏插入圖片描述
我們重啓taotao-manager-web,啓動之後,我們再去嘗試上傳圖片,這次發現圖片回顯成功,如下圖所示。

第二種:使用已有的jackson來處理
我們知道SpringMVC的@ResponseBody將對象轉變爲json傳到前臺展示,幫我們做轉換操作的便是便是jackson。那麼我們怎樣使用jackson來處理轉換操作呢?我們可以封裝一個JSonUtil類,還是放到taotao-common工程下,如下圖所示。
在這裏插入圖片描述

KindEditor的圖片上傳插件,對瀏覽器兼容性不好。
使用@ResponseBody註解返回java對象,
Content-Type:application/json;charset=UTF-8
返回字符串時:
Content-Type:text/plan;charset=UTF-8

/Users/zhangcongrong/IdeaProjects/taotao/taotao-manager-web/src/main/java/com/taotao/utils/JsonUtils.java

package com.taotao.utils;
 
import java.util.List;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
 
/**
 * json轉換對象或對象轉json
 */
public class JsonUtils {
 
    // 定義jackson對象
    private static final ObjectMapper MAPPER = new ObjectMapper();
 
    /**
     * 將對象轉換成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    	try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 將json結果集轉化爲對象
     * 
     * @param jsonData json數據
     * @param clazz 對象中的object類型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 將json數據轉換成pojo對象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
    	try {
    		List<T> list = MAPPER.readValue(jsonData, javaType);
    		return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
    	return null;
    }
    
}

注意:由於taotao-common工程添加了一個工具類,因此需要重新打下包,在工程上右鍵--------->Run As-------->Maven install。
下面使用JsonUtil來做json轉換,如下圖所示。在這裏插入圖片描述
在這裏插入圖片描述
下面我們重啓taotao-manager-web工程,重啓後,再嘗試上傳圖片,如下圖所示,發現成功了。兩種方法大家隨意選擇。

解決KindEditor上傳圖片 不顯示上傳按鈕問題

在學習淘淘商城第三天的時候,批量上傳圖片到服務器,正確的姿勢是這樣的:
在這裏插入圖片描述
但是添加圖片那個按鈕沒有出現,然後百度說是缺少flash ,所以把flash更新了,然而並沒有解決問題。

最終解決方案是,打開淘淘商城網頁,然後用瀏覽器調試功能,顯示缺少一個images包
在這裏插入圖片描述
然後去把images包添加進工程,ok解決問題。

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
原因:
在這裏插入圖片描述
是花括號不是圓括號

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

但是在查閱資料時發現了以下問題:

spring和springmvc的父子容器間訪問properties文件內容

在這裏插入圖片描述
spring相當於父容器,springmvc相當於子容器。
1、在同一個容器中,可以任意訪問對象
2、子容器可以訪問父容器的對象 比如:control中可以注入到service中
3、父容器不能訪問子容器的對象

由於springmvc是spring的子容器,springmvc可以訪問父容器的對象,但不能訪問父容器的屬性。
所以在controller層(子容器加載),要使用@Value註解訪問properties文件(父容器加載)中的屬性是不能訪問的
要實現訪問父容器的屬性,怎麼辦呢
我們思考,我們可以在service層(父容器加載)中使用@Value註解讀取properties文件屬性,並把屬性權限設置爲public,
這樣通過注入@Resource方式把service注入,然後通過service來訪問properties文件屬性

原因分析:
@Value作用:爲當前屬性注入值。
注入值:在Spring容器初始化(所有的bean)之後,在當前的所在ApplicationContext容器中獲取配置文件中的值,然後注入。

我們的Controller所在的容器是哪個? SpringMVC的容器
我們把配置文件注入了哪個容器?Spring容器
不在同一個容器中,這就是問題所在。

Spring的父子容器
Spring容器 – 父容器
SpringMVC容器 – 子容器
父子容器的關係:
1、子容器能夠訪問父容器的資源(bean)
a)示例:Controller可以注入Service
2、父容器不能訪問子容器的資源(bean)

解決父子容器資源問題
子容器可以訪問父容器的對象,但是@Value並不會主動去父容器中查找配置文件屬性值。這是現在的問題。

我們的解決方案是:
在父容器中註冊一個Bean,然後把配置文件的值注入到這個Bean中,然後子容器可以訪問到這個bean,自然可以訪問到屬性

因爲Service層的對象是有Spring容器創建,因此我們定義一個Service

PropertiesService
在這裏插入圖片描述

在controller中注入Service
在這裏插入圖片描述
在這裏插入圖片描述
測試結果
在這裏插入圖片描述

添加商品的實現

上節課我們一起學習了富文本編輯器的使用,這節課我們一起學習下商品添加的實現。

在item-add.jsp當中,當點擊提交按鈕後,會觸發submitForm方法,如下圖所示。
在這裏插入圖片描述

在提交表單前需要校驗輸入的內容是否合法,如下圖所示。
在這裏插入圖片描述

下面我們看下數據庫中商品表的建表信息,可以看到價格定義的字段類型是long型,單位爲分,之所以這樣做是爲了避免使用小數點,因爲小數點使用起來比較麻煩。因此存到數據庫中的價格都是價格(以元爲單位)乘以100的(變爲分)。
在這裏插入圖片描述

我們發現在商品表當中沒有商品描述這個字段,其實商品描述是專門用一張表來存放了,如下圖所示。可以看到商品描述與商品ID是一一對應的,之所以把商品描述單獨放到一張表當中是因爲它是個大文本字段,存儲的信息量非常大,對於不需要商品描述的查詢情況來說連帶這個字段查詢會影響查詢效率,因此單獨存放。

在這裏插入圖片描述

我們看看錶單中是如何表示的,如下圖所示,可以看到有兩個組件,第一個用來展示的價格,即單位爲元的價格(這更符合用戶的習慣),第二個是個隱藏域,專門用來存放以分爲單位而的價格(即將以元爲單位的價格乘以100)。表單提交便會提交name="price"的價格並保存到數據庫。
在這裏插入圖片描述

提交表單會請求url爲"/item/save",第二個參數$("#itemAddForm").serialize()是用來將表單的數據序列化爲key-value形式的字符串。如果提交成功應該返回狀態碼爲200。
在這裏插入圖片描述

由於每個操作都需要有狀態碼來表示操作成功與否以及相關信息,因此我們定義一個TaotaoResult來專門處理,該類定義三個屬性,分別是狀態、消息及數據。由於這個類會被多個工程所使用,因此放到taotao-common的pojo目錄下。
在這裏插入圖片描述
TaotaoResult類的全部代碼如下,裏面最常用的便是ok方法和build方法。

package com.taotao.common.pojo;
 
import java.io.Serializable;
import java.util.List;
 
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
 
/**
 * 淘淘商城自定義響應結構
 */
public class TaotaoResult implements Serializable{
 
    // 定義jackson對象
    private static final ObjectMapper MAPPER = new ObjectMapper();
 
    // 響應業務狀態
    private Integer status;
 
    // 響應消息
    private String msg;
 
    // 響應中的數據
    private Object data;
 
    public static TaotaoResult build(Integer status, String msg, Object data) {
        return new TaotaoResult(status, msg, data);
    }
 
    public static TaotaoResult ok(Object data) {
        return new TaotaoResult(data);
    }
 
    public static TaotaoResult ok() {
        return new TaotaoResult(null);
    }
 
    public TaotaoResult() {
 
    }
 
    public static TaotaoResult build(Integer status, String msg) {
        return new TaotaoResult(status, msg, null);
    }
 
    public TaotaoResult(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }
 
    public TaotaoResult(Object data) {
        this.status = 200;
        this.msg = "OK";
        this.data = data;
    }
 
//    public Boolean isOK() {
//        return this.status == 200;
//    }
 
    public Integer getStatus() {
        return status;
    }
 
    public void setStatus(Integer status) {
        this.status = status;
    }
 
    public String getMsg() {
        return msg;
    }
 
    public void setMsg(String msg) {
        this.msg = msg;
    }
 
    public Object getData() {
        return data;
    }
 
    public void setData(Object data) {
        this.data = data;
    }
 
    /**
     * 將json結果集轉化爲TaotaoResult對象
     * 
     * @param jsonData json數據
     * @param clazz TaotaoResult中的object類型
     * @return
     */
    public static TaotaoResult formatToPojo(String jsonData, Class<?> clazz) {
        try {
            if (clazz == null) {
                return MAPPER.readValue(jsonData, TaotaoResult.class);
            }
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            JsonNode data = jsonNode.get("data");
            Object obj = null;
            if (clazz != null) {
                if (data.isObject()) {
                    obj = MAPPER.readValue(data.traverse(), clazz);
                } else if (data.isTextual()) {
                    obj = MAPPER.readValue(data.asText(), clazz);
                }
            }
            return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
        } catch (Exception e) {
            return null;
        }
    }
 
    /**
     * 將json串轉化爲TaotaoResult對象
     * 
     * @param json
     * @return
     */
    public static TaotaoResult format(String json) {
        try {
            return MAPPER.readValue(json, TaotaoResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
 
    /**
     * Object是集合轉化
     * 
     * @param jsonData json數據
     * @param clazz 集合中的類型
     * @return
     */
    public static TaotaoResult formatToList(String jsonData, Class<?> clazz) {
        try {
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            JsonNode data = jsonNode.get("data");
            Object obj = null;
            if (data.isArray() && data.size() > 0) {
                obj = MAPPER.readValue(data.traverse(),
                        MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
            }
            return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
        } catch (Exception e) {
            return null;
        }
    }
 
}

添加商品和商品描述對應的都是單表操作,因此我們使用逆向工程生成的代碼即可,也就是說我們不用寫Dao層的代碼。下面我們來寫Service層代碼,首先在ItemService接口當中添加一個"添加商品"的接口(這一個接口要操作兩張表,一張是商品表,另一張是商品描述表)。如下圖所示,參數有兩個,一個是商品表的pojo,另一個是商品描述。之所以要拋出異常是因爲這個接口要操作兩張表,而且這兩張表的操作要都成功才叫成功,否則事務就回滾,因此異常要向上拋,在實現類代碼中不能用try catch來捕獲異常,因爲這樣的話springmvc會認爲代碼正常結束了,便不會回滾。
在這裏插入圖片描述

下面我們到service層來實現這個接口,如下圖所示,我們在itemServiceImpl當中實現了createItem接口,其中商品ID(也叫商品編號)是採用當前毫秒數加兩位隨機數來生成的,爲了方便以後調用,我們專門封裝了一個類,叫IDUtils,裏面不僅封裝了商品ID的生成方法還封裝了圖片名稱的生成方法,由於該類會被多個工程使用,因此我們也放到taotao-common的utils目錄下。
在這裏插入圖片描述
當前ItemServiceImpl的全部代碼如下

package com.taotao.service.impl;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.common.pojo.EasyUIDataGridResult;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.IDUtils;
import com.taotao.mapper.TbItemDescMapper;
import com.taotao.mapper.TbItemMapper;
import com.taotao.pojo.TbItem;
import com.taotao.pojo.TbItemDesc;
import com.taotao.pojo.TbItemExample;
import com.taotao.service.ItemService;
 
@Service
public class ItemServiceImpl implements ItemService {
	
	@Autowired
	private TbItemMapper itemMapper;
	@Autowired
	private TbItemDescMapper itemDescMapper;
 
	@Override
	public TbItem getItemById(long itemId) {
		TbItem tbItem = itemMapper.selectByPrimaryKey(itemId);
		return tbItem;
	}
 
	@Override
	public EasyUIDataGridResult getItemList(int page, int rows) {
		//設置分頁信息
		PageHelper.startPage(page, rows);
		//執行查詢
		TbItemExample example = new TbItemExample();
		List<TbItem>  list = itemMapper.selectByExample(example);
		//獲取查詢結果
		PageInfo<TbItem> pageInfo = new PageInfo<>(list);
		EasyUIDataGridResult result = new EasyUIDataGridResult();
		result.setRows(list);
		result.setTotal(pageInfo.getTotal());
		//返回結果
		return result;
	}
 
	@Override
	public TaotaoResult createItem(TbItem tbItem, String desc) throws Exception{
		//生成商品ID
		long itemId = IDUtils.genItemId();
		//補全item的屬性
		tbItem.setId(itemId);
		//商品狀態,1-正常,2-下架,3-刪除
		tbItem.setStatus(((byte) 1));
		tbItem.setCreated(new Date());
		tbItem.setUpdated(new Date());
		itemMapper.insert(tbItem);
		//添加商品描述
		insertItemDesc(itemId, desc);
		return TaotaoResult.ok();
	}
	
	//添加商品描述
	private void insertItemDesc(long itemId,String desc){
		//創建一個商品描述表對應的pojo
		TbItemDesc itemDesc = new TbItemDesc();
		//補全pojo的屬性
		itemDesc.setItemId(itemId);
		itemDesc.setItemDesc(desc);
		itemDesc.setCreated(new Date());
		itemDesc.setUpdated(new Date());
		//向商品描述表插入數據
		itemDescMapper.insert(itemDesc);
	}
 
}

IDUtils類的代碼如下。

package com.taotao.utils;
 
import java.util.Random;
 
/**
 * 各種id生成策略
 * <p>Title: IDUtils</p>
 * <p>Description: </p>
 * @version 1.0
 */
public class IDUtils {
 
	/**
	 * 圖片名生成
	 */
	public static String genImageName() {
		//取當前時間的長整形值包含毫秒
		long millis = System.currentTimeMillis();
		//long millis = System.nanoTime();
		//加上三位隨機數
		Random random = new Random();
		int end3 = random.nextInt(999);
		//如果不足三位前面補0
		String str = millis + String.format("%03d", end3);
		
		return str;
	}
	
	/**
	 * 商品id生成
	 */
	public static long genItemId() {
		//取當前時間的長整形值包含毫秒
		long millis = System.currentTimeMillis();
		//long millis = System.nanoTime();
		//加上兩位隨機數
		Random random = new Random();
		int end2 = random.nextInt(99);
		//如果不足兩位前面補0
		String str = millis + String.format("%02d", end2);
		long id = new Long(str);
		return id;
	}
	
	public static void main(String[] args) {
		for(int i=0;i< 100;i++)
		System.out.println(genItemId());
	}
}

下面我們來寫Controller層,我們在Controller層添加addItem方法,其中value="/item/save"是在list-add.jsp的js當中定義好的,我們要保持一致纔行。在Controller層我們要捕獲從實現類拋出的異常,避免異常直接拋到前臺頁面。
在這裏插入圖片描述

下面我們便來試試我們的添加商品功能是否好使,由於taotao-common工程以及taotao-manager工程都做了修改,因此我們需要對這兩個工程重新打包,打包方法是在工程上右鍵------>Run As------>Maven install。

下面我們重啓taotao-manager工程和taotao-manager-web工程,啓動完工程之後,我們到新增商品頁面,輸入相關表單信息,然後點擊"提交"按鈕。

我們會發現彈出一個提示框,提示我們添加成功,添加完之後,我們到商品列表中去查詢,看是否有我們剛纔添加的商品,我們直接查看最後一頁的數據,發現最後一條就是我剛纔添加的商品信息,說明添加商品成功了。

我們再到數據庫中看看添加的商品信息,首先看tb_item表,我們還是到最後一頁去查看,發現有我剛纔添加的信息,如下圖所示。

再看商品描述表,最後一頁也有我們添加的商品描述信息,這說明數據存儲完全沒問題。這樣,我們的商品添加功能便實現了。

第三天總結

8/21~8/27
1、商品類目選擇
2、圖片上傳
a) 圖片服務器FastDFS
b) 圖片上傳功能實現
3、富文本編輯器的使用KindEditor
4、商品添加功能完成

1、 商品類目選擇

展示商品分類列表,使用EasyUI的tree控件展示。異步樹控件:樹控件內建異步加載模式的支持,用戶先創建一個空的樹,然後指定一個服務器端,執行檢索後動態返回json數據來填充樹並完成異步請求。

初始化tree請求的url:/item/cat/list
參數:初始化tree時只需要把第一級節點展示,子節點異步加載。
long id(父節點id)
返回值:json。數據格式
[{
“id”: 1,
“text”: “Node 1”,
“state”: “closed”
},{
“id”: 2,
“text”: “Node 2”,
“state”: “closed”
}]
state:如果節點下有子節點“closed”,如果沒有子節點“open”
創建一個pojo來描述tree的節點信息,包含三個屬性id、text、state。放到taotao-common工程中。
查詢的表:tb_item_cat
查詢列:Id、name、isparent
查詢條件parentId

Dao層
tb_item_cat可以使用逆向工程生成的代碼
taotao-manager-dao/src/main/java/com/taotao/mapper/TbItemCatMapper.java
TbItemCatMapper.xml

taotao-manager-pojo/src/main/java/com/taotao/pojo/TbItemCat.java
TbItemCatExample.java

Service層
參數:longparentId
業務邏輯:
1、根據parentId查詢節點列表
2、轉換成EasyUITreeNode列表。
3、返回。
返回值:List
taotao-manager-interface/src/main/java/com/taotao/service/ItemCatService.java
taotao-manager-service/src/main/java/com/taotao/service/impl/ItemCatServiceImpl.java
發佈服務
Controller層
初始化tree請求的url:/item/cat/list
參數:
long id(父節點id)
返回值:json。數據格式
List
taotao-manager-web/src/main/java/com/taotao/controller/ItemCatController.java
引入服務

2、圖片上傳
a) 圖片服務器FastDFS

圖片上傳分析
我們知道,對於傳統項目來說,所有的模塊都在一個項目中開發,包括所有靜態資源文件比如圖片等,都存儲在這一個tomcat服務器上。如果訪問量小的話,這樣做問題倒不大,但是對於互聯網項目來說,用戶訪問量很大,這樣一個tomcat服務是遠遠不能滿足業務需求的。這就需要部署tomcat集羣,有集羣就需要用到負載均衡,我們一般都會使用nginx來作爲負載均衡服務器。如下圖所示,但是這種tomcat集羣的缺點也很明顯,假如我們把一張1.jpg的圖片上傳到了tomcat1的images目錄下了,由於nginx負責均衡處理請求,當用戶去請求訪問這張圖片的時候,第一次,Nginx把請求交給tomcat1去處理,它到自己的images目錄下去找這張圖片,發現是可以找到的,於是我們便能看到這張圖片,當我們第二次通過Nginx去請求訪問該圖片時,Nginx把請求交給tomcat2區處理了,這時tomcat2去它自己的images目錄下去查找這張圖片,發現並沒有這張圖片,因此頁面上便看不到圖片。作爲用戶來講,一次訪問能看到,再刷新就看不到,再刷新能看到,很不理解,直觀的感覺便是我們的系統太爛了。
傳統方式:
圖片上傳/下載。 Tomcat<webapap<Images|-a.jpg
集羣環境:
負載均衡服務器ngnix
1.上傳圖片。 Tomcat1<webapap<Images|-a.jpg
Tomcat2<webapap<Images|-a.jpg
2.上傳到圖片服務器
圖片服務器FastDFS < Images|-a.jpg<http服務器(1.Tomcat2.Apache3.ngnix)
3.訪問圖片

解決方案:搭建一個圖片服務器,專門保存圖片。可以使用分佈式文件系統FastDFS。
1.上傳圖片。 Tomcat1<webapap
Tomcat2<webapap
2.上傳到圖片服務器
圖片服務器FastDFS < Images|-a.jpg<http服務器
3.訪問圖片
針對上面提到的問題,我們對集羣做下改善,我們專門搞一個圖片服務器,所有的tomcat都將用戶上傳的圖片上傳到圖片服務器上,tomcat本身並不保存圖片。我們採用http的方式來訪問圖片,這樣我們就需要使用http服務器,能作爲http服務器的有多種選擇。
第一:tomcat可以作爲http服務器,但是由於tomcat的強項並不在於處理靜態資源( 它的強項是處理servlet和jsp等動態請求)因此我們不選擇tomcat。
第二:使用Apache作爲http服務器,Apache是由c語言編寫的一款服務器(注意,這裏指的並不是Apache 組織,僅僅是一個服務器),這款服務器在以前用的人是很多的,現在用的人少了。
第三:使用nginx,nginx因爲其獨特的優勢,作爲http服務器是目前最火的。我們就使用nginx來統一管理這些圖片,這樣用戶要訪問圖片的時候,nginx直接把圖片服務器上的圖片給返回就可以了,從而解決了tomcat集羣資源無法共享的問題。
但是這裏需要考慮一個問題,那就是作爲服務器,容量肯定是有限的,當這個服務器容量滿了,怎麼辦?還有就是圖片服務器掛了,怎麼辦?這些都是必須要解決的問題,爲了解決這兩個問題,我們使用FastDFS集羣來解決,FastDFS是一個開源的輕量級分佈式文件系統,它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題。特別適合以文件爲載體的在線服務,如相冊網站、視頻網站等等。它的優勢是可以水平擴容,FastDFS存儲資源的設備是按組來區分的,當存儲空間不足時,便可以通過水平增加分組並相應添加設備來達到擴容的目的,而且是沒有上限的。還有個優勢是高可用,也就是說FastDFS集羣能夠做到當提供服務的nginx發生故障時,自動切換到另一臺nginx設備上,保障服務的穩定。
圖片服務器的安裝
1、存儲空間可擴展。
2、提供一個統一的訪問方式。
使用FastDFS,分佈式文件系統。存儲空間可以橫向擴展,可以實現服務器的高可用。支持每個節點有備份機。
4.1. 什麼是FastDFS?
FastDFS是用c語言編寫的一款開源的分佈式文件系統。FastDFS爲互聯網量身定製,充分考慮了冗餘備份、負載均衡、線性擴容等機制,並注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的文件服務器集羣提供文件上傳、下載等服務。
4.2. FastDFS架構
FastDFS架構包括 Tracker server和Storage server。客戶端請求Tracker server進行文件上傳、下載,通過Tracker server調度最終由Storage server完成文件上傳和下載。
Trackerserver作用是負載均衡和調度,通過Trackerserver在文件上傳時可以根據一些策略找到Storage server提供文件上傳服務。可以將tracker稱爲追蹤服務器或調度服務器。
Storageserver作用是文件存儲,客戶端上傳的文件最終存儲在Storage服務器上,Storage server沒有實現自己的文件系統而是利用操作系統的文件系統來管理文件。可以將storage稱爲存儲服務器。

服務端兩個角色:
Tracker:管理集羣,tracker也可以實現集羣。每個tracker節點地位平等。
收集Storage集羣的狀態。
Storage:實際保存文件
Storage分爲多個組,每個組之間保存的文件是不同的。每個組內部可以有多個成員,組成員內部保存的內容是一樣的,組成員的地位是一致的,沒有主從的概念。
文件上傳的流程

組名:文件上傳後所在的storage組名稱,在文件上傳成功後有storage服務器返回,需要客戶端自行保存。
虛擬磁盤路徑:storage配置的虛擬路徑,與磁盤選項store_path*對應。如果配置了store_path0則是M00,如果配置了store_path1則是M01,以此類推。
數據兩級目錄:storage服務器在每個虛擬磁盤路徑下創建的兩級目錄,用於存儲數據文件。
文件名:與文件上傳時不同。是由存儲服務器根據特定信息生成,文件名包含:源存儲服務器IP地址、文件創建時間戳、文件大小、隨機數和文件拓展名等信息。
4.4. 文件下載

4.5. 最簡單的FastDFS架構

圖片服務器安裝方法
寫了博客

b) 圖片上傳功能實現
6.2.1. 上傳步驟
1、加載配置文件,配置文件中的內容就是tracker服務的地址。
配置文件內容:tracker_server=192.168.25.133:22122
2、創建一個TrackerClient對象。直接new一個。
3、使用TrackerClient對象創建連接,獲得一個TrackerServer對象。
4、創建一個StorageServer的引用,值爲null
5、創建一個StorageClient對象,需要兩個參數TrackerServer對象、StorageServer的引用
6、使用StorageClient對象上傳圖片。
7、返回數組。包含組名和圖片的路徑。

6.3. 使用工具類上傳
7. 圖片上傳功能
7.1. 功能分析
使用的是KindEditor的多圖片上傳插件。
請求的url:/pic/upload
參數:MultiPartFileuploadFile
返回值:返回格式JSON(成功時。{“error”:0,”url”:”http://www.example.com/path/to/file.ext”} 失敗時。{“error”:1,”message”:”錯誤信息”} )
可以創建一個pojo對應返回值。可以使用map

業務邏輯:
1、接收頁面傳遞的圖片信息uploadFile
2、把圖片上傳到圖片服務器。使用封裝的工具類實現。需要取文件的內容和擴展名。
3、圖片服務器返回圖片的url
4、將圖片的url補充完整,返回一個完整的url。
5、把返回結果封裝到一個Map對象中返回。

1、需要把commons-io、fileupload 的jar包添加到工程中。
2、配置多媒體解析器。

Controller
PictureController.java->fileUpload

解決瀏覽器兼容性的問題
KindEditor的圖片上傳插件,對瀏覽器兼容性不好。
使用@ResponseBody註解返回java對象,
Content-Type:application/json;charset=UTF-8
返回字符串時:
Content-Type:text/plan;charset=UTF-8
指定響應結果的content-type:

3、富文本編輯器的使用KindEditor
純js開發,跟後臺語言沒有關係。
使用方法
第一步:在jsp中引入KindEditor的css和js代碼。
第二步:在表單中添加一個textarea控件。是一個富文本編輯器的載體。類似數據源。
第三步:初始化富文本編輯器。使用官方提供的方法初始化。
第四步:取富文本編輯器的內容。
表單提交之前,把富文本編輯器的內容同步到textarea控件中。

4、商品添加功能完成
9.1. 功能分析
請求的url:/item/save
參數:表單的數據。可以使用pojo接收表單的數據,要求pojo的屬性和input的name屬性要一致。
使用TbItem對象接收表單的數據。
TbItem item,String desc
返回值:Json數據。應該包含一個status的屬性。
可以使用TaotaoResult,放到taotao-common中。(status msg data)
taotao-common/src/main/java/com/taotao/common/pojo/TaotaoResult.java
業務邏輯:
1、生成商品id
實現方案:
a) Uuid,字符串,不推薦使用。
b) 數值類型,不重複。日期+時間+隨機數20160402151333123123
c) 可以直接去毫秒值+隨機數。可以使用。
d) 使用redis。Incr。推薦使用。
使用IDUtils生成商品id
taotao-common/src/main/java/com/taotao/common/util/IDUtils.java
2、補全TbItem對象的屬性
3、向商品表插入數據
4、創建一個TbItemDesc對象
5、補全TbItemDesc的屬性
6、向商品描述表插入數據
7、TaotaoResult.ok()
9.2. Dao層
向tb_item,tb_item_desc表中插入數據
可以使用逆向工程
taotao-manager-pojo/src/main/java/com/taotao/pojo/TbItemDesc.java
TbItemDescExample.java
TbItem.java
TbItemExample.java
taotao-manager-dao/src/main/java/com/taotao/mapper/TbItemDescMapper.java
TbItemDescMapper.xml
TbItemMapper.java
TbItemMapper.xml

9.3. Service層
參數:TbItemitem,String desc
業務邏輯:略,參加上面
返回值:TaotaoResult
taotao-manager-interface/src/main/java/com/taotao/service/ItemService.java
taotao-manager-service/src/main/java/com/taotao/service/impl/ItemServiceImpl.java
發佈服務

9.4. 表現層
9.4.1. 引用服務
9.4.2. Controller
請求的url:/item/save
參數:TbItemitem,String desc
返回值:TaotaoResult
9.5. 作業
商品修改、商品刪除、上架下架。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章