`
wezly
  • 浏览: 484600 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

oschina非常重要的类—RequestContext

阅读更多
RequestContext 这个类在 OSChina 中是非常重要的一个类,该类由全局 Filter 进行初始化,并传递给包括 Action 和 页面中直接使用,使用时通过 RequestContext.get() 来获取当前请求上下文实例。 这个方法主要的功能包括:自动转码、处理文件上传、登录信息处理,以及一些跟请求相关的常用方法封装。 如果你从中发现了什么问题,请不吝赐教。

 

package my.mvc;

import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import my.util.CryptUtils;
import my.util.Multimedia;
import my.util.RequestUtils;
import my.util.ResourceUtils;
import net.oschina.beans.User;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.converters.SqlDateConverter;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 请求上下文
 * @author Winter Lau
 * @date 2010-1-13 下午04:18:00
 */
public class RequestContext {
 
 private final static Log log = LogFactory.getLog(RequestContext.class);

 private final static int MAX_FILE_SIZE = 10*1024*1024; 
 private final static String UTF_8 = "UTF-8";
 
 private final static ThreadLocal<RequestContext> contexts = new ThreadLocal<RequestContext>();
 private final static boolean isResin;
 private final static String upload_tmp_path;
 private final static String TEMP_UPLOAD_PATH_ATTR_NAME = "$OSCHINA_TEMP_UPLOAD_PATH$";

 private static String webroot = null;
 
 private ServletContext context;
 private HttpSession session;
 private HttpServletRequest request;
 private HttpServletResponse response;
 private Map<String, Cookie> cookies;
 
 static {
  webroot = getWebrootPath();
  isResin = _CheckResinVersion();
  //上传的临时目录
  upload_tmp_path = webroot + "WEB-INF" + File.separator + "tmp" + File.separator;
  try {
   FileUtils.forceMkdir(new File(upload_tmp_path));
  } catch (IOException excp) {}
  
  //BeanUtils对时间转换的初始化设置
  ConvertUtils.register(new SqlDateConverter(null), java.sql.Date.class);
  ConvertUtils.register(new Converter(){
   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
   SimpleDateFormat sdf_time = new SimpleDateFormat("yyyy-M-d H:m");
   @SuppressWarnings("rawtypes")
   public Object convert(Class type, Object value) {
    if(value == null) return null;
          if (value instanceof Date) return (value);
          try {
              return sdf_time.parse(value.toString());
          } catch (ParseException e) {
              try {
      return sdf.parse(value.toString());
     } catch (ParseException e1) {
      return null;
     }
          }
   }}, java.util.Date.class);
 }
 
 private final static String getWebrootPath() {
  String root = RequestContext.class.getResource("/").getFile();
  try {
   root = new File(root).getParentFile().getParentFile().getCanonicalPath();
   root += File.separator;
  } catch (IOException e) {
   throw new RuntimeException(e);
  }
  return root;
 }
 
 /**
  * 初始化请求上下文
  * @param ctx
  * @param req
  * @param res
  */
 public static RequestContext begin(ServletContext ctx, HttpServletRequest req, HttpServletResponse res) {
  RequestContext rc = new RequestContext();
  rc.context = ctx;
  rc.request = _AutoUploadRequest(_AutoEncodingRequest(req));
  rc.response = res;
  rc.response.setCharacterEncoding(UTF_8);
  rc.session = req.getSession(false);
  rc.cookies = new HashMap<String, Cookie>();
  Cookie[] cookies = req.getCookies();
  if(cookies != null)
   for(Cookie ck : cookies) {
    rc.cookies.put(ck.getName(), ck);
   }
  contexts.set(rc);
  return rc;
 }

 /**
  * 返回Web应用的路径
  * @return
  */
 public static String root() { return webroot; }
 
 /**
  * 获取当前请求的上下文
  * @return
  */
 public static RequestContext get(){
  return contexts.get();
 }
 
 public void end() {
  String tmpPath = (String)request.getAttribute(TEMP_UPLOAD_PATH_ATTR_NAME);
  if(tmpPath != null){
   try {
    FileUtils.deleteDirectory(new File(tmpPath));
   } catch (IOException e) {
    log.fatal("Failed to cleanup upload directory: " + tmpPath, e);
   }
  }
  this.context = null;
  this.request = null;
  this.response = null;
  this.session = null;
  this.cookies = null;
  contexts.remove();
 }
 
 public Locale locale(){ return request.getLocale(); }

 public void closeCache(){
        header("Pragma","No-cache");
        header("Cache-Control","no-cache");
        header("Expires", 0L);
 }
 
 /**
  * 自动编码处理
  * @param req
  * @return
  */
 private static HttpServletRequest _AutoEncodingRequest(HttpServletRequest req) {
  if(req instanceof RequestProxy)
   return req;
  HttpServletRequest auto_encoding_req = req;
  if("POST".equalsIgnoreCase(req.getMethod())){
   try {
    auto_encoding_req.setCharacterEncoding(UTF_8);
   } catch (UnsupportedEncodingException e) {}
  }
  else if(!isResin)
   auto_encoding_req = new RequestProxy(req, UTF_8);
  
  return auto_encoding_req;
 }
 
 /**
  * 自动文件上传请求的封装
  * @param req
  * @return
  */
 private static HttpServletRequest _AutoUploadRequest(HttpServletRequest req){
  if(_IsMultipart(req)){
   String path = upload_tmp_path + RandomStringUtils.randomAlphanumeric(10);
   File dir = new File(path);
   if(!dir.exists() && !dir.isDirectory()) dir.mkdirs();
   try{
    req.setAttribute(TEMP_UPLOAD_PATH_ATTR_NAME,path);
    return new MultipartRequest(req, dir.getCanonicalPath(), MAX_FILE_SIZE, UTF_8);
   }catch(NullPointerException e){    
   }catch(IOException e){
    log.fatal("Failed to save upload files into temp directory: " + path, e);
   }
  }
  return req;
 }
 
 public long id() {
  return param("id", 0L);
 }
 
 public String ip(){
  return RequestUtils.getRemoteAddr(request);
 }
 
 @SuppressWarnings("unchecked")
 public Enumeration<String> params() {
  return request.getParameterNames();
 }
 
 public String param(String name, String...def_value) {
  String v = request.getParameter(name);
  return (v!=null)?v:((def_value.length>0)?def_value[0]:null);
 }
 
 public long param(String name, long def_value) {
  return NumberUtils.toLong(param(name), def_value);
 }

 public int param(String name, int def_value) {
  return NumberUtils.toInt(param(name), def_value);
 }

 public byte param(String name, byte def_value) {
  return (byte)NumberUtils.toInt(param(name), def_value);
 }

 public String[] params(String name) {
  return request.getParameterValues(name);
 }

 public long[] lparams(String name){
  String[] values = params(name);
  if(values==null) return null;
  return (long[])ConvertUtils.convert(values, long.class);
 }
 
 public String uri(){
  return request.getRequestURI();
 }
 
 public String contextPath(){
  return request.getContextPath();
 }
 
 public void redirect(String uri) throws IOException {
  response.sendRedirect(uri);
 }
 
 public void forward(String uri) throws ServletException, IOException {
  RequestDispatcher rd = context.getRequestDispatcher(uri);
  rd.forward(request, response);
 }

 public void include(String uri) throws ServletException, IOException {
  RequestDispatcher rd = context.getRequestDispatcher(uri);
  rd.include(request, response);
 }
 
 public boolean isUpload(){
  return (request instanceof MultipartRequest);
 }
 public File file(String fieldName) {
  if(request instanceof MultipartRequest)
   return ((MultipartRequest)request).getFile(fieldName);
  return null;
 }
 public File image(String fieldname) {
  File imgFile = file(fieldname); 
  return (imgFile!=null&&Multimedia.isImageFile(imgFile.getName()))?imgFile:null;
 }
 
 public boolean isRobot(){
  return RequestUtils.isRobot(request);
 }

 public ActionException fromResource(String bundle, String key, Object...args){
  String res = ResourceUtils.getStringForLocale(request.getLocale(), bundle, key, args);
  return new ActionException(res);
 }

 public ActionException error(String key, Object...args){  
  return fromResource("error", key, args);
 }
 
 /**
  * 输出信息到浏览器
  * @param msg
  * @throws IOException
  */
 public void print(Object msg) throws IOException {
  if(!UTF_8.equalsIgnoreCase(response.getCharacterEncoding()))
   response.setCharacterEncoding(UTF_8);
  response.getWriter().print(msg);
 }

 public void output_json(String[] key, Object[] value) throws IOException {
  StringBuilder json = new StringBuilder("{");
  for(int i=0;i<key.length;i++){
   if(i>0)
    json.append(',');
   boolean isNum = value[i] instanceof Number ;
   json.append("\"");
   json.append(key[i]);
   json.append("\":");
   if(!isNum) json.append("\"");
   json.append(value[i]);
   if(!isNum) json.append("\"");
  }
  json.append("}");
  print(json.toString());
 }

 public void output_json(String key, Object value) throws IOException {
  output_json(new String[]{key}, new Object[]{value});
 }
 public void error(int code, String...msg) throws IOException {
  if(msg.length>0)
   response.sendError(code, msg[0]);
  else
   response.sendError(code);
 }
 
 public void forbidden() throws IOException { 
  error(HttpServletResponse.SC_FORBIDDEN); 
 }

 public void not_found() throws IOException { 
  error(HttpServletResponse.SC_NOT_FOUND); 
 }

 public ServletContext context() { return context; }
 public HttpSession session() { return session; }
 public HttpSession session(boolean create) { 
  return (session==null && create)?(session=request.getSession()):session; 
 }
 public Object sessionAttr(String attr) {
  HttpSession ssn = session();
  return (ssn!=null)?ssn.getAttribute(attr):null;
 }
 public HttpServletRequest request() { return request; }
 public HttpServletResponse response() { return response; }
 public Cookie cookie(String name) { return cookies.get(name); }
 public void cookie(String name, String value, int max_age, boolean all_sub_domain) {
  RequestUtils.setCookie(request, response, name, value, max_age, all_sub_domain);
 }
 public void deleteCookie(String name,boolean all_domain) { RequestUtils.deleteCookie(request, response, name, all_domain); }
 public String header(String name) { return request.getHeader(name); }
 public void header(String name, String value) { response.setHeader(name, value); }
 public void header(String name, int value) { response.setIntHeader(name, value); }
 public void header(String name, long value) { response.setDateHeader(name, value); }

 /**
  * 将HTTP请求参数映射到bean对象中
  * @param req
  * @param beanClass
  * @return
  * @throws Exception
  */
 public <T> T form(Class<T> beanClass) {
  try{
   T bean = beanClass.newInstance();
   BeanUtils.populate(bean, request.getParameterMap());
   return bean;
  }catch(Exception e) {
   throw new ActionException(e.getMessage());
  }
 }
 
 /**
  * 返回当前登录的用户资料
  * @return
  */
 public IUser user() {
  return User.GetLoginUser(request);
 }
 
 /**
  * 保存登录信息
  * @param req
  * @param res
  * @param user
  * @param save
  */
 public void saveUserInCookie(IUser user, boolean save) {
  String new_value = _GenLoginKey(user, ip(), header("user-agent"));
  int max_age = save ? MAX_AGE : -1;
  deleteCookie(COOKIE_LOGIN, true);
  cookie(COOKIE_LOGIN,new_value,max_age,true);
 }

 public void deleteUserInCookie() {
  deleteCookie(COOKIE_LOGIN, true);
 }
 
 /**
  * 3.0 以上版本的 Resin 无需对URL参数进行转码
  * @return
  */
 private final static boolean _CheckResinVersion() {
  try{
   Class<?> verClass = Class.forName("com.caucho.Version");
   String ver = (String)verClass.getDeclaredField("VERSION").get(verClass);
   String mainVer = ver.substring(0, ver.lastIndexOf('.'));
   /**
   float fVer = Float.parseFloat(mainVer);
   System.out.println("----------------> " + fVer);
   */
   return Float.parseFloat(mainVer) > 3.0;
  }catch(Throwable t) {}
  return false;
 }


 /**
  * 自动解码
  * @author liudong
  */
 private static class RequestProxy extends HttpServletRequestWrapper {
  private String uri_encoding; 
  RequestProxy(HttpServletRequest request, String encoding){
   super(request);
   this.uri_encoding = encoding;
  }
  
  /**
   * 重载getParameter
   */
  public String getParameter(String paramName) {
   String value = super.getParameter(paramName);
   return _DecodeParamValue(value);
  }

  /**
   * 重载getParameterMap
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public Map<String, Object> getParameterMap() {
   Map params = super.getParameterMap();
   HashMap<String, Object> new_params = new HashMap<String, Object>();
   Iterator<String> iter = params.keySet().iterator();
   while(iter.hasNext()){
    String key = (String)iter.next();
    Object oValue = params.get(key);
    if(oValue.getClass().isArray()){
     String[] values = (String[])params.get(key);
     String[] new_values = new String[values.length];
     for(int i=0;i<values.length;i++)
      new_values[i] = _DecodeParamValue(values[i]);
     
     new_params.put(key, new_values);
    }
    else{
     String value = (String)params.get(key);
     String new_value = _DecodeParamValue(value);
     if(new_value!=null)
      new_params.put(key,new_value);
    }
   }
   return new_params;
  }

  /**
   * 重载getParameterValues
   */
  public String[] getParameterValues(String arg0) {
   String[] values = super.getParameterValues(arg0);
   for(int i=0;values!=null&&i<values.length;i++)
    values[i] = _DecodeParamValue(values[i]);
   return values;
  }

  /**
   * 参数转码
   * @param value
   * @return
   */
  private String _DecodeParamValue(String value){
   if (StringUtils.isBlank(value) || StringUtils.isBlank(uri_encoding)
     || StringUtils.isNumeric(value))
    return value;  
   try{
    return new String(value.getBytes("8859_1"), uri_encoding);
   }catch(Exception e){}
   return value;
  }

 }
 
 private static boolean _IsMultipart(HttpServletRequest req) {
  return ((req.getContentType() != null) && (req.getContentType()
    .toLowerCase().startsWith("multipart")));
 }

 /**
  * 生成用户登录标识字符串
  * @param user
  * @param ip
  * @param user_agent
  * @return
  */
 public static String _GenLoginKey(IUser user, String ip, String user_agent) {
  StringBuilder sb = new StringBuilder();
  sb.append(user.getId());
  sb.append('|');
  sb.append(user.getPwd());
  sb.append('|');
  sb.append(ip);
  sb.append('|');
  sb.append((user_agent==null)?0:user_agent.hashCode());
  sb.append('|');
  sb.append(System.currentTimeMillis());
  return _Encrypt(sb.toString()); 
 }

 /**
  * 加密
  * @param value
  * @return 
  * @throws Exception 
  */
 private static String _Encrypt(String value) {
  byte[] data = CryptUtils.encrypt(value.getBytes(), E_KEY);
  try{
   return URLEncoder.encode(new String(Base64.encodeBase64(data)), UTF_8);
  }catch(UnsupportedEncodingException e){
   return null;
  }
 }

 /**
  * 解密
  * @param value
  * @return
  * @throws Exception 
  */
 private static String _Decrypt(String value) {
  try {
   value = URLDecoder.decode(value,UTF_8);
   if(StringUtils.isBlank(value)) return null;
   byte[] data = Base64.decodeBase64(value.getBytes());
   return new String(CryptUtils.decrypt(data, E_KEY));
  } catch (UnsupportedEncodingException excp) {
   return null;
  }
 } 

 /**
  * 从cookie中读取保存的用户信息
  * @param req
  * @return
  */
 public IUser getUserFromCookie() {
  try{
   Cookie cookie = cookie(COOKIE_LOGIN);
   if(cookie!=null && StringUtils.isNotBlank(cookie.getValue())){
    return userFromUUID(cookie.getValue());
   }
  }catch(Exception e){}
  return null;
 }

 /**
  * 从cookie中读取保存的用户信息
  * @param req
  * @return
  */
 public IUser userFromUUID(String uuid) {
  if(StringUtils.isBlank(uuid))
   return null;
  String ck = _Decrypt(uuid);
  final String[] items = StringUtils.split(ck, '|');
  if(items.length == 5){
   String ua = header("user-agent");
   int ua_code = (ua==null)?0:ua.hashCode();
   int old_ua_code = Integer.parseInt(items[3]);
   if(ua_code == old_ua_code){
    return new IUser(){
     public boolean IsBlocked() { return false; }
     public long getId() { return NumberUtils.toLong(items[0],-1L); }
     public String getPwd() { return items[1]; }
     public byte getRole() { return IUser.ROLE_GENERAL; }
    };
   }
  }
  return null;
 }
 
 public final static String COOKIE_LOGIN = "oscid";
 private final static int MAX_AGE = 86400 * 365;
 private final static byte[] E_KEY = new byte[]{'1','2','3','4','5','6','7','8'};
}

 

 

RequestContext的用例的全局过滤器源码:

package my.mvc;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import my.db.DBManager;

/**
 * 全局过滤器
 * @author Winter Lau
 * @date 2010-1-13 下午08:36:18
 */
public class ControllerFilter implements Filter {

	private ServletContext context;
	
	/**
	 * 过滤器初始化
	 */
	public void init(FilterConfig cfg) throws ServletException {
		this.context = cfg.getServletContext();
	}

	/**
	 * 执行过滤操作
	 */
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
		throws IOException, ServletException 
	{
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)res;
		RequestContext rc = RequestContext.begin(this.context, request, response);
		
		if(rc.uri().indexOf("/.svn/")>=0){
			rc.forbidden();
			return ;
		}

		try{
			chain.doFilter(rc.request(), rc.response());
		}finally{
			if(rc!=null) rc.end();
			DBManager.closeConnection();
		}
	}

	/**
	 * 过滤器释放资源
	 */
	public void destroy() {
	}

}

 

分享到:
评论

相关推荐

    OSChina Android客户端源码

    - 了解一个大型Android项目的目录结构是非常重要的。通常,一个Android项目会包含`app/src/main/java`(源代码)、`res`(资源文件)、`build.gradle`(构建配置)等多个关键部分。通过分析OSChina客户端的源码,你...

    oschina android 客户端源码

    理解Service的生命周期和使用方式,对于提升应用的性能和用户体验至关重要。 BroadcastReceiver用于监听系统或自定义广播事件,如网络状态变化或特定消息到达。在OSChina客户端中,BroadcastReceiver可能用于监听...

    oschina客户端android源代码

    1. `AsyncTask`:Android内置的异步任务类,用于执行后台操作并更新UI。 2. `Handler/Looper`:消息处理系统,用于在主线程中处理异步操作的结果。 3. `RxJava`:响应式编程库,提供更灵活的异步处理和事件驱动编程...

    如何在oschina新建项目代码托管

    1. **默认文件**:创建完成后,您将看到项目仓库中已经包含了两个默认文件(通常是README.md和LICENSE文件),这些文件对于项目来说非常重要。 2. **获取Git地址**:在项目页面中,您可以找到项目的Git地址,一般...

    OSChina[开源中国]源码

    对于大型系统,日志管理和监控至关重要。源码可能涉及Log4j、Logback等日志框架,以及Prometheus、ELK Stack(Elasticsearch、Logstash、Kibana)等监控解决方案。 总之,通过深入研究OSChina的源码,开发者不仅...

    OSChina iOS客户端工程

    4. **网络请求**:OSChina客户端可能使用了URLSession或者第三方库如Alamofire进行网络数据的获取,了解如何处理API请求、解析JSON数据是重要的一环。 5. **数据持久化**:客户端可能采用了Core Data或SQLite来存储...

    oschina(开源社区)技术架构介绍

    资源名称:oschina(开源社区)技术架构介绍内容简介:每日访问统计数据总览IP &gt; 10w动态请求接近 300w 页面请求 80w,Ajax请求 220w高峰期并发连接数 2000oschina 硬件配置DELL SC 1435 (1台) CPU: 双 AMD 2G 内存:...

    oschina android app 2.2.1 源码收藏

    总之,通过研究OSChina Android App 2.2.1的源码,开发者不仅可以提升Android开发技能,还能学习到项目管理、性能优化、安全防护等多个方面的知识,这对于个人成长和团队协作都有着重要的价值。因此,深入源码,是每...

    oschina android app

    3. **Java类**(如:MainActivity.java):实现了应用的主要逻辑,包括Activity的生命周期方法、事件处理和业务逻辑。 4. **网络请求**:可能使用了HttpURLConnection、OkHttp、Volley或Retrofit等库来处理网络请求...

    oschina+技术架构介绍

    oschina+技术架构介绍

    oschina 开源中国客户端

    AppCompatActivity是AppCompat库中的关键类,它扩展了ActionBarActivity(或现在是FragmentActivity),提供了Material Design风格的ActionBar和ToolBar。 3. **用户界面设计**:客户端的设计遵循Android Material ...

    OSChina 已开源的所有源码包括jar下载

    OSChina 已开源的所有源码包括jar 下载

    oschina客户端

    客户端(Client)或称为...对于这一类应用程序,需要网络中有相应的服务器和服务程序来提供相应的服务,如数据库服务,电子邮件服务等等,这样在客户机和服务器端,需要建立特定的通信连接,来保证应用程序的正常运行。

    oschina-app 最新源码

    在【oschina-app】源码中,我们可以深入研究以下几个重要的知识点: 1. **数据存储**:在Android平台上,数据存储有多种方式,包括SQLite数据库、SharedPreferences、文件存储、ContentProvider等。oschina-app可能...

    AndroidStudio与OSChina

    对于初学者来说,重点在于熟练掌握Git的基础知识和操作技巧,这对于后续的高效协作开发至关重要。随着Git在软件开发领域中的广泛应用,熟悉并掌握其使用方法,将有助于提升个人和团队的工作效率。

    oschina-android-app(开源中国).rar

    在“oschina-android-app”中,我们可能会找到处理网络请求的相关类,如OkHttpUtils或RetrofitUtils。 五、数据库操作 为了存储用户偏好设置或者离线缓存数据,Android应用通常会使用SQLite数据库。开源中国应用...

    oschina-android-app(开源中国)

    【标题】"oschina-android-app(开源中国)"是一个基于Android平台的应用程序源代码,它提供了访问开源中国网站的功能,让开发者能够深入了解Android应用开发的内部机制和实践。开源中国作为一个国内知名的开源技术...

    DotNetOpenAuth的OSChina登陆扩展OSChinaOAuth2.zip

    DotNetOpenAuth.OSChinaOAuth2 是 DotNetOpenAuth的OSChina登陆扩展。 安装: 1.通过 NuGut 安装 PM&gt; Install-Package DotNetOpenAuth.OSChinaOAuth2 ...OAuthWebSecurity.RegisterClient(client, "OSChina");

Global site tag (gtag.js) - Google Analytics