本次设计的是一个校园二手交易平台(C2C),C2C指个人与个人之间的电子商务,买家可以查看所有卖家发布的商品,并且根据分类进行商品过滤,也可以根据站内搜索引擎进行商品的查询,并且与卖家联系,达成交易的意向,也可以发布求购的信息,让卖家查看之后,与之联系,进行交易。而此次主要是针对校园用户所设计的网站,对于数据的分类应该更多的考虑校园用户的需求,例如二手书籍、二手数码等的分类应该更加细致。本次设计的主要难度在于数据的详细分类,对于数据的过滤必须要严谨,应当考虑敏感字体和敏感图片的过滤。
可能遇到的问题有,在数据交互过程中,出现由于属性名的差距导致的数据交互失败。由于Css属性设置的问题,导致界面不完整等等。设计的算法都是自己编写的,可能存在不是最优算法的情况。
每个手机号码只可以注册一个账号,并且通过账号完善个人信息和浏览商品,发布商品等,注册时需要通过手机号码获取验证码进行验证才能注册。
商城主要显示总的商品信息,并且可以通过侧边栏点击进行信息过滤。商品点击之后可以查看详细信息。
实现本站内特有的搜索引擎,可以输入字段,模糊查询合适的商品并且显示出来。
根据需求输入相应的信息,发布求购商品。
卖东西的用户,也可以通过求购商城查看是否有用户对自己拥有的二手物品有需求,查看详细的需求,有的话可以跟买家联系进行交易。
卖家可以发布二手商品的信息,对商品进行描述,并且添加图片增加可信度,也方便买家查看相应的信息。
将想要的物品添加到购物车,可以修改数量,选择是否要支付,移除商品。选择收货地址,并且进行结算。
用户发表求购信息和发布商品时需要先进行信息的完善,用户可以查看自己发布的商品,对发布的商品进行修改或删除,查看已发布求购信息,对求购的商品进行修改或删除。
系统的整体结构流程图如下
负责显示热门的商品信息,以及显示本网站的网站信息,导航栏负责跳转到各个页面,没有登录显示按钮可以让用户进行登陆和注册。已登录的用户显示用户名,并且可以发布商品信息,查看个人信息等。进入首页的时候,通过Ajax获取数据库中存在的热门商品数据集合,并且刷新页面的内容,点击商品之后跳转到商品详细信息模块。
首页的前端设计大体如下
顶部实现导航栏,导航栏包括网站logo支持点击之后返回到首页、输入框和按钮负责站内搜索引擎的实现、以及一个span包裹的数据,当有用户登陆时将它替换为用户名,没有用户登录时,则将它设置为登录注册按钮,方便用户进行登录和注册。用户登陆之后,显示出来的用户名可以通过绑定鼠标进入事件,弹出选择框让用户选择相应的操作,例如显示个人信息、查看发布的商品、查看求购的商品、发布商品、发布求购商品信息。导航栏与其他页面共用。
显示热门商品信息,采用轮播图实现,主要是先定义一个顶级的div指定position是绝对位置,将除了当前显示的页面之外的轮播图div都隐藏起来,为当前的div添加一个current类,判断点击的方向,如果是右则先获取到current的下一个div,并且将它准备在右侧等候进入,当前的div移出之后,就将下一个进入,并且删除原来的current类,将它添加给新的div。在此过程中控制动画,就可以实现一个精美的轮播图。
其他部分实现效果
负责显示所有的二手商品,提供类别的侧边栏给用户点击之后显示对应的商品信息。类别侧边栏的实现后,需要为每一个类别的元素都添加一个id,通过id来获取数据库中的数据,用Ajax获取数据并且刷新页面的信息。采用分页技术,防止数据过多的时候,显示在同一个页面,给用户带来不好的体验,分页支持点击下一页上一页或者直接点击指定页面,跳转到指定的页面。商品点击之后就要跳转到商品详情。
二手商城前端实现
主要是设计侧边栏比较有难度,首先获取后台返回的三级类别,并且将顶级类别显示在侧边栏中,当鼠标移动上去的时候,显示其余两级目录,显示次级目录作为标题,而第三级的目录则是可点击的按钮,点击之后显示相应类别的商品信息。
商城商品展示
其次是底部分页按钮的实现,左右切换需要通过jQuery来控制,下一页则判断是否已经到达当前显示的页数倒数第二个,如果是就删除第一个页数,并且添加下一页的页数(前提是还有页数可以继续),如果不是倒数第二个,就将当前元素的current类名删除并将它赋给下一个元素。
负责显示指定的商品详细信息,包括图片、名字、价格、数量等,当一个商品被点击之后,通过返回的id查询到这个数据集合,跳转到商品详细信息的页面,商品发布者可以在下方查看留言,并且与有意者打成交易意向。将对应的信息显示出来,并且提供加入到购物车的功能。商品详细信息下方显示其他用户的留言,并且已经登录的用户可以对这件商品进行评论,商品发布者可以在下方查看留言,并且与有意者打成交易意向。商品发布者可以在下方查看留言,并且与有意者打成交易意向。
显示商品的详细信息,并且添加可以留言的模块,用户发表留言之后,会在下方的留言板通过ajax进行实时的刷新。
留言
每一个页面顶部都存在一个搜索输入框,用户通过输入模糊的商品信息,后台数据库通过查询过滤相关的商品信息,并且显示出来给用户查看,显示出来的商品点击之后可以显示商品的详细信息。
搜索结果
用户输入指定的信息,以及选择商品的图片,之后将这些信息结合当前登陆的用户,通过Ajax发表到后台,并且通过框架存储数据到数据库指定表。
三级联动的实现,用Ajax获取到三级的类别JSON数据,之后解析JSON数据,将第一级的添加到第一个下拉框,第二级的添加到第二个下拉框,第三级的添加到第三个下拉框,当第一个或者是第二个发生改变的时候,通过获取父容器的子集合修改后两级或者一级的下拉框内容,用jQuery的html替换即可。
点击图片后显示缩略图,需要先采用一个file的input,获取到file的文件集合,并且获取它的网页缓存地址,获取后将它设置到img的src中,可以添加一个渐变的动画效果,给用户带来更好的视觉体验。
用户输入指定的信息,以及选择商品的图片,之后将这些信息结合当前登陆的用户,通过Ajax发表到后台,并且通过框架存储数据到数据库指定的求购信息表。三级联动采用前一个的即可。
显示个人信息,例如用户名、真实姓名、宿舍号、学号等,显示之后还需要支持对于数据进行修改,修改之后,要同步修改页面的信息,这需要用到Ajax进行数据的提交,并且进行页面的局部刷新。
所有信息采用jQuery的EasyUI中的accordion显示,标题显示信息,而底部内容则显示修改的组件,之后Ajax修改具体信息后需要将对应的新的内容,采用jQuery显示到标题中。
显示个人发表的商品信息,支持点击之后对数据进行修改,例如修改商品名字,修改商品的单价和数量等,修改之后将新的数据提交到数据库,数据库执行相应的修改操作,也可以直接下架某件商品,点击删除按钮之后,直接在后台数据库删除这一件商品,并且刷新当前页面上显示的个人发布的商品。给用户带来更好的体验效果。
点击修改
显示个人发表的求购商品信息,支持点击之后对数据进行修改,例如修改商品名字,修改商品的单价和数量等,修改之后将新的数据提交到数据库,数据库执行相应的修改操作,也可以直接下架某件商品,点击删除按钮之后,直接在后台数据库删除这一件商品,并且刷新当前页面上显示的个人求购的商品。
显示用户加入购物车的商品,计算总的价格,提供全选和取消全选的按钮,从后台获取商品的单价,判断当前剩余的数量,当用户点击数量添加或者减少之后,对于总价要实时刷新,采用jQuery对数据进行修改,当用户取消选中其中的某一个商品,要相应的减少价格并且刷新,提供选择收货地址,对收获地址进行管理,选好收货地址之后,结算购物车,弹出支付页面,让用户选择付款方式,并且提交。
点击添加数量和减少
用户通过手机号码和密码进行登录,登录之后显示首页。当用户没有账号的时候,提示用户进行注册,从登录界面切换到注册界面,注册需要通过手机号码获取验证码,后台通过页面传递的手机号码,随机生成4位数的验证码并且缓存,之后通过发送139邮箱的方式发送到指定的手机,手机收取到验证码之后输入验证码提交,判断是否正确,正确则注册成功,失败则注册失败。用户注册完之后直接跳转到首页。
登录界面需要4个页面,第一个是登录界面,显示手机号码和密码的组件,并且需要底部添加注册按钮,以及忘记密码。第二个是注册界面,注册界面首先提供用户输入手机号码以及验证码,获取验证码的按钮,获取之后跳转到下一步,也就是输入密码界面。输入密码界面需要两次确认密码,输入确认之后就是跳转到首页。最后一个界面是忘记密码,同样通过输入手机号码获取验证码即可。之后将这四个界面通过CSS3的transform属性,将四个界面组合成一个立方体,当用户点击切换到各自界面的按钮时,就采用transform的rotateY,将切换的效果实现成立体翻转的效果。
先在数据中创建名为c2c的数据库,使用Navicat for MySQL运行 c2c.sql文件创建表和导入数据
将图片解压到任意一个盘,然后配置Tomcat,将图片路径引用到本地配置的图片路径下。
用户信息表
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Username | Varchar(50) | 否 | 用户昵称 |
Phone | Char(11) | 否 | 用户手机号码 |
realName | Varchar(20) | 是 | 用户真实姓名 |
Clazz | Varchar(20) | 是 | 用户所在班级 |
Sno | Char(12) | 是 | 用户学号 |
Dormitory | Varchar(20) | 是 | 宿舍号 |
Gender | Char(2) | 是 | 性别 |
Createtime | Datetime | 是 | 创建时间 |
Avatar | Varchar(200) | 是 | 头像 |
用户密码表
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Password | Varchar(24) | 否 | 用户密码 |
Uid | Int | 否 | 用户id |
商品表
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Name | Varchar(50) | 否 | 商品名称 |
Level | Int | 否 | 商品成色 |
Remark | Varchar(255) | 是 | 商品详细信息 |
Price | Decimal(0.00) | 否 | 商品价格 |
Sort | Int | 否 | 商品类别 |
Count | Int | 否 | 商品数量 |
Display | Int | 否 | 商品是否被下架 |
Transaction | Int | 否 | 交易方式 |
Sales | Int | 否 | 商品销量 |
Uid | Int | 否 | 发表的用户id |
Image | Varchar(255) | 否 | 商品的图片地址 |
商品留言
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Sid | Int | 否 | 商品的id |
Content | Varchar(122) | 否 | 留言内容 |
Display | Int | 否 | 是否可见 |
Uid | Int | 否 | 评论的用户id |
我的收藏
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Sid | Int | 否 | 商品的id |
Display | Int | 否 | 是否可见 |
Uid | Int | 否 | 评论的用户id |
求购商品
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Name | Varchar(50) | 否 | 求购商品名称 |
Remark | Varchar(255) | 是 | 求购商品详情 |
Price | Decimal(0.00) | 否 | 求购商品价格 |
Sort | Int | 否 | 求购商品类别 |
Count | Int | 否 | 求购商品数量 |
Display | Int | 否 | 信息是否被删除 |
Transaction | Int | 否 | 交易方式 |
Uid | Int | 否 | 发表的用户id |
Image | Varchar(255) | 否 | 商品的图片地址 |
求购商品留言
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Qid | Int | 否 | 求购商品的id |
Content | Varchar(122) | 否 | 留言内容 |
Display | Int | 否 | 是否可见 |
Uid | Int | 否 | 评论的用户id |
我发布的商品
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Display | Int | 否 | 是否被删除 |
Uid | Int | 否 | 用户id |
Sid | Int | 否 | 对应商品id |
我求购的商品
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Display | Int | 否 | 是否被删除 |
Uid | Int | 否 | 用户id |
Qid | Int | 否 | 求购商品id |
已购买的商品
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
State | Int | 否 | 商品当前的状态 |
Uid | Int | 否 | 用户id |
Sid | Int | 否 | 商品id |
Quantity | Int | 否 | 商品数量 |
购物车
字段名 | 字段类型 | 是否可为空 | 备注 |
---|---|---|---|
Id | Int(11) | 否 | 主键 |
Modify | Datetime | 是 | 修改时间 |
Display | Int | 否 | 商品是否被删除 |
Uid | Int | 否 | 用户id |
Sid | Int | 否 | 商品id |
Quantity | Int | 否 | 商品数量 |
1. 总述:本次后台使用的编程语言为Java,使用的框架是Spring+SpringMVC+Mybatis,前端网页渲染的语言不使用JSP,而我选择使用的是thymeleaf框架,
原因如下:
a. thymeleaf可以直接渲染出HTML5和CSS3的效果。
b.前端写的网页合并到后台处理的时候不需要转换成jsp页面,方便快捷。
c. thymeleaf可以很方便的解析后台传输到前端的值。
d. thymeleaf,我个人认为是个比较好的模板,性能也比一般的,比如freemaker的要高,而且把将美工和程序员能够结合起来,美工能够在浏览器中查看静态效果,程序员可以在应用服务器查看带数据的效果。
e. thymeleaf是一个支持html原型的自然引擎,它在html标签增加额外的属性来达到模板+数据的展示方式,由于浏览器解释html时,忽略未定义的标签属性,因此thymeleaf的模板可以静态运行。
2. 后台结构总图
java:存放Java代码
bean:用于序列化到前端,然后解析的实体类。
controller:spring和springMVC的控制器,用于处理请求的链接
dao:,和数据库进行交互
pojo:普通的Java实体类
service:定义接口,用于连接controller和dao
token:生成唯一标识,用于防止用户重复提交。
tool:工具类,例如处理文件,文本敏感词过滤,图片色情鉴别等等。
resources:存放资源文件,例如Mybatis生成的xml文件,spring,springMVC,mybatis配置文件等等
css:网站样式
img:网站部分图片
js:JavaScript文件
templates:网站html文件
3.后台实现了一个只能单用户登录的功能:如果有两个用户使用同一个账号分别登录,那么后一个登录的用户会踢掉第一个用户登录的账号,也就是说先登录的用户会被强制退出。实现细节:主要使用的是websockt和spring websockt。首先前端判断用户有没有登录,如果有登录的话,就将用户的手机号码,当前时间发送到后台,后台接收到信息,解析信息,将信息存储到Map中,前台循环提交这些信息,并判断Map中手机号码对应的时间是否相等,如果不相等,证明有其他用户登录了该账号,后台发送下线信息到前端,前端收到信息后,触发退出当前账号事件。
4.常规数据库增删查改:考虑到密码是重要的信息,所以当操作密码的时候,都是先使用MD5对其进行加密后处理。例如修改密码,注册用户等等。各个数据表之间的关联都是通过逻辑处理进行数据联系的。
5.防止用户重复提交:在每个界面,都会由后台生成一个token,然后前端页面存储该token,如果用户进行提交按钮等事件时,就会连这个token一起发送到后台进行处理,后台若获取不到token或者token不相匹配,那么就判定该用户重复提交这个事件,后台直接返回原本页面。
6.敏感词过滤:管理员将敏感词编入到数据库中,用户发布商品时附带的商品名称,商品备注等等,都会被过滤,将其中的敏感词替代成**。然后返回对应的数值。用户在填写商品名称,详情的时候,还会ajax自动和后台进行验证判断,并实时提醒用户有没有输入敏感词。
7.图片色情鉴别:使用的是百度的百度开发者平台中的色情图片识别功能。通过提交一张图片到百度的这个功能中,该项目功能就会返回一个数字,姑且称该值为色情值,如果该色情值超过一个给定的数值,那么就可以判定该图片为色情图片,如果用户上传的是色情图片,那么就无法插入,修改,后台会直接返回一个错误值给前端,提示使用了非法的图片。
4.1 在实现只能单用户登录的时候,由于是第一次编写,以前没有经验,刚开始的想法是设计2个Map(m1,m2),用于存储前一次登录(m1)和再次登录(m2)的手机号码和对应的时间。首先,当用户第一次登录的时候,m1和m2必定都为空,m2先通过手机号码存储当前的时间,然后前端通过websockt发送定时信息过来请求判断,在后台处理前端发送过来的信息的时,先判断m1是否存在m2中该的该手机,如果不存在,则证明为第一次登录,那么m1存储m2中对应手机的对应时间。如果存在,那么将m1中时间和m2中的时间进行比较,若比较结果一致,是单用户登录;若不一致,该手机为前一次登录,强迫下线。当用户再次登录的时候,m2中存储手机对应的当前的时间,那么前一次登录的时候m1中存储的手机对应的时间必然小于再次登录中m2中存储的时间,此时,前一次登录强迫下线,m1中的时间刷新为m2中对应的时间。但是这个思路出现了一个严重的问题,在测试的时候,首次登录后,第二次登录确实会踢掉第一次登录,但是第三次登录的时候,所有的用户都平安无事,不会互相排挤,此时出现的问题应该是线程不安全导致的结果。m1,m2这2个map都可能会出现这种情况。
解决方法:设计一个Map(m),用于存储手机号码和其对应的时间。首先,用户登录后,将当前的时间,手机号码通过websockt发送到后台,后台进行判断处理,如果发送过来的时间和m中存储的时间进行比较,若一致,证明没有其他用户登录,若不一致,证明其他用户登录过,那么当前这次用户就会被迫下线
4.2 设计的工具类中,因为存在很多个类和包,如果没有使用工厂模式进行设计的时候,那么在启动项目的时候,多用户登录时,就会导致线程不安全或者线程堵塞,并且将类中的所有方法声明为static时,会占用了许多的内存。
解决方法:使用静态工厂模式-静态内部类。将所有的工具类集中到一个总类中,然后为给总类设计一个静态内部类,其他将要调用的方法设计为public非静态方法,如果调用的时候用工厂调用就可以了。
4.3 当使用多个参数通过mybatis获取数据库数据时,出现了参数未定义的情况,这是因为多个参数的时候,要将这些参数封装为一个Map。
解决方法:将多个参数封装为一个Map,然后将该Map作为参数传递给mybatis的处理方法。
4.4 发送手机验证码出现的错误:一开始像使用邮箱验证用户的,但是在通过邮箱给用法发送信息的时候,这个时候就有多个邮箱作发送者供选择-QQ,163,127,sina等等。原先使用的是163邮箱进行发送信息,但是由于发送的内容过于少,被系统认定为垃圾邮件不给发送或者接收。其他邮箱也类似。后来感觉使用邮箱发送验证码已经被淘汰了,现在流行手机验证了,所以改为发送手机验证码。但是手机发送验证码的话,不想使用网上别人提供的服务,打算自己写一个,关键是怎么将验证码发送到手机上。
解决方法:将验证码发送到139邮箱上就可以了,一般的手机用户都会默认绑定139邮箱的,如果139邮箱收到信息,那么就会通过发送短信的形式提示到对应的手机上,这样就可以实现手机验证码的发送了。
4.5 前端使用Ajax局部刷新时,有可能会导致新显示的内容无法绑定点击事件,最终导致在点击相应的按钮(例如加入购物车按钮)时,页面没有反应。
解决方法:在Ajax的for循环显示结果内容后,为按钮等绑定相应的事件。这样就可以解决该问题。
该C2C校园二手交易平台,界面简洁明了,能给用户一种美的视觉上的享受。并且操作简单易懂,可以大胆但是毫不夸张的说,本系统适用于99%的青少年愉快的使用,对于不是很了解智能科技的人来说,只要看看就基本可以掌握然后熟练的使用该系统了。并且本系统的动画效果做得非常的完美,前端工作人员争取使用最少的代码实现最炫酷的动态效果,例如3D页面转换,动态加入购物车效果,搜索的时候动态自动提示商品名字功能等等,无一不是本系统的亮点。由于前端本着使用最少的代码,实现最炫酷的动态效果,所以其性能可以来说是杠杠的。并且前端所构建的网站为响应式网站,当页面的大小发送变化的时候,页面会随着变化,但是我们的变化不会出现任何的纰漏。在兼容性方面,本网站可以完美的兼容ie8+,Firefox8+,chrome6+等等,虽然目前比较少用户使用这些版本以下的浏览器,但是要做的话,我们就要力争做到完美,前端人员通过查询资料,目前可以最完美的兼容上诉浏览器的以下版本。
前端页面缺点:对于那些不兼容HTML5和CSS3的浏览器,使用的是JavaScript来动态实现这些3D效果的,所以可能展示的效果不如支持HTML5和CSS3的本身效果好。对应浏览器版本真的是过低的用户,无法完美的显示本系统的动态网页。JavaScript实现的那些动画效果可能存在某些目前未知的bug,导致性能上的加载可能会出现瑕疵。
后台实现的优点:后台为了提高性能,使用了一些目前属于比较好的设计模式,例如工厂方法模式,代理模式,备忘录模式,单例模式等等。数据库表的设计思想主要是参考阿里巴巴的开发手册进行设计的,在性能上,建立了适当的索引,增强了查询速度,并且自己设计了许多的算法对后台数据的处理进行优化等等。本来想使用集群和分布式来实现后台,但是考虑到现在如果使用集群,分布式来实现,那么开发周期得提升不止一个档次的时间。
网站加载图片的时候,通常耗费的主要流量和影响速度的原因之一就是这个,所以后台设计了一个比较有意思的算法对图片进行适当的压缩,在前端显示的时候,主要显示的压缩后的图片,当鼠标移到图片上的时候,那么通过ajax显示未被压缩过的图片的放大版。这样,既可以节省带宽,又可以提高用户的体验。
为了防止XSS攻击,可以使用消毒和HttpOnly防止该现象;对于注入攻击,使用的方法为错误回显,盲注,参数绑定;对于CSRF攻击,可以使用表单token,验证码和Rererfer check。
对于密码,手机号码,真实信息等等敏感信息,通常都需要对其进行信息加密,我使用的是单向散列表加密和对称加密,还有就是使用公钥密钥配对核实认证。但是如果使用到密钥的话,那么一般会要求用户下载安全证书到本机。
信息过滤和反垃圾是目前一个比较主流的问题。我使用的主要是文本匹配来过滤敏感词的。当用户发布的信息很长的时候,使用的过滤算法是双数组Trie算法进行敏感词过滤,该算法利用两个稀疏数组存储树结构,base数组存储Trie树的节点,check数组进行状态检查。该算法需要根据业务场景和经验确定数组大小,避免数组过大或者冲突过多。
简而言之,前端效果简洁炫酷,操作简单易懂。
没有实现的功能:秒杀系统,前端反向代理,CDN加速。
[1] 李智慧. 大型网站技术架构 核心原理与案例分析[M].北京,工业机械出版社,2013.
[2] 马丁著 韩磊译.代码整洁之道[Clean Code A Handbook of Agile Software Craftsmanship] [M]. 北京,人们邮电出版社,2010.
[3] Craig Walls 著 张卫滨译. Spring In Action[M]. 北京,人民邮电出版社,2016
[4] Thomas H.Cormen , Charles E.Leiserson, Ronald L.Rivest, Clifford Stein著,徐云,王刚等译. 算法导论(原书第3版)[M]. 北京,机械工业出版社,2015
[5] Joshua Bloch 著 杨春花 俞黎敏 译. Effective Java(Second Edition) [M]. 北京,机械工业出版社,2016
[6] 本·弗莱恩(Ben Frain)著奇舞团 译. 响应式Web设计 HTML5和CSS3实战(第2版)[M]. 人民邮电出版社,2017
[7] 达科特(Jon Duckett) 著 刘涛,陈学敏 译. JavaScript&jQuery交互式Web前端开发[M]. 清华大学出版社,2015
[8] NicholasC.Zakas著 李松峰曹力 译. JavaScript高级程序设计(第3版)[M]. 人民邮电出版社,2016