zoukankan      html  css  js  c++  java
  • 微信点餐系统(十二)-买家与卖家端连通

     章节感悟

    1.cookie的设置与注销

    2.redis的使用,数据插入与删除

    3.AOP的使用

    4.全局捕获异常

    5.微信模板消息推送

    6.webSocket消息推送

    买家与卖家端连通

    卖家信息表dao开发和service开发

    1.创建卖家信息表seller_info

    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 '卖家信息表';

    2.DAO实体映射SellerInfo

    3.SellerInfoRepository

    4.创建SellerService接口

    登陆成功

    1.获取卖家openid,这是在微信开放平台获取的,由于这里我们没有企业资格,所以这里的openid我们设定为一个固定值oIe231KOhNAGPWEIsE52bdPBA910

    2.设置登录页面

    3.创建SellerUserController类,里面三个方法,登录页面跳转,登录和登出

    4.下载Redis Desktop Manager 可视化工具

    5.引入redis依赖,配置redis

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    
    redis:
      host: 192.168.1.105
      port: 6379

    6.设置一个redis常量,创建包constant,创建接口RedisConstant

    package com.xiong.sell.constant;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 10:55
     */
    public interface RedisConstant {
    
        String TOKEN_PREFIX = "token_%s";
        
        I

    7.设置openidcookie,创建一个cookie工具类,保存和获取cookie,设置cookie常量

    8.创建ProductUrlConfig类,获取配置文件中的路径

    9.登陆接口”/sell/seller/login”

    @PostMapping("/login")
    public ModelAndView login(@RequestParam("openid") String openid,
                              Map<String, Object> map,
                              HttpServletResponse response) {
        //1.openid和数据库匹配
        SellerInfo sellerInfo = sellerService.findSellerInfoByOpenid(openid);
        if (sellerInfo == null) {
            map.put("msg", ResultEnum.LOGIN_FAIL.getMessage());
            map.put("url", "/sell/seller/toLogin");
            return new ModelAndView("common/error", map);
        }
        //2.设置token到redis中
        String token = UUID.randomUUID().toString();
        Integer expire = RedisConstant.EXPORE;
        redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX, token, openid), openid, expire, TimeUnit.SECONDS);
        //3.设置token到cookie
        CookieUtil.set(response, CookieConstant.TOKEN, token, CookieConstant.EXPORE);
    
        //页面跳转
        return new ModelAndView("redirect:" + projectUrlConfig.getSell() + "/sell/seller/order/list");
    }

    登出成功

    1.登出接口”/sell/seller/logout”

    @GetMapping("/logout")
    public ModelAndView logout(HttpServletRequest request,
                               HttpServletResponse response,
                               Map<String, Object> map) {
        //1.从cookie里面查询
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        if (cookie != null) {
            //2.清除redis
            redisTemplate.opsForValue().getOperations().delete((String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())));
            //3.清除cookie,设置过期时间为0
            CookieUtil.set(response, CookieConstant.TOKEN, null, 0);
        }
        map.put("msg",ResultEnum.LOGOUT_SUCCESS.getMessage());
        map.put("url","/sell/seller/toLogin");
        return new ModelAndView("common/success",map);
    }

    1.获取cookie,并且注销cookie

    2.清除redis

    AOP实现身份验证

    1.创建SellerAuthorizeAspect类,设置拦截点以及操作,有问题则抛出异常

    package com.xiong.sell.aspect;
    
    import com.xiong.sell.constant.CookieConstant;
    import com.xiong.sell.constant.RedisConstant;
    import com.xiong.sell.exception.SellerAuthorizeException;
    import com.xiong.sell.utils.CookieUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 13:00
     */
    @Aspect
    @Component
    @Slf4j
    public class SellerAuthorizeAspect {
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @Pointcut("execution(public * com.xiong.sell.controller.Seller*.*(..))" +
                " && !execution(public * com.xiong.sell.controller.SellerUserController.*(..))")
        public void verify() {
        }
    
        @Before("verify()")
        public void doVerify() {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            //查询cookie
            Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
            if (cookie == null) {
                log.warn("【登录校验】 cookie中没有token");
                throw new SellerAuthorizeException();
            }
            //查询redis
            String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));
            if(StringUtils.isEmpty(tokenValue)){
                log.warn("【登录校验】 redis中没有token");
                throw new SellerAuthorizeException();
            }
        }
    }
    View Code

    2.创建SellerAuthorizeException

    package com.xiong.sell.exception;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 16:23
     */
    public class SellerAuthorizeException extends RuntimeException {
    }
    View Code

    3.拦截SellerAuthorizeException异常并且给出操作

    package com.xiong.sell.handler;
    
    import com.xiong.sell.config.ProjectUrlConfig;
    import com.xiong.sell.exception.SellerAuthorizeException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 16:28
     */
    @ControllerAdvice
    public class SellExceptionHandler {
    
        @Autowired
        private ProjectUrlConfig projectUrlConfig;
    
        /**
         * 拦截登录异常
         * @return
         */
        @ExceptionHandler(value = SellerAuthorizeException.class)
        public ModelAndView handlerAuthorizeException(){
            return new ModelAndView("redirect:" + projectUrlConfig.getSell() + "/sell/seller/toLogin");
        }
    } 
    View Code

    微信模板消息推送

    1.创建PushMessage接口service

    package com.xiong.sell.service;
    
    import com.xiong.sell.dto.OrderDTO;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 17:01
     */
    public interface PushMessage {
    
        void orderStatus(OrderDTO orderDTO);
    }
    View Code

    2.实现PushMassage接口

    package com.xiong.sell.service.impl;
    
    import com.xiong.sell.dto.OrderDTO;
    import com.xiong.sell.service.PushMessage;
    import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
    import lombok.extern.slf4j.Slf4j;
    import me.chanjar.weixin.common.error.WxErrorException;
    import me.chanjar.weixin.mp.api.WxMpService;
    import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
    import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 17:02
     */
    @Service
    @Slf4j
    public class PushMessageImpl implements PushMessage {
    
        @Autowired
        private WxMpService wxMpService;
    
        @Override
        public void orderStatus(OrderDTO orderDTO) {
            WxMpTemplateMessage templateMessage = new WxMpTemplateMessage();
            templateMessage.setTemplateId("sBkdCQcYxaVaIlhQ2wGuejjr_K1I0Rv2HVCZHIaNXdg");
            templateMessage.setToUser("oIe231KOhNAGPWEIsE52bdPBA910");
            List<WxMpTemplateData> data = new ArrayList<>();
            data.add(new WxMpTemplateData("first","这是标题"));
            data.add(new WxMpTemplateData("keyword1",String.valueOf(orderDTO.getBuyerOpenid())));
            data.add(new WxMpTemplateData("remark","这是结尾"));
            templateMessage.setData(data);
            try{
                wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
            }catch (WxErrorException e){
                log.info("【微信模板消息】发送失败,{}",e);
            }
        }
    }
    View Code

    3.取消订单则方法调用这个推送

    推送成功

     

    WebSocket接收并且推送新订单消息

    1.引入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    View Code

    2.修改order/list.ftl页面的Script

    <html>
    <#include "../common/header.ftl">
    
    <body>
    <div id="wrapper" class="toggled">
        <#--边栏sidebar-->
        <#include "../common/nav.ftl">
        <#--主要内容content-->
        <div id="page-content-wrapper">
            <div class="container-fluid">
                <div class="row clearfix">
                    <div class="col-md-12 column">
                        <table class="table table-condensed table-hover table-bordered">
                            <thead>
                            <tr>
                                <th>订单id</th>
                                <th>姓名</th>
                                <th>手机号</th>
                                <th>地址</th>
                                <th>金额</th>
                                <th>订单状态</th>
                                <th>支付状态</th>
                                <th>创建时间</th>
                                <th colspan="2">操作</th>
                            </tr>
                            </thead>
                            <tbody>
                            <#list orderDTOPage.content as orderDTO>
                                <tr>
                                    <td>${orderDTO.orderId}</td>
                                    <td>${orderDTO.buyerName}</td>
                                    <td>${orderDTO.buyerPhone}</td>
                                    <td>${orderDTO.buyerAddress}</td>
                                    <td>${orderDTO.orderAmount}</td>
                                    <td>${orderDTO.orderStatusEnum.message}</td>
                                    <td>${orderDTO.payStatusEnum.message}</td>
                                    <td>${orderDTO.createTime}</td>
                                    <td><a href="/sell/seller/order/detail?orderId=${orderDTO.orderId}">详情</a></td>
                                    <td>
                                        <#if orderDTO.orderStatusEnum.message == "新订单">
                                            <a href="/sell/seller/order/cancel?orderId=${orderDTO.orderId}">取消</a>
                                        </#if>
                                    </td>
                                </tr>
                            </#list>
                            </tbody>
                        </table>
                    </div>
                    <div class="col-md-12 column">
                        <ul class="pagination pull-right">
                            <#--上一页 小于1则无法显示上一页-->
                            <#if currentPage lte 1>
                                <li class="disabled"><a href="#">上一页</a></li>
                            <#else >
                                <li><a href="/sell/seller/order/list?page=${currentPage-1}&size=${size}">上一页</a></li>
                            </#if>
                            <#list 1..orderDTOPage.totalPages as index>
                                <#if currentPage == index>
                                    <li class="disabled"><a href="#">${index}</a></li>
                                <#else>
                                    <li><a href="/sell/seller/order/list?page=${index}&size=${size}">${index}</a></li>
                                </#if>
                            </#list>
                            <#--下一页 大于orderDTOPage.totalPages则无法显示下一页-->
                            <#if currentPage gte orderDTOPage.totalPages>
                                <li class="disabled"><a href="#">下一页</a></li>
                            <#else >
                                <li><a href="/sell/seller/order/list?page=${currentPage+1}&size=${size}">下一页</a></li>
                            </#if>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <#--弹窗-->
    <div class="modal fade" id="myModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                    <h4 class="modal-title" id="myModalLabel">
                        提醒
                    </h4>
                </div>
                <div class="modal-body">
                    你有新的订单
                </div>
                <div class="modal-footer">
                    <button onclick="javascript:document.getElementById('notice').pause()" type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                    <button onclick="location.reload()" type="button" class="btn btn-primary">查看新的订单</button>
                </div>
            </div>
        </div>
    </div>
    
    <#--播放音乐-->
    <audio id="notice" loop="loop">
        <source src="/sell/mp3/song.mp3" type="audio/mpeg" />
    </audio>
    
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    
    <script>
        var websocket = null;
        if('WebSocket' in window) {
            websocket = new WebSocket('ws://localhost: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)
            //弹窗提醒,
            $('#myModal').modal('show');
            // 播放音乐
            document.getElementById('notice').play();
        }
    
        websocket.onerror = function () {
            alert('websocket通信发生错误!');
        }
    
        window.onbeforeunload = function () {
            websocket.close();
        }
    
    </script>
    </body>
    </html>
    View Code

    3.添加websocket配置

    package com.xiong.sell.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 17:32
     */
    @Component
    public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    View Code 

    4.建立websocket连接

    package com.xiong.sell.service;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.OnClose;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.ServerEndpoint;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    /**
     * @author Xiong YuSong
     * 2019/1/28 17:32
     */
    @Component
    @ServerEndpoint("/webSocket")
    @Slf4j
    public class WebSocket {
    
        private Session session;
    
        private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
    
        @OnOpen
        public void onOpen(Session session) {
            this.session = session;
            webSocketSet.add(this);
            log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());
        }
    
        @OnClose
        public void onClose() {
            webSocketSet.remove(this);
            log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
        }
    
        @OnMessage
        public void onMessage(String message) {
            log.info("【websocket消息】收到客户端发来的消息:{}", message);
        }
    
        public void sendMessage(String message) {
            for (WebSocket webSocket: webSocketSet) {
                log.info("【websocket消息】广播消息, message={}", message);
                try {
                    webSocket.session.getBasicRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    View Code

    5.推送消息订单创建的service方法中插入下面一句话

    webSocket.sendMessage("您有新的订单");

  • 相关阅读:
    python中的有趣用法
    python计算程序运行时间
    python OptionParser模块
    优酷界面全新改版
    python数值计算模块NumPy scipy安装
    IOS开发-通知与消息机制
    四川大学线下编程比赛第一题:数字填充
    矩形旋转碰撞,OBB方向包围盒算法实现
    【Cocos2d-x 粒子系统】火球用手指飞起来
    它们的定义AlertDialog(二)
  • 原文地址:https://www.cnblogs.com/xzmxddx/p/10331289.html
Copyright © 2011-2022 走看看