需求
通过访问特定接口,生成动态URL,保证该URL一次有效
背景
一般情况下写Controller都是先在类上声明一个@RestController或是@Controller,然后在方法上加上url路径即可,其实也可以动态注册的,不用写@Controller,只写方法,可以在系统启动后,动态注册,动态移除。
SpringBoot最终会把"请求映射"封装在一个map中,所以我们也可以直接往这个map中存信息即可,这里的"请求"就是请求地址的url,"映射"就是把这个url的响应交给某个方法。
所以我们需要两个信息,url和具体的响应方法。
SpringBoot把他封装为RequestMappingInfo,那首先要做的就是构建RequestMappingInfo,但是他的构造方法非常的麻烦,好在提供了内部Builder类。
案例
- 动态文件下载地址,使用后销毁
@RestController
public class GenController {
private static Map<String, String> cache = new ConcurrentHashMap<>(3);
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
@GetMapping(value = "/test/gen")
public String genUrl() {
String path = "/tt/" + UUID.randomUUID().toString() + "/asdsasd/" + UUID.randomUUID().toString();
RequestMappingInfo requestMappingInfo = RequestMappingInfo
.paths(path)
.methods(RequestMethod.GET)
.build();
try {
requestMappingHandlerMapping.registerMapping(requestMappingInfo, "genController", GenController.class.getDeclaredMethod("sendDataToApp"));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
cache.put(path, UUID.randomUUID().toString());
return path;
}
public String sendDataToApp() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
HttpServletResponse response = servletRequestAttributes.getResponse();
String filePath = "./algoxy-zh-cn.pdf";
File file = new File(filePath);
response.reset();
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
byte[] buff = new byte[1024];
OutputStream os = response.getOutputStream();
int i = 0;
while ((i = bis.read(buff)) != -1) {
os.write(buff, 0, i);
os.flush();
}
} catch (IOException e) {
return "下载失败";
}
RequestMappingInfo mappingInfo = RequestMappingInfo.paths(request.getRequestURI()).methods(RequestMethod.GET).build();
//执行删除注册逻辑
requestMappingHandlerMapping.unregisterMapping(mappingInfo);
return "下载完成";
}
}