Merge remote-tracking branch 'origin/master'
# Conflicts: # system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsYunPianPlatform.javapull/1/head
						commit
						1e3ea29dbb
					
				
							
								
								
									
										13
									
								
								README.md
								
								
								
								
							
							
						
						
									
										13
									
								
								README.md
								
								
								
								
							|  | @ -30,19 +30,26 @@ | ||||||
| 
 | 
 | ||||||
| # 演示 | # 演示 | ||||||
| 
 | 
 | ||||||
|  | > 艿艿:目前的开发者,都是后端出身。所以,一帮没有审美自觉的人,撸出来的前端界面,可能是东半球倒数第二难看。 | ||||||
|  | > | ||||||
|  | > 迫切希望,有前端能力不错的小伙伴,加入我们,一起来完善「一个商城」。 | ||||||
|  | > | ||||||
|  | > 啊啊啊!我好像做店铺装修功能。 | ||||||
|  | 
 | ||||||
| ## H5 商城 | ## H5 商城 | ||||||
| 
 | 
 | ||||||
| [体验传送门](http://h5.shop.iocoder.cn:18099) | [体验传送门](http://h5.shop.iocoder.cn:18099) | ||||||
| 
 | 
 | ||||||
| TODO 此处应有一个演示的装逼 GIF 图。 |  | ||||||
| 
 | 
 | ||||||
| ## 管理后台 | ## 管理后台 | ||||||
| 
 | 
 | ||||||
| [体验传送门](http://admin.shop.iocoder.cn:18099) | [体验传送门](http://admin.shop.iocoder.cn:18099) | ||||||
| 
 | 
 | ||||||
| TODO 暂时不提供管理后台的账号密码,等后面提供。 | * 账号:yudaoyuanma | ||||||
|  | * 密码:yudaoyuanma | ||||||
| 
 | 
 | ||||||
| TODO 此处应有一个演示的装逼 GIF 图。 |  | ||||||
| 
 | 
 | ||||||
| ## 其它演示 | ## 其它演示 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -35,4 +35,8 @@ public class StringUtil { | ||||||
|         return org.apache.commons.lang3.StringUtils.substring(str, start); |         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.constant.MallConstants; | ||||||
| import cn.iocoder.common.framework.servlet.CorsFilter; | 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.spring.boot.web.interceptor.AccessLogInterceptor; | ||||||
| import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor; | import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor; | ||||||
| import cn.iocoder.mall.spring.boot.web.handler.GlobalExceptionHandler; | import cn.iocoder.mall.spring.boot.web.handler.GlobalExceptionHandler; | ||||||
|  | @ -34,6 +35,12 @@ public class AdminMVCAutoConfiguration implements WebMvcConfigurer { | ||||||
|         return new AdminSecurityInterceptor(); |         return new AdminSecurityInterceptor(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Bean | ||||||
|  |     @ConditionalOnMissingBean(AdminDemoInterceptor.class) | ||||||
|  |     public AdminDemoInterceptor adminDemoInterceptor() { | ||||||
|  |         return new AdminDemoInterceptor(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Bean |     @Bean | ||||||
|     @ConditionalOnMissingBean(GlobalResponseBodyHandler.class) |     @ConditionalOnMissingBean(GlobalResponseBodyHandler.class) | ||||||
|     public GlobalResponseBodyHandler globalReturnValueHandler() { |     public GlobalResponseBodyHandler globalReturnValueHandler() { | ||||||
|  | @ -50,6 +57,7 @@ public class AdminMVCAutoConfiguration implements WebMvcConfigurer { | ||||||
|     public void addInterceptors(InterceptorRegistry registry) { |     public void addInterceptors(InterceptorRegistry registry) { | ||||||
|         registry.addInterceptor(adminAccessLogInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**"); |         registry.addInterceptor(adminAccessLogInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**"); | ||||||
|         registry.addInterceptor(adminSecurityInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**"); |         registry.addInterceptor(adminSecurityInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**"); | ||||||
|  |         registry.addInterceptor(adminDemoInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Bean |     @Bean | ||||||
|  |  | ||||||
|  | @ -29,4 +29,6 @@ | ||||||
| - 用户相关 | - 用户相关 | ||||||
|     - [x] 登陆 |     - [x] 登陆 | ||||||
|     - [x] 注册 |     - [x] 注册 | ||||||
|     - [ ] 个人信息 |     - [x] 个人信息 | ||||||
|  |     - [ ] 手机改绑 | ||||||
|  |     - [ ] 微信登陆 | ||||||
|  |  | ||||||
|  | @ -10,31 +10,48 @@ | ||||||
|     - [ ] 支付单 20% 【待认领】 |     - [ ] 支付单 20% 【待认领】 | ||||||
|     - [ ] 退款单 20% 【待认领】 |     - [ ] 退款单 20% 【待认领】 | ||||||
|     - TODO 需要补充 |     - TODO 需要补充 | ||||||
|  | - [ ] 店铺装修【迫切需要靠谱前端一起做】 | ||||||
|  |     - [ ] H5 装修 | ||||||
|  |     - [ ] 小程序装修 | ||||||
|  |     - [ ] 自定义页面 | ||||||
| - [ ] 商品管理 | - [ ] 商品管理 | ||||||
|     - [x] 发布商品 |     - [x] 发布商品 | ||||||
|     - [x] 商品列表 |     - [x] 商品列表 | ||||||
|     - [x] 展示类目 |     - [x] 展示类目 | ||||||
|     - [ ] 品牌管理【待认领】 |     - [ ] 品牌管理【开发中 @黑子】 | ||||||
|  |     - [ ] 商品标签 | ||||||
| - [ ] 订单管理 | - [ ] 订单管理 | ||||||
|     - [ ] 销售单 开发中 |     - [x] 销售单 | ||||||
|     - [ ] 售后单 开发中 |     - [x] 售后单 | ||||||
|     - [ ] 订单评价【开发中】 |     - [ ] 订单评价【开发中 @wang171776704】 | ||||||
| - [ ] 会员管理 | - [ ] 会员管理 | ||||||
|     - [ ] 会员资料 20%【待认领】 |     - [ ] 会员资料 20%【待认领】 | ||||||
|  |     - [ ] 会员等级 | ||||||
|  |     - [ ] 会员积分 | ||||||
|  |     - [ ] 用户标签 | ||||||
|     - TODO 需要补充 |     - TODO 需要补充 | ||||||
| - [ ] 营销管理 | - [ ] 营销管理 | ||||||
|     - [x] 首页广告 |     - [x] 首页广告 | ||||||
|     - [x] 商品推荐 |     - [x] 商品推荐 | ||||||
|     - [x] 优惠劵 |     - [x] 优惠劵 | ||||||
|     - [ ] 优惠码【待认领】 |     - [ ] 优惠码【开发中 @native8623 2019-05-17】 | ||||||
|     - [ ] 满减送 20% 【待认领】 |     - [ ] 满减送 20% 【待认领】 | ||||||
|     - [ ] 限制折扣 20% 【待认领】 |     - [ ] 限制折扣 20% 【待认领】 | ||||||
|     - [ ] 多人拼团【待认领】 |     - [ ] 多人拼团【待认领】 | ||||||
|  |     - [ ] 积分商城 | ||||||
|  |     - [ ] 问卷调查 | ||||||
|  |     - [ ] 幸运大转盘 | ||||||
|  | - [ ] 分销管理 | ||||||
|  |     - [ ] 分销设置 | ||||||
|  |     - [ ] 分销员管理 | ||||||
|  |     - [ ] 提现管理 | ||||||
| - [ ] 系统管理 | - [ ] 系统管理 | ||||||
|     - [x] 员工管理 |     - [x] 员工管理 | ||||||
|     - [x] 角色管理 <!--【前端页面需要细化下】--> |     - [x] 角色管理 <!--【前端页面需要细化下】--> | ||||||
|     - [ ] 权限管理 |     - [x] 权限管理 <!--【前端页面需要细化下】--> | ||||||
|     - [ ] 短信管理 |     - [ ] 部门管理【待认领】 | ||||||
|  |     - [x] 数据字典 | ||||||
|  |     - [ ] 短信管理【开发中 @小范】 | ||||||
|         - [ ] 短信模板 |         - [ ] 短信模板 | ||||||
|         - [ ] 发送日志 |         - [ ] 发送日志 | ||||||
|     - [ ] 员工操作日志 |     - [ ] 员工操作日志 | ||||||
|  |  | ||||||
|  | @ -229,11 +229,11 @@ service.interceptors.response.use( | ||||||
| 
 | 
 | ||||||
|       // TODO token 过期
 |       // TODO token 过期
 | ||||||
|       // TODO 需要拿 refresh token 置换
 |       // TODO 需要拿 refresh token 置换
 | ||||||
|       if (code === 1001001011 // 访问令牌不存在
 |       if (code === 1002001011 // 访问令牌不存在
 | ||||||
|           || code === 1001001013 // 访问令牌已失效
 |           || code === 1002001013 // 访问令牌已失效
 | ||||||
|           || code === 1001001021 // 刷新令牌不存在
 |           || code === 1002001017 // 刷新令牌不存在
 | ||||||
|           || code === 1001001022 // 刷新令牌已过期
 |           || code === 1002001018 // 刷新令牌已过期
 | ||||||
|           || code === 1001001023) {  // 刷新令牌已失效
 |           || code === 1002001019) {  // 刷新令牌已失效
 | ||||||
|         Dialog.confirm({ |         Dialog.confirm({ | ||||||
|           title: '系统提示', |           title: '系统提示', | ||||||
|           message: res.message, |           message: res.message, | ||||||
|  | @ -249,7 +249,7 @@ service.interceptors.response.use( | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|       } else if (code === 1001001012) { // 访问令牌已过期
 |       } else if (code === 1002001012) { // 访问令牌已过期
 | ||||||
|         return refreshToken(response); |         return refreshToken(response); | ||||||
|       } else { |       } else { | ||||||
|         Dialog.alert({ |         Dialog.alert({ | ||||||
|  |  | ||||||
|  | @ -69,7 +69,7 @@ export default { | ||||||
|       let that = this; |       let that = this; | ||||||
|       let response = doPassportMobileRegister(this.mobile, this.code); |       let response = doPassportMobileRegister(this.mobile, this.code); | ||||||
|       response.then(data => { |       response.then(data => { | ||||||
|         setLoginToken(data.accessToken, data.refreshToken); |         setLoginToken(data.token.accessToken, data.token.refreshToken); | ||||||
|         Dialog.alert({ |         Dialog.alert({ | ||||||
|           title: '系统提示', |           title: '系统提示', | ||||||
|           message: '登陆成功', |           message: '登陆成功', | ||||||
|  |  | ||||||
|  | @ -50,21 +50,6 @@ | ||||||
|             <div class="category-div"> |             <div class="category-div"> | ||||||
|                 <!--<h4>热门分类</h4>--> |                 <!--<h4>热门分类</h4>--> | ||||||
|                 <ul> |                 <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"> |                     <li v-for="category in childCategories"> | ||||||
|                         <router-link :to="'/products/list?title=' + activeCategory.name + '&cidFirst=' + activeCategory.id + '&cidSecond=' + category.id"> |                         <router-link :to="'/products/list?title=' + activeCategory.name + '&cidFirst=' + activeCategory.id + '&cidSecond=' + category.id"> | ||||||
|                             <img :src="category.picUrl" /> |                             <img :src="category.picUrl" /> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| <template> | <template> | ||||||
|     <div> |     <div> | ||||||
|         <headerNav title="个人信息"/> |         <headerNav title="个人信息"/> | ||||||
|         <van-cell-group> |         <van-cell-group title="基础资料"> | ||||||
|             <!--<van-cell title="修改个人信息"  is-link />--> |             <!--<van-cell title="修改个人信息"  is-link />--> | ||||||
|             <!--<van-cell title="修改登录密码"  is-link />--> |             <!--<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> | ||||||
| 
 | 
 | ||||||
|  |         <van-cell-group title="密保资料"> | ||||||
|  |             <van-cell title="手机号" :value="user.mobile" /> | ||||||
|  |         </van-cell-group> | ||||||
|  | 
 | ||||||
|         <!-- 昵称修改弹出 --> |         <!-- 昵称修改弹出 --> | ||||||
|         <van-dialog |         <van-dialog | ||||||
|                 v-model="showNicknameDialog" |                 v-model="showNicknameDialog" | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ import cn.iocoder.mall.order.application.convert.OrderReturnConvert; | ||||||
| import cn.iocoder.mall.order.application.po.admin.OrderReturnQueryPO; | import cn.iocoder.mall.order.application.po.admin.OrderReturnQueryPO; | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
| 
 | 
 | ||||||
|  | @ -26,8 +25,7 @@ import javax.servlet.http.HttpServletRequest; | ||||||
| @Api("订单退货(admins api)") | @Api("订单退货(admins api)") | ||||||
| public class AdminOrderReturnController { | public class AdminOrderReturnController { | ||||||
| 
 | 
 | ||||||
|     @Autowired |     @Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}") | ||||||
|     @Reference(validation = "true") |  | ||||||
|     private OrderReturnService orderReturnService; |     private OrderReturnService orderReturnService; | ||||||
| 
 | 
 | ||||||
|     @GetMapping("list") |     @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.OrderItemBO; | ||||||
| import cn.iocoder.mall.order.api.bo.OrderPageBO; | import cn.iocoder.mall.order.api.bo.OrderPageBO; | ||||||
| import cn.iocoder.mall.order.api.bo.OrderRecipientBO; | 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.OrderConvertAPP; | ||||||
| import cn.iocoder.mall.order.application.convert.OrderDeliveryConvert; | import cn.iocoder.mall.order.application.convert.OrderDeliveryConvert; | ||||||
| import cn.iocoder.mall.order.application.po.admin.OrderDeliverPO; | 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.Api; | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
| 
 | 
 | ||||||
|  | @ -32,7 +33,7 @@ import java.util.List; | ||||||
| @Api(value = "订单 API(admins)") | @Api(value = "订单 API(admins)") | ||||||
| public class AdminsOrderController { | public class AdminsOrderController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true") |     @Reference(validation = "true", version = "${dubbo.provider.OrderService.version}") | ||||||
|     private OrderService orderService; |     private OrderService orderService; | ||||||
| 
 | 
 | ||||||
|     @GetMapping("page") |     @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.order.application.vo.UsersOrderConfirmCreateVO; | ||||||
| import cn.iocoder.mall.promotion.api.CouponService; | import cn.iocoder.mall.promotion.api.CouponService; | ||||||
| import cn.iocoder.mall.promotion.api.bo.CouponCardAvailableBO; | 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 cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
|  | @ -41,19 +42,23 @@ import static cn.iocoder.common.framework.vo.CommonResult.success; | ||||||
|  */ |  */ | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("users/order") | @RequestMapping("users/order") | ||||||
| @Api(description = "用户订单") | @Api(description = "用户订单") // TODO FROM 芋艿 to 小范,description 已经废弃啦
 | ||||||
| public class OrderController { | public class OrderController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true") |     @Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}") | ||||||
|     private OrderService orderService; |     private OrderService orderService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.provider.CartService.version}") |     @Reference(validation = "true", version = "${dubbo.provider.CartService.version}") | ||||||
|     private CartService cartService; |     private CartService cartService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") | ||||||
|     private DataDictService dataDictService; |     private DataDictService dataDictService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}") | ||||||
|     private CouponService couponService; |     private CouponService couponService; | ||||||
| 
 | 
 | ||||||
|     @GetMapping("order_page") |     @GetMapping("order_page") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("订单分页") |     @ApiOperation("订单分页") | ||||||
|     public CommonResult<OrderPageBO> getOrderPage(@Validated OrderQueryDTO orderQueryDTO) { |     public CommonResult<OrderPageBO> getOrderPage(@Validated OrderQueryDTO orderQueryDTO) { | ||||||
|         Integer userId = UserSecurityContextHolder.getContext().getUserId(); |         Integer userId = UserSecurityContextHolder.getContext().getUserId(); | ||||||
|  | @ -62,6 +67,7 @@ public class OrderController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("create_order") |     @PostMapping("create_order") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("创建订单") |     @ApiOperation("创建订单") | ||||||
|     public CommonResult<OrderCreateBO> createOrder(@RequestBody @Validated OrderCreatePO orderCreatePO, |     public CommonResult<OrderCreateBO> createOrder(@RequestBody @Validated OrderCreatePO orderCreatePO, | ||||||
|                                                    HttpServletRequest request) { |                                                    HttpServletRequest request) { | ||||||
|  | @ -72,6 +78,7 @@ public class OrderController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("create_order_from_cart") |     @PostMapping("create_order_from_cart") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("创建订单购物车") |     @ApiOperation("创建订单购物车") | ||||||
|     public CommonResult<OrderCreateBO> createOrderFromCart(@RequestParam("userAddressId") Integer userAddressId, |     public CommonResult<OrderCreateBO> createOrderFromCart(@RequestParam("userAddressId") Integer userAddressId, | ||||||
|                                                            @RequestParam(value = "couponCardId", required = false) Integer couponCardId, |                                                            @RequestParam(value = "couponCardId", required = false) Integer couponCardId, | ||||||
|  | @ -99,6 +106,7 @@ public class OrderController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @GetMapping("confirm_create_order") |     @GetMapping("confirm_create_order") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("确认创建订单") |     @ApiOperation("确认创建订单") | ||||||
|     public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder(@RequestParam("skuId") Integer skuId, |     public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder(@RequestParam("skuId") Integer skuId, | ||||||
|                                                                          @RequestParam("quantity") Integer quantity, |                                                                          @RequestParam("quantity") Integer quantity, | ||||||
|  | @ -118,6 +126,7 @@ public class OrderController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("confirm_receiving") |     @PostMapping("confirm_receiving") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("确认收货") |     @ApiOperation("确认收货") | ||||||
|     public CommonResult confirmReceiving(@RequestParam("orderId") Integer orderId) { |     public CommonResult confirmReceiving(@RequestParam("orderId") Integer orderId) { | ||||||
|         Integer userId = UserSecurityContextHolder.getContext().getUserId(); |         Integer userId = UserSecurityContextHolder.getContext().getUserId(); | ||||||
|  | @ -125,6 +134,7 @@ public class OrderController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @GetMapping("info") |     @GetMapping("info") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation("订单详情") |     @ApiOperation("订单详情") | ||||||
|     public CommonResult<OrderInfoBO> orderInfo(@RequestParam("orderId") Integer orderId) { |     public CommonResult<OrderInfoBO> orderInfo(@RequestParam("orderId") Integer orderId) { | ||||||
|         Integer userId = UserSecurityContextHolder.getContext().getUserId(); |         Integer userId = UserSecurityContextHolder.getContext().getUserId(); | ||||||
|  |  | ||||||
|  | @ -35,8 +35,9 @@ import java.util.stream.Collectors; | ||||||
| @Api(description = "订单物流信息") | @Api(description = "订单物流信息") | ||||||
| public class OrderLogisticsController { | public class OrderLogisticsController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true") |     @Reference(validation = "true", version = "${dubbo.provider.OrderLogisticsService.version}") | ||||||
|     private OrderLogisticsService orderLogisticsService; |     private OrderLogisticsService orderLogisticsService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") | ||||||
|     private DataDictService dataDictService; |     private DataDictService dataDictService; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,8 +25,9 @@ import java.util.List; | ||||||
| @RequestMapping("users/order_return") | @RequestMapping("users/order_return") | ||||||
| public class OrderReturnController { | public class OrderReturnController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true") |     @Reference(validation = "true", version = "${dubbo.provider.OrderReturnService.version}") | ||||||
|     private OrderReturnService orderReturnService; |     private OrderReturnService orderReturnService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.DataDictService.version}") | ||||||
|     private DataDictService dataDictService; |     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.order.application.vo.UsersOrderConfirmCreateVO; | ||||||
| import cn.iocoder.mall.promotion.api.CouponService; | import cn.iocoder.mall.promotion.api.CouponService; | ||||||
| import cn.iocoder.mall.promotion.api.bo.CouponCardAvailableBO; | 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 cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
|  | @ -31,8 +30,10 @@ public class UsersCartController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.provider.CartService.version}") |     @Reference(validation = "true", version = "${dubbo.provider.CartService.version}") | ||||||
|     private CartService cartService; |     private CartService cartService; | ||||||
|     @Reference(validation = "true") | 
 | ||||||
|  |     @Reference(validation = "true", version = "${dubbo.provider.OrderService.version}") | ||||||
|     private OrderService orderService; |     private OrderService orderService; | ||||||
|  | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.CouponService.version}") | ||||||
|     private CouponService couponService; |     private CouponService couponService; | ||||||
| 
 | 
 | ||||||
|  | @ -125,7 +126,6 @@ public class UsersCartController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @GetMapping("/calc_sku_price") |     @GetMapping("/calc_sku_price") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<UsersCalcSkuPriceVO> calcSkuPrice(@RequestParam("skuId") Integer skuId) { |     public CommonResult<UsersCalcSkuPriceVO> calcSkuPrice(@RequestParam("skuId") Integer skuId) { | ||||||
|         // 计算 sku 的价格
 |         // 计算 sku 的价格
 | ||||||
|         CalcSkuPriceBO calcSkuPrice = cartService.calcSkuPrice(skuId); |         CalcSkuPriceBO calcSkuPrice = cartService.calcSkuPrice(skuId); | ||||||
|  |  | ||||||
|  | @ -127,7 +127,7 @@ public interface OrderService { | ||||||
|     CommonResult updateLogistics(OrderLogisticsUpdateDTO orderLogisticsDTO); |     CommonResult updateLogistics(OrderLogisticsUpdateDTO orderLogisticsDTO); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 删除订单 |      * 删除订单 // TODO FROM 芋艿 to 小范。删除订单,不要使用 deleted 字段,对于用户是删除,实际是隐藏。
 | ||||||
|      * |      * | ||||||
|      * @param id |      * @param id | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ import lombok.experimental.Accessors; | ||||||
|  */ |  */ | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @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 = "用户编号不能为空") |     @NotNull(message = "用户编号不能为空") | ||||||
|     private Integer userId; |     private Integer userId; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 优惠劵编号 |      * 优惠劵编号 | ||||||
|      */ |      */ | ||||||
|     private Integer couponCardId; |     private Integer couponCardId; | ||||||
|  | 
 | ||||||
|     @NotNull(message = "商品数组不能为空") |     @NotNull(message = "商品数组不能为空") | ||||||
|     private List<Item> items; |     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) {
 | //        } catch (IOException e) {
 | ||||||
| //            throw new RuntimeException(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; |  | ||||||
|  | @ -18,7 +18,7 @@ import lombok.experimental.Accessors; | ||||||
| public class OrderCommentDO extends BaseDO { | public class OrderCommentDO extends BaseDO { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 评论id |      * 评论id // TODO FROM 芋艿 TO wtz 中英文之间,要有空格
 | ||||||
|      */ |      */ | ||||||
|     private Integer id; |     private Integer id; | ||||||
| 
 | 
 | ||||||
|  | @ -103,7 +103,7 @@ public class OrderCommentDO extends BaseDO { | ||||||
|     private Integer replayCount; |     private Integer replayCount; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 点赞数 |      * 点赞数 // TODO FROM 芋艿 TO wtz collect 是收藏的意思,最好换个单词噢。
 | ||||||
|      */ |      */ | ||||||
|     private Integer collectCount; |     private Integer collectCount; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ import lombok.experimental.Accessors; | ||||||
| /** | /** | ||||||
|  * 商品评价回复表 |  * 商品评价回复表 | ||||||
|  * |  * | ||||||
|  |  * // TODO FROM 芋艿 TO wtz 商品评价回复表 =》订单评论回复表
 | ||||||
|  |  * | ||||||
|  * @author wtz |  * @author wtz | ||||||
|  * @time 2019-05-14 21:00 |  * @time 2019-05-14 21:00 | ||||||
|  * |  * | ||||||
|  | @ -28,7 +30,7 @@ public class OrderCommentReplayDO extends BaseDO { | ||||||
|     private Integer commentId; |     private Integer commentId; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 回复的类型 |      * 回复的类型 // TODO FROM 芋艿 TO wtz 记得加下枚举类
 | ||||||
|      */ |      */ | ||||||
|     private Integer replyType; |     private Integer replyType; | ||||||
| 
 | 
 | ||||||
|  | @ -73,7 +75,7 @@ public class OrderCommentReplayDO extends BaseDO { | ||||||
|     private String replyUserAvatar; |     private String replyUserAvatar; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 回复用户身份 |      * 回复用户身份 // TODO FROM 芋艿 TO wtz 【提示】userType 和 UserTypeEnum 记录保持一致。
 | ||||||
|      */ |      */ | ||||||
|     private Integer replyUserType; |     private Integer replyUserType; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| package cn.iocoder.mall.order.biz.dataobject; | package cn.iocoder.mall.order.biz.dataobject; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.common.framework.dataobject.BaseDO; | import cn.iocoder.common.framework.dataobject.BaseDO; | ||||||
| import cn.iocoder.common.framework.dataobject.DeletableDO; |  | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
|  | @ -17,6 +16,8 @@ import java.util.Date; | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class OrderReturnDO extends BaseDO { | public class OrderReturnDO extends BaseDO { | ||||||
| 
 | 
 | ||||||
|  |     // TODO FROM 芋艿 TO 小范,存储下支付中心的退款单号
 | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 编号自动增长 |      * 编号自动增长 | ||||||
|      */ |      */ | ||||||
|  | @ -24,6 +25,7 @@ public class OrderReturnDO extends BaseDO { | ||||||
|     /** |     /** | ||||||
|      * 服务号 |      * 服务号 | ||||||
|      */ |      */ | ||||||
|  |     // TODO FROM 芋艿 to 小范,换个名字,看着怪怪的 哈哈哈哈。
 | ||||||
|     private String serviceNumber; |     private String serviceNumber; | ||||||
|     /** |     /** | ||||||
|      * 订单编号 |      * 订单编号 | ||||||
|  | @ -54,6 +56,7 @@ public class OrderReturnDO extends BaseDO { | ||||||
|     /** |     /** | ||||||
|      * 问题描述 |      * 问题描述 | ||||||
|      */ |      */ | ||||||
|  |     // TODO FROM 芋艿 to 小范,describe 是动词,换成名词 description
 | ||||||
|     private String describe; |     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.OrderItemDO; | ||||||
| import cn.iocoder.mall.order.biz.dataobject.OrderReturnDO; | import cn.iocoder.mall.order.biz.dataobject.OrderReturnDO; | ||||||
| import cn.iocoder.mall.pay.api.PayRefundService; | 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.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.stereotype.Service; | 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.dao.*; | ||||||
| import cn.iocoder.mall.order.biz.dataobject.*; | import cn.iocoder.mall.order.biz.dataobject.*; | ||||||
| import cn.iocoder.mall.pay.api.PayTransactionService; | import cn.iocoder.mall.pay.api.PayTransactionService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO; | ||||||
| import cn.iocoder.mall.product.api.ProductSpuService; | import cn.iocoder.mall.product.api.ProductSpuService; | ||||||
| import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO; | import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO; | ||||||
| import cn.iocoder.mall.promotion.api.CouponService; | import cn.iocoder.mall.promotion.api.CouponService; | ||||||
|  | @ -79,7 +79,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|     public CommonResult<OrderPageBO> getOrderPage(OrderQueryDTO orderQueryDTO) { |     public CommonResult<OrderPageBO> getOrderPage(OrderQueryDTO orderQueryDTO) { | ||||||
| 
 | 
 | ||||||
|         int totalCount = orderMapper.selectPageCount(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)); |             return CommonResult.success(new OrderPageBO().setOrders(Collections.EMPTY_LIST).setTotal(0)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -92,7 +92,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
| 
 | 
 | ||||||
|         // 获取订单 id
 |         // 获取订单 id
 | ||||||
|         Set<Integer> orderIds = orderDOList.stream() |         Set<Integer> orderIds = orderDOList.stream() | ||||||
|                 .map(orderDO -> orderDO.getId()) |                 .map(orderDO -> orderDO.getId()) // TODO FROM 芋艿 to 小范,记得用 Lambda
 | ||||||
|                 .collect(Collectors.toSet()); |                 .collect(Collectors.toSet()); | ||||||
| 
 | 
 | ||||||
|         // 获取配送信息
 |         // 获取配送信息
 | ||||||
|  | @ -231,10 +231,10 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         // 设置 orderItem
 |         // 设置 orderItem
 | ||||||
|         Map<Integer, ProductSkuDetailBO> productSpuBOMap = productList |         Map<Integer, ProductSkuDetailBO> productSpuBOMap = productList | ||||||
|                 .stream().collect(Collectors.toMap(ProductSkuDetailBO::getId, o -> o)); // 商品 SKU 信息的集合
 |                 .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 -> |         calcOrderPrice.getItemGroups().forEach(itemGroup -> | ||||||
|                 itemGroup.getItems().forEach(item -> priceItemMap.put(item.getId(), item))); |                 itemGroup.getItems().forEach(item -> priceItemMap.put(item.getId(), item))); | ||||||
| 
 |         // 遍历 orderItemDOList 数组,将商品信息、商品价格,设置到其中
 | ||||||
|         for (OrderItemDO orderItemDO : orderItemDOList) { |         for (OrderItemDO orderItemDO : orderItemDOList) { | ||||||
|             ProductSkuDetailBO productSkuDetailBO = productSpuBOMap.get(orderItemDO.getSkuId()); |             ProductSkuDetailBO productSkuDetailBO = productSpuBOMap.get(orderItemDO.getSkuId()); | ||||||
|             if (productSkuDetailBO.getQuantity() <= 0) { |             if (productSkuDetailBO.getQuantity() <= 0) { | ||||||
|  | @ -267,6 +267,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         // order
 |         // order
 | ||||||
| 
 | 
 | ||||||
|         // TODO: 2019-04-11 Sin 订单号需要生成规则
 |         // TODO: 2019-04-11 Sin 订单号需要生成规则
 | ||||||
|  |         // TODO FROM 芋艿 to 小范:可以考虑抽象成一个方法,下面几个也是。
 | ||||||
|         String orderNo = UUID.randomUUID().toString().replace("-", "").substring(0, 16); |         String orderNo = UUID.randomUUID().toString().replace("-", "").substring(0, 16); | ||||||
| //        Integer totalAmount = orderCommon.calculatedAmount(orderItemDOList);
 | //        Integer totalAmount = orderCommon.calculatedAmount(orderItemDOList);
 | ||||||
| //        Integer totalPrice = orderCommon.calculatedPrice(orderItemDOList);
 | //        Integer totalPrice = orderCommon.calculatedPrice(orderItemDOList);
 | ||||||
|  | @ -323,10 +324,6 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         // 一次性插入
 |         // 一次性插入
 | ||||||
|         orderItemMapper.insert(orderItemDOList); |         orderItemMapper.insert(orderItemDOList); | ||||||
| 
 | 
 | ||||||
|         if (true) { |  | ||||||
|             throw new RuntimeException("测试 seata 事务回滚"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // 创建预订单
 |         // 创建预订单
 | ||||||
|         createPayTransaction(orderDO, orderItemDOList, orderCreateDTO.getIp()); |         createPayTransaction(orderDO, orderItemDOList, orderCreateDTO.getIp()); | ||||||
| 
 | 
 | ||||||
|  | @ -358,7 +355,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         return cartService.calcOrderPrice(calcOrderPriceDTO); |         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 暂时取第一个子订单商品信息
 |         // TODO sin 支付订单 orderSubject 暂时取第一个子订单商品信息
 | ||||||
|         String orderSubject = orderItems.get(0).getSkuName(); |         String orderSubject = orderItems.get(0).getSkuName(); | ||||||
|         Date expireTime = DateUtil.addDate(Calendar.MINUTE, PAY_EXPIRE_TIME); |         Date expireTime = DateUtil.addDate(Calendar.MINUTE, PAY_EXPIRE_TIME); | ||||||
|  | @ -441,6 +438,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|                 .setUpdateTime(null); |                 .setUpdateTime(null); | ||||||
| 
 | 
 | ||||||
|         // 关闭订单,修改状态 item
 |         // 关闭订单,修改状态 item
 | ||||||
|  |         // TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
 | ||||||
|         orderItemMapper.updateByOrderId( |         orderItemMapper.updateByOrderId( | ||||||
|                 orderId, |                 orderId, | ||||||
|                 new OrderItemDO().setStatus(OrderStatusEnum.CLOSED.getValue()) |                 new OrderItemDO().setStatus(OrderStatusEnum.CLOSED.getValue()) | ||||||
|  | @ -454,18 +452,18 @@ public class OrderServiceImpl implements OrderService { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional // TODO FROM 芋艿 TO 小范:泛型,一定要明确哈。
 | ||||||
|     public CommonResult orderDelivery(OrderDeliveryDTO orderDelivery) { |     public CommonResult orderDelivery(OrderDeliveryDTO orderDelivery) { | ||||||
|         List<Integer> orderItemIds = orderDelivery.getOrderItemIds(); |         List<Integer> orderItemIds = orderDelivery.getOrderItemIds(); | ||||||
| 
 | 
 | ||||||
|         // 获取所有订单 items
 |         // 获取所有订单 items // TODO FROM 芋艿 TO 小范,deleted 是默认条件,所以 by 里面可以不带哈
 | ||||||
|         List<OrderItemDO> allOrderItems = orderItemMapper.selectByDeletedAndOrderId(orderDelivery.getOrderId(), DeletedStatusEnum.DELETED_NO.getValue()); |         List<OrderItemDO> allOrderItems = orderItemMapper.selectByDeletedAndOrderId(orderDelivery.getOrderId(), DeletedStatusEnum.DELETED_NO.getValue()); | ||||||
| 
 | 
 | ||||||
|         // 当前需要发货订单,检查 id 和 status
 |         // 当前需要发货订单,检查 id 和 status
 | ||||||
|         List<OrderItemDO> needDeliveryOrderItems = allOrderItems.stream() |         List<OrderItemDO> needDeliveryOrderItems = allOrderItems.stream() | ||||||
|                 .filter(orderItemDO -> orderItemIds.contains(orderItemDO.getId()) |                 .filter(orderItemDO -> orderItemIds.contains(orderItemDO.getId()) | ||||||
|                         && OrderStatusEnum.WAIT_SHIPMENT.getValue() == orderItemDO.getStatus()) |                         && OrderStatusEnum.WAIT_SHIPMENT.getValue() == orderItemDO.getStatus()) | ||||||
|                 .collect(Collectors.toList()); |                 .collect(Collectors.toList()); // TODO 芋艿,如果这里只是比对数字,可以用 Lambda 求和,不需要弄成一个集合的
 | ||||||
|         // 发货订单,检查
 |         // 发货订单,检查
 | ||||||
|         if (needDeliveryOrderItems.size() != orderItemIds.size()) { |         if (needDeliveryOrderItems.size() != orderItemIds.size()) { | ||||||
|             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_DELIVERY_INCORRECT_DATA.getCode()); |             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_DELIVERY_INCORRECT_DATA.getCode()); | ||||||
|  | @ -482,6 +480,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         orderLogisticsMapper.insert(orderLogisticsDO); |         orderLogisticsMapper.insert(orderLogisticsDO); | ||||||
| 
 | 
 | ||||||
|         // 关联订单item 和 物流信息
 |         // 关联订单item 和 物流信息
 | ||||||
|  |         // TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题,然后判断下更新数量,不对,就抛出异常。
 | ||||||
|         orderItemMapper.updateByIds( |         orderItemMapper.updateByIds( | ||||||
|                 orderItemIds, |                 orderItemIds, | ||||||
|                 new OrderItemDO() |                 new OrderItemDO() | ||||||
|  | @ -495,6 +494,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|                         && !orderItemIds.contains(orderItemDO.getId())) |                         && !orderItemIds.contains(orderItemDO.getId())) | ||||||
|                 .collect(Collectors.toList()); |                 .collect(Collectors.toList()); | ||||||
|         if (unShippedOrderItems.size() <= 0) { |         if (unShippedOrderItems.size() <= 0) { | ||||||
|  |             // TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
 | ||||||
|             orderMapper.updateById( |             orderMapper.updateById( | ||||||
|                     new OrderDO() |                     new OrderDO() | ||||||
|                             .setId(orderDelivery.getOrderId()) |                             .setId(orderDelivery.getOrderId()) | ||||||
|  | @ -513,7 +513,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional // TODO FROM 芋艿 to 小范,先不做这个功能,电商一班不存在这个功能哈。
 | ||||||
|     public CommonResult deleteOrderItem(OrderItemDeletedDTO orderItemDeletedDTO) { |     public CommonResult deleteOrderItem(OrderItemDeletedDTO orderItemDeletedDTO) { | ||||||
|         Integer orderId = orderItemDeletedDTO.getOrderId(); |         Integer orderId = orderItemDeletedDTO.getOrderId(); | ||||||
|         List<Integer> orderItemIds = orderItemDeletedDTO.getOrderItemIds(); |         List<Integer> orderItemIds = orderItemDeletedDTO.getOrderItemIds(); | ||||||
|  | @ -562,6 +562,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_UNABLE_CONFIRM_ORDER.getCode()); |             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_UNABLE_CONFIRM_ORDER.getCode()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // TODO FROM 芋艿 TO 小范,更新的时候,where 里面带下 status 避免并发的问题
 | ||||||
|         orderMapper.updateById( |         orderMapper.updateById( | ||||||
|                 new OrderDO() |                 new OrderDO() | ||||||
|                         .setId(orderId) |                         .setId(orderId) | ||||||
|  | @ -617,7 +618,7 @@ public class OrderServiceImpl implements OrderService { | ||||||
|         if (updateCount <= 0) { |         if (updateCount <= 0) { | ||||||
|             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage(); |             return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage(); | ||||||
|         } |         } | ||||||
|         // TODO 芋艿 更新 OrderItemDO
 |         // TODO FROM 芋艿 to 小范,把更新 OrderItem 给补全。
 | ||||||
|         return "success"; |         return "success"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ mybatis-plus: | ||||||
|       id-type: auto |       id-type: auto | ||||||
|   mapper-locations: classpath*:mapper/*.xml |   mapper-locations: classpath*:mapper/*.xml | ||||||
|   type-aliases-package: cn.iocoder.mall.order.biz.dataobject |   type-aliases-package: cn.iocoder.mall.order.biz.dataobject | ||||||
|   config-location: classpath:mybatis-config.xml |  | ||||||
| 
 | 
 | ||||||
| # dubbo | # dubbo | ||||||
| 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.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.PayRefundService; | import cn.iocoder.mall.pay.api.PayRefundService; | ||||||
| import cn.iocoder.mall.pay.api.PayTransactionService; | import cn.iocoder.mall.pay.api.PayTransactionService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundPageBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO; | ||||||
| import cn.iocoder.mall.pay.application.convert.PayRefundConvert; | import cn.iocoder.mall.pay.application.convert.PayRefundConvert; | ||||||
| import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundPageVO; | import cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundPageVO; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | 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.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.PayTransactionService; | import cn.iocoder.mall.pay.api.PayTransactionService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionPageDTO; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.format.annotation.DateTimeFormat; | import org.springframework.format.annotation.DateTimeFormat; | ||||||
| import org.springframework.web.bind.annotation.GetMapping; | 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.util.HttpUtil; | ||||||
| import cn.iocoder.common.framework.vo.CommonResult; | import cn.iocoder.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.PayTransactionService; | import cn.iocoder.mall.pay.api.PayTransactionService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayChannelEnum; | 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 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.apache.dubbo.config.annotation.Reference; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  | @ -18,8 +21,11 @@ import javax.servlet.http.HttpServletRequest; | ||||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| 
 | 
 | ||||||
|  | import static cn.iocoder.common.framework.vo.CommonResult.success; | ||||||
|  | 
 | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("users/transaction") // TODO 芋艿,理论来说,是用户无关的。这里先酱紫先~
 | @RequestMapping("users/transaction") | ||||||
|  | @Api("【用户】支付交易 API") | ||||||
| public class UsersPayTransactionController { | public class UsersPayTransactionController { | ||||||
| 
 | 
 | ||||||
|     private Logger logger = LoggerFactory.getLogger(getClass()); |     private Logger logger = LoggerFactory.getLogger(getClass()); | ||||||
|  | @ -28,23 +34,19 @@ public class UsersPayTransactionController { | ||||||
|     private PayTransactionService payTransactionService; |     private PayTransactionService payTransactionService; | ||||||
| 
 | 
 | ||||||
|     @GetMapping("/get") |     @GetMapping("/get") | ||||||
|     // TODO result 后面改下
 |     @ApiOperation("获得支付交易") | ||||||
|     public CommonResult<PayTransactionBO> get(@RequestParam("appId") String appId, |     public CommonResult<PayTransactionBO> get(PayTransactionGetDTO payTransactionGetDTO) { | ||||||
|                                               @RequestParam("orderId") String orderId) { |         payTransactionGetDTO.setUserId(UserSecurityContextHolder.getContext().getUserId()); | ||||||
|         return payTransactionService.getTransaction(UserSecurityContextHolder.getContext().getUserId(), appId, orderId); |         return success(payTransactionService.getTransaction(payTransactionGetDTO)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("/submit") // TODO api 注释
 |     @PostMapping("/submit") | ||||||
|     // TODO result 后面改下
 |     @ApiOperation("提交支付交易") | ||||||
|     public CommonResult<PayTransactionSubmitBO> submit(HttpServletRequest request, |     public CommonResult<PayTransactionSubmitBO> submit(HttpServletRequest request, | ||||||
|                                                        @RequestParam("appId") String appId, |                                                        PayTransactionSubmitDTO payTransactionSubmitDTO) { | ||||||
|                                                        @RequestParam("orderId") String orderId, |         payTransactionSubmitDTO.setCreateIp(HttpUtil.getIp(request)); | ||||||
|                                                        @RequestParam("payChannel") Integer payChannel) { |  | ||||||
|         PayTransactionSubmitDTO payTransactionSubmitDTO = new PayTransactionSubmitDTO() |  | ||||||
|                 .setAppId(appId).setOrderId(orderId).setPayChannel(payChannel) |  | ||||||
|                 .setCreateIp(HttpUtil.getIp(request)); |  | ||||||
|         // 提交支付提交
 |         // 提交支付提交
 | ||||||
|         return payTransactionService.submitTransaction(payTransactionSubmitDTO); |         return success(payTransactionService.submitTransaction(payTransactionSubmitDTO)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE) |     @PostMapping(value = "pingxx_pay_success", consumes = MediaType.APPLICATION_JSON_VALUE) | ||||||
|  | @ -63,11 +65,7 @@ public class UsersPayTransactionController { | ||||||
| //        JSONObject bodyObj = JSON.parseObject(sb.toString());
 | //        JSONObject bodyObj = JSON.parseObject(sb.toString());
 | ||||||
| //        bodyObj.put("webhookId", bodyObj.remove("id"));
 | //        bodyObj.put("webhookId", bodyObj.remove("id"));
 | ||||||
| //        String body = bodyObj.toString();
 | //        String body = bodyObj.toString();
 | ||||||
|         CommonResult<Boolean> result = payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); |         payTransactionService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString()); | ||||||
|         if (result.isError()) { |  | ||||||
|             logger.error("[pingxxPaySuccess][message({}) result({})]", sb, result); |  | ||||||
|             return "failure"; |  | ||||||
|         } |  | ||||||
|         return "success"; |         return "success"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| package cn.iocoder.mall.pay.application.convert; | 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 cn.iocoder.mall.pay.application.vo.admins.AdminsPayRefundDetailVO; | ||||||
| import org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
| import org.mapstruct.Mappings; | import org.mapstruct.Mappings; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package cn.iocoder.mall.pay.application.vo.admins; | package cn.iocoder.mall.pay.application.vo.admins; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| package cn.iocoder.mall.pay.api; | package cn.iocoder.mall.pay.api; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.common.framework.vo.CommonResult; | import cn.iocoder.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundPageBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO; | ||||||
| 
 | 
 | ||||||
| public interface PayRefundService { | public interface PayRefundService { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,23 +1,24 @@ | ||||||
| package cn.iocoder.mall.pay.api; | package cn.iocoder.mall.pay.api; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.common.framework.vo.CommonResult; | import cn.iocoder.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO; | 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.Collection; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| public interface PayTransactionService { | 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 进行处理。 |      *               因为不同平台,能够提供的参数不同,所以使用 String 类型统一接收,然后在使用不同的 AbstractPaySDK 进行处理。 | ||||||
|      * @return 是否支付成功 |      * @return 是否支付成功 | ||||||
|      */ |      */ | ||||||
|     CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params); |     Boolean updateTransactionPaySuccess(Integer payChannel, String params); | ||||||
| 
 | 
 | ||||||
|     List<PayTransactionBO> getTransactionList(Collection<Integer> ids); |     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.Data; | ||||||
| import lombok.experimental.Accessors; | 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.Data; | ||||||
| import lombok.experimental.Accessors; | 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.Data; | ||||||
| import lombok.experimental.Accessors; | 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.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| 
 | 
 | ||||||
| /** | @ApiModel("支付交易 BO") | ||||||
|  * 支付交易 BO |  | ||||||
|  */ |  | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class PayTransactionBO implements Serializable { | public class PayTransactionBO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     /** |     @ApiModelProperty(value = "交易编号", required = true, example = "POd4RC6a") | ||||||
|      * 编号,自增 |  | ||||||
|      */ |  | ||||||
|     private Integer id; |     private Integer id; | ||||||
|     /** | 
 | ||||||
|      * 应用编号 |     @ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a") | ||||||
|      */ |  | ||||||
|     private String appId; |     private String appId; | ||||||
|     /** | 
 | ||||||
|      * 发起交易的 IP |     @ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1") | ||||||
|      */ |  | ||||||
|     private String createIp; |     private String createIp; | ||||||
|     /** | 
 | ||||||
|      * 业务线的订单编号 |     @ApiModelProperty(value = "订单号不能为空", required = true, example = "1024") | ||||||
|      * |  | ||||||
|      * 1. 使用 String 的原因是,业务线可能使用 String 做为编号 |  | ||||||
|      * 2. 每个 appId 下,orderId 唯一 |  | ||||||
|      */ |  | ||||||
|     private String orderId; |     private String orderId; | ||||||
|     /** | 
 | ||||||
|      * 订单商品名 |     @ApiModelProperty(value = "商品名", required = true, example = "芋道源码") | ||||||
|      */ |  | ||||||
|     private String orderSubject; |     private String orderSubject; | ||||||
|     /** | 
 | ||||||
|      * 订单商品描述 |     @ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的") | ||||||
|      */ |  | ||||||
|     private String orderDescription; |     private String orderDescription; | ||||||
|     /** | 
 | ||||||
|      * 订单备注 |     @ApiModelProperty(value = "订单商品备注", example = "绵啾啾的") | ||||||
|      */ |  | ||||||
|     private String orderMemo; |     private String orderMemo; | ||||||
|     /** | 
 | ||||||
|      * 支付金额,单位:分。 |     @ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10") | ||||||
|      */ |  | ||||||
|     private Integer price; |     private Integer price; | ||||||
|     /** | 
 | ||||||
|      * 订单状态 |     @ApiModelProperty(value = "订单状态", required = true, example = "1", notes = "参见 PayTransactionStatusEnum 枚举") | ||||||
|      * |  | ||||||
|      * @see cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum |  | ||||||
|      */ |  | ||||||
|     private Integer status; |     private Integer status; | ||||||
|     /** | 
 | ||||||
|      * 交易过期时间 |     @ApiModelProperty(value = "交易过期时间", required = true) | ||||||
|      */ |  | ||||||
|     private Date expireTime; |     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.Data; | ||||||
| import lombok.experimental.Accessors; | 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; | 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_APP(100, "wx", "微信 App 支付"), | ||||||
|     WEIXIN_PUB(101, "wxjs", "微信 JS API 支付"), |     WEIXIN_PUB(101, "wxjs", "微信 JS API 支付"), | ||||||
|  | @ -13,6 +17,8 @@ public enum PayChannelEnum { | ||||||
|     PINGXX(9999, "ping++", "ping++ 支付"), |     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; |         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.Data; | ||||||
| import lombok.experimental.Accessors; | 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.Data; | ||||||
| import lombok.experimental.Accessors; | 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.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| import org.hibernate.validator.constraints.Length; | import org.hibernate.validator.constraints.Length; | ||||||
|  | @ -10,54 +12,43 @@ import javax.validation.constraints.NotNull; | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| 
 | 
 | ||||||
| /** | @ApiModel("支付交易创建 DTO") | ||||||
|  * 支付交易创建 DTO |  | ||||||
|  */ |  | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class PayTransactionCreateDTO implements Serializable { | public class PayTransactionCreateDTO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     /** |     @ApiModelProperty(value = "应用编号", required = true, example = "POd4RC6a") | ||||||
|      * 应用编号 |  | ||||||
|      */ |  | ||||||
|     @NotEmpty(message = "应用编号不能为空") |     @NotEmpty(message = "应用编号不能为空") | ||||||
|     private String appId; |     private String appId; | ||||||
|     /** | 
 | ||||||
|      * 发起交易的 IP |     @ApiModelProperty(value = "发起交易的 IP", required = true, example = "192.168.10.1") | ||||||
|      */ |  | ||||||
|     @NotEmpty(message = "IP 不能为空") |     @NotEmpty(message = "IP 不能为空") | ||||||
|     private String createIp; |     private String createIp; | ||||||
|     /** | 
 | ||||||
|      * 业务线的订单编号 |     @ApiModelProperty(value = "订单号不能为空", required = true, example = "1024") | ||||||
|      */ |  | ||||||
|     @NotEmpty(message = "订单号不能为空") |     @NotEmpty(message = "订单号不能为空") | ||||||
|     private String orderId; |     private String orderId; | ||||||
|     /** | 
 | ||||||
|      * 订单商品名 |     @ApiModelProperty(value = "商品名", required = true, example = "芋道源码") | ||||||
|      */ |  | ||||||
|     @NotEmpty(message = "商品名不能为空") |     @NotEmpty(message = "商品名不能为空") | ||||||
|     @Length(max = 32, message = "商品名不能超过32") |     @Length(max = 32, message = "商品名不能超过32") | ||||||
|     private String orderSubject; |     private String orderSubject; | ||||||
|     /** | 
 | ||||||
|      * 订单商品描述 |     @ApiModelProperty(value = "订单商品描述", required = true, example = "绵啾啾的") | ||||||
|      */ |  | ||||||
|     @NotEmpty(message = "商品描述不能为空") |     @NotEmpty(message = "商品描述不能为空") | ||||||
|     @Length(max = 128, message = "商品描述长度不能超过128") |     @Length(max = 128, message = "商品描述长度不能超过128") | ||||||
|     private String orderDescription; |     private String orderDescription; | ||||||
|     /** | 
 | ||||||
|      * 订单备注 |     @ApiModelProperty(value = "订单商品备注", example = "绵啾啾的") | ||||||
|      */ |     @Length(max = 256, message = "商品备注长度不能超过256") | ||||||
|     @Length(max = 256, message = "商品描述长度不能超过256") |  | ||||||
|     private String orderMemo; |     private String orderMemo; | ||||||
|     /** | 
 | ||||||
|      * 支付金额,单位:分。 |     @ApiModelProperty(value = "支付金额,单位:分。", required = true, example = "10") | ||||||
|      */ |  | ||||||
|     @NotNull(message = "金额不能为空") |     @NotNull(message = "金额不能为空") | ||||||
|     @DecimalMin(value = "0", inclusive = false, message = "金额必须大于零") |     @DecimalMin(value = "0", inclusive = false, message = "金额必须大于零") | ||||||
|     private Integer price; |     private Integer price; | ||||||
|     /** | 
 | ||||||
|      * 交易过期时间 |     @ApiModelProperty(value = "交易过期时间", required = true) | ||||||
|      */ |  | ||||||
|     @NotNull(message = "交易过期时间不能为空") |     @NotNull(message = "交易过期时间不能为空") | ||||||
|     private Date expireTime; |     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.Data; | ||||||
| import lombok.experimental.Accessors; | 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; | package cn.iocoder.mall.pay.biz.component; | ||||||
| 
 | 
 | ||||||
| import org.apache.dubbo.config.ApplicationConfig; | import cn.iocoder.common.framework.util.StringUtil; | ||||||
| import org.apache.dubbo.config.ReferenceConfig; |  | ||||||
| import org.apache.dubbo.config.RegistryConfig; |  | ||||||
| import org.apache.dubbo.rpc.service.GenericService; |  | ||||||
| import com.google.common.cache.CacheBuilder; | import com.google.common.cache.CacheBuilder; | ||||||
| import com.google.common.cache.CacheLoader; | import com.google.common.cache.CacheLoader; | ||||||
| import com.google.common.cache.LoadingCache; | import com.google.common.cache.LoadingCache; | ||||||
| import lombok.Data; | 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.beans.factory.annotation.Value; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
| @Component | @Component | ||||||
| public class DubboReferencePool { | public class DubboReferencePool { | ||||||
| 
 | 
 | ||||||
|  | @ -44,7 +47,8 @@ public class DubboReferencePool { | ||||||
|     private String dubboApplicationName; |     private String dubboApplicationName; | ||||||
| 
 | 
 | ||||||
|     private ReferenceMeta createGenericService(String notifyUrl) { |     private ReferenceMeta createGenericService(String notifyUrl) { | ||||||
|         String[] notifyUrlParts = notifyUrl.split("#"); |         // 使用 # 号分隔,格式为 服务名#方法名#版本号
 | ||||||
|  |         List<String> notifyUrlParts = StringUtil.split(notifyUrl, "#"); | ||||||
|         // 创建 ApplicationConfig 对象
 |         // 创建 ApplicationConfig 对象
 | ||||||
|         ApplicationConfig application = new ApplicationConfig(); |         ApplicationConfig application = new ApplicationConfig(); | ||||||
|         application.setName(dubboApplicationName); |         application.setName(dubboApplicationName); | ||||||
|  | @ -55,14 +59,14 @@ public class DubboReferencePool { | ||||||
|         application.setRegistry(registry); |         application.setRegistry(registry); | ||||||
|         // 创建 ReferenceConfig 对象
 |         // 创建 ReferenceConfig 对象
 | ||||||
|         ReferenceConfig<GenericService> reference = new ReferenceConfig<>(); |         ReferenceConfig<GenericService> reference = new ReferenceConfig<>(); | ||||||
|         reference.setInterface(notifyUrlParts[0]); // 弱类型接口名
 |         reference.setInterface(notifyUrlParts.get(0)); // 弱类型接口名
 | ||||||
|         reference.setGeneric(true); // 声明为泛化接口
 |         reference.setGeneric(true); // 声明为泛化接口
 | ||||||
|         reference.setApplication(application); |         reference.setApplication(application); | ||||||
| //        reference.setVersion("*"); // TODO 芋艿,后面要优化下。
 |         reference.setVersion(notifyUrlParts.size() > 2 ? notifyUrlParts.get(2) : "1.0.0"); // 如果未配置服务的版本号,则默认使用 1.0.0
 | ||||||
|         // 获得 GenericService 对象
 |         // 获得 GenericService 对象
 | ||||||
|         GenericService genericService = reference.get(); |         GenericService genericService = reference.get(); | ||||||
|         // 构建最终的 ReferenceMeta 对象
 |         // 构建最终的 ReferenceMeta 对象
 | ||||||
|         return new ReferenceMeta(reference, genericService, notifyUrlParts[1]); |         return new ReferenceMeta(reference, genericService, notifyUrlParts.get(1)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public ReferenceMeta getReferenceMeta(String notifyUrl) { |     public ReferenceMeta getReferenceMeta(String notifyUrl) { | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package cn.iocoder.mall.pay.biz.convert; | package cn.iocoder.mall.pay.biz.convert; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO; | ||||||
| import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; | import cn.iocoder.mall.pay.biz.dataobject.PayRefundDO; | ||||||
| import org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
| import org.mapstruct.Mappings; | import org.mapstruct.Mappings; | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| package cn.iocoder.mall.pay.biz.convert; | package cn.iocoder.mall.pay.biz.convert; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionSubmitDTO; | ||||||
| import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; | import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO; | ||||||
| import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; | import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO; | ||||||
| import org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ import java.util.Date; | ||||||
|         topic = PayRefundSuccessMessage.TOPIC, |         topic = PayRefundSuccessMessage.TOPIC, | ||||||
|         consumerGroup = "pay-consumer-group-" + PayRefundSuccessMessage.TOPIC |         consumerGroup = "pay-consumer-group-" + PayRefundSuccessMessage.TOPIC | ||||||
| ) | ) | ||||||
|  | @Deprecated // 艿艿:突然发现,业务方实际无需回调。参考了 https://help.youzan.com/displaylist/detail_4_998 的文章。业务方,只要记录下退款单号,进行关联即可。
 | ||||||
| public class PayRefundSuccessConsumer extends AbstractPayNotifySuccessConsumer<PayRefundSuccessMessage> | public class PayRefundSuccessConsumer extends AbstractPayNotifySuccessConsumer<PayRefundSuccessMessage> | ||||||
|         implements RocketMQListener<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.constant.CommonStatusEnum; | ||||||
| import cn.iocoder.common.framework.util.ServiceExceptionUtil; | 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.api.constant.PayErrorCodeEnum; | ||||||
| import cn.iocoder.mall.pay.biz.dao.PayAppMapper; | import cn.iocoder.mall.pay.biz.dao.PayAppMapper; | ||||||
| import cn.iocoder.mall.pay.biz.dataobject.PayAppDO; | import cn.iocoder.mall.pay.biz.dataobject.PayAppDO; | ||||||
|  | @ -15,17 +14,17 @@ public class PayAppServiceImpl { | ||||||
|     @Autowired |     @Autowired | ||||||
|     private PayAppMapper payAppMapper; |     private PayAppMapper payAppMapper; | ||||||
| 
 | 
 | ||||||
|     public CommonResult<PayAppDO> validPayApp(String appId) { |     public PayAppDO validPayApp(String appId) { | ||||||
|         PayAppDO payAppDO = payAppMapper.selectById(appId); |         PayAppDO payAppDO = payAppMapper.selectById(appId); | ||||||
|         // 校验是否存在
 |         // 校验是否存在
 | ||||||
|         if (payAppDO == null) { |         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())) { |         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 |     @Resource | ||||||
|     private RocketMQTemplate rocketMQTemplate; |     private RocketMQTemplate rocketMQTemplate; | ||||||
| 
 | 
 | ||||||
|  |     @Deprecated // 参见 PayRefundSuccessConsumer 类的说明
 | ||||||
|     public void addRefundNotifyTask(PayRefundDO refund) { |     public void addRefundNotifyTask(PayRefundDO refund) { | ||||||
|         PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl()) |         PayNotifyTaskDO payTransactionNotifyTask = this.createBasePayNotifyTaskDO(refund.getAppId(), refund.getNotifyUrl()) | ||||||
|                 .setType(PayNotifyType.REFUND.getValue()); |                 .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.util.ServiceExceptionUtil; | ||||||
| import cn.iocoder.common.framework.vo.CommonResult; | import cn.iocoder.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.PayRefundService; | import cn.iocoder.mall.pay.api.PayRefundService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundPageBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundPageBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO; | import cn.iocoder.mall.pay.api.bo.refund.PayRefundSubmitBO; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum; | import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayRefundStatus; | import cn.iocoder.mall.pay.api.constant.PayRefundStatus; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum; | import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundPageDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundPageDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO; | import cn.iocoder.mall.pay.api.dto.refund.PayRefundSubmitDTO; | ||||||
| import cn.iocoder.mall.pay.biz.client.AbstractPaySDK; | import cn.iocoder.mall.pay.biz.client.AbstractPaySDK; | ||||||
| import cn.iocoder.mall.pay.biz.client.PaySDKFactory; | import cn.iocoder.mall.pay.biz.client.PaySDKFactory; | ||||||
| import cn.iocoder.mall.pay.biz.client.RefundSuccessBO; | import cn.iocoder.mall.pay.biz.client.RefundSuccessBO; | ||||||
|  | @ -51,13 +51,9 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||||
|     private RocketMQTemplate rocketMQTemplate; |     private RocketMQTemplate rocketMQTemplate; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @SuppressWarnings("Duplicates") |  | ||||||
|     public CommonResult<PayRefundSubmitBO> submitRefund(PayRefundSubmitDTO payRefundSubmitDTO) { |     public CommonResult<PayRefundSubmitBO> submitRefund(PayRefundSubmitDTO payRefundSubmitDTO) { | ||||||
|         // 校验 App 是否有效
 |         // 校验 App 是否有效
 | ||||||
|         CommonResult<PayAppDO> appResult = payAppService.validPayApp(payRefundSubmitDTO.getAppId()); |         PayAppDO payAppDO = payAppService.validPayApp(payRefundSubmitDTO.getAppId()); | ||||||
|         if (appResult.isError()) { |  | ||||||
|             return CommonResult.error(appResult); |  | ||||||
|         } |  | ||||||
|         // 获得 PayTransactionDO ,并校验其是否存在
 |         // 获得 PayTransactionDO ,并校验其是否存在
 | ||||||
|         PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefundSubmitDTO.getAppId(), payRefundSubmitDTO.getOrderId()); |         PayTransactionDO payTransaction = payTransactionService.getTransaction(payRefundSubmitDTO.getAppId(), payRefundSubmitDTO.getOrderId()); | ||||||
|         if (payTransaction == null) { // 是否存在
 |         if (payTransaction == null) { // 是否存在
 | ||||||
|  | @ -82,7 +78,7 @@ public class PayRefundServiceImpl implements PayRefundService { | ||||||
|                 .setTransactionId(payTransaction.getId()) |                 .setTransactionId(payTransaction.getId()) | ||||||
|                 .setRefundCode(generateTransactionCode()) // TODO 芋艿,后续调整
 |                 .setRefundCode(generateTransactionCode()) // TODO 芋艿,后续调整
 | ||||||
|                 .setStatus(PayRefundStatus.WAITING.getValue()) |                 .setStatus(PayRefundStatus.WAITING.getValue()) | ||||||
|                 .setNotifyUrl(appResult.getData().getRefundNotifyUrl()) |                 .setNotifyUrl(payAppDO.getRefundNotifyUrl()) | ||||||
|                 .setRefundChannel(payTransaction.getPayChannel()); |                 .setRefundChannel(payTransaction.getPayChannel()); | ||||||
|         payRefundDO.setCreateTime(new Date()); |         payRefundDO.setCreateTime(new Date()); | ||||||
|         payRefundMapper.insert(payRefundDO); |         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.util.ServiceExceptionUtil; | ||||||
| import cn.iocoder.common.framework.vo.CommonResult; | import cn.iocoder.common.framework.vo.CommonResult; | ||||||
| import cn.iocoder.mall.pay.api.PayTransactionService; | import cn.iocoder.mall.pay.api.PayTransactionService; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionPageBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionPageBO; | ||||||
| import cn.iocoder.mall.pay.api.bo.PayTransactionSubmitBO; | import cn.iocoder.mall.pay.api.bo.transaction.PayTransactionSubmitBO; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum; | import cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum; | ||||||
| import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum; | import cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionCreateDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionPageDTO; | import cn.iocoder.mall.pay.api.dto.transaction.PayTransactionGetDTO; | ||||||
| import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO; | 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.AbstractPaySDK; | ||||||
| import cn.iocoder.mall.pay.biz.client.PaySDKFactory; | import cn.iocoder.mall.pay.biz.client.PaySDKFactory; | ||||||
| import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO; | import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO; | ||||||
|  | @ -68,23 +69,21 @@ public class PayTransactionServiceImpl implements PayTransactionService { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public CommonResult<PayTransactionBO> getTransaction(Integer userId, String appId, String orderId) { |     public PayTransactionBO getTransaction(PayTransactionGetDTO payTransactionGetDTO) { | ||||||
|         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(appId, orderId); |         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId(payTransactionGetDTO.getAppId(), | ||||||
|  |                 payTransactionGetDTO.getOrderId()); | ||||||
|         if (payTransaction == null) { |         if (payTransaction == null) { | ||||||
|             return ServiceExceptionUtil.error(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); |             throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_NOT_FOUND.getCode()); | ||||||
|         } |         } | ||||||
|         // TODO 芋艿 userId 的校验
 |         // TODO 芋艿 userId 的校验
 | ||||||
|         return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction)); |         return PayTransactionConvert.INSTANCE.convert(payTransaction); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @SuppressWarnings("Duplicates") |     @SuppressWarnings("Duplicates") | ||||||
|     public CommonResult<PayTransactionBO> createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) { |     public PayTransactionBO createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) { | ||||||
|         // 校验 App
 |         // 校验 App
 | ||||||
|         CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionCreateDTO.getAppId()); |         PayAppDO payAppDO = payAppService.validPayApp(payTransactionCreateDTO.getAppId()); | ||||||
|         if (appResult.isError()) { |  | ||||||
|             return CommonResult.error(appResult); |  | ||||||
|         } |  | ||||||
|         // 插入 PayTransactionDO
 |         // 插入 PayTransactionDO
 | ||||||
|         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId( |         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId( | ||||||
|                 payTransactionCreateDTO.getAppId(), payTransactionCreateDTO.getOrderId()); |                 payTransactionCreateDTO.getAppId(), payTransactionCreateDTO.getOrderId()); | ||||||
|  | @ -95,31 +94,28 @@ public class PayTransactionServiceImpl implements PayTransactionService { | ||||||
|         } else { |         } else { | ||||||
|             payTransaction = PayTransactionConvert.INSTANCE.convert(payTransactionCreateDTO); |             payTransaction = PayTransactionConvert.INSTANCE.convert(payTransactionCreateDTO); | ||||||
|             payTransaction.setStatus(PayTransactionStatusEnum.WAITING.getValue()) |             payTransaction.setStatus(PayTransactionStatusEnum.WAITING.getValue()) | ||||||
|                     .setNotifyUrl(appResult.getData().getNotifyUrl()); |                     .setNotifyUrl(payAppDO.getNotifyUrl()); | ||||||
|             payTransaction.setCreateTime(new Date()); |             payTransaction.setCreateTime(new Date()); | ||||||
|             payTransactionMapper.insert(payTransaction); |             payTransactionMapper.insert(payTransaction); | ||||||
|         } |         } | ||||||
|         // 返回成功
 |         // 返回成功
 | ||||||
|         return CommonResult.success(PayTransactionConvert.INSTANCE.convert(payTransaction)); |         return PayTransactionConvert.INSTANCE.convert(payTransaction); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @SuppressWarnings("Duplicates") |     @SuppressWarnings("Duplicates") | ||||||
|     public CommonResult<PayTransactionSubmitBO> submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) { |     public PayTransactionSubmitBO submitTransaction(PayTransactionSubmitDTO payTransactionSubmitDTO) { | ||||||
|         // TODO 校验支付渠道是否有效
 |         // TODO 校验支付渠道是否有效
 | ||||||
|         // 校验 App 是否有效
 |         // 校验 App 是否有效
 | ||||||
|         CommonResult<PayAppDO> appResult = payAppService.validPayApp(payTransactionSubmitDTO.getAppId()); |         payAppService.validPayApp(payTransactionSubmitDTO.getAppId()); | ||||||
|         if (appResult.isError()) { |  | ||||||
|             return CommonResult.error(appResult); |  | ||||||
|         } |  | ||||||
|         // 获得 PayTransactionDO ,并校验其是否存在
 |         // 获得 PayTransactionDO ,并校验其是否存在
 | ||||||
|         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId( |         PayTransactionDO payTransaction = payTransactionMapper.selectByAppIdAndOrderId( | ||||||
|                 payTransactionSubmitDTO.getAppId(), payTransactionSubmitDTO.getOrderId()); |                 payTransactionSubmitDTO.getAppId(), payTransactionSubmitDTO.getOrderId()); | ||||||
|         if (payTransaction == null) { // 是否存在
 |         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())) { // 校验状态,必须是待支付
 |         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 payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(payTransactionSubmitDTO) |         PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(payTransactionSubmitDTO) | ||||||
|  | @ -131,33 +127,32 @@ public class PayTransactionServiceImpl implements PayTransactionService { | ||||||
|         AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel()); |         AbstractPaySDK paySDK = PaySDKFactory.getSDK(payTransactionSubmitDTO.getPayChannel()); | ||||||
|         CommonResult<String> invokeResult = paySDK.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
 |         CommonResult<String> invokeResult = paySDK.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
 | ||||||
|         if (invokeResult.isError()) { |         if (invokeResult.isError()) { | ||||||
|             return CommonResult.error(invokeResult); |             throw ServiceExceptionUtil.exception(invokeResult.getCode(), invokeResult.getMessage()); | ||||||
|         } |         } | ||||||
|         // TODO 轮询三方接口,是否已经支付的任务
 |         // TODO 轮询三方接口,是否已经支付的任务
 | ||||||
|         // 返回成功
 |         // 返回成功
 | ||||||
|         PayTransactionSubmitBO payTransactionSubmitBO = new PayTransactionSubmitBO() |         return new PayTransactionSubmitBO().setId(payTransactionExtensionDO.getId()) | ||||||
|                 .setId(payTransactionExtensionDO.getId()).setInvokeResponse(invokeResult.getData()); |                 .setInvokeResponse(invokeResult.getData()); | ||||||
|         return CommonResult.success(payTransactionSubmitBO); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @Transactional |     @Transactional | ||||||
|     public CommonResult<Boolean> updateTransactionPaySuccess(Integer payChannel, String params) { |     public Boolean updateTransactionPaySuccess(Integer payChannel, String params) { | ||||||
|         // TODO 芋艿,记录回调日志
 |         // TODO 芋艿,记录回调日志
 | ||||||
|         // 解析传入的参数,成 TransactionSuccessBO 对象
 |         // 解析传入的参数,成 TransactionSuccessBO 对象
 | ||||||
|         AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel); |         AbstractPaySDK paySDK = PaySDKFactory.getSDK(payChannel); | ||||||
|         CommonResult<TransactionSuccessBO> paySuccessResult = paySDK.parseTransactionSuccessParams(params); |         CommonResult<TransactionSuccessBO> paySuccessResult = paySDK.parseTransactionSuccessParams(params); | ||||||
|         if (paySuccessResult.isError()) { |         if (paySuccessResult.isError()) { | ||||||
|             return CommonResult.error(paySuccessResult); |             throw ServiceExceptionUtil.exception(paySuccessResult.getCode(), paySuccessResult.getMessage()); | ||||||
|         } |         } | ||||||
|         // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
 |         // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
 | ||||||
|         // 1.1 查询 PayTransactionExtensionDO
 |         // 1.1 查询 PayTransactionExtensionDO
 | ||||||
|         PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); |         PayTransactionExtensionDO extension = payTransactionExtensionMapper.selectByTransactionCode(paySuccessResult.getData().getTransactionCode()); | ||||||
|         if (extension == null) { |         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())) { // 校验状态,必须是待支付
 |         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
 |         // 1.2 更新 PayTransactionExtensionDO
 | ||||||
|         PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO() |         PayTransactionExtensionDO updatePayTransactionExtension = new PayTransactionExtensionDO() | ||||||
|  | @ -172,7 +167,7 @@ public class PayTransactionServiceImpl implements PayTransactionService { | ||||||
|         // 2.1 判断 PayTransactionDO 是否处于待支付
 |         // 2.1 判断 PayTransactionDO 是否处于待支付
 | ||||||
|         PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId()); |         PayTransactionDO transaction = payTransactionMapper.selectById(extension.getTransactionId()); | ||||||
|         if (transaction == null) { |         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())) { // 校验状态,必须是待支付
 |         if (!PayTransactionStatusEnum.WAITING.getValue().equals(transaction.getStatus())) { // 校验状态,必须是待支付
 | ||||||
|             throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode()); |             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()); |             throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode()); | ||||||
|         } |         } | ||||||
|         logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId()); |         logger.info("[updateTransactionPaySuccess][PayTransactionDO({}) 更新为已支付]", transaction.getId()); | ||||||
|         // 3 新增 PayNotifyTaskDO
 |         // 3 新增 PayNotifyTaskDO 注释原因,参见 PayRefundSuccessConsumer 类。
 | ||||||
|         payNotifyService.addTransactionNotifyTask(transaction, extension); | //        payNotifyService.addTransactionNotifyTask(transaction, extension);
 | ||||||
|         // 返回结果
 |         // 返回结果
 | ||||||
|         return CommonResult.success(true); |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package cn.iocoder.mall.pay.biz.service; | package cn.iocoder.mall.pay.biz.service; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.mall.pay.api.PayRefundService; | 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.Test; | ||||||
| import org.junit.runner.RunWith; | import org.junit.runner.RunWith; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,6 @@ | ||||||
| package cn.iocoder.mall.pay.biz.service; | 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.junit.runner.RunWith; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; |  | ||||||
| import org.springframework.boot.test.context.SpringBootTest; | import org.springframework.boot.test.context.SpringBootTest; | ||||||
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | 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.api.bo.ProductCategoryBO; | ||||||
| import cn.iocoder.mall.product.application.convert.ProductCategoryConvert; | import cn.iocoder.mall.product.application.convert.ProductCategoryConvert; | ||||||
| import cn.iocoder.mall.product.application.vo.users.UsersProductCategoryVO; | 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.Api; | ||||||
| import io.swagger.annotations.ApiImplicitParam; | import io.swagger.annotations.ApiImplicitParam; | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
|  | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.web.bind.annotation.GetMapping; | import org.springframework.web.bind.annotation.GetMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | @ -30,7 +29,6 @@ public class UsersProductCategoryController { | ||||||
|     @GetMapping("/list") |     @GetMapping("/list") | ||||||
|     @ApiOperation("获得指定编号下的子分类的数组") |     @ApiOperation("获得指定编号下的子分类的数组") | ||||||
|     @ApiImplicitParam(name = "pid", value = "指定分类编号", required = true, example = "0") |     @ApiImplicitParam(name = "pid", value = "指定分类编号", required = true, example = "0") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<List<UsersProductCategoryVO>> list(@RequestParam("pid") Integer pid) { |     public CommonResult<List<UsersProductCategoryVO>> list(@RequestParam("pid") Integer pid) { | ||||||
|         List<ProductCategoryBO> result = productCategoryService.getListByPid(pid); |         List<ProductCategoryBO> result = productCategoryService.getListByPid(pid); | ||||||
|         return CommonResult.success(ProductCategoryConvert.Users.INSTANCE.convertToVO(result)); |         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.convert.ProductSpuConvert; | ||||||
| import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO; | import cn.iocoder.mall.product.application.vo.users.UsersProductSpuDetailVO; | ||||||
| import cn.iocoder.mall.product.application.vo.users.UsersProductSpuPageVO; | 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.Api; | ||||||
| import io.swagger.annotations.ApiImplicitParam; | import io.swagger.annotations.ApiImplicitParam; | ||||||
| import io.swagger.annotations.ApiImplicitParams; | import io.swagger.annotations.ApiImplicitParams; | ||||||
|  | @ -31,7 +30,6 @@ public class UsersProductSpuController { | ||||||
|     @GetMapping("/info") |     @GetMapping("/info") | ||||||
|     @ApiOperation("商品 SPU 明细") |     @ApiOperation("商品 SPU 明细") | ||||||
|     @ApiImplicitParam(name = "id", value = "SPU 编号", required = true, example = "100") |     @ApiImplicitParam(name = "id", value = "SPU 编号", required = true, example = "100") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<UsersProductSpuDetailVO> info(@RequestParam("id") Integer id) { |     public CommonResult<UsersProductSpuDetailVO> info(@RequestParam("id") Integer id) { | ||||||
|         return success(ProductSpuConvert.INSTANCE.convert4(productSpuService.getProductSpuDetail(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 = "pageNo", value = "页码,从 1 开始", example = "1"), | ||||||
|             @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, example = "10"), |             @ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, example = "10"), | ||||||
|     }) |     }) | ||||||
|     @PermitAll |  | ||||||
|     @Deprecated // 使用商品搜索接口
 |     @Deprecated // 使用商品搜索接口
 | ||||||
|     public CommonResult<UsersProductSpuPageVO> page(@RequestParam(value = "cid", required = false) Integer cid, |     public CommonResult<UsersProductSpuPageVO> page(@RequestParam(value = "cid", required = false) Integer cid, | ||||||
|                                                     @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo, |                                                     @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.api.bo.BannerBO; | ||||||
| import cn.iocoder.mall.promotion.application.convert.BannerConvert; | import cn.iocoder.mall.promotion.application.convert.BannerConvert; | ||||||
| import cn.iocoder.mall.promotion.application.vo.users.UsersBannerVO; | 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.Api; | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
|  | @ -27,7 +26,6 @@ public class UsersBannerController { | ||||||
| 
 | 
 | ||||||
|     @GetMapping("/list") |     @GetMapping("/list") | ||||||
|     @ApiOperation("获得所有 Banner 列表") |     @ApiOperation("获得所有 Banner 列表") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<List<UsersBannerVO>> list() { |     public CommonResult<List<UsersBannerVO>> list() { | ||||||
|         // 查询 Banner 列表
 |         // 查询 Banner 列表
 | ||||||
|         List<BannerBO> result = bannerService.getBannerListByStatus(CommonStatusEnum.ENABLE.getValue()); |         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.UsersCouponCardPageVO; | ||||||
| import cn.iocoder.mall.promotion.application.vo.users.UsersCouponCardVO; | import cn.iocoder.mall.promotion.application.vo.users.UsersCouponCardVO; | ||||||
| import cn.iocoder.mall.promotion.application.vo.users.UsersCouponTemplateVO; | 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 cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
| import io.swagger.annotations.ApiImplicitParam; | import io.swagger.annotations.ApiImplicitParam; | ||||||
|  | @ -35,7 +34,6 @@ public class UsersCouponController { | ||||||
|     @GetMapping("/template/get") |     @GetMapping("/template/get") | ||||||
|     @ApiOperation(value = "优惠劵(码)模板信息") |     @ApiOperation(value = "优惠劵(码)模板信息") | ||||||
|     @ApiImplicitParam(name = "id", value = "优惠劵(码)模板编号", required = true, example = "10") |     @ApiImplicitParam(name = "id", value = "优惠劵(码)模板编号", required = true, example = "10") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<UsersCouponTemplateVO> templateGet(@RequestParam("id") Integer id) { |     public CommonResult<UsersCouponTemplateVO> templateGet(@RequestParam("id") Integer id) { | ||||||
|         CouponTemplateBO template = couponService.getCouponTemplate(id); |         CouponTemplateBO template = couponService.getCouponTemplate(id); | ||||||
|         return success(CouponTemplateConvert.USERS.convert2(template)); |         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.api.bo.ProductRecommendBO; | ||||||
| import cn.iocoder.mall.promotion.application.convert.ProductRecommendConvert; | import cn.iocoder.mall.promotion.application.convert.ProductRecommendConvert; | ||||||
| import cn.iocoder.mall.promotion.application.vo.users.UsersProductRecommendVO; | 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.HashMultimap; | ||||||
| import com.google.common.collect.Multimap; | import com.google.common.collect.Multimap; | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
|  | @ -36,7 +35,6 @@ public class UsersProductRecommendController { | ||||||
| 
 | 
 | ||||||
|     @GetMapping("/list") |     @GetMapping("/list") | ||||||
|     @ApiOperation("获得所有 Banner 列表") |     @ApiOperation("获得所有 Banner 列表") | ||||||
|     @PermitAll |  | ||||||
|     public CommonResult<Map<Integer, Collection<UsersProductRecommendVO>>> list() { |     public CommonResult<Map<Integer, Collection<UsersProductRecommendVO>>> list() { | ||||||
|         // 查询商品推荐列表
 |         // 查询商品推荐列表
 | ||||||
|         List<ProductRecommendBO> productRecommends = productRecommendService.getProductRecommendList( |         List<ProductRecommendBO> productRecommends = productRecommendService.getProductRecommendList( | ||||||
|  |  | ||||||
|  | @ -12,11 +12,6 @@ spring: | ||||||
|       max-active: 5 |       max-active: 5 | ||||||
|       max-wait: 10000 |       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 | ||||||
| mybatis-plus: | mybatis-plus: | ||||||
|   configuration: |   configuration: | ||||||
|  | @ -26,7 +21,7 @@ mybatis-plus: | ||||||
|       id-type: auto |       id-type: auto | ||||||
|   mapper-locations: classpath*:mapper/*.xml |   mapper-locations: classpath*:mapper/*.xml | ||||||
|   type-aliases-package: cn.iocoder.mall.promotion.biz.dataobject |   type-aliases-package: cn.iocoder.mall.promotion.biz.dataobject | ||||||
|   config-location: classpath:mybatis-config.xml | 
 | ||||||
| # dubbo | # dubbo | ||||||
| dubbo: | dubbo: | ||||||
|   application: |   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) | @Accessors(chain = true) | ||||||
| public class AdminSecurityContext { | public class AdminSecurityContext { | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 管理员编号 | ||||||
|  |      */ | ||||||
|     private Integer adminId; |     private Integer adminId; | ||||||
|  |     /** | ||||||
|  |      * 管理员账号 | ||||||
|  |      */ | ||||||
|  |     private String username; | ||||||
|  |     /** | ||||||
|  |      * 拥有的角色编号 | ||||||
|  |      */ | ||||||
|     private Set<Integer> roleIds; |     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()); |             context.setAdminId(authentication.getUserId()); | ||||||
|             MallUtil.setUserId(request, authentication.getUserId()); // 记录到 request 中,避免 AdminSecurityContext 后续清理掉后,其它地方需要用到 userId
 |             MallUtil.setUserId(request, authentication.getUserId()); // 记录到 request 中,避免 AdminSecurityContext 后续清理掉后,其它地方需要用到 userId
 | ||||||
|             if (authorization != null) { |             if (authorization != null) { | ||||||
|  |                 context.setUsername(authorization.getUsername()); | ||||||
|                 context.setRoleIds(authorization.getRoleIds()); |                 context.setRoleIds(authorization.getRoleIds()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -113,8 +114,4 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter { | ||||||
|                 requiresPermissions != null ? Arrays.asList(requiresPermissions.value()) : null); |                 requiresPermissions != null ? Arrays.asList(requiresPermissions.value()) : null); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void checkPermission() { |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| /** | /** | ||||||
|  * 提供 SDK 给其它服务,使用如下功能: |  * 提供 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; | ||||||
|  | @ -17,7 +17,7 @@ import java.util.Map; | ||||||
| public interface AdminService { | public interface AdminService { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 用户认证。认证成功后,返回认证信息 |      * 管理员认证。认证成功后,返回认证信息 | ||||||
|      * |      * | ||||||
|      * 实际上,就是用户名 + 密码登陆 |      * 实际上,就是用户名 + 密码登陆 | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -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.bo.oauth2.OAuth2AuthenticationBO; | ||||||
| import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO; | 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.OAuth2GetTokenDTO; | ||||||
|  | import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RefreshTokenDTO; | ||||||
|  | import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Oauth2 服务接口 |  * Oauth2 服务接口 | ||||||
|  | @ -18,7 +20,20 @@ public interface OAuth2Service { | ||||||
|      */ |      */ | ||||||
|     OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO); |     OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO); | ||||||
| 
 | 
 | ||||||
|     // TODO @see 刷新 token
 |     /** | ||||||
|  |      * 基于用户移除 accessToken | ||||||
|  |      * | ||||||
|  |      * @param oauth2RemoveTokenDTO accessToken 信息 | ||||||
|  |      */ | ||||||
|  |     void removeToken(OAuth2RemoveTokenByUserDTO oauth2RemoveTokenDTO); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 刷新令牌,获得新的 accessToken 信息 | ||||||
|  |      * | ||||||
|  |      * @param oauth2RefreshTokenDTO refreshToken 信息 | ||||||
|  |      * @return accessToken 信息 | ||||||
|  |      */ | ||||||
|  |     OAuth2AccessTokenBO refreshToken(OAuth2RefreshTokenDTO oauth2RefreshTokenDTO); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 通过 accessToken 获得身份信息 |      * 通过 accessToken 获得身份信息 | ||||||
|  |  | ||||||
|  | @ -5,16 +5,20 @@ import io.swagger.annotations.ApiModelProperty; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
|  | import java.io.Serializable; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| @ApiModel("管理员授权 BO") | @ApiModel("管理员授权 BO") | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class AdminAuthorizationBO { | public class AdminAuthorizationBO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     @ApiModelProperty(value = "管理员编号", required = true, example = "1") |     @ApiModelProperty(value = "管理员编号", required = true, example = "1") | ||||||
|     private Integer id; |     private Integer id; | ||||||
| 
 | 
 | ||||||
|  |     @ApiModelProperty(value = "登陆账号", required = true, example = "1") | ||||||
|  |     private String username; | ||||||
|  | 
 | ||||||
|     @ApiModelProperty(value = "角色编号数组", required = true, example = "1") |     @ApiModelProperty(value = "角色编号数组", required = true, example = "1") | ||||||
|     private Set<Integer> roleIds; |     private Set<Integer> roleIds; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,10 +5,12 @@ import io.swagger.annotations.ApiModelProperty; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
|  | import java.io.Serializable; | ||||||
|  | 
 | ||||||
| @ApiModel("OAUTH2 认证 BO") | @ApiModel("OAUTH2 认证 BO") | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class OAuth2AuthenticationBO { | public class OAuth2AuthenticationBO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     @ApiModelProperty(value = "用户编号", required = true, example = "1") |     @ApiModelProperty(value = "用户编号", required = true, example = "1") | ||||||
|     private Integer userId; |     private Integer userId; | ||||||
|  |  | ||||||
|  | @ -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 class AdminConstants { | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 账号 - 管理员 | ||||||
|  |      */ | ||||||
|     public static final String USERNAME_ADMIN = "admin"; |     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_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"), | ||||||
|     OAUTH2_NOT_LOGIN(1002001015, "账号未登陆"), |     OAUTH2_NOT_LOGIN(1002001015, "账号未登陆"), | ||||||
|     OAUTH2_INVALID_TOKEN_ERROR_USER_TYPE(1002001016, "访问令牌用户类型不正确"), |     OAUTH2_INVALID_TOKEN_ERROR_USER_TYPE(1002001016, "访问令牌用户类型不正确"), | ||||||
| 
 |     OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND(1002001017, "刷新令牌不存在"), | ||||||
|     OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
 |     OAUTH_INVALID_REFRESH_TOKEN_EXPIRED(1002001018, "访问令牌已过期"), | ||||||
|  |     OAUTH_INVALID_REFRESH_TOKEN_INVALID(1002001019, "刷新令牌已失效"), | ||||||
| 
 | 
 | ||||||
|     // ========== 管理员模块 1002002000 ==========
 |     // ========== 管理员模块 1002002000 ==========
 | ||||||
|     ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"), |     ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"), | ||||||
|  | @ -30,6 +31,8 @@ public enum AdminErrorCodeEnum { | ||||||
|     ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE(1002002005, "管理员的账号状态不允许变更"), |     ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE(1002002005, "管理员的账号状态不允许变更"), | ||||||
|     ADMIN_ASSIGN_ROLE_NOT_EXISTS(1002002006, "分配员工角色时,有角色不存在"), |     ADMIN_ASSIGN_ROLE_NOT_EXISTS(1002002006, "分配员工角色时,有角色不存在"), | ||||||
|     ADMIN_INVALID_PERMISSION(1002002007, "没有该操作权限"), |     ADMIN_INVALID_PERMISSION(1002002007, "没有该操作权限"), | ||||||
|  |     ADMIN_ADMIN_CAN_NOT_UPDATE(1002002008, "管理员的账号不允许变更"), | ||||||
|  |     ADMIN_DEMO_CAN_NOT_WRITE(1002002009, "演示账号,暂不允许写操作。欢迎加入我们的交流群:http://t.cn/EKEr5WE"), | ||||||
| 
 | 
 | ||||||
|     // ========== 资源模块 1002003000 ==========
 |     // ========== 资源模块 1002003000 ==========
 | ||||||
|     RESOURCE_NAME_DUPLICATE(1002003000, "已经存在该名字的资源"), |     RESOURCE_NAME_DUPLICATE(1002003000, "已经存在该名字的资源"), | ||||||
|  |  | ||||||
|  | @ -8,11 +8,12 @@ import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
| import javax.validation.constraints.NotNull; | import javax.validation.constraints.NotNull; | ||||||
|  | import java.io.Serializable; | ||||||
| 
 | 
 | ||||||
| @ApiModel("OAuth2 创建 Token DTO") | @ApiModel("OAuth2 创建 Token DTO") | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class OAuth2CreateTokenDTO { | public class OAuth2CreateTokenDTO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     @ApiModelProperty(value = "用户编号", required = true, example = "1") |     @ApiModelProperty(value = "用户编号", required = true, example = "1") | ||||||
|     @NotNull(message = "用户编号不能为空") |     @NotNull(message = "用户编号不能为空") | ||||||
|  |  | ||||||
|  | @ -9,11 +9,12 @@ import lombok.experimental.Accessors; | ||||||
| 
 | 
 | ||||||
| import javax.validation.constraints.NotEmpty; | import javax.validation.constraints.NotEmpty; | ||||||
| import javax.validation.constraints.NotNull; | import javax.validation.constraints.NotNull; | ||||||
|  | import java.io.Serializable; | ||||||
| 
 | 
 | ||||||
| @ApiModel("OAuth2 身份验证 DTO") | @ApiModel("OAuth2 身份验证 DTO") | ||||||
| @Data | @Data | ||||||
| @Accessors(chain = true) | @Accessors(chain = true) | ||||||
| public class OAuth2GetTokenDTO { | public class OAuth2GetTokenDTO implements Serializable { | ||||||
| 
 | 
 | ||||||
|     @ApiModelProperty(value = "accessToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50") |     @ApiModelProperty(value = "accessToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50") | ||||||
|     @NotEmpty(message = "accessToken 不能为空") |     @NotEmpty(message = "accessToken 不能为空") | ||||||
|  |  | ||||||
|  | @ -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.OAuth2AccessTokenBO; | ||||||
| import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO; | 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 cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO; | ||||||
| import org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
| import org.mapstruct.Mapping; | import org.mapstruct.Mapping; | ||||||
| import org.mapstruct.Mappings; | import org.mapstruct.Mappings; | ||||||
| import org.mapstruct.factory.Mappers; | import org.mapstruct.factory.Mappers; | ||||||
| 
 | 
 | ||||||
| import java.util.List; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
| 
 |  | ||||||
| @Mapper | @Mapper | ||||||
| public interface OAuth2Convert { | public interface OAuth2Convert { | ||||||
| 
 | 
 | ||||||
|  | @ -28,15 +23,8 @@ public interface OAuth2Convert { | ||||||
|                 .setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0)); |                 .setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Mappings({}) |  | ||||||
|     OAuth2AuthenticationOldBO convertToAuthenticationOld(OAuth2AccessTokenDO oauth2AccessTokenDO); |  | ||||||
| 
 |  | ||||||
|     @Mappings({}) |     @Mappings({}) | ||||||
|     OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO); |     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 | @Repository | ||||||
| public interface OAuth2AccessTokenMapper extends BaseMapper<OAuth2AccessTokenDO> { | public interface OAuth2AccessTokenMapper extends BaseMapper<OAuth2AccessTokenDO> { | ||||||
| 
 | 
 | ||||||
|     default int updateToInvalidByAdminId(Integer adminId) { |     default int updateToInvalid(Integer userId, Integer userType) { | ||||||
|         QueryWrapper<OAuth2AccessTokenDO> query = new QueryWrapper<OAuth2AccessTokenDO>() |         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); |         return update(new OAuth2AccessTokenDO().setValid(false), query); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,9 +8,10 @@ import org.springframework.stereotype.Repository; | ||||||
| @Repository | @Repository | ||||||
| public interface OAuth2RefreshTokenMapper extends BaseMapper<OAuth2RefreshTokenDO> { | public interface OAuth2RefreshTokenMapper extends BaseMapper<OAuth2RefreshTokenDO> { | ||||||
| 
 | 
 | ||||||
|     default int updateToInvalidByAdminId(Integer adminId) { |     default int updateToInvalid(Integer userId, Integer userType) { | ||||||
|         QueryWrapper<OAuth2RefreshTokenDO> query = new QueryWrapper<OAuth2RefreshTokenDO>() |         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); |         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.constant.AdminErrorCodeEnum; | ||||||
| import cn.iocoder.mall.admin.api.dto.admin.*; | 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.OAuth2CreateTokenDTO; | ||||||
|  | import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO; | ||||||
| import cn.iocoder.mall.admin.convert.AdminConvert; | import cn.iocoder.mall.admin.convert.AdminConvert; | ||||||
| import cn.iocoder.mall.admin.dao.AdminMapper; | import cn.iocoder.mall.admin.dao.AdminMapper; | ||||||
| import cn.iocoder.mall.admin.dao.AdminRoleMapper; | import cn.iocoder.mall.admin.dao.AdminRoleMapper; | ||||||
|  | @ -96,9 +97,14 @@ public class AdminServiceImpl implements AdminService { | ||||||
|     @Override |     @Override | ||||||
|     public Boolean updateAdmin(Integer adminId, AdminUpdateDTO adminUpdateDTO) { |     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()); |             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()); |         AdminDO usernameAdmin = adminMapper.selectByUsername(adminUpdateDTO.getUsername()); | ||||||
|         if (usernameAdmin != null && !usernameAdmin.getId().equals(adminUpdateDTO.getId())) { |         if (usernameAdmin != null && !usernameAdmin.getId().equals(adminUpdateDTO.getId())) { | ||||||
|  | @ -120,7 +126,8 @@ public class AdminServiceImpl implements AdminService { | ||||||
|         if (admin == null) { |         if (admin == null) { | ||||||
|             throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode()); |             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()); |             throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE.getCode()); | ||||||
|         } |         } | ||||||
|         // 如果状态相同,则返回错误
 |         // 如果状态相同,则返回错误
 | ||||||
|  | @ -132,7 +139,7 @@ public class AdminServiceImpl implements AdminService { | ||||||
|         adminMapper.updateById(updateAdmin); |         adminMapper.updateById(updateAdmin); | ||||||
|         // 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
 |         // 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
 | ||||||
|         if (CommonStatusEnum.DISABLE.getValue().equals(adminUpdateStatusDTO.getStatus())) { |         if (CommonStatusEnum.DISABLE.getValue().equals(adminUpdateStatusDTO.getStatus())) { | ||||||
|             oauth2Service.removeToken(adminUpdateStatusDTO.getId()); |             oauth2Service.removeToken(new OAuth2RemoveTokenByUserDTO().setUserId(adminId).setUserType(UserTypeEnum.ADMIN.getValue())); | ||||||
|         } |         } | ||||||
|         // TODO 插入操作日志
 |         // 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) { |     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.constant.AdminErrorCodeEnum; | ||||||
| import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO; | 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.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.convert.OAuth2Convert; | ||||||
| import cn.iocoder.mall.admin.dao.OAuth2AccessTokenMapper; | import cn.iocoder.mall.admin.dao.OAuth2AccessTokenMapper; | ||||||
| import cn.iocoder.mall.admin.dao.OAuth2RefreshTokenMapper; | import cn.iocoder.mall.admin.dao.OAuth2RefreshTokenMapper; | ||||||
|  | @ -59,17 +61,37 @@ public class OAuth2ServiceImpl implements OAuth2Service { | ||||||
|         return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO); |         return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     @Override | ||||||
|      * 移除管理员对应的 Token |  | ||||||
|      * |  | ||||||
|      * @param adminId 管理员编号 |  | ||||||
|      */ |  | ||||||
|     @Transactional |     @Transactional | ||||||
|     public void removeToken(Integer adminId) { |     public void removeToken(OAuth2RemoveTokenByUserDTO oauth2RemoveTokenByUserDTO) { | ||||||
|  |         Integer userId = oauth2RemoveTokenByUserDTO.getUserId(); | ||||||
|  |         Integer userType = oauth2RemoveTokenByUserDTO.getUserType(); | ||||||
|         // 设置 access token 失效
 |         // 设置 access token 失效
 | ||||||
|         oauth2AccessTokenMapper.updateToInvalidByAdminId(adminId); |         oauth2AccessTokenMapper.updateToInvalid(userId, userType); | ||||||
|         // 设置 refresh token 失效
 |         // 设置 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 |     @Override | ||||||
|  |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| /** |  | ||||||
|  * @author Sin |  | ||||||
|  * @time 2019/5/16 10:52 AM |  | ||||||
|  */ |  | ||||||
| package cn.iocoder.mall.admin; |  | ||||||
|  | @ -1,17 +1,16 @@ | ||||||
| package cn.iocoder.mall.user.application.controller.users; | 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.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.MobileCodeService; | ||||||
| import cn.iocoder.mall.user.api.OAuth2Service; |  | ||||||
| import cn.iocoder.mall.user.api.UserService; | 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.application.convert.PassportConvert; | import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO; | ||||||
| import cn.iocoder.mall.user.application.vo.users.UsersAccessTokenVO; |  | ||||||
| import cn.iocoder.mall.user.application.vo.users.UsersMobileRegisterVO; |  | ||||||
| import cn.iocoder.mall.user.sdk.annotation.PermitAll; |  | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
| import io.swagger.annotations.ApiImplicitParam; | import io.swagger.annotations.ApiImplicitParam; | ||||||
| import io.swagger.annotations.ApiImplicitParams; |  | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
| import org.springframework.web.bind.annotation.PostMapping; | import org.springframework.web.bind.annotation.PostMapping; | ||||||
|  | @ -26,7 +25,7 @@ import static cn.iocoder.common.framework.vo.CommonResult.success; | ||||||
| @Api("Passport 模块") | @Api("Passport 模块") | ||||||
| public class PassportController { | public class PassportController { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version}") |     @Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}") | ||||||
|     private OAuth2Service oauth2Service; |     private OAuth2Service oauth2Service; | ||||||
|     @Reference(validation = "true", version = "${dubbo.provider.UserService.version}") |     @Reference(validation = "true", version = "${dubbo.provider.UserService.version}") | ||||||
|     private UserService userService; |     private UserService userService; | ||||||
|  | @ -40,20 +39,12 @@ public class PassportController { | ||||||
| //        return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
 | //        return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
 | ||||||
| //    }
 | //    }
 | ||||||
| 
 | 
 | ||||||
|     @PermitAll |  | ||||||
|     @PostMapping("/mobile/register") |     @PostMapping("/mobile/register") | ||||||
|     @ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建") |     @ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建") | ||||||
|     @ApiImplicitParams({ |     public CommonResult<UserAuthenticationBO> mobileRegister(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO) { | ||||||
|             @ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300"), |         return success(userService.authenticationByMobileCode(userAuthenticationByMobileCodeDTO)); | ||||||
|             @ApiImplicitParam(name = "code", value = "验证码", required = true, example = "9999") |  | ||||||
|     }) |  | ||||||
|     public CommonResult<UsersMobileRegisterVO> mobileRegister(@RequestParam("mobile") String mobile, |  | ||||||
|                                                               @RequestParam("code") String code) { |  | ||||||
|         OAuth2AccessTokenBO result = oauth2Service.getAccessToken(mobile, code); |  | ||||||
|         return success(PassportConvert.INSTANCE.convert(result)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PermitAll |  | ||||||
|     @PostMapping("mobile/send_register_code") |     @PostMapping("mobile/send_register_code") | ||||||
|     @ApiOperation(value = "发送手机验证码") |     @ApiOperation(value = "发送手机验证码") | ||||||
|     @ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300") |     @ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300") | ||||||
|  | @ -65,24 +56,21 @@ public class PassportController { | ||||||
|     // TODO 芋艿,改绑手机号
 |     // TODO 芋艿,改绑手机号
 | ||||||
| 
 | 
 | ||||||
|     // TODO 功能:qq 登陆
 |     // TODO 功能:qq 登陆
 | ||||||
|     @PermitAll |  | ||||||
|     @PostMapping("/qq/login") |     @PostMapping("/qq/login") | ||||||
|     public String qqLogin() { |     public String qqLogin() { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO 功能:qq 绑定
 |     // TODO 功能:qq 绑定
 | ||||||
|     @PermitAll |  | ||||||
|     @PostMapping("/qq/bind") |     @PostMapping("/qq/bind") | ||||||
|     public String qqBind() { |     public String qqBind() { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PermitAll |  | ||||||
|     @PostMapping("/refresh_token") // TODO 功能:刷新 token
 |     @PostMapping("/refresh_token") // TODO 功能:刷新 token
 | ||||||
|     public CommonResult<UsersAccessTokenVO> refreshToken(@RequestParam("refreshToken") String refreshToken) { |     public CommonResult<OAuth2AccessTokenBO> refreshToken(@RequestParam("refreshToken") String refreshToken) { | ||||||
|         OAuth2AccessTokenBO result = oauth2Service.refreshToken(refreshToken); |         return success(oauth2Service.refreshToken(new OAuth2RefreshTokenDTO().setRefreshToken(refreshToken) | ||||||
|         return success(PassportConvert.INSTANCE.convert2(result)); |                 .setUserType(UserTypeEnum.USER.getValue()))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO 功能:退出,销毁 token
 |     // 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.api.dto.UserUpdateDTO; | ||||||
| import cn.iocoder.mall.user.application.convert.UserConvert; | import cn.iocoder.mall.user.application.convert.UserConvert; | ||||||
| import cn.iocoder.mall.user.application.vo.users.UsersUserVO; | 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 cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | ||||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||||
|  | @ -23,6 +24,7 @@ public class UserController { | ||||||
|     private UserService userService; |     private UserService userService; | ||||||
| 
 | 
 | ||||||
|     @GetMapping("/info") |     @GetMapping("/info") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation(value = "用户信息") |     @ApiOperation(value = "用户信息") | ||||||
|     public CommonResult<UsersUserVO> info() { |     public CommonResult<UsersUserVO> info() { | ||||||
|         UserBO userResult = userService.getUser(UserSecurityContextHolder.getContext().getUserId()); |         UserBO userResult = userService.getUser(UserSecurityContextHolder.getContext().getUserId()); | ||||||
|  | @ -30,6 +32,7 @@ public class UserController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("/update_avatar") |     @PostMapping("/update_avatar") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation(value = "更新头像") |     @ApiOperation(value = "更新头像") | ||||||
|     public CommonResult<Boolean> updateAvatar(@RequestParam("avatar") String avatar) { |     public CommonResult<Boolean> updateAvatar(@RequestParam("avatar") String avatar) { | ||||||
|         // 创建
 |         // 创建
 | ||||||
|  | @ -40,6 +43,7 @@ public class UserController { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @PostMapping("/update_nickname") |     @PostMapping("/update_nickname") | ||||||
|  |     @RequiresLogin | ||||||
|     @ApiOperation(value = "更新昵称") |     @ApiOperation(value = "更新昵称") | ||||||
|     public CommonResult<Boolean> updateNickname(@RequestParam("nickname") String nickname) { |     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 io.swagger.annotations.ApiModelProperty; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||||
|  | import org.hibernate.validator.constraints.Length; | ||||||
| 
 | 
 | ||||||
|  | import javax.validation.constraints.NotEmpty; | ||||||
| import javax.validation.constraints.NotNull; | import javax.validation.constraints.NotNull; | ||||||
| import javax.validation.constraints.Size; | import javax.validation.constraints.Size; | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
|  | @ -39,13 +41,15 @@ public class UserAddressAddPO implements Serializable { | ||||||
|     @NotNull(message = "手机号为不能为空!") |     @NotNull(message = "手机号为不能为空!") | ||||||
|     @Size(min = 11, max = 11, message = "手机号为 11 位!") |     @Size(min = 11, max = 11, message = "手机号为 11 位!") | ||||||
|     private String mobile; |     private String mobile; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 收件详细地址 |      * 收件详细地址 | ||||||
|      */ |      */ | ||||||
|     @ApiModelProperty("收件详细地址") |     @ApiModelProperty("收件详细地址") | ||||||
|     @NotNull(message = "详细地址不能为空") |     @NotEmpty(message = "详细地址不能为空") | ||||||
|     @Size(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!") |     @Length(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!") | ||||||
|     private String address; |     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 { | ||||||
|  | } | ||||||
|  | @ -1,18 +1,18 @@ | ||||||
| package cn.iocoder.mall.user.sdk.context; | package cn.iocoder.mall.user.sdk.context; | ||||||
| 
 | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.experimental.Accessors; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * User Security 上下文 |  * User Security 上下文 | ||||||
|  */ |  */ | ||||||
|  | @Data | ||||||
|  | @Accessors(chain = true) | ||||||
| public class UserSecurityContext { | public class UserSecurityContext { | ||||||
| 
 | 
 | ||||||
|     private final Integer userId; |     /** | ||||||
| 
 |      * 用户编号 | ||||||
|     public UserSecurityContext(Integer userId) { |      */ | ||||||
|         this.userId = userId; |     private Integer userId; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public Integer getUserId() { |  | ||||||
|         return userId; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -17,7 +17,7 @@ public class UserSecurityContextHolder { | ||||||
|         UserSecurityContext ctx = SECURITY_CONTEXT.get(); |         UserSecurityContext ctx = SECURITY_CONTEXT.get(); | ||||||
|         // 为空时,设置一个空的进去
 |         // 为空时,设置一个空的进去
 | ||||||
|         if (ctx == null) { |         if (ctx == null) { | ||||||
|             ctx = new UserSecurityContext(null); |             ctx = new UserSecurityContext(); | ||||||
|             SECURITY_CONTEXT.set(ctx); |             SECURITY_CONTEXT.set(ctx); | ||||||
|         } |         } | ||||||
|         return ctx; |         return ctx; | ||||||
|  |  | ||||||
|  | @ -1,12 +1,15 @@ | ||||||
| package cn.iocoder.mall.user.sdk.interceptor; | package cn.iocoder.mall.user.sdk.interceptor; | ||||||
| 
 | 
 | ||||||
| import cn.iocoder.common.framework.constant.MallConstants; | import cn.iocoder.common.framework.constant.UserTypeEnum; | ||||||
| import cn.iocoder.common.framework.exception.ServiceException; | import cn.iocoder.common.framework.exception.ServiceException; | ||||||
| import cn.iocoder.common.framework.util.HttpUtil; | import cn.iocoder.common.framework.util.HttpUtil; | ||||||
| import cn.iocoder.common.framework.util.MallUtil; | import cn.iocoder.common.framework.util.MallUtil; | ||||||
| import cn.iocoder.mall.user.api.OAuth2Service; | import cn.iocoder.common.framework.util.StringUtil; | ||||||
| import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO; | import cn.iocoder.mall.admin.api.OAuth2Service; | ||||||
| import cn.iocoder.mall.user.sdk.annotation.PermitAll; | 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.RequiresLogin; | ||||||
| import cn.iocoder.mall.user.sdk.context.UserSecurityContext; | import cn.iocoder.mall.user.sdk.context.UserSecurityContext; | ||||||
| import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder; | ||||||
| import org.apache.dubbo.config.annotation.Reference; | import org.apache.dubbo.config.annotation.Reference; | ||||||
|  | @ -18,40 +21,55 @@ import javax.servlet.http.HttpServletRequest; | ||||||
| import javax.servlet.http.HttpServletResponse; | import javax.servlet.http.HttpServletResponse; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 安全拦截器 |  * User 安全拦截器 | ||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| public class UserSecurityInterceptor extends HandlerInterceptorAdapter { | public class UserSecurityInterceptor extends HandlerInterceptorAdapter { | ||||||
| 
 | 
 | ||||||
|     @Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version:1.0.0}") |     @Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version:1.0.0}") | ||||||
|     private OAuth2Service oauth2Service; |     private OAuth2Service oauth2Service; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||||||
|         // 设置当前访问的用户类型。注意,即使未登陆,我们也认为是用户
 |         // 设置当前访问的用户类型。注意,即使未登陆,我们也认为是用户
 | ||||||
|         MallUtil.setUserType(request, MallConstants.USER_TYPE_USER); |         MallUtil.setUserType(request, UserTypeEnum.USER.getValue()); | ||||||
|         // 校验访问令牌是否正确。若正确,返回授权信息
 | 
 | ||||||
|  |         // 根据 accessToken 获得认证信息,判断是谁
 | ||||||
|         String accessToken = HttpUtil.obtainAuthorization(request); |         String accessToken = HttpUtil.obtainAuthorization(request); | ||||||
|         OAuth2AuthenticationBO authentication = null; |         OAuth2AuthenticationBO authentication = null; | ||||||
|         if (accessToken != null) { |         ServiceException serviceException = null; | ||||||
|             authentication = oauth2Service.checkToken(accessToken); // TODO 芋艿,如果访问的地址无需登录,这里也不用抛异常
 |         if (StringUtil.hasText(accessToken)) { | ||||||
|             // 添加到 SecurityContext
 |             try { | ||||||
|             UserSecurityContext context = new UserSecurityContext(authentication.getUserId()); |                 authentication = oauth2Service.getAuthentication(new OAuth2GetTokenDTO().setAccessToken(accessToken) | ||||||
|             UserSecurityContextHolder.setContext(context); |                         .setUserType(UserTypeEnum.USER.getValue())); | ||||||
|             // 同时也记录管理员编号到 AdminAccessLogInterceptor 中。因为:
 |             } catch (ServiceException e) { | ||||||
|             // AdminAccessLogInterceptor 需要在 AdminSecurityInterceptor 之前执行,这样记录的访问日志才健全
 |                 serviceException = e; | ||||||
|             // AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
 |  | ||||||
|             // 因此,这里需要进行记录
 |  | ||||||
|             if (authentication.getUserId() != null) { |  | ||||||
|                 MallUtil.setUserId(request, authentication.getUserId()); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         // 校验是否需要已授权
 | 
 | ||||||
|  |         // 进行鉴权
 | ||||||
|         HandlerMethod method = (HandlerMethod) handler; |         HandlerMethod method = (HandlerMethod) handler; | ||||||
|         boolean isPermitAll = method.hasMethodAnnotation(PermitAll.class); |         boolean requiresLogin = method.hasMethodAnnotation(RequiresLogin.class); | ||||||
|         if (!isPermitAll && authentication == null) { |         if (requiresLogin) { // 如果需要鉴权
 | ||||||
|             throw new ServiceException(-1, "未授权"); // TODO 这里要改下
 |             if (serviceException != null) { // 认证失败,抛出上面认证失败的 ServiceException 异常
 | ||||||
|  |                 throw serviceException; | ||||||
|             } |             } | ||||||
|  |             if (authentication == null) { // 无认证信息,抛出未登陆 ServiceException 异常
 | ||||||
|  |                 throw new ServiceException(AdminErrorCodeEnum.OAUTH2_NOT_LOGIN.getCode(), AdminErrorCodeEnum.OAUTH2_NOT_LOGIN.getMessage()); | ||||||
|  |             } | ||||||
|  |             // TODO 芋艿,后续拓展读取用户信息
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 鉴权完成,初始化 AdminSecurityContext 上下文
 | ||||||
|  |         UserSecurityContext context = new UserSecurityContext(); | ||||||
|  |         UserSecurityContextHolder.setContext(context); | ||||||
|  |         if (authentication != null) { | ||||||
|  |             context.setUserId(authentication.getUserId()); | ||||||
|  |             MallUtil.setUserId(request, authentication.getUserId()); // 记录到 request 中,避免 AdminSecurityContext 后续清理掉后,其它地方需要用到 userId
 | ||||||
|  |             // TODO 芋艿,后续拓展读取用户信息
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 返回成功
 | ||||||
|         return super.preHandle(request, response, handler); |         return super.preHandle(request, response, handler); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,6 +17,11 @@ | ||||||
|             <artifactId>common-framework</artifactId> |             <artifactId>common-framework</artifactId> | ||||||
|             <version>1.0-SNAPSHOT</version> |             <version>1.0-SNAPSHOT</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>cn.iocoder.mall</groupId> | ||||||
|  |             <artifactId>system-service-api</artifactId> | ||||||
|  |             <version>1.0-SNAPSHOT</version> | ||||||
|  |         </dependency> | ||||||
| 
 | 
 | ||||||
|         <!-- 工具类相关 --> |         <!-- 工具类相关 --> | ||||||
|         <dependency> |         <dependency> | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	 sin
						sin