Web技术基础教程 7_第1页
Web技术基础教程 7_第2页
Web技术基础教程 7_第3页
Web技术基础教程 7_第4页
Web技术基础教程 7_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JavaWeb开发技术与案例教程第10章AJAX与FetchAPI第10章知识结构10.1AJAX•10.1.1AJAX工作原理•10.1.2AJAX应用开发•10.1.3实例:AJAX的应用10.2FetchAPI•10.2.1FetchAPI简介•10.2.2FetchAPI工作原理•10.2.3实例:FetchAPI的应用10.3AJAX与FetchAPI对比10.4本章小结1第10章课程导入在Web开发的征途中,前后端之间的顺畅沟通是项目成功的关键。传统的方式往往伴随着繁琐的页面刷新和复杂的数据交换逻辑,这不仅影响了用户体验,也拖慢了开发效率。幸运的是,随着AJAX和FetchAPI的出现,这一切都变得简单而高效。AJAX与FetchAPI革新了前后端通信,实现页面局部更新,提高用户体验。AJAX利用XMLHttpRequest异步交互,FetchAPI则基于Promise,语法简洁。两者均简化了HTTP请求处理,加速项目开发。本章将学习如何使用AJAX或者Fetch进行数据请求与响应处理,结合上述技术,可以让Web应用更流畅,开发更高效。◆本章要点•理解AJAX的核心价值:无需刷新整个页面即可异步更新局部数据。•掌握使用XMLHttpRequest(XHR)对象发送异步请求和处理响应的核心步骤。•理解FetchAPI作为XHR的现代替代方案,其基于Promise的链式语法(.then(),.catch())更简洁易用。•掌握在Servlet后端如何处理AJAX/Fetch请求并返回响应数据(如HTML片段或JSON)。•掌握AJAX/Fetch在用户名实时验证等场景中的应用。2第10章课程导入◆素养目标•提升用户体验,践行无缝交互理念:通过AJAX局部刷新案例学习,理解“异步通信”对减少页面跳转、提升响应速度的价值。•强化跨域安全意识,防范非法请求:在FetchAPI的CORS配置实践中,掌握同源策略与跨域资源共享机制。•推动前后端分离,提升协作效率:通过JSON数据格式在AJAX中的应用,理解“接口契约”对前后端协作的重要性。•弘扬创新精神,拥抱技术变革:对比XMLHttpRequest与FetchAPI的差异,理解Promise语法对异步编程的优化。310.1AJAX

AJAX,是一种用于创建快速动态网页的技术。它不是一种新的编程语言,而是一种使用现有技术(如HTML、CSS、JavaScript、XML等)的新方法,旨在创建更好、更快以及交互性更强的Web应用程序。AJAX通过在后台与服务器进行少量数据交换,使网页实现异步更新,从而在不重新加载整个网页的情况下,对网页的局部进行更新。AJAX具有以下优点:•减少页面刷新次数:通过异步请求,AJAX可以减少页面的刷新次数,从而提升用户体验。•减轻服务器和带宽负载:由于只传输需要更新的数据,而不是整个页面,因此可以减轻服务器和带宽的负载。•提高用户交互体验:AJAX可以实现页面的局部更新,从而提供更加流畅和即时的用户交互体验。410.1.1AJAX工作原理

AJAX其实不是新技术,而是对几项旧技术的整合。AJAX的工作原理基于JavaScript对象XMLHttpRequest(简称XHR)。该对象在InternetExplorer5中首次引入,是一种支持异步请求的技术。AJAX的工作流程◆事件触发用户在Web页面上与元素进行交互(如单击按钮、输入文本等)。用户在网页上触发一个需要从服务器获取新数据的事件(例如:单击按钮、滚动页面、输入搜索关键字、选择下拉菜单等)。◆创建对象

