分块化

This commit is contained in:
qiurunze 2019-02-03 22:17:07 +08:00
parent 9c25abb1ae
commit cc2860ae71
169 changed files with 19987 additions and 7 deletions

25
miaosha-2version/.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/

Binary file not shown.

View File

@ -0,0 +1 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>miaosha</artifactId>
<groupId>com.geekq</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>miaosha-common</artifactId>
<dependencies>
<!--lombook引用-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,17 @@
package com.geekq.miasha.entity;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @author qiurunze
*/
@Getter
@Setter
public class BaseDomain implements Serializable {
protected Long id;
}

View File

@ -0,0 +1,20 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
private Long id;
private String goodsName;
private String goodsTitle;
private String goodsImg;
private String goodsDetail;
private Double goodsPrice;
private Integer goodsStock;
}

View File

@ -0,0 +1,46 @@
package com.geekq.miasha.entity;
import lombok.Getter;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
import java.util.Date;
/**
* 登陆日志
* @author Administrator
*/
@Getter
@Setter
@Alias("IpLog")
public class IpLog extends BaseDomain {
public static int LOGINSTATE_FAILD = 0;//登陆失败
public static int LOGINSTATE_SUCCESS = 1;//登陆成功
private String username;
private Date loginTime;
private String ip;
private int loginState;
private int loginType;
private Long loginInfoId;
public String getDisplayState(){
return this.loginState==LOGINSTATE_FAILD?"登录失败":"登录成功";
}
public IpLog() {
super();
}
public IpLog(String username, Date loginTime, String ip, int loginType,
Long loginInfoId) {
super();
this.username = username;
this.loginTime = loginTime;
this.ip = ip;
this.loginState = IpLog.LOGINSTATE_FAILD;
this.loginType = loginType;
this.loginInfoId = loginInfoId;
}
}

View File

@ -0,0 +1,27 @@
package com.geekq.miasha.entity;
import com.geekq.miasha.enums.Constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Logininfo implements Serializable {
private Long id;
private String nickname;
private String password;
private String salt;
private Date registerDate;
private Date lastLoginDate;
private int state = Constants.STATE_NORMAL;
private int userType;//用户类型
private boolean admin = false;
}

View File

@ -0,0 +1,45 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 消息中心主体表
*/
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MiaoShaMessageInfo implements Serializable {
private Integer id ;
private Long messageId ;
private Long userId ;
private String content ;
private Date createTime;
private Integer status ;
private Date overTime ;
private Integer messageType ;
private Integer sendType ;
private String goodName ;
private BigDecimal price ;
private String messageHead ;
}

View File

@ -0,0 +1,30 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
/**
* 消息中心用戶存储关系表
*/
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MiaoShaMessageUser implements Serializable {
private Long id ;
private Long userId ;
private Long messageId ;
private String goodId ;
private Date orderId;
}

View File

@ -0,0 +1,22 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Alias("MiaoshaGoods")
public class MiaoshaGoods {
private Long id;
private Long goodsId;
private Integer stockCount;
private Date startDate;
private Date endDate;
}

View File

@ -0,0 +1,19 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Alias("miaoshaorder")
public class MiaoshaOrder {
private Long id;
private Long userId;
private Long orderId;
private Long goodsId;
}

View File

@ -0,0 +1,39 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Alias("MiaoshaUser")
public class MiaoshaUser {
private Long id;
private String nickname;
private String password;
private String salt;
private String head;
private Date registerDate;
private Date lastLoginDate;
private Integer loginCount;
@Override
public String toString() {
return "Logininfo{" +
"id=" + id +
", nickname='" + nickname + '\'' +
", password='" + password + '\'' +
", salt='" + salt + '\'' +
", head='" + head + '\'' +
", registerDate=" + registerDate +
", lastLoginDate=" + lastLoginDate +
", loginCount=" + loginCount +
'}';
}
}

View File

@ -0,0 +1,28 @@
package com.geekq.miasha.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Alias("OrderInfo")
public class OrderInfo {
private Long id;
private Long userId;
private Long goodsId;
private Long deliveryAddrId;
private String goodsName;
private Integer goodsCount;
private Double goodsPrice;
private Integer orderChannel;
private Integer status;
private Date createDate;
private Date payDate;
}

View File

