Day04_谷粒商城(谷粒商城高级篇三)摘要
文章目录
- 笔记链接:
- P211 认证服务环境的搭建
- P212 注册页面—验证码倒计时
- P213 注册页面—整合短信服务1
- P214 注册页面—整合短信服务2
- P215 注册页面—注册功能1
- P216 注册页面—注册功能2
- P217 注册页面—注册功能3
- P218 注册页面—注册功能4
- P219 登陆页面—用户名密码登录
- P220 登陆页面—完成微博登录1
- P221 登陆页面—完成微博登录2
- P222 登陆页面—完成微博登录3
- P223 登陆页面—完成微博登录4
- P224 登陆页面—完成微博登录5
- P225 SpringSession—session不共享、不跨域问题
- P226 SpringSession—session问题的解决
- P227 SpringSession—SpringSession整合redis1
- P228 SpringSession—SpringSession整合redis2
- P229 SpringSession—SpringSession整合redis3
- P230 页面调整
- P231 单点登录1
- P232 单点登录2
- P233 单点登录3
- P234 单点登录4
- P235 单点登录5
-
-
-
-
- 1.为什么要单点登录?
- 2.单点登录的原理?
- 3.单点登录代码的实现
-
-
-
- P236 购物车—环境的搭建
- P237 购物车—数据模型的分析1
- P238 购物车—数据模型的分析2
- P239 购物车—拦截器鉴别用户
- P240 页面调整
- P241 添加商品到购物车1
- P242 添加商品到购物车2
- P243 添加商品到购物车3
- P244 获取购物车
- P245 选中购物车项
- P246 修改购物项数量
- P247 删除购物项
笔记链接: 笔记链接:谷粒商城-个人笔记(高级篇三)
P211 认证服务环境的搭建
P212 注册页面—验证码倒计时
文章图片
文章图片
P213 注册页面—整合短信服务1 总说:
文章图片
文章图片
p213和p214的这些操作是完成用户在注册页面的发送验证码的操做:前台发送/sms/sendcode
的请求给后台的gulimall-auth-server,然后gulimall-auth-server会先验证一下验证码是否在60秒前发送过,如果没有就使用OpenFeign远程调用gulimall-thrid-party的sendCode方法完成第三方服务的发送验证码功能
P214 注册页面—整合短信服务2
文章图片
文章图片
文章图片
文章图片
文章图片
P215 注册页面—注册功能1 总说:
文章图片
文章图片
文章图片
【Day04_谷粒商城(谷粒商城高级篇三)摘要】p215和p216和p217和p218的这些操作是完成用户在注册页面的注册功能:我们之前把验证码发给用户了,用户会填好验证码和注册信息后发送给gulimall-auth-server,然后gulimall-auth-server会进行初步校验(校验密码格式、手机号格式 + 验证码校验),校验通过会利用OpenFeign远程调用gulimall-member的regist()方法来进行会员注册,会员注册肯定有失败有成功,对于那些注册失败我们使用异常机制
P216 注册页面—注册功能2
文章图片
文章图片
文章图片
请认真看这一节的注释,看不懂就回去看视频。这一节还是讲了不少有用的东西
P217 注册页面—注册功能3 给用户密码加密的三种方式对比:MD5加密、盐值加密、BCrypt加密
文章图片
文章图片
文章图片
文章图片
文章图片
P218 注册页面—注册功能4 本届内容就是完成测试
P219 登陆页面—用户名密码登录 总说:
文章图片
文章图片
文章图片
文章图片
前台发送 /login到后台的gulimall-auth-server模块中,然后gulimall-auth-server会使用OpenFeign远程调用gulimall-member的login()方法,在该方法中进行用户名密码比对完成登录
P220 登陆页面—完成微博登录1
文章图片
文章图片
文章图片
P221 登陆页面—完成微博登录2 P221讲了去微博开放平台进行社交登录申请与测试
文章图片
有两个地址很重要,
(1)是“ 在登录页引导用户至授权页”的地址:
这一步是前台完成的,前台html中的url要写成
Get
https://api.weibo.com/oauth2/authorize?client_id=1917008757&response_type=code&redirect_uri=http://gulimall.com/oauth2.0/weibo/success
client_id
:是你创建网站应用时的app key,redirect_uri
是用户使用微博登录后重定向到哪里去。我们指定redirect_uri=
http://gulimall.com/oauth2.0/weibo/success
也就是说用户用户使用微博登录后,相当于发送 /oauth2.0/weibo/success
到后台的gulimall-auth-server
模块中,那么gulimall-auth-server
会使用code换取token
,这就涉及到换取token的url:(2)是换取token的url
这一步是后台完成的,后台发送这样的url才能获取到token
POST
https://api.weibo.com/oauth2/access_token?client_id=1917008757&client_secret=94d9cc62c60d5f9f3d0c62389593024f&grant_type=authorization_code&redirect_uri=http://auth.gulimall.com/oauth2.0/weibo/success&code=CODE
client_id
: 创建网站应用时的app key;client_secret
: 创建网站应用时的app secretredirect_uri
: 认证完成后的跳转链接(需要和平台高级设置一致);code
:换取令牌的认证码后台发送这么个请求就可以根据用户授权返回的code换取token(换回来的不仅仅是token,还有uid用户id、expires_in令牌的过期时间等等),拿到token就可以向微博官方发送别的请求换取用户信息
P222 登陆页面—完成微博登录3
P223 登陆页面—完成微博登录4 P224 登陆页面—完成微博登录5 p222—p224就是编码与测试
文章图片
总说:
①前台发送/oauth2.0/weibo/success
到后台的gulimall-auth-server
模块中,然后gulimall-auth-server
会先使用code换取token
,然后拿着token到OpenFeign远程调用gulimall-member
的oauth2Login()
方法,在该方法中会先判断用户是否是第一次用微博登录,如果是第一次的话我们就得给该用户注册(到微博里面查询该用户的基本信息存储到咱们的数据库里面);如果该用户之前已经用微博登陆过,那就到数据库中更新一下token
②前台用户用微博登录后我们会拿到用户的code,后台用code到微博里面换取token这样才能用token访问到用户基本信息;用户每登陆一次访问微博的token就会变一次,所以当用户下次用微博登陆时我们需要到数据库更新一下tokenP225 SpringSession—session不共享、不跨域问题
(1)session不能跨域问题
文章图片
(2) 分布式下session共享问题
文章图片
文章图片
多台服务器都有会员服务,你在A服务器上把用户信息保存到内存上了,下次如果落在B服务器上,即使浏览器带着cookie来了,由于B服务器内存肯定没有存储用户信息,这也是问题。
P226 SpringSession—session问题的解决
文章图片
文章图片
- session复制
用户登录后,A服务器得到session后,把session也复制到别的机器上,显然这种处理很不好
- 客户端存储
把session存储到浏览器上,肯定相当不安全
- hash一致性
根据用户,到指定的机器上登录。但是远程调用还是不好解决
- redis统一存储
最终的选择方案,把session放到redis中,这样每个微服务都可以获取到session
浏览器会在auth.gulimall.com
里面登录成功,auth.gulimall.com
会将登陆成功的用户的从数据库查到的用户相关信息存到session里面,而且存session时不是存到自己的内存里面而是存到redis里面,然后auth.gulimall.com
给浏览器发cookie,而且发的cookie的作用域不能仅仅是auth.gulimall.com
而是要放大服务到.gulimall.com
,此时浏览器访问其它任何服务都会带上这个cookie。
如果你把redis里面的session情况,那就是把登陆过的用户信息清空,虽然前台的浏览器访问后台时携带了cookie信息,但是到redis里面查不到用户信息,所以你就得重新登陆。而且我们设置了redis里面的session默认30分钟过期,也就是30分钟后redis里面的用户信息就没有了
P230 页面调整
文章图片
文章图片
文章图片
P231 单点登录1 P232 单点登录2 P233 单点登录3 P234 单点登录4 P235 单点登录5 1.为什么要单点登录?
文章图片
文章图片
文章图片
springsession只能把auth.gulimall.com作用域放大到gulimall.com,解决了同域名的共享session问题,但要是访问同样是尚硅谷的atguigu.com怎么办呢?这种不同的域名也想共享session该怎么做呢?2.单点登录的原理? 两个域名不一样的服务端client1和client2,还有一个负责登录的ssoserver,还有一个浏览器,它们四个之间的故事
你在新浪微博里面注册登录了,同时就要保证在新浪体育、新浪新闻里面全都可以拿到session数据
文章图片
先说明一下这个路径的含义:http://ssoserver.com:8080/login.html?redirect_url=http:I/client1.com:8081/employees
的含义就是让你访问http://ssoserver.com:8080/login.html
登陆页面,而redirect_url=http:I/client1.com:8081/employees
的含义是当你完成登陆后会重定向到http:I/client1.com:8081/employees
的位置
第1-11步的解析:只有登陆了才能查看员工信息。一开始浏览器访问client1.com的员工信息http:I/client1.com:8081/employees
,client1会根据这个url有没有token参数判断是否登录,由于没有token参数也就是没有登陆,服务端会命令浏览器重定向到ssoserver.com的登陆页面http:I/ssoserver.com:8080/login.html?redirect_url=http:I/client1.com:8081/employees
,ssoserver.com会判断是否登陆过,没有登陆过就展示这个登陆页面,用户会输入账号密码进行登录,提交登陆请求http:/ssoserver.com:8080/doLogin?usermame,password,redirect_url
给ssoserver.com,那么ssoserver.com会保存用户状态到redis,同时ssoserver.com会命令重定向到http: /lclient1.com:8081/employees?token=dadadadsdeuieu
(浏览器访问路径),同时ssoserver.com会命令浏览器保存sso_token=dadadadsdeuieu
这样式的cookie。浏览器这次就可以访问员工信息了,他的访问路径是刚刚提到的http://lclient1.com:8081/employees?token=dadadadsdeuieu
比一开始访问员工信息的http:I/client1.com:8081/employees
多了token=dadadadsdeuieu
,这就回到第2步了,client1会根据有没有token参数判断是否登录,这次client1会觉得它登陆过了就可以访问员工信息了。
第12-19步解析:这次浏览器要访问客户端2的boss信息http:I/client2.com:8081/boss
,client2会根据有没有token参数判断是否登录,由于没有token参数也就是没有登陆,服务端会命令浏览器重定向到ssoserver.com的登陆页面http:I/ssoserver.com:8080/login.html?redirect_url=http:I/client2.com:8081/boss
,ssoserver.com会判断是否登陆过,由于浏览器有sso_token=dadadadsdeuieu
这样式的cookie,而且从redis能查到,说明它之前在client1或者client2登陆过,ssoserver.com会命令重定向到http:/lclient2.com:8082/boss?token=dadadadsdeuieu
,所以浏览器就会访问http://lclient2.com:8082/boss?token=dadadadsdeuieu
,这就回到了第2步,client2会根据有没有token参数判断是否登录,登陆过就响应页面。
所以说,以后浏览器无论访问client1还是client2,由于浏览器中保存了cookie,所以ssoserver.com就会判定它登陆过,所以以后都不用登陆。3.单点登录代码的实现 client1的代码:
@GetMapping(value = "https://www.it610.com/employees")
public String employees(Model model,
HttpSession session,
@RequestParam(value = "https://www.it610.com/article/redisKey", required = false) String redisKey) {if (!StringUtils.isEmpty(redisKey)) {//redisKey非空(也就是token非空),说明去过server端登录过了// 拿着token去服务器,在服务端从redis中查出来用户的username
RestTemplate restTemplate=new RestTemplate();
ResponseEntity
client2的代码:
文章图片
代码一模一样,就是改一下访问路径
@GetMapping(value = "https://www.it610.com/boss")
ssoserver的代码:
@Controller
public class LoginController { @Autowired
private StringRedisTemplate stringRedisTemplate;
@ResponseBody
@GetMapping("/userInfo") //client1或client2会调用这个方法得到redis中的存储过的user信息
public Object userInfo(@RequestParam("redisKey") String redisKey){// 拿着其他域名转发过来的token去redis里查
Object loginUser = stringRedisTemplate.opsForValue().get(redisKey);
return loginUser;
} @GetMapping("/login.html") // 子系统都来这
public String loginPage(@RequestParam("url") String url,
Model model,
@CookieValue(value = "https://www.it610.com/article/redisKey", required = false) String redisKey) {//这是从浏览器中拿到的cookie,非空代表就登录过了
if (!StringUtils.isEmpty(redisKey)) {//非空代表就登录过了
return "redirect:" + url + "?redisKey=" + redisKey;
}model.addAttribute("url", url);
//没登录过才去登录页
return "login";
} @PostMapping("/doLogin") //在前端输入用户名和密码后就会来到这里,进行server端统一认证
public String doLogin(@RequestParam("username") String username,
@RequestParam("password") String password,
HttpServletResponse response,
@RequestParam(value="https://www.it610.com/article/url",required = false) String url){//确认用户后,生成cookie,浏览器中存储,redis中也存储
if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
//非空就简单认为登录正确String redisKey = UUID.randomUUID().toString().replace("-", "");
//用uuid代替tokenCookie cookie = new Cookie("redisKey", redisKey);
response.addCookie(cookie);
//浏览器中存储cookiestringRedisTemplate.opsForValue().set(redisKey, username+password+"...", 30, TimeUnit.MINUTES);
//redis中存储return "redirect:" + url + "?redisKey=" + redisKey;
//重定向时候带着token
}// 登录失败,再次登录
return "login";
}}
演示
代码用的网友的,截屏用到老师的,网友喜欢自己起名字,把token改为redisKey什么的,不要计较细节上的不同
P236 购物车—环境的搭建
文章图片
文章图片
文章图片
文章图片
文章图片
文章图片
P237 购物车—数据模型的分析1 P238 购物车—数据模型的分析2 总说:
文章图片
文章图片
本节内容就是说明了用户购物车里的信息应该使用哪个数据库存储(MySQL还是Redis?),以及使用了Redis后是用List存储这些信息呢还是使用Hash存储这些信息?以及购物车VO、购物项VO的编写
文章图片
文章图片
在(3)VO编写中为什么不用@Data而是自己写getter和setter方法?因为在购物项VO中计算“总价=单价x数量”这是需要手动计算的,使用@Data只会覆盖了自定义的setter方法;而且在购物车VO中应该是获取总价、获取商品数量,所以有的属性不应该有setter方法。
P239 购物车—拦截器鉴别用户 总说:
文章图片
文章图片
在购物车的所有Controller执行之前,我们先执行一个拦截器。在拦截器里判断用户是否登录,从session中获取不到用户信息就说明他没有登录,没有登录的话就从浏览器中获取一下user-key,如果浏览器中没有user-key那就说明用户是第一次没有登录
的状态下进入京东,我们就得创建一个cookie名字叫做user-key,而且设置cookie的作用域、过期时间,假如明天他来了,我们能从浏览器中获取到该用户的user-key。
一个用户进来我们执行的 “ 拦截器—Controller—Service—Dao ” 这一套流程让同一个线程执行,这就使用了ThreadLocal技术,ThreadLocal是同一个线程共享数据,这个线程里面的数据会共享,使用过程就是:
ThreadLocal threadLocal = new ThreadLocal<>();
//创建一个threadLocal
threadLocal.set(userInfoTo);
//把要共享的数据设置进去
....
UserInfoTo userInfoTo = threadLocal.get();
//后期就可以获取到这个共享的数据
P240 页面调整 拦截器写了,Controller还有service什么的都没有写,在此之前,我们先打通整个页面(首页可以进入商品页,从商品页添加商品到购物车,然后点击购物车就可以进入购物车页),本节内容是前台代码。
文章图片
文章图片
文章图片
文章图片
P241 添加商品到购物车1 P242 添加商品到购物车2 P243 添加商品到购物车3 总说:
文章图片
文章图片
文章图片
文章图片
文章图片
文章图片
因为是拦截器先执行的,所以先得到拦截器ThreadLocal的返回结果UserInfoTo userInfoTo = threadLocal.get()
,如果userInfoTo.getUserId()
不为空表示账号用户,反之为临时用户 ,然后决定用临时购物车还是用户购物车。将用户购物车信息存到redis中,redis中肯定需要键值对,账号用户的购物车的redis中的key是gulimall:cart:1
(1是用户id,表示1号用户的购物车);临时用户的redis中的key是gulimall:cart:uuid
其中uuid就是我们拦截器里存下的user-key。redisTemplate.boundHashOps(cartKey)是说以后所有对redis的增删改查都是针对redia中key为cartKey的增删改查。上面的一套逻辑被封装到getCartOps()
方法里面了。
添加新商品到购物车,第一步先看redis里面能不能查到skuid,查不到说明购物车里面之前没有添加过此商品,那就需要远程查询此商品的一系列信息;能查到说明购物车有此商品,将数据取出修改数量即可。
文章图片
文章图片
文章图片
文章图片
//原文中的博客少了对getCartItem(Long skuId)方法的解释,你也许会问哪里少了getCartItem()?这还用问吗,你一个Ctrl+F搜一下不久知道了
@Override
public CartItemVo getCartItem(Long skuId) {//拿到要操作的购物车信息
BoundHashOperations cartOps = getCartOps();
String redisValue = https://www.it610.com/article/(String) cartOps.get(skuId.toString());
CartItemVo cartItemVo = JSON.parseObject(redisValue, CartItemVo.class);
return cartItemVo;
}
测试
P244 获取购物车
文章图片
文章图片
文章图片
总说:
若用户未登录,则直接使用user-key获取购物车数据;否则使用userId获取购物车数据,并将user-key对应临时购物车数据与用户购物车数据合并,并删除临时购物车
csdn上的笔记只是为了清楚地记录了老师这节课操作了什么,而具体代码我的建议就是尽量看idea上的代码,别看csdn上的代码,
文章图片
//原文中的博客少了对getCartItems(String cartKey) 方法的解释* 获取购物车里面的数据
private List getCartItems(String cartKey) {//获取购物车里面的所有商品
BoundHashOperations operations = redisTemplate.boundHashOps(cartKey);
List
//原文中的博客少了对clearCart()方法的解释
@Override
public void clearCart(String cartKey) {redisTemplate.delete(cartKey);
}
测试
P245 选中购物车项
文章图片
文章图片
文章图片
文章图片
文章图片
P246 修改购物项数量
文章图片
文章图片
P247 删除购物项
文章图片
文章图片
文章图片
推荐阅读
- java|java b2b2c shop 多用户商城系统源码- config 修改配置
- django开发电子商城(二十二)购物车商品的所有者身份转换
- Bear的产品迷途——一个简单商城小程序项目
- java|java B2B2C 仿淘宝电子商城系统-Spring Cloud构建分布式电子商务平台
- 谷粒学院|谷粒学院(一)项目介绍
- 信任优农保真商城丨自从知道这货,觉得以前的地瓜都白吃了!
- 小程序商城网站开发秒杀模块篇
- 一个好的小程序分销商城能给你带来什么()
- 分销商城小程序开发解决方案
- 微信商城小程序开发方式有哪些()