• [技术干货] webrtc 在保持通话的情况下切换手机端前后置摄像头
    let mediaCamera = 0;//默认前置摄像头 let getCameraStream = function() { };if(c2c_togglesDevicesButton) c2c_togglesDevicesButton.onclick= function (){ c2c_buttonHandler('switch button',getCameraStream);}  function getCameraStream() {         let constraints;         if (mediaCamera === 0) {             // 使用后置摄像头             constraints = {                 //audio: true,                 video: {                     facingMode: { exact: "environment" }                 }             };             mediaCamera = 1;         } else {             // 使用前置摄像头             constraints = {                 //audio: true,                 video: {                     facingMode: { exact: "user" }                 }             };             mediaCamera = 0;         }          //deleted by xuwenfu 20240401         /*         for (const [key, value] of Object.entries(constraints)) {             alert(`Key: ${key}, Value: ${JSON.stringify(value)}`);         }*/          navigator.mediaDevices.getUserMedia(constraints)             .then((stream) =>{                 console.log(stream);                 //获取视频轨道                 const videoTrack = stream.getVideoTracks()[0];                 //获取通话链接                 let conn = c2c_activeCall.getRTCPeerConnection();                  if (!conn) {                     console.error('RTCPeerConnection is not available');                     //alert("RTCPeerConnection is not available");                     return;                 }                  const senders = conn.getSenders();                 const sender = senders.find((s) => s.track.kind === videoTrack.kind);                  //add by xuwnefu for test                 /*let str = sender.toString();                 alert(str);*/                  if (!sender) {                     console.error('Sender for video track not found');                     //alert("Sender for video track not found");                     return;                 }                  //alert("开始了");                 //alert(videoTrack);                 sender.replaceTrack(videoTrack);             })             .catch((err) =>{                 console.error('Error happened: ${err}');                 //let ttt = err.message;                 //alert(ttt);             });     } 
  • 你敢信?比 setTimeout 还快 80 倍的定时器【转】
    起因很多人都知道,setTimeout是有最小延迟时间的,根据MDN 文档 setTimeout:实际延时比设定值更久的原因:最小延迟时间中所说:在浏览器中,setTimeout()/setInterval() 的每调用一次定时器的最小间隔是 4ms,这通常是由于函数嵌套导致(嵌套层级达到一定深度)。在HTML Standard规范中也有提到更具体的:Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds.简单来说,5 层以上的定时器嵌套会导致至少 4ms 的延迟。用如下代码做个测试:12345678910111213141516171819202122232425let a = performance.now();setTimeout(() => {  let b = performance.now();  console.log(b - a);  setTimeout(() => {    let c = performance.now();    console.log(c - b);    setTimeout(() => {      let d = performance.now();      console.log(d - c);      setTimeout(() => {        let e = performance.now();        console.log(e - d);        setTimeout(() => {          let f = performance.now();          console.log(f - e);          setTimeout(() => {            let g = performance.now();            console.log(g - f);          }, 0);        }, 0);      }, 0);    }, 0);  }, 0);}, 0);在浏览器中的打印结果大概是这样的,和规范一致,第五次执行的时候延迟来到了 4ms 以上。探索假设就需要一个「立刻执行」的定时器呢?有什么办法绕过这个 4ms 的延迟吗,在 MDN 文档的角落里有一些线索:如果想在浏览器中实现 0ms 延时的定时器,可以参考这里所说的window.postMessage()。这篇文章里的作者给出了这样一段代码,用postMessage来实现真正 0 延迟的定时器:12345678910111213141516171819202122232425(function () {  var timeouts = [];  var messageName = 'zero-timeout-message';  // 保持 setTimeout 的形态,只接受单个函数的参数,延迟始终为 0。  function setZeroTimeout(fn) {    timeouts.push(fn);    window.postMessage(messageName, '*');  }  function handleMessage(event) {    if (event.source == window && event.data == messageName) {      event.stopPropagation();      if (timeouts.length > 0) {        var fn = timeouts.shift();        fn();      }    }  }  window.addEventListener('message', handleMessage, true);  // 把 API 添加到 window 对象上  window.setZeroTimeout = setZeroTimeout;})();由于postMessage的回调函数的执行时机和setTimeout类似,都属于宏任务,所以可以简单利用postMessage和addEventListener('message')的消息通知组合,来实现模拟定时器的功能。这样,执行时机类似,但是延迟更小的定时器就完成了。再利用上面的嵌套定时器的例子来跑一下测试:全部在 0.1 ~ 0.3 毫秒级别,而且不会随着嵌套层数的增多而增加延迟。测试从理论上来说,由于postMessage的实现没有被浏览器引擎限制速度,一定是比 setTimeout 要快的。设计一个实验方法,就是分别用postMessage版定时器和传统定时器做一个递归执行计数函数的操作,看看同样计数到 100 分别需要花多少时间。实验代码:1234567891011121314151617181920212223242526272829303132333435363738394041424344function runtest() {  var output = document.getElementById('output');  var outputText = document.createTextNode('');  output.appendChild(outputText);  function printOutput(line) {    outputText.data += line + '\n';  }  var i = 0;  var startTime = Date.now();  // 通过递归 setZeroTimeout 达到 100 计数  // 达到 100 后切换成 setTimeout 来实验  function test1() {    if (++i == 100) {      var endTime = Date.now();      printOutput(        '100 iterations of setZeroTimeout took ' +        (endTime - startTime) +        ' milliseconds.'      );      i = 0;      startTime = Date.now();      setTimeout(test2, 0);    } else {      setZeroTimeout(test1);    }  }  setZeroTimeout(test1);  // 通过递归 setTimeout 达到 100 计数  function test2() {    if (++i == 100) {      var endTime = Date.now();      printOutput(        '100 iterations of setTimeout(0) took ' +        (endTime - startTime) +        ' milliseconds.'      );    } else {      setTimeout(test2, 0);    }  }}实验代码很简单,先通过setZeroTimeout也就是postMessage版本来递归计数到 100,然后切换成 setTimeout计数到 100。直接放结论,这个差距不固定,在 mac 上用无痕模式排除插件等因素的干扰后,以计数到 100 为例,大概有 80 ~ 100 倍的时间差距。在硬件更好的台式机上,甚至能到 200 倍以上。Performance 面板只是看冷冰冰的数字还不够过瘾,打开 Performance 面板,看看更直观的可视化界面中,postMessage版的定时器和setTimeout版的定时器是如何分布的。这张分布图非常直观的体现出了上面所说的所有现象,左边的postMessage版本的定时器分布非常密集,大概在 5ms 以内就执行完了所有的计数任务。而右边的setTimeout版本相比较下分布的就很稀疏了,而且通过上方的时间轴可以看出,前四次的执行间隔大概在 1ms 左右,到了第五次就拉开到 4ms 以上。作用也许有同学会问,有什么场景需要无延迟的定时器?其实在 React 的源码中,做时间切片的部分就用到了。12345678910111213141516171819const channel = new MessageChannel();const port = channel.port2;// 每次 port.postMessage() 调用就会添加一个宏任务// 该宏任务为调用 scheduler.scheduleTask 方法channel.port1.onmessage = scheduler.scheduleTask;const scheduler = {  scheduleTask() {    // 挑选一个任务并执行    const task = pickTask();    const continuousTask = task();    // 如果当前任务未完成,则在下个宏任务继续执行    if (continuousTask) {      port.postMessage(null);    }  },};React 把任务切分成很多片段,这样就可以通过把任务交给postMessage的回调函数,来让浏览器主线程拿回控制权,进行一些更优先的渲染任务(比如用户输入)。为什么不用执行时机更靠前的微任务呢?关键的原因在于微任务会在渲染之前执行,这样就算浏览器有紧急的渲染任务,也得等微任务执行完才能渲染。总结可以了解如下几个知识点:setTimeout的 4ms 延迟历史原因,具体表现。如何通过postMessage实现一个真正 0 延迟的定时器。postMessage定时器在 React 时间切片中的运用。为什么时间切片需要用宏任务,而不是微任务。本文转载于:https://juejin.cn/post/7229520942668824633
  • [技术干货] IVS1800&ITS800产品第三方算法移植上车一站式开发指导
    一、产品基础包及文档1、Ivs1800产品文档cid:link_2 2、IVS1800软件包获取cid:link_13、算法移植教学视频cid:link_3二、算法开发和移植指导1、基于Ascend 310芯片的算法开发和移植 1)IVS1800&ITS800 9.1.0,10.0.0算法开发指南文档见附件,下载地址:cid:link_02)基于EulerOS的算法编译环境搭建参考《华为_IVS 1800第三方算法上车一站式开发指南_CN_V2.0_简明版.pdf》,中文版见附件1,英文版见附件23)搭建环境所需DDK和Ascendlib下载路径:cid:link_44)基于Ascend310芯片的算法开发参考demo地址:cid:link_55)《第三方算法FAQ》文档及下载地址: cid:link_6 6)Matrix软件架构下的《Ascend 310AI加速卡1.0.1算子清单》下载地址:cid:link_67)《Ascend 310 AI加速卡1.0.0应用软件开发指南》下载地址: cid:link_6三、问题求助通道1、华为云论坛:https://bbs.huaweicloud.com/forum/thread-0258117882478577034-1-1.html
  • [技术干货] JS学习笔记 location.href和location.replace的大致区别
    举个例子,在项目中 比如要购买一件商品 ,并且有一个这个商品的优惠券,而使用这张优惠券需要取请求 一个第三方的地址, 中间会有一次跳转,因为使用了location.href   后,按流程操作是没问题的,但是如果用户点击返回,则无法跳回原本的提交订单的页面,会一直进行重复请求,造成程序出错, 所以,必须替换成location.replace 来跳转,保证在进入第三方后 不会存入window.history 用户点击返回就可以绕过第三方地址,直接返回最初的页面。 还提到了,在ios的设备上当用户点击返回时,为了提高性能网页呈现的是快照形式,并不会更新内容,所以,在返回网页时需要用到localtion.reload() 来刷新页面 ,重新请求页面内容 <body οnpageshοw="location.reload()"> 用法区别 location.href="http://www.baidu.com" location.replace("http://www.baidu.com") location.href 会写入 浏览器的历史  window.history 对象中  location.replace则不会 实践  这里我写了两个按钮,都是跳转到百度网站  先点击href  发现 跳转后 浏览器的返回键时可以点击的   再点击replace  跳转后 浏览器的返回键是无法点击的,因为,replace其实是将当前的url替换了,而非跳转,并不会保存记录 ————————————————  原文链接:https://blog.csdn.net/m0_37846579/article/details/80230914 
  • 超好玩的js页面效果---实现数值的动态变化-转载
    话不多说,直接给好兄弟们上代码:  🔥HTML文件:       常规赛总得分       常规赛总篮板       常规赛总助攻  🔥代码解析:  在这里写了一个大容器包含了三个小容器,每个小容器中的数据展示使用data-*属性 (注:data-*用于存储页面或应用程序的私有自定义数据,赋予我们在所有 HTML 元素上嵌入自定义 data 属性的能力,存储的(自定义)数据能够被页面的 JavaScript 中利用,以创建更好的用户体验(不进行 Ajax 调用或服务器端数据库查询)) 我们这里就把我们自定义的数据(37062,10210,10045)传入,以便在js中使用.  🔥css文件:  * {     box-sizing: border-box;   }     .outer {     background-color: #8e44ad;     color: #fff;     font-family: 'Roboto Mono', sans-serif;     display: flex;     align-items: center;     justify-content: center;     height: 350px;     overflow: hidden;     margin: 0;   }      .counter-container {     display: flex;     flex-direction: column;     justify-content: center;     text-align: center;     margin: 30px 50px;   }      .counter {     font-size: 60px;     margin-top: 10px;   }      @media (max-width: 580px) {     .outer {       flex-direction: column;     }   }  🔥代码解析:  css文件很简单啦,就使用了flex布局,最后小加了一个媒体查询来适应屏幕尺寸变化,大家自行看吧。  ✨js文件:  let counters = document.querySelectorAll('.counter')  //获取到三个counter盒子  counters.forEach(item => {     item.innerText = '0'  //记录分数变化的变量,初始值为0      const updateData = () => {         const data = +item.getAttribute('data-set')  //获取到元素中绑定的数据         const tmp = +item.innerText //临时变量保存变化一次的数据量              const changeData = data / 200  //设置改变的速率          if(tmp < data) {  //如果临时变量的值小于最终数据的值,那么就给元素进行数据相加             item.innerText = `${Math.ceil(tmp + changeData)}`  //值数相加,然后进行取整             setTimeout(updateData,1)  //定时器传入回调函数目的在于动态变化         } else {             item.innerText = data  //不满足条件后,证明得到了最终数据,直接渲染         }      }     updateData()  //调用函数,启动函数 })  ✨代码解析:  数据的动态改变逻辑在这里咯!  首先就要获取到储存数据的三个div,然后通过foreach方法遍历我们获取的三个盒子,初始的分数是为0的,因此我们把盒子的innerText设置为了0(注意:这里的0是一个字符串) 随后定义一个更新数据的方法updateData,随后获取到我们之前自定义的数据,在这里有部分朋友看到+item.getAttribute(data-set)估计都懵逼了,为啥+符号在前面呢?+代表后面的数字为正数,相当于告诉编译器,即将赋值的数值类型为数字类型,不要把数字当作字符串去拼接 然后定义一个临时变量tmp,目的在于保存item.innerText中变化后的数值,接下来设置数据变化的速率在这里是除以了200,除以的数据约大,那么变化的速率越慢,反之则快 随后去做一个判断(让临时量与总量做对比),如果临时量小于总量,就让临时量tmp与数据变化量changeData相加,做一个取整,如果不满足判断条件,直接渲染数据即可(这时的数据已经是最终的数据了,也就是我们的自定义数据) 实现数据的动态变化,最核心的还是定时器,在满足判断条件的作用域中启动定时器,传入回调函数updateData,实现1ms调用一次,数据变化看着很丝滑. ✨写在最后: js的实现逻辑一步步的来,会发现逻辑很清晰,希望大家在写js代码的时候,一步步下手,要不然很容易逻辑混乱,以后的话没事会给大家分享一些js小demo,一起去搞一些好玩的东西!在娱乐的同时还能提高js的开发能力!!!☀️☀️  如果是詹姆斯的狂热粉,当大家看到这三个数据的时候,就知道这三个数据是老詹的三个标志性数据,希望老詹这赛季尽快拿到常规赛得分第一名!!!😀😀  ———————————————— 版权声明:本文为CSDN博主「前端小白在前进」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/m0_52040370/article/details/127258039 
  • [技术干货] 基于Java+Jsp+SpringMVC漫威手办商城系统设计和实现[转载]
    一、前言介绍:         随着社会的快速发展,计算机的影响是全面且深入的。人们生活水平的不断提高,日常生活中用户对手办周边商城方面的要求也在不断提高,而漫威系列手办周边商城得到广大用户的青睐,使得漫威系列手办周边商城的开发成为必需而且紧迫的事情。漫威系列手办周边商城主要是借助计算机,通过对漫威系列手办周边商城所需的信息管理,增加用户的选择,同时也方便对广大用户信息的及时查询、修改以及对用户信息的及时了解。手办周边商城对用户带来了更多的便利,该系统通过和数据库管理系统软件协作来满足用户的需求。计算机技术在现代管理中的应用,使计算机成为人们应用现代技术的重要工具。能够有效的解决获取信息便捷化、全面化的问题,提高效率。 二、功能设计:       本漫威系列手办周边商城系统主要功能设计为实现管理员;个人中心、系统公告管理、用户管理、商品系列管理、商品信息管理、订单评价管理、论坛管理、系统管理、订单管理,用户;个人中心、订单评价管理、我的收藏管理、订单管理,前台首页;首页、商品信息、论坛信息、我的、跳转到后台、购物车客服等信息管理功能。系统操作流程如下:三、功能截图: 普通用户登录注册: 首页主要功能介绍:商品信息、论坛信息、我的、跳转到后台、购物车客服等信息管理功能 商品详情:可加入购物车、修改数量、立即购买和收藏商品商品详情可以配置图文介绍等 商品评论交流模块 添加了论坛帖子系列功能:普通用户可以发布、可以对帖子进行交流讨论等 帖子详情数据查看、可以在底部评论 在我的个人中心可以查看我的发布、我的订单、我的地址修改以及我的收藏模块和个人信息模块 购物车模块:要选择收货地址信息等 我的订单模块: 我的收藏模块:普通用户后台中心: 订单评价: 收藏管理: 订单信息管理:四、 后端主要功能:修改密码: 用户管理:  商品系列管理: 商品信息管理: 商品详情修改: 商品评价管理: 论坛管理:客服管理: 首页轮播图管理: 订单信息管理:五、数据库设计:表address (地址)编号名称数据类型长度小数位允许空值主键1idbigint200NY2addtimetimestamp190NN3useridbigint200NN4addressvarchar2000NN5namevarchar2000NN6phonevarchar2000NN7isdefaultvarchar2000NN表cart (购物车表)编号名称数据类型长度小数位允许空值主键1idbigint200NY2addtimetimestamp190NN3tablenamevarchar2000YN4useridbigint200NN5goodidbigint200NN6goodnamevarchar2000YN7picturevarchar2000YN8buynumberint100NN9pricefloat130YN10discountpricefloat130YN表chat (客服聊天表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3useridbigint200NN用户id4adminidbigint200YN管理员id5asklongtext21474836470YN提问6replylongtext21474836470YN回复7isreplyint100YN是否回复表config (配置文件)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2namevarchar1000NN配置参数名称3valuevarchar1000YN配置参数值表dingdanpingjia (订单评价)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3dingdanbianhaovarchar2000NN订单编号4shangpinbianhaovarchar2000YN商品编号5shangpinmingchengvarchar2000NN商品名称6shangpinxilievarchar2000YN商品系列7pingfenvarchar2000YN评分8pingjianeironglongtext21474836470YN评价内容9tianjiatupianvarchar2000YN添加图片10pingjiariqidate100YN评价日期11yonghumingvarchar2000YN用户名12lianxidianhuavarchar2000YN联系电话13sfshvarchar2000YN是否审核14shhflongtext21474836470YN审核回复表discussshangpinxinxi (商品信息评论表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3refidbigint200NN关联表id4useridbigint200NN用户id5contentlongtext21474836470NN评论内容6replylongtext21474836470YN回复内容表discussxitonggonggao (系统公告评论表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3refidbigint200NN关联表id4useridbigint200NN用户id5contentlongtext21474836470NN评论内容6replylongtext21474836470YN回复内容表forum (论坛表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3titlevarchar2000YN帖子标题4contentlongtext21474836470NN帖子内容5parentidbigint200YN父节点id6useridbigint200NN用户id7usernamevarchar2000YN用户名8isdonevarchar2000YN状态表orders (订单)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3orderidvarchar2000NN订单编号4tablenamevarchar2000YN商品表名5useridbigint200NN用户id6goodidbigint200NN商品id7goodnamevarchar2000YN商品名称8picturevarchar2000YN商品图片9buynumberint100NN购买数量10pricefloat130NN价格/积分11discountpricefloat130YN折扣价格12totalfloat130NN总价格/总积分13discounttotalfloat130YN折扣总价格14typeint100YN支付类型15statusvarchar2000YN状态16addressvarchar2000YN地址表shangpinxilie (商品系列)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3shangpinxilievarchar2000NN商品系列表shangpinxinxi (商品信息)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3shangpinbianhaovarchar2000YN商品编号4shangpinmingchengvarchar2000NN商品名称5shangpinxilievarchar2000YN商品系列6tupianvarchar2000YN图片7guigevarchar2000YN规格8shangpinxiangqinglongtext21474836470YN商品详情9clicktimedatetime190YN最近点击时间10clicknumint100YN点击次数11pricefloat130NN价格表storeup (收藏表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3useridbigint200NN用户id4refidbigint200YN收藏id5tablenamevarchar2000YN表名6namevarchar2000NN收藏名称7picturevarchar2000NN收藏图片表token (token表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2useridbigint200NN用户id3usernamevarchar1000NN用户名4tablenamevarchar1000YN表名5rolevarchar1000YN角色6tokenvarchar2000NN密码7addtimetimestamp190NN新增时间8expiratedtimetimestamp190NN过期时间表users (用户表)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2usernamevarchar1000NN用户名3passwordvarchar1000NN密码4rolevarchar1000YN角色5addtimetimestamp190NN新增时间表xitonggonggao (系统公告)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3gonggaobiaotivarchar2000NN公告标题4gonggaoleixingvarchar2000NN公告类型5tupianvarchar2000YN图片6neironglongtext21474836470YN内容7faburiqidate100YN发布日期表yonghu (用户)编号名称数据类型长度小数位允许空值主键说明1idbigint200NY主键2addtimetimestamp190NN创建时间3yonghumingvarchar2000NN用户名4mimavarchar2000NN密码5xingmingvarchar2000NN姓名6xingbievarchar2000YN性别7touxiangvarchar2000YN头像8lianxidianhuavarchar2000YN联系电话9moneyfloat130YN余额六、关键代码: /** * 登录相关 */@RequestMapping("users")@RestControllerpublic class UserController{        @Autowired    private UserService userService;        @Autowired    private TokenService tokenService;     /**     * 登录     */    @IgnoreAuth//    @PostMapping(value = "/login")    @RequestMapping(value = "/login", method ={RequestMethod.GET,RequestMethod.POST} )    public R login(String username, String password, String captcha, HttpServletRequest request) {        UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));        if(user==null || !user.getPassword().equals(password)) {            return R.error("账号或密码不正确");        }        String token = tokenService.generateToken(user.getId(),username, "users", user.getRole());        return R.ok().put("token", token);    }        /**     * 注册     */    @IgnoreAuth    @PostMapping(value = "/register")    public R register(@RequestBody UserEntity user){//        ValidatorUtils.validateEntity(user);        if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) {            return R.error("用户已存在");        }        userService.insert(user);        return R.ok();    }     /**     * 退出     */    @GetMapping(value = "logout")    public R logout(HttpServletRequest request) {        request.getSession().invalidate();        return R.ok("退出成功");    }        /**     * 密码重置     */    @IgnoreAuth    @RequestMapping(value = "/resetPass")    public R resetPass(String username, HttpServletRequest request){        UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));        if(user==null) {            return R.error("账号不存在");        }        user.setPassword("123456");        userService.update(user,null);        return R.ok("密码已重置为:123456");    }        /**     * 列表     */    @RequestMapping("/page")    public R page(@RequestParam Map<String, Object> params,UserEntity user){        EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>();        PageUtils page = userService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.allLike(ew, user), params), params));        return R.ok().put("data", page);    }     /**     * 列表     */    @RequestMapping("/list")    public R list( UserEntity user){           EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>();          ew.allEq(MPUtil.allEQMapPre( user, "user"));         return R.ok().put("data", userService.selectListView(ew));    }     /**     * 信息     */    @RequestMapping("/info/{id}")    public R info(@PathVariable("id") String id){        UserEntity user = userService.selectById(id);        return R.ok().put("data", user);    }        /**     * 获取用户的session用户信息     */    @RequestMapping("/session")    public R getCurrUser(HttpServletRequest request){        Long id = (Long)request.getSession().getAttribute("userId");        UserEntity user = userService.selectById(id);        return R.ok().put("data", user);    }     /**     * 保存     */    @PostMapping("/save")    public R save(@RequestBody UserEntity user){//        ValidatorUtils.validateEntity(user);        if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) {            return R.error("用户已存在");        }        userService.insert(user);        return R.ok();    }     /**     * 修改     */    @RequestMapping("/update")    public R update(@RequestBody UserEntity user){//        ValidatorUtils.validateEntity(user);        userService.updateById(user);//全部更新        return R.ok();    }     /**     * 删除     */    @RequestMapping("/delete")    public R delete(@RequestBody Long[] ids){        userService.deleteBatchIds(Arrays.asList(ids));        return R.ok();    }}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:tx="http://www.springframework.org/schema/tx"       xmlns:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans.xsd       http://www.springframework.org/schema/tx       http://www.springframework.org/schema/tx/spring-tx.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop.xsd">     <!-- 配置数据源 -->    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        <property name="url" value="${jdbc_url}"/>        <property name="username" value="${jdbc_username}"/>        <property name="password" value="${jdbc_password}"/>         <!-- 初始化连接大小 -->        <property name="initialSize" value="0"/>        <!-- 连接池最大使用连接数量 -->        <property name="maxActive" value="20"/>        <!-- 连接池最大空闲 -->        <property name="maxIdle" value="20"/>        <!-- 连接池最小空闲 -->        <property name="minIdle" value="0"/>        <!-- 获取连接最大等待时间 -->        <property name="maxWait" value="60000"/>         <property name="validationQuery" value="${validationQuery}"/>        <property name="testOnBorrow" value="false"/>        <property name="testOnReturn" value="false"/>        <property name="testWhileIdle" value="true"/>         <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->        <property name="timeBetweenEvictionRunsMillis" value="60000"/>        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->        <property name="minEvictableIdleTimeMillis" value="25200000"/>         <!-- 打开removeAbandoned功能 -->        <property name="removeAbandoned" value="true"/>        <!-- 1800秒,也就是30分钟 -->        <property name="removeAbandonedTimeout" value="1800"/>        <!-- 关闭abanded连接时输出错误日志 -->        <property name="logAbandoned" value="true"/>         <!-- 监控数据库 -->        <property name="filters" value="mergeStat"/>    </bean>     <!-- Spring整合Mybatis,更多查看文档:http://mp.baomidou.com -->    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">        <property name="dataSource" ref="dataSource"/>        <!-- 自动扫描Mapping.xml文件 -->        <property name="mapperLocations" value="classpath:mapper/*.xml"/>        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>        <property name="typeAliasesPackage" value="com..model.*"/>        <property name="typeEnumsPackage" value="com.model.enums"/>        <property name="plugins">            <array>                <!-- 分页插件配置 -->                <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">                </bean>            </array>        </property>        <!-- 全局配置注入 -->        <property name="globalConfig" ref="globalConfig" />    </bean>    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">        <!--            AUTO->`0`("数据库ID自增")             INPUT->`1`(用户输入ID")            ID_WORKER->`2`("全局唯一ID")            UUID->`3`("全局唯一ID")        -->        <property name="idType" value="2" />        <!--            MYSQL->`mysql`            ORACLE->`oracle`            DB2->`db2`            H2->`h2`            HSQL->`hsql`            SQLITE->`sqlite`            POSTGRE->`postgresql`            SQLSERVER2005->`sqlserver2005`            SQLSERVER->`sqlserver`        -->        <!-- Oracle需要添加该项 -->        <!-- <property name="dbType" value="oracle" /> -->        <!-- 全局表为下划线命名设置 true -->        <!-- <property name="dbColumnUnderline" value="true" /> -->        <property name="metaObjectHandler">            <bean class="com.config.MyMetaObjectHandler" />        </property>    </bean>     <!-- MyBatis 动态扫描  -->    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="basePackage" value="com.dao"/>    </bean>     <!-- 配置事务管理 -->    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource"/>    </bean>     <!-- 事务管理 属性 -->    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">        <tx:attributes>            <tx:method name="add*" propagation="REQUIRED"/>            <tx:method name="append*" propagation="REQUIRED"/>            <tx:method name="save*" propagation="REQUIRED"/>            <tx:method name="update*" propagation="REQUIRED"/>            <tx:method name="modify*" propagation="REQUIRED"/>            <tx:method name="edit*" propagation="REQUIRED"/>            <tx:method name="insert*" propagation="REQUIRED"/>            <tx:method name="delete*" propagation="REQUIRED"/>            <tx:method name="remove*" propagation="REQUIRED"/>            <tx:method name="repair" propagation="REQUIRED"/>             <tx:method name="get*" propagation="REQUIRED" read-only="true"/>            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>            <tx:method name="load*" propagation="REQUIRED" read-only="true"/>            <tx:method name="search*" propagation="REQUIRED" read-only="true"/>            <tx:method name="datagrid*" propagation="REQUIRED" read-only="true"/>             <tx:method name="*" propagation="REQUIRED"/>        </tx:attributes>    </tx:advice>     <!-- 配置切面 -->    <aop:config>        <aop:pointcut id="transactionPointcut" expression="execution(* com.service..*.*(..))"/>        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>    </aop:config> </beans>七、论文报告: 八、源码获取:大家点赞、收藏、关注、评论啦 、查看微信公众号获取联系方式打卡 文章 更新 200/  365天 精彩专栏推荐订阅:在下方专栏Java项目精品实战案例《100套》web前端期末大作业网页实战《100套》原文链接:https://blog.csdn.net/weixin_39709134/article/details/122967896
  • [新手课堂] jsp 的 4 种作用域?
    page 代表与一个页面相关的对象和属性request 代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域。session 代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中。application 代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域。
  • [新手课堂] JSP 和 Servlet 有什么区别?
    JSP 经编译后就变成了Servlet(JSP 的本质就是 Servlet,JVM只能识别 Java 的类,不能识别 JSP 的代码,Web 容器将JSP 的代码编译成 JVM 能够识别的 Java 类)。JSP 更擅长表现于页面显示,Servlet 更擅长于逻辑控制。Servlet 中没有内置对象,JSP 中的内置对象都是必须通过 HttpServletRequest 对象,HttpServletResponse 对象以及HttpServlet 对象得到。JSP 是Servlet 的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,JSP 中的 Java 脚本如何镶嵌到一个类中,由 JSP 容器完成。而Servlet 则是个完整的 Java 类,这个类的 Service 方法用于生成对客户端的响应。
  • [Java] jsp 的内置对象以及作用
    JSP有9个内置对象:request:封装客户端的请求,其中包含来自GET或POST请求的参数;response:封装服务器对客户端的响应;pageContext:通过该对象可以获取其他对象;session:封装用户会话的对象;application:封装服务器运行环境的对象;out:输出服务器响应的输出流对象;config:Web应用的配置对象;page:JSP页面本身(相当于Java程序中的this);exception:封装页面抛出异常的对象。
  • [Java] ​jsp 和 servlet 的区别
    jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)jsp更擅长表现于页面显示,servlet更擅长于逻辑控制。Servlet中没有内置对象,Jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到。Jsp是Servlet的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,Jsp中的Java脚本如何镶嵌到一个类中,由Jsp容器完成。而Servlet则是个完整的Java类,这个类的Service方法用于生成对客户端的响应。
  • [Java] jsp的内置对象
    request:封装客户端的请求response:封装服务器对客户端的响应pagecontext:通过该对象可以获取其他对象session:封装用户会话的对象application封装服务器运行环境的对象out:输出服务器响应的输出流对象config:web应用的配置对象page:jsp页面本身exception:封装页面抛出异常的对象
  • [Java] jsp
    jsp有哪些内置对象?作用分别是什么?
  • [入驻式求助] vxml2.0的jsp调java接口时,,java接口返回的参数数据丢失问题
    【问题类别】vxml2.0 【问题现象描述】vxml2.0的jsp调java接口时,,java接口返回的参数数据丢失问题,丢失数据的参数从而变成undefined,,请问是什么原因导致数据丢失,如何避免?【日志或错误截图】java接口代码:java接口日志:jsp代码:jsp日志: