parent
68027b9f16
commit
dbf2a43924
13
README.md
13
README.md
|
@ -30,19 +30,26 @@
|
|||
|
||||
# 演示
|
||||
|
||||
> 艿艿:目前的开发者,都是后端出身。所以,一帮没有审美自觉的人,撸出来的前端界面,可能是东半球倒数第二难看。
|
||||
>
|
||||
> 迫切希望,有前端能力不错的小伙伴,加入我们,一起来完善「一个商城」。
|
||||
>
|
||||
> 啊啊啊!我好像做店铺装修功能。
|
||||
|
||||
## H5 商城
|
||||
|
||||
[体验传送门](http://h5.shop.iocoder.cn:18099)
|
||||
|
||||
TODO 此处应有一个演示的装逼 GIF 图。
|
||||
![手残艿艿的 GIF 图](https://cdn.sinaimg.cn.52ecy.cn/large/005BYqpgly1g34hgm6fyhg31hc0u0nph.jpg)
|
||||
|
||||
## 管理后台
|
||||
|
||||
[体验传送门](http://admin.shop.iocoder.cn:18099)
|
||||
|
||||
TODO 暂时不提供管理后台的账号密码,等后面提供。
|
||||
* 账号:yudaoyuanma
|
||||
* 密码:yudaoyuanma
|
||||
|
||||
TODO 此处应有一个演示的装逼 GIF 图。
|
||||
![](http://ww1.sinaimg.cn/large/98a7a01cgy1g34j9b2ktqg21hc0u01lf.gif)
|
||||
|
||||
## 其它演示
|
||||
|
||||
|
|
|
@ -35,4 +35,8 @@ public class StringUtil {
|
|||
return org.apache.commons.lang3.StringUtils.substring(str, start);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(StringUtil.split("cn.iocoder.mall.order.api.OrderService#updatePaySuccess#1.0.0", "#").size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package cn.iocoder.mall.spring.boot;
|
|
@ -2,6 +2,7 @@ package cn.iocoder.mall.spring.boot.web;
|
|||
|
||||
import cn.iocoder.common.framework.constant.MallConstants;
|
||||
import cn.iocoder.common.framework.servlet.CorsFilter;
|
||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminDemoInterceptor;
|
||||
import cn.iocoder.mall.spring.boot.web.interceptor.AccessLogInterceptor;
|
||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
||||
import cn.iocoder.mall.spring.boot.web.handler.GlobalExceptionHandler;
|
||||
|
@ -34,6 +35,12 @@ public class AdminMVCAutoConfiguration implements WebMvcConfigurer {
|
|||
return new AdminSecurityInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AdminDemoInterceptor.class)
|
||||
public AdminDemoInterceptor adminDemoInterceptor() {
|
||||
return new AdminDemoInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(GlobalResponseBodyHandler.class)
|
||||
public GlobalResponseBodyHandler globalReturnValueHandler() {
|
||||
|
@ -50,6 +57,7 @@ public class AdminMVCAutoConfiguration implements WebMvcConfigurer {
|
|||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(adminAccessLogInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**");
|
||||
registry.addInterceptor(adminSecurityInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**");
|
||||
registry.addInterceptor(adminDemoInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**");
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -29,4 +29,6 @@
|
|||
- 用户相关
|
||||
- [x] 登陆
|
||||
- [x] 注册
|
||||
- [ ] 个人信息
|
||||
- [x] 个人信息
|
||||
- [ ] 手机改绑
|
||||
- [ ] 微信登陆
|
||||
|
|
|
@ -10,17 +10,25 @@
|
|||
- [ ] 支付单 20% 【待认领】
|
||||
- [ ] 退款单 20% 【待认领】
|
||||
- TODO 需要补充
|
||||
- [ ] 店铺装修【迫切需要靠谱前端一起做】
|
||||
- [ ] H5 装修
|
||||
- [ ] 小程序装修
|
||||
- [ ] 自定义页面
|
||||
- [ ] 商品管理
|
||||
- [x] 发布商品
|
||||
- [x] 商品列表
|
||||
- [x] 展示类目
|
||||
- [ ] 品牌管理【开发中 @黑子】
|
||||
- [ ] 商品标签
|
||||
- [ ] 订单管理
|
||||
- [ ] 销售单 开发中
|
||||
- [ ] 售后单 开发中
|
||||
- [x] 销售单
|
||||
- [x] 售后单
|
||||
- [ ] 订单评价【开发中 @wang171776704】
|
||||
- [ ] 会员管理
|
||||
- [ ] 会员资料 20%【待认领】
|
||||
- [ ] 会员等级
|
||||
- [ ] 会员积分
|
||||
- [ ] 用户标签
|
||||
- TODO 需要补充
|
||||
- [ ] 营销管理
|
||||
- [x] 首页广告
|
||||
|
@ -30,6 +38,13 @@
|
|||
- [ ] 满减送 20% 【待认领】
|
||||
- [ ] 限制折扣 20% 【待认领】
|
||||
- [ ] 多人拼团【待认领】
|
||||
- [ ] 积分商城
|
||||
- [ ] 问卷调查
|
||||
- [ ] 幸运大转盘
|
||||
- [ ] 分销管理
|
||||
- [ ] 分销设置
|
||||
- [ ] 分销员管理
|
||||
- [ ] 提现管理
|
||||
- [ ] 系统管理
|
||||
- [x] 员工管理
|
||||
- [x] 角色管理 <!--【前端页面需要细化下】-->
|
||||
|
|
|
@ -229,11 +229,11 @@ service.interceptors.response.use(
|
|||
|
||||
// TODO token 过期
|
||||
// TODO 需要拿 refresh token 置换
|
||||
if (code === 1001001011 // 访问令牌不存在
|
||||
|| code === 1001001013 // 访问令牌已失效
|
||||
|| code === 1001001021 // 刷新令牌不存在
|
||||
|| code === 1001001022 // 刷新令牌已过期
|
||||
|| code === 1001001023) { // 刷新令牌已失效
|
||||
if (code === 1002001011 // 访问令牌不存在
|
||||
|| code === 1002001013 // 访问令牌已失效
|
||||
|| code === 1002001017 // 刷新令牌不存在
|
||||
|| code === 1002001018 // 刷新令牌已过期
|
||||
|| code === 1002001019) { // 刷新令牌已失效
|
||||
Dialog.confirm({
|
||||
title: '系统提示',
|
||||
message: res.message,
|
||||
|
@ -249,7 +249,7 @@ service.interceptors.response.use(
|
|||
}
|
||||
}
|
||||
});
|
||||
} else if (code === 1001001012) { // 访问令牌已过期
|
||||
} else if (code === 1002001012) { // 访问令牌已过期
|
||||
return refreshToken(response);
|
||||
} else {
|
||||
Dialog.alert({
|
||||
|
|
|
@ -50,21 +50,6 @@
|
|||
<div class="category-div">
|
||||
<!--<h4>热门分类</h4>-->
|
||||
<ul>
|
||||
<!--<li><a ><img src="//img11.360buyimg.com/focus/s140x140_jfs/t21388/146/237407622/26923/221da1b3/5b054fedN2ba90518.jpg"><span>手机</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t20128/208/216721929/9242/472993da/5b05522dNa2aae1bb.png"><span>耳机</span></a></li>-->
|
||||
<!--<li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t21655/83/2186874549/15932/c273d29b/5b48802aN13fe73de.png"><span>剃须刀</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t21715/149/246679831/16257/ddbf2036/5b0565a7N8dbc0017.png"><span>路由器</span></a></li>-->
|
||||
<!--<li><a ><img src="//img14.360buyimg.com/focus/s140x140_jfs/t1/4478/16/633/36008/5b923503E39b9dfa9/13b099f187576d8c.png"><span>月饼</span></a></li>-->
|
||||
<!--<li><a ><img src="//img10.360buyimg.com/focus/s140x140_jfs/t1/1410/32/643/38009/5b9236b2Eb02fbf02/1e7de6987578dcdd.jpg" ><span>牛奶</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t1/4674/14/665/25245/5b9236bbE088d5efb/6c7c2f9857736c65.jpg"><span>男士内裤</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t1/1710/26/666/26147/5b9236c3E5fd1cd42/86c6bca8f4fe1efa.png"><span>小米8</span></a></li>-->
|
||||
<!--<li><a ><img src="//img11.360buyimg.com/focus/s140x140_jfs/t1/3653/6/655/42593/5b9236caEfef6235b/9e118f12705f52bb.png"><span>大闸蟹</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t23881/349/2204372862/9923/4c62864a/5b7693eeNf6883734.png"><span>三只松鼠</span></a></li>-->
|
||||
<!--<li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t24253/294/2182777138/4059/429945c9/5b76990bNde226fbc.png"><span>充电宝</span></a></li>-->
|
||||
<!--<li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t22051/318/235303191/9297/c5ea2761/5b055000N410a7553.png"><span>空调</span></a></li>-->
|
||||
<!--<li><a ><img src="//img10.360buyimg.com/focus/s140x140_jfs/t19960/243/653029866/38879/91bb398b/5b055555N9245f8aa.jpg"><span>电饭煲</span></a></li>-->
|
||||
<!--<li><a ><img src="//img12.360buyimg.com/focus/s140x140_jfs/t1/345/33/944/5582/5b9236d2E62d8da2e/99f72d51b8f195ed.jpg"><span>电话手表</span></a></li>-->
|
||||
<!--<li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t1/1446/14/631/8500/5b9237e5E0d1f9e16/b1a627b92323b5ed.png"><span>华为</span></a></li>-->
|
||||
<li v-for="category in childCategories">
|
||||
<router-link :to="'/products/list?title=' + activeCategory.name + '&cidFirst=' + activeCategory.id + '&cidSecond=' + category.id">
|
||||
<img :src="category.picUrl" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<headerNav title="个人信息"/>
|
||||
<van-cell-group>
|
||||
<van-cell-group title="基础资料">
|
||||
<!--<van-cell title="修改个人信息" is-link />-->
|
||||
<!--<van-cell title="修改登录密码" is-link />-->
|
||||
<!--<van-cell title="修改绑定手机" is-link />-->
|
||||
|
@ -14,6 +14,10 @@
|
|||
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group title="密保资料">
|
||||
<van-cell title="手机号" :value="user.mobile" />
|
||||
</van-cell-group>
|
||||
|
||||
<!-- 昵称修改弹出 -->
|
||||
<van-dialog
|
||||
v-model="showNicknameDialog"
|
||||
|
@ -83,4 +87,4 @@ export default {
|
|||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -9,7 +9,6 @@ import cn.iocoder.mall.order.application.convert.OrderReturnConvert;
|
|||
import cn.iocoder.mall.order.application.po.admin.OrderReturnQueryPO;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -26,8 +25,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
@Api("订单退货(admins api)")
|
||||
public class AdminOrderReturnController {
|
||||
|
||||
@Autowired
|
||||
@Reference(validation = "true")
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}")
|
||||
private OrderReturnService orderReturnService;
|
||||
|
||||
@GetMapping("list")
|
||||
|
|
|
@ -5,7 +5,9 @@ import cn.iocoder.mall.order.api.OrderService;
|
|||
import cn.iocoder.mall.order.api.bo.OrderItemBO;
|
||||
import cn.iocoder.mall.order.api.bo.OrderPageBO;
|
||||
import cn.iocoder.mall.order.api.bo.OrderRecipientBO;
|
||||
import cn.iocoder.mall.order.api.dto.*;
|
||||
import cn.iocoder.mall.order.api.dto.OrderItemUpdateDTO;
|
||||
import cn.iocoder.mall.order.api.dto.OrderLogisticsUpdateDTO;
|
||||
import cn.iocoder.mall.order.api.dto.OrderQueryDTO;
|
||||
import cn.iocoder.mall.order.application.convert.OrderConvertAPP;
|
||||
import cn.iocoder.mall.order.application.convert.OrderDeliveryConvert;
|
||||
import cn.iocoder.mall.order.application.po.admin.OrderDeliverPO;
|
||||
|
@ -15,7 +17,6 @@ import cn.iocoder.mall.order.application.po.admin.OrderPageQueryPO;
|
|||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -29,10 +30,10 @@ import java.util.List;
|
|||
*/
|
||||
@RestController
|
||||
@RequestMapping("admins/order")
|
||||
@Api(value = "订单API(admins)")
|
||||
@Api(value = "订单 API(admins)")
|
||||
public class AdminsOrderController {
|
||||
|
||||
@Reference(validation = "true")
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderService.version}")
|
||||
private OrderService orderService;
|
||||
|
||||
@GetMapping("page")
|
||||
|
|
|
@ -19,6 +19,7 @@ import cn.iocoder.mall.order.application.po.user.OrderCreatePO;
|
|||
import cn.iocoder.mall.order.application.vo.UsersOrderConfirmCreateVO;
|
||||
import cn.iocoder.mall.promotion.api.CouponService;
|
||||
import cn.iocoder.mall.promotion.api.bo.CouponCardAvailableBO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.RequiresLogin;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
@ -41,19 +42,23 @@ import static cn.iocoder.common.framework.vo.CommonResult.success;
|
|||
*/
|
||||
@RestController
|
||||
@RequestMapping("users/order")
|
||||
@Api(description = "用户订单")
|
||||
@Api(description = "用户订单") // TODO FROM 芋艿 to 小范,description 已经废弃啦
|
||||
public class OrderController {
|
||||
|
||||
@Reference(validation = "true")
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}")
|
||||
private OrderService orderService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.provider.CartService.version}")
|
||||
private CartService cartService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}")
|
||||
private DataDictService dataDictService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}")
|
||||
private CouponService couponService;
|
||||
|
||||
@GetMapping("order_page")
|
||||
@RequiresLogin
|
||||
@ApiOperation("订单分页")
|
||||
public CommonResult<OrderPageBO> getOrderPage(@Validated OrderQueryDTO orderQueryDTO) {
|
||||
Integer userId = UserSecurityContextHolder.getContext().getUserId();
|
||||
|
@ -62,6 +67,7 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@PostMapping("create_order")
|
||||
@RequiresLogin
|
||||
@ApiOperation("创建订单")
|
||||
public CommonResult<OrderCreateBO> createOrder(@RequestBody @Validated OrderCreatePO orderCreatePO,
|
||||
HttpServletRequest request) {
|
||||
|
@ -72,6 +78,7 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@PostMapping("create_order_from_cart")
|
||||
@RequiresLogin
|
||||
@ApiOperation("创建订单购物车")
|
||||
public CommonResult<OrderCreateBO> createOrderFromCart(@RequestParam("userAddressId") Integer userAddressId,
|
||||
@RequestParam(value = "couponCardId", required = false) Integer couponCardId,
|
||||
|
@ -99,6 +106,7 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@GetMapping("confirm_create_order")
|
||||
@RequiresLogin
|
||||
@ApiOperation("确认创建订单")
|
||||
public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder(@RequestParam("skuId") Integer skuId,
|
||||
@RequestParam("quantity") Integer quantity,
|
||||
|
@ -118,6 +126,7 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@PostMapping("confirm_receiving")
|
||||
@RequiresLogin
|
||||
@ApiOperation("确认收货")
|
||||
public CommonResult confirmReceiving(@RequestParam("orderId") Integer orderId) {
|
||||
Integer userId = UserSecurityContextHolder.getContext().getUserId();
|
||||
|
@ -125,6 +134,7 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@GetMapping("info")
|
||||
@RequiresLogin
|
||||
@ApiOperation("订单详情")
|
||||
public CommonResult<OrderInfoBO> orderInfo(@RequestParam("orderId") Integer orderId) {
|
||||
Integer userId = UserSecurityContextHolder.getContext().getUserId();
|
||||
|
|
|
@ -35,8 +35,9 @@ import java.util.stream.Collectors;
|
|||
@Api(description = "订单物流信息")
|
||||
public class OrderLogisticsController {
|
||||
|
||||
@Reference(validation = "true")
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderLogisticsService.version}")
|
||||
private OrderLogisticsService orderLogisticsService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}")
|
||||
private DataDictService dataDictService;
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ import java.util.List;
|
|||
@RequestMapping("users/order_return")
|
||||
public class OrderReturnController {
|
||||
|
||||
@Reference(validation = "true")
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}")
|
||||
private OrderReturnService orderReturnService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}")
|
||||
private DataDictService dataDictService;
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import cn.iocoder.mall.order.application.vo.UsersCartDetailVO;
|
|||
import cn.iocoder.mall.order.application.vo.UsersOrderConfirmCreateVO;
|
||||
import cn.iocoder.mall.promotion.api.CouponService;
|
||||
import cn.iocoder.mall.promotion.api.bo.CouponCardAvailableBO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
@ -31,8 +30,10 @@ public class UsersCartController {
|
|||
|
||||
@Reference(validation = "true", version = "${dubbo.provider.CartService.version}")
|
||||
private CartService cartService;
|
||||
@Reference(validation = "true")
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OrderService.version}")
|
||||
private OrderService orderService;
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}")
|
||||
private CouponService couponService;
|
||||
|
||||
|
@ -125,7 +126,6 @@ public class UsersCartController {
|
|||
}
|
||||
|
||||
@GetMapping("/calc_sku_price")
|
||||
@PermitAll
|
||||
public CommonResult<UsersCalcSkuPriceVO> calcSkuPrice(@RequestParam("skuId") Integer skuId) {
|
||||
// 计算 sku 的价格
|
||||
CalcSkuPriceBO calcSkuPrice = cartService.calcSkuPrice(skuId);
|
||||
|
|
|
@ -127,7 +127,7 @@ public interface OrderService {
|
|||
CommonResult updateLogistics(OrderLogisticsUpdateDTO orderLogisticsDTO);
|
||||
|
||||
/**
|
||||
* 删除订单
|
||||
* 删除订单 // TODO FROM 芋艿 to 小范。删除订单,不要使用 deleted 字段,对于用户是删除,实际是隐藏。
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,7 @@ import lombok.experimental.Accessors;
|
|||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OrderRecipientBO extends BaseDO {
|
||||
public class OrderRecipientBO extends BaseDO { // TODO FROM 芋艿 TO 小范,不要继承 BaseDO
|
||||
|
||||
/**
|
||||
* 编号
|
||||
|
|
|
@ -15,10 +15,12 @@ public class CalcOrderPriceDTO {
|
|||
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
|
||||
/**
|
||||
* 优惠劵编号
|
||||
*/
|
||||
private Integer couponCardId;
|
||||
|
||||
@NotNull(message = "商品数组不能为空")
|
||||
private List<Item> items;
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* 订单 api
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-16 13:15
|
||||
*/
|
||||
package cn.iocoder.mall.order.api;
|
|
@ -16,5 +16,5 @@ public class ServiceExceptionConfiguration {
|
|||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
}
|
||||
}
|
||||
} // TODO FROM 芋艿 to 小范,这里记得配置下,不然错误提示不出去呀。
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* 定义常量,以及枚举信息
|
||||
*
|
||||
* @author Sin
|
||||
* @time 2019-03-20 21:16
|
||||
*/
|
||||
package cn.iocoder.mall.order.biz.constants;
|
|
@ -1,7 +1,6 @@
|
|||
package cn.iocoder.mall.order.biz.dataobject;
|
||||
|
||||
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
@ -17,6 +16,8 @@ import java.util.Date;
|
|||
@Accessors(chain = true)
|
||||
public class OrderReturnDO extends BaseDO {
|
||||
|
||||
// TODO FROM 芋艿 TO 小范,存储下支付中心的退款单号
|
||||
|
||||
/**
|
||||
* 编号自动增长
|
||||
*/
|
||||
|
@ -24,6 +25,7 @@ public class OrderReturnDO extends BaseDO {
|
|||
/**
|
||||
* 服务号
|
||||
*/
|
||||
// TODO FROM 芋艿 to 小范,换个名字,看着怪怪的 哈哈哈哈。
|
||||
private String serviceNumber;
|
||||
/**
|
||||
* 订单编号
|
||||
|
@ -54,6 +56,7 @@ public class OrderReturnDO extends BaseDO {
|
|||
/**
|
||||
* 问题描述
|
||||
*/
|
||||
// TODO FROM 芋艿 to 小范,describe 是动词,换成名词 description
|
||||
private String describe;
|
||||
|
||||
///
|
||||
|
|
|
@ -21,7 +21,7 @@ import cn.iocoder.mall.order.biz.dataobject.OrderDO;
|
|||
import cn.iocoder.mall.order.biz.dataobject.OrderItemDO;
|
||||
import cn.iocoder.mall.order.biz.dataobject.OrderReturnDO;
|
||||
import cn.iocoder.mall.pay.api.PayRefundService;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
|
@ -14,8 +14,8 @@ import cn.iocoder.mall.order.biz.convert.*;
|
|||
import cn.iocoder.mall.order.biz.dao.*;
|
||||
import cn.iocoder.mall.order.biz.dataobject.*;
|
||||
import cn.iocoder.mall.pay.api.PayTransactionService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.product.api.ProductSpuService;
|
||||
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
|
||||
import cn.iocoder.mall.promotion.api.CouponService;
|
||||
|
@ -79,7 +79,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
public CommonResult<OrderPageBO> getOrderPage(OrderQueryDTO orderQueryDTO) {
|
||||
|
||||
int totalCount = orderMapper.selectPageCount(orderQueryDTO);
|
||||
if (totalCount == 0) {
|
||||
if (totalCount == 0) { // TODO FROM 芋艿 TO 小范 Collections.EMPTY_LIST 改成 Collections.emptyList()
|
||||
return CommonResult.success(new OrderPageBO().setOrders(Collections.EMPTY_LIST).setTotal(0));
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
|
||||
// 获取订单 id
|
||||
Set<Integer> orderIds = orderDOList.stream()
|
||||
.map(orderDO -> orderDO.getId())
|
||||
.map(orderDO -> orderDO.getId()) // TODO FROM 芋艿 to 小范,记得用 Lambda
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 获取配送信息
|
||||
|
@ -231,10 +231,10 @@ public class OrderServiceImpl implements OrderService {
|
|||
// 设置 orderItem
|
||||
Map<Integer, ProductSkuDetailBO> productSpuBOMap = productList
|
||||
.stream().collect(Collectors.toMap(ProductSkuDetailBO::getId, o -> o)); // 商品 SKU 信息的集合
|
||||
Map<Integer, CalcOrderPriceBO.Item> priceItemMap = new HashMap<>();
|
||||
Map<Integer, CalcOrderPriceBO.Item> priceItemMap = new HashMap<>(); // 商品 SKU 价格的映射
|
||||
calcOrderPrice.getItemGroups().forEach(itemGroup ->
|
||||
itemGroup.getItems().forEach(item -> priceItemMap.put(item.getId(), item)));
|
||||
|
||||
// 遍历 orderItemDOList 数组,将商品信息、商品价格,设置到其中
|
||||
for (OrderItemDO orderItemDO : orderItemDOList) {
|
||||
ProductSkuDetailBO productSkuDetailBO = productSpuBOMap.get(orderItemDO.getSkuId());
|
||||
if (productSkuDetailBO.getQuantity() <= 0) {
|
||||
|
@ -267,6 +267,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
// order
|
||||
|
||||
// TODO: 2019-04-11 Sin 订单号需要生成规则
|
||||
// TODO FROM 芋艿 to 小范:可以考虑抽象成一个方法,下面几个也是。
|
||||
String orderNo = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
|
||||
// Integer totalAmount = orderCommon.calculatedAmount(orderItemDOList);
|
||||
// Integer totalPrice = orderCommon.calculatedPrice(orderItemDOList);
|
||||
|
@ -323,10 +324,6 @@ public class OrderServiceImpl implements OrderService {
|
|||
// 一次性插入
|
||||
orderItemMapper.insert(orderItemDOList);
|
||||
|
||||
if (true) {
|
||||
throw new RuntimeException("测试 seata 事务回滚");
|
||||
}
|
||||
|
||||
// 创建预订单
|
||||
createPayTransaction(orderDO, orderItemDOList, orderCreateDTO.getIp());
|
||||
|
||||
|
@ -358,7 +355,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
return cartService.calcOrderPrice(calcOrderPriceDTO);
|
||||
}
|
||||
|
||||
private CommonResult<PayTransactionBO> createPayTransaction(OrderDO order, List<OrderItemDO> orderItems, String ip) {
|
||||
private PayTransactionBO createPayTransaction(OrderDO order, List<OrderItemDO> orderItems, String ip) {
|
||||
// TODO sin 支付订单 orderSubject 暂时取第一个子订单商品信息
|
||||
String orderSubject = orderItems.get(0).getSkuName();
|
||||
Date expireTime = DateUtil.addDate(Calendar.MINUTE, PAY_EXPIRE_TIME);
|
||||
|
@ -441,6 +438,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
.setUpdateTime(null);
|
||||
|
||||
// 关闭订单,修改状态 item
|
||||
// TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
|
||||
orderItemMapper.updateByOrderId(
|
||||
orderId,
|
||||
new OrderItemDO().setStatus(OrderStatusEnum.CLOSED.getValue())
|
||||
|
@ -454,18 +452,18 @@ public class OrderServiceImpl implements OrderService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional // TODO FROM 芋艿 TO 小范:泛型,一定要明确哈。
|
||||
public CommonResult orderDelivery(OrderDeliveryDTO orderDelivery) {
|
||||
List<Integer> orderItemIds = orderDelivery.getOrderItemIds();
|
||||
|
||||
// 获取所有订单 items
|
||||
// 获取所有订单 items // TODO FROM 芋艿 TO 小范,deleted 是默认条件,所以 by 里面可以不带哈
|
||||
List<OrderItemDO> allOrderItems = orderItemMapper.selectByDeletedAndOrderId(orderDelivery.getOrderId(), DeletedStatusEnum.DELETED_NO.getValue());
|
||||
|
||||
// 当前需要发货订单,检查 id 和 status
|
||||
List<OrderItemDO> needDeliveryOrderItems = allOrderItems.stream()
|
||||
.filter(orderItemDO -> orderItemIds.contains(orderItemDO.getId())
|
||||
&& OrderStatusEnum.WAIT_SHIPMENT.getValue() == orderItemDO.getStatus())
|
||||
.collect(Collectors.toList());
|
||||
.collect(Collectors.toList()); // TODO 芋艿,如果这里只是比对数字,可以用 Lambda 求和,不需要弄成一个集合的
|
||||
// 发货订单,检查
|
||||
if (needDeliveryOrderItems.size() != orderItemIds.size()) {
|
||||
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_DELIVERY_INCORRECT_DATA.getCode());
|
||||
|
@ -482,6 +480,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
orderLogisticsMapper.insert(orderLogisticsDO);
|
||||
|
||||
// 关联订单item 和 物流信息
|
||||
// TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题,然后判断下更新数量,不对,就抛出异常。
|
||||
orderItemMapper.updateByIds(
|
||||
orderItemIds,
|
||||
new OrderItemDO()
|
||||
|
@ -495,6 +494,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
&& !orderItemIds.contains(orderItemDO.getId()))
|
||||
.collect(Collectors.toList());
|
||||
if (unShippedOrderItems.size() <= 0) {
|
||||
// TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
|
||||
orderMapper.updateById(
|
||||
new OrderDO()
|
||||
.setId(orderDelivery.getOrderId())
|
||||
|
@ -513,7 +513,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional // TODO FROM 芋艿 to 小范,先不做这个功能,电商一班不存在这个功能哈。
|
||||
public CommonResult deleteOrderItem(OrderItemDeletedDTO orderItemDeletedDTO) {
|
||||
Integer orderId = orderItemDeletedDTO.getOrderId();
|
||||
List<Integer> orderItemIds = orderItemDeletedDTO.getOrderItemIds();
|
||||
|
@ -562,6 +562,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_UNABLE_CONFIRM_ORDER.getCode());
|
||||
}
|
||||
|
||||
// TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
|
||||
orderMapper.updateById(
|
||||
new OrderDO()
|
||||
.setId(orderId)
|
||||
|
@ -617,7 +618,7 @@ public class OrderServiceImpl implements OrderService {
|
|||
if (updateCount <= 0) {
|
||||
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage();
|
||||
}
|
||||
// TODO 芋艿 更新 OrderItemDO
|
||||
// TODO FROM 芋艿 to 小范,把更新 OrderItem 给补全。
|
||||
return "success";
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ mybatis-plus:
|
|||
id-type: auto
|
||||
mapper-locations: classpath*:mapper/*.xml
|
||||
type-aliases-package: cn.iocoder.mall.order.biz.dataobject
|
||||
config-location: classpath:mybatis-config.xml
|
||||
|
||||
# dubbo
|
||||
dubbo:
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
|
||||
<settings>
|
||||
<!-- 使用驼峰命名法转换字段。 -->
|
||||
<setting name="mapUnderscoreToCamelCase" value="true"/>
|
||||
</settings>
|
||||
|
||||
<typeAliases>
|
||||
<typeAlias alias="Integer" type="java.lang.Integer"/>
|
||||
<typeAlias alias="Long" type="java.lang.Long"/>
|
||||
<typeAlias alias="HashMap" type="java.util.HashMap"/>
|
||||
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
|
||||
<typeAlias alias="ArrayList" type="java.util.ArrayList"/>
|
||||
<typeAlias alias="LinkedList" type="java.util.LinkedList"/>
|
||||
</typeAliases>
|
||||
|
||||
</configuration>
|
|
@ -3,10 +3,10 @@ package cn.iocoder.mall.pay.application.controller.admins;
|
|||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.PayRefundService;
|
||||
import cn.iocoder.mall.pay.api.PayTransactionService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.application.convert.PayRefundConvert;
|
||||
import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundPageVO;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
|
|
|
@ -2,8 +2,8 @@ package cn.iocoder.mall.pay.application.controller.admins;
|
|||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.PayTransactionService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
|
|
@ -3,11 +3,14 @@ package cn.iocoder.mall.pay.application.controller.users;
|
|||
import cn.iocoder.common.framework.util.HttpUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.PayTransactionService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.constant.PayChannelEnum;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -18,8 +21,11 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("users/transaction") // TODO 芋艿,理论来说,是用户无关的。这里先酱紫先~
|
||||
@RequestMapping("users/transaction")
|
||||
@Api("【用户】支付交易 API")
|
||||
public class UsersPayTransactionController {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
@ -28,23 +34,19 @@ public class UsersPayTransactionController {
|
|||
private PayTransactionService payTransactionService;
|
||||
|
||||
@GetMapping("/get")
|
||||
// TODO result 后面改下
|
||||
public CommonResult<PayTransactionBO> get(@RequestParam("appId") String appId,
|
||||
@RequestParam("orderId") String orderId) {
|
||||
return payTransactionService.getTransaction(UserSecurityContextHolder.getContext().getUserId(), appId, orderId);
|
||||
@ApiOperation("获得支付交易")
|
||||
public CommonResult<PayTransactionBO> get(PayTransactionGetDTO payTransactionGetDTO) {
|
||||
payTransactionGetDTO.setUserId(UserSecurityContextHolder.getContext().getUserId());
|
||||
return success(payTransactionService.getTransaction(payTransactionGetDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/submit") // TODO api 注释
|
||||
// TODO result 后面改下
|
||||
@PostMapping("/submit")
|
||||
@ApiOperation("提交支付交易")
|
||||
public CommonResult<PayTransactionSubmitBO> submit(HttpServletRequest request,
|
||||
@RequestParam("appId") String appId,
|
||||
@RequestParam("orderId") String orderId,
|
||||
@RequestParam("payChannel") Integer payChannel) {
|
||||
PayTransactionSubmitDTO payTransactionSubmitDTO = new PayTransactionSubmitDTO()
|
||||
.setAppId(appId).setOrderId(orderId).setPayChannel(payChannel)
|
||||
.setCreateIp(HttpUtil.getIp(request));
|
||||
PayTransactionSubmitDTO payTransactionSubmitDTO) {
|
||||
payTransactionSubmitDTO.setCreateIp(HttpUtil.getIp(request));
|
||||
// 提交支付提交
|
||||
return payTransactionService.submitTransaction(payTransactionSubmitDTO);
|
||||
return success(payTransactionService.submitTransaction(payTransactionSubmitDTO));
|
||||
}
|
||||
|
||||
@PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
|
@ -63,11 +65,7 @@ public class UsersPayTransactionController {
|
|||
// JSONObject bodyObj = JSON.parseObject(sb.toString());
|
||||
// bodyObj.put("webhookId", bodyObj.remove("id"));
|
||||
// String body = bodyObj.toString();
|
||||
CommonResult<Boolean> result = payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
|
||||
if (result.isError()) {
|
||||
logger.error("[pingxxPaySuccess][message({}) result({})]", sb, result);
|
||||
return "failure";
|
||||
}
|
||||
payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
|
||||
return "success";
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package cn.iocoder.mall.pay.application.convert;
|
||||
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundDetailVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.mall.pay.application.vo.admins;
|
||||
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package cn.iocoder.mall.pay.api;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
|
||||
|
||||
public interface PayRefundService {
|
||||
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
package cn.iocoder.mall.pay.api;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface PayTransactionService {
|
||||
|
||||
CommonResult<PayTransactionBO> getTransaction(Integer userId, String appId, String orderId);
|
||||
PayTransactionBO getTransaction(PayTransactionGetDTO payTransactionGetDTO);
|
||||
|
||||
CommonResult<PayTransactionBO> createTransaction(PayTransactionCreateDTO payTransactionCreateDTO);
|
||||
PayTransactionBO createTransaction(PayTransactionCreateDTO payTransactionCreateDTO);
|
||||
|
||||
CommonResult<PayTransactionSubmitBO> submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO);
|
||||
PayTransactionSubmitBO submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO);
|
||||
|
||||
/**
|
||||
* 更新交易支付成功
|
||||
|
@ -29,7 +30,7 @@ public interface PayTransactionService {
|
|||
* 因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。
|
||||
* @return 是否支付成功
|
||||
*/
|
||||
CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params);
|
||||
Boolean updateTransactionPaySuccess(Integer payChannel, String params);
|
||||
|
||||
List<PayTransactionBO> getTransactionList(Collection<Integer> ids);
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 支付交易提交结果 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionSubmitBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 支付交易拓展单编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 调用三方平台的响应结果
|
||||
*/
|
||||
private String invokeResponse;
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
package cn.iocoder.mall.pay.api.bo.refund;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
package cn.iocoder.mall.pay.api.bo.refund;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
package cn.iocoder.mall.pay.api.bo.refund;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -1,63 +1,48 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
package cn.iocoder.mall.pay.api.bo.transaction;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 支付交易 BO
|
||||
*/
|
||||
@ApiModel("支付交易 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 编号,自增
|
||||
*/
|
||||
@ApiModelProperty(value = "交易编号", required = true, example = "POd4RC6a")
|
||||
private Integer id;
|
||||
/**
|
||||
* 应用编号
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
|
||||
private String appId;
|
||||
/**
|
||||
* 发起交易的 IP
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1")
|
||||
private String createIp;
|
||||
/**
|
||||
* 业务线的订单编号
|
||||
*
|
||||
* 1. 使用 String 的原因是,业务线可能使用 String 做为编号
|
||||
* 2. 每个 appId 下,orderId 唯一
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
|
||||
private String orderId;
|
||||
/**
|
||||
* 订单商品名
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "商品名", required = true, example = "芋道源码")
|
||||
private String orderSubject;
|
||||
/**
|
||||
* 订单商品描述
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的")
|
||||
private String orderDescription;
|
||||
/**
|
||||
* 订单备注
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单商品备注", example = "绵啾啾的")
|
||||
private String orderMemo;
|
||||
/**
|
||||
* 支付金额,单位:分。
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10")
|
||||
private Integer price;
|
||||
/**
|
||||
* 订单状态
|
||||
*
|
||||
* @see cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单状态", required = true, example = "1", notes = "参见 PayTransactionStatusEnum 枚举")
|
||||
private Integer status;
|
||||
/**
|
||||
* 交易过期时间
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "交易过期时间", required = true)
|
||||
private Date expireTime;
|
||||
|
||||
/**
|
||||
* 回调业务线完成时间
|
||||
*/
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.bo;
|
||||
package cn.iocoder.mall.pay.api.bo.transaction;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -0,0 +1,21 @@
|
|||
package cn.iocoder.mall.pay.api.bo.transaction;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@ApiModel("支付交易提交结果 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionSubmitBO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "支付交易拓展单编号", required = true, example = "1")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty(value = "调用三方平台的响应结果", required = true)
|
||||
private String invokeResponse;
|
||||
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
package cn.iocoder.mall.pay.api.constant;
|
||||
|
||||
import cn.iocoder.common.framework.core.IntArrayValuable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 支付通道
|
||||
*/
|
||||
public enum PayChannelEnum {
|
||||
public enum PayChannelEnum implements IntArrayValuable {
|
||||
|
||||
WEIXIN_APP(100, "wx", "微信 App 支付"),
|
||||
WEIXIN_PUB(101, "wxjs", "微信 JS API 支付"),
|
||||
|
@ -13,6 +17,8 @@ public enum PayChannelEnum {
|
|||
PINGXX(9999, "ping++", "ping++ 支付"),
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayChannelEnum::getId).toArray();
|
||||
|
||||
/**
|
||||
* 渠道编号
|
||||
*/
|
||||
|
@ -44,4 +50,9 @@ public enum PayChannelEnum {
|
|||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package cn.iocoder.mall.pay.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 支付交易提交 DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionSubmitDTO {
|
||||
|
||||
/**
|
||||
* 应用编号
|
||||
*/
|
||||
@NotEmpty(message = "应用编号不能为空")
|
||||
private String appId;
|
||||
/**
|
||||
* 发起交易的 IP
|
||||
*/
|
||||
@NotEmpty(message = "IP 不能为空")
|
||||
private String createIp;
|
||||
/**
|
||||
* 业务线的订单编号
|
||||
*/
|
||||
@NotEmpty(message = "订单号不能为空")
|
||||
private String orderId;
|
||||
/**
|
||||
* 支付渠道
|
||||
*/
|
||||
@NotNull(message = "支付渠道")
|
||||
private Integer payChannel;
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.dto;
|
||||
package cn.iocoder.mall.pay.api.dto.refund;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.dto;
|
||||
package cn.iocoder.mall.pay.api.dto.refund;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -1,5 +1,7 @@
|
|||
package cn.iocoder.mall.pay.api.dto;
|
||||
package cn.iocoder.mall.pay.api.dto.transaction;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
@ -10,54 +12,43 @@ import javax.validation.constraints.NotNull;
|
|||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 支付交易创建 DTO
|
||||
*/
|
||||
@ApiModel("支付交易创建 DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionCreateDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 应用编号
|
||||
*/
|
||||
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
|
||||
@NotEmpty(message = "应用编号不能为空")
|
||||
private String appId;
|
||||
/**
|
||||
* 发起交易的 IP
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1")
|
||||
@NotEmpty(message = "IP 不能为空")
|
||||
private String createIp;
|
||||
/**
|
||||
* 业务线的订单编号
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
|
||||
@NotEmpty(message = "订单号不能为空")
|
||||
private String orderId;
|
||||
/**
|
||||
* 订单商品名
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "商品名", required = true, example = "芋道源码")
|
||||
@NotEmpty(message = "商品名不能为空")
|
||||
@Length(max = 32, message = "商品名不能超过32")
|
||||
private String orderSubject;
|
||||
/**
|
||||
* 订单商品描述
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的")
|
||||
@NotEmpty(message = "商品描述不能为空")
|
||||
@Length(max = 128, message = "商品描述长度不能超过128")
|
||||
private String orderDescription;
|
||||
/**
|
||||
* 订单备注
|
||||
*/
|
||||
@Length(max = 256, message = "商品描述长度不能超过256")
|
||||
|
||||
@ApiModelProperty(value = "订单商品备注", example = "绵啾啾的")
|
||||
@Length(max = 256, message = "商品备注长度不能超过256")
|
||||
private String orderMemo;
|
||||
/**
|
||||
* 支付金额,单位:分。
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10")
|
||||
@NotNull(message = "金额不能为空")
|
||||
@DecimalMin(value = "0", inclusive = false, message = "金额必须大于零")
|
||||
private Integer price;
|
||||
/**
|
||||
* 交易过期时间
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "交易过期时间", required = true)
|
||||
@NotNull(message = "交易过期时间不能为空")
|
||||
private Date expireTime;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.mall.pay.api.dto.transaction;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("支付交易获得 DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionGetDTO {
|
||||
|
||||
@ApiModelProperty(value = "用户编号", required = true, example = "1", hidden = true) // hidden 的原因是,Service DTO 自己传入,无需暴露的 Controller API 里
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
|
||||
@NotEmpty(message = "应用编号不能为空")
|
||||
private String appId;
|
||||
|
||||
@ApiModelProperty(value = "订单号不能为空", required = true, example = "1024")
|
||||
@NotEmpty(message = "订单号不能为空")
|
||||
private String orderId;
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.iocoder.mall.pay.api.dto;
|
||||
package cn.iocoder.mall.pay.api.dto.transaction;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.mall.pay.api.dto.transaction;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.pay.api.constant.PayChannelEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("支付交易提交 DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PayTransactionSubmitDTO {
|
||||
|
||||
@ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a")
|
||||
@NotEmpty(message = "应用编号不能为空")
|
||||
private String appId;
|
||||
|
||||
@ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1", hidden = true) // hidden 的原因是,Service DTO 自己传入,无需暴露的 Controller API 里
|
||||
@NotEmpty(message = "IP 不能为空")
|
||||
private String createIp;
|
||||
|
||||
@ApiModelProperty(value = "订单号", required = true, example = "1024")
|
||||
@NotEmpty(message = "订单号不能为空")
|
||||
private String orderId;
|
||||
|
||||
@ApiModelProperty(value = "支付渠道", required = true, example = "1", notes = "参见 PayChannelEnum 枚举")
|
||||
@InEnum(value = PayChannelEnum.class, message = "支付渠道必须是 {value}")
|
||||
@NotNull(message = "支付渠道")
|
||||
private Integer payChannel;
|
||||
|
||||
}
|
|
@ -1,17 +1,20 @@
|
|||
package cn.iocoder.mall.pay.biz.component;
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import cn.iocoder.common.framework.util.StringUtil;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import lombok.Data;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class DubboReferencePool {
|
||||
|
||||
|
@ -44,7 +47,8 @@ public class DubboReferencePool {
|
|||
private String dubboApplicationName;
|
||||
|
||||
private ReferenceMeta createGenericService(String notifyUrl) {
|
||||
String[] notifyUrlParts = notifyUrl.split("#");
|
||||
// 使用 # 号分隔,格式为 服务名#方法名#版本号
|
||||
List<String> notifyUrlParts = StringUtil.split(notifyUrl, "#");
|
||||
// 创建 ApplicationConfig 对象
|
||||
ApplicationConfig application = new ApplicationConfig();
|
||||
application.setName(dubboApplicationName);
|
||||
|
@ -55,14 +59,14 @@ public class DubboReferencePool {
|
|||
application.setRegistry(registry);
|
||||
// 创建 ReferenceConfig 对象
|
||||
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
|
||||
reference.setInterface(notifyUrlParts[0]); // 弱类型接口名
|
||||
reference.setInterface(notifyUrlParts.get(0)); // 弱类型接口名
|
||||
reference.setGeneric(true); // 声明为泛化接口
|
||||
reference.setApplication(application);
|
||||
// reference.setVersion("*"); // TODO 芋艿,后面要优化下。
|
||||
reference.setVersion(notifyUrlParts.size() > 2 ? notifyUrlParts.get(2) : "1.0.0"); // 如果未配置服务的版本号,则默认使用 1.0.0
|
||||
// 获得 GenericService 对象
|
||||
GenericService genericService = reference.get();
|
||||
// 构建最终的 ReferenceMeta 对象
|
||||
return new ReferenceMeta(reference, genericService, notifyUrlParts[1]);
|
||||
return new ReferenceMeta(reference, genericService, notifyUrlParts.get(1));
|
||||
}
|
||||
|
||||
public ReferenceMeta getReferenceMeta(String notifyUrl) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.mall.pay.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package cn.iocoder.mall.pay.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
|
||||
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO;
|
||||
import org.mapstruct.Mapper;
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Date;
|
|||
topic = PayRefundSuccessMessage.TOPIC,
|
||||
consumerGroup = "pay-consumer-group-" + PayRefundSuccessMessage.TOPIC
|
||||
)
|
||||
@Deprecated // 艿艿:突然发现,业务方实际无需回调。参考了 https://help.youzan.com/displaylist/detail_4_998 的文章。业务方,只要记录下退款单号,进行关联即可。
|
||||
public class PayRefundSuccessConsumer extends AbstractPayNotifySuccessConsumer<PayRefundSuccessMessage>
|
||||
implements RocketMQListener<PayRefundSuccessMessage> {
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package cn.iocoder.mall.pay.biz.service;
|
|||
|
||||
import cn.iocoder.common.framework.constant.CommonStatusEnum;
|
||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
|
||||
import cn.iocoder.mall.pay.biz.dao.PayAppMapper;
|
||||
import cn.iocoder.mall.pay.biz.dataobject.PayAppDO;
|
||||
|
@ -15,17 +14,17 @@ public class PayAppServiceImpl {
|
|||
@Autowired
|
||||
private PayAppMapper payAppMapper;
|
||||
|
||||
public CommonResult<PayAppDO> validPayApp(String appId) {
|
||||
public PayAppDO validPayApp(String appId) {
|
||||
PayAppDO payAppDO = payAppMapper.selectById(appId);
|
||||
// 校验是否存在
|
||||
if (payAppDO == null) {
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_APP_NOT_FOUND.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_APP_NOT_FOUND.getCode());
|
||||
}
|
||||
// 校验是否禁用
|
||||
if (CommonStatusEnum.DISABLE.getValue().equals(payAppDO.getStatus())) {
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_APP_IS_DISABLE.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_APP_IS_DISABLE.getCode());
|
||||
}
|
||||
return CommonResult.success(payAppDO);
|
||||
return payAppDO;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public class PayNotifyServiceImpl {
|
|||
@Resource
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
@Deprecated // 参见 PayRefundSuccessConsumer 类的说明
|
||||
public void addRefundNotifyTask(PayRefundDO refund) {
|
||||
PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl())
|
||||
.setType(PayNotifyType.REFUND.getValue());
|
||||
|
|
|
@ -5,13 +5,13 @@ import cn.iocoder.common.framework.util.MathUtil;
|
|||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.PayRefundService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
|
||||
import cn.iocoder.mall.pay.api.constant.PayRefundStatus;
|
||||
import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.biz.client.AbstractPaySDK;
|
||||
import cn.iocoder.mall.pay.biz.client.PaySDKFactory;
|
||||
import cn.iocoder.mall.pay.biz.client.RefundSuccessBO;
|
||||
|
@ -51,13 +51,9 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("Duplicates")
|
||||
public CommonResult<PayRefundSubmitBO> submitRefund(PayRefundSubmitDTO payRefundSubmitDTO) {
|
||||
// 校验 App 是否有效
|
||||
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payRefundSubmitDTO.getAppId());
|
||||
if (appResult.isError()) {
|
||||
return CommonResult.error(appResult);
|
||||
}
|
||||
PayAppDO payAppDO = payAppService.validPayApp(payRefundSubmitDTO.getAppId());
|
||||
// 获得 PayTransactionDO ,并校验其是否存在
|
||||
PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefundSubmitDTO.getAppId(), payRefundSubmitDTO.getOrderId());
|
||||
if (payTransaction == null) { // 是否存在
|
||||
|
@ -82,7 +78,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||
.setTransactionId(payTransaction.getId())
|
||||
.setRefundCode(generateTransactionCode()) // TODO 芋艿,后续调整
|
||||
.setStatus(PayRefundStatus.WAITING.getValue())
|
||||
.setNotifyUrl(appResult.getData().getRefundNotifyUrl())
|
||||
.setNotifyUrl(payAppDO.getRefundNotifyUrl())
|
||||
.setRefundChannel(payTransaction.getPayChannel());
|
||||
payRefundDO.setCreateTime(new Date());
|
||||
payRefundMapper.insert(payRefundDO);
|
||||
|
|
|
@ -5,14 +5,15 @@ import cn.iocoder.common.framework.util.MathUtil;
|
|||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.pay.api.PayTransactionService;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO;
|
||||
import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO;
|
||||
import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum;
|
||||
import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO;
|
||||
import cn.iocoder.mall.pay.biz.client.AbstractPaySDK;
|
||||
import cn.iocoder.mall.pay.biz.client.PaySDKFactory;
|
||||
import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO;
|
||||
|
@ -68,23 +69,21 @@ public class PayTransactionServiceImpl implements PayTransactionService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<PayTransactionBO> getTransaction(Integer userId, String appId, String orderId) {
|
||||
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(appId, orderId);
|
||||
public PayTransactionBO getTransaction(PayTransactionGetDTO payTransactionGetDTO) {
|
||||
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(payTransactionGetDTO.getAppId(),
|
||||
payTransactionGetDTO.getOrderId());
|
||||
if (payTransaction == null) {
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
}
|
||||
// TODO 芋艿 userId 的校验
|
||||
return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction));
|
||||
return PayTransactionConvert.INSTANCE.convert(payTransaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("Duplicates")
|
||||
public CommonResult<PayTransactionBO> createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) {
|
||||
public PayTransactionBO createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) {
|
||||
// 校验 App
|
||||
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionCreateDTO.getAppId());
|
||||
if (appResult.isError()) {
|
||||
return CommonResult.error(appResult);
|
||||
}
|
||||
PayAppDO payAppDO = payAppService.validPayApp(payTransactionCreateDTO.getAppId());
|
||||
// 插入 PayTransactionDO
|
||||
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(
|
||||
payTransactionCreateDTO.getAppId(), payTransactionCreateDTO.getOrderId());
|
||||
|
@ -95,31 +94,28 @@ public class PayTransactionServiceImpl implements PayTransactionService {
|
|||
} else {
|
||||
payTransaction = PayTransactionConvert.INSTANCE.convert(payTransactionCreateDTO);
|
||||
payTransaction.setStatus(PayTransactionStatusEnum.WAITING.getValue())
|
||||
.setNotifyUrl(appResult.getData().getNotifyUrl());
|
||||
.setNotifyUrl(payAppDO.getNotifyUrl());
|
||||
payTransaction.setCreateTime(new Date());
|
||||
payTransactionMapper.insert(payTransaction);
|
||||
}
|
||||
// 返回成功
|
||||
return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction));
|
||||
return PayTransactionConvert.INSTANCE.convert(payTransaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("Duplicates")
|
||||
public CommonResult<PayTransactionSubmitBO> submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) {
|
||||
public PayTransactionSubmitBO submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) {
|
||||
// TODO 校验支付渠道是否有效
|
||||
// 校验 App 是否有效
|
||||
CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionSubmitDTO.getAppId());
|
||||
if (appResult.isError()) {
|
||||
return CommonResult.error(appResult);
|
||||
}
|
||||
payAppService.validPayApp(payTransactionSubmitDTO.getAppId());
|
||||
// 获得 PayTransactionDO ,并校验其是否存在
|
||||
PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(
|
||||
payTransactionSubmitDTO.getAppId(), payTransactionSubmitDTO.getOrderId());
|
||||
if (payTransaction == null) { // 是否存在
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
}
|
||||
if (!PayTransactionStatusEnum.WAITING.getValue().equals(payTransaction.getStatus())) { // 校验状态,必须是待支付
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
|
||||
}
|
||||
// 插入 PayTransactionExtensionDO
|
||||
PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(payTransactionSubmitDTO)
|
||||
|
@ -131,33 +127,32 @@ public class PayTransactionServiceImpl implements PayTransactionService {
|
|||
AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel());
|
||||
CommonResult<String> invokeResult = paySDK.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
|
||||
if (invokeResult.isError()) {
|
||||
return CommonResult.error(invokeResult);
|
||||
throw ServiceExceptionUtil.exception(invokeResult.getCode(), invokeResult.getMessage());
|
||||
}
|
||||
// TODO 轮询三方接口,是否已经支付的任务
|
||||
// 返回成功
|
||||
PayTransactionSubmitBO payTransactionSubmitBO = new PayTransactionSubmitBO()
|
||||
.setId(payTransactionExtensionDO.getId()).setInvokeResponse(invokeResult.getData());
|
||||
return CommonResult.success(payTransactionSubmitBO);
|
||||
return new PayTransactionSubmitBO().setId(payTransactionExtensionDO.getId())
|
||||
.setInvokeResponse(invokeResult.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params) {
|
||||
public Boolean updateTransactionPaySuccess(Integer payChannel, String params) {
|
||||
// TODO 芋艿,记录回调日志
|
||||
// 解析传入的参数,成 TransactionSuccessBO 对象
|
||||
AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel);
|
||||
CommonResult<TransactionSuccessBO> paySuccessResult = paySDK.parseTransactionSuccessParams(params);
|
||||
if (paySuccessResult.isError()) {
|
||||
return CommonResult.error(paySuccessResult);
|
||||
throw ServiceExceptionUtil.exception(paySuccessResult.getCode(), paySuccessResult.getMessage());
|
||||
}
|
||||
// TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
|
||||
// 1.1 查询 PayTransactionExtensionDO
|
||||
PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode());
|
||||
if (extension == null) {
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_NOT_FOUND.getCode());
|
||||
}
|
||||
if (!PayTransactionStatusEnum.WAITING.getValue().equals(extension.getStatus())) { // 校验状态,必须是待支付
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_WAITING.getCode());
|
||||
}
|
||||
// 1.2 更新 PayTransactionExtensionDO
|
||||
PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO()
|
||||
|
@ -172,7 +167,7 @@ public class PayTransactionServiceImpl implements PayTransactionService {
|
|||
// 2.1 判断 PayTransactionDO 是否处于待支付
|
||||
PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId());
|
||||
if (transaction == null) {
|
||||
return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode());
|
||||
}
|
||||
if (!PayTransactionStatusEnum.WAITING.getValue().equals(transaction.getStatus())) { // 校验状态,必须是待支付
|
||||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
|
||||
|
@ -191,10 +186,10 @@ public class PayTransactionServiceImpl implements PayTransactionService {
|
|||
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
|
||||
}
|
||||
logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId());
|
||||
// 3 新增 PayNotifyTaskDO
|
||||
payNotifyService.addTransactionNotifyTask(transaction, extension);
|
||||
// 3 新增 PayNotifyTaskDO 注释原因,参见 PayRefundSuccessConsumer 类。
|
||||
// payNotifyService.addTransactionNotifyTask(transaction, extension);
|
||||
// 返回结果
|
||||
return CommonResult.success(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.mall.pay.biz.service;
|
||||
|
||||
import cn.iocoder.mall.pay.api.PayRefundService;
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package cn.iocoder.mall.pay.biz.service;
|
||||
|
||||
import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
|
|
@ -5,11 +5,10 @@ import cn.iocoder.mall.product.api.ProductCategoryService;
|
|||
import cn.iocoder.mall.product.api.bo.ProductCategoryBO;
|
||||
import cn.iocoder.mall.product.application.convert.ProductCategoryConvert;
|
||||
import cn.iocoder.mall.product.application.vo.users.UsersProductCategoryVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -30,7 +29,6 @@ public class UsersProductCategoryController {
|
|||
@GetMapping("/list")
|
||||
@ApiOperation("获得指定编号下的子分类的数组")
|
||||
@ApiImplicitParam(name = "pid", value = "指定分类编号", required = true, example = "0")
|
||||
@PermitAll
|
||||
public CommonResult<List<UsersProductCategoryVO>> list(@RequestParam("pid") Integer pid) {
|
||||
List<ProductCategoryBO> result = productCategoryService.getListByPid(pid);
|
||||
return CommonResult.success(ProductCategoryConvert.Users.INSTANCE.convertToVO(result));
|
||||
|
|
|
@ -7,7 +7,6 @@ import cn.iocoder.mall.product.api.dto.ProductSpuPageDTO;
|
|||
import cn.iocoder.mall.product.application.convert.ProductSpuConvert;
|
||||
import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO;
|
||||
import cn.iocoder.mall.product.application.vo.users.UsersProductSpuPageVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
|
@ -31,7 +30,6 @@ public class UsersProductSpuController {
|
|||
@GetMapping("/info")
|
||||
@ApiOperation("商品 SPU 明细")
|
||||
@ApiImplicitParam(name = "id", value = "SPU 编号", required = true, example = "100")
|
||||
@PermitAll
|
||||
public CommonResult<UsersProductSpuDetailVO> info(@RequestParam("id") Integer id) {
|
||||
return success(ProductSpuConvert.INSTANCE.convert4(productSpuService.getProductSpuDetail(id)));
|
||||
}
|
||||
|
@ -43,7 +41,6 @@ public class UsersProductSpuController {
|
|||
@ApiImplicitParam(name = "pageNo", value = "页码,从 1 开始", example = "1"),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, example = "10"),
|
||||
})
|
||||
@PermitAll
|
||||
@Deprecated // 使用商品搜索接口
|
||||
public CommonResult<UsersProductSpuPageVO> page(@RequestParam(value = "cid", required = false) Integer cid,
|
||||
@RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo,
|
||||
|
|
|
@ -6,7 +6,6 @@ import cn.iocoder.mall.promotion.api.BannerService;
|
|||
import cn.iocoder.mall.promotion.api.bo.BannerBO;
|
||||
import cn.iocoder.mall.promotion.application.convert.BannerConvert;
|
||||
import cn.iocoder.mall.promotion.application.vo.users.UsersBannerVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
|
@ -27,7 +26,6 @@ public class UsersBannerController {
|
|||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获得所有 Banner 列表")
|
||||
@PermitAll
|
||||
public CommonResult<List<UsersBannerVO>> list() {
|
||||
// 查询 Banner 列表
|
||||
List<BannerBO> result = bannerService.getBannerListByStatus(CommonStatusEnum.ENABLE.getValue());
|
||||
|
|
|
@ -11,7 +11,6 @@ import cn.iocoder.mall.promotion.application.convert.CouponTemplateConvert;
|
|||
import cn.iocoder.mall.promotion.application.vo.users.UsersCouponCardPageVO;
|
||||
import cn.iocoder.mall.promotion.application.vo.users.UsersCouponCardVO;
|
||||
import cn.iocoder.mall.promotion.application.vo.users.UsersCouponTemplateVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
|
@ -35,7 +34,6 @@ public class UsersCouponController {
|
|||
@GetMapping("/template/get")
|
||||
@ApiOperation(value = "优惠劵(码)模板信息")
|
||||
@ApiImplicitParam(name = "id", value = "优惠劵(码)模板编号", required = true, example = "10")
|
||||
@PermitAll
|
||||
public CommonResult<UsersCouponTemplateVO> templateGet(@RequestParam("id") Integer id) {
|
||||
CouponTemplateBO template = couponService.getCouponTemplate(id);
|
||||
return success(CouponTemplateConvert.USERS.convert2(template));
|
||||
|
|
|
@ -8,7 +8,6 @@ import cn.iocoder.mall.promotion.api.ProductRecommendService;
|
|||
import cn.iocoder.mall.promotion.api.bo.ProductRecommendBO;
|
||||
import cn.iocoder.mall.promotion.application.convert.ProductRecommendConvert;
|
||||
import cn.iocoder.mall.promotion.application.vo.users.UsersProductRecommendVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import io.swagger.annotations.Api;
|
||||
|
@ -36,7 +35,6 @@ public class UsersProductRecommendController {
|
|||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获得所有 Banner 列表")
|
||||
@PermitAll
|
||||
public CommonResult<Map<Integer, Collection<UsersProductRecommendVO>>> list() {
|
||||
// 查询商品推荐列表
|
||||
List<ProductRecommendBO> productRecommends = productRecommendService.getProductRecommendList(
|
||||
|
|
|
@ -12,11 +12,6 @@ spring:
|
|||
max-active: 5
|
||||
max-wait: 10000
|
||||
|
||||
# mybatis
|
||||
#mybatis:
|
||||
# config-location: classpath:mybatis-config.xml
|
||||
# mapper-locations: classpath:mapper/*.xml
|
||||
# type-aliases-package: cn.iocoder.mall.promotion.biz.dataobject
|
||||
# mybatis-plus
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
|
@ -26,7 +21,7 @@ mybatis-plus:
|
|||
id-type: auto
|
||||
mapper-locations: classpath*:mapper/*.xml
|
||||
type-aliases-package: cn.iocoder.mall.promotion.biz.dataobject
|
||||
config-location: classpath:mybatis-config.xml
|
||||
|
||||
# dubbo
|
||||
dubbo:
|
||||
application:
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
|
||||
<configuration>
|
||||
|
||||
<settings>
|
||||
<!-- 使用驼峰命名法转换字段。 -->
|
||||
<setting name="mapUnderscoreToCamelCase" value="true"/>
|
||||
</settings>
|
||||
|
||||
<typeAliases>
|
||||
<typeAlias alias="Integer" type="java.lang.Integer"/>
|
||||
<typeAlias alias="Long" type="java.lang.Long"/>
|
||||
<typeAlias alias="HashMap" type="java.util.HashMap"/>
|
||||
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
|
||||
<typeAlias alias="ArrayList" type="java.util.ArrayList"/>
|
||||
<typeAlias alias="LinkedList" type="java.util.LinkedList"/>
|
||||
</typeAliases>
|
||||
|
||||
</configuration>
|
Binary file not shown.
|
@ -12,7 +12,17 @@ import java.util.Set;
|
|||
@Accessors(chain = true)
|
||||
public class AdminSecurityContext {
|
||||
|
||||
/**
|
||||
* 管理员编号
|
||||
*/
|
||||
private Integer adminId;
|
||||
/**
|
||||
* 管理员账号
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 拥有的角色编号
|
||||
*/
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package cn.iocoder.mall.admin.sdk.interceptor;
|
||||
|
||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.mall.admin.api.constant.AdminConstants;
|
||||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Admin 演示拦截器
|
||||
*
|
||||
* 这是个比较“奇怪”的拦截器,用于演示的管理员账号,禁止使用 POST 请求,从而实现即达到阉割版的演示的效果,又避免影响了数据
|
||||
*/
|
||||
@Component
|
||||
public class AdminDemoInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
if (AdminConstants.USERNAME_DEMO.equals(AdminSecurityContextHolder.getContext().getUsername())
|
||||
&& request.getMethod().equalsIgnoreCase(HttpMethod.POST.toString())) {
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_DEMO_CAN_NOT_WRITE.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -89,6 +89,7 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||
context.setAdminId(authentication.getUserId());
|
||||
MallUtil.setUserId(request, authentication.getUserId()); // 记录到 request 中,避免 AdminSecurityContext 后续清理掉后,其它地方需要用到 userId
|
||||
if (authorization != null) {
|
||||
context.setUsername(authorization.getUsername());
|
||||
context.setRoleIds(authorization.getRoleIds());
|
||||
}
|
||||
}
|
||||
|
@ -113,8 +114,4 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||
requiresPermissions != null ? Arrays.asList(requiresPermissions.value()) : null);
|
||||
}
|
||||
|
||||
private void checkPermission() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* 提供 SDK 给其它服务,使用如下功能:
|
||||
*
|
||||
* 1. 通过 {@link cn.iocoder.mall.admin.sdk.interceptor.UserSecurityInterceptor} 拦截器,实现需要登陆 URL 的鉴权
|
||||
* 1. 通过 {@link cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor} 拦截器,实现需要登陆 URL 的鉴权
|
||||
*/
|
||||
package cn.iocoder.mall.admin.sdk;
|
||||
package cn.iocoder.mall.admin.sdk;
|
||||
|
|
|
@ -4,6 +4,8 @@ import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
|||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
|
||||
|
||||
/**
|
||||
* Oauth2 服务接口
|
||||
|
@ -18,9 +20,20 @@ public interface OAuth2Service {
|
|||
*/
|
||||
OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO);
|
||||
|
||||
// TODO @see 刷新 token
|
||||
/**
|
||||
* 基于用户移除 accessToken
|
||||
*
|
||||
* @param oauth2RemoveTokenDTO accessToken 信息
|
||||
*/
|
||||
void removeToken(OAuth2RemoveTokenByUserDTO oauth2RemoveTokenDTO);
|
||||
|
||||
void removeToken(Integer userId); // TODO 需要优化
|
||||
/**
|
||||
* 刷新令牌,获得新的 accessToken 信息
|
||||
*
|
||||
* @param oauth2RefreshTokenDTO refreshToken 信息
|
||||
* @return accessToken 信息
|
||||
*/
|
||||
OAuth2AccessTokenBO refreshToken(OAuth2RefreshTokenDTO oauth2RefreshTokenDTO);
|
||||
|
||||
/**
|
||||
* 通过 accessToken 获得身份信息
|
||||
|
|
|
@ -5,16 +5,20 @@ import io.swagger.annotations.ApiModelProperty;
|
|||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
@ApiModel("管理员授权 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AdminAuthorizationBO {
|
||||
public class AdminAuthorizationBO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty(value = "登陆账号", required = true, example = "1")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "角色编号数组", required = true, example = "1")
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package cn.iocoder.mall.admin.api.bo.oauth2;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* OAUTH2 认证 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AuthenticationOldBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 管理员编号
|
||||
*/
|
||||
private Integer adminId;
|
||||
/**
|
||||
* 角色编号数组
|
||||
*/
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -2,6 +2,14 @@ package cn.iocoder.mall.admin.api.constant;
|
|||
|
||||
public class AdminConstants {
|
||||
|
||||
/**
|
||||
* 账号 - 管理员
|
||||
*/
|
||||
public static final String USERNAME_ADMIN = "admin";
|
||||
|
||||
}
|
||||
/**
|
||||
* 账号 - 演示账号
|
||||
*/
|
||||
public static final String USERNAME_DEMO = "yudaoyuanma";
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@ public enum AdminErrorCodeEnum {
|
|||
OAUTH2_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
|
||||
OAUTH2_NOT_LOGIN(1002001015, "账号未登陆"),
|
||||
OAUTH2_INVALID_TOKEN_ERROR_USER_TYPE(1002001016, "访问令牌用户类型不正确"),
|
||||
|
||||
OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
|
||||
OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND(1002001017, "刷新令牌不存在"),
|
||||
OAUTH_INVALID_REFRESH_TOKEN_EXPIRED(1002001018, "访问令牌已过期"),
|
||||
OAUTH_INVALID_REFRESH_TOKEN_INVALID(1002001019, "刷新令牌已失效"),
|
||||
|
||||
// ========== 管理员模块 1002002000 ==========
|
||||
ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"),
|
||||
|
@ -30,6 +31,8 @@ public enum AdminErrorCodeEnum {
|
|||
ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE(1002002005, "管理员的账号状态不允许变更"),
|
||||
ADMIN_ASSIGN_ROLE_NOT_EXISTS(1002002006, "分配员工角色时,有角色不存在"),
|
||||
ADMIN_INVALID_PERMISSION(1002002007, "没有该操作权限"),
|
||||
ADMIN_ADMIN_CAN_NOT_UPDATE(1002002008, "管理员的账号不允许变更"),
|
||||
ADMIN_DEMO_CAN_NOT_WRITE(1002002009, "演示账号,暂不允许写操作。欢迎加入我们的交流群:http://t.cn/EKEr5WE"),
|
||||
|
||||
// ========== 资源模块 1002003000 ==========
|
||||
RESOURCE_NAME_DUPLICATE(1002003000, "已经存在该名字的资源"),
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package cn.iocoder.mall.admin.api.dto.oauth2;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
@ApiModel("OAuth2 刷新 Token DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2RefreshTokenDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "refreshToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||
@NotEmpty(message = "refreshToken 不能为空")
|
||||
private String refreshToken;
|
||||
|
||||
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 ResourceTypeEnum 枚举")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "用户类型必须是 {value}")
|
||||
private Integer userType;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package cn.iocoder.mall.admin.api.dto.oauth2;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
@ApiModel("OAuth2 移除 Token DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2RemoveTokenByUserDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "用户编号", required = true, example = "1")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 ResourceTypeEnum 枚举")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "用户类型必须是 {value}")
|
||||
private Integer userType;
|
||||
|
||||
}
|
|
@ -2,17 +2,12 @@ package cn.iocoder.mall.admin.convert;
|
|||
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationOldBO;
|
||||
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
|
||||
import cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mapper
|
||||
public interface OAuth2Convert {
|
||||
|
||||
|
@ -28,15 +23,8 @@ public interface OAuth2Convert {
|
|||
.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
|
||||
}
|
||||
|
||||
@Mappings({})
|
||||
OAuth2AuthenticationOldBO convertToAuthenticationOld(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
@Mappings({})
|
||||
OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
default OAuth2AuthenticationOldBO convertToAuthenticationOld(OAuth2AccessTokenDO oauth2AccessTokenDO, List<AdminRoleDO> adminRoleDOs) {
|
||||
return convertToAuthenticationOld(oauth2AccessTokenDO)
|
||||
.setRoleIds(adminRoleDOs.stream().map(AdminRoleDO::getRoleId).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,9 +8,16 @@ import org.springframework.stereotype.Repository;
|
|||
@Repository
|
||||
public interface OAuth2AccessTokenMapper extends BaseMapper<OAuth2AccessTokenDO> {
|
||||
|
||||
default int updateToInvalidByAdminId(Integer adminId) {
|
||||
default int updateToInvalid(Integer userId, Integer userType) {
|
||||
QueryWrapper<OAuth2AccessTokenDO> query = new QueryWrapper<OAuth2AccessTokenDO>()
|
||||
.eq("admin_id", adminId).eq("valid", true);
|
||||
.eq("user_id", userId).eq("user_type", userType)
|
||||
.eq("valid", true);
|
||||
return update(new OAuth2AccessTokenDO().setValid(false), query);
|
||||
}
|
||||
|
||||
default int updateToInvalidByRefreshToken(String refreshToken) {
|
||||
QueryWrapper<OAuth2AccessTokenDO> query = new QueryWrapper<OAuth2AccessTokenDO>()
|
||||
.eq("refresh_token", refreshToken).eq("valid", true);
|
||||
return update(new OAuth2AccessTokenDO().setValid(false), query);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ import org.springframework.stereotype.Repository;
|
|||
@Repository
|
||||
public interface OAuth2RefreshTokenMapper extends BaseMapper<OAuth2RefreshTokenDO> {
|
||||
|
||||
default int updateToInvalidByAdminId(Integer adminId) {
|
||||
default int updateToInvalid(Integer userId, Integer userType) {
|
||||
QueryWrapper<OAuth2RefreshTokenDO> query = new QueryWrapper<OAuth2RefreshTokenDO>()
|
||||
.eq("admin_id", adminId).eq("valid", true);
|
||||
.eq("user_id", userId).eq("user_type", userType)
|
||||
.eq("valid", true);
|
||||
return update(new OAuth2RefreshTokenDO().setValid(false), query);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import cn.iocoder.mall.admin.api.constant.AdminConstants;
|
|||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||
import cn.iocoder.mall.admin.api.dto.admin.*;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
|
||||
import cn.iocoder.mall.admin.convert.AdminConvert;
|
||||
import cn.iocoder.mall.admin.dao.AdminMapper;
|
||||
import cn.iocoder.mall.admin.dao.AdminRoleMapper;
|
||||
|
@ -96,9 +97,14 @@ public class AdminServiceImpl implements AdminService {
|
|||
@Override
|
||||
public Boolean updateAdmin(Integer adminId, AdminUpdateDTO adminUpdateDTO) {
|
||||
// 校验账号存在
|
||||
if (adminMapper.selectById(adminUpdateDTO.getId()) == null) {
|
||||
AdminDO admin = adminMapper.selectById(adminUpdateDTO.getId());
|
||||
if (admin == null) {
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
|
||||
}
|
||||
if (AdminConstants.USERNAME_ADMIN.equals(admin.getUsername())
|
||||
|| AdminConstants.USERNAME_DEMO.equals(admin.getUsername())) { // 特殊账号,不允许编辑
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_ADMIN_CAN_NOT_UPDATE.getCode());
|
||||
}
|
||||
// 校验账号唯一
|
||||
AdminDO usernameAdmin = adminMapper.selectByUsername(adminUpdateDTO.getUsername());
|
||||
if (usernameAdmin != null && !usernameAdmin.getId().equals(adminUpdateDTO.getId())) {
|
||||
|
@ -120,7 +126,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
if (admin == null) {
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
|
||||
}
|
||||
if (AdminConstants.USERNAME_ADMIN.equals(admin.getUsername())) {
|
||||
if (AdminConstants.USERNAME_ADMIN.equals(admin.getUsername())
|
||||
|| AdminConstants.USERNAME_DEMO.equals(admin.getUsername())) { // 特殊账号,不允许编辑
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE.getCode());
|
||||
}
|
||||
// 如果状态相同,则返回错误
|
||||
|
@ -132,7 +139,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
adminMapper.updateById(updateAdmin);
|
||||
// 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
|
||||
if (CommonStatusEnum.DISABLE.getValue().equals(adminUpdateStatusDTO.getStatus())) {
|
||||
oauth2Service.removeToken(adminUpdateStatusDTO.getId());
|
||||
oauth2Service.removeToken(new OAuth2RemoveTokenByUserDTO().setUserId(adminId).setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
}
|
||||
// TODO 插入操作日志
|
||||
// 返回成功
|
||||
|
@ -234,8 +241,11 @@ public class AdminServiceImpl implements AdminService {
|
|||
}
|
||||
}
|
||||
}
|
||||
// 获得用户
|
||||
AdminDO admin = adminMapper.selectById(adminId);
|
||||
// 返回成功
|
||||
return new AdminAuthorizationBO().setId(adminId).setRoleIds(adminRoleIds);
|
||||
return new AdminAuthorizationBO().setId(adminId).setUsername(admin.getUsername())
|
||||
.setRoleIds(adminRoleIds);
|
||||
}
|
||||
|
||||
private String encodePassword(String password) {
|
||||
|
|
|
@ -7,6 +7,8 @@ import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
|||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
|
||||
import cn.iocoder.mall.admin.convert.OAuth2Convert;
|
||||
import cn.iocoder.mall.admin.dao.OAuth2AccessTokenMapper;
|
||||
import cn.iocoder.mall.admin.dao.OAuth2RefreshTokenMapper;
|
||||
|
@ -59,18 +61,37 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除管理员对应的 Token
|
||||
*
|
||||
* @param adminId 管理员编号
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeToken(Integer adminId) {
|
||||
public void removeToken(OAuth2RemoveTokenByUserDTO oauth2RemoveTokenByUserDTO) {
|
||||
Integer userId = oauth2RemoveTokenByUserDTO.getUserId();
|
||||
Integer userType = oauth2RemoveTokenByUserDTO.getUserType();
|
||||
// 设置 access token 失效
|
||||
oauth2AccessTokenMapper.updateToInvalidByAdminId(adminId);
|
||||
oauth2AccessTokenMapper.updateToInvalid(userId, userType);
|
||||
// 设置 refresh token 失效
|
||||
oauth2RefreshTokenMapper.updateToInvalidByAdminId(adminId);
|
||||
oauth2RefreshTokenMapper.updateToInvalid(userId, userType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenBO refreshToken(OAuth2RefreshTokenDTO oauth2RefreshTokenDTO) {
|
||||
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectById(oauth2RefreshTokenDTO.getRefreshToken());
|
||||
// 校验刷新令牌是否合法
|
||||
if (refreshTokenDO == null) { // 不存在
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND.getCode());
|
||||
}
|
||||
if (refreshTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_EXPIRED.getCode());
|
||||
}
|
||||
if (!refreshTokenDO.getValid()) { // 无效
|
||||
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_INVALID.getCode());
|
||||
}
|
||||
// 标记 refreshToken 对应的 accessToken 都不合法
|
||||
oauth2AccessTokenMapper.updateToInvalidByRefreshToken(oauth2RefreshTokenDTO.getRefreshToken());
|
||||
// 创建访问令牌
|
||||
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(refreshTokenDO.getUserId(), refreshTokenDO.getUserType(),
|
||||
refreshTokenDO.getId());
|
||||
// 转换返回
|
||||
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
/**
|
||||
* @author Sin
|
||||
* @time 2019/5/16 10:52 AM
|
||||
*/
|
||||
package cn.iocoder.mall.admin;
|
|
@ -1,15 +1,14 @@
|
|||
package cn.iocoder.mall.user.application.controller.users;
|
||||
|
||||
import cn.iocoder.common.framework.constant.UserTypeEnum;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
||||
import cn.iocoder.mall.user.api.MobileCodeService;
|
||||
import cn.iocoder.mall.user.api.OAuth2Service;
|
||||
import cn.iocoder.mall.user.api.UserService;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
|
||||
import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO;
|
||||
import cn.iocoder.mall.user.application.convert.PassportConvert;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersAccessTokenVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
@ -26,7 +25,7 @@ import static cn.iocoder.common.framework.vo.CommonResult.success;
|
|||
@Api("Passport 模块")
|
||||
public class PassportController {
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version}")
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}")
|
||||
private OAuth2Service oauth2Service;
|
||||
@Reference(validation = "true", version = "${dubbo.provider.UserService.version}")
|
||||
private UserService userService;
|
||||
|
@ -40,14 +39,12 @@ public class PassportController {
|
|||
// return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
|
||||
// }
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("/mobile/register")
|
||||
@ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建")
|
||||
public CommonResult<UserAuthenticationBO> mobileRegister(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO) {
|
||||
return success(userService.authenticationByMobileCode(userAuthenticationByMobileCodeDTO));
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("mobile/send_register_code")
|
||||
@ApiOperation(value = "发送手机验证码")
|
||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300")
|
||||
|
@ -59,24 +56,21 @@ public class PassportController {
|
|||
// TODO 芋艿,改绑手机号
|
||||
|
||||
// TODO 功能:qq 登陆
|
||||
@PermitAll
|
||||
@PostMapping("/qq/login")
|
||||
public String qqLogin() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO 功能:qq 绑定
|
||||
@PermitAll
|
||||
@PostMapping("/qq/bind")
|
||||
public String qqBind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("/refresh_token") // TODO 功能:刷新 token
|
||||
public CommonResult<UsersAccessTokenVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
OAuth2AccessTokenBO result = oauth2Service.refreshToken(refreshToken);
|
||||
return success(PassportConvert.INSTANCE.convert2(result));
|
||||
public CommonResult<OAuth2AccessTokenBO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
return success(oauth2Service.refreshToken(new OAuth2RefreshTokenDTO().setRefreshToken(refreshToken)
|
||||
.setUserType(UserTypeEnum.USER.getValue())));
|
||||
}
|
||||
|
||||
// TODO 功能:退出,销毁 token
|
||||
|
|
|
@ -6,6 +6,7 @@ import cn.iocoder.mall.user.api.bo.UserBO;
|
|||
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
|
||||
import cn.iocoder.mall.user.application.convert.UserConvert;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersUserVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.RequiresLogin;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
@ -23,6 +24,7 @@ public class UserController {
|
|||
private UserService userService;
|
||||
|
||||
@GetMapping("/info")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "用户信息")
|
||||
public CommonResult<UsersUserVO> info() {
|
||||
UserBO userResult = userService.getUser(UserSecurityContextHolder.getContext().getUserId());
|
||||
|
@ -30,6 +32,7 @@ public class UserController {
|
|||
}
|
||||
|
||||
@PostMapping("/update_avatar")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "更新头像")
|
||||
public CommonResult<Boolean> updateAvatar(@RequestParam("avatar") String avatar) {
|
||||
// 创建
|
||||
|
@ -40,6 +43,7 @@ public class UserController {
|
|||
}
|
||||
|
||||
@PostMapping("/update_nickname")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "更新昵称")
|
||||
public CommonResult<Boolean> updateNickname(@RequestParam("nickname") String nickname) {
|
||||
// 创建
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package cn.iocoder.mall.user.application.convert;
|
||||
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersAccessTokenVO;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersMobileRegisterVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface PassportConvert {
|
||||
|
||||
PassportConvert INSTANCE = Mappers.getMapper(PassportConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
UsersMobileRegisterVO convert(OAuth2AccessTokenBO oauth2AccessTokenBO);
|
||||
|
||||
@Mappings({})
|
||||
UsersAccessTokenVO convert2(OAuth2AccessTokenBO result);
|
||||
|
||||
}
|
|
@ -4,7 +4,9 @@ import io.swagger.annotations.ApiModel;
|
|||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
@ -39,13 +41,15 @@ public class UserAddressAddPO implements Serializable {
|
|||
@NotNull(message = "手机号为不能为空!")
|
||||
@Size(min = 11, max = 11, message = "手机号为 11 位!")
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 收件详细地址
|
||||
*/
|
||||
@ApiModelProperty("收件详细地址")
|
||||
@NotNull(message = "详细地址不能为空")
|
||||
@Size(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!")
|
||||
@NotEmpty(message = "详细地址不能为空")
|
||||
@Length(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!")
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 收件详细地址
|
||||
*/
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package cn.iocoder.mall.user.sdk.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* URL 是否允许所有都可访问。即用户不登陆,就可以访问指定 URL 。
|
||||
*
|
||||
* 例如说,注册接口,用户是不需要登陆,就可以访问的。
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // ElementType.TYPE 暂时不支持类级别。为了减少判断,略微提升性能。
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PermitAll {
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.iocoder.mall.user.sdk.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 要求用户登录注解。通过将该注解添加到 Controller 上,会自动校验用户是否登陆。
|
||||
*
|
||||
* 默认请求下,用户访问的 API 接口,无需登陆。主要的考虑是,
|
||||
* 1. 需要用户登陆的接口,本身会获取在线用户的编号。如果不添加 @RequiresLogin 注解就会报错。
|
||||
* 2. 大多数情况下,用户的 API 接口无需登陆。
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresLogin {
|
||||
}
|
|
@ -9,7 +9,7 @@ import cn.iocoder.mall.admin.api.OAuth2Service;
|
|||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import cn.iocoder.mall.user.sdk.annotation.RequiresLogin;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContext;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
|
@ -49,8 +49,8 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||
|
||||
// 进行鉴权
|
||||
HandlerMethod method = (HandlerMethod) handler;
|
||||
boolean isPermitAll = method.hasMethodAnnotation(PermitAll.class);
|
||||
if (!isPermitAll) { // 如果需要鉴权
|
||||
boolean requiresLogin = method.hasMethodAnnotation(RequiresLogin.class);
|
||||
if (requiresLogin) { // 如果需要鉴权
|
||||
if (serviceException != null) { // 认证失败,抛出上面认证失败的 ServiceException 异常
|
||||
throw serviceException;
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package cn.iocoder.mall.user.api;
|
||||
|
||||
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||
|
||||
@Deprecated
|
||||
public interface OAuth2Service {
|
||||
|
||||
/**
|
||||
* 校验访问令牌,获取身份信息( 不包括 accessToken 等等 )
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return 授权信息
|
||||
*/
|
||||
OAuth2AuthenticationBO checkToken(String accessToken);
|
||||
|
||||
OAuth2AccessTokenBO refreshToken(String refreshToken);
|
||||
|
||||
// TODO @see 移除 token
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package cn.iocoder.mall.user.api;
|
||||
|
||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
||||
|
||||
@Deprecated
|
||||
public interface UserAccessLogService {
|
||||
|
||||
void addUserAccessLog(UserAccessLogAddDTO userAccessLogAddDTO);
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package cn.iocoder.mall.user.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AccessTokenBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
private String refreshToken;
|
||||
/**
|
||||
* 过期时间,单位:秒。
|
||||
*/
|
||||
private Integer expiresIn;
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package cn.iocoder.mall.user.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AuthenticationBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package cn.iocoder.mall.user.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户访问日志添加 DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class UserAccessLogAddDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号 - 空
|
||||
*/
|
||||
public static final Integer USER_ID_NULL = 0;
|
||||
|
||||
/**
|
||||
* 用户编号.
|
||||
*
|
||||
* 当用户为空时,该值为0
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
@NotNull(message = "访问地址不能为空")
|
||||
private String uri;
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
@NotNull(message = "请求参数不能为空")
|
||||
private String queryString;
|
||||
/**
|
||||
* http 方法
|
||||
*/
|
||||
@NotNull(message = "http 请求方法不能为空")
|
||||
private String method;
|
||||
/**
|
||||
* User Agent
|
||||
*/
|
||||
@NotNull(message = "User-Agent 不能为空")
|
||||
private String userAgent;
|
||||
/**
|
||||
* ip
|
||||
*/
|
||||
@NotNull(message = "ip 不能为空")
|
||||
private String ip;
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
@NotNull(message = "请求时间不能为空")
|
||||
private Date startTime;
|
||||
/**
|
||||
* 响应时长 -- 毫秒级
|
||||
*/
|
||||
@NotNull(message = "响应时长不能为空")
|
||||
private Integer responseTime;
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package cn.iocoder.mall.user.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface OAuth2Convert {
|
||||
|
||||
OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(source = "id", target = "accessToken")
|
||||
})
|
||||
OAuth2AccessTokenBO convertToAccessToken(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
default OAuth2AccessTokenBO convertToAccessTokenWithExpiresIn(OAuth2AccessTokenDO oauth2AccessTokenDO) {
|
||||
return this.convertToAccessToken(oauth2AccessTokenDO)
|
||||
.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
|
||||
}
|
||||
|
||||
@Mappings({})
|
||||
OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package cn.iocoder.mall.user.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserAccessLogDO;
|
||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface UserAccessLogConvert {
|
||||
|
||||
UserAccessLogConvert INSTANCE = Mappers.getMapper(UserAccessLogConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
UserAccessLogDO convert(UserAccessLogAddDTO adminAccessLogAddDTO);
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2AccessTokenDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OAuth2AccessTokenMapper {
|
||||
|
||||
void insert(OAuth2AccessTokenDO entity);
|
||||
|
||||
OAuth2AccessTokenDO selectByTokenId(String tokenId);
|
||||
|
||||
void updateToInvalidByUserId(@Param("userId") Integer userId);
|
||||
|
||||
void updateToInvalidByRefreshToken(@Param("refreshToken") String refreshToken);
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2RefreshTokenDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OAuth2RefreshTokenMapper {
|
||||
|
||||
void insert(OAuth2RefreshTokenDO entity);
|
||||
|
||||
void updateToInvalidByUserId(@Param("userId") Integer userId);
|
||||
|
||||
OAuth2RefreshTokenDO selectById(@Param("id") String id);
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserAccessLogDO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserAccessLogMapper {
|
||||
|
||||
void insert(UserAccessLogDO entity);
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue