一、环境搭建
1、准备
(1)开发工具
- 编译器:IntelliJ IDEA 2018.3.5
- 数据库管理系统:mysql
- 服务器:tomcat9
- 数据库可视化界面:sqlyog
- 代码管理工具:svn
- 项目管理工具:maven
(2)新建maven项目
并在pom.xml配置文件中导入基本的依赖,后续在使用的过程中导入其他的依赖。
(3)添加项目到svn
在服务器端新建一个仓库,并将IDEA中新建的项目进行提交
(4)配置spring
- annotation.xml:扫描注解,只扫描service层的注解,dao层由mybatis管理,controller层由springmvc管理
- jdbc.xml:读取jdbc的配置文件的数据,获取dataSource
- jdbc.properties:jdbc的配置文件
- property.xml:读取jdbc配置,这样配置的好处是list中可以配置多个配置文件的读取
- transation.xml:配置事务、开启事务注解
- mybatis.xml:扫描dao层的注解、获取sessionFactory
- application-context.xml:引入以上关于spring的配置文件
(5)springmvc
- springmvc-back.xml:扫描controller层的包、视图解析器(后台)、配置springmvc支持上传图片
- springmvc-front.xml:扫描controller层的包、视图解析器(前台)
- web.xml:配置springmvc的前端控制器、引入spring的核心配置文件、spring的监听器、处理中文乱码的过滤器
二、后台
1、景点分类信息
(1)显示全部类别
显示全部的分类信息实际上是一个带有条件的分页查询,条件为类别的名称,分页的参数为起始行和每一页的大小。
在dao层需要执行一个带有条件的分页查询获取符合条件的分类的信息,还需要获取分类的总记录数将获取到的数据作为service层pagination的参数,pagination还需要页号、每页数作为参数
在service层pagination获取到以上三个参数后就创建成功了,然后将查询到的分类数据写入到pagination对象中。
在controller层会将页面提交的条件:页号和分类的名称封装到分类对象里面作为参数传递到service层,并获取到pagination对象,将路径和参数作为pagination的参数
页面中直接遍历pagination,进行分页显示;遍历pagination里面的list(分类信息),将分类信息显示在页面上
(2)图片上传
配置springmvc支持上传图片
搭建图片服务器,也就是说需要一台专门存储上传的图片的服务器:https://www.cnblogs.com/zhai1997/p/13337064.html,在服务器的webapp目录下创建文件夹作为图片存储的根目录
图片的上传采用的是Jersey(需要导包),利用该框架上传图片需要该图片的完整路径
由于需要避免图片的重名,采用当前时间加随机数拼接的方式来生成图片名称,将名称与获取到的扩展名、服务器地址和存储图片的目录进行拼接即可得到图片的完整路径
在页面的input标签内将name属性定义为pic,controller层获取到该属性,可以根据pic获取图片的后缀
提交图片是用的jQuery Form插件,它是一个优秀的Ajax表单插件,可以非常容易地、无侵入地升级HTML表单以支持Ajax。将图片提交到controller后,通过回调函数获取到图片的全路径和图片在服务器内部的地址(改地址将被存储到数据库),将图片的全路径赋给src属性进行图片的显示,图片在服务器的地址写在隐藏域。
(3)添加景区分类
在controller层获取到表单数据,最终执行insert语句将数据持久化到数据库。然后重定向到分类显示页面显示分类信息
(4)删除一个分类
删除的时候需要携带被删除的分类的id(用于确定分类并删除),分类的名称(运用jq获取到输入框中分类的名称)两个参数。将参数传递到controller层,分类名在重定向之后会重新显示到页面上,id则最终被传递到dao层根据id删除分类
(5)删除多个分类
要先实现多选的复选框,保证一次可以选中多个要删除的分类信息
删除的时候用到提交图片是用的jQuery Form插件,要确保要删除的元素在form表单内部。在提交的时候被选中的复选框的值(值是分类的id)将被提交到controller,并将分类的名称作为参数携带到controller层,分类名不为空的时候要进行回显,将被选中的分类的id作为参数最终传递到dao层,在dao层采用foreach标签取出数组中的数据
(6)修改
分为两步:
- 去修改页面,在页面中需要向controller传递被修改的分类的id,根据id获取到分类对象后在修改页面进行该分类的信息的回显。其中被修改的分类的id要写在隐藏域内,因为执行修改的sql语句需要借助于id对分类进行修改
- 填写相关信息后将表单提交到controller中,并将分类对象传递到dao层执行根据id修改分类信息的语句
2、景区信息管理
(1)显示全部景区信息
与分类信息相比,对sql语句进行了优化,如:查询的时候根据字段是否为空来确定是否查询此字段,通过减少字段的查询提高系统的执行效率,避免了对全表进行查询;通过mybatis的sql标签将sql语句封装为单独的模块,使用的时候根据id调用该模块,可以减少代码的冗余。
(2)景区描述
通过fck上传景区相关的图片,通过页面请求controller层的方法对图片进行处理,fck是支持多个图片的上传的
(3)添加景区
在页面获取到用户输入的信息,提交后传递到controller层直接封装为model不用手动获取参数在进行分装,这也就体现出了springmvc相比于传统的mvc模式的优势
由于景区的有一些属性的值不是单一的,例如:门票属性分为儿童票、成人票等。为了能够唯一确定一个景区的某一用户的票就需要使用sku,即景区的最小存储单元。在service层添加景区的时候还要添加景区的最小存储单元。
三、前台
主页面显示、景区详情、支付模块
(1)显示大分类、小分类、景点
大分类(国内、国外等)、小分类(踏青、展馆、游乐场、文化古迹、动植物园、历史名城等)景点,是采用的foreach标签的的嵌套来进行显示的,其中景点的显示是由大分类的ID和小分类的ID共同决定的
采用分页查询,每一个大分类下的小分类是采用的分页查询,为了页面的美观和用户友好性只显示八个景区的信息。
为了解决访问网站首页的空指针问题,需要在访问首页的链接中添加大分类和小分类的参数,因为采用是onclick事件,而首次加载的时候并未点击任何的分类,因此需要在初始化的时候传递参数。如果没有初始化参数,获取景区的条件查询没有查询的条件就会出现空指针异常。
(2)更多景点信息
根据景区大分类的ID(国内、国外、周边游)获取景区的信息,即:获取某一个大类的所有景区信息并展示
(3)查看某一景点信息
根据景点ID查询景点信息和该景点的门票信息
(4)门票预定
需要获取景点和门票信息进行展示,并获取购票者的信息写入到数据库中
(5)支付模块
运用的是支付宝的沙箱环境,只是模拟付款流程
注册模块
(1)邮箱注册
使用js的validation表单校验插件来在页面对输入的邮箱、密码、验证码进行格式、非空、长度等的校验
将用户的邮箱、密码、用户状态(初始值为0)、激活码写入到数据库后,会发送一个邮件提醒用户点击链接激活账户,该链接是访问controller层的方法,根据激活码来更新激活码对应的用户的状态(激活后为1)
(2)手机注册
采用的是手机号注册,获取注册的时候输入的手机号,并向这个手机号发送激活码,工具类负责激活码的发送,在service层将激活码与手机号拼接,在controller层再分别取出手机号与激活码,目的是保证注册的手机号与工具类发送激活码的手机号是同一个。所有的验证都正确的情况下将该账号的状态设置为1,并将用户的注册信息写入到数据库。
注册页面点击获取激活码其实是发送ajax请求,请求参数是手机号,返回值是发送激活码是否成功的布尔值。点击的同时开始60s倒计时,防止用户一直获取激活码。
手机验证的原理是:工具类根据用户输入的手机号向该手机号发送验证码,并且工具类会返回验证码。在service层将激活码与手机号拼接,在controller层再分别取出手机号与激活码,目的是保证注册的手机号与工具类发送激活码的手机号是同一个。如果controller层从session中获取到的验证码与从表单接收到的验证码是一致的则证明验证成功,否则,用户需要重新输入。
登录模块
登录模块分为手机号登录与邮箱登录,采用邮箱/手机号+密码+图片验证码的方式进行,图片验证码可以防止黑客对用户账号的暴力破解。
优化:
1、freemarker的应用
在后台景区管理处有景区静态化的按钮,点击后前台的景区详情页就是访问的静态页面(html),减少了前台的数据库的访问,但是存在一个问题就是当对景区修改后存在静态页与数据库中的数据不一致的问题,此时就可以点击按钮对已经存在不一致的景区进行手动的静态化,使得数据保持一致。
使用freemarker需要先导入相应的依赖,然后就是创建模板对象、获取数据,由模板对象和数据就可以生成目标对象了(html页面),这里是使用景区的ID与景区的分类ID获取到景区信息河景区的门票信息,然后是根据模板生成静态页面,前台访问静态页面即可。
2、sql语句
- 只对需要的字段进行查询
brandQuery.setFields("bid,bname");//传递分类的字段
取出需要查询的字段并执行查询操作:
<sql id="scenicspotSelector"> SELECT <if test="fields != null"> ${fields} </if>
- 进行字段的非空校验,如果字段为空就不会对该字段进行查询
<if test="sid != null"> and sid=#{sid} </if> <if test="description != null"> and description=#{description} </if> <if test="location != null"> and location=#{location} </if>
否则将导致引擎放弃使用索引而进行全表扫描
- mybatis的sql标签进行语句的模块化封装,实现了XML文件中sql语句的复用
<select id="getScenicSpotListWithPage" parameterType="com.zhb.core.query.scenicspot.ScenicSpotQuery" resultMap="scenicspot"> <include refid="scenicspotSelector" /> <include refid="scenicspotListWhere" /> <include refid="scenicspotListLimit1" /> </select>
3、使用单独的服务器来存储图片,减少主服务器的压力