JavaScript创建一个核心对象:XMLHttpRequest(简称XHR对象)。这是浏览器提供的API,用于在后台与服务器进行数据交换。XMLHttpRequest是早期实现AJAX的常用方法,但有以下局限性:•复杂的API:XMLHttpRequest的API较为复杂,使用起来容易出错。510.1.1AJAX工作原理•基于回调函数:通常需要使用回调函数处理响应,这可能导致代码结构复杂,不易维护。•不支持Promise:XMLHttpRequest不原生支持Promise,这使得异步代码的管理变得困难。◆配置请求使用XHR对象设置请求的细节:•open(method,url,async):指定HTTP请求方法(GET,POST,PUT,DELETE等)、目标服务器的URL(数据来源地址)以及最重要的async=true(表示这是一个异步请求)。异步是AJAX的关键,它允许浏览器在等待服务器响应时继续执行其他脚本和响应用户操作。•setRequestHeader()(可选):如果需要,设置HTTP请求头部信息(如Content-Type指定发送数据的格式)。610.1.1AJAX工作原理◆定义回调函数•为XHR对象的onreadystatechange事件(或使用onload,onerror等更现代的事件)绑定一个或多个JavaScript函数(回调函数)。这些函数将在请求状态发生变化时(特别是请求完成时)被自动调用。•最重要的回调函数负责检查请求的最终状态和处理返回的数据。◆发送请求•调用XHR对象的send()方法将配置好的请求发送到服务器。•如果请求是POST或PUT等需要发送数据的类型,数据通常作为参数传递给send(data)方法(例如:表单数据、JSON字符串)。•对于GET请求,数据通常附加在URL的查询字符串中。◆服务器处理•服务器接收到AJAX请求并处理:执行必要的业务逻辑(如查询数据库、计算、访问其他服务等)。710.1.1AJAX工作原理•服务器准备响应数据:虽然名字里有XML,但现在JSON(JavaScriptObjectNotation)是最常用的数据格式,因为它轻量且与JavaScript无缝集成。服务器也可以返回纯文本、HTML片段或XML(较少见)。◆处理服务器响应服务器将处理结果(数据或错误信息)通过HTTP响应发送回浏览器。浏览器的XHR对象接收到服务器返回的HTTP响应。响应包含:•status:HTTP状态码(如200表示成功,404表示未找到,500表示服务器内部错误等)。•responseText/responseXML/response:包含服务器返回的数据主体(文本、JSON字符串、XMLDOM等)。•readyState:表示XHR请求的当前状态(0=未初始化,1=已打开,2=已发送,3=接收中,4=完成)。810.1.1AJAX工作原理◆AJAX核心代码

AJAX尽管名称中包含XML,但现代AJAX实现更多是使用JSON传输数据,因为JSON格式更轻量且易于解析。一个AJAX实例代码如下所示。910.1.1AJAX工作原理(代码示例)<%@pagecontentType="text/html;charset=UTF-8"language="java"%><html><head><title>Ajax</title></head><body><scripttype="text/javascript">//创建一个新的XMLHttpRequest对象constxhr=newXMLHttpRequest();//配置请求:方法、URL、是否异步xhr.open('GET','/data',true);//设置请求完成后的回调函数xhr.onreadystatechange=function(){//检查请求是否完成(readyState=4)且成功(status=200)if(xhr.readyState===4&&xhr.status===200){//解析响应数据(这里假设返回的是JSON格式的数据)constresponseData=JSON.parse(xhr.responseText);//处理响应数据,例如更新网页的部分内容console.log(responseData);document.getElementById('result').innerText=responseData.message;}};//发送请求xhr.send();</script></body></html>1010.1.1AJAX工作原理(代码示例)下面对上述AJAX核心代码进行解析:◆创建XMLHttpRequest对象constxhr=newXMLHttpRequest();1110.1.1AJAX工作原理(代码示例)

XMLHttpRequest是AJAX的核心对象,用于发送和接收HTTP请求。◆配置请求xhr.open('GET','/data',true);1210.1.1AJAX工作原理上述代码利用open()方法初始化一个请求,该方法包含三个参数:•第一个参数是请求方法(如GET或POST)。•第二个参数是请求的URL。•第三个参数指定请求是否应该异步执行(true表示异步,false表示同步)。◆设置回调函数1310.1.1AJAX工作原理(代码示例)//定义XMLHttpRequest对象的回调函数,用于处理异步请求状态变化xhr.onreadystatechange=function(){//检查请求是否完成(readyState4表示请求完成)且响应成功(status200表示HTTPOK)if(xhr.readyState===4&&xhr.status===200){try{//解析JSON格式的响应文本为JavaScript对象constresponseData=JSON.parse(xhr.responseText);//在控制台输出完整响应数据console.log("Receivedresponse:",responseData);//将响应消息更新到页面元素中constresultElement=document.getElementById('result');if(resultElement){resultElement.innerText=responseData.message;}else{console.error("Elementwithid'result'notfound");}}catch(error){//错误处理:JSON解析失败或DOM操作异常console.error("Errorprocessingresponse:",error);}}};1410.1.1AJAX工作原理上述代码中,使用了onreadystatechange方法设置XMLHttpRequest对象的回调函数,也可以组合使用onload、onerror和ontimeout等方法设置回调函数,这样代码结构更清晰,职责分离更明确,如表10-1所示。1510.1.1AJAX工作原理表10-1设置回调函数的方法方法/事件说明实例onreadystatechangereadyState改变时触发。需要监控请求所有阶段(如连接建立、头部接收、数据接收中)的传统方式。onload请求成功完成时触发(无论HTTP状态码为何)。现代首选,用于处理请求完成后的逻辑,通常需要内部再检查status。onerror请求发生错误时触发(如网络问题)。处理网络层面的失败。ontimeout请求超时时触发。处理超时情况,需配合timeout属性使用。onprogress在接收响应数据期间周期性触发。实现下载进度条等功能。addEventListener为标准事件添加监听器。需要为同一事件绑定多个回调函数时使用。1610.1.1AJAX工作原理定义回调函数时,需要注意以下几点:•readyState属性表示请求的状态(0:未初始化;1:正在加载;2:已加载;3:交互中;4:完成)。•status属性表示HTTP状态码(例如200表示成功)。•在readyState为4且status为200时,请求成功完成,此时可以处理响应数据。•responseText属性包含响应的文本内容。•JSON.parse()方法用于将JSON格式的字符串解析为JavaScript对象。◆发送请求xhr.send();1710.1.1AJAX工作原理

send()方法用于发送HTTP请求。如果请求方法是POST,可以在这里传递数据(如xhr.send(data))。1810.1.2AJAX应用开发(1)◆数据交互在JavaWeb应用程序中,AJAX可以用于在客户端和服务器之间进行异步数据交互。例如,当用户填写表单时,可以使用AJAX在后台验证用户输入,而无需提交整个表单。这可以立即向用户反馈输入是否有效,而无需等待整个页面的刷新。

AJAX还可以用于从服务器动态加载数据,如加载新的帖子、评论或搜索结果等,而无需重新加载整个页面。这可以显著提高用户体验,使用户感觉页面更加流畅和响应迅速。◆实现方式在JavaWeb应用程序中,通常使用Servlet或SpringMVC等后端框架处理AJAX请求。Servlet可以接收AJAX发送的请求,并返回相应的响应数据。请求和响应数据可以是文本、HTML、JSON等格式,具体取决于AJAX请求的需求和服务器端的处理逻辑。1910.1.2AJAX应用开发(2)在客户端,可以使用JavaScript的XMLHttpRequest对象发送AJAX请求。请求可以是GET或POST等HTTP方法,具体取决于需要执行的操作和数据类型。◆应用场景

