国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

[Bootstrap-插件使用]Jcrop+fileinput組合實(shí)現(xiàn)頭像上傳功能實(shí)例代碼

2019-11-19 18:23:06
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

很久沒(méi)有更新博客了,再不寫(xiě)點(diǎn)東西都爛了。

這次更新一個(gè)小內(nèi)容,是兩個(gè)插件的組合使用,實(shí)現(xiàn)頭像上傳功能。

業(yè)務(wù)需求:

  • 頭像上傳功能,要對(duì)上傳的文件進(jìn)行剪切,且保證頭像到服務(wù)器時(shí)必須是正方形的。
  • 優(yōu)化<input type="file">的顯示樣式,基礎(chǔ)的樣式實(shí)在太難看了。
  • 上傳的頭像需要進(jìn)行質(zhì)量壓縮跟大小裁剪,以減緩瀏覽器的壓力。

成果預(yù)覽:

使用到的技術(shù)插件

  • Jcrop:用于前端“裁剪”圖片
  • bootstrap-fileinput:用于前端優(yōu)化上傳控件樣式
  • ARTtemplate:JS版的JSTL?反正就是一個(gè)騰訊的模板化插件,很好用,真心。
  • bootstrap-sco.modal.js:這個(gè)是bootstrap的一個(gè)模態(tài)插件
  • SpringMVC:使用框架自帶的MultipartFile來(lái)獲取文件(效率能夠大大的提高)
  • Image:這個(gè)是Java的內(nèi)置類,用于處理圖片很方便。

原理說(shuō)明

首先是Jcrop這個(gè)前端JS插件,這個(gè)插件很好用,其實(shí)在各大網(wǎng)站中也很常見(jiàn),先上圖:

說(shuō)說(shuō)原理,實(shí)際上,Jcrop并沒(méi)有在客戶端幫我們把圖片進(jìn)行裁剪,只是收集了用戶的“裁剪信息”,然后傳到后端,最后的裁剪和壓縮,還是要依靠服務(wù)器上的代碼來(lái)進(jìn)行。

我們可以看到這個(gè)插件在圖片上顯示出了8個(gè)控制點(diǎn),讓用戶選擇裁剪區(qū)域,當(dāng)用戶選擇成功后,會(huì)自動(dòng)的返回“裁剪信息”,所謂的裁剪信息,其實(shí)就是選框的左上角原點(diǎn)坐標(biāo),及裁剪框的寬度和高度,通過(guò)這四個(gè)值,在后端就可以進(jìn)行裁剪工作了。

但是我們要注意,用戶在上傳圖片的時(shí)候,長(zhǎng)度寬度都是不規(guī)則的,當(dāng)然我們可以用bootstap-fileinput這個(gè)插件去限制用戶只能上傳指定寬高的圖片,但這就失去了我們“裁剪”的意義,而且用戶的體驗(yàn)就非常差勁。然而jcrop所返回的坐標(biāo)值及寬高,并不是基于所上傳圖片自身的像素,而是如圖中所示,是外層DIV的寬高。舉一個(gè)例子,上圖我實(shí)際放入的個(gè)人照片寬度是852px,但是Jcrop的截取寬度是312px,這個(gè)312px并不是真正圖片上的實(shí)際寬度,是經(jīng)過(guò)縮放后的寬度,所以我們后端一定需要重新對(duì)這個(gè)312px進(jìn)行一次還原,還原到照片實(shí)際比例的寬度。

好啦,原理就是這樣子。接下來(lái),就是上代碼了。

HTML

