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


前言

前面我们已经把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前端代码。

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值