基于Vue+SpringCloudAlibaba微服务电商项目实战-构建会员服务-011:基于Vue快速整合会员服务接口

1 构建前端Vue项目调用后端接口实现联合登录效果演示

今日课程任务

  1. 如何快速理解前后端分离架构模式
  2. 前后端分离架构模式还存在哪些缺点
  3. 快速构建Vue项目调用后端接口
  4. 前后端分离架构如何解决跨域的问题
  5. 基于Vue调用后端接口实现联合登录
  6. 如何快速部署Vue项目

2 什么是微服务前后端分离开发的模式

早期java项目 分成三层结构
com.mayikt.controller 单独web项目 ftl/jsp
com.mayikt.service
com.mayikt.dao
这种架构模式没有体现让专业的人做专业的事情

微服务架构提倡:让专业的人做专业的事情 前后端分离架构模式

如何理解前后端分离架构模式?
将以前控制层业务逻辑的操作全部交给前端开发实现,后端工程师主要开发接口被前端调用。

Vue项目的应用场景:
适用于移动端Web、微信公众号、企业级管理平台 (对搜索引擎seo不友好)

前后端分离架构模式存在哪些优缺点:
缺点:
1.联调测试 需要搭建局域网或者外网映射
2.沟通成本比较高 后端有变动需要通知前端
3.只适合比较大的互联网团队
4.跨域问题
优点:
后端开发不需要修改页面,让专业的人做专业的事情,效率更高

前后端分离架构前端页面如何部署?
前端项目实际上就是静态html+ajax调用接口绑定数据,放在nginx/tomcat服务器/cdn加速服务器中均可运行。

3 联合登录接口接口简单回顾

  1. 需要提供查询联合登录渠道接口 首页登录展示图标
  2. 登录接口改造,如果有传递openIdToken,关联到数据库中
  3. 根据openIdToken判断是否已经关联账号,如果关联则跳转到首页,没有关联则跳转到关联页面

查询渠道接口
数据库表meite_union_login新增字段union_image_log,存储渠道图标用于页面展示
UnionLoginDTO

@Data
public class UnionLoginDTO {

    /**
     * 手机号码
     */
    @ApiModelProperty(value = "手机号码", name = "mobile", required = true)
    private String mobile;

    /**
     * 密码
     */
    @ApiModelProperty(value = "密码", name = "passWord", required = true)
    private String passWord;


    @ApiModelProperty(value = "开放平台令牌", name = "openIdToken", required = false)
    private String openIdToken;
}

MemberUnionLoginService/MemberUnionLoginServiceImpl

/**
 * 查询当前开通的渠道
 *
 * @return
 */
@GetMapping("/unionLoginList")
@ResponseBody
BaseResponse<List<UnionLoginDTO>> unionLoginList();
@Override
public BaseResponse<List<UnionLoginDTO>> unionLoginList() {
    List<UnionLoginDO> unionLoginList = unionLoginMapper.selectByUnionLoginList();
    if (unionLoginList == null) {
        return setResultError("当前没有可用渠道");
    }
    List<UnionLoginDO> unionLoginDtos = MeiteBeanUtils.doToDtoList(unionLoginList, UnionLoginDO.class);
    return setResultSuccess(unionLoginDtos);
}

测试效果:
在这里插入图片描述

4 前后端分离解决跨域的问题

前后端分离解决跨域的问题 来源浏览器的安全策略
浏览器地址访问http://127.0.0.1:8849/mayikt_mt_shop/login.html访问vue项目,
页面里面发出ajax请求必须要和地址栏的ip和端口必须要保持一致,否则浏览器会有安全策略问题。
ajax请求:http://127.0.0.1:7070/unionLoginList

