§自定义 Action 参数注入 Annotation

Action 参数注入章节中,我们看到 @Inject, @Config 等用于 Controller 注入的 Annotation,还看到了 @PathVariable, @RequestParam 等专门用于 Action 方法的参数注入的 Request/Session 相关的 Annotation。

同样的,我们在 IoC 相关的章节中也介绍了IoC 自定义注入 Annotation。但是在 IoC 容器中,只能使用 Request/Session 无关的自定义 Annotation。而本章节将介绍的是专门用于 Action 方法的参数注入的 Request 相关的自定义 Annotation。

§1. 看代码学习

先创建自己的 Annotation。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@ManagedWith(RequestHeaderArgumentGetter.class)
public @interface RequestHeader {
    String value();
}

注意,我们在这个 Annotation 上面标注了一个 @ManagedWith(RequestHeaderArgumentGetter.class),这个是关键点。告诉 jetbrick,这个 Annotation 将会由 RequestHeaderArgumentGetter 来处理。

下面我们在创建 RequestHeaderArgumentGetter.java

@Managed
public class RequestHeaderArgumentGetter implements AnnotatedArgumentGetter<RequestHeader, String> {
    private String name;

    @Override
    public void initialize(ArgumentContext<RequestHeader> ctx)
        this.name = ctx.getAnnotation().value();        
    }

    @Override
    public String get(RequestContext ctx) {
        return ctx.getRequest().getHeader(name);
    }
}

作为一个准备注入 Action 参数的自定义的 Annotation,我们的 Class 必须实现 jetbrick.web.mvc.action.annotations.AnnotatedArgumentGetter<A, T> 接口。

其中,泛型参数 A 代表你要处理的自定义 Annotation,T 代表返回值类型。

§2. 自定义注入类型

@ManagedWith(SessionUserArgumentGetter.class)
public class SessionUser {
    private int id;
    private String username;
    ...
}

其中 @ManagedWith(SessionUserArgumentGetter.class) 描述了 SessionUser 对象的注入将会由 SessionUserArgumentGetter 来实现。

我们再来看 SessionUserArgumentGetter 参数注入处理器:

@Managed
public class SessionUserArgumentGetter implements TypedArgumentGetter<SessionUser> {
    @Override
    public SessionUser get(RequestContext ctx) {
        return (SessionUser) ctx.getSession().getAttribute("SESSION_USER");
    }
}

其中,按类型注入必须实现 jetbrick.web.mvc.action.annotations.TypedArgumentGetter<T> 接口。

再来看一下如何使用这个 SessionUser

@Controller
public class PassportController {
    @Inject UserService userService;

    @Action("/passport/changepwd")
    public String changePassword(SessionUser me, @RequestParam("pwd") String pwd) {
        userService.changePassword(me.getId(), pwd);
        return "ok.jsp";
    }
}

如果我们要注入的类型是系统 Class 或者第三方提供的,无法为其添加 @ManagedWith(XXXArgumentGetter.class) Annotation,那么也没关系。只要有 XXXArgumentGetter.class 就可以了,比如我们想要注入 java.util.Locale,我们只要实现一个对应的 LocaleArgumentGetter 即可。如下:

@Managed(Locale.class)
public class LocaleArgumentGetter implements TypedArgumentGetter<Locale> {
    @Override
    public Locale get(RequestContext ctx) {
        return ctx.getSession().getLocale();
    }
}

其中 @Managed(Locale.class) 会将 Locale 对象和 LocaleArgumentGetter 绑定起来。如果省略 @Managed 的参数,那么 jetbrick 会自动从 TypedArgumentGetter<Locale> 定义中获取泛型参数。