文章目录

  • 概述
  • ShopService开发步骤
    • Service层接口类ShopService
    • Service层接口实现类ShopServiceImpl
    • ShopOperationException
    • 单元测试
  • 注意事项
  • Github地址

概述

截至目前,我们已经完成了持久层insertShop的开发,编写了操作图片和路径的工具类,使用ENUM定义了操作店铺使用的常量,定义了操作店铺返回的DTO类ShopExecution。

铺垫了这么多,终于可以编写Service层的代码了,service层操作店铺返回DTO类ShopExecution(不仅包含Shop的信息,同时也要包含操作店铺的状态信息)。


ShopService开发步骤


Service层接口类ShopService

src/main/java建立 com.artisan.o2o.service包,新增接口类ShopService

package com.artisan.o2o.service;import java.io.File;import com.artisan.o2o.dto.ShopExecution;
import com.artisan.o2o.entity.Shop;public interface ShopService {ShopExecution addShop(Shop shop, File shopFile);}

Service层接口实现类ShopServiceImpl

src/main/java先建立com.artisan.o2o.service.impl, 编写ShopService的接口实现类ShopServiceImpl

具体逻辑详见注释

package com.artisan.o2o.service.impl;import java.io.File;
import java.util.Date;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.artisan.o2o.dao.ShopDao;
import com.artisan.o2o.dto.ShopExecution;
import com.artisan.o2o.entity.Shop;
import com.artisan.o2o.enums.ShopStateEnum;
import com.artisan.o2o.exception.ShopOperationException;
import com.artisan.o2o.service.ShopService;
import com.artisan.o2o.util.FileUtil;
import com.artisan.o2o.util.ImageUtil;@Service
public class ShopServiceImpl implements ShopService {private static final Logger logger = LoggerFactory.getLogger(ShopServiceImpl.class);@Autowiredprivate ShopDao shopDao;/*** 3个步骤需要在一个事务中,添加@Transactional注解* * 1. 将shop基本信息添加到数据库,返回shopId* * 2. 根据shopId创建目录,得到图片存储的相对路径* * 3. 将相对路径更新到数据库* * * Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚* * (1)注解@Transactional 只能应用到 public 方法才有效* * (2)在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring成的代理对象来管理,这会造成自调用问题。* 若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,* 有@Transactional注解的方法的事务被忽略,不会发生回滚。* * * 上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP* 代理造成的。为解决这两个问题,可以使用 AspectJ 取代 Spring AOP 代理* * 在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP* 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional* 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor* 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑,* 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源* DataSource 提交或回滚事务* */@Override@Transactionalpublic ShopExecution addShop(Shop shop, File shopImg) {// 非空判断 (这里先判断shop是否为空,严格意义上讲shop中的are的属性也需要判断)if (shop == null) {return new ShopExecution(ShopStateEnum.NULL_SHOP_INFO);}// 关键步骤1. 设置基本信息,插入shop// 初始状态: 审核中shop.setEnableStatus(0);shop.setCreateTime(new Date());shop.setLastEditTime(new Date());int effectedNum = shopDao.insertShop(shop);if (effectedNum <= 0) {throw new ShopOperationException("店铺创建失败");} else {// 关键步骤2. 添加成功,则继续处理文件,获取shopid,用于创建图片存放的目录if (shopImg != null) {try {// 需要根据shopId来创建目录,所以也需要shop这个入参addShopImg(shop, shopImg);} catch (Exception e) {logger.error("addShopImg error {} ", e.toString());throw new ShopOperationException("addShopImg error:" + e.getMessage());}// 关键步骤3. 更新tb_shop中 shop_img字段effectedNum = shopDao.updateShop(shop);if (effectedNum <= 0) {logger.error("updateShop error {} ", "更新店铺失败");throw new ShopOperationException("updateShop error");}}}// 返回店铺的状态:审核中,以及店铺信息return new ShopExecution(ShopStateEnum.CHECK, shop);}/*** * * @Title: addShopImg* * @Description: 根据shopId创建目录,并生成水印图片* * @param shop* @param shopImg* * @return: void*/private void addShopImg(Shop shop, File shopImg) {String imgPath = FileUtil.getShopImagePath(shop.getShopId());// 生成图片的水印图String relativeAddr = ImageUtil.generateThumbnails(shopImg, imgPath);// 将相对路径设置个shop,用于更新数据库shop.setShopImg(relativeAddr);}}

ShopOperationException

package com.artisan.o2o.exception;/*** * * @ClassName: ShopOperationException* * @Description: 继承自RuntimeException ,这样在标注了@Transactional事务的方法中,出现了异常,才回回滚数据。* *               默认情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常)或者 Error,则 Spring*               将回滚事务;除此之外,Spring 不会回滚事务。* * @author: Mr.Yang* * @date: 2018年5月21日 下午5:37:53*/
public class ShopOperationException extends RuntimeException {private static final long serialVersionUID = 6860566652051914211L;public ShopOperationException(String message) {super(message);}}

单元测试

package com.artisan.o2o.service;import java.io.File;
import java.util.Date;import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;import com.artisan.o2o.BaseTest;
import com.artisan.o2o.dto.ShopExecution;
import com.artisan.o2o.entity.Area;
import com.artisan.o2o.entity.PersonInfo;
import com.artisan.o2o.entity.Shop;
import com.artisan.o2o.entity.ShopCategory;
import com.artisan.o2o.enums.ShopStateEnum;public class ShopServiceTest extends BaseTest {@AutowiredShopService shopService;@Testpublic void testAddShop() {Shop shop = new Shop();PersonInfo personInfo = new PersonInfo();Area area = new Area();ShopCategory shopCategory = new ShopCategory();personInfo.setUserId(1L);area.setAreaId(1);shopCategory.setShopCategoryId(1L);shop.setOwner(personInfo);shop.setArea(area);shop.setShopCategory(shopCategory);shop.setShopName("咖啡点");shop.setShopDesc("小工匠的咖啡店");shop.setShopAddr("NanJing");shop.setPhone("9876553");shop.setPriority(99);shop.setCreateTime(new Date());shop.setLastEditTime(new Date());shop.setEnableStatus(ShopStateEnum.CHECK.getState());shop.setAdvice("审核中");File shopFile = new File("D:/o2o/artisan.jpg");ShopExecution se = shopService.addShop(shop, shopFile);Assert.assertEquals(ShopStateEnum.CHECK.getState(), se.getState());}
}

可以在addShop方法中,加入断点,通过debug的方式,一步步的调试分析

mybatis操作数据库的信息:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
五月 21, 2018 6:09:55 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 2, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1br1ebw9v10u0o3ghf6lww|130d63be, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1br1ebw9v10u0o3ghf6lww|130d63be, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/o2o?useUnicode=true&characterEncoding=utf8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@3adcc812] will be managed by Spring
==>  Preparing: INSERT INTO tb_shop ( owner_id, area_id, shop_category_id, shop_name, shop_desc, shop_addr, phone, shop_img, priority, create_time, last_edit_time, enable_status, advice) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? );
==> Parameters: 1(Long), 1(Integer), 1(Long), 咖啡点(String), 小工匠的咖啡店(String), NanJing(String), 9876553(String), null, 99(Integer), 2018-05-21 18:09:57.067(Timestamp), 2018-05-21 18:09:57.067(Timestamp), 0(Integer), 审核中(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6] from current transaction
==>  Preparing: update tb_shop SET shop_name=?, shop_desc=?, shop_addr=?, phone=?, shop_img=?, priority=?, last_edit_time=?, enable_status=?, advice=?, area_id=?, shop_category_id=? where shop_id = ?
==> Parameters: 咖啡点(String), 小工匠的咖啡店(String), NanJing(String), 9876553(String), \upload\item\shopImage\24\2018052118095757182.jpg(String), 99(Integer), 2018-05-21 18:09:57.067(Timestamp), 0(Integer), 审核中(String), 1(Integer), 1(Long), 24(Long)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@512baff6]
五月 21, 2018 6:09:58 下午 org.springframework.context.support.GenericApplicationContext doClose
信息: Closing org.springframework.context.support.GenericApplicationContext@ae45eb6: startup date [Mon May 21 18:09:50 BOT 2018]; root of context hierarchy

