源码分析
项目结构
- 打包后的代码结构如图所示
- .idea目录.存放项目的配置信息,包括历史记录,版本控制信息等
- 其中 libraries目录中存放的都是maven依赖
- 其中 libraries目录中存放的都是maven依赖
src目录源码分析
main目录
java目录
包com/markerhub下
common
dto
-
LoginDto.java
-
DTO(Data Transfer Object,数据传送对象)
-
DTO是一个普通的Java类,它封装了要传送的批量的数据。当客户端需要读取服务器端的数据的时候,服务器端将数据封装在DTO中,这样客户端就可以在一个网络调用中获得它需要的所有数据
-
LoginDto用来封装登录用户的信息用以传输给客户端
package com.markerhub.common.dto; import lombok.Data; import javax.validation.constraints.NotBlank; import java.io.Serializable; @Data public class LoginDto implements Serializable { @NotBlank(message = "昵称不能为空") private String username; @NotBlank(message = "密码不能为空") private String password; }
exception
-
全局异常处理类,用来捕捉全局异常
package com.markerhub.common.exception; import com.markerhub.common.lang.Result; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.ShiroException; import org.springframework.http.HttpStatus; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.UNAUTHORIZED) //此处ExceptionHandlerd的value指定的类是org.apache.shiro.ShiroException所提供的而不是自定义的 @ExceptionHandler(value = ShiroException.class) public Result handler(ShiroException e) { log.error("运行时异常:----------------{}", e); return Result.fail(401, e.getMessage(), null); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(value = MethodArgumentNotValidException.class) public Result handler(MethodArgumentNotValidException e) { log.error("实体校验异常:----------------{}", e); BindingResult bindingResult = e.getBindingResult(); ObjectError objectError = bindingResult.getAllErrors().stream().findFirst().get(); return Result.fail(objectError.getDefaultMessage()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(value = IllegalArgumentException.class) public Result handler(IllegalArgumentException e) { log.error("Assert异常:----------------{}", e); return Result.fail(e.getMessage()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(value = RuntimeException.class) public Result handler(RuntimeException e) { log.error("运行时异常:----------------{}", e); return Result.fail(e.getMessage()); }
}
-
因为有日志输出,所以在集成了Slf4j进项目后,在这个全局异常处理类上加上 @Slf4j注解
-
@RestControllerAdvice注解,全局Controller用来捕捉全局异常
-
@ResponseStatus,带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析。可以实现自定义的一些异常,同时在页面上进行显示。有两个参数
- code:对应枚举HttpStatus的值,此值对应相应404,403,500
- reason:界面提示文字
全局异常处理类的处理逻辑:捕捉全局异常并进行处理
-
shiro认证授权时抛出的异常,在异常处理handler中先做日志输出,然后用封装的给前端返回信息的处理类Result做返回信息封装
Result.fail(401, e.getMessage(), null),同时会返回一个code为UNAUTHORIZED(放在返回头中的) -
后端数据校验时出错抛出异常,在异常处理类中做日志输出,取出异常中绑定的错误信息(从ObjectError对象中拿到)封装进前端返回信息处理类Result.fail(objectError.getDefaultMessage(),同时会返回一个code
HttpStatus.BAD_REQUEST-
注意这里后端使用的数据校验(使用SpringBoot集成的Hibernate Validation)现在实体类加@NotNull类注解的一个value为message为提示信息如下
-
在contoller在需要此实体类的地方加上@Valid 注解
-
校验数据出现的异常假设捕捉到e,e.getBindingResult()得到的绑定结果就是校验标签上的message
-
-
Assert异常时抛出异常(有断言时出错的地方抛出此异常),做日志输出后,拿到异常信息e.getMessage()封装进前端返回信息处理类Result.fail(e.getMessage()),同时将HttpStatus.BAD_REQUEST的code封装进返回头中
-
其他运行时异常全部捕捉起来,做日志输出,拿到异常信息e.getMessage()封装进前端返回信息处理类Result.fail(e.getMessage()),同时将HttpStatus.BAD_REQUEST的code封装进返回头中
lang
package com.markerhub.common.lang;
import lombok.Data;
import java.io.Serializable;
@Data
public class Result implements Serializable {
private int code; // 200是正常,非200表示异常
private String msg;
private Object data;
public static Result succ(Object data) {
return succ(200, "操作成功", data);
}
public static Result succ(int code, String msg, Object data) {
Result r = new Result();
r.setCode(code);
r.setMsg(msg);
r.setData(data);
return r;
}
public static Result fail(String msg) {
return fail(400, msg, null);
}
public static Result fail(String msg, Object data) {
return fail(400, msg, data);
}
public static Result fail(int code, String msg, Object data) {
Result r = new Result();
r.setCode(code);
r.setMsg(msg);
r.setData(data);
return r;
}
}
-
定义该异常类,三个成员变量,code(200正常,非200异常),msg状态信息,data表示数据(Object类型)
-
Result中实现了两种构造自定义Result对象的方法(其实就是将错误操作,成功信息封装进同一个类型对象Result),同时还实现了函数重载
Result类的处理逻辑
- 成功操作则调用Result的静态方法succ(Object data),底层为调用重载后的succ(200, “操作成功”, data);此时将三个参数封装进一个Result对象并返回
- 错误操作逻辑为,调用Result的静态方法,只传入错误信息fail(String msg),则调用 return fail(400, msg, null);如果传入错误信息和数据则调用 return fail(400, msg, data);统一由fail(int code, String msg, Object data) 实现Result的构造
- 可见正确操作给前端返回的信息是一定code为200,由正确信息和数据的,而错误操作状态码为400有错误信息,但可能没有数据的
util
JwtUtils.java
package com.markerhub.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* jwt工具类
*/
@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "