基于javaweb+mysql的ssm+maven网上图书商城系统(java+ssm+jsp+mysql+redis+easyui)

基于javaweb+mysql的ssm+maven网上图书商城系统(java+ssm+jsp+mysql+redis+easyui)

运行环境

Java≥8、MySQL≥5.7、Tomcat≥8

开发工具

eclipse/idea/myeclipse/sts等均可配置运行

适用

课程设计,大作业,毕业设计,项目练习,学习演示等

功能说明

基于javaweb+mysql的SSM+Maven网上图书商城系统(java+ssm+jsp+mysql+redis+easyui)

这个项目涉及到Shiro整合JWT、秒杀功能所具备的基本要求(限流、乐观锁、接口隐藏、JMeter高并发测试等等)、消息中间件RabbitMQ的异步邮件通知和死信队列、沙箱支付宝模拟支付等等技术亮点。

项目功能:该项目分为买家、卖家、管理员三个角色。买家角色的功能:登录、注册、浏览图书、管理购物车、结算订单、支付订单、查看订单、修改个人信息等等功能。

卖家角色的功能:登录、注册、浏览商品、管理自己发布的图书、管理收到的订单、查看自己的收益详情等等。管理员角色的功能:登录、管理所有用户信息、管理权限信息、管理所有卖家发布的图书、管理所有订单信息、管理所有支付信息、查看总共收益详情等等。

应用技术:SSM + Jsp + MySQL + Redis + JWT + Shiro + EasyUI等

运行环境:Eclipse/IntelliJ IDEA + MySQL5.7 + Maven3.6.3+ JDK1.8 + Redis5.0.5+ Tomcat8.5 +

 */

/**
 * 前台订单Order控制类
 */
@Controller
public class HomeOrderController {

    @Autowired
    private IOrderService orderService;

    /**
     * 前往订单结算页面
     * @return
     */
    @GetMapping("/home/order/index")
    public String index(){
        return "home/order/index";
    }

    /**
     * 前往订单结算页面前数据处理
     * @param ids
     * @param request
     * @return
     */
    @PostMapping("/home/order/index")
    @ResponseBody
    public ResponseVo<Boolean> index(String ids, HttpServletRequest request){
        return orderService.toOrderList(ids, request);
    }

