vue+springboot圖片上傳和顯示

1、前言

在使用spring boot作後臺系統,vue作前端系統,給客戶開發一套系統時候,其中用到了圖片上傳和顯示的功能。

2、環境

前端:vue
前端組件:tinymce
後臺:spring boot:2.2.3

3、正文

在客戶開發一套門戶管理系統時,集成了tinymce組件,用於編輯內容,springboot不一樣於其餘項目。  
是集成tomcat的,文件和圖片是不能直接訪問的。因此我在作集成富文本編輯器時,須要處理圖片的問題。
這個問題跟上傳頭像等顯示圖片的功能是相似的。下面記錄詳情步驟代碼。

第一步:集成tinymce組件

<!--引入tinymce組件-->
import Tinymce from '@/components/Tinymce'
<!--啓用tinymce組件-->
<el-form-item>
	<el-button type="primary" :loading="btnLoading" @click="onSubmit" >保 存</el-button>
</el-form-item>
<!--核心代碼-->
<template>
	<div class="page-container">
		<div class="page-title-section">
		
		</div>
		<div class="page-content-section">
			<div class="page-content-form">
				<el-form ref="dataForm" :model="formData" :rules="formRules" label-width="180px">
					
                    <el-form-item>
                        <div>
                            <tinymce v-model="formData.content" :height="300" />
                        </div>
                    </el-form-item>
					<el-form-item>
	                    <el-button type="primary" :loading="btnLoading" @click="onSubmit" >保 存</el-button>
					</el-form-item>
				</el-form>
			</div>
		</div>


	</div>
</template>
<script>

import Tinymce from '@/components/Tinymce'

export default {
    name:"contentEdit",
    components: {Tinymce},
	data(){
		return{
		
			formData:{
                content:'',
			},
			
		}
	},
	created() {
	
	},
	mounted() {},
	activated() {},
	deactivated() {},
	methods:{
		//表單提交
		onSubmit(){
			this.$refs['dataForm'].validate((valid) => {
				if (valid) {
					this.btnLoading = true
					this.$axios({
				        url: this.formData.id == '' ? '/products/save' : '/products/edit',
				        method: 'POST',
				        params: this.formData
				    }).then(res => {
				        //處理成功回調
				        const{ state,result , errmsg} = res.data
				        if( state && state == 1 ){
				        	this.$message.success('操做成功');
				        	this.$router.push( {path:'/products/list'} )
				        }else{
				        	return this.$message.error(errmsg || '操做失敗');
				        }

				    }).finally(() => {
				        this.btnLoading = false
				    })
				}
			})
		},


</script>
<!--Tinymce初始化代碼-->
initTinymce() {
      const _this = this
      window.tinymce.init({
        selector: `#${this.tinymceId}`,
        language: this.languageTypeList['en'],
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: plugins,
        end_container_on_empty_block: true,
        powerpaste_word_import: 'clean',
        code_dialog_height: 450,
        code_dialog_width: 1000,
        advlist_bullet_styles: 'square',
        advlist_number_styles: 'default',
        imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
        default_link_target: '_blank',
        link_title: false,
        nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
        //上傳圖片回調
        images_upload_handler:(blobInfo, success, failure) => {
             var xhr, formData;

              xhr = new XMLHttpRequest();
              xhr.withCredentials = false;
              xhr.open('POST', '/api/file/imageUpload');

              xhr.onload = function () {
                  var json;

                  if (xhr.status !== 200) {
                      failure('HTTP Error: ' + xhr.status);
                      return;
                  }

                  json = JSON.parse(xhr.responseText);
                  // console.log(json);
                  json.location = util.baseURL + json.data.filename; //在該位置,若是您的後端人員返回的字段已經包含json.location信息,則該處能夠省略
                  if (!json || typeof json.location !== 'string') {
                  failure('Invalid JSON: ' + xhr.responseText);
                      return;
                  }

                  success(json.location);
              };

              formData = new FormData();
              formData.append('file', blobInfo.blob(), blobInfo.filename());

            xhr.send(formData);

        },
        init_instance_callback: editor => {
          if (_this.value) {
            editor.setContent(_this.value)
          }
          _this.hasInit = true
          editor.on('NodeChange Change KeyUp SetContent', () => {
            this.hasChange = true
            this.$emit('input', editor.getContent())
          })
        },
        setup(editor) {
          editor.on('FullscreenStateChanged', (e) => {
            _this.fullscreen = e.state
          })
        }
        // 整合七牛上傳
        // images_dataimg_filter(img) {
        //   setTimeout(() => {
        //     const $image = $(img);
        //     $image.removeAttr('width');
        //     $image.removeAttr('height');
        //     if ($image[0].height && $image[0].width) {
        //       $image.attr('data-wscntype', 'image');
        //       $image.attr('data-wscnh', $image[0].height);
        //       $image.attr('data-wscnw', $image[0].width);
        //       $image.addClass('wscnph');
        //     }
        //   }, 0);
        //   return img
        // },
        // images_upload_handler(blobInfo, success, failure, progress) {
        //   progress(0);
        //   const token = _this.$store.getters.token;
        //   getToken(token).then(response => {
        //     const url = response.data.qiniu_url;
        //     const formData = new FormData();
        //     formData.append('token', response.data.qiniu_token);
        //     formData.append('key', response.data.qiniu_key);
        //     formData.append('file', blobInfo.blob(), url);
        //     upload(formData).then(() => {
        //       success(url);
        //       progress(100);
        //     })
        //   }).catch(err => {
        //     failure('出現未知問題,刷新頁面,或者聯繫程序員')
        //     console.log(err);
        //   });
        // },
      })
    },
    destroyTinymce() {
      const tinymce = window.tinymce.get(this.tinymceId)
      if (this.fullscreen) {
        tinymce.execCommand('mceFullScreen')
      }

      if (tinymce) {
        tinymce.destroy()
      }
    },
    setContent(value) {
      window.tinymce.get(this.tinymceId).setContent(value)
    },
    getContent() {
      window.tinymce.get(this.tinymceId).getContent()
    },
    imageSuccessCBK(arr) {
      const _this = this
      arr.forEach(v => {
        window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
      })
    }
  }

第二步:後臺代碼

@RequestMapping(value = "/imageUpload", method = RequestMethod.POST)
    public void imageUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
        try {
            logger.info("上傳圖片名 :" + file.getOriginalFilename());

            if (!file.isEmpty()) {
//				Properties p = new Properties();// 屬性集合對象
//	    		String path = RedisUtil.class.getClassLoader().getResource("").getPath()+"global.properties";
//	    		FileInputStream fis = new FileInputStream(path);// 屬性文件輸入流
//	    		p.load(fis);// 將屬性文件流裝載到Properties對象中
//	            fis.close();// 關閉流
//	            String uploadPath = p.getProperty("imgUpload.url");
//				//路徑名稱上加上-年/月日:yyyy/MMdd
//				uploadPath += "Uploads/"+new SimpleDateFormat("yyyy").format(new Date())+ "/" +new SimpleDateFormat("MMdd").format(new Date())+"/";

                String path= request.getServletContext().getRealPath("/");

path="/Users/qinshengfei/fsdownload";
                logger.error("path:"+path);
                //路徑名稱上加上-年/月日:yyyy/MMdd
                String uploadPath = File.separatorChar+"Uploads"+File.separatorChar+new SimpleDateFormat("yyyy").format(new Date())+
                        File.separatorChar +new SimpleDateFormat("MMdd").format(new Date())+File.separatorChar;

                // 文件上傳大小
                long fileSize = 10 * 1024 * 1024;
                //判斷文件大小是否超過
                if (file.getSize() > fileSize) {
                    backInfo(response, false, 2, "");
                    return;
                }
                //獲取上傳文件名稱
                String OriginalFilename = file.getOriginalFilename();
                //獲取文件後綴名:如jpg
                String fileSuffix = OriginalFilename.substring(OriginalFilename.lastIndexOf(".") + 1).toLowerCase();
                if (!Arrays.asList(TypeMap.get("image").split(",")).contains(fileSuffix)) {
                    backInfo(response, false, 3, "");
                    return;
                }
                //判斷是否有文件上傳
//				if (!ServletFileUpload.isMultipartContent(request)) {
//					backInfo(response, false, -1, "");
//					return;
//				}

                // 檢查上傳文件的目錄
                File uploadDir = new File(path+uploadPath);
                System.out.println(path+uploadPath);
                if (!uploadDir.isDirectory()) {
                    if (!uploadDir.mkdirs()) {
                        backInfo(response, false, 4, "");
                        return;
                    }
                }

                // 是否有上傳的權限
                if (!uploadDir.canWrite()) {
                    backInfo(response, false, 5, "");
                    return;
                }

                // 新文件名-加13爲隨機字符串
                String newname = getRandomString(13) +"." + fileSuffix;

                File saveFile = new File(path+uploadPath, newname);

                try {
                    file.transferTo(saveFile);

                    backInfo(response, true, 0, uploadPath+newname);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    backInfo(response, false, 1, "");
                    return;
                }
            } else {
                backInfo(response, false, -1, "");
                return;
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

    }

    // 返回信息
    private void backInfo(HttpServletResponse response, boolean flag, int message, String fileName) {
        fileName=fileName.replace("\\","/");
        String json = "";
        if (flag) {
            json = "{ \"status\": \"success";
        } else {
            json = "{ \"status\": \"error";
        }
        json += "\",\"fileName\": \"http://127.0.0.1:8090/file/show?fileName=" + fileName + "\",\"message\": \"" + message + "\"}";
        try {
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(json);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

第三步:後臺處理顯示圖片

/**
     * 顯示單張圖片
     * @return
     */
    @RequestMapping("/show")
    public ResponseEntity showPhotos(String fileName){

        try {
            String path = "/Users/qinshengfei/fsdownload";
            // 因爲是讀取本機的文件,file是必定要加上的, path是在application配置文件中的路徑
            logger.error("showPhotos:"+path+fileName);
            return ResponseEntity.ok(resourceLoader.getResource("file:" + path + fileName));
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

第四步:顯示效果

總結

這個例子是工做中遇到的一個問題,這裏只講述tinymce組件圖片功能。同時,工做中使用使用到了vue-cropper組件,原理相似。

ps:上述代碼使用中,若有問題,請聯繫公衆號:

相關文章
相關標籤/搜索