与用户有关的接口

news2024/11/16 21:42:21

1.获取用户详细信息

跟着黑马程序员继续学习SpringBoot3+Vue3

用户登录成功之后跳转到首页,需要获取用户的详细信息

打开接口文档

使用Token令牌解析得到用户名

我们需要根据用户名查询用户,获取详细信息 

但是请求参数是无,由于都需要携带Token令牌, 可以解析Token令牌得到用户名。

打开UserController.java

在下面声明方法userInfo,返回类型Result<User>,添加注解,映射路径。想得到用户名就要声明一个String类型的Token,并且从请求头获取的。

发送请求

401?为什么?因为没有携带请求头,打开postman,携带请求头,再次发送就成功了

很多接口都需要添加请求头,为了测试方便,在postman中,可以给集合里所有的请求头统一添加请求头

回到响应数据里发现把password也给响应回来了

在user类里面,passward上面添加@JsonIgnore

作用:让springmvc把当前对象转换成Json字符串的时候,忽略password,最终json字符串中就没有password这个属性了

But! 我遇到了问题(未解决)

我加上了后,password还是在这里????!!!!为什么?!

先不理!!

我们发现后面两个时间为null?为什么?因为数据库里的命名和实体类里的不一样

配置yml文件中添加://开启驼峰命名和下划线命令的自动转换
mybatis:
  configuration:
    map-underscore-to-camel-case: true

发现已经有数据了

 2.优化获取用户详细信息的代码

 因为我们在拦截器里已经解析了Token,所以在用户获取详细信息时,不用再次解析Token了。

我们需要复用拦截器中的代码,那如何能做到呢 

使用ThreadLocal对象优化

作用:提供线程的局部变量

ThreadLocal

  • 使用set()/get()存取数据
  • 使用TreadLocal存储的数据,线程安全(与局部变量一样,每个线程自己玩自己的)
  • 用完记得清除数据(自定义remove方法)

 在Test里创建一个测试类ThreadLocalTest .java

package org.exampletest;

import org.junit.jupiter.api.Test;

public class ThreadLocalTest {
    @Test
    public void testThreadLocalSetAndGet() {
        //提供一个ThreadLocal对象(线程局部对象)
        ThreadLocal tl = new ThreadLocal();

        //开启两个线程
        new Thread(()->{
            tl.set("笑言");
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
        },"蓝色").start();

        new Thread(()->{
            tl.set("药尘");
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
            System.out.println(Thread.currentThread().getName()+":"+tl.get());
        },"绿色").start();

    }
}

与当前的需求有什么关系呢?

假如程序中有这几个

都有add的方法且都需要userId信息,我们就需要在每个里面都声明一个userId

使用ThreadLocal优化,可以维护一个全局的ThreadLocal tl对象存储用户名这类数据,有了这个对象,请求到达拦截器之后,就可以调用ThreadLocal对象的set()方法存储用户id.

所以当请求到达Controller,Service,Dao之后就可以使用tl.get()方法获取到这个用户id进行使用。

每个Controller,Controller,Service,Dao在容器当中都是单例的,我们怎么知道用户id是哪个呢?

 借助ThreadLocal完成两个事情:

  • 减少参数的传递
  • 在同一个线程间进行共享数据

UserController.java类

使用ThreadLocal对象获取用户id(为了使用方便,封装到工具类里),不用再次解析Token

    @GetMapping("/userInfo")
    public Result<User> userInfo(/*@RequestHeader(name="Authorization") String token*/){
        //根据用户名查询用户
       // Map<String,Object>map=JwtUtil.parseToken(token);
        
        Map<String,Object>map = ThreadLocalUtil.get();
        
        String username=(String)map.get("username");//map.get("username")是Object类型,我们知道存username是String,强转
        User user=userService.findByUserName(username);
        return Result.success(user);//把user响应给浏览器
    }

工具类

ThreadLocalUtil.java
package org.exampletest.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal 工具类
 */
@SuppressWarnings("all")
public class ThreadLocalUtil {
    //提供ThreadLocal对象,
    private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();

    //根据键获取值
    public static <T> T get(){
        return (T) THREAD_LOCAL.get();
    }
	
    //存储键值对
    public static void set(Object value){
        THREAD_LOCAL.set(value);
    }


