手把手教你入门vue+springboot开发(六)--后端代码解读与优化

news2024/11/20 3:31:29

文章目录

  • 前言
  • 一、Lombok库
  • 二、spring-boot-starter-validation库
  • 三、ThreadLocalUtil
  • 四、全局异常处理
  • 总结


前言

前面我们已经把vue+springboot前后端分离开发和打包部署过程全部打通了,通过一个简单的demo来演示整个过程,主要关注在开发工具使用、框架目录结构、调试方法、打包部署上,虽然也有少量代码理解,但是并没有过多关注代码的实现细节。后面我们将通过代码解读优化来逐步熟悉vue和springboot的代码细节实现,本篇先解读一下后端springboot代码并做优化


一、Lombok库

我们先来看看《手把手教你入门vue+springboot开发(一)》中的User.java代码。

package com.example.demo.bean;

public class User {
    private String id;
    private String userName;
    private String password;
    private String sex;
    private String telephone;
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }
}

同C++开发一样,我们需要为类的每个成员变量编写get和set方法,这种繁琐的工作占用了我们大量的时间,所以springboot提供了很多好的库,可以让我们通过注解的方式省掉这些繁琐的工作,更专注于业务代码的实现。比如,我们可以使用Lombok库的Data注解,如下图所示修改User.java代码,简洁很多。

package com.example.demo.bean;

import lombok.Data;

@Data
public class User {
    private String id;
    private String userName;
    private String password;
    private String sex;
    private String telephone;
}

要使用lombok库,需要在pom.xml中增加lombok依赖

       <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

我理解,注解实际会在编译的时候生成代码,这部分生成的代码就不需要我们手写了。那么Data注解会生成什么代码呢?user.java编译后会在target目录生成User.class代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.example.demo.bean;

public class User {
    private String id;
    private String userName;
    private String password;
    private String sex;
    private String telephone;

    public User() {
    }

    public String getId() {
        return this.id;
    }

    public String getUserName() {
        return this.userName;
    }

    public String getPassword() {
        return this.password;
    }

    public String getSex() {
        return this.sex;
    }

    public String getTelephone() {
        return this.telephone;
    }

    public void setId(final String id) {
        this.id = id;
    }

    public void setUserName(final String userName) {
        this.userName = userName;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    public void setSex(final String sex) {
        this.sex = sex;
    }

    public void setTelephone(final String telephone) {
        this.telephone = telephone;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label71: {
                    Object this$id = this.getId();
                    Object other$id = other.getId();
                    if (this$id == null) {
                        if (other$id == null) {
                            break label71;
                        }
                    } else if (this$id.equals(other$id)) {
                        break label71;
                    }

                    return false;
                }

                Object this$userName = this.getUserName();
                Object other$userName = other.getUserName();
                if (this$userName == null) {
                    if (other$userName != null) {
                        return false;
                    }
                } else if (!this$userName.equals(other$userName)) {
                    return false;
                }

                label57: {
                    Object this$password = this.getPassword();
                    Object other$password = other.getPassword();
                    if (this$password == null) {
                        if (other$password == null) {
                            break label57;
                        }
                    } else if (this$password.equals(other$password)) {
                        break label57;
                    }

                    return false;
                }

                Object this$sex = this.getSex();
                Object other$sex = other.getSex();
                if (this$sex == null) {
                    if (other$sex != null) {
                        return false;
                    }
                } else if (!this$sex.equals(other$sex)) {
                    return false;
                }

                Object this$telephone = this.getTelephone();
                Object other$telephone = other.getTelephone();
                if (this$telephone == null) {
                    if (other$telephone == null) {
                        return true;
                    }
                } else if (this$telephone.equals(other$telephone)) {
                    return true;
                }

                return false;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $id = this.getId();
        result = result * 59 + ($id == null ? 43 : $id.hashCode());
        Object $userName = this.getUserName();
        result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
        Object $password = this.getPassword();
        result = result * 59 + ($password == null ? 43 : $password.hashCode());
        Object $sex = this.getSex();
        result = result * 59 + ($sex == null ? 43 : $sex.hashCode());
        Object $telephone = this.getTelephone();
        result = result * 59 + ($telephone == null ? 43 : $telephone.hashCode());
        return result;
    }

    public String toString() {
        String var10000 = this.getId();
        return "User(id=" + var10000 + ", userName=" + this.getUserName() + ", password=" + this.getPassword() + ", sex=" + this.getSex() + ", telephone=" + this.getTelephone() + ")";
    }
}

可以看到,Data注解为我们自动生成了构造函数、get/set方法、equals方法、canEqual方法、hashCode方法、toString方法。
我们再来看看《手把手教你入门vue+springboot开发(三)》中的Result.java代码。

package com.example.demo.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
    private Integer code;//业务状态码  0-成功  1-失败
    private String message;//提示信息
    private T data;//响应数据

