章节感悟
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.设置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
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();
}
}
}
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.取消订单则方法调用这个推送
推送成功
WebSocket接收并且推送新订单消息
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("您有新的订单");
来源:oschina
链接:https://my.oschina.net/u/4305979/blog/4524180