通用分页(下)

这篇具有很好参考价值的文章主要介绍了通用分页(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

通用分页(下),java,开发语言,java-ee,servlet

                                  一.理解分页思想

1.分页的实质

1.1(自我概述)

用最简单的话来说,就是在一个界面展示不了那么多数据时,通过一点手段将数据一部分一部分的加载出来,从而减少服务器的压力。并且使能够让服务器利用率提高!

1.2(专业术语)

分页思想是一种将大段文本或大量数据分成若干小块进行处理或显示的方法。它常用于各种计算机应用中,包括文本编辑器、浏览器、数据库查询等。

分页思想的主要目的是提高性能和用户体验。通过将大段文本或大量数据分成小块,可以减少一次性加载或处理的数据量,从而降低计算和传输的开销,并减少用户等待时间。此外,分页还可以提供更好的用户导航和浏览功能,使用户可以更方便地查看和操作数据。

在文本编辑器中,分页思想可以用于将长文本分成多个页面,以便用户能够逐页编辑和查看。在浏览器中,分页思想常用于将长网页内容分成多个可滚动的小块,以提供更好的浏览体验。在数据库查询中,分页思想可以用于将大量数据分成可翻页的结果集,以便用户可以分批次地浏览和获取数据。

分页思想的实现通常通过使用计数器、指针或索引来跟踪当前页和总页数,以及切换页面时的数据加载和更新。在用户界面中,常用的交互元素包括翻页按钮、滚动条或下拉列表,用于用户选择和导航不同的页面。

总之,分页思想是一种有效管理大量数据或大段文本的方法,可以提高性能、减少用户等待时间,并提供更好的用户体验和导航功能。


                                        二.优化pageBean

1.添加一部分分页需要类


     增加url保留上一次的请求地址
     增加parammap 保留上一次请求的参数  req.get
     增加一个最大页的方法
     增加一个上一页的方法
     增加一个下一页的方法
     初始化 pagebean方法

并且根据自己的需求来进行操作

	public String getUrl() {
		return url;
	}

	/**
	 * @param url the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * @return the paramMap
	 */
	public Map<String, String[]> getParamMap() {
		return paramMap;
	}

	/**
	 * @param paramMap the paramMap to set
	 */
	public void setParamMap(Map<String, String[]> paramMap) {
		this.paramMap = paramMap;
	}


	// 对pagebean进行初始化
	public void setRequest(HttpServletRequest req) {
		// 初始化默认查询第几页数据
		this.setPage(req.getParameter("page")); 
		// 初始化的页大小
		this.setRows(req.getParameter("rows"));
		// 初始化是否分页
		this.setPagination(req.getParameter("pagination"));
		// 保留上一次url的查询请求
		this.setUrl(req.getRequestURL().toString());
		// 保留上一次的查询条件
		this.setParameterMap(req.getParameterMap());
	}
	
	
	public void setParameterMap(Map<String, String[]>paramMap) {
		this.paramMap = paramMap;
	}

	private void setPagination(String pagination) {
		// 只有填写了false字符串,才代表不分页
		if (StringUtils.isNotBlank(pagination))
		this.setPagination(!"false".equals(pagination));
	}

	private void setRows(String rows) {
		if (StringUtils.isNotBlank(rows))
			this.setRows(Integer.valueOf(rows));
	}
	private void setPage(String page) {
		if (StringUtils.isNotBlank(page))
			this.setPage(Integer.valueOf(page));
	}

	// 上一页
		public int getPrevPage() {
			return this.page > 1 ? this.page - 1 : this.page;
		}

		// 下一页
		public int getNextPage() {
			return this.page < this.getMaxPage() ? this.page + 1 : this.page;
		}

		// 最大页
		public int getMaxPage() {
			return this.total % this.rows == 0 ? this.total 
			/ this.rows : (this.total / this.rows) + 1;
		}


	
    private       String   url;
    private    Map<String, String[]>paramMap;

                              三.分页自定义jsp标签

1为什么要使用自定义分页jsp标签?

1.1自我理解

旧版本的分页是通过,HTML分页条 ,JavaScript,form表单,三者组成然后再通过"C"标签,进行实现功能,在实现的过程中,代码赋值,代码重复,并且有许多无用代码

而新版本的分页:是通过自定义jsp标签实现,在实现具体功能时代码简单明了,但是拼接复杂,容易出现错误,但是熟能生巧,而且在检查错误时能过很简单的找到!

1.2专业术语

1. 代码重用:自定义 JSP 标签可以将分页逻辑封装成一个可复用的组件,可以在多个页面或多个项目中重复利用,避免了重复编写相同的分页代码。

2. 简化开发:使用自定义分页 JSP 标签可以简化分页功能的开发过程。通过定义标签的属性,开发人员可以灵活地配置分页的样式、显示内容、数据源等,而无需手动编写复杂的分页逻辑。

3. 提高可读性和维护性:自定义分页 JSP 标签将分页相关的代码分离出来,使页面代码更加简洁清晰,易于理解和维护。同时,当需要修改分页逻辑时,只需修改标签的定义,而不需要修改每个页面的代码。

4. 增强可扩展性:自定义分页 JSP 标签可以根据实际需求进行扩展和定制。开发人员可以自定义标签的行为和样式,以满足不同的分页需求,例如添加自定义的翻页按钮、指定显示的页码数量等。

5. 提供更好的用户体验:自定义分页 JSP 标签可以提供更友好和灵活的分页功能。标签可以处理分页相关的请求和响应,在页面上显示正确的分页链接和页码,从而使用户可以方便地进行翻页操作,并提供更好的用户导航和浏览体验。

总而言之,使用自定义分页 JSP 标签可以提高开发效率,简化代码编写,增强可读性和可维护性,并提供更好的用户体验,是开发分页功能的有效手段。

2.实现自定义分页标签

1.首先建立连接类

在实现连接类时,要将我们需要拼接的html,js,地代码通过”append“方法追加,当然我们的样式是不可进行拼接的

package com.lz.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.JspTag;

import com.lz.utils.PageBean;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
/**
 * 
 * @author lzzxq
 *
 */
public class PageTag extends BodyTagSupport {
	private PageBean pageBean;

	public PageBean getPageBean() {
		return pageBean;
	}

	public void setPageBean(PageBean pageBean) {
		this.pageBean = pageBean;
	}

	@Override
	public int doStartTag() throws JspException {
		JspWriter out = pageContext.getOut();
		try {
			out.print(toHTML());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return SKIP_BODY;
	}

	private String toHTML() {
		StringBuilder sb = new StringBuilder();

		// 这里拼接的是一个上一次发送的请求以及携带的参数,唯一改变的就是页码
		sb.append("<form id='pageBeanForm' action='" + pageBean.getUrl() + "' method='post'>");
		sb.append("<input type='hidden' name='methodName' value='list'>");
		sb.append("<input type='hidden' name='page'>");
		// 重要设置拼接操作,将上一次请求参数携带到下一次
		Map<String, String[]> paMap = pageBean.getParamMap();
		if (paMap != null && paMap.size() > 0) {
			Set<Map.Entry<String, String[]>> entrySet = paMap.entrySet();
			for (Map.Entry<String, String[]> entry : entrySet) {
				for (String val : entry.getValue()) {
					if (!"page".equals(entry.getKey())) {
						sb.append("<input type='hidden' name='" + entry.getKey() + "' value='" + val + "'>");
					}
				}
			}
		}
		sb.append("</form>");

		int page = pageBean.getPage();
		int max = pageBean.getMaxPage();
		int before = page > 4 ? 4 : page - 1;
		int after = 10 - 1 - before;
		after = page + after > max ? max - page : after;
		// disabled
		boolean startFlag = page == 1;
		boolean endFlag = max == page;

		// 拼接分页条
		sb.append("<ul class='pagination'>");
		sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>");
		sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPrevPage() + ")'>&lt;</a></li>");

		// 代表了当前页的前4页
		for (int i = before; i > 0; i--) {
			sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page - i) + ")'>"
					+ (page - i) + "</a></li>");
		}

		sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPage()
				+ ")'>" + pageBean.getPage() + "</a></li>");

		// 代表了当前页的后5页
		for (int i = 1; i <= after; i++) {
			sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page + i) + ")'>"
					+ (page + i) + "</a></li>");
		}

		sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getNextPage() + ")'>&gt;</a></li>");
		sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getMaxPage() + ")'>尾页</a></li>");
		sb.append(
				"<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>");
		sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>");
		sb.append("<li class='page-item'><b>共" + pageBean.getTotal() + "条</b></li>");
		sb.append("</ul>");

		// 拼接分页的js代码
		sb.append("<script type='text/javascript'>");
		sb.append("function gotoPage(page) {");
		sb.append("document.getElementById('pageBeanForm').page.value = page;");
		sb.append("document.getElementById('pageBeanForm').submit();");
		sb.append("}");
		sb.append("function skipPage() {");
		sb.append("var page = document.getElementById('skipPage').value;");
		sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > " + max + ") {");
		sb.append("alert('请输入1~N的数字');");
		sb.append("return;");
		sb.append("}");
		sb.append("gotoPage(page);");
		sb.append("}");
		sb.append("</script>");

		return sb.toString();
	}
}

 2.建立tid

