标签:
一、总结
二、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 <= CONCAT(#{yesterday},‘ 23:59:59‘) AND a.gmt_create >= 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位下载
记录一次bug解决过程:规范变量名称和mybatis的使用以及代码优化
标签:
原文地址:http://www.cnblogs.com/RunForLove/p/5742797.html