SpringBoot实战第二天

news2025/1/15 6:49:14

今日战报

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

        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方法即可

    @Override
    public 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层

    @Override
    public 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实体类修改如下

    @NotNull
    private Integer id;//主键ID

    @NotEmpty
    @Pattern(regexp = "^//S{1,10}$")
    private String nickname;//昵称
    
    @NotEmpty
    @Email
    private String email;//邮箱

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

接口更新如下:

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

更新用户头像

接口文档

    @Override
    public 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层

    @Override
    public 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")
    @Validated
    public 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.coloradmin.cn/o/1432920.html

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

相关文章

CSS 闪电按钮效果

<template><view class="const"><div class="voltage-button"><button>闪电按钮</button><svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox=&q…

PyTorch 2.2 中文官方教程(十七)

&#xff08;Beta&#xff09;使用缩放点积注意力&#xff08;SDPA&#xff09;实现高性能 Transformer 原文&#xff1a;pytorch.org/tutorials/intermediate/scaled_dot_product_attention_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这…

Flutter开发iOS问题记录

一、版本适配问题 warning: The iOS deployment target ‘IPHONEOS_DEPLOYMENT_TARGET’ is set to 10.0, but the range of supported deployment target versions is 12.0 to 17.2.99. (in target ‘Protobuf’ from project ‘Pods’) 可以通过在podfile中配置解决。 pos…

小埋的解密游戏的题解

题目描述 小埋最近在玩一个解密游戏&#xff0c;这个游戏的解密方法是这样的&#xff0c;这个游戏会给你提供 个数,让我们求出这 个数里面&#xff0c;有多少个连续的数的平均数大于某个给定的数 。这个数可能会很大&#xff0c;所以我们要输出这个数对 的取模结果。现在小…

Java并发之synchronized详解

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

使用Java实现基于HTTP的分布式系统:让你的应用“四处开花”

在数字世界里&#xff0c;分布式系统就像是一个大家庭&#xff0c;每个成员&#xff08;即节点&#xff09;都有自己的任务和职责&#xff0c;共同维护整个家庭的运转。如果你想使用Java来实现这样一个大家庭&#xff0c;让应用在各个节点上“四处开花”&#xff0c;那就需要借…

ensp实验合集(二)

实验6 VLAN划分....................................................................... - 30 - 实验7 路由器调试及常用命令使用........................................ - 42 - 实验8 配置静态路由器............................................................…

DevOps落地笔记-13|自动化测试:提高测试效率的不二之选

上一课时主要介绍了通过 API 管理平台来管理企业内部的 API。持续集成是能够保证软件处于可工作状态的实践&#xff0c;但实施持续集成有一个必不可少的步骤——测试。只有尽可能全面的测试覆盖&#xff0c;才能降低软件出错的概率。但是&#xff0c;大多数企业里还是基于人工来…

ChatGPT之搭建API代理服务

简介 一行Docker命令部署的 OpenAI/GPT API代理&#xff0c;支持SSE流式返回、腾讯云函数 。 项目地址&#xff1a;https://github.com/easychen/openai-api-proxy 这个项目可以自行搭建 OpenAI API 代理服务器工具&#xff0c;该项目是代理的服务器端&#xff0c;不是客户端。…

SpringMVC-组件解析

一、引子 我们在上一篇文章Spring MVC-基本概念中&#xff0c;为读者解释了如何使用SpringMVC框架&#xff0c;将承接客户端请求的工作从原生的Servlet转移到我们熟知的Controller中。那么我们不禁会好奇&#xff0c;SpringMVC框架到底做了什么&#xff0c;是怎么把请求分发给…

python爬虫代码示例:爬取京东详情页图片【京东API接口】

一、Requests请求示例【京东API接口】 爬虫爬取网页内容首先要获取网页的内容&#xff0c;通过requests库进行获取。 安装 pip install requests 示例代码 import requests url "http://store.weigou365.cn"res requests.get(url)res.text 执行效果如下&#x…

08. 【Linux教程】CentOS 目录介绍

CentOS 目录介绍 前面小节介绍了如何安装并登录连接 CentOS 系统&#xff0c;本小节围绕 CentOS 系统的目录&#xff0c;介绍其各个目录的作用&#xff0c;方便读者以后在工作中很好地将项目和软件归类存储&#xff0c;熟悉 CentOS 系统各个目录的功能介绍&#xff0c;有助于加…

javaEE - 20( 18000字 Tomcat 和 HTTP 协议入门 -1)

一&#xff1a; HTTP 协议 1.1. HTTP 是什么 HTTP (全称为 “超文本传输协议”) 是一种应用非常广泛的 应用层协议. HTTP 诞生与1991年. 目前已经发展为最主流使用的一种应用层协议. 最新的 HTTP 3 版本也正在完善中, 目前 Google / Facebook 等公司的产品已经支持了. HTT…

【JavaScript 漫游】【007】数据类型转换

文章简介 本文为【JavaScript 漫游】专栏的第 007 篇文章&#xff0c;对 JS 数据类型转化语法进行了简记。 数据类型的转换指的是将 JS 的某一数据类型的值转换为 JS 的某一原始数据类型的值&#xff0c;也就是 number、string 和 boolean。 Number 方法强制转换为 number 类…

Python||五城P.M.2.5数据分析与可视化_使用复式柱状图分析各个城市的P.M.2.5月度差异情况(中)

目录 4.上海市空气质量月度差异 5.沈阳市空气质量月度差异 五城P.M.2.5数据分析与可视化_使用复式柱状图分析各个城市的P.M.2.5月度差异情况 4.上海市空气质量月度差异 import numpy as np import pandas as pd import matplotlib.pyplot as plt#读入文件 sh pd.read_csv(./S…

arping交叉编译

arping命令依赖libpcap和libnet&#xff0c;需要先交叉编译这两个库。 1.交叉编译libpcap 下载libpcap源文件&#xff0c;从github上克隆: git clone https://github.com/the-tcpdump-group/libpcap.git source交叉编译环境 # environment-setup是本机的交叉编译环境, 里面…

12. onnx转为rknn测试时有很多重叠框的修改(python)

我们下载rknn-toolkit2-master后并进行前面的处理后&#xff0c;进入到rknn-toolkit2-master\examples\onnx\yolov5文件夹&#xff0c;里面有个test.py文件&#xff0c;打开该文件&#xff0c;其代码如下&#xff1a; # -*- coding: utf-8 -*- # coding:utf-8import os import…

解决问题(Tensorflow框架):ImportError: cannot import name ‘merge‘ from ‘keras.layers‘

看了一圈解决方案&#xff0c;没有找到跟我这个相关的 这就是版本兼容性问题 说句最简单的&#xff0c;针对我这个问题 直接把merge删除点就完事了&#xff0c;因为新版的tensorflow框架这个里面不包含merge&#xff0c;所以直接删掉问题就解决了

SD-WAN的安全性体现在哪里?

SD-WAN技术以其高度灵活、网络自动配置和低成本等优势&#xff0c;将多个物理WAN链接整合为一个逻辑网络&#xff0c;推动网络从“连通驱动”向“服务驱动”导向的转变。同时&#xff0c;企业在追求高效网络时&#xff0c;SD-WAN的安全性也成为一个重要的考量因素。 SD-WAN采用…

快速掌握西门子S7-1200 PLC的PID控制工艺

模拟量闭环控制系统-PID控制的特点&#xff1a; 不需要被控对象的数学模型&#xff0c;结构简单容易实现&#xff0c;使用方便有较强的灵活性和适应性。 用调试窗口整定PID控制器-调试窗口的功能&#xff1a; 1、使用“首次启动自调节”功能优化控制器 2、使用“运行中自调节…