商品管理模块
功能:
前台:
1.产品搜索
controller层实现:根据关键字或分类id进行搜索。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 前台搜索商品列表:搜索,分页,排序 3 * @param keyword 搜索关键字 4 * @param categoryId 分类id 5 * @param pageNum 页码 6 * @param pageSize 每页的数量 7 * @param orderBy 8 * @return 9 */ 10 @RequestMapping(value = "list.do", method = RequestMethod.POST) 11 @ResponseBody 12 //@RequestParam(required = false)表示可以不传该参数,而其默认值是true表示必传,所以要让其成为可选参数需将其置为false 13 public ServerResponse<PageInfo> list(@RequestParam(value = "keyword", required = false) String keyword, 14 @RequestParam(value = "categoryId", required = false) Integer categoryId, 15 @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, 16 @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, 17 @RequestParam(value = "orderBy", defaultValue = "") String orderBy) { 18 return iProductService.getProductByKeywordCategory(keyword, categoryId, pageNum, pageSize, orderBy); 19 }
service层实现:
先判断分类id是否传入,如果传入,调用iCategoryService.selectCategoryAndChildrenById(category.getId()).getData()递归查询出所有子分类,然后判断关键字是否传入,如果传入,则将关键字加上"%",最后判断orderby排序规则是否符合约定的排序规则,这里只约定了按价格升序或降序。最后根据关键字和id从数据库中查询出数据。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public ServerResponse<PageInfo> getProductByKeywordCategory(String keyword, Integer categoryId, int pageNum, int pageSize, String orderBy) { 2 //校验传入的参数是否正确 3 if(StringUtils.isBlank(keyword) && categoryId == null) { 4 return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDesc()); 5 } 6 //创建一个category分类集合 7 //如果传入的是一个高级分类,要调用递归算法,把所有子分类都查出来并加上其本身放入list中 8 List<Integer> categoryIdList = new ArrayList<Integer>(); 9 10 //如果分类id非空 11 if(categoryId != null) { 12 //根据分类id查出该分类对象 13 Category category = categoryMapper.selectByPrimaryKey(categoryId); 14 //如果没有该分类对象,且keyword关键字也为空 15 if(category == null && StringUtils.isBlank(keyword)) { 16 //没有该分类,并且还没有关键字,这个时候返回一个空的结果集,不报错 17 PageHelper.startPage(pageNum, pageSize); 18 List<ProductListVo> productListVoList = Lists.newArrayList(); 19 //这里将空的voList直接放入PageInfo中,下面不需要再加上set方法 20 //因为这里商品是空,也就是查询结果集没有变化,不需要将其从Pojo转成vo向前端展示,所以这里不需要重新加入set.list 21 PageInfo pageInfo = new PageInfo(productListVoList); 22 return ServerResponse.createBySuccess(pageInfo); 23 } 24 //查询其子分类,这里要取getData(),因为这里selectCategoryAndChildrenById返回的对象是一个ServerResponse,要取其中的data对象才是分类集合 25 categoryIdList = iCategoryService.selectCategoryAndChildrenById(category.getId()).getData(); 26 } 27 28 //如果关键字keyword非空 29 if(StringUtils.isNotBlank(keyword)) { 30 //将关键字加上%,以让其在sql语句中实现模糊查询 31 keyword = new StringBuilder().append("%").append(keyword).append("%").toString(); 32 } 33 //开始分页 34 PageHelper.startPage(pageNum, pageSize); 35 36 //排序处理:利用PageHelper自动实现 37 //校验传入的orderBy参数是否正确 38 if(StringUtils.isNotBlank(orderBy)) { 39 //校验传入的orderBy是否在约定的排序顺序中 40 if(Const.ProductListOrderBy.PRICE_ASC_DESC.contains(orderBy)) { 41 //将orderBy按照_下划线分割 42 String[] orderByArray = orderBy.split("_"); 43 //PageHelper调用orderBy方法的参数的规则是price asc表示按照价格升序排序 44 PageHelper.orderBy(orderByArray[0] + " " + orderByArray[1]); 45 } 46 } 47 48 //正式开始搜索商品,根据keyword和ids 49 List<Product> productList = productMapper.selectByNameAndCategoryIds(StringUtils.isBlank(keyword)?null:keyword, categoryIdList.size()==0?null:categoryIdList); 50 //将product对象转成voList对象 51 List<ProductListVo> productListVoList = Lists.newArrayList(); 52 for(Product product : productList) { 53 ProductListVo productListVo = assembleProductListVo(product); 54 productListVoList.add(productListVo); 55 } 56 //将查询结果放入pageInfo中,在此才开始分页 57 PageInfo pageInfo = new PageInfo(productList); 58 pageInfo.setList(productListVoList); 59 60 return ServerResponse.createBySuccess(pageInfo); 61 }
sql语句实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!--<foreach>标签:item是每次遍历所用的变量名字,collection是要遍历的集合,其要与dao层传入的参数名字完全一样,open是遍历以{开始,separator是以,分割,close是遍历以}结束--> 2 <select id="selectByNameAndCategoryIds" resultMap="BaseResultMap" parameterType="map"> 3 SELECT 4 <include refid="Base_Column_List"/> 5 FROM product 6 WHERE status = 1 7 <if test = "productName != null"> 8 AND name LIKE #{productName} 9 </if> 10 <if test = "categoryIdList != null"> 11 AND category_id IN 12 <foreach item="item" index="index" open="{" separator="," close="}" collection="categoryIdList"> 13 #{item} 14 </foreach> 15 </if> 16 </select>
2.商品详情
后台:
1.商品列表
controller层实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 @RequestMapping(value = "get_list.do", method = RequestMethod.POST) 2 @ResponseBody 3 public ServerResponse getList(HttpServletRequest request, @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) { 4 // User user = (User) session.getAttribute(Const.CURRENT_USER); 5 6 String loginToken = CookieUtil.readLoginToken(request); 7 if(StringUtils.isEmpty(loginToken)) { 8 return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息"); 9 } 10 String userJsonStr = RedisShardedPoolUtil.get(loginToken); 11 User user = JsonUtil.string2Obj(userJsonStr, User.class); 12 13 if(user == null) { 14 return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录管理员"); 15 } 16 if(iUserService.checkAdminRole(user).isSuccess()) { 17 //填充业务 18 return iProductService.getProductList(pageNum, pageSize); 19 } 20 else { 21 return ServerResponse.createByErrorMessage("无权限操作"); 22 } 23 //全部通过拦截器验证是否登录以及权限 24 //return iProductService.getProductList(pageNum, pageSize); 25 }
service层实现:
利用PageHelper插件进行分页,先调用PageHelper.startPage()进行物理分页,即会在后面的sql查询语句中加入limit语句,然后从数据库中分页查询出所需要的数据,最后将查询出的数据返回给PageInfo进行接收。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public ServerResponse<PageInfo> getProductList(int pageNum, int pageSize) { 2 //1.startPage--start 3 //开始分页,页码默认值是1,每页显示数量默认值是10 4 PageHelper.startPage(pageNum, pageSize); 5 6 //2.填充自己的sql查询逻辑 7 //从数据库中按分页查出所有product信息 8 //这里到底是先分页再查询还是先查询再分页? 9 //这里pageHelper会在sql语句中自动加入limit语句,这样在数据库层就实现了分页查询而不用把所有数据都查出来之后再进行分页处理 10 List<Product> productList = productMapper.selectList(); 11 //创建vo对象 12 List<ProductListVo> productListVoList = Lists.newArrayList(); 13 //将查出来的product对象转变成vo对象后放入voList中保存 14 for(Product productItem : productList) { 15 ProductListVo productListVo = assembleProductListVo(productItem); 16 productListVoList.add(productListVo); 17 } 18 19 //3.pageHelper--收尾 20 //分页结果用PageInfo接收,会根据productList这个集合自动进行分页处理 21 PageInfo pageResult = new PageInfo(productList); 22 //前端展示对象用vo,所以这里将voList对象再次传入PageInfo中,对其进行重置 23 pageResult.setList(productListVoList); 24 //将PageInfo返回 25 return ServerResponse.createBySuccess(pageResult); 26 }
2.商品搜索
3.图片上传
4.富文本上传
5.商品详情
6.商品上下架
7.增加和更新商品
controller层实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 @RequestMapping(value = "get_detail.do", method = RequestMethod.POST) 2 @ResponseBody 3 public ServerResponse getDetail(HttpServletRequest request, Integer productId) { 4 // User user = (User) session.getAttribute(Const.CURRENT_USER); 5 6 String loginToken = CookieUtil.readLoginToken(request); 7 if(StringUtils.isEmpty(loginToken)) { 8 return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息"); 9 } 10 String userJsonStr = RedisShardedPoolUtil.get(loginToken); 11 User user = JsonUtil.string2Obj(userJsonStr, User.class); 12 13 if(user == null) { 14 return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录管理员"); 15 } 16 if(iUserService.checkAdminRole(user).isSuccess()) { 17 //填充业务 18 return iProductService.manageProductDetail(productId); 19 } 20 else { 21 return ServerResponse.createByErrorMessage("无权限操作"); 22 } 23 //全部通过拦截器验证是否登录以及权限 24 //return iProductService.manageProductDetail(productId); 25 }
service层实现:
根据前端传过来的product对象,将子图中的第一个图片赋值给主图,然后根据是否传入了id来判断是新增商品还是更新商品,然后直接更新到数据库。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public ServerResponse saveOrUpdateProduct(Product product) { 2 //检查传过来的product是否非空 3 if(product != null) { 4 //如果当前商品的子图非空,取子图的第一个图片赋给主图 5 if(StringUtils.isNotBlank(product.getSubImages())) { 6 //将子图分割成数组,也就是把多张子图分成一张张的图片 7 String[] subImageArray = product.getSubImages().split(","); 8 if(subImageArray.length > 0) { 9 //将子图第一个图片作为我们的主图 10 product.setMainImage(subImageArray[0]); 11 } 12 } 13 //根据传入的product是否有id,来判断是增加商品还是更新商品 14 //因为product的id是自增的,所以如果是新增商品传进来的时候还没有id,而如果是更新商品,则有id 15 // 因此不用查数据库就可以知道是新增商品还是更新商品 16 if(product.getId() != null) { 17 //如果有id,是更新商品 18 //将product商品更新到数据库中 19 int rowCount = productMapper.updateByPrimaryKey(product); 20 if(rowCount > 0) { 21 return ServerResponse.createBySuccess("更新产品成功"); 22 } 23 return ServerResponse.createBySuccess("更新产品失败"); 24 } 25 else { 26 //如果没有id,是增加商品 27 //将product商品增加到数据库中 28 int rowCount = productMapper.insert(product); 29 if(rowCount > 0) { 30 return ServerResponse.createBySuccess("新增产品成功"); 31 } 32 return ServerResponse.createBySuccess("新增产品失败"); 33 } 34 } 35 return ServerResponse.createByErrorMessage("新增或更新产品参数不正确"); 36 }
掌握:
1.FTP上传文件
2.流读取Properties配置文件
静态代码块使用方法:http://blog.csdn.net/u010839779/article/details/43701457
路径问题:https://www.cnblogs.com/yejg1212/p/3270152.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class PropertiesUtil { 2 3 private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class); 4 5 private static Properties props; 6 7 //tomcat启动的时候就读取里面的内容,所有这里用static静态块来处理 8 //静态代码块会在类被加载的时候仅执行一次,一般用其做初始化静态变量 9 //执行顺序:静态代码块>普通代码块>构造器代码块 10 //Class.forName("com.mysql.jdbc.Driver")作用:注册驱动,把driver加载到jvm虚拟机中,其代码只执行一次 11 static { 12 String fileName = "mall.properties"; 13 props = new Properties(); 14 try { 15 // System.out.println("路径:" + PropertiesUtil.class.getClassLoader()); 16 // System.out.println("测试:" + PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName)); 17 props.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName),"utf-8")); 18 } catch (IOException e) { 19 logger.error("配置文件读取异常",e); 20 } 21 } 22 23 //根据key从properties获取value 24 public static String getProperty(String key){ 25 String value = props.getProperty(key.trim()); 26 if(StringUtils.isBlank(value)){ 27 return null; 28 } 29 return value.trim(); 30 } 31 32 public static String getProperty(String key, String defaultValue){ 33 String value = props.getProperty(key.trim()); 34 if(StringUtils.isBlank(value)){ 35 value = defaultValue; 36 } 37 return value.trim(); 38 } 39 }
3.抽象POJO、BO、VO对象之间的转换关系及解决思路
实现的date转换的工具类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class DateTimeUtil { 2 3 //joda-time 4 5 //Date类型标准格式 6 public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; 7 8 //字符串转Date类型 9 10 /** 11 * 字符串转Date类型 12 * @param dateTimeStr 要转的字符串 13 * @param formatStr 要转的字符串传入的格式 14 * @return 返回joda-time的date类型 15 */ 16 public static Date strToDate(String dateTimeStr,String formatStr){ 17 DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr); 18 DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); 19 return dateTime.toDate(); 20 } 21 22 /** 23 * Date类型转字符串 24 * @param date date时间 25 * @param formatStr 要转成的字符串格式 26 * @return 返回转成的字符串 27 */ 28 public static String dateToStr(Date date,String formatStr){ 29 if(date == null){ 30 return StringUtils.EMPTY; 31 } 32 DateTime dateTime = new DateTime(date); 33 return dateTime.toString(formatStr); 34 } 35 36 /** 37 * 字符串转成标准Date类型 38 * @param dateTimeStr 39 * @return 40 */ 41 public static Date strToDate(String dateTimeStr){ 42 DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT); 43 DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); 44 return dateTime.toDate(); 45 } 46 47 /** 48 * date类型转成标准字符串输出 49 * @param date 50 * @return 51 */ 52 public static String dateToStr(Date date){ 53 if(date == null){ 54 return StringUtils.EMPTY; 55 } 56 DateTime dateTime = new DateTime(date); 57 return dateTime.toString(STANDARD_FORMAT); 58 } 59 60 public static void main(String[] args) { 61 System.out.println(DateTimeUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss")); 62 System.out.println(DateTimeUtil.strToDate("2010-01-01 11:11:11","yyyy-MM-dd HH:mm:ss")); 63 } 64 }
5.Mybatis-PageHelper高效准确地分页及动态排序