ssm(Spring劫哼、Springmvc叮趴、Mybatis)實(shí)戰(zhàn)之淘淘商城-第三天(非原創(chuàng))

文章大綱

一、課程介紹
二权烧、簡(jiǎn)單功能實(shí)現(xiàn)
三眯亦、圖片上傳功能實(shí)戰(zhàn)
四伤溉、項(xiàng)目源碼與資料下載
五、參考文章

一妻率、課程介紹

一共14天課程
(1)第一天:電商行業(yè)的背景乱顾。淘淘商城的介紹。搭建項(xiàng)目工程宫静。Svn的使用走净。
(2)第二天:框架的整合。后臺(tái)管理商品列表的實(shí)現(xiàn)孤里。分頁(yè)插件伏伯。
(3)第三天:后臺(tái)管理。商品添加扭粱。商品類(lèi)目的選擇、圖片上傳震檩、富文本編輯器的使用琢蛤。
(4)第四天:商品規(guī)格的實(shí)現(xiàn)。
(5)第五天:商城前臺(tái)系統(tǒng)的搭建脱惰。首頁(yè)商品分類(lèi)的展示石窑。Jsonp模蜡。
(6)第六天:cms系統(tǒng)的實(shí)現(xiàn)。前臺(tái)大廣告位的展示慕淡。
(7)第七天:cms系統(tǒng)添加緩存。Redis沸毁。緩存同步峰髓。
(8)第八天:搜索功能的實(shí)現(xiàn)。使用solr實(shí)現(xiàn)搜索息尺。
(9)第九天:商品詳情頁(yè)面的展示携兵。
(10)第十天:?jiǎn)吸c(diǎn)登錄系統(tǒng)。Session共享搂誉。
(11)第十一天:購(gòu)物車(chē)訂單系統(tǒng)的實(shí)現(xiàn)徐紧。
(12)第十二天:nginx。反向代理工具炭懊。
(13)第十三天:redis集群的搭建并级、solr集群的搭建。系統(tǒng)的部署侮腹。
(14)項(xiàng)目總結(jié)嘲碧。

二、簡(jiǎn)單功能實(shí)現(xiàn)

1. kindeditor(富文本編輯器)的使用

??由于jsp在實(shí)際項(xiàng)目中已經(jīng)比較少使用父阻,現(xiàn)在更多的是前后端分離呀潭,所以文章重點(diǎn)關(guān)注于后端技術(shù)實(shí)現(xiàn)钉迷,該模塊詳細(xì)功能,請(qǐng)移步項(xiàng)目源碼與資料下載內(nèi)容中進(jìn)行學(xué)習(xí)钠署。

2. 新增糠聪、商品類(lèi)目選擇功能

??由于jsp在實(shí)際項(xiàng)目中已經(jīng)比較少使用,現(xiàn)在更多的是前后端分離谐鼎,所以文章重點(diǎn)關(guān)注于后端技術(shù)實(shí)現(xiàn)舰蟆,該模塊詳細(xì)功能,請(qǐng)移步項(xiàng)目源碼與資料下載內(nèi)容中進(jìn)行學(xué)習(xí)狸棍。

三身害、圖片上傳功能實(shí)戰(zhàn)

1. 傳統(tǒng)項(xiàng)目中的圖片管理

??傳統(tǒng)項(xiàng)目中,可以在web項(xiàng)目中添加一個(gè)文件夾草戈,來(lái)存放上傳的圖片塌鸯。例如在工程的根目錄WebRoot下創(chuàng)建一個(gè)images文件夾。把圖片存放在此文件夾中就可以直接使用在工程中引用唐片。
??優(yōu)點(diǎn):引用方便丙猬,便于管理
??缺點(diǎn):
??(1)如果是分布式環(huán)境圖片引用會(huì)出現(xiàn)問(wèn)題。
??(2)圖片的下載會(huì)給服務(wù)器增加額外的壓力

傳統(tǒng)圖片管理方式在分布式環(huán)境中的問(wèn)題

2. 分布式環(huán)境的圖片管理

??分布式環(huán)境一般都有一個(gè)專(zhuān)門(mén)的圖片服務(wù)器存放圖片费韭。
??我們使用虛擬機(jī)搭建一個(gè)專(zhuān)門(mén)的服務(wù)器來(lái)存放圖片茧球。在此服務(wù)器上安裝一個(gè)nginx來(lái)提供http服務(wù),安裝一個(gè)ftp服務(wù)器來(lái)提供圖片上傳服務(wù)星持。

