做一个springboot用户信息模块

目录

用户信息部分

1、获取用户详细信息

前言

代码分析

代码实现 

测试

 2、更新用户信息

前言

代码实现

测试

3、更新用户头像

前言

代码实现

测试

4、更新用户密码

前言

代码实现

测试


用户信息部分

1、获取用户详细信息

前言

承接上一篇博客登录注册功能实现

        由于我们的数据库字段是下划线命名的creat_time,而实体类中对应的是creatTime,字段不一致无法直接获取。

因此需要在yml配置文件中开启驼峰命名

mybatis:configuration:mapUnderscoreToCamelCase: true

        既然要获取用户的详细信息,所以会自然的想到在controller中写一个/info接口,然后在service中调用mapper,mapper再调数据库,这样也没有错。但是我们再学习token的时候就说过了,token本身就是由用户的各种信息组成的,所以其实我们直接从token获取用户信息就行了,这样效率更高代码更少。

代码分析

        首先由于token中包含了用户的各种信息,所以默认也会包含密码在内,但是我们不希望在响应的时候把密码也解析出来,这是很不安全的,因此我们需要使用一个注解@JsonIgnore

@JsonIgnore:让springmvc把当前对象转换为json字符串的时候,忽略掉该注解作用的字段,最终的json中就没有这个字段了

        其次我们在创建拦截器的时候就对令牌进行了一次解析响应,虽然我们在使用的时候也可以重新写一遍解析jwt,但是既然已经被解析过了,我们还是直接去拦截器中取比较好,这样显得比较专业和逼格。为此我们需要使用到ThreadLocal

ThreadLocal:提供线程变量

  • 用来存储数据:get()和set()
  • 使用ThreadLocal存储的数据,线程安全

        线程安全就是说假如我们直接使用一个全局静态变量才存储变量,那么两个不同的线程同时会对这一个变量进行操作,数据就会错乱。但是使用ThreadLocal就可以保证不同的线程中只使用到自己的变量,不会互相串数据        

代码实现 

ThreadLocalUtil工具类,这个类是为了让我们更方便的使用ThreadLocal。其中我们声明了一个全局的静态变量THREAD_LOCAL,可以对其进行set值和get值,还有一个remove方法是因为它的生命周期很长,为了防止内存泄漏要在一次线程完成时把这个变量的值删掉

