YangeIT大约 12 分钟中州养老AIIOT版本MysqlApifoxServletHTTPGETPOST

1. 接口开发

1.1 JWT令牌 🍐

前言

image
image
image
image

接下来,我们来学习Token

JWT全称:JSON Web Token (官网:https://jwt.io/)open in new window

  • 定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

    简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。

    自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}

  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}

  • 第三部分:Signature(签名)防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

    签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

image-20230106085442076
image-20230106085442076

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码

Base64🚀:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号

需要注意的是Base64是编码方式,而不是加密方式。

使用JWT令牌时需要注意:

  • JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥配套的。
  • 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法

JWT令牌最典型的应用场景就是登录认证 👇

image
image

代码操作

1. 生成JWT令牌

简单介绍了JWT令牌以及JWT令牌的组成之后,接下来我们就来学习基于Java代码如何。

image
image

直接使用代码中的工具类进行验证:

image
image

运行测试方法:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwidXNlcklkIjoxLCJleHAiOjE3NTMzNTQyMjR9.SDxuyOw01ttNC8TBWbjALfmpXqDa9ifS3JVPxkcJb74

输出的结果就是生成的JWT令牌,,通过英文的点分割对三个部分进行分割,我们可以将生成的令牌复制一下,然后打开Jwt解析网站(https://www.json.cn/jwtopen in new window),将生成的令牌直接放在Encoded位置,此时就会自动的将令牌解析出来。

image
image

第一部分解析出来,看到JSON格式的原始数据,所使用的签名算法为HS256。

第二个部分是我们自定义的数据,之前我们自定义的数据就是id,还有一个exp代表的是我们所设置的过期时间。

由于前两个部分是base64编码,所以是可以直接解码出来。但最后一个部分并不是base64编码,是经过签名算法计算出来的,所以最后一个部分是不会解析的。

你可删除一点最后一段字母,观察解析结果的变化

2. 校验JWT令牌(解析生成的令牌)

实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):

@Test
public void parseJwt(){
    Claims claims = Jwts.parser()
        .setSigningKey("itheima")//指定签名密钥(必须保证和生成令牌时使用相同的签名密钥)  
     .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk")
        .getBody();

    System.out.println(claims);
}

运行测试方法:

{id=1, exp=1672729730}

令牌解析后,我们可以看到id和过期时间,如果在解析的过程当中没有报错,就说明解析成功了。

下面我们做一个测试:将Token进行修改,观察是否解析失败:

image
image

结论: 篡改令牌中的任何一个字符,在对令牌进行解析时都会报错,所以JWT令牌是非常安全可靠的。

3. 测试令牌过期

我们继续测试:修改生成令牌的时指定的过期时间

image
image

总结

课堂作业

  1. jwt的组成部分?🎤
  2. JWT是如何将原始的JSON格式数据,转变为字符串的呢?🎤
  3. JWT令牌是非常安全可靠的,从何谈起?🎤

1.2 JWT集成代码中 ✏️ 🍐

JWT集成登陆模块

JWT令牌的生成和校验的基本操作我们已经学习完了,接下来我们就需要在案例当中通过JWT令牌技术来跟踪会话。具体的思路我们前面已经分析过了,主要就是两步操作: 👇 👇

  1. 生成令牌
    • 在登录成功之后来生成一个JWT令牌,并且把这个令牌直接返回给前端 👈
  2. 校验令牌
    • 拦截前端请求,从请求中获取到令牌,对令牌进行解析校验

代码实现

下图是登录成功后返回的token image

下图是每次请求的时候小程序携带的token

image
image

再次一次看下流图:

image
image

下面结合获取房型的代码,分析下如何获得JWT令牌中的数据: 👇

  1. 由小程序的请求截图可知,在请求头上有个的authorization字段,这个字段的值就是token,我们通过这个字段的值就可以获取到token。
  2. 那如何获得请求头尼?需要获取请求协议对象,如下图:👇
image
image

测试图如下:

image
image

总结

课堂作业

  1. 通过上述的讲解,我们知道了如何在代码中获取JWT令牌中的数据?🎤

1.3. 绑定家人 ✏️

绑定家人

请求截图
请求截图
添加失败截图
添加失败截图

绑定的家人必须是已经在住的老人,这样才可以看到老人的信息,考虑到管理后端还没有写,因此绑定的老人需要从下列的列表中进行填写 👇

