All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.http.server.servlet.ServletUtil Maven / Gradle / Ivy

There is a newer version: 6.0.0.M3
Show newest version
/*
 * 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.servlet;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.bean.copier.CopyOptions;
import org.dromara.hutool.core.bean.copier.ValueProvider;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.exception.HutoolException;
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.map.CaseInsensitiveMap;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.net.NetUtil;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.meta.HttpHeaderUtil;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.http.multipart.MultipartFormData;
import org.dromara.hutool.http.multipart.UploadSetting;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.*;

/**
 * Servlet相关工具类封装
 *
 * @author looly
 * @since 3.2.0
 */
public class ServletUtil {

	// --------------------------------------------------------- getParam start

	/**
	 * 获得所有请求参数
	 *
	 * @param request 请求对象{@link ServletRequest}
	 * @return Map
	 */
	public static Map getParams(final ServletRequest request) {
		final Map map = request.getParameterMap();
		return Collections.unmodifiableMap(map);
	}

	/**
	 * 获得所有请求参数
	 *
	 * @param request 请求对象{@link ServletRequest}
	 * @return Map
	 */
	public static Map getParamMap(final ServletRequest request) {
		final Map params = new HashMap<>();
		for (final Map.Entry entry : getParams(request).entrySet()) {
			params.put(entry.getKey(), ArrayUtil.join(entry.getValue(), StrUtil.COMMA));
		}
		return params;
	}

	/**
	 * 获取请求体
* 调用该方法后,getParam方法将失效 * * @param request {@link ServletRequest} * @return 获得请求体 * @since 4.0.2 */ public static String getBody(final ServletRequest request) { try (final BufferedReader reader = request.getReader()) { return IoUtil.read(reader); } catch (final IOException e) { throw new IORuntimeException(e); } } /** * 获取请求体byte[]
* 调用该方法后,getParam方法将失效 * * @param request {@link ServletRequest} * @return 获得请求体byte[] * @since 4.0.2 */ public static byte[] getBodyBytes(final ServletRequest request) { try { return IoUtil.readBytes(request.getInputStream()); } catch (final IOException e) { throw new IORuntimeException(e); } } // --------------------------------------------------------- getParam end // --------------------------------------------------------- fillBean start /** * ServletRequest 参数转Bean * * @param Bean类型 * @param request ServletRequest * @param bean Bean * @param copyOptions 注入时的设置 * @return Bean * @since 3.0.4 */ public static T fillBean(final ServletRequest request, final T bean, final CopyOptions copyOptions) { final String beanName = StrUtil.lowerFirst(bean.getClass().getSimpleName()); return BeanUtil.fillBean(bean, new ValueProvider() { @Override public Object value(final String key, final Type valueType) { String[] values = request.getParameterValues(key); if (ArrayUtil.isEmpty(values)) { values = request.getParameterValues(beanName + StrUtil.DOT + key); if (ArrayUtil.isEmpty(values)) { return null; } } if (1 == values.length) { // 单值表单直接返回这个值 return values[0]; } else { // 多值表单返回数组 return values; } } @Override public boolean containsKey(final String key) { // 对于Servlet来说,返回值null意味着无此参数 return (null != request.getParameter(key)) || (null != request.getParameter(beanName + StrUtil.DOT + key)); } }, copyOptions); } /** * ServletRequest 参数转Bean * * @param Bean类型 * @param request {@link ServletRequest} * @param bean Bean * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T fillBean(final ServletRequest request, final T bean, final boolean isIgnoreError) { return fillBean(request, bean, CopyOptions.of().setIgnoreError(isIgnoreError)); } /** * ServletRequest 参数转Bean * * @param Bean类型 * @param request ServletRequest * @param beanClass Bean Class * @param isIgnoreError 是否忽略注入错误 * @return Bean */ public static T toBean(final ServletRequest request, final Class beanClass, final boolean isIgnoreError) { return fillBean(request, ConstructorUtil.newInstanceIfPossible(beanClass), isIgnoreError); } // --------------------------------------------------------- fillBean end /** * 获取客户端IP * *

* 默认检测的Header: * *

	 * 1、X-Forwarded-For
	 * 2、X-Real-IP
	 * 3、Proxy-Client-IP
	 * 4、WL-Proxy-Client-IP
	 * 
* *

* otherHeaderNames参数用于自定义检测的Header
* 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。 *

* * @param request 请求对象{@link HttpServletRequest} * @param otherHeaderNames 其他自定义头文件,通常在Http服务器(例如Nginx)中配置 * @return IP地址 */ public static String getClientIP(final HttpServletRequest request, final String... otherHeaderNames) { String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"}; if (ArrayUtil.isNotEmpty(otherHeaderNames)) { headers = ArrayUtil.addAll(headers, otherHeaderNames); } return getClientIPByHeader(request, headers); } /** * 获取客户端IP * *

* headerNames参数用于自定义检测的Header
* 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。 *

* * @param request 请求对象{@link HttpServletRequest} * @param headerNames 自定义头,通常在Http服务器(例如Nginx)中配置 * @return IP地址 * @since 4.4.1 */ public static String getClientIPByHeader(final HttpServletRequest request, final String... headerNames) { String ip; for (final String header : headerNames) { ip = request.getHeader(header); if (!NetUtil.isUnknown(ip)) { return NetUtil.getMultistageReverseProxyIp(ip); } } ip = request.getRemoteAddr(); return NetUtil.getMultistageReverseProxyIp(ip); } /** * 获得MultiPart表单内容,多用于获得上传的文件 在同一次请求中,此方法只能被执行一次! * * @param request {@link ServletRequest} * @return MultipartFormData * @throws IORuntimeException IO异常 * @since 4.0.2 */ public static MultipartFormData getMultipart(final ServletRequest request) throws IORuntimeException { return getMultipart(request, new UploadSetting()); } /** * 获得multipart/form-data 表单内容
* 包括文件和普通表单数据
* 在同一次请求中,此方法只能被执行一次! * * @param request {@link ServletRequest} * @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等 * @return MultiPart表单 * @throws IORuntimeException IO异常 * @since 4.0.2 */ public static MultipartFormData getMultipart(final ServletRequest request, final UploadSetting uploadSetting) throws IORuntimeException { final MultipartFormData formData = new MultipartFormData(uploadSetting); try { formData.parseRequestStream(request.getInputStream(), CharsetUtil.charset(request.getCharacterEncoding())); } catch (final IOException e) { throw new IORuntimeException(e); } return formData; } // --------------------------------------------------------- Header start /** * 获取请求所有的头(header)信息 * * @param request 请求对象{@link HttpServletRequest} * @return header值 * @since 4.6.2 */ public static Map getHeaderMap(final HttpServletRequest request) { final Map headerMap = new HashMap<>(); final Enumeration names = request.getHeaderNames(); String name; while (names.hasMoreElements()) { name = names.nextElement(); headerMap.put(name, request.getHeader(name)); } return headerMap; } /** * 获取请求所有的头(header)信息 * * @param request 请求对象{@link HttpServletRequest} * @return header值 * @since 6.0.0 */ public static Map> getHeadersMap(final HttpServletRequest request) { final Map> headerMap = new LinkedHashMap<>(); final Enumeration names = request.getHeaderNames(); String name; while (names.hasMoreElements()) { name = names.nextElement(); headerMap.put(name, ListUtil.of(request.getHeaders(name))); } return headerMap; } /** * 获取响应所有的头(header)信息 * * @param response 响应对象{@link HttpServletResponse} * @return header值 */ public static Map> getHeadersMap(final HttpServletResponse response) { final Map> headerMap = new HashMap<>(); final Collection names = response.getHeaderNames(); for (final String name : names) { headerMap.put(name, response.getHeaders(name)); } return headerMap; } /** * 忽略大小写获得请求header中的信息 * * @param request 请求对象{@link HttpServletRequest} * @param nameIgnoreCase 忽略大小写头信息的KEY * @return header值 */ public static String getHeaderIgnoreCase(final HttpServletRequest request, final String nameIgnoreCase) { final Enumeration names = request.getHeaderNames(); String name; while (names.hasMoreElements()) { name = names.nextElement(); if (name != null && name.equalsIgnoreCase(nameIgnoreCase)) { return request.getHeader(name); } } return null; } /** * 获得请求header中的信息 * * @param request 请求对象{@link HttpServletRequest} * @param name 头信息的KEY * @param charset 字符集 * @return header值 * @since 4.6.2 */ public static String getHeader(final HttpServletRequest request, final String name, final Charset charset) { final String header = request.getHeader(name); if (null != header) { return CharsetUtil.convert(header, CharsetUtil.ISO_8859_1, charset); } return null; } /** * 客户浏览器是否为IE * * @param request 请求对象{@link HttpServletRequest} * @return 客户浏览器是否为IE */ public static boolean isIE(final HttpServletRequest request) { String userAgent = getHeaderIgnoreCase(request, "User-Agent"); if (StrUtil.isNotBlank(userAgent)) { userAgent = userAgent.toUpperCase(); return userAgent.contains("MSIE") || userAgent.contains("TRIDENT"); } return false; } /** * 是否为GET请求 * * @param request 请求对象{@link HttpServletRequest} * @return 是否为GET请求 */ public static boolean isGetMethod(final HttpServletRequest request) { return Method.GET.name().equalsIgnoreCase(request.getMethod()); } /** * 是否为POST请求 * * @param request 请求对象{@link HttpServletRequest} * @return 是否为POST请求 */ public static boolean isPostMethod(final HttpServletRequest request) { return Method.POST.name().equalsIgnoreCase(request.getMethod()); } /** * 是否为Multipart类型表单,此类型表单用于文件上传 * * @param request 请求对象{@link HttpServletRequest} * @return 是否为Multipart类型表单,此类型表单用于文件上传 */ public static boolean isMultipart(final HttpServletRequest request) { if (!isPostMethod(request)) { return false; } final String contentType = request.getContentType(); if (StrUtil.isBlank(contentType)) { return false; } return contentType.toLowerCase().startsWith("multipart/"); } // --------------------------------------------------------- Header end // --------------------------------------------------------- Cookie start /** * 获得指定的Cookie * * @param httpServletRequest {@link HttpServletRequest} * @param name cookie名 * @return Cookie对象 */ public static Cookie getCookie(final HttpServletRequest httpServletRequest, final String name) { return readCookieMap(httpServletRequest).get(name); } /** * 将cookie封装到Map里面 * * @param httpServletRequest {@link HttpServletRequest} * @return Cookie map */ public static Map readCookieMap(final HttpServletRequest httpServletRequest) { final Cookie[] cookies = httpServletRequest.getCookies(); if (ArrayUtil.isEmpty(cookies)) { return MapUtil.empty(); } return MapUtil.putAll( new CaseInsensitiveMap<>(), (Iterator) new ArrayIter<>(httpServletRequest.getCookies()), Cookie::getName); } /** * 设定返回给客户端的Cookie * * @param response 响应对象{@link HttpServletResponse} * @param cookie Servlet Cookie对象 */ public static void addCookie(final HttpServletResponse response, final Cookie cookie) { response.addCookie(cookie); } /** * 设定返回给客户端的Cookie * * @param response 响应对象{@link HttpServletResponse} * @param name Cookie名 * @param value Cookie值 */ public static void addCookie(final HttpServletResponse response, final String name, final String value) { response.addCookie(new Cookie(name, value)); } /** * 设定返回给客户端的Cookie * * @param response 响应对象{@link HttpServletResponse} * @param name cookie名 * @param value cookie值 * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. >0 : Cookie存在的秒数. * @param path Cookie的有效路径 * @param domain the domain name within which this cookie is visible; form is according to RFC 2109 */ public static void addCookie(final HttpServletResponse response, final String name, final String value, final int maxAgeInSeconds, final String path, final String domain) { final Cookie cookie = new Cookie(name, value); if (domain != null) { cookie.setDomain(domain); } cookie.setMaxAge(maxAgeInSeconds); cookie.setPath(path); addCookie(response, cookie); } /** * 设定返回给客户端的Cookie
* Path: "/"
* No Domain * * @param response 响应对象{@link HttpServletResponse} * @param name cookie名 * @param value cookie值 * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. >0 : Cookie存在的秒数. */ public static void addCookie(final HttpServletResponse response, final String name, final String value, final int maxAgeInSeconds) { addCookie(response, name, value, maxAgeInSeconds, "/", null); } // --------------------------------------------------------- Cookie end // --------------------------------------------------------- Response start /** * 获得PrintWriter * * @param response 响应对象{@link HttpServletResponse} * @return 获得PrintWriter * @throws IORuntimeException IO异常 */ public static PrintWriter getWriter(final HttpServletResponse response) throws IORuntimeException { try { return response.getWriter(); } catch (final IOException e) { throw new IORuntimeException(e); } } /** * 返回数据给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param text 返回的内容 * @param contentType 返回的类型 */ public static void write(final HttpServletResponse response, final String text, final String contentType) { response.setContentType(contentType); Writer writer = null; try { writer = response.getWriter(); writer.write(text); writer.flush(); } catch (final IOException e) { throw new IORuntimeException(e); } finally { IoUtil.closeQuietly(writer); } } /** * 返回文件给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param file 写出的文件对象 * @since 4.1.15 */ public static void write(final HttpServletResponse response, final File file) { final String fileName = file.getName(); final String contentType = ObjUtil.defaultIfNull(FileUtil.getMimeType(fileName), "application/octet-stream"); BufferedInputStream in = null; try { in = FileUtil.getInputStream(file); write(response, in, contentType, fileName); } finally { IoUtil.closeQuietly(in); } } /** * 返回数据给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param in 需要返回客户端的内容 * @param contentType 返回的类型,可以使用{@link FileUtil#getMimeType(String)}获取对应扩展名的MIME信息 *
    *
  • application/pdf
  • *
  • application/vnd.ms-excel
  • *
  • application/msword
  • *
  • application/vnd.ms-powerpoint
  • *
* docx、xlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题,但是下载下来了之后就变成doc格式了 * 参考:https://my.oschina.net/shixiaobao17145/blog/32489 *
    *
  • MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  • *
  • MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
  • *
  • MIME_WORDX_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
  • *
  • MIME_STREAM_TYPE = "application/octet-stream;charset=utf-8"; #原始字节流
  • *
* @param fileName 文件名,自动添加双引号 * @since 4.1.15 */ public static void write(final HttpServletResponse response, final InputStream in, final String contentType, final String fileName) { final String charset = ObjUtil.defaultIfNull(response.getCharacterEncoding(), CharsetUtil.NAME_UTF_8); response.setContentType(contentType); response.setHeader(HeaderName.CONTENT_DISPOSITION.getValue(), HttpHeaderUtil.createAttachmentDisposition(fileName, CharsetUtil.charset(charset))); write(response, in); } /** * 返回数据给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param in 需要返回客户端的内容 * @param contentType 返回的类型 */ public static void write(final HttpServletResponse response, final InputStream in, final String contentType) { response.setContentType(contentType); write(response, in); } /** * 返回数据给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param in 需要返回客户端的内容 */ public static void write(final HttpServletResponse response, final InputStream in) { write(response, in, IoUtil.DEFAULT_BUFFER_SIZE); } /** * 返回数据给客户端 * * @param response 响应对象{@link HttpServletResponse} * @param in 需要返回客户端的内容 * @param bufferSize 缓存大小 */ public static void write(final HttpServletResponse response, final InputStream in, final int bufferSize) { ServletOutputStream out = null; try { out = response.getOutputStream(); IoUtil.copy(in, out, bufferSize); } catch (final IOException e) { throw new HutoolException(e); } finally { IoUtil.closeQuietly(out); IoUtil.closeQuietly(in); } } /** * 设置响应的Header * * @param response 响应对象{@link HttpServletResponse} * @param name 名 * @param value 值,可以是String,Date, int */ public static void setHeader(final HttpServletResponse response, final String name, final Object value) { if (value instanceof String) { response.setHeader(name, (String) value); } else if (Date.class.isAssignableFrom(value.getClass())) { response.setDateHeader(name, ((Date) value).getTime()); } else if (value instanceof Integer || "int".equalsIgnoreCase(value.getClass().getSimpleName())) { response.setIntHeader(name, (int) value); } else { response.setHeader(name, value.toString()); } } // --------------------------------------------------------- Response end }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy