就目前来讲,CDI 基本仍是和 JSF 结合使用的比较多,CDI 的扩展能力很是的出色,Seam3 就是彻底基于 weld 的。固然咱们也能够扩展 CDI 实现和 Spring MVC, .Net MVC 差很少的功能结合 JSP 一块儿使用。这里我是看到了老外的这篇文章,而后对其已经实现的MVC功能作了一些扩展,添加了页面像 Controller 传值的功能,后面我还准备尝试添加表单实体的提交,还有 Controller 返回 JSon,Freemarker 等一些功能,这些功能都是借鉴于 RestEasy 。java
对于MVC,我就不去介绍了,网上有不少。
spring
JDK5 之后新增了自定义注解的功能,咱们先为MVC添加好须要的一些注解,在 CDI 中的限定词都是经过扩展注解来作的。基本取消了配置文件用注解来代替,Spring 3 MVC 也是。下面是目前咱们使用到的几个注解。
spring-mvc
添加 @Controller 注解,这个注解表示这个类为 MVC 中的 Controller。
mvc
@Target({ ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Controller { }
添加 @RequestMapping 注解,它有两个参数,第一个表示映射路径,第二个表示其对应的Http不一样的提交 GET POST DELETE。app
@Target({ ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { String[] value() default {}; RequestMethod[] method() default {}; }
定义一下 RequestMethod 的枚举java-ee
public enum RequestMethod { POST,GET,DELETE }
添加 @Param 注解,这个注解只能在 Controller 的参数中使用,他的值表示你请求该 Controller 值的名称。如 controller?xxx=123 ,当你为一个参数添加了 @Param("xxx") 注解,那调用这个这个Controller的时候就这个参数就会被传入 123 值。spa
@Qualifier @Target({ElementType.FIELD,ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface Param { String value(); }
当咱们定义一个 Controller的时候,就能够这样去写:.net
@Controller @RequestMapping("/person/") public class PersonController { public Person createPerson() { return new Person(null, "new", "person"); } @RequestMapping("list") public String doListPeople() { return "listPeople"; } @RequestMapping("view") public String doViewPerson() { return "viewPerson"; } @RequestMapping(value = "edit", method = RequestMethod.GET) public String doEditPerson() { return "editPerson"; } @RequestMapping(value = "edit", method = RequestMethod.POST) public String doPostUpdatePerson(@Param("first") String first,@Param("last") int last) { return "updatedPerson"; }
在容器启动的时候,咱们这里须要讲工程路径下面全部的 Controller 的基本信息初始化好,而后存在内存中。这里每个Controller 包括其类的映射路径,方法的路径,Http请求的方式,所执行的方法,已经方法的参数信息。咱们这里做为 MVC 的元数据初始化好放在一个 List 里面。而后咱们定义一个 Servlet 来拦截全部请求,而后遍历这个List找出匹配的 Controller 而后执行其方法之后,根据返回的 View 的路径而后开打这个页面。我没有去研究过 Spring MVC 是怎么作的,有知道的朋友能够在评论中介绍一下。
debug
定义 MVC 的基本信息对象code
public class ControllerMethod { private final String prefix; private final String suffix; private final RequestMethod[] requestMethod; private final Method method; private final List<Map<String,Class<?>>> args; // gets , sets }
咱们经过添加一个 CDI 的 ApplicationScoped 的 Bean 来完成咱们的初始化工做,咱们添加一个@PostConstruct的方法,这个方法会在工程第一次被访问的时候执行该方法。
@ApplicationScoped public class ControllerInfo { private final List<ControllerMethod> controllerMethods = new ArrayList<ControllerMethod>(); private static final String[] DEFAULT_MAPPING_PATHS = new String[] { "" }; public static final AnnotationLiteral<Controller> CONTROLLER_LITERAL = new AnnotationLiteral<Controller>() { private static final long serialVersionUID = -3226395594698453241L; }; @Inject private BeanManager beanManager; @PostConstruct public void initialize() { logger.debug("Initializing controller info"); Set<Bean<?>> controllers = beanManager.getBeans(Object.class, CONTROLLER_LITERAL); for (Bean<?> bean : controllers) { add(bean.getBeanClass()); } sortControllerMethods(); listMethods(); } ... ... }
在这个方法中,先经过 CDI 的 BeanManager 拿到全部具备 @Controller 注解的类,而后调用 add 方法,解析这个类里面的方法 具备@RequestMapping 的方法。初始化 ControllerMethod 对象放到 List 中。
private void add(Class<?> clazz) { logger.debug("Adding class {}", clazz); if(clazz == null){ throw new NullPointerException(); } if (clazz.isAnnotationPresent(Controller.class)) { logger.debug("Found controller on class {}", clazz); RequestMapping rm = clazz.getAnnotation(RequestMapping.class); Method[] methods = clazz.getMethods(); String[] controllerPaths = null; if (rm != null) { controllerPaths = rm.value(); } // if no paths are specified, then default to one blank path if (controllerPaths == null || controllerPaths.length == 0) { controllerPaths = DEFAULT_MAPPING_PATHS; } // add methods for each controller level paths for (String prefix : controllerPaths) { for (Method m : methods) { addMethod(prefix, m); } } } } private void addMethod(String prefix, Method javaMethod) { if(javaMethod == null){ throw new NullPointerException(); } RequestMapping mapping = javaMethod.getAnnotation(RequestMapping.class); Annotation[][] annotations = javaMethod.getParameterAnnotations(); Class<?>[] types = javaMethod.getParameterTypes(); // 这里对方法的参数处理,造成 名称:类型 的键值对 List<Map<String,Class<?>>> args = new ArrayList<Map<String,Class<?>>>(); for(int i = 0 , size = types.length; i<size; i ++){ Map<String,Class<?>> m = new HashMap<String,Class<?>>(); for(Annotation a : annotations[i]){ if(a instanceof Param){ m.put(((Param)a).value(),types[i]); } } args.add(m); } if (mapping != null) { logger.debug("Found request mapping on method {}", javaMethod .getName()); String[] paths = mapping.value(); // if these are blank, fill with defaults if (paths.length == 0) { paths = DEFAULT_MAPPING_PATHS; } for (String path : paths) { controllerMethods.add(new ControllerMethod(javaMethod, prefix, path, mapping.method(),args)); } } // check for other annotations in the future }这样,咱们就完成对MVC 的Controller 的基本信息的初始化,目前功能还比较简单。下面会给出处理请求的功能实现。不过,有知道Spring 3 MVC 是怎么处理的朋友,但愿不吝赐教。