1.cookie的設置與註銷javascript
2.redis的使用,數據插入與刪除css
3.AOP的使用html
4.全局捕獲異常java
5.微信模板消息推送jquery
6.webSocket消息推送web
1.建立賣家信息表seller_inforedis
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實體映射SellerInfospring
3.SellerInfoRepository數據庫
4.建立SellerService接口bootstrap
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.設置openid到cookie,建立一個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
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(); } } }
2.建立SellerAuthorizeException類
package com.xiong.sell.exception; /** * @author Xiong YuSong * 2019/1/28 16:23 */ public class SellerAuthorizeException extends RuntimeException { }
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"); } }
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); }
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); } } }
3.取消訂單則方法調用這個推送
推送成功
1.引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
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>
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(); } }
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(); } } } }
5.推送消息訂單建立的service方法中插入下面一句話
webSocket.sendMessage("您有新的訂單");