jQuery Image Annotation Plugin

 

jQuery Image Annotation Plugin

Tuesday, 17 March 2009

Download Released: 2nd April, 2009

Flickr was the first site to widely introduce the concept of annotating images with user comments. This concept was first pioneered by the Fotonotes JavaScript library, and has since been further popularised by Web 2.0 sites like Facebook.

When my current client asked my to integrate simlar functionality into there site, I started to look around for a jQuery plugin that could provide this, but none was available. The Image Annotate library for Drupal is based upon jQuery UI however, so taking this for a base, I adopted it to just use jQuery 1.2.6.

You can see a live example here.

Using the plugin is straight forward, simply hookup the plugin an call the imageAnnotate function on the image you would like to annotate.

  1. <html>  
  2.     <head>  
  3.   
  4.         <style type="text/css" media="all">@import "/css/annotation.css";</style>  
  5.         <script type="text/javascript" src="/js/jquery-1.2.6.min.js"></script>  
  6.         <script type="text/javascript" src="/js/jquery-ui-1.5.3.min.js"></script>  
  7.         <script type="text/javascript" src="/js/jquery.annotate.js"></script>  
  8.   
  9.         <script language="javascript">  
  10.   
  11.             $(window).load(function() {   
  12.   
  13.                $("#toAnnotate").annotateImage({   
  14.                     editable: true,   
  15.                     useAjax: false,   
  16.                     notes: [ { "top": 286,    
  17.                                "left": 161,    
  18.                                "width": 52,    
  19.                                "height": 37,    
  20.                                "text": "A read only annotation",    
  21.                                "editable": false },   
  22.                              { "top": 134,    
  23.                                "left": 179,    
  24.                                "width": 68,    
  25.                                "height": 74,    
  26.                                "text": "An editable annotation",    
  27.                                "editable": true } ]                       
  28.                 });   
  29.   
  30.             });   
  31.   
  32.         </script>  
  33.   
  34.     </head>  
  35.     <body>  
  36.   
  37.         <div class="main-content">  
  38.             <img src="/images/annotated.jpg" id="toAnnotate" />  
  39.         </div>  
  40.   
  41.     </body>  
  42. </html>  

The plugin requires jQuery 1.2.6 and jQuery UI with resiable and draggable options included. A saveAsHtml method is available in order to generate a dynamic HTML form with which to save the annotations back to the server.

AJAX Version

EDIT: see this post for server side code.

As well as operating in a static HTML mode, the plugin can load, update and delete annotations using AJAX calls. Specifying Get, Save and Delete URLs, plus setting the useAjax flag to true.

  1. $(window).load(function() {   
  2.                 $("#toAnnotate").annotateImage({   
  3.                     getUrl: "get.rails",   
  4.                     saveUrl: "save.rails",   
  5.                     deleteUrl: "delete.rails",   
  6.                     useAjax: true  
  7.                 });   
  8.             });  
$(window).load(function() {
                $("#toAnnotate").annotateImage({
                    getUrl: "get.rails",
                    saveUrl: "save.rails",
                    deleteUrl: "delete.rails",
                    useAjax: true
                });
            });

The Get url expects data to be returned as an JSON stream.

  1. [ { "top": 286,   
  2.     "left": 161,   
  3.     "width": 52,   
  4.     "height": 37,   
  5.     "text""Small people on the steps",   
  6.     "id""e69213d0-2eef-40fa-a04b-0ed998f9f1f5",   
  7.     "editable"false },   
  8.   { "top": 134,   
  9.     "left": 179,   
  10.     "width": 68,   
  11.     "height": 74,   
  12.     "text""National Gallery Dome",   
  13.     "id""e7f44ac5-bcf2-412d-b440-6dbb8b19ffbe",   
  14.     "editable"true } ]     
[ { "top": 286,
    "left": 161,
    "width": 52,
    "height": 37,
    "text": "Small people on the steps",
    "id": "e69213d0-2eef-40fa-a04b-0ed998f9f1f5",
    "editable": false },
  { "top": 134,
    "left": 179,
    "width": 68,
    "height": 74,
    "text": "National Gallery Dome",
    "id": "e7f44ac5-bcf2-412d-b440-6dbb8b19ffbe",
    "editable": true } ]   

Window Load Event

When calling the plugin it is important to use the $(window).load() event. This event fires after the page an all it's images have loaded. The $(document).ready() event fires after the page has loaded, but before the browser has retrieved all the images. Calling the plugin in this event will result in the plugin rending a blank DIV as the image hasn't loaded.

