开发笔记 | JAVA获取微信步数+日周月排行榜的实现

该博客详细介绍了如何实现微信步数的同步、获取用户当日步数以及日、周、月排行榜功能。首先,通过前端传递的encryptedData解密获取微信步数,然后根据用户ID和日期进行数据库的新增或更新操作。在获取排行榜时,根据时间范围对用户步数进行累加并排序。整个过程中涉及了数据验证、事务处理和数据库查询优化。
摘要由CSDN通过智能技术生成

目录

功能描述

微信步数同步

获取我当日的步数

日排行,周排行,月排行榜的实现


功能描述

实现微信步数的同步(也就是获取当前的微信步数更新至数据库)

实现获取我当日的微信步数的查询

实现按照日排行,周排行,月排行榜的功能

主要思路:通过前端传递的encryptedData加密数据包,解密后得到微信步数,此文中的方式,为前端获取微信步数并将加密数据包发送后端解析。

注意的点:数据库表设计为,一个用户,一天一条步数信息,在当天,第一次获取微信步数后为新增,之后同步均为更新,在根据不同条件获取排名时,将同一个用户,处于这个时间段内的步数相加后排序得出排名。

微信步数同步

请求参数实体

@Data
public class StepDTO implements Serializable {

    @ApiModelProperty(value = "小程序用户id",required=true)
    @NotBlank(message = "小程序用户id不能为空")
    private  String  appUserId;

    @ApiModelProperty(value = "微信昵称",required=true)
    @NotBlank(message = "微信昵称不能为空")
    private  String  nickName;

    //前端传递的步数数据包 用于解密获取步数
    @ApiModelProperty(value = "数据包",required=true)
    @NotBlank(message = "前端数据包不能为空")
    private String encryptedData;

    @ApiModelProperty(value = "iv" ,required=true)
    @NotBlank(message = "iv不能为空")
    private String iv;

    @ApiModelProperty(value = "session_key" ,required=false)
    private String sessionKey;

    @ApiModelProperty(value = "步数")
    private String step;

}

返回结果实体

@Data
public class BizStep extends BaseEntity{

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "小程序用户id")
    private  String  appUserId;

    @ApiModelProperty(value = "微信昵称")
    private  String  wechatName;

    @ApiModelProperty(value = "姓名")
    private  String  name;

    @ApiModelProperty(value = "步数")
    private  Integer  step;

    @ApiModelProperty(value = "头像")
    private String avatar ;

    @ApiModelProperty(value = "session_key")
    private String sessionKey;

    @ApiModelProperty(value = "手机号码")
    private String mobile;

}

微信步数VO

@Data
public class WxRunDataBO {

    @ApiModelProperty("stepInfoList")
    private List<StepInfoListBO> stepInfoList;

    @ApiModelProperty("stepInfoList")
    private WatermarkBO watermark;
}

@Data
public class StepInfoListBO {

    @ApiModelProperty("timestamp")
    private Long timestamp;

    @ApiModelProperty("step")
    private Integer step;
}

控制层

@Resource
private BizStepService bizStepService;

@PostMapping("/synchronize")
public ResponseEntity<BizStep> uploadStep(@RequestBody @Valid StepDTO stepDTO) {
            return ResultUtil.success("同步步数功",this.bizStepService.uploadStep(stepDTO));
}

service

业务层

@Resource
@Lazy
private AccountClient accountClient;
@Resource
private BizStepMapper bizStepMapper;

@Transactional(rollbackFor = Exception.class)
public BizStep uploadStep(StepDTO stepDTO) {
    Assert.isTrue(LocalTime.now().isBefore(LocalTime.parse("22:00:00")), "每日同步步数截止时间为22:00");
    //获取微信用户数据 此处的目的为获取用户的sessionKey
    WxUser wxUser = accountClient.getById(stepDTO.getAppUserId());
    stepDTO.setSessionKey(wxUser.getSessionKey());
    //获取用户步数
    String step = this.decryptWeChatStep(stepDTO);
    BizStep bizStep = new BizStep();
    //step入库
    if (StrUtil.isNotBlank(step)) {
        LocalDateTime localDateTime = LocalDateTime.now();
        String today = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(localDateTime);
        bizStep = 
        this.getOne(Wrappers.lambdaQuery(BizStep.class).eq(BizStep::getAppUserId, 
        stepDTO.getAppUserId())
            .apply("to_char(created_date,'yyyy-MM-dd') = {0}", today));
            if (null != bizStep) {
                //如果今天舒徐不为空则更新
                bizStep.setStep(Integer.valueOf(step));
                this.updateById(bizStep);
                //入果用户头像更改,需要更新历史数据的头像 保持一致性
                if (!wxUser.getAvatar().equals(bizStep.getAvatar())) {
                    this.update(Wrappers.lambdaUpdate(BizStep.class).eq(BizStep::getAppUserId, stepDTO.getAppUserId())
                            .set(BizStep::getAvatar, wxUser.getAvatar()));
                }
                //保持昵称的一致性 如果昵称改变保持历史数据的一致
                if (!wxUser.getNickName().equals(bizStep.getName())) {
                    this.update(Wrappers.lambdaUpdate(BizStep.class).eq(BizStep::getAppUserId, stepDTO.getAppUserId())
                            .set(BizStep::getName, wxUser.getNickName()));
                }
            } else {
                BizStep newBizStep = new BizStep();
                //如果今天数据为空则新增
                newBizStep.setAppUserId(stepDTO.getAppUserId());
                newBizStep.setWechatName(wxUser.getNickName());
                newBizStep.setName(wxUser.getNickName());
                newBizStep.setAvatar(wxUser.getAvatar());
                newBizStep.setSessionKey(wxUser.getSessionKey());
                newBizStep.setStep(Integer.valueOf(step));
                newBizStep.setMobile(wxUser.getMobile());
                this.save(newBizStep);
                return newBizStep;
            }
        }
        return bizStep;
    }

