js

bun 下一代js

bun

webRtc

网站 参考 参考 参考 参考

虚拟表格

参考

对象复制

参考

集成 websocket 的四种方案

详情1 详情2

netty

ws连接

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    public void ConnWebSocketServer() {
        EventLoopGroup client = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            URI wsUri = new URI("ws://119.29.180.139:9503/ws");
            bootstrap.group(client)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new HttpClientCodec());
                            pipeline.addLast(new HttpObjectAggregator(1024 * 10));
                            pipeline.addLast("WebSocketClientHandler", new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(wsUri,
                                    WebSocketVersion.V13, null, true, new DefaultHttpHeaders())));
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());
                        }
                    });
            ChannelFuture cf = bootstrap.connect(wsUri.getHost(), wsUri.getPort()).sync();
            cf.channel().closeFuture().sync();
        } catch (Exception ignored) {
        } finally {
            client.shutdownGracefully();
        }
    }

回调类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.wisdomsite.socket;

import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;

public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {

    private WebSocketClientHandshaker webSocketClientHandshaker;
    private ChannelPromise handshakeFuture = null;

    public WebSocketClientHandler(WebSocketClientHandshaker webSocketClientHandshaker) {
        this.webSocketClientHandshaker = webSocketClientHandshaker;
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        this.handshakeFuture = ctx.newPromise();
    }

    /**
     * 当客户端主动链接服务端的链接后,调用此方法
     *
     * @param channelHandlerContext ChannelHandlerContext
     */
    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) {
        Channel channel = channelHandlerContext.channel();
        // 握手
        webSocketClientHandshaker.handshake(channel);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 握手协议返回,设置结束握手
        if (!this.webSocketClientHandshaker.isHandshakeComplete()) {
            FullHttpResponse response = (FullHttpResponse) msg;
            this.webSocketClientHandshaker.finishHandshake(ctx.channel(), response);
            this.handshakeFuture.setSuccess();
            return;
        }

        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame textFrame = (TextWebSocketFrame) msg;
            System.out.println(textFrame);
        }

        if (msg instanceof CloseWebSocketFrame) {
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//        System.out.println("WebSocketClientHandler::channelInactive 服务端连接成功");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
    }

}

RSA 公钥解密

版本: “jsencrypt”: “3.2.0”, 原地址 js文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'

// 密钥对生成 http://web.chacuo.net/netrsakeypair

// 公钥
const publicKey = ``

// 利用公钥对数据加密
export function encrypt(text) {
  const encryptor = new JSEncrypt()
  encryptor.setPublicKey(publicKey)
  return encryptor.encrypt(text)
}

// 利用公钥对私钥加密的数据进行解密
export function decrypt(text) {
  const encryptor = new JSEncrypt()
  encryptor.setPublicKey(publicKey)
  let decrypt = encryptor.decrypt(text)
  return decrypt ? decrypt : ''
}

RSA默认不支持公钥解密私钥 修改jsencrypt.js文件

