記錄一次bug解決過程:規範變數名稱和mybatis的使用以及代碼優化

来源:http://www.cnblogs.com/RunForLove/archive/2016/08/05/5742797.html
-Advertisement-
Play Games

一、總結 二、Bug描述:Mybatis中parameterType使用 mapper層中使用parameterType="java.lang.Integer"基本類型,代碼報錯: 解決辦法,當入參為基本數據類型的使用,使用_parameter代替基本數據類型,如下: 或者在mapper層的介面中, ...


一、總結

  1. Mybatis中當parameterType為基本數據類型的時候,統一採用_parameter來代替基本數據類型變數。
  2. Mybatis中resultMap返回一個對象,resultType返回一個Map簡單數據類型(由於需要緩存到JVM中)的映射關係。
  3. String類型轉Integer類型;String類型轉int類型用到的方法是不一樣的。
  4. 方法入口處第一行寫new Date(),防止時間在23:59:59跨界對邏輯帶來影響。
  5. 考慮到上線app_resource表忘記配置供應商比例,在代碼中邏輯中註意要加入空指針判斷,增強代碼健壯性。
  6. 核心代碼處要加註釋,關鍵代碼處要打日誌,業務邏輯執行失敗要考慮是否需要告警郵件。
  7. 變數命名要規範;測試工單的工單標題命名要規範。
  8. 代碼邏輯中有if使用的地方,儘量想想else使用的場景,保證邏輯嚴謹性。
  9. VPN軟體的使用;熱部署的使用(http://docs.alibaba-inc.com/)。

二、Bug描述:Mybatis中parameterType使用

mapper層中使用parameterType="java.lang.Integer"基本類型,代碼報錯:

//org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: 
//  There is no getter for property named 'siteId' in 'class java.lang.Integer'

解決辦法,當入參為基本數據類型的使用,使用_parameter代替基本數據類型,如下:

  <select id="getRulesInfoBysiteId" parameterType="java.lang.Integer" resultMap="RulesMap" >
          SELECT
            a.site_id,
            a.site_name,
            b.id AS city_id,
            b.`name` AS city_name,
            c.id AS region_id,
            c.`name` AS region_name
        FROM
            idc_site a,
            city b,
            area c
        WHERE
            a.region = c.`name`
        AND a.city = b.`name`
        AND a.is_deleted = 'n'
        AND b.is_deleted = 'n'
        AND c.is_deleted = 'n'
        <if test="_parameter != null">
            AND a.site_id = #{_parameter,jdbcType=INTEGER}
        </if>
  </select>

或者在mapper層的介面中,給這個方法的參數加上@param(value=“siteId”),這樣就能在.xml中使用#{siteId,jdbcType=INTEGER}了,僅使用於基本數據類型

//mapper層對應的介面中必須加@Resource註解,否則在Dao層註入*Ext會失敗
@Resource public interface SiteMapperExt extends SiteMapper { //mapper層對應的介面中加mybatis提供的註解@Param("siteId") public RulesInfo getRulesInfoBysiteId(@Param("siteId")Integer siteId); }

更多使用詳情請看最後附文。

三、Bug描述:

    /**
     * 自動分配物流供應商
     */
    @Override
    public void autoAssignSupplier(RuleInfos ruleInfos, String deviceType, WorkOrderMain workOrder, int amounts) {

        // 精確匹配規則制定 物流供應商
        LogisticsAssignRules bean = getExactMatchSPId(ruleInfos.getSourceRegionId(), ruleInfos.getTargetRegionId(),
                                                      ruleInfos.getSourceCityId(), ruleInfos.getTargetCityId(),
                                                      ruleInfos.getSourceSiteName(), ruleInfos.getTargetSiteName(),
                                                      deviceType, amounts);
        if (null == bean) {
            // 按比例規則制定物流供應商
            Map<String, String> supplierRatesMap = getSpRates();
            Map<String, String> logicOf90DaysBefore = getAssignRates();
            String supplierId = getSupplierIdBy90Days(supplierRatesMap, logicOf90DaysBefore, amounts);
            logisticsWorkOrderBo.LogisticsAssigned(workOrder, WorkOrderStatsCst.LogisticsOrderState.unassigned,
                                                   supplierId, getSpRatesDesc(), WorkOrderCst.DEFAULT_VALUE_YES);
            logger.info("auto assign supplier as rates,supplierId = {}, description = {}", supplierId, getSpRatesDesc());
        } else {
            // 精確匹配,直接分配物流供應商
            logisticsWorkOrderBo.LogisticsAssigned(workOrder, WorkOrderStatsCst.LogisticsOrderState.unassigned,
                                                   bean.getSpId().toString(), bean.getRuleJsonVal(),
                                                   WorkOrderCst.DEFAULT_VALUE_YES);
            logger.info("auto assign supplier start as rules, supplierId = {}, description = {}",
                        bean.getSpId().toString(), getSpRatesDesc());
        }
    }

在介面調用中,當傳遞屬性過多的時候,可以考慮用對象來傳遞,方便以後的擴展。如本代碼中,當後續添加規則時,需要更新方法。另外對於公用的東西,儘量維護在靜態枚舉值中。

四、Bug描述:方法入口處統一獲取當前時間new Date()

在代碼中的時間要作為條件來篩選數據,如果同一個方法中,在多個地方出現new Date(),算上程式執行的納秒級別的時間,可能在當前日期的“23:59:59 納秒”產生跨界時間的問題,給代碼造成概率極低的隱患。

SELECT
    d.sp_id,
    COUNT(a.sn) AS asset_counts
FROM
    idc_asset_list a
LEFT JOIN idc_work_order_main b ON a.order_id = b.id
LEFT JOIN idc_order_atomic_list c ON c.order_id = b.id
LEFT JOIN idc_atomic_logistics d ON d.atomic_id = c.atomic_id
WHERE
    a.is_deleted = 'n'
AND b.is_deleted = 'n'
AND c.is_deleted = 'n'
AND d.is_deleted = 'n'
AND d.sp_id IS NOT NULL
AND b.gmt_create < CONCAT('2016-08-04', '23:59:59')
AND b.gmt_create > date_sub(
    '2016-08-04 00:00:00',
    INTERVAL 3 MONTH
)
AND (
    b.state != 'cancle'
    OR b.sub_state != 'cancle'
)
GROUP BY
    d.sp_id
ORDER BY
    sp_id DESC

因為要將上述數據緩存到JVM中,數據結構在集群中的一臺機器上只維護一份。一天最多查詢8次。

使用到的SQL如下:

    <select id = "getLogisticsList90DaysBefore" parameterType="java.lang.String" resultType ="java.util.Map">
            SELECT
                d.sp_id AS spId,
                COUNT(a.sn) AS assetCounts
            FROM
                idc_asset_list a
            LEFT JOIN idc_work_order_main b ON a.order_id = b.id
            LEFT JOIN idc_order_atomic_list c ON c.order_id = b.id
            LEFT JOIN idc_atomic_logistics d ON d.atomic_id = c.atomic_id
            WHERE
                a.is_deleted = 'n'
            AND b.is_deleted = 'n'
            AND c.is_deleted = 'n'
            AND d.is_deleted = 'n'
            AND d.sp_id IS NOT NULL
            AND (b.state != 'cancle' OR b.sub_state != 'cancle')
            <if test = "_parameter != null  and _parameter !=''">
                AND a.gmt_create &lt;= CONCAT(#{yesterday},' 23:59:59')
                AND a.gmt_create &gt;= DATE_SUB(CONCAT(#{yesterday},' 00:00:00'), INTERVAL 3 MONTH)
            </if>
            GROUP BY
                d.sp_id
            ORDER BY
                sp_id DESC
    </select>

mapper層的代碼中,我們使用了mysql函數date_sub(concat(""), interval 3 month),並且返回resultType="java.util.Map",我們使用結構List<String,Map<String,Object>>結構來接收查詢結果,而沒有採用resultMap封裝對象來接收結果。

SQL執行之後的返回結果為list,通過斷點跟蹤獲悉sp_id為Integer類型,asset_counts為Long類型。

//獲取spId
Integer spId = map.get("spId");
//獲取assetCounts
Long assetCounts = map.get("assetCounts");

故使用如下代碼獲取查詢結果,但是代碼中封裝了數據類型,所以統一採用Object來獲取。

五、Bug描述:考慮到線上缺失配置文件,添加空指針判斷;為程式健壯性,必須在前後端同時對參數完整性作出校驗。

    /**
     * 校驗參數的完整性 {設備類型與數量必填,用於規則匹配校驗}
     */
    private void checkParameters(AssignSupplierRulesDTO dto) {
        // 數量合理性校驗
        if (StringUtils.isNotBlank(dto.getAssetNum())) {
            if (dto.getAssetNum().toCharArray().length <= 1) {
                throw new ServiceException(ErrorCode.Params_Lost);
            } else {
                if (!(StringUtils.isNumeric(dto.getAssetNum().substring(1)))) {
                    throw new ServiceException(ErrorCode.Params_Invalid);
                }
                if (!("><=≤≥≠".contains(dto.getAssetNum().substring(0, 1)))) {
                    throw new ServiceException(ErrorCode.Params_Invalid);
                }
            }
        }
        // 供應商必填
        if (null == dto.getSpId()) {
            throw new ServiceException(ErrorCode.Params_Lost);
        }
        // 規則名稱必填
        if (StringUtils.isBlank(dto.getRuleName())) {
            throw new ServiceException(ErrorCode.Params_Lost);
        }

        // 當指定規則類型的時候,關聯性校驗
        if (StringUtils.isNotBlank(dto.getRuleType())) {
            // 同城校驗
            if (dto.getRuleType().equals(WorkOrderCst.RelocationType.SameCity.name())) {
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceCity()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceCity()))) {
                    if (dto.getSourceCity() != dto.getTargetCity()) {
                        throw new ServiceException(ErrorCode.Params_Invalid);
                    }
                }
            }
            // 同區域內校驗
            if (dto.getRuleType().equals(WorkOrderCst.RelocationType.RegionalIn)) {

                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceRegion()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetRegion()))) {
                    if (StringUtils.isNotBlank(dto.getSourceRegion()) && StringUtils.isNotBlank(dto.getTargetRegion())) {
                        // 區域必須相等
                        if (!(dto.getSourceRegion().equals(dto.getTargetRegion()))) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceCity()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetCity()))) {
                    if (StringUtils.isNotBlank(dto.getSourceCity()) && StringUtils.isNotBlank(dto.getTargetCity())) {
                        if (!addressBo.whetherCityInTheSameArea(dto.getSourceCity(), dto.getTargetCity())) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceSite()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetSite()))) {
                    if (StringUtils.isNotBlank(dto.getSourceSite()) && StringUtils.isNotBlank(dto.getTargetSite())) {
                        if (!addressBo.whetherSiteInTheSameArea(dto.getSourceSite(), dto.getTargetSite())) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
            }
            // 不同區域的校驗
            if (dto.getRuleType().equals(WorkOrderCst.RelocationType.RegionalOut)) {
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceRegion()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetRegion()))) {
                    if (StringUtils.isNotBlank(dto.getSourceRegion()) && StringUtils.isNotBlank(dto.getTargetRegion())) {
                        if (dto.getSourceRegion().equals(dto.getTargetRegion())) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceCity()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetCity()))) {
                    if (StringUtils.isNotBlank(dto.getSourceCity()) && StringUtils.isNotBlank(dto.getTargetCity())) {
                        if (addressBo.whetherCityInTheSameArea(dto.getSourceCity(), dto.getTargetCity())) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
                if (!(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getSourceSite()))
                    && !(WorkOrderCst.MATCH_ALL_PARAMETERS.equals(dto.getTargetSite()))) {
                    if (StringUtils.isNotBlank(dto.getSourceSite()) && StringUtils.isNotBlank(dto.getTargetSite())) {
                        if (addressBo.whetherSiteInTheSameArea(dto.getSourceSite(), dto.getTargetSite())) {
                            throw new ServiceException(ErrorCode.Params_Invalid);
                        }
                    }
                }
            }
        }
    }

