springboot整合百度富文本編輯器ueditor實現圖片上傳和文件上傳以及回顯

来源:https://www.cnblogs.com/rainbow-1/archive/2022/06/16/16383695.html
-Advertisement-
Play Games

springboot整合ueditor實現圖片上傳和文件上傳功能 寫在前面: 在閱讀本篇之前,請先按照我的這篇隨筆完成對ueditor的前期配置工作: springboot+layui 整合百度富文本編輯器ueditor入門使用教程(踩過的坑)https://www.cnblogs.com/rain ...


springboot整合ueditor實現圖片上傳和文件上傳功能

寫在前面:

在閱讀本篇之前,請先按照我的這篇隨筆完成對ueditor的前期配置工作:

springboot+layui 整合百度富文本編輯器ueditor入門使用教程(踩過的坑)https://www.cnblogs.com/rainbow-1/p/16365016.html

在完成對ueditor的基本配置後,圖片和文件的上傳主要是後端文件的配置,下麵簡單介紹一下步驟。

實現效果:


一、修改ueditor.config.js配置文件

首先第一步,要完成對配置文件的修改。預設的ueditor配置里,對配置文件的讀取是通過controller.jsp完成的,

因為springboot項目中,靜態jsp文件的訪問是不被允許的,所以我們需要重寫這段讀取配置文件信息的代碼,也就是通過寫自己的一個controller來完成這個過程,同時自定義圖片和文件上傳的位置等信息。

預設的controller.jsp位置如下圖:

這時候我們修改配置文件調用資源的介面名稱,打開ueditor.config.js,如下圖所示:

我通過server_url,拿到了項目的根路徑,然後拼接後面的/science-2.0/api/ueditor/config(項目名稱/路由名稱)拿到完整的訪問路徑。

二、編寫一個新的控制器(CommonController)

這個類就是我們第一步所修改的部分指向的這個控制器,它要完成對config.json文件(該文件位於jsp文件夾下,裡面是關於文件上傳的一些配置信息)的讀取,同時要完成對文件上傳的具體實現。

  • 下麵我們先來看一下config.json文件(/jsp目錄下)

​ 主要看一下圖片上傳配置的部分:

我們需要修改的部分如圖所示:basePath指的是你希望保存的磁碟位置(這個目錄最好事先存在),imageActionName是我們處理上傳圖片功能的那個路由,也就是在controller里是什麼,這裡就是什麼。

下麵的文件上傳部分類似:

  • 下麵給出完成的controller代碼
import com.alibaba.fastjson.JSONException;
import com.baidu.ueditor.ActionEnter;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ClassUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.net.URL;
@RestController
@RequestMapping("/api/ueditor")
public class CommonController {
    /**
     * 判斷當前系統是否是Windows系統
     * @return true:Windows系統,false:Linux系統
     */
    private boolean isWindowsSystem(){
        String property = System.getProperty("os.name").toLowerCase();
        return property.contains("windows");
    }

    /**
     * 獲取Ueditor的配置文件
     * @return
     */
    @RequestMapping("/config")
    public void getConfigInfo(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {
        System.out.println("讀取ueditor配置文件!");
        response.setContentType("application/json");
        String rootPath = "";
        // 判斷當前系統是否是Windows系統
        if(isWindowsSystem()){
            URL Path = ClassUtils.getDefaultClassLoader().getResource("");
            String afterPath = URLDecoder.decode(Path.getPath(), "UTF-8");
            rootPath = afterPath+ "static/UEditor/jsp";
        } else {
            // 將config.json文件放在jar包同級目錄下
            rootPath = "/usr/local/zgxsoft/yunapp-backend/service";
        }
        System.out.println("rootPath:{}"+ rootPath);
        try {
            String exec = new ActionEnter(request, rootPath, "/config.json").exec();
            PrintWriter writer = response.getWriter();
            writer.write(exec);
            writer.flush();
            writer.close();
        } catch (IOException | JSONException e) {
            e.printStackTrace();
        }
    }


    /**
     * Ueditor上傳文件
     * 這裡以上傳圖片為例,圖片上傳後,imgPath將存儲圖片的保存路徑,返回到編輯器中做展示
     * @param upfile
     * @return
     */

    @RequestMapping("uploadimage")
    @ResponseBody
    public Map<String,String> uploadImage(@RequestParam("upfile") MultipartFile upfile, HttpServletRequest request) throws IOException {
        System.out.println("上傳圖片!");
        //文件原名稱
        String fileName = upfile.getOriginalFilename();

        // 保存文件的新名字

        String timeFileName = DateHelper.getDateToString(new Date());
        String nowName = timeFileName+"_"+UUID.randomUUID()+fileName.substring(upfile.getOriginalFilename().lastIndexOf("."));
        String uploadPath = "";
        if(!upfile.isEmpty()){
            String path = "D:/science-2.0/";
            File f = new File(path);
            if(!f.exists()){
                // 第一次上傳文件新建文件夾
                f.mkdirs();
            }
            uploadPath = path+nowName;
            //按照路徑新建文件
            File newFile = new File(uploadPath);
            if(!newFile.exists()){
                newFile.createNewFile();
            }
            //複製
            FileCopyUtils.copy(upfile.getBytes(), newFile);
        }
        //返回結果信息(UEditor官方要求這個json格式)
        Map<String,String> map = new HashMap<String,String >();
        //是否上傳成功
        map.put("state", "SUCCESS");
        //現在文件名稱
        map.put("title", nowName);
        //文件原名稱
        map.put("original", fileName);
        //文件類型 .+尾碼名
        map.put("type", fileName.substring(upfile.getOriginalFilename().lastIndexOf(".")));
        //文件路徑
        // map.put("url", uploadPath);    // 瀏覽器不能直接訪問項目外目錄的圖片等文件,需要做虛擬路徑映射
        map.put("url", "/PathImage/"+nowName);  // 這個路徑的 /PathImage/ 是在配置類里指定的映射到本地的絕對路徑
        //文件大小(位元組數)
        map.put("size", upfile.getSize()+"");
        return map;
    }

    @RequestMapping("uploadfile")
    @ResponseBody
    public Map<String,String> uploadfile(@RequestParam("upfile") MultipartFile upfile, HttpServletRequest request) throws IOException {
        System.out.println("上傳文件!");
        //文件原名稱
        String fileName = upfile.getOriginalFilename();

        // 保存文件的新名字

        String timeFileName = DateHelper.getDateToString(new Date());
        String nowName = timeFileName+"_"+UUID.randomUUID()+fileName.substring(upfile.getOriginalFilename().lastIndexOf("."));
        //System.out.println("name---:"+nowName);
        String uploadPath = "";
        if(!upfile.isEmpty()){
            String path = "D:/science-2.0/";
            File f = new File(path);
            if(!f.exists()){
                // 第一次上傳文件新建文件夾
                f.mkdirs();
            }
            uploadPath = path+nowName;
            //按照路徑新建文件
            File newFile = new File(uploadPath);
            if(!newFile.exists()){
                newFile.createNewFile();
            }
            //複製
            FileCopyUtils.copy(upfile.getBytes(), newFile);
        }
        //返回結果信息(UEditor官方要求這個json格式)
        Map<String,String> map = new HashMap<String,String >();
        //是否上傳成功
        map.put("state", "SUCCESS");
        //現在文件名稱
        map.put("title", nowName);
        //文件原名稱
        map.put("original", fileName);
        //文件類型 .+尾碼名
        map.put("type", fileName.substring(upfile.getOriginalFilename().lastIndexOf(".")));
        //文件路徑
        // map.put("url", uploadPath);    // 瀏覽器不能直接訪問項目外目錄的圖片等文件,需要做虛擬路徑映射
        map.put("url", "/PathFile/"+nowName);  // 這個路徑的 /PathImage/ 是在配置類里指定的映射到本地的絕對路徑
        //文件大小(位元組數)
        map.put("size", upfile.getSize()+"");
        return map;
    }
}

這部分代碼裡面的內容簡單說一下:

  1. /api/ueditor/config,這個路徑是我們讀取config.json文件的地方,在這裡我們完成了對json文件的載入,這時候我們在點擊控制項上的上傳按鈕才可以被監聽到,那麼我們後面重寫的圖片和文件上傳的路徑才有了意義。
  2. /api/ueditor/uploadimage,這個路徑就是寫圖片上傳的部分,這部分代碼註釋比較詳細,讀者可以仔細閱讀。
  3. /api/ueditor/uploadfile,這個就是文件上傳的部分,和圖片類似(圖片實際上也是屬於文件範疇)

!!!!!!

劃重點:

下麵還需要完成一個重要的配置,我們目前完成的只是對文件的上傳存儲到磁碟的功能,但是我們還有一件事也很重要,那就是回顯,所謂回顯,就是把圖片和文件等對前端提供展示。那麼這部分要怎麼寫呢,其實道理很簡單,就是對本地磁碟的文件提供一個訪問的路徑就可以了。

我們回到最開始的話題,我們現在做的事情其實是放棄了控制項原有的controller,而自己寫了一個新的,這是因為springboot框架的訪問限制,那麼圖片和文件的回顯也就需要我們自己寫不可以直接用config.json中的預設配置,因為那裡其實已經不能用了,我們要重寫就得重寫得徹徹底底。

預設是這樣的:

"imageUrlPrefix":"", /* 圖片訪問路徑首碼 */
"imagePathFormat": "/document/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
                            /* {filename} 會替換成原文件名,配置這項需要註意中文亂碼問題 */
                            /* {rand:6} 會替換成隨機數,後面的數字是隨機數的位數 */
                            /* {time} 會替換成時間戳 */
                            /* {yyyy} 會替換成四位年份 */
                            /* {yy} 會替換成兩位年份 */
                            /* {mm} 會替換成兩位月份 */
                            /* {dd} 會替換成兩位日期 */
                            /* {hh} 會替換成兩位小時 */
                            /* {ii} 會替換成兩位分鐘 */
                            /* {ss} 會替換成兩位秒 */
                            /* 非法字元 \ : * ? " < > | */
                            /* 具請體看線上文檔: fex.baidu.com/ueditor/#use-format_upload_filename */
    

ueditor為我們提供了重寫之後需要給伺服器返回數據的格式:

{
    "state": "SUCCESS",
    "url": "upload/demo.jpg",
    "title": "demo.jpg",
    "original": "demo.jpg"
}
//這是官網提供的格式,我們還可以再加一些,比如上面的controller是這麼寫的:
//返回結果信息(UEditor官方要求這個json格式)
        Map<String,String> map = new HashMap<String,String >();
        //是否上傳成功
        map.put("state", "SUCCESS");
        //現在文件名稱
        map.put("title", nowName);
        //文件原名稱
        map.put("original", fileName);
        //文件類型 .+尾碼名
        map.put("type", fileName.substring(upfile.getOriginalFilename().lastIndexOf(".")));
        //文件路徑
        // map.put("url", uploadPath);    // 瀏覽器不能直接訪問項目外目錄的圖片等文件,需要做虛擬路徑映射
        map.put("url", "/PathFile/"+nowName);  // 這個路徑的 /PathImage/ 是在配置類里指定的映射到本地的絕對路徑
        //文件大小(位元組數)
        map.put("size", upfile.getSize()+"");

註意看map.put("url", "/PathFile/"+nowName);這段代碼

這段代碼完成的就是對應本地文件路徑的伺服器訪問路徑,所以我們需要再寫一個映射器文件完成對這個路徑的映射關係。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfiguration extends WebMvcConfigurerAdapter {
    /**
     * Spring Boot中有預設的靜態資源訪問路徑,瀏覽器也不允許訪問項目目錄外的資源文件
     * 添加一些虛擬路徑的映射
     * 設置靜態資源路徑和上傳文件的路徑
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // /** 表示該目錄下所有文件
        registry.addResourceHandler("/PathImage/**").addResourceLocations("file:/D:/science-2.0/");
        registry.addResourceHandler("/PathFile/**").addResourceLocations("file:/D:/science-2.0/");
        super.addResourceHandlers(registry);
    }
}

其中由於文件名的日期尾碼是根據當前系統時間生成的,所以又封裝了一個日期類,代碼如下:

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateHelper {
    public static String getDateToString(Date time) {
        SimpleDateFormat formatter;
        formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        String Time = formatter.format(time);
        return Time;
    }
}

小結一下

這裡我們主要在寫後端的代碼,我們一共需要三個類:一個是主控制器,一個是映射關係類,還有一個是日期處理類(這三個文件放一起就行)。註意裡面的一些關鍵路徑,和config.json里的路徑是一一對應的,一旦寫錯伺服器是無法訪問到的。還有映射關係類里的路徑也需要寫正確,否則伺服器只能完成對文件的上傳而無法完成對文件的回顯。


附ueditor.config.js

/**
 * ueditor完整配置項
 * 可以在這裡配置整個編輯器的特性
 */
/**************************提示********************************
 * 所有被註釋的配置項均為UEditor預設值。
 * 修改預設配置請首先確保已經完全明確該參數的真實用途。
 * 主要有兩種修改方案,一種是取消此處註釋,然後修改成對應參數;另一種是在實例化編輯器時傳入對應參數。
 * 當升級編輯器時,可直接使用舊版配置文件替換新版配置文件,不用擔心舊版配置文件中因缺少新功能所需的參數而導致腳本報錯。
 **************************提示********************************/

(function () {

    /**
     * 編輯器資源文件根路徑。它所表示的含義是:以編輯器實例化頁面為當前路徑,指向編輯器資源文件(即dialog等文件夾)的路徑。
     * 鑒於很多同學在使用編輯器的時候出現的種種路徑問題,此處強烈建議大家使用"相對於網站根目錄的相對路徑"進行配置。
     * "相對於網站根目錄的相對路徑"也就是以斜杠開頭的形如"/myProject/ueditor/"這樣的路徑。
     * 如果站點中有多個不在同一層級的頁面需要實例化編輯器,且引用了同一UEditor的時候,此處的URL可能不適用於每個頁面的編輯器。
     * 因此,UEditor提供了針對不同頁面的編輯器可單獨配置的根路徑,具體來說,在需要實例化編輯器的頁面最頂部寫上如下代碼即可。
     * 當然,需要令此處的URL等於對應的配置。
     * window.UEDITOR_HOME_URL = "/xxxx/xxxx/";
     */
   window.UEDITOR_HOME_URL = "/UEditor/";


    var server_url = window.location.protocol+"//"+window.location.hostname+":"+window.location.port;
    //alert("rul"+server_url);
    /**
     * 配置項主體。註意,此處所有涉及到路徑的配置別遺漏URL變數。
     */
    var ser_url=server_url+"/api/ueditor/config";
    var ip=window.location.hostname;
    if(ip=="10.1.10.148"){
        window.UEDITOR_HOME_URL = "/science-2.0/UEditor/";
        ser_url= server_url+"/science-2.0/api/ueditor/config";
    }
    var URL = window.UEDITOR_HOME_URL || getUEBasePath();
    window.UEDITOR_CONFIG = {

        //為編輯器實例添加一個路徑,這個不能被註釋
        UEDITOR_HOME_URL: URL

        // 伺服器統一請求介面路徑
        , serverUrl:  ser_url

        //工具欄上的所有的功能按鈕和下拉框,可以在new編輯器的實例時選擇自己需要的重新定義
        , toolbars: [[
            'undo', 'redo', '|', 'bold', 'italic', 
            'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 
            'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', 
            '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 
            'selectall', 'cleardoc', '|', 'rowspacingtop', 'rowspacingbottom', 'lineheight', 
            '|', 'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|', 'directionalityltr', 
            'directionalityrtl', 'indent', '|', 'justifyleft', 'justifycenter', 'justifyright',
            'justifyjustify', '|', 'touppercase', 'tolowercase', '|','link', 'unlink', 'anchor', 
            '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|', 'simpleupload',
            'insertimage', 'emotion', 'scrawl', 'insertvideo', 'music', 'attachment', 'map', 
            'pagebreak', 'template','|','horizontal', 'date', 'time', 'spechars', '|',
            'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow',
            'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells',
            'splittorows', 'splittocols', 'charts', '|', 'preview', 'searchreplace'
        ]]
        //當滑鼠放在工具欄上時顯示的tooltip提示,留空支持自動多語言配置,否則以配置值為準
        //,labelMap:{
        //    'anchor':'', 'undo':''
        //}

        //語言配置項,預設是zh-cn。有需要的話也可以使用如下這樣的方式來自動多語言切換,當然,前提條件是lang文件夾下存在對應的語言文件:
        //lang值也可以通過自動獲取 (navigator.language||navigator.browserLanguage ||navigator.userLanguage).toLowerCase()
        //,lang:"zh-cn"
        //,langPath:URL +"lang/"

        //主題配置項,預設是default。有需要的話也可以使用如下這樣的方式來自動多主題切換,當然,前提條件是themes文件夾下存在對應的主題文件:
        //現有如下皮膚:default
        //,theme:'default'
        //,themePath:URL +"themes/"

        //,zIndex : 900     //編輯器層級的基數,預設是900

        //針對getAllHtml方法,會在對應的head標簽中增加該編碼設置。
        //,charset:"utf-8"

        //若實例化編輯器的頁面手動修改的domain,此處需要設置為true
        //,customDomain:false

        //常用配置項目
        //,isShow : true    //預設顯示編輯器

        //,textarea:'editorValue' // 提交表單時,伺服器獲取編輯器提交內容的所用的參數,多實例時可以給容器name屬性,會將name給定的值最為每個實例的鍵值,不用每次實例化的時候都設置這個值

        //,initialContent:'歡迎使用ueditor!'    //初始化編輯器的內容,也可以通過textarea/script給值,看官網例子

        //,autoClearinitialContent:true //是否自動清除編輯器初始內容,註意:如果focus屬性設置為true,這個也為真,那麼編輯器一上來就會觸發導致初始化的內容看不到了

        //,focus:false //初始化時,是否讓編輯器獲得焦點true或false

        //如果自定義,最好給p標簽如下的行高,要不輸入中文時,會有跳動感
        //,initialStyle:'p{line-height:1em}'//編輯器層級的基數,可以用來改變字體等

        //,iframeCssUrl: URL + '/themes/iframe.css' //給編輯區域的iframe引入一個css文件

        //indentValue
        //首行縮進距離,預設是2em
        //,indentValue:'2em'

        //,initialFrameWidth:1000  //初始化編輯器寬度,預設1000
        //,initialFrameHeight:320  //初始化編輯器高度,預設320

        //,readonly : false //編輯器初始化結束後,編輯區域是否是只讀的,預設是false

        //,autoClearEmptyNode : true //getContent時,是否刪除空的inlineElement節點(包括嵌套的情況)

        //啟用自動保存
        //,enableAutoSave: true
        //自動保存間隔時間, 單位ms
        //,saveInterval: 500

        //,fullscreen : false //是否開啟初始化時即全屏,預設關閉

        //,imagePopup:true      //圖片操作的浮層開關,預設打開

        //,autoSyncData:true //自動同步編輯器要提交的數據
        //,emotionLocalization:false //是否開啟表情本地化,預設關閉。若要開啟請確保emotion文件夾下包含官網提供的images表情文件夾

        //粘貼只保留標簽,去除標簽所有屬性
        //,retainOnlyLabelPasted: false

        //,pasteplain:false  //是否預設為純文本粘貼。false為不使用純文本粘貼,true為使用純文本粘貼
        //純文本粘貼模式下的過濾規則
        //'filterTxtRules' : function(){
        //    function transP(node){
        //        node.tagName = 'p';
        //        node.setStyle();
        //    }
        //    return {
        //        //直接刪除及其位元組點內容
        //        '-' : 'script style object iframe embed input select',
        //        'p': {$:{}},
        //        'br':{$:{}},
        //        'div':{'$':{}},
        //        'li':{'$':{}},
        //        'caption':transP,
        //        'th':transP,
        //        'tr':transP,
        //        'h1':transP,'h2':transP,'h3':transP,'h4':transP,'h5':transP,'h6':transP,
        //        'td':function(node){
        //            //沒有內容的td直接刪掉
        //            var txt = !!node.innerText();
        //            if(txt){
        //                node.parentNode.insertAfter(UE.uNode.createText(' &nbsp; &nbsp;'),node);
        //            }
        //            node.parentNode.removeChild(node,node.innerText())
        //        }
        //    }
        //}()

        //,allHtmlEnabled:false //提交到後臺的數據是否包含整個html字元串

        //insertorderedlist
        //有序列表的下拉配置,值留空時支持多語言自動識別,若配置值,則以此值為準
        //,'insertorderedlist':{
        //      //自定的樣式
        //        'num':'1,2,3...',
        //        'num1':'1),2),3)...',
        //        'num2':'(1),(2),(3)...',
        //        'cn':'一,二,三....',
        //        'cn1':'一),二),三)....',
        //        'cn2':'(一),(二),(三)....',
        //     //系統自帶
        //     'decimal' : '' ,         //'1,2,3...'
        //     'lower-alpha' : '' ,    // 'a,b,c...'
        //     'lower-roman' : '' ,    //'i,ii,iii...'
        //     'upper-alpha' : '' , lang   //'A,B,C'
        //     'upper-roman' : ''      //'I,II,III...'
        //}

        //insertunorderedlist
        //無序列表的下拉配置,值留空時支持多語言自動識別,若配置值,則以此值為準
        //,insertunorderedlist : { //自定的樣式
        //    'dash' :'— 破折號', //-破折號
        //    'dot':' 。 小圓圈', //系統自帶
        //    'circle' : '',  // '○ 小圓圈'
        //    'disc' : '',    // '● 小圓點'
        //    'square' : ''   //'■ 小方塊'
        //}
        //,listDefaultPaddingLeft : '30'//預設的左邊縮進的基數倍
        //,listiconpath : 'http://bs.baidu.com/listicon/'//自定義標號的路徑
        //,maxListLevel : 3 //限制可以tab的級數, 設置-1為不限制

        //,autoTransWordToList:false  //禁止word中粘貼進來的列表自動變成列表標簽

        //fontfamily
        //字體設置 label留空支持多語言自動切換,若配置,則以配置值為準
        ,'fontfamily':[
            { label:'',name:'songti',val:'宋體,SimSun'},
            { label: '', name: 'SimSun', val: '仿宋,SimSun' },
            { label:'',name:'FangSong_GB2312',val:'仿宋_GB2312 ,FangSong_GB2312'},
            { label:'',name:'kaiti',val:'楷體,楷體_GB2312, SimKai'},
            { label:'',name:'yahei',val:'微軟雅黑,Microsoft YaHei'},
            { label:'',name:'heiti',val:'黑體, SimHei'},
            { label:'',name:'lishu',val:'隸書, SimLi'},
            { label:'',name:'andaleMono',val:'andale mono'},
            { label:'',name:'arial',val:'arial, helvetica,sans-serif'},
            { label:'',name:'arialBlack',val:'arial black,avant garde'},
            { label:'',name:'comicSansMs',val:'comic sans ms'},
            { label:'',name:'impact',val:'impact,chicago'},
            { label:'',name:'timesNewRoman',val:'times new roman'}
        ]

        //fontsize
        //字型大小
        //,'fontsize':[10, 11, 12, 14, 16, 18, 20, 24, 36]

        //paragraph
        //段落格式 值留空時支持多語言自動識別,若配置,則以配置值為準
        //,'paragraph':{'p':'', 'h1':'', 'h2':'', 'h3':'', 'h4':'', 'h5':'', 'h6':''}

        //rowspacingtop
        //段間距 值和顯示的名字相同
        //,'rowspacingtop':['5', '10', '15', '20', '25']

        //rowspacingBottom
        //段間距 值和顯示的名字相同
        //,'rowspacingbottom':['5', '10', '15', '20', '25']

        //lineheight
        //行內間距 值和顯示的名字相同
        //,'lineheight':['1', '1.5','1.75','2', '3', '4', '5']

        //customstyle
        //自定義樣式,不支持國際化,此處配置值即可最後顯示值
        //block的元素是依據設置段落的邏輯設置的,inline的元素依據BIU的邏輯設置
        //儘量使用一些常用的標簽
        //參數說明
        //tag 使用的標簽名字
        //label 顯示的名字也是用來標識不同類型的標識符,註意這個值每個要不同,
        //style 添加的樣式
        //每一個對象就是一個自定義的樣式
        //,'customstyle':[
        //    {tag:'h1', name:'tc', label:'', style:'border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;'},
        //    {tag:'h1', name:'tl',label:'', style:'border-bottom:#ccc 2px solid;padding:0 4px 0 0;margin:0 0 10px 0;'},
        //    {tag:'span',name:'im', label:'', style:'font-style:italic;font-weight:bold'},
        //    {tag:'span',name:'hi', label:'', style:'font-style:italic;font-weight:bold;color:rgb(51, 153, 204)'}
        //]

        //打開右鍵菜單功能
        //,enableContextMenu: true
        //右鍵菜單的內容,可以參考plugins/contextmenu.js裡邊的預設菜單的例子,label留空支持國際化,否則以此配置為準
        //,contextMenu:[
        //    {
        //        label:'',       //顯示的名稱
        //        cmdName:'selectall',//執行的command命令,當點擊這個右鍵菜單時
        //        //exec可選,有了exec就會在點擊時執行這個function,優先順序高於cmdName
        //        exec:function () {
        //            //this是當前編輯器的實例
        //            //this.ui._dialogs['inserttableDialog'].open();
        //        }
        //    }
        //]

        //快捷菜單
        //,shortcutMenu:["fontfamily", "fontsize", "bold", "italic", "underline", "forecolor", "backcolor", "insertorderedlist", "insertunorderedlist"]

        //elementPathEnabled
        //是否啟用元素路徑,預設是顯示
        //,elementPathEnabled : true

        //wordCount
        //,wordCount:true          //是否開啟字數統計
        //,maximumWords:10000       //允許的最大字元數
        //字數統計提示,{#count}代表當前字數,{#leave}代表還可以輸入多少字元數,留空支持多語言自動切換,否則按此配置顯示
        //,wordCountMsg:''   //當前已輸入 {#count} 個字元,您還可以輸入{#leave} 個字元
        //超出字數限制提示  留空支持多語言自動切換,否則按此配置顯示
        //,wordOverFlowMsg:''    //<span style="color:red;">你輸入的字元個數已經超出最大允許值,伺服器可能會拒絕保存!</span>

        //tab
        //點擊tab鍵時移動的距離,tabSize倍數,tabNode什麼字元做為單位
        //,tabSize:4
        //,tabNode:'&nbsp;'

        //removeFormat
        //清除格式時可以刪除的標簽和屬性
        //removeForamtTags標簽
        //,removeFormatTags:'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var'
        //removeFormatAttributes屬性
        //,removeFormatAttributes:'class,style,lang,width,height,align,hspace,valign'

        //undo
        //可以最多回退的次數,預設20
        //,maxUndoCount:20
        //當輸入的字元數超過該值時,保存一次現場
        //,maxInputCount:1

        //autoHeightEnabled
        // 是否自動長高,預設true
        //,autoHeightEnabled:true

        //scaleEnabled
        //是否可以拉伸長高,預設true(當開啟時,自動長高失效)
        //,scaleEnabled:false
        //,minFrameWidth:800    //編輯器拖動時最小寬度,預設800
        //,minFrameHeight:220  //編輯器拖動時最小高度,預設220

        //autoFloatEnabled
        //是否保持toolbar的位置不動,預設true
        //,autoFloatEnabled:true
        //浮動時工具欄距離瀏覽器頂部的高度,用於某些具有固定頭部的頁面
        //,topOffset:30
        //編輯器底部距離工具欄高度(如果參數大於等於編輯器高度,則設置無效)
        //,toolbarTopOffset:400

        //設置遠程圖片是否抓取到本地保存
        //,catchRemoteImageEnable: true //設置是否抓取遠程圖片

        //pageBreakTag
        //分頁標識符,預設是_ueditor_page_break_tag_
        //,pageBreakTag:'_ueditor_page_break_tag_'

        //autotypeset
        //自動排版參數
        //,autotypeset: {
        //    mergeEmptyline: true,           //合併空行
        //    removeClass: true,              //去掉冗餘的class
        //    removeEmptyline: false,         //去掉空行
        //    textAlign:"left",               //段落的排版方式,可以是 left,right,center,justify 去掉這個屬性表示不執行排版
        //    imageBlockLine: 'center',       //圖片的浮動方式,獨占一行劇中,左右浮動,預設: center,left,right,none 去掉這個屬性表示不執行排版
        //    pasteFilter: false,             //根據規則過濾沒事粘貼進來的內容
        //    clearFontSize: false,           //去掉所有的內嵌字型大小,使用編輯器預設的字型大小
        //    clearFontFamily: false,         //去掉所有的內嵌字體,使用編輯器預設的字體
        //    removeEmptyNode: false,         // 去掉空節點
        //    //可以去掉的標簽
        //    removeTagNames: {標簽名字:1},
        //    indent: false,                  // 行首縮進
        //    indentValue : '2em',            //行首縮進的大小
        //    bdc2sb: false,
        //    tobdc: false
        //}

        //tableDragable
        //表格是否可以拖拽
        //,tableDragable: true



        //sourceEditor
        //源碼的查看方式,codemirror 是代碼高亮,textarea是文本框,預設是codemirror
        //註意預設codemirror只能在ie8+和非ie中使用
        //,sourceEditor:"codemirror"
        //如果sourceEditor是codemirror,還用配置一下兩個參數
        //codeMirrorJsUrl js載入的路徑,預設是 URL + "third-party/codemirror/codemirror.js"
        //,codeMirrorJsUrl:URL + "third-party/codemirror/codemirror.js"
        //codeMirrorCssUrl css載入的路徑,預設是 URL + "third-party/codemirror/codemirror.css"
        //,codeMirrorCssUrl:URL + "third-party/codemirror/codemirror.css"
        //編輯器初始化完成後是否進入源碼模式,預設為否。
        //,sourceEditorFirst:false

        //iframeUrlMap
        //dialog內容的路徑 ~會被替換成URL,垓屬性一旦打開,將覆蓋所有的dialog的預設路徑
        //,iframeUrlMap:{
        //    'anchor':'~/dialogs/anchor/anchor.html',
        //}

        //allowLinkProtocol 允許的鏈接地址,有這些首碼的鏈接地址不會自動添加http
        //, allowLinkProtocols: ['http:', 'https:', '#', '/', 'ftp:', 'mailto:', 'tel:', 'git:', 'svn:']

        //webAppKey 百度應用的APIkey,每個站長必須首先去百度官網註冊一個key後方能正常使用app功能,註冊介紹,http://app.baidu.com/static/cms/getapikey.html
        //, webAppKey: ""

        //預設過濾規則相關配置項目
        //,disabledTableInTable:true  //禁止表格嵌套
        //,allowDivTransToP:true      //允許進入編輯器的div標簽自動變成p標簽
        //,rgb2Hex:true               //預設產出的數據中的color自動從rgb格式變成16進位格式

      // xss 過濾是否開啟,inserthtml等操作
      ,xssFilterRules: true
      //input xss過濾
      ,inputXssFilter: true
      //output xss過濾
      ,outputXssFilter: true
      // xss過濾白名單 名單來源: https://raw.githubusercontent.com/leizongmin/js-xss/master/lib/default.js
      ,whitList: {
         iframe: ['frameborder','border','marginwidth','marginheight','width','height','src','id'],//宋雨佳增加這一行
         a:      ['target', 'href', 'title', 'class', 'style'],
         abbr:   ['title', 'class', 'style'],
         address: ['class', 'style'],
         area:   ['shape', 'coords', 'href', 'alt'],
         article: [],
         aside:  [],
         audio:  ['autoplay', 'controls', 'loop', 'preload', 'src', 'class', 'style'],
         b:      ['class', 'style'],
         bdi:    ['dir'],
         bdo:    ['dir'],
         big:    [],
         blockquote: ['cite', 'class', 'style'],
         br:     [],
         caption: ['class', 'style'],
         center: [],
         cite:   [],
         code:   ['class', 'style'],
         col:    ['align', 'valign', 'span', 'width', 'class', 'style'],
         colgroup: ['align', 'valign', 'span', 'width', 'class', 'style'],
         dd:     ['class', 'style'],
         del:    ['datetime'],
         details: ['open'],
         div:    ['class', 'style'],
         dl:     ['class', 'style'],
         dt:     ['class', 'style'],
         em:     ['class', 'style'],
         font:   ['color', 'size', 'face'],
         footer: [],
         h1:     ['class', 'style'],
         h2:     ['class', 'style'],
         h3:     ['class', 'style'],
         h4:     ['class', 'style'],
         h5:     ['class', 'style'],
         h6:     ['class', 'style'],
         header: [],
         hr:     [],
         i:      ['class', 'style'],
         img:    ['src', 'alt', 'title', 'width', 'height', 'id', '_src', 'loadingclass', 'class', 'data-latex'],
         ins:    ['datetime'],
         li:     ['class', 'style'],
         mark:   [],
         nav:    [],
         ol:     ['class', 'style'],
         p:      ['class', 'style'],
         pre:    ['class', 'style'],
         s:      [],
         section:[],
         small:  [],
         span:   ['class', 'style'],
         sub:    ['class', 'style'],
         sup:    ['class', 'style'],
         strong: ['class', 'style'],
         table:  ['width', 'border', 'align', 'valign', 'class', 'style'],
         tbody:  ['align', 'valign', 'class', 'style'],
         td:     ['width', 'rowspan', 'colspan', 'align', 'valign', 'class', 'style'],
         tfoot:  ['align', 'valign', 'class', 'style'],
         th:     ['width', 'rowspan', 'colspan', 'align', 'valign', 'class', 'style'],
         thead:  ['align', 'valign', 'class', 'style'],
         tr:     ['rowspan', 'align', 'valign', 'class', 'style'],
         tt:     [],
         u:      [],
         ul:     ['class', 'style'],
         video:  ['autoplay', 'controls', 'loop', 'preload', 'src', 'height', 'width', 'class', 'style']
      }
    };

    function getUEBasePath(docUrl, confUrl) {

        return getBasePath(docUrl || self.document.URL || self.location.href, confUrl || getConfigFilePath());

    }

    function getConfigFilePath() {

        var configPath = document.getElementsByTagName('script');

        return configPath[ configPath.length - 1 ].src;

    }

    function getBasePath(docUrl, confUrl) {

        var basePath = confUrl;


        if (/^(\/|\\\\)/.test(confUrl)) {

            basePath = /^.+?\w(\/|\\\\)/.exec(docUrl)[0] + confUrl.replace(/^(\/|\\\\)/, '');

        } else if (!/^[a-z]+:/i.test(confUrl)) {

            docUrl = docUrl.split("#")[0].split("?")[0].replace(/[^\\\/]+$/, '');

            basePath = docUrl + "" + confUrl;

        }

        return optimizationPath(basePath);

    }

    function optimizationPath(path) {

        var protocol = /^[a-z]+:\/\//.exec(path)[ 0 ],
            tmp = null,
            res = [];

        path = path.replace(protocol, "").split("?")[0].split("#")[0];

        path = path.replace(/\\/g, '/').split(/\//);

        path[ path.length - 1 ] = "";

        while (path.length) {

            if (( tmp = path.shift() ) === "..") {
                res.pop();
            } else if (tmp !== ".") {
                res.push(tmp);
            }

        }

        return protocol + res.join("/");

    }

    window.UE = {
        getUEBasePath: getUEBasePath
    };

})();

附config.json

/* 前後端通信相關的配置,註釋只允許使用多行方式 */
{
    "basePath": "D:/scinece-2.0",
    /* 上傳圖片配置項 */
    "imageActionName": "uploadimage", /* 執行上傳圖片的action名稱 */
    "imageFieldName": "upfile", /* 提交的圖片表單名稱 */
    "imageMaxSize": 2048000, /* 上傳大小限制,單位B  */
    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上傳圖片格式顯示 */
    "imageCompressEnable": true, /* 是否壓縮圖片,預設是true */
    "imageCompressBorder": 1600, /* 圖片壓縮最長邊限制 */
    "imageInsertAlign": "none", /* 插入的圖片浮動方式 */
    "imageUrlPrefix":"", /* 圖片訪問路徑首碼 */
    "imagePathFormat": "/document/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
                                /* {filename} 會替換成原文件名,配置這項需要註意中文亂碼問題 */
                                /* {rand:6} 會替換成隨機數,後面的數字是隨機數的位數 */
                                /* {time} 會替換成時間戳 */
                                /* {yyyy} 會替換成四位年份 */
                                /* {yy} 會替換成兩位年份 */
                                /* {mm} 會替換成兩位月份 */
                                /* {dd} 會替換成兩位日期 */
                                /* {hh} 會替換成兩位小時 */
                                /* {ii} 會替換成兩位分鐘 */
                                /* {ss} 會替換成兩位秒 */
                                /* 非法字元 \ : * ? " < > | */
                                /* 具請體看線上文檔: fex.baidu.com/ueditor/#use-format_upload_filename */

    /* 塗鴉圖片上傳配置項 */
    "scrawlActionName": "uploadscrawl", /* 執行上傳塗鴉的action名稱 */
    "scrawlFieldName": "upfile", /* 提交的圖片表單名稱 */
    "scrawlPathFormat": "/document/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
    "scrawlMaxSize": 2048000, /* 上傳大小限制,單位B */
    "scrawlUrlPrefix":"", /* 圖片訪問路徑首碼 */
    "scrawlInsertAlign": "none",

    /* 截圖工具上傳 */
    "snapscreenActionName": "uploadimage", /* 執行上傳截圖的action名稱 */
    "snapscreenPathFormat": "/document/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
    "snapscreenUrlPrefix":"", /* 圖片訪問路徑首碼 */
    "snapscreenInsertAlign": "none", /* 插入的圖片浮動方式 */

    /* 抓取遠程圖片配置 */
    "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
    "catcherActionName": "catchimage", /* 執行抓取遠程圖片的action名稱 */
    "catcherFieldName": "source", /* 提交的圖片列表表單名稱 */
    "catcherPathFormat": "/document/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
    "catcherUrlPrefix":"", /* 圖片訪問路徑首碼 */
    "catcherMaxSize": 2048000, /* 上傳大小限制,單位B */
    "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取圖片格式顯示 */

    /* 上傳視頻配置 */
    "videoActionName": "uploadvideo", /* 執行上傳視頻的action名稱 */
    "videoFieldName": "upfile", /* 提交的視頻表單名稱 */
    "videoPathFormat": "/document/ueditor/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
    "videoUrlPrefix": "", /* 視頻訪問路徑首碼 */
    "videoMaxSize": 102400000, /* 上傳大小限制,單位B,預設100MB */
    "videoAllowFiles": [
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上傳視頻格式顯示 */

    /* 上傳文件配置 */
    "fileActionName": "uploadfile", /* controller里,執行上傳視頻的action名稱 */
    "fileFieldName": "upfile", /* 提交的文件表單名稱 */
    "filePathFormat": "/document/ueditor/file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,可以自定義保存路徑和文件名格式 */
    "fileUrlPrefix":"", /* 文件訪問路徑首碼 */
    "fileMaxSize": 307200000, /* 上傳大小限制,單位B,預設50MB */
    "fileAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
    ], /* 上傳文件格式顯示 */

    /* 列出指定目錄下的圖片 */
    "imageManagerActionName": "listimage", /* 執行圖片管理的action名稱 */
    "imageManagerListPath": "/document/ueditor/image/", /* 指定要列出圖片的目錄 */
    "imageManagerListSize": 20, /* 每次列出文件數量 */
    "imageManagerUrlPrefix":"", /* 圖片訪問路徑首碼 */
    "imageManagerInsertAlign": "none", /* 插入的圖片浮動方式 */
    "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件類型 */

    /* 列出指定目錄下的文件 */
    "fileManagerActionName": "listfile", /* 執行文件管理的action名稱 */
    "fileManagerListPath": "/document/ueditor/file/", /* 指定要列出文件的目錄 */
    "fileManagerUrlPrefix":"", /* 文件訪問路徑首碼 */
    "fileManagerListSize": 20, /* 每次列出文件數量 */
    "fileManagerAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
    ] /* 列出的文件類型 */

}

註意點 1 :如果你是按照我的上一篇隨筆完成的對ueditor的初始配置,那麼在你引入ueditor控制項的那個html文件里,一定存在這麼一段代碼:

<script type="text/javascript">
    window.UEDITOR_HOME_URL = "/UEditor/";
</script>

這次在ueditor.config.js文件中,我指定了這個路徑,所以在頁面里的這個聲明就可以去掉了。而且我留著這裡是存在問題的,當然我不太確定是不是這裡導致的問題,如果大家配置完沒有問題,那這裡保留著也可以。

註意點 2 :這裡面有幾個路徑需要再提醒一下

在CommonController中: @RequestMapping("uploadimage")和 @RequestMapping("uploadfile") 需要和 config.json中的imageActionName一一對應。

config.json中:"basePath": "D:/scinece-2.0" 需要是你保存在磁碟的路徑,當然這裡好像不改也行,因為這裡被新寫的controller覆蓋了,可以嘗試不改看看有沒有問題,博主保險起見就一起改了。

CommonController 中的 map.put("url", "/PathFile/"+nowName);需要和映射器類的registry.addResourceHandler("/PathImage/**").addResourceLocations("file:/D:/science-2.0/"); 一一對應

CommonController 中的 rootPath = afterPath+ "static/UEditor/jsp";是相對於項目的classpath的路徑

對於SpringBoot項目來說,classpath指的是src.main.java和src.main.resources路徑以及第三方jar包的根路徑,存放在這兩個路徑下的文件,都可以通過classpath作為相對路徑來引用;

因為在maven項目打包之後,會將項目變成如下圖所示的路徑,也就是說 /java 和 /resources 這兩個文件夾所在的路徑會消失springboot項目會直接識別這兩個文件夾裡面的內容,****所以我們寫路徑的時候就直接可以從 resources 目錄的下一級開始,比如從/static或者 /template等等開始。

分享完畢,有不准確的地方大家交流指正,希望對大家有幫助!

好看請贊,養成習慣!

本文來自博客園,作者:靠譜楊,轉載請註明原文鏈接:https://www.cnblogs.com/rainbow-1/p/16383695.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下載證書 申請證書 證書下載 文件格式為: PEM格式的證書文件。 PEM格式的證書文件是採用Base64編碼的文本文件,您可以根據需要將證書文件修改成其他格式。 KEY格式的證書私鑰文件。 安裝證書 登錄Linux 證書上傳到伺服器 新建存放證書的目錄 mkdir /usr/local/nginx ...
  • CentOS目前官網提供的下載版本有6、7、8,最新的版本為8,不過個人推薦CentOS 7 的版本,因為相比較於最新版本,版本7更加地穩定。而相比於版本6,版本7新增了很多的功能。CentOS 7 是目前主流的版本,穩定成熟,是大多數伺服器首選的版本。話不多說,直入主題。 下載centos官方鏡像 ...
  • 唉。下麵是我花了不知道多少個小時踩過的所有坑總結出來的血淚史,希望能幫你們少踩一些坑吧,正常來講一步一步下來就不會出現任何問題了。 背景 用的是百度雲的雲伺服器(其他雲伺服器同理),系統是Ubuntu 20.04 LTS,Mysql版本8.0+,需求是在Windows上開發,可以隨時遠程連接讀寫服務 ...
  • 分享嘉賓:張政 京東 演算法工程師 編輯整理:AMS 周金星 出品平臺:DataFunTalk 導讀: 內容生態建設是近幾年互聯網快速發展的關鍵動因,也是AI化的重點方向之一。本文主要分享在京東廣告業務下內容理解體系的建設情況,從標簽化、內容準入、質量美學評價等多個角度探討內容理解能力的應用;同時整體 ...
  • SQL的函數 函數的定義 函數是指一段可以直接被另一段程式調用的程式或代碼; 字元串函數 MySQL常用的字元串函數 函數 功能 concat(s1,s2,···sN) 字元串拼接,將s1···sN拼接為一個字元串 lower(str) 將字元串str全部轉換為小寫 upper(str) 將字元串s ...
  • 華為應用內支付服務(In-App Purchases,IAP)為開發者提供便捷的應用內支付體驗和簡便的接入流程。開發者的應用集成IAP SDK後,調用IAP SDK介面,啟動IAP收銀台,即可實現應用內支付。在集成過程中,開發者可能會遇到報錯的問題,這時我們可以通過查找日誌中的tag的方法對問題快速 ...
  • 今天把平臺屬性的管理基本完成了,後臺管理做到現在基本也開始熟悉,確實就是對ElementUI的一個熟練程度。 一.平臺屬性管理 1.動態展示數據 先把介面弄好,應該在第三級標題選擇後進行發請求 靜態頁面搭建 渲染數據 屬性值列表,用到一個新組件 tag,並且這裡有多個屬性值,所以要遍歷,既然要在裡面 ...
  • 這裡給大家分享我在OpenLayers 地圖開發工作中總結出的一下代碼和註意點,希望對大家有所幫助 效果如下: 核心代碼展示:附帶講解註釋 var map = new ol.Map({ // 初始化地圖 target: 'map',// 選擇地圖對象 layers: [ new ol.layer.T ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...