<script id="portraitUpload" type="text/html">  <div style="padding: 10px 20px">    <form role="form" enctype="multipart/form-data" method="post">      <div class="embed-responsive embed-responsive-16by9">        <div class="embed-responsive-item pre-scrollable">          <img alt="" src="${pageContext.request.contextPath}/img/showings.jpg" id="cut-img"             class="img-responsive img-thumbnail"/>        </div>      </div>      <div class="white-divider-md"></div>      <input type="file" name="imgFile" id="fileUpload"/>      <div class="white-divider-md"></div>      <div id="alert" class="alert alert-danger hidden" role="alert"></div>      <input type="hidden" id="x" name="x"/>      <input type="hidden" id="y" name="y"/>      <input type="hidden" id="w" name="w"/>      <input type="hidden" id="h" name="h"/>    </form>  </div></script>

這個(gè)就是一個(gè)ArtTemplate的模板代碼,就寫(xiě)在</body>標(biāo)簽上方就行了,因?yàn)閠ext/html這個(gè)類型,不會(huì)被識(shí)別,所以實(shí)際上用Chrome調(diào)試就可以看得到,前端用戶是看不到這段代碼的。

簡(jiǎn)單解釋一下這個(gè)模板,這個(gè)模板是我最后放入模態(tài)窗口時(shí)用的模板,就是把這段代碼,直接丟進(jìn)模態(tài)彈出來(lái)的內(nèi)容部分。因?yàn)槭俏募蟼鳎匀恍枰滓粋€(gè)<form>標(biāo)簽,然后必須給form標(biāo)簽放入 enctype="multipart/form-data",否則后端Spring就無(wú)法獲取這個(gè)文件。

"embed-responsive embed-responsive-16by9"這個(gè)類就是用來(lái)限制待編輯圖片加載后的寬度大小,值得注意的是,我在其內(nèi)種,加了一個(gè)

<div class="embed-responsive-item pre-scrollable">

pre-scrollable這個(gè)類,會(huì)讓加載的圖片不會(huì)因?yàn)樘蠖白冃巍保驗(yàn)槲彝鈱油ㄟ^(guò)embed-responsive-16by9限制死了圖片的寬高,圖片本身又加了img-responsive這個(gè)添加響應(yīng)式屬性的類,為了防止圖片縮放,導(dǎo)致截圖障礙,所以就給內(nèi)層加上pre-scrollable,這個(gè)會(huì)給圖片這一層div加上滾動(dòng)條,如果圖片高度太高,超過(guò)了外層框,則會(huì)出現(xiàn)滾動(dòng)條,而這不會(huì)影響圖片截取,同時(shí)又保證了模態(tài)窗口不會(huì)“太長(zhǎng)”,導(dǎo)致體驗(yàn)糟糕(尤其在移動(dòng)端)。

底下四個(gè)隱藏域相信大家看他們的name值也就知道個(gè)大概,這個(gè)就是用于存放Jcrop截取時(shí)所產(chǎn)生的原點(diǎn)坐標(biāo)和截取寬高的值。

JS

$(document).ready(function () {  new PageInit().init();});function PageInit() {  var api = null;  var _this = this;  this.init = function () {    $("[name='upload']").on('click', this.portraitUpload)  };  this.portraitUpload = function () {    var model = $.scojs_modal({        title: '頭像上傳',        content: template('portraitUpload'),        onClose: refresh      }    );    model.show();    var fileUp = new FileUpload();    var portrait = $('#fileUpload');    var alert = $('#alert');    fileUp.portrait(portrait, '/file/portrait', _this.getExtraData);    portrait.on('change', _this.readURL);    portrait.on('fileuploaderror', function (event, data, msg) {      alert.removeClass('hidden').html(msg);      fileUp.fileinput('disable');    });    portrait.on('fileclear', function (event) {      alert.addClass('hidden').html();    });    portrait.on('fileloaded', function (event, file, previewId, index, reader) {      alert.addClass('hidden').html();    });    portrait.on('fileuploaded', function (event, data) {      if (!data.response.status) {        alert.html(data.response.message).removeClass('hidden');      }    })  };  this.readURL = function () {    var img = $('#cut-img');    var input = $('#fileUpload');    if (input[0].files && input[0].files[0]) {      var reader = new FileReader();      reader.readAsDataURL(input[0].files[0]);      reader.onload = function (e) {        img.removeAttr('src');        img.attr('src', e.target.result);        img.Jcrop({          setSelect: [20, 20, 200, 200],          handleSize: 10,          aspectRatio: 1,          onSelect: updateCords        }, function () {          api = this;        });      };      if (api != undefined) {        api.destroy();      }    }    function updateCords(obj) {      $("#x").val(obj.x);      $("#y").val(obj.y);      $("#w").val(obj.w);      $("#h").val(obj.h);    }  };  this.getExtraData = function () {    return {      sw: $('.jcrop-holder').css('width'),      sh: $('.jcrop-holder').css('height'),      x: $('#x').val(),      y: $('#y').val(),      w: $('#w').val(),      h: $('#h').val()    }  }}

這個(gè)JS是上傳頁(yè)面的相關(guān)邏輯。會(huì)JS的人都看得懂它的意義,我就簡(jiǎn)單說(shuō)一下幾個(gè)事件的意義:

 portrait.on('fileuploaderror', function (event, data, msg) {       alert.removeClass('hidden').html(msg);       fileUp.fileinput('disable');     });

這個(gè)事件,是用于bootstrap-fileinput插件在校驗(yàn)文件格式、文件大小等的時(shí)候,如果不符合我們的要求,則會(huì)對(duì)前面HTML代碼中有一個(gè)

<div id="alert" class="alert alert-danger hidden" role="alert"></div>

進(jìn)行一些錯(cuò)誤信息的顯示操作。

 portrait.on('fileclear', function (event) {       alert.addClass('hidden').html();     });

這部分代碼,是當(dāng)文件移除時(shí),隱藏錯(cuò)誤信息提示區(qū),以及清空內(nèi)容,當(dāng)然這是符合我們的業(yè)務(wù)邏輯的。

 portrait.on('fileloaded', function (event, file, previewId, index, reader) {       alert.addClass('hidden').html();     });

這部分代碼是當(dāng)選擇文件時(shí)(此時(shí)還沒(méi)進(jìn)行文件校驗(yàn)),隱藏錯(cuò)誤信息,清空錯(cuò)誤內(nèi)容,這么做是為了應(yīng)對(duì)如果上一次文件校驗(yàn)時(shí)有錯(cuò)誤,而重新選擇文件時(shí),肯定要清空上一次的錯(cuò)誤信息,再顯示本次的錯(cuò)誤信息。

 portrait.on('fileuploaded', function (event, data) {       if (!data.response.status) {         alert.html(data.response.message).removeClass('hidden');       }     })

這部分是當(dāng)文件上傳后,后端如果返回了錯(cuò)誤信息,則需要進(jìn)行相關(guān)的提示信息處理。

this.getExtraData = function () {    return {      sw: $('.jcrop-holder').css('width'),      sh: $('.jcrop-holder').css('height'),      x: $('#x').val(),      y: $('#y').val(),      w: $('#w').val(),      h: $('#h').val()    }  }

這部分代碼是獲取上傳文件時(shí),附帶需要發(fā)往后端的參數(shù),這里面可以看到,x、y自然是Jcrop截取時(shí),選框的左上角原點(diǎn)坐標(biāo),w、h自然就是截取的寬高,但是剛才我說(shuō)了,這個(gè)是經(jīng)過(guò)縮放后的寬高,不是依據(jù)圖片實(shí)際像素的寬高。而sw、sh代表的是scaleWidth、scaleHeight,就是縮放寬高的意思。這個(gè).jcrop-holder的對(duì)象是當(dāng)Jcrop插件啟用后,加載的圖片外層容器的對(duì)象,只需要獲取這個(gè)對(duì)象的寬高,就是圖片被壓縮的寬高,但是因?yàn)槲蚁拗屏藞D片的寬度和高度,寬度的比例是定死的(不是寬高定死,只是比例定死,bootstrap本身就是響應(yīng)式框架,所以不能單純的說(shuō)寬高定死,寬高會(huì)隨著使用終端的變化而變化),高度是根據(jù)寬度保持16:4,可是我又加了pre-scrollable這個(gè)類讓圖片過(guò)高時(shí)以滾動(dòng)條的方式不破壞外層容器的高度,所以我們實(shí)際能拿來(lái)計(jì)算縮放比例的,是寬度,而不是高度,但是這里我一起傳,萬(wàn)一以后有其他的使用場(chǎng)景,要以高度為準(zhǔn)也說(shuō)不定。

