复盘工作-2024-09

复盘工作-2024-09-07

1.HTML当文档元素加载完后执行的简易写法:

/* 我一开始的写法是错误的:
         错误:$.(document).ready(function(){}) 运行程序浏览器控制台会报错
         错误:$.(function(){}) 运行程序浏览器控制台会报错
         点号用于访问对象的方法或属性。
         应该直接用$来调用jQuery的方法
         $(function() {})等价于$(document).ready(function() {}) */
     /* $(document).ready(function() {
         debugger;
         alert(2);
     }) */
     /**/
     $(function() {
         debugger;
         alert(1);
     });

复盘工作-2024-09-08

1.sql根据记录字段值判断取不同的值:case when a then b else c end as d:

select case
         when t.AZDD is null then
          ''
         else
          t.AZDD
       end as AZDD
  from pm_xtgs_qr_code t
 where t.ID = '8a8a8a8b8f9508d6018f950b8ac80026';

复盘工作-2024-09-09

1.可变参数:

private void printArray(int[] args) {
        System.out.println("练习可变参数:直接遍历数组");
        // for(类型 变量名 : 要遍历的实现了Iterable接口的变量名),增强for循环,从jdk5开始引入
        for (int i : args) {
            System.out.println(i);
        }
    }

    /**
     * 验证可变参数
     *
     * 可变参数,varargs,即variable-length arguments,从jdk5开始引入
     * 用法(定义):类型... 变量名
     * 可接受0个或其他任意数量个数的 该类型的 变量,作为参数
     * 例如int... args,可接受0个或其他任意数量的int类型的参数,作为参数
     *
     * 如果传数组进来,也行。会自动将数组转成多个参数。例如将入参new int[]{1, 2}转换为1, 2
     * @param args
     */
    private void printVariableLengthArguments(int... args) {
        System.out.println("练习可变参数:使用可变参数");
        for (int i : args) {
            System.out.println(i);
        }
    }

    private void practice() {
        // 练习可变参数:直接遍历数组
        // 声明数组:new int[]{1, 2};而不是我一开始的错误的:new int("1", "2")
        System.out.println("练习可变参数:直接遍历数组");
        this.printArray(new int[]{1, 2});
        // 练习可变参数:使用可变参数
        System.out.println("练习可变参数:使用可变参数");
        this.printVariableLengthArguments(3, 4);
        this.printVariableLengthArguments();
        System.out.println("练习可变参数:使用可变参数:如果传数组进来,自动将数组转成多个参数");
        this.printVariableLengthArguments(new int[]{5, 6});
    }

2关于sql中and条件的顺序是否会影响性能:

private void practiceAndOrder() {
        StringBuilder stringBuilder = new StringBuilder();
        String str1 = " where columnA = 1 and columnB = 2 ";
        String str2 = " where columnB = 2 and columnA = 1 ";
        // 在开发中,无需过分关注and条件的顺序对性能的影响。str1和str2用哪个都行,可以根据实际拼接sql时方便程度自行决定。
        // 因为这是sql的设计原则之一:and条件顺序无关性:and逻辑运算的各条件顺序不影响sql执行的结果和性能
        // oracle也必然遵循了这一原则。
    }

3.关于向数组中加入元素,尤其是动态的加入:实现了Collection接口的对象的toArray(T[] arr)方法:

/**
     * 练习向数组中加入元素,尤其是动态的加入:实现了Collection接口的对象的toArray(T[] arr)方法
     */
    private void practiceAddItemToArray() {
        // 方式1:声明时直接初始化:
        System.out.println("声明时直接初始化:");
        String[] arr1 = {"hello", "world", "java"};
        for (String s : arr1) {
            System.out.println(s);
        }
        // 方式2:先声明数组然后赋值元素:
        int size = 4;
        String[] arr2 = new String[size];
        for (int i = 0; i < size; i++) {
            arr2[i] = "Element" + i;
        }
        System.out.println("先声明数组然后赋值元素:");
        for (String s : arr2) {
            System.out.println(s);
        }
        // 方式3:动态的向数组中加入元素,例如数组大小编译时未知、需要在程序运行时添加或删除元素:
        List<String> strList = new ArrayList<>();
        strList.add("hello");
        strList.add("word");
        strList.add("SpringMVC");
        strList.add("Java");
        // toArray(T[] arr)是Collection接口中定义的。List接口继承了Collection接口。而Collection接口定义了toArray()方法
        // 需要传入一个数组类型,这里只会用到数组的类型,不会用到数组的具体内容,只使用其类型信息
        // toArray(T[] arr)方法返回一个新的数组,包含ArrayList中的所有元素
        String[] arr3 = strList.toArray(new String[0]);
        System.out.println("动态的向数组中加入元素:");
        for (String s : arr3) {
            System.out.println(s);
        }
    }

复盘工作-2024-09-11

1.java后端处理带有反斜杠\的sql:

/**
     * 当要执行的sql中有反斜杠(backslash)\时,java代码需对其前面加个\表示转义。否则会报错(java会将其识别为转义字符的开始)
     * 即java代码里用两个\\来表示一个反斜杠\。
     *
     * 反斜杠 backslash \
     * 斜杠 slash /
     * 
     * regexp_substr是oracle提供的函数,通过正则表达式从字符串中提取子串
     * regexp_substr(x.xlmc, '\d+')提取xlmc字段中第一个连续的数字序列,例如从“产品编号12345描述”中提取出“12345”
     */
    private void practiceSqlWithBackslash() {
        StringBuilder builder = new StringBuilder();
        builder.append("select x.id, x.xlmc, to_number(regexp_substr(x.xlmc, '\\d+')) BH  from PM_SB_ZWYC_XL x");
        List<Map<String, Object>> mapList = systemService.findForJdbc(builder.toString());
        System.out.println("练习处理sql中的反斜杠:");
        for (Map<String, Object> map : mapList) {
            System.out.println(map.get("BH").toString());
        }
    }

2.js控制隐藏/显示元素:通过属性选择器:

/**
      * 隐藏一个元素:选中元素后,通过.hide()方法来隐藏
      *
      * 这里为测试方便调用框架查询方法,无实际意义
      */
     function pmSjbQrCodeStatisticsListsearch() {
         debugger;
         // 一开始我写的是错误的:$(name='ywdw').hide();
         // 正确的应该是通过属性选择器来选择:通过[属性名="属性值"]来选择
         $('[name="ywdw"]').hide();
     }
     /**
      * 恢复显示一个(被隐藏了的)元素:选中元素后,通过.show()方法来恢复显示
      *
      * 这里为测试方便调用框架查询方法,无实际意义
      */
     function searchpmSjbQrCodeStatisticsListReset() {
         debugger;
         $('[name="ywdw"]').show();
     }

复盘工作-2024-09-12

1.js判空,以及假如基于具体需求判空:

let arr = new Array();
     arr.push('1');
     console.log('练习js获取数组长度.length方法:自测数组长度是:' + arr.length);

     /**
      * js通用判空
      *
      * 一般js判空是比较 null、''、undefined、NaN
      * 与NaN比较使用Number.isNaN(val)
      *
      * NaN:not a number的缩写
      * Number是js内置的对象,用于严格判断是否严格等于NaN
      */
     function isEmpty(val) {
         return val === null || val === '' || val === undefined || Number.isNaN(val);
     }

     /**
      * js判空:基于具体业务,假如空数组[]、空对象{}也需要被判为空
      *
      * Array.isArray(val)判断val是否是数组,
      *     若是数组,再通过.length属性取数组长度
      *
      * typeof val === 'object'判断val是否是对象类型,
      *     若是对象,则再通过Object.keys(val)获取val对象的可枚举属性的键组成的数组
      *         若该数组长度为0,则证明val是空对象
      */
     function isEmptyOrEmptyArrayOrEmptyObj(val) {
         return val === null || val === '' || val === undefined || Number.isNaN(val)
                || (Array.isArray(val) && val.length === 0)
                || (typeof val === 'object' && Object.keys(val).length === 0);
     }

     /**
      * 测试判空方法
      */
     console.log('isEmpty(null):' + isEmpty(null));// true
     // js里转义字符也是反斜杠,与java相同
     console.log('isEmpty(\'\'):' + isEmpty(''));// true
     console.log('isEmpty(undefined):' + isEmpty(undefined));// true
     console.log('isEmpty(NaN):' + isEmpty(NaN));// true
     console.log('isEmpty(false):' + isEmpty(false));// false
     console.log('isEmpty([]):' + isEmpty([]));// false
     console.log('isEmpty({}):' + isEmpty({}));// false

     /**
      * 测试判空方法:基于具体业务,假如空数组[]、空对象{}也需要被判为空
      */
     console.log('isEmptyOrEmptyArrayOrEmptyObj(null):' + isEmptyOrEmptyArrayOrEmptyObj(null));// true
     console.log('isEmptyOrEmptyArrayOrEmptyObj(\'\'):' + isEmptyOrEmptyArrayOrEmptyObj(''));// true
     console.log('isEmptyOrEmptyArrayOrEmptyObj(undefined):' + isEmptyOrEmptyArrayOrEmptyObj(undefined));// true
     console.log('isEmptyOrEmptyArrayOrEmptyObj(NaN):' + isEmptyOrEmptyArrayOrEmptyObj(NaN));// true
     console.log('isEmptyOrEmptyArrayOrEmptyObj(false):' + isEmptyOrEmptyArrayOrEmptyObj(false));// false
     console.log('isEmptyOrEmptyArrayOrEmptyObj([]):' + isEmptyOrEmptyArrayOrEmptyObj([]));// true
     console.log('isEmptyOrEmptyArrayOrEmptyObj({}):' + isEmptyOrEmptyArrayOrEmptyObj({}));// true

