SpringBoot微信點餐專案(三)——後臺管理和訊息
iwehdio的部落格園:https://www.cnblogs.com/iwehdio/
1、賣家訂單
-
請求:
訂單列表: /seller/order/list?page=1&size=10 取消訂單: /seller/order/cancel?orderId=1 訂單詳情: /seller/order/detail?orderId=1 完結訂單: /seller/order/finish?orderId=1
-
訂單業務層OrderMasterService:
-
檢視訂單列表:
-
控制器:
@Controller @RequestMapping("/seller/order") public class SellerOrderController { @Autowired private OrderMasterService masterService; @GetMapping("/list") public ModelAndView list(@RequestParam(value = "page",defaultValue = "1") Integer page, @RequestParam(value = "size",defaultValue = "10") Integer size, Map<String,Object> map){ PageRequest request = new PageRequest(page-1, size); Page<OrderDTO> orderDTOPage = masterService.findAll(request); map.put("orderDTOPage",orderDTOPage); return new ModelAndView("order/list",map); } }
-
業務層:
@Override public Page<OrderDTO> findAll(Pageable pageable) { Page<OrderMaster> masterPage = masterDao.findAll(pageable); List<OrderDTO> orderDTOList = OrderMaster2OrderDTOConverter.convert(masterPage.getContent()); return new PageImpl<OrderDTO>(orderDTOList, pageable, masterPage.getTotalElements()); }
-
-
根據資料庫中訂單狀態和支付狀態的code獲取對應的列舉的message資訊:
-
建立介面,兩個狀態的列舉都實現該介面:
public interface CodeEnum { Integer getCode(); }
-
建立工具類:
public class EnumUtil { public static <T extends CodeEnum> T getByCode(Integer code, Class<T> enumClass){ for (T enumConstant : enumClass.getEnumConstants()) { if (code.equals(enumConstant.getCode())){ return enumConstant; } } return null; } }
-
在OrderDTO中建立對應方法:
@JsonIgnore public OrderStatusEnum getOrderStatusEnum() { return EnumUtil.getByCode(orderStatus, OrderStatusEnum.class); } @JsonIgnore public PayStatusEnum getpayStatusEnum() { return EnumUtil.getByCode(payStatus, PayStatusEnum.class); }
-
前端使用:
<#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.getOrderStatusEnum().getMessage()}</td> <td>${orderDTO.getpayStatusEnum().getMessage()}</td> <td>${orderDTO.createTime}</td> <td> <a href="/sell/seller/order/detail?orderId=${orderDTO.orderId}">詳情</a> </td> <td> <#if orderDTO.getOrderStatusEnum().getMessage() =="新訂單"> <a href="/sell/seller/order/cancel?orderId=${orderDTO.orderId}">取消</a> </#if> </td> </tr> </#list >
-
-
翻頁效果:
<div class="col-md-12 column"> <ul class="pagination pull-right"> <#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.getTotalPages() 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> <#if currentPage gte orderDTOPage.getTotalPages()> <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>
-
取消訂單按鈕:
-
控制器:
private String returnUrl = "/sell/seller/order/list"; @GetMapping("/cancel") public ModelAndView cancel(@RequestParam("orderId") String orderId, Map<String,Object> map){ OrderDTO orderDTO; try { orderDTO = masterService.findOne(orderId); masterService.cancel(orderDTO); } catch (SellException e) { map.put("msg", e.getMessage()); map.put("url",returnUrl); return new ModelAndView("sellerOrder/error",map); } map.put("msg", "SUCCESS"); map.put("url",returnUrl); return new ModelAndView("sellerOrder/success",map); }
-
前端:
<td> <#if orderDTO.getOrderStatusEnum().getMessage() !="已取消"> <a href="/sell/seller/order/cancel?orderId=${orderDTO.orderId}">取消</a> </#if> </td>
-
所要跳轉的頁面:
<body> <div class="container"> <div class="row clearfix"> <div class="col-md-12 column"> <div class="alert alert-dismissable alert-success"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4> 成功! </h4> <strong>${msg}</strong><a href="${url}" class="alert-link"> 3s後返回</a> </div> </div> </div> </div> <script> setTimeout('location.href="${url}"',3000); </script> </body>
-
-
詳情按鈕:
-
控制器:
@GetMapping("/detail") public ModelAndView detail(@RequestParam("orderId") String orderId, Map<String,Object> map) { OrderDTO orderDTO; try { orderDTO = masterService.findOne(orderId); } catch (SellException e) { map.put("msg", e.getMessage()); map.put("url",returnUrl); return new ModelAndView("sellerOrder/error",map); } map.put("orderDTO", orderDTO); return new ModelAndView("sellerOrder/detail",map); }
-
前端:
<div class="container"> <div class="row clearfix"> <div class="col-md-12 column"> <table class="table table-hover table-bordered"> <thead> <tr> <th>訂單id</th> <th>訂單金額</th> </tr> </thead> <tbody> <tr> <td>${orderDTO.orderId}</td> <td>${orderDTO.orderAmount}</td> </tr> </tbody> </table> </div> <div class="col-md-12 column"> <table class="table table-hover table-bordered"> <thead> <tr> <th>商品id</th> <th>商品名稱</th> <th>價格</th> <th>數量</th> <th>總價</th> </tr> </thead> <tbody> <#list orderDTO.orderDetailList as detail> <tr> <td>${detail.productId}</td> <td>${detail.productName}</td> <td>${detail.productPrice}</td> <td>${detail.productQuantity}</td> <td>${detail.productPrice * detail.productQuantity}</td> </tr> </#list> </tbody> </table> </div> <div class="col-md-12 column"> <#if orderDTO.getOrderStatusEnum().getMessage() != "已取消"> <a href="/sell/seller/order/finish?orderId=${orderDTO.orderId}" type="button" class="btn btn-default btn-primary">完結訂單</a> <a href="/sell/seller/order/cancel?orderId=${orderDTO.orderId}" type="button" class="btn btn-default btn-danger">取消訂單</a> </#if> </div> </div> </div>
-
完結訂單:
@GetMapping("/finish") public ModelAndView finish(@RequestParam("orderId") String orderId, Map<String,Object> map) { OrderDTO orderDTO; try { orderDTO = masterService.findOne(orderId); masterService.finish(orderDTO); } catch (SellException e) { map.put("msg", e.getMessage()); map.put("url",returnUrl); return new ModelAndView("sellerOrder/error",map); } map.put("msg", "SUCCESS"); map.put("url",returnUrl); return new ModelAndView("sellerOrder/success",map); }
-
-
2、商品列表
-
請求:
商品列表: /seller/product/list?page=1&size=10 商品上架: /seller/product/onSale?productId=1 商品下架: /seller/product/offSale?productId=1 商品新增: /seller/product/index 商品修改: /seller/product/index?productId=1
-
賣家後端側邊欄(需要css樣式):
<nav class="navbar navbar-inverse navbar-fixed-top" id="sidebar-wrapper" role="navigation"> <ul class="nav sidebar-nav"> <li class="sidebar-brand"> <a href="#"> 賣家管理系統 </a> </li> <li> <a href="/sell/seller/order/list"><i class="fa fa-fw fa-list-alt"></i> 訂單</a> </li> <li class="dropdown open"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true"><i class="fa fa-fw fa-plus"></i> 商品 <span class="caret"></span></a> <ul class="dropdown-menu" role="menu"> <li class="dropdown-header">操作</li> <li><a href="/sell/seller/product/list">列表</a></li> <li><a href="/sell/seller/product/index">新增</a></li> </ul> </li> <li class="dropdown open"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true"><i class="fa fa-fw fa-plus"></i> 類目 <span class="caret"></span></a> <ul class="dropdown-menu" role="menu"> <li class="dropdown-header">操作</li> <li><a href="/sell/seller/category/list">列表</a></li> <li><a href="/sell/seller/category/index">新增</a></li> </ul> </li> <li> <a href="/sell/seller/logout"><i class="fa fa-fw fa-list-alt"></i> 登出</a> </li> </ul> </nav>
-
引入側邊欄:
<link rel="stylesheet" href="/sell/css/style.css"> <div id="wrapper" class="toggled"> <!-- 側邊欄,這裡的引入路徑是從templates下開始的絕對路徑 --> <#include "/sellerOrder/nav.ftl"> <!-- 主體內容在這個div中 --> <div id="page-content-wrapper"> </div> </div>
-
商品列表控制器:
@Controller @RequestMapping("/seller/product") public class SellerProductController { @Autowired private ProductInfoService productService; @Autowired private ProductCategoryService categoryService; @GetMapping("/list") public ModelAndView list(@RequestParam(value = "page",defaultValue = "1") Integer page, @RequestParam(value = "size",defaultValue = "10") Integer size, Map<String,Object> map){ PageRequest request = new PageRequest(page-1, size); Page<ProductInfo> productInfoPage = productService.findAll(request); map.put("productInfoPage",productInfoPage); map.put("currentPage",page); map.put("size",size); return new ModelAndView("sellerProduct/list",map); } }
-
商品上下架:
-
商品資訊業務層:
@Override public ProductInfo onSale(String pruductId) { ProductInfo productInfo = dao.findOne(pruductId); if (productInfo == null) { throw new SellException(ResultEnum.PRODUCT_NOT_EXIST); } if (productInfo.getProductStatusEnum() == ProductStatusEnum.UP) { throw new SellException(ResultEnum.PRODUCT_STATUS_ERROR); } productInfo.setProductStatus(ProductStatusEnum.UP.getCode()); return dao.save(productInfo); }
-
控制器:
private String returnUrl = "/sell/seller/product/list"; @GetMapping("/onSale") public ModelAndView onSale(@RequestParam("productId") String productId, Map<String,Object> map) { try { productService.onSale(productId); } catch (SellException e) { map.put("msg", e.getMessage()); map.put("url",returnUrl); return new ModelAndView("common/error",map); } map.put("msg", "SUCCESS"); map.put("url",returnUrl); return new ModelAndView("common/success",map); }
-
-
商品新增修改:
-
跳轉商品修改頁並回顯:
-
控制器:
@GetMapping("/index") public ModelAndView index(@RequestParam(value = "productId",required = false) String productId, Map<String,Object> map) { if (productId!=null && !productId.isEmpty()) { ProductInfo productInfo = productService.findOne(productId); map.put("productInfo",productInfo); } List<ProductCategory> categoryList = categoryService.findAll(); map.put("categoryList", categoryList); return new ModelAndView("sellerProduct/index",map); }
-
前端:
<html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="/sell/css/style.css"> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div id="wrapper" class="toggled"> <!-- 側邊欄 --> <#include "common/nav.ftl"> <!-- 主體內容在這個div中 --> <div id="page-content-wrapper"> <div class="container-fluid"> <div class="row clearfix"> <div class="col-md-12 column"> <form role="form" method="post" action="/sell/seller/product/save"> <div class="form-group"> <label>名稱</label> <input name="productName" value="${(productInfo.productName)!''}" type="text" class="form-control" > </div> <div class="form-group"> <label>庫存</label> <input name="productName" value="${(productInfo.productStock)!''}" type="number" class="form-control" > </div> <div class="form-group"> <label>描述</label> <input name="productName" value="${(productInfo.productDescription)!''}" type="text" class="form-control" > </div> <div class="form-group"> <label>圖片</label> <img height="100" width="100" src="${(productInfo.productIcon)!''}" alt=""> <input name="productName" value="${(productInfo.productIcon)!''}" type="text" class="form-control" > </div> <div class="form-group"> <label>類目</label> <select name="categoryType" class="form-control"> <#list categoryList as category> <option value="${category.categoryType}" <#if productInfo.categoryType == category.categoryType> selected </#if> >${category.categoryName} </option> </#list> </select> </div> <input type="hidden" name="productId" value="${(productInfo.productId)!''}"> <button type="submit" class="btn btn-default">提交</button> </form> </div> </div> </div> </div> </div> </body> </html>
-
-
修改和新增:
-
表單類:
public class ProductForm { private String productId; private String productName; private BigDecimal productPrice; private Integer productStock; private String productDescription; private String productIcon; private Integer categoryType; }
-
控制器:
@PostMapping("/save") public ModelAndView save(@Valid ProductForm form, BindingResult bindingResult, Map<String,Object> map){ if (bindingResult.hasErrors()) { map.put("msg", bindingResult.getFieldError().getDefaultMessage()); map.put("url","/sell/seller/product/index"); return new ModelAndView("common/error",map); } ProductInfo productInfo = new ProductInfo(); try { if (form.getProductId()!=null && !form.getProductId().isEmpty()) { productInfo = productService.findOne(form.getProductId()); }else { form.setProductId(KeyUtil.genUniqueKey()); productInfo.setProductStatus(ProductStatusEnum.DOWN.getCode()); } BeanUtils.copyProperties(form,productInfo); productService.save(productInfo); } catch (Exception e) { map.put("msg", e.getMessage()); map.put("url","/sell/seller/product/index"); return new ModelAndView("common/error",map); } map.put("msg", "SUCCESS"); map.put("url",returnUrl); return new ModelAndView("common/success",map); }
-
-
3、類目列表
-
請求:
類名列表: /seller/category/list 類名新增: /seller/category/index 類名修改: /seller/category/index?categoryId=1
-
類目列表控制器:
@Controller @RequestMapping("/seller/category") public class SellerCategoryController { @Autowired private ProductCategoryService categoryService; @GetMapping("/list") public ModelAndView list(Map<String,Object> map) { List<ProductCategory> categoryList = categoryService.findAll(); map.put("categoryList", categoryList); return new ModelAndView("sellerCategory/list",map); } }
-
類目修改控制器:
@GetMapping("/index") public ModelAndView index(@RequestParam(value = "categoryId",required = false) Integer categoryId, Map<String,Object> map) { if (categoryId != null) { ProductCategory productCategory = categoryService.findOne(categoryId); map.put("category",productCategory); } return new ModelAndView("sellerCategory/index",map); }
-
類目儲存:
-
表單類:
public class CategoryForm { private Integer categoryId; private String categoryName; private Integer categoryType; }
-
控制器:
@PostMapping("/save") public ModelAndView save(@Valid CategoryForm form, BindingResult bindingResult, Map<String,Object> map) { if (bindingResult.hasErrors()) { map.put("msg",bindingResult.getFieldError().getDefaultMessage()); map.put("url","/sell/seller/category/index"); return new ModelAndView("common/error",map); } ProductCategory productCategory = new ProductCategory(); try { if (form.getCategoryId() !=null) { productCategory = categoryService.findOne(form.getCategoryId()); } BeanUtils.copyProperties(form,productCategory); categoryService.save(productCategory); } catch (Exception e) { map.put("msg",e.getMessage()); map.put("url","/sell/seller/category/index"); return new ModelAndView("common/error",map); } map.put("msg","SUCCESS"); map.put("url","/sell/seller/category/list"); return new ModelAndView("common/success",map); }
-
-
前端頁面與之前類似。
4、登入登出
-
什麼是分散式系統:
- 旨在支援應用程式和服務的開發,可以利用物理架構由多個自治的處理元素,不共享主記憶體,但通過網路傳送訊息合作。
- 與叢集的聯絡:叢集中的節點都是同一個角色,而分散式是不同的功能模組。
- 水平擴充套件:多個伺服器提供相同的服務。
- 垂直擴充套件:多個伺服器提供不同的服務,或者說一塊大的服務被拆分為多個功能模組。
-
session:
- 在無狀態的Http請求中獲取和儲存狀態。
- 分散式session,水平或垂直擴充套件的不同伺服器需要保持session統一。
- 可以使用redis叢集,所有的session都存入該叢集中。
-
建立賣家資訊表:
-
MySQL:
CREATE TABLE `seller_info`( `seller_id` VARCHAR(32) PRIMARY KEY, `username` VARCHAR(32) NOT NULL, `password` VARCHAR(32) NOT NULL, `openid` VARCHAR(64) NOT NULL, `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
-
實體類:
@Entity public class SellerInfo { @Id private String sellerId; private String username; private String passWord; private String openid; }
-
dao:
public interface SellerInfoDao extends JpaRepository<SellerInfo,String> { SellerInfo findByOpenid(String openid); SellerInfo save(SellerInfo sellerInfo); }
-
業務層:
@Service public class SellerInforServiceImpl implements SellerInfoService { @Autowired private SellerInfoDao dao; @Override public SellerInfo findSellerInfoByOpenid(String openid) { return dao.findByOpenid(openid); } }
-
-
微信掃描獲取openid:
-
阿里雲安裝redis:
docker pull redis:3.2.8-alpine docker run -itd --name redis_wxdc -p 6379:6379 redis:3.2.8-alpine --requirepass 123456
-
SpringBoot配置檔案:
Spring: redis: host: ip地址 port: 6379 password:
-
登入:
- openid與資料庫中的資料匹配。如果不匹配就跳轉錯誤頁面。
- 設定token到redis。token由UUID生成,是儲存的鍵,儲存的值是openid,並且設定過期時間。
- 設定token到Cookie。鍵是"token",值是生成的UUID。
- 校驗登入狀態,通過Cookie中的token查詢redis中有沒有對應的資料。
-
登出:
- 從Cookie中獲取token,並從Cookie中清除。
- 根據token清除redis中的openid。
-
AOP實現身份驗證:
- 建立切面類,切入點表示式設定為Seller開頭的Controller,且不為登入方法。
- 建立前置通知,獲取請求,查詢Cookie和redis。
- 如果校驗不通過則丟擲一個登入校驗異常。
- 使用
@ControllerAdvice
全域性異常處理。
-
簡單的賬戶密碼登入:
-
在SellerInfoDao中新增方法
SellerInfo findByUsername(String username)
。在業務層也增加對應的方法。 -
登入:
@Controller @RequestMapping("/seller") public class SellerLogController { private final String prefix = "token_"; private final Integer expire = 7200; //過期時間 @Autowired private SellerInfoService sellerInfoService; @Autowired private StringRedisTemplate redisTemplate; @GetMapping("/login") public ModelAndView login(){ return new ModelAndView("login/login"); } @GetMapping("/loginning") public ModelAndView loginning(@RequestParam("username") String username, @RequestParam("password") String password, Map<String,Object> map, HttpServletResponse response){ SellerInfo sellerInfo = sellerInfoService.findSellerInfoByUsername(username); if (sellerInfo==null || sellerInfo.getPassword()==null || !sellerInfo.getPassword().equals(password)) { map.put("msg","登入失敗"); map.put("url","/sell/seller/login"); return new ModelAndView("common/error",map); } String token = UUID.randomUUID().toString(); redisTemplate.opsForValue().set(prefix + token, username, expire, TimeUnit.SECONDS); CookieUtil.saveCookie(response,prefix, prefix + token); return new ModelAndView("redirect:/seller/order/list"); } }
-
登出:
@GetMapping("/logout") public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, Map<String,Object> map) { String cookie = CookieUtil.removeCookie(request, response,prefix); if (cookie!=null) { redisTemplate.opsForValue().getOperations().delete(cookie); } map.put("msg","登出成功"); map.put("url","#"); return new ModelAndView("common/success",map); }
-
Cookie工具類:
public class CookieUtil { public static void saveCookie(HttpServletResponse response,String key,String value) { Cookie cookie = new Cookie(key, value); response.addCookie(cookie); } public static Cookie findCookie(HttpServletRequest request,String key){ Cookie[] cookies = request.getCookies(); if (cookies!=null) { for (Cookie cookie : cookies) { if (key.equals(cookie.getName())) { return cookie; } } } return null; } public static String removeCookie(HttpServletRequest request,HttpServletResponse response, String key){ Cookie cookie = findCookie(request, key); if (cookie!=null){ cookie.setMaxAge(0); response.addCookie(cookie); return cookie.getValue(); } return null; } }
-
-
AOP實現身份驗證:
-
Aspect切面類:
@Aspect @Component public class SellerAuthAspect { private final String prefix = "token_"; @Autowired private StringRedisTemplate redisTemplate; @Pointcut("execution(public * cn.iwehdio.sell.controller.Seller*.*(..))" + "&& !execution(public * cn.iwehdio.sell.controller.SellerLogController.*(..))") public void verify(){} @Before("verify()") public void doVerify(){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); Cookie cookie = CookieUtil.findCookie(request, prefix); if (cookie==null){ throw new SellerAuthException(); } String s = redisTemplate.opsForValue().get(cookie.getValue()); if (s==null){ throw new SellerAuthException(); } } }
-
全域性異常處理器:
@ControllerAdvice public class SellerAuthExceptionHandler { @ExceptionHandler(SellerAuthException.class) public ModelAndView handlerSellerAuth(){ return new ModelAndView("redirect:/seller/login"); } }
-
5、訊息推送
-
微信模板訊息文件:模板訊息介面。
-
設定模板訊息介面:
-
模板id:ScqECQqmMIsSVnHiw8LhlNUY17bq9qa9TkN5zZO1nBc。
-
模板內容:
{{first.DATA}} 商家名稱:{{sellerName.DATA}} 訂單號:{{orderId.DATA}} 狀態:{{orderStatus.DATA}} 總價:{{orderAmount.DATA}} 派送地址:{{orderAddress.DATA}} {{endMsg.DATA}}
-
-
業務層實現:
public interface PushMessageService { void orderStatus(OrderDTO orderDTO); } @Service public class PushMessageServiceImpl implements PushMessageService { @Autowired private WxMpService wxMpService; @Autowired private WechatAccountConfig wechatAccountConfig; private final String TEMPLATEID = "confirmMessage"; @Override public void orderStatus(OrderDTO orderDTO) { WxMpTemplateMessage templateMessage = new WxMpTemplateMessage(); templateMessage.setTemplateId(wechatAccountConfig.getTemplateIds().get(TEMPLATEID)); templateMessage.setToUser(orderDTO.getBuyerOpenid()); List<WxMpTemplateData> data = Arrays.asList( new WxMpTemplateData("first","請確認訂單"), new WxMpTemplateData("sellerName","iwehdio"), new WxMpTemplateData("orderId",orderDTO.getOrderId()), new WxMpTemplateData("orderStatus",orderDTO.getOrderStatusEnum().getMessage()), new WxMpTemplateData("orderAmount",orderDTO.getOrderAmount().toString()), new WxMpTemplateData("orderAddress",orderDTO.getBuyerAddress()), new WxMpTemplateData("endMsg","---------------------") ); templateMessage.setData(data); try { wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); } catch (WxErrorException e) { e.printStackTrace(); } } }
-
效果:
-
WebSocket:
-
分為客戶端和服務端,客戶端接收訊息,服務端傳送訊息。
-
客戶端在本專案中就是買家後臺管理頁面的前端頁面。
-
WebSocket配置類:
@Component public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
-
後端傳送WebSocket請求:
@Component @ServerEndpoint("/webSocket") public class WebSocket { private Session session; private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>(); @OnOpen public void onOpen(Session session) { this.session = session; webSockets.add(this); } @OnClose public void onClose() { webSockets.remove(this); } @OnMessage public void onMessage(String message) { } public void sendMessage(String message) { for (WebSocket webSocket : webSockets) { try { webSocket.session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } }
-
前端處理WebSocket訊息:
<div class="modal fade" id="msgmodal" 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" id="modal-body"> 訂單號: </div> <div class="modal-footer"> <button 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> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script> <script> var webSocket = null; if('WebSocket' in window) { webSocket = new WebSocket('ws://n5a8qq.natappfree.cc/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); $('#modal-body').text($('#modal-body').text()+ event.data); $("#msgmodal").modal('show'); }; webSocket.onerror = function (event) { console.log('出錯'); }; window.onbeforeunload = function () { webSocket.close(); }; </script>
-
效果:
-
iwehdio的部落格園:https://www.cnblogs.com/iwehdio/