SSE 消息开发

This commit is contained in:
Jack 2024-12-21 00:30:44 +08:00
parent 0ec8e3f0a8
commit 85d06fc9b0
11 changed files with 271 additions and 78 deletions

View File

@ -0,0 +1,100 @@
package com.suisung.mall.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@Slf4j
public class SseEmitterUtil {
//当前连接数
public static final AtomicInteger count = new AtomicInteger(0);
//使用 map 对象便于根据 userId 来获取对应的 SseEmitter或者放 redis 里面
public static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
/**
* 创建用户连接并返回 SseEmitter
*
* @param channel 通道
*/
public static SseEmitter connect(String channel) {
//设置超时时间0表示不过期默认30秒超过时间未完成会抛出异常AsyncRequestTimeoutException
SseEmitter sseEmitter = new SseEmitter(1200000L); // 20分钟
try {
//注册回调完成失败超时
sseEmitter.onCompletion(completionCallBack(channel));
sseEmitter.onError(errorCallBack(channel));
sseEmitter.onTimeout(timeoutCallBack(channel));
// 缓存
sseEmitterMap.put(channel, sseEmitter);
// 数量+1
count.getAndIncrement();
log.debug("创建新的sse连接当前通道{}", channel);
} catch (Exception e) {
log.error("创建新的sse连接异常当前通道{}", channel);
}
return sseEmitter;
}
/**
* 给指定通道发送信息
*/
public static SseEmitter sendMessage(String channel, String message) {
SseEmitter sseEmitter = sseEmitterMap.get(channel);
if (sseEmitter == null) {
sseEmitter = connect(channel);
}
try {
sseEmitter.send(message);
log.info("向通道:{} 发送了:{}", channel, message);
return sseEmitter;
} catch (IOException e) {
log.error("通道:{} 推送异常:{}", channel, e.getMessage());
removeChannel(channel);
return null;
}
}
/**
* 移除通道连接
*/
public static void removeChannel(String channel) {
sseEmitterMap.remove(channel);
// 数量-1
count.getAndDecrement();
log.debug("移除通道:{}", channel);
}
/**
* 获取当前连接数量
*/
public static int getUserCount() {
return count.intValue();
}
private static Runnable completionCallBack(String channel) {
return () -> {
log.debug("结束连接:{}", channel);
removeChannel(channel);
};
}
private static Runnable timeoutCallBack(String channel) {
return () -> {
log.error("连接超时:{}", channel);
removeChannel(channel);
};
}
private static Consumer<Throwable> errorCallBack(String channel) {
return throwable -> {
log.error("连接异常:{}", channel);
removeChannel(channel);
};
}
}

View File

@ -1,5 +1,7 @@
package com.suisung.mall.common.utils; package com.suisung.mall.common.utils;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -12,6 +14,8 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 字符串工具类继承lang3字符串工具类 * 字符串工具类继承lang3字符串工具类
@ -20,7 +24,18 @@ import java.util.UUID;
*/ */
public final class StringUtils extends org.apache.commons.lang3.StringUtils { public final class StringUtils extends org.apache.commons.lang3.StringUtils {
private static Logger logger = LoggerFactory.getLogger(StringUtils.class); public static void main(String[] args) {
System.out.println(removeProvinceCityDistrict("广西壮族自治区贵港市桂平市西山镇新安街粤桂花城1102号"));
}
/**
* 随机字符串
*/
private static final String INT_TEMP = "0123456789";
private static final String STR_TEMP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final String ALL_TEMP = INT_TEMP + STR_TEMP;
private static final Random RANDOM = new Random();
private static final Logger logger = LoggerFactory.getLogger(StringUtils.class);
public static String encode(String str) { public static String encode(String str) {
String encode = null; String encode = null;
@ -41,7 +56,6 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
return UUID.randomUUID().toString().replace("-", ""); return UUID.randomUUID().toString().replace("-", "");
} }
/** /**
* 要求外部订单号必须唯一 * 要求外部订单号必须唯一
* *
@ -97,33 +111,6 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
return txt.replaceAll("[   `·•<C2B7>\\f\\t\\v]", ""); return txt.replaceAll("[   `·•<C2B7>\\f\\t\\v]", "");
} }
/**
* 随机字符串
*/
private static final String INT_TEMP = "0123456789";
private static final String STR_TEMP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final String ALL_TEMP = INT_TEMP + STR_TEMP;
private static final Random RANDOM = new Random();
/**
* 生成的随机数类型
*/
public enum RandomType {
/**
* 整数
*/
INT,
/**
* 字符串
*/
STRING,
/**
* 所有类型
*/
ALL
}
/** /**
* 随机数生成 * 随机数生成
* *
@ -170,7 +157,6 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
return ""; return "";
} }
public static String[] shortUrl(String url) { public static String[] shortUrl(String url) {
// 可以自定义生成 MD5 加密字符传前的混合 KEY // 可以自定义生成 MD5 加密字符传前的混合 KEY
String key = "alexis"; String key = "alexis";
@ -208,8 +194,10 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
return resUrl; return resUrl;
} }
/** /**
* MD5加密(32位大写) * MD5加密(32位大写)
*
* @param src * @param src
* @return * @return
*/ */
@ -235,4 +223,55 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
return ""; return "";
} }
} }
/**
* 全地址去除省市区保留详细地址
* @param fullAddress 比如广西壮族自治区贵港市桂平市西山镇新安街粤桂花城1102号 -> 西山镇新安街粤桂花城1102号
* @return
*/
public static String removeProvinceCityDistrict(String fullAddress) {
if (StrUtil.isBlank(fullAddress)) {
return "";
}
// 使用正则表达式匹配省市区信息
Pattern pattern = Pattern.compile("(.*?省|.*?自治区)?(.*?市|.*?自治州)?(.*?区|.*?县|.*?市辖区|.*?市)?");
Matcher matcher = pattern.matcher(fullAddress);
if (!matcher.find()) {
return fullAddress;
}
if (matcher.group(1) != null) {
fullAddress = fullAddress.replace(matcher.group(1), "");
}
if (matcher.group(2) != null) {
fullAddress = fullAddress.replace(matcher.group(2), "");
}
if (matcher.group(3) != null) {
fullAddress = fullAddress.replace(matcher.group(3), "");
}
return fullAddress;
}
/**
* 生成的随机数类型
*/
public enum RandomType {
/**
* 整数
*/
INT,
/**
* 字符串
*/
STRING,
/**
* 所有类型
*/
ALL
}
} }

6
mall-shop/README.MD Normal file
View File

@ -0,0 +1,6 @@
项目备份录
account_user_bind_connect 用户手机、邮件、微博、QQ、微信绑定表
admin_base_protocol
admin_rights_base
权限赋值的表

View File

@ -8370,6 +8370,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
// 顺丰同城给的测试店铺id // 顺丰同城给的测试店铺id
String shopId = "3243279847393"; String shopId = "3243279847393";
//3269768224353 到时启用这个正式店铺 type:便利店
Integer businessType = 6;// 生鲜分类 Integer businessType = 6;// 生鲜分类
if (enable_sf_express.equals(CommonConstant.Enable)) {//开启正式配送服务的时候 if (enable_sf_express.equals(CommonConstant.Enable)) {//开启正式配送服务的时候
// 顺丰同城业务员给的店铺id // 顺丰同城业务员给的店铺id
@ -8431,6 +8432,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
SFOrderShopReq shop = new SFOrderShopReq(); SFOrderShopReq shop = new SFOrderShopReq();
SFOrderReceiveReq receive = new SFOrderReceiveReq(); SFOrderReceiveReq receive = new SFOrderReceiveReq();
if (enable_sf_express.equals(CommonConstant.Enable)) {//开启正式配送服务的时候 if (enable_sf_express.equals(CommonConstant.Enable)) {//开启正式配送服务的时候
// 店铺信息发货人信息 // 店铺信息发货人信息
Pair<Boolean, StandardAddressDTO> pairShopAddr = shopStoreBaseService.checkStoreAddress(shopStoreBase); Pair<Boolean, StandardAddressDTO> pairShopAddr = shopStoreBaseService.checkStoreAddress(shopStoreBase);
shop.setShop_name(shopStoreBase.getStore_name()); shop.setShop_name(shopStoreBase.getStore_name());
@ -8438,6 +8440,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
shop.setShop_address(pairShopAddr.getSecond().getFullAddress()); shop.setShop_address(pairShopAddr.getSecond().getFullAddress());
shop.setShop_lng(pairShopAddr.getSecond().getLongitude()); shop.setShop_lng(pairShopAddr.getSecond().getLongitude());
shop.setShop_lat(pairShopAddr.getSecond().getLatitude()); shop.setShop_lat(pairShopAddr.getSecond().getLatitude());
// 收货人信息 // 收货人信息
Pair<Boolean, StandardAddressDTO> pairReceiveAddr = shopOrderDeliveryAddressService.checkAddress(shopOrderDeliveryAddress); Pair<Boolean, StandardAddressDTO> pairReceiveAddr = shopOrderDeliveryAddressService.checkAddress(shopOrderDeliveryAddress);
receive.setUser_name(shopOrderDeliveryAddress.getDa_name()); receive.setUser_name(shopOrderDeliveryAddress.getDa_name());
@ -8445,6 +8448,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
receive.setUser_address(pairReceiveAddr.getSecond().getFullAddress()); receive.setUser_address(pairReceiveAddr.getSecond().getFullAddress());
receive.setUser_lng(pairReceiveAddr.getSecond().getLongitude()); receive.setUser_lng(pairReceiveAddr.getSecond().getLongitude());
receive.setUser_lat(pairReceiveAddr.getSecond().getLatitude()); receive.setUser_lat(pairReceiveAddr.getSecond().getLatitude());
} else { } else {
// 店铺信息发货人信息 // 店铺信息发货人信息
shop.setShop_name("顺丰同城开放平台"); shop.setShop_name("顺丰同城开放平台");

View File

@ -3,6 +3,7 @@ package com.suisung.mall.shop.order.service.impl;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.suisung.mall.common.modules.order.ShopOrderDeliveryAddress; import com.suisung.mall.common.modules.order.ShopOrderDeliveryAddress;
import com.suisung.mall.common.pojo.dto.StandardAddressDTO; import com.suisung.mall.common.pojo.dto.StandardAddressDTO;
import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.order.mapper.ShopOrderDeliveryAddressMapper; import com.suisung.mall.shop.order.mapper.ShopOrderDeliveryAddressMapper;
import com.suisung.mall.shop.order.service.ShopOrderDeliveryAddressService; import com.suisung.mall.shop.order.service.ShopOrderDeliveryAddressService;
@ -58,7 +59,7 @@ public class ShopOrderDeliveryAddressServiceImpl extends BaseServiceImpl<ShopOrd
sb.append(shopOrderDeliveryAddress.getDa_county()); sb.append(shopOrderDeliveryAddress.getDa_county());
} }
if(StrUtil.isNotBlank(shopOrderDeliveryAddress.getDa_address())){ if(StrUtil.isNotBlank(shopOrderDeliveryAddress.getDa_address())){
sb.append(shopOrderDeliveryAddress.getDa_address()); sb.append(StringUtils.removeProvinceCityDistrict(shopOrderDeliveryAddress.getDa_address()));
} }

View File

@ -8,18 +8,27 @@
package com.suisung.mall.shop.sfexpress.controller.api; package com.suisung.mall.shop.sfexpress.controller.api;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.pojo.res.SFExpressApiRes; import com.suisung.mall.common.pojo.res.SFExpressApiRes;
import com.suisung.mall.common.utils.SseEmitterUtil;
import com.suisung.mall.shop.sfexpress.service.SFExpressApiService; import com.suisung.mall.shop.sfexpress.service.SFExpressApiService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArrayList;
@Api(tags = "顺丰同城Api端") @Api(tags = "顺丰同城Api端")
@RestController @RestController
@RequestMapping("/shop/sf-express") @RequestMapping("/shop/sf-express")
public class SFExpressApiController { public class SFExpressApiController {
private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();
@Autowired @Autowired
private SFExpressApiService sfExpressApiService; private SFExpressApiService sfExpressApiService;

View File

@ -8,15 +8,15 @@
package com.suisung.mall.shop.sfexpress.controller.mobile; package com.suisung.mall.shop.sfexpress.controller.mobile;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.pojo.res.SFExpressApiRes; import com.suisung.mall.common.pojo.res.SFExpressApiRes;
import com.suisung.mall.common.utils.SseEmitterUtil;
import com.suisung.mall.shop.sfexpress.service.SFExpressApiService; import com.suisung.mall.shop.sfexpress.service.SFExpressApiService;
import com.suisung.mall.shop.store.service.ShopStoreSfOrderService; import com.suisung.mall.shop.store.service.ShopStoreSfOrderService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap; import java.util.HashMap;
@ -87,4 +87,27 @@ public class SFExpressController {
params.put("order_id", shopStoreSfOrderService.getSfOrderIdByShopOrderId(orderId)); params.put("order_id", shopStoreSfOrderService.getSfOrderIdByShopOrderId(orderId));
return sfExpressApiService.riderViewV2(params); return sfExpressApiService.riderViewV2(params);
} }
/**
* 顺丰同城订单状态监听 SSE 服务
* @param channel
* @return
*/
@CrossOrigin(allowCredentials = "true")
@GetMapping(value = "/order/status/listening", produces = "text/event-stream;charset=UTF-8")
public SseEmitter sfOrderStatusSseConn(@RequestParam(value = "channel", required = true) String channel) {
return SseEmitterUtil.connect(channel);
}
/**
* 关闭顺丰同城订单状态监听 SSE 服务
* @param channel
* @return
*/
@CrossOrigin(allowCredentials = "true")
@GetMapping(value ="/order/status/listening/close")
public CommonResult sfOrderStatusSseClose(@RequestParam(name = "channel") String channel) {
SseEmitterUtil.removeChannel(channel);
return CommonResult.success();
}
} }

View File