复盘工作-2024-09-13~202409-16

1.html包含两个标签页的页面初始化、及标签(切换)点击事件:

<!-- 这个#divBox无实际意义,仅用于验证结构伪类选择器里first和first-child的区别 -->
<div id="pracBox">
    <ul id="pracUl">
        <div id="pracInnerDiv">id为pracUl的ul下的第一个子元素:id为pracInnerDiv的div</div>
        <li>练习li-1-不能被$("#pracBox li:first-child").hide()选中并隐藏(因为其不是其父元素的第一个子元素,第一个子元素是pracInnerDiv</li>
        <li>练习li-2-可以被$("#pracBox li:eq(1)").hide()选中并隐藏</li>
    </ul>
</div>
<script>
    $(document).ready(function() {
        /**
         * 隐藏(#content下所有具有hideTab类的)所有标签的内容,目的是在页面加载时仅显示一个标签的内容
         * jQuery中$()函数用于选择或查找html元素,并返回这些元素的jQuery对象
         * #content id选择器
         * .hideTab 类选择器
         * #content .hideTab 后代选择器(选择所有后代,对太爷来说,爷爷 爸爸 孙子 全是其后代)
         * .hide()是jQuery提供的方法,用于隐藏($()匹配的)对象
         */
        $("#content .hideTab").hide();
        /**
         * 激活第一个标签。为#tabs下的第一个li元素设置id为current,以此标记它为当前激活的标签
         * (id为current就能标记为激活,应该是与jeecg框架封装的效果有关)
         * #tabs li:first 结构伪类选择器,选择#tabs下第一个li元素
         * 而#tabs li:first-child 也是结构伪类选择器,但first-child 选择#tabs下所有作为其父元素第一个子元素的li元素
         *         即只有当li元素恰好是它直接父元素的第一个子元素时,它才会被选中。
         *             这个父元素可能是#tabs的直接子元素(例如ul或ol),也可能是嵌套更深的元素。
         */
        $("#tabs li:first").attr("id", "current");
        /**
         * 仅用于练习,无实际意义
         * $("#pracBox li:first-child").hide();不能隐藏掉#parcBox下第一个li。
         *         因为这个li不是其直接父元素(即#pracBox)的第一个子元素(#pracBox的第一个子元素是<div id="pracInnerDiv"></div>)
         * $("#pracBox li:eq(1)").hide();能选中#pracBox下的
         *         第二个li(即练习li-2)并隐藏掉。(备注:eq,equal with index,索引相同。索引从0开始算。
         *             eq(1)即我们传统意义上口语数数的第二个li,而第一个li使用first就可以选中,li:first相当于li:eq(0))
         */
        $("#pracBox li:first-child").hide();
        $("#pracBox li:eq(1)").hide();

        /**
         * 显示第一个标签的内容。.fadeIn()是jQuery函数,淡入显示某元素,透明度从0(完全透明)变为1(完全不透明)
         * 我一开始写的$("#content .hideTab:first").fadeIn;有两问题:1.用div:first更好,
         *         这样可以避免需要确认第一个div始终是hideTab类的一个实例;2.应该写为.fadeIn()而不是.fadeIn
         */
        $("#content div:first").fadeIn();

        /**
         * 标签点击事件处理
         * 我一开始写的是错的:$("#tabs a").onclick(function(e){});因为onclick不是jQuery对象的一个方法。
         * 解析:应该写为$("#tabs a").click(function(e){});
         *
         * jQuery的.click(function(e){});
         *         1.是jQuery提供的方法,用于为匹配的元素集合中的每个元素添加一个点击事件监听器
         *         2.其内部实际调用.on('click', handler);方法
         *         3.其允许使用jQuery强大功能,例如选择器,链式调用
         *
         * 原生JavaScript的.onclick=function(e){};
         *         1.是原生JavaScript的属性,用于为单个元素直接添加一个点击事件处理函数
         *         2.不支持选择器,并且一次只能为一个元素添加一个处理函数(如果再次设置.onclick,之前的处理函数将被覆盖。
         */
        $("#tabs a").click(function (e) {
            /**
             * 阻止默认行为,(阻止原超链接例如跳转等行为)
             */
            e.preventDefault();
            // 隐藏所有内容
            $("#content .hideTab").hide();
            /**
             * 重置标签的ID。
             * 我一开始写的有问题:$("#tabs a").attr("id", "");应该是$("#tabs li").attr("id", "");
             * 分析:
             * 1.选择器差异:
             *         $("#tabs li").attr("id", "");用于将#tabs下所有li的id属性置为空字符串。这通常用于重置或清除这些
             *             li元素的id属性,以便后续可以重新给当前激活的li标签设置id。
             *         $("#tabs a").attr("id", "");将#tabs下所有a元素的id属性设置为空字符串。然而,在标准html标签页(tabs)
             *             实现中,a标签通常用于点击以切换内容,但其本身并不直接用作内容的容器或表示当前激活的标签。因此,将a标签的
             *             id置为空字符串对于管理标签页的激活状态来说并不是有用的操作。
             * 2.功能目的:
             *         $("#tabs li").attr("id", "");是为了清除所有li标签的id,这样可以确保只有一个li(即当前激活的那个)有特定的
             *             id(例如current),从而可以通过CSS或JavaScript更容易地识别和管理它。
             *         $("#tabs a").attr("id", "");对管理标签页的激活状态没帮助,因为a标签本身并不直接控制内容的隐藏与显示
             */
            $("#tabs li").attr("id", "");
            /**
             * 激活当前(被点击)标签。我一开始写错了:$($(this)).attr("id", "current");
             * 应该是$(this).parent().attr("id", "current");
             * 1.大体解析:
             *         1.1我一开始错误瞎写的:$($(this)).attr("id", "current");
             *             $(this)获取当前(被点击)元素,然后再套一层$()没有用,仍是当前(被点击)元素,
             *                 再.attr("id", "current");即对当前被点击元素a设置id为current,无意义
             *         1.2正确的:$(this).parent().attr("id", "current");解析:
             *             $(this)选中当前(被点击)元素(即被点击的a),然后.parent选中其父元素(即li),
             *                 .attr("id", "current");将li的id属性置为current
             * 2.细节解析:
             *         2.1 $(this)
             *             2.1.1 $(this).parent().attr("id", "current");被触发时(通常是在一个事件处理函数里,例如点击事件),
             *                 this关键字会引用触发该事件的元素。
             *                 在当前上下文中,在$("#tabs a").click(function(e){});内,
             *                 this指的是当前被点击的a标签的dom元素。
             *             2.1.2 $(this)将这个dom元素转换成一个jQuery对象。这样就可以用jQuery提供的
             *                 一系列方法和属性来操作这个元素了。
             *         2.2 .parent()
             *             2.2.1 .parent()是jQuery中的一个方法,它用于获取当前jQuery对象集合中每个元素的直接父元素,
             *                     并将这些父元素包装成一个新的jQuery对象返回。
             *             2.2.2 本例中,调用.parent()会找到a标签的直接父元素,即li标签,然后转换成jQuery对象返回。
             */
            $(this).parent().attr("id", "current");
            /**
             * 显示对应的内容。
             * 我一开始瞎写的错误代码:$("$parent(this)").fadeIn;
             * 正确的应该是:$("#" + $(this).attr("title")).fadeIn();
             */
            $("#" + $(this).attr("title")).fadeIn();
            // $("#tabs a").click(function(e){});最后一定加;分号
        });
    });
</script>

2.html里点击不同区域触发展示不同页面并给出被点击区域的激活效果:

<script>
    /**
     * 设备域点击切换事件触发函数
     * @param sbArea
     */
    function changeBaseView(sbArea) {
        if (!isEmpty(sbArea) && sbArea != originalSbArea) {
            /**
             * 将iframe的src置为空字符串,从而重置iframe内容
             */
            var iframe = document.getElementById('iframe');
            iframe.src = '';
            /**
             * 显示iframe内容(页面中默认通过css将iframe设置为display:none了)
             * 我一开始写的是错的:bmTab.style.display = block;
             * CSS中属性值应该被当作字符串来处理。需要用引号包起来。
             * 应该是bmTab.style.display = 'block';
             * 详细解析:
             * bmTab是一个指向html中元素的引用(通过document.getElementById获取的)
             * .style是访问该元素样式的一个接口,
             * .display是样式对象中的一个属性,用于控制样式的显示类型。
             * .display设置为'block'时,是告诉浏览器以块级元素的方式来展示该元素。
             * 设置为'none'时,该元素就是不可见的。
             */
            let bmTab = document.getElementById('bm-tab');
            bmTab.style.display = 'block';
            // 设置iframe新内容
            iframe.src = 'pmSjbQrCode' + sbArea + 'Controller.do?statisticsList';
            /**
             * 页面上除了被点击的(设备域)div外,其余均去掉“激活”样式
             * document.querySelectorAll('.top-tap-check-state')选择页面上
             *      所有具有类名'top-tap-check-state'的元素,并将这些元素的集合存储到elements里。
             *      querySelectorAll方法返回一个NodeList对象,类似于数组
             * element.classList是一个实时的DOMTokenList集合,元素的类列表。
             *      .classList.remove是一个dom元素的方法,从一个元素的类列表中移除一个或多个类名。
             *      调用remove方法时,classList集合会立即更新,页面上该元素的类属性也会相应的更新。
             */
            let elements = document.querySelectorAll('.top-tap-check-state');
            elements.forEach(element => {
                element.classList.remove('top-tap-check-state');
            })
            /**
             * 给选中的设备域div设置激活样式
             * 我一开始写的是:document.getElementById('top-table-' + sbArea).classList.add('top-tap-check-state');
             *      这是在原有的类基础上加上'top-tap-check-state'类
             * 更好的是用原版写法:document.getElementById('top-table-'+sbArea).className = 'top-tap-check-state';
             *      备注:不能写成.className('top-tap-check-state');因为className是一个属性,而不是方法。
             */
            document.getElementById('top-table-' + sbArea).className = 'top-tap-check-state';
        }
    }
</script>
<style>
    .bm-tab{
        display: none;
    }
</style>

复盘工作-2024-09-17~2024-09-18

1.jQuery移除页面数据字典组件中的某个选项:模糊匹配和完全精确匹配:

$(document).ready(function(){
     /**
      * 移除select的某个option,例如"---请选择---"
      * select[name="ywdw"] option 后代选择器
      * :contains("---请选择---") 过滤出内容包含"---请选择---"的(选项);备注:contains是模糊匹配
      *
      * 完全相同匹配:
      * 我第一次写的是错的;
      * 错误:$('select[name="ywdw"] option').filter(item => function () {
      * 错误:     return item.innerHTML().toUpperCase() === '---请选择---';
      * 错误:}).remove();
      * 错误原因解析:
      * 1.  .filter()函数,其回调函数的返回期望是一个布尔值,true/false(表示是否保留当前元素),而不是一个函数
      *     我的上述写法是尝试在箭头函数中返回一个函数。
      * 2.  jQuery中获取dom元素的文本或html内容,用的是.html(),或.text()(对于纯文本内容,.text()比.html()更合适),
      *         而.innerHTML是原生JavaScript dom元素的属性。
      * 我第二次写的也是错的;
      * 错误:$('select[name="ywdw"] option').filter($(this).text()==='---请选择---').remove()
      * 错误原因解析:
      * 1.filter方法的回调函数中没有正确使用this关键字。
      *     在jQuery的.filter()方法中,回调函数会被自动调用,并且每次调用时this都会被设置为当前迭代的元素。
      *     但是我的写法里,直接在.filter()方法外部使用了$(this),这里的this不指向任何特定的<option>元素。
      * 2.并且.filter()期望回调函数返回一个布尔值,表示是否保留当前元素,
      *     而我写的$(this).text()==='---请选择---'只是进行了比较操作,(并没有返回)
      * 正确的写法:
      * $('select[name="ywdw"] option').filter(function() {
      *     return $(this).text()==='---请选择---';
      * }).remove();
      */
     // $('select[name="ywdw"] option:contains(---请选择--- ")').remove();
     $('select[name="ywdw"] option').filter(function() {
         return $(this).text()==='---请选择---';
     }).remove();
 });

复盘工作-2024-09-20

1.java类中定义常量List

/**
     * java类中定义常量List
     */
    private static final List<String> MY_CONSTANT_LIST =
            Collections.unmodifiableList(Arrays.asList("Java", "Spring", "Oracle"));

/**
     * 在业务接口中验证常量List
     */

    @RequestMapping(params = "datagrid")
    public void datagrid(PmLpGzpEntity pmLpGzp,HttpServletRequest request, HttpServletResponse response, DataGrid dataGrid) {
        System.out.println("=====================================================");
        System.out.println("输出常量List:");
        for (String s : MY_CONSTANT_LIST) {
            System.out.println(s);
        }
        System.out.println("验证确实是常量List:尝试向其中插入元素,会报错:");
        try {
            MY_CONSTANT_LIST.add("Hibernate");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("错误:" + e.getMessage());
        }
        System.out.println("=====================================================");
        MY_CONSTANT_LIST.add("VUE");
        // 后续语句不会执行,因为上一句MY_CONSTANT_LIST.add("VUE");已经报错了,未try catch,程序不会继续走后续代码
        System.out.println("尝试添加后,再次输出常量List:");
        for (String s : MY_CONSTANT_LIST) {
            System.out.println(s);
        }
    }

2.练习获取request中的请求参数ParameterMap,以及遍历Map并获取其中每个键值对的键和值:

@RequestMapping(params = "datagrid")
public void datagrid(PmXtgsQrCodeEntity pmXtgsQrCode,HttpServletRequest request, HttpServletResponse response, DataGrid dataGrid) {
    /**
     * 练习获取request中的请求参数ParameterMap
     *
     * .getParameterMap()是Java servlet API中HttpServletRequest的一个方法,
     *         返回Map<String, String[]>。因为一个请求参数可能对应多个值,所以是String[]。
     *
     * parameterMap.entrySet()返回Set集合(包含映射的每一个键值对构成的set集合),
     *         然后可以通过entry遍历parameterMap(的entrySet())
     * entry.getKey();获取键值对的键(key)
     * entry.getValue();获取键值对的值(value)
     * 解析:
     * .entrySet()是Map接口的一部分,返回一个Set<Map.Entry<K,V>>,
     *         这个集合包含了Map中所有的键值对(Entry)。
     *         每个Entry都是一个键值对的表示,它提供了获取键(getKey())和值(getValue())的方法。
     */
    Map<String, String[]> parameterMap = request.getParameterMap();
    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
        String key = entry.getKey();
        System.out.println("key: " + key);
        String[] value = entry.getValue();
        System.out.println("value: ");
        for (String s : value) {
            System.out.println(" " + s);
        }
    }
}

