spring mvc多文件上傳

適用 spring mvc, spring boot

Controller代碼:

@PostMapping("/files")
@ResponseStatus(HttpStatus.CREATED)
public List<String> handleFileUpload(@RequestParam("files") MultipartFile[] files, String dir) {
    //獲取項目當(dāng)前路徑
    String projectFolder = System.getProperty("user.dir");
    
    List<String> publicPathList = Lists.newArrayList();
    for (MultipartFile file : files) {
        //根據(jù)需求提供上傳路徑
        String publicPath = "/upload/" + dir + "/" + file.getOriginalFilename();
        File realFile = new File(projectFolder + publicPath);
        
        file.transferTo(realFile);
        
        publicPathList.add(publicPath);
    }
    return publicPathList;
}

html代碼:

<form action="/files" method="post" encType="multipart/form-data">
    <!--注意accept屬性不要寫成*/*,會卡成翔,根據(jù)需求寫對應(yīng)的mime橙喘,別偷懶-->
    <input type="file" name="files" multiple="multiple" accept="image/jpg,image/jpeg,image/png" />
    <!--和文件一起提交別的參數(shù)-->
    <input type="hidden" name="dir" value="avatar" />
</form>

文件處理 :

可以利用MultipartFile的getInputStream方法對文件進一步處理嘿架,舉個栗子,圖片壓縮:

//使用阿里的圖片處理庫:SimpleImage
private void scale(InputStream inputStream, FileOutputStream outputStream) throws SimpleImageException{
    //這里默認(rèn)最大寬度1024,最大高度1024了慎式,可根據(jù)需求做成參數(shù)
    ScaleParameter scaleParam = new ScaleParameter(1024,1024);
    WriteParameter writeParam = new WriteParameter();

    ImageRender rr = new ReadRender(inputStream);
    ImageRender sr = new ScaleRender(rr, scaleParam);
    ImageRender wr = null;
    try {
        wr = new WriteRender(sr, outputStream, ImageFormat.JPEG, writeParam);
        wr.render();
    } catch (SimpleImageException e) {
        throw e;
    } finally {
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
        try {
            if (wr != null) {
                wr.dispose();
            }
        } catch (SimpleImageException e) {
            // ignore ...
        }
    }
}

調(diào)用

scale(file.getInputStream(), new FileOutputStream(realFile));

踩坑

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>simpleimage</artifactId>
    <version>1.2.3</version>
    <!--使用spring boot時會和默認(rèn)引入的log4j-over-slf4j沖突终佛,需要干掉-->
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--SimpleImage依賴的javax.media.jai.core在官方的maven倉庫中并沒有,需要引用spring提供的-->
<dependency>
    <groupId>javax.media.jai</groupId>
    <artifactId>com.springsource.javax.media.jai.core</artifactId>
    <version>1.1.3</version>
</dependency>

代碼組織:

建議將文件上傳處理部分抽出來翔忽,如:

FileService //文件處理接口
    LocalFileServiceImpl    //本地存儲文件處理實現(xiàn)
    QiniuFileServiceImpl    //七牛云存儲文件處理實現(xiàn)

上傳路徑和可訪問路徑可放到配置文件中英融,貼下spring-boot環(huán)境完整本地文件處理實現(xiàn)供參考:

LocalFileServiceImpl

@Service
public class LocalFileServiceImpl implements FileService {

    @Resource
    private UploadProperties uploadProperties;

    @Override
    public String upload(MultipartFile file, String dir, int maxWidth, int maxHeight) throws Exception {
        String projectFolder = System.getProperty("user.dir");
        String folderAndName = getFileUriGeneratedPart(file, dir);
        String path = projectFolder + uploadProperties.getPath() + folderAndName;

        File realFile = new File(path);
        if(!realFile.getParentFile().exists()) {
            if(!realFile.getParentFile().mkdirs()) {
                throw new Exception("創(chuàng)建文件上傳目錄失敗");
            }
        }
        try {
            scale(file.getInputStream(), new FileOutputStream(realFile), maxWidth, maxHeight);
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
        return uploadProperties.getPublicPath() + folderAndName;
    }

    private String getFileUriGeneratedPart(MultipartFile file, String dir) {
        return "/" + dir + "/"+ genRandomString(16) +
                "." + getExtensionName(file.getOriginalFilename());
    }

    //縮放用戶上傳圖片,減小寬帶占用
    private void scale(InputStream inputStream, FileOutputStream outputStream, int maxWidth, int maxHeight) throws SimpleImageException{
        ScaleParameter scaleParam = new ScaleParameter(maxWidth, maxHeight);
        WriteParameter writeParam = new WriteParameter();

        ImageRender rr = new ReadRender(inputStream);
        ImageRender sr = new ScaleRender(rr, scaleParam);
        ImageRender wr = null;
        try {
            wr = new WriteRender(sr, outputStream, ImageFormat.JPEG, writeParam);
            wr.render();
        } catch (SimpleImageException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
            try {
                if (wr != null) {
                    wr.dispose();
                }
            } catch (SimpleImageException e) {
                // ignore ...
            }

        }
    }

    private static String getExtensionName(String filename) {
        if (StringUtils.isNotBlank(filename)) {
            int dot = filename.lastIndexOf('.');
            if ((dot >-1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1).toLowerCase();
            }
        }
        return filename;
    }
    
    private static String genRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}

以上代碼移除了自定義的異常類

UploadProperties

@Component
@ConfigurationProperties("custom.upload")
public class UploadProperties {
    private String path;
    private String publicPath;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getPublicPath() {
        return publicPath;
    }

    public void setPublicPath(String publicPath) {
        this.publicPath = publicPath;
    }
}

spring boot配置 application-local.yml

custom.upload:
  path: /src/upload
  public-path: /upload
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歇式,一起剝皮案震驚了整個濱河市驶悟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贬丛,老刑警劉巖撩银,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異豺憔,居然都是意外死亡额获,警方通過查閱死者的電腦和手機够庙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抄邀,“玉大人耘眨,你說我怎么就攤上這事【成觯” “怎么了剔难?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奥喻。 經(jīng)常有香客問我偶宫,道長,這世上最難降的妖魔是什么环鲤? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任纯趋,我火速辦了婚禮,結(jié)果婚禮上冷离,老公的妹妹穿的比我還像新娘吵冒。我一直安慰自己,他們只是感情好西剥,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布痹栖。 她就那樣靜靜地躺著,像睡著了一般瞭空。 火紅的嫁衣襯著肌膚如雪揪阿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天匙铡,我揣著相機與錄音图甜,去河邊找鬼。 笑死鳖眼,一個胖子當(dāng)著我的面吹牛黑毅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钦讳,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼矿瘦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了愿卒?” 一聲冷哼從身側(cè)響起缚去,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎琼开,沒想到半個月后易结,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年搞动,在試婚紗的時候發(fā)現(xiàn)自己被綠了躏精。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹦肿,死狀恐怖矗烛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情箩溃,我是刑警寧澤瞭吃,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站涣旨,受9級特大地震影響歪架,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜开泽,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一牡拇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧穆律,春花似錦、人聲如沸导俘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旅薄。三九已至辅髓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間少梁,已是汗流浹背洛口。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凯沪,地道東北人第焰。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像妨马,于是被迫代替她去往敵國和親挺举。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

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