仿12306项目(2)-- 基础功能的实现

        本章是完成乘车人的增删改查功能

乘车人表的设计

        在实际的购票流程中,用户不仅能够登录自己的账号为自己购买票务,还可以帮助他人购票。因此,在设计数据库中的乘客表时,引入了两个关键字段:idmember_id。这里,id 代表为哪些人购票的唯一标识符,由雪花算法生成,而 member_id 则与登录账户(即会员表中的 id)相对应,用于记录是哪个会员进行了购票操作。这里member_id 被设置为普通索引而非唯一索引,这是为了支持一个会员为多个人购票的需求,即支持一对多的关系映射,并方便通过 member_id 查询该会员为哪些人购买了什么票。如果将member_id设置为主键,由于member_id为多人买票时,member_id是相同的,不满足主键对应的每一条购票记录都需要有一个独一无二的标识符。

 旅客类型|枚举[PassengerTypeEnum]是为了后面的代码生成器,由于旅客类型是一个枚举型,总体表示type 字段的值应从 PassengerTypeEnum 枚举中选择数据。

        其他可以优化的点:分区表:如果数据量非常大,可以根据 member_id 或者时间等维度对表进行分区,这样可以加快特定条件下的查询速度。

drop table if exists member;
create table member(
    id bigint not null comment 'id',
    mobile varchar(11) comment '手机号',
    primary key (id),
    unique key mobile_unique(mobile)
)engine=InnoDB default charset=utf8mb4 comment='会员';

DROP TABLE IF EXISTS passenger;
CREATE TABLE passenger (
    id BIGINT NOT NULL COMMENT 'id',
    member_id BIGINT NOT NULL COMMENT '会员id',
    name VARCHAR(20) NOT NULL COMMENT '姓名',
    id_card VARCHAR(18) NOT NULL COMMENT '身份证',
    type CHAR(1) NOT NULL COMMENT '旅客类型|枚举[PassengerTypeEnum]',
    create_time DATETIME(3) COMMENT '新增时间',
    update_time DATETIME(3) COMMENT '修改时间',
    PRIMARY KEY (id),
    INDEX member_id_index (member_id)
) ENGINE = INNODB DEFAULT CHARSET=utf8mb4 COMMENT='乘车人';

为了旅客类型的枚举,可以在member模块增加一个enums包,增加一个PassengerTypeEnum类,和上面的表进行对应,字母是为了编写代码,第一个字符串放到数据库表中,第二个字段是为了显示到页面,为了购票人进行理解。最后调用mybatis的代码生成器完成Mapper层的编写。

ADULT("1", "成人"),
CHILD("2", "儿童"),
STUDENT("3", "学生");

乘车表新增用户 

        对于Mapper(数据持久层)来说,完成对于数据库的CRUD操作,这里已经使用了Mybatis代码生成器完成了这部分的代码。对于Service层来说,需要根据具体业务需求准备相应的输入数据。由于一个乘客对象包含多个属性,在进行诸如插入等操作时,如果逐个传递这些属性会显得繁琐且不易维护。因此可以将这些信息封装到一个特定的请求类req类)中。为什么不直接使用乘客类?由于对数据库进行不同操作的时候,所需要传入的参数是不同的,如果都是由乘客类,那么乘客类又承担了其他的业务操作,就感觉代码不那么的纯净。对于新增用户来说,这里设计的是传入的姓名,身份证和旅客类型,因此在Serivice层中还需要添加id,member_id和新增时间以及修改时间。将准备好的完整用户对象传递给Mapper层,通过MyBatis映射机制将其转换为SQL语句并执行插入操作。

    @Resource
    private PassengerMapper passengerMapper;
    public void save(PassengerSaveReq req) {
        DateTime now = DateTime.now();
        Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
        passenger.setMemberId(LoginMemberContext.getId());
        passenger.setId(SnowUtil.getSnowflakeNextId());
        passenger.setCreateTime(now);
        passenger.setUpdateTime(now);
        passengerMapper.insert(passenger);
    }

        Controller层主要负责处理外部请求并将它们转发给相应的Service层进行业务逻辑处理。处理完成后,Controller层会根据Service层的执行结果构造适当的响应返回给客户端。同理,由于不同方法返回值类型的不同,因此也可以将返回值封装成一个类,这里是Resp。第一次封装。在构建后端接口时,若针对同一数据模型的不同操作返回不同类型的结果,这会增加前端处理的复杂度。因此可以对所有后端接口的响应进行标准化封装,确保所有的接口返回统一的数据结构。这种可以简化了前端工作量,还提升了系统的可维护性和用户体验。第二次封装。换句话说,第一层是业务特定响应类。第二层是通用响应包装类

    @PostMapping("/save")
    public CommonResp<Object> save(@Valid @RequestBody PassengerSaveReq req) {
        passengerService.save(req);
        return new CommonResp<>();
    }

  @RequestBody 注解用于将HTTP请求的正文部分(通常是JSON或XML格式的数据)转换为一个Java对象。否则后端这里就会拿不到数据。同样的,为了增加用户输入的值是否为空,可以在请求类中增加@NotBlank(message = "【XXX】不能为空")。

乘车人查询用户

        由于乘车人是根据自己的id,即表中的member_id来查询为那些人购买了车票,因此在对对应的req类中只需要保留memberId即可。

public class PassengerQueryReq extends PageReq {
    private Long memberId;

    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PassengerQueryReq{");
        sb.append("memberId=").append(memberId);
        sb.append('}');
        return sb.toString();
    }
}

        对于乘车人来说,只能够查询到自己id购买的火车票,但是对于控制台来说,可以查询所有乘车人员的车票,由于查询功能类似,不过只是传入的参数不同而已,因此可以将两种查询合并成一中查询方法,由于查询返回的可能不止一个,为了增加通用性,返回值是一个List<PassengerQueryResp>。由于是查询,是将req转化为list,最后一行做的就是这个,可以称为拷贝。

    // 查询列表
    public List<PassengerQueryResp> queryList(PassengerQueryReq req) {
        PassengerExample passengerExample = new PassengerExample();
        PassengerExample.Criteria criteria = passengerExample.createCriteria();
        if(ObjectUtil.isNotNull(req.getMemberId())){
            criteria.andMemberIdEqualTo(req.getMemberId());
        }
        List<Passenger> passengerList= passengerMapper.selectByExample(passengerExample);
        return BeanUtil.copyToList(passengerList, PassengerQueryResp.class);
    }

由于是会员端,是根据自己的id去查询乘车人的信息,因此可以从登录界面去获取到id,根据自己登录的id进行查询,当然,他这里不能写道service层,如果写道service层,那么service层就是根据 id查询,但是我们为了更加的通用,将传入id写道controller层

    @GetMapping("/query-list")
    public CommonResp<List<PassengerQueryResp>> queryList(@Valid PassengerQueryReq req) {
        req.setMemberId(LoginMemberContext.getId());
        List<PassengerQueryResp> list = passengerService.queryList(req);
        return new CommonResp<>(list);
    }

乘车人编辑用户

前面提到,编辑可以和新增写道一起,因此只需要将save方法的代码进行修改,只需要判断参数是否为空即可。其他的不需要进行修改。

public void save(PassengerSaveReq req) {
        DateTime now = DateTime.now();
        Passenger passenger = BeanUtil.copyProperties(req, Passenger.class);
        if(ObjectUtil.isNull(passenger.getId())) {
            passenger.setMemberId(LoginMemberContext.getId());
            passenger.setId(SnowUtil.getSnowflakeNextId());
            passenger.setCreateTime(now);
            passenger.setUpdateTime(now);
            passengerMapper.insert(passenger);
        }else {
            passenger.setUpdateTime(now);
            passengerMapper.updateByPrimaryKey(passenger);
        }
    }

乘车人删除用户

删除就更加的简单,直接根据数据库中的id进行删除即可,不过多的解释。代码如下:

    public void delete(Long id) {
        passengerMapper.deleteByPrimaryKey(id);
    }
    
        @DeleteMapping("/delete/{id}")
    public CommonResp<Object> delete(@PathVariable Long id) {
        passengerService.delete(id);
        return new CommonResp<>();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值