/*** 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();}
}

优化拦截器 ,相比上次写的多了一个afterCompletion方法,这个方法也是顾名思义在目标方法执行后它再执行

@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取令牌String token = request.getHeader("Authorization");//验证tokentry {Map<String,Object> claims = JwtUtil.parseToken(token);//将解析的token信息放入ThreadLocalThreadLocalUtil.set(claims);//没有异常就放行return true;} catch (Exception e) {//未登录,不放行response.setStatus(401);return false;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//清空ThreadLocal的数据ThreadLocalUtil.remove();}
}

 Controller

        可以直接这里面获取ThreadLocal的值,之前往里存放的是什么类型的值就用什么类型接收就行了。

@RestController
@RequestMapping("/article")
public class ArticleController {@Autowiredprivate UserService userService;@GetMapping("/list")public Result<User> list(){Map<String,Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User user = userService.findByUserName(username);return Result.success(user);}
}

测试

发起请求

 2、更新用户信息

前言

        使用者在前端修改用户的个人信息,发送到后端。我们接收过来的就是一个User对象,但是spring无法直接识别一个对象类,所以我们需要使用注解@RequestBody。

        其次就是参数校验,实际上这个功能是要在前端完成的,不过我们在后端也写一下吧。我们之前在注册模块对密码进行过检验,让他限定在5~16位。使用Spring Validation,在需要被校验的参数前加上@Pattern(regexp = "^正则表达式$"),在需要生效的地方加上@Validated就完成了。

代码实现

user实体类,直接在类上加上注解即可参数校验

测试

数据校验

3、更新用户头像

前言

因为头像只是更新用户信息中的一部分,所以使用PATCH请求方式

avaterUrl是头像的地址,一般都存放在阿里云中

代码实现

controller

@URL是数据校验是否是一个url格式的字符串,防止胡乱上传

    @PatchMapping("/updateAvatar")public Result updateAvatar(@RequestParam @URL String avatarUrl){userService.updateAvatar(avatarUrl);return Result.success(avatarUrl);}

service

直接从mapper中获取当前登录人token中的id

    @Overridepublic void updateAvatar(String avatarUrl) {Map<String,Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("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);

测试

4、更新用户密码

前言

        同样地,更新密码也是用户信息整体的一部分,所以用PATCH请求方式

        在之前我们更新用户基本信息的时候,传递的参数是一个user实体类参数,且json字段名和user属性名一摸一样。但是在更新密码中,有一个new_pwd和old_pwd来表示新密码和旧密码,user类中就没有这个属性了,添加进去在逻辑上也不太合适。所以我们可以通过传递一个map集合来表示这个参数。

        由于我们的密码在数据库中已经经过了MD5加密,所以直接拿传递过来的参数与数据库中的密码比对是不行的,可以先对参数进行MD5加密,然后在与数据库数据进行比对检验是否正确。

代码实现

Controller

    @PatchMapping("/updatePwd")public Result updatePwd(@RequestBody Map<String,String> params){//校验参数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("原密码错误");}//比较新密码和重复新密码是否正确if (!rePwd.equals(newPwd)){return Result.error("两次填写的新密码不一样");}//调用service完成密码更新userService.updatePwd(newPwd);return Result.success();}

Service

    @Overridepublic void updatePwd(String newPwd) {Map<String,Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");userMapper.updatePwd(Md5Util.getMD5String(newPwd),id);}

Mapper

    @Update("update user set password=#{newPwd},update_time=now() where id = #{id} ")void updatePwd(String newPwd,Integer id);

测试

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis】redis的下载安装

目录 1.window安装 2.Linux安装 下载 解压 移动redis目录 编译 1.window安装 在github 下载redis的安装包 https://github.com/microsoftarchive/redis/releases 下载完后安装相应的目录下&#xff0c;比如我是放在c盘的Program Files下 开启redis&#xff0c;双击运行…

前端NaN解决方案

// 2.3 函数表达式可以传递参数还可以有返回值&#xff0c;使用方法和前面具名函数类似let sum function (x, y) { // 形参xx||0yy||0return x y}let re sum() // 实参console.log(re) // 3 function sum(x 0, y 0) {return x y}console.log(sum()) // 0console.log(s…

tcpdump抓包的字节数量与ethtool统计数据不同的原因

情况介绍 在进行RDMA抓包流量分析时&#xff0c;我使用ethtool工具统计了RDMA网卡的流量发送数据数量&#xff0c;然后使用tcpdump进行抓包。 经过分析发现&#xff0c;tcpdump得到的数据数量总是大于ethtool得到的数据数量&#xff0c;而且每个数据包会多出4个字节。 分析 …

Amazon Bedrock | 大语言模型CLAUDE 2体验

这场生成式AI与大语言模型的饥饿游戏&#xff0c;亚马逊云科技也参与了进来。2023年&#xff0c;亚马逊云科技正式发布了 Amazon Bedrock&#xff0c;是客户使用基础模型构建和扩展生成式AI应用程序的最简单方法&#xff0c;为所有开发者降低使用门槛。在 Bedrock 上&#xff0…

【HttpRunnerManager】搭建接口自动化测试平台实战

一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和配置、mysql 安装和配置 2. python: django 配置、uwsgi 配置 二、我搭建的环境 1. Centos7 &#xff08;配置 rabbitmq、mysql 、Supervisord&#xff09; 2. python 3.6.8 &#xff08;配置 django、uwsgi&am…

Semantic Kernel 学习笔记1

1. 挂代理跑通openai API 2. 无需魔法跑通Azure API 下载Semantic Kernel的github代码包到本地&#xff0c;主要用于方便学习python->notebooks文件夹中的内容。 1. Openai API&#xff1a;根据上述文件夹中的.env.example示例创建.env文件&#xff0c;需要填写下方两个内…

Day02_《MySQL索引与性能优化》

文章目录 一、SQL执行顺序二、索引简介1、关于索引2、索引的类型Btree 索引Btree 索引 三、Explain简介四、Explain 详解1、id2、select_type3、table4、type5、possible_keys6、key7、key_len8、ref9、rows10、Extra11、小案例 五、索引优化1、单表索引优化2、两表索引优化3、…

C语言--从键盘输入当月利润I,求应发奖金总数。

题目描述&#xff1a; 企业发放的奖金根据利润提成。利润I低于或等于100000元的&#xff0c;奖金可提成10%; 利润高于100000 元&#xff0c;低于200000元(1000001000000时&#xff0c;超过1000000元的部分按 1%提成。从键盘输入当月利润I,求应发奖金总数。 int main() {int m…

Prim算法(C++)

目录 介绍&#xff1a; 代码&#xff1a; 结果&#xff1a; 介绍&#xff1a; Prim算法是一种用于解决最小生成树问题的贪心算法。该算法的主要思想是从一个顶点开始&#xff0c;不断向图中添加边&#xff0c;直到构成一棵包含所有顶点的生成树&#xff0c;使得树的边权之…

react 修改less文件后保存,内存溢出,项目崩溃问题解决

一、完整报错 一个很老的react项目&#xff0c;因为没有package-lock.json版本锁&#xff0c;导致拉下来的时候&#xff0c;安装的依赖版本冲突&#xff0c;好不容易启动起来&#xff0c;修改less文件后只要一保存&#xff0c;项目就会崩溃&#xff0c;需要重启&#xff0c;报…

NSF服务器

目录 1.简介 1.1 NFS背景介绍 1.2 生产应用场景 2.NFS工作原理 2.1 实例图 2.2 流程 3.NFS的使用 3.1.安装 3.2.配置文件 3.3.主配置文件分析 3.4 实验 服务端&#xff1a; 客户端&#xff1a; 3.5.NFS账户映射 3.5.1.实验2 3.5.2.实验3 4.autofs自动挂载服务…

使用微信小程序控制蓝牙小车(微信小程序端)

目录 使用接口界面效果界面设计界面逻辑设计 使用接口 微信小程序官方开发文档 接口说明wx.openBluetoothAdapter初始化蓝牙模块wx.closeBluetoothAdapter关闭蓝牙模块(调用该方法将断开所有已建立的连接并释放系统资源)wx.startBluetoothDevicesDiscovery开始搜寻附近的蓝牙…