卖家登陆
标签(空格分隔): springboot java wechat
分布式session
登陆(验证身份,存储信息)
登出(失效浏览状态)
-
分布式
特点:多节点、消息通信、不共享内存概念:分布式系统、集群、分布式计算
分布式: 不同节点,相会组合应用,集群:相同节点,相会组合应用。
本视频的分布式session通过redis库来做用户验证。
卖家表
create table `seller_info`(
`seller_id` varchar(32) not null,
`username` varchar(32) not null,
`password` varchar(32) not null,
`openid` varchar(64) not null comment '微信openid',
`create_time` timestamp not null default current_timestamp comment '创建时间',
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '更新时间',
primary key(`seller_id`)
) comment '卖家信息表';
- dao层创建并测试
这里就不过多描述,model创建,jpa继承,插入和查询单元测试。
- service层的开发
简单的一个openid查询获取用户信息,别忘了单元测试
扫码登陆
- 扫码获取用户openid
@Autowired
private WechatAccountConfig wechatAccountConfig;
/**
* 配置设置
* @return
*/
@Bean
public WxMpService wxOpenMpService(){
WxMpService wxOpenService = new WxMpServiceImpl();
wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage());
return wxOpenService;
}
/**
* 返回参数
* @return
*/
@Bean
public WxMpConfigStorage wxOpenConfigStorage(){
WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage();
wxMpInMemoryConfigStorage.setAppId(wechatAccountConfig.getOpenAppid());
wxMpInMemoryConfigStorage.setSecret(wechatAccountConfig.getOpenSecret());
return wxMpInMemoryConfigStorage;
}
/**
* 微信开放平台重定向
* @param returnUrl
* @return
*/
@GetMapping("/qrAuthrize")
public String qrAuthrize(@RequestParam("returnUrl") String returnUrl){
String url = projectUrl.getWechatOpenAuthrize() + "/sell/wechat/qruserinfo";
String rediectUrl = wxOpenMpService.buildQrConnectUrl(url,WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN, URLEncoder.encode(returnUrl));
return "redirectUrl:" + rediectUrl;
}
/**
* 微信开放平台重定向
* @param code
* @param returnUrl
* @return
*/
@GetMapping("/qruserinfo")
public String qruserinfo(@RequestParam("code") String code,
@RequestParam("state") String returnUrl){
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
try {
wxMpOAuth2AccessToken = wxOpenMpService.oauth2getAccessToken(code);
}catch (WxErrorException e){
log.error("【微信网页授权】 e={}",e);
throw new SellException(ResultEnum.WECHAT_WEB_ERROR.getCode(),e.getError().getErrorMsg());
}
String openid = wxMpOAuth2AccessToken.getOpenId();
return "redirectUrl:"+ returnUrl + "?openid="+openid;
}
- redis和cookie用户身份缓存设置登陆操作
@RequestMapping("/login")
public ModelAndView login(@RequestParam("openid")String openid,HttpServletResponse response,Map<String,Object> map){
//openid数据匹配
SellerInfo sellerInfo = sellerService.findBySellerInfoOpenid(openid);
if(sellerInfo == null){
map.put("msg", ResultEnum.SELLER_USER_LOGIN.getMessage());
map.put("url","/sell/seller/order/list");
return new ModelAndView("common/error",map);
}
// 设置token至redis
String token = UUID.randomUUID().toString();
Integer maxAge = RedisConstant.EXPIRE;
redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,token),
openid,maxAge, TimeUnit.SECONDS);
//设置token至cookie
CookieUtil.set(response, CookieConstant.NAME,token,maxAge);
return new ModelAndView("redirect:" + "/seller/order/list");
}
- 登出操作
//通过便利cookie并找到浏览器的存储值,通过重新设置为控制,过期时间为0
/**
* 登出成功
* @param request
* @param response
* @param map
* @return
*/
@GetMapping("/logout")
public ModelAndView logout(HttpServletRequest request,HttpServletResponse response,Map<String,Object> map){
// 获取cookie内容
Cookie cookie = CookieUtil.get(request,CookieConstant.NAME);
if(cookie != null){
// 清楚redis数据库中的值
redisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));
// 清除cookie 的值
CookieUtil.set(response,CookieConstant.NAME,null,0);
}
map.put("msg",ResultEnum.SELLER_SUCCESS_LOGOUT);
map.put("url","/sell/seller/order/list");
return new ModelAndView("common/success",map);
}
/**
* cookie匹配返回
* @param request
* @param name
* @return
*/
public static Cookie get(HttpServletRequest request,String name){
Map<String,Cookie> map = getCookieMap(request);
if(map.containsKey(name)){
return map.get(name);
}else{
return null;
}
}
/**
* cookie 集合转换map
* @param request
* @return
*/
private static Map<String,Cookie> getCookieMap(HttpServletRequest request){
Map<String,Cookie> mapResult = new HashMap();
Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
mapResult.put(cookie.getName(),cookie);
}
return mapResult;
}
AOP身份验证
- 切片认证
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 拦截规则
*/
@Pointcut(value = "execution(public * com.xiaojinzi.controller.Seller*.*(..))" +
"&& !execution(public * com.xiaojinzi.controller.SellerUserController.*(..))")
public void verify(){
}
/**
*拦截处理
*/
@Before("verify()")
public void doverify(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
Cookie cookie = CookieUtil.get(request, CookieConstant.NAME);
if(cookie==null){
log.trace("【登陆验证】 cookie不存在");
throw new SellerAuthorizeException();
}
String token = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));
if(token==null){
log.trace("【登陆验证】 redis数据库token不存在");
}
}
- 拦截后处理
//拦截处理
@ExceptionHandler(value = SellerAuthorizeException.class)
public ModelAndView handlerException(){
return new ModelAndView("redirect:"
.concat(projectUrl.getWechatMpAuthrize())
.concat("/seller/wehcat/qrAuthrize")
.concat("?returnUrl=")
.concat(projectUrl.getSell())
.concat("/sell/seller/order/list"));
}
webSocke消息推送
- 客户端
//js
<script>
WebSocket websocket= null;
if('WebSocket'in window){
websocket = new WebSocket('ws://127.0.0.1:8080/sell/websocket');
}else{
alert('浏览器不支持websocket');
}
websocket.onopen= function (event) {
console.log('建立连接');
}
websocket.onclose = function (event) {
console.log('关闭连接');
}
websocket.onmessage= function (event) {
console.log('通信消息:'+event.data);
// 弹窗提醒,播放音乐
$("#mymodel").model('show');
document.getElementById('notice').play();
}
websocket.onerror = function (event) {
console.log('发生错误');
}
window.onbeforeunload = function () {
websocket.close();
}
</script>
<#--弹窗-->
<div id="mymodel" class="modal hide fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">标题栏</h3>
</div>
<div class="modal-body">
<p>显示信息</p>
</div>
<div class="modal-footer">
<button onclick="javascript:document.getElementById('notice').pause();" class="btn" data-dismiss="modal" aria-hidden="true">关闭</button>
<button onclick="location.reload();" class="btn btn-primary">查看订单</button>
</div>
</div>
<#--播放音乐-->
<audio id="notice" loop="loop">
<source src="/sell/mp3/song.mp3" type="audio/mpeg"/>
</audio>
<script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
- 服务端
//websocketConfig
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
//消息通信
@Component
@ServerEndpoint("/websocket")
@Slf4j
public class WebSocket {
/** session 对象. */
private Session session;
private static CopyOnWriteArrayList<WebSocket> webSocketSet = new CopyOnWriteArrayList<>();
@OnOpen
public void onOpen(Session session){
this.session = session;
webSocketSet.add(this);
log.info("【WebSocke通信】开始链接 通信数量={}",webSocketSet.size());
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
log.info("【WebSocke通信】连接关闭 通信数量={}",webSocketSet.size());
}
@OnMessage
public void onMessage(String message){
log.info("【WebSocke通信】收到消息发送 消息内容={}",message);
}
/**
* 发送消息
* @param message
*/
public void sendMessage(String message){
for(WebSocket webSocket:webSocketSet){
try {
webSocket.session.getBasicRemote().sendText(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
//下订单触发消息发送
webSocket.sendMessage(orderId);
- 原视频UP主慕课网(SpringBoot企业级微信点餐项目)
- 本篇博客撰写人: XiaoJinZi 转载请注明出处
- 学生能力有限 附上邮箱: 986209501@qq.com 不足以及误处请大佬指责