六、Bug描述:String轉Integer;String轉int的熟練使用。

public class Test {
    public static void main(String[] args) {
        String number = "520";
        Integer a = 521;
        int b = 522;
        
        //String轉Integer
        Integer.valueOf(number);
        
        //String轉int
        Integer.parseInt(number);
        new Integer(number).intValue();
        
        //Integer轉String
        a.toString();
        
        //Integer轉int
        a.intValue();
        
        //int轉String
        String.valueOf(b);
        Integer.toString(b);
        String str = "" + b;
        
        //int轉Integer
        new Integer(b);
        
        //String轉BigDecimal
        new BigDecimal(number);
        //獲取今天日期
        new Date(System.currentTimeMillis()); // Fri Aug 05 20:16:07 CST 2016
        DateFormat.getDateInstance().format(new Date()); // 2016-8-5 
    }
}

七、List和數組的轉換

public class Test {
    public static void main(String[] args) {
        String[] family = { "XuG", "XuX", "GaiZ", "LianW" };
        List<String> list = new ArrayList<String>(Arrays.asList("XuG", "XuX", "GaiZ", "LianW"));
        
        //數組轉list
        List<String> list_01 = new ArrayList<String>(Arrays.asList(family));
        
        //list轉數組
        String[] str = (String[])list.toArray();
    }
}

