【JavaWeb】——帝可得实践项目-App与设备端补充

目录

  • [1. 运营管理App](#1. 运营管理App)
    • [1.1. 代码运行](#1.1. 代码运行)
    • [1.2. 代码简介](#1.2. 代码简介)
    • [1.3. App测试](#1.3. App测试)
  • [2. 设备屏幕端](#2. 设备屏幕端)
    • [2.1. 代码运行](#2.1. 代码运行)
    • [2.2. 支付实现](#2.2. 支付实现)

1. 运营管理App

1.1. 代码运行

  • 业务场景

    管理员在后台创建工单后,工作人员可在运营管理App中查看并根据情况选择接受或取消分配给自己的任务

  • 安装配置

    • 客户端

      本项目的App客户端部分已经由前端团队进行开发完成,并且以apk的方式提供出来,供我们测试使用

      1. 安装模拟器

      2. 安装APK

      3. 配置后端地址

    • 后端搭建

      本项目运营管理App的java后端已开发完成,在资料中已提供源码,导入idea中即可

1.2. 代码简介

  • 代码组成

    运营管理App的java后端技术栈:SpringBoot+MybatisPlus+阿里云短信

    复制代码
    + 员工管理(EmpController):发送短信、App登录、查询员工信息
    + 工单管理(TaskController):查询工单、接受工单、拒绝/取消工单、完成工单
    + 工单详情(TaskDetailsController):根据工单id查询补货详情列表
    
    ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8588e2050fa6432687ad30bbfcea7478.png)
  • 阿里云短信

    这里提一下我们以前可能没有接触到的短信认证服务,看一下实现代码。

    • 工具类(SmsTemplate)

      java 复制代码
      //短信发送工具类
      @Data
      @Component
      @ConfigurationProperties(prefix = "dkd.sms")
      public class SmsTemplate {
      
          private String key;
          private String secret;
          private String signName;
          private String templateCode;
      
          // 调用阿里云平台发送短信
          public void sendSms(String phoneNumbers, String code) {
              //设置超时时间
              System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
              System.setProperty("sun.net.client.defaultReadTimeout", "10000");
      
              try {
                  //初始化acsClient,暂不支持region化
                  IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", key, secret);
                  DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com");
                  IAcsClient acsClient = new DefaultAcsClient(profile);
      
                  //组装请求对象-具体描述见控制台-文档部分内容
                  SendSmsRequest request = new SendSmsRequest();
                  request.setPhoneNumbers(phoneNumbers);//手机号
                  request.setSignName(signName);//短信前面
                  request.setTemplateCode(templateCode);//短信模板
                  request.setTemplateParam("{\"code\":\"" + code + "\"}");//验证码
      
                  SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
    • yml相关配置

      yaml 复制代码
      sms:
      key:
      secret:
      sign-name: 阿里云短信测试
      template-code: SMS_154950909
    • 封装返回结果

      java 复制代码
      // 封装返回结果
      private EmpVo convertToVM(Emp emp) {
          EmpVo empVo = new EmpVo();
          empVo.setMobile(emp.getMobile());
          empVo.setRoleId(emp.getRoleId());
          empVo.setRoleCode(emp.getRoleCode());
          empVo.setLoginName(emp.getUserName());
          empVo.setUserId(emp.getId());
          empVo.setRoleName(roleService.getById(emp.getRoleId()).getRoleName());
          empVo.setUserName(emp.getUserName());
          empVo.setStatus(emp.getStatus());
          empVo.setRegionId(emp.getRegionId());
          empVo.setRegionName(emp.getRegionName());
          empVo.setImage(emp.getImage());
          return empVo;
      }    // 封装返回结果
      private EmpVo convertToVM(Emp emp) {
          EmpVo empVo = new EmpVo();
          empVo.setMobile(emp.getMobile());
          empVo.setRoleId(emp.getRoleId());
          empVo.setRoleCode(emp.getRoleCode());
          empVo.setLoginName(emp.getUserName());
          empVo.setUserId(emp.getId());
          empVo.setRoleName(roleService.getById(emp.getRoleId()).getRoleName());
          empVo.setUserName(emp.getUserName());
          empVo.setStatus(emp.getStatus());
          empVo.setRegionId(emp.getRegionId());
          empVo.setRegionName(emp.getRegionName());
          empVo.setImage(emp.getImage());
          return empVo;
      }
    • Controller

      java 复制代码
      // 发送短信验证码
      @GetMapping("/code/{mobile}")
      public void sendSms(@PathVariable("mobile") String mobile) {
          empService.sendSms(mobile);
      }
      java 复制代码
      // 登录
      @PostMapping("/login")
      public LoginVo login(@RequestBody LoginDto req) throws IOException {
          return empService.login(req);
      }
    • Service实现类

      java 复制代码
      @Override
      public void sendSms(String mobile) {
          // String code = RandomUtil.randomNumbers(5); // 生成5位随机验证码
          String code = "12345";
          // smsTemplate.sendSms(mobile,code); // 调用阿里云发送短信
          // 将验证码存入redis  dkd.sms:手机号 验证码  5分钟有效
          redisTemplate.opsForValue().set("dkd.sms:" + mobile, code, Duration.ofSeconds(300));
      }
      java 复制代码
      @Override
      public LoginVo login(LoginDto req) throws IOException {
          //1. 比对验证码
          // 从redis中查询
          String redisCode = redisTemplate.opsForValue().get("dkd.sms:" + req.getMobile());
          if (!StrUtil.equals(req.getCode(), redisCode)) { // 注意此处有感叹号
              throw new LogicException("验证码错误");
          }
      
          // 2.比对手机号
          LambdaQueryWrapper<Emp> qw = new LambdaQueryWrapper<>();
          qw.eq(Emp::getMobile, req.getMobile());
          Emp emp = this.getOne(qw);
          if (ObjectUtil.isEmpty(emp)) {
              throw new LogicException("手机号非法");
          }
          //3. 登录成功,制作token返回结果
          LoginVo resp = new LoginVo();
          resp.setSuccess(true);
          resp.setRoleCode(emp.getRoleCode());
          resp.setUserName(emp.getUserName());
          resp.setUserId(emp.getId());
          resp.setRegionId(emp.getRegionId().toString());
          resp.setMsg("登录成功");
          TokenObject tokenObject = new TokenObject();
          tokenObject.setUserId(emp.getId());
          tokenObject.setMobile(emp.getMobile());
          tokenObject.setLoginType(req.getLoginType());
          tokenObject.setUserName(emp.getUserName());
          String token = JWTUtil.createJWTByObj(tokenObject);
          resp.setToken(token);
          // 是否为维修员
          if (emp.getRoleCode().equals("1003")) {
              resp.setRepair(true);
          }
      
          // 删除redis中验证码
          redisTemplate.delete("dkd.sms:" + req.getMobile());
          return resp;
      }

1.3. App测试

  • 后端测试

    后端代码更改相关配置并启动(记得将java的jdk版本切换为jdk17,并修改yaml配置文件的mysql和redis的连接信息)。这里有一点我们需要改,因为我的管理端的表都没有tb_前缀,我们这里就需要修改一下官方的代码,将app项目的后端代码的@TableName注解的value的所有tb_前缀去掉。

    java 复制代码
    @Data
    @TableName(value = "task_details")
  • 前端测试

    这里使用Mumu模拟器来进行App模拟,这里建议自己去官网下载最新版的模拟器,因为老版本可能会不兼容Hyper-V

    修改后端Url(默认为:https://likede2-java.itheima.net/api),这里需要改为http://10.0.2.2:9007

    • 关于IP和DHCP

      • 静态IP:就是手动设置的固定IP地址。你自己或者系统管理员直接指定一组IP,不会变。
      • DHCP(动态主机配置协议):由路由器或网络中的DHCP服务器自动分配IP,设备每次连接可能拿到不同的IP。
    • 关于连接地址

      你直接使用http://10.0.2.2:9007一般来说是连接不成功的,因为这是10.0.2.2 是模拟器内置的转发地址,专门用来访问 宿主机(运行模拟器的电脑) 的本地服务,而你的电脑并不会是这个地址,我这里使用网络桥接(注意IP要不一样)

      你可以运行命令ipfonfig,找到无线局域网适配器 WLAN:

      bash 复制代码
      无线局域网适配器 WLAN:
      
         连接特定的 DNS 后缀 . . . . . . . :
         本地链接 IPv6 地址. . . . . . . . : ****::****:****:****:****
         IPv4 地址 . . . . . . . . . . . . : 192.168.124.80
         子网掩码  . . . . . . . . . . . . : 255.255.255.0
         默认网关. . . . . . . . . . . . . : 192.168.124.1

      配置MuMu模拟器配置,开启网络桥接模式(我这里已经下载好了驱动),将上面的配置一一对应。这里也不一定要和我一样,DHCP也可以,不过重启关机后ip可能会改变(但是局域网换了,ip也会改变,比如说换了WIFI),然后重新设置应用的url即可。

    • 最佳实践

      • 所以我最建议的还是:局域网能跑通后,将项目放在服务器中,使用公网ip访问
      • 如果服务器部署,那么不要配置域名和SSL证书,直接http访问,因为没有前端源码,就不能修改,前端是http,如果后端使用https,就会造成内容混用问题
    • 登录成功

      运维工单如图(运营工单也差不多)

2. 设备屏幕端

2.1. 代码运行

  • 业务场景

    消费者可以在设备屏幕端查看商品列表--选择支付方式--显示支付二维码--用户扫码完成支付--商品出货

  • 后端搭建

    修改mysql、redis配置,以及tb前缀的表名

  • 前端搭建

    先修改index.html文件中的后端url,然后直接在浏览器中打开index.html文件,再输入设备编号(innerCode)

    js 复制代码
    let domain = "http://localhost:8005";

    html项目也可以单独运行在服务器哈,只需要将将项目目录指向index.html的父文件夹

    大家可以看看我发布的屏幕端:帝可得屏幕端

2.2. 支付实现

  • 支付框架介绍

    仓库地址https://gitee.com/myelegent/elegent-pay

    ElegentPay是封装了支付宝和微信支付的支付框架,用户使用该框架,可以用最小的学习成本,在几分钟内快速集成并在项目中使用。

    1. 为支付宝和微信提供了统一的调用入口。
    2. 支持native、小程序、H5、APP等多种支付方式,并提供统一入口。
    3. 提供了统一的dto类作为前端的调用参数,用户使用简便。
    4. 封装了回调入口和验签逻辑,简化了用户编写支付回调中繁琐的验签逻辑。
    5. 提供了扩展机制,用户可以自定义其它的支付方式。
    6. 对支付回调和退款回调提供了幂等性校验。
    7. 提供了回调补偿功能。
    8. ElegentPay是封装了支付宝和微信支付的支付框架,用户使用该框架,可以用最小的学习成本,在几分钟内快速集成并在项目中使用。
  • 支付框架使用

    1. 引入依赖

      xml 复制代码
      <!--微信支付-->
      <dependency>
          <groupId>cn.elegent.pay</groupId>
          <artifactId>elegent-pay-wxpay</artifactId>
          <version>1.0.0</version>
      </dependency>
      <!--支付宝支付-->
      <dependency>
          <groupId>cn.elegent.pay</groupId>
          <artifactId>elegent-pay-alipay</artifactId>
          <version>1.0.0</version>
      </dependency>
    2. 添加配置

      yaml 复制代码
      elegent:
        pay:
          wxpay:
            mchId: 1561414331
            appId: wx6592a2db3f85ed25
            appSecret: d9a9ff00a633cd7353a8925119063b01
            mchSerialNo: 25FBDE3EFD31B03A4377EB9A4A47C517969E6620
            apiV3Key: CZBK51236435wxpay435434323FFDuv3
          alipay:
            appId: 2021003141676135
          callback:
            domain: https://2d3ac179.r5.cpolar.top
            watch: true
            cycle: 10
    3. 业务代码编写

      去仓库Readme看吧,这里就不过多叙述了。

  • 支付流程

    • 生成二维码流程

    • 支付流程

相关推荐
SunnyDays10112 小时前
Java 高效实现 CSV 转 PDF
java·csv转pdf
隐形喷火龙2 小时前
SpringBoot 异步任务持久化方案:崩溃重启不丢任务的完整实现
java·spring boot·后端
我是koten2 小时前
K8s启动pod失败,日志报非法的Jar包排查思路(Invalid or corrupt jarfile /app/xxxx,jar)
java·docker·容器·kubernetes·bash·jar·shell
Andy工程师2 小时前
Filter 的加载机制 和 Servlet 容器(如 Tomcat)的请求处理流程
spring boot
WX-bisheyuange2 小时前
基于Spring Boot的库存管理系统的设计与实现
java·spring boot·后端
J_liaty2 小时前
Docker 部署 Spring Boot 项目完整指南:从零到生产环境
spring boot·docker·容器
YanDDDeat2 小时前
【JVM】类初始化和加载
java·开发语言·jvm·后端
码农水水2 小时前
阿里Java面试被问:单元测试的最佳实践
java·面试·单元测试
indexsunny2 小时前
互联网大厂Java面试实战:Spring Cloud微服务与Redis缓存在电商场景中的应用
java·spring boot·redis·spring cloud·微服务·消息队列·电商
hunter14502 小时前
2026.1.4 html简单制作
java·前端·笔记·html