SpringBoot实战第二天

今日战报

继续完善用户相关接口开发:

        1.完成获取用户信息功能

        2.完成更新用户信息功能

        3.完成更新用户头像功能

        4.完成更新用户密码功能

获取用户信息

接口文档

如接口文档所示,我们需要做的就是从header中的Authorization中读取token,解码后返回用户的全部信息,接口如下:

    @GetMapping("/userInfo")public Result<User> userInfo(@RequestHeader(name = "Authorization") String token){Map<String,Object> map = JwtUtil.parseToken(token);String username = (String) map.get("username");User user = userService.getByUserName(username);return Result.success(user);}

 这是运行结果

这里会发现一个问题,我们返回的数据中有经过加密的用户密码,这显然是不合适的,所以我们需要解决这个问题,Spring也给我们提供了用于解决这个问题的注解

    @JsonIgnore//SpringMVC把当前对象转换为json字符串时,忽略password,最终的json字符串中就没有password

把这行注解加到user实体类中的password变量声明的上方即可

还有一个小问题,我们在数据库中对于时间的名称使用的是_,例如创建时间create_time,而在实体类中使用的却是驼峰法,这样会导致mybatis从数据库中接收出的时间数据为null(上图是我解决了这个问题后截的),我么们需要在yml配置文件中解决这个问题

mybatis:configuration:map-underscore-to-camel-case: true #开启驼峰命名和下划线命名的自动转换

ThreadLocal

提供线程局部变量

        用来存取数据:set()/get()

        使用ThreadLocal存储的数据,线程安全

在ThreadLocal中,每个线程get到的数据只能是它自身set的,是读取不到其他线程set的数据的

而在TomCat运行时会给每个用户提供一个单独的线程,故可以通过ThreadLocal来在拦截器中set我们需要的信息,再去对应的接口中get信息,形成同一个线程内的数据共享,以减少参数的传递

ThreadLocal优化

先给出要用的ThreadLocal工具类

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

然后在拦截器的preHandle方法中将方法内解析出的token数据通过get方法存储

        try {Map<String,Object> claims =  JwtUtil.parseToken(token);//将token解析出的树蕨存入到ThreadLocal中去ThreadLocalUtil.set(claims);//放行return true;

然后在需要用到claims的接口中通过get()方法取出数据(以获取用户信息时为例)

 

    @GetMapping("/userInfo")public Result<User> userInfo(){
//        Map<String,Object> map = JwtUtil.parseToken(token);
//        String username = (String) map.get("username");Map<String,Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User user = userService.getByUserName(username);return Result.success(user);}

当然,为了防止数据长期存储导致内存泄露,我们也需要在请求结束后释放掉存储的信息,在拦截器的 afterCompletion方法中调用方法类中的close方法即可

    @Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//在请求结束后 清空ThreadLocal中的数据ThreadLocalUtil.remove();}

 

更新用户信息

接口文档

 

分析接口文档,我们需要从1json数据中获取一个User对象,然后更新其中的nickname和email,当然,也要写入新的更新时间。同时,参数校验也是保证程序健壮性不可或缺的一环

先看Controller层

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

Service层

    @Overridepublic void update(User user) {user.setUpdateTime(LocalDateTime.now());userMapper.update(user);}

在Service层实现更新时间的写入

Mapper层

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

注意,等号前是数据库列名,#{}内是user实体类中的变量名

 

测试结果如上,当然,Header中要写入token(因为拦截器的存在)

 

参数校验

由于我们不提供username的修改,所以我们并不关注username的限制,我们要关注的参数校验主要集中在id与email中 

我们可以使用如下注解

 User实体类修改如下

    @NotNullprivate Integer id;//主键ID@NotEmpty@Pattern(regexp = "^//S{1,10}$")private String nickname;//昵称@NotEmpty@Emailprivate String email;//邮箱

当然,为了使这些规则生效,在调用规则对应实体时我么要使用 @Validated注解来使规范生效

接口更新如下:

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

更新用户头像

接口文档

    @Overridepublic void updateAvatar(String avatarUrl) {Map<String,Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");userMapper.updateAvatar(avatarUrl,id);}

 读取文档,我们需要注意的点便是头像格式是一个url路径

请求方式也是之前没有用过的pATCH

Controller层

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

Service层

    @Overridepublic void updateAvatar(String avatarUrl) {Map<String,Object> map = ThreadLocalUtil.get();Integer id = (Integer) map.get("id");userMapper.updateAvatar(avatarUrl,id);}

 我们这里利用ThreadLocal来获取当前请求用户的id,一并传给mapper层 

Mapper层

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

我们通过sql自带的now()函数来获取更改的时间

  参数校验

可以通过@URL来校验参数是否满足URL格式

Controller层更新如下

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

更新用户密码

接口文档

 

阅读更新文档,json传递的数据不像以前可以直接对应到User的变量,所以我们需要使用一个map来接收数据

并且我们发现文档没有考虑密码可能会被修改为空,所以也需要校验一下密码格式

写的好累,直接上Controller层和dao层吧

    @PatchMapping("updatePwd")@Validatedpublic Result updatePwd(@RequestBody @Valid 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 lUser  = userService.getByUserName(username);if(!lUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){return Result.error("原密码输入错误");}//校验新密码是否符合格式if(!newPwd.matches(PWD_REGEXP)){return Result.error("新密码非法!");}//校验newPwd与rePwd是否一致if (!rePwd.equals(newPwd)){return Result.error("两次填写新密码不一致");}userService.updatePwd( newPwd);return Result.success();}
    @Update("update user set password = #{newPwd} , update_time = now() where id = #{id}")void updatePwd(String newPwd,Integer id);

对了,还用了一个正则,我单独放到正则类里去了(顺便把之前用到的正则全甩里面去了)

package com.cacb.pattern;public class RegexPatterns {public static final String PWD_REGEXP =  "^\\S{11,16}$";public static final String NICKNAME_REGEXP = "^\\S{1,10}$";public static final String USERNAME_REGEXP = "^\\S{4,16}$";}

 

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

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

相关文章

问题:测风站应设置在平直的巷道中,其前后()范围内不得有障碍物和拐弯等局部阻力。 #微信#媒体

问题&#xff1a;测风站应设置在平直的巷道中&#xff0c;其前后&#xff08;&#xff09;范围内不得有障碍物和拐弯等局部阻力。 参考答案如图所示

stable-diffusion | v1-5-pruned.ckpt和v1-5-pruned-emaonly.ckpt的区别

https://github.com/runwayml/stable-diffusion?tabreadme-ov-file#reference-sampling-script 对于 1.5 模型&#xff0c;其中可能包括四部分&#xff1a;标准模型、文本编码器、VAE模型、EMA模型。 标准模型&#xff1a;生成图片的核心模块&#xff0c;潜空间中的前向扩散和…

C语言中那些后知后觉的细节冷知识(二)typedef、死循环、位移、内存访问

系列文章目录 C语言中那些后知后觉的细节冷知识&#xff08;一&#xff09;static、const、volatile、数组、宏 C语言中那些后知后觉的细节冷知识&#xff08;二&#xff09;typedef、死循环、位移、内存访问 持续更新中… … 文章目录 系列文章目录前言一、typedef二、死循环…

Qt之漂亮的地球

这个画的是一个东西围绕着中心的地球不停的旋转&#xff0c;可以放在界面的中部&#xff0c;增加美感。 展示 界面展示 设计过程 标题在之前的博客有写过&#xff0c;这里不再重复 下面是关于地球旋转的相关 1.资源文件添加 先将相关的资源文件添加&#xff0c;三个图片 2…

【lesson32】MySQL用户管理

文章目录 用户管理介绍用户用户信息创建用户 删除用户修改用户密码数据库的权限给用户授权回收权限 用户管理介绍 用户 用户信息 MySQL中的用户&#xff0c;都存储在系统数据库mysql的user表中 //操作语法 mysql> use mysql; Database changed mysql> select host,use…

微信小程序封装wx.request以及小程序登录

1.封装wx.request const GET GET; const POST POST; const PUT PUT; const FORM FORM; const DELETE DELETE;const baseURL https://alimini.ck9696.com/wxmall; // const baseURL http://192.168.0.17:8601/wxmall; var app getApp(); function request(method, url…

VR全景技术可以应用在哪些行业,VR全景技术有哪些优势

引言&#xff1a; VR全景技术&#xff08;Virtual Reality Panorama Technology&#xff09;是一种以虚拟现实技术为基础&#xff0c;通过360度全景影像、立体声音、交互元素等手段&#xff0c;创造出沉浸式的虚拟现实环境。该技术不仅在娱乐领域有着广泛应用&#xff0c;还可…

ABAC模型简单介绍——通过casbin进行简单举例

ABAC模型简单介绍——通过casbin进行简单举例 文章目录 ABAC模型简单介绍——通过casbin进行简单举例定义相关术语Casbin实现ABAC&#xff08;Python版&#xff09;假设情境定义对象定义静态模型模板测试代码最终结果 相关链接 定义 Attribute Based Access Control (基于属性…

Git使用命令大全

命令大全参考阮一峰的博客&#xff0c;根据自己的使用习惯作了调整。 Git常用命令 其他常用的命令 配置Git # 显示当前的Git配置 $ git config --list# 编辑Git配置文件 $ git config -e [--global]# 设置提交代码时的用户信息 $ git config [--global] user.name "[nam…

第14章_视图

第14章_视图 1.常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记录数据字典就是系统表&#xff0c;存放数据库相关信息的表。系统表的数据通常由数据库系统维护&#xff0c; 程序员通常不…

MDK Keil uVision5 cannot read project file 解决办法

MDK Keil uVision5 cannot read project file 解决办法 问题描述 我的系统重装过后是英文版的Windows 10&#xff0c;在打开别人/以前中文系统环境下保存的Keil Project文件&#xff08;uvprojx文件&#xff09;会报错&#xff0c;内容大致是 Cannot read project file D:\xx…

JAVA生成Word文档

第一步&#xff1a;导入依赖 <!--生成word文档--> <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.10.3</version> </dependency> <!--数字转为汉字大写--> <depend…

《代码之丑》学习笔记18——写代码是一件可以一生精进的事

结束语 | 写代码是一件可以一生精进的事 文章目录 结束语 | 写代码是一件可以一生精进的事代码的敏感度 在很多人心目中&#xff0c;程序员是一个辛苦的职业&#xff0c;一方面&#xff0c;各种新东西层出不穷&#xff0c;程序员们要努力追随&#xff0c;另一方面&#xff0c;业…

十、VTK创建圆锥体vtkConeSource 带颜色

为圆锥体的每一面,添加一种颜色: 上述效果的代码: #include <vtkSmartPointer.h> #include <vtkPoints.h> #include <vtkLine.h> #include <vtkPolyData.h> #include <vtkPolyDataWriter.h> #include <vtkPolyDataMapper.h> #incl…

机器学习复习(6)——numpy的数学操作

加减法运算 # 创建两个不同的数组 a np.arange(4) #list(0,1,2,3 b np.array([5,10,15,20]) # 两个数组做减法运算 b-a 运行结果&#xff1a; 计算数组的平方 #b*2代表数组b每个元素乘以2 #b**2代表数组b每个元素的2次方 b**2 运行结果&#xff1a; 计算数组的正弦值 #…

Java 数据结构 二叉树(二)红黑树

目录 数据结构图-树 简介 规则 旋转 重新着色 红黑树构建过程 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xf…

UnityShader(十五)纹理的属性

目录 面板属性&#xff1a; 多级渐远纹理技术&#xff08;mipmapping&#xff09; Filter Mode&#xff08;滤波模式&#xff09; 面板属性&#xff1a; 在Unity中导入一些纹理资源后可以在它的材质面板上调整其属性 如图&#xff1a; 在这个面板上有许多可以调整的属性&am…

Python的作用域

Python中的作用域是用来确定变量和函数的作用范围和生命周期的规则。在Python中&#xff0c;有四种类型的作用域&#xff1a;局部作用域、外层作用域、全局作用域和内置作用域。 一&#xff1a;局部作用域 在函数内部定义的所有变量都属于局部作用域。这些变量只能在该函数内…

西瓜书学习笔记——核化线性降维(公式推导+举例应用)

文章目录 算法介绍实验分析 算法介绍 核化线性降维是一种使用核方法&#xff08;Kernel Methods&#xff09;来进行降维的技术。在传统的线性降维方法中&#xff0c;例如主成分分析&#xff08;PCA&#xff09;和线性判别分析&#xff08;LDA&#xff09;&#xff0c;数据被映…

C++学习Day03之构造函数的调用规则

目录 一、程序及输出1.1 编译器会给一个类 至少添加3个函数1.2 自己提供了 有参构造函数1.3 自己提供了 拷贝构造函数 二、分析与总结 一、程序及输出 1.1 编译器会给一个类 至少添加3个函数 编译器会给一个类 至少添加3个函数 默认构造&#xff08;空实现&#xff09; 析构函…