八、Bug描述:變數命名規範。

 

變數的命名規範要有意義,在資料庫建表,創建java bean的時候,一定要保證單詞使用的正確性。如label和lable;region和regin。要註意到變數的命名可能跟資料庫的關鍵字或java的關鍵字有衝突,可以採用下劃線的原則處理關鍵字衝突

九、Bug描述:邏輯嚴謹性。

private String getSupplierIdBy90Days(Map<String, String> supplierRatesMap, Map<String, String> logicOf90DaysBefore,
                                         int dispatchNum) {
        int ratesCount = 0, dispatchCount = 0;
        for (String spId : supplierRatesMap.keySet()) {
            ratesCount = ratesCount + Integer.parseInt(supplierRatesMap.get(spId));
        }
        for (String spId : logicOf90DaysBefore.keySet()) {
            dispatchCount = dispatchCount + Integer.parseInt(logicOf90DaysBefore.get(spId));
        }
        Map<String, String> idealizedMap = new HashMap<String, String>();
        for (String spId : supplierRatesMap.keySet()) {
            Integer dispathNum = (dispatchCount * Integer.parseInt(supplierRatesMap.get(spId))) / ratesCount;
            idealizedMap.put(spId, dispathNum.toString());
        }
        int gap = -1;
        String supplierId = StringUtils.EMPTY;
        if (CollectionUtils.isNotEmpty(logicOf90DaysBefore.keySet())) {
            for (String spId : logicOf90DaysBefore.keySet()) {
                if (null != idealizedMap.get(spId)) {
                    int mix = Integer.parseInt(idealizedMap.get(spId))
                              - Integer.parseInt(logicOf90DaysBefore.get(spId));
                    if (mix < gap) {
                        gap = mix;
                        supplierId = spId;
                    }
                } else {
                    supplierId = spId; // 新添加的供應商比例
                }
            }
        } else {
            supplierId = new ArrayList<String>(supplierRatesMap.keySet()).get(0);
        }
        return supplierId;
    }

  有判斷if條件的地方,要考慮到else的可能出現情況,尤其是if else 嵌套多層的時候,可能某些else的情況遺漏,會給程式帶來問題。如上述代碼中的else的缺失,可能在“新添加供應商比例”的情況下,出現沒有分配供應商的情況。

十、VPN工具

  VPN工具下載使用:Cisco AnyConnect VPN Client 64位下載

附:Mybatis中parameterType和resultType的相關用法

1、parameterType用法,parameterType的傳入參數類型大致分為如下幾類:

基本數據類型(_parameter接收參數)

<!-- mapper對應介面層 -->
public RulesInfo getRulesInfoBysiteId(Integer siteId);

<!-- mapper中指定Integer類型,用_parameter來接收 -->
<select id="getRulesInfoBysiteId" parameterType="java.lang.Integer" resultMap="RulesMap" >
    SELECT
      a.site_id,
      a.site_name,
      b.id AS city_id,
      b.`name` AS city_name,
      c.id AS region_id,
      c.`name` AS region_name
    FROM
      idc_site a,
      city b,
      area c
    WHERE
      a.region = c.`name`
    AND a.city = b.`name`
    AND a.is_deleted = 'n'
    AND b.is_deleted = 'n'
    AND c.is_deleted = 'n'
    <if test="_parameter != null">
      AND a.site_id = #{_parameter,jdbcType=INTEGER}
    </if>
</select>

數組類型(foreach中的collection必須是array,不管變數的具體名稱是什麼。如下麵變數名為ids,collection卻是array)

<!-- mapper對應介面層:根據工單角色獲取有許可權的機房 -->
public List<User> findUserListByIdList(int[] ids); 

