Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.dromara.hutool.http.server.HttpServerResponse Maven / Gradle / Ivy
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.http.server;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.net.url.UrlEncoder;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.meta.ContentType;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.HttpStatus;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
/**
* Http响应对象,用于写出数据到客户端
*/
@SuppressWarnings("resource")
public class HttpServerResponse extends HttpServerBase {
private Charset charset;
/**
* 是否已经发送了Http状态码,如果没有,提前写出状态码
*/
private boolean isSendCode;
/**
* 构造
*
* @param httpExchange {@link HttpExchange}
*/
public HttpServerResponse(final HttpExchange httpExchange) {
super(httpExchange);
}
/**
* 发送HTTP状态码,Content-Length为0不定长度,会输出Transfer-encoding: chunked
*
* @param httpStatusCode HTTP状态码,见HttpStatus
* @return this
*/
public HttpServerResponse send(final int httpStatusCode) {
return send(httpStatusCode, 0);
}
/**
* 发送成功状态码
*
* @return this
*/
public HttpServerResponse sendOk() {
return send(HttpStatus.HTTP_OK);
}
/**
* 发送成功状态码
*
* @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
* @return this
* @since 5.5.7
*/
public HttpServerResponse sendOk(final int bodyLength) {
return send(HttpStatus.HTTP_OK, bodyLength);
}
/**
* 发送404错误页
*
* @param content 错误页页面内容,默认text/html类型
* @return this
*/
public HttpServerResponse send404(final String content) {
return sendError(HttpStatus.HTTP_NOT_FOUND, content);
}
/**
* 发送错误页
*
* @param errorCode HTTP错误状态码,见HttpStatus
* @param content 错误页页面内容,默认text/html类型
* @return this
*/
public HttpServerResponse sendError(final int errorCode, final String content) {
send(errorCode);
setContentType(ContentType.TEXT_HTML.toString());
return write(content);
}
/**
* 发送HTTP状态码
*
* @param httpStatusCode HTTP状态码,见HttpStatus
* @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
* @return this
*/
public HttpServerResponse send(final int httpStatusCode, final long bodyLength) {
if (this.isSendCode) {
throw new IORuntimeException("Http status code has been send!");
}
try {
this.httpExchange.sendResponseHeaders(httpStatusCode, bodyLength);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
this.isSendCode = true;
return this;
}
/**
* 获得所有响应头,获取后可以添加新的响应头
*
* @return 响应头
*/
public Headers getHeaders() {
return this.httpExchange.getResponseHeaders();
}
/**
* 添加响应头,如果已经存在,则追加
*
* @param header 头key
* @param value 值
* @return this
*/
public HttpServerResponse addHeader(final String header, final String value) {
getHeaders().add(header, value);
return this;
}
/**
* 设置响应头,如果已经存在,则覆盖
*
* @param headerName 头key
* @param value 值
* @return this
*/
public HttpServerResponse setHeader(final HeaderName headerName, final String value) {
return setHeader(headerName.getValue(), value);
}
/**
* 设置响应头,如果已经存在,则覆盖
*
* @param header 头key
* @param value 值
* @return this
*/
public HttpServerResponse setHeader(final String header, final String value) {
getHeaders().set(header, value);
return this;
}
/**
* 设置响应头,如果已经存在,则覆盖
*
* @param header 头key
* @param value 值列表
* @return this
*/
public HttpServerResponse setHeader(final String header, final List value) {
getHeaders().put(header, value);
return this;
}
/**
* 设置所有响应头,如果已经存在,则覆盖
*
* @param headers 响应头map
* @return this
*/
public HttpServerResponse setHeaders(final Map> headers) {
getHeaders().putAll(headers);
return this;
}
/**
* 设置Content-Type头,类似于:text/html;charset=utf-8
* 如果用户传入的信息无charset信息,自动根据charset补充,charset设置见{@link #setCharset(Charset)}
*
* @param contentType Content-Type头内容
* @return this
*/
public HttpServerResponse setContentType(String contentType) {
if (null != contentType && null != this.charset) {
if (!contentType.contains(";charset=")) {
contentType = ContentType.build(contentType, this.charset);
}
}
return setHeader(HeaderName.CONTENT_TYPE, contentType);
}
/**
* 设置Content-Length头
*
* @param contentLength Content-Length头内容
* @return this
*/
public HttpServerResponse setContentLength(final long contentLength) {
return setHeader(HeaderName.CONTENT_LENGTH, String.valueOf(contentLength));
}
/**
* 设置响应的编码
*
* @param charset 编码
* @return this
*/
public HttpServerResponse setCharset(final Charset charset) {
this.charset = charset;
return this;
}
/**
* 设置属性
*
* @param name 属性名
* @param value 属性值
* @return this
*/
public HttpServerResponse setAttr(final String name, final Object value) {
this.httpExchange.setAttribute(name, value);
return this;
}
/**
* 获取响应数据流
*
* @return 响应数据流
*/
public OutputStream getOut() {
if (!this.isSendCode) {
sendOk();
}
return this.httpExchange.getResponseBody();
}
/**
* 获取响应数据流
*
* @return 响应数据流
*/
public PrintWriter getWriter() {
final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
return new PrintWriter(new OutputStreamWriter(getOut(), charset));
}
/**
* 写出数据到客户端
*
* @param data 数据
* @param contentType Content-Type类型
* @return this
*/
public HttpServerResponse write(final String data, final String contentType) {
setContentType(contentType);
return write(data);
}
/**
* 写出数据到客户端
*
* @param data 数据
* @return this
*/
public HttpServerResponse write(final String data) {
final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
return write(ByteUtil.toBytes(data, charset));
}
/**
* 写出数据到客户端
*
* @param data 数据
* @param contentType 返回的类型
* @return this
*/
public HttpServerResponse write(final byte[] data, final String contentType) {
setContentType(contentType);
return write(data);
}
/**
* 写出数据到客户端
*
* @param data 数据
* @return this
*/
public HttpServerResponse write(final byte[] data) {
final ByteArrayInputStream in = new ByteArrayInputStream(data);
return write(in, in.available());
}
/**
* 返回数据给客户端
*
* @param in 需要返回客户端的内容
* @param contentType 返回的类型
* @return this
* @since 5.2.6
*/
public HttpServerResponse write(final InputStream in, final String contentType) {
return write(in, 0, contentType);
}
/**
* 返回数据给客户端
*
* @param in 需要返回客户端的内容
* @param length 内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
* @param contentType 返回的类型
* @return this
* @since 5.2.7
*/
public HttpServerResponse write(final InputStream in, final int length, final String contentType) {
setContentType(contentType);
return write(in, length);
}
/**
* 写出数据到客户端
*
* @param in 数据流
* @return this
*/
public HttpServerResponse write(final InputStream in) {
return write(in, 0);
}
/**
* 写出数据到客户端
*
* @param in 数据流
* @param length 指定响应内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
* @return this
*/
public HttpServerResponse write(final InputStream in, final int length) {
if (!isSendCode) {
sendOk(Math.max(0, length));
}
OutputStream out = null;
try {
out = this.httpExchange.getResponseBody();
IoUtil.copy(in, out);
} finally {
IoUtil.closeQuietly(out);
IoUtil.closeQuietly(in);
}
return this;
}
/**
* 返回文件给客户端(文件下载)
*
* @param file 写出的文件对象
* @return this
* @since 5.2.6
*/
public HttpServerResponse write(final File file) {
return write(file, null);
}
/**
* 返回文件给客户端(文件下载)
*
* @param file 写出的文件对象
* @param fileName 文件名
* @return this
* @since 5.5.8
*/
public HttpServerResponse write(final File file, String fileName) {
final long fileSize = file.length();
if(fileSize > Integer.MAX_VALUE){
throw new IllegalArgumentException("File size is too bigger than " + Integer.MAX_VALUE);
}
if(StrUtil.isBlank(fileName)){
fileName = file.getName();
}
final String contentType = FileUtil.getMimeType(fileName, ContentType.OCTET_STREAM.getValue());
BufferedInputStream in = null;
try {
in = FileUtil.getInputStream(file);
write(in, (int)fileSize, contentType, fileName);
} finally {
IoUtil.closeQuietly(in);
}
return this;
}
/**
* 返回文件数据给客户端(文件下载)
*
* @param in 需要返回客户端的内容
* @param contentType 返回的类型
* @param fileName 文件名
* @since 5.2.6
*/
public void write(final InputStream in, final String contentType, final String fileName) {
write(in, 0, contentType, fileName);
}
/**
* 返回文件数据给客户端(文件下载)
*
* @param in 需要返回客户端的内容
* @param length 长度
* @param contentType 返回的类型
* @param fileName 文件名
* @return this
* @since 5.2.7
*/
public HttpServerResponse write(final InputStream in, final int length, final String contentType, final String fileName) {
final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
if (!contentType.startsWith("text/")) {
// 非文本类型数据直接走下载
setHeader(HeaderName.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", UrlEncoder.encodeAll(fileName, charset)));
}
return write(in, length, contentType);
}
}