数据库信息:

同样的需要检查下操作水印图片的操作是否正常,加上了水印,OK


注意事项

1. addShop的多个操作步骤(设置基本信息,插入tb_shop || 添加成功,则继续处理文件,获取shopid,用于创建图片存放的目录 || 更新tb_shop中 shop_img字段 ),需要找同一个事务中,所以addShop方法添加了@Transactional注解

2. Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚,所以ShopOperationException必须继承RuntimeException才可以实现回滚,如果继承Exception则不会回滚数据库操作。


Github地址

代码地址: https://github.com/yangshangwei/o2o

实战SSM_O2O商铺_10【商铺注册】Service层的实现相关推荐

  1. 校园O2O商铺平台-店铺注册Service层和Controller层

    店铺注册之Service层的实现 正在更新 店铺注册功能之Controller层的实现 正在更新 店铺注册功能之Controller层的改造 正在更新

  2. 【校园商铺 4章】:店铺注册--Service层的实现(后期还要改造,先前没实现)

    文章目录 1.Thumbnailator图片处理 2. 编写工具类:ImageUtil和PathUtil 3.dto:ShopException和enums:ShopStateEnum 4. Serv ...

  3. 校园O2O商铺平台-店铺注册DAO层与图片处理

    DAO层之新增店铺 正在更新 DAO层之更新店铺 正在更新 Thumbnailator图片处理和封装Util 正在更新 Dto之ShopExecution的实现 正在更新

  4. 实战SSM_O2O商铺_15【商铺注册】View层+Controller层之图片上传

    文章目录 概述 Maven依赖 文件上传解析器bean的配置 页面 shopoperation.html增加上传组件 shopoperation.js Controller层 Github地址 概述 ...

  5. 实战SSM_O2O商铺_11【商铺注册】Controller层的实现

    文章目录 概述 结构 Maven依赖 封装工具类HttPServletRequestUtil Controller控制层编写 Service层的改造 单元测试 Github地址 概述 实战SSM_O2 ...

  6. 实战SSM_O2O商铺_46【Redis缓存】头条信息+商铺目录Service层加入缓存

    文章目录 概述 HeadLineServiceImpl的改造 代码 单元测试 ShopCategoryServiceImpl的改造 代码 单元测试 Github地址 概述 根据数据的特点,不经常变动的 ...

  7. 实战SSM_O2O商铺_13【商铺注册】View层之初始化页面数据

    文章目录 请求过程分析 DAO层的实现 AreaDao接口,Mapper映射文件及单元测试 ShopCategoryDao接口 ShopCategoryDao.xml Mapper映射文件 单元测试 ...

  8. 实战SSM_O2O商铺_07【商铺注册】DAO层-新增与更新商铺

    文章目录 概述 增加商铺 ShopDao新增insertShop接口 ShopDao.xml中新增insertShop语句 单元测试 更新商铺 ShopDao中新增updateShop接口 ShopD ...

  9. 实战SSM_O2O商铺_12【商铺注册】View层之前台页面

    文章目录 概述 前端框架选择 页面目录结构 搭建商铺注册页面 JS部分 shopoperation.js common.js 乱码问题 将页面迁到WEB-INF目录下 Controller层的编写 访 ...

