diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dbfef5d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### 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/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+
+nginx-1.18.0/
+!nginx-1.18.0/html/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6f85c2a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,90 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.12.RELEASE
+
+
+ com.hmdp
+ hm-dianping
+ 0.0.1-SNAPSHOT
+ hm-dianping
+ Demo project for Spring Boot
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.apache.commons
+ commons-pool2
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+ 5.1.47
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.4.3
+
+
+
+ cn.hutool
+ hutool-all
+ 5.7.17
+
+
+
+ org.aspectj
+ aspectjweaver
+ 1.9.7
+
+
+ org.redisson
+ redisson
+ 3.22.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/hmdp/HmDianPingApplication.java b/src/main/java/com/hmdp/HmDianPingApplication.java
new file mode 100644
index 0000000..5e9d293
--- /dev/null
+++ b/src/main/java/com/hmdp/HmDianPingApplication.java
@@ -0,0 +1,18 @@
+package com.hmdp;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+// 让对象代理生效
+@EnableAspectJAutoProxy(exposeProxy = true)
+@MapperScan("com.hmdp.mapper")
+@SpringBootApplication
+public class HmDianPingApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(HmDianPingApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/hmdp/config/MvcConfig.java b/src/main/java/com/hmdp/config/MvcConfig.java
new file mode 100644
index 0000000..856ab05
--- /dev/null
+++ b/src/main/java/com/hmdp/config/MvcConfig.java
@@ -0,0 +1,32 @@
+package com.hmdp.config;
+
+import com.hmdp.utils.LoginInterceptor;
+import com.hmdp.utils.RefreshTokenInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new LoginInterceptor())
+ .excludePathPatterns(
+ "/shop/**",
+ "/voucher/**",
+ "/shop-type/**",
+ "/upload/**",
+ "/blog/hot",
+ "/user/code",
+ "/user/login"
+ ).order(1);
+ registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate))
+ .addPathPatterns("/**")
+ .order(0);
+ }
+}
diff --git a/src/main/java/com/hmdp/config/MybatisConfig.java b/src/main/java/com/hmdp/config/MybatisConfig.java
new file mode 100644
index 0000000..ffd08c4
--- /dev/null
+++ b/src/main/java/com/hmdp/config/MybatisConfig.java
@@ -0,0 +1,17 @@
+package com.hmdp.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MybatisConfig {
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ return interceptor;
+ }
+}
diff --git a/src/main/java/com/hmdp/config/RedissonConfig.java b/src/main/java/com/hmdp/config/RedissonConfig.java
new file mode 100644
index 0000000..e5b274f
--- /dev/null
+++ b/src/main/java/com/hmdp/config/RedissonConfig.java
@@ -0,0 +1,19 @@
+package com.hmdp.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+ @Bean
+ public RedissonClient redissonClient() {
+ //1.创建配置
+ Config config = new Config();
+ config.useSingleServer().setAddress("redis://192.168.56.10:6379").setPassword("123456");
+ //2.根据 Config 创建出 RedissonClient 实例
+ return Redisson.create(config);
+ }
+}
diff --git a/src/main/java/com/hmdp/config/WebExceptionAdvice.java b/src/main/java/com/hmdp/config/WebExceptionAdvice.java
new file mode 100644
index 0000000..ae0da66
--- /dev/null
+++ b/src/main/java/com/hmdp/config/WebExceptionAdvice.java
@@ -0,0 +1,17 @@
+package com.hmdp.config;
+
+import com.hmdp.dto.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@Slf4j
+@RestControllerAdvice
+public class WebExceptionAdvice {
+
+ @ExceptionHandler(RuntimeException.class)
+ public Result handleRuntimeException(RuntimeException e) {
+ log.error(e.toString(), e);
+ return Result.fail("服务器异常");
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/BlogCommentsController.java b/src/main/java/com/hmdp/controller/BlogCommentsController.java
new file mode 100644
index 0000000..3408b71
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/BlogCommentsController.java
@@ -0,0 +1,20 @@
+package com.hmdp.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/blog-comments")
+public class BlogCommentsController {
+
+}
diff --git a/src/main/java/com/hmdp/controller/BlogController.java b/src/main/java/com/hmdp/controller/BlogController.java
new file mode 100644
index 0000000..0a2fa6c
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/BlogController.java
@@ -0,0 +1,83 @@
+package com.hmdp.controller;
+
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.hmdp.dto.Result;
+import com.hmdp.dto.UserDTO;
+import com.hmdp.entity.Blog;
+import com.hmdp.entity.User;
+import com.hmdp.service.IBlogService;
+import com.hmdp.service.IUserService;
+import com.hmdp.utils.SystemConstants;
+import com.hmdp.utils.UserHolder;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/blog")
+public class BlogController {
+
+ @Resource
+ private IBlogService blogService;
+ @Resource
+ private IUserService userService;
+
+ @PostMapping
+ public Result saveBlog(@RequestBody Blog blog) {
+ // 获取登录用户
+ UserDTO user = UserHolder.getUser();
+ blog.setUserId(user.getId());
+ // 保存探店博文
+ blogService.save(blog);
+ // 返回id
+ return Result.ok(blog.getId());
+ }
+
+ @PutMapping("/like/{id}")
+ public Result likeBlog(@PathVariable("id") Long id) {
+ // 修改点赞数量
+ blogService.update()
+ .setSql("liked = liked + 1").eq("id", id).update();
+ return Result.ok();
+ }
+
+ @GetMapping("/of/me")
+ public Result queryMyBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
+ // 获取登录用户
+ UserDTO user = UserHolder.getUser();
+ // 根据用户查询
+ Page page = blogService.query()
+ .eq("user_id", user.getId()).page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
+ // 获取当前页数据
+ List records = page.getRecords();
+ return Result.ok(records);
+ }
+
+ @GetMapping("/hot")
+ public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
+ // 根据用户查询
+ Page page = blogService.query()
+ .orderByDesc("liked")
+ .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
+ // 获取当前页数据
+ List records = page.getRecords();
+ // 查询用户
+ records.forEach(blog ->{
+ Long userId = blog.getUserId();
+ User user = userService.getById(userId);
+ blog.setName(user.getNickName());
+ blog.setIcon(user.getIcon());
+ });
+ return Result.ok(records);
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/FollowController.java b/src/main/java/com/hmdp/controller/FollowController.java
new file mode 100644
index 0000000..b4d67f3
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/FollowController.java
@@ -0,0 +1,20 @@
+package com.hmdp.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/follow")
+public class FollowController {
+
+}
diff --git a/src/main/java/com/hmdp/controller/ShopController.java b/src/main/java/com/hmdp/controller/ShopController.java
new file mode 100644
index 0000000..4a4158f
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/ShopController.java
@@ -0,0 +1,102 @@
+package com.hmdp.controller;
+
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Shop;
+import com.hmdp.service.IShopService;
+import com.hmdp.utils.SystemConstants;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/shop")
+public class ShopController {
+
+ @Resource
+ public IShopService shopService;
+
+ /**
+ * 根据id查询商铺信息
+ * @param id 商铺id
+ * @return 商铺详情数据
+ */
+ @GetMapping("/{id}")
+ public Result queryShopById(@PathVariable("id") Long id) {
+// return Result.ok(shopService.getById(id));
+ return shopService.queryById(id);
+ }
+
+ /**
+ * 新增商铺信息
+ * @param shop 商铺数据
+ * @return 商铺id
+ */
+ @PostMapping
+ public Result saveShop(@RequestBody Shop shop) {
+ // 写入数据库
+ shopService.save(shop);
+ // 返回店铺id
+ return Result.ok(shop.getId());
+ }
+
+ /**
+ * 更新商铺信息
+ * @param shop 商铺数据
+ * @return 无
+ */
+ @PutMapping
+ public Result updateShop(@RequestBody Shop shop) {
+ // 写入数据库
+
+ return shopService.updateShopById(shop);
+ }
+
+ /**
+ * 根据商铺类型分页查询商铺信息
+ * @param typeId 商铺类型
+ * @param current 页码
+ * @return 商铺列表
+ */
+ @GetMapping("/of/type")
+ public Result queryShopByType(
+ @RequestParam("typeId") Integer typeId,
+ @RequestParam(value = "current", defaultValue = "1") Integer current
+ ) {
+ // 根据类型分页查询
+ Page page = shopService.query()
+ .eq("type_id", typeId)
+ .page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
+ // 返回数据
+ return Result.ok(page.getRecords());
+ }
+
+ /**
+ * 根据商铺名称关键字分页查询商铺信息
+ * @param name 商铺名称关键字
+ * @param current 页码
+ * @return 商铺列表
+ */
+ @GetMapping("/of/name")
+ public Result queryShopByName(
+ @RequestParam(value = "name", required = false) String name,
+ @RequestParam(value = "current", defaultValue = "1") Integer current
+ ) {
+ // 根据类型分页查询
+ Page page = shopService.query()
+ .like(StrUtil.isNotBlank(name), "name", name)
+ .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
+ // 返回数据
+ return Result.ok(page.getRecords());
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/ShopTypeController.java b/src/main/java/com/hmdp/controller/ShopTypeController.java
new file mode 100644
index 0000000..7addf13
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/ShopTypeController.java
@@ -0,0 +1,35 @@
+package com.hmdp.controller;
+
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.ShopType;
+import com.hmdp.service.IShopTypeService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/shop-type")
+public class ShopTypeController {
+ @Resource
+ private IShopTypeService typeService;
+
+ @GetMapping("list")
+ public Result queryTypeList() {
+// List typeList = typeService
+// .query().orderByAsc("sort").list();
+// return Result.ok(typeList);
+ return typeService.queryTypeList();
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/UploadController.java b/src/main/java/com/hmdp/controller/UploadController.java
new file mode 100644
index 0000000..56d32e4
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/UploadController.java
@@ -0,0 +1,63 @@
+package com.hmdp.controller;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import com.hmdp.dto.Result;
+import com.hmdp.utils.SystemConstants;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+@Slf4j
+@RestController
+@RequestMapping("upload")
+public class UploadController {
+
+ @PostMapping("blog")
+ public Result uploadImage(@RequestParam("file") MultipartFile image) {
+ try {
+ // 获取原始文件名称
+ String originalFilename = image.getOriginalFilename();
+ // 生成新文件名
+ String fileName = createNewFileName(originalFilename);
+ // 保存文件
+ image.transferTo(new File(SystemConstants.IMAGE_UPLOAD_DIR, fileName));
+ // 返回结果
+ log.debug("文件上传成功,{}", fileName);
+ return Result.ok(fileName);
+ } catch (IOException e) {
+ throw new RuntimeException("文件上传失败", e);
+ }
+ }
+
+ @GetMapping("/blog/delete")
+ public Result deleteBlogImg(@RequestParam("name") String filename) {
+ File file = new File(SystemConstants.IMAGE_UPLOAD_DIR, filename);
+ if (file.isDirectory()) {
+ return Result.fail("错误的文件名称");
+ }
+ FileUtil.del(file);
+ return Result.ok();
+ }
+
+ private String createNewFileName(String originalFilename) {
+ // 获取后缀
+ String suffix = StrUtil.subAfter(originalFilename, ".", true);
+ // 生成目录
+ String name = UUID.randomUUID().toString();
+ int hash = name.hashCode();
+ int d1 = hash & 0xF;
+ int d2 = (hash >> 4) & 0xF;
+ // 判断目录是否存在
+ File dir = new File(SystemConstants.IMAGE_UPLOAD_DIR, StrUtil.format("/blogs/{}/{}", d1, d2));
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ // 生成文件名
+ return StrUtil.format("/blogs/{}/{}/{}.{}", d1, d2, name, suffix);
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/UserController.java b/src/main/java/com/hmdp/controller/UserController.java
new file mode 100644
index 0000000..2a0faf5
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/UserController.java
@@ -0,0 +1,86 @@
+package com.hmdp.controller;
+
+
+import cn.hutool.core.util.RandomUtil;
+import com.hmdp.dto.LoginFormDTO;
+import com.hmdp.dto.Result;
+import com.hmdp.dto.UserDTO;
+import com.hmdp.entity.User;
+import com.hmdp.entity.UserInfo;
+import com.hmdp.service.IUserInfoService;
+import com.hmdp.service.IUserService;
+import com.hmdp.utils.RegexUtils;
+import com.hmdp.utils.UserHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpSession;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Slf4j
+@RestController
+@RequestMapping("/user")
+public class UserController {
+
+ @Resource
+ private IUserService userService;
+
+ @Resource
+ private IUserInfoService userInfoService;
+
+ /**
+ * 发送手机验证码
+ */
+ @PostMapping("code")
+ public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
+ return userService.sendCode(phone, session);
+ }
+
+ /**
+ * 登录功能
+ * @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码
+ */
+ @PostMapping("/login")
+ public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
+ return userService.login(loginForm, session);
+ }
+
+ /**
+ * 登出功能
+ * @return 无
+ */
+ @PostMapping("/logout")
+ public Result logout(){
+ // TODO 实现登出功能
+ return Result.fail("功能未完成");
+ }
+
+ @GetMapping("/me")
+ public Result me(){
+ //获取当前登录的用户并返回
+ UserDTO user = UserHolder.getUser();
+ return Result.ok(user);
+ }
+
+ @GetMapping("/info/{id}")
+ public Result info(@PathVariable("id") Long userId){
+ // 查询详情
+ UserInfo info = userInfoService.getById(userId);
+ if (info == null) {
+ // 没有详情,应该是第一次查看详情
+ return Result.ok();
+ }
+ info.setCreateTime(null);
+ info.setUpdateTime(null);
+ // 返回
+ return Result.ok(info);
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/VoucherController.java b/src/main/java/com/hmdp/controller/VoucherController.java
new file mode 100644
index 0000000..328a0e6
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/VoucherController.java
@@ -0,0 +1,57 @@
+package com.hmdp.controller;
+
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Voucher;
+import com.hmdp.service.IVoucherService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/voucher")
+public class VoucherController {
+
+ @Resource
+ private IVoucherService voucherService;
+
+ /**
+ * 新增普通券
+ * @param voucher 优惠券信息
+ * @return 优惠券id
+ */
+ @PostMapping
+ public Result addVoucher(@RequestBody Voucher voucher) {
+ voucherService.save(voucher);
+ return Result.ok(voucher.getId());
+ }
+
+ /**
+ * 新增秒杀券
+ * @param voucher 优惠券信息,包含秒杀信息
+ * @return 优惠券id
+ */
+ @PostMapping("seckill")
+ public Result addSeckillVoucher(@RequestBody Voucher voucher) {
+ voucherService.addSeckillVoucher(voucher);
+ return Result.ok(voucher.getId());
+ }
+
+ /**
+ * 查询店铺的优惠券列表
+ * @param shopId 店铺id
+ * @return 优惠券列表
+ */
+ @GetMapping("/list/{shopId}")
+ public Result queryVoucherOfShop(@PathVariable("shopId") Long shopId) {
+ return voucherService.queryVoucherOfShop(shopId);
+ }
+}
diff --git a/src/main/java/com/hmdp/controller/VoucherOrderController.java b/src/main/java/com/hmdp/controller/VoucherOrderController.java
new file mode 100644
index 0000000..0ddf4f8
--- /dev/null
+++ b/src/main/java/com/hmdp/controller/VoucherOrderController.java
@@ -0,0 +1,32 @@
+package com.hmdp.controller;
+
+
+import com.hmdp.dto.Result;
+import com.hmdp.service.impl.VoucherOrderServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@RestController
+@RequestMapping("/voucher-order")
+public class VoucherOrderController {
+
+ @Autowired
+ private VoucherOrderServiceImpl voucherOrderService;
+
+ @PostMapping("seckill/{id}")
+ public Result seckillVoucher(@PathVariable("id") Long voucherId) {
+// System.out.println(voucherId);
+ return voucherOrderService.seckillVoucher(voucherId);
+ }
+}
diff --git a/src/main/java/com/hmdp/dto/LoginFormDTO.java b/src/main/java/com/hmdp/dto/LoginFormDTO.java
new file mode 100644
index 0000000..f8f4016
--- /dev/null
+++ b/src/main/java/com/hmdp/dto/LoginFormDTO.java
@@ -0,0 +1,10 @@
+package com.hmdp.dto;
+
+import lombok.Data;
+
+@Data
+public class LoginFormDTO {
+ private String phone;
+ private String code;
+ private String password;
+}
diff --git a/src/main/java/com/hmdp/dto/Result.java b/src/main/java/com/hmdp/dto/Result.java
new file mode 100644
index 0000000..cc098e6
--- /dev/null
+++ b/src/main/java/com/hmdp/dto/Result.java
@@ -0,0 +1,30 @@
+package com.hmdp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result {
+ private Boolean success;
+ private String errorMsg;
+ private Object data;
+ private Long total;
+
+ public static Result ok(){
+ return new Result(true, null, null, null);
+ }
+ public static Result ok(Object data){
+ return new Result(true, null, data, null);
+ }
+ public static Result ok(List> data, Long total){
+ return new Result(true, null, data, total);
+ }
+ public static Result fail(String errorMsg){
+ return new Result(false, errorMsg, null, null);
+ }
+}
diff --git a/src/main/java/com/hmdp/dto/ScrollResult.java b/src/main/java/com/hmdp/dto/ScrollResult.java
new file mode 100644
index 0000000..530fcac
--- /dev/null
+++ b/src/main/java/com/hmdp/dto/ScrollResult.java
@@ -0,0 +1,12 @@
+package com.hmdp.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ScrollResult {
+ private List> list;
+ private Long minTime;
+ private Integer offset;
+}
diff --git a/src/main/java/com/hmdp/dto/UserDTO.java b/src/main/java/com/hmdp/dto/UserDTO.java
new file mode 100644
index 0000000..4dd1802
--- /dev/null
+++ b/src/main/java/com/hmdp/dto/UserDTO.java
@@ -0,0 +1,10 @@
+package com.hmdp.dto;
+
+import lombok.Data;
+
+@Data
+public class UserDTO {
+ private Long id;
+ private String nickName;
+ private String icon;
+}
diff --git a/src/main/java/com/hmdp/entity/Blog.java b/src/main/java/com/hmdp/entity/Blog.java
new file mode 100644
index 0000000..f5c8872
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/Blog.java
@@ -0,0 +1,95 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_blog")
+public class Blog implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+ /**
+ * 商户id
+ */
+ private Long shopId;
+ /**
+ * 用户id
+ */
+ private Long userId;
+ /**
+ * 用户图标
+ */
+ @TableField(exist = false)
+ private String icon;
+ /**
+ * 用户姓名
+ */
+ @TableField(exist = false)
+ private String name;
+ /**
+ * 是否点赞过了
+ */
+ @TableField(exist = false)
+ private Boolean isLike;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 探店的照片,最多9张,多张以","隔开
+ */
+ private String images;
+
+ /**
+ * 探店的文字描述
+ */
+ private String content;
+
+ /**
+ * 点赞数量
+ */
+ private Integer liked;
+
+ /**
+ * 评论数量
+ */
+ private Integer comments;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/BlogComments.java b/src/main/java/com/hmdp/entity/BlogComments.java
new file mode 100644
index 0000000..086f356
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/BlogComments.java
@@ -0,0 +1,81 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_blog_comments")
+public class BlogComments implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 探店id
+ */
+ private Long blogId;
+
+ /**
+ * 关联的1级评论id,如果是一级评论,则值为0
+ */
+ private Long parentId;
+
+ /**
+ * 回复的评论id
+ */
+ private Long answerId;
+
+ /**
+ * 回复的内容
+ */
+ private String content;
+
+ /**
+ * 点赞数
+ */
+ private Integer liked;
+
+ /**
+ * 状态,0:正常,1:被举报,2:禁止查看
+ */
+ private Boolean status;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/Follow.java b/src/main/java/com/hmdp/entity/Follow.java
new file mode 100644
index 0000000..4c8fd3b
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/Follow.java
@@ -0,0 +1,51 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_follow")
+public class Follow implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 关联的用户id
+ */
+ private Long followUserId;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/SeckillVoucher.java b/src/main/java/com/hmdp/entity/SeckillVoucher.java
new file mode 100644
index 0000000..a2d25ee
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/SeckillVoucher.java
@@ -0,0 +1,61 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 秒杀优惠券表,与优惠券是一对一关系
+ *
+ *
+ * @author 虎哥
+ * @since 2022-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_seckill_voucher")
+public class SeckillVoucher implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 关联的优惠券的id
+ */
+ @TableId(value = "voucher_id", type = IdType.INPUT)
+ private Long voucherId;
+
+ /**
+ * 库存
+ */
+ private Integer stock;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 生效时间
+ */
+ private LocalDateTime beginTime;
+
+ /**
+ * 失效时间
+ */
+ private LocalDateTime endTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/Shop.java b/src/main/java/com/hmdp/entity/Shop.java
new file mode 100644
index 0000000..2a3a626
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/Shop.java
@@ -0,0 +1,109 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_shop")
+public class Shop implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 商铺名称
+ */
+ private String name;
+
+ /**
+ * 商铺类型的id
+ */
+ private Long typeId;
+
+ /**
+ * 商铺图片,多个图片以','隔开
+ */
+ private String images;
+
+ /**
+ * 商圈,例如陆家嘴
+ */
+ private String area;
+
+ /**
+ * 地址
+ */
+ private String address;
+
+ /**
+ * 经度
+ */
+ private Double x;
+
+ /**
+ * 维度
+ */
+ private Double y;
+
+ /**
+ * 均价,取整数
+ */
+ private Long avgPrice;
+
+ /**
+ * 销量
+ */
+ private Integer sold;
+
+ /**
+ * 评论数量
+ */
+ private Integer comments;
+
+ /**
+ * 评分,1~5分,乘10保存,避免小数
+ */
+ private Integer score;
+
+ /**
+ * 营业时间,例如 10:00-22:00
+ */
+ private String openHours;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+ @TableField(exist = false)
+ private Double distance;
+}
diff --git a/src/main/java/com/hmdp/entity/ShopType.java b/src/main/java/com/hmdp/entity/ShopType.java
new file mode 100644
index 0000000..5d4f259
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/ShopType.java
@@ -0,0 +1,64 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_shop_type")
+public class ShopType implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 类型名称
+ */
+ private String name;
+
+ /**
+ * 图标
+ */
+ private String icon;
+
+ /**
+ * 顺序
+ */
+ private Integer sort;
+
+ /**
+ * 创建时间
+ */
+ @JsonIgnore
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ @JsonIgnore
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/User.java b/src/main/java/com/hmdp/entity/User.java
new file mode 100644
index 0000000..29f0de7
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/User.java
@@ -0,0 +1,66 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_user")
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 手机号码
+ */
+ private String phone;
+
+ /**
+ * 密码,加密存储
+ */
+ private String password;
+
+ /**
+ * 昵称,默认是随机字符
+ */
+ private String nickName;
+
+ /**
+ * 用户头像
+ */
+ private String icon = "";
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/UserInfo.java b/src/main/java/com/hmdp/entity/UserInfo.java
new file mode 100644
index 0000000..428be15
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/UserInfo.java
@@ -0,0 +1,87 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-24
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_user_info")
+public class UserInfo implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键,用户id
+ */
+ @TableId(value = "user_id", type = IdType.AUTO)
+ private Long userId;
+
+ /**
+ * 城市名称
+ */
+ private String city;
+
+ /**
+ * 个人介绍,不要超过128个字符
+ */
+ private String introduce;
+
+ /**
+ * 粉丝数量
+ */
+ private Integer fans;
+
+ /**
+ * 关注的人的数量
+ */
+ private Integer followee;
+
+ /**
+ * 性别,0:男,1:女
+ */
+ private Boolean gender;
+
+ /**
+ * 生日
+ */
+ private LocalDate birthday;
+
+ /**
+ * 积分
+ */
+ private Integer credits;
+
+ /**
+ * 会员级别,0~9级,0代表未开通会员
+ */
+ private Boolean level;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/Voucher.java b/src/main/java/com/hmdp/entity/Voucher.java
new file mode 100644
index 0000000..daffdee
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/Voucher.java
@@ -0,0 +1,105 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_voucher")
+public class Voucher implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 商铺id
+ */
+ private Long shopId;
+
+ /**
+ * 代金券标题
+ */
+ private String title;
+
+ /**
+ * 副标题
+ */
+ private String subTitle;
+
+ /**
+ * 使用规则
+ */
+ private String rules;
+
+ /**
+ * 支付金额
+ */
+ private Long payValue;
+
+ /**
+ * 抵扣金额
+ */
+ private Long actualValue;
+
+ /**
+ * 优惠券类型
+ */
+ private Integer type;
+
+ /**
+ * 优惠券类型
+ */
+ private Integer status;
+ /**
+ * 库存
+ */
+ @TableField(exist = false)
+ private Integer stock;
+
+ /**
+ * 生效时间
+ */
+ @TableField(exist = false)
+ private LocalDateTime beginTime;
+
+ /**
+ * 失效时间
+ */
+ @TableField(exist = false)
+ private LocalDateTime endTime;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/entity/VoucherOrder.java b/src/main/java/com/hmdp/entity/VoucherOrder.java
new file mode 100644
index 0000000..1e5f673
--- /dev/null
+++ b/src/main/java/com/hmdp/entity/VoucherOrder.java
@@ -0,0 +1,81 @@
+package com.hmdp.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("tb_voucher_order")
+public class VoucherOrder implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.INPUT)
+ private Long id;
+
+ /**
+ * 下单的用户id
+ */
+ private Long userId;
+
+ /**
+ * 购买的代金券id
+ */
+ private Long voucherId;
+
+ /**
+ * 支付方式 1:余额支付;2:支付宝;3:微信
+ */
+ private Integer payType;
+
+ /**
+ * 订单状态,1:未支付;2:已支付;3:已核销;4:已取消;5:退款中;6:已退款
+ */
+ private Integer status;
+
+ /**
+ * 下单时间
+ */
+ private LocalDateTime createTime;
+
+ /**
+ * 支付时间
+ */
+ private LocalDateTime payTime;
+
+ /**
+ * 核销时间
+ */
+ private LocalDateTime useTime;
+
+ /**
+ * 退款时间
+ */
+ private LocalDateTime refundTime;
+
+ /**
+ * 更新时间
+ */
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/src/main/java/com/hmdp/mapper/BlogCommentsMapper.java b/src/main/java/com/hmdp/mapper/BlogCommentsMapper.java
new file mode 100644
index 0000000..6d40ad0
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/BlogCommentsMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.BlogComments;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface BlogCommentsMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/BlogMapper.java b/src/main/java/com/hmdp/mapper/BlogMapper.java
new file mode 100644
index 0000000..ec3b62e
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/BlogMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.Blog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface BlogMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/FollowMapper.java b/src/main/java/com/hmdp/mapper/FollowMapper.java
new file mode 100644
index 0000000..926308a
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/FollowMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.Follow;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface FollowMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/SeckillVoucherMapper.java b/src/main/java/com/hmdp/mapper/SeckillVoucherMapper.java
new file mode 100644
index 0000000..3cf4af8
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/SeckillVoucherMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.SeckillVoucher;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * 秒杀优惠券表,与优惠券是一对一关系 Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2022-01-04
+ */
+public interface SeckillVoucherMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/ShopMapper.java b/src/main/java/com/hmdp/mapper/ShopMapper.java
new file mode 100644
index 0000000..d5694d4
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/ShopMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.Shop;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface ShopMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/ShopTypeMapper.java b/src/main/java/com/hmdp/mapper/ShopTypeMapper.java
new file mode 100644
index 0000000..b09890b
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/ShopTypeMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.ShopType;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface ShopTypeMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/UserInfoMapper.java b/src/main/java/com/hmdp/mapper/UserInfoMapper.java
new file mode 100644
index 0000000..77b9250
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/UserInfoMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.UserInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-24
+ */
+public interface UserInfoMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/UserMapper.java b/src/main/java/com/hmdp/mapper/UserMapper.java
new file mode 100644
index 0000000..adcebe3
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/UserMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface UserMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/mapper/VoucherMapper.java b/src/main/java/com/hmdp/mapper/VoucherMapper.java
new file mode 100644
index 0000000..2db21ed
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/VoucherMapper.java
@@ -0,0 +1,20 @@
+package com.hmdp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hmdp.entity.Voucher;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface VoucherMapper extends BaseMapper {
+
+ List queryVoucherOfShop(@Param("shopId") Long shopId);
+}
diff --git a/src/main/java/com/hmdp/mapper/VoucherOrderMapper.java b/src/main/java/com/hmdp/mapper/VoucherOrderMapper.java
new file mode 100644
index 0000000..e0cd90a
--- /dev/null
+++ b/src/main/java/com/hmdp/mapper/VoucherOrderMapper.java
@@ -0,0 +1,16 @@
+package com.hmdp.mapper;
+
+import com.hmdp.entity.VoucherOrder;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface VoucherOrderMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/hmdp/service/IBlogCommentsService.java b/src/main/java/com/hmdp/service/IBlogCommentsService.java
new file mode 100644
index 0000000..12dbee0
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IBlogCommentsService.java
@@ -0,0 +1,16 @@
+package com.hmdp.service;
+
+import com.hmdp.entity.BlogComments;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IBlogCommentsService extends IService {
+
+}
diff --git a/src/main/java/com/hmdp/service/IBlogService.java b/src/main/java/com/hmdp/service/IBlogService.java
new file mode 100644
index 0000000..33ffd0e
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IBlogService.java
@@ -0,0 +1,16 @@
+package com.hmdp.service;
+
+import com.hmdp.entity.Blog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IBlogService extends IService {
+
+}
diff --git a/src/main/java/com/hmdp/service/IFollowService.java b/src/main/java/com/hmdp/service/IFollowService.java
new file mode 100644
index 0000000..767c12d
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IFollowService.java
@@ -0,0 +1,16 @@
+package com.hmdp.service;
+
+import com.hmdp.entity.Follow;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IFollowService extends IService {
+
+}
diff --git a/src/main/java/com/hmdp/service/ISeckillVoucherService.java b/src/main/java/com/hmdp/service/ISeckillVoucherService.java
new file mode 100644
index 0000000..fb6642b
--- /dev/null
+++ b/src/main/java/com/hmdp/service/ISeckillVoucherService.java
@@ -0,0 +1,16 @@
+package com.hmdp.service;
+
+import com.hmdp.entity.SeckillVoucher;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 秒杀优惠券表,与优惠券是一对一关系 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2022-01-04
+ */
+public interface ISeckillVoucherService extends IService {
+
+}
diff --git a/src/main/java/com/hmdp/service/IShopService.java b/src/main/java/com/hmdp/service/IShopService.java
new file mode 100644
index 0000000..6dd6bb7
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IShopService.java
@@ -0,0 +1,20 @@
+package com.hmdp.service;
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Shop;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IShopService extends IService {
+
+ Result queryById(Long id);
+
+ Result updateShopById(Shop shop);
+}
diff --git a/src/main/java/com/hmdp/service/IShopTypeService.java b/src/main/java/com/hmdp/service/IShopTypeService.java
new file mode 100644
index 0000000..a4e5183
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IShopTypeService.java
@@ -0,0 +1,18 @@
+package com.hmdp.service;
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.ShopType;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IShopTypeService extends IService {
+
+ Result queryTypeList();
+}
diff --git a/src/main/java/com/hmdp/service/IUserInfoService.java b/src/main/java/com/hmdp/service/IUserInfoService.java
new file mode 100644
index 0000000..e8df101
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IUserInfoService.java
@@ -0,0 +1,16 @@
+package com.hmdp.service;
+
+import com.hmdp.entity.UserInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-24
+ */
+public interface IUserInfoService extends IService {
+
+}
diff --git a/src/main/java/com/hmdp/service/IUserService.java b/src/main/java/com/hmdp/service/IUserService.java
new file mode 100644
index 0000000..ed5685c
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IUserService.java
@@ -0,0 +1,23 @@
+package com.hmdp.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.hmdp.dto.LoginFormDTO;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.User;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IUserService extends IService {
+
+ Result sendCode(String phone, HttpSession session);
+
+ Result login(LoginFormDTO loginForm, HttpSession session);
+}
diff --git a/src/main/java/com/hmdp/service/IVoucherOrderService.java b/src/main/java/com/hmdp/service/IVoucherOrderService.java
new file mode 100644
index 0000000..91f8fa4
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IVoucherOrderService.java
@@ -0,0 +1,20 @@
+package com.hmdp.service;
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.VoucherOrder;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IVoucherOrderService extends IService {
+
+ Result seckillVoucher(Long voucherId);
+
+ Result creatVoucheOrder(Long voucherId);
+}
diff --git a/src/main/java/com/hmdp/service/IVoucherService.java b/src/main/java/com/hmdp/service/IVoucherService.java
new file mode 100644
index 0000000..bac7ad2
--- /dev/null
+++ b/src/main/java/com/hmdp/service/IVoucherService.java
@@ -0,0 +1,21 @@
+package com.hmdp.service;
+
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Voucher;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+public interface IVoucherService extends IService {
+
+ Result queryVoucherOfShop(Long shopId);
+
+ void addSeckillVoucher(Voucher voucher);
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/BlogCommentsServiceImpl.java b/src/main/java/com/hmdp/service/impl/BlogCommentsServiceImpl.java
new file mode 100644
index 0000000..4224ff9
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/BlogCommentsServiceImpl.java
@@ -0,0 +1,20 @@
+package com.hmdp.service.impl;
+
+import com.hmdp.entity.BlogComments;
+import com.hmdp.mapper.BlogCommentsMapper;
+import com.hmdp.service.IBlogCommentsService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class BlogCommentsServiceImpl extends ServiceImpl implements IBlogCommentsService {
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/BlogServiceImpl.java b/src/main/java/com/hmdp/service/impl/BlogServiceImpl.java
new file mode 100644
index 0000000..dc85c57
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/BlogServiceImpl.java
@@ -0,0 +1,20 @@
+package com.hmdp.service.impl;
+
+import com.hmdp.entity.Blog;
+import com.hmdp.mapper.BlogMapper;
+import com.hmdp.service.IBlogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class BlogServiceImpl extends ServiceImpl implements IBlogService {
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/FollowServiceImpl.java b/src/main/java/com/hmdp/service/impl/FollowServiceImpl.java
new file mode 100644
index 0000000..c044b79
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/FollowServiceImpl.java
@@ -0,0 +1,20 @@
+package com.hmdp.service.impl;
+
+import com.hmdp.entity.Follow;
+import com.hmdp.mapper.FollowMapper;
+import com.hmdp.service.IFollowService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class FollowServiceImpl extends ServiceImpl implements IFollowService {
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/SeckillVoucherServiceImpl.java b/src/main/java/com/hmdp/service/impl/SeckillVoucherServiceImpl.java
new file mode 100644
index 0000000..485860f
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/SeckillVoucherServiceImpl.java
@@ -0,0 +1,20 @@
+package com.hmdp.service.impl;
+
+import com.hmdp.entity.SeckillVoucher;
+import com.hmdp.mapper.SeckillVoucherMapper;
+import com.hmdp.service.ISeckillVoucherService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 秒杀优惠券表,与优惠券是一对一关系 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2022-01-04
+ */
+@Service
+public class SeckillVoucherServiceImpl extends ServiceImpl implements ISeckillVoucherService {
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/ShopServiceImpl.java b/src/main/java/com/hmdp/service/impl/ShopServiceImpl.java
new file mode 100644
index 0000000..3d17787
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/ShopServiceImpl.java
@@ -0,0 +1,135 @@
+package com.hmdp.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Shop;
+import com.hmdp.mapper.ShopMapper;
+import com.hmdp.service.IShopService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+import java.util.concurrent.TimeUnit;
+
+import static com.hmdp.utils.RedisConstants.CACHE_SHOP_KEY;
+import static com.hmdp.utils.RedisConstants.CACHE_SHOP_TTL;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class ShopServiceImpl extends ServiceImpl implements IShopService {
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ @Override
+ public Result queryById(Long id) {
+ Shop shop = queryByIdWithMutex(id);
+ if (shop == null){
+ return Result.fail("店铺不存在");
+ }
+ return Result.ok(shop);
+ }
+
+ public Shop queryByIdWithRedis(Long id) {
+ // 使用redis缓存
+ // 查询缓存
+ String cacheShop = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
+ // 判断是否存在
+ Shop shop = new Shop();
+ if(StrUtil.isNotBlank(cacheShop)){
+ // 存在直接返回
+ shop = JSONUtil.toBean(cacheShop, Shop.class);
+ return shop;
+ }
+ // 不存在,查询数据库
+ shop = getById(id);
+ if(shop == null){
+ // 数据库不存在,返回错误
+ return null;
+ // 解决缓存穿透的话,就在这往redis存一个null
+ }
+ stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
+ return shop;
+ }
+
+ public Shop queryByIdWithMutex(Long id) {
+ String key = CACHE_SHOP_KEY + id;
+ // 使用redis缓存
+ // 查询缓存
+ String cacheShop = stringRedisTemplate.opsForValue().get(key);
+ // 判断是否存在
+ Shop shop = new Shop();
+ if(StrUtil.isNotBlank(cacheShop)){
+ // 存在直接返回
+ shop = JSONUtil.toBean(cacheShop, Shop.class);
+ return shop;
+ }
+
+ boolean isLock = false;
+ try {
+ isLock =tryLock(id);
+ // 不存在,尝试获取互斥锁
+ if(isLock){
+ // 获取到互斥锁,查询数据库
+ shop = getById(id);
+ Thread.sleep(200); //模拟重建时的延迟
+ if(shop == null){
+ // 解决缓存穿透的话,就在这往redis存一个null
+ stringRedisTemplate.opsForValue().set(key, "",CACHE_SHOP_TTL, TimeUnit.MINUTES);
+ // 数据库不存在,返回错误
+ return null;
+ }
+ // 存入缓存
+ stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
+ }
+ // 没有获取到互斥锁
+ // 休眠后重新执行
+ Thread.sleep(50);
+ return queryByIdWithMutex (id);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ // 释放互斥锁
+ if (isLock) {
+ delectLock(id);
+ }
+
+ }
+ }
+
+ private boolean tryLock(Long id) {
+ // 本质就是设置一个redis缓存,key任意
+ // 设置10秒过期时间防止死锁,10秒就够,因为这些请求一半都很快
+ Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock:shop:"+id, "1",10, TimeUnit.SECONDS);
+ return BooleanUtil.isTrue(flag);
+ }
+ private void delectLock(Long id) {
+ // 本质就是删除上面key对应的缓存
+ stringRedisTemplate.delete("lock:shop:"+id);
+ }
+
+ @Override
+ @Transactional // 保证原子性
+ public Result updateShopById(Shop shop) {
+ Long shopId = shop.getId();
+ if(shopId == null){
+ return Result.fail("店铺id不能为空");
+ }
+ // 更新数据库
+ updateById(shop);
+ // 删除缓存
+ stringRedisTemplate.delete(CACHE_SHOP_KEY + shopId);
+ return Result.ok();
+ }
+}
diff --git a/src/main/java/com/hmdp/service/impl/ShopTypeServiceImpl.java b/src/main/java/com/hmdp/service/impl/ShopTypeServiceImpl.java
new file mode 100644
index 0000000..68628f3
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/ShopTypeServiceImpl.java
@@ -0,0 +1,48 @@
+package com.hmdp.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.ShopType;
+import com.hmdp.mapper.ShopTypeMapper;
+import com.hmdp.service.IShopTypeService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hmdp.utils.RedisConstants;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static com.hmdp.utils.RedisConstants.CACHE_SHOP_TTL;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class ShopTypeServiceImpl extends ServiceImpl implements IShopTypeService {
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ @Override
+ public Result queryTypeList() {
+ // list类型的数据怎么处理
+ String cacheShop = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + "list");
+ if(StrUtil.isNotBlank(cacheShop)){
+ // 将string转成list
+ return Result.ok(JSONUtil.toList(cacheShop, ShopType.class));
+ }
+ // 如果为空去数据库查
+ List sortShop = query().orderByAsc("sort").list();
+ if(sortShop == null){
+ return Result.fail("查询失败");
+ }
+ stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + "list", JSONUtil.toJsonStr(sortShop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
+ return Result.ok(sortShop);
+ }
+}
diff --git a/src/main/java/com/hmdp/service/impl/UserInfoServiceImpl.java b/src/main/java/com/hmdp/service/impl/UserInfoServiceImpl.java
new file mode 100644
index 0000000..402977f
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/UserInfoServiceImpl.java
@@ -0,0 +1,20 @@
+package com.hmdp.service.impl;
+
+import com.hmdp.entity.UserInfo;
+import com.hmdp.mapper.UserInfoMapper;
+import com.hmdp.service.IUserInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-24
+ */
+@Service
+public class UserInfoServiceImpl extends ServiceImpl implements IUserInfoService {
+
+}
diff --git a/src/main/java/com/hmdp/service/impl/UserServiceImpl.java b/src/main/java/com/hmdp/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..ea63632
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/UserServiceImpl.java
@@ -0,0 +1,102 @@
+package com.hmdp.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.bean.copier.CopyOptions;
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hmdp.dto.LoginFormDTO;
+import com.hmdp.dto.Result;
+import com.hmdp.dto.UserDTO;
+import com.hmdp.entity.User;
+import com.hmdp.mapper.UserMapper;
+import com.hmdp.service.IUserService;
+import com.hmdp.utils.RegexUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpSession;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static com.hmdp.utils.RedisConstants.*;
+import static com.hmdp.utils.SystemConstants.USER_NICK_NAME_PREFIX;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Slf4j
+@Service
+public class UserServiceImpl extends ServiceImpl implements IUserService {
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ @Override
+ public Result sendCode(String phone, HttpSession session) {
+ // 校验手机号是否合格
+ if(RegexUtils.isPhoneInvalid(phone)){
+ return Result.fail("手机号格式错误");
+ }
+ // 合格生成验证码
+ String code = RandomUtil.randomNumbers(6);
+// // 保存到session
+// session.setAttribute("code",code);
+ // 保存到redis,并且两分钟失效
+ stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);
+ // 发送验证码
+ log.debug("发送验证码成功,验证码为:{}",code);
+ return Result.ok();
+ }
+
+ @Override
+ public Result login(LoginFormDTO loginForm, HttpSession session) {
+ // 校验手机号是否合格
+ String phone = loginForm.getPhone();
+ if(RegexUtils.isPhoneInvalid(phone)){
+ return Result.fail("手机号格式错误");
+ }
+ // 获取loginForm中的code对比session中的
+ String code = loginForm.getCode();
+// if(code == null || !code.equals(session.getAttribute("code"))){
+// return Result.fail("验证码错误");
+// }
+ String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
+ if(code == null || !code.equals(cacheCode)){
+ return Result.fail("验证码错误");
+ }
+ // 判断用户是否存在,存在存到session,不存在创建用户
+ User user = query().eq("phone", phone).one();
+ if (user == null){
+ user = saveUserByPhone(phone);
+ save(user);
+ }
+// session.setAttribute("user",user);
+ // 保存用户信息到 redis中
+ // 随机生成token,作为登录令牌
+ String token = UUID.randomUUID().toString(true);
+ // 将user对象转成hashMap
+ UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
+ Map userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
+ CopyOptions.create()
+ .setIgnoreNullValue(true)
+ .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
+ stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY+token,userMap);
+ stringRedisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL,TimeUnit.MINUTES);
+ return Result.ok(token);
+ }
+
+ private User saveUserByPhone(String phone) {
+ User user = new User();
+ user.setPhone(phone);
+ user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(10));
+ return user;
+ }
+}
diff --git a/src/main/java/com/hmdp/service/impl/VoucherOrderServiceImpl.java b/src/main/java/com/hmdp/service/impl/VoucherOrderServiceImpl.java
new file mode 100644
index 0000000..76cf478
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/VoucherOrderServiceImpl.java
@@ -0,0 +1,120 @@
+package com.hmdp.service.impl;
+
+import cn.hutool.db.handler.RsHandler;
+import com.hmdp.config.RedissonConfig;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.SeckillVoucher;
+import com.hmdp.entity.Voucher;
+import com.hmdp.entity.VoucherOrder;
+import com.hmdp.mapper.VoucherOrderMapper;
+import com.hmdp.service.ISeckillVoucherService;
+import com.hmdp.service.IVoucherOrderService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hmdp.service.IVoucherService;
+import com.hmdp.utils.RedisIdWorker;
+import com.hmdp.utils.SimpleRedisLock;
+import com.hmdp.utils.UserHolder;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.aop.framework.AopProxy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class VoucherOrderServiceImpl extends ServiceImpl implements IVoucherOrderService {
+ @Autowired
+ private ISeckillVoucherService iSeckillVoucherService;
+ @Autowired
+ private RedisIdWorker redisIdWorker;
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ @Resource
+ private RedissonClient redissonClient;
+ @Override
+ public Result seckillVoucher(Long voucherId) {
+
+ // 根据vorcherId查询优惠券
+ SeckillVoucher seckillVoucher = iSeckillVoucherService.getById(voucherId);
+ // 判断秒杀功能是否已经开始或结束
+ if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())) {
+ return Result.fail("秒杀功能还未开始");
+ } else if (seckillVoucher.getEndTime().isBefore(LocalDateTime.now())) {
+ return Result.fail("秒杀功能已经结束");
+ }
+ // 判断库存是否充足
+ if(seckillVoucher.getStock()<1){
+ return Result.fail("库存不足");
+ }
+ Long userID = UserHolder.getUser().getId();
+
+// // 基于悲观锁,但是这个在集群环境下还是会导致线程不安全
+// synchronized(userID.toString().intern()) {
+// // 获取代理对象,才能让事务生效
+// IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
+// return proxy.creatVoucheOrder(voucherId);
+// }
+ // 不再用自己实现的分布式锁了,因为它存在不可重入,不可重试,超时释放,主从一致的问题
+// SimpleRedisLock simpleRedisLock = new SimpleRedisLock("oreder:" + userID, stringRedisTemplate);
+// boolean isLock = simpleRedisLock.tryLock(1200L);
+ // 利用redission 的分布式锁可以解决上述问题
+ RLock lock = redissonClient.getLock("lock:oreder:" + userID);
+ boolean isLock = lock.tryLock();
+ if(!isLock){
+ return Result.fail("请勿重复下单");
+ }
+ // 获取代理对象,才能让事务生效
+ try {
+ IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
+ return proxy.creatVoucheOrder(voucherId);
+ } finally {
+ // 释放锁
+ lock.unlock();
+ }
+
+ }
+ @Transactional
+ public Result creatVoucheOrder(Long voucherId) {
+ Long userID = UserHolder.getUser().getId();
+
+ // 判断当前用户是否已经抢过订单了
+ Integer count = query().eq("user_id", userID).eq("voucher_id", voucherId).count();
+
+ if(count>0){
+ return Result.fail("您已经抢过该优惠券了");
+ }
+ // 扣减库存,乐观锁,CAS法
+ // boolean succed = iSeckillVoucherService.update().setSql("stock = stock-1").
+ // eq("voucher_id",voucherId).eq("stock",seckillVoucher.getStock()).update(); 这种情况会导致即使有很多余额也会说库存不足
+ boolean succed = iSeckillVoucherService.update().setSql("stock = stock-1").
+ eq("voucher_id",voucherId).gt("stock",0).update();
+ if(!succed){
+ System.out.println("失败");
+ return Result.fail("库存不足");
+ }
+ // 创建一个新的voucherOrder订单
+ VoucherOrder voucherOrder = new VoucherOrder();
+ long orderId = redisIdWorker.nextId("order");
+ voucherOrder.setId(orderId);
+
+ voucherOrder.setUserId(userID);
+ voucherOrder.setVoucherId(voucherId);
+ save(voucherOrder);
+ // 返回订单id
+ return Result.ok(orderId);
+
+ }
+}
diff --git a/src/main/java/com/hmdp/service/impl/VoucherServiceImpl.java b/src/main/java/com/hmdp/service/impl/VoucherServiceImpl.java
new file mode 100644
index 0000000..8a8a3f6
--- /dev/null
+++ b/src/main/java/com/hmdp/service/impl/VoucherServiceImpl.java
@@ -0,0 +1,51 @@
+package com.hmdp.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hmdp.config.RedissonConfig;
+import com.hmdp.dto.Result;
+import com.hmdp.entity.Voucher;
+import com.hmdp.mapper.VoucherMapper;
+import com.hmdp.entity.SeckillVoucher;
+import com.hmdp.service.ISeckillVoucherService;
+import com.hmdp.service.IVoucherService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2021-12-22
+ */
+@Service
+public class VoucherServiceImpl extends ServiceImpl implements IVoucherService {
+ @Resource
+ private ISeckillVoucherService seckillVoucherService;
+
+ @Override
+ public Result queryVoucherOfShop(Long shopId) {
+ // 查询优惠券信息
+ List vouchers = getBaseMapper().queryVoucherOfShop(shopId);
+ // 返回结果
+ return Result.ok(vouchers);
+ }
+
+ @Override
+ @Transactional
+ public void addSeckillVoucher(Voucher voucher) {
+ // 保存优惠券
+ save(voucher);
+ // 保存秒杀信息
+ SeckillVoucher seckillVoucher = new SeckillVoucher();
+ seckillVoucher.setVoucherId(voucher.getId());
+ seckillVoucher.setStock(voucher.getStock());
+ seckillVoucher.setBeginTime(voucher.getBeginTime());
+ seckillVoucher.setEndTime(voucher.getEndTime());
+ seckillVoucherService.save(seckillVoucher);
+ }
+}
diff --git a/src/main/java/com/hmdp/utils/ILock.java b/src/main/java/com/hmdp/utils/ILock.java
new file mode 100644
index 0000000..b617aa5
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/ILock.java
@@ -0,0 +1,7 @@
+package com.hmdp.utils;
+
+public interface ILock {
+ boolean tryLock(Long timeOutSec);
+
+ void unLock();
+}
diff --git a/src/main/java/com/hmdp/utils/LoginInterceptor.java b/src/main/java/com/hmdp/utils/LoginInterceptor.java
new file mode 100644
index 0000000..1910098
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/LoginInterceptor.java
@@ -0,0 +1,30 @@
+package com.hmdp.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.hmdp.dto.UserDTO;
+import com.hmdp.entity.User;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
+
+public class LoginInterceptor implements HandlerInterceptor {
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ if(UserHolder.getUser() == null){
+ response.setStatus(401);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/hmdp/utils/PasswordEncoder.java b/src/main/java/com/hmdp/utils/PasswordEncoder.java
new file mode 100644
index 0000000..1360e38
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/PasswordEncoder.java
@@ -0,0 +1,34 @@
+package com.hmdp.utils;
+
+
+import cn.hutool.core.util.RandomUtil;
+import org.springframework.util.DigestUtils;
+
+import java.nio.charset.StandardCharsets;
+
+public class PasswordEncoder {
+
+ public static String encode(String password) {
+ // 生成盐
+ String salt = RandomUtil.randomString(20);
+ // 加密
+ return encode(password,salt);
+ }
+ private static String encode(String password, String salt) {
+ // 加密
+ return salt + "@" + DigestUtils.md5DigestAsHex((password + salt).getBytes(StandardCharsets.UTF_8));
+ }
+ public static Boolean matches(String encodedPassword, String rawPassword) {
+ if (encodedPassword == null || rawPassword == null) {
+ return false;
+ }
+ if(!encodedPassword.contains("@")){
+ throw new RuntimeException("密码格式不正确!");
+ }
+ String[] arr = encodedPassword.split("@");
+ // 获取盐
+ String salt = arr[0];
+ // 比较
+ return encodedPassword.equals(encode(rawPassword, salt));
+ }
+}
diff --git a/src/main/java/com/hmdp/utils/RedisConstants.java b/src/main/java/com/hmdp/utils/RedisConstants.java
new file mode 100644
index 0000000..c8f8c66
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/RedisConstants.java
@@ -0,0 +1,22 @@
+package com.hmdp.utils;
+
+public class RedisConstants {
+ public static final String LOGIN_CODE_KEY = "login:code:";
+ public static final Long LOGIN_CODE_TTL = 2L;
+ public static final String LOGIN_USER_KEY = "login:token:";
+ public static final Long LOGIN_USER_TTL = 30L;
+
+ public static final Long CACHE_NULL_TTL = 2L;
+
+ public static final Long CACHE_SHOP_TTL = 30L;
+ public static final String CACHE_SHOP_KEY = "cache:shop:";
+
+ public static final String LOCK_SHOP_KEY = "lock:shop:";
+ public static final Long LOCK_SHOP_TTL = 10L;
+
+ public static final String SECKILL_STOCK_KEY = "seckill:stock:";
+ public static final String BLOG_LIKED_KEY = "blog:liked:";
+ public static final String FEED_KEY = "feed:";
+ public static final String SHOP_GEO_KEY = "shop:geo:";
+ public static final String USER_SIGN_KEY = "sign:";
+}
diff --git a/src/main/java/com/hmdp/utils/RedisData.java b/src/main/java/com/hmdp/utils/RedisData.java
new file mode 100644
index 0000000..8f777fc
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/RedisData.java
@@ -0,0 +1,11 @@
+package com.hmdp.utils;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class RedisData {
+ private LocalDateTime expireTime;
+ private Object data;
+}
diff --git a/src/main/java/com/hmdp/utils/RedisIdWorker.java b/src/main/java/com/hmdp/utils/RedisIdWorker.java
new file mode 100644
index 0000000..7a4ce0a
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/RedisIdWorker.java
@@ -0,0 +1,31 @@
+package com.hmdp.utils;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+
+@Component
+public class RedisIdWorker {
+ private static final long BEGIN_TIMESTAMP = 1640995200L;
+ private static final long COUNT_BITS = 32;
+ @Resource
+ private StringRedisTemplate stringRedisTemplate;
+ // 拼接一个时间戳,再加一个根据输入的字符串自增长的32位id
+ public long nextId(String prefix) {
+ LocalDateTime now = LocalDateTime.now();
+ long GapSecond = now.toEpochSecond(ZoneOffset.UTC)-BEGIN_TIMESTAMP;
+ String date = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+ long count = stringRedisTemplate.opsForValue().increment("icr:" + prefix+date);
+ return GapSecond <<32 | count;
+ }
+
+
+// public static void main(String[] args) {
+// LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
+// System.out.println(localDateTime.toEpochSecond(ZoneOffset.UTC)); //获取这个时间的秒数
+// }
+}
diff --git a/src/main/java/com/hmdp/utils/RefreshTokenInterceptor.java b/src/main/java/com/hmdp/utils/RefreshTokenInterceptor.java
new file mode 100644
index 0000000..c2b10dd
--- /dev/null
+++ b/src/main/java/com/hmdp/utils/RefreshTokenInterceptor.java
@@ -0,0 +1,52 @@
+package com.hmdp.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.hmdp.dto.UserDTO;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
+
+public class RefreshTokenInterceptor implements HandlerInterceptor {
+ private final StringRedisTemplate stringRedisTemplate;
+ public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
+ this.stringRedisTemplate = stringRedisTemplate;
+ }
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ // 获取token
+ String token = request.getHeader("authorization");
+ if (StrUtil.isBlank(token)) {
+ return true;
+ }
+// HttpSession session = request.getSession();
+// User user = (User) session.getAttribute("user");
+ System.out.println(stringRedisTemplate);
+ Map