整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          fly coding字典改造(一):引用剝離,功能直

          fly coding字典改造(一):引用剝離,功能直接關聯查詢字典

          前,我內置表單功能中,已有自動關聯字典數據方式。由于,此前字典數據過于依賴表單字段,導致內存占用較高,字典數據重復性較大,字典緩存清理不便捷。

          故,我欲改造之,將其與表單字段,單獨剝離,并統一與功能對象進行關聯,從而解決如上問題。

          開發思路

          后端,需設計“功能字典關聯表”用于查詢,獨立“字典配置”注解,改造功能管理類。

          前端,需提供通用字典獲取函數,改造使用字典的元素如(下拉框、單選框、多選框等)。

          整體看來,此次改造還是比較簡單的,接下來就直接進入編碼環節。

          后端

          orm對象表定義

          package com.flycoding.drivenlibrary.engine.function.entity;
          
          import com.flycoding.dblibrary.annotation.create.Column;
          import com.flycoding.dblibrary.annotation.create.PrimaryAuto;
          import com.flycoding.dblibrary.annotation.create.Table;
          import com.flycoding.dblibrary.enums.ColumnType;
          import com.flycoding.drivenlibrary.engine.constants.SqlConstants;
          import com.flycoding.drivenlibrary.engine.function.entity.base.BaseFunctionMessage;
          
          /**
           * 功能字典關聯表
           *
           * @author 趙屈犇
           * @version 1.0
           * @date 創建時間: 2022/10/18 20:47
           * @Copyright(C): 2022 by 趙屈犇
           */
          @Table(tableName="Sy_Func_Dict")
          public class FuncDictInfo extends BaseFunctionMessage {
          
              /** 主鍵 */
              @PrimaryAuto
              private Integer id;
              /** 普通字典編碼 */
              @Column(columnName="dict_code", columnType=ColumnType.VARCHAR, length=SqlConstants.DB_CODE_SIZE)
              private String dictCode;
              /** 數據字典編碼 */
              @Column(columnName="data_dict_code", columnType=ColumnType.VARCHAR, length=SqlConstants.DB_CODE_SIZE)
              private String dataDictCode;
              /** 字典驅動庫關聯配置編碼 */
              @Column(columnName="db_config_code", columnType=ColumnType.VARCHAR, length=SqlConstants.DB_CODE_SIZE)
              private String dbConfigCode;
          
              public Integer getId() {
                  return id;
              }
          
              public void setId(Integer id) {
                  this.id=id;
              }
          
              public String getDictCode() {
                  return dictCode;
              }
          
              public void setDictCode(String dictCode) {
                  this.dictCode=dictCode;
              }
          
              public String getDataDictCode() {
                  return dataDictCode;
              }
          
              public void setDataDictCode(String dataDictCode) {
                  this.dataDictCode=dataDictCode;
              }
          
              public String getDbConfigCode() {
                  return dbConfigCode;
              }
          
              public void setDbConfigCode(String dbConfigCode) {
                  this.dbConfigCode=dbConfigCode;
              }
          }

          此對象,用于功能與字典之間的關聯。當,用戶獲取功能時,后臺通過此函數,自動裝載入字典數據。

          字典配置注解

          package com.threeox.drivenlibrary.engine.annotation.function.form.field;
          
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;
          
          /**
           * 字典配置
           *
           * @author 趙屈犇
           * @version 1.0
           * @date 創建時間: 2022/10/18 20:18
           * @Copyright(C): 2022 by 趙屈犇
           */
          @Retention(RetentionPolicy.RUNTIME)
          @Target({ ElementType.ANNOTATION_TYPE })
          public @interface DictConfig {
          
              /**
               * 普通字典編碼
               *
               * @return
               */
              String dictCode() default "";
          
              /**
               * 數據字典編碼
               *
               * @return
               */
              String dataDictCode() default "";
          
              /**
               * 字典驅動庫關聯配置
               *
               * @return
               */
              String dbConfigCode() default "";
              /**
               * 是否使用配置
               *
               * @return
               */
              boolean isUseConfig() default true;
          
          }
          

          此注解,暫用于表單字段與字典配置的關聯函數。

          生成數據預覽

          可以看到,字典數據已于功能進行綁定。

          接下來,我準備將字典數據,直接綁定至功能對象上,并返回給前端。

          查詢關聯字典數據

          為提升查詢效率, 此處仍采用初次查詢,后續緩存的方式。

          package com.threeox.drivenlibrary.engine.function.factory.config;
          
          import com.threeox.drivenlibrary.cache.impl.function.FuncDictCacheManager;
          import com.threeox.drivenlibrary.engine.constants.config.request.ConfigRequestConstants;
          import com.threeox.drivenlibrary.engine.function.entity.FuncDictInfo;
          import com.threeox.drivenlibrary.engine.function.factory.base.BaseCustomFactory;
          import com.threeox.drivenlibrary.engine.request.execute.ExecuteRequestFactory;
          
          import java.util.List;
          
          /**
          * 功能字典關聯工廠
          *
          * @author 趙屈犇
          * @version 1.0
          * @date 創建時間: 2022/10/20 20:42
          * @Copyright(C): 2022 by 趙屈犇
          */
          public class FuncDictFactory extends BaseCustomFactory<List<FuncDictInfo>> {
          
              private static FuncDictFactory inst=null;
          
              public static FuncDictFactory getInstance() {
                  if (inst==null) {
                      synchronized (FuncDictFactory.class) {
                          if (inst==null) {
                              inst=new FuncDictFactory();
                          }
                      }
                  }
                  return inst;
              }
          
              private FuncDictFactory() {
              }
          
              @Override
              protected void init() {
              }
          
              @Override
              protected void initCacheManager() {
                  cache=FuncDictCacheManager.getInstance();
              }
          
              @Override
              protected List<FuncDictInfo> initResult(ExecuteRequestFactory requestFactory, String dbConfigCode, Object key, Integer relatedId, Object... extendParams) throws Exception {
                  // 查詢關聯字典配置根據功能主鍵
                  return getResult(requestFactory, ConfigRequestConstants.QUERY_FUNC_DICT_BY_FUNC_ID, relatedId);
              }
          }
          

          綁定字典結果至功能

          最后,我在獲取功能對象時,動態獲取字典配置,并綁定字典結果數據。

          為兼容普通字典和數據字典主鍵可能重復問題,我根據dictCode,dataDictCode,dbConfigCode進行拼接,生成新的key值。

          /**
          * 初始化功能字典數據
          *
          * @param functionInfo
          * @return a
          * @author 趙屈犇
          * @date 創建時間: 2022/10/20 20:58
          * @version 1.0
          */
          private void initFuncDictData(FunctionMessage functionInfo) {
              if (functionInfo !=null) {
              // 獲取關聯字典數據
              List<FuncDictInfo> dictInfos=funcDictFactory.getResult(functionInfo.getDbConfigCode(), functionInfo.getFuncCode(), functionInfo.getFuncId());
              if (ArrayUtils.isNotEmpty(dictInfos)) {
                  Map <String, List<DictDataInfo>> dictMap=new HashMap<>();
                  dictInfos.forEach(dictInfo - > {
                      // key
                      String key=StringUtils.appendStrings(dictInfo.getDictCode(), dictInfo.getDataDictCode(), dictInfo.getDbConfigCode());
                      if (!dictMap.containsKey(key)) {
                          List<DictDataInfo> dictionaryInfos=null;
                          // 普通字典
                          if (StringUtils.isNotEmpty(dictInfo.getDictCode())) {
                              // 普通字典類型
                              dictionaryInfos=dictFactory.getResult(dictInfo.getDbConfigCode(), dictInfo.getDictCode());
                              // 數據字典
                          } else if (StringUtils.isNotEmpty(dictInfo.getDataDictCode())) {
                              dictionaryInfos=dataDictResultFactory.getResult(dictInfo.getDataDictCode());
                          }
                          dictMap.put(key, dictionaryInfos);
                      }
                  });
                  functionInfo.setDictDatas(dictMap);
              }
          }

          至此,后端功能業已完成。此下,將進行改造前端功能。

          前端

          通用字典獲取函數

          /**
           * 獲取字典數據
           *
           * @param elementConfig
           * @returns {null|*}
           */
          engine.getDictData=function (elementConfig) {
              if (self.funcMessage) {
                  let key=[elementConfig['dictCode'], elementConfig['dataDictCode'], elementConfig['dictDBConfigCode']].join(
                      "");
                  return self.funcMessage.dictDatas[key];
              }
              return null;
          }

          此函數,內置在基礎引擎js段中,故可以直接獲取功能對象,并通過功能對象直接獲取字典數據。

          選擇框元素

          此下,我選了選擇框元素進行改造,其他的復刻即可。

          // 定義選擇框元素
          let selectView=factory.byId("${fieldCode}");
          // 定義過濾lay
          let layFilter="${fieldCode}_" + self.containerId;
          // 設置屬性
          selectView.attr("lay-filter", layFilter);
          // 獲取字典
          let dicts=factory.getDictData(elementConfig);
          if (!engineCommon.isListEmpty(dicts)) {
            for (let i=0, length=dicts.length; i < length; i++) {
              try {
                let dict=dicts[i];
                let dictionaryValue=dict["dictionaryValue"];
                let optionHtml="<option name='" + layFilter + "' id='${fieldCode}_" + dictionaryValue + "' value='" + dictionaryValue + "'>" + dictionary["dictionaryName"] + "</option>";
                selectView.append(optionHtml);
              } catch(e) {
                console.log(e);
              }
            }
            layFactory.render('select');
          }
          // 監聽選中事件
          layFactory.on(LayEventConstants.SELECT, layFilter, function(data){
            selectView.val(data.value);
            // 回調lay事件
            if (self.factory && self.factory['onLayEvent']) {
              self.factory.onLayEvent('${fieldCode}', LayEventConstants.SELECT, data);
            }
          });

          至此,其他字典組件相繼修改,既完成。

          在尋找支持在Java中用編程方法處理各類格式文檔的API嗎?好巧,Java版企業級文檔管理組合套包Spire.Office 2020全新上線!Word、Excel、PPT、PDF、條形碼等格式一網打盡。

          目前,Spire.Office for Java 迎來v3.1.0版的更新。Excel格式處理控件Spire.XLS(點擊下載)強勢加入,同時各個產品也增加了新功能。如Spire.PDF 支持轉換PDF到SVG時設置寬度和高度像素,并公開了PdfFileLinkAnnotationWidget類及getValue屬性;Spire.Presentation 支持轉換PPT到HMTL時,可設置內容居中;同時,也修復了將PDF轉換為Word/HTML、PPT轉換為PDF/圖片、Word轉換為PDF/HTML、給PPT設置圖片背景、對Word文檔進行加密時出現的問題。

          新功能及問題修復詳情,請參閱如下內容。(點擊文末“了解更多”可下載Spire.office全部產品)


          Spire.PDF for Java

          新功能:

          • 公開了PdfFileLinkAnnotationWidget類,支持在轉換PDF到Svg時設置寬度和高度像素 pdf.getConvertOptions().setPdfToSvgOptions(float widthPixel, float heightPixel);
          • 公開了getValue屬性用以獲取radio button的值 PdfRadioButtonWidgetItem item=items.get(j);item.getValue();

          問題修復:

          • 修復了轉換PDF到Word文檔,程序掛起的問題
          • 修復了轉換PDF到HTML,程序拋異常的問題
          • 修復了在MAC環境中水印無法繪制成功的問題

          Spire.Presentation for Java

          新功能:

          • 支持轉換PPT到HMTL時,可設置內容居中 Presentation ppt1=new Presentation(); ppt1.loadFromFile(inputFile); ppt1.getSaveToHtmlOption().setCenter(true); ppt1.saveToFile(outputFile, FileFormat.HTML);
          • 新增getTargetSlide()方法獲取含超鏈接類型為GO_SLIDE的目標幻燈片 Presentation ppt=new Presentation(); ppt.loadFromFile("test.pptx"); IAutoShape shape=(IAutoShape) ppt.getSlides().get(0).getShapes().get(0); HyperlinkActionType type=shape.getClick().getActionType(); ISlide slide=shape.getClick().getTargetSlide(); int slideNumber=slide.getSlideNumber();

          問題修復:

          • 修復了在MAC系統上保存.pptx文檔時,拋異常"cannot found font installed on the system" 的問題
          • 修復了加載.pptx文檔程序拋AppException異常的問題
          • 修復了添加HTML到形狀里時,進程拋 "Cannot find table '0S/2' in the font file"異常的問題
          • 修復了在MAC系統上給PPT添加背景圖拋異常的問題
          • 修復了轉換到PPT到PDF后,多出黑線的問題
          • 修復了轉換形狀到圖片進程拋異常的問題
          • 修復了轉換組合形狀到圖片失敗的問題
          • 修復了保存Slide 到圖片,拋OutOfMemoryError的問題
          • 修復了PPT轉圖片拋異常的問題

          Spire.Doc for Java

          問題修復:

          • 修復了垂直或水平合并單元格時,只保留了第一個單元格數據的問題
          • 修復了轉換.docx文檔到html文檔時,公式丟失的問題
          • 修復了修改文檔的內容格式后,保存文檔失敗的問題
          • 修復了移除分節符時,失敗的問題
          • 修復了加載.docx文檔時,拋異常"Operation is not valid due to the current state of the object."的問題
          • 修復了多線程并發轉換Word到PDF失敗的問題
          • 修復了轉換.docx文檔到PDF時,拋出異常“pItem have not found in paragraph items”的問題
          • 修復了保護文檔后,輸入密碼打開顯示“密碼錯誤”的問題
          • 修復了轉換.docx文檔到PDF時,多出空白行的問題
          • 修復了轉換doc文檔到PDF時,拋出IllegalStateException異常的問題
          • 修復了合并文檔時,拋出異常“No have this value 1”的問題
          • 修復了轉換Word到PDF耗時長的問題
          • 修復了加載文檔拋異常的問題
          • 修復了轉換Word到PDF后,頁碼錯誤的問題
          • 修復了獲取段落ListText,內容不正確的問題
          • 修復了加載文檔拋異常的問題
          • 修復了移除分節符后,保存文檔拋異常的問題
          • 修復了轉換Word到PDF后,頁眉圖片重復的問題
          • 修復了轉換Word到PDF,圖片位置不正確的問題
          • 修復了更新TOC目錄拋異常的問題
          • 修復了轉換Word到PDF后,頁面右邊距增大的問題
          • 修復了郵件合并后需要保存文檔后才能獲取文本的問題
          • 修復了添加頁眉頁腳后,文本重疊的問題
          • 修復了轉換Word到PDF拋NullReferenceException異常的問題

          在表單的設計過程中,會有一些表單字段需要在已知的內容中進行選擇,這在html中會使用select組件來設計該表單字段。而在Material中,同樣有與之對應的 <mat-select> 組件。這種組件在選項內容較少的情況下使用非常方便,能很好的引導用戶在表單中,輸入規范的內容:

          但是在選項內容過多時,這種 <mat-select> 組件,對用戶來說,想要找到自己想要的選項就比較麻煩,需要一個個選項去對比,查找:

          幸運的是,在Material中提供了 mat-autocomplete ,這個組件和我們以前在JQuery時代使用的select2類似。它支持用戶鍵盤輸入功能,并根據輸入內容在已有的數據集合中進行過濾,選項內容動態的顯示過濾后的結果。


          MatAutocomplete


          基本用法

          html:

          <form class="example-form">
            <mat-form-field class="example-full-width">
              <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
              <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of options" [value]="option">
                  {{option}}      </mat-option>
              </mat-autocomplete>
            </mat-form-field></form>

          TypeScript:

          import {Component} from '@angular/core';import {FormControl} from '@angular/forms';/**
           * @title Simple autocomplete
           */@Component({
            selector: 'autocomplete-simple-example',
            templateUrl: 'autocomplete-simple-example.html',
            styleUrls: ['autocomplete-simple-example.css'],
          })export class AutocompleteSimpleExample {
            myControl=new FormControl();
            options: string[]=['One', 'Two', 'Three'];
          }

          呈現的效果如下:


          高級API

          在簡單用法中,我們發現,選項內容為字符串,選擇中的值和顯示的值為相同的。但在實際的應用過程中,我們需要選中的值和顯示的內容是不同的。

          displayWith

          舉個例子,我們有個需要選擇企業的字段,要存儲到數據庫的值是企業的編碼,而在界面上顯示的需要是企業的名稱。在這個例子中,我們有個企業的數據結構:

          interface Company {
            code: string;
            name: string;
          }
          companies: Company[]=[]; constructor() {    this.companies.push({code: 'qiye-01', name: '企業01'});    this.companies.push({code: 'qiye-02', name: '企業02'});    this.companies.push({code: 'qiye-03', name: '企業03'});    this.companies.push({code: 'qiye-04', name: '企業04'});
           }
          <form class="example-form">
            <mat-form-field class="example-full-width">
              <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
              <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of companies" [value]="option">
                  {{option.name}}      </mat-option>
              </mat-autocomplete>
            </mat-form-field></form>

          在html中,我們將mat-option的顯示內容修改成name,如 {{option.name}} 。這樣我們的下拉選項中就會顯示企業的名稱:

          但是如果我們選中其中一個選項,就會發現結果和我們想象的不一樣,選中后的結果顯示并不是我們想要的企業名稱

          此時,我們就需要使用API中提供的

          在MatAutocomplete的API: displayWith。文檔已經很明確的告訴我們 displayWith 需要我們傳入一個已定義的函數

          @Input()
          displayWith: ((value: any)=> string) | null

          其中的函數形參value指的是 <mat-option *ngFor="let option of companies" [value]="option"> 中value對應的option,此處option就是一個我們后臺定義的Company。這樣我們的value就擁有code和name兩個屬性。

          這樣我們就可以定義一個displayWith的函數:

          displayFn(value: any): string { // value: Company
            return value ? value.name : undefined;
          }

          同時修改html

          <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
            <mat-option *ngFor="let option of companies" [value]="option">
              {{option.name}}  </mat-option></mat-autocomplete>

          這樣就會顯示我們想要的結果

          在這種方式下,我們的formControl得到的其實是一個company對象,要存儲code,需要在從company對象中獲取code屬性值。

          那么如果我們想在formControl中直接得到code呢?

          擴展用法通過分析,我們發現,formControl獲得值的內容,其實和中的value是一致的。

          因此,我們可以做如下修改, 將value改成option.code

          <form class="example-form">
            <mat-form-field class="example-full-width">
              <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
              <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of companies" [value]="option.code">
                  {{option.name}}      </mat-option>
              </mat-autocomplete>
            </mat-form-field></form>

          得到如下顯示結果:

          發現顯示的是code值,那我們還可以使用displayWith函數,讓它顯示企業名稱嗎?

          答案是可以的。不過我們就不能再使用上面定義的displayFn方法了。此時我們需要重新定義一個更高級的方法:

          displayWith() {  return (value)=> {    if (value) {      const arr=that.companies.filter(item=> item.code===value);      if (arr.length) {        return arr[0].name;
                }
              }    return undefined;
            }
          }

          在html中的使用方法如下:

          <form class="example-form">
            <mat-form-field class="example-full-width">
              <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
              <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayWith()">
                <mat-option *ngFor="let option of companies" [value]="option.code">
                  {{option.name}}      </mat-option>
              </mat-autocomplete>
            </mat-form-field></form>

          需要[displayWith]=”displayWithThis(this)” 這樣特殊的使用方法。

          為什么同樣是用displayWith,不同的value中,實際寫法差異卻如此大呢?這個和JS的This作用于有關。

          在不是用匿名函數的情況下,如:

          displayFn(value) {    if (value) {        const arr=this.companies.filter(item=> item.code===value);        if (arr.length) {            return arr[0].name;
                  }
              }    return undefined;
          }

          此時,如果將displayFn直接設置到mat-autocomplete中,此時的this表示mat-autocomplete對象,這樣this.companies.filter就會拋出異常。


          結論

          在本文中,我們主要講了MatAutocomplete在實際開發過程中,在不同的業務場景中,同樣的組件我們用到的不同的實現方式。每一種語言都有它自己的特性,掌握了這些特性,會讓我們工作時更加得心應手。


          主站蜘蛛池模板: 人妻内射一区二区在线视频| 无码午夜人妻一区二区不卡视频| 国产午夜精品一区二区| 男人的天堂亚洲一区二区三区| 内射少妇一区27P| 久久一区二区三区精品| 国产成人一区二区三区高清| 亚洲第一区香蕉_国产a| 色欲AV无码一区二区三区| 国产成人精品日本亚洲专一区 | 日韩人妻不卡一区二区三区| 国产精品一区二区久久乐下载| 国产区精品一区二区不卡中文| 日本一区二区三区日本免费| 一区二区三区亚洲| 中文字幕一区二区视频| 日韩美女在线观看一区| 国产精品一区二区不卡| 岛国精品一区免费视频在线观看| 99国产精品欧美一区二区三区| 一区二区不卡在线| 在线成人一区二区| 怡红院一区二区三区| 福利一区二区三区视频午夜观看| 国模大胆一区二区三区| 无码日韩AV一区二区三区| 无码日韩精品一区二区人妻| 无码人妻精品一区二区蜜桃AV| 国产高清一区二区三区四区| 精品国产香蕉伊思人在线在线亚洲一区二区 | 亚洲国产成人久久一区WWW | 好爽毛片一区二区三区四| 91一区二区三区| 中字幕一区二区三区乱码 | 成人精品一区二区三区校园激情| 无码国产精品一区二区免费vr| 久久久无码一区二区三区| 精品视频一区二区三区四区| 亚洲丰满熟女一区二区哦| 国产精品免费综合一区视频| 亚洲av高清在线观看一区二区|