解决跨域方案(浏览器访问端口号和页面请求的端口号不一致)

  1. 在响应头中设置允许跨域 只适合于小公司
    响应配置response.setHeader(“Access-Control-Allow-Origin”,"*")
  2. 使用HttpClient转发 效率低
  3. 使用jsonp处理 Jsonp不支持post请求,属于前端解决
  4. 使用Nginx解决跨域,保持域名和端口一致性
    www.mayikt.com/vue 转发到vue项目
    www.mayikt.com/api 转发到接口项目
  5. 可以直接在nginx中配置允许跨域的代码
    “Access-Control-Allow-Origin”,"*"
  6. 使用网关配置类似于nginx允许跨域的代码
  7. 使用SpringBoot注解形式@CrossOrigin
  8. 使用微服务网关也可以配置,配置浏览器访问的项目与接口项目的域名和端口号一致
    在这里插入图片描述

5 Vue项目中构建登录页面加载网络

Vue前端页面
Axios 官方文档 https://www.kancloud.cn/yunye/axios/234845

login.html

<div class="logon_others"><span class="logon_others_title">其他登录方式</span>
<a class="logon_qq" v-for="(p) in dunionLogins" :href="p.requestAddress">
<img :src="p.unionImgLog" :alt="p.unionName"></a>
</div><script src="./js/union_login.js"></script>

union_login.js

var vue = new Vue({
	el: "#app",
	data: {
		msg: "mayikt",
		dunionLogins: []
	},
	created: function() {
		this.loadUnionLoginList();
	},
	methods: {
		loadUnionLoginList: function() {
			var temp = this;
			axios.get('http://127.0.0.1:7070/unionLoginList')
				.then(function(response) {
					// alert(response);
					var data = response.data.data;
					temp.dunionLogins = data;
					console.log(response);
				})
				.catch(function(error) {
					console.log(error);
				});
		}

	}
})

测试效果:
在这里插入图片描述

6 回调接口需要Web层实现中转的原理

在这里插入图片描述
会员接口中直接写重定向代码到vue项目不符合规范,需要一个web项目作为中转。
通常情况应该起一个web-member项目调用会员服务接口,配置qq、微信回调地址为web接口地址,调用成功返回bindingurl页面,失败返回错误页面。

为了简化流程此处先将回调接口改为重定向到Vue项目

@GetMapping("/login/oauth/callback")
//    public BaseResponse<JSONObject> unionLoginCallback(@RequestParam("unionPublicId") String unionPublicId);
    public String unionLoginCallback(@RequestParam("unionPublicId") String unionPublicId);
@Controller
@CrossOrigin
public class MemberUnionLoginServiceImpl extends BaseApiService implements MemberUnionLoginService {

    @Autowired
    private UnionLoginMapper unionLoginMapper;
    @Autowired
    private TokenUtil tokenUtil;
    @Value("${mayikt.login.vue.bindingurl}")
    private String bindingurl;

    @Override
    public String unionLoginCallback(String unionPublicId) {
        // 根据渠道id查询 联合基本信息
        UnionLoginDO unionLoginDo = unionLoginMapper.selectByUnionLoginId(unionPublicId);
        String unionBeanId = unionLoginDo.getUnionBeanId();
        //  从Spring容器中根据beanid 查找到我们的策略类
        UnionLoginStrategy unionLoginStrategy = SpringContextUtils.getBean(unionBeanId, UnionLoginStrategy.class);
        // 根据当前线程获取request对象
        HttpServletRequest request = ((ServletRequestAttributes)
                (RequestContextHolder.currentRequestAttributes())).getRequest();
        String openId = unionLoginStrategy.unionLoginCallback(request, unionLoginDo);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("openId", openId);
        jsonObject.put("unionPublicId", unionPublicId);
        String openToken = tokenUtil.createToken("mayikt.unionLogin.", jsonObject.toJSONString());
        return "redirect:" + bindingurl + openToken;
    }
}

bootstrap.yml

mayikt:
  login:
      vue:
      bindingurl: http://127.0.0.1:8849/mayikt_mt_shop/relation_login.html?openIdToken=

7 前端获取Url中的token参数实现传递

relation_login.html 第三方登录页面