    //快速返回操作成功响应结果(带响应数据)
    public static <E> Result<E> success(E data) {
        return new Result<>(0, "操作成功", data);
    }

    //快速返回操作成功响应结果
    public static Result success() {
        return new Result(0, "操作成功", null);
    }

    public static Result error(String message) {
        return new Result(1, message, null);
    }
}

这里除了使用了Data注解,还使用了NoArgsConstructor和AllArgsConstructor注解,NoArgsConstructor注解表示自动生成无参数构造函数,AllArgsConstructor注解表示自动生成全参数构造函数。
以下是target目录编译生成的Result.class文件。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.example.demo.bean;

public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <E> Result<E> success(E data) {
        return new Result(0, "操作成功", data);
    }

    public static Result success() {
        return new Result(0, "操作成功", (Object)null);
    }

    public static Result error(String message) {
        return new Result(1, message, (Object)null);
    }

    public Result() {
    }

    public Result(final Integer code, final String message, final T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public Integer getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public T getData() {
        return this.data;
    }

    public void setCode(final Integer code) {
        this.code = code;
    }

    public void setMessage(final String message) {
        this.message = message;
    }

    public void setData(final T data) {
        this.data = data;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Result)) {
            return false;
        } else {
            Result<?> other = (Result)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label47: {
                    Object this$code = this.getCode();
                    Object other$code = other.getCode();
                    if (this$code == null) {
                        if (other$code == null) {
                            break label47;
                        }
                    } else if (this$code.equals(other$code)) {
                        break label47;
                    }

                    return false;
                }

                Object this$message = this.getMessage();
                Object other$message = other.getMessage();
                if (this$message == null) {
                    if (other$message != null) {
                        return false;
                    }
                } else if (!this$message.equals(other$message)) {
                    return false;
                }

                Object this$data = this.getData();
                Object other$data = other.getData();
                if (this$data == null) {
                    if (other$data != null) {
                        return false;
                    }
                } else if (!this$data.equals(other$data)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Result;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $code = this.getCode();
        result = result * 59 + ($code == null ? 43 : $code.hashCode());
        Object $message = this.getMessage();
        result = result * 59 + ($message == null ? 43 : $message.hashCode());
        Object $data = this.getData();
        result = result * 59 + ($data == null ? 43 : $data.hashCode());
        return result;
    }

    public String toString() {
        Integer var10000 = this.getCode();
        return "Result(code=" + var10000 + ", message=" + this.getMessage() + ", data=" + String.valueOf(this.getData()) + ")";
    }
}

Lombok库除了提供Data注解、NoArgsConstructor注解、AllArgsConstructor注解,还提供了很多其它注解,大家有兴趣可以自行百度一下,后面我们用到了再给大家介绍。

二、spring-boot-starter-validation库

spring-boot-starter-validation库主要用于校验,我们需要先在pom.xml增加依赖

        <!--validation依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

它主要提供以下常用注解。
在这里插入图片描述
UserController.java代码中使用了Pattern注解对参数username和password做校验。

public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password)

我们再在User.java中增加NotNull、NotEmpty、JsonIgnore三个注解,代码如下:

package com.example.demo.bean;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

@Data
public class User{
    @NotNull
    private String id;
    @NotEmpty
    private String userName;
    @JsonIgnore
    private String password;
    private String sex;
    private String telephone;
}

@JsonIgnore/注解让springboot把当前对象转换成json字符串的时候,忽略password,最终的json字符串中就没有password这个属性。

三、ThreadLocalUtil

