博主介绍:专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作
☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟我的博客空间发布了1000+毕设题目 方便大家学习使用
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多的人
【摘要】本课题设计一个基于android的购物APP,客户端能实现用户的注册以及登陆,能够通过服务端获取商品的信息并且显示在商品列表上。使用者可以对商品进行按分类搜索等,随后可以对看中的商品进行加入购物车的操作。购买方面,可以直接购买或者通过购物车对看中的商品进行购买。客户端确认购买后购买的商品信息会传到服务端,并且显示在后台的网页上。本系统客服端运用了JAVA语言在Eclipse环境下开发,服务端则运用了servlet,JSP,数据库用的则是MySQL。
【关键词】android;购物APP;手机商城;JAVA
1引言
1.1课题背景
随着移动互联网的飞速发展,人们的生活方式以及消费观念都在逐渐的被改变。移动设备使得消费者可以在生活以及工作的间隙,能够把更多的零碎的时间放在“随时随地的享受移动购物以及浏览商品的乐趣当中”。相比于传统购物以及在PC端进行网购而言,移动设备上进行购物能够更加的方便、快捷。移动设备能够为用户提供随时随地的服务,应用,信息,娱乐等,并且能够在享受一系列更为方便、快捷的服务的同时,还能够省下一大块的时间,这也使得移动购物更易让广大人民群众所接受,也更容易受到年轻一族的青睐。正因为如此,近几年的移动电商得到了非常迅速的发展,移动电商APP开发市场也就存在着非常巨大的用户以及商业价值。
1.2主要工作内容
本设计主要运用JAVA语言在Eclipse环境下进行客户端的开发,android客户端整体的构架以及界面的优化等。客户端通过调用第三方库“volley”的方法将订单等信息传回服务端。服务端则对数据库进行访问,获得用户数据表以及商品数据表以用于客户端的用户注册,登陆,以及商品的展示。通过对客户端传回的商品信息进行分析,将信息进行完善(加入买家真实姓名,联系方式以及收货地址)并且存入订单数据表。然后在服务端的主页上将订单打印在表格当中。
1.3 相关软件工具介绍介绍
Eclipse:Eclipse是一个著名的跨平台免费的集成开发环境(IDE)。 最初主要用于Java语言开发,通过安装不同的插件,Eclipse可以支持不同的计算机语言,如C ++和Python等开发语言。 Eclipse本身只是一个框架平台,但是许多插件的支持运用,使得Eclipse具有其他功能相对固定的IDE软件难以拥有灵活性。 许多软件开发人员使用Eclipse作为开发自己的IDE的框架。
Android操作系统:Android操作系统是基于Linux内核,由谷歌公司在2007年11月5日发布的手机操作系统,前期由谷歌公司开发,后由开放手持设备联盟(Open Handset Alliance)开发。它采用了软件堆层(software stack,又名以软件叠层)的架构,主要分为三部分。 底层Linux内核只提供基本功能; 其他应用软件由公司自己开发,一些程序是用Java编写的。 2011年第一季度,Android在全球市场份额首次超过塞班系统,居世界第一。 2013年第四季度,Android平台手机的全球市场份额已经达到78.1%。 2013年09月09日,Google开发操作系统Android迎来了5岁生日,全球使用该系统的设备数已达10亿台。
Tomcat: Tomcat是Apache软件基金会(Apache Software Foundation)的雅加达项目的一个核心项目,由Apache,sun和其他一些公司和个人共同开发而成的。由于有了Sun的参与和支持,最新的Servlet和JSP规范总能在Tomcat中体现出来,Tomcat 5支持最新的Servlet 2.4和JSP 2规范。因为Tomcat技术先进、性能稳定、自由,因而深受java爱好者的喜爱,也得到很多软件开发商的认可,成为目前比较流行的Web应用服务器。
Mysql:MySQL是由瑞典MySQL AB公司开发的关系数据库管理系统,目前属于Oracle的产品。 MySQL是最流行的关系数据库管理系统之一,在WEB应用方面,MySQL是最好的RDBMS(Relational Database Management System,关系数据库管理系统)应用软件。MySQL使用的SQL语言是用于访问数据库的最常用的标准化语言。MySQL软件采用双重许可政策,分为社区版和商业版,由于体积小,速度快,总体拥有成本低,特别是开放源码的特点,大多数中小型网站的开发一般选择MySQL为网站数据库。
1.4 相关技术介绍
Java:java是一种面向对象的编程语言,不仅吸收各种优势的C++语言,同时摒弃了C++中难以理解的多继承、指针等概念,因此java语言具有强大的和易于使用的两个特征。java语言作为一种面向对象的编程语言的代表,一个优秀的面向对象理论的实现,允许程序员对复杂的编程思想以优雅的方式表达出来。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java语言在的桌面应用程序,Web应用,分布式系统和嵌入式系统中都有很多的应用。
Servlet: Servlet使用Java语言编写的一种服务器的程序,就像JSP、能够生成动态网页,Servlet运行在服务器端,由服务器调用和执行,是一种按照Servlet标准开发的类。Servlet程序是实现Java的CGI程序,但多线程和传统的CGI多进程是不同的,Servlet采用多线的处理方式,这使得Servlet程序的运行效率比传统的CGI更强而且Servlet有更强的可移植性,这使得Servlet更容易的使用也更加强大。
Jsp:JSP全名是Java Server Pages,中文名为java服务器页面,其本质是一个简化的Servlet技术,由Sun Microsystems发起,许多公司都参与而建立的一种动态Web技术标准。 JSP技术与ASP技术类似,它是在传统的网页HTML(标准通用标记语言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 使用JSP开发的Web是一个跨平台,能在Linux运行或者其他操作系统中运行的程序。
Html:HTML(超文本置标语言,HyperText Markup Language)是一个用于网页创建和实现其他能在网页浏览器看到网页信息而涉及的一种置标语言。HTML用于结构化信息,如标题、段落和列表等,也可以用来在一定程度上描述文档的外观和语义。由蒂姆·伯纳斯-李给出原始定义,由IETF用简化的SGML(标准通用置标语言)语法进行进一步发展的HTML后来成为国际标准,由万维网联盟(W3C)维护。
2需求分析
2.1系统功能结构设计
该购物APP分为客户端和服务端。其中客户端功能模块如图2-1所示:
图2-1 客户端功能模块
后台功能模块如图2-2所示:
图2-2 服务端功能模块
2.2功能性需求
2.2.1购物APP客户端模块功能需求:
- 爱逛:显示商品,将从服务端拿到的手机商品信息按品牌分类(iPhone,小米,三星,华为,魅族等)罗列出来,并且在用户点击商品的时候可以查看商品的详情,并在浏览详情之后能选在将商品加入购物车或者选择直接购买;
- 分类:按屏幕尺寸(分为小于4.5英寸,4.5至5.0英寸以及大于5.0英寸三档),按价格区间(分为1000元以下,1000-2000元,2000-3000元,以及大于3000元四档),以及按手机系统进行分类(分为android和ios两种系统),便于用户查找自己喜欢的类型的手机;
- 搜货:可供用户直接在搜索框搜索自己喜欢的手机;
- 我的:实现用户注册,并能够进行格式校验,实现用户登录,每个登陆的用户都能够对自己的购物车,以及收货地址进行管理。
2.2.2购物APP服务端模块功能需求:
- Dao:存放对用户信息的操作方法(注册,查看用户是否已存在,登陆等),对商品信息的操作方法(通过品牌,系统,价格区间,屏幕尺寸,手机名等信息查找对应手机并返回相应数据)以及订单信息的操作方法(从数据库读出订单信息并返回相应数据);
- entity:存放用户信息类,商品信息类以及订单信息类对象,定义用户信息,商品信息以及订单信息的一些基本属性以及设置和取出相应数据的方法();
- servlet:通过对dao层的方法进行调用,并返回相应的数据(通过对手机名,屏幕尺寸,价位区间等给出条件对数据库中的商品进行检索所得到的数据或者是对用户表进行检索所得到的用户注册以及登陆所需要的数据)给客户端;
- tool:JDBC方法,连接数据库,并返回数据库连接的句柄conn以供dao层方法调用
- webroot:通过从客户端收取到的订单信息(商品,数量,用户名),检索用户数据表,得到用户的收货地址,联系方式以及真实姓名,然后将数据加入订单数据表中,服务端网页上加载订单数据表中的内容,并逐行显示在订单表格当中。
3 系统实现
3.1客户端
客户端即为android手机软件,购物APP,通过使用JAVA语言在Eclipse上进行开发,最后运行在安卓智能手机平台上。客户端功能模块主要分为:爱逛(商品列表展示),分类(商品按一定规则分类),搜货(自定义搜索商品),我的(登陆注册以及部分提供给已登录用户的功能)
3.1.1客户端注册以及登陆界面
注册以及登陆界面主要实现用户的注册以及登陆功能。
注册以及登陆界面如下图所示:
图3-1 用户注册 图3-2 用户登录
主要代码实现:
点击注册或登陆按钮,客户端将相应的信息传送至服务端,并且通过解析从服务器获取的响应,提示用户是否注册或者登陆成功,以及提示用户注册失败或者登陆失败的原因。
3.1.2客户端爱逛界面
客户端爱逛界面主要用于显示商品,在该页面的顶端会循环显示一些热门的商品的消息,然后在爱逛界面的中间有一条商品品牌的选项卡分别为:苹果,三星,小米,华为,魅族。在界面的下半部分,根据用户点击的选项卡,显示被选中的品牌该类的商品信息,显示的信息主要是商品的名称,商品的图片,商品的价格以及商品的部分简介。并且能够通过点击相应的商品信息进入商品详情显示界面对商品的详情进行查看并选择是加入购物车或者直接购买。
客户端爱逛界面显示商品列表如下:
图3-3 商品列表显示
主要代码实现:
通过解析从服务端获取的响应,将收到的商品信息存入实现创建的链表当中
将从服务端获取到的商品信息显示到ListView当中
商品详情显示界面如下:
图3-4 详情显示界面
主要实现代码:
通过从显示手机ListView的商品单项点击进入之后,将从intent获得的手机详情信息逐条对应的显示在商品详情界面上
3.1.3客户端商品分类界面
客户端的商品分类界面主要是将商品按照“屏幕尺寸”,“商品价格”以及“手机系统”分成了三类,又在每一个大类中细分了几个小类,用户可以通过以上给出的这些分类去找到自己喜欢的那一类商品,进行查看或购买。
客户端商品分类界面如下:
图3-5 商品分类界面
主要代码实现:
初始化及自定义TreeViewAdapter用来显示分类菜单
选中分类菜单后商品列表如下:
图3-6 分类商品列表
主要代码实现:
通过实例化对象Intent并调用方法Intent对象的方法getStringExtra(“categoryModel”).trim();获取代表用户选中的分类列表情况的字符串categoryModel,然后根据字符串categoryModel判断,对数据库进行条件查找,返回符合条件的集合,并将该集合所包含的商品信息在ListView当中显示出来。
3.1.4 客户端搜货界面
通过对需求的商品信息的关键字进行搜索,返回符合条件的商品列表
客户端搜货界面如下:
图3-7 客户端搜货界面
主要代码实现
通过对所输入的关键字的判断,从服务端获取相应的数据,有则将所有从服务端传回的商品信息在ListView当中显示出来,没有则显示“没有搜到符合条件的产品”。
3.1.5 客户端账户中心界面
客户端的账户中心是在用户注册并且登陆之后,用于管理客户的信息的界面,主要有管理客户的收获地址以及用户的购物车
收获地址管理界面如下:
图3-8 客户端收货地址管理界面
主要代码实现:
添加相应的收货地址,并将所添加的信息以及当前登录的用户信息传到服务端,将新增的信息录入到数据库当中。
购物车界面如下:
图3-9 购物车界面图 3-10 购物车购买商品确认界面
图3-11 购物车删除商品界面
主要代码实现
将购物车数据表当中的商品信息显示在购物车界面上,长按对应的商品可删除,并且提示是否确认删除,点击商品后面的数字上的加号可进行商品的增加,选中商品先择结算则可以进行商品的购买。
3.2服务端
3.2.1服务端文件列表
图3-12 服务端文件列表
服务端文件列表主要包括com.phoneshop.dao包,com.phoneshop.entity包,com.phoneshop.servlet包,com.phoneshop.tool包以及index.jsp和order.jsp文件。
com.phoneshop.dao包:
- OrderInfoDao.java:通过数据库获取orderinfo列表中的订单信息,并且将订单的所有信息存入到List当中;
- PhoneInfoDao.java:通过对从客户端传来的值进行数据库的搜索,查找phoneinfo表格当中的商品信息,并且将查找到的所有商品的信息存入List中;
- UserDao.java:通过对客户端传来的用户名以及密码的值,对数据库进行检索,查找shop_user表格当中是否有匹配的用户名和密码,从而判断是否能够完成注册或者登陆。
com.phoneshop.entity包:
- OrderInfo.java:定义Orderinfo类,声明该类的属性以及设置和取出属性的方法,便于实例化;
- PhoneInfo.java:定于PhoneInfo类,声明该类的属性以及设置和取出对应属性的方法,便于实例化,并且写了toString方法;
- User.java:定义了User类,声明了该类特有的属性以及设置和取出相应属性的方法。
com.phoneshop.servlet包:
- BrandServlet.java:重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的query(String brand)方法,拿到返回的含有相关商品信息的List。其中,brand参数是通过request拿到从客户端传来的参数;
- LoginServlet.java: 重写doGet和doPost方法,通过request拿到“operation”参数,判断需要进行的操作。如果是login,则获取从客户端传来的username和password参数,实例化User对象,调用User中的query(User user)方法,判断该用户是否存在,能否登陆;如果是register则获取从客户端传来的数据并进行账号注册;如果是save则获取从客户端传来的收货地址的信息并存入相应的用户表当中;
- NameServlet.java: 重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的queryByName(String phoneName)方法,拿到返回的含有相关商品信息的List。其中,phoneName参数是通过request拿到从客户端传来的参数;
- PriceServlet.java : 重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的queryByPrice(String priceLevel)方法,拿到返回的含有相关商品信息的List。其中,priceLevel参数是通过request拿到从客户端传来的参数;
- ScreenSizeServlet.java: 重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的queryByScreenSize(String screenSize)方法,拿到返回的含有相关商品信息的List。其中,screenSize参数是通过request拿到从客户端传来的参数;
- ShoppingCartsServlet.java: 重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的addToShoppingCart(String username,String phoneName,int phoneNum)方法,将从客户端传来的商品信息存入购物车表当中;
- SystemServlet.java: 重写doGet和doPost方法,实例化PhoneInfo对象,调用PhoneInfo中的queryBySystem(String system)方法,通过传入从客户端得到的system的值,得到返回的含有相关商品信息的List。
com.phoneshop.tool包:
JdbcTool.java:获取shop数据库连接的句柄,返回一个java.sql.Connection变量。
order.jsp文件:
通过获取到客户端传来的“username”参数,查找“shop_user”表,获得该用户的真实姓名,电话,以及地址,然后将获取到的信息加上从客户端收到的信息(“phonename”“ordernum”)存入订单数据表“orderinfo”中;
index.jsp文件:
服务端主页,用于显示所有的订单列表。实例化OrderInfo对象,通过调用OrderInfo的loadOrderInfo()方法,将传回的所有订单信息存入List当中,然后使用迭代器Iterator将List当中所有的订单信息逐行打印在主页上。
订单信息在服务端显示如下:
4 数据库MySQL表单设计
表4-1 用户表(shop_user)
字段名 | 数据类型 | 长度 | 约束性 | 描述 |
u_id | Int | 11 | 主键,非空 | 用户编号 |
username | varchar | 20 | 非空 | 用户名 |
pwd | varchar | 30 | 非空 | 用户密码 |
phone | varchar | 20 | 非空 | 电话 |
| varchar | 20 | 非空 | 邮箱地址 |
trueName | varchar | 20 | 非空 | 真实姓名 |
address | varchar | 20 | 非空 | 收货地址 |
表4-2 商品表(phoneinfo)
字段名 | 数据类型 | 长度 | 约束性 | 描述 |
p_id | int | 11 | 主键,非空 | 手机编号 |
p_name | text | 自适应 | 非空 | 手机名称 |
p_brand | varchar | 10 | 非空 | 手机品牌 |
p_price | int | 11 | 非空 | 手机价格 |
p_url | varchar | 20 | 非空 | 图片路径 |
p_screensize | varchar | 10 | 非空 | 屏幕尺寸 |
p_thick | varchar | 10 | 非空 | 手机厚度 |
p_timetomarket | varchar | 10 | 非空 | 上市时间 |
p_pixel | varchar | 10 | 非空 | 手机像素 |
p_cpu | varchar | 10 | 非空 | 使用的cpu |
p_netsize | varchar | 20 | 非空 | 支持网络 |
p_system | varchar | 10 | 非空 | 手机系统 |
p_describe | varchar | 10 | 非空 | 详细描述 |
表4-3 订单表(orderinfo)
字段名 | 数据类型 | 长度 | 约束性 | 描述 |
order_id | int | 11 | 主键,非空 | 订单编号 |
phoneName | text | 自适应 | 非空 | 手机名称 |
userName | text | 自适应 | 非空 | 用户名称 |
phoneNum | text | 自适应 | 非空 | 电话号码 |
address | text | 自适应 | 非空 | 收货地址 |
trueName | text | 自适应 | 非空 | 真实姓名 |
orderNum | text | 自适应 | 非空 | 手机数量 |
5 第三方库使用说明
Volley框架:Volley是android开发团队在2013年Google I/O大会上推出的一个新的网络通信框架。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。Volley的主要特点就是使用起来简单又方便,而且拥有高效的性能,主要用来进行数据量不大但又通信频繁的网络操作。本次设计作品的传输数据量都不大,因此,非常适合使用Volley框架。
使用Volley框架非常简单,只要把volley.jar这个第三方库放置到工程的libs文件夹下就能使用了。使用方法也很简单。获取到一个RequestQueue对象,可以调用如下方法获取到:
然后创建一个StringRequest对象,如下所示:
Get方法:
Post方法:
最后,将这个StringRequest对象添加到RequestQueue里面就可以了,如下所示:
6遇到问题及解决方法
开发一个作品来就不可能一蹴而就,再加上自身技术水平有限,所以在开发过程当中难免会遇到一些问题,曾经因为一个问题苦思冥想了一下午还没找到症结的所在。所幸周遭有诸多的良师益友,每次在我遇到问题时都能够热心相助,再加上我自己本身的不懈努力,一路披荆斩棘,最后终于能够拨开雨雾见天日,顺利的完成了这个设计作品。同时也非常感激这些问题所在,正是这些问题的所在,让我能够发现自己的不足,知道还有很多东西等着我学,而在解决问题的过程中也让我学到了很多新的知识。
本次开发过程遇到的问题有:
- 购物车确认购买之后,订单显示的所有商品名称一直是第一次购买的商品名称,无论购买了多少次商品,购买了什么商品。
原因:由于最初的时候没有规划好,实现代码的时候只是实现了一次加入一个订单,所以将数据的角标写死了,由于这是第一次使用第三方库Volley,所以下意识的以为错误会出在Volley相关的代码当中,直接导致后来在改动代码的时候又没有注意到这个地方,结果每次都只传第一个数据
解决办法:循环遍历List,将所有的订单信息都传到服务端
- 购买商品的时候下完订单服务端都会抛出数据库异常
原因:在order.jsp文件中,通过从客户端传来的username找到对应的用户真实姓名,电话号码以及收货地址,数据检索模块,由于认为username只可能对应数据库中的一个用户,所以就直接写了一个rs.next();没有写循环,最后查完资料才发现数据库操作中,即使只有单一组数据也需要写一个循环体,否则会抛出异常。
解决方法:写一个循环体,循环遍历返回的数据,即使返回的数据可能只有一个
- 商品列表等地方没办法显示商品的图片无论图片的路径是写同级目录或返回上级目录查找
原因:存放图片的文件夹image放在服务端phoneshop同级目录下,而调用查看图片的方法作用的范围在服务端phoneshop里面,所以即使image文件夹在phoneshop同级目录下也不能被检索到。
解决方法:将image文件夹放到phoneshop文件夹里面的webroot文件夹当中,并修改对应的文件路径。
7.总结
经过这一段时间的努力,终于把毕业设计做完了,虽然说不上完美,但毕竟是我的心血。回想当初开始制作时,真是一片茫然,不知道从何入手,于是只能边靠着感觉一边不断思考。毕竟本人才疏学浅,水平有限,在开发过程中踩过一个又一个坑,所幸有善良负责任的导师的不断答题解惑,也感谢热心的同学们鼎力相助,才使的毕业设计能够按时完成,真的非常感谢。
毕业设计是一个检验我们学习成果的重要平台,通过毕业设计,将我们大学所学习的知识串联在一起。在开发过程中,既巩固了基础也培养了学以致用的能力,同时也为进入社会寻求一份满意的工作做了一定的热身。毕业设计是一个从无到有的过程,从一开始的一片空白到构思出想要的功能,在思考实现方法,到动手实现过程都是自己一个人完成的,锻炼了自己独当一面的能力,学会以一个大局观思考问题。
毕业论文的完成,也标准着大学生涯的已经接近尾声。回想第一次来到大学,看到美丽的大学,富有活力的同学,那份喜悦仿佛还在心头。现在,忽然要毕业了,心中还是有诸多不舍,不舍美丽的校园,,不舍敬业的老师,不舍可爱的同学,不舍藏书丰富的又玄图书馆,不舍食堂可口的饭菜,太多太多,但是作为一个人就要做那个年龄段该做的事,我会用学习带来的知识,品格践行到工作,践行到生活,践行到方方面面,做一个有所用的人。
8.致谢
在论文结束之际,我要感谢我的指导老师陈家祯老师,谢谢陈家祯老师在开题报告选题、题目审核、以及在分析题目可行性上给予我耐心合理的指导,在我遇到问题时孜孜不倦的答题解惑。
感谢我敬爱的父母二十多年含辛茹苦的养育我,在读书这条路上无论多大的困难都在背后默默支持着我。
感谢学校在这大学四年来给予我诸多支持和帮助,提供如此舒适的生活学习环境,安排如此多的优秀负责任的老师教导我们
感谢同窗好友大学四年的陪伴与支持,在我需要帮助的时候提供的所有帮助我都熟记于心,感谢你们每一次的体谅和支持。
感谢大学每一个为我们提供服务的人,没有你们,我们无法在一个如此舒适干净而又便利的大学快乐的学习知识,谢谢你们。
最后,需要感谢自己,感谢自己能够坚持着一步一步走过来,无论遇到什么样的挫折都没有轻言放弃。
参考文献
[1] 李清华,王月清.Java Web开发实战经典基础篇(JSP、Servelt、Struts、Ajax).北京:清华大学出版社,2010,1-245.
[2] 郭霖.第一行代码.北京:人民邮电出版社,2014,1-552
[3] 徐宜生.Android群英传.北京:电子工业出版社,2015,10-332
[4] [美] Bill Phillips,[美]Brian Hardy.Android权威编程指南.北京:人民邮电出版社,2014,1-263
[5] 任玉刚.Android开发艺术探索.北京:电子工业出版社,2015,32-355
[6] 李刚.疯狂Android讲义.北京:电子工业出版社,2011,1-400
[7] 常倬林.Java Web从入门到精通.北京:机械工业出版社,2011,100-203
[8] 刘京华.Java Web整合开发王者归来.北京:清华大学出版社,2010,5-331
[9] 刘伟,张利国.Java Web开发与实战.北京:科学出版社,2008,20-100
[10] 李兴华,Android开发实战经典.北京:清华大学出版社,2012,1-154
其他的定制服务 下方联系卡片↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 或者私信作者