当前位置:网站首页>Seckill system 2 redis solves the problem of distributed session
Seckill system 2 redis solves the problem of distributed session
2022-07-03 15:21:00 【You are my forever bug】
Preface
If you operate on one Tomcat On , There is no problem , But when we deploy multiple systems , coordination Nginx There will be a problem of user login .
reason
because Nginx Use a load balancing policy , Distribute the request to the backend ,
in other words , stay Tomcat 1 After logging in , User information exists Tomcat1 Of Session in , The next request is coming Tomcat2 On , At this time Tomcat2 On Session There is no user information in , I'm going to log in .
solve
redis Installation tutorial self-study
Redis Implement distributed Session
Method 1、 Use SpringSession Realization ( This method can't jump to the page )
1、 Add dependency :
<!-- spring data redis rely on -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 Object pool dependency -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- spring-session rely on -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
2、 To configure Redis
spring:
# thymeleaf Turn off caching
thymeleaf:
cache: false
# MySql Data source configuration
datasource:
driver-class-name: com.mysql.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
# Redis To configure
redis:
host: 127.0.0.1
port: 6379
# Database used 0
database: 0
# Connection timeout
timeout: 10000ms
lettuce:
# Configuration of connection pool
pool:
# maximum connection 8
max-active: 8
# Maximum connection blocking time
max-wait: 10000ms
# Maximum free connection
max-idle: 200
# Minimum free connection
min-idle: 5
# 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
This is the time Just OK 了 , After logging in ,Session It will be saved Redis - 0( library ) -spring Session in
here Comment out the
// /**
// * 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);
Log in again Discovery will also be saved Redis in .
Method 2、 Save user information in redis in
1、 Add dependency
<!-- spring data redis rely on -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 Object pool dependency -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、redis Configuration of And methods 1 equally
3、Redsi Configuration class
package com.example.seckill.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/** * Redis To configure */
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//key serialize
redisTemplate.setKeySerializer(new StringRedisSerializer());
//value serialize
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//hash type value serialize
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
// Injection connection factory
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
4、json Tool class
This is very important , If not from redis From user The information does not match , I can't jump Product page
package com.example.seckill.util;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
/** * Json Tool class * * @author zhoubin * @since 1.0.0 */
public class JsonUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
/** * Converts an object to json character string * * @param obj * @return */
public static String object2JsonStr(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
// Print exception information
e.printStackTrace();
}
return null;
}
/** * Convert a string to an object * * @param <T> Generic */
public static <T> T jsonStr2Object(String jsonStr, Class<T> clazz) {
try {
return objectMapper.readValue(jsonStr.getBytes("UTF-8"), clazz);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/** * take json Data to pojo object list * <p>Title: jsonToList</p> * <p>Description: </p> * * @param jsonStr * @param beanType * @return */
public static <T> List<T> jsonToList(String jsonStr, Class<T> beanType) {
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = objectMapper.readValue(jsonStr, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
5、 modify UserServiceImpl Code
After verifying the user , take user Put in redis
And add through cookie obtain user Methods
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.JsonUtil;
import com.example.seckill.util.MD5Util;
import com.example.seckill.util.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
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;
@Autowired
private RedisTemplate redisTemplate;
@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);
redisTemplate.opsForValue().set("user:" + cookie, JsonUtil.object2JsonStr(user));
// Set up cookie
CookieUtil.setCookie(request,response,"userCookie",cookie);
return RespBean.success(cookie);
}
@Override
public User getUserByCookie(String cookie, HttpServletRequest request, HttpServletResponse response) {
if (StringUtils.isEmpty(cookie)){
return null;
}
String userJson = (String) redisTemplate.opsForValue().get("user:" + cookie);
User user = JsonUtil.jsonStr2Object(userJson, User.class);
if (null != user){
// Set up cookie
CookieUtil.setCookie(request,response,"userCookie",cookie);
}
return user;
}
}
6、 goods Controller
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 com.example.seckill.service.IUserService;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RequestMapping("/goods")
@Controller
@Slf4j
public class GoodsController {
@Autowired
IGoodsService goodsService;
@Autowired
IUserService userService;
/** * Jump to product page * @param * @param model * @param cookie * @return */
@RequestMapping("/toList")
public String toList(HttpServletRequest request, HttpServletResponse response, 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);
User user = userService.getUserByCookie(cookie, request, response);
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";
}
}
Avoid completing each interface above according to Cookie obtain User Information , Avoid code redundancy , Special optimization :
1、UserArgumentResolvers class
package com.example.seckill.config;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IUserService;
import com.example.seckill.util.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** * Custom user parameters */
@Component
public class UserArgumentResolvers implements HandlerMethodArgumentResolver {
@Autowired
IUserService userService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> parameterType = parameter.getParameterType();
return parameterType == User.class;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
String cookie = "486ceb27176a485f85e3c3d1f4f35e77";
// String cookie = CookieUtil.getCookieValue(request, "userCookie");
if (StringUtils.isEmpty(cookie)){
// If cookie by empty Jump to The login page
return null;
}
return userService.getUserByCookie(cookie, request, response);
}
}
2、
package com.example.seckill.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/** * MVC Configuration class * */
@Configuration
//@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
UserArgumentResolvers userArgumentResolvers;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers){
resolvers.add(userArgumentResolvers);
}
}
3、goodController
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 com.example.seckill.service.IUserService;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RequestMapping("/goods")
@Controller
@Slf4j
public class GoodsController {
@Autowired
IGoodsService goodsService;
@Autowired
IUserService userService;
/** * Jump to product page * @param * @param model * @param * @return */
@RequestMapping("/toList")
public String toList(Model model,User user){
// Put user information To the front page
model.addAttribute("user",user);
return "goodsList";
}
}
problem : Here I have a problem , Each generation Cookie Put in Redis It's normal , But call other interfaces after successful login adopt CookieUtil Acquired Cookie Not generated by this login Cookie It's annoying ~ I don't know much about this So I'm making sure that redis There is this cookie , take cookie It's dead
边栏推荐
- What is label encoding? How to distinguish and use one hot encoding and label encoding?
- 什么是one-hot encoding?Pytorch中,将label变成one hot编码的两种方式
- 秒杀系统1-登录功能
- Didi off the shelf! Data security is national security
- 详解指针进阶2
- Puppet automatic operation and maintenance troubleshooting cases
- PyTorch crop images differentiablly
- Halcon与Winform学习第一节
- Tensorflow realizes verification code recognition (III)
- Jvm-03-runtime data area PC, stack, local method stack
猜你喜欢
【Transform】【实践】使用Pytorch的torch.nn.MultiheadAttention来实现self-attention
北京共有产权房出租新规实施的租赁案例
Unity hierarchical bounding box AABB tree
Tensorflow realizes verification code recognition (I)
[transform] [NLP] first proposed transformer. The 2017 paper "attention is all you need" by Google brain team
Baidu AI Cloud helps Shizuishan upgrade the smart health care model of "Internet + elderly care services"
Finally, someone explained the financial risk management clearly
Kubernetes vous emmène du début à la fin
Jvm-03-runtime data area PC, stack, local method stack
需要知道的字符串函数
随机推荐
Qt常用语句备忘
Summary of JVM knowledge points
Leasing cases of the implementation of the new regulations on the rental of jointly owned houses in Beijing
【Transformer】入门篇-哈佛Harvard NLP的原作者在2018年初以逐行实现的形式呈现了论文The Annotated Transformer
Kubernetes vous emmène du début à la fin
Jvm-08-garbage collector
socket. IO build distributed web push server
Idea does not specify an output path for the module
Characteristics of MySQL InnoDB storage engine -- Analysis of row lock
The state does not change after the assignment of El switch
redis缓存穿透,缓存击穿,缓存雪崩解决方案
Detailed comments on MapReduce instance code on the official website
Functional modules and application scenarios covered by the productization of user portraits
视觉上位系统设计开发(halcon-winform)
Relationship between truncated random distribution and original distribution
Kubernetes - yaml file interpretation
使用JMeter对WebService进行压力测试
Nppexec get process return code
Dataframe returns the whole row according to the value
Jvm-09 byte code introduction