当前位置:网站首页>Secsha system 1- login function

Secsha system 1- login function

2022-07-03 15:28:00 You are my forever bug

Learning goals
 Insert picture description here
Technical point
 Insert picture description here
This is mainly seckill business , No front and rear end separation

How to design a seckill system

1、 Second kill system solves two problems

  1. Concurrent reading
  2. Write concurrently

2、 Technical requirements of seckill system :

  1. High performance
    Seckill involves a lot of concurrent reads and writes , Therefore, it is important to support high concurrent access , Solution : Dynamic and static separation 、 Discovery and isolation of hot spots 、 Peak clipping and layered filtering of requests 、 The ultimate optimization of the server .
  2. Uniformity
    Limited goods are requested in large numbers , Take stock reduction 、 Payment minus stock 、 There are several ways to deduct inventory, such as withholding , Ensure the accuracy of data under large concurrency .
  3. High availability
    Avoid unexpected situations , There is also a design planB programme , Ensure the high availability and correctness of the system .

spring boot (java8) Environment building

 Insert picture description here

Technology Architecture :springboot + mybatis-plus + mysql + thymeleaf
1、pom file

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>seckill</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>seckill</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2、application.yaml The configuration file
among : Use springboot The default data connection thread pool :hikari( Hey, Cary ), Known as the fastest thread pool

spring:
  # thymeleaf Turn off caching 
  thymeleaf:
    cache: false

  # MySql Data source configuration 
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/secKill?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

    #  Fastest connection pool 
    hikari:
      #  The name of the connection pool 
      pool-name: DateHikariCP
      #  Minimum number of idle connections 
      minimum-idle: 5
      #  Maximum free connection lifetime   Default 600000(10 minute )
      idle-timeout: 1800000
      #  maximum connection   Default 10
      maximum-pool-size: 10
      #  Connections returned from the connection pool are automatically submitted 
      auto-commit: true
      #  Maximum connection lifetime   0 For permanent survival , Default  1800000( minute )
      max-lifetime: 1800000
      #  Connection timeout   Default 30000(30 second )
      connection-timeout: 30000
      #  A query statement to test whether the connection is possible 
      connection-test-query: SELECT 1

# mybatis-plus  To configure 
mybatis-plus:
  #  To configure  Mapper.xml The path of the mapping file 
  mapper-locations: classpath*:/mapper/*.xml # mybatis SQL  Print ( Interface method in package , No  mapper.xml The bag where it is ) logging: level: com.example.seckill.mapper: DEBUG 

3、 Add to the startup class mapper Package scanning
@MapperScan(“com.example.seckill.mapper”)

Okay Write a test request Look at the problems of the project
controller

package com.example.seckill.controller;

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

@Controller
@RequestMapping("/my")
public class TestDemo {
    

    @RequestMapping("/hello")
    public String hello(Model model) {
    
        model.addAttribute("name","lishuang");
        return "hello";
    }
}

thymeleaf

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> test </title>
</head>
<body>

<p th:text="'hello:'+${name}"></p>
</body>
</html>

 Insert picture description here
ok 了

Table information of database

CREATE TABLE t_user(
	`id` BIGINT(20) NOT NULL COMMENT ' user ID, Phone number ',
	`nickname` VARCHAR(255) not NULL,
	`password` VARCHAR(32) DEFAULT NULL COMMENT 'MD5(MD5(pass Plaintext + Fix salt)+salt)',
	`salt` VARCHAR(10) DEFAULT NULL,
	`head` VARCHAR(128) DEFAULT NULL COMMENT ' Head portrait ',
	`register_date` datetime DEFAULT NULL COMMENT ' Registration time ',
	`last_login_date` datetime DEFAULT NULL COMMENT ' Last login event ',
	`login_count` int(11) DEFAULT '0' COMMENT ' Login times ',
	PRIMARY KEY(`id`)
)
COMMENT ' User table ';

CREATE TABLE t_goods(
	id BIGINT(20) not NULL AuTO_increment COMMENT ' goods ID',
	goods_name VARCHAR(16) DEFAULT NULL COMMENT ' Name of commodity ',
	goods_title VARCHAR(64) DEFAULT NULL COMMENT ' Commodity title ',
	goods_img VARCHAR(64) DEFAULT NULL COMMENT ' Commodity images ',
	goods_detail LONGTEXT COMMENT ' Goods details ',
	goods_price DECIMAL(10,2) DEFAULT '0.00' COMMENT ' commodity price ',
	goods_stock INT(11) DEFAULT '0' COMMENT ' inventory ,-1 There is no limit ',
	PRIMARY KEY(id)
)
COMMENT ' Commodity list ';

CREATE TABLE `t_order` (
	`id` BIGINT(20) NOT NULL  AUTO_INCREMENT COMMENT ' Order ID',
	`user_id` BIGINT(20) DEFAULT NULL COMMENT ' user ID',
	`goods_id` BIGINT(20) DEFAULT NULL COMMENT ' goods ID',
	`delivery_addr_id` BIGINT(20) DEFAULT NULL  COMMENT ' Harvest address ID',
	`goods_name` VARCHAR(16) DEFAULT NULL  COMMENT ' Commodity name ',
	`goods_count` INT(20) DEFAULT '0'  COMMENT ' The number ',
	`goods_price` DECIMAL(10,2) DEFAULT '0.00'  COMMENT ' commodity price ',
	`order_channel` TINYINT(4) DEFAULT '0'  COMMENT '1 pc,2 android, 3 ios',
	`status` TINYINT(4) DEFAULT '0'  COMMENT ' The order status ,0 New unpaid ,1 Paid ,2 Shipped ,3 Received goods ,4 Has returned ,5 Completed ',
	`create_date` datetime DEFAULT NULL  COMMENT ' Order creation time ',
	`pay_date` datetime DEFAULT NULL  COMMENT ' Time of payment ',
	PRIMARY KEY(`id`)
)ENGINE = INNODB AUTO_INCREMENT=12 DEFAULT CHARSET = utf8mb4;
COMMENT ' The order sheet '
;

CREATE TABLE `t_seckill_goods`(
	`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT ' Second kill goods ID',
	`goods_id` BIGINT(20) NOT NULL COMMENT ' goods ID',
	`seckill_price` DECIMAL(10,2) NOT NULL COMMENT ' Second kill home ',
	`stock_count` INT(10) NOT NULL  COMMENT ' Inventory quantity ',
	`start_date` datetime NOT NULL  COMMENT ' Second kill start time ',
	`end_date` datetime NOT NULL COMMENT ' End time of seckill ',
	PRIMARY KEY(`id`)
)ENGINE = INNODB AUTO_INCREMENT=3 DEFAULT CHARSET = utf8mb4
COMMENT ' Second kill commodity watch '
;

CREATE TABLE `t_seckill_order` (
	`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT ' Second kill order ID',
	`user_id` BIGINT(20) NOT NULL  COMMENT ' user ID',
	`order_id` BIGINT(20) NOT NULL  COMMENT ' Order ID',
	`goods_id` BIGINT(20) NOT NULL  COMMENT ' goods ID',
	PRIMARY KEY(`id`)
)ENGINE = INNODB AUTO_INCREMENT=3 DEFAULT CHARSET = utf8mb4
COMMENT ' Second kill order watch '
;

--  Add index , At that time, I will add 
ALTER TABLE `seckill`.`t_seckill_order` 
ADD UNIQUE INDEX `seckill_uid_gid`(user_id, goods_id) USING BTREE COMMENT ' user ID+ goods ID Become a unique index ,';

client :PW=MD5( Plaintext + Fix Salt)
Server side :PW=MD5( User input + Random Salt)

User side MD5 Encryption is to prevent user passwords from being transmitted in clear text in the network , Server side MD5 Encryption is to improve password security , double
Heavy insurance

Implement login function

Because it uses MD5 You need to add MD5 Related dependence of

<!-- md5  rely on  -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>

1、MD5 Tool class

On the password Encryption twice + salt The password part here can be ignored , Simply put, encrypt the password Guarantee safety , It's a little complicated. , Understanding can , Not critical .

package com.example.seckill.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;

/** * MD5 Tool class  */
@Component
public class MD5Util {
    

    //  Encryption uses  -- salt 
    //  This salt  Unify with the salt in the front 
    private static final String salt = "1a2b3c4d";

    /** * MD5 encryption  * @param src * @return */
    public static String md5(String src) {
    
        return DigestUtils.md5Hex(src);
    }

    //  First encryption 
    public static String inputPassToFromPass(String inputPass) {
    
        String str = salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
        return md5(str);
    }

    //

    /** *  Second encryption : Back end password to database password  * * @param formPass  The password received by the backend  * @param salt  Stored in the database   salt  * @return */
    public static String formPassToDBPass(String formPass, String salt) {
    
        String str = salt.charAt(0) + salt.charAt(2) + formPass + salt.charAt(5) + salt.charAt(4);
        return md5(str);
    }


    /** *  This is the password that our backend will actually call  * @param inputPass * @param salt * @return */
    public static String inputPassToDBPass(String inputPass, String salt) {
    
        String fromPass = inputPassToFromPass(inputPass);
        String dbPass = formPassToDBPass(fromPass, salt);
        return dbPass;
    }



}

2、mybatis Reverse engineering

Reverse engineering

3、 The return of the request

Response enumeration class

package com.example.seckill.common;

/** *  Public return object enumeration  * * @author: LC * @date 2022/3/2 1:44  Afternoon  * @ClassName: RespBean */

public enum RespBeanEnum {
    

    // Universal 
    SUCCESS(200, "SUCCESS"),
    ERROR(500, " Server exception "),

    // Login module 
    LOGIN_ERROR(500210, " Incorrect username or password "),
    MOBILE_ERROR(500211, " Incorrect format of mobile phone number "),
    BIND_ERROR(500212, " Parameter verification exception "),
    MOBILE_NOT_EXIST(500213, " Mobile number does not exist "),
    PASSWORD_UPDATE_FAIL(500214, " Failed to update password "),
    SESSION_ERROR(500215, " user SESSION non-existent "),


    // Second kill module 
    EMPTY_STOCK(500500, " Insufficient inventory "),
    REPEATE_ERROR(500501, " This product is limited to one per person "),
    REQUEST_ILLEGAL(500502, " Illegal request , Please try again "),
    ERROR_CAPTCHA(500503, " Verification code error , Please re-enter "),
    ACCESS_LIMIT_REACHED(500504, " Too many visits , Please try again later "),
    // Order module 5003xx
    ORDER_NOT_EXIST(500300, " The order does not exist "),


    ;

    private final Integer code;
    private final String message;

    public Integer getCode() {
    
        return code;
    }

    public String getMessage() {
    
        return message;
    }

    RespBeanEnum(Integer code, String message) {
    
        this.code = code;
        this.message = message;
    }
}

Response information

package com.example.seckill.common;

/** *  Public return object  * * @author: LC * @date 2022/3/2 1:50  Afternoon  * @ClassName: RespBean */
public class RespBean {
    

    private long code;
    private String message;
    private Object object;

    public static RespBean success() {
    
        return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(), null);
    }

    public static RespBean success(Object object) {
    
        return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(), object);
    }

    public static RespBean error(RespBeanEnum respBeanEnum) {
    
        return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), null);
    }

    public static RespBean error(RespBeanEnum respBeanEnum, Object object) {
    
        return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), object);
    }

    public RespBean(long code, String message, Object object) {
    
        this.code = code;
        this.message = message;
        this.object = object;
    }

    public RespBean() {
    

    }

    public long getCode() {
    
        return code;
    }

    public void setCode(long code) {
    
        this.code = code;
    }

    public String getMessage() {
    
        return message;
    }

    public void setMessage(String message) {
    
        this.message = message;
    }

    public Object getObject() {
    
        return object;
    }

    public void setObject(Object object) {
    
        this.object = object;
    }
}


3、 Jump to the login page

@RequestMapping("/login")
@Controller
@Slf4j
public class LoginController {
    

    @RequestMapping ("toLogin")
    public String toLogin(){
    
        return "login";
    }


// @PostMapping("/doLogin")
// public String doLogin(){
    
//
// }
}

Login page and Login function implementation

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title> Sign in </title>
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}"/>
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
    <!-- jquery-validator -->
    <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
    <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
    <!-- layer -->
    <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <script type="text/javascript" th:src="@{/js/common.js}"></script>
</head>
<body>
<form name="loginForm" id="loginForm" method="post" style="width:50%; margin:0 auto">

    <h2 style="text-align:center; margin-bottom: 20px"> The user login </h2>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4"> Please enter your mobile number </label>
            <div class="col-md-5">
                <input id="mobile" name="mobile" class="form-control" type="text" placeholder=" Phone number " required="true"
                />
                <!--              Remove the digit limit           minlength="11" maxlength="11"-->
            </div>
            <div class="col-md-1">
            </div>
        </div>
    </div>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4"> Please input a password </label>
            <div class="col-md-5">
                <input id="password" name="password" class="form-control" type="password" placeholder=" password "
                       required="true"
                />
                <!--              Remove the digit limit             minlength="6" maxlength="16"-->
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="reset" onclick="reset()"> Reset </button>
        </div>
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="submit" onclick="login()"> Sign in </button>
        </div>
    </div>
