0
点赞
收藏
分享

微信扫一扫

使用redis,创建一个demo体验“秒杀“系统

木匠0819 2022-04-21 阅读 81

一.项目搭建

1.新建一个SpringBoot项目
2.导入依赖

Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎,类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。
Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用
3.编辑配置文件 application.yml

spring:
  #thymeleaf 配置
  thymeleaf:
    # 关闭缓存
    cache: false
  #配置数据源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///seckill?useUnicode=true&characterEncoding=utf-8&serverTimeZone=Asia/Shanghai
    username: root
    password: root
    #配置连接池
    hikari:
      #连接池名字
      pool-name: HikariPool
      #最小空间连接数
      minimum-idle: 5
      #最大连接数,默认10,可以不设置
      maximum-pool-size: 10
      #连接最大存活时间,0表示永久,默认30分钟,可以不设置
      max-lifetime: 1800000
      #空闲连接存活最大时间,默认10分钟(600000ms),这里设置半个小时
      idle-timeout: 1800000
      #连接超时时间,默认30秒
      connection-timeout: 30000
      #心态机制,测试连接是否可用,如果有问题说明我们的连接池有问题
      connection-test-query: select 1
      #从连接池返回的连接自动提交
      auto-commit: true

#Mybatis-plus配置
mybatis-plus:
  #配置XXXMapper.xml的映射路径
  mapper-locations: classpath*:/mapper/*Mapper.xml
  #配置Mybatis别名包
  type-aliases-package: cn.bs.seckill.pojo

#Mybatis Sql日志打印(指定方法接口所在的包,不是你xml所在的包)
logging:
  level:
    cn.bs.seckill.mapper: debug

4.把包建好
在这里插入图片描述

二 编写测试类

Model是每次请求中都存在的默认参数,利用其addAttribute()方法即可将服务器的值传递到jsp页面中
1.新建一个TestController类

package cn.bs.seckill.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/*本类用于测试*/
@Controller
@RequestMapping("/test")
public class TestController {

    //测试页面跳转
    @RequestMapping("/hello")
    public String hello(Model model){
         model.addAttribute("msg","老王");
         return "hello";
    }
}

2.在tenplates包下新建一个hello.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>测试</title>
</head>
<body>
    <p th:text="'我是你亲爱的'+${msg}"></p>
</body>
</html>

3.启动项目,测试看是否成功
输入controller的地址,就会跳转到页面

三 编写数据库

1.新建一个数据库,seckill,注意选择编码格式
2.建表

CREATE TABLE t_user(
	`id` BIGINT(20) NOT NULL COMMENT '用户ID,用手机号码代替',
	`nickname` VARCHAR(200) NOT NULL COMMENT '昵称',
	`password` VARCHAR(32) DEFAULT NULL COMMENT '前端传给后端先用md5加密(明文+固定的salt值),后端存数据库之前再加盐加密,双重加密',
	`slat` VARCHAR(10) DEFAULT NULL COMMENT '盐值', 
	`head` VARCHAR(128) DEFAULT NULL COMMENT '头像',
	`register_date` datetime DEFAULT NULL COMMENT '注册时间',
	`last_login_date` datetime DEFAULT NULL COMMENT '最后一次登录时间',
	`login_count` INT(10) DEFAULT '0' COMMENT '登录次数',
	PRIMARY KEY(`id`)
)

四 编写工具类

1.需要用到md5加密,md5加密操作
2.编写各个包,这里需要添加一个vo包

  • 1 创建LoginVo
package cn.bs.demoseckill.vo;

import com.sun.istack.internal.NotNull;
import lombok.Data;
//介绍账号密码
@Data
public class LoginVo {
    @NotNull
    //@IsMobile
    private String mobile;
    @NotNull
    //@Length(min = 32)
    private String password;
}

这里注释掉的东西后面我们在补回来

  • 2 创建一个RespBean
package cn.bs.demoseckill.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RespBean {

    private long code;
    private String message;
    private Object obj;

    //登录成功返回的消息
    public static RespBean success(){
        return new RespBean(RespBeanEnum.SUCCESS.getCODE(), RespBeanEnum.SUCCESS.getMESSAGE(), null);
    }
    public static RespBean success(Object obj){
        return new RespBean(RespBeanEnum.SUCCESS.getCODE(), RespBeanEnum.SUCCESS.getMESSAGE(), obj);
    }
    //登录失败返回的消息
    public static RespBean error(RespBeanEnum pe){
        return new RespBean(pe.getCODE(), pe.getMESSAGE(), null);
    }
    public static RespBean error(RespBeanEnum pe, Object obj){
        return new RespBean(pe.getCODE(), pe.getMESSAGE(), obj);
    }
}
  • 3 创建一个RespBeaEnum
package cn.bs.demoseckill.vo;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

@AllArgsConstructor
@ToString
@Getter
public enum RespBeanEnum {
    SUCCESS("成功",200),
    ERROR("服务器异常",500),

    LOGIN_ERROR("休想白嫖,请登录",530),
    LOGIN_FAILED("账号或者密码不正确",531),
    LOGIN_FAILEDP("密码不对",532);

    private final String MESSAGE;
    private final Integer CODE;
}

五 导入静态资源

在这里插入图片描述

  1. 分析login跳转
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

六 编写登录功能

  1. 编写登录层
package cn.bs.seckill.controller;

import cn.bs.seckill.service.UserService;
import cn.bs.seckill.vo.LoginVo;
import cn.bs.seckill.vo.RespBean;
import lombok.extern.slf4j.Slf4j;
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.ResponseBody;