    /**
     * 获取订单数据
     * @param request
     * @return
     */
    @PostMapping("/home/order/data")
    @ResponseBody
    public ResponseVo<Order> data(HttpServletRequest request){
    private Logger log = LoggerFactory.getLogger(CaptchaController.class);

    /**
     * 通用验证码生成器
     * @param vcodeLength
     * @param fontSize
     * @param width
     * @param height
     * @param method
     * @param request
     * @param response
     */
    @GetMapping(value="/common/captcha/generate_captcha")
    public void generateCaptcha(
            @RequestParam(name="vl",defaultValue="4")Integer vcodeLength,//vcodeLength,验证码长度
            @RequestParam(name="fs",defaultValue="21")Integer fontSize,//fontSize,验证码字体大小
            @RequestParam(name="w",defaultValue="98")Integer width,//width,图片宽度
            @RequestParam(name="h",defaultValue="33")Integer height,//height,图片高度
            @RequestParam(name="method")String method,//用来调用此方法的名称,以此名称为键,存入到session中
            HttpServletRequest request,
            HttpServletResponse response){
        CaptchaUtil captchaUtil = new CaptchaUtil(vcodeLength,fontSize,width,height);
        String generatorVCode = captchaUtil.generatorVCode(); //验证码的值
        //将生成的验证码放入session,以供放后面程序的验证使用
        request.getSession().setAttribute(method, generatorVCode);
        log.info("验证码成功生成,method=" + method + ",value=" + generatorVCode);
        try {
            ImageIO.write(captchaUtil.generatorRotateVCodeImage(generatorVCode, true), "gif", response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

    }

    /**
     * 后台用户列表页面
     * @return
     */
    @GetMapping("/admin/user/list")
    public String list(){
        return "admin/user/list";
    }

    /**
     * 后台用户列表信息获取
     * @param page
     * @param rows
     * @param roleId
     * @param username
     * @return
     */
    @PostMapping("/admin/user/list")
    @ResponseBody
    public Map<String, Object> list(Integer page, Integer rows, Integer roleId, String username){
        return userService.getUserList(page, rows, roleId, username);
    }

    /**
     * 后台添加用户信息操作处理
     * @param user
     * @return
     */
    @PostMapping("/admin/user/add")
    @ResponseBody
    public ResponseVo<Boolean> add(User user){
        return userService.addUser(user);
    }

    /**
     * 后台修改用户信息操作处理
     * @param user
     * @return
     */
    @PostMapping("/admin/user/edit")
    @ResponseBody
    public ResponseVo<Boolean> edit(User user){
        return userService.editUser(user);
    }

    /**
     * 后台删除用户信息操作处理
     * @param ids
     * @return
    public Map<String, Object> list(Page page, String customerName, String sellerName, Integer state, String orderNo){
        return orderService.getOrderList(page, customerName, sellerName, state, orderNo);
    }

    /**
     * 删除订单操作处理
     * @param ids
     * @return
     */
    @PostMapping("/admin/order/delete")
    @ResponseBody
    public ResponseVo<Boolean> delete(String ids){
        return orderService.deleteOrder(ids);
    }

    /**
     * 修改订单状态操作处理
     * @param order
     * @return
     */
    @PostMapping("/admin/order/edit_state")
    @ResponseBody
    public ResponseVo<Boolean> editState(Order order){
        return orderService.editState(order);
    }
}

/**
 */

/**
     * @return
     */
    @GetMapping("/admin/authority/list")
    public String list(){
        return "admin/authority/list";
    }

    /**
     * 获取权限列表信息
     * @param page
     * @param rows
     * @param roleId
     * @param name
     * @return
     */
    @PostMapping("/admin/authority/list")
    @ResponseBody
    public Map<String, Object> list(Integer page, Integer rows, Integer roleId, String name){
        return authorityService.getAuthorityList(page, rows, roleId, name);
    }

    /**
     * 添加权限信息操作处理
     * @param authority
     * @return
     */
    @PostMapping("/admin/authority/add")
    @ResponseBody
    public ResponseVo<Boolean> add(Authority authority){
        return authorityService.addAuthority(authority);
    }

    /**
     * 修改权限信息操作处理
     * @param authority
     * @return
     */
    @PostMapping("/admin/authority/edit")
    @ResponseBody
    public ResponseVo<Boolean> edit(Authority authority){
        return authorityService.editAuthority(authority);
    }

    /**
     * 修改权限信息操作处理
     * @param ids
     * @return
     */
    @PostMapping("/admin/authority/delete")
    @ResponseBody
//        //商户订单号,商户网站订单系统中唯一订单号,必填
//        //生成随机Id
//        String out_trade_no = selectedPay.getPayNo();
//        //付款金额,必填
//        String total_amount = String.valueOf(selectedPay.getTotalAmount());
//        //订单名称,必填
//        String subject ="网上图书商城订单支付";
//        //商品描述,可空
//        String body = "尊敬的用户:"+user.getUsername()+",欢迎您在网上图书商城下单!";
//        request.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
//                + "\"total_amount\":\""+ total_amount +"\","
//                + "\"subject\":\""+ subject +"\","
//                + "\"body\":\""+ body +"\","
//                + "\"timeout_express\":\""+"5m"+"\","
//                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//        String form = "";
//        try {
//            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
//        } catch (AlipayApiException e) {
//            e.printStackTrace();
//        }
//        httpResponse.setContentType("text/html;charset=" + CHARSET);
//        httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
//        httpResponse.getWriter().flush();
//        httpResponse.getWriter().close();
//    }
//
//
//    /**
//     * 继续支付页面
//     * @param orderId
//     * @param req
//     * @param httpResponse
//     * @throws IOException
//     */
//    @GetMapping("/common/alipay/continue")
//    public void continuePay(String orderId, HttpServletRequest req, HttpServletResponse httpResponse) throws IOException {
//        User user = (User) SecurityUtils.getSubject().getPrincipal();
//        if(user == null){
//            throw new RuntimeException("还未登录或会话失效,请重新登录!");
//        }
//        if(CommonUtil.isEmpty(orderId)){
//            throw new RuntimeException("数据非法,支付失败,请重新操作!");
//        }
//        QueryWrapper<Order> orderQueryWrapper = new QueryWrapper<>();
//        orderQueryWrapper.eq("customer_id", user.getId());
//        orderQueryWrapper.eq("id", orderId);
    }

    /**
     * 上架图书操作处理
     * @param id
     * @return
     */
    @PostMapping("/admin/book/on_shelves")
    @ResponseBody
    public ResponseVo<Boolean> onShelves(String id){
        return bookService.onShelves(id);
    }

    /**
     * 修改图书状态操作处理
     * @param id
     * @param state
     * @return
     */
    @PostMapping("/admin/book/edit_state")
    @ResponseBody
    public ResponseVo<Boolean> editState(String id, Integer state){
        return bookService.editState(id, state);
    }
}

/**
 */

/**
 * 后台用户User控制类
 */
@Controller
public class UserController {
                }
                return false;
            }
            //不是ajax请求,直接跳转页面
            try {
                log.info("没有登录或token非法,跳转登录界面!当前URL={}",requestURI);
                //根据路径分别跳转不同的登录页面
                if(requestURI.contains("/home/")){
                    response.sendRedirect("../system/index");
                }else if(requestURI.contains("/admin/")){
                    response.sendRedirect("../user/login");
                }else{
                    response.sendRedirect("../../common/system/not_permit");
                }
            } catch (IOException e3) {
                e3.printStackTrace();
            }
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}