</form>
</body>
<script>
    function login() {
    
        $("#loginForm").validate({
    
            submitHandler: function (form) {
    
                doLogin();
            }
        });
    }

    function doLogin() {
    
        g_showLoading();

        var inputPass = $("#password").val();
        var salt = g_passsword_salt;
        var str = "" + salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
        var password = md5(str);

        $.ajax({
    
            url: "/login/doLogin",
            type: "POST",
            data: {
    
                mobile: $("#mobile").val(),
                password: password
            },
            success: function (data) {
    
                layer.closeAll();
                if (data.code == 200) {
    
                    layer.msg(" success ");
                    console.log(data);
                    document.cookie = "userCookie=" + data.object;
                    window.location.href = "/goods/toList";
                } else {
    
                    layer.msg(data.message);
                }
            },
            error: function () {
    
                layer.closeAll();
            }
        });
    }
</script>
</html>


 Insert picture description here

OKOKOOKOKOK

4、 The realization of login function

Global exception handling , as well as @NotNull Wait for the use of annotations

Custom verification mobile number annotation @IsMobile

controller

    @RequestMapping("/doLogin")
    @ResponseBody
    public RespBean doLogin(@Valid LoginRequestParam param){
    

        log.info("{}",param);

        return userService.doLogin(param);
    }

Parameters

@Data
public class LoginRequestParam {
    

    @NotBlank(message = "mobile Can't be empty ")
    @IsMobile
    private String mobile;

    @NotBlank(message = "password Can't be empty ")
    @Length(min = 32,message = "password  The length is not right ")
    private String password;

}

service

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    
    @Autowired(required = false)
    UserMapper userMapper;


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

        User user = userMapper.selectById(mobile);
        if (null == user){
    
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }

        if (!MD5Util.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){
    
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);

        }
        return RespBean.success();
    }
}

Thus, the exception handling of login can be realized
 Insert picture description here
 Insert picture description here
 Insert picture description here

perfect Login function , use cookie + session Record user information

1、 Use uuid Tool class establish cookie Value

package com.example.seckill.util;

import java.util.UUID;

/** * UUID  Tool class  */
public class UUIDUtil {
    
    public static String uuid() {
    
        return UUID.randomUUID().toString().replace("-", "");
    }
}

2、 cookie Tool class , Yes cookie To operate

package com.example.seckill.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/** * Cookie Tool class  * * @author: LC * @date 2022/3/2 5:48  Afternoon  * @ClassName: CookieUtil */
public final class CookieUtil {
    

    /** *  obtain Cookie Value ,  No coding  * * @param request * @param cookieName * @return */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
    