在LoginInterceptor.java代码中我们使用了线程局部变量ThreadLocalUtil,如下图所示:
在这里插入图片描述
前面我们讲过,LoginInterceptor实现的是拦截器功能,preHandle方法实现请求进入controller处理前要做的事,这里我们主要是校验token,并把它保存起来,因为token信息中带了用户ID,后面的代码就不需要再从数据库中去拿用户ID。那么这里我们为什么要用线程局部变量ThreadLocalUtil呢?
因为在B/S架构中,每个用户登录服务器,tomcat会为它创建一个线程,如果有3个用户同时登录,那tomcat就会创建3个线程,每个用户的请求都进入它自己的线程处理,显然在这种情况下只能使用ThreadLocalUtil来保存token了。
afterCompletion方法实现请求处理完后要做的事情,那么为了防止内存泄漏,在这里我们需要清空ThreadLocalUtil的数据。

四、全局异常处理

增加exception包,里面增加GlobalExceptionHandler类来处理全局异常,主要目的是为了把各类异常统一返回成Result的格式。
GlobalExceptionHandler.java代码如下:

package com.example.demo.exception;

import com.example.demo.bean.Result;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e){
        e.printStackTrace();
        return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage() : "操作失败");
    }
}

这里使用了RestControllerAdvice和ExceptionHandler注解。RestControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。ExceptionHandler注解用于指定异常处理方法,当与@RestControllerAdvice注解配合使用时,用于全局处理控制器里的异常。


总结

本篇主要通过对前面实现的登录demo实例的后端代码解读并进行一些优化,来熟悉java或者springboot编程的基础细节,一些库和注解的使用。下一篇我们将解读登录demo实例的vue前端代码。

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

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

相关文章

CAD使用技巧,图片去边框,直线等分

CAD插入图片之后怎么去除图片边框 有时候我们需要将图片插入到CAD里面&#xff0c;但是发现插入进去之后&#xff0c;图片周围带有白色边框&#xff0c;这样看着就不是很舒服&#xff0c;要去除边框要如何操作呢 命令操作法&#xff1a;在命令栏输入“imageframe”回车&#xf…

蜜雪冰城小程序逆向

app和小程序算法一样 小程序是wasm

谈谈Flink消费kafka的偏移量

offset配置: flinkKafkaConsumer.setStartFromEarliest():从topic的最早offset位置开始处理数据&#xff0c;如果kafka中保存有消费者组的消费位置将被忽略。 flinkKafkaConsumer.setStartFromLatest():从topic的最新offset位置开始处理数据&#xff0c;如果kafka中保存有消费…

Golang | Leetcode Golang题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; func numIslands(grid [][]byte) int {res : 0for i : 0; i < len(grid); i {for j : 0; j < len(grid[i]); j {if grid[i][j] 1 {resdfs(grid, i, j)}}}return res }func dfs(grid [][]byte, r, c int) {h, w : len(grid), len(gri…

C++感受12-Hello Object 派生版

不变的功能&#xff0c;希望直接复用原有代码&#xff1b;变化的功能&#xff0c;希望在分开的代码里实现。 派生的基本概念和目的如何定义派生类以及创建派生对象派生对象的生死过程 0. 课堂视频 ff14-HelloObject-派生版 1. 派生的基本概念与目的 编程&#xff0c;或者说软…

Games101学习笔记 Lecture 14: Ray Tracing 2 (Acceleration Radiometry)

Lecture 14: Ray Tracing 2 (Acceleration & Radiometry 一、加速光线追踪 AABB1.均匀网格 Uniform Spatial Partitions (Grids)①前处理-构建加速网格②射线与场景相交③网格分辨率④适用情况 2.空间划分KD-Tree①预处理②数据结构③遍历④问题 3.对象划分 & 包围盒层…

使用Python绘制极坐标图

使用Python绘制极坐标图 极坐标图极坐标图的优点使用场景 效果代码 极坐标图 极坐标图&#xff08;Polar Chart&#xff09;是一种图表类型&#xff0c;用于显示在极坐标系中的数据。极坐标图使用圆形坐标系&#xff0c;角度表示一个变量的值&#xff0c;半径表示另一个变量的…

森马基于MaxCompute+Hologres+DataWorks构建数据中台

讲师&#xff1a;晋银龙 浙江森马数仓高级经理 本次案例主要分享森马集团面对多年自建的多套数仓产品体系&#xff0c;通过阿里云MaxComputeHologresDataWorks统一数仓平台&#xff0c;保障数据生产稳定性与数据质量&#xff0c;减少ETL链路及计算时间&#xff0c;每年数仓整体…

Vue中的axios深度探索:从基础安装到高级功能应用的全面指南

文章目录 前言一、axios 请求1. axios的概念2. axios的安装3. axiso请求方式介绍4. axios请求本地数据5. axios跨域6. axios全局注册7. axios支持的请求类型1&#xff09;get请求2&#xff09;post请求3&#xff09;put请求4&#xff09;patch请求5&#xff09;delete请求 二、…

K8s的基本使用和认识

目录 介绍 控制端 Node(节点) 控制端与节点的关系图 基本使用 创建和运行资源 查找和参看资源 修改和删除资源 介绍 控制端 api-server(api)是集群的核心是k8s中最重要的组件,因为它是实现声明式api的关键 kubernetes api-server的核心功能是提供了Kubernetes各类资…

基于FreeRTOS+STM32CubeMX+LCD1602+MCP3008(SPI接口)的ADC转换器Proteus仿真

一、仿真原理图: 二、运行效果: 三、STM32CubeMX配置: 1)、RCC配置: 2)、SPI配置: 四、部分代码: 1)、主函数: /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main…

