load-more-button是在循环遍历某个ul时候出现
时间: 2025-08-24 13:22:09 浏览: 5
<think>好的,我现在需要解决用户的问题,将DrissionPage集成到Scrapy中处理点击“加载更多”按钮,并结合response.css进行数据提取。用户之前已经得到了一些指导,现在想更深入了解具体的实现方法。首先,我需要回顾用户提供的引用内容,看看是否有相关的信息可以参考。
用户提供的引用[1]提到items.py的作用,定义数据结构,这可能对数据存储有帮助,但当前问题更多集中在中间件和页面交互上。引用[2]和[3]涉及Playwright和中间件的使用,尤其是处理动态网站和分页。引用[4]是关于Scrapy中解析URL和处理请求的示例,可能与如何触发后续请求有关。
用户的上一次回答中,已经提到了创建自定义中间件,使用DrissionPage处理动态加载,并将结果转换为HtmlResponse。现在用户可能希望更详细的步骤,或者遇到问题需要进一步解决。
首先,我需要确认用户的需求:在Scrapy项目中,如何集成DrissionPage来处理需要点击加载更多按钮的情况,并且能够使用response.css解析数据。可能的挑战包括中间件的正确设置、处理动态加载内容与Scrapy请求的协调,以及数据提取的兼容性。
接下来,我需要结合之前的回答和引用内容,构建一个清晰的步骤指南。可能需要详细说明中间件的工作流程,如何触发点击事件,以及如何确保动态加载后的内容能够被response.css正确解析。此外,可能需要考虑错误处理、等待策略以及如何与Scrapy的异步机制协同工作。
用户可能还关心如何优化性能,比如减少不必要的点击次数,或者处理页面元素加载失败的情况。此外,如何将动态加载后的数据传递到Scrapy的items中,可能需要结合items.py的定义,确保数据结构正确。
另外,需要注意DrissionPage和Scrapy的结合可能带来的问题,比如请求拦截和响应的转换是否正确,以及如何处理可能出现的JavaScript执行问题。例如,在中间件中,使用DrissionPage获取页面内容后,是否能够正确生成HtmlResponse对象,使得后续的response.css能够正常工作。
还需要考虑代码示例的准确性,比如中间件中的process_request方法是否正确处理了请求,是否在点击加载更多按钮后等待足够的时间以确保内容加载完成。同时,在parse方法中如何发起带有meta标记的请求,以触发中间件的处理。
最后,可能需要验证整个过程是否可行,比如测试中间件是否能正确拦截请求,执行点击操作,并将完整页面内容返回给Scrapy的解析函数。如果有错误,可能需要调试中间件中的代码,查看是否有元素定位失败或页面加载不完全的情况。
综上所述,我需要提供一个结构化的回答,涵盖中间件的创建、配置、动态加载处理、数据提取以及可能的问题和解决方案。同时,确保示例代码正确,并且与用户之前的问题和引用内容中的信息一致,避免出现矛盾或错误。</think>将DrissionPage集成到Scrapy中处理动态加载并保持response.css解析能力,可通过以下技术方案实现:
### 一、完整集成流程(含代码更新版)
#### 1. 创建混合型中间件
```python
# middlewares.py
from scrapy.http import HtmlResponse
from drissionpage import SessionPage
class HybridMiddleware:
def process_request(self, request, spider):
if request.meta.get('use_drissionpage'):
page = SessionPage()
page.get(request.url)
# 动态加载处理逻辑
while True:
load_btn = page.ele('#load-more-btn', timeout=3)
if not load_btn:
break
load_btn.click()
page.wait.load_start() # 使用内置等待新加载开始
page.wait.load_complete() # 等待加载完成[^1]
return HtmlResponse(
url=page.url,
body=page.html.encode('utf-8'),
encoding='utf-8',
request=request
)
```
#### 2. 爬虫调用示例
```python
class ProductSpider(scrapy.Spider):
name = 'dynamic_spider'
def start_requests(self):
yield scrapy.Request(
url='https://example.com/products',
callback=self.parse_initial,
meta={'use_drissionpage': False} # 初始请求不使用DrissionPage
)
def parse_initial(self, response):
# 常规CSS选择器提取数据
yield {'page_title': response.css('title::text').get()}
# 触发动态加载请求
yield response.follow(
response.url,
callback=self.parse_full_data,
meta={'use_drissionpage': True} # 启用DrissionPage处理
)
def parse_full_data(self, response):
# 处理完整加载后的数据
for product in response.css('div.product-item'):
item = {
'name': product.css('h2::text').get().strip(),
'price': product.css('.price::text').re_first(r'\d+\.\d+'),
'specs': product.xpath('.//ul[@class="spec-list"]/li/text()').getall()
}
yield item
```
### 二、关键技术实现原理
1. **混合解析机制**:
- 初始请求使用原生Scrapy下载器($response.meta['use_drissionpage']=False$)
- 动态加载请求通过中间件切换为DrissionPage渲染($response.meta['use_drissionpage']=True$)
2. **动态加载检测**:
```python
page.wait.load_start() # 监测到新网络请求时触发
page.wait.load_complete(timeout=10) # 等待所有资源加载完成[^2]
```
3. **选择器兼容性保障**:
- DrissionPage生成的HTML通过$HtmlResponse$封装后,保持与原生response.css相同的DOM结构
- 支持混合使用CSS选择器和XPath:
```python
response.css('div.price::text').get()
response.xpath('//span[@class="discount"]/text()').get()
```
### 三、性能优化策略
1. **智能等待配置**:
```python
page.set.load_strategy.normal() # 平衡模式
page.set.timeouts(
base=10, # 基础等待时间
page_load=30 # 页面加载超时
)
```
2. **元素定位优化**:
```python
# 使用模糊匹配提高按钮识别率
page.ele('text:加载更多', timeout=5).click()
```
3. **请求过滤机制**:
```python
page.set.blocked_urls(['*.png', '*.gif']) # 屏蔽非必要资源
```
### 四、异常处理方案
```python
try:
while page.ele('tag:button@text():Load More', timeout=2):
page.ele('tag:button@text():Load More').click()
page.wait(2)
except PageElementNotFoundError:
self.logger.info('No more items to load')
except PageTimeoutError as e:
self.logger.warning(f'Loading timeout: {str(e)}')
```
### 五、与Item Pipeline的集成
```python
# items.py
import scrapy
class ProductItem(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field(
input_processor=MapCompose(str.strip),
output_processor=TakeFirst()
)
specs = scrapy.Field(
output_processor=Join(',')
)
```
阅读全文
相关推荐











<input autocomplete="off" spellcheck="false" type="text" placeholder="考核目标" class="ivu-input ivu-input-default"> <input autocomplete="off" spellcheck="false" type="text" placeholder="考核标准" class="ivu-input ivu-input-default"> <button data-v-3c1c8183="" type="button" class="btns ivu-btn ivu-btn-info" style="width: 56px;">
查询
</button><button data-v-3c1c8183="" type="button" class="btns ivu-btn ivu-btn-primary">
导入
</button><button data-v-3c1c8183="" type="button" class="btns ivu-btn ivu-btn-primary">
导出
</button><button data-v-3c1c8183="" type="button" class="btns ivu-btn ivu-btn-warning">
新增
</button><button data-v-3c1c8183="" type="button" class="btns ivu-btn ivu-btn-error">
删除
</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 分类 序号 权重(%) 考核目标 考核标准 操作 <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 1 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 2 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 3 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 4 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 价值观指标 5 10 试用期内进入XX项目,并通过客户考核 试用期内进入XX项目,并通过客户考核 ①通过则合格②未通过且未进入其他项目的为不合格,原则上不能转正。 ①通过则合格②未通过且未进入其他项目的为不合格,原则上不能转正。 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 价值观指标 6 10 综合素质 ①积极主动,责任心强,严格自律,能自觉遵守公司各项规章制度;
②接受任务主动,责任心较强,能较准确接受上级指示,遵守公司的各项规章制度;
③接受任务不主动,责任心不强,有违纪现象。
④能主动积极与本部门其他成员建立良好的协作关系,保持良好的团队合作气氛;与部门外、公司外人员,建立良好的人际关系,促进业务上的沟通;
⑤能与其他成员建立较好的协作关系,保持较好的团队合作气氛;与部门外、公司外人员,建立较好的人际关系,促进业务沟通;
⑥不能很好保持的团队合作气氛;与部门内、外、公司外人员,人际关系较弱,不能很好促进工作沟通。
⑦为人礼貌、正直、豁达,能实事求是阐述问题,有良好的适应能力,能很快加入公司的团队,能主动更新业务知识;
⑧为人诚实,较能实事求是阐述问题,有较好的适应能力,融入公司的团队较快,更新业务知识较强;
⑨有一定性格问题,阐述问题有片面性,适应能力较弱,融入公司的团队较难,不能主动更新业务知识。 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> 暂无筛选结果 操作 <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 分类 序号 权重(%) 考核目标 考核标准 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 1 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 2 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 3 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 关键业务指标 4 20 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 考核目标需要SMART化;例如:在XX时间按XX标准完成XX项目交付。 ①在2024年X月X日前,完成包括考核目标内的其他模块开发交付,且无bug,为优秀;②在2024年X月X日前,完成考核目标要求的模块开发交付,且无bug,为合格;③2024年X月X日未完成考核目标要求的模块开发交付,或完成后出现bug,为不足 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 价值观指标 5 10 试用期内进入XX项目,并通过客户考核 试用期内进入XX项目,并通过客户考核 ①通过则合格②未通过且未进入其他项目的为不合格,原则上不能转正。 ①通过则合格②未通过且未进入其他项目的为不合格,原则上不能转正。 <button type="button" class="ivu-btn ivu-btn-success ivu-btn-small" style="display: inline-block;"> 编辑</button> <label class="ivu-checkbox-wrapper ivu-checkbox-default"> <input type="checkbox" class="ivu-checkbox-input"> </label> 价值观指标 6 10 综合素质 ①积极主动,责任心强,严格自律,能自觉遵守公司各项规章制度;
②接受任务主动,责任心较强,能较准确接受上级指示,遵守公司的各项规章制度;
③接受任务不主动,责任心不强,有违纪现象。
④能主动积极与本部门其他成员建立良好的协作关系,保持良好的团队合作气氛;与部门外、公司外人员,建立良好的人际关系,促进业务上的沟通;
⑤能与其他成员建立较好的协作关系,保持较好的团队合作气氛;与部门外、公司外人员,建立较好的人际关系,促进业务沟通;
⑥不能很好保持的团队合作气氛;与部门内、外、公司外人员,人际关系较弱,不能很好促进工作沟通。
⑦为人礼貌、正直、豁达,能实事求是阐述问题,有良好的适应能力,能很快加入公司的团队,能主动更新业务知识;
⑧为人诚实,较能实事求是阐述问题,有较好的适应能力,融入公司的团队较快,更新业务知识较强;
⑨有一定性格问题,阐述问题有片面性,适应能力较弱,融入公司的团队较难,不能主动更新业务知识。 <object tabindex="-1" type="text/html" data="about:blank" style="display: block; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; border: none; padding: 0px; margin: 0px; opacity: 0; z-index: -1000; pointer-events: none;"></object> 1 <input type="hidden" value="10"> 10 条/页 无匹配数据 10 条/页20 条/页50 条/页100 条/页 加载中
跳至
<input type="text" autocomplete="off" spellcheck="false">
页
第 1 - 6 共 6 <button data-v-3c1c8183="" type="button" class="refresh ivu-btn ivu-btn-default ivu-btn-circle ivu-btn-small ivu-btn-icon-only"> </button>
1 document.querySelector("div.cover .dataContent .ivu-col .ivu-card-body "); 打印如上面的html 结构
2 完善查询 找到导入按钮

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
}
<modelVersion>4.0.0</modelVersion>
<groupId>KuCun2</groupId>
<artifactId>KuCun2</artifactId>
<version>0.0.1-SNAPSHOT</version>
war
<name>KuCun2</name>
<description/>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/>
<webVersion>4.0</webVersion>
UTF-8
3.21.12
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<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>
<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>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<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>
<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>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</build>
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”>
<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>
峤丞木材仓库管理
峤丞木材仓库管理
<button class=“.menu-button” style=“”>注销</button>
首页
材料录入
材料录入
<iframe id="iframeid" name="main" src="main/index.html" width="100%" height="100%" frameborder="0">
</iframe>
</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”>
</head>
<body>
登 录
<form class="login100-form validate-form">
用户名
<input class="input100" type="text" name="andy" placeholder="请输入用户名">
密码
<input class="input100" type="password" name="pass" placeholder="请输入用户密码">
<input class="input-checkbox100" id="ckb1" type="checkbox" name="remember-me">
<label class="label-checkbox100" for="ckb1">记住我</label>
忘记密码?
<button class="login100-form-btn">登 录</button>
</form>
<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=[]
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=""; boo=false}
tr+=""
$.each(value, function(name,val) {
if(name!="pass"){
if(name!="id"){
tr+=${val} ;
}else{
tr+=${val} ;
}
}
})
tr+=" "
if(index==0){ tr+=""}
te.append(tr)
});
addRight("#DataTable");
//
// let sclass = “table table-striped”;
// let bodys=[]
//
// for(let i = -1; i <= row; i++) {
// bodys.push(“”);
//
// if(i=-1){
//
// for(var a in c[0]) {
//
// var bo= “”+c[0][a]+“”;
// bodys.push(bo)
//
// }
//
//
// }else{
//
//
// for(let j = 0; j <= col; j++) {
// if(j == 0) {
// var bo = “ ” + e[i][b[j]] + “# ”;
// bodys.push(bo)
// } else {
// var bo= “”
// +
//
// ‘’
// +“ ”;
// bodys.push(bo)
// }
// }
// }
// bodys.push( “ ”);
//
// }
// bodys.push(“”);
// var s=bodys.join(‘’)
// $(“#TableView”).append(s);
// addRight(“#DataTable”);
//
})
})(jQuery) 登录后访问index.html会被重定向到login.html其他以页面不回,

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
}
<modelVersion>4.0.0</modelVersion>
<groupId>KuCun2</groupId>
<artifactId>KuCun2</artifactId>
<version>0.0.1-SNAPSHOT</version>
war
<name>KuCun2</name>
<description/>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/>
<webVersion>4.0</webVersion>
UTF-8
3.21.12
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<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>
<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>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<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>
<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>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</build>
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">
<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>
峤丞木材仓库管理
峤丞木材仓库管理
<button class=".menu-button" style="">注销</button>
首页
材料录入
材料录入
<iframe id="iframeid" name="main" src="main/index.html" width="100%" height="100%" frameborder="0">
</iframe>
</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">
</head>
<body>
登 录
<form class="login100-form validate-form">
用户名
<input class="input100" type="text" name="andy" placeholder="请输入用户名">
密码
<input class="input100" type="password" name="pass" placeholder="请输入用户密码">
<input class="input-checkbox100" id="ckb1" type="checkbox" name="remember-me">
<label class="label-checkbox100" for="ckb1">记住我</label>
忘记密码?
<button class="login100-form-btn">登 录</button>
</form>
<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" />
// $(document).ready(function(){
// $("#submit").click(function(){
//
//
// $.ajax({
// url:"../users/login",
// async:false,
// data:JSON.stringify({
// andy:$("#andy").val(),
// pass:$("#pass").val(),
// name:$("#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=[]
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=""; boo=false}
tr+=""
$.each(value, function(name,val) {
if(name!="pass"){
if(name!="id"){
tr+=${val} ;
}else{
tr+=${val} ;
}
}
})
tr+=" "
if(index==0){ tr+=""}
te.append(tr)
});
addRight("#DataTable");
//
// let sclass = "table table-striped";
// let bodys=[]
//
// for(let i = -1; i <= row; i++) {
// bodys.push("");
//
// if(i=-1){
//
// for(var a in c[0]) {
//
// var bo= ""+c[0][a]+"";
// bodys.push(bo)
//
// }
//
//
// }else{
//
//
// for(let j = 0; j <= col; j++) {
// if(j == 0) {
// var bo = "<td><span>" + e[i][b[j]] + "# ";
// bodys.push(bo)
// } else {
// var bo= ""
// +
//
// ''
// +" ";
// bodys.push(bo)
// }
// }
// }
// bodys.push( " ");
//
// }
// bodys.push("");
// var s=bodys.join('')
// $("#TableView").append(s);
// addRight("#DataTable");
//
})
})(jQuery) 访问index.html会被重定向到login.html其他以页面不回



import os import re import math import http.server import socketserver import urllib.parse from collections import defaultdict from lxml import etree, html # 配置信息 PORT = 8000 DOCUMENTS_DIR = "documents" # 存放HTML文件的目录 INDEX_FILE = "search_index.json" # 创建文档目录(如果不存在) os.makedirs(DOCUMENTS_DIR, exist_ok=True) # 示例文档(实际应用中会从文件系统加载) sample_docs = [ { "id": 1, "title": "Python编程语言", "content": "Python是一种高级编程语言,由Guido van Rossum创建。它强调代码可读性和简洁的语法。", "url": "doc1.html" }, { "id": 2, "title": "lxml库简介", "content": "lxml是Python中处理XML和HTML的强大库,基于libxml2和libxslt库构建。", "url": "doc2.html" }, { "id": 3, "title": "构建搜索网站", "content": "使用Python和lxml可以构建高效的搜索系统,解析HTML并提取关键信息。", "url": "doc3.html" } ] # 创建示例文档 for doc in sample_docs: with open(os.path.join(DOCUMENTS_DIR, doc["url"]), "w", encoding="utf-8") as f: f.write(f""" <!DOCTYPE html> <html> <head> <title>{doc['title']}</title> </head> <body> {doc['title']} {doc['content']} 相关主题: Python, 编程, lxml, 搜索系统 </body> </html> """) class SearchEngine: def __init__(self): self.index = defaultdict(dict) # 倒排索引 {词: {文档ID: 词频}} self.documents = {} # 文档元数据 {文档ID: {标题, url, content}} self.doc_count = 0 self.doc_lengths = {} # 文档长度(词数) def tokenize(self, text): """简单的分词函数""" words = re.findall(r'\b\w+\b', text.lower()) return words def build_index(self, documents_dir): """构建搜索索引""" self.index.clear() self.documents.clear() self.doc_count = 0 # 遍历文档目录中的所有HTML文件 for filename in os.listdir(documents_dir): if filename.endswith(".html"): doc_id = self.doc_count + 1 self.doc_count += 1 filepath = os.path.join(documents_dir, filename) # 使用lxml解析HTML with open(filepath, "r", encoding="utf-8") as f: content = f.read() tree = html.fromstring(content) # 提取文档内容 title = tree.findtext(".//title") or filename body_text = " ".join(tree.xpath("//body//text()")) # 存储文档元数据 self.documents[doc_id] = { "title": title.strip(), "url": filename, "content": body_text.strip()[:200] + "..." # 摘要 } # 分词并更新索引 words = self.tokenize(title + " " + body_text) self.doc_lengths[doc_id] = len(words) # 更新倒排索引 for word in set(words): # 使用set避免重复计数 if doc_id not in self.index[word]: self.index[word][doc_id] = 0 self.index[word][doc_id] += words.count(word) def tf_idf(self, term, doc_id): """计算TF-IDF分数""" # 词频(TF) tf = self.index[term].get(doc_id, 0) / self.doc_lengths[doc_id] # 逆文档频率(IDF) idf = math.log(self.doc_count / (1 + len(self.index[term]))) return tf * idf def search(self, query): """执行搜索查询""" if not self.index: self.build_index(DOCUMENTS_DIR) query_terms = self.tokenize(query) scores = defaultdict(float) # 计算每个文档的相关性分数 for term in query_terms: if term in self.index: for doc_id in self.index[term]: score = self.tf_idf(term, doc_id) scores[doc_id] += score # 按分数排序 sorted_results = sorted(scores.items(), key=lambda x: x[1], reverse=True) # 准备结果 results = [] for doc_id, score in sorted_results: if score > 0: # 只返回有相关性的文档 doc_info = self.documents[doc_id].copy() doc_info["score"] = round(score, 4) results.append(doc_info) return results # 创建搜索引擎实例 search_engine = SearchEngine() class SearchHandler(http.server.SimpleHTTPRequestHandler): def do_GET(self): """处理GET请求""" if self.path == "/": # 显示搜索页面 self.send_response(200) self.send_header("Content-type", "text/html; charset=utf-8") self.end_headers() html_content = self.generate_search_page() self.wfile.write(html_content.encode("utf-8")) elif self.path.startswith("/search?"): # 处理搜索请求 query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query).get("q", [""])[0] self.send_response(200) self.send_header("Content-type", "text/html; charset=utf-8") self.end_headers() results = search_engine.search(query) html_content = self.generate_results_page(query, results) self.wfile.write(html_content.encode("utf-8")) else: # 处理静态文件请求 super().do_GET() def generate_search_page(self): """生成搜索页面""" return f""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Python搜索网站</title> <style> body {{ font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; }} .container {{ max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }} h1 {{ color: #2c3e50; text-align: center; }} .search-box {{ display: flex; margin: 20px 0; }} input[type="text"] {{ flex: 1; padding: 12px; font-size: 16px; border: 1px solid #ddd; border-radius: 4px 0 0 4px; }} button {{ padding: 12px 20px; background: #3498db; color: white; border: none; border-radius: 0 4px 4px 0; cursor: pointer; font-size: 16px; }} button:hover {{ background: #2980b9; }} .result-item {{ margin: 15px 0; padding: 15px; border: 1px solid #eee; border-radius: 4px; }} .result-title {{ font-size: 18px; font-weight: bold; margin-bottom: 5px; color: #3498db; }} .result-url {{ color: #006621; font-size: 14px; margin-bottom: 5px; }} .result-snippet {{ color: #545454; }} .no-results {{ text-align: center; padding: 20px; color: #777; }} .footer {{ margin-top: 30px; text-align: center; color: #777; font-size: 14px; }} </style> </head> <body> Python搜索网站 <form action="/https/wenku.csdn.net/search" method="get"> <input type="text" name="q" placeholder="输入搜索关键词..."> <button type="submit">搜索</button> </form> 这个搜索网站使用Python内置库和lxml构建,可以索引和搜索本地HTML文档。 示例文档已包含在系统中,尝试搜索: "Python", "lxml", "搜索"等关键词。 使用Python + lxml构建 | 本地搜索系统 </body> </html> """ def generate_results_page(self, query, results): """生成搜索结果页面""" results_html = "" if results: for result in results: results_html += f""" {result['title']} /{DOCUMENTS_DIR}/{result['url']} {result['content']} 相关性: {result['score']} """ else: results_html = '没有找到相关结果' return f""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>搜索: {query} - Python搜索网站</title> <style> body {{ font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; }} .container {{ max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }} h1 {{ color: #2c3e50; }} .search-box {{ display: flex; margin: 20px 0; }} input[type="text"] {{ flex: 1; padding: 12px; font-size: 16px; border: 1px solid #ddd; border-radius: 4px 0 0 4px; }} button {{ padding: 12px 20px; background: #3498db; color: white; border: none; border-radius: 0 4px 4px 0; cursor: pointer; font-size: 16px; }} button:hover {{ background: #2980b9; }} .results-count {{ color: #777; margin-bottom: 20px; }} .result-item {{ margin: 15px 0; padding: 15px; border: 1px solid #eee; border-radius: 4px; }} .result-title {{ font-size: 18px; font-weight: bold; margin-bottom: 5px; color: #3498db; }} .result-url {{ color: #006621; font-size: 14px; margin-bottom: 5px; }} .result-snippet {{ color: #545454; }} .result-info {{ color: #777; font-size: 14px; margin-top: 5px; }} .no-results {{ text-align: center; padding: 20px; color: #777; }} </style> </head> <body> Python搜索网站 <form action="/https/wenku.csdn.net/search" method="get"> <input type="text" name="q" value="{query}"> <button type="submit">搜索</button> </form> 找到 {len(results)} 条结果 {results_html} 返回首页 | 使用Python + lxml构建 </body> </html> """ # 启动服务器 with socketserver.TCPServer(("", PORT), SearchHandler) as httpd: print(f"服务器运行在端口 {PORT}") print(f"访问地址: http://localhost:{PORT}/") print("按Ctrl+C停止服务器") try: httpd.serve_forever() except KeyboardInterrupt: print("\n服务器已停止")让浏览器成为专业AI工具,无需字典列表元组集合,还有网络请求,无需外部库,加上后的完整代码