好了,然后我需要貼上bootstrap-fileinput插件的配置代碼:

this.portrait = function (target, uploadUrl, data) {    target.fileinput({      language: 'zh', //設(shè)置語(yǔ)言      maxFileSize: 2048,//文件最大容量      uploadExtraData: data,//上傳時(shí)除了文件以外的其他額外數(shù)據(jù)      showPreview: false,//隱藏預(yù)覽      uploadAsync: true,//ajax同步      dropZoneEnabled: false,//是否顯示拖拽區(qū)域      uploadUrl: uploadUrl, //上傳的地址      allowedFileExtensions: ['jpg'],//接收的文件后綴      showUpload: true, //是否顯示上傳按鈕      showCaption: true,//是否顯示標(biāo)題      browseClass: "btn btn-primary", //按鈕樣式      previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",      ajaxSettings: {//這個(gè)是因?yàn)槲沂褂昧薙pringSecurity框架,有csrf跨域提交防御,所需需要設(shè)置這個(gè)值        beforeSend: function (xhr) {          xhr.setRequestHeader(header, token);        }      }    });  }

這個(gè)代碼有寫(xiě)了注釋,我就不多解釋了。關(guān)于Ajax同步,是因?yàn)槲覀€(gè)人認(rèn)為,上傳文件這個(gè)還是做成同步比較好,等文件上傳完成后,js代碼才能繼續(xù)執(zhí)行下去。因?yàn)槲募蟼鳟吘故且粋€(gè)耗時(shí)的工作,有的邏輯又確實(shí)需要當(dāng)文件上傳成功以后才執(zhí)行,比如刷新頁(yè)面,所以為了避免出現(xiàn)問(wèn)題,還是做成同步的比較好。還有就是去掉預(yù)覽,用過(guò)bootstrap-fileinput插件的都知道,這個(gè)插件的圖片預(yù)覽功能很強(qiáng)大,甚至可以單獨(dú)依靠這個(gè)插件來(lái)制作相冊(cè)管理。但是因?yàn)槲覀冞@次要結(jié)合Jcrop,所以要割掉這部分功能。

SpringMVC-Controller獲取文件

@ResponseBody  @RequestMapping(value = "/portrait", method = {RequestMethod.POST})  public JsonResult upload(HttpServletRequest request) throws Exception {    Integer x = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("x"), "圖片截取異常:X!"));    Integer y = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("y"), "圖片截取異常:Y!"));    Integer w = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("w"), "圖片截取異常:W!"));    Integer h = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("h"), "圖片截取異常:H!"));    String scaleWidthString = MyStringTools.checkParameter(request.getParameter("sw"), "圖片截取異常:SW!");    int swIndex = scaleWidthString.indexOf("px");    Integer sw = Integer.parseInt(scaleWidthString.substring(0, swIndex));    String scaleHeightString = MyStringTools.checkParameter(request.getParameter("sh"), "圖片截取異常:SH!");    int shIndex = scaleHeightString.indexOf("px");    Integer sh = Integer.parseInt(scaleHeightString.substring(0, shIndex));    //獲取用戶ID用于指向?qū)?yīng)文件夾    SysUsers sysUsers = HttpTools.getSessionUser(request);    int userID = sysUsers.getUserId();    //獲取文件路徑    String filePath = FileTools.getPortraitPath(userID);    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(        request.getSession().getServletContext());    String path;    //檢查form中是否有enctype="multipart/form-data"    if (multipartResolver.isMultipart(request)) {      //將request變成多部分request      MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;      //獲取multiRequest 中所有的文件名      Iterator iterator = multiRequest.getFileNames();      while (iterator.hasNext()) {        //一次遍歷所有文件        MultipartFile multipartFile = multiRequest.getFile(iterator.next().toString());        if (multipartFile != null) {          String[] allowSuffix = {".jpg",".JPG"};          if (!FileTools.checkSuffix(multipartFile.getOriginalFilename(), allowSuffix)) {            throw new BusinessException("文件后綴名不符合要求!");          }          path = filePath + FileTools.getPortraitFileName(multipartFile.getOriginalFilename());          //存入硬盤(pán)          multipartFile.transferTo(new File(path));          //圖片截取          if (FileTools.imgCut(path, x, y, w, h, sw, sh)) {            CompressTools compressTools = new CompressTools();            if (compressTools.simpleCompress(new File(path))) {              return JsonResult.success(FileTools.filePathToSRC(path, FileTools.IMG));            } else {              return JsonResult.error("圖片壓縮失敗!請(qǐng)重新上傳!");            }          } else {            return JsonResult.error("圖片截取失敗!請(qǐng)重新上傳!");          }        }      }    }    return JsonResult.error("圖片獲取失敗!請(qǐng)重新上傳!");  }

Image圖片切割

/**   * 截圖工具,根據(jù)截取的比例進(jìn)行縮放裁剪   *   * @param path    圖片路徑   * @param zoomX    縮放后的X坐標(biāo)   * @param zoomY    縮放后的Y坐標(biāo)   * @param zoomW    縮放后的截取寬度   * @param zoomH    縮放后的截取高度   * @param scaleWidth 縮放后圖片的寬度   * @param scaleHeight 縮放后的圖片高度   * @return 是否成功   * @throws Exception 任何異常均拋出   */  public static boolean imgCut(String path, int zoomX, int zoomY, int zoomW,                 int zoomH, int scaleWidth, int scaleHeight) throws Exception {    Image img;    ImageFilter cropFilter;    BufferedImage bi = ImageIO.read(new File(path));    int fileWidth = bi.getWidth();    int fileHeight = bi.getHeight();    double scale = (double) fileWidth / (double) scaleWidth;    double realX = zoomX * scale;    double realY = zoomY * scale;    double realW = zoomW * scale;    double realH = zoomH * scale;    if (fileWidth >= realW && fileHeight >= realH) {      Image image = bi.getScaledInstance(fileWidth, fileHeight, Image.SCALE_DEFAULT);      cropFilter = new CropImageFilter((int) realX, (int) realY, (int) realW, (int) realH);      img = Toolkit.getDefaultToolkit().createImage(          new FilteredImageSource(image.getSource(), cropFilter));      BufferedImage bufferedImage = new BufferedImage((int) realW, (int) realH, BufferedImage.TYPE_INT_RGB);      Graphics g = bufferedImage.getGraphics();      g.drawImage(img, 0, 0, null);      g.dispose();      //輸出文件      return ImageIO.write(bufferedImage, "JPEG", new File(path));    } else {      return true;    }  }

縮放比例scale一定要用double,并且寬高也要轉(zhuǎn)換成double后再相除,否則會(huì)變成求模運(yùn)算,這樣會(huì)降低精度,別小看這里的精度下降,最終的截圖效果根據(jù)圖片的縮放程度,誤差可是有可能被放大的很離譜的。

圖片壓縮

package com.magic.rent.tools;/** * 知識(shí)產(chǎn)權(quán)聲明:本文件自創(chuàng)建起,其內(nèi)容的知識(shí)產(chǎn)權(quán)即歸屬于原作者,任何他人不可擅自復(fù)制或模仿. * 創(chuàng)建者: wu  創(chuàng)建時(shí)間: 2016/12/15 * 類說(shuō)明: 縮略圖類(通用) 本java類能將jpg、bmp、png、gif圖片文件,進(jìn)行等比或非等比的大小轉(zhuǎn)換。 具體使用方法 * 更新記錄: */import com.magic.rent.exception.custom.BusinessException;import com.sun.image.codec.jpeg.JPEGCodec;import com.sun.image.codec.jpeg.JPEGImageEncoder;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.imageio.ImageIO;import java.awt.*;import java.awt.image.BufferedImage;import java.io.File;import java.io.FileOutputStream;public class CompressTools {  private File file; // 文件對(duì)象  private String inputDir; // 輸入圖路徑  private String outputDir; // 輸出圖路徑  private String inputFileName; // 輸入圖文件名  private String outputFileName; // 輸出圖文件名  private int outputWidth = 100; // 默認(rèn)輸出圖片寬  private int outputHeight = 100; // 默認(rèn)輸出圖片高  private boolean proportion = true; // 是否等比縮放標(biāo)記(默認(rèn)為等比縮放)  private static Logger logger = LoggerFactory.getLogger(CompressTools.class);  public CompressTools() {  }  public CompressTools(boolean proportion) {    this.proportion = proportion;  }  /**   * 設(shè)置輸入?yún)?shù)   *   * @param inputDir   * @param inputFileName   * @return   */  public CompressTools setInputInfo(String inputDir, String inputFileName) {    this.inputDir = inputDir;    this.inputFileName = inputFileName;    return this;  }  /**   * 設(shè)置輸出參數(shù)   *   * @param outputDir   * @param outputFileName   * @param outputHeight   * @param outputWidth   * @param proportion   * @return   */  public CompressTools setOutputInfo(String outputDir, String outputFileName, int outputHeight, int outputWidth, boolean proportion) {    this.outputDir = outputDir;    this.outputFileName = outputFileName;    this.outputWidth = outputWidth;    this.outputHeight = outputHeight;    this.proportion = proportion;    return this;  }  // 圖片處理  public boolean compress() throws Exception {    //獲得源文件    file = new File(inputDir);    if (!file.exists()) {      throw new BusinessException("文件不存在!");    }    Image img = ImageIO.read(file);    // 判斷圖片格式是否正確    if (img.getWidth(null) == -1) {      System.out.println(" can't read,retry!" + "<BR>");      return false;    } else {      int newWidth;      int newHeight;      // 判斷是否是等比縮放      if (this.proportion) {        // 為等比縮放計(jì)算輸出的圖片寬度及高度        double rate1 = ((double) img.getWidth(null)) / (double) outputWidth + 0.1;        double rate2 = ((double) img.getHeight(null)) / (double) outputHeight + 0.1;        // 根據(jù)縮放比率大的進(jìn)行縮放控制        double rate = rate1 > rate2 ? rate1 : rate2;        newWidth = (int) (((double) img.getWidth(null)) / rate);        newHeight = (int) (((double) img.getHeight(null)) / rate);      } else {        newWidth = outputWidth; // 輸出的圖片寬度        newHeight = outputHeight; // 輸出的圖片高度      }      long start = System.currentTimeMillis();      BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);      /*       * Image.SCALE_SMOOTH 的縮略算法 生成縮略圖片的平滑度的       * 優(yōu)先級(jí)比速度高 生成的圖片質(zhì)量比較好 但速度慢       */      tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);      FileOutputStream out = new FileOutputStream(outputDir);      // JPEGImageEncoder可適用于其他圖片類型的轉(zhuǎn)換      JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);      encoder.encode(tag);      out.close();      long time = System.currentTimeMillis() - start;      logger.info("[輸出路徑]:" + outputDir + "/t[圖片名稱]:" + outputFileName + "/t[壓縮前大小]:" + getPicSize() + "/t[耗時(shí)]:" + time + "毫秒");      return true;    }  }  /**   * 簡(jiǎn)單壓縮方法,壓縮后圖片將直接覆蓋源文件   *   * @param images   * @return   * @throws Exception   */  public boolean simpleCompress(File images) throws Exception {    setInputInfo(images.getPath(), images.getName());    setOutputInfo(images.getPath(), images.getName(), 300, 300, true);    return compress();  }  /**   * 獲取圖片大小,單位KB   *   * @return   */  private String getPicSize() {    return file.length() / 1024 + "KB";  }  public static void main(String[] args) throws Exception {    CompressTools compressTools = new CompressTools();    compressTools.setInputInfo("/Users/wu/Downloads/background.jpg", "background.jpg");    compressTools.setOutputInfo("/Users/wu/Downloads/background2.jpg", "background2.jpg", 633, 1920, false);    compressTools.compress();  }}

我專門(mén)把圖片壓縮寫(xiě)成了一個(gè)類。

其中可以看到一些關(guān)于文件路徑的方法,其實(shí)沒(méi)有什么特別的,就是截取后綴獲取路徑之類的,我這邊也貼出來(lái)吧,免得有些朋友看的云里霧里的。

package com.magic.rent.tools;import com.magic.rent.exception.custom.BusinessException;import javax.imageio.ImageIO;import java.awt.*;import java.awt.image.BufferedImage;import java.awt.image.CropImageFilter;import java.awt.image.FilteredImageSource;import java.awt.image.ImageFilter;import java.io.File;import java.util.ArrayList;/** * 知識(shí)產(chǎn)權(quán)聲明:本文件自創(chuàng)建起,其內(nèi)容的知識(shí)產(chǎn)權(quán)即歸屬于原作者,任何他人不可擅自復(fù)制或模仿. * 創(chuàng)建者: wu  創(chuàng)建時(shí)間: 2016/11/25 * 類說(shuō)明: * 更新記錄: */public class FileTools {  public static final int IMG = 1;  /**   * 獲取項(xiàng)目根目錄   *   * @return 根目錄   */  public static String getWebRootPath() {    return System.getProperty("web.root");  }  /**   * 獲取頭像目錄,若不存在則直接創(chuàng)建一個(gè)   *   * @param userID 用戶ID   * @return   */  public static String getPortraitPath(int userID) {    String realPath = getWebRootPath() + "img/portrait/" + userID + "/";    File file = new File(realPath);    //判斷文件夾是否存在,不存在則創(chuàng)建一個(gè)    if (!file.exists() || !file.isDirectory()) {      if (!file.mkdirs()) {        throw new BusinessException("創(chuàng)建頭像文件夾失敗!");      }    }    return realPath;  }  /**   * 重命名頭像文件   *   * @param fileName 文件名   * @return   */  public static String getPortraitFileName(String fileName) {    // 獲取文件后綴    String suffix = getSuffix(fileName);    return "portrait" + suffix;  }  /**   * 判斷文件后綴是否符合要求   *   * @param fileName  文件名   * @param allowSuffix 允許的后綴集合   * @return   * @throws Exception   */  public static boolean checkSuffix(String fileName, String[] allowSuffix) throws Exception {    String fileExtension = getSuffix(fileName);    boolean flag = false;    for (String extension : allowSuffix) {      if (fileExtension.equals(extension)) {        flag = true;      }    }    return flag;  }  public static String getSuffix(String fileName) {    return fileName.substring(fileName.lastIndexOf(".")).toLowerCase();  }  /**   * 將文件地址轉(zhuǎn)成鏈接地址   *   * @param filePath 文件路徑   * @param fileType 文件類型   * @return   */  public static String filePathToSRC(String filePath, int fileType) {    String href = "";    if (null != filePath && !filePath.equals("")) {      switch (fileType) {        case IMG:          if (filePath.contains("/img/")) {            int index = filePath.indexOf("/img/");            href = filePath.substring(index);          } else {            href = "";          }          return href;      }    }    return href;  }  /**   * 獲取指定文件或文件路徑下的所有文件清單   *   * @param fileOrPath 文件或文件路徑   * @return   */  public static ArrayList<File> getListFiles(Object fileOrPath) {    File directory;    if (fileOrPath instanceof File) {      directory = (File) fileOrPath;    } else {      directory = new File(fileOrPath.toString());    }    ArrayList<File> files = new ArrayList<File>();    if (directory.isFile()) {      files.add(directory);      return files;    } else if (directory.isDirectory()) {      File[] fileArr = directory.listFiles();      if (null != fileArr && fileArr.length != 0) {        for (File fileOne : fileArr) {          files.addAll(getListFiles(fileOne));        }      }    }    return files;  }  /**   * 截圖工具,根據(jù)截取的比例進(jìn)行縮放裁剪   *   * @param path    圖片路徑   * @param zoomX    縮放后的X坐標(biāo)   * @param zoomY    縮放后的Y坐標(biāo)   * @param zoomW    縮放后的截取寬度   * @param zoomH    縮放后的截取高度   * @param scaleWidth 縮放后圖片的寬度   * @param scaleHeight 縮放后的圖片高度   * @return 是否成功   * @throws Exception 任何異常均拋出   */  public static boolean imgCut(String path, int zoomX, int zoomY, int zoomW,                 int zoomH, int scaleWidth, int scaleHeight) throws Exception {    Image img;    ImageFilter cropFilter;    BufferedImage bi = ImageIO.read(new File(path));    int fileWidth = bi.getWidth();    int fileHeight = bi.getHeight();    double scale = (double) fileWidth / (double) scaleWidth;    double realX = zoomX * scale;    double realY = zoomY * scale;    double realW = zoomW * scale;    double realH = zoomH * scale;    if (fileWidth >= realW && fileHeight >= realH) {      Image image = bi.getScaledInstance(fileWidth, fileHeight, Image.SCALE_DEFAULT);      cropFilter = new CropImageFilter((int) realX, (int) realY, (int) realW, (int) realH);      img = Toolkit.getDefaultToolkit().createImage(          new FilteredImageSource(image.getSource(), cropFilter));      BufferedImage bufferedImage = new BufferedImage((int) realW, (int) realH, BufferedImage.TYPE_INT_RGB);      Graphics g = bufferedImage.getGraphics();      g.drawImage(img, 0, 0, null);      g.dispose();      //輸出文件      return ImageIO.write(bufferedImage, "JPEG", new File(path));    } else {      return true;    }  }}

順便一提:getWebRootPath這個(gè)方法,要生效,必須在Web.xml中做一個(gè)配置:

 <context-param>    <param-name>webAppRootKey</param-name>     <param-value>web.root</param-value>   </context-param>

否則是無(wú)法動(dòng)態(tài)獲取項(xiàng)目的本地路徑的。這個(gè)配置只要跟在Spring配置后面就行了,應(yīng)該就不會(huì)有什么大礙,其實(shí)就是獲取本地路徑然后設(shè)置到系統(tǒng)參數(shù)當(dāng)中。

好了,這就是整個(gè)插件的功能了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 佛冈县| 景泰县| 仁布县| 田阳县| 通化县| 铜山县| 松原市| 新密市| 平原县| 高雄市| 偃师市| 宜州市| 高清| 万全县| 宜宾市| 福贡县| 渭源县| 花莲市| 大连市| 运城市| 奉节县| 古田县| 兴隆县| 新昌县| 格尔木市| 登封市| 大石桥市| 昂仁县| 临湘市| 喀喇| 东台市| 宜良县| 黎城县| 海林市| 始兴县| 抚州市| 阿克苏市| 府谷县| 巢湖市| 吉隆县| 沅江市|