DAO接口后的思考 (Data Access Object) 数据访问对象
DAO层工作演变为:接口设计+SQL编写
代码和SQL的分析,方便Review
DAO拼接等逻辑在Service层完成
Service接口和实现类
创建包:service、dto、exception
在resources/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/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--扫描service包下所有使用注解的类型-->
<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>
在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.SeckillException;
import java.util.List;
/**
* Created by shirukai on 2017/10/10.
* 业务接口:站在“使用者”角度设计接口
* 三个方面:方法定义粒度,参数,返回类型(return 类型/异常)
*/
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 SeckillException,RepeatKillException,SeckillCloseException;
}
在enums下创建枚举
SeckillStateEnum
package org.seckill.enums;
/**
* 使用枚举表述常量数据字段
* Created by shirukai on 2017/10/10.
*/
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.state = state;
this.stateInfo = stateInfo;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
public static SeckillStateEnum stateOf(int index){
for (SeckillStateEnum state :values()){
if (state.getState() == index){
return state;
}
}
return null;
}
}
在dto包下创建实体类
Exposer
package org.seckill.dto;
/**
* 暴露秒杀地址DTO
* Created by shirukai on 2017/10/10.
*/
public class Exposer {
//是否开启秒杀
private boolean exposed;
//一种加密措施
private String md5;
//秒杀id
private long seckillId;
//系统时间(毫秒)
private long now;
//开启时间
private long start;
//结束时间
private long end;
public Exposer(boolean exposed, String md5, long seckillId) {
this.exposed = exposed;
this.md5 = md5;
this.seckillId = seckillId;
}
public Exposer(boolean exposed,long seckillId, long now, long start, long end) {
this.exposed = exposed;
this.seckillId = seckillId;
this.now = now;
this.start = start;
this.end = end;
}
public Exposer(boolean exposed, long seckillId) {
this.exposed = exposed;
this.seckillId = seckillId;
}
public boolean isExposed() {
return exposed;
}
public void setExposed(boolean exposed) {
this.exposed = exposed;
}
public String getMd5() {
return md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public long getNow() {
return now;
}
public void setNow(long now) {
this.now = now;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
@Override
public String toString() {
return "Exposer{" +
"exposed=" + exposed +
", md5='" + md5 + '\'' +
", seckillId=" + seckillId +
", now=" + now +
", start=" + start +
", end=" + end +
'}';
}
}
SeckillExecution
package org.seckill.dto;
import org.seckill.entity.SuccessKilled;
import org.seckill.enums.SeckillStateEnum;
/**
* 分装秒杀执行后的结果
* Created by shirukai on 2017/10/10.
*/
public class SeckillExecution {
private long seckillId;
//秒杀状态
private int state;
//状态表示
private String stateInfo;
//秒杀成功对象
private SuccessKilled successKilled;
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
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 SuccessKilled getSuccessKilled() {
return successKilled;
}
public void setSuccessKilled(SuccessKilled successKilled) {
this.successKilled = successKilled;
}
public SeckillExecution(long seckillId, SeckillStateEnum stateEnum, SuccessKilled successKilled) {
this.seckillId = seckillId;
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.successKilled = successKilled;
}
public SeckillExecution(long seckillId, SeckillStateEnum stateEnum) {
this.seckillId = seckillId;
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
}
@Override
public String toString() {
return "SeckillExecution{" +
"seckillId=" + seckillId +
", state=" + state +
", stateInfo='" + stateInfo + '\'' +
", successKilled=" + successKilled +
'}';
}
}
日志配置:
在resources下创建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<jmxConfigurator />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%date [%thread] %-5level %logger{25} - %msg%n</Pattern>
</layout>
</appender>
<root level="debug">
<appender-ref ref="console" />
</root>
</configuration>
编写测试类
package org.seckill.service;
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.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 shirukai on 2017/10/10.
*/
@RunWith(SpringJUnit4ClassRunner.class)
//告诉junit spring配置文件
@ContextConfiguration({
"classpath:spring/spring-dao.xml",
"classpath:spring/spring-service.xml"})
public class SeckillServiceTest {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SeckillService seckillService;
@Test
public void getSeckillList() throws Exception {
List<Seckill> list = seckillService.getSeckillList();
logger.info("list={}",list);
}
@Test
public void getById() throws Exception {
long id = 1000;
Seckill seckill = seckillService.getById(id);
logger.info("seckill={}",seckill);
}
/**
* exposer=Exposer{exposed=true, md5='90fd6692b6a36386755db05cfe52f57a', seckillId=1000, now=0, start=0, end=0}
* @throws Exception
*/
@Test
public void exportSeckillUrl() throws Exception {
long id = 1000;
Exposer exposer = seckillService.exportSeckillUrl(id);
logger.info("exposer={}",exposer);
}
@Test
public void executeSeckill() throws Exception {
long id = 1000;
long phone = 15552211520L;
String md5 = "90fd6692b6a36386755db05cfe52f57a";
SeckillExecution execution = seckillService.executeSeckill(id,phone,md5);
logger.info("execution={}",execution);
}
}