店铺注册的前端设计:
这里使用的是阿里的开源前端框架SUI Mobile:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>SUI Mobile Demo</title> <meta name="description" content="MSUI: Build mobile apps with simple HTML, CSS, and JS components."> <meta name="author" content="阿里巴巴国际UED前端"> <meta name="viewport" content="initial-scale=1, maximum-scale=1"> <link rel="shortcut icon" href="/favicon.ico"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="format-detection" content="telephone=no"> <!-- Google Web Fonts --> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css"> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css"> <link rel="apple-touch-icon-precomposed" href="/assets/img/apple-touch-icon-114x114.png"> <script> //ga </script> <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "//hm.baidu.com/hm.js?ba76f8230db5f616edc89ce066670710"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> </head> <body> <div class="page-group"> <div id="page-layout" class="page"> <header class="bar bar-nav"> <a class="button button-link button-nav pull-left back" href="/demos/form"> <span class="icon icon-left"></span> 返回 </a> <h1 class="title">表单</h1> </header> <div class="content"> <div class="list-block"> <ul> <!-- Text inputs --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-name"></i> </div> <div class="item-inner"> <div class="item-title label">Name</div> <div class="item-input"> <input type="text" placeholder="Your name"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-email"></i> </div> <div class="item-inner"> <div class="item-title label">E-mail</div> <div class="item-input"> <input type="email" placeholder="E-mail"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-password"></i> </div> <div class="item-inner"> <div class="item-title label">Password</div> <div class="item-input"> <input type="password" placeholder="Password" class=""> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-gender"></i> </div> <div class="item-inner"> <div class="item-title label">Gender</div> <div class="item-input"> <select> <option>Male</option> <option>Female</option> </select> </div> </div> </div> </li> <!-- Date --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-calendar"></i> </div> <div class="item-inner"> <div class="item-title label">Birth date</div> <div class="item-input"> <input type="date" placeholder="Birth day" value="2014-04-30"> </div> </div> </div> </li> <!-- Switch (Checkbox) --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-toggle"></i> </div> <div class="item-inner"> <div class="item-title label">Switch</div> <div class="item-input"> <label class="label-switch"> <input type="checkbox"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li class="align-top"> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-comment"></i> </div> <div class="item-inner"> <div class="item-title label">Textarea</div> <div class="item-input"> <textarea></textarea> </div> </div> </div> </li> </ul> </div> <div class="content-block"> <div class="row"> <div class="col-50"> <a href="#" class="button button-big button-fill button-danger">取消</a> </div> <div class="col-50"> <a href="#" class="button button-big button-fill button-success">提交</a> </div> </div> </div> </div> </div> </div> <script type='text/javascript' src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script> <script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script> <script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script> </body> </html>
或者这个页面的过程:
1.进入http://m.sui.taobao.org/
2.点击:实例
3.选择表单
4.选择只有文案和输入框
5.右键查看网页源代码
6.复制粘贴到你的html文件
7.进入http://m.sui.taobao.org/
8.点击:开始使用
9.将css和js文件全部替换成上面的css和js文件。(注意这个地方,为什么要把css放上面而js放在下面呢?因为我们希望与布局有关的先加载,然后再填充内容,可以提高用户体验)
重新修改,将index.html改名并换位置:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>SUI Mobile Demo</title> <meta name="description" content="MSUI: Build mobile apps with simple HTML, CSS, and JS components."> <meta name="author" content="阿里巴巴国际UED前端"> <meta name="viewport" content="initial-scale=1, maximum-scale=1"> <link rel="shortcut icon" href="/favicon.ico"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="format-detection" content="telephone=no"> <!-- Google Web Fonts --> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css"> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css"> <link rel="apple-touch-icon-precomposed" href="/assets/img/apple-touch-icon-114x114.png"> <script> //ga </script> <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "//hm.baidu.com/hm.js?ba76f8230db5f616edc89ce066670710"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> </head> <body> <div class="page-group"> <div id="page-layout" class="page"> <header class="bar bar-nav"> <a class="button button-link button-nav pull-left back" href="/demos/form"> <span class="icon icon-left"></span> 返回 </a> <h1 class="title">商店信息</h1> </header> <div class="content"> <div class="list-block"> <ul> <!-- Text inputs --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-name"></i> </div> <div class="item-inner"> <div class="item-title label">商铺名称</div> <div class="item-input"> <input type="text" id="shop-name" placeholder="商铺名称"> </div> </div> </div> </li> <!-- 商铺分类 下拉列表 --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-gender"></i> </div> <div class="item-inner"> <div class="item-title label">商铺分类</div> <div class="item-input"> <select id="shop-category"> </select> </div> </div> </div> </li> <!-- 区域分类 下拉列表 --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-gender"></i> </div> <div class="item-inner"> <div class="item-title label">所属区域</div> <div class="item-input"> <select id="area"> </select> </div> </div> </div> </li> <!-- 详细地址 text --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-name"></i> </div> <div class="item-inner"> <div class="item-title label">详细地址</div> <div class="item-input"> <input type="text" id="shop-addr" placeholder="详细地址"> </div> </div> </div> </li> <!-- 联系电话 text --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-name"></i> </div> <div class="item-inner"> <div class="item-title label">联系电话</div> <div class="item-input"> <input type="text" id="shop-phone" placeholder="联系电话"> </div> </div> </div> </li> <!-- 缩略图 上传控件 --> <li> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-name"></i> </div> <div class="item-inner"> <div class="item-title label">缩略图</div> <div class="item-input"> <input type="file" id="shop-img"> </div> </div> </div> </li> <!-- 店铺简介 textarea--> <li class="align-top"> <div class="item-content"> <div class="item-media"> <i class="icon icon-form-comment"></i> </div> <div class="item-inner"> <div class="item-title label">店铺简介</div> <div class="item-input"> <textarea id="shop-desc" placeholder="店铺简介"></textarea> </div> </div> </div> </li> <!-- 验证码 kaptcha--> </ul> </div> <div class="content-block"> <div class="row"> <div class="col-50"> <a href="#" class="button button-big button-fill button-danger">取消</a> </div> <div class="col-50"> <a href="#" class="button button-big button-fill button-success">提交</a> </div> </div> </div> </div> </div> </div> <script type='text/javascript' src='//g.alicdn.com/sj/lib/zepto/zepto.min.js' charset='utf-8'></script> <script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js' charset='utf-8'></script> <script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm-extend.min.js' charset='utf-8'></script> </body> </html>
新建controller,通过服务器内部转发请求而非直接访问:
package com.ouyan.o2o.web.shopadmin; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping(value="shopadmin",method={RequestMethod.GET}) public class ShopAdminController { @RequestMapping(value="/shopoperate") public String shopOperation(){ return "shop/shopoperation"; } }
访问:http://localhost:8080/o2o/shopadmin/shopoperate
新建文件夹及文件:
/** * */ $(function(){ var initUrl='/o2o/shopadmin/getshopinitinfo'; var registerShopUrl='/o2o/shopadmin/registershop'; getShopInitInfo(); function getShopInitInfo(){ $.getJSON(initUrl,function(data){ if(data.success){ var tempHtml = ''; var tempAreaHtml = ''; data.shopCategoryList.map(function(item,index){ tempHtml+='<option data-id="'+item.shopCategoryId+'">' +item.shopCategoryName+'</option>'; }); data.areaList.map(function(item,index){ tempAreaHtml +='<option data-id="'+item.areaId+'">' +item.areaName+'</oprion>'; }); $('#shop-category').html(tempHtml); $('#area').html(tempAreaHtml); } }); $('#submit').click(function(){ var shop = {}; shop.shopName=$('#shop-name').val(); shop.shopAddr=$('#shop-addr').val(); shop.phone=$('#shop-phone').val(); shop.shopDesc=$('#shop-desc').val(); shop.shopCategory={ shopCategory:$('#shop-category').find('option').not(function(){ return !this.selected; }).data('id') }; shop.area={ areaId:$('#area').find('option').not(function(){ return !this.selected; }).data('id') }; var shopImg=$('#shop-img')[0].files[0]; var formData=new FormData(); formData.append('shopImg',shopImg); formData.append('shopStr',JSON.stringify(shop)); $.ajax({ url:registerShopUrl, type:'POST', data:formData, contentType:false, processData:false, cache:false, success:function(data){ if(data.success){ $.toast('提交成功!'); }else{ $.toast('提交失败!'+data.errMsg); } } }); }); } })
数据库插入:
这里注意我把ShopCategory 这个类的一个属性改了:private ShopCategory parent
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ouyan.o2o.dao.ShopCategoryDao"> <select id="queryShopCategory" resultType="com.ouyan.o2o.entity.ShopCategory"> SELECT shop_category_id, shop_category_name, shop_category_desc, shop_category_img, priority, create_time, parent_id FROM tb_shop_category <where> <if test="shopCategoryCondition.parent!=null"> and parent_id=#{shopCategoryCondition.parent.shopCategoryId} </if> </where> ORDER BY priority DESC </select> </mapper>
package com.ouyan.o2o.dao; import static org.junit.Assert.assertEquals; import java.util.List; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import com.ouyan.o2o.BaseTest; import com.ouyan.o2o.entity.ShopCategory; public class ShopCategoryDaoTest extends BaseTest{ @Autowired private ShopCategoryDao shopCategoryDao; @Test public void testQueryShopCategory(){ List<ShopCategory> shopCategoryList=shopCategoryDao.queryShopCategory(new ShopCategory()); assertEquals(2,shopCategoryList.size()); ShopCategory testCategory = new ShopCategory(); ShopCategory parentCategory = new ShopCategory(); parentCategory.setShopCategoryId(33L); testCategory.setParent(parentCategory); shopCategoryList=shopCategoryDao.queryShopCategory(testCategory); assertEquals(1,shopCategoryList.size()); System.out.println(shopCategoryList.get(0).getShopCategoryName()); } }
dao层测试完毕。
package com.ouyan.o2o.web.shopadmin; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import com.fasterxml.jackson.databind.ObjectMapper; import com.ouyan.o2o.dto.ShopExecution; import com.ouyan.o2o.entity.Area; import com.ouyan.o2o.entity.PersonInfo; import com.ouyan.o2o.entity.Shop; import com.ouyan.o2o.entity.ShopCategory; import com.ouyan.o2o.enums.ShopStateEnum; import com.ouyan.o2o.exceptions.ShopOperationException; import com.ouyan.o2o.service.AreaService; import com.ouyan.o2o.service.ShopCategoryService; import com.ouyan.o2o.service.ShopService; import com.ouyan.o2o.util.HttpServletRequestUtil; @Controller @RequestMapping("/shopadmin") public class ShopManagementController { @Autowired private ShopService shopService; @Autowired private ShopCategoryService ShopCategoryService; @Autowired private AreaService areaService; @RequestMapping(value = "/getshopinitinfo", method = RequestMethod.GET) @ResponseBody private Map<String,Object> getShopInitInfo(){ Map<String,Object> modelMap = new HashMap<String,Object>(); List<ShopCategory> shopCategoryList = new ArrayList<ShopCategory>(); List<Area> areaList = new ArrayList<Area>(); try { shopCategoryList=ShopCategoryService.getShopCategoryList(new ShopCategory()); areaList = areaService.getAreaList(); modelMap.put("shopCategoryList", shopCategoryList); modelMap.put("areaList", areaList); modelMap.put("success", true); } catch (Exception e) { modelMap.put("success", false); modelMap.put("errMsg", e.getMessage()); } return modelMap; } @RequestMapping(value = "/registershop", method = RequestMethod.POST) @ResponseBody public Map<String, Object> registerShop(HttpServletRequest request) { Map<String, Object> modelMap = new HashMap<String, Object>(); // 接受并转化相应参数 String shopStr = HttpServletRequestUtil.getString(request, "shopStr"); ObjectMapper mapper = new ObjectMapper(); Shop shop = null; try { shop = mapper.readValue(shopStr, Shop.class); } catch (Exception e) { modelMap.put("success", false); modelMap.put("errMsg", e.getMessage()); return modelMap; } CommonsMultipartFile shopImg = null; CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver( request.getSession().getServletContext()); if (commonsMultipartResolver.isMultipart(request)) { MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request; shopImg = (CommonsMultipartFile) multipartHttpServletRequest.getFile("shopImg"); } else { modelMap.put("success", false); modelMap.put("errMsg", "上传文件不能为空"); return modelMap; } // 注册店铺 if (shop != null && shopImg != null) { PersonInfo owner = new PersonInfo(); // session TODO owner.setUserId(1L); shop.setOwner(owner); ShopExecution se; try { se = shopService.addShop(shop, shopImg.getInputStream(), shopImg.getOriginalFilename()); if (se.getState() == ShopStateEnum.CHECK.getState()) { modelMap.put("success", true); } else { modelMap.put("success", false); modelMap.put("errMsg", se.getStateInfo()); } } catch (ShopOperationException e) { modelMap.put("success", false); modelMap.put("errMsg", e.getMessage()); } catch (IOException e) { modelMap.put("success", false); modelMap.put("errMsg", e.getMessage()); } return modelMap; } else { modelMap.put("success", false); modelMap.put("errMsg", "请输入店铺信息"); return modelMap; } } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ouyan.o2o.dao.ShopCategoryDao"> <select id="queryShopCategory" resultType="com.ouyan.o2o.entity.ShopCategory"> SELECT shop_category_id, shop_category_name, shop_category_desc, shop_category_img, priority, create_time, parent_id FROM tb_shop_category <where> <if test="shopCategoryCondition!=null"> and parent_id is not null </if> <if test="shopCategoryCondition.parent!=null"> and parent_id=#{shopCategoryCondition.parent.shopCategoryId} </if> </where> ORDER BY priority DESC </select> </mapper>
接著訪問:http://localhost:8080/o2o/shopadmin/shopoperate