文章目录
- RequestContextHolder源码:
- 项目中使用RequestContextHolder
- 在项目中获得完整请求路径
- 关于ServletRequestAttributes源码 :
- 关于 HttpServletRequest和 HttpServletResponse
- cookie的写入和获得
1.通过RequestContextHolder的静态方法可以随时随地取到当前请求的request对象
该类可以用于获得客户端请求的上下文
RequestContextHolder源码:
Holder class to expose the web request in the form of a thread-bound RequestAttributes object. The request will be inherited by any child threads spawned by the current thread if the inheritable flag is set to true.
Use RequestContextListener or to expose the current web request. Note that already exposes the current request by default.
package ;
翻译:
Holder类以线程绑定的RequestAttributes对象的形式公开web请求。如果可继承标志设置为true,该请求将被当前线程的所有子线程继承。
使用RequestContextListener或来暴露当前的web请求。注意,已经默认暴露了当前请求。
源码:
//
import javax.faces.context.FacesContext;
import org.springframework.core.NamedInheritableThreadLocal;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
public abstract class RequestContextHolder {
private static final boolean jsfPresent = ClassUtils.isPresent("", RequestContextHolder.class.getClassLoader());
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
public RequestContextHolder() {
}
public static void resetRequestAttributes() {
requestAttributesHolder.remove();
inheritableRequestAttributesHolder.remove();
}
public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
setRequestAttributes(attributes, false);
}
public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {
if (attributes == null) {
resetRequestAttributes();
} else if (inheritable) {
inheritableRequestAttributesHolder.set(attributes);
requestAttributesHolder.remove();
} else {
requestAttributesHolder.set(attributes);
inheritableRequestAttributesHolder.remove();
}
}
@Nullable
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
if (attributes == null) {
attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
}
return attributes;
}
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
RequestAttributes attributes = getRequestAttributes();
if (attributes == null) {
if (jsfPresent) {
attributes = RequestContextHolder.FacesRequestAttributesFactory.getFacesRequestAttributes();
}
if (attributes == null) {
throw new IllegalStateException("No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
}
}
return attributes;
}
private static class FacesRequestAttributesFactory {
private FacesRequestAttributesFactory() {
}
@Nullable
public static RequestAttributes getFacesRequestAttributes() {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext != null ? new FacesRequestAttributes(facesContext) : null;
}
}
}
个人理解用ThreadLocal保证了数据间的隔离性
项目中使用RequestContextHolder
用一个servlet工具类:
public class ServletUtils
{
/**
* 定义移动端请求的所有可能类型
*/
private final static String[] agent = { "Android", "iPhone", "iPod", "iPad", "Windows Phone", "MQQBrowser" };
/**
* 获取String参数
*/
public static String getParameter(String name)
{
return getRequest().getParameter(name);
}
public static ServletRequestAttributes getRequestAttributes()
{
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();//这里用RequestContextHolder获得ServletRequestAttributes
return (ServletRequestAttributes) attributes;
}
/**
* 获取request
*/
public static HttpServletRequest getRequest()
{
return getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse()
{
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession()
{
return getRequest().getSession();
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string)
{
try
{
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
通过这个工具类获得cookies:
Cookie[] cookies = ().getCookies();
在项目中获得完整请求路径
/**
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
*
* @return 服务地址
*/
public String getUrl()
{
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request)
{
StringBuffer url = request.getRequestURL();
String contextPath = request.getServletContext().getContextPath();//getServletContext()方法:获取这个ServletRequest最后被分派到的servlet上下文。返回:这个ServletRequest最后被分派到的servlet上下文
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
关于ServletRequestAttributes源码 :
/**
* Servlet-based implementation of the {@link RequestAttributes} interface.
*
* <p>Accesses objects from servlet request and HTTP session scope,
* with no distinction between "session" and "global session".
*
* @author Juergen Hoeller
* @since 2.0
* @see #getAttribute
* @see #getAttribute
*/
public class ServletRequestAttributes extends AbstractRequestAttributes {
/**
* Constant identifying the {@link String} prefixed to the name of a
* destruction callback when it is stored in a {@link HttpSession}.
*/
public static final String DESTRUCTION_CALLBACK_NAME_PREFIX =
ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK.";
protected static final Set<Class<?>> immutableValueTypes = new HashSet<>(16);
static {
immutableValueTypes.addAll(NumberUtils.STANDARD_NUMBER_TYPES);
immutableValueTypes.add(Boolean.class);
immutableValueTypes.add(Character.class);
immutableValueTypes.add(String.class);
}
private final HttpServletRequest request;
@Nullable
private HttpServletResponse response;
@Nullable
private volatile HttpSession session;
private final Map<String, Object> sessionAttributesToUpdate = new ConcurrentHashMap<>(1);
/**
* Create a new ServletRequestAttributes instance for the given request.
* @param request current HTTP request
*/
public ServletRequestAttributes(HttpServletRequest request) {
Assert.notNull(request, "Request must not be null");
this.request = request;
}
/**
* Create a new ServletRequestAttributes instance for the given request.
* @param request current HTTP request
* @param response current HTTP response (for optional exposure)
*/
public ServletRequestAttributes(HttpServletRequest request, @Nullable HttpServletResponse response) {
this(request);
this.response = response;
}
/**
* Exposes the native {@link HttpServletRequest} that we're wrapping.
*/
public final HttpServletRequest getRequest() {
return this.request;
}
/**
* Exposes the native {@link HttpServletResponse} that we're wrapping (if any).
*/
@Nullable
public final HttpServletResponse getResponse() {
return this.response;
}
/**
* Exposes the {@link HttpSession} that we're wrapping.
* @param allowCreate whether to allow creation of a new session if none exists yet
*/
@Nullable
protected final HttpSession getSession(boolean allowCreate) {
if (isRequestActive()) {
HttpSession session = this.request.getSession(allowCreate);
this.session = session;
return session;
}
else {
// Access through stored session reference, if any...
HttpSession session = this.session;
if (session == null) {
if (allowCreate) {
throw new IllegalStateException(
"No session found and request already completed - cannot create new session!");
}
else {
session = this.request.getSession(false);
this.session = session;
}
}
return session;
}
}
private HttpSession obtainSession() {
HttpSession session = getSession(true);
Assert.state(session != null, "No HttpSession");
return session;
}
@Override
public Object getAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot ask for request attribute - request is not active anymore!");
}
return this.request.getAttribute(name);
}
else {
HttpSession session = getSession(false);
if (session != null) {
try {
Object value = session.getAttribute(name);
if (value != null) {
this.sessionAttributesToUpdate.put(name, value);
}
return value;
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
return null;
}
}
@Override
public void setAttribute(String name, Object value, int scope) {
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot set request attribute - request is not active anymore!");
}
this.request.setAttribute(name, value);
}
else {
HttpSession session = obtainSession();
this.sessionAttributesToUpdate.remove(name);
session.setAttribute(name, value);
}
}
@Override
public void removeAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) {
if (isRequestActive()) {
removeRequestDestructionCallback(name);
this.request.removeAttribute(name);
}
}
else {
HttpSession session = getSession(false);
if (session != null) {
this.sessionAttributesToUpdate.remove(name);
try {
session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name);
session.removeAttribute(name);
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
}
}
@Override
public String[] getAttributeNames(int scope) {
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot ask for request attributes - request is not active anymore!");
}
return StringUtils.toStringArray(this.request.getAttributeNames());
}
else {
HttpSession session = getSession(false);
if (session != null) {
try {
return StringUtils.toStringArray(session.getAttributeNames());
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
return new String[0];
}
}
@Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
if (scope == SCOPE_REQUEST) {
registerRequestDestructionCallback(name, callback);
}
else {
registerSessionDestructionCallback(name, callback);
}
}
@Override
public Object resolveReference(String key) {
if (REFERENCE_REQUEST.equals(key)) {
return this.request;
}
else if (REFERENCE_SESSION.equals(key)) {
return getSession(true);
}
else {
return null;
}
}
@Override
public String getSessionId() {
return obtainSession().getId();
}
@Override
public Object getSessionMutex() {
return WebUtils.getSessionMutex(obtainSession());
}
/**
* Update all accessed session attributes through {@code }
* calls, explicitly indicating to the container that they might have been modified.
*/
@Override
protected void updateAccessedSessionAttributes() {
if (!this.sessionAttributesToUpdate.isEmpty()) {
// Update all affected session attributes.
HttpSession session = getSession(false);
if (session != null) {
try {
for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
String name = entry.getKey();
Object newValue = entry.getValue();
Object oldValue = session.getAttribute(name);
if (oldValue == newValue && !isImmutableSessionAttribute(name, newValue)) {
session.setAttribute(name, newValue);
}
}
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
this.sessionAttributesToUpdate.clear();
}
}
/**
* Determine whether the given value is to be considered as an immutable session
* attribute, that is, doesn't have to be re-set via {@code }
* since its value cannot meaningfully change internally.
* <p>The default implementation returns {@code true} for {@code String},
* {@code Character}, {@code Boolean} and standard {@code Number} values.
* @param name the name of the attribute
* @param value the corresponding value to check
* @return {@code true} if the value is to be considered as immutable for the
* purposes of session attribute management; {@code false} otherwise
* @see #updateAccessedSessionAttributes()
*/
protected boolean isImmutableSessionAttribute(String name, @Nullable Object value) {
return (value == null || immutableValueTypes.contains(value.getClass()));
}
/**
* Register the given callback as to be executed after session termination.
* <p>Note: The callback object should be serializable in order to survive
* web app restarts.
* @param name the name of the attribute to register the callback for
* @param callback the callback to be executed for destruction
*/
protected void registerSessionDestructionCallback(String name, Runnable callback) {
HttpSession session = obtainSession();
session.setAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name,
new DestructionCallbackBindingListener(callback));
}
@Override
public String toString() {
return this.request.toString();
}
}
关于 HttpServletRequest和 HttpServletResponse
关于servlet的介绍:
客户端的网络请求首先会被Http服务器接收(也叫Web服务器、web容器,其需要提供web应用运行所需的环境,接收客户端的Http请求);
Web服务器根据请求的路径将请求转交给对应的Servlet容器(也称Servlet引擎,为Servlet的运行提供环境支持,可以理解为tomcat或其他服务器);
Servlet容器根据对应的虚拟路径(@WebServlet中配置的)来加载Servlet,如果Serlvet没有被实例化则创建该Servlet的一个实例(调用init方法);
Servlet容器根据用户的HTTP请求,创建一个ServletRequest对象(HTTP的请求信息被封装在其中)和一个可以对HTTP请求进行响应的ServletResponse对象(类似于寄信,并在信中说明回信的地址),然后调用HttpServlet中重写的service(ServletRequest req, ServletResponse res)方法,并在这个方法中,将ServletRequest、ServletResponse这两个对象向下转型,得到我们非常熟悉的HttpServletRequest和HttpServletResponse两个对象,然后将客户端的请求转发到HttpServlet中protected修饰的service(HttpServletRequest req, HttpServletResponse resp)
cookie的写入和获得
/**
* 获得指定Cookie的值
*
* @param request 请求对象
* @param response 响应对象
* @param name 名字
* @param isRemove 是否移除
* @return 值
*/
public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,
boolean isRemove)
{
String value = null;
Cookie[] cookies = request.getCookies();
if (cookies != null)
{
for (Cookie cookie : cookies)
{
if (cookie.getName().equals(name))
{
try
{
value = URLDecoder.decode(cookie.getValue(), "utf-8");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
if (isRemove)
{
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
}
}
return value;
}
/**
* 设置 Cookie
*
* @param name 名称
* @param value 值
* @param maxAge 生存时间(单位秒)
* @param uri 路径
*/
public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge)
{
Cookie cookie = new Cookie(name, null);
cookie.setPath(path);
cookie.setMaxAge(maxAge);//该方法用于设置cookie的生存时间,
try
{
cookie.setValue(URLEncoder.encode(value, "utf-8"));//()可以对要传递的中文进行编码a ,如果url参数值含有特殊字符时,需要使用 url 编码。否则可能特殊字符会消失
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
response.addCookie(cookie);
}