韩源-末日生存手册 - 工具
type: channel
link: https://kerryhan.cn/index.php/tag/工具/
items: FastDFS分布式文件系统之防盗链权限控制
items: 基于过滤拦截技术实现的身份认证方案
items: MockMvc详解
items: springboot+mybatisPlus代码层级梳理
items: Aop和MockMvc学习

FastDFS分布式文件系统之防盗链权限控制
type: item
date: 2023-10-26T07:45:38+00:00
description: 问题所在FastDFS采用的是tracker和storage的模式。tracker负责负载均衡storage负责文件存储、文件同步、提供文件访问接口（也就是说用户要从storage直接获取文件）其实，storage的http端口是开着的，外界只要知道端口和文件路径信息就可以直接访问到文件。这种操作，对于文件而言是不安全的。解决方式在storage上配置访问规则，打开防盗链功能，首先要确保不能直接访问到文件。其次，限制访问文件时必须带有一个本地应用服务器生成的token，这个token需要有文件id、自己设置的密钥、时间戳三个部分组成。但是只有本地应用服务器保存密钥是不可行的，需要把密钥同时保存到storage上，用于token的解密验证工作。配置storage进入etc/fdfs，编辑http.conf文件编辑后的内容Javaresources下新建fdfs_cilent.conf文件#默认值为30s connect_timeout = 10 #默认值为30s network_timeout = 30 charset = UTF-8 #tracker的http端口 http.tracker_http_port = 8888 #服务器 tracker_server = 192.168.1.106:22122 #开启防盗链，防盗链密钥 http.anti_steal_token = true http.secret_key= 密钥主要的工具类文件/** * 上传下载等文件操作工具类 */ public class FastDFSClient { private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class); /*** * 初始化加载FastDFS的TrackerServer配置 */ static { try { String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath(); ClientGlobal.init(filePath); } catch (Exception e) { logger.error("FastDFS Client Init Fail!",e); } } public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, MyException { String fileName = "M00/00/00/wKgBa2U4dPSAO7fXAAC5PC_5iKw01.docx"; String groupName = "group1"; String sourceUrl = getSourceUrl(groupName,fileName); System.out.println(sourceUrl); } public static FastDFSFile getFastDFSFile(MultipartFile file,String author) { InputStream inputStream = null; //获取文件名称（带有后缀） String allFileName = file.getOriginalFilename(); //获取文件扩展名 String ext = ""; byte[] content = null; if (allFileName != null && !"".equals(allFileName)) { ext = (allFileName.substring(allFileName.lastIndexOf("."))).replaceAll("\\.",""); } //文件名称（不带后缀） String fileName = allFileName.replaceAll("." + ext, ""); try { inputStream = file.getInputStream(); //获取文件所有的字节内容 content = inputStream.readAllBytes(); //一定要关闭输入流，不然会报错 inputStream.close(); } catch (IOException e) { throw new CustomException("文件上传错误", ResultCode.UPLOAD_ERROR); } //创建文件实体类对象 FastDFSFile fastDFSFile…

基于过滤拦截技术实现的身份认证方案
type: item
date: 2022-03-20T04:58:00+00:00
description: 基于过滤拦截技术实现的身份认证方案系统基本流程用户发送请求过滤器过滤掉，访问需要保持登录状态的资源但是又没有携带token的请求拦截器拦截掉，访问需要具备相应权限的资源但是又没有对应权限的请求进入业务逻辑代码层级configMyFilterConfig：自定义过滤器的基础配置，对所有资源都进行过滤MyInterceptorConfig：自定义拦截器的基础配置，设置所需拦截的放行的URLcontrollerUserController：接口层entityUser：用户的实体对象。目前为了简化操作，不必新建权限表，所以在用户的实体对象里存放了list<String>集合，即用户的属性里就带着用户的所有权限信息filter：MyFilter：自定义过滤器，这块主要是判断用户请求有没有携带token，如果没有携带token，而且还访问的是需要携带token(即保持登录)的接口，那么就过滤掉用户的这次请求。但是，有的资源是属于开放资源，即不需要用户保持登录状态，因此，在这个模块，做了白名单列表，过滤器不对白名单列表进行过滤。interceptorMyInterceptor：自定义拦截器，这块主要是拦截需要权限的接口，获取用户的token，并且解析出用户权限信息，拿用户权限信息和接口所需权限进行比对，失败则拒绝，成功则让请求进行接口层。serviceUserService：接口所对应的具体业务逻辑，这块目前主要是有判断用户名密码，进而生成token，返回前端。utilJWTUtil：JWT工具类，可以用于生成JWT，解密JWT

MockMvc详解
type: item
date: 2020-05-11T15:18:00+00:00
description: MockMvc详解MockMvc是什么简单来说，对于web应用来讲，你需要对你的各个模块进行测试，但是通过启动项目使用postman来测试的话比较麻烦（程序启动速度慢，测试验证不方便，依赖网络环境），那么为了使我们的单元测试更加简单、高效，我们引入了MockMvcMockMvc实现了对于Http请求的模拟，能够直接使用网络的形式，转换到contoller的调用，可以使得测试速度快、不依赖网络环境，而且还提供了专门的一套验证的工具。测试的逻辑MockMvcBuilder构造MockMvc的构造器MockMvc调用perform，执行一个RequestBuilder请求，调用controller的业务处理逻辑perform返回ResultActions,返回操作的结果，通过ResultActions，提供了统一的验证方式使用StatusResultMatchers对请求结果进行验证使用ContentResultMatchers对请求的内容进行验证如何获取mockMvc实例两个获取mockMvc实例的方式：StandaloneMockMvcBuilderDefaultMockMvcBuilder具体实现方式：MockMvcBuilders.webAppContextSetup(WebApplicationContext context)指定WebApplicationContext，将会从该上下文获取相应的控制器并得到相应的MockMvcMockMvcBuilders.standaloneSetup(Object... controllers)通过参数指定一组控制器，这样就不需要从上下文获取了比如this.mockMvc = MockMvcBuilders.standaloneSetup(this.controller).build();## 构造请求——MockMvcRequestBuilders构造请求示例：MockMvcRequestBuilders.get("/user")MockMvcRequestBuilders主要APIMockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables)：根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder；如get(/user/{id}, 1L)； MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables)：同get类似，但是是POST方法； MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables)：同get类似，但是是PUT方法； MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) ：同get类似，但是是DELETE方法； MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables)：同get类似，但是是OPTIONS方法； MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables)： 提供自己的Http请求方法及uri模板和uri变量，如上API都是委托给这个API； MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables)：提供文件上传方式的请求，得到MockMultipartHttpServletRequestBuilder； RequestBuilder asyncDispatch(final MvcResult mvcResult)：创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder； 指定请求参数——MockHttpServletRequestBuilder当然，我们不仅可以设置它的请求方式，同样也可以设置它的请求参数MockHttpServletRequestBuilder主要APIMockHttpServletRequestBuilder header(String name, Object... values…

springboot+mybatisPlus代码层级梳理
type: item
date: 2020-04-30T14:40:00+00:00
description: 代码层级梳理代码层级annotation层ExcelVoAttribut主要用于写@ExcelVoAttribute注解，可以更灵活的配置Excel数据表导出的一些基本配置LogDirection主要用于写@LogDirection注解，注解里包含一个字段（接口描述），通过接口添加这个注解，填写上接口的功能，当用户在访问接口时候，可以利用aop技术，把用户的操作记到日志里aspect层LogDrectionAspect主要定义了aop切点的位置和增强的方法/** * @Author Johnny * @Date 2020/4/16 * @Version 1.0 */ @Aspect @Component @Slf4j public class LogDirectionAspect { @Pointcut("@annotation(logDirection)") public void doLogDirection(LogDirection logDirection){ } @Around(value = "doLogDirection(logDirection)",argNames = "pjp,logDirection") public Object doBefore(ProceedingJoinPoint pjp,LogDirection logDirection) throws Throwable{ if (!"".equals(logDirection.direction())) { log.info(logDirection.direction()+"接口被调用"); return pjp.proceed(); } return "接口信息不规范"; } }@Pointcut定义切点，此处定义切点为使用@LogDirection的方法@Around定义增强的方法，通过around的参数ProceedingJoinPoint可以很好的控制程序能不能继续执行下一步，在权限判定发挥着比较重要的作用拓展：利用下面的这种方法，需要在xml文件中配置bean实例，当然也可以在方法中通过手动扫包的方法获得bean实例进行操作/** * @Author Johnny * @Date 2020/4/16 * @Version 1.0 */ @Aspect public class MyAdvice { /** * 配置切点 */ @Pointcut("execution(* com.soft1851.spring.web.dao..*.insert*(..))") public void pointCut() { } /** * 配置前置增强 */ @Before("MyAdvice.pointCut()") public void beforeMethod() { System.out.println("等待数据插入"); } /** * 配置后置增强 */ @AfterReturning("execution(* com.soft1851.spring.web.dao..*.*(..))") public void afterMethod(){ System.out.println("关闭数据库"); } }xml配置实例 <bean name="forumDao" class="com.soft1851.spring.web.dao.impl.ForumDaoImpl"/> <bean name="myAdvice" class="com.soft1851.spring.web.interceptor.MyAdvice"/> <aop:aspectj-autoproxy/>common层ResponseResult和ResultCode这两个类可以将响应体统一进行封装，将接口的响应体规范化，使前端获取数据也更加友好贴下代码，防止以后找不到ResponseResult类package com.soft1851.music.admin.common; import lombok.Data; import java.io.Serializable; /** * @author Johnny * @Date: 2020/4/21 19:52 * @Description: */ @Data public class ResponseResult implements Serializable { private static final long serialVersionUID = -3948389268046368059L; private Integer code; private String msg; private Obje…

Aop和MockMvc学习
type: item
date: 2020-04-12T11:37:00+00:00
description: Aop和MockMvc学习Java中的四个元注解@Document@Documented注解标记的元素，Javadoc工具会将此注解标记元素的注解信息包含在javadoc中.默认，注解信息不会包含在Javadoc中@Inherited说明子类可以继承父类中的该注解、示例package org.springmorning.demo.javabase.annotation.meta; import java.lang.annotation.Documented; import java.lang.annotation.Inherited; @Documented @Inherited public @interface Book { String name(); String publishedDate(); String author(); }package org.springmorning.demo.javabase.annotation.meta; @Book( name = "Spring in Action", author = "Johnny", publishedDate = "2020-10-1" ) public class DocumentAnnotation {}@Retention注解的保留位置@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中，在class字节码文件中不包含@Retention(RetentionPolicy.CLASS) // 默认的保留策略，注解会在class字节码文件中存在，但运行时无法获得，@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在，在运行时可以通过反射获取到@Target注解的作用目标@Target(ElementType.TYPE) //接口、类、枚举、注解@Target(ElementType.FIELD) //字段、枚举的常量@Target(ElementType.METHOD) //方法@Target(ElementType.PARAMETER) //方法参数@Target(ElementType.CONSTRUCTOR) //构造函数@Target(ElementType.LOCAL_VARIABLE)//局部变量@Target(ElementType.ANNOTATION_TYPE)//注解@Target(ElementType.PACKAGE) ///包mock示例controller层接口示例@RequestMapping(value = "home") public String home(){ RequestAttributes at = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) at; HttpServletRequest request = sra.getRequest(); Cookie[] cookies = request.getCookies(); String name = ""; String device = request.getHeader("platform"); for (Cookie cookie : cookies) { name = cookie.getValue(); } if(name==null || device==null){ return "I don't know who you are"; } return "Welcome to "+name+" from "+device; }测试方法package com.soft1851.boot.aop.controller; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org…