这是我的servlet的代码。
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
Map m=request.getParameterMap();
Set s = m.entrySet();
Iterator it = s.iterator();
int index=0;
while (it.hasNext()) {
Map.Entry<String,String[]> entry = (Map.Entry<String,String[]>) it.next();
String key = entry.getKey();
String[] value = entry.getValue();
System.out.println("Value is " + value[0].toString());
switch(key) {
case "RegId":
RegId = value[0].toString();
break;
case "isTrackingRequested":
isTrackingRequested = Boolean.valueOf(value[0]);
break;
}
}
// Create a session object if it is already not created.
HttpSession session = request.getSession(true);
if (session.isNew()) {
session.setAttribute("id",isTrackingRequested);
}
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
boolean isTrackingRequestednew = (boolean) session.getAttribute("id");
// code to run
if (isTrackingRequestednew) {
try {
System.out.println("===========================================================================");
System.out.println("new track status is " + isTrackingRequestednew);
System.out.println("===========================================================================");
} catch (Exception e) {
}
} else {
ses.shutdown();
}
}
}, 0, 1, TimeUnit.SECONDS);
}
我正在尝试使用ScheduledExcecutorService
跟踪车辆。我正在使用标志isTrackingRequested
来检查用户是否已请求跟踪。因此,我将保存会话中的值,但每当我请求停止跟踪时,先前设置的会话属性都会显示null
值。
简而言之,我试图访问以前设置的会话变量,但最终得到了null
。我尝试过的任何解决方案似乎都不起作用。
每当我请求停止跟踪时,先前设置的会话属性都显示null值。
一个合理可能的解释是,请求不在同一会话中。维护会话需要客户的合作,但不能保证给予合作。将请求与会话关联起来的最常见机制是cookie和URL重写。如果客户端拒绝cookie并向静态URL发出请求,那么每个请求都可能在自己的会话中。
然而,这是你的一个较小的问题。你也有这些:
在每个POST请求中,您都会创建一个新的ScheduledExecutorService
和一个要管理的新任务。这肯定不是你想要的。
添加:您不会使用属于现有会话的请求所携带的跟踪状态来更新这些会话。只有当会话是为正在服务的请求新创建的时,才能设置会话属性
此外,当我上次研究JavaEE规范(一个版本之前)时,JavaEE组件(如servlet)不允许启动自己的线程,但您的组件(其中许多)可以在所有ScheduledExecutorService
s内启动。这并不意味着启动新线程(或创建ScheduledExecutorService
)必然会失败,但您违反规范确实意味着您不能依赖JavaEEAPI来按照文档进行操作
此外,您的代码没有正确同步。您在没有正确同步的情况下访问共享状态(Session
)。
此外,当会话过期或手动终止时,您似乎没有关闭跟踪的机制。
为了正确地执行此操作,应该在servlet容器外部运行的单独服务中执行跟踪。或者,您可以将它与只在容器外部运行的调度器本身以及在容器内部运行的所有跟踪状态一起破解。然后,调度器只需要通过向同一容器中的不同servlet发送周期性请求来充当时钟
您最好将任务与会话解耦。与其让它从会话中获取跟踪状态,不如给它一个成员变量,并在会话中存储对任务本身的引用。响应请求直接修改任务的状态,而不是通过会话间接传递该信息。并确保对该对象共享状态的所有访问都正确同步!
添加:此外,我建议您让任务实现HttpSessionBindingListener
,这样当它从会话中解除绑定时——无论是手动解除绑定,还是由于会话达到其生命周期的末尾——它都可以自行取消
添加:此外,请注意,现代JavaEE需要容器使ScheduledExecutorService
可用于企业组件。您应该能够通过JNDI名称java:comp/DefaultManagedScheduledExecutorService
获得对它的引用(请参阅Java EE 7平台规范中的EE.5.21节)。明智的做法是使用这个容器提供的服务,而不是尝试建立自己的服务
您提供的代码中有一些错误。每次都应该检查isTrackingRequested
的值,因为请求者可以发送值false
来停止跟踪。还应考虑isTrackingRequested
的null
值。如果它为空,那么这可能意味着用户希望继续执行之前的决定。
这些已经在下面的代码中进行了更正,现在应该可以工作了。
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String RegId = String.valueOf(request.getParameter("RegId"));
// Create a session object if it is already not created.
final HttpSession session = request.getSession(true);
String trackingRequestParam = request.getParameter("isTrackingRequested");
boolean isTrackingRequested = false;
if(trackingRequestParam != null) {
isTrackingRequested = Boolean.valueOf(trackingRequestParam);
session.setAttribute("id", isTrackingRequested);
}
if(trackingRequestParam != null && isTrackingRequested) {
final ScheduledExecutorService ses = Executors
.newSingleThreadScheduledExecutor();
session.setAttribute("isRunning", true);
ses.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
boolean isTrackingRequestednew = Boolean.valueOf(String.valueOf(session.getAttribute("id") ));
System.out.println("inside repeater : " + session.getAttribute("id") + " : " + isTrackingRequestednew);
// code to run
if (isTrackingRequestednew) {
try {
System.out.println("===========================================================================");
System.out.println("new track status is " + isTrackingRequestednew);
System.out.println("===========================================================================");
} catch (Exception e) {
}
} else {
ses.shutdown();
}
}
}, 0, 1, TimeUnit.SECONDS);
}
}
编辑*****
我正在添加我在这里使用的整个TestServlet代码。为了便于测试,我已经将POST方法转换为GET方法。
TestServlet
package test;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Boolean isLogout = Boolean.valueOf(String.valueOf(request.getParameter("logout")));
String RegId = String.valueOf(request.getParameter("RegId"));
// Create a session object if it is already not created.
final HttpSession session = request.getSession(true);
String trackingRequestParam = request.getParameter("isTrackingRequested");
boolean isTrackingRequested = false;
if(trackingRequestParam != null) {
isTrackingRequested = Boolean.valueOf(trackingRequestParam);
session.setAttribute("id", isTrackingRequested);
}
if(isLogout) {
session.invalidate();
}
if(trackingRequestParam != null && isTrackingRequested) {
final ScheduledExecutorService ses = Executors
.newSingleThreadScheduledExecutor();
session.setAttribute("isRunning", true);
ses.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
boolean isTrackingRequestednew = Boolean.valueOf(String.valueOf(session.getAttribute("id") ));
System.out.println("inside repeater : " + session.getAttribute("id") + " : " + isTrackingRequestednew);
// code to run
if (isTrackingRequestednew) {
try {
System.out.println("===========================================================================");
System.out.println("new track status is " + isTrackingRequestednew);
System.out.println("===========================================================================");
} catch (Exception e) {
}
} else {
ses.shutdown();
}
} catch (Exception ex) {
ex.printStackTrace();
ses.shutdown();
}
}
}, 0, 1, TimeUnit.SECONDS);
}
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
}
整个测试Servlet
测试
点击下面的URL(在我的情况下,TestWeb是上下文名称,用你的替换它)
http://localhost:8080/TestWeb/TestServlet?isTrackingRequested=true<br>
//then after a few seconds<br>
http://localhost:8080/TestWeb/TestServlet?isTrackingRequested=false
输出(测试在Tomcat 7.0.59上完成)
内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:true:true===========================================================================新轨道状态为true===========================================================================内部中继器:false:false
跟踪设置为false后,由于执行器关闭,它将停止打印。
注意:清除Cookie即可开始新会话
第2版***添加了支持手动注销的代码,调用下面的URL进行注销。
http://localhost:8080/TestWeb/TestServlet?logout=true