最新文章

  1. chrome 请求带上cookie_【编号0002】请求头的内容,及其相关知识铺垫
  2. 802.11协议中帧控制域中To DS and From DS 比特位的含义
  3. 四种π型RC滤波电路
  4. linux下用u盘安装xp系统安装教程,全新Linux笔记本电脑用U盘装Win7/XP系统教程
  5. 图(Graph)的学习
  6. 【软件工程】极限编程
  7. MapReduce整体架构分析
  8. 【洛谷 P1070】道路游戏 (DP)
  9. Netty工作笔记0080---编解码器和处理器链梳理
  10. linux通过usb给windows,如何从Linux创建Windows USB安装程序 | MOS86
  11. 1.7 COMS边沿触发器
  12. 流量卡之家:物联网实施安全性是建筑行业部署物联网计划主要障碍
  13. python adf单位根检验 如何查看结果
  14. ADC噪声全面分析 -01- ADC噪声的类型以及ADC特性
  15. Spectrum数据采集卡和任意波形发生器在杨百翰大学声波研究中的应用
  16. “跑分”手机已过时,“双高”手机成新方向
  17. 无线通信模块——WiFi,蓝牙,2.4G
  18. 因特网计算机地址被称为什么,因特网上每台计算机有一个规定的“地址”,这个地址被称为地址.A.TCPB.IPC.WebD.以上都不对...
  19. Teamcity NuGet Installer
  20. 短视频配音用什么软件?推荐几款可以用自己视频配音的app

热门文章

  1. C++用顶层函数重载操作符(三)用友元优化
  2. pyspark dataframe基本用法
  3. 课堂经验值管理小程序_柳州人事管理小程序要有这些功能
  4. 重温强化学习之无模型学习方法:时间差分方法
  5. 文巾解题 1833. 雪糕的最大数量
  6. 从C语言的角度重构数据结构系列(四)-静态链表动态链表
  7. Python简明教程
  8. Python零碎知识(6):split 和 join
  9. 使用solr的DIHandler 构建mysql大表全量索引,内存溢出问题的解决方法
  10. Java 编程的动态性, 第4部分: 用 Javassist 进行类转换--转载