mysql8.0.19安装zip版本

下载地址https://downloads.mysql.com/archives/community/ 下载版本 下载后解压&#xff0c;不包括data 和my.ini文件。其中data 文件是自动生成的【mysqld --initialize --console】&#xff0c;my.ini需要自己编写设置。 新建my.ini文件 需要自己设置 basedirG:\soft\mysql…

华为DCN网络之:VXLAN

VXLAN RFC定义了VLAN扩展方案VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;。VXLAN采用MAC in UDP封装方式&#xff0c;是NVO3&#xff08;Network Virtualization over Layer 3&#xff09;中的一种网络虚拟化技术。 VXLAN…

android studio 添加aar包

按着以前旧的导包方式栽了大跟头&#xff0c;后面在留老板的的博客下找到了解决办法&#xff0c;记录一下。 Andriod Studio 导入aar最新的方式_gradle 8 引入arr-CSDN博客 最新导包方式 1.在新建libs目录&#xff0c;在app/libs目录下导入aar包&#xff08;其实就是拷贝过去…

hive4 从入门到精通

查询hive 架构 准备 HDFS配置 vim $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有节点的root用户都可作为代理用户--><property><name>hadoop.proxyuser.root.hosts</name><value>*</value></property><!--配置root用户…

ETH巨鲸鱼异动和最大BTC爆仓

小编使用币界网地址监控工具&#xff0c;跟踪了在一次令人震惊的链上巨鲸地址异动&#xff0c;一个新创建的地址在过去四个小时内从 Coinbase 提取了价值 2121 万美元的 ETH。总共积累了 6,215 个 ETH&#xff0c;平均购买价格为每 ETH 3,414 美元。如此大规模的提款暗示着周一…

JVM原理(八):JVM虚拟机工具之基础故障工具

这里主要介绍监视虚拟机运行状态和进行故障处理的工具 1. jsp:虚拟机进程状况工具 jsp命令格式&#xff1a; jsp [options] [hostid] jps远程查询虚拟机进程状态 2. jstat:虚拟机统计信息监视工具 jstat命令格式&#xff1a; jstat [option vmid [interval [s|ms] [count]…

【Elasticsearch】Elasticsearch索引创建与管理详解

文章目录 &#x1f4d1;引言一、Elasticsearch 索引的基础概念二、创建索引2.1 使用默认设置创建索引2.2 自定义设置创建索引2.3 创建索引并设置映射 三、索引模板3.1 创建索引模板3.2 使用索引模板创建索引 四、管理索引4.1 查看索引4.2 更新索引设置4.3 删除索引 五、索引别名…

基于VUE3+VITE+SpringBoot+Nginx部署项目之跨域配置等问题

前言&#xff1a;遇到问题&#xff0c;解决问题。 第一部分&#xff1a;VUE 配置 1、vite.config.js 文件 server: {proxy: {/api: {target: env.VITE_BASE_URL,changeOrigin: true,secure: false,rewrite: path > path.replace(/^\/api/, )}}}, 2、.env 文件 VITE_BAS…