@ -0,0 +1,26 @@
package com.geekq.miasha.enums;
public class Constanst {
public static String CLOSE_ORDER_INFO_TASK_LOCK = "CLOSE_ORDER_INFO_KEY";
public static String COUNTLOGIN = "count:login";
public enum orderStaus{
ORDER_NOT_PAY("新建未支付");
orderStaus(String name){
this.name=name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -0,0 +1,15 @@
package com.geekq.miasha.enums;
/**
* @author 邱润泽
* 常用数据静态变量类型集合
*/
public class Constants {
public static final int STATE_NORMAL = 0;
public static final int STATE_LOCK = 1;
public static final int STATE_DELETE = -1;
public static final int USERTYPE_NORMAL = 0;//前段用户
public static final int USERTYPE_SYSTEM = 1;//后台用户
}

View File

@ -0,0 +1,67 @@
package com.geekq.miasha.enums;
public class MessageStatus {
public static final Integer ZORE = 0;
/**
* 消息类型
*/
public enum messageType {
maiosha_message("秒杀消息"),
buy_message("购买消息"),
system_message("系统消息");
private String message;
private messageType(String message){
this.message = message;
}
public String getMessage() {
return message;
}
}
/**
* 消息内容
*/
public enum ContentEnum {
system_message_register(7000,"尊敬的用户你好,你已经成功注册!"),
system_message_register_head(7001,"注册成功");
private int code;
private String message;
private ContentEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
/**
* 消息类型
*/
public enum sendType {
// maiosha_message("秒杀消息"),
// buy_message("购买消息"),
// system_message("系统消息");
// private String message;
//
// private messageType(String message){
// this.message = message;
// }
//
// public String getMessage() {
// return message;
// }
}
}

View File

@ -0,0 +1,40 @@
package com.geekq.miasha.enums;
/**
*
* @Description: 订单状态
*/
public enum OrderStatusEnum {
WAIT_PAY(10, "待付款"), // 代付款
PAYING(20, "付款中"), // 付款中
PAID(30, "已付款"), // 已付款
PAID_FAILD(40, "付款失败"), // 付款失败
CANCELED(50, "已取消"), // 已取消
CLOSED(60, "交易关闭"); // 超时未支付, 交易关闭
public final int key;
public final String value;
OrderStatusEnum(int key, String value) {
this.key = key;
this.value = value;
}
public static String getName(int key) {
for (OrderStatusEnum status : OrderStatusEnum.values()) {
if (status.getKey() == key) {
return status.value;
}
}
return null;
}
public int getKey() {
return key;
}
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,23 @@
package com.geekq.miasha.enums;
/**
*
* @Description: 男女枚举
*/
public enum SexEnum {
GIRL(0), //
BOY(1), //
SECRET(2); // 保密
public final int value;
SexEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@ -0,0 +1,22 @@
package com.geekq.miasha.enums;
/**
*
* @Description: 是否枚举
*/
public enum YesOrNo {
YES(1), // 有错误
NO(0); // 无错误
public final int value;
YesOrNo(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@ -0,0 +1,67 @@
package com.geekq.miasha.enums.enums;
public class MessageStatus {
public static final Integer ZORE = 0;
/**
* 消息类型
*/
public enum messageType {
maiosha_message("秒杀消息"),
buy_message("购买消息"),
system_message("系统消息");
private String message;
private messageType(String message){
this.message = message;
}
public String getMessage() {
return message;
}
}
/**
* 消息内容
*/
public enum ContentEnum {
system_message_register(7000,"尊敬的用户你好,你已经成功注册!"),
system_message_register_head(7001,"注册成功");
private int code;
private String message;
private ContentEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
/**
* 消息类型
*/
public enum sendType {
// maiosha_message("秒杀消息"),
// buy_message("购买消息"),
// system_message("系统消息");
// private String message;
//
// private messageType(String message){
// this.message = message;
// }
//
// public String getMessage() {
// return message;
// }
}
}

View File

@ -0,0 +1,103 @@
package com.geekq.miasha.enums.enums;
/**
* 普通返回类
* 1打头 系统系列错误
* 2 注册登录系列错误
* 3 check 系列错误
* 4 秒杀错误
* 5 商品错误
* 6 订单错误
* @author qiurunze
*/
public enum ResultStatus {
SUCCESS(0, "成功"),
FAILD(-1, "失败"),
EXCEPTION(-1, "系统异常"),
PARAM_ERROR(10000, "参数错误"),
SYSTEM_ERROR(10001, "系统错误"),
FILE_NOT_EXIST(10002, "文件不存在"),
FILE_NOT_DOWNLOAD(10003, "文件没有下载"),
FILE_NOT_GENERATE(10004, "文件没有生成"),
FILE_NOT_STORAGE(10005, "文件没有入库"),
SYSTEM_DB_ERROR(10006, "数据库系统错误"),
FILE_ALREADY_DOWNLOAD(10007, "文件已经下载"),
DATA_ALREADY_PEXISTS(10008, "数据已经存在"),
/**
* 注册登录
*/
RESIGETR_SUCCESS(20000,"注册成功!"),
RESIGETER_FAIL(200001,"注册失败!"),
CODE_FAIL(200002,"验证码不一致!"),
/**
* check
*/
BIND_ERROR (30001,"参数校验异常:%s"),
ACCESS_LIMIT_REACHED (30002,"请求非法!"),
REQUEST_ILLEGAL (30004,"访问太频繁!"),
SESSION_ERROR (30005,"Session不存在或者已经失效!"),
PASSWORD_EMPTY (30006,"登录密码不能为空!"),
MOBILE_EMPTY (30007,"手机号不能为空!"),
MOBILE_ERROR (30008,"手机号格式错误!"),
MOBILE_NOT_EXIST (30009,"手机号不存在!"),
PASSWORD_ERROR (30010,"密码错误!"),
USER_NOT_EXIST(30011,"用户不存在!"),
/**
* 订单模块
*/
ORDER_NOT_EXIST(60001,"订单不存在"),
/**
* 秒杀模块
*/
MIAO_SHA_OVER(40001,"商品已经秒杀完毕"),
REPEATE_MIAOSHA(40002,"不能重复秒杀"),
MIAOSHA_FAIL(40003,"秒杀失败");
/**
* 商品模块
*/
private int code;
private String message;
private ResultStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return this.code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public String getName() {
return this.name();
}
public String getOutputName() {
return this.name();
}
public String toString() {
return this.getName();
}
private ResultStatus(Object... args) {
this.message = String.format(this.message, args);
}
}

View File

@ -0,0 +1,63 @@
package com.geekq.miasha.enums.resultbean;
import com.geekq.miasha.enums.enums.ResultStatus;
public class AbstractResult {
private ResultStatus status;
private int code;
private String message;
protected AbstractResult(ResultStatus status, String message) {
this.code = status.getCode();
this.status = status;
this.message = message;
}
protected AbstractResult(ResultStatus status) {
this.code = status.getCode();
this.message = status.getMessage();
this.status = status;
}
public static boolean isSuccess(AbstractResult result) {
return result != null && result.status == ResultStatus.SUCCESS && result.getCode() == ResultStatus.SUCCESS.getCode();
}
public AbstractResult withError(ResultStatus status) {
this.status = status;
return this;
}
public AbstractResult withError(String message) {
this.status = ResultStatus.SYSTEM_ERROR;
this.message = message;
return this;
}
public AbstractResult withError(int code, String message) {
this.code = code;
this.message = message;
return this;
}
public AbstractResult success() {
this.status = ResultStatus.SUCCESS;
return this;
}
public ResultStatus getStatus() {
return this.status;
}
public String getMessage() {
return this.message == null ? this.status.getMessage() : this.message;
}
public int getCode() {
return this.code;
}
public void setCode(int code) {
this.code = code;
}
}

View File

@ -0,0 +1,53 @@
package com.geekq.miasha.enums.resultbean;
import com.geekq.miasha.enums.enums.ResultStatus;
import java.io.Serializable;
public class ResultGeekQ<T> extends AbstractResult implements Serializable {
private static final long serialVersionUID = 867933019328199779L;
private T data;
private Integer count;
protected ResultGeekQ(ResultStatus status, String message) {
super(status, message);
}
protected ResultGeekQ(ResultStatus status) {
super(status);
}
public static <T> ResultGeekQ<T> build() {
return new ResultGeekQ(ResultStatus.SUCCESS, (String)null);
}
public static <T> ResultGeekQ<T> build(String message) {
return new ResultGeekQ(ResultStatus.SUCCESS, message);
}
public static <T> ResultGeekQ<T> error(ResultStatus status) {
return new ResultGeekQ<T>(status);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Integer getCount() {
return this.count;
}
public void setCount(Integer count) {
this.count = count;
}
public void success(T value) {
this.success();
this.data = value;
this.count = 0;
}
}

View File

@ -0,0 +1,23 @@
package com.geekq.miasha.exception;
import com.geekq.miasha.enums.enums.ResultStatus;
public class GlobleException extends RuntimeException {
private ResultStatus status;
public GlobleException(ResultStatus status){
super();
this.status = status;
}
public ResultStatus getStatus() {
return status;
}
public void setStatus(ResultStatus status) {
this.status = status;
}
}

View File

@ -0,0 +1,50 @@
package com.geekq.miasha.exception;
import com.geekq.miasha.enums.enums.ResultStatus;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import static com.geekq.miasha.enums.enums.ResultStatus.SESSION_ERROR;
import static com.geekq.miasha.enums.enums.ResultStatus.SYSTEM_ERROR;
/**
* 拦截异常
* @author qiurunze
*/
@ControllerAdvice
@ResponseBody
public class GlobleExceptionHandler {
private static Logger logger = LoggerFactory.getLogger(GlobleExceptionHandler.class);
@ExceptionHandler(value=Exception.class)
public ResultGeekQ<String> exceptionHandler(HttpServletRequest request , Exception e){
e.printStackTrace();
if(e instanceof GlobleException){
GlobleException ex= (GlobleException)e;
return ResultGeekQ.error(ex.getStatus());
}else if( e instanceof BindException){
BindException ex = (BindException) e ;
List<ObjectError> errors = ex.getAllErrors();
ObjectError error = errors.get(0);
String msg = error.getDefaultMessage();
/**
* 打印堆栈信息
*/
logger.error(String.format(msg, msg));
return ResultGeekQ.error(SESSION_ERROR);
}else {
return ResultGeekQ.error(SYSTEM_ERROR);
}
}
}

View File

@ -0,0 +1,61 @@
package com.geekq.miasha.utils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.Date;
/**
* Created by geely
*/
public class DateTimeUtils {
//joda-time
//str->Date
//Date->str
public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static Date strToDate(String dateTimeStr,String formatStr){
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr);
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
return dateTime.toDate();
}
public static String dateToStr(Date date,String formatStr){
if(date == null){
return StringUtils.EMPTY;
}
DateTime dateTime = new DateTime(date);
return dateTime.toString(formatStr);
}
public static Date strToDate(String dateTimeStr){
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT);
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
return dateTime.toDate();
}
public static String dateToStr(Date date){
if(date == null){
return StringUtils.EMPTY;
}
DateTime dateTime = new DateTime(date);
return dateTime.toString(STANDARD_FORMAT);
}
public static void main(String[] args) {
System.out.println(DateTimeUtils.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
System.out.println(DateTimeUtils.strToDate("2010-01-01 11:11:11","yyyy-MM-dd HH:mm:ss"));
}
}

View File

@ -0,0 +1,65 @@
package com.geekq.miasha.utils;
import org.apache.commons.codec.digest.DigestUtils;
import java.security.SecureRandom;
/**
* @author 邱润泽
*/
public class MD5Utils {
public static String md5(String src) {
return DigestUtils.md5Hex(src);
}
public static final String getSaltT (){
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[15];
random.nextBytes(bytes);
String salt = org.apache.commons.codec.binary.Base64.encodeBase64String(bytes);
return salt;
}
private static String getSalt = getSaltT();
public static String MD5( String keyName ){
/**
* 返回16
*/
return DigestUtils.md5Hex(keyName);
}
/**
* 测试使用
* @param inputPass
* @return
*/
public static String inputPassFormPass ( String inputPass ){
String str = "" + getSalt.charAt(0) + getSalt.charAt(2) + inputPass + getSalt.charAt(4) + getSalt.charAt(6) ;
return MD5(str);
}
/**
* 盐值salt 随机 二次加密
* @param inputPass
* @return
*/
public static String formPassFormPass ( String inputPass ){
String str = "" + getSalt.charAt(0) + getSalt.charAt(2) +inputPass + getSalt.charAt(4) + getSalt.charAt(6) ;
return MD5(str);
}
/**
* 第二次md5--反解密 用户登录验证 --- salt 可随机 
* @param formPass
* @param salt
* @return
*/
public static String formPassToDBPass ( String formPass ,String salt ) {
String str = "" + salt.charAt(0) + salt.charAt(2)+ formPass + salt.charAt(4) + salt.charAt(6) ;
return MD5(str);
}
}

View File

@ -0,0 +1,163 @@
package com.geekq.miasha.utils;
/**
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识由于long基本类型在Java中是带符号的最高位是符号位正数是0负数是1所以id一般是正数最高位是0<br>
* 41位时间截(毫秒级)注意41位时间截不是存储当前时间的时间截而是存储时间截的差值当前时间截 - 开始时间截)
* 得到的值这里的的开始时间截一般是我们的id生成器开始使用的时间由我们程序来指定的如下下面程序IdWorker类的startTime属性41位的时间截可以使用69年年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位可以部署在1024个节点包括5位datacenterId和5位workerId<br>
* 12位序列毫秒内的计数12位的计数顺序号支持每个节点每毫秒(同一机器同一时间截)产生4096个ID序号<br>
* 加起来刚好64位为一个Long型<br>
* SnowFlake的优点是整体上按照时间自增排序并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分)并且效率较高经测试SnowFlake每秒能够产生26万ID左右
*/
public class SnowflakeIdWorker {
// ==============================Fields===========================================
/** 开始时间截 (2015-01-01) */
private final long twepoch = 1420041600000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码这里为4095 (0b111111111111=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
//==============================Constructors=====================================
/**
* 构造函数
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 生成订单唯一ID
* @param workerId
* @param datacenterId
* @return
*/
public static long getOrderId(long workerId, long datacenterId){
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
return idWorker.nextId();
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
//==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
for (int i = 0; i < 1000; i++) {
long id = idWorker.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
}
}
}

View File

@ -0,0 +1,10 @@
package com.geekq.miasha.utils;
import java.util.UUID;
public class UUIDUtil {
public static String uuid(){
return UUID.randomUUID().toString().replace("-","");
}
}

View File

@ -0,0 +1,22 @@
package com.geekq.miasha.utils;
import com.geekq.miasha.entity.MiaoshaUser;
public class UserContext {
private static ThreadLocal<MiaoshaUser> userHolder = new ThreadLocal<MiaoshaUser>();
public static void setUser(MiaoshaUser user) {
userHolder.set(user);
}
public static MiaoshaUser getUser() {
return userHolder.get();
}
public static void removeUser() {
userHolder.remove();
}
}

View File

@ -0,0 +1,22 @@
package com.geekq.miasha.utils;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ValidatorUtil {
private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
public static boolean isMobile(String src) {
if(StringUtils.isEmpty(src)) {
return false;
}
Matcher m = mobile_pattern.matcher(src);
return m.matches();
}
}

View File

@ -0,0 +1,19 @@
package com.geekq.miasha.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {MobileValidator.class})
public @interface MobileCheck {
boolean required() default true ;
String message() default "手机号码格式有误!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,30 @@
package com.geekq.miasha.validator;
import com.geekq.miasha.utils.ValidatorUtil;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MobileValidator implements ConstraintValidator<MobileCheck, String> {
private boolean require = false ;
@Override
public void initialize(MobileCheck isMobile) {
require = isMobile.required() ;
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if(require){
return ValidatorUtil.isMobile(value) ;
}else{
if(StringUtils.isEmpty(value)){
return true ;
}else {
return ValidatorUtil.isMobile(value) ;
}
}
}
}

View File

@ -0,0 +1,20 @@
package com.geekq.miasha.vo;
import com.geekq.miasha.entity.MiaoshaUser;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class GoodsDetailVo {
private int miaoshaStatus = 0;
private int remainSeconds = 0;
private GoodsVo goods ;
private MiaoshaUser user;
}

View File

@ -0,0 +1,22 @@
package com.geekq.miasha.vo;
import com.geekq.miasha.entity.Goods;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.Alias;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Alias("goodsVo")
public class GoodsVo extends Goods {
private Double miaoshaPrice;
private Integer stockCount;
private Date startDate;
private Date endDate;
}

View File

@ -0,0 +1,32 @@
package com.geekq.miasha.vo;
import com.geekq.miasha.validator.MobileCheck;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class LoginVo {
@NotNull
@MobileCheck
private String mobile ;
@NotNull
@Length(min=32)
private String password;
@Override
public String toString() {
return "LoginVo{" +
"mobile='" + mobile + '\'' +
", password='" + password + '\'' +
'}';
}
}

View File

@ -0,0 +1,47 @@
package com.geekq.miasha.vo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MiaoShaMessageVo implements Serializable {
private static final long serialVersionUID = -1341750239648941486L;
private Integer id ;
private Long userId;
private String goodId ;
private Date orderId;
private Long messageId ;
private String content ;
private Date createTime;
private Integer status ;
private Date overTime ;
private Integer messageType ;
private Integer sendType ;
private String goodName ;
private BigDecimal price ;
private String messageHead ;
}

View File

@ -0,0 +1,28 @@
package com.geekq.miasha.vo;
import com.geekq.miasha.entity.OrderInfo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class OrderDetailVo {
private GoodsVo goods;
private OrderInfo order;
public GoodsVo getGoods() {
return goods;
}
public void setGoods(GoodsVo goods) {
this.goods = goods;
}
public OrderInfo getOrder() {
return order;
}
public void setOrder(OrderInfo order) {
this.order = order;
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>miaosha</artifactId>
<groupId>com.geekq</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>miaosha-service</artifactId>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.ini</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,20 @@
package com.geekq.miaosha.mapper;
import com.geekq.miasha.entity.MiaoshaGoods;
import com.geekq.miasha.vo.GoodsVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author 邱润泽
*/
public interface GoodsMapper {
public List<GoodsVo> listGoodsVo();
public GoodsVo getGoodsVoByGoodsId(@Param("goodsId") long goodsId);
public int reduceStock(MiaoshaGoods g);
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.geekq.miaosha.mapper.GoodsMapper" >
<resultMap id="BaseResultMap" type="goodsVo" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="goods_name" property="goodsName" jdbcType="VARCHAR" />
<result column="goods_title" property="goodsTitle" jdbcType="VARCHAR" />
<result column="goods_img" property="goodsImg" jdbcType="VARCHAR" />
<result column="goods_detail" property="goodsDetail" jdbcType="VARCHAR" />
<result column="goods_price" property="goodsPrice" jdbcType="DOUBLE" />
<result column="goods_stock" property="goodsStock" jdbcType="BIGINT" />
<result column="stock_count" property="stockCount" jdbcType="BIGINT" />
<result column="start_date" property="startDate" jdbcType="TIMESTAMP" />
<result column="end_date" property="endDate" jdbcType="TIMESTAMP" />
<result column="miaosha_price" property="miaoshaPrice" jdbcType="DOUBLE" />
</resultMap>
<sql id="base_column">
miaosha_goods.id as id, goods_name, goods_title, goods_img, goods_detail, goods_price, goods_stock,stock_count,start_date
,end_date,miaosha_price
</sql>
<select id="listGoodsVo" resultMap="BaseResultMap" >
select <include refid="base_column" />
from miaosha_goods left join goods on miaosha_goods.goods_id = goods.id
</select>
<select id="getGoodsVoByGoodsId" resultMap="BaseResultMap" >
select <include refid="base_column" />
from miaosha_goods left join goods on miaosha_goods.goods_id = goods.id
WHERE miaosha_goods.goods_id = #{goodsId,jdbcType=BIGINT}
</select>
<update id="reduceStock" >
update miaosha_goods set stock_count = stock_count - 1
where goods_id = #{goodsId} and stock_count > 0
</update>
</mapper>

View File

@ -0,0 +1,19 @@
package com.geekq.miaosha.mapper;
import com.geekq.miasha.entity.IpLog;
import java.util.List;
public interface IpLogMapper {
int deleteByPrimaryKey(Long id);
int insert(IpLog record);
IpLog selectByPrimaryKey(Long id);
List<IpLog> selectAll();
int updateByPrimaryKey(IpLog record);
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.geekq.miaosha.mapper.IpLogMapper" >
<resultMap id="BaseResultMap" type="IpLog" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="ip" property="ip" jdbcType="VARCHAR" />
<result column="loginState" property="loginState" jdbcType="TINYINT" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="loginInfoId" property="loginInfoId" jdbcType="BIGINT" />
<result column="loginType" property="loginType" jdbcType="TINYINT" />
<result column="loginTime" property="loginTime" jdbcType="TIMESTAMP" />
</resultMap>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
delete from iplog
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="IpLog" useGeneratedKeys="true" keyProperty="id" >
insert into iplog (ip, loginState, username,
loginInfoId, loginType, loginTime)
values (#{ip,jdbcType=VARCHAR}, #{loginState,jdbcType=TINYINT}, #{username,jdbcType=VARCHAR},
#{loginInfoId,jdbcType=BIGINT}, #{loginType,jdbcType=TINYINT}, #{loginTime,jdbcType=TIMESTAMP})
</insert>
<update id="updateByPrimaryKey" parameterType="IpLog" >
update iplog
set ip = #{ip,jdbcType=VARCHAR},
loginState = #{loginState,jdbcType=TINYINT},
username = #{username,jdbcType=VARCHAR},
loginInfoId = #{loginInfoId,jdbcType=BIGINT},
loginType = #{loginType,jdbcType=TINYINT},
loginTime = #{loginTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
<sql id="base_column">
id, ip, loginState, username, loginInfoId, loginType, loginTime
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select <include refid="base_column" />
from iplog
where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectAll" resultMap="BaseResultMap" >
select <include refid="base_column" />
from iplog
</select>
<sql id="base_query">
<where>
<if test="beginDate!=null">
AND loginTime &gt;=#{beginDate}
</if>
<if test="endDate!=null">
AND loginTime &lt;=#{endDate}
</if>
<if test="username!=null and like">
AND username like concat('%',#{username},'%')
</if>
<if test="username!=null and !like">
AND username =#{username}
</if>
<if test="userType>-1">
AND loginType =#{userType}
</if>
<if test="state >-1">
AND loginstate = #{state}
</if>
</where>
</sql>
</mapper>

View File

@ -0,0 +1,31 @@
package com.geekq.miaosha.mapper;
import com.geekq.miasha.entity.Logininfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface LogininfoMapper {
int deleteByPrimaryKey(Long id);
int insert(Logininfo record);
Logininfo selectByPrimaryKey(Long id);
List<Logininfo> selectAll();
int updateByPrimaryKey(Logininfo record);
int getCountByNickname(@Param("nickname") String nickname,
@Param("userType") int userType);
Logininfo getLoginInfoByNickname(@Param("nickname") String nickname,
@Param("userType") int userType);
Logininfo login(@Param("name") String name,
@Param("password") String password, @Param("userType") int userType);
List<Map<String, Object>> autoComplate(@Param("word") String word, @Param("userType") int userType);
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.geekq.miaosha.mapper.LogininfoMapper">
<!--<cache type="redis" />-->
<resultMap id="BaseResultMap" type="com.geekq.miasha.entity.Logininfo">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="nickname" jdbcType="VARCHAR" property="nickname" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="state" jdbcType="TINYINT" property="state" />
<result column="admin" property="admin" />
<result column="usertype" property="userType" />
<result column="salt" property="salt" />
<result column="usertype" property="userType" />
<result column="registerDate" property="registerDate" />
<result column="lastLoginDate" property="lastLoginDate" />
</resultMap>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from
logininfo
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" keyProperty="id" parameterType="com.geekq.miasha.entity.Logininfo" useGeneratedKeys="true">
insert into logininfo (nickname,password, state,usertype,admin,salt,registerdate,lastlogindate)
values (#{nickname,jdbcType=VARCHAR},#{password,jdbcType=VARCHAR},#{state,jdbcType=TINYINT},#{userType},#{admin}
,#{salt},#{registerDate},#{lastLoginDate})
</insert>
<update id="updateByPrimaryKey" parameterType="com.geekq.miasha.entity.Logininfo">
update logininfo set nickname = #{nickname,jdbcType=VARCHAR},password =#{password,jdbcType=VARCHAR},
state = #{state,jdbcType=TINYINT},usertype = #{userType},admin=#{admin},salt = #{salt},
registerdate = #{registerDate},lastlogindate = #{lastLoginDate}
where id = #{id,jdbcType=BIGINT}
</update>
<sql id="base_column">
id, nickname, password, state,usertype,admin ,salt , registerdate , lastlogindate
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap" useCache="true">
select <include refid="base_column" />
from logininfo where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectAll" resultMap="BaseResultMap" useCache="false">
select <include refid="base_column" />
from logininfo
</select>
<select id="getCountByNickname" resultType="int" useCache="false">
select count(id) from logininfo where nickname=#{nickname} and usertype = #{userType}
</select>
<select id="getLoginInfoByNickname" resultMap="BaseResultMap" useCache="false">
select <include refid="base_column" />
from logininfo where nickname=#{nickname} and usertype = #{userType}
</select>
<select id="login" resultMap="BaseResultMap" useCache="true">
select <include refid="base_column"/>
from logininfo where nickname= #{name} and password=#{password} and usertype=#{userType}
</select>
<select id="autoComplate" resultType="hashmap" useCache="false">
select id,nickname as name
from logininfo where nickname LIKE concat(#{word},'%') AND usertype = #{userType}
</select>
</mapper>

View File

@ -0,0 +1,19 @@
package com.geekq.miaosha.mapper;
import com.geekq.miasha.entity.MiaoshaUser;
import org.apache.ibatis.annotations.Param;
/**
* @author 邱润泽
*/
public interface MiaoShaUserMapper {
public MiaoshaUser getByNickname(@Param("nickname") String nickname) ;
public MiaoshaUser getById(@Param("id") long id) ;
public void update(MiaoshaUser toBeUpdate);
public void insertMiaoShaUser(MiaoshaUser miaoshaUser);
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.geekq.miaosha.mapper.MiaoShaUserMapper" >
<resultMap id="BaseResultMap" type="MiaoshaUser" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="nickname" property="nickname" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="BIGINT" />
<result column="salt" property="salt" jdbcType="VARCHAR" />
<result column="head" property="head" jdbcType="VARCHAR" />
<result column="register_date" property="registerDate" jdbcType="TIMESTAMP" />
<result column="last_login_date" property="lastLoginDate" jdbcType="TIMESTAMP" />
<result column="login_count" property="loginCount" jdbcType="BIGINT" />
</resultMap>
<sql id="base_column">
id,nickname,password,salt,head,register_date,last_login_date,login_count
</sql>
<select id="getByNickname" resultMap="BaseResultMap" >
select <include refid="base_column" />
from miaosha_user where nickname = #{nickname}
</select>
<select id="getById" resultMap="BaseResultMap" >
select <include refid="base_column" />
from miaosha_user where id = #{id}
</select>
<insert id="insertMiaoShaUser" parameterType="miaoshauser" useGeneratedKeys="true" keyProperty="id" >
insert into miaosha_user (id , nickname ,password , salt ,head,register_date,last_login_date)
value (#{id},#{nickname},#{password},#{salt},#{head},
#{registerDate},#{lastLoginDate})
</insert>
<update id="update" parameterType="miaoshauser" >
update miaosha_user set password = #{password} where id = #{id}
</update>
</mapper>

View File

@ -0,0 +1,26 @@
package com.geekq.miaosha.mapper;
import com.geekq.miasha.entity.MiaoshaOrder;
import com.geekq.miasha.entity.OrderInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author 邱润泽
*/
public interface OrderMapper {
public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(@Param("userNickName") long userNickName, @Param("goodsId") long goodsId);
public long insert(OrderInfo orderInfo);
public int insertMiaoshaOrder(MiaoshaOrder miaoshaOrder);
public OrderInfo getOrderById(@Param("orderId") long orderId);
public List<OrderInfo> selectOrderStatusByCreateTime(@Param("status") Integer status, @Param("createDate") String createDate);
public int closeOrderByOrderInfo();
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.geekq.miaosha.mapper.OrderMapper" >
<resultMap id="BaseResultMap" type="OrderInfo" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="user_id" property="userId" jdbcType="BIGINT" />
<result column="goods_id" property="goodsId" jdbcType="BIGINT" />
<result column="delivery_addr_id" property="deliveryAddrId" jdbcType="BIGINT" />
<result column="goods_name" property="goodsName" jdbcType="VARCHAR" />
<result column="goods_count" property="goodsCount" jdbcType="BIGINT" />
<result column="goods_price" property="goodsPrice" jdbcType="DOUBLE" />
<result column="order_channel" property="orderChannel" jdbcType="DOUBLE" />
<result column="status" property="status" jdbcType="BIGINT" />
<result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
<result column="pay_date" property="payDate" jdbcType="TIMESTAMP" />
</resultMap>
<resultMap id="BaseResultMapMiaoShaOrder" type="miaoshaorder" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="user_id" property="userId" jdbcType="BIGINT" />
<result column="order_id" property="orderId" jdbcType="BIGINT" />
<result column="goods_id" property="goodsId" jdbcType="BIGINT" />
</resultMap>
<sql id="base_column">
id,user_id,goods_id,delivery_addr_id,goods_name,goods_count,goods_price,order_channel
,status,create_date,pay_date
</sql>
<sql id="base_column_miaosha_order">
id,user_id,goods_id,order_id
</sql>
<select id="getMiaoshaOrderByUserIdGoodsId" resultMap="BaseResultMapMiaoShaOrder" >
select <include refid="base_column_miaosha_order" />
from miaosha_order where user_id=#{userNickName} and goods_id=#{goodsId}
</select>
<select id="getOrderById" resultMap="BaseResultMap" >
select * from order_info where id = #{orderId}
</select>
<insert id="insert" parameterType="miaoshaorder" useGeneratedKeys="true" keyProperty="id" >
insert into order_info(user_id, goods_id, goods_name, goods_count, goods_price, order_channel, status, create_date)values( #{userId}, #{goodsId}, #{goodsName}, #{goodsCount}, #{goodsPrice}, #{orderChannel},#{status},#{createDate} )
</insert>
<insert id="insertMiaoshaOrder" parameterType="OrderInfo" useGeneratedKeys="true" keyProperty="id" >
insert into miaosha_order (user_id, goods_id, order_id)values(#{userId}, #{goodsId}, #{orderId})
</insert>
<select id="selectOrderStatusByCreateTime" resultMap="BaseResultMap" >
select * from order_info where status=#{status} and create_Date $lt;=#{createDate}
</select>
<update id="closeOrderByOrderInfo" parameterType="int" >
update order_info set status=0 where id=#{id}
</update>
</mapper>

View File

@ -0,0 +1,99 @@
package com.geekq.miaosha.rabbitmq;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class MQConfig {
/**
* /usr/sbin/rabbitmq-plugins enable rabbitmq_management
* mq页面
*/
public static final String MIAOSHA_QUEUE = "miaosha.queue";
public static final String EXCHANGE_TOPIC = "exchange_topic";
public static final String MIAOSHA_MESSAGE = "miaosha_mess";
public static final String MIAOSHATEST = "miaoshatest";
public static final String QUEUE = "queue";
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";
public static final String HEADER_QUEUE = "header.queue";
public static final String TOPIC_EXCHANGE = "topicExchage";
public static final String FANOUT_EXCHANGE = "fanoutxchage";
public static final String HEADERS_EXCHANGE = "headersExchage";
/**
* Direct模式 交换机Exchange
* */
@Bean
public Queue queue() {
return new Queue(QUEUE, true);
}
/**
* Topic模式 交换机Exchange
* */
@Bean
public Queue topicQueue1() {
return new Queue(TOPIC_QUEUE1, true);
}
@Bean
public Queue topicQueue2() {
return new Queue(TOPIC_QUEUE2, true);
}
@Bean
public TopicExchange topicExchage(){
return new TopicExchange(TOPIC_EXCHANGE);
}
@Bean
public Binding topicBinding1() {
return BindingBuilder.bind(topicQueue1()).to(topicExchage()).with("topic.key1");
}
@Bean
public Binding topicBinding2() {
return BindingBuilder.bind(topicQueue2()).to(topicExchage()).with("topic.#");
}
/**
* Fanout模式 交换机Exchange
* */
@Bean
public FanoutExchange fanoutExchage(){
return new FanoutExchange(FANOUT_EXCHANGE);
}
@Bean
public Binding FanoutBinding1() {
return BindingBuilder.bind(topicQueue1()).to(fanoutExchage());
}
@Bean
public Binding FanoutBinding2() {
return BindingBuilder.bind(topicQueue2()).to(fanoutExchage());
}
/**
* Header模式 交换机Exchange
* */
@Bean
public HeadersExchange headersExchage(){
return new HeadersExchange(HEADERS_EXCHANGE);
}
@Bean
public Queue headerQueue1() {
return new Queue(HEADER_QUEUE, true);
}
@Bean
public Binding headerBinding() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("header1", "value1");
map.put("header2", "value2");
return BindingBuilder.bind(headerQueue1()).to(headersExchage()).whereAll(map).match();
}
}

View File

@ -0,0 +1,73 @@
package com.geekq.miaosha.rabbitmq;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miaosha.service.GoodsService;
import com.geekq.miaosha.service.MiaoShaMessageService;
import com.geekq.miaosha.service.MiaoshaService;
import com.geekq.miaosha.service.OrderService;
import com.geekq.miasha.entity.MiaoshaOrder;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.vo.GoodsVo;
import com.geekq.miasha.vo.MiaoShaMessageVo;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class MQReceiver {
private static Logger log = LoggerFactory.getLogger(MQReceiver.class);
@Autowired
RedisService redisService;
@Autowired
GoodsService goodsService;
@Autowired
OrderService orderService;
@Autowired
MiaoshaService miaoshaService;
// @Autowired
// MiaoShaMessageService messageService ;
@RabbitListener(queues=MQConfig.MIAOSHA_QUEUE)
public void receive(String message) {
log.info("receive message:"+message);
MiaoshaMessage mm = RedisService.stringToBean(message, MiaoshaMessage.class);
MiaoshaUser user = mm.getUser();
long goodsId = mm.getGoodsId();
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
int stock = goods.getStockCount();
if(stock <= 0) {
return;
}
//判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(Long.valueOf(user.getNickname()), goodsId);
if(order != null) {
return;
}
//减库存 下订单 写入秒杀订单
miaoshaService.miaosha(user, goods);
}
// @RabbitListener(queues=MQConfig.MIAOSHATEST)
// public void receiveMiaoShaMessage(Message message, Channel channel) throws IOException {
// log.info("接受到的消息为:{}",message);
// String messRegister = new String(message.getBody(), "UTF-8");
// channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
// MiaoShaMessageVo msm = RedisService.stringToBean(messRegister, MiaoShaMessageVo.class);
// messageService.insertMs(msm);
// }
}

View File

@ -0,0 +1,49 @@
package com.geekq.miaosha.rabbitmq;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miasha.vo.MiaoShaMessageVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MQSender {
private static Logger log = LoggerFactory.getLogger(MQSender.class);
@Autowired
AmqpTemplate amqpTemplate ;
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendMiaoshaMessage(MiaoshaMessage mm) {
String msg = RedisService.beanToString(mm);
log.info("send message:"+msg);
amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE, msg);
}
/**
* 站内信
* @param mm
*/
public void sendMessage(MiaoshaMessage mm) {
// String msg = RedisService.beanToString(mm);
log.info("send message:"+"11111");
rabbitTemplate.convertAndSend(MQConfig.EXCHANGE_TOPIC,"miaosha_*", "111111111");
}
/**
* 站内信
* @param
*/
public void sendRegisterMessage(MiaoShaMessageVo miaoShaMessageVo) {
String msg = RedisService.beanToString(miaoShaMessageVo);
log.info("send message:{}" , msg);
rabbitTemplate.convertAndSend(MQConfig.MIAOSHATEST,msg);
// rabbitTemplate.convertAndSend(MQConfig.EXCHANGE_TOPIC,"miaosha_*", msg);
}
}

View File

@ -0,0 +1,21 @@
package com.geekq.miaosha.rabbitmq;
import com.geekq.miasha.entity.MiaoshaUser;
public class MiaoshaMessage {
private MiaoshaUser user;
private long goodsId;
public MiaoshaUser getUser() {
return user;
}
public void setUser(MiaoshaUser user) {
this.user = user;
}
public long getGoodsId() {
return goodsId;
}
public void setGoodsId(long goodsId) {
this.goodsId = goodsId;
}
}

View File

@ -0,0 +1,33 @@
package com.geekq.miaosha.redis;
public abstract class BasePrefix implements KeyPrefix {
private int expireSeconds;
private String prefix ;
public BasePrefix(int expireSeconds , String prefix ){
this.expireSeconds = expireSeconds ;
this.prefix = prefix;
}
public BasePrefix(String prefix) {
this(0,prefix);
}
@Override
public int expireSeconds() {//默认0代表永远过期
return expireSeconds;
}
/**
* 可确定获取唯一key
* @return
*/
@Override
public String getPrefix() {
String className = getClass().getSimpleName();
return className+":" +prefix;
}
}

View File

@ -0,0 +1,14 @@
package com.geekq.miaosha.redis;
import java.util.concurrent.TimeUnit;
public interface DistributedLocker {
void lock(String lockKey);
void unlock(String lockKey);
void lock(String lockKey, int timeout);
void lock(String lockKey, TimeUnit unit, int timeout);
}

View File

@ -0,0 +1,12 @@
package com.geekq.miaosha.redis;
public class GoodsKey extends BasePrefix {
private GoodsKey(int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static GoodsKey getGoodsList = new GoodsKey(60, "gl");
public static GoodsKey getGoodsDetail = new GoodsKey(60, "gd");
public static GoodsKey getMiaoshaGoodsStock = new GoodsKey(0, "gs");
}

View File

@ -0,0 +1,9 @@
package com.geekq.miaosha.redis;
public interface KeyPrefix {
public int expireSeconds() ;
public String getPrefix() ;
}

View File

@ -0,0 +1,11 @@
package com.geekq.miaosha.redis;
public class MiaoShaUserKey extends BasePrefix{
public static final int TOKEN_EXPIRE = 3600 *24*2;
public static MiaoShaUserKey token = new MiaoShaUserKey(TOKEN_EXPIRE,"tk") ;
public static MiaoShaUserKey getByNickName = new MiaoShaUserKey(0, "nickName");
public MiaoShaUserKey(int expireSeconds ,String prefix) {
super(expireSeconds,prefix);
}
}

View File

@ -0,0 +1,13 @@
package com.geekq.miaosha.redis;
public class MiaoshaKey extends BasePrefix{
private MiaoshaKey( int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static MiaoshaKey isGoodsOver = new MiaoshaKey(0, "go");
public static MiaoshaKey getMiaoshaPath = new MiaoshaKey(60, "mp");
public static MiaoshaKey getMiaoshaVerifyCode = new MiaoshaKey(300, "vc");
public static MiaoshaKey getMiaoshaVerifyCodeRegister = new MiaoshaKey(300, "register");
}

View File

@ -0,0 +1,11 @@
package com.geekq.miaosha.redis;
public class OrderKey extends BasePrefix {
public OrderKey( String prefix) {
super( prefix);
}
public static OrderKey getMiaoshaOrderByUidGid = new OrderKey("moug");
}

View File

@ -0,0 +1,58 @@
package com.geekq.miaosha.redis;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
private String host;
private int port;
private int timeout;//
private String password;
private int poolMaxTotal;
private int poolMaxIdle;
private int poolMaxWait;//
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPoolMaxTotal() {
return poolMaxTotal;
}
public void setPoolMaxTotal(int poolMaxTotal) {
this.poolMaxTotal = poolMaxTotal;
}
public int getPoolMaxIdle() {
return poolMaxIdle;
}
public void setPoolMaxIdle(int poolMaxIdle) {
this.poolMaxIdle = poolMaxIdle;
}
public int getPoolMaxWait() {
return poolMaxWait;
}
public void setPoolMaxWait(int poolMaxWait) {
this.poolMaxWait = poolMaxWait;
}
}

View File

@ -0,0 +1,26 @@
package com.geekq.miaosha.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Service
public class RedisPoolFactory {
@Autowired
RedisConfig redisConfig;
@Bean
public JedisPool JedisPoolFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
return jp;
}
}

View File

@ -0,0 +1,301 @@
package com.geekq.miaosha.redis;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import java.util.ArrayList;
import java.util.List;
@Service
@Slf4j
public class RedisService {
@Autowired
JedisPool jedisPool;
/**
* 设置失效时间
* @param key
* @param value
* @return
*/
public Long setnx(String key ,String value){
Jedis jedis =null;
Long result = null;
try {
jedis = jedisPool.getResource();
result = jedis.setnx(key,value);
}catch (Exception e){
log.error("expire key:{} error",key,e);
jedisPool.returnResource(jedis);
return result;
}
jedisPool.returnResource(jedis);
return result;
}
/**
* 设置key的有效期单位是秒
* @param key
* @param exTime
* @return
*/
public Long expire(String key,int exTime){
Jedis jedis = null;
Long result = null;
try {
jedis = jedisPool.getResource();
result = jedis.expire(key,exTime);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
jedisPool.returnBrokenResource(jedis);
return result;
}
jedisPool.returnResource(jedis);
return result;
}
/**
* 获取当个对象
* */
public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
String str = jedis.get(realKey);
T t = stringToBean(str, clazz);
return t;
}finally {
returnToPool(jedis);
}
}
public String get(String key){
Jedis jedis = null;
String result = null;
try {
jedis = jedisPool.getResource();
result = jedis.get(key);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
jedisPool.returnBrokenResource(jedis);
return result;
}
jedisPool.returnResource(jedis);
return result;
}
public String getset(String key,String value){
Jedis jedis = null;
String result = null;
try {
jedis = jedisPool.getResource();
result = jedis.getSet(key,value);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
jedisPool.returnBrokenResource(jedis);
return result;
}
jedisPool.returnResource(jedis);
return result;
}
/**
* 设置对象
* */
public <T> boolean set(KeyPrefix prefix, String key, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
if(str == null || str.length() <= 0) {
return false;
}
//生成真正的key
String realKey = prefix.getPrefix() + key;
int seconds = prefix.expireSeconds();
if(seconds <= 0) {
jedis.set(realKey, str);
}else {
jedis.setex(realKey, seconds, str);
}
return true;
}finally {
returnToPool(jedis);
}
}
/**
* 判断key是否存在
* */
public <T> boolean exists(KeyPrefix prefix, String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
return jedis.exists(realKey);
}finally {
returnToPool(jedis);
}
}
/**
* 删除
* */
public boolean delete(KeyPrefix prefix, String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
long ret = jedis.del(realKey);
return ret > 0;
}finally {
returnToPool(jedis);
}
}
/**
* 增加值
* */
public <T> Long incr(KeyPrefix prefix, String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
return jedis.incr(realKey);
}finally {
returnToPool(jedis);
}
}
/**
* 减少值
* */
public <T> Long decr(KeyPrefix prefix, String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
return jedis.decr(realKey);
}finally {
returnToPool(jedis);
}
}
public Long del(String key){
Jedis jedis = null;
Long result = null;
try {
jedis = jedisPool.getResource();
result = jedis.del(key);
} catch (Exception e) {
log.error("del key:{} error",key,e);
jedisPool.returnBrokenResource(jedis);
return result;
}
jedisPool.returnResource(jedis);
return result;
}
public boolean delete(KeyPrefix prefix) {
if(prefix == null) {
return false;
}
List<String> keys = scanKeys(prefix.getPrefix());
if(keys==null || keys.size() <= 0) {
return true;
}
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.del(keys.toArray(new String[0]));
return true;
} catch (final Exception e) {
e.printStackTrace();
return false;
} finally {
if(jedis != null) {
jedis.close();
}
}
}
public List<String> scanKeys(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
List<String> keys = new ArrayList<String>();
String cursor = "0";
ScanParams sp = new ScanParams();
sp.match("*"+key+"*");
sp.count(100);
do{
ScanResult<String> ret = jedis.scan(cursor, sp);
List<String> result = ret.getResult();
if(result!=null && result.size() > 0){
keys.addAll(result);
}
//再处理cursor
cursor = ret.getStringCursor();
}while(!cursor.equals("0"));
return keys;
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public static <T> String beanToString(T value) {
if(value == null) {
return null;
}
Class<?> clazz = value.getClass();
if(clazz == int.class || clazz == Integer.class) {
return ""+value;
}else if(clazz == String.class) {
return (String)value;
}else if(clazz == long.class || clazz == Long.class) {
return ""+value;
}else {
return JSON.toJSONString(value);
}
}
@SuppressWarnings("unchecked")
public static <T> T stringToBean(String str, Class<T> clazz) {
if(str == null || str.length() <= 0 || clazz == null) {
return null;
}
if(clazz == int.class || clazz == Integer.class) {
return (T)Integer.valueOf(str);
}else if(clazz == String.class) {
return (T)str;
}else if(clazz == long.class || clazz == Long.class) {
return (T)Long.valueOf(str);
}else {
return JSON.toJavaObject(JSON.parseObject(str), clazz);
}
}
private void returnToPool(Jedis jedis) {
if(jedis != null) {
jedis.close();
}
}
}

View File

@ -0,0 +1,42 @@
package com.geekq.miaosha.redis;
import java.util.concurrent.TimeUnit;
/**
* redis分布式锁帮助类
*
*/
public class RedissLockUtil {
private static DistributedLocker redissLock;
public static void setLocker(DistributedLocker locker) {
redissLock = locker;
}
public static void lock(String lockKey) {
redissLock.lock(lockKey);
}
public static void unlock(String lockKey) {
redissLock.unlock(lockKey);
}
/**
* 带超时的锁
* @param lockKey
* @param timeout 超时时间 单位
*/
public static void lock(String lockKey, int timeout) {
redissLock.lock(lockKey, timeout);
}
/**
* 带超时的锁
* @param lockKey
* @param unit 时间单位
* @param timeout 超时时间
*/
public static void lock(String lockKey, TimeUnit unit , int timeout) {
redissLock.lock(lockKey, unit, timeout);
}
}

View File

@ -0,0 +1,76 @@
package com.geekq.miaosha.redis;//package com.geekq.miaosha.redis;
//
//import org.apache.commons.lang3.StringUtils;
//import org.redisson.Redisson;
//import org.redisson.api.RedissonClient;
//import org.redisson.config.Config;
//import org.redisson.config.SentinelServersConfig;
//import org.redisson.config.SingleServerConfig;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
//import org.springframework.boot.context.properties.EnableConfigurationProperties;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//@Configuration
//@ConditionalOnClass(Config.class)
//@EnableConfigurationProperties(RedissonProperties.class)
//public class RedissonAutoConfiguration {
//
// @Autowired
// private RedissonProperties redssionProperties;
//
// /**
// * 哨兵模式自动装配
// * @return
// */
// @Bean
// @ConditionalOnProperty(name="redisson.master-name")
// RedissonClient redissonSentinel() {
// Config config = new Config();
// SentinelServersConfig serverConfig = config.useSentinelServers().addSentinelAddress(redssionProperties.getSentinelAddresses())
// .setMasterName(redssionProperties.getMasterName())
// .setTimeout(redssionProperties.getTimeout())
// .setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())
// .setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize());
//
// if(StringUtils.isNotBlank(redssionProperties.getPassword())) {
// serverConfig.setPassword(redssionProperties.getPassword());
// }
// return Redisson.create(config);
// }
//
// /**
// * 单机模式自动装配
// * @return
// */
// @Bean
// @ConditionalOnProperty(name="redisson.address")
// RedissonClient redissonSingle() {
// Config config = new Config();
// SingleServerConfig serverConfig = config.useSingleServer()
// .setAddress(redssionProperties.getAddress())
// .setTimeout(redssionProperties.getTimeout())
// .setConnectionPoolSize(redssionProperties.getConnectionPoolSize())
// .setConnectionMinimumIdleSize(redssionProperties.getConnectionMinimumIdleSize());
//
// if(StringUtils.isNotBlank(redssionProperties.getPassword())) {
// serverConfig.setPassword(redssionProperties.getPassword());
// }
//
// return Redisson.create(config);
// }
//
// /**
// * 装配locker类并将实例注入到RedissLockUtil中
// * @return
// */
// @Bean
// DistributedLocker distributedLocker(RedissonClient redissonSingle) {
// RedissonDistributedLocker locker = new RedissonDistributedLocker();
// locker.setRedissonClient(redissonSingle);
// RedissLockUtil.setLocker(locker);
// return locker;
// }
//}

View File

@ -0,0 +1,39 @@
package com.geekq.miaosha.redis;//package com.geekq.miaosha.redis;
//
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//
//import java.util.concurrent.TimeUnit;
//
//public class RedissonDistributedLocker implements DistributedLocker {
//
// private RedissonClient redissonClient;
//
// @Override
// public void lock(String lockKey) {
// RLock lock = redissonClient.getLock(lockKey);
// lock.lock();
// }
//
// @Override
// public void unlock(String lockKey) {
// RLock lock = redissonClient.getLock(lockKey);
// lock.unlock();
// }
//
// @Override
// public void lock(String lockKey, int leaseTime) {
// RLock lock = redissonClient.getLock(lockKey);
// lock.lock(leaseTime, TimeUnit.SECONDS);
// }
//
// @Override
// public void lock(String lockKey, TimeUnit unit ,int timeout) {
// RLock lock = redissonClient.getLock(lockKey);
// lock.lock(timeout, unit);
// }
//
// public void setRedissonClient(RedissonClient redissonClient) {
// this.redissonClient = redissonClient;
// }
//}

View File

@ -0,0 +1,98 @@
package com.geekq.miaosha.redis;//package com.geekq.miaosha.redis;
//
//import org.springframework.boot.context.properties.ConfigurationProperties;
//
//@ConfigurationProperties(prefix = "redisson")
//public class RedissonProperties {
//
// private int timeout = 3000;
//
// private String address;
//
// private String password;
//
// private int connectionPoolSize = 64;
//
// private int connectionMinimumIdleSize=10;
//
// private int slaveConnectionPoolSize = 250;
//
// private int masterConnectionPoolSize = 250;
//
// private String[] sentinelAddresses;
//
// private String masterName;
//
// public int getTimeout() {
// return timeout;
// }
//
// public void setTimeout(int timeout) {
// this.timeout = timeout;
// }
//
// public int getSlaveConnectionPoolSize() {
// return slaveConnectionPoolSize;
// }
//
// public void setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {
// this.slaveConnectionPoolSize = slaveConnectionPoolSize;
// }
//
// public int getMasterConnectionPoolSize() {
// return masterConnectionPoolSize;
// }
//
// public void setMasterConnectionPoolSize(int masterConnectionPoolSize) {
// this.masterConnectionPoolSize = masterConnectionPoolSize;
// }
//
// public String[] getSentinelAddresses() {
// return sentinelAddresses;
// }
//
// public void setSentinelAddresses(String sentinelAddresses) {
// this.sentinelAddresses = sentinelAddresses.split(",");
// }
//
// public String getMasterName() {
// return masterName;
// }
//
// public void setMasterName(String masterName) {
// this.masterName = masterName;
// }
//
// public String getPassword() {
// return password;
// }
//
// public void setPassword(String password) {
// this.password = password;
// }
//
// public String getAddress() {
// return address;
// }
//
// public void setAddress(String address) {
// this.address = address;
// }
//
// public int getConnectionPoolSize() {
// return connectionPoolSize;
// }
//
// public void setConnectionPoolSize(int connectionPoolSize) {
// this.connectionPoolSize = connectionPoolSize;
// }
//
// public int getConnectionMinimumIdleSize() {
// return connectionMinimumIdleSize;
// }
//
// public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
// this.connectionMinimumIdleSize = connectionMinimumIdleSize;
// }
//}
//

View File

@ -0,0 +1,146 @@
package com.geekq.miaosha.redis;//package com.geekq.miaosha.redis;
//
//import org.redisson.api.*;
//import org.redisson.config.Config;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//
//import java.io.IOException;
//
///**
// * redisson操作类
// */
//@Service("redissonService")
//public class RedissonService {
//
// @Autowired
// private RedissonClient redissonClient;
//
// public void getRedissonClient() throws IOException {
// Config config = redissonClient.getConfig();
// System.out.println(config.toJSON().toString());
// }
//
// /**`
// * 获取字符串对象
// *
// * @param objectName
// * @return
// */
// public <T> RBucket<T> getRBucket(String objectName) {
// RBucket<T> bucket = redissonClient.getBucket(objectName);
// return bucket;
// }
//
// /**
// * 获取Map对象
// *
// * @param objectName
// * @return
// */
// public <K, V> RMap<K, V> getRMap(String objectName) {
// RMap<K, V> map = redissonClient.getMap(objectName);
// return map;
// }
//
// /**
// * 获取有序集合
// *
// * @param objectName
// * @return
// */
// public <V> RSortedSet<V> getRSortedSet(String objectName) {
// RSortedSet<V> sortedSet = redissonClient.getSortedSet(objectName);
// return sortedSet;
// }
//
// /**
// * 获取集合
// *
// * @param objectName
// * @return
// */
// public <V> RSet<V> getRSet(String objectName) {
// RSet<V> rSet = redissonClient.getSet(objectName);
// return rSet;
// }
//
// /**
// * 获取列表
// *
// * @param objectName
// * @return
// */
// public <V> RList<V> getRList(String objectName) {
// RList<V> rList = redissonClient.getList(objectName);
// return rList;
// }
//
// /**
// * 获取队列
// *
// * @param objectName
// * @return
// */
// public <V> RQueue<V> getRQueue(String objectName) {
// RQueue<V> rQueue = redissonClient.getQueue(objectName);
// return rQueue;
// }
//
// /**
// * 获取双端队列
// *
// * @param objectName
// * @return
// */
// public <V> RDeque<V> getRDeque(String objectName) {
// RDeque<V> rDeque = redissonClient.getDeque(objectName);
// return rDeque;
// }
//
//
// /**
// * 获取锁
// *
// * @param objectName
// * @return
// */
// public RLock getRLock(String objectName) {
// RLock rLock = redissonClient.getLock(objectName);
// return rLock;
// }
//
// /**
// * 获取读取锁
// *
// * @param objectName
// * @return
// */
// public RReadWriteLock getRWLock(String objectName) {
// RReadWriteLock rwlock = redissonClient.getReadWriteLock(objectName);
// return rwlock;
// }
//
// /**
// * 获取原子数
// *
// * @param objectName
// * @return
// */
// public RAtomicLong getRAtomicLong(String objectName) {
// RAtomicLong rAtomicLong = redissonClient.getAtomicLong(objectName);
// return rAtomicLong;
// }
//
// /**
// * 获取记数锁
// *
// * @param objectName
// * @return
// */
// public RCountDownLatch getRCountDownLatch(String objectName) {
// RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch(objectName);
// return rCountDownLatch;
// }
//
//}

View File

@ -0,0 +1,13 @@
package com.geekq.miaosha.redis;
public class Userkey extends BasePrefix {
private Userkey(String prefix) {
super( prefix);
}
public static Userkey getById = new Userkey("id") ;
public static Userkey getByName = new Userkey("name") ;
}

View File

@ -0,0 +1,58 @@
package com.geekq.miaosha.redis.redismanager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.List;
import java.util.UUID;
public class RedisLock {
public String getLock(String key , int timeOut){
try {
Jedis jedis = RedisManager.getJedis();
String value = UUID.randomUUID().toString();
long end =System.currentTimeMillis()+timeOut;
while (System.currentTimeMillis()<end){
if(jedis.setnx(key,value) ==1){
jedis.expire(key, timeOut);
//锁设置成功 redis操作成功
return value;
}
if(jedis.ttl(key)== -1){
jedis.expire(key, timeOut);
}
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* watch 监控多个key 一防止其他地方调用释放锁的时候对这个key进行修改 那么事务里面的代码就不会被执行
*/
public boolean releaseLock(String key , String value){
try {
Jedis jedis = RedisManager.getJedis();
while (true){
jedis.watch(key);
if(value.equals(jedis.get(key))){
Transaction transaction = jedis.multi();
transaction.del(key);
List<Object> list = transaction.exec();
if(list ==null){
continue;
}
jedis.unwatch();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -0,0 +1,95 @@
package com.geekq.miaosha.redis.redismanager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.List;
/**
* lua脚本使用
*/
public class RedisLua {
private static Logger logger = LoggerFactory.getLogger(RedisLua.class);
/**
* 未完成 evalsha更方便 限制ip 或者 手机号访问次数
*/
public static void getLuaLimit() {
Jedis jedis = null;
try {
jedis = RedisManager.getJedis();
} catch (Exception e) {
e.printStackTrace();
}
String lua =
"local num=redis.call('incr',KEYS[1]) if tonumber(num)==1 " +
"then redis.call('expire',KEYS[1],ARGV[1]) " +
"return 1 elseif tonumber(num)>" +
"tonumber(ARGV[2]) then return 0 else return 1 end";
List<String> keys = new ArrayList<String>();
keys.add("ip:limit:127.0.0.1");
List<String> argves = new ArrayList<String>();
argves.add("6000");
argves.add("5");
jedis.auth("xxxx");
// Object evalSha = jedis.evalsha(lua);
String luaScript = jedis.scriptLoad(lua);
System.out.println(luaScript);
Object object = jedis.evalsha(luaScript, keys, argves);
System.out.println(object);
}
/**
* 统计访问次数
*/
public static Object getVistorCount(String key) {
Jedis jedis = null;
Object object = null;
try {
jedis = RedisManager.getJedis();
String count =
"local num=redis.call('get',KEYS[1]) return num";
List<String> keys = new ArrayList<String>();
keys.add(key);
List<String> argves = new ArrayList<String>();
jedis.auth("youxin11");
String luaScript = jedis.scriptLoad(count);
System.out.println(luaScript);
object = jedis.evalsha(luaScript, keys, argves);
} catch (Exception e) {
logger.error("统计访问次数失败!!!",e);
return "0";
}
return object;
}
/**
* 统计访问次数
*/
public static void vistorCount(String key) {
Jedis jedis = null;
Object object = null;
try {
jedis = RedisManager.getJedis();
String count =
"local num=redis.call('incr',KEYS[1]) return num";
List<String> keys = new ArrayList<String>();
keys.add(key);
List<String> argves = new ArrayList<String>();
jedis.auth("youxin11");
String luaScript = jedis.scriptLoad(count);
System.out.println(luaScript);
jedis.evalsha(luaScript, keys, argves);
} catch (Exception e) {
logger.error("统计访问次数失败!!!",e);
}
}
}

View File

@ -0,0 +1,26 @@
package com.geekq.miaosha.redis.redismanager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisManager {
private static JedisPool jedisPool;
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxWaitMillis(20);
jedisPoolConfig.setMaxIdle(10);
jedisPool = new JedisPool(jedisPoolConfig,"39.107.245.253");
}
public static Jedis getJedis() throws Exception{
if(null!=jedisPool){
return jedisPool.getResource();
}
throw new Exception("Jedispool was not init !!!");
}
}

View File

@ -0,0 +1,5 @@
package com.geekq.miaosha.redis.redismanager.lua;
public class RedisLuaLock {
}

View File

@ -0,0 +1,27 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by qiurunze.
--- DateTime: 2018/12/22 18:20
---
--- 释放锁
if redis.call('get',KEY[1] == ARGV[1]) then
return redis.call('del',KEY[1])
else
return 0
end
--- 加锁
local key = KEY[1]
local content = KEY[2]
local ttl = AVG[1]
local lockSet = redis.call('setnx',key,content)
if lockSet==1 then
redis.call('pexpire',key,ttl)
else
local value = redis.call('get',key)
if value==content then
lockSet=1
redis.call('pexpire',key,ttl)
end
end
return lockSet

View File

@ -0,0 +1,5 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by qiurunze.
--- DateTime: 2018/12/24 13:22
---

View File

@ -0,0 +1,10 @@
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by qiurunze.
--- DateTime: 2018/12/22 16:33
---
---
print(10)

View File

@ -0,0 +1,35 @@
package com.geekq.miaosha.service;
import com.geekq.miaosha.mapper.GoodsMapper;
import com.geekq.miasha.entity.MiaoshaGoods;
import com.geekq.miasha.vo.GoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class GoodsService {
@Autowired
GoodsMapper goodsMapper;
public List<GoodsVo> listGoodsVo(){
return goodsMapper.listGoodsVo();
}
public GoodsVo getGoodsVoByGoodsId(long goodsId) {
return goodsMapper.getGoodsVoByGoodsId(goodsId);
}
public boolean reduceStock(GoodsVo goods) {
MiaoshaGoods g = new MiaoshaGoods();
g.setGoodsId(goods.getId());
int ret = goodsMapper.reduceStock(g);
return ret > 0;
}
}

View File

@ -0,0 +1,9 @@
package com.geekq.miaosha.service;
/**
* @author 邱润泽
*/
public interface LoginInfoService {
public String checkName();
}

View File

@ -0,0 +1,41 @@
package com.geekq.miaosha.service;
import com.geekq.miasha.entity.MiaoShaMessageInfo;
import com.geekq.miasha.entity.MiaoShaMessageUser;
import com.geekq.miasha.vo.MiaoShaMessageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Service
public class MiaoShaMessageService {
// @Autowired
// private MiaoShaMessageDao messageDao;
//
// public List<MiaoShaMessageInfo> getmessageUserList(Long userId , Integer status ){
// return messageDao.listMiaoShaMessageByUserId(userId,status);
// }
//
//
// @Transactional(rollbackFor = Exception.class)
// public void insertMs(MiaoShaMessageVo miaoShaMessageVo){
// MiaoShaMessageUser mu = new MiaoShaMessageUser() ;
// mu.setUserId(miaoShaMessageVo.getUserId());
// mu.setMessageId(miaoShaMessageVo.getMessageId());
// messageDao.insertMiaoShaMessageUser(mu);
// MiaoShaMessageInfo miaoshaMessage = new MiaoShaMessageInfo();
// miaoshaMessage.setContent(miaoShaMessageVo.getContent());
//// miaoshaMessage.setCreateTime(new Date());
// miaoshaMessage.setStatus(miaoShaMessageVo.getStatus());
// miaoshaMessage.setMessageType(miaoShaMessageVo.getMessageType());
// miaoshaMessage.setSendType(miaoShaMessageVo.getSendType());
// miaoshaMessage.setMessageId(miaoShaMessageVo.getMessageId());
// miaoshaMessage.setCreateTime(new Date());
// miaoshaMessage.setMessageHead(miaoShaMessageVo.getMessageHead());
// messageDao.insertMiaoShaMessage(miaoshaMessage);
// }
}

View File

@ -0,0 +1,185 @@
package com.geekq.miaosha.service;
import com.geekq.miaosha.mapper.MiaoShaUserMapper;
import com.geekq.miaosha.rabbitmq.MQSender;
import com.geekq.miaosha.redis.MiaoShaUserKey;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miasha.entity.IpLog;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.enums.Constants;
import com.geekq.miasha.enums.MessageStatus;
import com.geekq.miasha.exception.GlobleException;
import com.geekq.miasha.utils.MD5Utils;
import com.geekq.miasha.utils.SnowflakeIdWorker;
import com.geekq.miasha.utils.UUIDUtil;
import com.geekq.miasha.vo.LoginVo;
import com.geekq.miasha.vo.MiaoShaMessageVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import static com.geekq.miasha.enums.enums.ResultStatus.MOBILE_NOT_EXIST;
import static com.geekq.miasha.enums.enums.ResultStatus.PASSWORD_ERROR;
import static com.geekq.miasha.enums.enums.ResultStatus.SYSTEM_ERROR;
@Service
public class MiaoShaUserService {
public static final String COOKIE_NAME_TOKEN = "token" ;
private static Logger logger = LoggerFactory.getLogger(MiaoShaUserService.class);
@Autowired
private MiaoShaUserMapper miaoShaUserMapper;
@Autowired
private RedisService redisService ;
@Autowired
private MQSender sender ;
public MiaoshaUser getByToken(HttpServletResponse response , String token) {
if(StringUtils.isEmpty(token)){
return null ;
}
MiaoshaUser user =redisService.get(MiaoShaUserKey.token,token,MiaoshaUser.class) ;
if(user!=null) {
addCookie(response, token, user);
}
return user ;
}
public MiaoshaUser getByNickName(String nickName) {
//取缓存
MiaoshaUser user = redisService.get(MiaoShaUserKey.getByNickName, ""+nickName, MiaoshaUser.class);
if(user != null) {
return user;
}
//取数据库
user = miaoShaUserMapper.getByNickname(nickName);
if(user != null) {
redisService.set(MiaoShaUserKey.getByNickName, ""+nickName, user);
}
return user;
}
// http://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/78693323
public boolean updatePassword(String token, String nickName, String formPass) {
//取user
MiaoshaUser user = getByNickName(nickName);
if(user == null) {
throw new GlobleException(MOBILE_NOT_EXIST);
}
//更新数据库
MiaoshaUser toBeUpdate = new MiaoshaUser();
toBeUpdate.setNickname(nickName);
toBeUpdate.setPassword(MD5Utils.formPassToDBPass(formPass, user.getSalt()));
miaoShaUserMapper.update(toBeUpdate);
//处理缓存
redisService.delete(MiaoShaUserKey.getByNickName, ""+nickName);
user.setPassword(toBeUpdate.getPassword());
redisService.set(MiaoShaUserKey.token, token, user);
return true;
}
public boolean register(String userName , String passWord , String salt ,
HttpServletResponse response , HttpServletRequest request) {
MiaoshaUser miaoShaUser = new MiaoshaUser();
miaoShaUser.setNickname(userName);
String DBPassWord = MD5Utils.formPassToDBPass(passWord , MD5Utils.getSaltT());
miaoShaUser.setPassword(DBPassWord);
miaoShaUser.setRegisterDate(new Date());
miaoShaUser.setSalt(salt);
miaoShaUser.setNickname(userName);
try {
miaoShaUserMapper.insertMiaoShaUser(miaoShaUser);
IpLog log = new IpLog(userName,new Date(),request.getRemoteAddr(),
Constants.USERTYPE_NORMAL,null);
MiaoshaUser user = miaoShaUserMapper.getByNickname(miaoShaUser.getNickname());
if(user == null){
return false;
}
//生成cookie 将session返回游览器 分布式session
String token= UUIDUtil.uuid();
addCookie(response, token, user);
} catch (Exception e) {
logger.error("注册失败",e);
return false;
}
return true;
}
public boolean login(HttpServletResponse response , LoginVo loginVo) {
if(loginVo ==null){
throw new GlobleException(SYSTEM_ERROR);
}
String mobile =loginVo.getMobile();
String password =loginVo.getPassword();
MiaoshaUser user = getByNickName(mobile);
if(user == null) {
throw new GlobleException(MOBILE_NOT_EXIST);
}
String dbPass = user.getPassword();
String saltDb = user.getSalt();
String calcPass = MD5Utils.formPassToDBPass(password,saltDb);
if(!"b7797cce01b4b131b433b6acf4add449".equals(dbPass)){
throw new GlobleException(PASSWORD_ERROR);
}
//生成cookie 将session返回游览器 分布式session
String token= UUIDUtil.uuid();
addCookie(response, token, user);
return true ;
}
public String createToken(HttpServletResponse response , LoginVo loginVo) {
if(loginVo ==null){
throw new GlobleException(SYSTEM_ERROR);
}
String mobile =loginVo.getMobile();
String password =loginVo.getPassword();
MiaoshaUser user = getByNickName(mobile);
if(user == null) {
throw new GlobleException(MOBILE_NOT_EXIST);
}
String dbPass = user.getPassword();
String saltDb = user.getSalt();
String calcPass = MD5Utils.formPassToDBPass(password,saltDb);
if(!calcPass.equals(dbPass)){
throw new GlobleException(PASSWORD_ERROR);
}
//生成cookie 将session返回游览器 分布式session
String token= UUIDUtil.uuid();
addCookie(response, token, user);
return token ;
}
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
redisService.set(MiaoShaUserKey.token, token, user);
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN, token);
//设置有效期
cookie.setMaxAge(MiaoShaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
}

View File

@ -0,0 +1,207 @@
package com.geekq.miaosha.service;
import com.geekq.miaosha.redis.MiaoshaKey;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miasha.entity.MiaoshaOrder;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.entity.OrderInfo;
import com.geekq.miasha.utils.MD5Utils;
import com.geekq.miasha.utils.UUIDUtil;
import com.geekq.miasha.vo.GoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
@Service
public class MiaoshaService {
@Autowired
GoodsService goodsService;
@Autowired
OrderService orderService;
@Autowired
RedisService redisService;
@Transactional
public OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {
//减库存 下订单 写入秒杀订单
boolean success = goodsService.reduceStock(goods);
if(success){
return orderService.createOrder(user,goods) ;
}else {
//如果库存不存在则内存标记为true
setGoodsOver(goods.getId());
return null;
}
}
public long getMiaoshaResult(Long userId, long goodsId) {
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);
if(order != null) {//秒杀成功
return order.getOrderId();
}else {
boolean isOver = getGoodsOver(goodsId);
if(isOver) {
return -1;
}else {
return 0;
}
}
}
private void setGoodsOver(Long goodsId) {
redisService.set(MiaoshaKey.isGoodsOver, ""+goodsId, true);
}
private boolean getGoodsOver(long goodsId) {
return redisService.exists(MiaoshaKey.isGoodsOver, ""+goodsId);
}
public boolean checkPath(MiaoshaUser user, long goodsId, String path) {
if(user == null || path == null) {
return false;
}
String pathOld = redisService.get(MiaoshaKey.getMiaoshaPath, ""+user.getNickname() + "_"+ goodsId, String.class);
return path.equals(pathOld);
}
public String createMiaoshaPath(MiaoshaUser user, long goodsId) {
if(user == null || goodsId <=0) {
return null;
}
String str = MD5Utils.md5(UUIDUtil.uuid()+"123456");
redisService.set(MiaoshaKey.getMiaoshaPath, ""+user.getNickname() + "_"+ goodsId, str);
return str;
}
public BufferedImage createVerifyCode(MiaoshaUser user, long goodsId) {
if(user == null || goodsId <=0) {
return null;
}
int width = 80;
int height = 32;
//create the image
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// set the background color
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
// draw the border
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
// create a random instance to generate the codes
Random rdm = new Random();
// make some confusion
for (int i = 0; i < 50; i++) {
int x = rdm.nextInt(width);
int y = rdm.nextInt(height);
g.drawOval(x, y, 0, 0);
}
// generate a random code
String verifyCode = generateVerifyCode(rdm);
g.setColor(new Color(0, 100, 0));
g.setFont(new Font("Candara", Font.BOLD, 24));
g.drawString(verifyCode, 8, 24);
g.dispose();
//把验证码存到redis中
int rnd = calc(verifyCode);
redisService.set(MiaoshaKey.getMiaoshaVerifyCode, user.getNickname()+","+goodsId, rnd);
//输出图片
return image;
}
/**
* 注册时用的验证码
* @param verifyCode
* @return
*/
public boolean checkVerifyCodeRegister(int verifyCode) {
Integer codeOld = redisService.get(MiaoshaKey.getMiaoshaVerifyCodeRegister,"regitser", Integer.class);
if(codeOld == null || codeOld - verifyCode != 0 ) {
return false;
}
redisService.delete(MiaoshaKey.getMiaoshaVerifyCode, "regitser");
return true;
}
public BufferedImage createVerifyCodeRegister() {
int width = 80;
int height = 32;
//create the image
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// set the background color
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
// draw the border
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
// create a random instance to generate the codes
Random rdm = new Random();
// make some confusion
for (int i = 0; i < 50; i++) {
int x = rdm.nextInt(width);
int y = rdm.nextInt(height);
g.drawOval(x, y, 0, 0);
}
// generate a random code
String verifyCode = generateVerifyCode(rdm);
g.setColor(new Color(0, 100, 0));
g.setFont(new Font("Candara", Font.BOLD, 24));
g.drawString(verifyCode, 8, 24);
g.dispose();
//把验证码存到redis中
int rnd = calc(verifyCode);
redisService.set(MiaoshaKey.getMiaoshaVerifyCodeRegister,"regitser",rnd);
//输出图片
return image;
}
private static int calc(String exp) {
try {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
Integer catch1 = (Integer)engine.eval(exp);
return catch1.intValue();
}catch(Exception e) {
e.printStackTrace();
return 0;
}
}
public boolean checkVerifyCode(MiaoshaUser user, long goodsId, int verifyCode) {
if(user == null || goodsId <=0) {
return false;
}
Integer codeOld = redisService.get(MiaoshaKey.getMiaoshaVerifyCode, user.getNickname()+","+goodsId, Integer.class);
if(codeOld == null || codeOld - verifyCode != 0 ) {
return false;
}
redisService.delete(MiaoshaKey.getMiaoshaVerifyCode, user.getNickname()+","+goodsId);
return true;
}
private static char[] ops = new char[] {'+', '-', '*'};
/**
* + - *
* */
private String generateVerifyCode(Random rdm) {
int num1 = rdm.nextInt(10);
int num2 = rdm.nextInt(10);
int num3 = rdm.nextInt(10);
char op1 = ops[rdm.nextInt(3)];
char op2 = ops[rdm.nextInt(3)];
String exp = ""+ num1 + op1 + num2 + op2 + num3;
return exp;
}
}

View File

@ -0,0 +1,70 @@
package com.geekq.miaosha.service;
import com.geekq.miaosha.mapper.OrderMapper;
import com.geekq.miaosha.redis.OrderKey;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miasha.entity.MiaoshaOrder;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.entity.OrderInfo;
import com.geekq.miasha.utils.DateTimeUtils;
import com.geekq.miasha.vo.GoodsVo;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import static com.geekq.miasha.enums.Constanst.orderStaus.ORDER_NOT_PAY;
@Service
public class OrderService {
@Autowired
OrderMapper orderMapper;
@Autowired
private RedisService redisService ;
public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(long userId, long goodsId) {
return redisService.get(OrderKey.getMiaoshaOrderByUidGid,""+userId+"_"+goodsId,MiaoshaOrder.class) ;
}
public OrderInfo getOrderById(long orderId) {
return orderMapper.getOrderById(orderId);
}
@Transactional
public OrderInfo createOrder(MiaoshaUser user, GoodsVo goods) {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setCreateDate(new Date());
orderInfo.setDeliveryAddrId(0L);
orderInfo.setGoodsCount(1);
orderInfo.setGoodsId(goods.getId());
orderInfo.setGoodsName(goods.getGoodsName());
orderInfo.setGoodsPrice(goods.getMiaoshaPrice());
orderInfo.setOrderChannel(1);
orderInfo.setStatus(0);
orderInfo.setUserId(Long.valueOf(user.getNickname()));
orderMapper.insert(orderInfo);
MiaoshaOrder miaoshaOrder = new MiaoshaOrder();
miaoshaOrder.setGoodsId(goods.getId());
miaoshaOrder.setOrderId(orderInfo.getId());
miaoshaOrder.setUserId(Long.valueOf(user.getNickname()));
orderMapper.insertMiaoshaOrder(miaoshaOrder);
redisService.set(OrderKey.getMiaoshaOrderByUidGid,""+user.getNickname()+"_"+goods.getId(),miaoshaOrder) ;
return orderInfo;
}
public void closeOrder(int hour){
Date closeDateTime = DateUtils.addHours(new Date(),-hour);
List<OrderInfo> orderInfoList = orderMapper.selectOrderStatusByCreateTime(Integer.valueOf(ORDER_NOT_PAY.ordinal()), DateTimeUtils.dateToStr(closeDateTime));
for (OrderInfo orderInfo:orderInfoList){
System.out.println("orderinfo infomation "+orderInfo.getGoodsName());
}
}
}

View File

@ -0,0 +1,28 @@
package com.geekq.miaosha.service.impl;
import com.geekq.miaosha.mapper.IpLogMapper;
import com.geekq.miaosha.mapper.LogininfoMapper;
import com.geekq.miaosha.service.LoginInfoService;
import com.geekq.miasha.entity.IpLog;
import com.geekq.miasha.entity.Logininfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.geekq.miasha.utils.SnowflakeIdWorker;
import java.util.List;
/**
* @author 邱润泽
*/
@Service
public class LoginInfoServiceImpl implements LoginInfoService {
@Autowired
private LogininfoMapper logininfoMapper;
@Override
public String checkName() {
logininfoMapper.selectAll();
return "" ;
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>miaosha</artifactId>
<groupId>com.geekq</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>miaosha-web</artifactId>
<dependencies>
<dependency>
<groupId>com.geekq</groupId>
<artifactId>miaosha-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
package com.geekq.miaosha;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.geekq.miaosha.mapper")
public class GeekQMainApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(GeekQMainApplication.class, args);
}
}

View File

@ -0,0 +1,122 @@
package com.geekq.miaosha.access;
import com.alibaba.fastjson.JSON;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.enums.enums.ResultStatus;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import com.geekq.miasha.utils.UserContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import static com.geekq.miasha.enums.enums.ResultStatus.ACCESS_LIMIT_REACHED;
import static com.geekq.miasha.enums.enums.ResultStatus.SESSION_ERROR;
@Service
public class AccessInterceptor extends HandlerInterceptorAdapter {
private static Logger logger = LoggerFactory.getLogger(AccessInterceptor.class);
@Autowired
MiaoShaUserService userService;
@Autowired
RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/**
* 获取调用 获取主要方法
*/
if(handler instanceof HandlerMethod) {
logger.info("打印拦截方法handler {} ",handler);
HandlerMethod hm = (HandlerMethod)handler;
//方便mybatis 测试
// if(hm.getMethod().getName().startsWith("test")){
// return true;
// }
MiaoshaUser user = getUser(request, response);
UserContext.setUser(user);
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if(accessLimit == null) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
boolean needLogin = accessLimit.needLogin();
String key = request.getRequestURI();
if(needLogin) {
if(user == null) {
render(response, SESSION_ERROR);
return false;
}
key += "_" + user.getNickname();
}else {
//do nothing
}
AccessKey ak = AccessKey.withExpire(seconds);
Integer count = redisService.get(ak, key, Integer.class);
if(count == null) {
redisService.set(ak, key, 1);
}else if(count < maxCount) {
redisService.incr(ak, key);
}else {
render(response, ACCESS_LIMIT_REACHED);
return false;
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
UserContext.removeUser();
}
private void render(HttpServletResponse response, ResultStatus cm)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(ResultGeekQ.error(cm));
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
private MiaoshaUser getUser(HttpServletRequest request, HttpServletResponse response) {
String paramToken = request.getParameter(MiaoShaUserService.COOKIE_NAME_TOKEN);
String cookieToken = getCookieValue(request, MiaoShaUserService.COOKIE_NAME_TOKEN);
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return null;
}
String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
return userService.getByToken(response, token);
}
private String getCookieValue(HttpServletRequest request, String cookiName) {
Cookie[] cookies = request.getCookies();
if(cookies == null || cookies.length <= 0){
return null;
}
for(Cookie cookie : cookies) {
if(cookie.getName().equals(cookiName)) {
return cookie.getValue();
}
}
return null;
}
}

View File

@ -0,0 +1,15 @@
package com.geekq.miaosha.access;
import com.geekq.miaosha.redis.BasePrefix;
public class AccessKey extends BasePrefix {
private AccessKey( int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static AccessKey withExpire(int expireSeconds) {
return new AccessKey(expireSeconds, "access");
}
}

View File

@ -0,0 +1,15 @@
package com.geekq.miaosha.access;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
int seconds();
int maxCount();
boolean needLogin() default true;
}

View File

@ -0,0 +1,184 @@
package com.geekq.miaosha.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@ConfigurationProperties(prefix="spring.datasource")
public class DruidConfig {
private String url;
private String username;
private String password;
private String driverClassName;
private String type;
private String filters;
private int maxActive;
private int initialSize;
private int minIdle;
private long maxWait;
private long timeBetweenEvictionRunsMillis;
private long minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxOpenPreparedStatements;
@Bean
public ServletRegistrationBean druidSverlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
reg.addInitParameter("loginUsername", "joshua");
reg.addInitParameter("loginPassword", "123456");
reg.addInitParameter("logSlowSql", "true");
reg.addInitParameter("slowSqlMillis", "1000");
return reg;
}
@Bean
public DataSource druidDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
return datasource;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getInitialSize() {
return initialSize;
}
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public long getMaxWait() {
return maxWait;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public long getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public long getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public boolean isTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public boolean isTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public boolean isPoolPreparedStatements() {
return poolPreparedStatements;
}
public void setPoolPreparedStatements(boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}
public int getMaxOpenPreparedStatements() {
return maxOpenPreparedStatements;
}
public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) {
this.maxOpenPreparedStatements = maxOpenPreparedStatements;
}
}

View File

@ -0,0 +1,33 @@
package com.geekq.miaosha.config;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.utils.UserContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private MiaoShaUserService userService;
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
Class<?> clazz = methodParameter.getParameterType() ;
return clazz == MiaoshaUser.class ;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
/**
* threadlocal 存储线程副本 保证线程不冲突
*/
return UserContext.getUser();
}
}

View File

@ -0,0 +1,31 @@
package com.geekq.miaosha.config;
import com.geekq.miaosha.access.AccessInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
UserArgumentResolver resolver;
@Autowired
private AccessInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(interceptor);
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(resolver);
}
}

View File

@ -0,0 +1,65 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.redis.KeyPrefix;
import com.geekq.miaosha.redis.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
@Controller
public class BaseController {
//加一个配置项
@Value("#{'${pageCache.enbale}'}")
private boolean pageCacheEnable;
@Autowired
ThymeleafViewResolver thymeleafViewResolver;
@Autowired
RedisService redisService;
public String render(HttpServletRequest request, HttpServletResponse response, Model model, String tplName, KeyPrefix prefix, String key) {
if(!pageCacheEnable) {
return tplName;
}
//取缓存
String html = redisService.get(prefix, key, String.class);
if(!StringUtils.isEmpty(html)) {
out(response, html);
return null;
}
//手动渲染
WebContext ctx = new WebContext(request,response,
request.getServletContext(),request.getLocale(), model.asMap());
html = thymeleafViewResolver.getTemplateEngine().process(tplName, ctx);
if(!StringUtils.isEmpty(html)) {
redisService.set(prefix, key, html);
}
out(response, html);
return null;
}
public static void out(HttpServletResponse res, String html){
res.setContentType("text/html");
res.setCharacterEncoding("UTF-8");
try{
OutputStream out = res.getOutputStream();
out.write(html.getBytes("UTF-8"));
out.flush();
out.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,148 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.redis.GoodsKey;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miaosha.service.GoodsService;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import com.geekq.miasha.vo.GoodsDetailVo;
import com.geekq.miasha.vo.GoodsVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Controller
@RequestMapping("/goods")
public class GoodsController extends BaseController {
private static Logger log = LoggerFactory.getLogger(GoodsController.class);
@Autowired
private MiaoShaUserService userService;
@Autowired
private RedisService redisService;
@Autowired
private GoodsService goodsService;
@Autowired
ThymeleafViewResolver viewResolver;
@Autowired
ApplicationContext applicationContext;
/**
* QPS:1267 load:15 mysql
* 5000 * 10
* QPS:2884, load:5
* */
@RequestMapping(value="/to_list", produces="text/html")
@ResponseBody
public String list(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user) {
model.addAttribute("user", user);
List<GoodsVo> goodsList = goodsService.listGoodsVo();
model.addAttribute("goodsList", goodsList);
return render(request,response,model,"goods_list", GoodsKey.getGoodsList,"");
}
@RequestMapping(value="/to_detail2/{goodsId}",produces="text/html")
@ResponseBody
public String detail2(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user,
@PathVariable("goodsId")long goodsId) {
model.addAttribute("user", user);
//取缓存
String html = redisService.get(GoodsKey.getGoodsDetail, ""+goodsId, String.class);
if(!StringUtils.isEmpty(html)) {
return html;
}
//手动渲染
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
model.addAttribute("goods", goods);
long startAt = goods.getStartDate().getTime();
long endAt = goods.getEndDate().getTime();
long now = System.currentTimeMillis();
int miaoshaStatus = 0;
int remainSeconds = 0;
if(now < startAt ) {//秒杀还没开始倒计时
miaoshaStatus = 0;
remainSeconds = (int)((startAt - now )/1000);
}else if(now > endAt){//秒杀已经结束
miaoshaStatus = 2;
remainSeconds = -1;
}else {//秒杀进行中
miaoshaStatus = 1;
remainSeconds = 0;
}
model.addAttribute("miaoshaStatus", miaoshaStatus);
model.addAttribute("remainSeconds", remainSeconds);
// return "goods_detail";
WebContext ctx = new WebContext(request, response,
request.getServletContext(), request.getLocale(), model.asMap());
html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
// WebContext ctx = new WebContext(request,response,
// request.getServletContext(),request.getLocale(),
// model.asMap(), applicationContext );
// html = viewResolver.getTemplateEngine().process("goods_detail", ctx);
if(!StringUtils.isEmpty(html)) {
redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
}
return html;
}
/**
* 数据库很少使用long的  id 正常使一般使用 snowflake 分布式自增id
* @param model
* @param user
* @param goodsId
* @return
*/
@RequestMapping(value="/detail/{goodsId}")
@ResponseBody
public ResultGeekQ<GoodsDetailVo> detail(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user,
@PathVariable("goodsId")long goodsId) {
ResultGeekQ<GoodsDetailVo> result = ResultGeekQ.build();
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
long startAt = goods.getStartDate().getTime();
long endAt = goods.getEndDate().getTime();
long now = System.currentTimeMillis();
int miaoshaStatus = 0;
int remainSeconds = 0;
if(now < startAt ) {//秒杀还没开始倒计时
miaoshaStatus = 0;
remainSeconds = (int)((startAt - now )/1000);
}else if(now > endAt){//秒杀已经结束
miaoshaStatus = 2;
remainSeconds = -1;
}else {//秒杀进行中
miaoshaStatus = 1;
remainSeconds = 0;
}
GoodsDetailVo vo = new GoodsDetailVo();
vo.setGoods(goods);
vo.setUser(user);
vo.setRemainSeconds(remainSeconds);
vo.setMiaoshaStatus(miaoshaStatus);
result.setData(vo);
return result;
}
}

View File

@ -0,0 +1,56 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.redis.redismanager.RedisLua;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import com.geekq.miasha.vo.LoginVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import static com.geekq.miasha.enums.Constanst.COUNTLOGIN;
@Controller
@RequestMapping("/login")
public class LoginController {
private static Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private MiaoShaUserService userService;
@RequestMapping("/to_login")
public String tologin(LoginVo loginVo, Model model) {
logger.info(loginVo.toString());
//未完成
RedisLua.vistorCount(COUNTLOGIN);
String count = RedisLua.getVistorCount(COUNTLOGIN).toString();
logger.info("访问网站的次数为:{}",count);
model.addAttribute("count",count);
return "login";
}
@RequestMapping("/do_login")
@ResponseBody
public ResultGeekQ<Boolean> dologin(HttpServletResponse response, @Valid LoginVo loginVo) {
ResultGeekQ<Boolean> result = ResultGeekQ.build();
logger.info(loginVo.toString());
userService.login(response, loginVo);
return result;
}
@RequestMapping("/create_token")
@ResponseBody
public String createToken(HttpServletResponse response, @Valid LoginVo loginVo) {
logger.info(loginVo.toString());
String token = userService.createToken(response, loginVo);
return token;
}
}

View File

@ -0,0 +1,22 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.service.impl.LoginInfoServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 邱润泽
*/
@Controller
@RequestMapping("/login")
public class LoginInfoController {
@Autowired
private LoginInfoServiceImpl loginInfoService;
@RequestMapping("/login")
public String login(){
return "hello";
}
}

View File

@ -0,0 +1,57 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.rabbitmq.MQSender;
import com.geekq.miaosha.service.MiaoShaMessageService;
import com.geekq.miasha.entity.MiaoShaMessageInfo;
import com.geekq.miasha.enums.MessageStatus;
import com.geekq.miasha.enums.enums.ResultStatus;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/message")
public class MiaoShaMessageController {
@Autowired
private MiaoShaMessageService messageService;
@Autowired
private MQSender sendMessage;
@RequestMapping(value = "/list", produces = "text/html")
public String list(@RequestParam(value = "userid",required= true) String userId, Model model) {
ResultGeekQ resultGeekQ = ResultGeekQ.build();
if (StringUtils.isBlank(userId)) {
resultGeekQ.withError(ResultStatus.USER_NOT_EXIST);
}
// List<MiaoShaMessageInfo> miaoShaMessageInfos = messageService.getmessageUserList(Long.valueOf(userId), null);
//
// model.addAttribute("message",miaoShaMessageInfos);
return "message_list";
}
@RequestMapping(value = "/getNewMessage", produces = "text/html")
@ResponseBody
public String getNewMessage(@RequestParam(value = "userid",required= true) String userId, Model model) {
// if (StringUtils.isBlank(userId)) {
// return "0";
// }
// List<MiaoShaMessageInfo> miaoShaMessageInfos = messageService.getmessageUserList(Long.valueOf(userId), MessageStatus.ZORE);
// if(miaoShaMessageInfos.isEmpty()){
// return "0";
// }else {
// return "1";
// }
return "";
};
}

View File

@ -0,0 +1,220 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.access.AccessLimit;
import com.geekq.miaosha.rabbitmq.MQSender;
import com.geekq.miaosha.rabbitmq.MiaoshaMessage;
import com.geekq.miaosha.redis.GoodsKey;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miaosha.service.GoodsService;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miaosha.service.MiaoshaService;
import com.geekq.miaosha.service.OrderService;
import com.geekq.miasha.entity.MiaoshaOrder;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import com.geekq.miasha.vo.GoodsVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import static com.geekq.miasha.enums.enums.ResultStatus.*;
@Controller
@RequestMapping("/miaosha")
public class MiaoshaController implements InitializingBean {
private static Logger logger = LoggerFactory.getLogger(MiaoshaController.class);
@Autowired
MiaoShaUserService userService;
@Autowired
RedisService redisService;
@Autowired
GoodsService goodsService;
@Autowired
OrderService orderService;
@Autowired
MiaoshaService miaoshaService;
@Autowired
MQSender mqSender;
private HashMap<Long, Boolean> localOverMap = new HashMap<Long, Boolean>();
/**
* QPS:1306
* 5000 * 10
* get post get 幂等 从服务端获取数据 不会产生影响  post 对服务端产生变化
*/
@AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
@RequestMapping(value="/{path}/do_miaosha", method= RequestMethod.POST)
@ResponseBody
public ResultGeekQ<Integer> miaosha(Model model, MiaoshaUser user, @PathVariable("path") String path,
@RequestParam("goodsId") long goodsId) {
ResultGeekQ<Integer> result = ResultGeekQ.build();
if (user == null) {
result.withError(SESSION_ERROR.getCode(), SESSION_ERROR.getMessage());
return result;
}
//验证path
boolean check = miaoshaService.checkPath(user, goodsId, path);
if (!check) {
result.withError(REQUEST_ILLEGAL.getCode(), REQUEST_ILLEGAL.getMessage());
return result;
}
// //使用RateLimiter 限流
// RateLimiter rateLimiter = RateLimiter.create(10);
// //判断能否在1秒内得到令牌如果不能则立即返回false不会阻塞程序
// if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
// System.out.println("短期无法获取令牌,真不幸,排队也瞎排");
// return ResultGeekQ.error(CodeMsg.MIAOSHA_FAIL);
//
// }
//是否已经秒杀到
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(Long.valueOf(user.getNickname()), goodsId);
if (order != null) {
result.withError(EXCEPTION.getCode(), REPEATE_MIAOSHA.getMessage());
return result;
}
//内存标记减少redis访问
boolean over = localOverMap.get(goodsId);
if (over) {
result.withError(EXCEPTION.getCode(), MIAO_SHA_OVER.getMessage());
return result;
}
//预见库存
Long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
if (stock < 0) {
localOverMap.put(goodsId, true);
result.withError(EXCEPTION.getCode(), MIAO_SHA_OVER.getMessage());
return result;
}
MiaoshaMessage mm = new MiaoshaMessage();
mm.setGoodsId(goodsId);
mm.setUser(user);
mqSender.sendMiaoshaMessage(mm);
return result;
}
/**
* orderId成功
* -1秒杀失败
* 0 排队中
*/
@AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
@RequestMapping(value = "/result", method = RequestMethod.GET)
@ResponseBody
public ResultGeekQ<Long> miaoshaResult(Model model, MiaoshaUser user,
@RequestParam("goodsId") long goodsId) {
ResultGeekQ<Long> result = ResultGeekQ.build();
if (user == null) {
result.withError(SESSION_ERROR.getCode(), SESSION_ERROR.getMessage());
return result;
}
model.addAttribute("user", user);
Long miaoshaResult = miaoshaService.getMiaoshaResult(Long.valueOf(user.getNickname()), goodsId);
result.setData(miaoshaResult);
return result;
}
@AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
@RequestMapping(value = "/path", method = RequestMethod.GET)
@ResponseBody
public ResultGeekQ<String> getMiaoshaPath(HttpServletRequest request, MiaoshaUser user,
@RequestParam("goodsId") long goodsId,
@RequestParam(value = "verifyCode", defaultValue = "0") int verifyCode
) {
ResultGeekQ<String> result = ResultGeekQ.build();
if (user == null) {
result.withError(SESSION_ERROR.getCode(), SESSION_ERROR.getMessage());
return result;
}
boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);
if (!check) {
result.withError(REQUEST_ILLEGAL.getCode(), REQUEST_ILLEGAL.getMessage());
return result;
}
String path = miaoshaService.createMiaoshaPath(user, goodsId);
result.setData(path);
return result;
}
@RequestMapping(value = "/verifyCodeRegister", method = RequestMethod.GET)
@ResponseBody
public ResultGeekQ<String> getMiaoshaVerifyCod(HttpServletResponse response
) {
ResultGeekQ<String> result = ResultGeekQ.build();
try {
BufferedImage image = miaoshaService.createVerifyCodeRegister();
OutputStream out = response.getOutputStream();
ImageIO.write(image, "JPEG", out);
out.flush();
out.close();
return result;
} catch (Exception e) {
logger.error("生成验证码错误-----注册:{}", e);
result.withError(MIAOSHA_FAIL.getCode(), MIAOSHA_FAIL.getMessage());
return result;
}
}
@RequestMapping(value = "/verifyCode", method = RequestMethod.GET)
@ResponseBody
public ResultGeekQ<String> getMiaoshaVerifyCod(HttpServletResponse response, MiaoshaUser user,
@RequestParam("goodsId") long goodsId) {
ResultGeekQ<String> result = ResultGeekQ.build();
if (user == null) {
result.withError(SESSION_ERROR.getCode(), SESSION_ERROR.getMessage());
return result;
}
try {
BufferedImage image = miaoshaService.createVerifyCode(user, goodsId);
OutputStream out = response.getOutputStream();
ImageIO.write(image, "JPEG", out);
out.flush();
out.close();
return result;
} catch (Exception e) {
logger.error("生成验证码错误-----goodsId:{}", goodsId, e);
result.withError(MIAOSHA_FAIL.getCode(), MIAOSHA_FAIL.getMessage());
return result;
}
}
/**
* 系统初始化
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
List<GoodsVo> goodsList = goodsService.listGoodsVo();
if (goodsList == null) {
return;
}
for (GoodsVo goods : goodsList) {
redisService.set(GoodsKey.getMiaoshaGoodsStock, "" + goods.getId(), goods.getStockCount());
localOverMap.put(goods.getId(), false);
}
}
}

View File

@ -0,0 +1,62 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.redis.RedisService;
import com.geekq.miaosha.service.GoodsService;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miaosha.service.OrderService;
import com.geekq.miasha.entity.MiaoshaUser;
import com.geekq.miasha.entity.OrderInfo;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import com.geekq.miasha.vo.GoodsVo;
import com.geekq.miasha.vo.OrderDetailVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import static com.geekq.miasha.enums.enums.ResultStatus.ORDER_NOT_EXIST;
import static com.geekq.miasha.enums.enums.ResultStatus.SESSION_ERROR;
@Controller
@RequestMapping("/order")
public class OrderController {
@Autowired
MiaoShaUserService userService;
@Autowired
RedisService redisService;
@Autowired
OrderService orderService;
@Autowired
GoodsService goodsService;
@RequestMapping("/detail")
@ResponseBody
public ResultGeekQ<OrderDetailVo> info(Model model, MiaoshaUser user,
@RequestParam("orderId") long orderId) {
ResultGeekQ<OrderDetailVo> result = ResultGeekQ.build();
if (user == null) {
result.withError(SESSION_ERROR.getCode(), SESSION_ERROR.getMessage());
return result;
}
OrderInfo order = orderService.getOrderById(orderId);
if(order == null) {
result.withError(ORDER_NOT_EXIST.getCode(), ORDER_NOT_EXIST.getMessage());
return result;
}
long goodsId = order.getGoodsId();
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
OrderDetailVo vo = new OrderDetailVo();
vo.setOrder(order);
vo.setGoods(goods);
result.setData(vo);
return result;
}
}

View File

@ -0,0 +1,60 @@
package com.geekq.miaosha.controller;
import com.geekq.miaosha.service.MiaoShaUserService;
import com.geekq.miaosha.service.MiaoshaService;
import com.geekq.miasha.enums.resultbean.ResultGeekQ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static com.geekq.miasha.enums.enums.ResultStatus.CODE_FAIL;
import static com.geekq.miasha.enums.enums.ResultStatus.RESIGETER_FAIL;
@Controller
@RequestMapping("/user")
public class RegisterController {
private static Logger logger = LoggerFactory.getLogger(RegisterController.class);
@Autowired
private MiaoShaUserService miaoShaUserService;
@Autowired
private MiaoshaService miaoshaService ;
@RequestMapping("/do_register")
public String registerIndex(){
return "register2";
}
/**
* 注册网站
* @param userName
* @param passWord
* @param salt
* @return
*/
@RequestMapping("/register")
@ResponseBody
public ResultGeekQ<String> register(@RequestParam("username") String userName ,
@RequestParam("password") String passWord,
@RequestParam("salt") String salt,
HttpServletResponse response ,
HttpServletRequest request){
ResultGeekQ<String> result = ResultGeekQ.build();
boolean registerInfo = miaoShaUserService.register(userName,passWord,salt,response ,request);
if(!registerInfo){
result.withError(RESIGETER_FAIL.getCode(),RESIGETER_FAIL.getMessage());
return result;
}
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More