    //清除ThreadLocal 防止内存泄漏
    public static void remove(){
        THREAD_LOCAL.remove();
    }
}

在拦截器里把业务数据存储到ThreadLocal中,并且需要在请求完成之后清除数据,防止内存泄漏
  //把业务数据存储到ThreadLocal中
            ThreadLocalUtil.set(claims);

完整代码:

package org.exampletest.interceptors;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.exampletest.pojo.Result;
import org.exampletest.utils.JwtUtil;
import org.exampletest.utils.ThreadLocalUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        //令牌验证
        String token=request.getHeader("Authorization");

        //验证token
        try{
            Map<String, Object> claims= JwtUtil.parseToken(token);
            //把业务数据存储到ThreadLocal中
            ThreadLocalUtil.set(claims);
            return true;
        }catch (Exception e){
            response.setStatus(401);
            //不放行
            return false;
        }
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception{
        //移除ThreadLocal中的数据
        ThreadLocalUtil.remove();
    }
}

 3.更新用户基本信息

 查看接口文档

得到请求路径,请求方式,请求参数,响应数据等

实现思路

在UserController中添加一个方法,方法上添加注解@PutMapping("/update"),因为这个方法是put请求方式。

浏览器将来会给我们提供id,nickname,email这样的数据并且是在请求体中以json格式给我们携带过来的,所以就把这些数据封装到一个实体类对象User里面进行接收。为了让我们的框架能够自动的把请求体里面的json数据转换成一个实体类对象,需要在参数前面添加一个注解@RequestBoby

 @PutMapping("/update")
    public Result update(@RequestBody User user){
        userService.update(user);
        return Result.success();
    }

接下来在方法体内,只需要调用service层的方法完成更新就可以了,所以service层也要提供对应的更新的相关方法,在mapper层也要执行对应的sql(username,用户不能进行修改;updatetime更新时间也要进行修改)

service层:

void update(User user);

实现接口:UserServiceImpl.java

   @Override
    public void update(User user) {
        user.setUpdateTime(now());
        userMapper.update(user);
    }

mapper层

 @Update("update user set nickname=#{nickname},email=#{email},update_time=#{updateTimme} where id=#{id}")
    void update(User user);

在Body里面添加 

 

遇到的问题?(为解决版)

数据库中user表: 

参数校验 

 

我们把请求的参数封装到一个实体类对象user里面

对实体参数完成校验

1.在实体类成员变量上添加 Validation提供的注解,对指定的属性值完成校验

 2.添加完指定注解之后,在实体类参数前添加注解@Validated(使得实体类中属性上的注解生效)

    @PutMapping("/update")
    public Result update(@RequestBody @Validated User user){
        userService.update(user);
        return Result.success();
    }

 此时校验已经生效了(虽然我遇到了问题,但是请求是成功的)

 

4.更新用户头像

 接口文档

实现

 需要从RequestParam里面获取到这个数据

 

@URL校验是不是一个url地址

参数里没有id,而sql语句中需要根据用户名进行查询,使用拦截器解析得的,ThreadLocal中的数据

    @PatchMapping("/updateAvatar")
    public Result updateAvatar(@RequestParam  @URL String avatarUrl){
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer id = (Integer) map.get("id");
        userService.updateAvatar(avatarUrl,id);
        return Result.success();
    }

 service层

//更新头像
    void updateAvatar(String avatarUrl,Integer id);

 实现接口.Impl

  @Override
    public void updateAvatar(String avatarUrl, Integer id) {
        userMapper.updateAvatar(avatarUrl,id);
    }

mapper层

  @Update("update user set user_pic=#{avatarUrl},update_time=now() where id= #{id}")
     void updateAvatar(String avatarUrl, Integer id) ;

5.更新用户密码

 接口文档

实现

 在UserController里添加一个方法,方法上添加@PatchMapping("/updatePwd")指定访问的路径

 方法上需要声明一个Map类型的参数params,用来接收前端提交的json参数。

在前面更新用户信息时,也接收json参数,当时是声明一个user实体对象来接收。当时传递的json数据中的键名和实体类属性名一样。

现在请求参数中键名是old_pwd,new_pwd,re_pwd等,没有和实体类属性名一致,所以需要声明一个map集合来接收参数,到时候MVC框架会自动帮我们把json数据转换成map集合对象