上面的是我的项目结构,现在我想要加入开源的通义大模型,实现项目具有以下功能 自行准备本地知识库资料(如本专业相关资料内容)作为大模型本地知识库的输入 教师侧:备课与设计: 根据所提供的本地课程大纲、课程知识库文档等自动设计教学内容,包括知识讲解、实训练习与指导、时间分布等。 · 考核内容生成: 根据教学内容自动生成考核题目及参考答案,考核题目种类可多样化,根据学科设计,如计算机类可设计相关编程题和答案 · 学情数据分析: 对学生提交的答案进行自动化检测,提供错误定位与修正建议。对学生整体数据进行分析,总结知识掌握情况与教学建议。 学生侧: · 在线学习助手: 对学生的提出的问题,结合教学内容进行解答; · 实时练习评测助手: 根据学生历史练习情况,以及学生的练习要求,生成随练题目,并对练习纠错。 管理侧: 用户管理:管理员/教师/学生等用户的基本管理 课件资源管理:按学科列表教师备课产生的课件、练习等资源,可以导出。 大屏概览: · 教师使用次数统计/活跃板块(当日/本周) · 学生使用次数统计/活跃板块(当日/本周) · 教学效率指数(备课与修正耗时、课后练习设计与修正耗时、课程优化方向(如:某学科通过率持续偏低) · 学生学习效果(平均正确率趋势、知识点掌握情况,高频错误知识点等) 非功能性需求 需明确使用至少1个开源大模型作为核心技术组件; 需采用本地知识库作为输入,知识库资料总量不大于100M; 生成的内容、练习与答案与本地知识库的关联性和准确性;(对抽取知识点设计的题目验证关联性和与答案的准确性有知识点说明) 我该在哪里添加 下面我再对功能进行进一步的说明:1、首先本地知识库可以让用户自己上传(即用户自己可以控制本地知识库,但一开始会有一个默认的知识库,知识库是在项目中的某个目录中可以吗), 2、在备课与设计的功能上ai可以帮助教师设计教学内容,并且教师可以下载该教学内容 3、在考核内容生成中,考核题目同样可以进行下载,而且可以有带答案不带答案两种方式; 完整的项目结构又是怎样的,哪些内容需要更改 下面是我目前的项目结构卷 Windows-SSD 的文件夹 PATH 列表 卷序列号为 20C7-404E C:. | project_structure.txt | +---main | +---java | | \---com | | | Aiapp1Application.java | | | | | +---annotation | | | APPLoginUser.java | | | IgnoreAuth.java | | | LoginUser.java | | | | | +---config | | | InterceptorConfig.java | | | MybatisPlusConfig.java | | | MyMetaObjectHandler.java | | | | | +---controller | | | CommonController.java | | | ConfigController.java | | | DictionaryController.java | | | ExampaperController.java | | | ExamquestionController.java | | | ExamrecordController.java | | | ExamredetailsController.java | | | ExamrewrongquestionController.java | | | FileController.java | | | ForumController.java | | | JiaoshiController.java | | | KechengController.java | | | KechengLiuyanController.java | | | NewsController.java | | | UsersController.java | | | YonghuController.java | | | | | +---dao | | | CommonDao.java | | | ConfigDao.java | | | DictionaryDao.java | | | ExampaperDao.java | | | ExamquestionDao.java | | | ExamrecordDao.java | | | ExamredetailsDao.java | | | ExamrewrongquestionDao.java | | | ForumDao.java | | | JiaoshiDao.java | | | KechengDao.java | | | KechengLiuyanDao.java | | | NewsDao.java | | | TokenDao.java | | | UsersDao.java | | | YonghuDao.java | | | | | +---entity | | | | ConfigEntity.java | | | | DictionaryEntity.java | | | | EIException.java | | | | ExampaperEntity.java | | | | ExamquestionEntity.java | | | | ExamrecordEntity.java | | | | ExamredetailsEntity.java | | | | ExamrewrongquestionEntity.java | | | | ForumEntity.java | | | | JiaoshiEntity.java | | | | KechengEntity.java | | | | KechengLiuyanEntity.java | | | | NewsEntity.java | | | | TokenEntity.java | | | | UsersEntity.java | | | | YonghuEntity.java | | | | | | | +---model | | | | DictionaryModel.java | | | | ExampaperModel.java | | | | ExamquestionModel.java | | | | ExamrecordModel.java | | | | ExamredetailsModel.java | | | | ExamrewrongquestionModel.java | | | | ForumModel.java | | | | JiaoshiModel.java | | | | KechengLiuyanModel.java | | | | KechengModel.java | | | | NewsModel.java | | | | YonghuModel.java | | | | | | | +---view | | | | DictionaryView.java | | | | ExampaperView.java | | | | ExamquestionView.java | | | | ExamrecordView.java | | | | ExamredetailsView.java | | | | ExamrewrongquestionView.java | | | | ForumView.java | | | | JiaoshiView.java | | | | KechengLiuyanView.java | | | | KechengView.java | | | | NewsView.java | | | | YonghuView.java | | | | | | | \---vo | | | DictionaryVO.java | | | ExampaperVO.java | | | ExamquestionVO.java | | | ExamrecordVO.java | | | ExamredetailsVO.java | | | ExamrewrongquestionVO.java | | | ForumVO.java | | | JiaoshiVO.java | | | KechengLiuyanVO.java | | | KechengVO.java | | | NewsVO.java | | | YonghuVO.java | | | | | +---interceptor | | | AuthorizationInterceptor.java | | | | | +---model | | | \---enums | | | TypeEnum.java | | | | | +---service | | | | CommonService.java | | | | ConfigService.java | | | | DictionaryService.java | | | | ExampaperService.java | | | | ExamquestionService.java | | | | ExamrecordService.java | | | | ExamredetailsService.java | | | | ExamrewrongquestionService.java | | | | ForumService.java | | | | JiaoshiService.java | | | | KechengLiuyanService.java | | | | KechengService.java | | | | NewsService.java | | | | TokenService.java | | | | UsersService.java | | | | YonghuService.java | | | | | | | \---impl | | | CommonServiceImpl.java | | | ConfigServiceImpl.java | | | DictionaryServiceImpl.java | | | ExampaperServiceImpl.java | | | ExamquestionServiceImpl.java | | | ExamrecordServiceImpl.java | | | ExamredetailsServiceImpl.java | | | ExamrewrongquestionServiceImpl.java | | | ForumServiceImpl.java | | | JiaoshiServiceImpl.java | | | KechengLiuyanServiceImpl.java | | | KechengServiceImpl.java | | | NewsServiceImpl.java | | | TokenServiceImpl.java | | | UsersServiceImpl.java | | | YonghuServiceImpl.java | | | | | +---ServletContextListener | | | DictionaryServletContextListener.java | | | | | +---thread | | | MyThreadMethod.java | | | | | \---utils | | BaiduUtil.java | | CommonUtil.java | | FileUtil.java | | HttpClientUtils.java | | JQPageInfo.java | | MPUtil.java | | PageUtils.java | | PoiUtil.java | | Query.java | | R.java | | SpringContextUtils.java | | SQLFilter.java | | StringUtil.java | | ValidatorUtils.java | | | \---resources | | application.yml | | | +---front | | | index.html | | | | | +---css | | | bootstrap.min.css | | | common.css | | | front-kaoshi-style.css | | | homeworkPC.min.css | | | style.css | | | theme.css | | | | | +---elementui | | | | elementui.css | | | | elementui.js | | | | | | | \---fonts | | | element-icons.ttf | | | element-icons.woff | | | | | +---img | | | avator.png | | | banner.jpg | | | jianshe.png | | | jiaotong.png | | | line.jpg | | | nongye.png | | | seckilling.jpg | | | select.png | | | selectActive.png | | | unselect.png | | | weixin.png | | | yuan.png | | | zhifubao.png | | | zhongguo.png | | | | | +---js | | | bootstrap.AMapPositionPicker.js | | | bootstrap.min.js | | | config.js | | | jquery.js | | | utils.js | | | validate.js | | | vue.js | | | | | +---layui | | | | layui.all.js | | | | layui.js | | | | | | | +---css | | | | | layui.css | | | | | layui.mobile.css | | | | | | | | | \---modules | | | | | code.css | | | | | | | | | +---laydate | | | | | \---default | | | | | laydate.css | | | | | | | | | \---layer | | | | \---default | | | | icon-ext.png | | | | icon.png | | | | layer.css | | | | loading-0.gif | | | | loading-1.gif | | | | loading-2.gif | | | | | | | +---font | | | | iconfont.eot | | | | iconfont.svg | | | | iconfont.ttf | | | | iconfont.woff | | | | iconfont.woff2 | | | | | | | +---images | | | | \---face | | | | 0.gif | | | | 1.gif | | | | 10.gif | | | | 11.gif | | | | 12.gif | | | | 13.gif | | | | 14.gif | | | | 15.gif | | | | 16.gif | | | | 17.gif | | | | 18.gif | | | | 19.gif | | | | 2.gif | | | | 20.gif | | | | 21.gif | | | | 22.gif | | | | 23.gif | | | | 24.gif | | | | 25.gif | | | | 26.gif | | | | 27.gif | | | | 28.gif | | | | 29.gif | | | | 3.gif | | | | 30.gif | | | | 31.gif | | | | 32.gif | | | | 33.gif | | | | 34.gif | | | | 35.gif | | | | 36.gif | | | | 37.gif | | | | 38.gif | | | | 39.gif | | | | 4.gif | | | | 40.gif | | | | 41.gif | | | | 42.gif | | | | 43.gif | | | | 44.gif | | | | 45.gif | | | | 46.gif | | | | 47.gif | | | | 48.gif | | | | 49.gif | | | | 5.gif | | | | 50.gif | | | | 51.gif | | | | 52.gif | | | | 53.gif | | | | 54.gif | | | | 55.gif | | | | 56.gif | | | | 57.gif | | | | 58.gif | | | | 59.gif | | | | 6.gif | | | | 60.gif | | | | 61.gif | | | | 62.gif | | | | 63.gif | | | | 64.gif | | | | 65.gif | | | | 66.gif | | | | 67.gif | | | | 68.gif | | | | 69.gif | | | | 7.gif | | | | 70.gif | | | | 71.gif | | | | 8.gif | | | | 9.gif | | | | | | | \---lay | | | \---modules | | | carousel.js | | | code.js | | | colorpicker.js | | | element.js | | | flow.js | | | form.js | | | jquery.js | | | laydate.js | | | layedit.js | | | layer.js | | | laypage.js | | | laytpl.js | | | mobile.js | | | rate.js | | | slider.js | | | table.js | | | transfer.js | | | tree.js | | | upload.js | | | util.js | | | | | +---modules | | | | config.js | | | | | | | +---http | | | | http.js | | | | | | | +---layarea | | | | layarea.js | | | | | | | \---tinymce | | | | index.html | | | | tinymce.js | | | | | | | \---tinymce | | | | jquery.tinymce.min.js | | | | license.txt | | | | readme.md | | | | tinymce.js | | | | tinymce.min.js | | | | | | | +---langs | | | | readme.md | | | | zh_CN.js | | | | | | | +---plugins | | | | +---advlist | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---anchor | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autolink | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autoresize | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---autosave | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---bbcode | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---charmap | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---code | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---codesample | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---colorpicker | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---contextmenu | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---directionality | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---emoticons | | | | | | plugin.js | | | | | | plugin.min.js | | | | | | | | | | | \---js | | | | | emojis.js | | | | | emojis.min.js | | | | | | | | | +---fullpage | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---fullscreen | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---help | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---hr | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---image | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---imagetools | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---importcss | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---indent2em | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---insertdatetime | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---legacyoutput | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---link | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---lists | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---media | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---nonbreaking | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---noneditable | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---pagebreak | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---paste | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---preview | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---print | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---quickbars | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---save | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---searchreplace | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---spellchecker | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---tabfocus | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---table | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---template | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---textcolor | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---textpattern | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---toc | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---visualblocks | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | +---visualchars | | | | | plugin.js | | | | | plugin.min.js | | | | | | | | | \---wordcount | | | | plugin.js | | | | plugin.min.js | | | | | | | +---skins | | | | +---content | | | | | +---dark | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | +---default | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | +---document | | | | | | content.css | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | | | | | | \---writer | | | | | content.css | | | | | content.min.css | | | | | content.min.css.map | | | | | | | | | \---ui | | | | +---oxide | | | | | | content.css | | | | | | content.inline.css | | | | | | content.inline.min.css | | | | | | content.inline.min.css.map | | | | | | content.min.css | | | | | | content.min.css.map | | | | | | content.mobile.css | | | | | | content.mobile.min.css | | | | | | content.mobile.min.css.map | | | | | | skin.css | | | | | | skin.min.css | | | | | | skin.min.css.map | | | | | | skin.mobile.css | | | | | | skin.mobile.min.css | | | | | | skin.mobile.min.css.map | | | | | | | | | | | \---fonts | | | | | tinymce-mobile.woff | | | | | | | | | \---oxide-dark | | | | | content.css | | | | | content.inline.css | | | | | content.inline.min.css | | | | | content.inline.min.css.map | | | | | content.min.css | | | | | content.min.css.map | | | | | content.mobile.css | | | | | content.mobile.min.css | | | | | content.mobile.min.css.map | | | | | skin.css | | | | | skin.min.css | | | | | skin.min.css.map | | | | | skin.mobile.css | | | | | skin.mobile.min.css | | | | | skin.mobile.min.css.map | | | | | | | | | \---fonts | | | | tinymce-mobile.woff | | | | | | | \---themes | | | +---mobile | | | | theme.js | | | | theme.min.js | | | | | | | \---silver | | | theme.js | | | theme.min.js | | | | | +---pages | | | +---chat | | | | chat.html | | | | | | | +---dictionary | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---exampaper | | | | add.html | | | | detail.html | | | | exam.html | | | | list.html | | | | | | | +---examquestion | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examrecord | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examredetails | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---examrewrongquestion | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---forum | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---home | | | | home.html | | | | | | | +---jiaoshi | | | | add.html | | | | center.html | | | | detail.html | | | | list.html | | | | register.html | | | | | | | +---kecheng | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---kechengLiuyan | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---login | | | | login.html | | | | | | | +---news | | | | add.html | | | | detail.html | | | | list.html | | | | | | | +---recharge | | | | recharge.html | | | | | | | \---yonghu | | | add.html | | | center.html | | | detail.html | | | list.html | | | register.html | | | | | \---xznstatic | | +---css | | | | bootstrap.min.css | | | | common.css | | | | element.min.css | | | | login.css | | | | public.css | | | | style.css | | | | swiper.min.css | | | | | | | \---fonts | | | element-icons.ttf | | | element-icons.woff | | | | | +---img | | | 162237296.jpg | | | 162240878.jpg | | | 19.jpg | | | 1_092ZZ2503138.jpg | | | 20.jpg | | | index_24.gif | | | index_35.gif | | | index_41.gif | | | index_44.gif | | | logo.png | | | news_list_time.jpg | | | service_btn.png | | | service_img.png | | | service_title.png | | | | | \---js | | bootstrap.min.js | | element.min.js | | index.js | | jquery-1.11.3.min.js | | jquery.SuperSlide.2.1.1.js | | swiper.min.js | | | +---img | | \---img | | back-img-bg.jpg | | front-img-bg.jpg | | logo.jpg | | | +---mapper | | CommonDao.xml | | ConfigDao.xml | | DictionaryDao.xml | | ExampaperDao.xml | | ExamquestionDao.xml | | ExamrecordDao.xml | | ExamredetailsDao.xml | | ExamrewrongquestionDao.xml | | ForumDao.xml | | JiaoshiDao.xml | | KechengDao.xml | | KechengLiuyanDao.xml | | NewsDao.xml | | TokenDao.xml | | UsersDao.xml | | YonghuDao.xml | | | +---static | | +---admin | | | | 1-install.bat | | | | 2-run.bat | | | | 3-build.bat | | | | babel.config.js | | | | package-lock.json | | | | package.json | | | | vue.config.js | | | | | | | +---dist | | | | | favicon.ico | | | | | index.html | | | | | | | | | +---css | | | | | app.381d2044.css | | | | | chunk-vendors.a72b0961.css | | | | | | | | | +---fonts | | | | | element-icons.535877f5.woff | | | | | element-icons.732389de.ttf | | | | | | | | | +---img | | | | | 404.3648f234.png | | | | | zhongguo.20798bfa.png | | | | | | | | | \---js | | | | app.b100d28f.js | | | | app.b100d28f.js.map | | | | chunk-vendors.213b68ba.js | | | | chunk-vendors.213b68ba.js.map | | | | | | | +---public | | | | favicon.ico | | | | index.html | | | | | | | \---src | | | | App.vue | | | | main.js | | | | | | | +---assets | | | | +---css | | | | | element-variables.scss | | | | | style.scss | | | | | | | | | \---img | | | | | 404.png | | | | | avator.png | | | | | bg.jpg | | | | | captcha.jpg | | | | | login.png | | | | | logo.png | | | | | password.png | | | | | role.png | | | | | username.png | | | | | | | | | \---test | | | | jianshe.png | | | | jiaotong.png | | | | nongye.png | | | | weixin.png | | | | zhifubao.png | | | | zhongguo.png | | | | | | | +---components | | | | +---common | | | | | BreadCrumbs.vue | | | | | Editor.vue | | | | | FileUpload.vue | | | | | | | | | +---home | | | | | HomeCard.vue | | | | | HomeChart.vue | | | | | HomeComment.vue | | | | | HomeProgress.vue | | | | | | | | | +---index | | | | | IndexAside.vue | | | | | IndexAsideStatic.vue | | | | | IndexAsideSub.vue | | | | | IndexHeader.vue | | | | | IndexMain.vue | | | | | | | | | \---SvgIcon | | | | index.vue | | | | | | | +---icons | | | | | index.js | | | | | svgo.yml | | | | | | | | | \---svg | | | | | 404.svg | | | | | articleEdit.svg | | | | | banner.svg | | | | | bug.svg | | | | | build.svg | | | | | cfg.svg | | | | | channel.svg | | | | | chart.svg | | | | | clipboard.svg | | | | | code.svg | | | | | component.svg | | | | | contacts.svg | | | | | dashboard.svg | | | | | date.svg | | | | | dept.svg | | | | | dict.svg | | | | | documentation.svg | | | | | download.svg | | | | | drag.svg | | | | | druid.svg | | | | | edit.svg | | | | | education.svg | | | | | email.svg | | | | | excel.svg | | | | | exit-fullscreen.svg | | | | | eye-open.svg | | | | | file.svg | | | | | form.svg | | | | | fullscreen.svg | | | | | icon.svg | | | | | international.svg | | | | | job.svg | | | | | language.svg | | | | | link.svg | | | | | list.svg | | | | | lock.svg | | | | | log.svg | | | | | logininfor.svg | | | | | menu.svg | | | | | message.svg | | | | | money.svg | | | | | monitor.svg | | | | | nested.svg | | | | | nested0.svg | | | | | online.svg | | | | | operation.svg | | | | | password.svg | | | | | password0.svg | | | | | pdf.svg | | | | | people.svg | | | | | peoples.svg | | | | | phone.svg | | | | | post.svg | | | | | qq.svg | | | | | search.svg | | | | | sender.svg | | | | | server.svg | | | | | shopping.svg | | | | | shoppingCard.svg | | | | | size.svg | | | | | skill.svg | | | | | star.svg | | | | | swagger.svg | | | | | system.svg | | | | | tab.svg | | | | | table.svg | | | | | table0.svg | | | | | task.svg | | | | | template.svg | | | | | theme.svg | | | | | tool.svg | | | | | tree-table.svg | | | | | tree.svg | | | | | user.svg | | | | | user0.svg | | | | | validCode.svg | | | | | wechat.svg | | | | | zip.svg | | | | | | | | | \---svg | | | | agricultureRegister.svg | | | | AI.svg | | | | AIDeviceLayout.svg | | | | area.svg | | | | base.svg | | | | batch.svg | | | | board.svg | | | | board1.svg | | | | boardConfig.svg | | | | cfg.svg | | | | code.svg | | | | company.svg | | | | crop.svg | | | | crops.svg | | | | dashboard.svg | | | | dataAbnormal.svg | | | | dataLack.svg | | | | dept.svg | | | | device.svg | | | | deviceMonitorData.svg | | | | dict.svg | | | | diseasesinsect.svg | | | | diseasesinsects.svg | | | | documentation.svg | | | | EIM.svg | | | | email.svg | | | | environmental.svg | | | | eye-open.svg | | | | farmingProject.svg | | | | finance.svg | | | | financeBudget.svg | | | | financeReality.svg | | | | firm.svg | | | | firms.svg | | | | harvestBatch.svg | | | | harvestDetection.svg | | | | harvestManage.svg | | | | harvestWorks.svg | | | | heavyMetalDetection.svg | | | | home.svg | | | | inspection.svg | | | | internet.svg | | | | internetActive.svg | | | | log.svg | | | | mainSystem.svg | | | | mainSystemActive.svg | | | | menu.svg | | | | monitorEquipment.svg | | | | news.svg | | | | order.svg | | | | password.svg | | | | peoples.svg | | | | pest.svg | | | | pestActive.svg | | | | pesticideResidue.svg | | | | pests.svg | | | | phone.svg | | | | plant.svg | | | | plants.svg | | | | plantsActive.svg | | | | residual.svg | | | | retroactiveCoding.svg | | | | scheme.svg | | | | source.svg | | | | sourceActive.svg | | | | system.svg | | | | task.svg | | | | tempFarm.svg | | | | traceability.svg | | | | traceabilityList.svg | | | | traceabilityStyle.svg | | | | user.svg | | | | user0.svg | | | | validCode.svg | | | | video.svg | | | | videoEquipment.svg | | | | videoKey.svg | | | | VIP.svg | | | | vipCustomized.svg | | | | warnings.svg | | | | workOrder.svg | | | | ┐┤?х╣▄└э.svg | | | | ╓╪╜Ё╩?╝ь▓т╣▄└э.svg | | | | | | | +---router | | | | router-static.js | | | | | | | +---store | | | | store.js | | | | | | | +---utils | | | | api.js | | | | base.js | | | | http.js | | | | i18n.js | | | | menu.js | | | | storage.js | | | | style.css | | | | style.js | | | | utils.js | | | | validate.js | | | | | | | \---views | | | | 404.vue | | | | center.vue | | | | home.vue | | | | index.vue | | | | login.vue | | | | pay.vue | | | | register.vue | | | | update-password.vue | | | | | | | \---modules | | | +---config | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionary | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryExampaper | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryExamquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryForumState | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryKecheng | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionaryNews | | | | add-or-update.vue | | | | list.vue | | | | | | | +---dictionarySex | | | | add-or-update.vue | | | | list.vue | | | | | | | +---exampaper | | | | add-or-update.vue | | | | exam.vue | | | | list.vue | | | | | | | +---examquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examrecord | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examredetails | | | | add-or-update.vue | | | | list.vue | | | | | | | +---examrewrongquestion | | | | add-or-update.vue | | | | list.vue | | | | | | | +---forum | | | | add-or-update.vue | | | | list.vue | | | | | | | +---jiaoshi | | | | add-or-update.vue | | | | list.vue | | | | | | | +---kecheng | | | | add-or-update.vue | | | | list.vue | | | | | | | +---kechengLiuyan | | | | add-or-update.vue | | | | list.vue | | | | | | | +---news | | | | add-or-update.vue | | | | list.vue | | | | | | | +---users | | | | add-or-update.vue | | | | list.vue | | | | | | | \---yonghu | | | add-or-update.vue | | | list.vue | | | | | \---upload | | a.txt | | config1.jpg | | config2.jpg | | config3.jpg | | file.rar | | jiaoshi.xls | | jiaoshi1.jpg | | jiaoshi2.jpg | | jiaoshi3.jpg | | jiaoshi4.jpg | | jiaoshi5.jpg | | jiaoshi6.jpg | | kecheng1.jpg | | kecheng2.jpg | | kecheng3.jpg | | kecheng4.jpg | | kecheng5.jpg | | kecheng6.jpg | | music.mp3 | | news1.jpg | | news2.jpg | | news3.jpg | | news4.jpg | | news5.jpg | | news6.jpg | | video.mp4 | | yonghu1.jpg | | yonghu2.jpg | | yonghu3.jpg | | | \---templates \---test \---java \---com Aiapp1ApplicationTests.java
最新发布
07-15
index.js (function ($){ // 页面加载时检查登录状态 checkLoginStatus(); })(jQuery); function checkLoginStatus() { if(window.location.href== '/KuCun2/login.html')return; const username = localStorage.getItem("name"); alert(username) if(!username) window.location.href = '/KuCun2/login.html?11212121'; } login.js // 登录按钮点击事件 function login(datas) { var data={} datas.each(function(a,element){ alert() data[$(element).attr('name')]=$(element).val() }) //var data={ andy,pass } // 模拟 AJAX 请求 https("/KuCun2/users/login",data,function (response) { alert("1"); if (response.name) { localStorage.setItem("name", response.name); // 保存用户名到本地存储 localStorage.setItem("role", response.role); // 保存权限到本地存储 window.location.href = '/KuCun2/index.html'; } else { alert("登录失败,请检查用户名和密码!"); } }) }; package com.kucun.Config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; import com.kucun.Config.Role.RoleConverter; import com.kucun.Config.user.CustomUserDetails; import com.kucun.data.entity.User; import com.kucun.dataDo.UserRepository; /** * 获取数据 * @author Administrator * */ @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private RoleConverter roleConverter; public CustomUserDetailsService() { super(); System.out.println("11111"); } /** * 获取数据库中用户信息 * @param andy 账号 * * @return * */ @Override public UserDetails loadUserByUsername(String andy) { System.out.println(andy); User user = userRepository.findByAndy(andy); System.out.println(user); return new CustomUserDetails(user, roleConverter.convert(user.getRole()) // 关键转换点[^1] ); } }package com.kucun.Config; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.json.Json; import javax.servlet.Filter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import com.fasterxml.jackson.databind.ObjectMapper; import com.kucun.Config.user.CustomUserDetails; // 2. 基础安全配置 @Configuration @EnableWebSecurity // 启用Web安全功能 public class SecurityConfig extends WebSecurityConfigurerAdapter{ /** * 核心安全过滤器链配置 * @param http HTTP安全构建器 * @return 安全过滤器链 * @throws Exception 配置异常 * * █ 配置逻辑说明: * 1. authorizeHttpRequests: 定义访问控制规则 * 2. formLogin: 配置表单登录 * 3. logout: 配置注销行为 * 4. exceptionHandling: 处理权限异常[^3] */ // 修正后的配置方法 @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .invalidSessionUrl("/login.html?session=invalid") .maximumSessions(1) .maxSessionsPreventsLogin(false) .and() .and() .addFilterBefore(jsonAuthFilter(), UsernamePasswordAuthenticationFilter.class) // 关键配置 .authorizeRequests() .antMatchers("/login.html").permitAll() .antMatchers(HttpMethod.POST, "/users/login").permitAll() .antMatchers("/users/guanli/**").hasAuthority("ROLE_ADMIN") .antMatchers("/js/**", "/css/**", "/fonts/**", "/images/**","/*").permitAll() .anyRequest().authenticated() .and() .formLogin().disable() // .loginPage("/login.html") // .loginProcessingUrl("/users/login") // // .successHandler(ajaxAuthenticationSuccessHandler()) // 自定义成功处理器 // .failureHandler(ajaxAuthenticationFailureHandler()) // 自定义失败处理器 // .defaultSuccessUrl("/index.html") // .failureUrl("/login.html?error=true") // .usernameParameter("andy") // 修改用户名参数名 // .passwordParameter("pass") // 修改密码参数名 // .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login.html") .and() .csrf() .ignoringAntMatchers("/users/login") .and() .headers() .frameOptions().sameOrigin() .and() .exceptionHandling() .accessDeniedHandler(accessDeniedHandler()); // 统一使用Handler } // 返回JSON格式的成功响应 @Bean public AuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() { return (request, response, authentication) -> { // 强制创建服务端会话 request.getSession(true); //构建安全响应数据 Map<String, Object> responseData = new HashMap<>(); responseData.put("sessionId", request.getSession().getId()); responseData.put("userInfo",Collections.unmodifiableMap(new HashMap<String, Object>() {/** * */ private static final long serialVersionUID = 1L; { put("Name", ((CustomUserDetails)authentication.getPrincipal()).getName()); put("role", ((CustomUserDetails)authentication.getPrincipal()).getRole()); }})); // 统一返回JSON格式 response.setContentType(MediaType.APPLICATION_JSON_VALUE); // new ObjectMapper().writeValue(response.getWriter(), responseData); response.setContentType(MediaType.APPLICATION_JSON_VALUE); CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); response.setStatus(HttpStatus.OK.value()); System.out.println(authentication.getPrincipal()+""+authentication.getName()); if (request.getHeader("X-Requested-With") == null) { // 非AJAX请求 response.sendRedirect("/index.html"); } else { //String re=userDetails.getUser().toString() new ObjectMapper().writeValue(response.getWriter(), userDetails.getUser() ); } }; } // 返回401状态码和错误信息 @Bean public AuthenticationFailureHandler ajaxAuthenticationFailureHandler() { return (request, response, exception) -> { if (request.getHeader("X-Requested-With") == null) { response.sendRedirect("/login.html?error=true"); } else { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write("{\"error\":\"Authentication failed\"}"); } }; } // 处理未认证请求 @Bean public AuthenticationEntryPoint ajaxAuthenticationEntryPoint() { return (request, response, exception) -> { if (request.getHeader("X-Requested-With") == null) { response.sendRedirect("/login.html?error=true"); } else { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write("{\"error\":\"Authentication failed\"}"); } }; } @Bean public JsonUsernamePasswordAuthenticationFilter jsonAuthFilter() throws Exception { JsonUsernamePasswordAuthenticationFilter filter = new JsonUsernamePasswordAuthenticationFilter(); filter.setAuthenticationManager(authenticationManagerBean()); filter.setUsernameParameter("andy"); // 设置自定义参数名 filter.setPasswordParameter("pass"); filter.setFilterProcessesUrl("/users/login"); filter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler()); filter.setAuthenticationFailureHandler(ajaxAuthenticationFailureHandler()); return filter; } /** * 密码编码器(必须配置) * 使用BCrypt强哈希算法加密 */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AccessDeniedHandler accessDeniedHandler() { System.out.println("0000"); return (request, response, ex) -> { if (!response.isCommitted()) { response.sendRedirect("/error/403"); } }; } } class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { System.out.println("收到认证请求,路径:" + request.getRequestURI()); System.out.println("请求方法:" + request.getMethod()); System.out.println("Content-Type:" + request.getContentType()); if (request.getContentType() != null && request.getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE)) { try (InputStream is = request.getInputStream()) { Map<String, String> authMap = objectMapper.readValue(is, Map.class); String username = authMap.getOrDefault(getUsernameParameter(), ""); String password = authMap.getOrDefault(getPasswordParameter(), ""); // 调试日志 System.out.println("Authentication attempt with: " + username+'_'+ password); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } catch (IOException e) { throw new AuthenticationServiceException("认证请求解析失败", e); } } return super.attemptAuthentication(request, response); } } package com.kucun.Config.user; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import com.kucun.data.entity.User; public class CustomUserDetails implements UserDetails { /** * */ private static final long serialVersionUID = 1L; private final String andy; // 对应andy字段 private final String name; private final int role; private final String password; private final User users; private final Collection<? extends GrantedAuthority> authorities; public CustomUserDetails(User user, Collection<? extends GrantedAuthority> authorities) { this.andy = user.getAndy(); this.name = user.getName(); this.role = user.getRole(); this.password = user.getPass(); user.setPass(null); this.users=user; this.authorities = authorities; } // 实现UserDetails接口方法 @Override public String getUsername() { return andy; } @Override public String getPassword() { return password; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } // 自定义字段访问方法 public String getName() { return name; } public User getUser() { return users; } public int getRole() { return role; } // 其他必要方法 @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }package com.kucun.data.entity; import java.util.Objects; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import com.fasterxml.jackson.databind.ObjectMapper; @Entity @Table(name="user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; /** * 名字 */ @Column(nullable=false) private String name; /** * 账号 */ @Column(nullable=false) private String andy; /** * 密码 */ @Column(nullable=false) private String pass; /** * 权限 */ @Column(nullable=false) private int role; public User() { super(); } public User(int id, String name, String andy, String pass) { super(); this.id = id; this.name = name; this.andy = andy; this.pass = pass; } public Integer getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAndy() { return andy; } public void setAndy(String andy) { this.andy = andy; } public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } public int getRole() { System.out.println(role); return role; } public void setRole(int role) { this.role = role; } @Override public String toString() { return "{id:" + id + ", name:" + name + ", andy:" + andy + ", pass:" + pass + ", role:" + role + "}"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(andy, user.andy)&& Objects.equals(role, user.role); //添加所有属性比较 } @Override public int hashCode() { return Objects.hash(id, name, andy,pass,role); } } <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>KuCun2</groupId> <artifactId>KuCun2</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>KuCun2</name> <description/> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <!-- 请根据需要选择版本 --> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <webVersion>4.0</webVersion> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <protobuf.version>3.21.12</protobuf.version> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>8.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.servlet.jsp.jstl</artifactId> <version>1.2.4</version> </dependency> <!-- Spring Boot Starter Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency> <!-- Optional: Lombok for reducing boilerplate code --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> <!-- Jackson Databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- Jackson Core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </dependency> <!-- Jackson Annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>${protobuf.version}</version> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.30</version> <!-- 统一版本号 --> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> 登录后跳转index.html ,刚刚加载并跳出弹窗显示name有值完就重定向为login.html界面
05-30
function https(url,data,fu){ $.ajax({ contentType:“application/json”, url: url, // 假设后端 API 地址 method: “POST”, data: JSON.stringify(data), type: “json”, dataType: “json”, success:function(e){ console.log(e.data) if(e.status==200){ console.log(e.data) fu(e.data) }else{ alert(e.text) } }, error: function (e) { console.log(e.data) console.error(e) alert(“请求失败,请稍后再试!”+e); } }); } function checkLoginStatus() { if (window.location.href.includes(‘/login.html’)) return; } window.addEventListener(‘beforeunload’, function(e) { console.trace(‘触发页面跳转的堆栈跟踪:’); }); //安全验证函数 function validateUserSession() { try { // 防御性数据获取 + 数据清洗 const rawValue = localStorage.getItem(“name”); const username = String(rawValue ?? ‘’) .trim() .replace(/[\u200B-\u200D\uFEFF]/g, ‘’); // 移除零宽字符 // 调试信息 console.log('[Auth] Raw:', rawValue, 'Processed:', username); // 复合验证条件 const isValid = ( username.length >= 2 && // 最小长度要求 !/[<>]/.test(username) && // 防止XSS username !== 'null' && username !== 'undefined' ); if (!isValid) { console.warn('无效用户标识:', username); // 安全跳转方法 //window.location.replace('/KuCun2/login.html'); // 立即终止执行 return Promise.reject('Invalid session'); } // 返回清洗后的用户名 return username; } catch (error) { console.error(‘会话验证失败:’, error); // window.location.replace(‘/KuCun2/login.html’); return Promise.reject(error); } } function deepMergeArrays(frontend, backend) { const resultMap = new Map(); // 遍历前端数据并存入 Map 中以便快速查找 frontend.forEach(item => resultMap.set(item.id, { ...item })); // 遍历后端数据并与前端数据进行合并 backend.forEach(item => { if (resultMap.has(item.id)) { // 如果存在相同 ID,则合并两者的内容 resultMap.set( item.id, Object.assign(resultMap.get(item.id), item) ); } else { // 如果不存在相同 ID,则新增该条目 resultMap.set(item.id, { ...item }); } }); // 将最终结果转回数组形式 return Array.from(resultMap.values()); } (function ($){ // 页面加载时检查登录状态 checkLoginStatus(); })(jQuery); function removeSpecificCharactersAndConvertToNumber(str, charsToRemove) { const regex = new RegExp([${charsToRemove}], ‘g’); // 创建用于匹配指定字符的正则表达式 const cleanedStr = str.replace(regex, ‘’); // 移除指定字符 const numberValue = parseFloat(cleanedStr); // 转换为浮点数 return isNaN(numberValue) ? null : numberValue; // 如果无法解析,则返回 null } <project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”> <modelVersion>4.0.0</modelVersion> <groupId>KuCun2</groupId> <artifactId>KuCun2</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>KuCun2</name> <description/> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <!-- 请根据需要选择版本 --> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <webVersion>4.0</webVersion> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <protobuf.version>3.21.12</protobuf.version> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>8.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.servlet.jsp.jstl</artifactId> <version>1.2.4</version> </dependency> <!-- Spring Boot Starter Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <exclusions> <exclusion> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> </exclusion> </exclusions> </dependency> <!-- Optional: Lombok for reducing boilerplate code --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> <!-- Jackson Databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- Jackson Core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </dependency> <!-- Jackson Annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </dependency> <dependency> <groupId>org.mindrot</groupId> <artifactId>jbcrypt</artifactId> <version>0.4</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>${protobuf.version}</version> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.30</version> <!-- 统一版本号 --> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> package com.kucun; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication( ) public class DemoApplication extends SpringBootServletInitializer { public static void main(String[] args) { // // ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); // Arrays.stream(ctx.getBeanNamesForType(SecurityFilterChain.class)) // .forEach(System.out::println); // // // // 测试密码加密示例 // BCryptPasswordEncoder encoder = new BCrypt(); // String rawPassword = “987987”; // String encodedPassword = encoder.encode(rawPassword); // System.out.println(“加密后的密码:” + encodedPassword); SpringApplication.run(DemoApplication.class, args); } }package com.kucun.Config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.kucun.Config.Role.RoleConverter; import com.kucun.Config.user.CustomUserDetails; import com.kucun.data.entity.User; import com.kucun.dataDo.UserRepository; /** 获取数据 @author Administrator / @Service public class CustomUserDetailsService/ implements UserDetailsService /{ // // @Autowired // private UserRepository userRepository; // // @Autowired // private RoleConverter roleConverter; // // public CustomUserDetailsService() { // // super(); // System.out.println(“11111”); // } ///* // * 获取数据库中用户信息 // * @param andy 账号 // * // * @return // * // */ // @Override // public UserDetails loadUserByUsername(String andy) { // System.out.println(andy); // User user = userRepository.findByAndy(andy); // System.out.println(user); // return new CustomUserDetails(user, // roleConverter.convert(user.getRole()) // 关键转换点1 // ); // } }package com.kucun.Config; // 2. 基础安全配置 //@Configuration //@EnableWebSecurity // 启用Web安全功能 public class SecurityConfig //extends WebSecurityConfigurerAdapter { // @Override // public void configure(WebSecurity web) { // web.ignoring().antMatchers(“/check-session”); // } // // 添加自定义Controller // @RestController // public static class SessionCheckController { // @GetMapping(“/check-session”) // public ResponseEntity<?> checkSession(HttpServletRequest request) { // return request.getSession(false) != null ? // ResponseEntity.ok().build() : // ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); // } // } // /** // * 核心安全过滤器链配置 // * @param http HTTP安全构建器 // * @return 安全过滤器链 // * @throws Exception 配置异常 // * // * █ 配置逻辑说明: // * 1. authorizeHttpRequests: 定义访问控制规则 // * 2. formLogin: 配置表单登录 // * 3. logout: 配置注销行为 // * 4. exceptionHandling: 处理权限异常3 // / // // // 修正后的配置方法 // @Override // protected void configure(HttpSecurity http) throws Exception { // // // // http // .csrf().disable() // .sessionManagement() // .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) // .invalidSessionUrl(“/login.html?session=invalid”) // .maximumSessions(1) // .maxSessionsPreventsLogin(false) // .and() // .and() // .addFilterBefore(jsonAuthFilter(), UsernamePasswordAuthenticationFilter.class) // 关键配置 // .authorizeRequests() // .antMatchers(“/login.html”, “/users/login”).permitAll() // .antMatchers(“/js/", "/css/”, “/fonts/", "/images/”,“/check-session”,“/main/bootstrap-3.3.7-dist/“).permitAll() // .antMatchers(”/users/guanli/”).hasAuthority(“ROLE_ADMIN”) // .anyRequest().authenticated() // .and() // .formLogin().disable() //// .loginPage(“/login.html”) //// .loginProcessingUrl(“/users/login”) //// //// .successHandler(ajaxAuthenticationSuccessHandler()) // 自定义成功处理器 //// .failureHandler(ajaxAuthenticationFailureHandler()) // 自定义失败处理器 //// .defaultSuccessUrl(“/index.html”) //// .failureUrl(“/login.html?error=true”) //// .usernameParameter(“andy”) // 修改用户名参数名 //// .passwordParameter(“pass”) // 修改密码参数名 //// .and() // // .logout() // .logoutUrl(“/logout”) // .logoutSuccessUrl(“/login.html”) // .and() // .csrf() // .ignoringAntMatchers(“/users/login”) // .and() // .headers() // .frameOptions().sameOrigin() // .and() // .exceptionHandling() // .accessDeniedHandler(accessDeniedHandler()); // 统一使用Handler // } // // // // // // // 返回JSON格式的成功响应 // @Bean // public AuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() { // return (request, response, authentication) -> { // // // // // 强制创建服务端会话 // request.getSession(true); // // // // // String contextPath = request.getContextPath(); // HttpSession session = request.getSession(true); // Cookie cookie = new Cookie(“JSESSIONID”, session.getId()); // cookie.setPath(contextPath.isEmpty() ? “/” : contextPath + “/”); // cookie.setMaxAge(1800); // 30分钟 // response.addCookie(cookie); // // // //构建安全响应数据 // Map<String, Object> responseData = new HashMap<>(); // responseData.put(“sessionId”, request.getSession().getId()); // responseData.put(“userInfo”,Collections.unmodifiableMap(new HashMap<String, Object>() {/* // * // / // private static final long serialVersionUID = 1L; // // { // put(“Name”, ((CustomUserDetails)authentication.getPrincipal()).getName()); // put(“role”, ((CustomUserDetails)authentication.getPrincipal()).getRole()); // }})); // // // // // 统一返回JSON格式 // response.setContentType(MediaType.APPLICATION_JSON_VALUE); // // new ObjectMapper().writeValue(response.getWriter(), responseData); // // // // // // // // // // response.setContentType(MediaType.APPLICATION_JSON_VALUE); // CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); // // response.setStatus(HttpStatus.OK.value()); // System.out.println(authentication.getPrincipal()+“”+authentication.getName()); // // if (request.getHeader(“X-Requested-With”) == null) { // 非AJAX请求 // response.sendRedirect(“/index.html”); // } else { // // //String re=userDetails.getUser().toString() // new ObjectMapper().writeValue(response.getWriter(), userDetails.getUser() // ); // // } // // // // // // // }; // } // // // 返回401状态码和错误信息 // @Bean // public AuthenticationFailureHandler ajaxAuthenticationFailureHandler() { // return (request, response, exception) -> { // if (request.getHeader(“X-Requested-With”) == null) { // response.sendRedirect(“/login.html?error=true”); // } else { // response.setStatus(HttpStatus.UNAUTHORIZED.value()); // response.getWriter().write(“{"error":"Authentication failed"}”); // } // }; // } // // // 处理未认证请求 // @Bean // public AuthenticationEntryPoint ajaxAuthenticationEntryPoint() { // return (request, response, exception) -> { // if (request.getHeader(“X-Requested-With”) == null) { // response.sendRedirect(“/login.html?error=true”); // } else { // response.setStatus(HttpStatus.UNAUTHORIZED.value()); // response.getWriter().write(“{"error":"Authentication failed"}”); // } // }; // } // // // // // // @Bean // public JsonUsernamePasswordAuthenticationFilter jsonAuthFilter() throws Exception { // // JsonUsernamePasswordAuthenticationFilter filter = // new JsonUsernamePasswordAuthenticationFilter(); // filter.setAuthenticationManager(authenticationManagerBean()); // filter.setUsernameParameter(“andy”); // 设置自定义参数名 // filter.setPasswordParameter(“pass”); // filter.setFilterProcessesUrl(“/users/login”); // filter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler()); // filter.setAuthenticationFailureHandler(ajaxAuthenticationFailureHandler()); // // return filter; // } // // // /* // * 密码编码器(必须配置) // * 使用BCrypt强哈希算法加密 // */ // @Bean // public PasswordEncoder passwordEncoder() { // return new BCryptPasswordEncoder(); // } // // // @Bean // public AccessDeniedHandler accessDeniedHandler() { // System.out.println(“0000”); // return (request, response, ex) -> { // if (!response.isCommitted()) { // response.sendRedirect(“/error/403”); // } // }; // } // // //} // // // // // // //class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { // private final ObjectMapper objectMapper = new ObjectMapper(); // // @Override // public Authentication attemptAuthentication(HttpServletRequest request, // HttpServletResponse response) // throws AuthenticationException { // System.out.println(“收到认证请求,路径:” + request.getRequestURI()); // System.out.println(“请求方法:” + request.getMethod()); // System.out.println(“Content-Type:” + request.getContentType()); // if (request.getContentType() != null && // request.getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE)) { // // try (InputStream is = request.getInputStream()) { // Map<String, String> authMap = objectMapper.readValue(is, Map.class); // // String username = authMap.getOrDefault(getUsernameParameter(), “”); // String password = authMap.getOrDefault(getPasswordParameter(), “”); // // // 调试日志 // System.out.println("Authentication attempt with: " + username+‘_’+ password); // // UsernamePasswordAuthenticationToken authRequest = // new UsernamePasswordAuthenticationToken(username, password); // // setDetails(request, authRequest); // return this.getAuthenticationManager().authenticate(authRequest); // } catch (IOException e) { // throw new AuthenticationServiceException(“认证请求解析失败”, e); // } // } // Authentication aut= super.attemptAuthentication(request, response); // System.out.println(“结果:”+aut.isAuthenticated()); // // return aut; // } } package com.kucun.Config.Role; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.json.Json; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; /** 权限转化 @author Administrator */ @Component public class RoleConverter { // private static final Map<Integer, String> ROLE_MAP = new HashMap<>(); // // @PostConstruct // public void init() { // ROLE_MAP.put(0, “ROLE_ADMIN”); // ROLE_MAP.put(1, “ROLE_USER”); // ROLE_MAP.put(2, “ROLE_MANAGER”); // ROLE_MAP.put(3, “ROLE_AUDITOR”); // } // // public List<GrantedAuthority> convert(int roleCode) { // ObjectMapper mapper = new ObjectMapper(); // try { // System.out.println(mapper.writeValueAsString(Collections.singletonList( // new SimpleGrantedAuthority(ROLE_MAP.getOrDefault(roleCode, “ROLE_GUEST”)))).toString());//输出[{“authority”:“ROLE_ADMIN”}] // } catch (JsonProcessingException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // // return Collections.singletonList( // new SimpleGrantedAuthority(ROLE_MAP.getOrDefault(roleCode, “ROLE_GUEST”)) // ); // } // }package com.kucun.Config.user; import java.util.Collection; import com.kucun.data.entity.User; public class CustomUserDetails /implements UserDetails/ { // /** // * // */ // private static final long serialVersionUID = 1L; // private final String andy; // 对应andy字段 // private final String name; // private final int role; // private final String password; // private final User users; // private final Collection<? extends GrantedAuthority> authorities; // // public CustomUserDetails(User user, Collection<? extends GrantedAuthority> authorities) { // this.andy = user.getAndy(); // this.name = user.getName(); // this.role = user.getRole(); // this.password = user.getPass(); // user.setPass(null); // this.users=user; // this.authorities = authorities; // } // // // 实现UserDetails接口方法 // @Override public String getUsername() { return andy; } // @Override public String getPassword() { return password; } // @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } // // // 自定义字段访问方法 // public String getName() { return name; } // public User getUser() { return users; } // public int getRole() { return role; } // // // 其他必要方法 // @Override public boolean isAccountNonExpired() { return true; } // @Override public boolean isAccountNonLocked() { return true; } // @Override public boolean isCredentialsNonExpired() { return true; } // @Override public boolean isEnabled() { return true; } } <!doctype html> <html> <head> <meta charset=“utf-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1, maximum-scale=1”> <title>峤丞板材库存管理</title> <meta name=“viewport” content=“width=device-width, initial-scale=1”> <link rel=“stylesheet” type=“text/css” href=“fonts/font-awesome-4.7.0/css/font-awesome.min.css”> <link rel=“stylesheet” type=“text/css” href=“css/util.css”> <link rel=“stylesheet” type=“text/css” href=“css/main.css”> <link rel=“stylesheet” type=“text/css” href=“css/index2.css”> <style type=“text/css”> *{ margin:0; padding:0; } .frame-header { height: 60px; background-color: #23262E; justify-content: space-between; } .frame-header-li{ font-family: Arial, Helvetica, sans-serif; font-size:40px; } .frame-ul{ } .frame-ul li{ border-style: solid; border-width:1px 0px 1px 0px; margin-top: 1px; height: 35px; text-align: center } #username{ position: absolute; right: 0; /* 靠右 */ } .frame-body { position: fixed; top: 60px; right: 0; bottom: 0; left: 0; display: flex; flex-direction: row; } .frame-side { scrollbar-width: none; /* firefox隐藏滚动条 / -ms-overflow-style: none; / IE 10+隐藏滚动条 / overflow-x: hidden; overflow-y: auto; width: 200px; background-color:#9e5; } .frame-side::-webkit-scrollbar { display: none; / Chrome Safari 隐藏滚动条*/ } .frame-main { flex-grow: 1; background-color:#fff; } .jiaoluo{ margin: auto; margin-right: 0px; } </style> </head> <body> <div class=“frame-header”> <a class=‘frame-header-li’ style=“color:#fff”>峤丞木材仓库管理</a> <a id=“username” class=‘frame-header-li’ style=“color:#520”>峤丞木材仓库管理</a> <button class=“.menu-button” style=“”>注销</button> </div> <div class=“frame-body”> <div class=“frame-side”> <ul class=‘frame-ul’ style=“text-align:center;”> <li ><a href=“main/test.html” target=“main”>首页</a></li> <li><a href=“main/LuRul.html” target=“main”>材料录入</a></li> <li><a href="main/Guanli.html" target="main">材料录入</a></li> </ul> </div> <div class="frame-main"> <!-- 内容主体区域 --> <iframe id="iframeid" name="main" src="main/index.html" width="100%" height="100%" frameborder="0"> </iframe> </div> </div> </body> <script type=“text/javascript” src=“js/jquery-3.2.1.min.js”></script> <script type=“text/javascript” src=“js/jsyilai.js”></script> </html><!DOCTYPE html> <html lang=“zh-CN”> <head> <title>扁平简洁的登录页面演示_dowebok</title> <meta charset=“utf-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1”> <link rel=“stylesheet” type=“text/css” href=“fonts/font-awesome-4.7.0/css/font-awesome.min.css”> <link rel=“stylesheet” type=“text/css” href=“css/util.css”> <link rel=“stylesheet” type=“text/css” href=“css/main.css”> </head> <body> <div class=“limiter”> <div class=“container-login100”> <div class=“wrap-login100”> <div class=“login100-form-title” style=“background-image: url(images/bg-01.jpg);”> <span class=“login100-form-title-1”>登 录</span> </div> <form class="login100-form validate-form"> <div class="wrap-input100 validate-input m-b-26" data-validate="用户名不能为空"> <span class="label-input100">用户名</span> <input class="input100" type="text" name="andy" placeholder="请输入用户名"> <span class="focus-input100"></span> </div> <div class="wrap-input100 validate-input m-b-18" data-validate="密码不能为空"> <span class="label-input100">密码</span> <input class="input100" type="password" name="pass" placeholder="请输入用户密码"> <span class="focus-input100"></span> </div> <div class="flex-sb-m w-full p-b-30"> <div class="contact100-form-checkbox"> <input class="input-checkbox100" id="ckb1" type="checkbox" name="remember-me"> <label class="label-checkbox100" for="ckb1">记住我</label> </div> <div> <a href="javascript:" class="txt1">忘记密码?</a> </div> </div> <div class="container-login100-form-btn"> <button class="login100-form-btn">登 录</button> </div> </form> </div> </div> </div> <script type=“text/javascript”> </script> <script src=“js/jquery-3.2.1.min.js”></script> <script type=“text/javascript” src=“js/jsyilai.js”></script> </body> </html> yilai.js (function ($) { var pathName = window.location.pathname; console.log(pathName); // 输出类似于 ‘/index.html’ //alert(pathName) switch (pathName){ case "/KuCun2/login.html": jQuery.getScript('/KuCun2/js/main.js?'+Date.now()) jQuery.getScript('/KuCun2/js/login.js?'+Date.now()) break; case "/KuCun2/main/Guanli.html": jQuery.getScript('/KuCun2/js/main.js?'+Date.now()) jQuery.getScript('/KuCun2/js/guanli.js?'+Date.now()) jQuery.getScript('/KuCun2/main/bootstrap-3.3.7-dist/js/FileSaver.js?'+Date.now()) jQuery.getScript('/KuCun2/main/bootstrap-3.3.7-dist/js/MyTable.js?'+Date.now()) break; case "/KuCun2/index.html": jQuery.getScript('/KuCun2/js/main.js?'+Date.now()) jQuery.getScript('/KuCun2/js/index.js?'+Date.now()) break; } })(jQuery) main.js function https(url,data,fu){ $.ajax({ contentType:“application/json”, url: url, // 假设后端 API 地址 method: “POST”, data: JSON.stringify(data), type: “json”, dataType: “json”, success:function(e){ console.log(e.data) if(e.status==200){ console.log(e.data) fu(e.data) }else{ alert(e.text) } }, error: function (e) { console.log(e.data) console.error(e) alert(“请求失败,请稍后再试!”+e); } }); } function checkLoginStatus() { if (window.location.href.includes(‘/login.html’)) return; } window.addEventListener(‘beforeunload’, function(e) { console.trace(‘触发页面跳转的堆栈跟踪:’); }); //安全验证函数 function validateUserSession() { try { // 防御性数据获取 + 数据清洗 const rawValue = localStorage.getItem(“name”); const username = String(rawValue ?? ‘’) .trim() .replace(/[\u200B-\u200D\uFEFF]/g, ‘’); // 移除零宽字符 // 调试信息 console.log('[Auth] Raw:', rawValue, 'Processed:', username); // 复合验证条件 const isValid = ( username.length >= 2 && // 最小长度要求 !/[<>]/.test(username) && // 防止XSS username !== 'null' && username !== 'undefined' ); if (!isValid) { console.warn('无效用户标识:', username); // 安全跳转方法 //window.location.replace('/KuCun2/login.html'); // 立即终止执行 return Promise.reject('Invalid session'); } // 返回清洗后的用户名 return username; } catch (error) { console.error(‘会话验证失败:’, error); // window.location.replace(‘/KuCun2/login.html’); return Promise.reject(error); } } function deepMergeArrays(frontend, backend) { const resultMap = new Map(); // 遍历前端数据并存入 Map 中以便快速查找 frontend.forEach(item => resultMap.set(item.id, { ...item })); // 遍历后端数据并与前端数据进行合并 backend.forEach(item => { if (resultMap.has(item.id)) { // 如果存在相同 ID,则合并两者的内容 resultMap.set( item.id, Object.assign(resultMap.get(item.id), item) ); } else { // 如果不存在相同 ID,则新增该条目 resultMap.set(item.id, { ...item }); } }); // 将最终结果转回数组形式 return Array.from(resultMap.values()); } (function ($){ // 页面加载时检查登录状态 checkLoginStatus(); })(jQuery); function removeSpecificCharactersAndConvertToNumber(str, charsToRemove) { const regex = new RegExp([${charsToRemove}], ‘g’); // 创建用于匹配指定字符的正则表达式 const cleanedStr = str.replace(regex, ‘’); // 移除指定字符 const numberValue = parseFloat(cleanedStr); // 转换为浮点数 return isNaN(numberValue) ? null : numberValue; // 如果无法解析,则返回 null } logi.js/// <reference path=“jquery.d.ts” /> // ParseError: KaTeX parse error: Expected '}', got 'EOF' at end of input: …function(){ // (“#submit”).click(function(){ // // // ParseError: KaTeX parse error: Expected '}', got 'EOF' at end of input: … // andy:(“#andy”).val(), // pass:ParseError: KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲pass").val(), /…(“#name”).val()}), // type:“post”, // contentType:“application/json”, // success:function(e){ // alert(e) // } // }); // // // }); // }) (function ($) { “use strict”; /*================================================================== [ Focus Contact2 ]*/ $('.input100').each(function () { $(this).on('blur', function () { if ($(this).val().trim() != "") { $(this).addClass('has-val'); } else { $(this).removeClass('has-val'); } }) }) /*================================================================== [ Validate ]*/ var input = $('.validate-input .input100'); $('.validate-form').on('submit', function (e) { e.preventDefault(); var check = true; for (var i = 0; i < input.length; i++) { if (validate(input[i]) == false) { showValidate(input[i]); check = false; } } confirm(input) if(check) login(input); return check; }); $('.validate-form .input100').each(function () { $(this).focus(function () { hideValidate(this); }); }); function validate(input) { if ($(input).attr('type') == 'email' || $(input).attr('name') == 'email') { if ($(input).val().trim().match(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{1,5}|[0-9]{1,3})(\]?)$/) == null) { return false; } } else { if ($(input).val().trim() == '') { return false; } } } function showValidate(input) { var thisAlert = $(input).parent(); alert(input) $(thisAlert).addClass('alert-validate'); } function hideValidate(input) { var thisAlert = $(input).parent(); $(thisAlert).removeClass('alert-validate'); } // 登录按钮点击事件 function login(datas) { var data={} datas.each(function(a,element){ data[$(element).attr('name')]=$(element).val() }) alert(data.name); //var data={ andy,pass } // 模拟 AJAX 请求 https("/KuCun2/users/login",data,function (response) { alert("122222"); if (response.name) { localStorage.setItem("name", response.name); // 保存用户名到本地存储 localStorage.setItem("role", response.role); // 保存权限到本地存储 alert( response.name) window.location.href = '/KuCun2/index.html'; } else { alert("登录失败,请检查用户名和密码!"); } }) }; // 注销按钮点击事件 $("#logout-btn").click(function () { localStorage.removeItem("name"); // 清除本地存储中的用户名 checkLoginStatus(); // 更新登录状态 }); })(jQuery);index.js$().ready(function () { const username = localStorage.getItem("name"); $("#username").text(username) const $username = $('#username'); const $menuButton = $('.menu-button'); let hideTimeout = null; // 点击显示按钮 $username.on('click', function(e) { e.stopPropagation(); $menuButton.show(); }); // 区域外点击隐藏 $(document).on('click', function(e) { if (!$username.add($menuButton).is(e.target) && $username.has(e.target).length === 0 && $menuButton.has(e.target).length === 0) { $menuButton.hide(); } }); // 智能隐藏逻辑 const elements = $username.add($menuButton); elements.on('mouseleave', function() { hideTimeout = setTimeout(() => { $menuButton.hide(); }, 200); }).on('mouseenter', function() { clearTimeout(hideTimeout); }); var $iframe = $('<iframe>') // 使用 jQuery 监听 iframe 的 load 事件 $iframe.on('load', function() { try { // 确保 iframe 的内容可以被访问(非跨域情况下) var iframeDocument = $(this).contents(); var result = iframeDocument.find('body').text(); // 获取 iframe 内部的内容作为返回值 console.log("Iframe 加载完成后的返回值:", result); window.location.href="/KuCun2/login.html" } catch (error) { console.error("无法访问 iframe 内容,可能是因为跨域限制:", error.message); } }); // 将 iframe 添加到文档中 $('body').append($iframe); }); guanli.js(function ($) { //checkLoginStatus();//权限 https(“/KuCun2/users/guanli/getusers”,null,function(e){ $(“#DataTable”).remove() const c=[{id:" 序号 ", name:“名字”, andy:“账号”, role:“权限” }] let row = e.length+1; //c.concat(b); //const combinedArray = [c,e]; var r=deepMergeArrays(c,e) console.log(r ) let sclass = "table table-hover"; let bodys=[`<table id='DataTable' class='text-center ${sclass}'>`] let table=$("#TableView") table.append(bodys) let te= table.find("table") $.each(r, function(index, value) { var tr="" var boo=false if(index==0){var tr="<thead>"; boo=false} tr+="<tr>" $.each(value, function(name,val) { if(name!="pass"){ if(name!="id"){ tr+=`<td name='${name}' ><div contenteditable='${name!="id"&&boo}' style='float: left;width: 70%'>${val}</div></td>`; }else{ tr+=`<td name='${name}' style='float: left;width: 70%'>${val}</td>`; } } }) tr+="</tr>" if(index==0){ tr+="</thead>"} te.append(tr) }); addRight("#DataTable"); // // let sclass = “table table-striped”; // let bodys=[<table id='DataTable' class='text-center ${sclass}'>] // // for(let i = -1; i <= row; i++) { // bodys.push(“<tr>”); // // if(i=-1){ // // for(var a in c[0]) { // // var bo= “<td><div contenteditable=‘true’ style=‘float: left;width: 70%’>”+c[0][a]+“</div>”; // bodys.push(bo) // // } // // // }else{ // // // for(let j = 0; j <= col; j++) { // if(j == 0) { // var bo = “<td><div style=‘text-align: center;height: 100%’>” + e[i][b[j]] + “#</div></td>”; // bodys.push(bo) // } else { // var bo= “<td><div contenteditable=‘true’ style=‘text-align: center;height: 100%’>” // + // // ‘<span class=“glyphicon glyphicon-remove-sign” style=“color: #999;font-size: 16px;” onclick=“Deleterow(this)” aria-hidden=“true”></span>’ // +“</div></td>”; // bodys.push(bo) // } // } // } // bodys.push( “</tr>”); // // } // bodys.push(“</table>”); // var s=bodys.join(‘’) // $(“#TableView”).append(s); // addRight(“#DataTable”); // }) })(jQuery) 登录后访问index.html会被重定向到login.html其他以页面不回,
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值