Service层Spring开发
新建service包和exception包和dto包
exception包用来存放自定义异常
dto用来存放定义的结果集数据类型
service包接口
CourseService.java
package me.debugjoker.service;
import me.debugjoker.dto.CourseExecution;
import me.debugjoker.dto.Exposer;
import me.debugjoker.entity.Course;
import me.debugjoker.exception.ChooseCloseException;
import me.debugjoker.exception.ChooseException;
import me.debugjoker.exception.RepeatChooseException;
import java.util.List;
public interface CourseService {
/**
* 查询所有的课程 * @return
*/
List<Course> getCourseList();
/**
* 查询一个课程记录 * @param courseId
* @return
*/
Course queryCourseById(long courseId);
/**
* 选课开始时暴露选课地址,未开始时输出系统时间和秒杀时间
* @param courseId
*/
Exposer exportCourseUrl(long courseId);
/**
* 开始执行选课操作
*/
CourseExecution executeCourseChoose(long courseId, long studentId, String md5)throws ChooseException,ChooseCloseException,RepeatChooseException;
}
dto包下的数据类
Exposer.java
package me.debugjoker.dto;
/**
* 暴露选课地址DTO
*/
public class Exposer {
/*是否开启选课*/
private boolean isExposed;
/* 加密措施*/
private String md5;
/*课程id*/
private long courseId;
/*系统当前时间*/
private long now;
/*选课开始时间*/
private long start;
/*选课结束时间*/
private long end;
public Exposer(boolean isExposed, String md5, long courseId) {
this.isExposed = isExposed;
this.md5 = md5;
this.courseId = courseId;
}
public Exposer(boolean isExposed, long now, long start, long end) {
this.isExposed = isExposed;
this.now = now;
this.start = start;
this.end = end;
}
public Exposer(boolean isExposed, long courseId) {
this.isExposed = isExposed;
this.courseId = courseId;
}
public boolean isExposed() {
return isExposed;
}
public void setExposed(boolean exposed) {
isExposed = exposed;
}
public String getMd5() {
return md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
public long getCourseId() {
return courseId;
}
public void setCourseId(long courseId) {
this.courseId = courseId;
}
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;
}
}
CourseExecution.java
package me.debugjoker.dto;
import me.debugjoker.entity.SuccessChoose;
/**
* 选课之后结果对象封装
*/
public class CourseExecution {
private long seckillId;
//选课结果状态
private int state;
//状态表示
private String stateInfo;
//选课成功对象
private SuccessChoose successChoose;
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 SuccessChoose getSuccessChoose() {
return successChoose;
}
public void setSuccessChoose(SuccessChoose successChoose) {
this.successChoose = successChoose;
}
public CourseExecution(long seckillId, int state, String stateInfo, SuccessChoose successChoose) {
this.seckillId = seckillId;
this.state = state;
this.stateInfo = stateInfo;
this.successChoose = successChoose;
}
public CourseExecution(long seckillId, int state, String stateInfo) {
this.seckillId = seckillId;
this.state = state;
this.stateInfo = stateInfo;
}
}
自定义异常类exception包下
package me.debugjoker.exception;
/**
* 选课相关异常
*/
public class ChooseException extends RuntimeException {
public ChooseException(String message) {
super(message);
}
public ChooseException(String message, Throwable cause) {
super(message, cause);
}
}
package me.debugjoker.exception;
/**
* 选课关闭异常
*/
public class ChooseCloseException extends ChooseException {
public ChooseCloseException(String message) {
super(message);
}
public ChooseCloseException(String message, Throwable cause) {
super(message, cause);
}
}
package me.debugjoker.exception;
/**
* 重复选课异常
*/
public class RepeatChooseException extends ChooseException{
public RepeatChooseException(String message) {
super(message);
}
public RepeatChooseException(String message, Throwable cause) {
super(message, cause);
}
}
Service实现
service下新建impl包
CourseServiceImpl.java
package me.debugjoker.service.impl;
import me.debugjoker.dao.CourseDao;
import me.debugjoker.dao.SuccessChooseDao;
import me.debugjoker.dto.CourseExecution;
import me.debugjoker.dto.Exposer;
import me.debugjoker.entity.Course;
import me.debugjoker.entity.SuccessChoose;
import me.debugjoker.enums.CourseStateEnum;
import me.debugjoker.exception.ChooseCloseException;
import me.debugjoker.exception.ChooseException;
import me.debugjoker.exception.RepeatChooseException;
import me.debugjoker.service.CourseService;
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;
@Service public class CourseServiceImpl implements CourseService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private CourseDao courseDao;
@Autowired
private SuccessChooseDao successChooseDao;
//MD5加密混淆值
private final String slat = "skcAsw;sjc,q01;'`l0QWcjeJ.";
public List<Course> getCourseList() {
return courseDao.queryAll(0, 100);
}
public Course queryCourseById(long courseId) {
return courseDao.queryById(courseId);
}
public Exposer exportCourseUrl(long courseId) {
Course course = courseDao.queryById(courseId);
if (course == null) {
//没有查到这门课
return new Exposer(false, courseId);
}
Date startTime = course.getStartTime();
Date endTime = course.getEndTime();
Date nowTime = new Date();
//判断选课是否开始
if (nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()) {
//选课未开始或者选课已经结束 不暴露选课URL地址
return new Exposer(false, courseId, nowTime.getTime(), startTime.getTime(), endTime.getTime());
}
String md5 = getMD5(courseId);
return new Exposer(true, md5, courseId);
}
//注解开启事务
@Transactional
public CourseExecution executeCourseChoose(long courseId, long studentId, String md5) throws ChooseException, ChooseCloseException, RepeatChooseException {
if (md5 == null || !md5.equals(getMD5(courseId))) {
throw new ChooseException("MD5数据被篡改");
}
//执行选课逻辑
Date nowTime = new Date();
try {
int updateCount = courseDao.reduceNumber(courseId, nowTime);
if (updateCount <= 0) {
//选课失败
throw new ChooseCloseException("选课已结束");
} else {
int insertCount = successChooseDao.insertSuccessChoose(courseId, studentId);
if (insertCount <= 0) {
throw new RepeatChooseException("重复选课");
} else {
SuccessChoose successChoose = successChooseDao.queryByIdwithCourse(courseId, studentId);
return new CourseExecution(courseId, CourseStateEnum.SUCCESS, successChoose);
}
}
} catch (ChooseCloseException e) {
throw e;
} catch (RepeatChooseException e) {
throw e;
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new ChooseException("内部逻辑异常" + e.getMessage());
}
}
//根据课程id生成MD5字符串串
private String getMD5(long seckillId) {
String base = seckillId + "/" + slat;
String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
return md5;
}
}
新建enums包创建数据字典枚举类
package me.debugjoker.enums;
/**
* 数据字典枚举
*/
public enum CourseStateEnum {
SUCCESS (1,"选课成功"),
END(0,"选课已结束"),
REPEAT_CHOOSE(-1,"重复选课"),
INNER_ERROR(-2,"系统异常"),
DATA_REWRITE(-3,"数据篡改");
private int state;
private String stateInfo;
CourseStateEnum(int state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
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 CourseStateEnum stateEnum(int index){
for (CourseStateEnum stateEnum : values()){
if (stateEnum.getState() == index){
return stateEnum;
}
}
return null;
}
}
Spring整合service
resources/spring下新建spring-service.xml
使用@Service和@Autowired 配置声明式事务@Transactional
<?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.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">
<!--扫描service包下所有使用注解的类型-->
<context:component-scan base-package="me.debugjoker.service"/>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据库连接池-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置基于注解的声明式事务 默认使用注解来管理事务行为-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
配置logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>