添加@RequestBodyMVC框架才会自动读取请求体里面的数据,然后转换成map集合对象

 @PatchMapping("/updatePwd")
    public Result updatePwd(@RequestBody Map<String,String> params){
    //1.校验参数,没有提供相应的注解能满足,需要手动校验参数
        String oldPwd=params.get("old_pwd");
        String newPwd=params.get("new_pwd");
        String rePwd =params.get("re_pwd");
        if(!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)){
            return Result.error("缺少必要的参数");
        }
        //原密码是否正确
        //根据用户名查询用户拿到密码
        Map<String,Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User loginUser = userService.findByUserName(username);
       if(! loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
           return Result.error("原密码不正确");
       }
       //校验newPwd与rePwd是否一致
        if(!newPwd.equals(rePwd)){
            return Result.error("两次输入的新密码不一致");
        }
    //2.调用service完成密码更新
        Integer id = (Integer) map.get("id");
        userService.updatePwd(newPwd,id);
        return Result.success();
    }
//更新密码
    void updatePwd(String newPwd,Integer id);
   @Override
    public void updatePwd(String newPwd, Integer id) {
       usermapper.updatePwd(Md5Util.getMD5String(newPwd),id);
    }
@Update("update user set password=#{md5String},update_time=now() where id=#{id}")
    void updatePwd(String md5String, Integer id);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1975395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

标题生成器:开启创意写作的新篇章

文章目录 角色与目标标题生成器的功能标题生成器的优势指导原则限制与澄清应用场景对创意写作的影响智能体发布到微信公众号配置公众号菜单配置自动回复自动回复文本链接自动回复二维码图片 标题生成器的未来发展总结 博主介绍&#xff1a;全网粉丝10w、CSDN合伙人、华为云特邀…

C++入门基本语法(1)

一、命名空间namespace 定义变量、函数时&#xff0c;定义的名称可能会和头文件中或者自己重复使用的名称冲突&#xff1b;namespace可以对标识符的名称进行本地化&#xff0c;以避免冲突的问题&#xff1b; ## 例如&#xff1a; ## 出现这种问题的原因&#xff1a; &#x…

MySQL系列之--详细安装教程和启动方法

文章目录 安装教程打开或关闭方式方式1&#xff1a;方式2&#xff1a; 客户端连接方式客户端连接方式1&#xff1a;客户端连接方式2&#xff1a;MySQL环境变量的配置 安装教程 1、mysql官网下载最新的符合本系统的版本 2、点击.msi文件进入安装页面 选择默认的选项开发者安…

品味食家巷蛋奶酪饼,感受西北美食魅力

在广袤的西北大地&#xff0c;美食的丰富多样令人叹为观止。而食家巷蛋奶酪饼&#xff0c;宛如一颗璀璨的明珠&#xff0c;散发着独特的魅力。 这款蛋奶酪饼&#xff0c;是传统工艺与现代口味的完美融合。而当你继续品尝&#xff0c;鸡蛋的鲜嫩和奶酪的浓郁醇厚便会在口中交融…

跟《经济学人》学英文:2024年08月03日这期 GPT, Claude, Llama? How to tell which AI model is best

GPT, Claude, Llama? How to tell which AI model is best Beware model-makers marking their own homework 原文&#xff1a; When Meta, the parent company of Facebook, announced its latest open- source large language model (LLM) on July 23rd, it claimed that…

vue2 使用 tinymce富文本编辑器

注意&#xff1a; 在vue2中使用tinymce有版本限制的&#xff0c;最新版都是支持v3的&#xff0c;官方也说明了&#xff1b; vue2中不能使用tinymce/tinymce-vue 为4以上的版本&#xff1b; 使用步骤&#xff1a; 1、vue项目中安装 tinymce&#xff1b; npm install tinymce5.…

用TensorFlow训练自己的第一个模型

现在学AI的一个优势就是&#xff1a;前人栽树后人乘凉&#xff0c;很多资料都已完善&#xff0c;而且有很多很棒的开源作品可以学习&#xff0c;感谢大佬们 项目 项目源码地址 视频教程地址 我在大佬的基础上基于此模型还加上了根据特征值缓存进行快速识别的方法&#xff0c;…

【教程】Python语言的地球科学常见数据——全球大气再分析数据

