当前位置: 首页 > news >正文

旅游网站建设国内外现状网站关键词百度自然排名优化

旅游网站建设国内外现状,网站关键词百度自然排名优化,百度预测大数据官网,图片在线制作表情2023.12.6 短信登陆如果基于session来实现,会存在session共享问题:多台Tomcat不能共享session存储空间,这会导致当请求切换到不同服务器时出现数据丢失的问题。 早期的解决办法是让session提供一个数据拷贝的功能,即让各个Tomcat的…

2023.12.6

        短信登陆如果基于session来实现,会存在session共享问题:多台Tomcat不能共享session存储空间,这会导致当请求切换到不同服务器时出现数据丢失的问题。

        早期的解决办法是让session提供一个数据拷贝的功能,即让各个Tomcat的数据实现一个互相的拷贝,但是这种方式容易造成内存空间的浪费,并且拷贝是需要时间的,这段时间内依然存在数据不一致的问题。

        于是我们可以基于Redis来完成,由于Redis数据本身就是共享的,就可以避免session共享的问题了,并且redis是基于内存的,读写性能高。

发送短信验证码

         之前是将验证码保存到session中,现在是将验证码保存到redis中,此时需要考虑redis采用什么数据结构来保存验证码:key需要保证唯一性,所以使用用户的手机号作为key;由于验证码就是一个六位数的字符串,所以value直接采用String保存就好。

该模块的代码如下:

    public Result sendCode(String phone, HttpSession session) {//1.校验手机号if(RegexUtils.isPhoneInvalid(phone)){//2.不符合则返回错误信息return Result.fail("手机号格式错误!");}//3.符合,生成验证码String code = RandomUtil.randomNumbers(6);//保存验证码到session//session.setAttribute("code",code);//4.保存验证码到redisstringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);//设置过期时间定期清理redis中的验证码//5.发送验证码log.debug("发送验证码成功,验证码:{}",code);return Result.ok();}

        这里不真的发验证码,就模拟一下就好了,验证码直接输入到控制台上。

短信验证码登陆和注册模块

         这里的redis要存的是用户对象信息,于是我们采用HashMap数据结构去存,该结构可以将对象的每个字段独立存储,方便针对单个字段进行CRUD。

        redis的key的选择这里不选择手机号,而是采用一个随机token作为key,此处的token最终是要返回给前端页面的,类似于之前的session id(登陆凭证),所以key填手机号的话不安全;并且为了后续能够通过这个token得到用户信息,需要将此token返回给客户端。

 该模块代码如下:

@Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {//1.校验手机号String phone = loginForm.getPhone();if(RegexUtils.isPhoneInvalid(phone)){//2.不符合则返回错误信息return Result.fail("手机号格式错误!");}//3.从redis获取验证码并校验String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if(cacheCode == null || !cacheCode.equals(code)){//3.验证码不一致,报错return Result.fail("验证码错误");}//4.一致,根据手机号查询用户User user = query().eq("phone", phone).one();//5.判断用户是否存在if(user == null){//6.不存在,创建新用户并保存user = createUserWithPhone(phone);}//7.保存用户信息到redis中//7.1 随机生成token,作为登陆令牌String token = UUID.randomUUID().toString(true);//7.2 将User对象转为HashMap存储UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName,fieldValue) ->fieldValue.toString()));//7.3 存储String tokenKey = LOGIN_USER_KEY + token;stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);//7.4 设置token有效期stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);//        返回tokenreturn Result.ok(token);}private User createUserWithPhone(String phone) {//1.创建用户User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));//2.保存用户save(user);return user;}

        此处有个细节,虽然我们设置了token有效期为30分钟,但是不管我们登陆后做什么操作,token始终都是30分钟后被消除。 而正常情况应该是我们登陆后如果有操作行为,token的有效期应该被重置为30分钟。

         于是我们可以使用一个拦截器对请求进行拦截,每当有请求发生,就将token的有效期重置。

拦截器的代码为:

public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.获取请求头中的tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)){return true;}//2.基于Token获取redis中的用户String key = RedisConstants.LOGIN_USER_KEY+token;Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(RedisConstants.LOGIN_USER_KEY + token);//3.判断用户是否存在if(userMap.isEmpty()){return true;}//5.将查询到的Hash数据转为UserDTO对象UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);//6.保存用户信息到ThreadLocalUserHolder.saveUser(userDTO);//7.刷新token有效期stringRedisTemplate.expire(key,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserHolder.removeUser();}
}

        写完拦截器的代码之后,还需要在MvcConfig中进行配置:

@Configuration
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//登陆拦截器registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot","/user/code","/user/login").order(1);//token刷新拦截器registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).order(0);}
}

         这里虽然是在第二行配置的刷新有效期拦截器,但是它会先进行拦截,因为我们order里填的数字是0,数字越小优先级越高。

        第一行的拦截器是用来进行登陆校验的,即如果你访问了除代码中路径以外的路径的话,需要判断你有没有登陆,那如何判断你有没有登陆呢?只需要查看当前ThreadLocal中有无用户信息就知道了,该拦截器代码如下:

public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断是否需要拦截(即ThreadLocal中是否有用户)if(UserHolder.getUser() == null){response.setStatus(401);return false;}return true;}}

        拦截器的整体架构图如下:

http://www.yayakq.cn/news/354533/

相关文章:

  • 怎么做文学动漫网站网站没收录可以做推广吗
  • 下载官方网站app网站建设系统教程
  • 深圳彩票网站开发人员硬件开发工程师是干什么的
  • 做网站霸屏公司销售好做吗网站素材设计框架
  • 选择好的佛山网站建设个人可以做的外贸网站
  • 做网站需要服务器团购网站的发展
  • 公司做网站该注意哪些中山专业门户网站制作平台
  • 嘉兴市建设教育网站网站开发群
  • 文山州建设局网站鼎豪网络网站建设
  • 购物网站 wordpress 英文模板中铁建设集团门户网门户
  • 计算机网站开发职业定位太原市建站外包公司
  • 北京赛车彩票网站怎么做概念产品设计网站
  • 专门做婚纱儿童摄影网站南宁大型网站推广公司
  • 如何建网站赚取佣金网站建设在哪里找人
  • 清远医院网站建设费用网页设计尺寸早起可视区域
  • 代码网站有哪些最便宜云主机永久免费
  • php大型网站开发视频wordpress 电商版本
  • 成都建立网站营销设计外贸订单怎样去寻找
  • 网站全程设计技术淄博高端网站
  • 阿里云 外贸网站怎么对网站做seo优化
  • 浙江江能建设有限公司网站百度引流推广
  • 信息网站建设汇报哪里有个人品牌营销公司
  • 外销网站宣传型企业网站设计
  • 杭州设计网站的公司linu安装wordpress
  • 为什么要用h5建站怎样才能创建自己的网站
  • wordpress 文件下载插件石家庄seo外包公司
  • 做网站优化找谁网站如何做免费的推广
  • 织梦做淘宝客网站视频aso优化服务站
  • 工程科技 网站设计wordpress4.9安装
  • 做外贸哪个网站比较好2017建设一个百度百科类网站