开启生长之旅!这是我参与「日新计划 12 月更文挑战」的第1天,点击查看活动概况

springboot实现复杂业务下的更新操作

咱们好,我是雄雄,欢迎关注微信大众号:雄雄的小课堂

前言

现在是2022年5月4日19:25:55!今日写了个这样的功用:

某用户在一天内有多个练习项目,比如:晨跑,有氧练习,跳绳这三个项目。这三个练习项目都在数据库中有记载,每个项目都有开端时刻,完毕时刻以及状况。状况包含:未开端,进行中和已完毕。

下图展现的便是练习项目

springboot实现复杂业务下的更新操作

用户早上醒来之后,点击第一个晨跑的小卡片,那么就开端记载当时时刻便是晨跑的开端时刻。练习完之后,用户接着点击有氧练习的小卡片,那么此刻,晨跑项目的完毕时刻便是当时时刻,有氧练习的开端时刻也是当时时刻,此刻的晨跑状况是已完毕,有氧练习的状况是进行中

没理解的话多看几遍就理解了,哈哈哈,这儿有点绕。

由于这是两个体系,练习项目所属一个项目,调用的是另一个项目,下面说一下我的完成方式。

完成思路

  1. 在练习项目的体系上,只完成更新操作,传参:项目id,开端时刻,完毕时刻,状况
  2. 在调用的体系上,编写事务代码块,一共有三个接口
  3. 接口一:记载第一个练习项目的开端时刻,将当时练习项目的id放在redis中。
  4. 接口二:从redis中获取上一个动作的id,传递动作的id,时刻戳,然后修正上一个动作的完毕时刻是当时的时刻戳,第一个动作的状况是【已完毕】,当时动作的开端时刻是当时的时刻戳,状况是【练习中】,删除上一个动作的id,将当时动作的id放在redis里边
  5. 接口三:最终一个动作的完毕:传递当时计划的id,动作的id,用户id,时刻戳,然后修正当时动作的完毕时刻是时刻戳,状况是【已完毕】,删掉redis里边的用户id

说明:咱们能够看到,我将第一个练习项目的id放在了redis中,这么放的目的便是下一个练习项目传过来之后,更好的知道上一个练习项目是哪个,由于咱们需要更改它的状况和完毕时刻。之后还需要更改当时练习项目的开端时刻和状况。以此类推,一直到最终一个。

接口三首要完成的功用便是更新最终一个练习项目的完毕时刻,这样咱们就能够顺次更改每个练习项目的开端时刻、完毕时刻以及练习状况

上面仍是有点绕,咱们能够细心的看看~

完成代码

下面我来介绍一下代码是怎样完成的。

首先是练习项目中的更新操作,这个办法就一个修正的操作,没啥特别杂乱的,下面是代码:

        /**
     * 根据项目project的id,修正动作状况和开端时刻,完毕时刻
     * 参数:动作id,状况,开端时刻,完毕时刻
     */
    @PostMapping(value = "/updateProjectById")
    public String updateProjectById(@RequestHeader("Authorization")
                                            String token,
                                            Long pid,
                                            int status,
                                            Long beginTime,
                                            Long endTime) {
        JSONObject jsonObject = new JSONObject();
        //1.验证token
        boolean isOk = TokenUtil.verify(token);
        if (!isOk) {
            jsonObject.put("code", 401);
            jsonObject.put("msg", "令牌失效");
            return jsonObject.toString();
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //查询
            Project project = projectService.getById(pid);
            //练习项目状况,0未开端,1进行中,2已完成
            project.setProjectStatus(status + "");
            //将时刻戳转换成时刻
            if (beginTime != null) {
                String kstime = DateParseUtils.getTimeChuo(beginTime);
                project.setBeginTime(format.parse(kstime));
            }
            //完毕时刻
            if (endTime != null) {
                String jstime = DateParseUtils.getTimeChuo(endTime);
                project.setEndTime(format.parse(jstime));
            }
            projectService.updateById(project);
            jsonObject.put("code",200);
            jsonObject.put("msg","操作成功");
            jsonObject.put("status",true);
        } catch (ParseException e) {
            jsonObject.put("code",500);
            jsonObject.put("msg","操作失利");
            jsonObject.put("status",false);
            e.printStackTrace();
        }
        return jsonObject.toJSONString();
    }

能够发现,开端时刻和完毕时刻都不能是必填,由于在更新第一个练习项目的时分,咱们只能知道当时的时刻是开端时刻,并不知道何时完毕。同理,在更新第二个练习项目时,咱们只需拿着当时时刻更新上一个练习项目的完毕时刻就行。

下面是调用方的完成:

  1. 将参数封装成实体:
    package org.springblade.modules.system.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * @author: muxiongxiong
 * @date: 2022年04月30日 20:34
 * 大众号:雄雄的小课堂
 * 博客:https://blog.csdn.net/qq_34137397
 * 个人站:http://www.穆雄雄.com
 * 个人站:http://www.muxiongxiong.cn
 * @Description: 类的描绘
 */
@Data
@ApiModel(value = "TrainingVO目标", description = "TrainingVO目标")
public class TrainingVO {
    /**
     * 动作id
     */
    private Long projectId;
    /**
     * 计划id
     */
    private Long programmeId;
    /**
     * 用户id
     */
    private Long userId;
    /**
     * 动作状况
     */
    private Integer status;
    /**
     * 时刻戳 接收前台传过来的时刻戳
     */
    private Long time;
    /**
     * 事务上处理的动作,开端时刻
     */
    private Long beginTime;
    /**
     * 事务上处理的动作,完毕时刻
     */
    private Long endTime;
}
  1. 公共接口,也便是更新的接口:
    /**
     * 公共的接口
     * 调用练习计划的
     * 更新动作的状况和时刻
     *
     * @param trainingVO
     * @return
     */
    @Override
    public R updateTrainingProgrammeAndProjectStatusAndTime(TrainingVO trainingVO) {
        //判别是否为空
        R rt = getToken();
        String token = "";
        if (rt != null) {
            JSONObject jsonObject = (JSONObject) rt.getData();
            if (jsonObject != null) {
                token = jsonObject.getStr("access_token");
            }
        } else {
            return R.fail(500, "获取token失利");
        }
        if (StringUtil.isEmpty(token)) {
            return R.fail(500, "获取token失利");
        }
        //请求接口地址
        String url = TrainingSchemeConstant.updateProjectById;
        Map paramMap = new HashMap();
        //动作id
        if (trainingVO.getProjectId() != null) {
            paramMap.put("pid", trainingVO.getProjectId());
        }
        //开端时刻
        if (trainingVO.getBeginTime() != null) {
            paramMap.put("beginTime", trainingVO.getBeginTime());
        }
        //状况
        if (trainingVO.getStatus() != null) {
            paramMap.put("status", trainingVO.getStatus());
        }
        //完毕时刻
        if (trainingVO.getEndTime() != null) {
            paramMap.put("endTime", trainingVO.getEndTime());
        }
        try {
            String body = HttpUtil.createPost(url).header("Authorization", token).form(paramMap).execute().body();
            if (StringUtils.isBlank(body)) {
                return R.status(false);
            }
            JSONObject obj = JSONUtil.parseObj(body);
            if (obj == null) {
                return R.status(false);
            }
            boolean flag = Boolean.parseBoolean(obj.get("status").toString());
            return R.status(flag);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
            return R.status(false);
        }
    }
  1. 接口一,更新第一个练习项目的开端时刻状况:
    /**
     * 接口一:第一个动作的开端:
     * 1.当时动作的id,时刻戳,然后将当时动作的开端时刻修正,当时动作的状况该成 【练习中】
     * 2.将当时动做的id放在redis里边。
     * 参数:用户id,计划id,首要是放在redis的时分需要用
     *
     * @param trainingVO
     * @return
     */
    @PostMapping("/updateProjectBeginTime")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "threePlant-第一个动作的更新", notes = "传入userId,programmeId,projectId,time")
    public R updateProjectBeginTime(@ApiParam(value = "练习计划事务目标", required = true) @RequestBody  TrainingVO trainingVO) {
        //第一个动作的开端时刻
        trainingVO.setBeginTime(trainingVO.getTime());
        //第一个动作:练习中
        trainingVO.setStatus(1);
        //将第一个动作放在redis的缓存中
        bladeRedis.set("training:updateTrainingStatusAndTime:" +
            trainingVO.getUserId() + ":" +
            trainingVO.getProgrammeId(), trainingVO.getProjectId());
        //调用更新的托言
        return trainingSchemeUrlService.updateTrainingProgrammeAndProjectStatusAndTime(trainingVO);
    }
  1. 接口二,更新当时动作的开端时刻,状况和上一个动作的完毕时刻、状况。
    /**
     * 接口二:中心的动作操作:
     * 1.从redis中获取上一个动作的id。
     * 2.传递动作的id,时刻戳,然后修正上一个动作的完毕时刻是当时的时刻戳,第一个动作的状况是【已完毕】,当时动作的开端时刻是当时的时刻戳,状况是【练习中】
     * 3.删除上一个动作的id,将当时动作的id放在redis里边
     *
     * @param trainingVO
     * @return
     */
    @PostMapping("/updateProjectBeginTimeAndEndTime")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "threePlant-中心动作的更新", notes = "传入userId,programmeId,projectId,time")
    public R updateProjectBeginTimeAndEndTime(@ApiParam(value = "练习计划事务目标", required = true) @RequestBody TrainingVO trainingVO) {
        TrainingVO trainingVONew = new TrainingVO();
        //先从redis中获取上一个动作的id
        Long beforePid = bladeRedis.get("training:updateTrainingStatusAndTime:" + trainingVO.getUserId() + ":" + trainingVO.getProgrammeId());
        //用完之后删掉redis里边的数据
        bladeRedis.del("training:updateTrainingStatusAndTime:" + trainingVO.getUserId() + ":" + trainingVO.getProgrammeId());
        //修正上个动作的完毕时刻是当时的时刻戳
        trainingVONew.setEndTime(trainingVO.getTime());
        //上个动作的状况是已完毕
        trainingVONew.setStatus(2);
        trainingVONew.setProjectId(beforePid);
        //调用更新的托言
        R resultR = trainingSchemeUrlService.updateTrainingProgrammeAndProjectStatusAndTime(trainingVONew);
        if (resultR.getCode() == 200) {
            //更新没啥问题
            //开端修正当时状况
            //状况是练习中
            trainingVO.setStatus(1);
            //开端时刻是时刻戳
            trainingVO.setBeginTime(trainingVO.getTime());
            //将当时的动作在放在redis里边
            bladeRedis.set("training:updateTrainingStatusAndTime:" +
                trainingVO.getUserId() + ":" +
                trainingVO.getProgrammeId(), trainingVO.getProjectId());
            //调用更新的办法
            return trainingSchemeUrlService.updateTrainingProgrammeAndProjectStatusAndTime(trainingVO);
        } else {
            return R.status(false);
        }
    }
  1. 接口三,更新最终一个练习项目的完毕时刻和练习状况:
    /**
     * 接口三:最终一个动作的完毕:
     * 1.传递当时计划的id,动作的id,用户id,时刻戳,然后修正当时动作的完毕时刻是时刻戳,状况是【已完毕】
     * 2.删掉redis里边的用户id
     *
     * @param trainingVO
     * @return
     */
    @PostMapping("/updateProjectEndTime")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "threePlant-最终一个动作的更新", notes = "传入userId,programmeId,projectId,time")
    public R updateProjectEndTime(@ApiParam(value = "练习计划事务目标", required = true) @RequestBody TrainingVO trainingVO) {
        //最终一个动作的完毕时刻是时刻戳
        trainingVO.setEndTime(trainingVO.getTime());
        //最终一个动作是已完毕
        trainingVO.setStatus(2);
        //删掉redis中的动作id
        bladeRedis.del("training:updateTrainingStatusAndTime:" +
            trainingVO.getUserId() + ":" +
            trainingVO.getProgrammeId());
        return trainingSchemeUrlService.updateTrainingProgrammeAndProjectStatusAndTime(trainingVO);
    }
        trainingVO.setStatus(2);
        //删掉redis中的动作id
        bladeRedis.del("training:updateTrainingStatusAndTime:" +
            trainingVO.getUserId() + ":" +
            trainingVO.getProgrammeId());
        return trainingSchemeUrlService.updateTrainingProgrammeAndProjectStatusAndTime(trainingVO);
    }

以上便是整个流程的完成,其实写代码难的不是代码,而是事务,当你理解了事务是什么,随之而来的便是完成方式,所以,事务是重中之重的~