<script>
		load();
		function getQueryString(name) {
			var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
			var r = window.location.search.substr(1).match(reg);
			if (r != null) return unescape(r[2]);
			return null;
		}

		function locationBindLogin() {
			window.location.href = "bind_login.html?openIdToken=" + getQueryString('openIdToken');
		}
		function load() {
			axios.get('http://127.0.0.1:7070/openIdToken?openIdToken=' + getQueryString('openIdToken'))
				.then(function(response) {
					var data = response.data;
					if (data.code == 200) {
						var userToken = data.data.userToken;
						window.location.href = "index.html?userToken=" + userToken;
						return;
					}
				})
				.catch(function(error) {
					console.log(error);
				});
		}
	</script><body>
		<div class="bind">
			<div class="bind_contain">
				<h1>确认关联小米账号</h1>
				<img src="http://static.mayikt.com/QQ20191226.png" />
				<p class="name">蚂蚁课堂创始人-余胜军</p>
				<p>您的QQ尚未关联小米账号</p>
				<div class="bind_bottom">
					<a href="register.html">关联新账号</a>
					<a class="old_" href="javascript:void(0);" onclick="locationBindLogin()">关联到已有账号</a>
				</div>
			</div>

		</div>
		</body>

bind_login.html 绑定账号页面

	<body>
		<div class="Joint">
			<a class="logon_logo">
				<img src="http://static.mayikt.com/logomayishangcheng.png" />
			</a>
			<div class="Joint_container" id="app">
				<h2>请登录您要关联的账号</h2>
				<div class="regbox">
					<div class="el-input el-input--suffix">
						<input type="text" autocomplete="off"
						  v-model="phone"
						 placeholder="账号" class="el-input__inner">
					</div>
					<div class="el-input el-input--suffix">
						<input type="password"
						  v-model="passWord"
						 autocomplete="off" placeholder="密码" class="el-input__inner">
						<span class="el-input__suffix"><span class="el-input__suffix-inner">
							</span>
						</span>
					</div>
				</div>
				<button type="button"  @click="login()"   class="el-button el-button--default">
					<span >绑定并登录</span>
				</button>
			</div>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
		<script>
			function getQueryString(name) {
				var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
				var r = window.location.search.substr(1).match(reg);
				if (r != null) return unescape(r[2]);
				return null;
			}
		</script>
		<script src="js/bind_login.js"></script>
	</body>

bind_login.js

var vue = new Vue({
	el: "#app",
	data: {
		phone: "",
		passWord: ""
	},
	methods: {
		login: function() {
			var temp = this;
			axios.post('http://127.0.0.1:7070/login', {
					mobile: this.phone,
					passWord: this.passWord,
					openIdToken: getQueryString("openIdToken")
				}, {
					headers: {
						'X-Real-IP': '127.0.0.1',
						'channel': 'PC',
						'deviceInfor': 'huawei8'
					}
				})
				.then(function(response) {
					var data = response.data;
					if (data.code != 200) {
						alert(data.msg);
						return;
					}
					alert('登录成功');
					var userToken = data.data.userToken;
					window.location.href = "index.html?userToken=" + userToken;
				})
				.catch(function(error) {
					console.log(error);
				});
		}
	}
})

测试效果:
在这里插入图片描述
填入账号密码调用后台login接口传递openIdToken,异步方法AsyncLoginLogManage更新数据库绑定账户openId。
在这里插入图片描述

8 Vue整合后端微服务接口实现联合登录演示

测试效果:
在这里插入图片描述
注意:实现类MemberOpenIdTokenLoginImpl/MemberUnionLoginServiceImpl/
MemberLoginServiceImpl上面都要加上注解@CrossOrigin

9 微信联合登录生成二维码说明

整体流程同qq联合登录类似,不同之处在于点击微信登录图标前端页面显示二维码(后端调用生成二维码接口返回给前端),用户微信扫码相当于QQ点击头像授权操作,然后账户未绑定则更新openId,如果已绑定直接跳转到首页。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值