注意:tag-class是:实现类路径;

<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
	<tlib-version>1.0</tlib-version>
	<jsp-version>1.2</jsp-version>
	<short-name>Simple Tags</short-name>
	<uri>/lz</uri>
	
	<tag>
		<name>page</name>
		<tag-class>com.lz.tag.PageTag</tag-class>
		<!--该标签有标签体-->
		<body-content>jsp</body-content>
		<attribute>
			<name>pageBean</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		
	
	</tag>
	
	

</taglib>

 3.导入jsp即可

<%@taglib  prefix="z"   uri="/lz"%>

3.servelt编写,过滤器

1.servelt代码实现

在servelt中将

    String bname = request.getParameter("bname");
    //map包含浏览器传输的所有键值对
    Map<String, String[]>map=request.getParameterMap();
    //请求的浏览器地址
    String url = request.getRequestURI().toString();

替换成了

        PageBean  pageBean=new PageBean();
        pageBean.setRequest(request);

从而减少代码量

package com.lz.servelt;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.lz.dao.BookDao;
import com.lz.entity.Book;
import com.lz.utils.PageBean;

@WebServlet("/book.action")
public class BookServelt extends HttpServlet {
	
	private static final String UNUSED = "unused";
	/**
	 *  
	 */ 
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
	doPost(request, response);
	} 
	
	@SuppressWarnings(UNUSED)
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		PageBean  pageBean=new PageBean();
		pageBean.setRequest(request);
		BookDao  bd=new  BookDao();
		Book  bk=new Book();
		bk.setBname(request.getParameter("bname"));
		try {
		List<Book>book=	bd.list(bk, pageBean);
//		System.out.println(book);
		request.setAttribute("book",book);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		request.setAttribute("pageBean",pageBean);

	request.getRequestDispatcher("bookList.jsp").forward(request, response);
	}

}

 2.处理乱码