3. Linux環(huán)境下搭建圖片服務(wù)器

3.1 圖片服務(wù)器相關(guān)服務(wù)
??圖片服務(wù)器兩個(gè)服務(wù):
??http:可以使用nginx做靜態(tài)資源服務(wù)器抢埋。也可以使用apache。推薦使用nginx督暂,效率更高揪垄。
??Nginx功能:
??(1)http服務(wù)
??(2)反向代理
??(3)負(fù)載均衡

ftp服務(wù):
使用linux做服務(wù)器,在linux中有個(gè)ftp組件vsftpd逻翁。
??ngnix服務(wù)器的安裝過(guò)程包括配置資源福侈、啟動(dòng)、停止卢未、重啟肪凛、開(kāi)機(jī)自動(dòng)啟動(dòng)等,F(xiàn)TP服務(wù)安裝包括添加vsftpd組件辽社、添加ftp用戶伟墙、分配ftp用戶密碼、開(kāi)啟防火墻21端口滴铅、關(guān)閉匿名訪問(wèn)戳葵、開(kāi)啟被動(dòng)模式等,具體教程請(qǐng)參考資料下載中的內(nèi)容汉匙。

4. 代碼中管理圖片的上傳

4.1 工具類(lèi)編寫(xiě)
taotao-common項(xiàng)目中編寫(xiě)上傳圖片的返回結(jié)果的實(shí)體類(lèi)PictureResult.java

public class PictureResult {

    private int error;//判斷是否成功   0位成功拱烁,1為失敗
    
    private String url;//如果成功  該參數(shù)為圖片的請(qǐng)求地址  失敗則為null
    
    private String message;//如果失敗生蚁,該參數(shù)是描述原因,如果成功戏自,則為null
    
    private PictureResult(int error, String url, String message) {
        this.error = error;
        this.url = url;
        this.message = message;
    }
    //成功時(shí)調(diào)用的方法
    public static PictureResult ok(String url) {
        return new PictureResult(0, url, null);
    }
    //失敗時(shí)調(diào)用的方法
    public static PictureResult error(String message) {
        return new PictureResult(1, null, message);
    }
    public int getError() {
        return error;
    }
    public void setError(int error) {
        this.error = error;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    
    
}

taotao-common項(xiàng)目中編寫(xiě)ftp上傳下載工具類(lèi)FtpUtil.java

public class FtpUtil {

    /** 
     * Description: 向FTP服務(wù)器上傳文件 
     * @param host FTP服務(wù)器hostname 
     * @param port FTP服務(wù)器端口 
     * @param username FTP登錄賬號(hào) 
     * @param password FTP登錄密碼 
     * @param basePath FTP服務(wù)器基礎(chǔ)目錄
     * @param filePath FTP服務(wù)器文件存放路徑邦投。例如分日期存放:/2015/01/01。文件的路徑為basePath+filePath
     * @param filename 上傳到FTP服務(wù)器上的文件名 
     * @param input 輸入流 
     * @return 成功返回true擅笔,否則返回false 
     */  
    public static boolean uploadFile(String host, int port, String username, String password, String basePath,
            String filePath, String filename, InputStream input) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);// 連接FTP服務(wù)器
            // 如果采用默認(rèn)端口志衣,可以使用ftp.connect(host)的方式直接連接FTP服務(wù)器
            ftp.login(username, password);// 登錄
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
            //切換到上傳目錄
            if (!ftp.changeWorkingDirectory(basePath+filePath)) {
                //如果目錄不存在創(chuàng)建目錄
                String[] dirs = filePath.split("/");
                String tempPath = basePath;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)) continue;
                    tempPath += "/" + dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            return result;
                        } else {
                            ftp.changeWorkingDirectory(tempPath);
                        }
                    }
                }
            }
            //設(shè)置上傳文件的類(lèi)型為二進(jìn)制類(lèi)型
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //上傳文件
            if (!ftp.storeFile(filename, input)) {
                return result;
            }
            input.close();
            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }
    
    /** 
     * Description: 從FTP服務(wù)器下載文件 
     * @param host FTP服務(wù)器hostname 
     * @param port FTP服務(wù)器端口 
     * @param username FTP登錄賬號(hào) 
     * @param password FTP登錄密碼 
     * @param remotePath FTP服務(wù)器上的相對(duì)路徑 
     * @param fileName 要下載的文件名 
     * @param localPath 下載后保存到本地的路徑 
     * @return 
     */  
    public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
            String fileName, String localPath) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默認(rèn)端口,可以使用ftp.connect(host)的方式直接連接FTP服務(wù)器
            ftp.login(username, password);// 登錄
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
            ftp.changeWorkingDirectory(remotePath);// 轉(zhuǎn)移到FTP服務(wù)器目錄
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    File localFile = new File(localPath + "/" + ff.getName());

                    OutputStream is = new FileOutputStream(localFile);
                    ftp.retrieveFile(ff.getName(), is);
                    is.close();
                }
            }

            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }
    
    public static void main(String[] args) {
        try {  
            FileInputStream in=new FileInputStream(new File("D:\\temp\\image\\gaigeming.jpg"));  
            boolean flag = uploadFile("192.168.25.133", 21, "ftpuser", "ftpuser", "/home/ftpuser/www/images","/2015/01/21", "gaigeming.jpg", in);  
            System.out.println(flag);  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        }  
    }
}

編寫(xiě)完成后的文件結(jié)構(gòu)如下:

4.2 Service層編寫(xiě)

taotao-manager-web項(xiàng)目編寫(xiě)資源文件resource.properties猛们,用于存放于FTP相關(guān)的變量

#FTP\u7684\u76f8\u5173\u914d\u7f6e
FTP_ADDRESS=192.168.101.6
FTP_PORT=21
FTP_USER_NAME=haha
FTP_PASSWORD=147258qq
FTP_BASE_PATH=/home/ftpuser/www/images
#\u56fe\u7247\u670d\u52a1\u5668\u7684url
IMAGE_BASE_URL=http://192.168.101.6/images

taotao-manager-service項(xiàng)目中編寫(xiě)上傳圖片處理接口PictureService.java

/**
 * 上傳圖片處理
 */
public interface PictureService {

    PictureResult uploadPicture(MultipartFile uploadFile);
}

taotao-manager-service項(xiàng)目中編寫(xiě)上傳圖片處理實(shí)現(xiàn)類(lèi)PictureServiceImpl.java

/**
 * 上傳圖片處理服務(wù)實(shí)現(xiàn)類(lèi)
 */
@Service
public class PictureServiceImpl implements PictureService {

    //使用@Value注解時(shí)候念脯,當(dāng)配置文件中內(nèi)容修改時(shí)候,映射過(guò)來(lái)的內(nèi)容會(huì)自動(dòng)更改的
    @Value("${FTP_ADDRESS}")
    private String FTP_ADDRESS;
    @Value("${FTP_PORT}")
    private Integer FTP_PORT;
    @Value("${FTP_USER_NAME}")
    private String FTP_USER_NAME;
    @Value("${FTP_PASSWORD}")
    private String FTP_PASSWORD;
    @Value("${FTP_BASE_PATH}")
    private String FTP_BASE_PATH;
    @Value("${IMAGE_BASE_URL}")
    private String IMAGE_BASE_URL;


    @Override
    public PictureResult uploadPicture(MultipartFile uploadFile) {
        //判斷上傳圖片是否為空
        if (null == uploadFile || uploadFile.isEmpty()) {
            return PictureResult.error("上傳圖片為空");
        }
        //取文件擴(kuò)展名
        String originalFilename = uploadFile.getOriginalFilename();
        String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
        //生成新文件名
        //可以使用uuid生成新文件名弯淘。
        //UUID.randomUUID()
        //可以是時(shí)間+隨機(jī)數(shù)生成文件名
        String imageName = IDUtils.genImageName();
        //把圖片上傳到ftp服務(wù)器(圖片服務(wù)器)
        //需要把ftp的參數(shù)配置到配置文件中
        //文件在服務(wù)器的存放路徑绿店,應(yīng)該使用日期分隔的目錄結(jié)構(gòu)
        DateTime dateTime = new DateTime();
        String filePath = dateTime.toString("/yyyy/MM/dd");
        try {
            FtpUtil.uploadFile(FTP_ADDRESS, FTP_PORT, FTP_USER_NAME, FTP_PASSWORD,
                    FTP_BASE_PATH, filePath, imageName + ext, uploadFile.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            return PictureResult.error(ExceptionUtil.getStackTrace(e));
        }
        //返回結(jié)果,生成一個(gè)可以訪問(wèn)到圖片的url返回

        return PictureResult.ok(IMAGE_BASE_URL + filePath + "/" + imageName + ext);
    }

}

編寫(xiě)完成后的項(xiàng)目結(jié)構(gòu)如下

功能:接收controller層傳遞過(guò)來(lái)的圖片對(duì)象庐橙,把圖片上傳到ftp服務(wù)器假勿。給圖片生成一個(gè)新的名字。
參數(shù):MultiPartFile uploadFile
返回值:返回一個(gè)pojo怕午,應(yīng)該是PictureResult废登。

溫馨提示:在resource.properties文件中編寫(xiě)的變量?jī)?nèi)容淹魄,與service層中@Value注解的內(nèi)容一一對(duì)應(yīng)郁惜,若resource.properties中內(nèi)容變了,@Value會(huì)隨之變化

