美文网首页
第十二章 企业级微信点餐项目(卖家登陆)

第十二章 企业级微信点餐项目(卖家登陆)

作者: Xia0JinZi | 来源:发表于2017-12-27 10:12 被阅读0次

    卖家登陆

    标签(空格分隔): 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 不足以及误处请大佬指责

    相关文章

      网友评论

          本文标题:第十二章 企业级微信点餐项目(卖家登陆)

          本文链接:https://www.haomeiwen.com/subject/lmiygxtx.html