/**
     * 微信步数同步
     *
     * @param stepDTO
     * @return
     */
    public String decryptWeChatStep(StepDTO stepDTO) {
        String step = "0";
        byte[] encrypData = Base64.decodeBase64(stepDTO.getEncryptedData());
        byte[] ivData = Base64.decodeBase64(stepDTO.getIv());
        byte[] sessionKeyB = Base64.decodeBase64(stepDTO.getSessionKey());

        try {
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivData);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeySpec keySpec = new SecretKeySpec(sessionKeyB, AES);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] doFinal = cipher.doFinal(encrypData);
            String result = new String(doFinal);
            WxRunDataBO wxRunDataBO = JSON.parseObject(result, WxRunDataBO.class);
            List<StepInfoListBO> stepInfoList = wxRunDataBO.getStepInfoList();
            Assert.isTrue(stepInfoList.size() > 0, "微信没有您今日的步数");
            StepInfoListBO stepInfoListBO = stepInfoList.get(stepInfoList.size() - 1);
            log.info("stepInfoListBO={}", stepInfoListBO);
            Long timestamp = stepInfoListBO.getTimestamp();
            step = String.valueOf(stepInfoListBO.getStep());
            log.info("step={}", step);
        } catch (Exception e) {
            log.error("解析步数报错", e);
            throw new IllegalArgumentException("微信步数解析异常");
        }
        return step;
    }

获取我当日的步数

入参实体(结果实体同上BizStep)

@Data
public class MineStepDTO {

    @ApiModelProperty(value = "小程序用户id",required=true)
    @NotBlank(message = "小程序用户id不能为空")
    private  String  appUserId;
}

controller层

@PostMapping("/getStep")
@ApiOperation(value = "获取我当天的步数" , notes = "")
@PreAuthorize("hasRole('MINI_APP')")
public ResponseEntity<BizStep> getMineStep(@RequestBody @Valid MineStepDTO mineStepDTO) {
    return ResultUtil.success(this.bizStepService.getMineStep(mineStepDTO));
}

 service

对我方步数表的查询

public BizStep getMineStep(MineStepDTO mineStepDTO) {
    LocalDateTime localDateTime = LocalDateTime.now();
    String today = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(localDateTime);
    BizStep bizStep = this.getOne(Wrappers.lambdaQuery(BizStep.class).eq(BizStep::getAppUserId, mineStepDTO.getAppUserId())
                .apply("to_char(created_date,'yyyy-MM-dd') = {0}", today));
     if (null == bizStep) {
         //如果今日无数据 返回0步
         BizStep newBizStep = new BizStep();
         //如果今天数据为空则新增
         newBizStep.setAppUserId(mineStepDTO.getAppUserId());
         newBizStep.setStep(0);
         return newBizStep;

        }
     return bizStep;
}

日排行,周排行,月排行榜的实现

请求实体

@Data
public class RankDTO implements Serializable {

    @ApiModelProperty(value = "排序方式 月month 周week 日day", required = true)
    @NotBlank(message = "请选择排序方式")
    private String type;

    @ApiModelProperty(value = "小程序用户id", required = true)
    @NotBlank(message = "小程序用户id不能为空")
    private String appUserId;

    //当前页,默认第一页
    @ApiModelProperty(value = "当前页")
    private Integer currPage = 1;

    //每页记录数,默认为10
    @ApiModelProperty(value = "显示条数")
    private Integer size = 100000;

}

 controller

@PostMapping("/rank")
public ResponseEntity<List<StepRankVO>> getRank(@RequestBody @Valid RankDTO rankDTO) {
    return ResultUtil.success(this.bizStepService.getRank(rankDTO));
}

service

 public StepRankVO getRank(RankDTO rankDTO) {
        StepRankVO stepRankVO = new StepRankVO();
        //时间条件
        String startDate = "";
        String endDate = "";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());

        if (MONTH.equals(rankDTO.getType())) {
            calendar.add(Calendar.MONTH, 0);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            startDate = dateFormat.format(calendar.getTime()) + " 00:00:00";
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, 0);
            endDate = dateFormat.format(calendar.getTime()) + " 23:59:59";
        }
        if (WEEK.equals(rankDTO.getType())) {
            calendar.setFirstDayOfWeek(Calendar.MONDAY);
            calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            startDate = dateFormat.format(calendar.getTime()) + " 00:00:00";
            calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
            endDate = dateFormat.format(calendar.getTime()) + " 23:59:59";
        }
        if (DAY.equals(rankDTO.getType())) {
            calendar.add(Calendar.DATE, 0);
            String today = dateFormat.format(calendar.getTime());
            startDate = today + " 00:00:00";
            endDate = today + " 23:59:59";
        }
        Page<RankResultVO> ranks = this.bizStepMapper.getRank(new Page<>(rankDTO.getCurrPage(), rankDTO.getSize()), startDate, endDate);
        if (CollectionUtil.isNotEmpty(ranks.getRecords())) {
            stepRankVO.setRankList(ranks.getRecords());
            RankResultVO myRankVO = new RankResultVO();
            List<RankResultVO> myRank = ranks.getRecords().stream().filter(e -> rankDTO.getAppUserId().equals(e.getAppUserId())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(myRank)) {
                BeanUtils.copyProperties(myRank.get(0), myRankVO);
            }
            stepRankVO.setMine(myRankVO);

        }

        return stepRankVO;
    }

mapper

@Mapper
public interface BizStepMapper extends BaseMapper<BizStep> {

    Page<RankResultVO> getRank(Page<RankResultVO> page, @Param("startDate") String startDate, @Param("endDate") String endDate);

}

xml

 <select id="getRank" resultType="com.vo.mp.RankResultVO">
        SELECT
        rank ( ) over ( ORDER BY t.step DESC ) AS rank,
        t.step,
        t.app_user_id,
        t.NAME,
        t.avatar
        FROM
        (
        SELECT
        sum( a.step ) AS step,
        a.app_user_id,
        a.NAME,
        a.avatar
        FROM
        ssyy_biz_step a
        where
        to_char(created_date,'yyyy-MM-dd HH24:MI:ss') <![CDATA[>=]]>  #{startDate}
        and
        to_char(created_date,'yyyy-MM-dd HH24:MI:ss')<![CDATA[<=]]> #{endDate}
        GROUP BY
        a.app_user_id,
        a.NAME,
        a.avatar
        ) t
    </select>

获取 Android 设备的每日步数,可以使用 Google Fit API。以下是获取步数的简单示例代码: 1. 在 build.gradle 文件中添加以下依赖项: ``` dependencies { implementation 'com.google.android.gms:play-services-fitness:20.0.0' } ``` 2. 在 AndroidManifest.xml 文件中添加以下权限: ``` <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> ``` 3. 在 MainActivity.java 文件中添加以下代码: ``` import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; import com.google.android.gms.fitness.Fitness; import com.google.android.gms.fitness.data.DataSet; import com.google.android.gms.fitness.request.DataReadRequest; import com.google.android.gms.fitness.result.DataReadResult; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit; public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private GoogleApiClient mClient = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a GoogleApiClient instance mClient = new GoogleApiClient.Builder(this) .addApi(Fitness.HISTORY_API) .addScope(Fitness.SCOPE_ACTIVITY_READ) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); // Connect to the Google Fit API mClient.connect(); } @Override public void onConnected(@Nullable Bundle bundle) { // Get the current date Calendar cal = Calendar.getInstance(); Date now = new Date(); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); long startTime = cal.getTimeInMillis(); // Create a data request for the step count DataReadRequest readRequest = new DataReadRequest.Builder() .aggregate(Fitness.HISTORY_API, Fitness.HistoryApi.AggregateRequest.STEP_COUNT_DELTA) .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS) .build(); // Retrieve the step count Fitness.HistoryApi.readData(mClient, readRequest).setResultCallback(new ResultCallback<DataReadResult>() { @Override public void onResult(DataReadResult dataReadResult) { DataSet dataSet = dataReadResult.getDataSet(Fitness.HistoryApi.AggregateRequest.STEP_COUNT_DELTA); int totalSteps = 0; for (com.google.android.gms.fitness.data.DataPoint dp : dataSet.getDataPoints()) { for (com.google.android.gms.fitness.data.Field field : dp.getDataType().getFields()) { int steps = dp.getValue(field).asInt(); totalSteps += steps; } } Log.i("Step Count", "Total steps: " + totalSteps); } }); } @Override public void onConnectionSuspended(int i) { Log.i("Google Fit", "Connection suspended"); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.i("Google Fit", "Connection failed"); } @Override protected void onDestroy() { super.onDestroy(); mClient.disconnect(); } } ``` 这将获取当前日期的步数,并将其打印到 Logcat 中。您可以根据需要更改日期范围。注意,此代码需要用户授权才能访问步数数据,因此您需要在运行时请求相应的权限。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值