Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/mx_charging_pile
41个文件已修改
2个文件已删除
25个文件已添加
New file |
| | |
| | | package com.ruoyi.account.api.factory; |
| | | |
| | | import com.ruoyi.account.api.feignClient.AppUserVipDetailClient; |
| | | import com.ruoyi.account.api.model.TAppUserVipDetail; |
| | | import com.ruoyi.account.api.vo.GetAppUserVipDetail; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | |
| | | /** |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Component |
| | | public class AppUserVipDetailFallbackFactory implements FallbackFactory<AppUserVipDetailClient> |
| | | { |
| | | private static final Logger log = LoggerFactory.getLogger(AppUserVipDetailFallbackFactory.class); |
| | | |
| | | @Override |
| | | public AppUserVipDetailClient create(Throwable throwable) { |
| | | log.error("用户会员明细调用失败:{}", throwable.getMessage()); |
| | | return new AppUserVipDetailClient() { |
| | | |
| | | @Override |
| | | public R<TAppUserVipDetail> getAppUserVipDetail(GetAppUserVipDetail getAppUserVipDetail) { |
| | | return R.fail("获取用户当前有效的VIP明细调用失败:" + throwable.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.web.page.PageInfo; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | |
| | |
| | | * 管理后台远程调用 根据优惠券ids 查询对应的发放数量 |
| | | * @return 优惠券ids 查询每个优惠券的发放数量 |
| | | */ |
| | | @PostMapping("/t-app-coupon/getCountByCouponIds") |
| | | public R<List<Integer>> getCountByCouponIds(String couponIds); |
| | | @PostMapping("/t-app-coupon/getCountByCouponIds/{couponIds}") |
| | | public R<List<Integer>> getCountByCouponIds(@PathVariable("couponIds") String couponIds); |
| | | /** |
| | | * 管理后台远程调用 根据优惠券id 查询对应的使用数量 |
| | | * @param couponId |
| | | * @return |
| | | */ |
| | | @PostMapping("/t-app-coupon/getUseCountByCouponId") |
| | | public R<Integer> getUseCountByCouponId(Integer couponId); |
| | | @PostMapping("/t-app-coupon/getUseCountByCouponId/{couponId}") |
| | | public R<Integer> getUseCountByCouponId(@PathVariable("couponId")Integer couponId); |
| | | /** |
| | | * 后台远程调用 根据优惠券id 查询领取记录 |
| | | * @param couponId |
New file |
| | |
| | | package com.ruoyi.account.api.feignClient; |
| | | |
| | | import com.ruoyi.account.api.factory.AppUserVipDetailFallbackFactory; |
| | | import com.ruoyi.account.api.model.TAppUserVipDetail; |
| | | import com.ruoyi.account.api.vo.GetAppUserVipDetail; |
| | | import com.ruoyi.common.core.constant.ServiceNameConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 10:27 |
| | | */ |
| | | @FeignClient(contextId = "AppUserVipDetailClient", value = ServiceNameConstants.ACCOUNT_SERVICE, fallbackFactory = AppUserVipDetailFallbackFactory.class) |
| | | public interface AppUserVipDetailClient { |
| | | |
| | | /** |
| | | * 获取用户当前有效的VIP明细 |
| | | * @param getAppUserVipDetail |
| | | * @return |
| | | */ |
| | | @PostMapping("/appUserVipDetail/getAppUserVipDetail") |
| | | R<TAppUserVipDetail> getAppUserVipDetail(GetAppUserVipDetail getAppUserVipDetail); |
| | | |
| | | |
| | | } |
| | |
| | | @ApiModelProperty(value = "剩余充电次数") |
| | | @TableField("charge_num") |
| | | private Integer chargeNum; |
| | | |
| | | |
| | | |
| | | @ApiModelProperty(value = "购买时折扣金额") |
| | | |
| | | @ApiModelProperty(value = "折扣") |
| | | @TableField("discount") |
| | | private BigDecimal discount; |
| | | |
| | | @ApiModelProperty(value = "最高优惠金额") |
| | | @TableField("discount_money") |
| | | private BigDecimal discountMoney; |
| | | |
New file |
| | |
| | | package com.ruoyi.account.api.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 10:30 |
| | | */ |
| | | @Data |
| | | public class GetAppUserVipDetail { |
| | | /** |
| | | * 用户id |
| | | */ |
| | | private Long appUserId; |
| | | /** |
| | | * vipid |
| | | */ |
| | | private Integer vipId; |
| | | } |
| | |
| | | public R<SiteInfoVO> getSiteInfoByNumber(String number) { |
| | | return R.fail("通过桩编号获取电站信息失败:"+throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<TChargingPile> getChargingPileById(Integer id) { |
| | | return R.fail(throwable.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | |
| | | @PostMapping("/site/getSiteInfoByNumber") |
| | | @ApiOperation(value = "扫一扫后通过桩编号获取电站信息", tags = {"小程序-扫一扫"}) |
| | | R<SiteInfoVO> getSiteInfoByNumber(@RequestParam("number") String number); |
| | | |
| | | |
| | | @PostMapping("/t-charging-pile/getChargingPileById/{id}") |
| | | R<TChargingPile> getChargingPileById(@PathVariable("id") Integer id); |
| | | } |
| | |
| | | private String name; |
| | | @ApiModelProperty(value = "桩编号") |
| | | private String number; |
| | | @ApiModelProperty(value = "充电枪id") |
| | | private Integer chargingGunId; |
| | | @ApiModelProperty(value = "普通电价") |
| | | private BigDecimal electrovalence; |
| | | @ApiModelProperty(value = "会员电价") |
| | |
| | | private BigDecimal vipPaymentAmount; |
| | | |
| | | @ApiModelProperty(value = "优惠券说明") |
| | | @TableField("explain") |
| | | private String explain; |
| | | @TableField("explains") |
| | | private String explains; |
| | | |
| | | @ApiModelProperty(value = "说明") |
| | | @TableField("remark") |
| | |
| | | @EqualsAndHashCode(callSuper = false) |
| | | @TableName("t_role_site") |
| | | @ApiModel(value="TRoleSite对象", description="") |
| | | public class TRoleSite extends BasePojo { |
| | | public class TRoleSite { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | |
| | | @EqualsAndHashCode(callSuper = false) |
| | | @TableName("t_user_site") |
| | | @ApiModel(value="TUserSite对象", description="") |
| | | public class TUserSite extends BasePojo { |
| | | public class TUserSite { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
New file |
| | |
| | | package com.ruoyi.other.api.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 17:43 |
| | | */ |
| | | @Data |
| | | public class WebSocketMsg { |
| | | /** |
| | | * 用户id |
| | | */ |
| | | private Long userId; |
| | | /** |
| | | * 消息内容 |
| | | */ |
| | | private String msg; |
| | | } |
| | |
| | | |
| | | @Override |
| | | public R addUserSite(List<TUserSite> userSite) { |
| | | return R.fail("添加用户站点失败:" + throwable.getMessage()); |
| | | throw new RuntimeException("添加用户站点失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
New file |
| | |
| | | package com.ruoyi.other.api.factory; |
| | | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.other.api.domain.TVip; |
| | | import com.ruoyi.other.api.dto.WebSocketMsg; |
| | | import com.ruoyi.other.api.feignClient.VipClient; |
| | | import com.ruoyi.other.api.feignClient.WebSocketClient; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 会员服务降级处理 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Component |
| | | public class WebSocketFallbackFactory implements FallbackFactory<WebSocketClient> { |
| | | private static final Logger log = LoggerFactory.getLogger(WebSocketFallbackFactory.class); |
| | | |
| | | @Override |
| | | public WebSocketClient create(Throwable throwable) { |
| | | log.error("WebSocket调用失败:{}", throwable.getMessage()); |
| | | return new WebSocketClient() { |
| | | |
| | | @Override |
| | | public R send(WebSocketMsg webSocketMsg) { |
| | | return R.fail("发送WebSocket消息失败:" + throwable.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.api.feignClient; |
| | | |
| | | import com.ruoyi.common.core.constant.ServiceNameConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.other.api.dto.WebSocketMsg; |
| | | import com.ruoyi.other.api.factory.WebSocketFallbackFactory; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 17:41 |
| | | */ |
| | | @FeignClient(contextId = "WebSocketClient", value = ServiceNameConstants.ORDER_SERVICE, fallbackFactory = WebSocketFallbackFactory.class) |
| | | public interface WebSocketClient { |
| | | |
| | | |
| | | /** |
| | | * 发送WebSocket消息 |
| | | * @return |
| | | */ |
| | | @PostMapping("/webSocket/send") |
| | | R send(WebSocketMsg webSocketMsg); |
| | | } |
| | |
| | | com.ruoyi.other.api.factory.IntegralRuleFallbackFactory |
| | | com.ruoyi.other.api.factory.GoodsFallbackFactory |
| | | com.ruoyi.other.api.factory.CouponFallbackFactory |
| | | com.ruoyi.other.api.factory.InvoiceTypeFallbackFactory |
| | | com.ruoyi.other.api.factory.InvoiceTypeFallbackFactory |
| | | com.ruoyi.other.api.factory.WebSocketFallbackFactory |
New file |
| | |
| | | package com.ruoyi.payment.api.factory; |
| | | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.payment.api.feignClient.WxPaymentClient; |
| | | import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; |
| | | import com.ruoyi.payment.api.vo.PaymentOrder; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 充电订单服务降级处理 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Component |
| | | public class WxPaymentFallbackFactory implements FallbackFactory<WxPaymentClient> |
| | | { |
| | | private static final Logger log = LoggerFactory.getLogger(WxPaymentFallbackFactory.class); |
| | | |
| | | @Override |
| | | public WxPaymentClient create(Throwable throwable) { |
| | | log.error("微信支付调用失败:{}", throwable.getMessage()); |
| | | return new WxPaymentClient() { |
| | | |
| | | @Override |
| | | public R<NotifyV3PayDecodeRespBody> queryOrderInfo(String orderId) { |
| | | return R.fail("查询支付订单信息失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<Map<String, Object>> orderPay(PaymentOrder paymentOrder) { |
| | | throw new RuntimeException("调起微信支付失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<Map<String, Object>> payNotify(HttpServletRequest request) { |
| | | return R.fail("微信支付回调失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public void ack() { |
| | | |
| | | } |
| | | }; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.payment.api.feignClient; |
| | | |
| | | import com.ruoyi.common.core.constant.ServiceNameConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.payment.api.factory.WxPaymentFallbackFactory; |
| | | import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; |
| | | import com.ruoyi.payment.api.vo.PaymentOrder; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 充电订单服务 |
| | | * @author ruoyi |
| | | */ |
| | | @FeignClient(contextId = "WxPaymentClient", value = ServiceNameConstants.PAYMENT_SERVICE, fallbackFactory = WxPaymentFallbackFactory.class) |
| | | public interface WxPaymentClient { |
| | | |
| | | /** |
| | | * 查询支付订单信息 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @PostMapping("/wx/query/queryOrderInfo") |
| | | R<NotifyV3PayDecodeRespBody> queryOrderInfo(String orderId); |
| | | |
| | | |
| | | /** |
| | | * 订单支付 |
| | | * @param paymentOrder |
| | | * @return |
| | | */ |
| | | @PostMapping("/wx/orderPay") |
| | | R<Map<String, Object>> orderPay(@RequestBody PaymentOrder paymentOrder); |
| | | |
| | | |
| | | /** |
| | | * 支付回调 |
| | | * @param request |
| | | * @return |
| | | */ |
| | | @PostMapping("/wx/pay/notify") |
| | | R<Map<String, Object>> payNotify(HttpServletRequest request); |
| | | |
| | | /** |
| | | * 支付回调成功后的成功应答 |
| | | */ |
| | | @PostMapping("/wx/pay/ack") |
| | | void ack(); |
| | | |
| | | |
| | | /** |
| | | * 关闭订单 |
| | | * @param outTradeNo |
| | | */ |
| | | @PostMapping("/wx/pay/close") |
| | | void close(String outTradeNo); |
| | | } |
New file |
| | |
| | | package com.ruoyi.payment.api.vo; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author xiaochen |
| | | * @ClassName FacilV3PayNotifyRespBody |
| | | * @Description |
| | | */ |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public class NotifyV3PayDecodeRespBody implements Serializable { |
| | | // 合单--开始 |
| | | private String combine_appid; |
| | | private String combine_mchid; |
| | | private String combine_out_trade_no; |
| | | private List<SubOrders> sub_orders; |
| | | // 合单--结束 |
| | | /** |
| | | * 服务商应用ID |
| | | */ |
| | | private String sp_appid; |
| | | /** |
| | | * 服务商户号 |
| | | */ |
| | | private String sp_mchid; |
| | | /** |
| | | * 商户号 |
| | | */ |
| | | private String mchid; |
| | | /** |
| | | * 子商户应用ID |
| | | */ |
| | | private String sub_appid; |
| | | /** |
| | | * 子商户号 |
| | | */ |
| | | private String sub_mchid; |
| | | /** |
| | | * 商户订单号 |
| | | */ |
| | | private String out_trade_no; |
| | | /** |
| | | * 交易状态描述 |
| | | */ |
| | | private String trade_state_desc; |
| | | /** |
| | | * 交易类型,枚举值: |
| | | * JSAPI:公众号支付 |
| | | * NATIVE:扫码支付 |
| | | * APP:APP支付 |
| | | * MICROPAY:付款码支付 |
| | | * MWEB:H5支付 |
| | | * FACEPAY:刷脸支付 |
| | | */ |
| | | private String trade_type; |
| | | /** |
| | | * 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 |
| | | */ |
| | | private String attach; |
| | | /** |
| | | * 微信支付订单号 |
| | | */ |
| | | private String transaction_id; |
| | | /** |
| | | * 交易状态,枚举值: |
| | | * SUCCESS:支付成功 |
| | | * REFUND:转入退款 |
| | | * NOTPAY:未支付 |
| | | * CLOSED:已关闭 |
| | | * REVOKED:已撤销(付款码支付) |
| | | * USERPAYING:用户支付中(付款码支付) |
| | | * PAYERROR:支付失败(其他原因,如银行返回失败) |
| | | */ |
| | | private String trade_state; |
| | | /** |
| | | * 银行类型,采用字符串类型的银行标识。银行标识请参考《银行类型对照表》 |
| | | * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/terms_definition/chapter1_1_3.shtml#part-6 |
| | | */ |
| | | private String bank_type; |
| | | /** |
| | | * 支付完成时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE, |
| | | * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒, |
| | | * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。 |
| | | * 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 |
| | | * 示例值:2018-06-08T10:34:56+08:00 |
| | | */ |
| | | private String success_time; |
| | | /** |
| | | * 支付者信息 |
| | | */ |
| | | private Payer payer; |
| | | |
| | | /** |
| | | * 支付者 |
| | | */ |
| | | private Payer combine_payer_info; |
| | | |
| | | /** |
| | | * 订单金额信息 |
| | | */ |
| | | private Amount amount; |
| | | /** |
| | | * 场景信息 |
| | | */ |
| | | private SceneInfo scene_info; |
| | | /** |
| | | * 优惠功能,享受优惠时返回该字段 |
| | | */ |
| | | private List<PromotionDetail> promotion_detail; |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class Amount implements Serializable{ |
| | | /** |
| | | * 用户支付金额 |
| | | */ |
| | | private int payer_total; |
| | | /** |
| | | * 总金额 |
| | | */ |
| | | private int total; |
| | | /** |
| | | * 标价金额 |
| | | */ |
| | | private int total_amount; |
| | | /** |
| | | * 现金支付金额 |
| | | */ |
| | | private int payer_amount; |
| | | private String currency; |
| | | private String payer_currency; |
| | | } |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class GoodsDetail implements Serializable{ |
| | | private String goods_id; |
| | | private int quantity; |
| | | private int unit_price; |
| | | private int discount_amount; |
| | | private String goods_remark; |
| | | |
| | | } |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class Payer implements Serializable{ |
| | | private String openid; |
| | | private String sp_openid; |
| | | private String sub_openid; |
| | | } |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class PromotionDetail implements Serializable{ |
| | | private String coupon_id; |
| | | private String name; |
| | | private String scope; |
| | | private String type; |
| | | private int amount; |
| | | private String stock_id; |
| | | private int wechatpay_contribute; |
| | | |
| | | private int merchant_contribute; |
| | | private int other_contribute; |
| | | private String currency; |
| | | |
| | | private List<GoodsDetail> goods_detail; |
| | | |
| | | } |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class SceneInfo implements Serializable{ |
| | | /** |
| | | * 商户端设备号 |
| | | */ |
| | | private String device_id; |
| | | } |
| | | |
| | | |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Data |
| | | public static class SubOrders implements Serializable{ |
| | | private String mchid; |
| | | private String trade_type; |
| | | private String trade_state; |
| | | private String trade_state_desc; |
| | | private String bank_type; |
| | | private String attach; |
| | | private String success_time; |
| | | private String transaction_id; |
| | | private String out_trade_no; |
| | | private String sub_mchid; |
| | | private Amount amount; |
| | | /** |
| | | * 优惠功能,享受优惠时返回该字段 |
| | | */ |
| | | private List<PromotionDetail> promotion_detail; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.payment.api.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 9:06 |
| | | */ |
| | | @Data |
| | | public class PaymentOrder { |
| | | /** |
| | | * 订单流水号 |
| | | */ |
| | | private String code; |
| | | /** |
| | | * 支付金额 |
| | | */ |
| | | private BigDecimal amount; |
| | | /** |
| | | * openid |
| | | */ |
| | | private String openId; |
| | | /** |
| | | * 描述 |
| | | */ |
| | | private String description; |
| | | /** |
| | | * 回调地址 |
| | | */ |
| | | private String notifyUrl; |
| | | } |
| | |
| | | */ |
| | | @Data |
| | | @ApiModel |
| | | @TableName("") |
| | | public class SysOperLog extends BaseEntity { |
| | | @TableName("sys_oper_log") |
| | | public class SysOperLog { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | |
| | | /** |
| | | * 日志主键 |
| | | */ |
| | |
| | | @ApiModelProperty("数据id") |
| | | @TableId(value = "oper_id", type = IdType.AUTO) |
| | | private Long operId; |
| | | |
| | | |
| | | /** |
| | | * 操作模块 |
| | | */ |
| | | @Excel(name = "操作模块") |
| | | @ApiModelProperty("操作模块") |
| | | private String title; |
| | | |
| | | |
| | | /** |
| | | * 业务类型(0其它 1新增 2修改 3删除) |
| | | */ |
| | |
| | | @ApiModelProperty("0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据") |
| | | @TableField("business_type") |
| | | private Integer businessType; |
| | | |
| | | |
| | | /** |
| | | * 业务类型数组 |
| | | */ |
| | | @TableField(exist = false) |
| | | private Integer[] businessTypes; |
| | | |
| | | |
| | | /** |
| | | * 请求方法 |
| | | */ |
| | | @Excel(name = "请求方法") |
| | | @ApiModelProperty("请求方法") |
| | | private String method; |
| | | |
| | | |
| | | /** |
| | | * 请求方式 |
| | | */ |
| | |
| | | @ApiModelProperty("请求方式") |
| | | @TableField("request_method") |
| | | private String requestMethod; |
| | | |
| | | |
| | | /** |
| | | * 操作类别(0其它 1后台用户 2手机端用户) |
| | | */ |
| | |
| | | @ApiModelProperty("0=其它,1=后台用户,2=手机端用户") |
| | | @TableField("operator_type") |
| | | private Integer operatorType; |
| | | |
| | | |
| | | /** |
| | | * 操作人员 |
| | | */ |
| | | @Excel(name = "操作人员") |
| | | @ApiModelProperty("操作人员") |
| | | @TableField("operator_type") |
| | | @TableField("oper_name") |
| | | private String operName; |
| | | |
| | | |
| | | /** |
| | | * 部门名称 |
| | | */ |
| | | @Excel(name = "部门名称") |
| | | @ApiModelProperty("部门名称") |
| | | @TableField("dept_name") |
| | | private String deptName; |
| | | |
| | | |
| | | /** |
| | | * 请求url |
| | | */ |
| | | @Excel(name = "请求地址") |
| | | @ApiModelProperty("请求地址") |
| | | @TableField("oper_url") |
| | | private String operUrl; |
| | | |
| | | |
| | | /** |
| | | * 操作地址 |
| | | */ |
| | | @Excel(name = "操作地址") |
| | | @ApiModelProperty("操作地址") |
| | | @TableField("oper_ip") |
| | | private String operIp; |
| | | |
| | | |
| | | /** |
| | | * 请求参数 |
| | | */ |
| | | @Excel(name = "请求参数") |
| | | @ApiModelProperty("请求参数") |
| | | @TableField("oper_param") |
| | | private String operParam; |
| | | |
| | | |
| | | /** |
| | | * 返回参数 |
| | | */ |
| | | @Excel(name = "返回参数") |
| | | @ApiModelProperty("返回参数") |
| | | @TableField("json_result") |
| | | private String jsonResult; |
| | | |
| | | |
| | | /** |
| | | * 操作状态(0正常 1异常) |
| | | */ |
| | | @Excel(name = "状态", readConverterExp = "0=正常,1=异常") |
| | | @ApiModelProperty("0=正常,1=异常") |
| | | private Integer status; |
| | | |
| | | |
| | | /** |
| | | * 错误消息 |
| | | */ |
| | | @Excel(name = "错误消息") |
| | | @ApiModelProperty("错误消息") |
| | | @TableField("error_msg") |
| | | private String errorMsg; |
| | | |
| | | |
| | | /** |
| | | * 操作时间 |
| | | */ |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") |
| | | @ApiModelProperty("操作时间") |
| | | @TableField("oper_time") |
| | | private Date operTime; |
| | | |
| | | |
| | | /** |
| | | * 消耗时间 |
| | | */ |
| | | @Excel(name = "消耗时间", suffix = "毫秒") |
| | | @ApiModelProperty("消耗时间") |
| | | @TableField("cost_time") |
| | | private Long costTime; |
| | | |
| | | public Long getOperId() { |
| | | return operId; |
| | | } |
| | | |
| | | public void setOperId(Long operId) { |
| | | this.operId = operId; |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void setTitle(String title) { |
| | | this.title = title; |
| | | } |
| | | |
| | | public Integer getBusinessType() { |
| | | return businessType; |
| | | } |
| | | |
| | | public void setBusinessType(Integer businessType) { |
| | | this.businessType = businessType; |
| | | } |
| | | |
| | | public Integer[] getBusinessTypes() { |
| | | return businessTypes; |
| | | } |
| | | |
| | | public void setBusinessTypes(Integer[] businessTypes) { |
| | | this.businessTypes = businessTypes; |
| | | } |
| | | |
| | | public String getMethod() { |
| | | return method; |
| | | } |
| | | |
| | | public void setMethod(String method) { |
| | | this.method = method; |
| | | } |
| | | |
| | | public String getRequestMethod() { |
| | | return requestMethod; |
| | | } |
| | | |
| | | public void setRequestMethod(String requestMethod) { |
| | | this.requestMethod = requestMethod; |
| | | } |
| | | |
| | | public Integer getOperatorType() { |
| | | return operatorType; |
| | | } |
| | | |
| | | public void setOperatorType(Integer operatorType) { |
| | | this.operatorType = operatorType; |
| | | } |
| | | |
| | | public String getOperName() { |
| | | return operName; |
| | | } |
| | | |
| | | public void setOperName(String operName) { |
| | | this.operName = operName; |
| | | } |
| | | |
| | | public String getDeptName() { |
| | | return deptName; |
| | | } |
| | | |
| | | public void setDeptName(String deptName) { |
| | | this.deptName = deptName; |
| | | } |
| | | |
| | | public String getOperUrl() { |
| | | return operUrl; |
| | | } |
| | | |
| | | public void setOperUrl(String operUrl) { |
| | | this.operUrl = operUrl; |
| | | } |
| | | |
| | | public String getOperIp() { |
| | | return operIp; |
| | | } |
| | | |
| | | public void setOperIp(String operIp) { |
| | | this.operIp = operIp; |
| | | } |
| | | |
| | | public String getOperParam() { |
| | | return operParam; |
| | | } |
| | | |
| | | public void setOperParam(String operParam) { |
| | | this.operParam = operParam; |
| | | } |
| | | |
| | | public String getJsonResult() { |
| | | return jsonResult; |
| | | } |
| | | |
| | | public void setJsonResult(String jsonResult) { |
| | | this.jsonResult = jsonResult; |
| | | } |
| | | |
| | | public Integer getStatus() { |
| | | return status; |
| | | } |
| | | |
| | | public void setStatus(Integer status) { |
| | | this.status = status; |
| | | } |
| | | |
| | | public String getErrorMsg() { |
| | | return errorMsg; |
| | | } |
| | | |
| | | public void setErrorMsg(String errorMsg) { |
| | | this.errorMsg = errorMsg; |
| | | } |
| | | |
| | | public Date getOperTime() { |
| | | return operTime; |
| | | } |
| | | |
| | | public void setOperTime(Date operTime) { |
| | | this.operTime = operTime; |
| | | } |
| | | |
| | | public Long getCostTime() { |
| | | return costTime; |
| | | } |
| | | |
| | | public void setCostTime(Long costTime) { |
| | | this.costTime = costTime; |
| | | } |
| | | } |
| | |
| | | */ |
| | | public static final int PASSWORD_MIN_LENGTH = 5; |
| | | |
| | | public static final int PASSWORD_MAX_LENGTH = 20; |
| | | public static final int PASSWORD_MAX_LENGTH = 40; |
| | | } |
| | |
| | | import com.ruoyi.common.core.utils.ServletUtils; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.core.utils.html.EscapeUtil; |
| | | import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties; |
| | | import com.ruoyi.gateway.config.properties.XssProperties; |
| | | import io.netty.buffer.ByteBufAllocator; |
| | | import org.apache.commons.codec.binary.Base64; |
| | |
| | | */ |
| | | @Component |
| | | public class RequestParamGlobalFilter implements GlobalFilter, Ordered { |
| | | |
| | | @Autowired |
| | | private IgnoreWhiteProperties ignoreWhite; |
| | | |
| | | |
| | | @Override |
| | | public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
| | | ServerHttpRequest request = exchange.getRequest(); |
| | | ServerHttpRequest.Builder mutate = request.mutate(); |
| | | HttpMethod method = request.getMethod(); |
| | | if(method != HttpMethod.POST){ |
| | | return chain.filter(exchange.mutate().request(mutate.build()).build()); |
| | | } |
| | | // 跳过不需要验证的路径 |
| | | String url = request.getURI().getPath(); |
| | | if (StringUtils.matches(url, ignoreWhite.getWhites())) { |
| | | return chain.filter(exchange); |
| | | } |
| | | ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); |
| | | return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); |
| | | } |
| | |
| | | @Value("${security.sign}") |
| | | private boolean parameter_signature; |
| | | |
| | | @Autowired |
| | | private IgnoreWhiteProperties ignoreWhite; |
| | | |
| | | |
| | | @Override |
| | | public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
| | |
| | | if(method != HttpMethod.POST){ |
| | | return chain.filter(exchange.mutate().request(mutate.build()).build()); |
| | | } |
| | | // 跳过不需要验证的路径 |
| | | String url = request.getURI().getPath(); |
| | | if (StringUtils.matches(url, ignoreWhite.getWhites())) { |
| | | return chain.filter(exchange); |
| | | } |
| | | String sign = request.getHeaders().getFirst(TokenConstants.SIGN); |
| | | String nonce_str = request.getHeaders().getFirst(TokenConstants.NONCE_STR); |
| | | if (parameter_signature && StringUtils.isEmpty(sign)) { |
| | |
| | | import com.ruoyi.system.domain.vo.CompanyUserVo; |
| | | import com.ruoyi.system.domain.vo.TCompanyToUserVo; |
| | | import com.ruoyi.system.query.GetSysUserList; |
| | | import com.ruoyi.system.query.ShopUserStart; |
| | | import com.ruoyi.system.service.*; |
| | | import io.seata.spring.annotation.GlobalTransactional; |
| | | import io.swagger.annotations.Api; |
| | |
| | | public AjaxResult<List<String>> getRoleSiteName(@PathVariable Integer roleId){ |
| | | List<Integer> ids = roleSiteClient.getSiteIds(roleId.longValue()).getData(); |
| | | List<Site> data = siteClient.getSiteByIds(ids).getData(); |
| | | if(null == data){ |
| | | return AjaxResult.success(new ArrayList<>()); |
| | | } |
| | | List<String> siteNames = data.stream().map(Site::getName).collect(Collectors.toList()); |
| | | return AjaxResult.success(siteNames); |
| | | } |
| | |
| | | |
| | | @PostMapping("/shopUserStart") |
| | | @ApiOperation(value = "账号管理--禁用/启用", tags = {"管理后台-系统用户管理"}) |
| | | public AjaxResult shopUserStart(@RequestParam("userId") Long userId, @RequestParam("remark") String remark) { |
| | | if (userId == null) { |
| | | public AjaxResult shopUserStart(@RequestBody ShopUserStart shopUserStart) { |
| | | if (shopUserStart.getUserId() == null) { |
| | | return AjaxResult.error("userId不能为空"); |
| | | } |
| | | SysUser sysUser = userService.selectUserById(userId); |
| | | SysUser sysUser = userService.selectUserById(shopUserStart.getUserId()); |
| | | if (sysUser.getStatus().equals("0")) { |
| | | sysUser.setStatus("1"); |
| | | sysUser.setRemark(remark); |
| | | sysUser.setRemark(shopUserStart.getRemark()); |
| | | } else { |
| | | sysUser.setStatus("0"); |
| | | sysUser.setRemark(""); |
| | |
| | | import com.ruoyi.system.domain.vo.MetaVo; |
| | | import com.ruoyi.system.domain.vo.RouterVo; |
| | | import com.ruoyi.system.domain.vo.TreeSelect; |
| | | import com.ruoyi.system.mapper.SysMenuMapper; |
| | | import com.ruoyi.system.mapper.SysRoleMapper; |
| | | import com.ruoyi.system.mapper.SysRoleMenuMapper; |
| | | import com.ruoyi.system.mapper.SysUserRoleMapper; |
| | | import com.ruoyi.system.mapper.*; |
| | | import com.ruoyi.system.service.ISysMenuService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.system.api.domain.SysRole; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | /** |
| | | * 菜单 业务层处理 |
| | |
| | | |
| | | @Autowired |
| | | private SysUserRoleMapper sysUserRoleMapper; |
| | | |
| | | @Resource |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据用户查询系统菜单列表 |
| | |
| | | |
| | | @Override |
| | | public List<SysMenus> getAllMenu() { |
| | | Long roleId = tokenService.getLoginUser().getSysUser().getRoles().get(0).getRoleId(); |
| | | Long userid = tokenService.getLoginUser().getUserid(); |
| | | SysUserRole sysUserRole = sysUserRoleMapper.selectSysUserRoleByUserId(userid); |
| | | Long roleId = sysUserRole.getRoleId(); |
| | | List<SysMenus> list=null; |
| | | if(roleId!=1){ |
| | | list = menuMapper.getAllOne(); |
| | |
| | | import com.ruoyi.system.domain.SysUserRole; |
| | | import com.ruoyi.system.query.GetSysUserList; |
| | | import com.ruoyi.system.service.ISysConfigService; |
| | | import com.ruoyi.system.service.ISysRoleService; |
| | | import com.ruoyi.system.service.ISysUserRoleService; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import org.slf4j.Logger; |
| | |
| | | |
| | | @Resource |
| | | private SiteClient siteClient; |
| | | |
| | | @Resource |
| | | private ISysRoleService sysRoleService; |
| | | |
| | | |
| | | |
| | |
| | | for (SysUser sysUser : list) { |
| | | List<SysUserRole> list1 = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, sysUser.getUserId())); |
| | | List<Integer> data1 = userSiteClient.getSiteIds(sysUser.getUserId()).getData(); |
| | | if(null == data1){ |
| | | data1 = new ArrayList<>(); |
| | | } |
| | | for (SysUserRole sysUserRole : list1) { |
| | | List<Integer> data = roleSiteClient.getSiteIds(sysUserRole.getRoleId()).getData(); |
| | | if (null == data){ |
| | | continue; |
| | | } |
| | | data1.addAll(data); |
| | | } |
| | | Set<Integer> siteIds = new HashSet<>(data1); |
| | | sysUser.setSiteIds(siteIds.stream().collect(Collectors.toList())); |
| | | List<Site> data = siteClient.getSiteByIds(siteIds.stream().collect(Collectors.toList())).getData(); |
| | | List<String> siteNames = data.stream().map(Site::getName).collect(Collectors.toList()); |
| | | sysUser.setSiteNames(siteNames); |
| | | |
| | | Set<Long> collect = list1.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet()); |
| | | List<SysRole> sysRoles = roleMapper.selectBatchIds(collect); |
| | | List<String> roleNames = sysRoles.stream().map(SysRole::getRoleName).collect(Collectors.toList()); |
| | | if(null != data){ |
| | | List<String> siteNames = data.stream().map(Site::getName).collect(Collectors.toList()); |
| | | sysUser.setSiteNames(siteNames); |
| | | } |
| | | List<String> roleNames = new ArrayList<>(); |
| | | for (SysUserRole sysUserRole : list1) { |
| | | SysRole sysRole = sysRoleService.selectRoleById(sysUserRole.getRoleId()); |
| | | roleNames.add(sysRole.getRoleName()); |
| | | } |
| | | Long[] roleIds = new Long[]{}; |
| | | sysUser.setRoleIds(list1.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()).toArray(roleIds)); |
| | | sysUser.setRoleNames(roleNames); |
| | | } |
| | | return pageInfo.setRecords(list); |
| | |
| | | import com.ruoyi.account.api.model.TAppCoupon; |
| | | import com.ruoyi.account.api.model.TAppUserCar; |
| | | import com.ruoyi.account.api.query.ExchangeRecordGoodsQuery; |
| | | import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; |
| | | import com.ruoyi.chargingPile.api.model.TChargingGun; |
| | | import com.ruoyi.chargingPile.api.model.TChargingPile; |
| | | import com.ruoyi.other.api.vo.CouponListVOVO; |
| | | import com.ruoyi.account.api.vo.ExchangeRecordVO; |
| | | import com.ruoyi.account.service.TAppCouponService; |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | |
| | | private ChargingPileClient chargingPileClient; |
| | | @Autowired |
| | | private ChargingOrderClient chargingOrderClient; |
| | | |
| | | @Resource |
| | | private ChargingGunClient chargingGunClient; |
| | | |
| | | |
| | | /** |
| | | * 小程序扫一扫 添加车辆 |
| | | * @param dto |
| | |
| | | * 查询用户可用优惠券数量 |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "通过桩编号和预付金额获取电站详情", tags = {"小程序-扫一扫"}) |
| | | @ApiOperation(value = "通过充电枪id和预付金额获取电站详情", tags = {"小程序-扫一扫"}) |
| | | @GetMapping(value = "/scan/siteInfo") |
| | | public AjaxResult<SiteInfoVO> siteInfo(String number,BigDecimal money) { |
| | | SiteInfoVO data = chargingPileClient.getSiteInfoByNumber(number).getData(); |
| | | public AjaxResult<SiteInfoVO> siteInfo(Integer id, BigDecimal money) { |
| | | TChargingGun chargingGun = chargingGunClient.getChargingGunById(id).getData(); |
| | | TChargingPile chargingPile = chargingPileClient.getChargingPileById(chargingGun.getChargingPileId()).getData(); |
| | | SiteInfoVO data = chargingPileClient.getSiteInfoByNumber(chargingPile.getNumber().toString()).getData(); |
| | | data.setChargingGunId(id); |
| | | List<TAppUserCar> cars = appUserCarService.list(new QueryWrapper<TAppUserCar>() |
| | | .eq("app_user_id",tokenService.getLoginUserApplet().getUserId()) |
| | | .orderByDesc("create_time")); |
| | |
| | | * 管理后台远程调用 根据优惠券ids 查询对应的发放数量 |
| | | * @return 优惠券ids 查询每个优惠券的发放数量 |
| | | */ |
| | | @PostMapping("/getCountByCouponIds") |
| | | public R<List<Integer>> getCountByCouponIds(@RequestParam("couponIds") String couponIds) { |
| | | @PostMapping("/getCountByCouponIds/{couponIds}") |
| | | public R<List<Integer>> getCountByCouponIds(@PathVariable("couponIds")String couponIds) { |
| | | // 最终结果 和优惠券id一一对应 |
| | | List<Integer> res = new ArrayList<>(); |
| | | String[] split = couponIds.split(","); |
| | |
| | | * @param couponId |
| | | * @return |
| | | */ |
| | | @PostMapping("/getUseCountByCouponId") |
| | | public R<Integer> getUseCountByCouponId(Integer couponId){ |
| | | @PostMapping("/getUseCountByCouponId/{couponId}") |
| | | public R<Integer> getUseCountByCouponId(@PathVariable("couponId") Integer couponId){ |
| | | return R.ok(tAppCouponService.list(new QueryWrapper<TAppCoupon>() |
| | | .eq("coupon_id", couponId) |
| | | .eq("status",2)).size()); |
New file |
| | |
| | | package com.ruoyi.account.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.account.api.model.TAppUserVipDetail; |
| | | import com.ruoyi.account.api.vo.GetAppUserVipDetail; |
| | | import com.ruoyi.account.service.TAppUserVipDetailService; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 10:35 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/appUserVipDetail") |
| | | public class TAppUserVipDetailController { |
| | | |
| | | @Resource |
| | | private TAppUserVipDetailService appUserVipDetailService; |
| | | |
| | | /** |
| | | * 获取用户当前有效的vip明细 |
| | | * @param getAppUserVipDetail |
| | | * @return |
| | | */ |
| | | @PostMapping("/getAppUserVipDetail") |
| | | public R<TAppUserVipDetail> getAppUserVipDetail(@RequestBody GetAppUserVipDetail getAppUserVipDetail){ |
| | | TAppUserVipDetail one = appUserVipDetailService.getOne(new LambdaQueryWrapper<TAppUserVipDetail>() |
| | | .eq(TAppUserVipDetail::getAppUserId, getAppUserVipDetail.getAppUserId()) |
| | | .eq(TAppUserVipDetail::getVipId, getAppUserVipDetail.getVipId()) |
| | | .last(" and now() between start_time and end_time")); |
| | | return R.ok(one); |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | <setting name="cacheEnabled" value="true"/> |
| | | <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false --> |
| | | <!-- <setting name="lazyLoadingEnabled" value="true"/> --> |
| | | <setting name="mapUnderscoreToCamelCase" value="false"/><!--是否将map下划线方式转为驼峰式命名--> |
| | | <setting name="mapUnderscoreToCamelCase" value="true"/><!--是否将map下划线方式转为驼峰式命名--> |
| | | <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖--> |
| | | <!-- <setting name="aggressiveLazyLoading" value="false"/>--> |
| | | <!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST --> |
| | |
| | | */ |
| | | @Api(tags = "服务器文件上传") |
| | | @RestController |
| | | @CrossOrigin |
| | | @RequestMapping("/file/") |
| | | public class FileController { |
| | | |
| | |
| | | // 获取文件名称 |
| | | String filename = mf.getOriginalFilename(); |
| | | // 获取文件后缀 |
| | | String ext = filename.substring(filename.lastIndexOf("."), filename.length()); |
| | | String ext = filename.substring(filename.lastIndexOf(".") + 1, filename.length()); |
| | | // 检查文件类型 |
| | | if (!fileUploadConfig.getAllowExt().contains(ext)) { |
| | | return AjaxResult.error("上传文件格式不正确,仅支持" + fileUploadConfig.getAllowExt()); |
| | |
| | | return AjaxResult.success(siteService.list(new QueryWrapper<>())); |
| | | } |
| | | |
| | | @PostMapping("/getSiteListGun") |
| | | @GetMapping("/getSiteListGun") |
| | | @ApiOperation(value = "获取站点列表 不分页", tags = {"管理后台-接口信息使用"}) |
| | | public AjaxResult<List<Site>> getSiteListGun(){ |
| | | return AjaxResult.success(siteService.getSiteListGun()); |
| | |
| | | import com.ruoyi.common.log.annotation.Log; |
| | | import com.ruoyi.common.log.enums.BusinessType; |
| | | import com.ruoyi.common.log.enums.OperatorType; |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.feignClient.SysUserClient; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | |
| | | import java.math.BigDecimal; |
| | | import java.math.BigInteger; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | import static com.ruoyi.common.core.context.SecurityContextHolder.getUserId; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "添加计费策略") |
| | | @PostMapping(value = "/add") |
| | | public AjaxResult<Integer> add(@RequestBody TAccountingStrategyDTO dto) { |
| | | if(null != dto.getSiteId()){ |
| | | dto.setAuditStatus(3); |
| | | } |
| | | Long userId = SecurityUtils.getLoginUser().getUserid(); |
| | | dto.setUserId(userId); |
| | | accountingStrategyService.save(dto); |
| | | // 添加明细 |
| | | dto.getAccountingStrategyDetails().forEach(detail -> detail.setAccountingStrategyId(dto.getId())); |
| | |
| | | TAccountingStrategyVO accountingStrategyVO = new TAccountingStrategyVO(); |
| | | BeanUtils.copyProperties(accountingStrategy,accountingStrategyVO); |
| | | // 查询用户信息 |
| | | String firstUserName = sysUserClient.getSysUser(accountingStrategy.getFirstUserId()).getData().getNickName(); |
| | | String twoUserName = sysUserClient.getSysUser(accountingStrategy.getTwoUserId()).getData().getNickName(); |
| | | accountingStrategyVO.setFirstUserName(firstUserName); |
| | | accountingStrategyVO.setTwoUserName(twoUserName); |
| | | if(null != accountingStrategy.getFirstUserId()){ |
| | | String firstUserName = sysUserClient.getSysUser(accountingStrategy.getFirstUserId()).getData().getNickName(); |
| | | accountingStrategyVO.setFirstUserName(firstUserName); |
| | | } |
| | | if(null != accountingStrategy.getTwoUserId()){ |
| | | String twoUserName = sysUserClient.getSysUser(accountingStrategy.getTwoUserId()).getData().getNickName(); |
| | | accountingStrategyVO.setTwoUserName(twoUserName); |
| | | } |
| | | return AjaxResult.ok(accountingStrategyVO); |
| | | } |
| | | |
| | |
| | | return AjaxResult.ok(accountingStrategyService.pageList(query)); |
| | | } |
| | | |
| | | // @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "审核") |
| | | // @PostMapping(value = "/auth/pass") |
| | | // public AjaxResult<PageInfo<TAccountingStrategyVO>> authPass(@RequestBody SteategyPassDto steategyPassDto) { |
| | | // TAccountingStrategy byId = accountingStrategyService.getById(steategyPassDto.getId()); |
| | | // Long userId = tokenService.getLoginUser().getSysUser().getUserId(); |
| | | // if (byId.getAuditStatus()==1&&byId.getFirstUserId()!=userId){ |
| | | // return AjaxResult.error("您不是一级审核人员,无法审核"); |
| | | // } |
| | | // if (byId.getAuditStatus()==2&&byId.getTwoUserId()!=userId){ |
| | | // return AjaxResult.error("您不是二级审核人员,无法审核"); |
| | | // } |
| | | // if (steategyPassDto.getPass()==1){ |
| | | // if (byId.getAuditStatus()==1){ |
| | | // |
| | | // byId.setAuditStatus(2); |
| | | // byId.setFirstRemark(steategyPassDto.getRemark()); |
| | | // |
| | | // }else if (byId.getAuditStatus()==2){ |
| | | // byId.setAuditStatus(3); |
| | | // byId.setTwoRemark(steategyPassDto.getRemark()); |
| | | // |
| | | // } |
| | | // }else { |
| | | // byId.setAuditStatus(4); |
| | | // } |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // } |
| | | @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "审核") |
| | | @PostMapping(value = "/auth/pass") |
| | | public AjaxResult<PageInfo<TAccountingStrategyVO>> authPass(@RequestBody SteategyPassDto steategyPassDto) { |
| | | TAccountingStrategy byId = accountingStrategyService.getById(steategyPassDto.getId()); |
| | | Long userId = SecurityUtils.getLoginUser().getUserid(); |
| | | if (byId.getAuditStatus()==1&&byId.getFirstUserId()!=userId){ |
| | | return AjaxResult.error("您不是一级审核人员,无法审核"); |
| | | } |
| | | if (byId.getAuditStatus()==2&&byId.getTwoUserId()!=userId){ |
| | | return AjaxResult.error("您不是二级审核人员,无法审核"); |
| | | } |
| | | if (steategyPassDto.getPass()==1){ |
| | | if (byId.getAuditStatus()==1){ |
| | | |
| | | byId.setAuditStatus(2); |
| | | byId.setFirstRemark(steategyPassDto.getRemark()); |
| | | byId.setFirstAuditTime(LocalDateTime.now()); |
| | | |
| | | }else if (byId.getAuditStatus()==2){ |
| | | byId.setAuditStatus(3); |
| | | byId.setTwoRemark(steategyPassDto.getRemark()); |
| | | byId.setTwoAuditTime(LocalDateTime.now()); |
| | | } |
| | | }else { |
| | | byId.setAuditStatus(4); |
| | | } |
| | | accountingStrategyService.updateById(byId); |
| | | |
| | | return AjaxResult.success(); |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | @ApiOperation(tags = {"后台-申请表单-计费模板审核"},value = "删除") |
| | | @DeleteMapping(value = "/delete") |
| | | public R delete(String ids) { |
| | | String[] split = ids.split(","); |
| | | for (String s : split) { |
| | | accountingStrategyService.removeById(s); |
| | | } |
| | | return R.ok(); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 小程序远程调用 根据会员折扣、预付金额 计算服务费 |
| | |
| | | import com.ruoyi.chargingPile.api.dto.ApplyChargingRemarkDto; |
| | | import com.ruoyi.chargingPile.api.model.TApplyChargingPile; |
| | | import com.ruoyi.chargingPile.service.TApplyChargingPileService; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.log.annotation.Log; |
| | | import com.ruoyi.common.log.enums.BusinessType; |
| | |
| | | * 建桩申请 |
| | | */ |
| | | @Log(title = "建桩申请", businessType = BusinessType.INSERT,operatorType = OperatorType.MOBILE) |
| | | @ApiOperation(tags = {"小程序-建桩申请","后台-申请表单-申请建桩"},value = "建桩申请") |
| | | @ApiOperation(tags = {"小程序-建桩申请"},value = "建桩申请") |
| | | @PostMapping(value = "/add") |
| | | public AjaxResult<Boolean> add(@RequestBody TApplyChargingPile dto) { |
| | | // 用户id |
| | | Long userId = tokenService.getLoginUserApplet().getUserId(); |
| | | dto.setAppUserId(userId); |
| | | return AjaxResult.ok(applyChargingPileService.save(dto)); |
| | | } |
| | | |
| | | @Log(title = "建桩申请", businessType = BusinessType.INSERT,operatorType = OperatorType.MOBILE) |
| | | @ApiOperation(tags = {"后台-申请表单-申请建桩"},value = "建桩申请") |
| | | @PostMapping(value = "/manage/add") |
| | | public AjaxResult<Boolean> manageAdd(@RequestBody TApplyChargingPile dto) { |
| | | |
| | | return AjaxResult.ok(applyChargingPileService.save(dto)); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | @ApiOperation(tags = {"后台-申请表单-申请建桩"},value = "导出") |
| | | @PostMapping(value = "/export") |
| | | public R export() { |
| | | return R.ok(); |
| | | } |
| | | |
| | | @ApiOperation(tags = {"后台-申请表单-申请建桩"},value = "详情") |
| | | @PostMapping(value = "/detail/{id}") |
| | | public AjaxResult<TApplyChargingPile> detail(@PathVariable Integer id) { |
| | |
| | | */ |
| | | @Log(title = "结束充电", businessType = BusinessType.UPDATE,operatorType = OperatorType.MANAGE) |
| | | @ApiOperation(tags = {"后台-充电枪"},value = "结束充电") |
| | | @PostMapping(value = "/stopCharging") |
| | | public AjaxResult<String> stopCharging() { |
| | | @PutMapping(value = "/stopCharging") |
| | | public AjaxResult<String> stopCharging(@RequestParam("id") Integer id) { |
| | | // TODO 硬件 结束充电 |
| | | return AjaxResult.success(); |
| | | } |
| | |
| | | PageInfo<ChargingGunMonitoring> chargingGunMonitoring = chargingPileService.getChargingGunMonitoring(query); |
| | | return AjaxResult.success(chargingGunMonitoring); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据id获取充电桩信息 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/getChargingPileById/{id}") |
| | | public R<TChargingPile> getChargingPileById(@PathVariable Integer id){ |
| | | TChargingPile chargingPile = chargingPileService.getById(id); |
| | | return R.ok(chargingPile); |
| | | } |
| | | } |
| | | |
| | |
| | | AND tcg.status = #{query.status} |
| | | </if> |
| | | <if test="query.chargeMode != null"> |
| | | AND tcg.chargeMode = #{query.chargeMode} |
| | | AND tcg.charge_mode = #{query.chargeMode} |
| | | </if> |
| | | <if test="null != siteIds"> |
| | | and tcg.site_id in |
| | |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-api-chargingPile</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-api-payment</artifactId> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- SpringCloud Alibaba Nacos --> |
| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.chargingPile.api.vo.SiteVO; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.redis.service.RedisService; |
| | | import com.ruoyi.common.security.service.TokenService; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.core.web.page.BasePage; |
| | |
| | | import com.ruoyi.order.dto.MyChargingOrderInfo; |
| | | import com.ruoyi.order.dto.MyChargingOrderList; |
| | | import com.ruoyi.order.dto.OrderEvaluateVo; |
| | | import com.ruoyi.order.dto.*; |
| | | import com.ruoyi.order.service.TChargingOrderService; |
| | | import com.ruoyi.order.service.TOrderEvaluateService; |
| | | import com.ruoyi.order.service.TOrderEvaluateTagService; |
| | | import com.ruoyi.payment.api.feignClient.WxPaymentClient; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiImplicitParam; |
| | | import io.swagger.annotations.ApiImplicitParams; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.List; |
| | |
| | | private TOrderEvaluateService orderEvaluateService; |
| | | @Autowired |
| | | private TOrderEvaluateTagService orderEvaluateTagService; |
| | | |
| | | @Resource |
| | | private WxPaymentClient wxPaymentClient; |
| | | |
| | | @Resource |
| | | private RedisService redisService; |
| | | |
| | | |
| | | |
| | | |
| | | @ResponseBody |
| | | @PostMapping(value = "/chargingOrder") |
| | |
| | | @ResponseBody |
| | | @GetMapping(value = "/getNoInvoicedOrder") |
| | | @ApiOperation(value = "获取未开票的订单数据", tags = {"小程序-充电发票"}) |
| | | public AjaxResult<List<MyChargingOrderList>> getNoInvoicedOrder(@RequestBody GetNoInvoicedOrder query){ |
| | | public AjaxResult<List<MyChargingOrderList>> getNoInvoicedOrder(GetNoInvoicedOrder query){ |
| | | List<MyChargingOrderList> list = chargingOrderService.getNoInvoicedOrder(query); |
| | | return AjaxResult.success(list); |
| | | } |
| | | |
| | | |
| | | |
| | | @ResponseBody |
| | | @PostMapping(value = "/paymentChargingOrder") |
| | | @ApiOperation(value = "支付充电充值费用", tags = {"小程序-扫一扫"}) |
| | | public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder){ |
| | | return chargingOrderService.paymentChargingOrder(addChargingOrder); |
| | | } |
| | | |
| | | /** |
| | | * 充电充值支付回调 |
| | | * @param request |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping(value = "/chargingOrderWXCallback") |
| | | public void chargingOrderWXCallback(HttpServletRequest request){ |
| | | Map<String, Object> data = wxPaymentClient.payNotify(request).getData(); |
| | | if(null != data){ |
| | | String out_trade_no = data.get("out_trade_no").toString(); |
| | | String transaction_id = data.get("transaction_id").toString(); |
| | | String attach = data.get("attach").toString(); |
| | | AjaxResult ajaxResult = chargingOrderService.chargingOrderCallback(1, out_trade_no, transaction_id, attach); |
| | | if(ajaxResult.isSuccess()){ |
| | | wxPaymentClient.ack(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 支付宝支付成功后的回调 |
| | | * @param request |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping(value = "/chargingOrderALICallback") |
| | | public void chargingOrderALICallback(HttpServletRequest request){ |
| | | Map<String, Object> data = wxPaymentClient.payNotify(request).getData(); |
| | | if(null != data){ |
| | | String out_trade_no = data.get("out_trade_no").toString(); |
| | | String transaction_id = data.get("transaction_id").toString(); |
| | | String attach = data.get("attach").toString(); |
| | | AjaxResult ajaxResult = chargingOrderService.chargingOrderCallback(2, out_trade_no, transaction_id, attach); |
| | | if(ajaxResult.isSuccess()){ |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @ResponseBody |
| | | @GetMapping(value = "/preChargeCheck/{id}") |
| | | @ApiOperation(value = "获取安全检测数据", tags = {"小程序-扫一扫"}) |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "id", value = "充电枪id", required = true) |
| | | }) |
| | | public AjaxResult<PreChargeCheck> preChargeCheck(@PathVariable Integer id){ |
| | | String key = "AQJC_" + id; |
| | | Object cacheObject = redisService.getCacheObject(key); |
| | | return AjaxResult.success(cacheObject); |
| | | } |
| | | |
| | | |
| | | |
| | | @ResponseBody |
| | | @GetMapping(value = "/getChargingDetails/{id}") |
| | | @ApiOperation(value = "获取充电中页面数据", tags = {"小程序-扫一扫"}) |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "id", value = "充电枪id", required = true) |
| | | }) |
| | | public AjaxResult<ChargingDetails> getChargingDetails(@PathVariable Integer id){ |
| | | ChargingDetails chargingDetails = chargingOrderService.getChargingDetails(id); |
| | | return AjaxResult.success(chargingDetails); |
| | | } |
| | | |
| | | |
| | | |
| | | @ResponseBody |
| | | @PutMapping(value = "/stopCharging/{id}") |
| | | @ApiOperation(value = "手动停止充电", tags = {"小程序-扫一扫"}) |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "id", value = "订单id", required = true) |
| | | }) |
| | | public AjaxResult stopCharging(@PathVariable String id){ |
| | | return chargingOrderService.stopCharging(id); |
| | | } |
| | | } |
| | | |
| | |
| | | package com.ruoyi.order.controller; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDateTime; |
| | | |
| | | |
| | |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | @PostMapping("/create") |
| | | public R<Long> exchangeCreate(@RequestBody ExchangeDto exchangeDto){ |
| | | TExchangeOrder tExchangeOrder = new TExchangeOrder(); |
| | | tExchangeOrder.setCode(""); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | String code = "DH" + Math.random() * 1000 + sdf.format(new Date()); |
| | | tExchangeOrder.setCode(code); |
| | | tExchangeOrder.setAppUserId(exchangeDto.getUserId()); |
| | | tExchangeOrder.setOrderType(0); |
| | | tExchangeOrder.setGoodsId(0); |
New file |
| | |
| | | package com.ruoyi.order.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/20 13:54 |
| | | */ |
| | | @Data |
| | | @ApiModel |
| | | public class AddChargingOrder { |
| | | @ApiModelProperty("充电枪id") |
| | | public Integer id; |
| | | @ApiModelProperty("支付金额") |
| | | private BigDecimal paymentAmount; |
| | | @ApiModelProperty("优惠券id") |
| | | private Long appUserCouponId; |
| | | @ApiModelProperty("车辆id") |
| | | private Long appUserCarId; |
| | | @ApiModelProperty("支付方式(1=微信,2=支付宝)") |
| | | private Integer paymentType; |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 14:09 |
| | | */ |
| | | @Data |
| | | @ApiModel |
| | | public class ChargingDetails { |
| | | @ApiModelProperty("订单id") |
| | | private String id; |
| | | @ApiModelProperty("充电电流") |
| | | private BigDecimal chargeCurrent; |
| | | @ApiModelProperty("充电电压") |
| | | private BigDecimal ChargeVoltage; |
| | | @ApiModelProperty("充电功率") |
| | | private BigDecimal ChargePower; |
| | | @ApiModelProperty("完成比例") |
| | | private Integer completionRatio; |
| | | @ApiModelProperty("续航") |
| | | private BigDecimal endurance; |
| | | @ApiModelProperty("剩余充电时间") |
| | | private Long remainingChargeTime; |
| | | @ApiModelProperty("充电枪名") |
| | | private String name; |
| | | @ApiModelProperty("订单编号") |
| | | private String code; |
| | | @ApiModelProperty("已充电度数") |
| | | private BigDecimal chargedDegrees; |
| | | @ApiModelProperty("已充电时间") |
| | | private Long chargedTime; |
| | | @ApiModelProperty("充电费用") |
| | | private BigDecimal ChargingCost; |
| | | @ApiModelProperty("充电状态(0=未知,1=等待中,2=启动中,3=充电中,4=停止中,5=已结束)") |
| | | private Integer status; |
| | | } |
| | |
| | | private String title; |
| | | @ApiModelProperty("充电度数") |
| | | private BigDecimal chargingDegree; |
| | | @ApiModelProperty("充电枪id") |
| | | private Integer chargingGunId; |
| | | @ApiModelProperty("充电桩枪名称") |
| | | private String name; |
| | | @ApiModelProperty("结束方式(0=异常终止,1=主动终止,2=满电终止,3=费用不足终止)") |
New file |
| | |
| | | package com.ruoyi.order.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 13:47 |
| | | */ |
| | | @Data |
| | | @ApiModel |
| | | public class PreChargeCheck { |
| | | @ApiModelProperty("安全连接检测") |
| | | private Boolean secureConnectionDetection; |
| | | @ApiModelProperty("绝缘检测") |
| | | private Boolean insulationTesting; |
| | | @ApiModelProperty("电子锁锁止") |
| | | private Boolean electronicLockLock; |
| | | } |
| | |
| | | package com.ruoyi.order.service; |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.core.web.page.BasePage; |
| | | import com.ruoyi.order.api.model.TChargingOrder; |
| | | import com.ruoyi.order.dto.GetMyChargingOrderList; |
| | | import com.ruoyi.order.dto.GetNoInvoicedOrder; |
| | | import com.ruoyi.order.dto.MyChargingOrderInfo; |
| | | import com.ruoyi.order.dto.MyChargingOrderList; |
| | | import com.ruoyi.order.dto.*; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | |
| | | import java.util.List; |
| | |
| | | * @return |
| | | */ |
| | | List<MyChargingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query); |
| | | |
| | | |
| | | /** |
| | | * 充电支付 |
| | | * @param addChargingOrder |
| | | * @return |
| | | */ |
| | | AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder); |
| | | |
| | | |
| | | /** |
| | | * 支付成功后的回调处理逻辑 |
| | | * @param paymentType 支付方式:1=微信,2=支付宝 |
| | | * @param out_trade_no 业务流水号 |
| | | * @param transaction_id 三方支付流水号 |
| | | * @param attach 附加数据 |
| | | * @return |
| | | */ |
| | | AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach); |
| | | |
| | | |
| | | /** |
| | | * 获取充电中的详情 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | ChargingDetails getChargingDetails(Integer id); |
| | | |
| | | |
| | | /** |
| | | * 停止充电 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | AjaxResult stopCharging(String id); |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.account.api.feignClient.AppUserCarClient; |
| | | import com.ruoyi.account.api.feignClient.AppUserClient; |
| | | import com.ruoyi.account.api.feignClient.AppUserVipDetailClient; |
| | | import com.ruoyi.account.api.model.TAppUser; |
| | | import com.ruoyi.account.api.model.TAppUserCar; |
| | | import com.ruoyi.account.api.model.TAppUserVipDetail; |
| | | import com.ruoyi.account.api.vo.GetAppUserVipDetail; |
| | | import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; |
| | | import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; |
| | | import com.ruoyi.chargingPile.api.feignClient.SiteClient; |
| | | import com.ruoyi.chargingPile.api.model.Site; |
| | | import com.ruoyi.chargingPile.api.model.TChargingGun; |
| | | import com.ruoyi.chargingPile.api.model.TChargingPile; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.core.web.page.BasePage; |
| | | import com.ruoyi.common.redis.service.RedisService; |
| | | import com.ruoyi.common.security.service.TokenService; |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.order.api.model.TChargingOrder; |
| | | import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; |
| | | import com.ruoyi.order.dto.GetMyChargingOrderList; |
| | | import com.ruoyi.order.dto.GetNoInvoicedOrder; |
| | | import com.ruoyi.order.dto.MyChargingOrderInfo; |
| | | import com.ruoyi.order.dto.MyChargingOrderList; |
| | | import com.ruoyi.order.dto.*; |
| | | import com.ruoyi.order.mapper.TChargingOrderMapper; |
| | | import com.ruoyi.order.service.TChargingOrderAccountingStrategyService; |
| | | import com.ruoyi.order.service.TChargingOrderService; |
| | | import com.ruoyi.payment.api.feignClient.WxPaymentClient; |
| | | import com.ruoyi.payment.api.vo.NotifyV3PayDecodeRespBody; |
| | | import com.ruoyi.payment.api.vo.PaymentOrder; |
| | | import io.seata.spring.annotation.GlobalTransactional; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | import java.time.ZoneOffset; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @Resource |
| | | private TokenService tokenService; |
| | | |
| | | @Resource |
| | | private WxPaymentClient wxPaymentClient; |
| | | |
| | | @Resource |
| | | private ChargingPileClient chargingPileClient; |
| | | |
| | | @Resource |
| | | private AppUserClient appUserClient; |
| | | |
| | | @Resource |
| | | private AppUserVipDetailClient appUserVipDetailClient; |
| | | |
| | | @Resource |
| | | private RedisService redisService; |
| | | |
| | | |
| | | |
| | | |
| | |
| | | myChargingOrderList.setTitle(site.getName()); |
| | | myChargingOrderList.setChargingDegree(tChargingOrder.getChargingCapacity()); |
| | | String name = chargingGunClient.getAllName(tChargingOrder.getChargingGunId()).getData(); |
| | | myChargingOrderList.setChargingGunId(tChargingOrder.getChargingGunId()); |
| | | myChargingOrderList.setName(name); |
| | | myChargingOrderList.setEndMode(tChargingOrder.getEndMode()); |
| | | BigDecimal payMoney = tChargingOrder.getStatus() < 4 ? tChargingOrder.getRechargeAmount() : tChargingOrder.getPaymentAmount(); |
| | |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 充电支付 |
| | | * @param addChargingOrder |
| | | * @return |
| | | */ |
| | | @Override |
| | | @GlobalTransactional(rollbackFor = Exception.class) |
| | | public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder) { |
| | | Long userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TAppUser appUser = appUserClient.getUserById(userId).getData(); |
| | | //查询待支付状态的订单,没有支付则删除订单 |
| | | List<TChargingOrder> list = this.list(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId) |
| | | .eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0)); |
| | | for (TChargingOrder tChargingOrder : list) { |
| | | Integer rechargePaymentType = tChargingOrder.getRechargePaymentType(); |
| | | if(1 == rechargePaymentType){ |
| | | NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(tChargingOrder.getCode()).getData(); |
| | | if(null != data){ |
| | | String trade_state = data.getTrade_state(); |
| | | //支付失败,删除无效的订单 |
| | | if(trade_state.equals("REFUND") || trade_state.equals("NOTPAY") || trade_state.equals("REVOKED") || trade_state.equals("PAYERROR")){ |
| | | this.removeById(tChargingOrder.getId()); |
| | | } |
| | | } |
| | | } |
| | | if(2 == rechargePaymentType){ |
| | | |
| | | } |
| | | } |
| | | |
| | | //检查当前枪是否是正在使用中 |
| | | TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getChargingGunId, addChargingOrder.getId()) |
| | | .in(TChargingOrder::getStatus, Arrays.asList(1, 2, 3)).eq(TChargingOrder::getDelFlag, 0)); |
| | | if(null != one){ |
| | | return AjaxResult.error("充电枪正在充电桩中,启动失败"); |
| | | } |
| | | //查询当前充电枪是否有正在支付的订单 |
| | | one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getChargingGunId, addChargingOrder.getId()) |
| | | .eq(TChargingOrder::getAppUserCarId, userId).eq(TChargingOrder::getRechargePaymentStatus, 1).eq(TChargingOrder::getDelFlag, 0)); |
| | | if(null != one){ |
| | | //查询三方支付数据,支付中直接结束三方订单 |
| | | if(1 == one.getRechargePaymentType()){ |
| | | NotifyV3PayDecodeRespBody data = wxPaymentClient.queryOrderInfo(one.getCode()).getData(); |
| | | if(null != data){ |
| | | String trade_state = data.getTrade_state(); |
| | | //支付失败,删除无效的订单 |
| | | if(trade_state.equals("REFUND") || trade_state.equals("NOTPAY") || trade_state.equals("REVOKED") || trade_state.equals("PAYERROR")){ |
| | | this.removeById(one.getId()); |
| | | }else{ |
| | | //结束第三方支付,删除订单 |
| | | wxPaymentClient.close(one.getCode()); |
| | | this.removeById(one.getId()); |
| | | } |
| | | } |
| | | } |
| | | if(2 == one.getRechargePaymentType()){ |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | //构建新的待支付订单 |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | TChargingOrder chargingOrder = new TChargingOrder(); |
| | | String code = "CD" + Math.random() * 1000 + sdf.format(new Date()); |
| | | chargingOrder.setCode(code); |
| | | chargingOrder.setOrderType(1); |
| | | chargingOrder.setOrderClassification(1); |
| | | chargingOrder.setAppUserId(userId); |
| | | chargingOrder.setAppUserCarId(addChargingOrder.getAppUserCarId()); |
| | | TChargingGun tChargingGun = chargingGunClient.getChargingGunById(addChargingOrder.getId()).getData(); |
| | | chargingOrder.setSiteId(tChargingGun.getSiteId()); |
| | | chargingOrder.setChargingPileId(tChargingGun.getChargingPileId()); |
| | | chargingOrder.setChargingGunId(addChargingOrder.getId()); |
| | | chargingOrder.setRechargePaymentType(addChargingOrder.getPaymentType()); |
| | | chargingOrder.setRechargePaymentStatus(1); |
| | | chargingOrder.setRechargeAmount(addChargingOrder.getPaymentAmount()); |
| | | chargingOrder.setAppCouponId(addChargingOrder.getAppUserCouponId()); |
| | | if(null != appUser.getVipId()){ |
| | | GetAppUserVipDetail getAppUserVipDetail = new GetAppUserVipDetail(); |
| | | getAppUserVipDetail.setAppUserId(appUser.getId()); |
| | | getAppUserVipDetail.setVipId(appUser.getVipId()); |
| | | TAppUserVipDetail vipDetail = appUserVipDetailClient.getAppUserVipDetail(getAppUserVipDetail).getData(); |
| | | if(null != vipDetail){ |
| | | Integer chargeNum = vipDetail.getChargeNum(); |
| | | if(0 > chargeNum){ |
| | | chargingOrder.setVipDiscount(vipDetail.getDiscount()); |
| | | BigDecimal discountAmount = addChargingOrder.getPaymentAmount().multiply((new BigDecimal(10) |
| | | .subtract(vipDetail.getDiscount())).divide(new BigDecimal(10))).setScale(4, BigDecimal.ROUND_HALF_EVEN); |
| | | chargingOrder.setVipDiscountAmount(discountAmount); |
| | | } |
| | | } |
| | | |
| | | } |
| | | this.save(chargingOrder); |
| | | //会员优惠折扣将其计入增加充电时长(增加总充电金额) |
| | | //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额) |
| | | if(1 == addChargingOrder.getPaymentType()){ |
| | | PaymentOrder paymentOrder = new PaymentOrder(); |
| | | paymentOrder.setCode(chargingOrder.getCode()); |
| | | paymentOrder.setAmount(addChargingOrder.getPaymentAmount()); |
| | | paymentOrder.setOpenId(appUser.getWxOpenid()); |
| | | paymentOrder.setDescription("充电充值"); |
| | | paymentOrder.setNotifyUrl("/order/t-charging-order/chargingOrderWXCallback"); |
| | | Map<String, Object> data = wxPaymentClient.orderPay(paymentOrder).getData(); |
| | | return AjaxResult.success(data); |
| | | } |
| | | if(2 == addChargingOrder.getPaymentType()){ |
| | | |
| | | } |
| | | throw new RuntimeException("无效的支付方式"); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 支付成功后的回调处理逻辑 |
| | | * @param paymentType 支付方式:1=微信,2=支付宝 |
| | | * @param out_trade_no 业务流水号 |
| | | * @param transaction_id 三方支付流水号 |
| | | * @param attach 附加数据 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach) { |
| | | TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, out_trade_no)); |
| | | if(chargingOrder.getRechargePaymentStatus() == 2){ |
| | | return AjaxResult.success(); |
| | | } |
| | | chargingOrder.setRechargePaymentStatus(2); |
| | | chargingOrder.setRechargeSerialNumber(transaction_id); |
| | | this.updateById(chargingOrder); |
| | | //添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据 |
| | | PreChargeCheck preChargeCheck = new PreChargeCheck(); |
| | | preChargeCheck.setElectronicLockLock(false); |
| | | preChargeCheck.setInsulationTesting(false); |
| | | preChargeCheck.setSecureConnectionDetection(false); |
| | | String key = "AQJC_" + chargingOrder.getChargingGunId(); |
| | | redisService.setCacheObject(key, preChargeCheck); |
| | | //开始检测充电桩状,将检查状态写入缓存。检测完成后开始开启充电 |
| | | //充电结束后需要计算退款剩余金额 |
| | | // todo 需要完善 |
| | | |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取充电中的详情 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @Override |
| | | public ChargingDetails getChargingDetails(Integer id) { |
| | | Long userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId).eq(TChargingOrder::getChargingGunId, id) |
| | | .in(TChargingOrder::getStatus, Arrays.asList(1, 2, 3)).eq(TChargingOrder::getRechargePaymentStatus, 2).eq(TChargingOrder::getDelFlag, 0)); |
| | | if(null == one){ |
| | | return null; |
| | | } |
| | | // todo 需要完善充电实时数据 |
| | | ChargingDetails chargingDetails = new ChargingDetails(); |
| | | chargingDetails.setId(one.getId().toString()); |
| | | TChargingGun chargingGun = chargingGunClient.getChargingGunById(id).getData(); |
| | | TChargingPile chargingPile = chargingPileClient.getChargingPileById(chargingGun.getChargingPileId()).getData(); |
| | | Site site = siteClient.getSiteByIds(Arrays.asList(chargingPile.getSiteId())).getData().get(0); |
| | | chargingDetails.setName(site.getName() + "-" + chargingPile.getName()); |
| | | chargingDetails.setCode(one.getCode()); |
| | | chargingDetails.setStatus(one.getStatus()); |
| | | return chargingDetails; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 停止充电操作 |
| | | * @param id 订单id |
| | | * @return |
| | | */ |
| | | @Override |
| | | public AjaxResult stopCharging(String id) { |
| | | TChargingOrder chargingOrder = this.getById(id); |
| | | Integer status = chargingOrder.getStatus(); |
| | | if(status == 4 || status == 5){ |
| | | return AjaxResult.error("不能重复操作"); |
| | | } |
| | | chargingOrder.setStatus(4); |
| | | chargingOrder.setEndMode(1); |
| | | this.updateById(chargingOrder); |
| | | //调用硬件停止充电,停止成功后开始计算费用退款 |
| | | // todo 待完善 |
| | | return AjaxResult.success(); |
| | | } |
| | | } |
| | |
| | | <artifactId>spring-boot-starter-test</artifactId> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.netty</groupId> |
| | | <artifactId>netty-all</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | import com.ruoyi.common.security.annotation.EnableCustomConfig; |
| | | import com.ruoyi.common.security.annotation.EnableRyFeignClients; |
| | | import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; |
| | | import com.ruoyi.other.webSocket.NettyServer; |
| | | import org.mybatis.spring.annotation.MapperScan; |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | |
| | | public class RuoYiOtherApplication { |
| | | public static void main(String[] args) { |
| | | SpringApplication.run(RuoYiOtherApplication.class, args); |
| | | new NettyServer().bind(); |
| | | System.out.println("(♥◠‿◠)ノ゙ 基础模块启动成功 ლ(´ڡ`ლ)゙ \n" + |
| | | " .-------. ____ __ \n" + |
| | | " | _ _ \\ \\ \\ / / \n" + |
| | |
| | | import com.ruoyi.other.api.domain.TActivity; |
| | | import com.ruoyi.other.api.domain.TGoods; |
| | | import com.ruoyi.other.api.dto.AdvertisingDTO; |
| | | import com.ruoyi.other.api.dto.ExchangeDto; |
| | | import com.ruoyi.order.api.vo.ExchangeDto; |
| | | import com.ruoyi.other.api.dto.GoodsDTO; |
| | | import com.ruoyi.other.service.TActivityService; |
| | | import com.ruoyi.other.service.TAdvertisingService; |
| | |
| | | return AjaxResult.error("当前用户已到达兑换上限"); |
| | | } |
| | | //生成积分兑换成功的订单 |
| | | orderClient.exchangeCreate(exchangeDto); |
| | | // orderClient.exchangeCreate(exchangeDto); |
| | | |
| | | //如果是优惠卷,赠送优惠卷给用户 |
| | | |
New file |
| | |
| | | package com.ruoyi.other.controller; |
| | | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.other.webSocket.NettyChannelMap; |
| | | import com.ruoyi.other.webSocket.NettyWebSocketController; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | | * @Date 2024/8/21 17:31 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/webSocket") |
| | | public class WebSocketController { |
| | | |
| | | |
| | | /** |
| | | * 发送websocket消息 |
| | | * @param userId |
| | | * @param msg |
| | | * @return |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/send") |
| | | public R send(@RequestParam("userId") Long userId, @RequestParam("msg") String msg){ |
| | | ChannelHandlerContext channel = NettyChannelMap.getData("Applets" + userId); |
| | | return NettyWebSocketController.sendMsgToClient(channel, msg); |
| | | } |
| | | |
| | | } |
| | |
| | | for (TCoupon tCoupon : list) { |
| | | couponIds.append(tCoupon.getId()).append(","); |
| | | } |
| | | if (StringUtils.hasLength(couponIds)){ |
| | | // 去除最后一个字符 |
| | | couponIds.deleteCharAt(couponIds.length()-1); |
| | | } |
| | | List<Integer> data = appCouponClient.getCountByCouponIds(couponIds.toString()).getData(); |
| | | for (int i = 0; i < list.size(); i++) { |
| | | list.get(i).setCount(data.get(i)); |
| | | if (!list.isEmpty()){ |
| | | if (StringUtils.hasLength(couponIds)){ |
| | | // 去除最后一个字符 |
| | | couponIds.deleteCharAt(couponIds.length()-1); |
| | | } |
| | | List<Integer> data = appCouponClient.getCountByCouponIds(couponIds.toString()).getData(); |
| | | for (int i = 0; i < list.size(); i++) { |
| | | list.get(i).setCount(data.get(i)); |
| | | } |
| | | } |
| | | pageInfo.setRecords(list); |
| | | return pageInfo; |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import io.netty.channel.ChannelInitializer; |
| | | import io.netty.channel.socket.SocketChannel; |
| | | import io.netty.handler.codec.http.HttpObjectAggregator; |
| | | import io.netty.handler.codec.http.HttpServerCodec; |
| | | import io.netty.handler.ssl.SslHandler; |
| | | import io.netty.handler.stream.ChunkedWriteHandler; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | | public class ChildChannelHandler extends ChannelInitializer<SocketChannel> { |
| | | @Override |
| | | protected void initChannel(SocketChannel socketChannel) throws Exception { |
| | | String path = "C:\\cert\\tomcat\\scs1723443475715_fxcx.yunyu666.com_server.jks"; |
| | | // String path = "/usr/local/server/apache-tomcat-80/conf/cert/6064978_okyueche.com.pfx"; |
| | | SSLContext sslContext = createSSLContext.createSSLContext("JKS" |
| | | , path, "Pe7>4nS#st$dAnpp"); |
| | | //SSLEngine 此类允许使用ssl安全套接层协议进行安全通信 |
| | | SSLEngine engine = sslContext.createSSLEngine(); |
| | | engine.setUseClientMode(false); |
| | | socketChannel.pipeline().addLast("ssl", new SslHandler(engine)); |
| | | |
| | | // 设置30秒没有读到数据,则触发一个READER_IDLE事件。 |
| | | // pipeline.addLast(new IdleStateHandler(30, 0, 0)); |
| | | // HttpServerCodec:将请求和应答消息解码为HTTP消息 |
| | | socketChannel.pipeline().addLast("http-codec", new HttpServerCodec()); |
| | | // HttpObjectAggregator:将HTTP消息的多个部分合成一条完整的HTTP消息 |
| | | socketChannel.pipeline().addLast("aggregator", new HttpObjectAggregator(65536)); |
| | | // ChunkedWriteHandler:向客户端发送HTML5文件 |
| | | socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); |
| | | // 在管道中添加我们自己的接收数据实现方法 |
| | | socketChannel.pipeline().addLast("handler", new WebSocketHandler()); |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import io.netty.channel.group.ChannelGroup; |
| | | import io.netty.channel.group.DefaultChannelGroup; |
| | | import io.netty.util.concurrent.GlobalEventExecutor; |
| | | |
| | | public class Global { |
| | | public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | /** |
| | | * 即时通讯【通讯类型类】 |
| | | * |
| | | * @author TaoNingBo |
| | | * @version 1.0 |
| | | * @createDate 2016年6月14日 |
| | | */ |
| | | public class Method { |
| | | |
| | | /** |
| | | * 心跳【推送】 |
| | | */ |
| | | public static final String ok = "OK"; |
| | | |
| | | /** |
| | | * 心跳【接收】 |
| | | */ |
| | | public final static String ping = "PING"; |
| | | |
| | | /** |
| | | * 心跳【响应】 |
| | | */ |
| | | public final static String pong = "PONG"; |
| | | |
| | | /** |
| | | * 司机上传位置 |
| | | */ |
| | | public static final String location = "LOCATION"; |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | public class NettyChannelMap { |
| | | |
| | | public static Map<String, ChannelHandlerContext> ctxMap = new HashMap<>();//单点登录存储的通道 |
| | | protected static Map<String, ChannelHandlerContext> map = new ConcurrentHashMap<>(); |
| | | |
| | | |
| | | private NettyChannelMap() { |
| | | // 放置外部实例化 |
| | | } |
| | | |
| | | /** |
| | | * Get data from source. |
| | | * |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public static ChannelHandlerContext getData(String key) { |
| | | if (map == null) { |
| | | map = new HashMap<String, ChannelHandlerContext>(); |
| | | } |
| | | return map.get(key); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Save data from source. |
| | | * |
| | | * @param key |
| | | * @param val |
| | | */ |
| | | public static synchronized void saveData(String key, ChannelHandlerContext val) { |
| | | map.put(key, val); |
| | | } |
| | | |
| | | /** |
| | | * Determine whether the cache key contains the key. |
| | | * |
| | | * @param key |
| | | * @return true|false |
| | | * @author TaoNingBo |
| | | */ |
| | | public static synchronized boolean containsKey(String key) { |
| | | return map.containsKey(key); |
| | | } |
| | | |
| | | /** |
| | | * Determine whether the cache value contains the value. |
| | | * |
| | | * @param val |
| | | * @return |
| | | */ |
| | | public static synchronized boolean containsVal(ChannelHandlerContext val) { |
| | | return map.containsValue(val); |
| | | } |
| | | |
| | | /** |
| | | * Remove the data resources. |
| | | * |
| | | * @param value |
| | | */ |
| | | @SuppressWarnings("rawtypes") |
| | | public static synchronized void remove(ChannelHandlerContext value) { |
| | | Set<String> strings = map.keySet(); |
| | | for (String key : strings) { |
| | | ChannelHandlerContext channelHandlerContext = map.get(key); |
| | | String s = channelHandlerContext.channel().remoteAddress().toString(); |
| | | String s1 = value.channel().remoteAddress().toString(); |
| | | if (s.equals(s1)) { |
| | | channelHandlerContext.close();//关闭通道 |
| | | map.remove(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | public static synchronized void remove_(ChannelHandlerContext value) { |
| | | Set<String> strings = ctxMap.keySet(); |
| | | for (String key : strings) { |
| | | ChannelHandlerContext channelHandlerContext = ctxMap.get(key); |
| | | String s = channelHandlerContext.channel().remoteAddress().toString(); |
| | | String s1 = value.channel().remoteAddress().toString(); |
| | | if (s.equals(s1)) { |
| | | channelHandlerContext.close();//关闭通道 |
| | | ctxMap.remove(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Remove the data resources. |
| | | * |
| | | * @param key |
| | | * @author TaoNingBo |
| | | */ |
| | | public static synchronized void remove(String key) { |
| | | map.remove(key); |
| | | } |
| | | |
| | | /** |
| | | * Update the data resources. |
| | | * |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public static synchronized void update(String key, ChannelHandlerContext value) { |
| | | map.put(key, value); |
| | | } |
| | | |
| | | |
| | | public static synchronized void update_(String key, ChannelHandlerContext value) { |
| | | ctxMap.put(key, value); |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.Unpooled; |
| | | import io.netty.channel.ChannelFuture; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | |
| | | public class NettyMsg { |
| | | |
| | | /** |
| | | * 返回一个正确数据 |
| | | * |
| | | * @param method |
| | | * @param data |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String setMsg(String method, Map<String, Object> data) { |
| | | StringBuffer json = new StringBuffer(); |
| | | json.append(getHeader(200, "SUCCESS", method)); |
| | | json.append(JSON.toJSONString(data)); |
| | | json.append("}"); |
| | | //return JSON.toJSONString(json); |
| | | return json.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 返回一个正确数据 |
| | | * |
| | | * @param method |
| | | * @param data |
| | | * @return |
| | | */ |
| | | public static String setMsg(String method, List<Map<String, Object>> data) { |
| | | StringBuffer json = new StringBuffer(); |
| | | json.append(getHeader(200, "SUCCESS", method)); |
| | | List<JSONObject> jsonList = new ArrayList<JSONObject>(); |
| | | for (Map<String, Object> map : data) { |
| | | JSONObject dataJson = new JSONObject(map); |
| | | jsonList.add(dataJson); |
| | | } |
| | | json.append(jsonList); |
| | | json.append("}"); |
| | | |
| | | // return JSON.toJSONString(json); |
| | | return json.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 返回一个错误数据 |
| | | * |
| | | * @param method |
| | | * @param data |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String setErrMsg(String method, String data) { |
| | | StringBuffer json = new StringBuffer(); |
| | | json.append(getHeader(-1, "FAILURE", method)); |
| | | json.append("\"" + data + "\""); |
| | | json.append("}"); |
| | | // return JSON.toJSONString(json); |
| | | return json.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 生成一个返回JSON的头 |
| | | * |
| | | * @param code |
| | | * @param msg |
| | | * @param method |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | private static String getHeader(int code, String msg, String method) { |
| | | StringBuffer header = new StringBuffer(); |
| | | header.append("{"); |
| | | header.append("\"code\":\"" + code); |
| | | header.append("\",\"msg\":\"" + msg); |
| | | header.append("\",\"method\":\"" + method); |
| | | header.append("\",\"data\":"); |
| | | return header.toString(); |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import io.netty.bootstrap.ServerBootstrap; |
| | | import io.netty.channel.Channel; |
| | | import io.netty.channel.EventLoopGroup; |
| | | import io.netty.channel.nio.NioEventLoopGroup; |
| | | import io.netty.channel.socket.nio.NioServerSocketChannel; |
| | | |
| | | import java.util.Timer; |
| | | import java.util.TimerTask; |
| | | |
| | | |
| | | /** |
| | | * 即时通讯服务启动类 |
| | | * |
| | | * @version 1.0 |
| | | * @date 2016年6月25日 |
| | | */ |
| | | public class NettyServer { |
| | | |
| | | /** |
| | | * 延迟启动设置 |
| | | * <p> |
| | | * NettyServer启动方法. |
| | | */ |
| | | public void bind() { |
| | | final Thread thread = new Thread(new NettyRunnable()); |
| | | Timer timer = new Timer(); |
| | | timer.schedule(new TimerTask() { |
| | | @Override |
| | | public void run() { |
| | | thread.start(); |
| | | } |
| | | }, 1000 * 2); |
| | | } |
| | | |
| | | /** |
| | | * 即时通讯服务启动 |
| | | * |
| | | * @version 1.0 |
| | | * @date 2016年6月24日 |
| | | */ |
| | | public class NettyRunnable implements Runnable { |
| | | |
| | | /** |
| | | * 获取即时通讯启动端口 |
| | | */ |
| | | @Override |
| | | public void run() { |
| | | System.out.println("===========================Netty端口启动========"); |
| | | // Boss线程:由这个线程池提供的线程是boss种类的,用于创建、连接、绑定socket, |
| | | // (有点像门卫)然后把这些socket传给worker线程池。 |
| | | // 在服务器端每个监听的socket都有一个boss线程来处理。在客户端,只有一个boss线程来处理所有的socket。 |
| | | EventLoopGroup bossGroup = new NioEventLoopGroup(); |
| | | // Worker线程:Worker线程执行所有的异步I/O,即处理操作 |
| | | EventLoopGroup workrGroup = new NioEventLoopGroup(); |
| | | try { |
| | | |
| | | // ServerBootstrap 启动NIO服务的辅助启动类,负责初始话netty服务器,并且开始监听端口的socket请求 |
| | | ServerBootstrap b = new ServerBootstrap(); |
| | | b.group(bossGroup, workrGroup); |
| | | // 设置非阻塞,用它来建立新accept的连接,用于构造serversocketchannel的工厂类 |
| | | b.channel(NioServerSocketChannel.class); |
| | | // ChildChannelHandler 对出入的数据进行的业务操作,其继承ChannelInitializer |
| | | b.childHandler(new ChildChannelHandler()); |
| | | System.out.println("服务端开启等待客户端连接 ... ..."); |
| | | Channel ch = b.bind(9090).sync().channel(); |
| | | ch.closeFuture().sync(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | bossGroup.shutdownGracefully(); |
| | | workrGroup.shutdownGracefully(); |
| | | } |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.Unpooled; |
| | | import io.netty.channel.ChannelFuture; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; |
| | | |
| | | import java.util.Hashtable; |
| | | |
| | | public class NettyWebSocketController { |
| | | |
| | | public static Hashtable<String, Hashtable<ChannelHandlerContext, String>> map = new Hashtable<String, Hashtable<ChannelHandlerContext, String>>(); |
| | | |
| | | |
| | | public static Hashtable<String, String> table; |
| | | public static int i = 0; |
| | | |
| | | static { |
| | | if (table == null) { |
| | | table = new Hashtable<>(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 向客户端发送消息 |
| | | * |
| | | * @param ctx |
| | | * @param msg |
| | | * @author TaoNingBo |
| | | */ |
| | | public static R sendMsgToClient(ChannelHandlerContext ctx, String msg) { |
| | | if (ctx != null && ctx.channel().isActive()) { |
| | | ByteBuf buffer = Unpooled.copiedBuffer((msg).getBytes()); |
| | | ChannelFuture sync; |
| | | try { |
| | | sync = ctx.channel().writeAndFlush(new TextWebSocketFrame(msg)).sync(); |
| | | if (!sync.isSuccess()) { |
| | | boolean b = true; |
| | | for (int i = 0; i < 10; i++) { |
| | | ctx.wait(3000); |
| | | sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); |
| | | if (sync.isSuccess()) { |
| | | b = false; |
| | | break; |
| | | } |
| | | System.err.println("小程序-》推送不成功,将继续推送" + msg); |
| | | } |
| | | if (b) { |
| | | NettyChannelMap.remove(ctx); |
| | | return R.fail("无效的消息通道"); |
| | | } |
| | | } |
| | | return R.ok(); |
| | | } catch (Exception e) { |
| | | NettyChannelMap.remove(ctx); |
| | | e.printStackTrace(); |
| | | return R.fail("发送消息失败:" + e.getMessage()); |
| | | } |
| | | } else { |
| | | NettyChannelMap.remove(ctx); |
| | | return R.fail("无效的消息通道"); |
| | | } |
| | | } |
| | | |
| | | // **链接断开 将推送消息记录 |
| | | public static void sendMsgToClient(String cacheType, Integer id, String msg) { |
| | | ChannelHandlerContext ctx = NettyChannelMap.getData(cacheType + id); |
| | | if (ctx != null) { |
| | | ChannelFuture sync; |
| | | try { |
| | | sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); |
| | | if (!sync.isSuccess()) { |
| | | for (int i = 0; i < 10; i++) { |
| | | sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); |
| | | ; |
| | | if (!sync.isSuccess()) { |
| | | sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); |
| | | ; |
| | | System.err.println("推送不成功,将继续推送" + msg); |
| | | if (i == 9) { |
| | | table.put(cacheType + id, msg); |
| | | ctx.close(); |
| | | System.err.println("推送发生异常,记录:" + msg); |
| | | } |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | table.put(cacheType + id, msg); |
| | | System.err.println("推送发生异常,记录:" + msg); |
| | | } |
| | | } else { |
| | | table.put(cacheType + id, msg); |
| | | System.err.println("链接断开,记录:id=" + cacheType + id + ",消息:" + msg); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断客户端要执行什么操作 |
| | | * |
| | | * @param ctx |
| | | * @param msg |
| | | * @author TaoNingBo |
| | | */ |
| | | public void JudgeOperation(ChannelHandlerContext ctx, String msg) { |
| | | try { |
| | | // 验证即时通讯命令是否正确有效 |
| | | if (StringUtils.isEmpty(msg)) { |
| | | return; |
| | | } |
| | | String msgStr = msg.toString(); |
| | | if (msgStr.indexOf("{") == -1 || msgStr.indexOf("}") == -1 || msgStr.indexOf("code") == -1 || msgStr.indexOf("msg") == -1 || msgStr.indexOf("data") == -1 || msgStr.indexOf("method") == -1) { |
| | | return; |
| | | } |
| | | |
| | | // 获取socket信息,保存相应的socket |
| | | JSONObject jsonMsg = JSONObject.parseObject(msg.toString()); |
| | | int code = jsonMsg.getIntValue("code"); |
| | | String message = jsonMsg.getString("msg"); |
| | | String method = jsonMsg.getString("method"); |
| | | if (code != 200 || !message.equals("SUCCESS")) { |
| | | return; |
| | | } |
| | | JSONObject jsonCon = JSONObject.parseObject(jsonMsg.get("data").toString()); |
| | | |
| | | if (null != ctx && ctx.channel().isActive()) { |
| | | jsonMsg.put("method", Method.pong); |
| | | sendMsgToClient(ctx, jsonMsg.toJSONString()); |
| | | } |
| | | |
| | | |
| | | // ############################### 心跳 ############################ |
| | | // 心跳 |
| | | if (method.equals(Method.ping)) { |
| | | String userId1 = jsonCon.getString("userId"); |
| | | if (StringUtils.isNotEmpty(userId1)) { |
| | | //存储业务使用的通道 |
| | | if (null != ctx && ctx.channel().isActive()) { |
| | | NettyChannelMap.update("Applets" + userId1, ctx); |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import io.netty.buffer.ByteBuf; |
| | | import io.netty.buffer.Unpooled; |
| | | import io.netty.channel.ChannelFuture; |
| | | import io.netty.channel.ChannelFutureListener; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | | import io.netty.channel.SimpleChannelInboundHandler; |
| | | import io.netty.handler.codec.http.*; |
| | | import io.netty.handler.codec.http.websocketx.*; |
| | | import io.netty.handler.timeout.IdleState; |
| | | import io.netty.handler.timeout.IdleStateEvent; |
| | | import io.netty.util.CharsetUtil; |
| | | |
| | | import java.util.HashMap; |
| | | |
| | | |
| | | public class WebSocketHandler extends SimpleChannelInboundHandler<Object> { |
| | | private static final String WEB_SOCKET_URL = "wss://localhost:9090/websocket"; |
| | | //用于websocket握手的处理类 |
| | | private WebSocketServerHandshaker handshaker; |
| | | |
| | | @Override |
| | | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
| | | ctx.flush(); |
| | | } |
| | | |
| | | /** |
| | | * 心跳 |
| | | */ |
| | | @Override |
| | | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { |
| | | if (evt instanceof IdleStateEvent) { |
| | | IdleStateEvent event = (IdleStateEvent) evt; |
| | | if (event.state().equals(IdleState.READER_IDLE)) { |
| | | // |
| | | } else if (event.state().equals(IdleState.WRITER_IDLE)) { |
| | | // |
| | | } else if (event.state().equals(IdleState.ALL_IDLE)) { |
| | | String msg = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); |
| | | if (ctx != null && ctx.channel().isActive()) { |
| | | ctx.writeAndFlush(Unpooled.copiedBuffer((msg).getBytes())); |
| | | } |
| | | } |
| | | } |
| | | // super.userEventTriggered(ctx, evt); |
| | | } |
| | | |
| | | @Override |
| | | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { |
| | | ctx.close(); |
| | | } |
| | | |
| | | private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { |
| | | // Http解码失败,向服务器指定传输的协议为Upgrade:websocket |
| | | if (!req.getDecoderResult().isSuccess() || !("websocket").equals(req.headers().get("Upgrade"))) { |
| | | sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); |
| | | return; |
| | | } |
| | | // 握手相应处理,创建websocket握手的工厂类, |
| | | WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WEB_SOCKET_URL, null, false); |
| | | // 根据工厂类和HTTP请求创建握手类 |
| | | handshaker = wsFactory.newHandshaker(req); |
| | | if (handshaker == null) { |
| | | // 不支持websocket |
| | | WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); |
| | | } else { |
| | | // 通过它构造握手响应消息返回给客户端 |
| | | handshaker.handshake(ctx.channel(), req); |
| | | } |
| | | } |
| | | |
| | | private void handleWebSocketRequest(ChannelHandlerContext ctx, WebSocketFrame req) throws Exception { |
| | | if (req instanceof CloseWebSocketFrame) { |
| | | // 关闭websocket连接 |
| | | handshaker.close(ctx.channel(), (CloseWebSocketFrame) req.retain()); |
| | | return; |
| | | } |
| | | if (req instanceof PingWebSocketFrame) { |
| | | ctx.channel().write(new PongWebSocketFrame(req.content().retain())); |
| | | return; |
| | | } |
| | | if (!(req instanceof TextWebSocketFrame)) { |
| | | throw new UnsupportedOperationException("当前只支持文本消息,不支持二进制消息"); |
| | | } |
| | | if (ctx == null || this.handshaker == null || ctx.isRemoved()) { |
| | | throw new Exception("尚未握手成功,无法向客户端发送WebSocket消息"); |
| | | } |
| | | String requestmsg = ((TextWebSocketFrame) req).text(); |
| | | |
| | | |
| | | //给连接的客户端返回数据 |
| | | //返回心跳 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("code", 200); |
| | | jsonObject.put("method", Method.ok); |
| | | jsonObject.put("msg", "SUCCESS"); |
| | | jsonObject.put("data", new JSONObject()); |
| | | TextWebSocketFrame tws = new TextWebSocketFrame(jsonObject.toJSONString()); |
| | | // ctx.channel().writeAndFlush(tws); |
| | | |
| | | new NettyWebSocketController().JudgeOperation(ctx, requestmsg);//小程序心跳处理 |
| | | |
| | | // 群发服务端心跳响应 |
| | | Global.group.writeAndFlush(new TextWebSocketFrame((tws).text())); |
| | | } |
| | | |
| | | private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { |
| | | // BAD_REQUEST(400) 客户端请求错误返回的应答消息 |
| | | if (res.getStatus().code() != 200) { |
| | | ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); |
| | | res.content().writeBytes(buf); |
| | | buf.release(); |
| | | } |
| | | //服务端向客户端发送数据 |
| | | ChannelFuture f = ctx.channel().writeAndFlush(res); |
| | | // 非法连接直接关闭连接 |
| | | if (res.getStatus().code() != 200) { |
| | | f.addListener(ChannelFutureListener.CLOSE); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void channelActive(ChannelHandlerContext ctx) throws Exception { |
| | | Global.group.add(ctx.channel()); |
| | | System.err.println("客户端与服务器端开启"); |
| | | } |
| | | |
| | | @Override |
| | | public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
| | | Global.group.remove(ctx.channel()); |
| | | NettyChannelMap.remove(ctx); |
| | | System.err.println("客户端与服务器链接关闭"); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
| | | if (msg instanceof FullHttpRequest) { |
| | | // websocket连接请求 |
| | | handleHttpRequest(ctx, (FullHttpRequest) msg); |
| | | } else if (msg instanceof WebSocketFrame) { |
| | | // websocket业务处理 |
| | | handleWebSocketRequest(ctx, (WebSocketFrame) msg); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { |
| | | if (msg instanceof FullHttpRequest) { |
| | | // websocket连接请求 |
| | | handleHttpRequest(ctx, (FullHttpRequest) msg); |
| | | } else if (msg instanceof WebSocketFrame) { |
| | | // websocket业务处理 |
| | | handleWebSocketRequest(ctx, (WebSocketFrame) msg); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.other.webSocket; |
| | | |
| | | import javax.net.ssl.KeyManagerFactory; |
| | | import javax.net.ssl.SSLContext; |
| | | import java.io.FileInputStream; |
| | | import java.io.InputStream; |
| | | import java.security.KeyStore; |
| | | |
| | | public class createSSLContext { |
| | | |
| | | /** |
| | | * 获取SSLContext |
| | | * |
| | | * @param type |
| | | * @param path |
| | | * @param password |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public static SSLContext createSSLContext(String type, String path, String password) throws Exception { |
| | | KeyStore ks = KeyStore.getInstance(type); /// "JKS" |
| | | InputStream ksInputStream = new FileInputStream(path); /// 证书存放地址 |
| | | ks.load(ksInputStream, password.toCharArray()); |
| | | //KeyManagerFactory充当基于密钥内容源的密钥管理器的工厂。 |
| | | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());//getDefaultAlgorithm:获取默认的 KeyManagerFactory 算法名称。 |
| | | kmf.init(ks, password.toCharArray()); |
| | | //SSLContext的实例表示安全套接字协议的实现,它充当用于安全套接字工厂或 SSLEngine 的工厂。 |
| | | SSLContext sslContext = SSLContext.getInstance("TLS"); |
| | | sslContext.init(kmf.getKeyManagers(), null, null); |
| | | return sslContext; |
| | | } |
| | | } |
| | |
| | | <select id="pageList" resultType="com.ruoyi.other.api.domain.TActivity"> |
| | | select * from t_activity |
| | | <where> |
| | | <if test="req.name != null and req.name != ''"> |
| | | AND `name` LIKE concat('%',#{req.name}, '%') |
| | | <if test="req.title != null and req.title != ''"> |
| | | AND `name` LIKE concat('%',#{req.title}, '%') |
| | | </if> |
| | | <if test="req.state == 1"> |
| | | <if test="req.startState == 1"> |
| | | AND start_time >= NOW() |
| | | </if> |
| | | <if test="req.state == 2"> |
| | | <if test="req.startState == 2"> |
| | | AND start_time <= NOW() AND end_time >= NOW() |
| | | </if> |
| | | <if test="req.state == 3"> |
| | | <if test="req.startState == 3"> |
| | | AND end_time <= NOW() |
| | | </if> |
| | | AND del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()} |
| | |
| | | <artifactId>joda-time</artifactId> |
| | | <version>2.10.10</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-api-payment</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | package com.ruoyi.payment.wx.controller; |
| | | |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.payment.api.vo.PaymentOrder; |
| | | import com.ruoyi.payment.wx.enums.RefundEnum; |
| | | import com.ruoyi.payment.wx.model.WxPaymentRefundModel; |
| | | import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; |
| | | import com.ruoyi.payment.wx.utils.WxV3Pay; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | |
| | | /** |
| | | * 按实际修改 |
| | | */ |
| | | @PostMapping("order") |
| | | @PostMapping("orderPay") |
| | | @ApiOperation("订单支付") |
| | | public AjaxResult<Map<String, Object>> orderPay(@RequestParam Long orderId) { |
| | | public R<Map<String, Object>> orderPay(@RequestBody PaymentOrder paymentOrder) { |
| | | // 查询订单 |
| | | // 0元订单不走支付 |
| | | // 价格 |
| | | Integer totalPrice = 0; |
| | | Integer totalPrice = paymentOrder.getAmount().multiply(new BigDecimal(100)).intValue(); |
| | | // 生成订单号 |
| | | String orderNo = ""; |
| | | String orderNo = paymentOrder.getCode(); |
| | | // 查询用户信息 用户openid |
| | | String openId = ""; |
| | | String openId = paymentOrder.getOpenId(); |
| | | // 订单做修改 |
| | | // 调用支付方法 |
| | | Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId,""); |
| | | Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId, paymentOrder.getNotifyUrl(),paymentOrder.getDescription()); |
| | | log.info("支付参数:{}", result); |
| | | return AjaxResult.ok(result); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 支付回调 |
| | | */ |
| | | @PostMapping("pay/notify") |
| | | public void payNotify(HttpServletRequest request) throws IOException { |
| | | public R<Map<String, Object>> payNotify(HttpServletRequest request) throws Exception { |
| | | try { |
| | | Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() { |
| | | }); |
| | | Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() {}); |
| | | log.info("支付回调:{}", params); |
| | | // 商户订单号 |
| | | String tradeNo = params.get("out_trade_no").toString(); |
| | | // 交易状态 |
| | | String trade_state = params.get("trade_state").toString(); |
| | | // 交易状态描述 |
| | | String trade_state_desc = params.get("trade_state_desc").toString(); |
| | | // 微信支付订单号 |
| | | String transaction_id = params.get("transaction_id").toString(); |
| | | // 支付完成时间 |
| | | // 时间不对的话,可以调用 WxTimeUtils.toRfc3339Date(success_time)转换一下 |
| | | String success_time = params.get("success_time").toString(); |
| | | // 附加数据 |
| | | Integer attach = Integer.parseInt(params.get("attach").toString()); |
| | | // TODO 业务处理 |
| | | return R.ok(params); |
| | | } catch (Exception e) { |
| | | log.error("支付回调异常:{}", e, e); |
| | | wxV3Pay.ack(false, e.getMessage()); |
| | | return R.fail("回调异常"); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 支付回调成功后 |
| | | */ |
| | | @PostMapping("pay/ack") |
| | | public void ack(){ |
| | | try { |
| | | wxV3Pay.ack(); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 退款回调 |
| | |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 查询订单信息 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @PostMapping("query/queryOrderInfo") |
| | | public R<NotifyV3PayDecodeRespBody> queryOrderInfo(@RequestParam("orderId") String orderId){ |
| | | NotifyV3PayDecodeRespBody query = wxV3Pay.query(orderId); |
| | | return R.ok(query); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 关闭订单 |
| | | * @param outTradeNo |
| | | */ |
| | | @PostMapping("pay/close") |
| | | public void close(@RequestParam("outTradeNo") String outTradeNo){ |
| | | wxV3Pay.close(outTradeNo); |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.payment.wx.model; |
| | | |
| | | import lombok.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author xiaochen |
| | | * @ClassName WxPaymentRefundModel |
| | | * @Description |
| | | */ |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | @Getter |
| | | @Setter |
| | | @ToString |
| | | public class WxCloseOrderModel { |
| | | private String mchid; |
| | | |
| | | private String out_trade_no; |
| | | } |
| | |
| | | |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.ruoyi.common.core.utils.WebUtils; |
| | | import com.ruoyi.payment.wx.model.WxCloseOrderModel; |
| | | import com.ruoyi.payment.wx.model.WxPaymentInfoModel; |
| | | import com.ruoyi.payment.wx.model.WxPaymentRefundModel; |
| | | import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; |
| | |
| | | * @param mchid |
| | | * @return |
| | | */ |
| | | public abstract NotifyV3PayDecodeRespBody query(String out_trade_no, String mchid); |
| | | public abstract NotifyV3PayDecodeRespBody query(String out_trade_no); |
| | | |
| | | |
| | | /** |
| | |
| | | * @return |
| | | */ |
| | | public abstract Map<String, Object> refund(WxPaymentRefundModel refundModel); |
| | | |
| | | |
| | | |
| | | public abstract String close(String out_trade_no); |
| | | |
| | | /** |
| | | * 订单退款 |
| | |
| | | writer.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 关闭订单 |
| | | * @param httpClient |
| | | * @param uri |
| | | * @param httpReadTimeoutMs |
| | | * @param httpConnectTimeoutMs |
| | | * @param closeModel |
| | | * @return |
| | | */ |
| | | public String close(CloseableHttpClient httpClient, |
| | | String uri, |
| | | int httpReadTimeoutMs, |
| | | int httpConnectTimeoutMs, |
| | | WxCloseOrderModel closeModel) { |
| | | String reqBody = WxJsonUtils.toJsonString(closeModel); |
| | | //请求URL |
| | | HttpEntityEnclosingRequestBase httpPost = requestPost( |
| | | uri |
| | | , httpReadTimeoutMs |
| | | , httpConnectTimeoutMs, reqBody); |
| | | String repBody = result(httpClient, httpPost); |
| | | return repBody; |
| | | } |
| | | |
| | | } |
| | |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.ruoyi.payment.wx.model.WeixinProperties; |
| | | import com.ruoyi.payment.wx.model.WxCloseOrderModel; |
| | | import com.ruoyi.payment.wx.model.WxPaymentInfoModel; |
| | | import com.ruoyi.payment.wx.model.WxPaymentRefundModel; |
| | | import com.ruoyi.payment.wx.resp.NotifyV3PayDecodeRespBody; |
| | |
| | | * @author xiaochen |
| | | * @date 2022-03-22 12:47 |
| | | */ |
| | | public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String description) { |
| | | public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String notify_url, String description) { |
| | | WxPaymentInfoModel requestBody = WxPaymentInfoModel.builder() |
| | | .mchid(this.config.getMchId()) |
| | | .appid(this.config.getAppId()) |
| | | .description(description) |
| | | .out_trade_no(tradeNo) |
| | | .notify_url(notify_url) |
| | | // .attach("") |
| | | .amount(WxPaymentInfoModel.Amount.builder().total(amount).build()) |
| | | .payer(WxPaymentInfoModel.Payer.builder().openid(openid).build()) |
| | |
| | | * 订单查询 |
| | | * |
| | | * @param out_trade_no |
| | | * @param mchid |
| | | * @return com.abl.biz.center.payment.wx.v3.NotifyV3PayDecodeRespBody |
| | | * @author xiaochen |
| | | * @date 2021-12-20 16:47 |
| | | */ |
| | | @Override |
| | | public NotifyV3PayDecodeRespBody query(String out_trade_no, String mchid) { |
| | | public NotifyV3PayDecodeRespBody query(String out_trade_no) { |
| | | String url = |
| | | String.format("/v3/pay/transactions/out-trade-no/%s", out_trade_no) + String.format("?mchid=%s", mchid); |
| | | String.format("/v3/pay/transactions/out-trade-no/%s", out_trade_no) + String.format("?mchid=%s", this.getConfig().getMchId()); |
| | | return query(this.httpClient, this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), url); |
| | | } |
| | | |
| | |
| | | // refundModel.setNotify_url(this.config.getV3().getNotifyRefundUrl()); |
| | | return refund(this.httpClient, "/v3/refund/domestic/refunds", this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), refundModel); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 关闭订单 |
| | | * @param out_trade_no |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String close(String out_trade_no) { |
| | | String uri = String.format("/v3/pay/transactions/out-trade-no/%s/close", out_trade_no); |
| | | WxCloseOrderModel wxCloseOrderModel = new WxCloseOrderModel(); |
| | | wxCloseOrderModel.setMchid(this.config.getMchId()); |
| | | return close(this.httpClient, uri, this.config.getHttpReadTimeoutMs(), this.config.getHttpConnectTimeoutMs(), wxCloseOrderModel); |
| | | } |
| | | } |