Database 带有数据库信息的自定义筛选器删除向导
我正在使用dropwizard 0.7.0,我想创建一个自定义筛选器 自定义筛选器应检查数据库中是否存在令牌。 创建筛选器并在应用程序类中注册此筛选器的正确方法是什么 我曾经实现过过滤器,但当我将代码更改为以下内容时:Database 带有数据库信息的自定义筛选器删除向导,database,filter,dropwizard,Database,Filter,Dropwizard,我正在使用dropwizard 0.7.0,我想创建一个自定义筛选器 自定义筛选器应检查数据库中是否存在令牌。 创建筛选器并在应用程序类中注册此筛选器的正确方法是什么 我曾经实现过过滤器,但当我将代码更改为以下内容时: final AuthenticationDAO authenticationDAO = new AuthenticationDAO(hibernateBundle.getSessionFactory()); environment.servlets().addFilter("au
final AuthenticationDAO authenticationDAO = new AuthenticationDAO(hibernateBundle.getSessionFactory());
environment.servlets().addFilter("authenticationFilter", new AuthenticationFilter(authenticationDAO)).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/transaction/*");
这是我的过滤器:
public class AuthenticationFilter implements Filter {
private final AuthenticationDAO authenticationDAO;
public AuthenticationFilter(AuthenticationDAO authenticationDAO) {
this.authenticationDAO = authenticationDAO;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String authenticationToken = ((Request) servletRequest).getHeader(Constants.HEADER_TOKEN_PARAM_NAME);
HttpServletResponse response = (HttpServletResponse)servletResponse;
if(Strings.isNullOrEmpty(authenticationToken)){
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else if(!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()){
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() {
}
}
当访问筛选器时,由于没有活动的会话,我收到以下错误:
警告[2014-04-22 14:37:42733]org.eclipse.jetty.servlet.ServletHandler:/test/show
! org.hibernate.HibernateException:当前没有绑定到执行上下文的会话
! 在org.hibernate.context.internal.ManagedSessionContext.currentSession(ManagedSessionContext.java:75)~[hibernate-core-4.3.1.Final.jar:4.3.1.Final]
! 在org.hibernate.internal.SessionFactoryImpl.getCurrentSession(sessionfactorympl.java:1013)~[hibernate-core-4.3.1.Final.jar:4.3.1.Final]也许您可以尝试:
import com.google.common.base.Strings;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
public class AuthenticationFilter implements ContainerRequestFilter {
private final AuthenticationDAO authenticationDAO;
public AuthenticationFilter(AuthenticationDAO authenticationDAO) {
this.authenticationDAO = authenticationDAO;
}
@Override
public ContainerRequest filter(final ContainerRequest containerRequest) {
String authenticationToken = containerRequest.getHeaderValue(Constants.HEADER_TOKEN_PARAM_NAME);
if (Strings.isNullOrEmpty(authenticationToken)) {
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
} else if (!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()) {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN).build());
}
return containerRequest;
}
}
在run方法中,您可以添加:
environment.jersey().getResourceConfig().getContainerRequestFilters().add(new AuthenticationFilter(...));
此拉取请求可能会满足您的需要。我自己也遇到了这个问题,我认为我的问题与Dropwizard线程中讨论的一样: 简言之,您可能需要打开并绑定自己的会话—Dropwizard管理的my类使用的会话很好,但Dropwizard未管理的类遇到此错误 我正试图在打开和绑定我自己的会话之间做出决定,而只是将类移动到Dropwizard管理的会话,以便使用@UnitOfWork注释 此外,如果您不在@UnitOfWork中(它似乎只对rest调用有效),那么您可以很好地使用会话,但不能使用DAO层。如果您使用DAO,您将得到该错误。可能还有更多,但出于我的目的,我只使用了一个SQLQuery:
SQLQuery deleteQuery = session.createSQLQuery("DELETE FROM MYTABLE WHERE REPORTTIME < ?");
deleteQuery.setTimestamp(0, cutoffDate.toDate());
deleteQuery.executeUpdate();
SQLQuery deleteQuery=session.createSQLQuery(“从我的表中删除,其中REPORTTIME<?”;
deleteQuery.setTimestamp(0,截止日期.toDate());
deleteQuery.executeUpdate();
这是否是最好的解决方案还存在争议,但就我而言,这已经足够了。要在代码的非托管部分启用DropWizard“magic”(Hibernate),必须插入SessionFactory。您可以在DropWizard配置中查看如何创建一个:
然后可以将sessionFacotry注入构造函数中的AuthenticationFilter
在筛选器中,您必须手动绑定hibernate会话,如:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String authenticationToken = ((Request) servletRequest).getHeader(Constants.HEADER_TOKEN_PARAM_NAME);
Session session = sessionFactory.openSession();
session.setDefaultReadOnly(true);
session.setCacheMode(CacheMode.NORMAL);
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
// DropWizard magic enabled from this point.
HttpServletResponse response = (HttpServletResponse)servletResponse;
if(Strings.isNullOrEmpty(authenticationToken)){
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else if(!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()){
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
session.close();
// DropWizard magic disabled from this point.
}
这就是本质。在bind()和close()之间发生的任何事情都将启用DropWizard magic,同样在托管Dao中。您可以通过错误处理等使其更加健壮来改进它
即使您使用的是示例中所示的托管资源,这种方法也有效。发生的情况是DropWizards RequestDispatcher激活并执行与您相同的操作:它打开一个会话并将其绑定到线程。其效果是,托管资源使用的会话与您手动打开的会话不同,并且您最初绑定的会话将在不进行清理的情况下被删除。在您的示例中,这样做的效果是,在调用doFilter(…)之后,魔术结束了。如果以后要访问数据库,必须重新绑定之前创建的会话。只要打电话:
ManagedSessionContext.bind(session);
我还没有遇到过这种技术的任何问题,但我可以想象,如果您需要访问另一个会话中的一个会话中的数据,就会出现问题。这可能需要对隔离级别进行一些调整。在事务外部使用AuthenticationDAO时会出现问题。如中所述,注释可用于创建事务边界 但是,要使这项工作适用于Jersey资源以外的类,您需要使用 首先创建一个工厂
UnitOfWorkAwareProxyFactory proxyFactory = new UnitOfWorkAwareProxyFactory("session factory", hibernateBundle.getSessionFactory());
然后使用它创建AuthenticationFilter
AuthenticationFilter filter = proxyFactory.create(AuthenticationFilter.class, AuthenticationDAO.class, authenticationDAO);
environment.servlets().addFilter("authenticationFilter", filter).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/transaction/*");
最后用@UnitOfWork注释doFilter
public class AuthenticationFilter implements Filter {
@UnitOfWork
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
...
谢谢你的回答,但这不是正确的答案,我应该添加一个url模式。使用此解决方案将无法访问筛选器。访问令牌检查时也会出现错误:org.hibernate.HibernateException:当前没有绑定到执行上下文的会话如何以这种方式添加url模式?我不确定是否正确,但是,您不能从containerRequest对象获取url并执行以下操作:final Pattern urlPattern=Pattern.compile(“url regex Pattern”);如果(urlPattern.matcher(containerRequest.getAbsolutePath().getPath()).matches(){return containerRequest;}我不使用Hibernate,所以我确定是什么导致了这个问题。检查用户名和密码是否有效。:)是否只有在使用过滤器时您才有Hibernate问题?如果没有,请尝试隔离问题。我在创建dropwizard任务时也使用了此方法来解决相同的问题。