SpringBoot实战第五天

最后在开发一个文件上传接口,结束后端部分开发

文件上传接口

先看接口文档

阅读接口文档,唯一问题就是项目暂时还没有传到服务器上,所以对文件的存储与读取暂时在项目本地进行 

Controller层

@RestController
public class FileUploadController {
    @PostMapping("/upload")
    public Result<String> upload(MultipartFile file) throws IOException {
        //获取文件名
        String originalFilename = file.getOriginalFilename();
        //保证文件的名字是唯一的,防止文件覆盖
        String filename = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        //把文件内容存储到本地磁盘
        file.transferTo(new File("H:\\Desktop\\chessmanfile\\"+filename));
        return Result.success("rul地址");
    }
}

 

云存储头像

初见阿里OSS

下面使用阿里云OSS服务来存储头像

有关OSS存储的获取,bucket创建等部分掠过

由于我们写的项目是一个maven项目,根据官网的SDK引导,我们需要导入如下坐标

<!--        阿里云OSS依赖坐标-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.15.1</version>
        </dependency>

官网提示我们,使用1.9版本以上的JDK还需导入JAXB相关坐标

<!--        JAXB相关依赖-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- no more than 2.3.3-->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>

 坐标导入完成后,我们使用官方给的一个示例文件进行测试

如上图,是从阿里云OSS官方示例文件修改而来的测试程序,其中修改了的部分都用下划线标出,第一个要修改的是endpoint,在控制台中可以找到

接下来就是accesskey的id和secret,官方文档给出的方法是将这两个信息配置进系统环境变量中去,这里不采用,直接定义两个变量来 ,再创建OSSClient实例中也作出了相应的修改

接下来就是本身的实例给服务器传入的是content,由于我们要存储的就是头像,所以直接改成传入一个图片来测试

运行了测试程序后在后台可以查看到我们的测试图片已经上传成功,下一步就是将图片的上传集成到我们的程序中去

云存储头像文件集成入程序 

我们书写一个工具类来使用,实际上就是根据上述修改方法对工具类进行仿写

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

    private static final String ACCESS_KEY_ID = "马赛克";
    private static final String ACCESS_KEY_SECRET = "马赛克";
    // 填写Bucket名称,例如examplebucket。
    private static final String BUCKET_NAME = "chessman";

    public static String main(String objectName , InputStream in) throws Exception {
        //初始化URL
        String URL = "";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。


        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SECRET );

        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_INDEX+"/"+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;
    }
}

在main方法的参数中我们传入了文件存储路径和一个字符输入流,对应的替换我们之前在测试时写死的两个地方

还有,我们之前在书写有关头像的接口时都是要获取其URL信息,所以我们要让该方法返回头像对应的URL信息

有关URL组成

https://chessman.oss-cn-beijing.aliyuncs.com/111.jpg

这是刚刚上传的111.jpg的URL,可以看出,URL的组成为

https://BucketName.Endpoint/ObjectName

这一格式

所以我们可以通过字符串的拼接来实现URL的返回

下面就是对刚刚写的文件上传接口进行修改

文件上传接口修改

@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("H:\\Desktop\\chessmanfile\\"+filename));
        String url = AliOSSUtil.uploadFile(filename,file.getInputStream());
        return Result.success(url);
    }
}

至此,后端的所有接口全部构建完毕!!!!!!!!!

完结撒花!

redis登录接口优化

当然,接口书写完毕不代表程序的维护和健壮性增强也到此为止,下面就用redis对登录接口进行优化

问题提出:我们对于用户的身份验证是依靠令牌的识别,但是我们令牌只有一个24小时过期机制,当用户更新了他的密码之后,会生成一个新的令牌,但此时旧令牌没有被我们回收,仍然能使用,我们需要有令牌主动失效机制

令牌主动失效机制

登陆成功后,给浏览器相应令牌的同时,给浏览器相应令牌的同时,把该令牌存储到redis中

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

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

SpirngBoot集成redis

导入spring-boot-starter-data-redis起步依赖

<!--        redis坐标-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

在yml配置文件中,配置redis连接信息

  data:
    redis:
      host: localhost
      port: 6379

调用API(StringRedisTemplate)完成字符串的存取操作

以两个测试方法为例

    @Test
    public void testSet(){
        //redis中存储键值对 StringRedisTemplate
        ValueOperations<String, String> Operations = stringRedisTemplate.opsForValue();
        Operations.set("username","cacb");
        //设置键值对及其过期时间
        Operations.set("timetest","haha" ,15, TimeUnit.SECONDS);
    }

    @Test
    public void tsetGet(){
        //从redis中获取键值对
        ValueOperations<String, String> Operations = stringRedisTemplate.opsForValue();
        System.out.println(Operations.get("username"));
    }

令牌主动失效代码实现

第一步、修改登录接口代码

            //将token存入到redis中
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(token,token,12, TimeUnit.HOURS);
            return Result.success(token);

可以看到,修改就是在成功登录后向页面返回token的同时将token存入到redis中去,这里我设置的键值对过期时间与token过期时间一致 

第二步、修改修改密码接口代码

        userService.updatePwd( newPwd);
        //删除redis中对应的token
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.getOperations().delete(token);

        return Result.success();

可以看到,在成功玩修改了密码之后,要删除掉redis中的旧token,这里token从请求头中获取 

 public Result updatePwd(@RequestBody @Valid Map<String,String> params,@RequestHeader("Authorization") String token)

所以要对修改密码接口的传参进行如上修改 

第三步、修该登录拦截器代码

            //从redis中获取相同的的token
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            String redis_token = operations.get(token);
            if(redis_token == null){
                //此时token已经失效
                throw new RuntimeException();
            }

可以看到,在拦截其中我们将浏览器中获取的token作为键来从redis中获取值,如果查询到的值为空,那么就证明浏览器给出的token已经失效了,所以这时候就要拦截浏览。

至此,redis完善登录相关接口工作就基本完毕了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值