a、多年数据的读取 b、趋势分析 c、多时间尺度统计。 ECMWF 中心推出的 ERA5 全球大气再分析数据提供了大量大气、陆地和海洋气候变量的逐小时数据。这些数据在 30km 网格上覆盖了全球&#xff0c;在时间跨度上从 1979 至今。该数据能够提供全球范围的格点气象数据。 将针对该…

react-native从入门到实战系列教程一Switch组件和StatusBar的运用

跨平台通用的组件。这是一个受控组件&#xff0c;你必须使用onValueChange回调来更新value属性以响应用户的操作。如果不更新value属性&#xff0c;组件只会按一开始给定的value值来渲染且保持不变&#xff0c;看上去就像完全点不动。 实现效果 代码实现 import {View, Text,…

力扣hot100-二叉树

文章目录 概要二叉树的基本概念常见的二叉树类型常用的二叉树遍历二叉树的常用技巧 题目&#xff1a;二叉树的中序遍历方法1--递归遍历方法2--使用栈 概要 二叉树&#xff08;Binary Tree&#xff09;是一种树形数据结构&#xff0c;其中每个节点最多有两个子节点&#xff0c;…

DC-2靶机试试看 继续打靶!!冲冲冲!!

要更改一下自己的host&#xff0c;这样才可以正确的访问我们的靶机的页面。 下面看看我的思路吧&#xff1a; 前面还是老样子&#xff0c;先发现靶机的ip地址以及收集他开放了哪些端口等等的信息 查看相对应的cms 我用了一些msf的模块没有打下来这个站点 收集相关的信息&…

【计算机人接私活】手把手教你上手挖到第一个漏洞,从底薪3k到月入过万,只有一步之遥!

计算机人想接靠谱的私活&#xff1f;看这篇&#xff01; 暑假想做兼职赚生活费&#xff1f;看这篇&#xff01; 挖漏洞找不到门路&#xff1f;看这篇&#xff01; 挖漏洞必备工具 Up入行网安多年&#xff0c;一直在探索副业项目。 从最初的月薪5k&#xff0c;到现在一个漏…

[米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-01 以太网协议介绍

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

SpringBoot 3的两种SPI加载方式

从spring boot 2.7.0发布后&#xff0c; 自动配置类的加载方式就发生了改变&#xff0c;原来从META-INF/spring.factories文件中加载&#xff0c;变为了从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中加载&#xff0c;对应的加载实…

Ubuntu下python3.12安装, 分布式 LLM 推理 exo 安装调试过程, 运行自己的 AI 集群

创作不易 只因热爱!! 热衷分享&#xff0c;一起成长! “你的鼓励就是我努力付出的动力” —调试有点废,文章有点长,希望大家用心看完,肯定能学废,感谢. 1. Ubuntu下python3.12安装 1.1 导入 Python 的稳定版 PPA,不用编译 sudo add-apt-repository ppa:deadsnakes/ppa sudo…

82.WEB渗透测试-信息收集-框架组件识别利用(6)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;81.WEB渗透测试-信息收集-框架组件识别利用&#xff08;5&#xff09; log4j/log4j2&…

《Excelize权威指南》新书发布

在数据洪流涌动的数字化时代&#xff0c;数据处理与分析已跃升为解锁无限洞察力的金钥匙&#xff0c;赋能商业智慧、重塑医疗健康版图、驱动教育科研创新。然而&#xff0c;当数据量级爆炸式增长&#xff0c;传统工具如 Excel 虽被誉为数据处理领域的常青树&#xff0c;其手动操…

modelsim仿真quartus IP

开发环境&#xff1a;quartus prime pro 20&#xff1b;modelsim se-64 10.6d 1. 生成Altera的IP库 使用quartus生成IP库&#xff0c;需要使用Simulation Library Compiler&#xff08;Tools->Launch Simulation Library Compiler&#xff09; 如下图操作&#xff0c;选择…

车载音频开发(一):从看懂wav开始

背景介绍&#xff1a;随着电车的发展势头迅猛&#xff0c;国内车载音频也成为电车火热宣称的势头&#xff0c;要想深入了解车载音频&#xff0c;那首先还是得从最为普通的音频文件WAV开始。 我们都知道&#xff0c;计算机只能存储数字&#xff0c;声音确实靠不同频率的波组成&a…