<!-- mapper中指定java.util.List類型,一般用於MySQL中IN語句中 -->
<select id="findUserListByIdList" parameterType="java.util.HashList" resultType="User">  
    select * from user
    <where>  
        user.ID in (  
            <foreach item="guard" index="index" collection="array" separator=","> 
                #{guard} 
            </foreach>  
        )  
    </where>  
</select>  

List類型(單獨傳入list時,foreach中的collection必須是list,不管變數的具體名稱是什麼。比如代碼中變數名為staffIds,collection中確實list)

<!-- mapper對應介面層 -->
public List<IdcStaff>  selectStaffsbyIdnumbers(List<String> staffIds);

<!-- mapper中指定java.util.List類型,一般用於MySQL中IN語句中 -->
<select id="selectStaffsbyIdnumbers" parameterType="java.util.List" resultMap="BaseResultMap">
    SELECT 
    <include refid="Base_Column_List"/>
    FROM idc_staff where id_number IN
    <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
        #{item}
    </foreach>
    AND IS_DELETED='n'
    ORDER BY staff_status
</select>

Map類型(MAP中有list或array時,foreach中的collection必須是具體list或array的變數名。同上)

<!--*BoImpl.java層構造傳入的map參數-->
public List<SiteUserVo> getSiteUserPermission(String siteName, Long roleId, String workNo) {
    Map<String, Object> siteByUser = new HashMap<String, Object>();
    if (StringUtils.isNotBlank(siteName) && !"".equals(siteName.trim())) {
        siteByUser.put("site", siteName);
    }
    if (null != roleId && 0 != roleId) {
        siteByUser.put("roleId", roleId);
    }
    if (StringUtils.isNotBlank(workNo) && !"".equals(workNo.trim())) {
        siteByUser.put("workNo", workNo);
    }
    return siteMapperExt.getSiteUserPermission(siteByUser);
}

<!-- mapper對應介面層:根據工單角色獲取有許可權的機房 -->
public List<SiteUserVo> getSiteUserPermission(Map siteByUser);

<!-- mapper中指定java.util.List類型,一般用於MySQL中IN語句中 -->
<select id="getSiteUserPermission" parameterType="java.util.HashMap" resultMap="SiteUserVoMap">
    SELECT
        i.site_name,
        t.role_id,
        h.work_no
    FROM
        idc_site_user t
    LEFT JOIN idc_site i ON t.site_id = i.site_id
    LEFT JOIN app_user h ON t.user_id = h.id
    WHERE
        t.IS_DELETED = 'n'
    AND h.IS_DELETED = 'n'
    AND i.IS_DELETED = 'n' 
    <IF test = "site!=null" >
        AND i.site_name = #{site}
    </IF > 
    <IF test = "roleId!=null" >
        AND t.role_Id = #{roleId}
    </IF > 
    <IF test = "workNo!=null" >
        AND h.work_no = #{workNo}
    </IF >
</select>

Java對象

<!-- mapper對應介面層:根據工單角色獲取有許可權的機房 -->
List<AssignRulesVo> selectByQuery(QueryAssignRulesrDo query);