其中称呼,可以随便写,如叔叔,义父,爷爷等等,只要不是老人本人就行,因为老人本人是看不到这个列表的,只有家属可以看到。

序号姓名身份证
1刘备110123195001016688
2关羽110123195101016688
3刘爱国132112196712137788
4张飞110123195201016688
5码云132122194812052345
6张芳132123195208121235

用户添加家人,需要搞清楚数据库表关系:多对多的关系,因此需要三张表,一张是老人表,一张是家属表,还有一个中间表,用于存储老人和家属的关系。 👇

image
image

也就是说,绑定老人,其实是添加老人和家属的关系,往中间表中(family_member_elder)添加数据.

接下来,我们来分析下流程: 👇

image
image

好了,接下来来看下接口信息:👇

  • 请求路径:http://127.0.0.1:9995/customer/user/add
  • 请求方式:POST
  • 参数类型:application/json
  • 请求参数:
{
  "idCard": "110123195001016688",
  "name": "刘备",
  "relation": "义父"
}
  • 请求参数说明:
参数名类型是否必填说明
idCardString老人身份证号
nameString家属姓名
relationString家属与老人的关系
  • 返回值类型:application/json
  • 返回值:
{
  "code": 200,
  "msg": "操作成功",
  "data": null
}
  • 返回值说明:
参数名类型说明
codeInteger状态码
msgString消息
dataObject数据

核心代码如下:👇

1. Controller代码如下:👇

@RestController
@RequestMapping("/customer/user")
@Api(tags = "老人家属的接口")
public class FamilyMemberController {
@Autowired
ElderMapper elderMapper;
@Autowired
FamilyMemberElderMapper familyMemberElderMapper;

/**
 * 新增客户老人关联记录
 * @param memberElderDto 客户老人关联 DTO
 * @return 操作结果
 */
@PostMapping("/add")
@ApiOperation(value = "新增客户老人关联记录")
public AjaxResult add(@RequestBody MemberElderDto memberElderDto, HttpServletRequest request) {
    //根据身份证号查询老人
    QueryWrapper<Elder> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("id_card_no",memberElderDto.getIdCard());
    Elder elder = elderMapper.selectOne(queryWrapper);

    //判断老人是否存在
    if(ObjectUtil.isEmpty(elder)){
        return   AjaxResult.error("该老人未入住,请检查输入信息");
    }

    //当前登录人
----这里代码需要自己补充start--



----这里代码需要自己补充start--


    //判断是否已经绑定
    QueryWrapper<FamilyMemberElder> queryWrapper2 = new QueryWrapper<>();
    queryWrapper2.eq("elder_id",elder.getId());
    queryWrapper2.eq("family_member_id",userId);
    long count = familyMemberElderMapper.selectCount(queryWrapper2);

    if(count > 0){
        return   AjaxResult.error("该老人已绑定,请勿重复绑定");
    }


    //保存家属与老人的关系
    FamilyMemberElder familyMemberElder = BeanUtil.toBean(memberElderDto, FamilyMemberElder.class);
    familyMemberElder.setElderId(elder.getId());
    familyMemberElder.setFamilyMemberId(Long.valueOf(userId));
    familyMemberElder.setCreateTime(new Date());
    familyMemberElderMapper.insert(familyMemberElder);

    return AjaxResult.success();
}}




























 
 
 
 
 






















2. 因为mapper中都有现成的方法,因此不需要写,直接调用即可。

3.测试截图:

image
image
image
image

总结

课堂作业

  1. 参考上述逻辑和流程图,完成绑定家人的功能,可以参考上述的代码🎤

完成后,将练习代码截图提交到任务平台,直接作为实训分数!(http://taskshare.yangeit.cn:21016/)open in new window

1.4. 家人列表 ✏️

前言

接下来完成家人列表的功能,如下:👇 image

开发功能前,先阅读接口文档,了解请求和响应数据格式,如下:👇

  • 请求路径:/customer/user/list-by-page
  • 请求方式:GET
  • 请求参数:/customer/user/list-by-page?pageNum=1&pageSize=10
  • 响应数据:application/json
  • 响应数据格式:
{
    "msg": "操作成功",
    "code": 200,
    "data": [
        {
            "mid": "17",//用户id
            "mremark": "义父",//备注
            "elderId": "3",//老人id
            "name": "张飞",//老人姓名
            "image": "https://itheim.oss-cn-beijing.aliyuncs.com/6528514b-e7db-468d-8aeb-590d3102125b.png",//头像
            "bedNumber": "303-1",//床号
            "typeName": "豪华单人间",//房间类型
            "iotId": "dHMuAjTk1D9scHXtmpvrk1bok0",//设备id
            "deviceName": null,//设备名称
            "productKey": null//产品key
        }
    ]
}

通过接口文档的返回值可知,内容需要涉及到多多张表,因此需要使用到多表查询,如下:👇

image
image

sql语句如下:查询的字段和实体类需要一一对应 👇

select m.id     as mid
      , m.remark as mremark
      , m.elder_id
      , e.name
      , e.image
      , e.bed_number
from family_member_elder m
          left join elder e on m.elder_id = e.id
where m.family_member_id  = 家属用户ID

Controller代码如下:👇

@GetMapping("/list-by-page")
@ApiOperation(value = "查询客户老人关联记录")
public AjaxResult listByPage(Integer pageNum, Integer pageSize,HttpServletRequest request) {
    //1.从请求头中获取当前userId
  -----这里代码需要自己补充start--



  -----这里代码需要自己补end---

    //2.通过多表查询出MemberElderVo列表
    List<MemberElderVo> memberElders = familyMemberElderMapper.listByPage(userId);
    //补点假数据,后期来真的数据
    memberElders.forEach(memberElder -> {
        memberElder.setTypeName("豪华单人间");
        memberElder.setIotId("dHMuAjTk1D9scHXtmpvrk1bok0");
    });

    //3.返回数据
    return AjaxResult.success(memberElders);
}




 
 
 
 
 












FamilyMemberElderMapper代码如下:

@Mapper
public interface FamilyMemberElderMapper extends BaseMapper<FamilyMemberElder> {

    List<MemberElderVo> listByPage(Integer userId);
}

FamilyMemberElderMapper映射文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.yangeit.mapper.FamilyMemberElderMapper">

    <resultMap id="BaseResultMap" type="cn.yangeit.pojo.FamilyMemberElder">
            <id property="id" column="id" jdbcType="BIGINT"/>
            <result property="familyMemberId" column="family_member_id" jdbcType="BIGINT"/>
            <result property="elderId" column="elder_id" jdbcType="BIGINT"/>
            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
            <result property="createBy" column="create_by" jdbcType="BIGINT"/>
            <result property="updateBy" column="update_by" jdbcType="BIGINT"/>
            <result property="remark" column="remark" jdbcType="VARCHAR"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,family_member_id,elder_id,
        create_time,update_time,create_by,
        update_by,remark
    </sql>

    <select id="listByPage" resultType="cn.yangeit.vo.MemberElderVo">
        select m.id     as mid
             , m.remark as mremark
             , m.elder_id
             , e.name
             , e.image
             , e.bed_number
        from family_member_elder m
                 left join elder e on m.elder_id = e.id
        where m.family_member_id  = #{memberId}
    </select>
</mapper>
























 
 
 
 
 
 
 
 
 
 
 


写完逻辑后,进行重新启动项目测试如下:👇 image

总结

课堂作业

  1. 参考上述完成家人列表功能🎤

完成后,将练习代码截图提交到任务平台,直接作为实训分数!(http://taskshare.yangeit.cn:21016/)open in new window

1.5. 解绑家人 ✏️

前言

好了已经完成绑定家人,家人列表,接下来就是解绑家人了,解绑家人需要提供家人ID,然后进行解绑,解绑后,家人列表中就不再显示该家人了。

image
image

老规矩,我们先从接口文档中获取接口信息:👇

  • 请求路径:/customer/user/deleteById
  • 请求方式:delete
  • 请求参数:/customer/user/deleteById?id=17
  • 响应数据:application/json
  • 响应数据格式:
{
    "msg": "操作成功",
    "code": 200,
    "data": null
}

Controller代码如下:👇

@DeleteMapping("/deleteById")
@ApiOperation(value = "根据id删除客户老人关联记录")
public AjaxResult deleteById(@RequestParam Long id) {
    int result = familyMemberElderMapper.deleteById(id);
    //判断是否删除成功 result是影响行数
    return result>0?AjaxResult.success():AjaxResult.error();

}

删除方法Mp已经实现类,所以直接调用即可。重启后测试一下

image
image

总结

课堂作业

  1. 完成家人解绑功能🎤

完成后,将练习代码截图提交到任务平台,直接作为实训分数!(http://taskshare.yangeit.cn:21016/)open in new window