复盘工作-2024-09-21

1.myeclipse开发时js缓存相关问题解决:

1.1首先使用chrome无痕模式,更改js后默认刷新页面就能加载最新代码;若未生效,则ctrl+shift+delete清浏览器缓存;

1.2若上述未生效(即js文件位于web应用内,且更改没有通过浏览器刷新或清除缓存后生效),则在myeclipse的server选项卡里右击(已经部署到Tomcat的)项目,选择redeploy/reload application,即重新部署redeploy下项目;

1.3在实际开发中,上述两步骤可以解决大多数静态资源更新相关问题。

1.4另外有个project/clean菜单,

1.4.1用于清理项目的构建目录(通常是bin或target目录),并重新构建项目。还可以解决一些由于旧的编译文件或资源文件引起的问题。

1.3.2使用场景:如果改变了项目的构建路径、依赖关系或其他构建相关的设置,并且这些更改没有反映在运行时,这时可以考虑使用clean功能。

2.EasyUI获取列表选中行

/**
     * EasyUI获取列表选中行
     * 解析:
     * <t:datagrid name="pmSjbQrCodeList">,是EasyUI的datagrid组件,
     *         对于js,上述代码会产生一个id为pmSjbQrCodeList的table并将datagrid追加到这个table上
     *         即浏览器控制台可以看到的<table width="100%" id="pmSjbQrCodeList"
     *             toolbar="#pmSjbQrCodeListtb" style="display: none;"></table>
     *         所以可以通过$('#pmSjbQrCodeList') id选择器来选择到这个table
     * getSelections是EasyUI的datagrid组件的方法,用于返回所有的选中行,返回一个数组
     */
    let rowData = $('#pmSjbQrCodeList').datagrid('getSelections');
    console.log('输出所选行:');
    /**
     * 一开始我写的是错的:i < rowData.size。
     * js获取数组长度,应该用rowData.length;
     */
    if (rowData.length > 0) {
        for (let i = 0; i < rowData.length; i++) {
            console.log(rowData[i]);
        }
    } else {
        console.log('没选中行');
    }

3.sql:group by语句后要接原始列名,因为sql引擎在解析group by语句时还没有看到select列表中定义的别名。order by也是同理,后面接原始列名。

/*这里一定是group by z.P_ID,而不能是group by SSZF。
若写成group by SSZF,会报错:不是group by表达式
解析:sql引擎在解析group by时还没有看到select列表中定义的别名。
所以group by后面要跟原始列名,而不是跟select xx as 后的别名字段。*/
/*这里order by z.P_ID无实际业务意义(实际并不用该字段排序),仅为了说明order by最好也是跟原始列名。
尽管有的数据库支持order by后接select列表定义的别名(例如mysql、oracle),
但这并不是所有数据库都支持的行为。为了兼容性和可读性,最好跟原始列名。*/
select max(z.YWDW) as YWDW,
       z.P_ID as SSZF,
       count(z.ID) as TOTAL_NUM,
       count(q.ID) as HAS_GEN_NUM,
       (count(z.ID) - count(q.ID)) as NOT_GEN_NUM
  from v_code_znyc z
  left join pm_sjb_qr_code q
    on z.ID = q.SB_ID
 group by z.P_ID
 order by z.P_ID;

4.参数化查询时,写模糊查询时参数绑定符号?的位置、%拼接方法及位置问题

/**
         * 参数化查询时,写模糊查询时参数绑定符号?的位置、%拼接方法及位置问题。
         * 我一开始写的是错误的:
         *      错误:notGenQrSbBuilder.append(" and z.SBMC like '%?%' "); 备注:notGenQrSbBuilder是用于构建查询条件的StringBuilder
         *      错误:argList.add(sbmc);
         *          备注:argList是后续要用于转换成数组(然后作为参数传递给可接受可变参数的框架查询方法)的List<String>
         *              sbmc是查询参数“设备名称”
         *      错误解析:
         *      不能把参数绑定符号(例如?)写在字符串常量内部(例如'%?%'),这样会被数据库会将?识别为字符串的一部分,
         *          而不是一个可以替换的参数,最终导致参数化查询时报错“无效的索引列”
         * 正确的应该是java代码里,将%%和查询参数sbmc拼接后的结果(作为一个整体),作为参数化查询的参数
         */
        if (!StringUtil.isEmptyOrStrNull(sbmc)) {
            // 错误代码:
//            notGenQrSbBuilder.append(" and z.SBMC like '%?%' ");
//            argList.add(sbmc);
            // 正确代码:
            notGenQrSbBuilder.append(" and z.SBMC like ? ");
            argList.add("%" + sbmc + "%");
        }

