Dropwizard中的Jersey过滤器设置一些全局FreeMarker变量

And*_*row 7 java freemarker jersey dropwizard

我正在阅读https://jersey.github.io/documentation/latest/filters-and-interceptors.htmlhttp://www.dropwizard.io/1.1.4/docs/manual/core.html#jersey-过滤器尝试使这个:

@CookieParam("User-Data") userData: String,
@HeaderParam("User-Agent") userAgent: String,
Run Code Online (Sandbox Code Playgroud)

我的网络应用程序的每个资源GET方法都不需要.userData是来自cookie的json数据,其中包含"name"和"id"等字段,并且userAgent是标题中的完整User-Agent字符串.对于我传入的每个视图:

AppUser.getName(userData), AppUser.isMobile(userAgent)
Run Code Online (Sandbox Code Playgroud)

getName函数解析json并仅返回name字段,isMobile如果找到字符串"mobile" ,函数将返回true布尔值.

我在FreeMarker中的应用程序的每个视图中使用它来显示用户的名字,并在移动设备为真时更改一些布局内容.

有没有办法减少重复次数?我宁愿每次都使用BeforeFilter来自动设置它.

Pau*_*tha 7

听起来像你可以在a中做的事情,在视图资源/控制器返回ContainerResponseFilter调用.假设你返回,你得到的从,从它那里得到的模型,并添加额外的信息模型.ViewableViewableContainerRequestContext#getEntity

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

@UserInModel注释是一个自定义的名称绑定注解,这是用来确定哪些资源类或方法应该通过这个过滤器.由于您不希望所有端点都通过此过滤器,因此只需注释所需的方法或类.

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Dropwizard,您只需注册过滤器即可.

env.jersey().register(UserInModelFilter.class);
Run Code Online (Sandbox Code Playgroud)

如果要在调用资源方法之前对cookie和标头进行一些预处理,则可以在a中执行此操作,ContainerRequestFilter也可以使用名称绑定.而不是AppUser.xxx在响应过滤器中重新计算方法,您也可以只设置一个属性,ContainerRequestContext#setProperty以后可以从getProperty响应过滤器中的相同上下文()中检索该属性.

UPDATE

上面的答案假设您正在使用Jersey的MVC支持,因此使用Viewable.如果你使用Dropwizard的视图支持,那么它没有太大的不同.您可能希望创建一个抽象类作为所有视图类的父类,这样您就可以在从过滤器中检索实体时转换为抽象类型.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在过滤器中

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

已完成测试的资源类

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)