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.hqwc.cn/news/454894.html

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

相关文章

Nginx: a little source code

Nginx被称为C程序员必学的源码之一&#xff0c;我觉得名副其实&#xff0c;它的事件机制、内存管理、进程通信都可以说是顶级实践&#xff0c;非常值得学习。 Nginx源码比较多&#xff0c;本文只看几个重要的模块&#xff0c;更详细的内容请参考《深入理解nginx模块开发与架构》…

单片机学习笔记---按键控制LED流水灯模式定时器时钟

目录 代码讲解 初始化函数 1.定时器部分的配置步骤 第一步&#xff0c;对TMOD的赋值 第二步&#xff0c;给TF0赋值 第三步&#xff0c;给TR0赋值开启定时器 第四步&#xff0c;给TL0和TH0赋初值 2.中断系统部分的配置步骤 第一步&#xff0c;给ET0赋值 第二步&#x…

Linux系统安全①iptables防火墙

目录 一.iptables防火墙概述 1.netfilter与iptables &#xff08;1&#xff09;netfilter &#xff08;2&#xff09;iptables 2.iptables防火墙默认规则表、链结构 二.iptables四表五链 1.四表 2.五链 3.总结 三.iptables的配置 1.安装 2.配置方法 &#xff08;1…

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 PySpark SQL 基础 PySpark SQL与Hive的异同 Hive和Spark 均是:“分…

c语言动态数组的实现

动态数组是在程序运行时动态分配内存空间的数组&#xff0c;可以根据需要随时改变大小。在C语言中&#xff0c;动态数组通常通过指针和malloc函数来实现。 使用malloc函数动态分配内存空间&#xff1a; int *arr; int size 10; arr (int*)malloc(size * sizeof(int));使用r…

扩展鸿蒙textinput组件

扩展鸿蒙textinput组件&#xff0c;支持快速扩展展性&#xff0c;标题文本等&#xff0c;文本内容双向绑定、文本组件快速复用。 组件代码 /*** 单选文本*/ Component export default struct DiygwInput{//绑定的值Link value:string;//未选中图标State labelImg: Resource …

sql非查询知识点(增删改-crud没有r)

1.建库 create database database_name 2.使用该数据库 use database_name 3.建表 3.1普通建表 create table if not exists actor(actor_id smallint(5) not null primary key comment "主键id",first_name varchar(45) not null comment "名字",last…

挂耳式耳机什么牌子的好?年度最值得入手的挂耳式耳机推荐

近年来耳机市场发展迅猛&#xff0c;蓝牙耳机品类日益增多。而挂耳式耳机尤其火爆&#xff0c;得益于其出色的佩戴体验&#xff0c;赢得了众多消费者的青睐。市场上挂耳式耳机的品牌种类繁多&#xff0c;让许多消费者在选择时感到困惑&#xff0c;挂耳机耳机什么牌子的好&#…

详细了解ref和reactive.

这几天看到好多文章标题都是类似于&#xff1a; 不用 ref 的 xx 个理由不用 reactive 的 xx 个理由历数 ref 的 xx 宗罪 我就很不解&#xff0c;到底是什么原因导致有这两批人&#xff1a; 抵触 ref 的人抵触 reactive 的人 看了这些文章&#xff0c;我可以总结出他们的想法…

工作与生活平衡:在生活中寻找和谐

工作和生活是我们生活中不断交织的两个重要方面。对许多人来说&#xff0c;找到两者之间的完美平衡已经成为一个持久的挑战。然而&#xff0c;与其专注于平衡&#xff0c;更重要的是要认识到工作和生活并不是可以相互平衡的两个分离实体&#xff0c;而是一个相互影响的循环。正…

python的进程,线程、协程

python进程的实现 #coding:utf-8 from multiprocessing import Process import timedef run(name):print(%s is running % name)time.sleep(3)print(%s finished his run % name)if __name__ __main__:p Process(targetrun, args(XWenXiang,)) # 创建一个进程对象p.start()…

提高效率:如何利用易点易动设备管理系统优化设备移动巡检流程

在现代企业中&#xff0c;设备的移动巡检是一个重要的任务&#xff0c;涉及到设备的维护、保养和安全等方面。然而&#xff0c;传统的手动巡检方式存在着效率低、准确性不高等问题。为了解决这些问题&#xff0c;引入易点易动设备管理系统成为了一个值得考虑的选择。本文将介绍…