首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java Web 頭像上傳實戰:SpringMVC + Bootstrap + Cropper 前後端完整方案

     編輯:Java 綜合教學

方案概覽

一、前端頁面:模態框內集成 Cropper

核心結構:<form> 包裹文件輸入 + 隱藏域(剪裁坐標 x,y,width,height,rotate),Cropper 綁定 <div class="avatar-wrapper"> 容器,預覽區實時同步。

<!-- 簡化關鍵片段 -->
<div class="container" id="crop-avatar">
  <div class="avatar-view" title="點擊更換頭像">
    <img src="images/default.jpg" alt="Avatar" />
  </div>

  <div class="modal fade" id="avatar-modal">
    <form class="avatar-form" action="/vip/image/updateuserlogo" method="post" enctype="multipart/form-data">
      <div class="modal-body">
        <div class="avatar-upload">
          <input type="hidden" class="avatar-src" name="avatar_src" />
          <input type="hidden" class="avatar-data" name="avatar_data" />
          <label for="avatarInput">頭像上傳</label>
          <input type="file" class="avatar-input" id="avatarInput" name="avatar_file" accept="image/*" />
        </div>
        <div class="row">
          <div class="col-md-9"><div class="avatar-wrapper"></div></div>
          <div class="col-md-3">
            <div class="avatar-preview preview-md"><label>100×100</label></div>
            <div class="avatar-preview preview-sm"><label>50×50</label></div>
            <div class="avatar-preview preview-xs"><label>30×30</label></div>
          </div>
        </div>
        <!-- 隱藏域:Cropper 實時寫入剪裁參數 -->
        <input type="hidden" name="x" id="dataX" />
        <input type="hidden" name="y" id="dataY" />
        <input type="hidden" name="width" id="dataWidth" />
        <input type="hidden" name="height" id="dataHeight" />
        <input type="hidden" name="degree" id="dataRotate" />
      </div>
      <div class="modal-footer">
        <button type="submit" class="btn btn-primary avatar-save">確定</button>
      </div>
    </form>
  </div>
</div>

二、Cropper 初始化與交互邏輯

$(function () {
    var $image = $('#image'); // avatar-wrapper 內動態生成的 img
    var options = {
        aspectRatio: 1,           // 頭像通常 1:1
        viewMode: 1,              // 限制選區在圖片內
        preview: '.avatar-preview', // 綁定多尺寸預覽區
        crop: function (e) {      // 實時回寫隱藏域
            $('#dataX').val(Math.round(e.detail.x));
            $('#dataY').val(Math.round(e.detail.y));
            $('#dataWidth').val(Math.round(e.detail.width));
            $('#dataHeight').val(Math.round(e.detail.height));
            $('#dataRotate').val(e.detail.rotate);
        }
    };

    // 文件選擇 → 讀取為 Blob URL → 替換 Cropper 圖片
    $('#avatarInput').on('change', function () {
        var file = this.files[0];
        if (!/^image\/\w+$/.test(file.type)) return alert('請選擇圖片');
        var blobURL = URL.createObjectURL(file);
        $image.one('built.cropper', function () { URL.revokeObjectURL(blobURL); })
              .cropper('reset').cropper('replace', blobURL);
    });

    // 旋轉按鈕委託
    $('.docs-buttons').on('click', '[data-method]', function () {
        var data = $(this).data();
        $image.cropper(data.method, data.option);
    });

    $image.cropper(options);
});

三、後端控制器:SpringMVC 接收 MultipartFile + 剪裁參數

@Controller
@RequestMapping("/{vip}/image")
public class ImageAction {
    @Resource private IImageService imageService;
    @Resource private UUserService userService;
    @Resource private BSiteService siteService;