1
2
3
4
5
6
7
t.prototype.decrypt=function(t){
  // var e=P(t,16),i=this.doPrivate(e);
  var e=P(t,16),i=this.doPublic(e);
  return null==i?null:function(t,e){
    for(var i=t.toByteArray(),r=0;r<i.length&&0==i[r];)++r;
    // if(i.length-r!=e-1||2!=i[r])return null;
    for(++r;0!=i[r];)if(++r>=i.length)return null;

后台java文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 * rsa 密钥加密解密
 */
public class RsaUtils {

	/**
	 * Rsa 私钥
	 */
	public static String privateKey = "";

	/**
	 * 私钥解密
	 *
	 * @param text 待解密的文本
	 * @return 解密后的文本
	 */
	public static String decryptByPrivateKey(String text) throws Exception {
		return decryptByPrivateKey(privateKey, text);
	}

	/**
	 * 私钥加密
	 *
	 * @param text 待加密的文本
	 * @return 加密后的文本
	 */
	public static String decryptByPublicKey(String text) throws Exception {
		return encryptByPrivateKey(privateKey, text);
	}

	/**
	 * 私钥加密
	 *
	 * @param privateKeyString 私钥
	 * @param text             待加密的信息
	 * @return 加密后的文本
	 */
	public static String encryptByPrivateKey(String privateKeyString, String text) throws Exception {
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		byte[] result = cipher.doFinal(text.getBytes());
		return Base64.encodeBase64String(result);
	}

	/**
	 * 私钥解密
	 *
	 * @param privateKeyString 私钥
	 * @param text             待解密的文本
	 * @return 解密后的文本
	 */
	public static String decryptByPrivateKey(String privateKeyString, String text) throws Exception {
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] result = cipher.doFinal(Base64.decodeBase64(text));
		return new String(result);
	}

}

异步 Promise详解(resolve,reject,catch)

详情

其他

// 获取描述信息(可查询不可修改)

浅拷贝 Object.assign()

深拷贝 Object.getOwnPropertyDescriptors()

想要修改需要使用

Object.defineProperties

Object.defineProperties()

方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象

1
2
Object.defineProperties({},student对象) 
// 相当于拷贝一个新的student对象

在js中使用 = 为赋值对象的引用(指针),并不能创建一个一模一样的对象

mouseover(鼠标覆盖)mouseenter(鼠标进入)两个事件的区别

详情

剪切板复制粘贴

highlightjs前端代码高亮

官方 中文网站

vue使用highlight.js的坑

详情

Thymeleaf

时间

1
#dates.format(#dates.createNow(),'yyyy-MM-dd HH:mm:ss')

保留小数

${#numbers.formatDecimal(num,0,‘COMMA’,2,‘POINT’)}则显示 .00

${#numbers.formatDecimal(num,1,‘COMMA’,2,‘POINT’)}则显示 0.00

COMMA:’,’

POINT:‘.’

配置文件

spring.thymeleaf

关闭缓存

cache=false

模板位置

prefix=classpath:/**/

suffix=.html

html属性

html头属性 xmlns:th=“http://www.thymeleaf.org

th:标签属性

#{取值}

th:text="${}"

th:object="${}" “*{}”

[[${取作用域的值}]]

url@{}

th:each=“a:${**}”

aStat

第一个 first

最后一个 last

奇数 even

偶数 odd

排除 th:unless

使用工具包

1
#strings.isEmpty(msg)

jsp攻略

a标签

1
2
//新页面
target="_blank"

下拉框

1
2
3
4
//获取下拉框 已选择的值
alert($("#create-transactionStage option:selected").text())
//获取下拉框 已选择的内容
alert($("#create-transactionStage option:selected").val())

禁止修改属性

1
readonly 
1
disabled 用表单提交不了 是灰色的背景

输入的值只能是数字

1
oninput="value=value.replace(/[^\d]/g,'')"

关于表单

中有一个输入框的时候回车默认触发action事件

1
2
3
4
5
6
设置表单数据没有都不触发
action="javascript:;"
设置输入框不提示缓存内容
autocomplete="off"
选择多个文件
multiple

上传文件

1
2
3
4
enctype="multipart/form-data"

ajax
new FormData($('#dataForm')[0]),

鼠标放上去的提示以及图片加载失败提示

1
2
3
4
鼠标放上去的提示
title="没有图片"
    图片加载失败图片
    onerror="onerror=null;src='static/images/products/c_0001.jpg'"
1
2
获得焦点
$("#name").focus()

取整

1
parseInt(数值)

显示

1
juery对象.hide()

隐藏

1
juery对象.show()

元素追加

选择器.htm;()重新设置内部内容

选择器.empty()删除元素内部内容

选择器.append()元素内部

选择器.after()元素外部后面

选择器.before()元素外部前面

判断不为空

1
${not empty activity.startDate && !(activity.startDate eq null)?activity.startDate:"未设置"}

正则表达式

/表达式/.test(变量)

选择器

id:#id

class:.id

标签:id

表单::id

提示删除信息

1
if (!confirm("确认删除吗")) return;

过滤器(筛选器)

$(“id:first”) //第一个

$(“id:last”) //第后一个

$(“id:eq(2)”) //按照下标查询

table

1
2
3
4
rowspan=""
colspan=""

空格

换行

1
<br/>

一行


JSTL标签库

for循环

1
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
1
<c:forEach items="${requestScope.list}" var="emp"></c:forEach>
1
2
3
<c:if test="${not empty 判断数据(对象)}">
//不为空    
</c:if>
1
2
<c:forEach items="${集合(容器)}" var="自定义名称">
</c:forEach>

and 和

or 或者

选择标签

1
2
3
4
5
6
7
8
<c:choose>
            <c:when test="">
<%--                选择标签--%>
            </c:when>
            <c:otherwise>
<%--                都不成立执行这个--%>
            </c:otherwise>
        </c:choose>

判断回车按键

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$(window).keydown(e => {
    if (e.key == "Enter") {
        if (!createClueModal.is(":hidden")) {
                        //判断是否失去焦点
                        if (!($("#noteContent")[0] == document.activeElement)) {
                            updateRemarkBtn.click()
                        }
            createClueBtn.click()
        }
    }
})

$(document).ready(function () {  
        $(":text").keydown(function () {    // 按键按下时触发的事件;  
            $(":text").css("background-color", "green");  
        });  

        $(":text").keyup(function () {      // 按键弹起时触发的事件;  
            $(":text").css("background-color", "blue");  
        });  

        $("button").click(function () {  
            $(":text").keyup();             // keyup()方法触发keyup事件  
        });  

        var i = 0;  
        $(":text").keypress(function () {   // keypress:输入框每获取一个字符,就触发一次该事件。  
            $("span").text(i++);  
        });  
    });

内置对象

request:请求

response:响应

session:会话

application:ServletContext

config:ServletConfing

out:页面输出对象

page:this

exception:异常对象

pageContext:jsp核心,功能对象

指令元素

<$@ 元素%>

page里面的属性

pageEncoding:响应编码

contentType:相应类型

language: 指定语言java

isErrorPage:是否接收异常

errorPage:

import:导包

include:包含其他jsp

taglib:引入其他标签库

脚本元素

<% %>定义jspService()方法内容

<%! %>声明标签:定义类下的内容

<%= %>输出标签:表达式标签

<%– –%>注释标签

动作元素

<jsp:include 包含其他jsp

<jsp:forward 请求转发

<jsp:param 传参数

<jsp:useBean 类实例化

<jsp:setProperty 属性设置

<jspgetProperty 属性获取

EL表达式

${id}

默认从四个作用域中获取

从最小的page中开始获取

内置对象(小>大)

(6个作用域范围)

pageScope

requsetScope

sessionScope

applicationScope

获取 ?后面的请求参数

${param.id}

获取同名的多个参数

${param.id[0]}

${param.id[1]}

${param.id[2]}

获取cookie内容

${cookie.id}

获取Map

${对象(键)}

获取List

${对象[下标]}

ajax

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$.ajax({
    url: 'settings/qx/user/login.do',
    data: {
        loginAct: loginAct,
        loginPwd: loginPwd,
        isRemPew: isRemPew,
    },
    type: 'post',
    dataType: 'json',
    //如果你想要用传统的方式来序列化数据,那么就设置为true
    //用来上传数组
    traditional:true,
    success: function (data) {
        if (data.code == "1") {
            window.location.href = "workbench/index.do";
        } else {
            $("#msg").text(data.message);
        }
    },
    beforeSend:function () {//在发生ajax之前执行这个函数

       }
})

截取字符串

str.substr(从哪里开始,截取的长度)

str.substr(从哪里开始) 截取到字符串最后

str.substring(从哪里开始,截取到哪里)

获取某个值的下标

1
str.lastIndexOf(".")

返回上一页

1
onclick="window.history.back();"

全选

方式1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var $chk = $(":checkbox[name=chk]");
// 全选
$("#selectAll").click(function() {
    // 让所有复选框的选中状态和全选按钮的选中状态一致
    $chk.prop("checked", this.checked);
});

// 当取消选中某个商品,全选按钮也应该取消选中,即选择商品的复选框会影响全选按钮的选中状态
$chk.click(function() {
    /*// 先让全选按钮选中
    $("#selectAll").prop("checked", true);
    // 遍历查找未选中的复选框,如果有,则全选按钮一定是未选中的
    $chk.each(function() {
        if (!this.checked) {
            $("#selectAll").prop("checked", false);
            // 必须return false才可以结束each循环
            return false;
        }
    });*/

    // 判断选中的数量和总数据是否一致,如果一致,则全选按钮选中
    //$("#selectAll").prop("checked", $chk.length == $(":checkbox[name=chk]:checked").length);
    // $("#selectAll").prop("checked", $chk.length == $chk.filter(":checked").length);
    $("#selectAll").prop("checked", !$chk.is(":not(:checked)"));
});

方式2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//单击全选按钮
$("#selectAll").click(function () {
    $("#checkTable input[type='checkbox']").prop('checked', $("#selectAll").prop('checked'))
})

//给所有复选框添加单击事件
var arrayObj = $("#checkTable input[type='checkbox']")
arrayObj.splice(0, 1)
// console.log(arrayObj)
arrayObj.click(function () {
    if ($("#selectAll").prop('checked')) {
        if (!($("#checkTable input[type='checkbox']:checked").size() == ($("#checkTable input[type='checkbox']").size()))) {
            $("#selectAll").prop('checked', false)
        }
    } else {
        if ($("#checkTable input[type='checkbox']:checked").size() == ($("#checkTable input[type='checkbox']").size() - 1)) {
            $("#selectAll").prop('checked', true)
        }
    }
})

老师笔记

1、js截取字符串: str.substr(startIndex,length); str.substr(startIndex);//从下标为startIndex的字符开始截取,截取到字符串的最后,得到目标字符串。 var str=“abcdef”; str.substr(2);//===>cdef

str.substring(startIndex,endIndex);

js中获取指定字符在字符串中的下标:str.indexOf(".") js中获取指定的最后一个字符在字符串中的下标:str.lastIndexOf(".") js中把字符串中所有的字母统一转化成大写字母: str.toUpperCase(); 2、ajax发送异步请求: data:向后台提交参数,三种写法: 1)、{ name1:value2, name2:value2, ….. } 只能用于提交文本数据 2)、name1=value1&name2=value2&…. 只能用于提交文本数据 3)、FormData对象:FormData是ajax提供的一个接口,可以模拟name1-value1键值对向后台提交参数; FormData最大的优势是不但能提交文本数据,还能提交二进制数据。 var formData=new FormData(); formData.append(“activityFile”,activityFile); formData.append(“username”,“zhangsan”); 3、在页面中给元素添加事件的方式: 1)、使用事件属性: 2)、使用jquery的事件函数: 选择器.click(function(){ //….. }); 只能对固有元素添加事件,不能对动态生成的元素添加事件。 在页面加载过程中产生的元素,叫固有元素; 在页面加载完成之后产生的元素,叫动态生成的元素。 3)、使用jquery的on函数: 不但能给固有元素添加事件,还能给动态生成的元素添加事件,通常用来给动态生成的元素添加事件。 父选择器.on(事件类型,目标选择器,function(){ //…. });

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
   父选择器:要求父选择器必须是固有元素,不一定是直接父元素,但是要求必须是固有的。
            <div id="div2">//固有 
             <div id="div1">
                <input type="button">
     </div>
     </div>

     $("#div2").on();
 事件类型:跟jquery的事件函数一致。
 目标选择器:在父选择器基础之上查找目标元素。
            <div id="div2">//固有 
             <div id="div1">
                <input type="button">
     </div>
     </div>
     <input type="button">
            $("#div2").on("click","input[type='button']");
 function:回调函数。
            $("#div2").on("click","input[type='button']",function(){......});

bs分页

1
容器.bs_pagination('getOption', 'rowsPerPage')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//分页插件
let totalPages = 0;
if (data.data.totalRows % pageSize == 0) {
    totalPages = data.data.totalRows / pageSize
} else {
    totalPages = parseInt(data.data.totalRows / pageSize) + 1
}
$("#demo_pag").bs_pagination({
    currentPage: pageNo,//当前页
    rowsPerPage: pageSize,//每有显示条数
    totalRows: data.data.totalRows,//总条数
    totalPages: totalPages,//总页数

    visiblePageLinks: 5,//显示的翻页卡片数

    showGoToPage: true,//是否显示“跳转到第几页”
    showRowsPerPage: true,//是否显示“每页显示条数”
    showRowsInfo: true,//是否显示记录的信息

    //每次切换页号对会触发函数,函数那返回切换后的页号和每页显示条数
    onChangePage: (e, pageObj) => {
        findTransaction(pageObj.currentPage, pageObj.rowsPerPage)
    }
})

jquery

获取标签的元素值

选择器.attr(""); 获取不是true|false

选择器.prop(""); 获取是true|false

jquery转换为dom对象

var j = $("#id")

方式1:var is = j[0];

方式2:var id = j.get[0];

dom转换为jquery对象

$(dom对象)

父子选择器

1
2
3
$("#tBody input[type='checkbox']")
//tBody(id)选择器下的所有input标签
[]表示input标签所有的type='checkbox'属性

空格和>都可以表示父子选择器

空格表示标签下的所有标签

小于号(>)只能表示标签下的子标签(直接子标签),孙子标签的表示不了

[]表示根据属性过滤

实现复选框全选和取消全选

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//实现全选和取消全选
$("#chkedAll").click(function () {
    //让列表中所有的复选框属性值和全选按钮的属性值一样
    $("#tBody input[type='checkbox']").prop("checked", $("#chkedAll").prop("checked"))
})
//给所有的复选框添加单击事件
$("#tBody input[type='checkbox']").click(function () {
    if ($("#tBody input[type='checkbox']").size() == $("#tBody input[type='checkbox']:checked").size()) {
        $("#chkedAll").prop("checked", true)
    } else {
        $("#chkedAll").prop("checked", false)
    }
})

遍历数组

1
2
3
4
$.each(需要遍历的数组, function (index(下标), object(每次遍历的内容)) {

})
//遍历一次执行一次function

删除元素

1
数组.splice(下标,数量)

equals

参考

人脸

参考

水印

微信小程序

动画

lax.js

js多继承

参考

echarts双Y轴

参考

前端cdn 资源访问加速 icons资源

cdn

jsdelivr

bootcdn

cdnjs

icons

阿里云iconfont icons8

国内访问拒绝问题

图片拖拽

https://github.com/SortableJS/vue.draggable.next/issues/216 https://vueuse.org/integrations/usesortable/

axios

参考

cdn导入参考

npm pnpm

node 多版本管理

参考

详情 换源

pnpm

运行以下命令设置新的存储路径

1
pnpm config set store-dir <new path> //将<new path> 替换为目标存储路径(非中文)

3.输入命令验证是否修改成功

1
pnpm store path

换源(npm 和 pnpm 一样)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 查看源
pnpm get registry
pnpm config get registry

# 切换到淘宝镜像
pnpm config set registry https://registry.npmmirror.com/

# 切换到腾讯云镜像
http://mirrors.cloud.tencent.com/npm/

# 华为
https://mirrors.huaweicloud.com/repository/npm

命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
加 -g 为全局
install 安装
uninstall 卸载
update 更新

# 查看全局安装的包
npm list -g --depth 0

# 依赖包远程信息
npm into xxx