中文乱码处理
@WebFilter("*.action")

package com.lz.utils;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebFilter("*.action")
public class EncodingFiter implements Filter {

	private String encoding = "UTF-8";// 默认字符集

	public EncodingFiter() {
		super();
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		// 中文处理必须放到 chain.doFilter(request, response)方法前面
		res.setContentType("text/html;charset=" + this.encoding);
		if (req.getMethod().equalsIgnoreCase("post")) {
			req.setCharacterEncoding(this.encoding);
		} else {
			Map map = req.getParameterMap();// 保存所有参数名=参数值(数组)的Map集合
			Set set = map.keySet();// 取出所有参数名
			Iterator it = set.iterator();
			while (it.hasNext()) {
				String name = (String) it.next();
				String[] values = (String[]) map.get(name);// 取出参数值[注:参数值为一个数组]
				for (int i = 0; i < values.length; i++) {
					values[i] = new String(values[i].getBytes("ISO-8859-1"),
							this.encoding);
				}
			}
		}

		chain.doFilter(request, response);
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		String s = filterConfig.getInitParameter("encoding");// 读取web.xml文件中配置的字符集
		if (null != s && !s.trim().equals("")) {
			this.encoding = s.trim();
		}
	}

}

 3.最终效果图:

通用分页(下),java,开发语言,java-ee,servlet


                                  四.debug使用