<!-- mapper中指定對象類型,對象的屬性名可以直接使用;如果要在SQL中判定對象是否為空,還要用_parameter -->
<select id="selectByQuery" parameterType="com.alibaba.tboss.dal.mysql.workOrder.query.QueryAssignRulesrDo" resultMap="BaseResult">
    SELECT
        a.id,
        a.is_valid,
        a.rule_lable,
        a.rule_name,
        a.type,
        b.sp_id,
        b.sp_name,
        a.rule_content,
        c.user_name,
        a.gmt_modified,
        a.ordering,
        a.rule_json_val
    FROM
        idc_logistics_assign_rules a
        LEFT JOIN app_user c on c.work_no=a.modifier and c.is_deleted='n',
        idc_sp_info b   
    WHERE
        a.is_deleted = 'n'
    AND b.is_deleted = 'n'
    AND a.sp_id = b.sp_id
    <if test="ruleId != null">
        AND a.id = #{ruleId,jdbcType=BIGINT}
    </if>
    <if test="ruleName != null and ruleName != ''">
        AND a.rule_name IN (${ruleName})
    </if>
    ORDER BY ordering asc
    <if test="doPage == true">
        limit #{skip,jdbcType=INTEGER}, #{take,jdbcType=INTEGER}
    </if>
</select>

補充${}會導致SQL註入攻擊,不建議使用。

//取值的時候用的是#{}。它具體的意思是告訴MyBatis創建一個預處理語句參數。
//使用JDBC,這樣的一個參數在SQL中會由一個“?”來標識,並被傳遞到一個新的預處理語句中。

//一般情況下,我們採用#{}取值,產生預處理語句,但是有時我們可能不希望Mybatis來幫我們預處理。
//${columnName},這裡MyBatis不會修改或轉義字元串。而是直接拼接到SQL字元串後面。

 


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

-Advertisement-
Play Games
更多相關文章
  • 在windows2008伺服器上安裝wampserver3.0.4集成環境,預設卻是無法遠程訪問,如果要遠程訪問需要修改apache的配置文件httpd.conf,修改如下: <Directory "D:/wamp64/www/"> # # Possible values for the Optio ...
  • 註釋規範 1、 類註釋 在每個類前面必須加上類註釋,註釋模板如下: 2、 屬性註釋 在每個屬性前面必須加上屬性註釋,註釋模板如下: 3、 方法註釋 在每個方法前面必須加上方法註釋,註釋模板如下: 4、 構造方法註釋 在每個構造方法前面必須加上註釋,註釋模板如下: 5、 方法內部註釋 在方法內部使用單 ...
  • 函數指針、回調函數、系統調用區別1.函數指針 2.回調函數 體現: 1.函數名作為參數傳遞給調用函數。 2.將調用者和被調函數分開,回調函數實現具體的功能,調用者無需關註實現的具體細節。3.系統調用系統調用 --> (0x80)軟中斷(系統調用表) --> 內核函數 --> 返回到系統調用層 rea ...
  • 用遞歸的方法實現無限極分類 通常我在寫項目的時候,在寫一些例如商城分類的時候會實現對應分類的上級分類,或者其它項目部門管理的上級部門的時候一般就會用到無限極分類來進行分類 第一步:首先在數據表設計的時候,如果要實現無限極分類,一般我會在數據表多添加一個欄位pid,下麵我通過一張新建的數據表來說明一下 ...
  • php程式是部署在IIS7上面,ajax提交數據時,遇到了兩個問題,一個就是跨域,一個php程式總會被執行兩次。 第一個問題的解決方法,是百度出來的,添加下麵幾行代碼就可以了: header('Access-Control-Allow-Origin:*'); header("Access-Contr ...
  • 虛擬記憶體按頁劃分,我們可以明確告訴系統:某一個虛擬記憶體頁需要和實際記憶體幀相關聯。這樣一來,該記憶體頁就被換進來了,而且不會被系統換出去。這一行為叫做鎖頁(locking a page)。 一般來講頁的換進換出是透明的,一般程式接觸不到這一層。但是呢,鎖頁可以為我們帶來如下好處: 1、速度:如果你的程式 ...
  • 函數的遞歸調用 遞歸的含義 遞歸其實也只是一種演算法上的描述,不是一種新的語法! 有時候,我們解決問題的時候,會遇到這種情況,當我們把一個大的問題按照某種解決方案分成若幹個小的問題的時候,發現這些小問題的解決方案其實和剛纔大問題的解決方案又是一樣的! 典型的,比如:求階乘! 10! = 10 * 9! ...
  • 最近由於公司慢慢往spark方面開始轉型,本人也開始學習,今後陸續會更新一些spark學習的新的體會,希望能夠和大家一起分享和進步。 Spark是什麼? Apache Spark™ is a fast and general engine for large-scale data processin ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...