一、分布式系统web端控制
系统概述:
现在已经完成了:
1、会员服务
2、消息服务平台
3、注册中心
4、web系统
分布式微服务电商项目:
SOA就是面向服务开发,提供接口给前端来调用。
SOA层就是把传统的项目中的控制层抽取出来,暴露接口给其他平台
来进行调用。
前端给了两个页面,分别为登录页面和注册页面
1、使用ajax调用接口服务,在js里面去控制
2、使用java web项目,用rpc远程调用技术来调用接口服务
在springcloud中使用fegin或rest来调用接口。
3、安卓使用的是httpclient来调用接口服务
二、创建web项目
web控制层怎么分?控制层、来源来分
如:leeue-h5-web ---手机端h5访问
leeue-pc-web--电脑访问。
前端请求处理
package com.leeue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import lombok.extern.slf4j.Slf4j;
/**
* @classDesc: 功能描述:(首页前端 控制层)
* @author:<a href="leeue@foxmail.com">李月</a>
* @Version:v1.0
* @createTime:2018年12月26日 下午3:16:05
*/
//这个上面加的Controller跳转到页面的
@Controller
@Slf4j
public class IndexController {
//
private static final String INDEX = "index";
// 返回String类型的表示跳转页面,加上一个/表示只要输入一个/后面不输入了就可以进入index请求里面拉
@RequestMapping(value = "/",method=RequestMethod.GET)
public String index() {
log.info("请求了主页的页面了......");
return INDEX;
}
}
三、使用fegin调用会员服务实现注册
为什么当初在设计会员项目的时候设计一个接口项目?
答:因为为了后面其他的项目使用fegin来调用的时候代码重复了很多。
现在抽象出了一个接口项目,可以直接使用fegin调用的项目中,集成接口项目
中的类就可以了。
传统的fegin调用的时候要这样写来操作
在使用抽象接口项目的时候就可以这样去做了。member 集成这个接口的,实现
类项目的名称。
注意:fegin 是接口
实现注册主逻辑(一些验证没有写)
/**
* 注册业务具体实现
* @return
*/
@RequestMapping(value="/register",method=RequestMethod.POST)
public String registerPost(UserEntity userEntity,HttpServletRequest request) {
//1.验证参数
if(userEntity == null) {
request.setAttribute("error", "注册用户信息不能为空!");
return REGISTER;
}
if(StringUtils.isEmpty(userEntity.getUsername())) {
request.setAttribute("error", "注册用户姓名不能为空");
return REGISTER;
}
if(StringUtils.isEmpty(userEntity.getPassword())) {
request.setAttribute("error", "注册密码不能为空");
return REGISTER;
}
if(StringUtils.isEmpty(userEntity.getEmail())) {
request.setAttribute("error", "注册邮箱不能为空");
return REGISTER;
}
if(!userEntity.getEmail().contains("@")) {
request.setAttribute("error", "注册邮箱格式错误");
return REGISTER;
}
//2.调用会员注册接口
ResponseBase responseBase = memberServiceFegin.regUser(userEntity);
//3.如果失败跳转到注册失败页面
if(!responseBase.getRtnCode().equals(Constants.HTTP_RES_CODE_200)) {
request.setAttribute("error", "注册失败!");
return REGISTER;
}
//4.如果成功跳转到成功页面
return LOGIN;
}
四、使用fegin调用会员服务实现登录
1、fegin调用会员服务实现的接口
2、登录实现,调用会员服务登录接口、获取token然后存放在cookie中。
/**
* 登录请求具体实现
*
* @return
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginPost(UserEntity userEntity, HttpServletRequest request,HttpServletResponse response) {
// 1.验证参数
if (StringUtils.isEmpty(userEntity.getUsername())) {
request.setAttribute("error", "用户名不能为空");
return LOGIN;
}
if (StringUtils.isEmpty(userEntity.getPassword())) {
request.setAttribute("error", "密码不能为空");
return LOGIN;
}
// 2.调用登录接口获取token信息
ResponseBase responseBase = memberserviceFegin.login(userEntity);
if (!responseBase.getRtnCode().equals(Constants.HTTP_RES_CODE_200)) {
request.setAttribute("error", "账号或密码错误");
return LOGIN;
}
//注意:在reponseBase中取data类型的时候,已经不是jsonObject了,因为使用了
/// fegin调用远程的接口,所以这里是linkedHashMap类型了。
// 3.将token信息存放在cookie中
LinkedHashMap<String,Object> loginData = (LinkedHashMap<String, Object>) responseBase.getData();
String token = (String) loginData.get("memberToken");
if(StringUtils.isEmpty(token)) {
request.setAttribute("error", "会话信息已经失效");
return LOGIN;
}
//最好把cookie中的有效期,比redis中存放token的有效期少一天 我就是这样设置的
//将token放去cookie中去
CookieUtil.addCookie(response, Constants.COOKIE_MEMBER_TOKEN, token, Constants.TOKEEN_MEMBER_COOKIE_TIME_OUT);
return INDEX;
}
五、使用fegin调用会员服务查询用户信息
使用本地的token去换取userId,是比较安全的一种做法。
已进入系统的时候就检查token
// 返回String类型的表示跳转页面,加上一个/表示只要输入一个/后面不输入了就可以进入index请求里面拉
/**
* 跳转首页
*
* @return
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(HttpServletRequest request) {
log.info("请求了主页的页面了......");
// 1.从cookie中获取token信息
String token = CookieUtil.getUid(request, Constants.COOKIE_MEMBER_TOKEN);
if (StringUtils.isEmpty(token)) {
// request.setAttribute("error", "登录失败,token已经过期");
return LOGIN;
}
// 2.如果cookie中存在token 就拿token查用户信息
ResponseBase responseBase = memberservicefegin.findByTokenUser(token);
if (!responseBase.getRtnCode().equals(Constants.HTTP_RES_CODE_200)) {
request.setAttribute("error", "登录失败,token已经过期");
return LOGIN;
}
LinkedHashMap<String, Object> userData = (LinkedHashMap<String, Object>) responseBase.getData();
LinkedHashMap userEntity = (LinkedHashMap) userData.get("userInfo");
request.setAttribute("username", userEntity.get("username"));
return INDEX;
}
六、QQ授权登录流程&OAuth2.0
使用的事OAuth2.0协议 授权认证。多个平台的账号能够进行互绑
Oauth2.0协议是你要关联那个账号,那个平台就会搭建这个平台。
QQ登录授权流程:
1、QQ平台
2、网站
业务需求:
1、在网站没有注册账号
2、在网站已经注册账号
Oauth2.0开发协议:就是授权认证,多个平台账号能够进行互绑。
流程:
1、腾讯QQ提供授权码给 你的网站
2、网站获取到授权码之后,使用授权码换取accessToken(有有效期)
3、使用accestoken获取openid
openid: 这个是唯一不重复的,且永久不会变的,对外部提供的用户的id。
实现步骤:
1、腾讯QQ提供授权码给蚂蚁课堂
1、:需要生成授权码链接,通过接口,授权码授权成功后。
2、使用授权码获取accessToken
3、使用accessToken获取到openid
https://graph.qq.com/oauth2.0/me?access_token=E2516674D356604AB3E8A8F042B31173
4、可以使用openid获取部分用户信息。
七、会员服务提供联合登录接口
注意点:
什么时候使用LinkedHashMap来获取值?当使用rpc远程调用的时候
返回的数据,如果要获取里面的数据的话,要使用LinkedHashMap来进行接收。
如果是本地内部自己调用自己就可以用JSONObject来接收数据。
八、关联账号原理
获取到openid直接关联账号
1、获取到openId 就直接关联账号
2、使用openid去数据库查查询user表
3、如果对应的openid已经存在了,关联账号直接登录。
4、使用openid去查找user表,如果没有找到对应的openid,就跳转到管理账号关联
会员服务应该提供:
1、使用openid来查询用户信息
2、登录并且绑定openid
九、在前端进行关联
获取授权链接:注意这里有个session可能丢失的问题