基于Spring+SpringMVC+Mybatis的秒杀系统之Service层(2)
来源:互联网 发布:怎么注销淘宝卖家账户 编辑:程序博客网 时间:2024/05/29 12:29
接上一节(1)
spring/spring-service.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 扫描servie包下所有使用注解的类型 --> <context:component-scan base-package="org.seckill.service"/> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入数据库的连接池 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置基于注解声明式事务 默认使用注解来管理事务行为 --> <tx:annotation-driven transaction-manager="transactionManager"/></beans>
org.seckill.enums.SeckillStateEnum:
package org.seckill.enums;/** * 使用枚举表述常量数据字段 * Created by tianjun on 2016/8/4. */public enum SeckillStateEnum { SUCCESS(1,"秒杀成功"), END(0,"秒杀结束"), REPEAT_KILL(-1,"重复秒杀"), INNER_ERROR(-2,"系统异常"), DATA_REWRITE(-3,"数据篡改"); private int state; private String stateInfo; SeckillStateEnum( int state,String stateInfo) { this.stateInfo = stateInfo; this.state = state; } public int getState() { return state; } public void setState(int state) { this.state = state; } public String getStateInfo() { return stateInfo; } public void setStateInfo(String stateInfo) { this.stateInfo = stateInfo; } public static SeckillStateEnum stateOf(int index){ for (SeckillStateEnum state : values()){ if(state.getState() == index ){ return state; } } return null; }}
org.seckill.exception.SeckillExpection:
package org.seckill.exception;/** * 秒杀相关业务异常 * Created by tianjun on 2016/8/4. */public class SeckillExpection extends RuntimeException { public SeckillExpection(String message) { super(message); } public SeckillExpection(String message, Throwable cause) { super(message, cause); }}
org.seckill.exception.RepeatKillException:
package org.seckill.exception;/** * 重复秒杀异常(运行期异常) * Created by tianjun on 2016/8/4. */public class RepeatKillException extends SeckillExpection { public RepeatKillException(String message) { super(message); } public RepeatKillException(String message, Throwable cause) { super(message, cause); }}
org.seckill.exception.SeckillCloseException:
package org.seckill.exception;/** * 秒杀关闭异常 * Created by tianjun on 2016/8/4. */public class SeckillCloseException extends SeckillExpection { public SeckillCloseException(String message) { super(message); } public SeckillCloseException(String message, Throwable cause) { super(message, cause); }}
org.seckill.service.SeckillService:
package org.seckill.service;import org.seckill.dto.Exposer;import org.seckill.dto.SeckillExecution;import org.seckill.entity.Seckill;import org.seckill.exception.RepeatKillException;import org.seckill.exception.SeckillCloseException;import org.seckill.exception.SeckillExpection;import java.util.List;/** * 业务接口:站在:“使用者”的角度设计接口 * 三个方面:方法的粒度,参数,返回类型(return 类型/异常) * Created by tianjun on 2016/8/4. */public interface SeckillService { /** * 查询所有秒杀记录 * @return */ List<Seckill> getSeckillList(); /** * 查询单个秒杀记录 * @param seckillId * @return */ Seckill getById(long seckillId); /** * 秒杀开启时输出秒杀接口地址,否则输出系统时间和秒杀时间 * @param seckillId */ Exposer exportSeckillUrl(long seckillId); /** * 执行秒杀操作 * @param seckillId * @param userPhone * @param md5 */ SeckillExecution executeSeckill(long seckillId,long userPhone,String md5) throws SeckillExpection,RepeatKillException,SeckillCloseException;}
org.seckill.service.impl.SeckillServiceImpl:
package org.seckill.service.impl;import org.seckill.dao.SeckillDao;import org.seckill.dao.SuccessKilledDao;import org.seckill.dto.Exposer;import org.seckill.dto.SeckillExecution;import org.seckill.entity.Seckill;import org.seckill.entity.SuccessKilled;import org.seckill.enums.SeckillStateEnum;import org.seckill.exception.RepeatKillException;import org.seckill.exception.SeckillCloseException;import org.seckill.exception.SeckillExpection;import org.seckill.service.SeckillService;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 org.springframework.util.DigestUtils;import java.util.Date;import java.util.List;/** * * Created by tianjun on 2016/8/4. */@Service("seckillService")public class SeckillServiceImpl implements SeckillService { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillDao seckillDao; @Autowired private SuccessKilledDao successKilledDao; //md5盐值,用来混淆md5 private final String slat = "123*&*^%%^^(-9lsdjfsjflsyiyiiuiuiu"; @Override public List<Seckill> getSeckillList() { return seckillDao.queryAll(0,4); } @Override public Seckill getById(long seckillId) { return seckillDao.queryById(seckillId); } @Override public Exposer exportSeckillUrl(long seckillId) { Seckill seckill = seckillDao.queryById(seckillId); if(seckill == null){ return new Exposer(false,seckillId); } Date startTime = seckill.getStartTime(); Date endTime = seckill.getEndTime(); //系统当前时间 Date nowTime = new Date(); if(nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()){ return new Exposer(false,seckillId,nowTime.getTime(),startTime.getTime(),endTime.getTime()); } //转化特定字符串的过程,不可逆 String md5 = getMD5(seckillId); return new Exposer(true,md5,seckillId); } private String getMD5(long seckillId){ String base = seckillId + "/" + slat; String md5 = DigestUtils.md5DigestAsHex(base.getBytes()); return md5; } @Override @Transactional /** * 使用事务控制事务方法的有点: * 1:开发团队达成一致约定,明确标注事务方法的编程格式。 * 2:保证事务方法的而执行时间尽可能短,不要穿插其他的网络操作,RPC/HTTP请求或者剥离到事务方法外部。 * 3: 不是所有的方法都需要事务,如只有一条修改操作,只读操作不需要事务控制。 */ public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5) throws SeckillExpection, RepeatKillException, SeckillCloseException { if(md5 == null || !md5.equals(getMD5(seckillId))){ throw new SeckillExpection("seckill data rewrite"); } //执行秒杀逻辑 + 记录购买行为 Date nowTime = new Date(); try { int updateCount = seckillDao.reduceNumber(seckillId,nowTime); if(updateCount<=0){ //没有更新到记录 throw new SeckillCloseException("seckill is close"); } else { //记录购买行为 int insertCount = successKilledDao.insertSuccessKilled(seckillId,userPhone); //唯一:seckillId,userPhone if(insertCount<=0){ //重复秒杀 throw new RepeatKillException("seckill repeat"); }else { //秒杀成 SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId,userPhone); return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS,successKilled); } } } catch (SeckillCloseException e1){ throw e1; } catch (RepeatKillException e2) { throw e2; }catch (Exception e) { logger.error(e.getMessage(),e); //所有编译期异常转化为运行期异常 (spring事务回滚只对运行期异常起作用) throw new SeckillExpection("seckill inner error:"+e.getMessage()); } }}
org.seckill.service.impl.SeckillServiceImplTest:
package org.seckill.service.impl;import org.junit.Test;import org.junit.runner.RunWith;import org.seckill.dto.Exposer;import org.seckill.dto.SeckillExecution;import org.seckill.entity.Seckill;import org.seckill.exception.RepeatKillException;import org.seckill.exception.SeckillCloseException;import org.seckill.exception.SeckillExpection;import org.seckill.service.SeckillService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;import static org.junit.Assert.*;/** * 测试类 * Created by tianjun on 2016/8/4. */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({ "classpath:spring/spring-dao.xml", "classpath:spring/spring-service.xml"})public class SeckillServiceImplTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @Test public void testGetSeckillList() throws Exception { List<Seckill> list = seckillService.getSeckillList(); logger.info("list={}",list); } @Test public void testGetById() throws Exception { long id = 1000L; Seckill seckill = seckillService.getById(id); logger.info("seckill={}",seckill); } //测试代码完整逻辑,注意可重复执行 @Test public void testSeckillLogic() throws Exception { long id = 1001L; Exposer exposer = seckillService.exportSeckillUrl(id); if(exposer.isExposed()){ logger.info("exposer={}",exposer); long phone = 18867102345L; String md5 = exposer.getMd5(); try { SeckillExecution seckillExecution = seckillService.executeSeckill(id, phone, md5); logger.info("result={}",seckillExecution); } catch (RepeatKillException e) { logger.error(e.getMessage()); } catch (SeckillCloseException e) { logger.error(e.getMessage()); } }else { //秒杀未开启 logger.warn("exposer={}",exposer); } }}
综上,测试通过,即Service层完成,进入controller层。
0 0
- 基于Spring+SpringMVC+Mybatis的秒杀系统之Service层(2)
- 基于Spring+SpringMVC+Mybatis的秒杀系统之Dao层(1)
- 基于Spring+SpringMVC+Mybatis的秒杀系统之web层(3)
- 用springmvc+spring+mybatis实现秒杀的DAO层实现
- 基于Spring+SpringMVC+MyBatis实现高并发秒杀APIM
- 基于SSM的秒杀业务学习[1] spring/ mybatis/springmvc整合及配置
- 4.29 SSM项目实战(二)--秒杀系统api之Service层
- 秒杀系统Service层设计
- 基于spring+springmvc+mybatis的图书管理系统
- SSM,Spring,SpringMVC,Mybatis之Service---29
- 基于Mybatis的通用Service层实现
- 基于SSM框架+Mybatis+Maven的秒杀系统
- 初学SpringMVC+Mybatis之Spring基于注解的组件扫描
- springmvc+mybatis整合service层
- spring boot + Mybatis + redis 秒杀系统
- 基于Spring+SpringMVC+Hibernate框架系统, 利用SpringAOP实现写日志,切入点的Controller层出现@AutoWire 注入Service为null的情况分析
- JAVA高并发秒杀系统构建之——Service层
- 基于Maven的SSM框架整合(Spring+SpringMVC+MyBatis)
- c++ 构造函数初始化列表,构造函数的调用顺序
- Pch文件如何配置?
- 去除集合中自定义对象的重复值(对象的成员变量值都相同)
- hdu-4737-rmq+二分
- Github上fork之后如何保持同步(Windows环境)
- 基于Spring+SpringMVC+Mybatis的秒杀系统之Service层(2)
- Android开发资源获取国内代理(转载)
- Qualcomm DragonBoard 410c Display之DSI浅析
- 网络流-最大流算法
- 【官方方法】xcode7免证书真机调试
- 多线程程序挂起问题解决
- 屏蔽掉viewpager中按左右键进行切换功能
- 关于LayoutInflater的inflate方法和LayoutParam分析(二)
- C#开发学习笔记:向Dev控件库中的GridControl添加自定义复选框