访问接口–指定时间限制次数
1.maven引入2个依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.9</version>
</dependency>
2.创建一个注解
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD) // 说明该注解只能放在方法上面
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitRequest {
long time() default 6000; // 限制时间 单位:毫秒
int count() default 1; // 允许请求的次数
}
3.创建一个切面
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class LimitRequestAspect {
private static ConcurrentHashMap<String, ExpiringMap<String, Integer>> book = new ConcurrentHashMap<>();
// 定义切点
// 让所有有@LimitRequest注解的方法都执行切面方法
@Pointcut("@annotation(limitRequest)")
public void excudeService(LimitRequest limitRequest) {
}
@Around("excudeService(limitRequest)")
public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable {
// 获得request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
// 获取Map对象, 如果没有则返回默认值
// 第一个参数是key, 第二个参数是默认值
ExpiringMap<String, Integer> uc = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
Integer uCount = uc.getOrDefault(request.getRemoteAddr(), 0);
String requestURI = request.getRequestURI();
String remoteAddr = request.getRemoteAddr();
if (uCount >= limitRequest.count()) { // 超过次数,不执行目标方法
return "接口请求超过次数";
} else if (uCount == 0) { // 第一次请求时,设置有效时间
/** Expires entries based on when they were last accessed */
// ACCESSED,
/** Expires entries based on when they were created */
// CREATED;
uc.put(request.getRemoteAddr(), uCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS);
} else { // 未超过次数, 记录加一
uc.put(request.getRemoteAddr(), uCount + 1);
}
book.put(request.getRequestURI(), uc);
// result的值就是被拦截方法本身的返回值
Object result = pjp.proceed();
return result;
}
}
4.放在任意一个方法上就行,可以自定义时间次数,这个是以请求方ip作为标志
@RequestMapping("/test")
@LimitRequest(time = 2000,count = 2)
public String testController() {
return "hello";
}
网页显示资源–图片或json文件
json
@GetMapping("/json/{path}")
public ResponseEntity<FileSystemResource> json(@PathVariable String path) {
ResponseEntity<FileSystemResource> body = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(new FileSystemResource("C:\\Users\\Administrator\\Desktop\\" + path));
return body;
}
图片
@GetMapping("/pic/{path}")
public ResponseEntity<FileSystemResource> pic(@PathVariable String path) {
ResponseEntity<FileSystemResource> body = ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(new FileSystemResource("C:\\Users\\Administrator\\Desktop\\" + path));
return body;
}
这样就只需要修改:C:\Users\Administrator\Desktop\
如果显示txt文件,可能出现中文乱码,在yml里设置
#设置网页编码为UTF-8
server:
servlet:
encoding:
charset: UTF-8
force: true
enabled: true
提供文件下载
比如一个docx文件——文档.docx
@GetMapping("/doc/{path}")
public ResponseEntity<FileSystemResource> download(@PathVariable String path) throws UnsupportedEncodingException {
String contentDisposition = ContentDisposition
.builder("attachment") //表示提供下载
.filename(path) //文件下载后显示的名字
.build().toString();
String encode = URLEncoder.encode(contentDisposition, StandardCharsets.UTF_8.toString()); //转换成URL编码,以免filename无法显示中文
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, encode)
.contentType(MediaType.TEXT_PLAIN)
.body(new FileSystemResource("C:\\Users\\Administrator\\Desktop\\" + path));
}
下载后标题、正文编码正常
修改图片hash,并随机命名(支持单张复制为多张,或者多张批量修改)
public class ChangeHash {
/**
* 同一图片改变hash,并随机命名
* 依赖hutool
*
* @param count 需要复制多少张,单次不要超过9999张
* @param filePath 原始照片地址
* @param outDir 新照片输出文件夹
* @param length 随机生成的文件名长度
*/
public static void changeHashForSinglePic(int count, String filePath, String outDir, int length) {
//确保为标准的文件格式
outDir += FileUtil.FILE_SEPARATOR;
for (int i = 1; i <= count; i++) {
//轻微调整压缩比小数点后2位开始的值,
double a = 0.9 + i * 0.00001;
Img.from(FileUtil.file(filePath))
.setQuality(a)//压缩比率,改变hash值,同时随机生成指定位数文件名(数字、字符)
.write(FileUtil.file(outDir + RandomUtil.randomString(length) + ".jpg"));
}
}
/**
* 批量改变多张照片的hash值,可以重命名,也可以不用
* 依赖hutool
*
* @param fileDir 原始照片的文件夹
* @param outDir 输出照片的文件夹
* @param rate 压缩比率,建议0.9
* @param isRename 是否随机生成字符串用于重命名,如果填false。length可以填0
* @param length 如果重命名,随机字符串长度
*/
public static void changeHashForMultiPic(String fileDir, String outDir, double rate, boolean isRename, int length) {
//确保为标准的文件格式
fileDir += FileUtil.FILE_SEPARATOR;
outDir += FileUtil.FILE_SEPARATOR;
//获取所有原始照片的名字
List<String> fileNames = FileUtil.listFileNames(fileDir);
for (String fileName : fileNames) {
//重命名
if (isRename) {
FileUtil.mkdir(outDir);
Img.from(FileUtil.file(fileDir + fileName))
.setQuality(rate)//压缩比率,改变hash值,同时随机生成指定位数文件名(数字、字符)
.write(FileUtil.file(outDir + RandomUtil.randomString(length) + ".jpg"));
} else {
FileUtil.mkdir(outDir);
Img.from(FileUtil.file(fileDir + fileName))
.setQuality(rate)//压缩比率,改变hash值,按原文件名命名
.write(FileUtil.file(outDir + fileName));
}
}
}
}