    @RequestMapping("/updateuserlogo")
    @ResponseBody
    public IImageDto updateUserLogo(
            @PathVariable String vip,
            @RequestParam Integer x, @RequestParam Integer y,
            @RequestParam Integer width, @RequestParam Integer height,
            @RequestParam Integer degree,
            @RequestParam("avatar_file") MultipartFile imageFile,
            HttpServletRequest request) {

        IImageDto dto = new IImageDto();
        if (imageFile == null || imageFile.isEmpty()) return dto;

        try {
            // 1. 構建存儲路徑:/upload/image/{userId}/{yyyy}/{MM}/{dd}/
            String realPath = request.getServletContext().getRealPath("/");
            UUserDto user = (UUserDto) request.getSession().getAttribute("user");
            String relPath = "upload/image/" + user.getUserId() + "/"
                    + DateUtils.getYear(new Date()) + "/"
                    + DateUtils.getMonth(new Date()) + "/"
                    + DateUtils.getDay(new Date()) + "/";
            File dir = new File(realPath + relPath);
            if (!dir.exists()) dir.mkdirs();

            // 2. 保存原圖
            String fileName = System.currentTimeMillis() + ".jpg";
            File srcFile = new File(dir, fileName);
            imageFile.transferTo(srcFile);

            // 3. 圖像處理管道:旋轉+剪裁 → 多規格縮放
            String base = realPath + relPath + System.currentTimeMillis();
            boolean ok = true;
            ok &= ImageUtils.cutAndRotateImage(srcFile.getPath(), base + "_s.jpg", x, y, width, height, degree);
            ok &= ImageUtils.scale2(base + "_s.jpg", base + "_s_200.jpg", 200, 200, true);
            ok &= ImageUtils.scale2(base + "_s.jpg", base + "_s_100.jpg", 100, 100, true);
            ok &= ImageUtils.scale2(base + "_s.jpg", base + "_s_50.jpg", 50, 50, true);
            ok &= ImageUtils.scale2(base + "_s.jpg", base + "_s_30.jpg", 30, 30, true);
            ok &= ImageUtils.scale2(srcFile.getPath(), base + "_200.jpg", 200, 200, true);

            if (ok) {
                // 4. 持久化記錄 & 更新用戶/站點頭像
                dto.setUUserDto(user);
                dto.setName(fileName);
                dto.setUrl(relPath + fileName);
                dto.setPreviewUrl(relPath + fileName.replace(".jpg", "_200.jpg"));
                dto.setExt3(relPath + fileName.replace(".jpg", "_s_200.jpg"));
                dto.setExt4(relPath + fileName.replace(".jpg", "_s_100.jpg"));
                // ... 設置其他字段:時間、寬高、客戶端信息、狀態等
                int id = imageService.addImage(dto);
                if (id > 0) {
                    user.setPortrait(relPath + fileName.replace(".jpg", "_s_30.jpg"));
                    userService.updateUser(user);
                    dto.setLoginFlag("1");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dto;
    }
}

四、ImageUtils 核心工具類:AWT 圖像處理全集

封裝 ImageIO、BufferedImage、AffineTransform,提供:

  • 旋轉:Rotate(Image, angle) 計算外接矩形,避免裁切;cutAndRotateImage 組合旋轉+剪裁。
  • 剪裁:ImageReadParam.setSourceRegion(Rectangle) 直接解碼目標區域,內存效率高。
  • 縮放:scale2 支持等比縮放 + 白邊填充(bb=true),生成多規格頭像(200/100/50/30)。
  • 水印:圖片水印(透明度 AlphaComposite)+ 文字水印(字體/顏色/位置)。
  • 工具方法:獲取寬高、格式轉換、灰度化。
// 關鍵方法簽名
public static boolean cutAndRotateImage(String src, String dest, int x, int y, int w, int h, int degree);
public static boolean scale2(String src, String dest, int targetW, int targetH, boolean padWhite);
public static BufferedImage Rotate(Image src, int angle); // 返回旋轉後完整圖像
public static boolean pressImage(String watermark, String src, String dest, int x, int y, float alpha);
public static boolean pressText(String text, String src, String dest, String font, int style, Color color, int size, int x, int y, float alpha);

五、關鍵注意點與優化建議

  1. 前端剪裁坐標 基於 Cropper 顯示尺寸,若原圖極大需在後端按比例換算,或前端限制上傳尺寸(max-width)。
  2. 大文件上傳:配置 MultipartResolver 的 maxUploadSize,必要時分片上傳/直傳 OSS。
  3. 圖片格式統一:統一轉 JPEG 輸出,避免 PNG 透明通道導致白邊/黑邊問題。
  4. 異步化:圖像處理耗時,建議異步隊列處理,前端輪詢/websocket 推送結果。
  5. 安全:校驗 Content-Type、魔數、文件大小;存儲路徑隨機化,防遍歷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
層次技術棧職責
前端展示Bootstrap 3響應式佈局、模態框、表單樣式
圖片剪裁Cropper.js圖片預覽、拖拽選區、旋轉縮放、坐標輸出
後端控制SpringMVC文件接收、參數綁定、業務編排、JSON 響應
圖像處理Java AWT (ImageIO)旋轉、剪裁、縮放、水印、格式轉換