前言
本文将深入探讨 JWT(JSON Web Token)的组成与使用,以及 Redis 的依赖配置和文件操作功能。此外,我们还将列举一些常见的 HTTP 请求错误代码,并详细解释 @RequestParam 与 @PathVariable 等参数注解的区别与用法。
jwt
组成
一个token 有 3 部分 头部 (header) 载荷 (plyload) 签证 (signature) 三部分 之间 用 . 号 分隔
依赖
<!--jwt--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
创建工具类
@Component public class TokenUtils { /** * 返回的 则为生成的token */ public static String genToken(String userId, String sign) { return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷 .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期 .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥 } }
String token = TokenUtils.genToken(one.getId().toString(), one.getPassword()); userDTO.setToken(token);
拦截器
package com.example.springboot.utils.intercepter; import cn.hutool.core.util.StrUtil; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.example.springboot.common.Constants; import com.example.springboot.exception.ServiceException; import com.example.springboot.pojo.User; import com.example.springboot.server.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class JwtInterceptor implements HandlerInterceptor { @Autowired UserService userService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 前端的 token String token = request.getHeader("token"); // 如果 不是 映射方法 则 直接 通过 if(!(handler instanceof HandlerMethod)){ return true; } // 执行 认证 if(StrUtil.isBlank(token)){ throw new ServiceException(Constants.CODE_401,"无token,请重新登录"); } // 获取 token 的 user id String userId; try{ userId= JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } User user = userService.getById(userId); if(user == null){ throw new ServiceException(Constants.CODE_401,"用户不存在,请重新登录"); } // 用户密码 加 签 验证 token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try{ jwtVerifier.verify(token); } catch (JWTVerificationException e) { throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } return true; } }
配置类
package com.example.springboot.config; import com.example.springboot.utils.intercepter.JwtInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 需要通过 注入 的 方式 registry.addInterceptor(jwtInterceptor2()) .addPathPatterns("/**") // 拦截所有请求,通过判断token是否合法来决定是否需要登录 .excludePathPatterns("/user/login", "/user/register", "/**/export", "/**/import","/echarts/example"); } // 创建一个bean @Bean public JwtInterceptor jwtInterceptor2(){ return new JwtInterceptor(); } }
redis
依赖
<!-- redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
在yaml 里面 使用
spring: redis: host: 127.0.0.1 password: 123456 port: 6379 database: 1
文件操作
fileMapper
package com.example.springboot.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.springboot.pojo.Files; public interface FileMapper extends BaseMapper<Files> { }
upload
yaml
编辑 储存 文件 的 路径
files: upload: path: E:/springBootLearn/sys_file/
导入路径
@Value("${files.upload.path}") private String fileUploadPath;
使用
@PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) throws IOException { // 文件 名字 String originFileName = file.getOriginalFilename(); // 类型 String type = FileUtil.extName(originFileName); // 大小 long size = file.getSize(); // 判断 配置的文件 路径 是否 存在 不存在则 新建 File uploadParentFile = new File(fileUploadPath); if(!uploadParentFile.exists()){ uploadParentFile.mkdirs(); } // 定义 一个 文件 唯一 的 标识码 String uuid = IdUtil.fastSimpleUUID(); File uploadFile = new File(fileUploadPath + uuid + StrUtil.DOT + type); // 把 获取 到 的文件 存到 磁盘 file.transferTo(uploadFile); return "成功"; }
hutool
<!-- hutool--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.5.11</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency>
优化 使用上 MD5 来 判断 文件 唯一性
// 通过文件的MD5 查询文件 private Files getFileByMd5(String md5){ // 查询数据库中 的 md5 QueryWrapper<Files> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("md5", md5); List<Files> filesList = fileMapper.selectList(queryWrapper); return filesList.size() == 0 ? null : filesList.get(0); }
down
// 文件下载 路径 和 对应的接口是一样 的 // String url = "http://localhost:8081/file/"+fileUUID; // uuid id @GetMapping("/{fileUUID}") public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException { // 设置 文件 唯一 标识码 获取文件 File uploadFile = new File(fileUploadPath + fileUUID); // 设置文件 输出 流 格式 ServletOutputStream out=response.getOutputStream(); response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileUUID, StandardCharsets.UTF_8)); response.setContentType("application/octet-stream"); // 读取文件 字节 流 out.write(FileUtil.readBytes(uploadFile)); out.flush(); out.close(); } }
删除和批量删除
// 删除 @DeleteMapping("/{id}") public Result delete(@PathVariable Integer id){ // 在 类中找到 唯一的 id Files files= fileMapper.selectById(id); // 将文件删除 设置为 true files.setIsDelete(true); // 更新 数据 fileMapper.updateById(files); return Result.success(); }
// 批量删除 @PostMapping("/del/batch") // select * from sys_file where id in (id,id,id) public Result deleteBatch(@RequestBody List<Integer>ids){ //[1,2,3] // 实例化一个 查函数的方法 QueryWrapper<Files> queryWrapper = new QueryWrapper<>(); // id in id 查 找 选择的 id queryWrapper.in("id",ids); // 查找函数 一个 列表 List<Files> files = fileMapper.selectList(queryWrapper); for (Files file : files) { // 选中 的 都 设置 为 true file.setIsDelete(true); // 将 选中 的 id 都 更新 fileMapper.updateById(file); } return Result.success(); }
取用或 不取用
// 更新enable 字段 @PostMapping("/update") public Result update(@RequestBody Files files){ // 新增或则 更新 都在里面 return Result.success(fileMapper.updateById(files)); }
常见请求错误代码
400 请求无效,服务器无法处理 401 未经 授权,无身份验证 403 服务器 拒绝请求,没有权限 404 请求资源 不存在 405 请求 方法不允许,使用了错误的请求方式 408 请求超时 500 服务器错误 503 服务器暂时无法处理 请求 也可以自定义
参数注解
@RequestParam
和 @PathVariable
注解是用于从request中接收请求的,两个都可以接收参数,关键点不同的是@RequestParam
是从request里面拿取值,而 @PathVariable
是从一个URI模板里面来填充
@RequestParam 看下面一段代码: http://localhost:8080/springmvc/hello/101?param1=10¶m2=20 根据上面的这个URL,你可以用这样的方式来进行获取 public String getDetails( @RequestParam(value="param1", required=true) String param1, @RequestParam(value="param2", required=false) String param2){} @RequestParam 支持下面四种参数 defaultValue 如果本次请求没有携带这个参数,或者参数为空,那么就会启用默认值 name 绑定本次参数的名称,要跟URL上面的一样 required 这个参数是不是必须的 value 跟name一样的作用,是name属性的一个别名
@PathVariable 这个注解能够识别URL里面的一个模板,我们看下面的一个URL http://localhost:8080/springmvc/hello/101?param1=10¶m2=20 1 上面的一个url你可以这样写: @RequestMapping("/hello/{id}") public String getDetails(@PathVariable(value="id") String id, @RequestParam(value="param1", required=true) String param1, @RequestParam(value="param2", required=false) String param2){}
@PathParam 这个注解是和spring的pathVariable是一样的,也是基于模板的,但是这个是jboss包下面的一个实现,上面的是spring的一个实现,都要导包 @QueryParam @QueryParam 是 JAX-RS 本来就提供的,和Spring的RequestParam作用一致 @ResponseBody responseBody表示服务器返回的时候以一种什么样的方式进行返回, 将内容或对象作为 HTTP 响应正文返回,值有很多,一般设定为json @RequestBody 一般是post请求的时候才会使用这个请求,把参数丢在requestbody里面