@Controller
//@RestController 返回的是类里面东西,Controller才是跳转到静态资源
@Slf4j
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private UserService userService;

    //跳转登录页面
    @RequestMapping("/login")
    public String login(){
        return "login";
    }

    @RequestMapping("/doLogin")
    @ResponseBody
    public RespBean doLogin(LoginVo loginVo){
        return userService.doLogin(loginVo);
    }
}
@RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径;用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法

@RequestMapping 后,<font color='red'>返回值通常解析为跳转路径</font>,加上 *@Responsebody* 后返回结果<font color='red'>不会被解析为跳转路径,而是直接写入HTTP 响应正文中</font>,一般在异步获取数据时使用【也就是AJAX】,所以你如果是ajax请求,请把它加上,不然报错你又瓜起

2.编写业务逻辑,先在UserService接口里面添加doLogin方法,然后去实现类实现

public interface UserService {
    //登录接口
    RespBean doLogin(LoginVo loginVo);
}

然后在实现类里写好我们的登录方法

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public RespBean doLogin(LoginVo loginVo) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();

        //判断账号密码是否为空
        if (StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }
        //判断是否正确输入手机号
        if (!ValidatorUtil.isMobile(mobile)){
            return RespBean.error(RespBeanEnum.LOGIN_FAILED);
        }
        User user = userMapper.selectById(mobile);
        //判断手机号是否存在
        if (null==user){
            return RespBean.error(RespBeanEnum.LOGIN_FAILED);
        }
        //判断密码是否正确
        if (!(user.getPassword()).equals(MD5Util.toDBPassEpt(password))){
            return RespBean.error(RespBeanEnum.LOGIN_FAILEDP);

        }
        return RespBean.success();
    }
}

3.测试是否能登录

输入一个账号密码,我这里以123456为例子,把它做两次加密,然后存入数据库中
数据库里id就是登录的账号

七 引入303校验

1.导入依赖

   		<!--JSR303数据校验-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

我们为了判断用户是否输入了正确的账号格式编写了大量的代码,为了节省时间,我们可以用303数据校验
2.因为我的账号密码是通过传到后端是通过我们的LoginVo这个类里面的两个属性搞的,所以我们需要在这个类的两个属性上面加上判断注解

@Data
public class LoginVo {
    @NotNull
    @IsMobile
    private String mobile;
    @NotNull
    @Length(min = 32)
    private String password;
}
@IsMobile是我们自定义的注解,以后在开发当中,我们也可以仿照这种方式来自定义需要的注解

3.新建一个IsMobile注解,下面的代码不用自己写,可以通过进入@NotNull注解进入底层代码复制这一段,为什么需要自定义这个注解呢?因为我们需要判断手机号是否是必须输入的内容,而@NotNull做不到

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//校验规则
@Constraint(
        validatedBy = {MobileValidator.class}
)
public @interface IsMobile {

    //添加一个方法作为验证手机号为必填
    boolean required() default true;

    String message() default "{请输入正确的手机号}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

4.@Constraint( validatedBy = {MobileValidator.class})这个方法里面的参数,是校验规则,所以我们需要新建一个类来负责编写校验规则

public class MobileValidator implements ConstraintValidator<IsMobile, String> {


    private boolean required = false;

    //初始化,因为是手机号,所以我们就判断是否为必填
    @Override
    public void initialize(IsMobile constraintAnnotation) {
        //调用此方法,把required赋值为真
        required = constraintAnnotation.required();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        //如果是必填
        if (required) {
            //判断手机号格式是否正确
            return ValidatorUtil.isMobile(s);
        }
        //如果是非必填
        else {
            //返回为真
            if (StringUtils.isEmpty(s)) {
                return true;
            } else {
                //判断格式是否正确
                return ValidatorUtil.isMobile(s);
            }
        }
    }
}
其中initialize为初始化方法,可以在里面做一些初始化操作,isValid方法就是我们最终需要的校验方法了。可以在该方法中实现具体的校验步骤。

5.接下来把UserServiceImpl层里面的两个判断手机是否为空和格式是否正确的两段代码注释掉

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public RespBean doLogin(LoginVo loginVo) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();

/*        //判断账号密码是否为空
        if (StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }
        //判断是否正确输入手机号
        if (!ValidatorUtil.isMobile(mobile)){
            return RespBean.error(RespBeanEnum.LOGIN_FAILED);
        }*/
        User user = userMapper.selectById(mobile);
        //判断手机号是否存在
        if (null==user){
            return RespBean.error(RespBeanEnum.LOGIN_FAILED);
        }
        //判断密码是否正确
        if (!(user.getPassword()).equals(MD5Util.toDBPassEpt(password))){
            return RespBean.error(RespBeanEnum.LOGIN_FAILEDP);

        }
        return RespBean.success();
    }
}

6.在LoginController层的doLogin方法的参数里加上我们的注解

@Controller
//@RestController 返回的是类里面东西,Controller才是跳转到静态资源
@Slf4j
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private UserService userService;

    //跳转登录页面
    @RequestMapping("/login")
    public String login(){
        return "login";
    }

    @RequestMapping("/doLogin")
    //注意必须的有Resp这个注解,不然
    @ResponseBody
    public RespBean doLogin( @Valid LoginVo loginVo){
       /* log.info("{}",loginVo);
        return null;*/
        return userService.doLogin(loginVo);
    }
}

7.开始测试,故意乱输手机号,后端就会收到异常

举报

相关推荐

0 条评论