AJAX在JavaWeb应用程序中有广泛的应用场景,如实时搜索、动态加载内容、表单验证和实时聊天等。这些应用场景都需要在不重新加载整个页面的情况下,与服务器进行异步通信,并对页面进行局部更新。例如,在电子商务网站上,可以使用AJAX动态加载商品列表、购物车状态和用户评论等内容。这可以提高用户的购物体验,使用户能够更轻松地浏览和购买商品。◆安全性在使用AJAX进行数据交互时,需要注意安全性问题。例如,需要确保AJAX请求的数据在传输过程中是加密的,以防止数据被窃取或篡改。此外,还需要在服务器端对数据进行验证和过滤,以避免恶意攻击和SQL注入等安全问题。2010.1.3实例:AJAX的应用下面实例演示如何在JavaWeb中使用AJAX技术,实现用户名是否可用的验证功能。◆创建页面清单10-1所示的代码是一个使用原生JavaScript实现AJAX异步用户名验证的前端页面,通过oninput事件实时监听输入框变化,利用XMLHttpRequest对象向服务器发送GET请求验证用户名可用性,并将服务器返回的验证结果动态更新到页面的提示区域。2110.1.3实例:AJAX的应用(清单10-1ajax_validate.jsp)1/2<%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Ajax用户名验证</title><script>functionvalidate(input){letusername=input.value;//创建一个新的XMLHttpRequest对象constxhr=newXMLHttpRequest();//配置请求:方法、URL、是否异步xhr.open('GET','./checkUsername?username='+username,true);//设置请求完成后的回调函数xhr.onreadystatechange=function(){//检查请求是否完成(readyState=4)且成功(status=200)if(xhr.readyState===4&&xhr.status===200){//处理响应数据,例如更新网页的部分内容document.getElementById('message').innerHTML=xhr.responseText;}};//发送请求2210.1.3实例:AJAX的应用(清单10-1ajax_validate.jsp)2/2xhr.send();}</script></head><body><h2>Ajax用户名验证</h2><labelfor="username">用户名:</label><inputtype="text"id="username"name="username"oninput="validate(this)"><pid="message"></p></body></html>2310.1.3实例:AJAX的应用上述JavaScript代码是AJAX功能的核心。validate函数绑定在输入框的oninput事件上,用户每次输入都会触发此函数。它创建了一个XMLHttpRequest对象,并配置了一个异步GET请求,将输入框的username作为URL参数发送到后端的checkUsernameServlet。关键在于onreadystatechange回调函数。它会监听请求状态,当readyState变为4(完成)且status为200(成功)时,它会获取Servlet返回的响应文本(xhr.responseText),并将其动态插入到id="message"的<p>标签中,从而实现页面的局部刷新。◆创建请求处理类在服务器端,需要创建一个处理AJAX请求的Servlet。用于处理用户名验证请求的Servlet实例代码如清单10-2所示。2410.1.3实例:AJAX的应用(清单10-2CheckUsernameServlet.java)1/3packagecom.example.ch10;importjakarta.servlet.ServletException;importjakarta.servlet.annotation.WebServlet;importjakarta.servlet.http.HttpServlet;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;importjava.util.HashMap;importjava.util.Map;/***用户名可用性检查Servlet*@WebServlet注解定义Servlet访问路径为/checkUsername*处理GET请求,验证用户名是否已被注册*/@WebServlet("/checkUsername")publicclassCheckUsernameServletextendsHttpServlet{//模拟数据库的静态用户存储(实际项目应使用数据库)staticMap<String,String>users=newHashMap<>();static{//初始化模拟数据(静态代码块)users.put("admin","admin@");//预置管理员账号2510.1.3实例:AJAX的应用(清单10-2CheckUsernameServlet.java)2/3users.put("fucz","fucz@");//预置测试账号}/***处理GET请求*@paramrequest包含客户端请求信息*@paramresponse用于返回响应结果*/@OverrideprotectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{//设置响应内容类型为纯文本(注意:实际返回的是HTML片段)response.setContentType("text/plain;charset=UTF-8");PrintWriterout=response.getWriter();//获取客户端提交的用户名参数Stringusername=request.getParameter("username");//执行用户名验证逻辑booleanisAvailable=isUsernameAvailable(username);//根据验证结果返回不同提示(使用HTML颜色样式)if(isAvailable){out.print("<fontcolor=green>用户名可以使用</font>");}else{out.print("<fontcolor=red>用户名已经被注册</font>");2610.1.3实例:AJAX的应用(清单10-2CheckUsernameServlet.java)3/3}//确保输出流正确关闭out.flush();out.close();}/***模拟用户名可用性检查(实际项目应连接数据库)*@paramusername待检查的用户名*@returntrue表示可用,false表示已存在*/privatebooleanisUsernameAvailable(Stringusername){//控制台输出调试信息(实际项目应使用日志框架)System.out.println("Checkingusername:"+username);//检查用户名是否存在于模拟数据中//注意:HashMap的get方法时间复杂度为O(1),适合快速查找returnusers.get(username)==null;}}2710.1.3实例:AJAX的应用◆部署和运行将项目代码部署到Tomcat,然后启动服务器并访问页面。在输入框中输入用户名,页面将发送AJAX请求到Servlet进行用户名验证,并在页面上显示验证结果。如图10-1所示,输入用户名“fucz”时,AJAX异步请求后端接口,页面无刷新即时显示了“用户名已经被注册”的验证提示,http://localhost:8080/ch10/ajax_validate.jsp图10-1AJAX用户名验证运行结果2810.1.3实例:AJAX的应用◆XMLHttpRequest的局限性

XMLHttpRequest是早期实现AJAX的常用方法,但有以下局限性:•复杂的API:XMLHttpRequest的API较为复杂,使用起来容易出错。•基于回调函数:通常需要使用回调函数处理响应,这可能导致代码结构复杂,不易维护。•不支持Promise:XMLHttpRequest不原生支持Promise,这使得异步代码的管理变得困难。2910.2.1FetchAPI简介

FetchAPI请求是一种现代WebAPI,用于在JavaScript中发出HTTP数据请求。它是XMLHttpRequest的一种替代方案,提供了更加简洁和现代化的方式处理网络请求,Fetch也被称为下一代AJAX技术。Fetch函数是原生JavaScript的一部分,不需要使用XMLHttpRequest对象。Fetch请求使用Promise处理异步操作,Promise是现代JavaScript中异步编程的基础,是一个由异步函数返回的对象,可以指示操作当前所处的状态。在Promise返回给调用者的时候,操作往往还没有完成,但Promise对象提供了方法处理操作最终的请求结果。3010.2.2FetchAPI工作原理

FetchAPI是一个现代的、基于Promise的API,用于在JavaScript中进行网络请求。它提供了更简洁、更易用的方式处理网络请求和响应。FetchAPI返回的是Promise对象,这使得异步操作更加直观和易于管理。下面示例代码为FetchAPI的基本形式:3110.2.2FetchAPI工作原理(代码示例)//使用fetchAPI发起GET请求(默认方法)//返回一个Promise对象,用于异步处理响应fetch('/data')//第一个.then()处理HTTP响应//注意:fetch不会将HTTP错误状态(如404/500)视为reject,需手动检查.then(response=>{//解析响应体为JSON格式(返回新的Promise)returnresponse.json()})//第二个.then()处理解析后的数据.then(data=>{//在控制台输出获取的数据console.log('成功获取数据:',data)})//统一的错误处理(捕获网络错误、解析错误等).catch(error=>{//输出带错误标识的日志console.error('请求失败:',error)});3210.2.2FetchAPI工作原理上述代码中,首先调用fetch()函数,传入请求的URL。fetch()返回一个Promise对象,使用then()方法处理响应。response.json()也是一个异步操作,它读取响应体内容并解析为JSON对象。最后,使用catch捕获异常。默认情况下,FetchAPI不发送Cookie。如果需要发送Cookie,需要在请求选项中设置credentials属性的值为include,主要代码如下。fetch('/data',{credentials:'include'});//后续处理...3310.2.2FetchAPI工作原理

FetchAPI本身不提供请求超时的功能。可以通过封装Promise实现超时功能。下面示例代码是一个封装了超时控制功能的网络请求工具函数,通过结合fetchAPI和setTimeout实现了可自定义超时时间的异步请求机制,当请求超过指定时间(默认3秒)时会自动拒绝并返回超时错误,有效提升了前端应用的网络请求可靠性。3410.2.2FetchAPI工作原理(代码示例)1/2/***带超时控制的网络请求封装函数*@param{string}url-请求的目标URL*@param{number}[timeout=3000]-超时时间(毫秒),默认3秒*@returns{Promise}包含请求结果的Promise对象*/functionfetchWithTimeout(url,timeout=3000){returnnewPromise((resolve,reject)=>{//启动fetch请求fetch(url).then(resolve)//请求成功时resolve.catch(reject);//请求失败时reject//设置超时计时器setTimeout(()=>{//创建自定义超时错误reject(newError('Requesttimeout'));},timeout);});}//使用实例:请求API数据,设置5秒超时fetchWithTimeout('/data',5000).then(response=>{3510.2.2FetchAPI工作原理(代码示例)2/2//处理成功响应if(!response.ok)thrownewError('HTTPerror');returnresponse.json();}).then(data=>console.log('Received:',data));//后续处理...3610.2.3实例:FetchAPI的应用在这个案例中,通过改写前面AJAX实现的检查用户是否存在的案例,演示如何使用FetchAPI从前端向后端发送请求,并处理响应,以检查用户名是否存在。◆创建页面清单10-3所示的代码是一个使用现代FetchAPI结合async/await语法实现的异步用户名验证页面,通过oninput事件实时监听用户输入,利用fetch方法向服务器发送GET请求验证用户名,并将返回的验证结果动态更新到页面提示区域,代码结构清晰且具有更好的可读性。3710.2.3实例:FetchAPI的应用(清单10-3fetch_validate.jsp)1/2<%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><htmllang="en"><head><%--设置浏览器编码和页面标题--%><metacharset="UTF-8"><title>Fetch用户名验证</title><%--客户端验证逻辑--%><script>//异步验证函数(使用async/await处理异步操作)asyncfunctionvalidate(input){//获取输入框的值letusername=input.value;//发送GET请求到校验接口(注意:参数直接拼接在URL中)constresponse=awaitfetch("./checkUsername?username="+username,{method:"GET"});//解析响应文本constdata=awaitresponse.text();//控制台输出调试信息console.log(data);//更新页面提示信息document.getElementById('message').innerHTML=data;}3810.2.3实例:FetchAPI的应用(清单10-3fetch_validate.jsp)2/2</script></head><body><%--页面标题--%><h2>Fetch用户名验证</h2><%--用户名输入表单--%><labelfor="username">用户名:</label><%--输入框实时触发验证(oninput事件在值变化时立即触发)--%><inputtype="text"id="username"name="username"oninput="validate(this)"><%--用于显示校验结果的段落--%><pid="message"></p></body></html>3910.2.3实例:FetchAPI的应用上述代码是对上一节XMLHttpRequest的现代化改进。fetch()函数返回一个Promise,await关键字会暂停函数的执行,直到网络响应返回。awaitresponse.text()再次暂停,直到响应体被完全读取为文本。对比上一节的onreadystatechange回调函数,FetchAPI的async/await方式将异步代码写得像同步代码一样直观易读,极大地简化了异步请求的逻辑。◆创建请求处理类与AJAX类似,在Web应用程序中创建一个Servlet处理请求,这里后台功能与AJAX是一样的,所以采用AJAX中编写的CheckUsernameServlet.java,此处不再复述该类编写方法。4010.2.3实例:FetchAPI的应用◆部署和测试如图10-2所示,启动服务器并访问fetch_validate.jsp页面。输入用户名后,将自动显示验证结果。http://localhost:8080/ch10/fetch_validate.jsp图10-2Fetch用户名验证运行结果【注意】FetchAPI为JavaScript中的网络请求提供了一种更现代、更简洁的方法。它基于Promise,使得异步操作更加直观和易于管理。然而,在使

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论