1.什么是debug?

Debug 是指在软件开发或故障排查过程中,通过追踪和分析程序的执行过程、变量的值以及程序输出,以发现和解决错误和异常的过程

在软件开发过程中,debug 的主要目的是找出程序中的错误或异常,确保程序能够按照预期的方式运行。当程序出现 bug(错误)时,debug 可以帮助开发人员定位问题的原因,从而逐步排除 bug。

调试过程可以包括以下步骤:

1. 设置断点:在程序中设置断点,通常是在代码的特定位置,以使程序在该位置暂停执行,以便开发人员可以逐行检查程序的状态。

2. 执行程序:运行程序并触发特定的操作或输入,以使程序按预期方式运行。

3. 追踪变量值:在断点处,开发人员可以查看和监控程序中各个变量的值,以确保它们的值与预期相符。

4. 单步执行:逐行运行程序,观察程序的执行路径和状态变化,以及每个操作的结果。

5. 查看日志或输出:检查程序的输出、日志或错误消息,以获取与问题相关的信息。

6. 分析堆栈跟踪:当程序出现异常或错误时,查看堆栈跟踪信息,以确定错误发生的位置和调用关系。

7. 修复问题:根据调试过程中获得的信息,确定错误的原因,并进行相应的修复、调整或优化。

常用的调试工具包括集成开发环境(IDE)提供的调试器,例如在 Java 开发中的 Eclipse、IntelliJ IDEA,以及浏览器开发者工具提供的调试器等。

总之,debug 是一种追踪和分析程序执行过程的方法,用于发现和解决程序中的错误和异常,以确保程序按照预期的方式运行。

2.怎么使用?

1. 设置断点:在开发工具中选择要调试的代码位置,通常是在代码行号旁边点击或通过快捷键设置断点。断点是一个标记,它将使程序在运行到该位置时暂停执行。

2. 启动调试:运行程序,并启动调试模式。这通常可以通过点击调试按钮、使用快捷键或选择调试菜单中的选项来实现。启动调试模式后,程序将以调试模式运行,并在遇到断点时停止。

3. 逐行执行:通过单步执行,在每个断点处逐行执行代码。这可以使用“下一步”或“单步执行”按钮或使用快捷键进行操作。在每个步骤中,观察程序的执行路径、变量值和输出结果。

4. 查看变量值:在断点处,可以查看程序的变量值,以了解它们的当前状态。通常,在调试工具的变量窗口或监视窗口中,可以查看和监控各个变量的值。

5. 跟踪调用堆栈:如果程序出现异常或错误,可以查看调用堆栈跟踪信息,以了解错误发生的位置和调用关系。调试工具通常提供堆栈跟踪窗口或调用堆栈面板以便查看。

6. 添加条件断点:除了普通断点,还可以为断点添加条件,以便在满足特定条件时才触发断点。这可以提高调试的效率,以便在关键的代码路径上进行调试。

7. 观察输出和日志:查看程序的输出、日志或错误消息,以获取与问题相关的信息。这可以帮助了解程序的预期行为与实际行为之间的差异,并定位问题所在。

8. 修复问题:根据调试的结果和产生的错误信息,确定错误的原因,并进行相应的修复、调整或优化。

注意:不同的开发工具和环境可能会提供更多的调试功能和选项。建议在使用特定的调试工具之前,了解该工具的具体用法和功能。

总之,使用 debug 的关键是设置断点、逐行执行代码、观察变量和输出,以及利用调试工具提供的功能和选项。通过调试,可以更快地定位和解决程序中的错误和异常。文章来源地址https://www.toymoban.com/news/detail-517659.html

到了这里,关于通用分页(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java EE 突击 11 - Spring MVC 程序开发 (2)

    这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架 JavaEE 进阶专栏 Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在 接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点 并且带领大家进行环境的配置 , 让大家真正用好

    2024年02月13日
    浏览(69)
  • Java EE 突击 10 - Spring MVC 程序开发 (1)

    这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架 JavaEE 进阶专栏 Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在 接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点 并且带领大家进行环境的配置 , 让大家真正用好

    2024年02月13日
    浏览(44)
  • Java EE企业级应用开发(SSM)第10章

    1.第九章的细节处理 1-1.mappers标签中的配置 1-2.jdbc属性文件的配置 1-3.包的别名配置 2.Mybatis核心配置文件 2-1:settings标签(P145-146中的表10-1) 2-2.类型别名 3.Mybatis映射文件 3-1:insert、update、delete元素属性 3-2:select元素 3-3:ResultMap详解 ResultMap详解 4.动态SQL 4-1:if 注意模糊查询

    2024年02月03日
    浏览(47)
  • Java EE企业级应用开发(SSM)第6章

    1.Spring MVC的请求参数 项目的基础配置 web.xml springmvc-config.xml jar包资源引入: 1-1:获取默认参数 jsp页面如下: Controller如下: 1-2:简单数据类型(获取数据不同,只展示Controller) 1-3:注解配置参数名(RequestParam) 2.Spring MVC的请求响应 2-1:响应ModelAndView:返回数据和页面 2-2:响

    2023年04月18日
    浏览(49)
  • Java EE企业级应用开发(SSM)第9章

    1.MyBatis框架的特点 1-1.简单易学 1-2.灵活 1-3.提供映射标签 2.MyBatis核心类 2-1.Configuration 2-2.SqlSessionFactory 2-3.SqlSession 2-4.Exector 2-5.MappedStatement 3.MyBatis工作流程 4.Mybatis入门程序 4-0:导入jar包资源 4-1:编写实体类 4-2:编写mapper接口以及映射文件 4-3:编写mybatis-config配置文件 4-4:编

    2024年02月04日
    浏览(46)
  • 从vue小白到高手,从一个内容管理网站开始实战开发第七天,登录功能后台功能设计--通用分页、枚举以及相关工具类

    上一篇实现了数据库访问层的相关功能,还没有了解的小伙伴可以去看前面文章实现的内容,因为每一篇内容都是连贯的,不学习的话可能下面的内容学习起来会有点摸不着头脑 从vue小白到高手,从一个内容管理网站开始实战开发第六天,登录功能后台功能设计--API项目中的

    2024年01月22日
    浏览(38)
  • Java EE开发系列教程 - 使用EJB组件与JPA层交互

    因为之前JPA原生 property 属性在Wildfly实现中并不总是生效,所以这里换成了Wildfly默认的JPA实现,即Hibernate。把属性改成了Hibernate专有的。 hibernate.hbm2ddl.auto 定义是否自动生成表, create-and-drop 意为如果表存在,则删除后再创建。 hibernate.dialect 用来指定数据库厂商,以根据不同

    2024年04月13日
    浏览(33)
  • Servlet | Servlet原理、开发第一个带有Java小程序Servlet

    ✅作者简介:一位材料转码农的选手,希望一起努力,一起进步!  📃个人主页:@每天都要敲代码的个人主页 🔥系列专栏:Web后端 | Servlet 目录 一:模拟实现Servlet 二:开发第一个带有Java小程序Servlet【重点】 有了上一章节的分析,我们来模拟实现以下Servlet;下面先分析一

    2024年02月02日
    浏览(44)
  • 基于Servlet实现分页查询

    Servlet + JSP+JSTL +MySQL+Bootstrap 等技术实现分页查询功能。  所用工具:IDEA 2022.3.3 + Navicat +Tomcat 等。 本文目录 一:运行效果  二:代码详解 (1)index.jsp  (2)PageBean  (3)Servlet (4)DAO层 (5)BaseDao (6)JSP  (7)所需数据表  (8)案例项目结构 三:功能展示 点击下一页

    2024年02月10日
    浏览(26)
  • 博客系统 Java Web 开发(Servlet)

    目录 一、准备工作 二、设计数据库 三、编写数据库代码 1、建表sql 2、封装数据库的连接操作 3、创建实体类 4、封装数据库的一些增删改查 (1)BlogDao 新增博客:  根据博客 id 来查询指定博客(用于博客详情页) 直接查询出数据库中所有的博客列表 删除博客 (2)UserDao

    2024年02月10日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包