【Springboot】基础业务学习笔记

发布时间:2024年01月04日

参数校验

方法步骤

1.引入Spring Validation起步依赖

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

2.在参数面前添加@Pattern注解

@Pattern(regexp = "^\\S{5,16}$")

3.在Controller类上添加 @Vallidated 注解

参数校验失败异常处理

@RestControllerAdvice
public class GlobalExceptionHandle {

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

其中,Resul类是自定义的返回结果类

@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);
    }
}

封装好的实体对象校验

User对象为例

对指定属性值加上 Validation对应注解

@NotNull值不能为空
@NotEmpty不能为空且字符串不能为空字符串""
@Email满足邮箱格式
@URL对参数是否是url路径进行校验

@Data
public class User {
    @NotNull
    private Integer id;//主键ID
    private String username;//用户名
    @JsonIgnore //让springmvc把当前对象转换成json字符串的时候,忽略password,最终的json字符串中就没有password这个属性了
    private String password;//密码


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

    @NotEmpty
    @Email
    private String email;//邮箱
    private String userPic;//用户头像地址
    private LocalDateTime createTime;//创建时间
    private LocalDateTime updateTime;//更新时间
}

方法参数前添加注解

@Validated

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

分组校验

将校验项归类分组,校验指定组中的校验项。

在实体类内部定义接口,通过groups属性进行指定,给 @validated注解的value属性赋值,默认为Default

@Data
public class Category {
    @NotNull(groups = Update.class)
    private Integer id;//主键ID
    @NotEmpty
    private String categoryName;//分类名称
    @NotEmpty
    private String categoryAlias;//分类别名
    private Integer createUser;//创建人ID
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;//创建时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;//更新时间
    //如果说某个校验项没有指定分组,默认属于Default分组
    //分组之间可以继承, A extends B  那么A中拥有B中所有的校验项
    public interface Add extends Default {

    }
    public interface Update extends Default{

    }
}

这种情况下,id的校验是在更新的时候去判断传入的参数是否为空。

	@PostMapping
    public Result add(@RequestBody @Validated(Category.Add.class) Category category) {
        categoryService.add(category);
        return Result.success();
    }

Controller在参数中指明当前实体类校验的类型

自定义校验

已有的注解不能满足所有的校验需求,特殊的情况需要自定义校验(自定义校验注解)

1.自定义注解State

@Documented
// 指定校验规则由谁提供
@Constraint(
        validatedBy = {StateValidation.class}
)
// 元注解 标明该注解的使用范围
/**
 * ElementType.METHOD 方法体,
 * ElementType.FIELD 属性,
 * ElementType.ANNOTATION_TYPE 注释类,
 * ElementType.CONSTRUCTOR 构造,
 * ElementType.PARAMETER 参数,
 * ElementType.TYPE_USE
 */
@Target({ElementType.FIELD})
// 注解保留阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface State {
    // 提供校验失败后的信息
    String message() default "state 参数的值只能是已发布或草稿";
    // 指定分组
    Class<?>[] groups() default {};
    // 负载 获取到 State 注解的附加信息
    Class<? extends Payload>[] payload() default {};
}

2.自定义校验数据的类 StateValidation 实现 ConstraintValidator接口

public class StateValidation  implements ConstraintValidator<State, String> {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null) return false;
        if (value.equals("已发布") || value.equals("草稿")) {
            return true;
        }
        return false;
    }
}

3.在需要校验的地方使用自定义注解

登录认证

令牌规范JWT

全称:JSON Web Token (https:/jwt.io/

组成:

Header(),记录令牌类型和签名算法等
PayLoad(载荷),携带自定义的信息。注意不要承载私密数据。
Signature(签名),对头部和载荷进行加密计算得来

使用步骤

1.添加依赖

<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>4.4.0</version>
</dependency>

2.调用API生成和校验令牌

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;

public class JwtUtil {
    private static final String KEY = "itheima"; // 令牌加密密钥字符串
	//接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims) // 设置令牌承载数据
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)) // 设置令牌失效时间
                .sign(Algorithm.HMAC256(KEY)); // 设置令牌加密算法
    }
	//接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }
}

3.解析令牌抛出异常,则令牌被篡改或过期

单个设置登录验证

Token在请求头中的Authorization字段,从请求头中获取。若未登录,则不存在该字段。

	@GetMapping("/list")
    public Result<String> list(@RequestHeader(name = "Authorization") String token, HttpServletResponse response) {
        // 验证Token
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            return Result.success("所有文章数据");
        } catch (Exception e) {
            // 设置响应状态码 401
            response.setStatus(401);
            return Result.error("未登录");
        }
    }

设置拦截器进行登录验证

首先设置登录拦截器

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 令牌验证
        String token = request.getHeader("Authorization");
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            // 放行
            return true;
        } catch (Exception e) {
            // 设置响应状态码 401
            response.setStatus(401);
            // 不放行
            return false;
        }
    }
}

随后配置注册拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登录和注册接口不拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login", "/user/register");
    }
}

ThreadLocal

用来存取数据:set(0/get()
使用ThreadLocal存储的数据,线程安全
用完记得调用remove方法释放

文章来源:https://blog.csdn.net/weixin_44581175/article/details/135297515
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。