店铺编辑和列表功能
店铺信息的编辑
dao层开发
在对店铺信息编辑之前需要获取店铺原先的信息,更新的接口之前已经实现,这里需要创建一个查询接口

在mapper里实现queryByShopId这个方法,这个方法不止返回shop,还返回area,personinfo,shopcategory,可以根据shop表里的area_id,personinfo_id,shopcategory_id分别取获取。那么再mapper里面我们需要设置一个resultMap去接收这几张表联合起来的返回值。
column是数据库字段名,property是成员变量名

定义复合类型

返回类型定义好之后再编写select语句
<select id="queryByShopId" resultMap="shopMap" parameterType="Long">
SELECT
s.shop_id,
s.shop_name,
s.shop_desc,
s.shop_addr,
s.phone,
s.shop_img,
s.priority,
s.create_time,
s.last_edit_time,
s.enable_status,
s.advice,
a.area_id,
a.area_name,
sc.shop_category_id,
sc.shop_category_name
FROM
tb_shop s,
tb_area a,
tb_shop_category sc
WHERE
s.area_id=a.area_id
AND
s.shop_category_id=sc.shop_category_id
</select>
我们的表设置得很合理,这里并未出现重名的字段,如果出现重名的字段会有什么影响,比如说上面的s.priority,如果我们也要取这个a.priority,这样就会出现重名,这时候a.priority取出来的就不是a.priority实际的值而是s.priority的值,这种情况可以使用别名解决,a.priority AS area_priority,我们表设计合理,所以没有重名的情况出现。
接着测试,我们之前已经测试过了update,把update测试加上@Ingore

实现service层
/**
* 通过店铺Id获取店铺信息
*
* @param shopId
* @return
*/
Shop getByShopId(long shopId);
/**
* 修改店铺信息包括图片处理
*
* @param shop
* @param shopImgInputStream
* @param fileName
* @return
* @throws ShopOperationException
*/
ShopExecution modifyShop(Shop shop, InputStream shopImgInputStream, String fileName) throws ShopOperationException;
@Override
public Shop getByShopId(long shopId) {
return shopDao.queryByShopId(shopId);
}
主要是第二个,需要先编写一个工具类,一旦你更新新的图片就把旧的图片删除掉,

写完后回去编写service


编写junit,queryByShopIddao层已经测试好了,所以就不用再测试那个了,运行之后可能会出现file not read,把水印放到test的rescource下就行了。

controller层实现
controller层就是接收前端发来的信息嘛,所以我们先看看前端店铺的哪些信息不能修改的,店铺名字还有店铺类别是不能修改的吧。这两个一旦创建就不能更改了。
在controller可以定义两个方法,一个getShopById,通过id获取shop并以json格式返回给前端

controller层的测试都是访问网页测试的,启动tomcat,输入,其中shopadmin是类的路由,回车之后就可以看到返回的字符串了。

编写第二个方法,更改店铺信息方法modifyShop,这个方法和registerShop是如出一辙的,复制修改一下就行了。回顾一下注册方法
1、首先验证码验证,接收前台传过来的验证码,如果输入值和它图片相匹配的话,如果正确就下一步
2、接着接收前台传过来的shopstr对象,然后将这个对象转换为shop实体类,
3、然后将前台传过来的文件流通过CommonsMultipartResolver去解析,
4、最后再将shop实体类和shopImg传入service层做处理




主要修改的点是路由,然后就是删除如果没有上传图片的错误判断,还有更新店铺的图片,如果文件流里没有就设置为null,registershop改为modifyshop,check改为success状态,最后错误信息改为请输入店铺id。
编写session部分,也就是说你要修改店铺信息,你必须得有权限,必须是管理员或者是注册店铺的人,session的概念:服务器可以为每个用户浏览器创建会话对象,就是我们的session对象。一个浏览器独占一个session对象,因此在需要保存用户数据时,服务器程序可以把用户信息写到浏览器独占的session对象中,当用户使用浏览器访问服务器时,服务器程序可以从用户的session中取出该用户的数据为用户服务,服务器创建session出来后会把session的一个id号以cookie的形式回写到客户机,这样只要浏览器不关,再去访问服务器都会带着session的id号去,服务器就会发现客户端的浏览器带session的id过来了。就会使用内容中对应的session为了服务,session有默认时间。tomcat为30分钟。这里的session主要为了保存用户和店铺的信息,在外面去存储数据的时候可以从里面取出我们想要的信息来。同时还能方便我们做权限的验证,
把修改信息的session去掉,因为修改店铺不需要获取用户信息,主要获取session是在注册店铺那里,当我们注册成功后再把该用户信息存入session并且键为“user”,然后取出来就行了。


又因为用户跟店铺的关系是一对多的,就是一个owner能创建多个店铺,因此需要在session里面保存一个店铺列表,来显示这个用户可以操作的店铺是哪几个,

可以看到上面的代码有相同的地方我们可以重构一下

有警告加上就行

主要思路就是当你要注册店铺的时候,就去获取session里已经登录的user信息,然后将注册的店铺的shopInfo设置为user,第二步就是当我们店铺添加成功后将店铺添加到用户的店铺列表中。
店铺修改前端页面,
之前我们的注册页面为什么不叫registershop而是shopoperation就是因为店铺操作包括注册和修改,所以我们修改页面同样可以使用这个页面,只需要去修改js代码就行,

js代码增加两个初始化url,其中shopId是从客户请求的url中来的,我们先在common.js中写一个共有方法去获取这个id,

这样就能在shopoperation里取到shopid,相关url的初始化

之后实现一些方法,第一个方法是传入shopId获取shop信息,


之后进行判断到底是调用哪个方法

点击事件的代码基本不用改除了提交的url

debug方式启动tomcat,在controller的getshopbyid和modifyshop设置断点,然后前端做调试http://localhost:8080/o2o/shopadmin/shopoperation?shopId=1,按f12,然后在var shopId设置断点,按f10下一步,然后再var shop设置断点,之前当到达shopInfo的时候就传到后台,f6之后到return modelmap什么都不用做,回到前端f8,可以看到data里就有东西了,之后f8,整个页面就有东西了。之后修改图片,名字和种类,然后点击提交。
店铺列表
dao
/**
* 分页查询店铺,可输入的条件有:店铺名(模糊),店铺状态,店铺类别,区域Id,owner
* @param shopCondition
* @param rowIndex 从第几行开始取数据
* @param pageSize 返回的条数
* 这里为什么要加param因为之前的都只是一个参数,直接取就行了
* 现在这里有三个参数所以你必须指定param的唯一标识
* @return
*/
List<Shop> queryShopList(@Param("shopCondition") Shop shopCondition, @Param("rowIndex") int rowIndex,
@Param("pageSize") int pageSize);
/**
* 返回queryShopList的总数
* @param shopCondition
* @return
*/
int queryShopCount(@Param("shopCondition") Shop shopCondition);
dao层实现
<select id="queryShopList" resultMap="shopMap">
SELECT
s.shop_id,
s.shop_name,
s.shop_desc,
s.shop_addr,
s.phone,
s.shop_img,
s.priority,
s.create_time,
s.last_edit_time,
s.enable_status,
s.advice,
a.area_id,
a.area_name,
sc.shop_category_id,
sc.shop_category_name
FROM
tb_shop s,
tb_area a,
tb_shop_category sc
<where>
<if
test="shopCondition.shopCategory!=null and
shopCondition.shopCategory.shopCategoryId!=null">
and s.shop_category_id = #{shopCondition.shopCategoryId}
</if>
<if
test="shopCondition.area!=null and
shopCondition.area.areaId!=null">
and s.area_id = #{shopCondition.areaId}
</if>
<if test="shopCondition.shopName!=null">
and s.shop_name like %${shopCondition.shopName}% </if>
<if test="shopCondition.enableStatus!=null">
and s.enable_status = #{shopCondition.enableStatus}
</if>
<if
test="shopCondition.owner!=null and
shopCondition.owner.userId!=null">
and s.owner_id = #{shopCondition.owner.userId}
</if>
AND s.area_id = a.area_id
AND S.shop_category_id = sc.shop_category_id
</where>
ORDER BY
s.priority DESC
LIMIT #{rowIndex},#{pageSize};
</select>
<select id="queryShopCount" resultType="int">
SELECT
count(1)
FROM
tb_shop s,
tb_area a,
tb_shop_category sc
<where>
<if
test="shopCondition.shopCategory!=null and
shopCondition.shopCategory.shopCategoryId!=null">
and s.shop_category_id = #{shopCondition.shopCategoryId}
</if>
<if
test="shopCondition.area!=null and
shopCondition.area.areaId!=null">
and s.area_id = #{shopCondition.areaId}
</if>
<if test="shopCondition.shopName!=null">
and s.shop_name like %${shopCondition.shopName}% </if>
<if test="shopCondition.enableStatus!=null">
and s.enable_status = #{shopCondition.enableStatus}
</if>
<if
test="shopCondition.owner!=null and
shopCondition.owner.userId!=null">
and s.owner_id = #{shopCondition.owner.userId}
</if>
AND s.area_id = a.area_id
AND S.shop_category_id = sc.shop_category_id
</where>
</select>
junit测试

测试之后会报错,原因是shopCondition后面忘记加shopCategory,所以一直报There is no getter for property named 'shopCategoryId' in 'class com.imooc.o2o.entity.Shop'

service层编写

为什么这里是返回shopExecution,因为我们需要将shoplist和count整合在一起返回,还有为什么是pageIndex,而不是rowIndex,因为我们前端只认页数,而dao层只认行数,因为我们需要先编写一个工具类,使前端点击某页的时候,第一行都能是(页数-1)*pageSize。

在回来实现service

junit

controller编写
首先第一方法是获取店铺列表



debug浏览器测试

我们不要返回user的id而是返回username,

当显示店铺列表之后,点击某个店铺显示如下,先从session

所以编写一个方法,进行这些操作,首先获取浏览器的请求参数shopId对应的值,如果没有请求参数就去session里看看之前是否有请求过的店铺,如果有请求成功的店铺就传入之前的请求的店铺,如果没有就重定位到店铺列表,如果有请求参数就把当前的店铺id设置为参数值,并且设置到session里去。


前端开发
商店列表页面
选择sui demo的栅格,然后选择查看网页代码
因为我们的html页面在webapp下,所以前端要访问该页面需要在shopadminController里定义一下路由,

然后是两个html,分别是shopmanage.html和shoplist.html和一个js,shoplist.js以后再补全。