听起来像是你可以在ContainerResponseFilter 中做的事情,它在视图资源/控制器返回后被调用。假设您返回一个Viewable,您从ContainerRequestContext#getEntity 中获取Viewable,从中获取模型,并将额外信息添加到模型中。
@Provider
@UserInModel
public class UserInModelFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
Cookie cookie = request.getCookies().get("User-Data");
String header = request.getHeaderString("User-Agent");
String username = AppUser.getName(cookie.getValue());
boolean isMobile = AppUser.isMobile(header);
Viewable returnViewable = (Viewable) response.getEntity();
Map<String, Object> model = (Map<String, Object>) returnViewable.getModel();
model.put("username", username);
model.put("isMobile", isMobile);
}
}
@UserInModel注解是自定义的Name Binding注解,用于确定哪些资源类或方法应该通过这个过滤器。由于您不希望所有端点都通过此过滤器,因此只需注释您想要的方法或类。
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface UserInModel {
}
@Path("/")
public class IndexController {
@GET
@UserInModel
@Produces(MediaType.TEXT_HTML)
public Viewable home() {
Map<String, Object> model = new HashMap<>();
return new Viewable("/index", model);
}
}
使用 Dropwizard,您只需注册过滤器即可。
env.jersey().register(UserInModelFilter.class);
如果您想在调用资源方法之前对cookie 和标头进行一些预处理,您可以在ContainerRequestFilter 中进行,这也可以是名称绑定。除了在响应过滤器中重新计算 AppUser.xxx 方法之外,您还可以在 ContainerRequestContext#setProperty 上设置一个属性,以后可以在响应过滤器中从同一上下文 (getProperty) 中检索该属性。
更新
以上答案假设您使用的是Jersey's MVC support,因此使用Viewable。如果您使用的是Dropwizard's view support,那么并没有太大的不同。您可能希望创建一个抽象类作为所有视图类的父类,这样您就可以在从过滤器中检索实体时强制转换为抽象类型。
public class AbstractView extends View {
private String userName;
private boolean isMobile;
protected AbstractView(String templateName) {
super(templateName);
}
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public boolean isMobile() { return isMobile; }
public void setIsMobile(boolean mobile) { isMobile = mobile; }
}
public class PersonView extends AbstractView {
private final Person person;
public PersonView(Person person) {
super("person.ftl");
this.person = person;
}
public Person getPerson() {
return this.person;
}
}
在过滤器中
@Provider
@UserInModel
public class UserInModelFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
Cookie cookie = request.getCookies().get("User-Data");
String header = request.getHeaderString("User-Agent");
String username = AppUser.getName(cookie.getValue());
boolean isMobile = AppUser.isMobile(header);
AbstractView returnViewable = (AbstractView) response.getEntity();
returnViewable.setUserName(username);
returnViewable.setIsMobile(isMobile);
}
}
测试资源类的完整性
@Path("person")
public class PersonController {
@GET
@UserInModel
@Produces(MediaType.TEXT_HTML)
public PersonView person() {
Person person = new Person("peeskillet@fake.com");
return new PersonView(person);
}
}