/**
 */

/**
 * 后台订单Order控制类
 */
@Controller
public class OrderController {

    @Autowired
    private IOrderService orderService;

    /**
     * 订单列表页面
     * @return
     */
    @GetMapping("/admin/order/list")
    public String list(){
        return "admin/order/list";
    }

    /**
     * 近期订单收益图表页面
     * @return
     */
    @GetMapping("/admin/order/stats")
    public String stats(){
        return "admin/order/stats";
    }

    /**
            if(stockDao.updateStock(cart.getQuantity(), stock) <= 0){
                throw new RuntimeException("提交订单失败,请稍后重试!");
            }
        }
        // 6.创建订单  6.1同一个卖家的商品归并到一个订单中  Map<> 键key:卖家id 值value:购物车列表
        Map<String, List<Cart>> orderItemMap = new HashMap<>();
        cartList.forEach(e->{
            if(orderItemMap.containsKey(String.valueOf(e.getBook().getSellerId()))){
                //如果key中存在某卖家id
                List<Cart> selectedCartList = orderItemMap.get(String.valueOf(e.getBook().getSellerId()));
                selectedCartList.add(e);
                orderItemMap.put(String.valueOf(e.getBook().getSellerId()), selectedCartList);
            }else{
                //如果key中不存在某卖家id
                List<Cart> selectedCartList = new ArrayList<>();
                selectedCartList.add(e);
                orderItemMap.put(String.valueOf(e.getBook().getSellerId()), selectedCartList);
            }
        });
        Set<Long> orderIdSet = new HashSet<>();  //储存订单id的Set集合
        BigDecimal payTotalAmount = new BigDecimal("0.00"); //计算一个用户本次购买的总金额
        // 6.创建订单  6.2给每个订单赋值,准备存入数据库
        for(Map.Entry<String, List<Cart>> entry : orderItemMap.entrySet()){
            BigDecimal totalPrice = new BigDecimal("0.00");
            List<OrderItem> orderItemList = new ArrayList<>();
            List<Cart> selectedCartList = entry.getValue(); //值
            //计算总价,并封装订单详情数据
            for(Cart cart : selectedCartList){
                OrderItem orderItem = new OrderItem();
                if(BookIsKillEnum.YES.getCode().equals(cart.getBook().getIsKill())){
                    BigDecimal subtotal = new BigDecimal(cart.getQuantity()).multiply(cart.getBook().getNewPrice());
                    orderItem.setSubtotal(subtotal);
                    orderItem.setBookPrice(cart.getBook().getNewPrice());
                    totalPrice = totalPrice.add(subtotal);
                } else if(BookIsKillEnum.NO.getCode().equals(cart.getBook().getIsKill())){
                    BigDecimal subtotal = new BigDecimal(cart.getQuantity()).multiply(cart.getBook().getOldPrice());
                    orderItem.setSubtotal(subtotal);
                    orderItem.setBookPrice(cart.getBook().getOldPrice());
                    totalPrice = totalPrice.add(subtotal);
                }
                orderItem.setQuantity(cart.getQuantity());
                orderItem.setBookId(cart.getBook().getId());
                orderItem.setBookName(cart.getBook().getName());
                orderItem.setBookPic(cart.getBook().getPhoto());
                orderItemList.add(orderItem);
            }
            order.setOrderNo(String.valueOf(new SnowFlake(2,3).nextId()));
            order.setTotalPrice(totalPrice);
            payTotalAmount = payTotalAmount.add(totalPrice);
            order.setCustomerId(user.getId());
            order.setSellerId(Long.valueOf(entry.getKey()));
            }
            // 2.判断图书的状态是否是审核通过
            if(!BookStateEnum.AUDIT_SUCCESS.getCode().equals(cart.getBook().getState())){
                //图书状态不是审核通过,自定义错误消息返回
                throw new RuntimeException("图书《"+cart.getBook().getName()+"》的状态异常,不允许购买了哦!");
            }
            // 3.判断是否是秒杀图书。若是,则是否已过秒杀时间
            if(bookService.checkKillBook(cart.getBookId(), new Date())){
                //是秒杀图书并且已过秒杀时间 自定义错误消息返回
                throw new RuntimeException("限时秒杀图书《"+cart.getBook().getName()+"》的秒杀时间已过,不允许购买了哦!");
            }
            // 4.库存检查
            Stock stock = stockService.checkStock(cart.getBookId(), cart.getQuantity());
            if(stock == null){
                //库存检查不合格,自定义错误消息返回
                throw new RuntimeException("图书《"+cart.getBook().getName()+"》已售罄,不允许购买了哦!");
            }
            // 5.更新库存 使用乐观锁版本号控制 避免超卖现象出现
            if(stockDao.updateStock(cart.getQuantity(), stock) <= 0){
                throw new RuntimeException("提交订单失败,请稍后重试!");
            }
        }
        // 6.创建订单  6.1同一个卖家的商品归并到一个订单中  Map<> 键key:卖家id 值value:购物车列表
        Map<String, List<Cart>> orderItemMap = new HashMap<>();
        cartList.forEach(e->{
            if(orderItemMap.containsKey(String.valueOf(e.getBook().getSellerId()))){
                //如果key中存在某卖家id
                List<Cart> selectedCartList = orderItemMap.get(String.valueOf(e.getBook().getSellerId()));
                selectedCartList.add(e);
                orderItemMap.put(String.valueOf(e.getBook().getSellerId()), selectedCartList);
            }else{
                //如果key中不存在某卖家id
                List<Cart> selectedCartList = new ArrayList<>();
                selectedCartList.add(e);
                orderItemMap.put(String.valueOf(e.getBook().getSellerId()), selectedCartList);
            }
        });
        Set<Long> orderIdSet = new HashSet<>();  //储存订单id的Set集合
        BigDecimal payTotalAmount = new BigDecimal("0.00"); //计算一个用户本次购买的总金额
        // 6.创建订单  6.2给每个订单赋值,准备存入数据库
        for(Map.Entry<String, List<Cart>> entry : orderItemMap.entrySet()){
            BigDecimal totalPrice = new BigDecimal("0.00");
            List<OrderItem> orderItemList = new ArrayList<>();
            List<Cart> selectedCartList = entry.getValue(); //值
            //计算总价,并封装订单详情数据
            for(Cart cart : selectedCartList){
                OrderItem orderItem = new OrderItem();
                if(BookIsKillEnum.YES.getCode().equals(cart.getBook().getIsKill())){
                    BigDecimal subtotal = new BigDecimal(cart.getQuantity()).multiply(cart.getBook().getNewPrice());
                    orderItem.setSubtotal(subtotal);
                    orderItem.setBookPrice(cart.getBook().getNewPrice());

/**
 */

/**
 * 后台订单Order控制类
 */
@Controller
public class OrderController {

    @Autowired
    private IOrderService orderService;

    /**
     * 订单列表页面
     * @return
     */
    @GetMapping("/admin/order/list")
    public String list(){
        return "admin/order/list";
    }

    /**
     * 近期订单收益图表页面
     * @return
     */
    @GetMapping("/admin/order/stats")
    public String stats(){
        return "admin/order/stats";
    }

    /**
     * 获取订单收益图表的数据
     * @return
     */
    @PostMapping("/admin/order/stats")
    @ResponseBody
    public Map<String, Object> getStats(){
        return orderService.getStatsData();
    }

    /**
     * 获取订单数据操作处理
     * @param page
     * @param customerName
     * @param sellerName
     * @param state
            }
            //不是ajax请求,直接跳转页面
            try {
                log.info("没有登录或token非法,跳转登录界面!当前URL={}",requestURI);
                //根据路径分别跳转不同的登录页面
                if(requestURI.contains("/home/")){
                    response.sendRedirect("../system/index");
                }else if(requestURI.contains("/admin/")){
                    response.sendRedirect("../user/login");
                }else{
                    response.sendRedirect("../../common/system/not_permit");
                }
            } catch (IOException e3) {
                e3.printStackTrace();
            }
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

        if(payItemList == null || payItemList.size() == 0){
            throw new RuntimeException("支付成功,但订单状态异常,下单失败,请及时联系管理员解决!");
        }
        payItemList.forEach(e->{orderIdSet.add(e.getOrderId());});
        List<Order> orderList = orderDao.selectBatchIds(orderIdSet);
        if(orderList == null || orderList.size() == 0){
            throw new RuntimeException("支付成功,但订单状态异常,下单失败,请及时联系管理员解决!");
        }
        for(Order order : orderList){
            order.setState(OrderStateEnum.PAYED.getCode());
            if(orderDao.updateById(order) <= 0){
                throw new RuntimeException("支付成功,但订单状态异常,下单失败,请及时联系管理员解决!");
            }
        }
        return orderList;
    }

    @Override
    public ResponseVo<Map<String, Object>> getUserOrderData(Page page) {
        Map<String, Object> ret = new HashMap<>();
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        if(user == null){
            return ResponseVo.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
        }
        Map<String, Object> queryMap = new HashMap<>();
        if(page != null){
            page.setRows(1); //每页1条数据
            queryMap.put("offset", page.getOffset());
            queryMap.put("pageSize", page.getRows());
        }
        queryMap.put("customerId", user.getId());
        queryMap.put("isDeleted", OrderDeleteEnum.NO.getCode());
        List<Order> orderList = orderDao.selectAll(queryMap);
        ret.put("orderList", orderList);
        ret.put("page", page.getPage());
        ret.put("totalCount", orderDao.getAllTotal(queryMap));
        page.setTotalCount(orderDao.getAllTotal(queryMap));
        ret.put("totalPage", page.getTotalPage());
        ret.put("sendTotal", orderDao.getCountByOrderState(user.getId(), OrderStateEnum.SEND.getCode()));
        ret.put("signTotal", orderDao.getCountByOrderState(user.getId(), OrderStateEnum.SIGN.getCode()));
        return ResponseVo.success(ret);
    }

    @Override
    public ResponseVo<Boolean> delOrderByUser(String orderId) {
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        if(user == null){
            return ResponseVo.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
        }
    @PostMapping("/admin/order/list")
    @ResponseBody
    public Map<String, Object> list(Page page, String customerName, String sellerName, Integer state, String orderNo){
        return orderService.getOrderList(page, customerName, sellerName, state, orderNo);
    }

    /**
     * 删除订单操作处理
     * @param ids
     * @return
     */
    @PostMapping("/admin/order/delete")
    @ResponseBody
    public ResponseVo<Boolean> delete(String ids){
        return orderService.deleteOrder(ids);
    }

    /**
     * 修改订单状态操作处理
     * @param order
     * @return
     */
    @PostMapping("/admin/order/edit_state")
    @ResponseBody
    public ResponseVo<Boolean> editState(Order order){
        return orderService.editState(order);
    }
}

/**
            if(requestURI.contains("/admin/")){
                DecodedJWT decodedJWT = JWTUtil.verifyToken(adminToken);
                request.setAttribute("id", decodedJWT.getClaim("id").asString());
                request.setAttribute("username", decodedJWT.getClaim("username").asString());
                request.setAttribute("phone", decodedJWT.getClaim("phone").asString());
                request.setAttribute("email", decodedJWT.getClaim("email").asString());
                request.setAttribute("roleId", decodedJWT.getClaim("roleId").asString());
                //如果token合法,提交给Shiro
                Subject subject = SecurityUtils.getSubject();
                subject.getSession().setTimeout(604800000); //设置session过期时间:604800000ms = 7天
                UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(decodedJWT.getClaim("username").asString(), decodedJWT.getClaim("password").asString());
                subject.login(usernamePasswordToken);
            }

        }catch(Exception e){
            //e.printStackTrace();
            //token失效或非法
            //判断该路径是否需要验证
            for(String str : RuntimeConstant.userNotNeedConfirmUrl){
                if(requestURI.equals(str)){
                    return true; //该路径不需要验证,直接通行
                }
            }
            //判断是否是ajax请求或者是axios请求
            if (CommonUtil.isAjax(request) || CommonUtil.isAxios(request)) {
                //表示是ajax请求或者是axios请求
                try {
                    response.setCharacterEncoding("UTF-8");
                    //JSON.parseObject,是将Json字符串转化为相应的对象;JSON.toJSONString则是将对象转化为Json字符串。
                    response.getWriter().write(JSON.toJSONString(CodeMsg.USER_SESSION_EXPIRED));
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
                return false;
            }
            //不是ajax请求,直接跳转页面
            try {
                log.info("没有登录或token非法,跳转登录界面!当前URL={}",requestURI);
                //根据路径分别跳转不同的登录页面
                if(requestURI.contains("/home/")){
                    response.sendRedirect("../system/index");
                }else if(requestURI.contains("/admin/")){
                    response.sendRedirect("../user/login");
                }else{
                    response.sendRedirect("../../common/system/not_permit");
     * 获取用户我的订单的数据
     * @param page
     * @return
     */
    @PostMapping("/home/user/my_order")
    @ResponseBody
    public ResponseVo<Map<String, Object>> getMyOrderData(@RequestBody Page page){
        return orderService.getUserOrderData(page);
    }

    /**
     * 用户删除订单操作处理
     * @param orderId
     * @return
     */
    @PostMapping("/home/user/del_order")
    @ResponseBody
    public ResponseVo<Boolean> delOrderByUser(String orderId){
        return orderService.delOrderByUser(orderId);
    }
}

/**
 */

/**
 * 运行时触发异常捕获
 */
@ControllerAdvice
public class RuntimeExceptionHandler {

    private  final Logger logger = LoggerFactory.getLogger(RuntimeExceptionHandler.class);

    @ExceptionHandler(RuntimeException.class)

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值