@ -10,18 +10,22 @@ package com.suisung.mall.shop.sfexpress.service.impl;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.api.StateCode; import com.suisung.mall.common.api.StateCode;
import com.suisung.mall.common.constant.SFExpressConstant; import com.suisung.mall.common.constant.SFExpressConstant;
import com.suisung.mall.common.domain.UserDto;
import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.exception.ApiException;
import com.suisung.mall.common.modules.store.ShopStoreSfOrder; import com.suisung.mall.common.modules.store.ShopStoreSfOrder;
import com.suisung.mall.common.pojo.req.*; import com.suisung.mall.common.pojo.req.*;
import com.suisung.mall.common.pojo.res.SFExpressApiRes; import com.suisung.mall.common.pojo.res.SFExpressApiRes;
import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.I18nUtil;
import com.suisung.mall.common.utils.JsonUtil; import com.suisung.mall.common.utils.JsonUtil;
import com.suisung.mall.common.utils.SseEmitterUtil;
import com.suisung.mall.shop.order.service.ShopOrderBaseService; import com.suisung.mall.shop.order.service.ShopOrderBaseService;
import com.suisung.mall.shop.order.service.ShopOrderInfoService; import com.suisung.mall.shop.order.service.ShopOrderInfoService;
import com.suisung.mall.shop.sfexpress.service.SFExpressApiService; import com.suisung.mall.shop.sfexpress.service.SFExpressApiService;
@ -42,6 +46,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
@Service @Service
public class SFExpressApiServiceImpl implements SFExpressApiService { public class SFExpressApiServiceImpl implements SFExpressApiService {
@ -235,7 +241,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
public SFExpressApiRes cancelOrder(Map<String, Object> params) { public SFExpressApiRes cancelOrder(Map<String, Object> params) {
// TODO 检验用户权限 // TODO 检验用户权限
if (params == null || params.get("order_id") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -306,7 +312,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
*/ */
@Override @Override
public SFExpressApiRes addOrderGratuityFee(Map<String, Object> params) { public SFExpressApiRes addOrderGratuityFee(Map<String, Object> params) {
if (params == null || params.get("order_id") == null || params.get("gratuity_fee") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id")) || params.get("gratuity_fee") == null) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -334,7 +340,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
*/ */
@Override @Override
public SFExpressApiRes reminderOrder(Map<String, Object> params) { public SFExpressApiRes reminderOrder(Map<String, Object> params) {
if (params == null || params.get("order_id") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -364,7 +370,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
*/ */
@Override @Override
public SFExpressApiRes listOrderFeed(Map<String, Object> params) { public SFExpressApiRes listOrderFeed(Map<String, Object> params) {
if (params == null || params.get("order_id") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -392,7 +398,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
*/ */
@Override @Override
public SFExpressApiRes riderLatestPosition(Map<String, Object> params) { public SFExpressApiRes riderLatestPosition(Map<String, Object> params) {
if (params == null || params.get("order_id") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -420,7 +426,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
*/ */
@Override @Override
public SFExpressApiRes riderViewV2(Map<String, Object> params) { public SFExpressApiRes riderViewV2(Map<String, Object> params) {
if (params == null || params.get("order_id") == null) { if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
return new SFExpressApiRes().fail(1003, "请求参数有误!"); return new SFExpressApiRes().fail(1003, "请求参数有误!");
} }
@ -564,11 +570,15 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
} }
success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), orderStatus, orderIsOutStatus, orderIsShippedStatus); success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), orderStatus, orderIsOutStatus, orderIsShippedStatus);
if (!success) { if (!success) {
throw new ApiException(I18nUtil._("状态处理失败!")); throw new ApiException(I18nUtil._("状态处理失败!"));
} }
// 状态更改之后 SSE 监听服务发送更改的数据
// logger.debug("准备发送SSE消息...");
SseEmitterUtil.sendMessage(shopStoreSfOrder.getSf_order_id(), jsonData);
// logger.debug("向 SSE 通道 {} 发送了:{}", shopStoreSfOrder.getSf_order_id(), jsonData);
return new SFExpressApiRes().success("success"); return new SFExpressApiRes().success("success");
} }

View File

@ -1,9 +1,11 @@
package com.suisung.mall.shop.store.controller.admin; package com.suisung.mall.shop.store.controller.admin;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.modules.store.ShopStorePrinter; import com.suisung.mall.common.modules.store.ShopStorePrinter;
import com.suisung.mall.common.utils.PositionUtil; import com.suisung.mall.common.utils.PositionUtil;
import com.suisung.mall.common.utils.SseEmitterUtil;
import com.suisung.mall.shop.store.service.ShopStoreEmployeeService; import com.suisung.mall.shop.store.service.ShopStoreEmployeeService;
import com.suisung.mall.shop.store.service.ShopStorePrinterService; import com.suisung.mall.shop.store.service.ShopStorePrinterService;
import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService; import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService;
@ -13,10 +15,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,7 +47,10 @@ public class ShopStorePrinterController {
// BigDecimal s = new BigDecimal(2.50).setScale(2, RoundingMode.HALF_UP); // BigDecimal s = new BigDecimal(2.50).setScale(2, RoundingMode.HALF_UP);
// List<Integer> list = shopStoreEmployeeService.selectEmployeeByStoreId(3,"店铺管理员"); // List<Integer> list = shopStoreEmployeeService.selectEmployeeByStoreId(3,"店铺管理员");
return CommonResult.success(data); String userId = "1";
SseEmitterUtil.sendMessage(userId, JSONUtil.toJsonStr(data));
return CommonResult.success(1);
} }
@ApiOperation(value = "测试打印模版消息", notes = "测试打印模版消息") @ApiOperation(value = "测试打印模版消息", notes = "测试打印模版消息")

View File

@ -1,10 +1,7 @@
package com.suisung.mall.shop.store.controller.mobile; package com.suisung.mall.shop.store.controller.mobile;
import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.pojo.dto.ShopStoreSameCityTransportBaseDTO;
import com.suisung.mall.common.utils.JsonUtil;
import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService; import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService;
import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -14,17 +11,14 @@ import javax.annotation.Resource;
@Api(tags = "同城配送运费设置控制器") @Api(tags = "同城配送运费设置控制器")
@RestController @RestController
@RequestMapping("/mobile/shop/store/same-city-transport") @RequestMapping("/mobile/shop/store/same-city-transport")
public class ShopStoreSameCityTransportBaseController { public class ShopStoreSameCityTransportBaseMobileController {
@Resource @Resource
private ShopStoreSameCityTransportBaseService transportBaseService; private ShopStoreSameCityTransportBaseService transportBaseService;
@Resource
private ShopStoreSameCityTransportService transportService;
@ApiOperation(value = "下单前检测同城订单配送是否符合要求", notes = "下单前检测同城订单配送是否符合要求") @ApiOperation(value = "下单前检测同城订单配送是否符合要求", notes = "下单前检测同城订单配送是否符合要求")
@RequestMapping(value = "/check/same-city/delivery", method = {RequestMethod.POST}) @RequestMapping(value = "/check/same-city/delivery", method = {RequestMethod.POST})
public CommonResult checkSameCityDelivery(@RequestBody ShopStoreSameCityTransportBaseDTO transportBaseDTO) { public CommonResult checkSameCityDelivery(@RequestParam(name = "store_id", defaultValue = "0") Integer storeId) {
return transportBaseService.ShopStoreSameCityTransportBaseDetail(); return transportBaseService.ShopStoreSameCityTransportBaseDetail();
} }
} }

View File

@ -40,6 +40,7 @@ import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService
import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportService; import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.util.Pair; import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -53,6 +54,7 @@ import java.util.List;
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
@Lazy
@Service @Service
public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<ShopStoreSameCityTransportBaseMapper, ShopStoreSameCityTransportBase> implements ShopStoreSameCityTransportBaseService { public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<ShopStoreSameCityTransportBaseMapper, ShopStoreSameCityTransportBase> implements ShopStoreSameCityTransportBaseService {
@ -61,8 +63,6 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
private ShopStoreSameCityTransportService shopStoreSameCityTransportService; private ShopStoreSameCityTransportService shopStoreSameCityTransportService;
@Resource @Resource
private ShopStoreBaseService shopStoreBaseService; private ShopStoreBaseService shopStoreBaseService;
@Resource
private ShopChainUserController user;
/** /**
* 获取同城配送设置详情信息 * 获取同城配送设置详情信息
@ -381,24 +381,25 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "同城配送缺少店铺基本信息。"); return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "同城配送缺少店铺基本信息。");
} }
String storeName = storeBase.getStore_name();
String storeLng = storeBase.getStore_longitude(); String storeLng = storeBase.getStore_longitude();
String storeLat = storeBase.getStore_latitude(); String storeLat = storeBase.getStore_latitude();
if (StrUtil.isBlank(storeLng) || StrUtil.isBlank(storeLat)) { if (StrUtil.isBlank(storeLng) || StrUtil.isBlank(storeLat)) {
logger.error("同城配送费计算:店铺经纬度为空"); logger.error("{}同城配送费计算:店铺经纬度为空", storeName);
if (canThrow) { if (canThrow) {
throw new ApiException(I18nUtil._("无法获取店铺的具体位置,请联系商家。")); throw new ApiException(I18nUtil._("无法获取" + storeName + "的具体位置,请联系商家。"));
} }
return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "无法获取店铺的具体位置,请联系商家。"); return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "无法获取" + storeName + "的具体位置,请联系商家。");
} }
// 获取基础运费设置记录 // 获取基础运费设置记录
ShopStoreSameCityTransportBase transportBase = getShopStoreSameCityTransportBaseById(storeId); ShopStoreSameCityTransportBase transportBase = getShopStoreSameCityTransportBaseById(storeId);
if (transportBase == null) { if (transportBase == null) {
logger.error("同城配送费计算:无法获取基础运费设置记录。"); logger.error("{}同城配送费计算:无法获取基础运费设置记录。", storeName);
if (canThrow) { if (canThrow) {
throw new ApiException(I18nUtil._("商家尚未完成同城配送设置。")); throw new ApiException(I18nUtil._("商家尚未完成同城配送设置。"));
} }
return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "商家尚未完成同城配送设置。"); return new SameCityDeliveryFeeRespDTO(false, false, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, storeName + "尚未完成同城配送设置。");
} }
if (transportBase.getDistance_base() == null) { if (transportBase.getDistance_base() == null) {
@ -418,7 +419,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
} }
// 实际配送距离单位米 // 实际配送距离单位米
Integer distance = distanceD.intValue(); Integer distance = distanceD.intValue();
logger.debug("下单时,店铺与收货地址两地,经纬度:{},{}|{},{} 距离:{} 米", storeLng, storeLat, orderLongitude, orderLatitude, distance); logger.debug(storeName + "下单时,店铺与收货地址两地,经纬度:{},{}|{},{} 距离:{} 米", storeLng, storeLat, orderLongitude, orderLatitude, distance);
// ### 基础配送费计算 // ### 基础配送费计算
BigDecimal deliveryBaseFee = transportBase.getDelivery_base_fee(); BigDecimal deliveryBaseFee = transportBase.getDelivery_base_fee();
@ -456,11 +457,10 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
deliveryBaseFee = deliveryBaseFee.add(transportBase.getWeight_increase_fee().multiply(times)); deliveryBaseFee = deliveryBaseFee.add(transportBase.getWeight_increase_fee().multiply(times));
} }
logger.debug("下单时,店铺与收货地址超出基础距离和重量:额外增加 {} 元运费。", deliveryBaseFee); logger.debug(storeName + "下单时,店铺与收货地址超出基础距离和重量:额外增加 {} 元运费。", deliveryBaseFee);
// #### 基础配送费计算完毕 // #### 基础配送费计算完毕
// 优惠减免的配送费重要 // 优惠减免的配送费重要
BigDecimal reduceDeliveryFee = BigDecimal.ZERO; BigDecimal reduceDeliveryFee = BigDecimal.ZERO;
@ -480,7 +480,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
for (ShopStoreSameCityTransport transport : transportList) { for (ShopStoreSameCityTransport transport : transportList) {
DeliveryFeeResultDTO deliveryFeeResultDTO = new DeliveryFeeResultDTO(); DeliveryFeeResultDTO deliveryFeeResultDTO = new DeliveryFeeResultDTO();
deliveryFeeResultDTO.setId(transport.getTransport_id()); deliveryFeeResultDTO.setId(transport.getTransport_id());
logger.debug("下单时,店铺与收货地址的距离是{}米,最大配送范围是{}米以内", distance, transport.getMax_delivery_radius()); logger.debug(storeName + "下单时,店铺与收货地址的距离是{}米,最大配送范围是{}米以内", distance, transport.getMax_delivery_radius());
// 判断订单距离在不在配送范围内 // 判断订单距离在不在配送范围内
if (transport.getMax_delivery_radius() < distance) { if (transport.getMax_delivery_radius() < distance) {
@ -488,7 +488,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
// 订单距离不在配送范围内返回不送了 // 订单距离不在配送范围内返回不送了
deliveryFeeResultDTO.setLevel(2); deliveryFeeResultDTO.setLevel(2);
deliveryFeeResultDTO.setDistancePassed(false); deliveryFeeResultDTO.setDistancePassed(false);
deliveryFeeResultDTO.setDistanceReason("订单不在配送范围内,订单无法配送。"); deliveryFeeResultDTO.setDistanceReason(storeName + "订单不在配送范围内,订单无法配送。");
noPassed.add(deliveryFeeResultDTO); noPassed.add(deliveryFeeResultDTO);
@ -502,7 +502,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
deliveryFeeResultDTO.setMoneyPassed(false); deliveryFeeResultDTO.setMoneyPassed(false);
BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderProductAmount); BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderProductAmount);
deliveryFeeResultDTO.setDiffMoney(diffMoney); deliveryFeeResultDTO.setDiffMoney(diffMoney);
deliveryFeeResultDTO.setMoneyReason(String.format("商品原价金额还差%.2f元,才满足配送条件,请检查订单。", diffMoney)); deliveryFeeResultDTO.setMoneyReason(String.format("%s商品原价金额还差%.2f元,才满足配送条件,请检查订单。", storeName, diffMoney));
} else { } else {
deliveryFeeResultDTO.setMoneyPassed(true); deliveryFeeResultDTO.setMoneyPassed(true);
} }
@ -513,7 +513,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
deliveryFeeResultDTO.setMoneyPassed(false); deliveryFeeResultDTO.setMoneyPassed(false);
BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderDiscountAmount); BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderDiscountAmount);
deliveryFeeResultDTO.setDiffMoney(diffMoney); deliveryFeeResultDTO.setDiffMoney(diffMoney);
deliveryFeeResultDTO.setMoneyReason(String.format("订单折后金额还差%.2f元,才满足配送条件,请检查订单。", diffMoney)); deliveryFeeResultDTO.setMoneyReason(String.format("%s订单折后金额还差%.2f元,才满足配送条件,请检查订单。", storeName, diffMoney));
} else { } else {
deliveryFeeResultDTO.setMoneyPassed(true); deliveryFeeResultDTO.setMoneyPassed(true);
} }
@ -524,7 +524,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
deliveryFeeResultDTO.setMoneyPassed(false); deliveryFeeResultDTO.setMoneyPassed(false);
BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderDiscountAmount); BigDecimal diffMoney = transport.getMin_delivery_amount().subtract(orderDiscountAmount);
deliveryFeeResultDTO.setDiffMoney(diffMoney); deliveryFeeResultDTO.setDiffMoney(diffMoney);
deliveryFeeResultDTO.setMoneyReason(String.format("应支付订单金额还差%.2f元,才满足配送条件,请检查订单。", diffMoney)); deliveryFeeResultDTO.setMoneyReason(String.format("%s订单应支付金额还差%.2f元,才满足配送条件,请检查订单。", storeName, diffMoney));
} else { } else {
deliveryFeeResultDTO.setMoneyPassed(true); deliveryFeeResultDTO.setMoneyPassed(true);
} }
@ -557,12 +557,12 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
} }
logger.debug("下单时,根据商家运费设置规则减免{}元运费", reduceDeliveryFee); logger.debug(storeName + "下单时,根据商家运费设置规则减免{}元运费", reduceDeliveryFee);
logger.debug("下单时,不符合规则的:\n {}\n符合规则的:{}", JSONUtil.toJsonStr(noPassed), JSONUtil.toJsonStr(passed)); logger.debug(storeName + "下单时,不符合规则的:\n {}\n符合规则的:{}", JSONUtil.toJsonStr(noPassed), JSONUtil.toJsonStr(passed));
if (passed.size() == 0 && noPassed.size() > 0) { if (passed.size() == 0 && noPassed.size() > 0) {
// 没有一个满足起送距离和起送金额的规则订单 // 没有一个满足起送距离和起送金额的规则订单
String canNotDeliveryReason="订单不在配送范围内或订单未达起送金额,请检查!"; String canNotDeliveryReason = storeName + "订单不在配送范围内或未达起送金额,请检查!";
// 根据 level 优先级升序排序 // 根据 level 优先级升序排序
noPassed = CollUtil.sort(noPassed, new FieldsComparator<>(DeliveryFeeResultDTO.class, "level", "diffMoney")); noPassed = CollUtil.sort(noPassed, new FieldsComparator<>(DeliveryFeeResultDTO.class, "level", "diffMoney"));