当前位置:网站首页>Secsha system 1- login function
Secsha system 1- login function
2022-07-03 15:28:00 【You are my forever bug】
Learning goals 
Technical point 
This is mainly seckill business , No front and rear end separation
How to design a seckill system
1、 Second kill system solves two problems
- Concurrent reading
- Write concurrently
2、 Technical requirements of seckill system :
- 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 . - 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 . - 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

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>

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
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>

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 


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 
4、goods Controller

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 
边栏推荐
- Concurrency-02-visibility, atomicity, orderliness, volatile, CAS, atomic class, unsafe
- Tensorflow realizes verification code recognition (III)
- leetcode_ Power of Four
- Seckill system 2 redis solves the problem of distributed session
- SQL server installation location cannot be changed
- 详解指针进阶2
- GCC cannot find the library file after specifying the link library path
- Popular understanding of ovo and ovr
- WinDbg分析dump文件
- Markdown file titles are all reduced by one level
猜你喜欢

运维体系的构建

Srs4.0+obs studio+vlc3 (environment construction and basic use demonstration)

视觉上位系统设计开发(halcon-winform)-1.流程节点设计

Second kill system 3 - list of items and item details

Wechat payment -jsapi: code implementation (payment asynchronous callback, Chinese parameter solution)

Final review points of human-computer interaction

Redis lock Optimization Practice issued by gaobingfa

Visual upper system design and development (Halcon WinForm) -3 Image control

Baidu AI Cloud helps Shizuishan upgrade the smart health care model of "Internet + elderly care services"

Visual upper system design and development (Halcon WinForm) -5 camera
随机推荐
Markdown file titles are all reduced by one level
Redis single thread problem forced sorting layman literacy
socket.io搭建分布式Web推送服务器
The difference between RAR and zip files
Kubernetes will show you from beginning to end
Popular understanding of linear regression (II)
运维体系的构建
Subclass hides the function with the same name of the parent class
Digital image processing -- popular understanding of corrosion and expansion
Using notepad++ to build an arbitrary language development environment
[combinatorics] combinatorial identities (recursive combinatorial identities | sum of variable terms | simple combinatorial identities and | sum of variable terms | staggered sums of combinatorial ide
win32创建窗口及按钮(轻量级)
redis单线程问题强制梳理门外汉扫盲
WinDbg分析dump文件
Tensorflow realizes verification code recognition (II)
Visual upper system design and development (Halcon WinForm) -5 camera
CString的GetBuffer和ReleaseBuffer使用说明
视觉上位系统设计开发(halcon-winform)-6.节点与宫格
Didi off the shelf! Data security is national security
Detailed explanation of string function and string function with unlimited length