1

因此,对于一个学校项目,我们创建了一个网站,用户可以在其中提交有关水下生活等的报告。我们使用了简单的依赖注入 (javax.inject) 和错误检查模式,如下所示:

报告服务.java

public interface ReportService {
    public static enum ReportServiceErrorsENUM {
        DB_FAILURE, WRONG_COORD // etc
    }
    public Set<ReportServiceErrorsENUM> getLastErrors();
    public int addNewReport(Report report);
}

ReportServiceImpl.java

public class ReportServiceImpl implements ReportService {

    private Set<ReportServiceErrorsENUM> lastErrors;
    private @Inject ReportDAO reportDAO;

    @Override
    public Set<ReportServiceErrorsENUM> getLastErrors() {
        return this.lastErrors;
    }

    @Override
    public int addNewReport(Report report) {
        lastErrors= new HashSet<ReportServiceErrorsENUM>();//throw away previous errors
        UserInput input = report.getUserInput();
        if (input.getLatitude() == null) {
            addError(ReportServiceErrorsENUM.WRONG_COORD);
        }
        // etc etc
        if (reportDAO.insertReport(report) != 0) {
            // failure inserting the report in the DB
            addError(ReportServiceErrorsENUM.DB_ERROR);
        }
        if (lastErrors.isEmpty()) // if there were no errors
            return EXIT_SUCCESS; // 0
        return EXIT_FAILURE;  // 1
    }
}

提交报告控制器.java

@WebServlet("/submitreport")
public class SubmitReportController extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private @Inject ReportService reportService;

    @Override
    protected void doPost(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
        Report report = new Report();
        // set the report's fields from the HttpServletRequest attributes
        if(reportService.addNewReport(report) == ReportService.EXIT_FAILURE) {
            for(ReportServiceErrorsENUM error : reportService.getLastErrors())
                // display the errors etc
        } else {
            // display confirmation
        }
    }
}

这个想法是 Servlet 控制器调用服务(被注入)然后检查服务的返回值并在服务上调用 getLastErrors() 如果有错误 - 通知用户出了什么问题等等。现在我来了意识到这不是线程安全的 - @Inject'ed ReportService (reportService) 将由使用 servlet 的所有线程共享

  1. 是(交叉手指)吗?
  2. 如何改进这种错误机制?

谢谢

4

2 回答 2

1

通常对于 servlet,您希望将这些变量(通常称为“状态”)保留在某些容器管理的上下文中。我会将这些错误移到请求范围内——这样它们就存储在请求对象上(从概念上讲),并且任何处理同一请求的 servlet/jsp/任何东西都可以看到/编辑它们。不同的请求意味着不同的数据存储。

可以在此处找到使用 servlet 请求范围的示例代码:http ://www.exampledepot.com/egs/javax.servlet/State.html

于 2012-07-22T19:00:29.730 回答
1

您的设计既不是线程安全的,也不是准备好为多个用户提供服务。它不是线程安全的,因为多个用户(浏览器)可以同时访问 servlet,进而lastErrors同时访问设置。(是的,servlet 和您的服务只有一个实例)。HashSet您使用的不是线程安全的。

此外,如果两个不同的人尝试使用同一个应用程序,他们将覆盖并访问彼此提交的报告(错误)。换句话说,所有用户之间共享全局状态,而每个用户/会话应该有一个状态。

通过修复第二个问题(我给了你一个提示:使用HTTPSession),你不太可能看到第一个问题。这是因为很少看到对同一会话的并发访问。但这是可能的(并发 AJAX 请求,两个浏览器选项卡)。请记住这一点,但现在还有更重要的问题需要解决。

于 2012-07-22T19:02:11.497 回答