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

SpringMVC 整合 MyBatis 實現文件上傳下載與圖片處理

     編輯:Java 相關知識

技術棧與環境

  • 構建工具:Maven
  • 框架:SpringMVC + Spring + MyBatis
  • 數據庫:MySQL (BLOB 類型存儲二進制數據)
  • 文件上傳:CommonsMultipartResolver

核心配置

1. Multipart 解析器配置

<bean id="multipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="1073741824" /> <!-- 1GB -->
</bean>

2. 前端表單關鍵屬性

<form action="addAction.do" method="post" enctype="multipart/form-data">
    <input type="file" name="studentPhoto" />
    <input type="submit" value="上傳" />
</form>

關鍵點:enctype="multipart/form-data",input name 需與 Form 對象屬性名一致。

3. 表單對象 (StudentForm)

public class StudentForm extends GeneralForm {
    private String studentName;
    private int studentSex;
    private String studentBirthday;
    private MultipartFile studentPhoto; // 對應文件上傳欄位
    // getter/setter 省略
}

數據庫設計

CREATE TABLE PHOTO_TBL (
    PHOTO_ID VARCHAR(100) PRIMARY KEY,
    PHOTO_DATA LONGBLOB,        -- 存儲文件二進制數據
    FILE_NAME VARCHAR(100)      -- 原始文件名
);

MyBatis Mapper 實現

實體類 (PhotoEntity)

public class PhotoEntity {
    private String photoId;
    private byte[] photoData;
    private String fileName;
    // getter/setter
}

Mapper 接口 (PhotoMapper)

@Repository
@Transactional
public interface PhotoMapper {
    void createPhoto(PhotoEntity entity);
    int deletePhotoByPhotoId(String photoId);
    int updatePhotoData(@Param("photoId") String photoId, @Param("photoData") byte[] photoData);
    PhotoEntity getPhotoEntityByPhotoId(String photoId);
}

XML 映射關鍵配置 (PhotoMapper.xml)

<resultMap type="PhotoEntity" id="photoResultMap">
    <id property="photoId" column="PHOTO_ID" jdbcType="VARCHAR" />
    <result property="photoData" column="PHOTO_DATA" 
           javaType="byte[]" jdbcType="BLOB" 
           typeHandler="org.apache.ibatis.type.BlobTypeHandler" />
    <result property="fileName" column="FILE_NAME" jdbcType="VARCHAR" />
</resultMap>

<insert id="createPhoto" parameterType="PhotoEntity">
    <selectKey keyProperty="photoId" resultType="String" order="BEFORE">
        SELECT UUID() -- 或自定義序列生成策略
    </selectKey>
    INSERT INTO PHOTO_TBL (PHOTO_ID, PHOTO_DATA, FILE_NAME)
    VALUES (
        #{photoId, jdbcType=VARCHAR},
        #{photoData, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},
        #{fileName, jdbcType=VARCHAR}
    )
</insert>

<select id="getPhotoEntityByPhotoId" resultMap="photoResultMap">
    SELECT PHOTO_ID, PHOTO_DATA, FILE_NAME FROM PHOTO_TBL WHERE PHOTO_ID = #{photoId, jdbcType=VARCHAR}
</select>

關鍵點:BLOB 類型必須指定 typeHandler="org.apache.ibatis.type.BlobTypeHandler",否則讀寫異常。

業務邏輯實現

方案一:文件存服務器磁盤

@RequestMapping("addAction.do")
public String uploadToServer(StudentForm form) {
    MultipartFile file = form.getStudentPhoto();
    String filename = file.getOriginalFilename();
    File target = new File("d:/temp_upload_file/", filename);
    
    // 衝突處理:刪除同名舊文件
    if (target.exists()) target.delete();
    
    try (InputStream is = file.getInputStream();
         FileOutputStream fos = new FileOutputStream(target)) {
        byte[] buffer = new byte[8192];
        int count;
        while ((count = is.read(buffer)) > 0) {
            fos.write(buffer, 0, count);
        }
    } catch (IOException e) { e.printStackTrace(); }
    return "success";
}