复盘工作-2024-09-22

1.myeclipse redeploy完成的标志:控制台输出:信息: 已完成重新加载名为/xxxx的上下文(备注:xxxx为项目名)

2.java中continue和break:

2.1停止本次迭代中的后续语句,继续执行下一次迭代中的内容,使用continue

2.2直接结束整个循环,使用break

/**
             * java中continue和break
             * 1.停止本次迭代中的后续语句,继续执行下一次迭代中的内容,使用continue
             * 2.直接结束整个循环,使用break
             */
            System.out.println("停止本次迭代中的后续内容,继续执行下一次迭代中的内容,使用continue:");
            // 输出 0 1 2 3 4 6 7 8 9
            for (int i = 0; i < 10; i++) {
                if (i == 5) {
                    continue;
                }
                System.out.println(i);
            }
            System.out.println("直接结束整个循环,使用break:");
            // 输出 0 1 2 3 4
            for (int i = 0; i < 10; i++) {
                if (i == 5) {
                    break;
                }
                System.out.println(i);
            }

3.myeclipse中java类定义修改后,redeploy application即可,无需restart server。

redeploy(重新部署):清理服务器上已有的项目文件,然后重新部署最新内容。通常包括JSP、XML、HTML、jar包及class文件等。

而restart重启服务器:如果没有影响Tomcat运行的配置修改,无需进行restart server操作。

