環境:maven+SpringMVC + Spring + MyBatis + MySqlhtml
本文主要說明如何使用input上傳文件到服務器指定目錄,或保存到數據庫中;如何從數據庫下載文件,和顯示圖像文件並實現縮放。java
將文件存儲在數據庫中,通常是存文件的byte數組,對應的數據庫數據類型爲blob。mysql
首先要建立數據庫,此處使用MySql數據庫。web
注意:文中給出的代碼多爲節選重要片斷,並不齊全。spring
1. 前期準備sql
使用maven建立一個springMVC+spring+mybatis+mysql的項目。數據庫
關於如何整合Spring+mybatis+mysql,請見MyBatis簡介與配置MyBatis+Spring+MySql:apache
關於SpringMVC環境的搭建請見:使用Eclipse構建Maven的SpringMVC項目:編程
在前臺html中,form的enctype爲multipart/form-data。注意input、select的name要和StudentForm中成員一一對應。
上傳的url爲addAction.do,此action方法的參數中使用StudentForm來映射提交的數據。此時就能夠獲取到提交的文件的數據。而後咱們就對文件進行操做。
建立PHOTO_TBL表:PHOTO_DATA字段用於存放文件,類型爲MyBatis的longblob;而後寫Mapper的Java接口PhotoMapper:包括增刪改查;mapper的xml文件:對應JAVA接口的sql語句。
而且須要Spring配置文件添加一個bean的聲明。
下面給出html、action、StudentForm的代碼片斷;建立PHOTO_TBL表的sql、PhotoMapper.java接口代碼、PhotoMapper.xml文件代碼。
1.1 html的form表單寫法
- <form action="<c:url value='addAction.do' />" method="post" enctype="multipart/form-data">
- <table>
- <tr>
- <td width="100" align="right">照片:</td>
- <td><input type="file" name="studentPhoto"/></td>
- </tr>
- </table>
- <input type="submit">
- </form>
1.2 action方法
- /**
- * 新增 - 提交
- */
- @RequestMapping(value = "addAction.do")
- public String add_action(ModelMap model, StudentForm form) {
-
- }
1.3 StudentForm類
- package liming.student.manager.web.model;
-
- import org.springframework.web.multipart.MultipartFile;
-
- public class StudentForm extends GeneralForm {
-
- private String studentName;
- private int studentSex;
- private String studentBirthday;
- private MultipartFile studentPhoto;
-
- }
1.4 建立PHOTO_TBL
- CREATE TABLE PHOTO_TBL
- (
- PHOTO_ID VARCHAR(100) PRIMARY KEY,
- PHOTO_DATA LONGBLOB,
- FILE_NAME VARCHAR(10)
- );
1.5 PhotoMapper接口
- @Repository
- @Transactional
- public interface PhotoMapper {
-
- public void createPhoto(PhotoEntity entity);
-
- public int deletePhotoByPhotoId(String photoId);
-
- public int updatePhotoDate(@Param("photoId") String photoId, @Param("photoDate") byte[] photoDate);
-
- public PhotoEntity getPhotoEntityByPhotoId(String photoId);
-
- }
1.6 PhotoMapper.xml文件
包括增、刪、改、查。其中新增中的photoId使用的是mysql自定義函數自動生成主鍵。在操做blob時須要制定typeHandler爲"org.apache.ibatis.type.BlobTypeHandler。insert、update時參數後面須要指定,resultMap中須要指定。
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="liming.student.manager.data.PhotoMapper">
- <resultMap type="liming.student.manager.data.model.PhotoEntity" id="photoMapper_resultMap_photoEntity">
- <id property="photoId" column="PHOTO_ID" javaType="String" jdbcType="VARCHAR" />
- <result property="photoData" column="PHOTO_DATA" javaType="byte[]" jdbcType="BLOB" typeHandler="org.apache.ibatis.type.BlobTypeHandler" />
- <result property="fileName" column="FILE_NAME" javaType="String" jdbcType="VARCHAR" />
- </resultMap>
-
- <insert id="createPhoto" parameterType="liming.student.manager.data.model.PhotoEntity">
- <selectKey keyProperty="photoId" resultType="String" order="BEFORE">
- select nextval('photo')
- </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>
-
- <delete id="deletePhotoByPhotoId">
- DELETE FROM PHOTO_TBL
- WHERE PHOTO_ID = #{photoId, jdbcType=VARCHAR}
- </delete>
-
- <update id="updatephotoData" >
- UPDATE PHOTO_TBL
- SET PHOTO_DATA = #{photoData, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},
- FILE_NAME = #{fileName, jdbcType=VARCHAR}
- WHERE PHOTO_ID = #{photoId, jdbcType=VARCHAR}
- </update>
-
- <select id="getPhotoEntityByPhotoId" resultMap="photoMapper_resultMap_photoEntity">
- SELECT PHOTO_ID,
- PHOTO_DATA,
- FILE_NAME
- FROM PHOTO_TBL
- WHERE PHOTO_ID = #{photoId, jdbcType=VARCHAR}
- </select>
- </mapper>
1.7 spring配置文件
須要Spring配置文件添加一個org.springframework.web.multipart.commons.CommonsMultipartResolver的bean的聲明。
- <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
- <property name="maxUploadSize" value="1073741824" />
- </bean>
2. 將文件到服務器上
- private static final String uploadFilePath = "d:\\temp_upload_file\\";
-
- /**
- * 新增 - 提交 – 只保存文件到服務器上
- */
- @RequestMapping(value = "addAction.do")
- public String add_action(ModelMap model, StudentForm form) {
- try {
- MultipartFile uploadFile = form.getStudentPhoto();
- String filename = uploadFile.getOriginalFilename();
- InputStream is = uploadFile.getInputStream();
- // 若是服務器已經存在和上傳文件同名的文件,則輸出提示信息
- File tempFile = new File(uploadFilePath + filename);
- if (tempFile.exists()) {
- boolean delResult = tempFile.delete();
- System.out.println("刪除已存在的文件:" + delResult);
- }
- // 開始保存文件到服務器
- if (!filename.equals("")) {
- FileOutputStream fos = new FileOutputStream(uploadFilePath + filename);
- byte[] buffer = new byte[8192]; // 每次讀8K字節
- int count = 0;
- // 開始讀取上傳文件的字節,並將其輸出到服務端的上傳文件輸出流中
- while ((count = is.read(buffer)) > 0) {
- fos.write(buffer, 0, count); // 向服務端文件寫入字節流
- }
- fos.close(); // 關閉FileOutputStream對象
- is.close(); // InputStream對象
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
3. 將文件上傳到數據庫中
- /**
- * 新增 - 提交 – 保存文件到數據庫
- */
- @RequestMapping(value = "addAction.do")
- public String add_action(ModelMap model, StudentForm form) {
- InputStream is = form.getStudentPhoto().getInputStream();
- byte[] studentPhotoData = new byte[(int) form.getStudentPhoto().getSize()];
- is.read(studentPhotoData);
- String fileName = form.getStudentPhoto().getOriginalFilename();
- PhotoEntity photoEntity = new PhotoEntity();
- photoEntity.setPhotoData(studentPhotoData);
- photoEntity.setFileName(fileName);
- this.photoMapper.createPhoto(photoEntity);
- }
4.下載文件
下載文件須要將byte數組還原成文件。
首先使用mybatis將數據庫中的byte數組查出來,指定文件名(包括格式)。而後使用OutputStream將文件輸入
- @RequestMapping(value = "downPhotoById")
- public void downPhotoByStudentId(String id, final HttpServletResponse response){
- PhotoEntity entity = this.photoMapper.getPhotoEntityByPhotoId(id);
- byte[] data = entity.getPhotoData();
- String fileName = entity.getFileName()== null ? "照片.png" : entity.getFileName();
- fileName = URLEncoder.encode(fileName, "UTF-8");
- response.reset();
- response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
- response.addHeader("Content-Length", "" + data.length);
- response.setContentType("application/octet-stream;charset=UTF-8");
- OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
- outputStream.write(data);
- outputStream.flush();
- outputStream.close();
- }
- <a href="<%=request.getContextPath() %>/downPhotoById.do?id=8000001">下載照片</a>
5. 顯示byte圖片文件
- @RequestMapping(value = "getPhotoById")
- public void getPhotoById (String id, final HttpServletResponse response){
- PhotoEntity entity = this.photoMapper.getPhotoEntityByPhotoId(id);
- byte[] data = entity.getPhotoData();
- response.setContentType("image/jpeg");
- response.setCharacterEncoding("UTF-8");
- OutputStream outputSream = response.getOutputStream();
- InputStream in = new ByteArrayInputStream(data);
- int len = 0;
- byte[] buf = new byte[1024];
- while ((len = in.read(buf, 0, 1024)) != -1) {
- outputSream.write(buf, 0, len);
- }
- outputSream.close();
- }
- <img src="<%=request.getContextPath() %>/getPhotoById.do?id=8000001"/>
6. 按長寬等比例縮放圖片
- @RequestMapping(value = "getPhotoId")
- public void getPhotoById (String id, int width, int height, final HttpServletResponse response){
- PhotoEntity entity = this.photoMapper.getPhotoEntityByPhotoId(id);
- byte[] data = entity.getPhotoData();
- if (width != 0 && height != 0) {
- data = scaleImage(data, width, height);
- }
- response.setContentType("image/jpeg");
- response.setCharacterEncoding("UTF-8");
- OutputStream outputSream = response.getOutputStream();
- InputStream in = new ByteArrayInputStream(data);
- int len = 0;
- byte[] buf = new byte[1024];
- while ((len = in.read(buf, 0, 1024)) != -1) {
- outputSream.write(buf, 0, len);
- }
- outputSream.close();
- }
-
- public static byte[] scaleImage(byte[] data, int width, int height) throws IOException {
- BufferedImage buffered_oldImage = ImageIO.read(new ByteArrayInputStream(data));
- int imageOldWidth = buffered_oldImage.getWidth();
- int imageOldHeight = buffered_oldImage.getHeight();
- double scale_x = (double) width / imageOldWidth;
- double scale_y = (double) height / imageOldHeight;
- double scale_xy = Math.min(scale_x, scale_y);
- int imageNewWidth = (int) (imageOldWidth * scale_xy);
- int imageNewHeight = (int) (imageOldHeight * scale_xy);
- BufferedImage buffered_newImage = new BufferedImage(imageNewWidth, imageNewHeight, BufferedImage.TYPE_INT_RGB);
- buffered_newImage.getGraphics().drawImage(buffered_oldImage.getScaledInstance(imageNewWidth, imageNewHeight, BufferedImage.SCALE_SMOOTH), 0, 0, null);
- buffered_newImage.getGraphics().dispose();
- ByteArrayOutputStream outPutStream = new ByteArrayOutputStream();
- ImageIO.write(buffered_newImage, "jpeg", outPutStream);
- return outPutStream.toByteArray();
- }
- <img src="<%=request.getContextPath() %>/getPhotoById.do?id=8000001&width=300&height=300"/>
評論
你這句話 有問題吧
實體類裏 是 private MultipartFile studentPhoto;
MultipartFile 類型的
set的時候byte[] 類型
類型不符合 編譯都通不過的