方案二:文件存數據庫 BLOB

@RequestMapping("addAction.do")
public String uploadToDb(StudentForm form) {
    MultipartFile file = form.getStudentPhoto();
    byte[] data = file.getBytes(); // 簡化讀取
    
    PhotoEntity entity = new PhotoEntity();
    entity.setPhotoData(data);
    entity.setFileName(file.getOriginalFilename());
    photoMapper.createPhoto(entity);
    return "success";
}

文件下載與圖片展示

通用文件下載

@RequestMapping("downPhotoById")
public void download(String id, HttpServletResponse response) {
    PhotoEntity entity = photoMapper.getPhotoEntityByPhotoId(id);
    byte[] data = entity.getPhotoData();
    String filename = entity.getFileName() != null ? entity.getFileName() : "photo.png";
    
    response.reset();
    response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(filename, "UTF-8") + "\"");
    response.addHeader("Content-Length", String.valueOf(data.length));
    response.setContentType("application/octet-stream;charset=UTF-8");
    
    try (OutputStream os = new BufferedOutputStream(response.getOutputStream())) {
        os.write(data);
        os.flush();
    } catch (IOException e) { e.printStackTrace(); }
}

前端調用:<a href="downPhotoById.do?id=8000001">下載照片</a>

圖片直接顯示

@RequestMapping("getPhotoById")
public void showImage(String id, HttpServletResponse response) {
    PhotoEntity entity = photoMapper.getPhotoEntityByPhotoId(id);
    byte[] data = entity.getPhotoData();
    
    response.setContentType("image/jpeg");
    response.setCharacterEncoding("UTF-8");
    
    try (InputStream in = new ByteArrayInputStream(data);
         OutputStream out = response.getOutputStream()) {
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
    } catch (IOException e) { e.printStackTrace(); }
}

前端調用:<img src="getPhotoById.do?id=8000001" />

圖片等比縮放顯示

@RequestMapping("getPhotoById")
public void showScaledImage(String id, int width, int height, HttpServletResponse response) {
    PhotoEntity entity = photoMapper.getPhotoEntityByPhotoId(id);
    byte[] data = entity.getPhotoData();
    
    if (width > 0 && height > 0) {
        data = scaleImage(data, width, height);
    }
    // 輸出邏輯同 showImage...
}

public static byte[] scaleImage(byte[] data, int targetW, int targetH) throws IOException {
    BufferedImage src = ImageIO.read(new ByteArrayInputStream(data));
    double scale = Math.min((double) targetW / src.getWidth(), (double) targetH / src.getHeight());
    int newW = (int) (src.getWidth() * scale);
    int newH = (int) (src.getHeight() * scale);
    
    BufferedImage dest = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_RGB);
    dest.getGraphics().drawImage(src.getScaledInstance(newW, newH, Image.SCALE_SMOOTH), 0, 0, null);
    
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(dest, "jpeg", baos);
    return baos.toByteArray();
}

前端調用:<img src="getPhotoById.do?id=8000001&width=300&height=300" />

架構選型建議

存儲方式優點缺點適用場景
數據庫 BLOB事務一致性強、備份簡單、權限隨數據庫數據庫膨脹快、讀寫性能較差、併發壓力大小文件、強一致性要求、文檔管理系統
服務器磁盤性能高、不佔用數據庫資源、易於 CDN 分發事務管理複雜、備份需單獨處理、多節點同步難圖片/視頻等大文件、高併發讀取、靜態資源
對象存儲 (OSS/S3)無限擴展、高可用、內置 CDN、生命周期管理引入外部依賴、成本較高、延遲略高生產環境推薦、海量文件、分佈式架構

總結

本文完整演示了 SpringMVC + MyBatis 文件上傳下載全流程,涵蓋磁盤存儲、數據庫 BLOB 存儲、圖片流式輸出、等比縮放等實戰技巧。生產環境建議採用對象存儲 + 數據庫存元數據架構,利用簽名直傳減輕應用服務器壓力,MyBatis 僅負責元數據 CRUD,實現職責分離與高性能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved