1. 程式人生 > 其它 >springboot+ueditor+OSS+若依框架+vue-cli3前後端分離

springboot+ueditor+OSS+若依框架+vue-cli3前後端分離

一、準備UEditor
在 官網下載合適的UEditor(這裡使用的是jsp版本)
解壓紅 色 框 部 分 是 前 端 需 要 的 \color{red}{紅色框部分是前端需要的}紅色框部分是前端需要的,j s p 文 件 夾 裡 面 的 是 後 臺 需 要 的 \color{blue}{jsp資料夾裡面的是後臺需要的}jsp資料夾裡面的是後臺需要的 

 

 

二、vue-ueditor-wrap元件
安裝vue-ueditor-wrap
npm i vue-ueditor-wrap
在main.js引入vue-ueditor-wrap
import VueUeditorWrap from 'vue-ueditor-wrap'
在main.js中進行全域性元件掛載
Vue.component('vue-ueditor-wrap', VueUeditorWrap)
參考vue-ueditor-wrap的github

三、前端配置UEditor
在public目錄下新建ueditor資料夾,將屬於前端的ueditor內容複製到該資料夾內 

 

 

在env檔案中配置V U E _ A P P _ U E D I T O R _ H O M E _ U R L \color{red}{VUE\_ APP\_UEDITOR\_HOME\_URL}VUE_APP_UEDITOR_HOME_URL和V U E _ A P P _ U E D I T O R _ S E R V E R _ U R L \color{red}{VUE\_APP\_UEDITOR\_SERVER\_URL}VUE_APP_UEDITOR_SERVER_URL,用於在vue檔案中使用vue-ueditor-wrap

 

# 開發環境配置
ENV = 'development'

# 若依管理系統/開發環境
VUE_APP_BASE_API = '/dev-api'

# 路由懶載入
VUE_CLI_BABEL_TRANSPILE_MODULES = true

VUE_APP_UEDITOR_HOME_URL = '/ueditor/'

VUE_APP_UEDITOR_SERVER_URL = '/dev-api/ueditor'
 

 

 

說明:

紅色部分:使用vue-ueditor-wrap需要配置的部分,這樣做的好處是,當ueditor的伺服器地址變化後,只需要修改環境配置檔案即可,而不是到每個用到的頁面去替換修改
藍色部分:表示在哪個環境(開發環境,生產環境,…環境)的字首,推薦配置的時候加上,這樣進行NGINX反向代理或者介面訪問的時候,可以統一入口url
綠色部分:ueditor後臺訪問地址
在vue.config.js中找到devServer配置Dev代理

// webpack-dev-server 相關配置
devServer: {
host: '0.0.0.0',
port: port,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
},
// 加入ueditor服務端地址的代理
[process.env.VUE_APP_UEDITOR_SERVER_URL]: {
target: `http://localhost:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_UEDITOR_SERVER_URL]: ''
}
},
},
disableHostCheck: true
},

四、後臺配置UEditor
在專案路徑下新建lib目錄,並將jsp資料夾下的jar包拷貝進去,值得注意的是,你需要檢視一下jsp資料夾下的jar包在專案裡面是不是已經有了,如果有的話,就不需要拷貝進去了,其 實 就 是 缺 哪 個 , 拷 貝 哪 個 \color{red}{其實就是缺哪個,拷貝哪個}其實就是缺哪個,拷貝哪個

 

 

因為我的專案裡面已經有了其他的jar包,所以就只匯入了json.jar和ueditor-1.1.2.jar

修改pom檔案引入本地jar包依賴

<dependency>
<groupId>ueditor</groupId>
<artifactId>ueditor</artifactId>
<version>1.1.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/ueditor-1.1.2.jar</systemPath>
</dependency>
<dependency>
<groupId>myjson</groupId>
<artifactId>myjson</artifactId>
<version>1.1.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/json.jar</systemPath>
</dependency>

修改pom檔案配置打包
這裡的關鍵配置是< i n c l u d e S y s t e m S c o p e > t r u e < / i n c l u d e S y s t e m S c o p e > \color{red}{<includeSystemScope>true</includeSystemScope>}<includeSystemScope>true</includeSystemScope>這句話,使得打包的時候,能夠將本地jar包一起包含進去

 

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>

複製config.json到resource目錄下

 

 

 

修改config.json的controller對映路徑,設定圖片訪問字首為空
修改ConfigManager讀取config.json,注意:這裡只列出了修改過的方法,由於篇幅原因,沒有將未修改的部分列出。修 改 部 分 均 已 添 加 注 釋 \color{red}{修改部分均已添加註釋}修改部分均已添加註釋

 

package com.baidu.ueditor;

import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

public final class ConfigManager {
private ConfigManager(String rootPath, String contextPath, String uri) throws FileNotFoundException, IOException {
rootPath = rootPath.replace("\\", "/");
this.rootPath = rootPath;
this.contextPath = contextPath;
// 這裡填寫配置檔案位置,雖然載入時沒有用到,但是起到了註釋的作用
this.originalPath = "src/main/resources/config.json";
this.initEnv();
}
private void initEnv() throws FileNotFoundException, IOException {
File file = new File(this.originalPath);
// 因為專案採用的jar包方式啟動,使用檔案方式獲取的話,是存在問題的
// 所以註釋掉
// if (!file.isAbsolute()) {
// file = new File(file.getAbsolutePath());
// }
this.parentPath = file.getParent();
String configContent = this.readFile(this.getConfigPath());

try {
JSONObject jsonConfig = new JSONObject(configContent);
this.jsonConfig = jsonConfig;
} catch (Exception var4) {
this.jsonConfig = null;
}
}

private String readFile(String path) throws IOException {
StringBuilder builder = new StringBuilder();
try {
// 在這裡並沒有使用傳進來的path,
// 而是使用spring的ClassPathResource來載入檔案
// 防止打包方式為jar時,找不到檔案的問題
ClassPathResource resource = new ClassPathResource("config.json");
InputStreamReader reader = new InputStreamReader(resource.getInputStream(), "UTF-8");
BufferedReader bfReader = new BufferedReader(reader);
String tmpContent = null;

while((tmpContent = bfReader.readLine()) != null) {
builder.append(tmpContent);
}

bfReader.close();
} catch (UnsupportedEncodingException var6) {
}

return this.filter(builder.toString());
}
}

 

五、配置類、工具類及Controller編寫

配置類

  • CloudApiConfig
    
    
  • package com.ruoyi.project.cloud.config;

    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;

    @Data
    @Component
    @ConfigurationProperties(prefix = "cloud")
    public class CloudApiConfig {

    private String accessKeyId;
    private String accessKeySecret;
    private String ossBucketName;
    private String ossEndpoint;
    private String smsSdkAppid;
    }

  • UploadImgConfig
    
    
  • package com.ruoyi.project.cloud.config;

    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;

    @Data
    @Component
    @ConfigurationProperties(prefix = "upload.img")
    public class UploadImgConfig {
    private String accessUrlPrefix = "";
    private long maxSize = -1;
    }

工具類

 

package com.ruoyi.project.cloud.util;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;
import com.ruoyi.project.cloud.config.CloudApiConfig;
import com.ruoyi.project.cloud.config.UploadImgConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Optional;

/**
* OSS工具類
*/
@Slf4j
public final class OssUtils {
private OssUtils() {}

/**
* 預設格式化方式
*/
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM/dd/HHmmssSSS", Locale.CHINESE);

public static final ClientConfiguration DEFAULT_CLIENT_CONFIGURATION = new ClientConfiguration();

/**
* 進行圖片上傳
*/
public static BaseState uploadImg(CloudApiConfig cloudApiConfig, UploadImgConfig uploadImgConfig, MultipartFile file) {
if (file == null || file.isEmpty()) {
return new BaseState(false, 7);
}
String contentType = file.getContentType();
if (!contentType.matches("^image/(?:png|jpg|jpeg|gif|bmp)$")) {// 檔案格式不匹配
return new BaseState(false, 8);
}
return upload(cloudApiConfig, uploadImgConfig, file);
}

/**
* 進行檔案上傳
* 返回值為BaseState是為了讓前端ueditor能夠識別
* 同時因為BaseState有返回上傳後的url,能夠滿足業務需求
*/
public static BaseState upload(CloudApiConfig cloudApiConfig, UploadImgConfig uploadImgConfig, MultipartFile file) {
if (file == null || file.isEmpty()) {
return new BaseState(false, 7);
}
String fileName = file.getOriginalFilename();
if (!validSize(file.getSize(), uploadImgConfig.getMaxSize())) {
return new BaseState(false, 1);
}
OSSClient ossClient = null;
try {
String suffix = "." + FilenameUtils.getExtension(fileName);
// 工程中可以有多個OSSClient,也可以只有一個OSSClient;OSSClient可以併發使用;OSS支援https,當您的安全需求更高時,可以使用https;OSSClient.shutdown之後不能再使用。
ossClient = new OSSClient(cloudApiConfig.getOssEndpoint(), cloudApiConfig.getAccessKeyId(),
cloudApiConfig.getAccessKeySecret(), DEFAULT_CLIENT_CONFIGURATION);
String dt = new StringBuilder()
.append(LocalDateTime.now().format(DATE_TIME_FORMATTER))
.append(RandomStringUtils.randomAlphabetic(6))
.append(suffix)
.toString();
ossClient.putObject(cloudApiConfig.getOssBucketName(), dt, file.getInputStream());
// 需要注意,這裡的uploadImgConfig.getAccessUrlPrefix()
// 雖然是上傳到OSS,但是很多情況下並不會直接通過OSS訪問上傳的檔案
// 因為可能涉及跨域等其他問題,所以採用配置訪問字首拼接上oss路徑的方式來避免此問題
String accessUrl = new StringBuilder()
.append(uploadImgConfig.getAccessUrlPrefix())
.append("/").append(dt).toString();
BaseState storageState = new BaseState(true);
storageState.putInfo("size", file.getSize());
storageState.putInfo("title", file.getName());
storageState.putInfo("url", accessUrl);
storageState.putInfo("type", suffix);
storageState.putInfo("original", "");
return storageState;
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
Optional.ofNullable(ossClient).ifPresent(OSSClient::shutdown);
}
return new BaseState(false, 6);
}

/**
* 校驗檔案大小
* @param dataLength dataLength
* @param maxSize maxSize
* @return boolean
*/
public static boolean validSize(long dataLength, long maxSize) {
return maxSize == -1 || dataLength <= maxSize;
}
}

 

Controller

package com.ruoyi.project.cloud.controller;

import com.baidu.ueditor.ActionEnter;
import com.ruoyi.project.cloud.config.CloudApiConfig;
import com.ruoyi.project.cloud.config.UploadImgConfig;
import com.ruoyi.project.cloud.util.OssUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONException;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Slf4j
@RestController
// 前端配置的訪問地址,必須和這裡的相同,這樣才能正確獲取到ueditor配置
@RequestMapping("/ueditor")
public class UeditorController {
@Resource
private UploadImgConfig uploadImgConfig;
@Resource
private CloudApiConfig cloudApiConfig;

/**
* 獲取ueditor配置資訊時會走此方法
* 由於ueditor並不能單獨指定是通過那個URL獲取配置
* 而是通過URL後面攜帶的action引數來進行識別
* 所以這裡加上了if ("config".equals(action))的判斷
*/
@GetMapping
public void config(HttpServletRequest request, HttpServletResponse response) throws JSONException {
String action = request.getParameter("action");
if ("config".equals(action)) {
response.setContentType("application/json");
String rootPath = request.getSession().getServletContext().getRealPath("/");
try {
ActionEnter actionEnter = new ActionEnter(request, rootPath);
String exec = actionEnter.exec();
PrintWriter writer = response.getWriter();
writer.write(exec);
writer.flush();
writer.close();
} catch (IOException e) {
log.error("獲取ueditor配置失敗");
}
}
}

/**
* 進行檔案上傳時
* post方式會走這個方法
* 這裡並沒有直接用JOSN.toJSONString方法來轉換結果為json字串
* 因為查看了轉換後的結果為{"state":true}
* 這樣的json字串是不能被前端ueditor正確解析的
* 所以採用了BaseState自己的toJSONString方法
*/
@PostMapping
public String upload(HttpServletRequest request) {
List<MultipartFile> files = ((StandardMultipartHttpServletRequest) request).getMultiFileMap().get("upfile");
MultipartFile file = CollectionUtils.isNotEmpty(files) ? files.get(0) : null;
return OssUtils.uploadImg(cloudApiConfig, uploadImgConfig, file).toJSONString();
}
}

 

六、使用

在需要用到的地方直接使用,myConfig是對ueditor的一些配置項進行自定義

<vue-ueditor-wrap v-model="這裡是繫結的屬性" :config="myConfig"></vue-ueditor-wrap>

在data裡面配置myConfig

myConfig: {
// 編輯器不自動被內容撐高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 400,
// 初始容器寬度
initialFrameWidth: '100%',
// 這裡的serverUrl,UEDITOR_HOME_URL用到的值就是在環境配置檔案中統一設定的
serverUrl: process.env.VUE_APP_UEDITOR_SERVER_URL,
UEDITOR_HOME_URL: process.env.VUE_APP_UEDITOR_HOME_URL
}

進行測試

 

 

 

 

問題總結
前端路徑對映問題
在配置前端env檔案時,建議路徑加上相應的VUE_APP_BASE_API值
如:

VUE_APP_BASE_API = '/dev-api'
VUE_APP_UEDITOR_SERVER_URL = '/dev-api/ueditor'
1
2
假設沒有環境標識字首:VUE_APP_UEDITOR_SERVER_URL = ‘/ueditor’
那麼部署後將會導致專案路徑為/dev-api/xxxx,而ueditor的訪問路徑為/ueditor
這樣將導致NGINX反向代理時需要多配置一個對映,多專案部署時,將導致衝突

後臺打包問題
配置打包時引入本地jar,一定不要使用這種方式,如果你配置了多個resource,而其他的resource又包含了專案配置檔案,那還好,如果像下面這樣的話,那就只有一個字,坑
當 配 置 成 這 樣 時 , 打 包 後 發 現 項 目 配 置 文 件 並 不 存 在 於 j a r 包 中 \color{red}{當配置成這樣時,打包後發現專案配置檔案並不存在於jar包中}當配置成這樣時,打包後發現專案配置檔案並不存在於jar包中

<build>
<resources>
<resource>
<directory>lib</directory>
<targetPath>/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>
</build>

正確的方式是使用< i n c l u d e S y s t e m S c o p e > t r u e < / i n c l u d e S y s t e m S c o p e > \color{red}{<includeSystemScope>true</includeSystemScope>}<includeSystemScope>true</includeSystemScope>

 

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>

圖片訪問路徑問題
當配置了自己的accessUrlPrefix後,在config.json中的imageUrlPrefix一定要配置成空字串,否則結果將是config.json中的字首+自己配置的字首,最後導致圖片無法正常顯示。

ueditor彈出窗被遮擋
找到ueditor.config.js的65行左右,修改zIndex的值大一些,這樣就可以解決彈出窗被遮擋的問題


————————————————
版權宣告:本文為CSDN博主「大叔熊貓」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/xyllp/article/details/106311944