4.3 Controller層編寫(xiě)
在taotao-manager-web項(xiàng)目的springmvc.xml文件中添加以下內(nèi)容

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

在taotao-manager-web項(xiàng)目中編寫(xiě)接收的圖片的PictureController.java

package com.taotao.controller;

import org.springframework.beans.factory.annotation.Autowired;
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.common.pojo.PictureResult;
import com.taotao.common.utils.JsonUtils;
import com.taotao.service.PictureService;

/**
 * 圖片上傳controller
 */
@Controller
public class PictureController {
    @Autowired
    private PictureService pictureService;
    
    @RequestMapping("/pic/upload")
    @ResponseBody
    public String upload(MultipartFile uploadFile) {
        
        PictureResult result = pictureService.uploadPicture(uploadFile);
        
        //將對(duì)象轉(zhuǎn)化成json字符串
        return JsonUtils.objectToJson(result);
        
    }
    
}

5. 總結(jié)

??在實(shí)際開(kāi)發(fā)中兆蕉,我們圖片管理的方式可以有多種,比如:
??(1)自己搭建圖片服務(wù)器缤沦,之后將圖片上傳后的訪問(wèn)路徑保存在數(shù)據(jù)庫(kù)中虎韵,之后返回給前端進(jìn)行渲染
??(2)采用第三方提供的OSS存儲(chǔ)空間(阿里云、騰訊云等)缸废,將圖片托管在云端包蓝,之后上傳時(shí)候,自己備份一份在自己服務(wù)器企量,所有的操作以第三方文檔為準(zhǔn)

四测萎、項(xiàng)目源碼與資料下載

鏈接:https://pan.baidu.com/s/12lllAj4PdrGV6_b2WsrhfQ
提取碼:f5qm

五、參考文章

http://yun.itheima.com/course?hm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末届巩,一起剝皮案震驚了整個(gè)濱河市硅瞧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恕汇,老刑警劉巖腕唧,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件或辖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡枣接,警方通過(guò)查閱死者的電腦和手機(jī)颂暇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)月腋,“玉大人蟀架,你說(shuō)我怎么就攤上這事∮苌В” “怎么了片拍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妓肢。 經(jīng)常有香客問(wèn)我捌省,道長(zhǎng),這世上最難降的妖魔是什么碉钠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任纲缓,我火速辦了婚禮,結(jié)果婚禮上喊废,老公的妹妹穿的比我還像新娘祝高。我一直安慰自己,他們只是感情好污筷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布工闺。 她就那樣靜靜地躺著,像睡著了一般瓣蛀。 火紅的嫁衣襯著肌膚如雪陆蟆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天惋增,我揣著相機(jī)與錄音叠殷,去河邊找鬼。 笑死诈皿,一個(gè)胖子當(dāng)著我的面吹牛林束,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稽亏,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼壶冒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了措左?” 一聲冷哼從身側(cè)響起依痊,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后胸嘁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瓶摆,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年性宏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了群井。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毫胜,死狀恐怖书斜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酵使,我是刑警寧澤荐吉,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站口渔,受9級(jí)特大地震影響样屠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缺脉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一痪欲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧攻礼,春花似錦业踢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至深员,卻和暖如春负蠕,著一層夾襖步出監(jiān)牢的瞬間蛙埂,已是汗流浹背倦畅。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绣的,地道東北人叠赐。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像屡江,于是被迫代替她去往敵國(guó)和親芭概。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容