项目随笔-【大事件(文章类)】

项目随笔-【大事件(文章类)】

自定义参数校验注解

需要写一个自定义注解Xxx+校验规则的类XxxValidation【需要继承ConstraintValidator】

自定义注解

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {StateValidation.class})//使用 `StateValidation` 类来验证该字段的值是否满足特定的约束条件
public @interface State {
    String message() default "state参数的值只能是已发布或者草稿";//验证失败的错误提示信息

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

注解校验规则

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

  • <State>ConstraintValidator 接口的第一个泛型参数,它指定了验证器将要验证的约束注解的类型。在这个例子中,State 可能是一个自定义的注解,用于标记需要验证的字段。
  • <String>ConstraintValidator 接口的第二个泛型参数,它指定了验证器将要验证的属性值的类型。在这个例子中,String 表示 StateValidation 类将验证 String 类型的属性值。

阿里云Oss存储

工具类

public class AliOssUtil {
    // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
    private static final String ENDPOINT = "https://oss-cn-hangzhou.aliyuncs.com";

    // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。【这里没使用】
    // EnvironmentVariableCredentialsProvider credentialsProvider =
    // CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();

    private static final String ACCESS_KEY_ID = "LTAI5tJKk5H98ZmQQ9CgeG8y";
    private static final String ACCESS_KEY_SECRET = "90xHhXxKig6LNnbb4ubpRBeIdw7RAT";
    // 填写Bucket名称,例如examplebucket。
    private static final String BUCKET_NAME = "zy-bigevent";

    public static String uploadFile(String objectName, InputStream in) throws Exception {
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        String url = "";
        try {
            // 填写字符串。
            String content = "Hello OSS,你好世界";

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, objectName, in);

            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 上传字符串。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            url = "https://" + BUCKET_NAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }
}

Controller

@RestController
public class FileUploadController {

    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file) throws Exception {
        //把文件的内容存储到本地磁盘
        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
//        file.transferTo(new File("C:\\Users\\23117\\Desktop\\files\\"+originalFilename));
        String url = AliOssUtil.uploadFile(fileName, file.getInputStream());
        return Result.success(url);
    }
}

Redis主动失效令牌

令牌主动失效机制

● 登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中。

● LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中存储的与之相同的令牌。

● 当用户修改密码成功后,删除redis中存储的旧令牌。

登录

@PostMapping("/login")
public Result<String> login(String username,String password) {

   		//业务逻辑...
    
        String token = JwtUtil.genToken(claims);
        //把 token 存储到 redis 中
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
    //redis存储令牌 key 和 value 都是 token
        operations.set(token,token,1, TimeUnit.HOURS);//TimeUnit.HOURS 是 redis key 的过期时间单位
        return Result.success(token);
    

  		//业务逻辑...
}

更换密码【此时需要主动删除redis中的token】

@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody Map<String, String> parms,@RequestHeader("Authorization") String token) {
  
  	//业务逻辑...
  	
    userService.updatePwd(newPwd);//更新新密码
    
    //删除redis对应的token
    ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
    operations.getOperations().delete(token);

    return Result.success();
}

拦截器

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //令牌验证
    String token = request.getHeader("Authorization");
    try {
        //获取redid key
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        String redisToken = operations.get(token);
        if (redisToken == null){
            //token 已经失效
            throw new RuntimeException();
        }

        Map<String, Object> claims = JwtUtil.parseToken(token);
        ThreadLocalUtil.set(claims);
        //放行
        return true;
    } catch (Exception e) {
        response.setStatus(401);
        //不放行
        return false;
    }
}

SpringBoot项目部署

需要pom.xml文件加入打包插件

<build>
    <plugins>
    <!--  打包插件-->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>3.3.0</version>
      </plugin>
    </plugins>
  </build>

在maven生命周期中点击 package生成jar

在对应环境部署 java -jar 【 jar的名字 】

SpringBoot配置方式

SpringBoot多环境开发

  • SpringBoot多环境开发需要分开发环境、测试环境、生产环境

SpringBoot多环境开发单文件配置

#通用信息,指定生效的环境
spring:
  profiles:
    active: dev
server:
  servlet:
    context-path: /aaa

---

#开发环境
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/big_event
    username: root
    password: zy
  servlet:
    multipart:
      max-file-size: 5MB
  data:
    redis:
      host: localhost
      port: 6379
  config:
    activate:
      on-profile: dev
mybatis:
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名/下划线命名转换
server:
  port: 8081

---

#测试环境
spring:
  config:
    activate:
      on-profile: test
server:
  port: 8082

---

#生产环境
spring:
  config:
    activate:
      on-profile: pro
server:
  port: 8084

SpringBoot多环境开发多文件配置

application.yml

#通用信息,指定生效的环境
spring:
  profiles:
    active: test
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/big_event
    username: root
    password: zy
server:
  servlet:
    context-path: /aaa

application-dev.yml

#开发环境
config:
  activate:
    on-profile: dev
server:
  port: 8081

application-pro.yml

#生产环境
spring:
  config:
    activate:
      on-profile: pro
server:
  port: 8084

application-test.yml

#测试环境
spring:
  config:
    activate:
      on-profile: test
server:
  port: 8082

SpringBoot多环境开发多文件配置-分组

application.yml

#通用信息,指定生效的环境
spring:
  profiles:
    group:
      "dev": devService,devDB,devSelf
    active: dev

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/big_event
    username: root
    password: zy
server:
  servlet:
    context-path: /aaa

application-devService

#开发环境
server:
  port: 8085

application-devDb

#数据库相关配置

application-devSelf

#自定义相关配置

项目参考:
B站:BV14z4y1N7pg

热门相关:我在镇夜司打开地狱之门   九阳剑圣   侯门弃女之妖孽丞相赖上门   帝少宠妻有点甜   贩罪