注意:文件下载这种场景的web请求,不应该由ajax发出,应该以表单提交等方式,比如:
- window.open(downloadUrl); // 这种方式会新打开一个浏览器窗口
- window.location.href = downloadUrl;
Service接口
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
@Path("/service")
public interface IXxxService {
@GET
@Path("/downloadAll")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
Response downloadAll(String dataId, @Context HttpServletRequest req, @Context HttpServletResponse resp) throws Exception;
}
实现类
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.ws.rs.WebApplicationException;
@Service
@Slf4j
public class XxxServiceImpl implements IXxxService {
@Override
public Response downloadAll(String dataId, HttpServletRequest req, HttpServletResponse resp) throws Exception {
String msg = "";
String dataId = req.getParameter("dataId");
// region 省略业务代码不到一万行
// ...
// ...
// ...
// 本场景比较特殊,此处调用的公共方法中,把多个文件先压缩为zip文件,再将zip文件流写入到response的OutputStream中
// 所以需要多做一步,即将字节流从response的OutputStream转入到StreamingOutput中
// 普通场景,或下载单个文件时,可以直接将文件流写入到Response
// ...
// ...
// ...
// endregion
if (正常) {
// region 方式1
// StreamingOutput fileStream = outputStream -> {
// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//
// byteArrayOutputStream.writeTo(resp.getOutputStream());
// outputStream.write(byteArrayOutputStream.toByteArray());
// byteArrayOutputStream.close();
// outputStream.close();
// };
//
//return Response.ok(fileStream).header("Content-Disposition", "attachment; filename=" + URLEncoder.encode("全部下载", "UTF-8") + ".zip").build();
// endregion
// region 方式2
return Response.status(Response.Status.OK).header("Content-Disposition", "attachment; filename=" + URLEncoder.encode("全部下载", "UTF-8") + ".zip").entity( new StreamingOutput() {
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.writeTo(resp.getOutputStream());
outputStream.write(byteArrayOutputStream.toByteArray());
byteArrayOutputStream.close();
outputStream.close();
}
} ).build();
// endregion
// region 方式3
/*return getNoCacheResponseBuilder(Response.Status.OK).entity( new StreamingOutput() {
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.writeTo(resp.getOutputStream());
outputStream.write(byteArrayOutputStream.toByteArray());
//byteArrayOutputStream.close();
outputStream.close();
}
} ).build();*/
// endregion
/*// 附件导出目录
URL resource = this.getClass().getClassLoader().getResource("/");
String classPathDir = resource.getFile().substring(1);
String waterExpDir = classPathDir + File.separator + "expDir" + File.separator + "water";
// 数据文件目录,不存在就创建
File dataDirFile = new File(waterExpDir + File.separator + "datas");
// 压缩文件目录,不存在就创建
File zipDirFile = new File(waterExpDir + File.separator + "zips");
if (!zipDirFile.exists()) {
zipDirFile.mkdirs();
}
File zip = new File(zipDirFile.getPath() + File.separator + "全部附件.zip");
try (OutputStream outputStream= resp.getOutputStream();
InputStream inputStream = Files.newInputStream(zip.toPath())) {
//开始生成压缩文件
zipFiles(dataDirFile.listFiles(), zip);
resp.setContentType("application/zip");
resp.setHeader("Location",zip.getName());
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zip.getName(), "UTF-8"));
byte[] buffer = new byte[1024];
int i;
while ((i = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, i);
}
outputStream.flush();
}*/
}
// 非正常返回
return Response.status(Response.Status.EXPECTATION_FAILED).entity(msg).build();
}
private void zipFiles(File[] srcfile, File zipfile) throws Exception {
byte[] buf = new byte[1024];
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(zipfile.toPath()))) {
for (File file : srcfile) {
try (FileInputStream in = new FileInputStream(file)) {
out.putNextEntry(new ZipEntry(file.getName()));
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.closeEntry();
}
}
}
}
protected Response.ResponseBuilder getNoCacheResponseBuilder(Response.Status status) {
CacheControl cc = new CacheControl();
cc.setNoCache( true );
cc.setMaxAge( -1 );
cc.setMustRevalidate( true );
return Response.status( status ).cacheControl( cc );
}
}
其他示例
// @PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,
@Path("test")
@POST
@Produces(MediaType.APPLICATION_JSON + "; charset=utf-8")
// The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
// public Response test(@HeaderParam("User-Agent") String whichBrowser, @QueryParam("data") String data, @DefaultValue("0")@FormParam("data") String data1, @CookieParam("sessionid") String sessionid, @MatrixParam("data") String data2, @Context InputStream requestBody) {
// public Response test(@Context HttpServletRequest request, @HeaderParam("User-Agent") String whichBrowser, @QueryParam("data") String data, @CookieParam("sessionid") String sessionid, @MatrixParam("data") String data2/*, @Context InputStream requestBody*/) {
//public Response test(@Context HttpServletRequest request) {
// 从请求body里获取参数
public Response test(String data) {
StringBuilder stringBuilder = new StringBuilder();
/*String line;
try (BufferedReader reader = request.getReader();) {
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append('\n');
}
String body = stringBuilder.toString();
System.out.println(body);
} catch (Exception e) {
log.error("出现异常:", e);
}*/
/*StringBuilder out = new StringBuilder();
String line1;
try (BufferedReader reader1 = new BufferedReader(new InputStreamReader(requestBody))) {
while ((line1 = reader1.readLine()) != null) {
out.append(line1);
}
} catch (Exception e) {
log.error("出现异常:", e);
}
System.out.println(out);*/
// return "{\"code\": \"\"}";
return Response.ok().entity("{\"code\": \"Success\"}").build();
}