        return getCookieValue(request, cookieName, false);
    }

    /** *  obtain Cookie Value , * * @param request * @param cookieName * @return */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
    
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
    
            return null;
        }
        String retValue = null;
        try {
    
            for (int i = 0; i < cookieList.length; i++) {
    
                if (cookieList[i].getName().equals(cookieName)) {
    
                    if (isDecoder) {
    
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
    
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
    
            e.printStackTrace();
        }
        return retValue;
    }

    /** *  obtain Cookie Value , * * @param request * @param cookieName * @return */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
    
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
    
            return null;
        }
        String retValue = null;
        try {
    
            for (int i = 0; i < cookieList.length; i++) {
    
                if (cookieList[i].getName().equals(cookieName)) {
    
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
    
            e.printStackTrace();
        }
        return retValue;
    }

    /** *  Set up Cookie Value   If the effective time is not set, the browser will be disabled by default , No coding  */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue) {
    
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /** *  Set up Cookie Value   Take effect within the specified time , But don't code  */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage) {
    
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /** *  Set up Cookie Value   Do not set the effective time , But coding  */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, boolean isEncode) {
    
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /** *  Set up Cookie Value   Take effect within the specified time ,  Encoding parameters  */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, boolean isEncode) {
    
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /** *  Set up Cookie Value   Take effect within the specified time ,  Encoding parameters ( Specified encoding ) */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, String encodeString) {
    
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /** *  Delete Cookie belt cookie domain name  */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
                                    String cookieName) {
    
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /** *  Set up Cookie Value , And make it effective within the specified time  * * @param cookieMaxage cookie The maximum number of seconds in effect  */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
    
        try {
    
            if (cookieValue == null) {
    
                cookieValue = "";
            } else if (isEncode) {
    
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {
    //  Set the domain name cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
    
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
    
            e.printStackTrace();
        }
    }

    /** *  Set up Cookie Value , And make it effective within the specified time  * * @param cookieMaxage cookie The maximum number of seconds in effect  */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
    
        try {
    
            if (cookieValue == null) {
    
                cookieValue = "";
            } else {
    
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0) {
    
                cookie.setMaxAge(cookieMaxage);
            }
            if (null != request) {
    //  Set the domain name cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
    
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
    
            e.printStackTrace();
        }
    }

    /** *  obtain cookie Domain name of  */
    private static final String getDomainName(HttpServletRequest request) {
    
        String domainName = null;
        //  adopt request Object to get the of access url Address 
        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
    
            domainName = "";
        } else {
    
            //  take url Convert underground to lowercase 
            serverName = serverName.toLowerCase();
            //  If url The address is http:// start   take http:// Intercept 
            if (serverName.startsWith("http://")) {
    
                serverName = serverName.substring(7);
            }
            int end = serverName.length();
            //  Judge url Whether the address contains "/"
            if (serverName.contains("/")) {
    
                // Get the first one "/" Position of appearance 
                end = serverName.indexOf("/");
            }

            //  Intercept 
            serverName = serverName.substring(0, end);
            //  according to "." Segmentation 
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
    
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
    
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
    
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
    
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}

3、 After verifying the user successfully, generate cookie, take cookie Save with the user session in

This is what is needed controller Medium plus HttpServletRequest ,HttpServletResponse Two into the refs

@RequestMapping("/doLogin")
    @ResponseBody
    public RespBean doLogin(@Valid LoginRequestParam param,HttpServletRequest request,HttpServletResponse response){
    

        log.info("{}",param);

        return userService.doLogin(param, request, response);
    }

After the user passes the verification

package com.example.seckill.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.common.RespBean;
import com.example.seckill.common.RespBeanEnum;
import com.example.seckill.controller.parm.LoginRequestParam;
import com.example.seckill.exception.GlobalException;
import com.example.seckill.mapper.UserMapper;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IUserService;
import com.example.seckill.util.CookieUtil;
import com.example.seckill.util.MD5Util;
import com.example.seckill.util.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** * <p> *  User table   Service implementation class  * </p> * * @author jobob * @since 2022-06-13 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    
    @Autowired(required = false)
    UserMapper userMapper;


    @Override
    public RespBean doLogin(LoginRequestParam param, HttpServletRequest request, HttpServletResponse response) {
    
        String password = param.getPassword();
        String mobile = param.getMobile();

        User user = userMapper.selectById(mobile);
        if (null == user){
    
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }

        if (!MD5Util.formPassToDBPass(password,user.getSalt()).equals(user.getPassword())){
    
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }

        /** *  After verifying the user successfully, generate  cookie, take cookie  Save with the user  session in  */
        //  Use UUID Generate  cookie
        String cookie = UUIDUtil.uuid();
        //  take  cookie  Save with the user  session  in 
        request.getSession().setAttribute(cookie,user);
        //  Set up  cookie
        CookieUtil.setCookie(request,response,"userCookie",cookie);


        return RespBean.success();
    }
}

Click login to see cookie Value
 Insert picture description here

4、goods Controller

 Insert picture description here
Because successful login will jump to the product list page

<!doctype html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> List of goods </title>
</head>
<body>
<p th:text="'hello:' + ${user.nickname}"></p>
</body>
</html>

package com.example.seckill.controller;

import com.example.seckill.common.RespBean;
import com.example.seckill.controller.parm.LoginRequestParam;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IGoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;


@RequestMapping("/goods")
@Controller
@Slf4j
public class GoodsController {
    

    @Autowired
    IGoodsService goodsService;


    /** *  Jump to product page  * @param session * @param model * @param cookie * @return */
    @RequestMapping("/toList")
    public String toList(HttpSession session, Model model, @CookieValue("userCookie") String cookie){
    

        if (StringUtils.isEmpty(cookie)){
     // If  cookie by   empty   Jump to   The login page 
            return "login";

        }
        //  from session  Get users 
        User user = (User) session.getAttribute(cookie);

        if (null == user){
     //  If the user information is empty   Jump to login 
            return "login";
        }
        //  Put user information   To the front page 
        model.addAttribute("user",user);
        return "goodsList";

    }

}

Click login Will jump to the page
 Insert picture description here

原网站

版权声明
本文为[You are my forever bug]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/184/202207031518189024.html