1.Application对象
多个用户共享的应用级别的作用域,在服务器端,相比前两者,这个存在时间是最长的,只有当关闭服务器的时候才死亡!所以他可以活很长时间。
Application用于保存所有用户的公共的数据信息,如果使用Application对象,一个需要考虑的问题是任何写操作都要在Application_OnStart事件(global.asax)中完成.尽管使用Application.Lock和Applicaiton.Unlock方法来避免写操作的同步,但是它串行化了对Application对象的请求,当网站访问量大的时候会产生严重的性能瓶颈.因此最好不要用此对象保存大的数据集合
2.Session对象
session是服务器端技术,利用这个技术,服务器可以把与会话相关的数据写到一个代表会话的 session对象中,用来存储用户跨网页程序的变量或对象,只针对单一用户。
Session用于保存每个用户的专用信息.她的生存期是用户持续请求时间再加上一段时间(一般是20分钟左右).Session中的信息保存在Web服务器内容中,保存的数据量可大可小.当Session超时或被关闭时将自动释放保存的数据信息.由于用户停止使用应用程序后它仍然在内存中保持一段时间,因此使用Session对象使保存用户数据的方法效率很低.对于小量的数据,使用Session对象保存还是一个不错的选择.使用Session对象保存信息:
session有效期可以自己设置
方法一:在web.xm中使用l<session-config>的子标签 <session.timeout>,单位为分钟,主要是针对整个应用的所有session。
方法二:
HttpSession session = request.getSession();
session.setMaxInactiveInterval(“自己想要设置的具体时间”)。
默认情况下关闭浏览器session就失效,但是可以手动设置时间的。
3.Cookie对象
Cookie用于保存客户浏览器请求服务器页面的请求信息,程序员也可以用它存放非敏感性的用户信息,信息保存的时间可以根据需要设置.如果没有设置Cookie失效日期,它们仅保存到关闭浏览器程序为止.如果将Cookie对象的Expires属性设置为Minvalue,则表示Cookie永远不会过期.Cookie存储的数据量很受限制,大多数浏览器支持最大容量为4096,因此不要用来保存数据集及其他大量数据.由于并非所有的浏览器都支持Cookie,并且数据信息是以明文文本的形式保存在客户端的计算机中,因此最好不要保存敏感的,未加密的数据,否则会影响网站的安全性.使用Cookie对象保存的代码如下:
//存放信息
Response.Cookies["UserID"].Value="0001";
//读取信息
string UserID=Response.Cookies["UserID"].Value;
Cookie cookie = new Cookie(“mycookie”,“name”);
cookie.setMaxAge("自己指定的时间")。。
cookie存放在客户端中,因此有效期时间以客户端的时间为准。可以自己手动设置,
如果没有指定Cookies对象的有效期,则Cookies对象只存在于客户端的内存。当浏览器关闭时,Cookies就会失效。
ThreadLocal来存储Session,以便实现Session any where
ThreadLocal使用场景用来解决 数据库连接、Session管理等。
package com.enation.framework.context.webcontext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.enation.framework.context.webcontext.impl.WebSessionContextImpl;
/**
* 用ThreadLocal来存储Session,以便实现Session any where
* @author kingapex
* <p>2009-12-17 下午03:10:09</p>
* @version 1.1
* 新增request any where
*/
public class ThreadContextHolder {
protected static final Logger logger = Logger.getLogger(ThreadContextHolder.class);
private static ThreadLocal<WebSessionContext> SessionContextThreadLocalHolder = new ThreadLocal<WebSessionContext>();
private static ThreadLocal<HttpServletRequest> HttpRequestThreadLocalHolder = new ThreadLocal<HttpServletRequest>();
private static ThreadLocal<HttpServletResponse> HttpResponseThreadLocalHolder = new ThreadLocal<HttpServletResponse>();
public static void setHttpRequest(HttpServletRequest request){
HttpRequestThreadLocalHolder.set(request);
}
public static HttpServletRequest getHttpRequest(){
return HttpRequestThreadLocalHolder.get();
}
public static void remove(){
SessionContextThreadLocalHolder.remove();
HttpRequestThreadLocalHolder.remove();
HttpResponseThreadLocalHolder.remove();
}
public static void setHttpResponse(HttpServletResponse response){
HttpResponseThreadLocalHolder.set(response);
}
public static HttpServletResponse getHttpResponse(){
return HttpResponseThreadLocalHolder.get();
}
public static void setSessionContext(WebSessionContext context) {
SessionContextThreadLocalHolder.set(context);
}
public static void destorySessionContext() {
WebSessionContext context = SessionContextThreadLocalHolder.get();
if (context != null) {
context.destory();
}
}
public static WebSessionContext getSessionContext() {
if (SessionContextThreadLocalHolder.get() == null) {
//if(logger.isDebugEnabled())
//logger.debug("create new webSessionContext.");
SessionContextThreadLocalHolder.set(new WebSessionContextImpl());
}else{
//if(logger.isDebugEnabled())
//logger.debug(" webSessionContext not null and return ...");
}
return SessionContextThreadLocalHolder.get();
}
}
ThreadLocal获取session
ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。
ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。
但是要注意,虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用ThreadLocal要大。
ThreadLocal类提供的几个方法:
1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值,获取ThreadLocal在当前线程中保存的变量副本
2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值,设置当前线程中变量的副本
3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。
4、ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值,是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法
一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用。在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程。
也就是说,同一线程贯通N层,不同的线程可能由于参数等不同会对程序中的某些变量进行修改,但是又要防止修改后的值对其它线程产生影响,因为不同的线程可以同时运行滴,这就需要我们解决对某些线程共享的变量的访问冲突问题。ThreadLocal本地线程变量就是一种解决方式,它通过将程序中不安全的变量封装进ThreadLocal中,这相当于为每一个线程提供一个独立的变量副本(其实是不同的对象),线程修改变量的值对其它线程来说没影响了,因为其它线程有自己的一个副本信息。
二、借助ThreadLocal对象每个线程只创建一个实例
public static final String dateFormat="yyyy-MM-dd";
private static final ThreadLocal<DateFormat> dfThreadLocal=new ThreadLocal<DateFormat>(){
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(dateFormat);
}
};
public static String dateToString(Date date){
return dfThreadLocal.get().format(date);
}
对于每个线程,都有一个类似于Map的东西ThreadLocalMap(ThreadLocal的静态类 ),那它里面保存了什么东东呢,肯定是key-value啊,key就是上面代码中的共享静态变量 dfThreadLocal,value就是DateFormat实例了,即new SimpleDateFormat(dateFormat)这个东东。那接下来,在线程内我要如何去获取这个值呢,就是靠dfThreadLocal.get()实现滴,方法源码如下:
ThreadLocal .ThreadLocalMap inheritableThreadLocals = null ;
public T get () {
Thread t = Thread.currentThread ();
ThreadLocalMap map = getMap(t );
if ( map != null) {
ThreadLocalMap.Entry e = map.getEntry (this);
if ( e != null)
return ( T)e .value;
}
return setInitialValue ();
}
ThreadLocalMap getMap (Thread t) {
return t .inheritableThreadLocals;
}
可以很明显的看出,首先根据Thread.currentThread ()获取到inheritableThreadLocals(即ThreadLocalMap,他是Thread的一个变量),然后将this(即最上面代码的dfThreadLocal对象)作为key(或索引)获取到真正的值T(就是SimpleDateFormat对象)啊,至此应该比较清楚了。
为什么不同的线程有各自的值,因为 不同的线程--->不同的ThreadLocalMap对象(线程的变量)--->通过相同的key(如果有被static修饰)获取到不同的value值。
备注:一般都被static修饰,因为可以避免在一个线程内可能发生的重复创建TSO(Thread Specific Object,即ThreadLocal所关联的对象),被statis修饰了,同一线程key也肯定一样,value也肯定只有一份了。
一个ThreadLocal实例关联当前线程的一个TSO对象,如果把ThreadLocal声明为实例变量,那么每创建一个类实例就会导致一个TSO实例诞生,这肯定没有这个必要滴。
具体实现
获取session的工具类
<!-- http session 处理类 -->
<bean id="httpSessionService" class="com.session.impl.HttpSessionService" lazy-init="false"/>
package com.platform.framework.session.impl;
import com.platform.framework.context.ThreadContextHolder;
import com.platform.inf.ISessionService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class HttpSessionService
implements ISessionService
{
private final Log logger = LogFactory.getLog(getClass());
public Object getAttribute(String arg0)
{
HttpSession session = getSession();
return session == null ? null : session.getAttribute(arg0);
}
public String getId()
{
HttpSession session = getSession();
return session == null ? null : session.getId();
}
public void invalidate()
{
HttpSession session = getSession();
if (session != null) {
session.invalidate();
}
}
public void removeAttribute(String arg0)
{
HttpSession session = getSession();
if (session != null) {
session.removeAttribute(arg0);
}
}
public void setAttribute(String arg0, Object arg1)
{
HttpSession session = getSession();
if (session != null) {
session.setAttribute(arg0, arg1);
}
}
private HttpSession getSession()
{
HttpServletRequest request = ThreadContextHolder.getHttpRequest();
if ((request == null) || (request.getSession() == null)) {
this.logger.info("============================>>>sessoin 失效");
}
return request.getSession();
}
}
package com.platform.framework.context;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ThreadContextHolder
{
private static ThreadLocal<HttpServletRequest> HttpRequestThreadLocalHolder = new ThreadLocal();
private static ThreadLocal<HttpServletResponse> HttpResponseThreadLocalHolder = new ThreadLocal();
private static ThreadLocal<Map<String, Object>> threadVar = new ThreadLocal();
public static void setThreadValue(String key, Object value)
{
Map<String, Object> map = (Map)threadVar.get();
if (map == null)
{
map = new HashMap();
map.put(key, value);
threadVar.set(map);
}
else
{
map.put(key, value);
}
}
public static <T> T getThreadValue(String key)
{
Map<String, Object> map = (Map)threadVar.get();
if (map != null) {
return map.get(key);
}
return null;
}
public static void setHttpRequest(HttpServletRequest request)
{
HttpRequestThreadLocalHolder.set(request);
}
public static HttpServletRequest getHttpRequest()
{
return (HttpServletRequest)HttpRequestThreadLocalHolder.get();
}
public static void setHttpResponse(HttpServletResponse response)
{
HttpResponseThreadLocalHolder.set(response);
}
public static HttpServletResponse getHttpResponse()
{
return (HttpServletResponse)HttpResponseThreadLocalHolder.get();
}
public static String getSessionId()
{
HttpServletRequest request = (HttpServletRequest)HttpRequestThreadLocalHolder.get();
if (null != request) {
return request.getSession().getId();
}
return null;
}
public static void clearThreadValues()
{
threadVar.remove();
}
}
public String getDict(String dictCode, String value) {
Dictionary dict = getDict(dictCode);
if (dict == null || value == null)
return null;
List<DictionaryItem> dictionaryItems = dict.getDictItems();
if(dictionaryItems == null && dict.getDictType() == Constant.NUMBER_INTEGER_1) { //内部字典,但字典项为null(单独获取内部字典项,并放入缓存中)
dictionaryItems = dictContextService.getDictItems(dict);
dict.setDictItems(dictionaryItems);
}else if(dict.getDictType() == Constant.NUMBER_INTEGER_2) { //外部字典(获取字典项从线程缓存中)
Dictionary odict = ThreadContextHolder.getThreadValue(dictCode);
if(odict == null) {
dictionaryItems = dictContextService.getDictItems(dict);
dict.setDictItems(dictionaryItems);
ThreadContextHolder.setThreadValue(dict.getDictCode(), dict);
}else {
dictionaryItems = odict.getDictItems();
}
}
@ResponseBody
@RequestMapping(value = "/loginCheck", method = RequestMethod.POST)
public AssembleJSON loginCheck(Model model,HttpServletRequest request) {
try {
String userCode = request.getParameter("userCode");
String sender = request.getParameter("userCode") + request.getParameter("password");
String EncryptedStr = MD5Util.MD5Encrypted(sender);
String str = userService.checkUser(userCode);
if (LoginConstant.LOGIN_USER_NOTEXIST_CODE.equals(str)) { // 用户不存在
return AssembleJSON.SUCCESS(Integer.valueOf(LoginConstant.LOGIN_USER_NOTEXIST_CODE),
LoginConstant.LOGIN_NOTEXIST_STRING);
}
if (str == LoginConstant.LOGIN_USER_INVALID_CODE) { // 无效用户
return AssembleJSON.SUCCESS(Integer.valueOf(LoginConstant.LOGIN_USER_INVALID_CODE),
LoginConstant.LOGIN_USER_INVALID_STRING);
}
if (str == LoginConstant.LOGIN_USER_LOCKED_CODE) { // 锁定用户
return AssembleJSON.SUCCESS(Integer.valueOf(LoginConstant.LOGIN_USER_LOCKED_CODE),
LoginConstant.LOGIN_USER_LOCKED_STRING);
}
String verifyCode = request.getParameter("verifyCode");
String code = (String) request.getSession().getAttribute("verCode");
if (null == code) { // 验证码过期
return AssembleJSON.SUCCESS(Integer.valueOf(LoginConstant.LOGIN_VERIFYCODE_OUTDATE_CODE),
LoginConstant.LOGIN_VERIFYCODE_OUTDATE_STRING);
}
if (null != code && verifyCode.toLowerCase().equals(code.toLowerCase())) {
if (EncryptedStr.equals(str)) {
User user = userService.getUserByCode(userCode);
user.setUserPass(request.getParameter("password"));
request.getSession(true).setAttribute(LoginConstant.LOGIN_USER_SESSION_KEY, user);
ThreadContextHolder.setHttpRequest(request); // 将当前登录 Request 放入线程变量
return AssembleJSON.SUCCESS(user);
} else { // 用户密码错误
return checkLoginNum(request,userCode);
}
} else { // 验证码错误
return AssembleJSON.SUCCESS(Integer.valueOf(LoginConstant.LOGIN_VERIFYCODE_ERROR_CODE),
LoginConstant.LOGIN_VERIFYCODE_ERROR_STRING);
}
}finally{
try {
User user = (User) request.getSession().getAttribute(LoginConstant.LOGIN_USER_SESSION_KEY);
if(user != null) {
Log log = new Log();
log.setLogUserCode(user.getUserCode());
log.setLogUserName(user.getUserName());
log.setLogType(Constant.LOG_TYPE_LOGIN);
log.setLogTime(new Date());
log.setLogIp(request.getRemoteAddr());
logService.insertLog(log); // 添加登录记录到系统日志表
}
}catch(Exception e) {
log.error(e.getMessage());
}
}
}
取线程中的中的user
User user = (User)ThreadContextHolder.getHttpRequest().getSession().getAttribute("current_login_user");
实现request anywhere
import com.platform.core.web.Request;
public class AppMgr {
/**
* 线程级变量
*/
private static final ThreadLocal TL = new ThreadLocal();
/**
* 获取线程级实例对象
* @return rtnBean rtnBean
*/
private static Bean threadBean() {
Bean bean = (Bean) TL.get();
if (bean == null) {
bean = new Bean();
TL.set(bean);
}
return bean;
}
/**
* 获取线程级实例对象中某参数值
* @param key key
* @return rtnObj rtnObj
*/
public static Object threadVar(String key) {
return threadBean().get(key);
}
/**
* 设置线程级实例对象中某参数值
* @param key key
* @param obj setter objInst
*/
public static void setThreadVar(String key, Object obj) {
threadBean().set(key, obj);
}
/**
* 参数BEAN键
*/
public static final String KEY_PARAM_BEAN = "$PARAM_BEAN";
/**
* 参数值
* @param key
* @return Object
*/
public static Object paramVar(String key) {
IBean bean = (IBean) threadVar(KEY_PARAM_BEAN);
if (bean != null) {
return bean.get(key);
} else {
return null;
}
}
}
public class Request {
/**
* 获取Request实例
*
* @return Request实例对象
*/
public static HttpServletRequest getInst() {
return (HttpServletRequest) AppMgr.threadVar("request");
}
/**
* @param request
* void
*/
public static void setInst(HttpServletRequest request) {
AppMgr.setThreadVar("request", request);
}
/**
* 返回当前请求的Session
*
* @param create
* 没有有效的Session时,是否创建新Session,不创建返回null
* @return Session
*/
public static HttpSession getSession(boolean create) {
return getInst().getSession(create);
}
/**
* 返回当前请求的Session
*
* @return Session
*/
public static HttpSession getSession() {
return getInst().getSession();
}
}
代理线程中的HttpServletRequest变量,使代码中可以通过静态方法访问request
var namesalt = getNowFormatDate();
var strUrl = Leopard.getContextPath() +
"/DoMyServlet?className=ExcelPoiAction&methodName=createExcel&btnCode=empdata&forWard=isFile&namesalt="+namesalt+"&func="+_func
+"&pbean="+encodeURI(encodeURI(strwhere))+"&btnCode"+empexcel;
var ifm;
if (document.getElementById("empexcel_iframe") == undefined) {
ifm = document.createElement("IFRAME");
ifm.setAttribute("id", "empexcel_iframe");
ifm.setAttribute("name", "empexcel_iframe");
ifm.style.height = "0";
ifm.style.width = "0";
ifm.style.display = "block";
ifm.src = "";
document.body.appendChild(ifm);
document.getElementById("empexcel_iframe").attachEvent(
"onload",
function() {
window.frames['empexcel'].document.getElementById("empexcel").click();
});
} else { ifm = document.getElementById("empexcel_iframe"); }
ifm.src = strUrl;
public class ExcelPoiAction {
public void createExcel() throws IOException {
HttpServletRequest req = Request.getInst();
this.funcCode = req.getParameter("func"); //功能单元
//this.strWhere = req.getParameter("pbean"); //附件查询条件
this.strWhere = java.net.URLDecoder.decode(req.getParameter("pbean"),"utf-8");
if (!StringUtils.isEmpty(strWhere)) {
try {
objWhere = new JSONObject("{" + strWhere + "}");
} catch (JSONException e) {}
}
//获取业务参数
String busiStr = req.getParameter("busiData");
if(!StringUtils.isEmpty(busiStr)){
try {
this.busiData = JsonUtils.transferToBean(busiStr);
} catch (Exception e) {}
}
}
线程共享变量缓存如下:
Thread.ThreadLocalMap<ThreadLocal, Object>;
1、Thread: 当前线程,可以通过Thread.currentThread()获取。
2、ThreadLocal:我们的static ThreadLocal变量。
3、Object: 当前线程共享变量。
我们调用ThreadLocal.get方法时,实际上是从当前线程中获取ThreadLocalMap<ThreadLocal, Object>,然后根据当前ThreadLocal获取当前线程共享变量Object。
ThreadLocal.set,ThreadLocal.remove实际上是同样的道理。
这种存储结构的好处:
1、线程死去的时候,线程共享变量ThreadLocalMap则销毁。
2、ThreadLocalMap<ThreadLocal,Object>键值对数量为ThreadLocal的数量,一般来说ThreadLocal数量很少,相比在ThreadLocal中用Map<Thread, Object>键值对存储线程共享变量(Thread数量一般来说比ThreadLocal数量多),性能提高很多。
关于ThreadLocalMap<ThreadLocal, Object>弱引用问题:
当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。
虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用,所以为了防止此类情况的出现,我们有两种手段。
1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;
2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。
源码实现
ThreadLocal类提供的几个方法:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
---------------------
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
---------------------
ThreadLocal.ThreadLocalMap threadLocals = null;
---------------------
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
---------------------
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
---------------------
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
request和response
Servlet
说明servlet主要有三个生命周期:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象,注意这个实例是单例的,所以调用后面的service方法的时候可能有并发问题。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
关于servlet线程安全的问题这里多提一下:
对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。只要该Servlet中不存在全局变量就不存在线程安全问题,因为每个线程访问的时候都会有自己的方法栈,局部变量是互不影响的。
web.xml
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>com.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/servlet/ServletDemo</url-pattern>
</servlet-mapping>
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < (lastModified / 1000L) * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else
{
resp.setStatus(304);
}
}
} else
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else
if(method.equals("POST"))
doPost(req, resp);
else
if(method.equals("PUT"))
doPut(req, resp);
else
if(method.equals("DELETE"))
doDelete(req, resp);
else
if(method.equals("OPTIONS"))
doOptions(req, resp);
else
if(method.equals("TRACE"))
{
doTrace(req, resp);
} else
{
String errMsg = lStrings.getString("http.method_not_implemented");
Object errArgs[] = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
Request
1.获取请求的基本信息
1>获取请求的url和uri
2>获取url后面的请求参数部分的字符串
3>获取请求方式
4>获取主机名,IP地址
5>获取 Contexpath
String url = request.getRequestURL().toString();
System.out.println(url);
String uri = request.getRequestURI().toString();
System.out.println(uri);
String params = request.getQueryString();
System.out.println(params);
String method = request.getMethod();
System.out.println(method);
String addr = request.getRemoteHost() + request.getRemotePort() + request.getRemoteAddr() +
"==user=" + request.getRemoteUser();
System.out.println("addr: " + addr);
String contextPath = request.getContextPath();
response.sendRedirect(contextPath + "/index.jsp");
获取请求参数
Map<String, String[]> params = request.getParameterMap();
for (String name : params.keySet()) {
String value = request.getParameter(name);
System.out.println("name=" + name + ", value=" + value);
}
解决请求乱码问题:
request.setCharacterEncoding("Utf-8");
如果上面的代码只能解决POST的乱码问题, 则可以自行进行解码操作
String userName = request.getParameter("username");
userName = new String(userName.getBytes("ISO8859-1"), "UTF-8");
前段使用 UTF-8 进行编码, 传输到服务器, 服务器可以使用 ISO8859-1 解码得到UTF-8编码后的码值, 然后通过new String(bytes, charset)的方式进行解码
设置和获取域属性
Object attr = request.getAttribute("attr");
request.setAttribute("key", "value");
request.removeAttribute("attr");
Enumeration<String> attributeNames = request.getAttributeNames();
一般我们的应用是servlet处理数据, 将处理好的数据放到request域中,然后带到jsp页面上进行展示操作.
请求转发与请求包含
请求转发:
request.getRequestDispatcher("/DispatcherTest2").forward(request, response);
或
this.getServletContext().getRequestDispatcher("/DispatcherTest2").forward(request, response);
1)一次请求只能转发一次, 否则会发生下面的异常: -- 可以得到第一次转发获取的数据
java.lang.IllegalStateException: Cannot forward after response has been committed
2)当有数据已经写到客户端时再请求转发也会抛出异常.
3)若转发前有数据写入到response缓冲区,则请求转发会清空response缓冲区的实体内容, 但不会清空请求头信息.
请求包含:
当需要将多个servlet的输出合并到一块打给浏览器时可以使用请求包含
request.getRequestDispatcher("/DispatcherTest2").include(request, response);
或
this.getServletContext().getRequestDispatcher("/DispatcherTest2").include(request, response);
1)被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略.
2)常被用来进行页面布局
response.sendRedirect(request.getContextPath() + "/DispatcherTest2");
1) 不能在数据已经发送到浏览器之后再进行请求重定向:
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
2) 在请求重定向之前写入到response缓冲区的数据会被清空
3) 一次请求只能重定向一次
请求重定向地址栏会发生变化.请求转发地址栏不发生变化.
请求重定向两次请求两次响应.请求转发一次请求一次响应.
如果需要在资源跳转时利用request域传递域属性则必须使用请求转发
如果希望资源跳转后修改用户的地址栏则使用请求重定向
如果使用请求转发也可以重定向也可以,则优先使用请求转发,减少浏览器对服务器的访问次数减轻服务器的压力.
response
ServletResponse -- 通用的response提供了一个响应应该具有最基本的属性和方法
|
|-HttpServletResponse -- 在ServletResponse的基础上针对于HTTP协议增加了很多强化的属性和方法
2.输出数据
1)getOutputStream字节输出流
response.getOutputStream().write("中国".getBytes("utf-8"));
string.getBytes()如果没有指定编码方式,会使用平台默认的编码方式
2)getWriter字符输出流
response.getWriter().write("北京");
getWriter和getOutputStream在一次请求中只能使用一个
使用字符输出流输出中文时, 由于网线上只能输出高低电平,如果没有指定编码方式,那么服务器在发送数据时会使用默认的ISO-8859-1对数据编码(该码表中没有汉字, 因此汉字会被编码为?, 传送到浏览器上的数据实际就是?).
解决乱码
1> 通知服务器发送数据时使用utf-8编码
response.setCharacterEncoding("utf-8");
2> 通知浏览器接受数据时使用utf-8解码
response.setHeader("Content-Type", "text/html;charset=utf-8");
a. response对象中对Content-Type响应头进行了封装,可以使用一下代码代替 2>
response.setContentType("text/html;charset=utf-8");
b. 如果设置了Content-Type,服务器会自动的设置 characterEncoding,因此解决乱码只需要设置Content-Type响应头一行代码就可以了,但是为了代码的可读性更高,一般还是建议同时设置 characterEncoding 和 Content-Type.
3)实现下载
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("美女.jpg"));
InputStream in = new FileInputStream(this.getServletContext().getRealPath("美女.jpg"));
OutputStream out = response.getOutputStream();
byte[] bytes = new byte[1024];
int len = -1;
while(-1 != (len = in.read(bytes))) {
out.write(bytes, 0, len);
}
in.close();
}
4) 实现定时刷新
Servlet实现
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("恭喜您注册成功, 3秒后回到主页");
response.setHeader("Refresh", "3;url=OutServlet");
html实现
<meta charset="UTF-8">
<meta http-equiv="Refresh" content="3; url=index.jsp" >
<title>Insert title here</title>
</head>
<body>
恭喜您注册成功, 3秒后回到主页....
</body>
5)控制浏览器是否缓存
response.setIntHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.getWriter().write(new Date().toLocaleString());
6)实现请求重定向
response.sendRedirect(this.getServletContext().getContextPath());
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ThreadContextHolder
{
private static ThreadLocal<HttpServletRequest> HttpRequestThreadLocalHolder = new ThreadLocal();
private static ThreadLocal<HttpServletResponse> HttpResponseThreadLocalHolder = new ThreadLocal();
private static ThreadLocal<Map<String, Object>> threadVar = new ThreadLocal();
public static void setThreadValue(String key, Object value)
{
Map<String, Object> map = (Map)threadVar.get();
if (map == null)
{
map = new HashMap();
map.put(key, value);
threadVar.set(map);
}
else
{
map.put(key, value);
}
}
public static <T> T getThreadValue(String key)
{
Map<String, Object> map = (Map)threadVar.get();
if (map != null) {
return map.get(key);
}
return null;
}
public static void setHttpRequest(HttpServletRequest request)
{
HttpRequestThreadLocalHolder.set(request);
}
public static HttpServletRequest getHttpRequest()
{
return (HttpServletRequest)HttpRequestThreadLocalHolder.get();
}
public static void setHttpResponse(HttpServletResponse response)
{
HttpResponseThreadLocalHolder.set(response);
}
public static HttpServletResponse getHttpResponse()
{
return (HttpServletResponse)HttpResponseThreadLocalHolder.get();
}
public static String getSessionId()
{
HttpServletRequest request = (HttpServletRequest)HttpRequestThreadLocalHolder.get();
if (null != request) {
return request.getSession().getId();
}
return null;
}
public static void clearThreadValues()
{
threadVar.remove();
}
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class HttpSessionService
implements ISessionService
{
private final Log logger = LogFactory.getLog(getClass());
public Object getAttribute(String arg0)
{
HttpSession session = getSession();
return session == null ? null : session.getAttribute(arg0);
}
public String getId()
{
HttpSession session = getSession();
return session == null ? null : session.getId();
}
public void invalidate()
{
HttpSession session = getSession();
if (session != null) {
session.invalidate();
}
}
public void removeAttribute(String arg0)
{
HttpSession session = getSession();
if (session != null) {
session.removeAttribute(arg0);
}
}
public void setAttribute(String arg0, Object arg1)
{
HttpSession session = getSession();
if (session != null) {
session.setAttribute(arg0, arg1);
}
}
private HttpSession getSession()
{
HttpServletRequest request = ThreadContextHolder.getHttpRequest();
if ((request == null) || (request.getSession() == null)) {
this.logger.info("============================>>>sessoin 失效");
}
return request.getSession();
}
}
public class SessionContextHolder
{
private static ISessionService sessionService;
public static ISessionService getInstance()
{
sessionService = (ISessionService)SpringContextHolder.getBean("httpSessionService");
return sessionService;
}
}
<!-- bean 管理器 -->
<bean id="springContextHolder" class="com.platform.framework.context.SpringContextHolder" lazy-init="false"/>
public List<Map<String, Object>> getOrgUsers(){
User user = (User) SessionContextHolder.getInstance().getAttribute(LoginConstant.LOGIN_USER_SESSION_KEY);
return userMapper.selectOrgUsers(user);
}