1 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gzz</groupId>
<artifactId>08-kaptcha</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2 index.html
<!DOCTYPE html>
<html>
<head><meta charset='UTF-8'><title>axios优雅的下载文件</title></head>
<head>
<script type='text/javascript' src='axios.min.js'></script>
</head>
<body>
验证码:<img src="/code" id="image" ><input type="button" value="刷新" onclick="refresh()" /><br>
<a id="file_01" ></a><br>
<input type="button" value="下载" onclick="downFile1()" />
<input type="button" value="下载" onclick="downFile2()" />
<input type="button" value="下载" onclick="downFile3()" />
</body>
<script>
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
axios.interceptors.response.use(res => res.data);
function refresh(){
image.src = "/code?t=" + new Date().getTime();
}
function downFile1() {
let param={id:1,age:2,name:'高振中'}; //对象参数很有用
axios.post('/file_01', param ,{ responseType: "blob" }).then(res => {
file_01.href = window.URL.createObjectURL(new Blob([res], { type: res.type })); //创建下载的链接;
file_01.download = "中文-文件名.xlsx"; //下载后文件名
file_01.click(); //点击下载
});
}
function downFile2() {
axios.post('/file_02', null ,{ responseType: "blob" }).then(res => {
file_01.href = window.URL.createObjectURL(new Blob([res], { type: res.type }));
file_01.download = "中文-文件名.xlsx";
file_01.click();
});
}
function downFile3() {
axios.post('/file_03', null ,{ responseType: "blob" }).then(res => {
file_01.href = window.URL.createObjectURL(new Blob([res], { type: res.type }));
file_01.download = "image.png";
file_01.click();
});
}
</script>
</html>
3 FileController.java
package com.gzz.sys;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gzz.config.Kaptcha;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
/**
* @author https://www.jianshu.com/u/3bd57d5f1074
* @date 2023-02-08 10:50:00
*/
@Slf4j
@RestController
public class FileController {
@Autowired
private ObjectMapper mapper;
@SneakyThrows
@GetMapping("code")
public HttpEntity<byte[]> code() {
String code = Kaptcha.code(); // 放到缓存里
log.info("code={}", code);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new HttpEntity<>(Kaptcha.imageByte(code), headers);
}
@SneakyThrows
@PostMapping("file_01")
public ResponseEntity<byte[]> file_01(@RequestBody User user) {
log.info("user={}", mapper.writeValueAsString(user));
byte[] bytes = Files.readAllBytes(Paths.get(ResourceUtils.getFile("classpath:中文-文件名.xlsx").getPath()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// headers.setContentDispositionFormData("attachment", new String(name.getBytes("GBK"), "ISO8859-1"));
return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
}
@SneakyThrows
@PostMapping("file_03")
public HttpEntity<byte[]> file_03() {
byte[] bytes = Files.readAllBytes(Paths.get(ResourceUtils.getFile("classpath:image.png").getPath()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// headers.setContentDispositionFormData("attachment", name);
return new HttpEntity<byte[]>(bytes, headers);
}
@SneakyThrows
@PostMapping("file_02")
public HttpEntity<byte[]> file_02() {
byte[] bytes = Files.readAllBytes(Paths.get(ResourceUtils.getFile("classpath:中文-文件名.xlsx").getPath()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new HttpEntity<byte[]>(bytes, headers);
}
}
4 User.java
import lombok.Data;
/**
* @author https://www.jianshu.com/u/3bd57d5f1074
* @date 2023-02-08 10:50:00
*/
@Data
public class User {
Integer id;
Integer age;
String name;
}
5 Kaptcha .java
package com.gzz.config;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* @author https://www.jianshu.com/u/3bd57d5f1074
* @date 2023-02-08 10:50:00
*/
public class Kaptcha {
private static final Random RAND = new Random();
private static final int LENGTH = 4; // 验证码位数
private static final int SIZE = 60; // 字号
private static final int WIDTH = 160; // 画板宽
private static final int HEIGHT = 60; // 画板高
private static final BufferedImage IMG = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);// 创建画板
private static final Graphics2D GRAPH = IMG.createGraphics();// 画笔
public static byte[] imageByte(String code) throws IOException {
GRAPH.setColor(color()); // 随机颜色
GRAPH.fillRect(0, 0, WIDTH, HEIGHT); // 0,0,100宽度,30表示高度
GRAPH.setColor(color()); // 随机颜色
GRAPH.setFont(font()); // 随机字体-可选
GRAPH.drawString(code, 10, 50); // 坐标10,50开始画
GRAPH.setStroke(new BasicStroke(2f)); // 画笔
for (int i = 0; i < 6; i++) { // 干扰线-可选
GRAPH.setColor(color());
GRAPH.drawLine(RAND.nextInt(WIDTH), RAND.nextInt(HEIGHT), RAND.nextInt(WIDTH), RAND.nextInt(HEIGHT));// 区域内随机两个点画线
}
for (int i = 0; i < 20; i++) { // 干扰点-可选
GRAPH.setColor(color());
GRAPH.drawOval(RAND.nextInt(WIDTH), RAND.nextInt(HEIGHT), 2, 2);
}
ByteArrayOutputStream stream = new ByteArrayOutputStream(); // 转成字节数组
ImageIO.write(IMG, "jpg", stream);
return stream.toByteArray();
}
// 纯随机字符
public static String code() {
StringBuilder code = new StringBuilder();
for (int i = 0; i < LENGTH; i++) {
switch (RAND.nextInt(3)) {
case 0 -> code.append((char) (RAND.nextInt(26) + 65));
case 1 -> code.append((char) (RAND.nextInt(26) + 97));
case 2 -> code.append(RAND.nextInt(10));
}
}
return code.toString();
}
// 随机字体
private static Font font() {
Font[] fonts = { new Font("微软雅黑", Font.ITALIC, SIZE), //
new Font("新宋体", Font.PLAIN, SIZE), //
new Font("Microsoft YaHei Ul", Font.PLAIN, SIZE), //
new Font("仿宋", Font.PLAIN, SIZE), //
new Font("Cambria", Font.BOLD, SIZE) };
return fonts[RAND.nextInt(fonts.length)];
}
// 随机颜色
private static Color color() {
return new Color(RAND.nextInt(256), RAND.nextInt(256), RAND.nextInt(256));
}
}
6 目录结构
1675783526166.png7 下载地址:
https://gitee.com/gao_zhenzhong/spring-boots/tree/master/ok/66-java/08-kaptcha
8 运行效果
访问地址: http://localhost:8080/
网友评论