4.将组装查询sql及参数的代码抽成公共方法后,封装该dto,用于该公共方法向业务方法返回sql及参数数组,(返回参数数组便于业务方法获取后,直接传给接收可变参数作为参数的框架查询方法)。解析:参数传递时,封装dto,便于存取。

dto:

/**
 * @author 
 * @Description: 将组装查询sql及参数的代码抽成公共方法后,
 * 封装该dto,用于该公共方法向业务方法返回sql及参数数组
 * (返回参数数组便于业务方法获取后,直接传给接收可变参数作为参数的框架查询方法)
 * 解析:
 * 参数传递时,封装dto,便于存取
 * @date 2024/9/22
 */
public class PracSqlWithParams {
    /**
     * 查询sql
     */
    private String sql;

    /**
     * 查询参数构成的对象数组
     */
    Object[] params;

    /**
     * 构造函数
     * @param sql
     * @param params
     */
    public PracSqlWithParams(String sql, Object[] params) {
        this.sql = sql;
        this.params = params;
    }

    public String getSql() {
        return sql;
    }

    public Object[] getParams() {
        return params;
    }
}

练习:获取未生成二维码设备列表的sql及参数

/**
     * 练习:获取未生成二维码设备列表的sql及参数
     * @param request
     * @return
     */
    private PracSqlWithParams pracGenerateSearchNotGenSqlWithParams(HttpServletRequest request) {
        StringBuilder notGenBuilder = new StringBuilder();
        notGenBuilder.append(" select z.ID, ");
        notGenBuilder.append("        z.YWDW, ");
        notGenBuilder.append("        case ");
        notGenBuilder.append("          when z.xl_id is null then ");
        notGenBuilder.append("           'KGZ' ");
        notGenBuilder.append("          else ");
        notGenBuilder.append("           'XL' ");
        notGenBuilder.append("        end as TYPE_XL_OR_KGZ, ");
        notGenBuilder.append("        z.p_id as SSZF, ");
        notGenBuilder.append("        z.SBLXBM, ");
        notGenBuilder.append("        z.SBMC ");
        notGenBuilder.append("   from v_code_znyc z ");
        notGenBuilder.append("   left join pm_sjb_qr_code q ");
        notGenBuilder.append("     on z.id = q.sb_id ");
        notGenBuilder.append("  where z.ewm = '1' ");
        notGenBuilder.append("    and q.id is null ");
        // 参数list
        List<String> argList = new ArrayList<>();
        String ywdw = StringUtil.getEncodePra(request.getParameter("ywdw"));
        if (!StringUtil.isEmptyOrStrNull(ywdw)) {
            notGenBuilder.append(" and z.ywdw = ? ");
            argList.add(ywdw);
        }
        String typeXlOrKgz = StringUtil.getEncodePra(request.getParameter("typeXlOrKgz"));
        if (PmisCommonConstant.TYPE_XL_OR_KGZ_XL.equals(typeXlOrKgz)) {
            notGenBuilder.append(" and z.xl_id is not null ");
        } else if (PmisCommonConstant.TYPE_XL_OR_KGZ_KGZ.equals(typeXlOrKgz)) {
            notGenBuilder.append(" and z.xl_id is null ");
        }
        String sszf = StringUtil.getEncodePra(request.getParameter("sszf"));
        if (!StringUtil.isEmptyOrStrNull(sszf)) {
            notGenBuilder.append(" and z.p_id = ? ");
            argList.add(sszf);
        }
        String sblxbm = StringUtil.getEncodePra(request.getParameter("sblxbm"));
        if (!StringUtil.isEmptyOrStrNull(sblxbm)) {
            notGenBuilder.append(" and z.sblxbm = ? ");
            argList.add(sblxbm);
        }
        String sbmc = StringUtil.getEncodePra(request.getParameter("sbmc"));
        if (!StringUtil.isEmptyOrStrNull(sbmc)) {
            notGenBuilder.append(" and z.sbmc like ? ");
            argList.add("%" + sbmc + "%");
        }
        return new PracSqlWithParams(notGenBuilder.toString(), argList.toArray());
    }

5.增强for循环,从jdk5开始支持

/**
         * 增强for循环,jdk5开始支持
         */
        System.out.println("====================练习增强for循环:===================");
        int[] arr = {1, 2, 3, 4, 5};
        for (int i : arr) {
            System.out.println(i);
        }

复盘工作-2024-09-23

1.练习:后端转码获取前端输入的查询内容:ISO8859-1转UTF-8。读取ISO8859-1编码的appQuery的byte[],然后以UTF-8编码返回字符串。

后端:

/**
     * 练习:后端转码获取前端输入的查询内容:ISO8859-1转UTF-8
     *
     * String s = new String(appQuery.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
     * 解析:
     * 读取ISO8859-1编码的appQuery的byte[],然后以UTF-8编码返回字符串
     * @param request
     * @param dataGrid
     * @return
     */
    @RequestMapping("/practiceGetList")
    public DataGrid practiceGetList(HttpServletRequest request, DataGrid dataGrid) {
        String appQuery = request.getParameter("appQuery");
        if (!StringUtil.isEmptyOrStrNull(appQuery)) {
            // 前端查询“二”时,这里输出:后端直接输出原始ISO8859-1编码的查询参数:appQuery:???
            System.out.println("后端直接输出原始ISO8859-1编码的查询参数:appQuery:" + appQuery);
            String s = new String(appQuery.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            // 前端查询“二”时,这里输出:读取ISO8859-1编码的appQuery的byte[],然后以UTF-8编码返回字符串:s:二
            System.out.println("读取ISO8859-1编码的appQuery的byte[],然后以UTF-8编码返回字符串:s:" + s);
        }
        // 省略具体查询代码
        return dataGrid;
    }

前端:

encodeURI是js提供的将统一资源标识符(URI)的组件进行编码。对ASCII字母和数字、-、_、.、!、~、*、'、(、) 以及 # 等字符进行编码,但会对其他所有字符进行编码(如空格会被转换为 %20)。从而避免用户输入的其他字符在URL中导致问题。通过encodeURI进行编码,可以确保用户输入搜索词可以安全的用于生成查询字符串并作为URL的一部分发送。

/**
           * 查询事件
           *
           * let inputValue = document.getElementById('searchInputId').getElementsByTagName('input')[0].value;
           * 解析:
           * document.getElementById('searchInputId')通过id获取元素,
           * 然后.getElementsByTagName('input')在通过id找到元素内部,查找所有的input元素,
           *    .getElementsByTagName返回的是一个HTMLCollection(一个类数组对象),包含了所有匹配的元素,所以通过[0]来访问第一个input元素,
           * 最后通过.value获取input元素的值
           *
           * encodeURI(filter);
           * 解析:
           * encodeURI是js提供的将统一资源标识符(URI)的组件进行编码。
           * 对ASCII字母和数字、-、_、.、!、~、*、'、(、) 以及 # 等字符进行编码,但会对其他所有字符进行编码(如空格会被转换为 %20)。
           * 从而避免用户输入的其他字符在URL中导致问题。
           * 通过encodeURI进行编码,可以确保用户输入搜索词可以安全的用于生成查询字符串并作为URL的一部分发送。
           *
           * 注意我一开始写的是错的:
           * 错误:filter = '?appQuery=' + inputValue;
           * 错误:filter = encodeURI(filter);
           * 应该是只对用户输入进行encodeURI。即:
           * inputValue = encodeURI(inputValue);
           * filter = '?appQuery=' + inputValue;
           *
           * @param event
           */
          goSearch(event) {
            const _self = this;
            let filter = '';
            if ('input' === event) {
              let inputValue = document.getElementById('searchInputId').getElementsByTagName('input')[0].value;
              debugger;
              // 首先要判空
              if (!_self.commonUtils.isStrIsNull(inputValue)) {
                inputValue = encodeURI(inputValue);
                filter = '?appQuery=' + inputValue;
              }
            }
            _self.defaultSearchTodoTask.params.filter = filter;
            _self.pracGetListTodoTask(1, false);
          },

前端请求时url:

_self.request.getList(
                {
                  url: 'workflow/practiceGetList' + _self.defaultSearchTodoTask.params.filter,
                  params: _self.defaultSearchTodoTask.params
                }

 

posted on 2024-09-08 10:35  平凡力量  阅读(5)  评论(0编辑  收藏  举报