Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
正在寻找使用另一个组件/注释扩展Spring MVC的解决方案_Spring_Spring Mvc_Architecture - Fatal编程技术网

正在寻找使用另一个组件/注释扩展Spring MVC的解决方案

正在寻找使用另一个组件/注释扩展Spring MVC的解决方案,spring,spring-mvc,architecture,Spring,Spring Mvc,Architecture,假设我有一个网站是在正常模式(浏览器)和其他一些模式下使用的,比如MobileView模式(在移动应用程序中)。对于我创建的每个控制器,MobileView可能都有相应的控制器,处理相同的url 最简单的解决方案是在所有具有MobileView逻辑的控制器中创建ifs。另一种解决方案是为MobileView使用一个对应的url(类似于普通url)和两个独立的控制器(可能是其中一个控制器从另一个控制器扩展而来;或者使用其他方法来回收公共代码) 但是,一个更优雅的解决方案是有一些额外的注释,比如@S

假设我有一个网站是在正常模式(浏览器)和其他一些模式下使用的,比如MobileView模式(在移动应用程序中)。对于我创建的每个控制器,MobileView可能都有相应的控制器,处理相同的url

最简单的解决方案是在所有具有MobileView逻辑的控制器中创建ifs。另一种解决方案是为MobileView使用一个对应的url(类似于普通url)和两个独立的控制器(可能是其中一个控制器从另一个控制器扩展而来;或者使用其他方法来回收公共代码)

但是,一个更优雅的解决方案是有一些额外的注释,比如@SupportsMobileView(标记一个控制器,并告诉应用程序这将有一个对应的MobileView控制器)和@MobileView控制器(标记第二个控制器,并告诉应用程序此控制器需要在标记为@SupportsMobileView的初始控制器之后立即运行)。普通控制器和MobileView控制器之间的链接将通过它们处理的url(使用@RequestMapping定义)进行

是否可以扩展Spring MVC(A)?在何处注入新的注释扫描程序(B)和注释处理程序/组件处理程序(C)?如何执行MobileView控制器(D)(现在我认为它可以通过AOP执行,在AOP中,我的新控制器类型的新处理程序以编程方式在相应的普通控制器上创建一个连接点)

注意我没有提到如何触发和检测此MobileView模式。让我们只说有一个会话布尔变量(标志)

欢迎对任何(A)、(B)、(C)或(D)点提出批评,以及任何点或整个解决方案的技术提示和替代解决方案。

可用于拦截RequestMapping处理。这是一个如何配置和实现的简单示例

您可以检查您的会话变量,并将有一系列方法,允许您进行自定义处理,或仅使用移动视图交换正常控制器处理的视图。

确定,警告:

这只是一个概念证明,证明了我所理解的必须这样做:

+@MOBILEVIEWABLE和@MobileView注释(和相关)方法需要保持在同一个控制器中

+没有检查所使用的httpAction

+这两个方法必须具有相同的签名

+mobileView注释值和requestMapping注释值必须等于且唯一

+callYourLogic(..)中的逻辑定义了要调用的方法,目前有一个非常简单的逻辑,用于检查请求中是否存在参数(“mobile”),以进行测试

+此代码不打算按原样使用(根本不)

+不知道它是否在我的电脑之外工作(笑话:D,嗯..)

因此:

注释:

@Retention(RetentionPolicy.RUNTIME)
public @interface MobileView {
    String value() default "";
}

@Retention(RetentionPolicy.RUNTIME)
public @interface MobileViewEnable {

}
示例控制器:

@Controller
public class MainController extends BaseController {

    private final static Logger logger = LoggerFactory.getLogger(MainController.class);
    private final static String PROVA_ROUTE = "prova";

    @MobileViewEnable
    @RequestMapping(PROVA_ROUTE)
    public String prova() {
        logger.debug("inside prova!!!");
        return "provaview";
    }

    @MobileView(PROVA_ROUTE)
    public String prova2() {
        logger.debug("inside prova2!!!");
        return "prova2view";
    }
}
方面定义:

<bean id="viewAspect" class="xxx.yyy.ViewAspect" />

<aop:config>
    <aop:pointcut expression="@annotation(xxx.yyy.MobileViewEnable)" id="viewAspectPointcut" />
    <aop:aspect ref="viewAspect" order="1">
        <aop:around method="around" pointcut-ref="viewAspectPointcut" arg-names="viewAspectPointcut"/>
    </aop:aspect>
</aop:config>

我认为这在实际意义上是不可能的,因为您必须重新编写所有Spring注释,以完成它们现在所做的事情,我假设这不仅仅是一个以不同方式格式化的HTML页面?@CodeChimp不,如果我在MobileView中,我需要做一些业务逻辑,这与普通视图逻辑不同什么样的业务逻辑?这可能是适合作为侦听器或过滤器的东西吗?或者你可以用AOP做些什么?@CodeChimp-actual实际上,我需要的是,在控制器内部,调用表示某些业务逻辑的接口,其中具体逻辑(普通或移动视图)将根据会话中的内容注入(并通过过滤器注入策略),或者,创建两个单独的控制器,对它们进行注释以区分哪一个是正常的,哪一个是移动视图(但使它们处理相同的url),然后根据会话中的内容决定使用哪一个控制器(同样,由过滤器决定,因为它在控制器之前运行)同样,我认为你正在尝试做一些不一定可能的事情,或者至少不是事情的设计方式。然而,我认为你可以研究一些可行的解决办法。我认为我的最简单建议是使用(at)RequestMapping注释对根据参数排序的请求进行排序,但假设您可以通过POST/GET参数直接作为会话发送“移动”指示符。或者,是否可以更改所使用的URI?
public class ViewAspect implements BeforeAdvice, ApplicationContextAware {

        private final static Logger logger = LoggerFactory.getLogger(ViewAspect.class);

        private ApplicationContext applicationContext;

        public Object around(ProceedingJoinPoint joinPoint) {
            Method mobileViewAnnotatedMethod = null;
            HttpServletRequest request = getCurrentHttpRequest();
            String controllerName = getSimpleClassNameWithFirstLetterLowercase(joinPoint);
            Object[] interceptedMethodArgs = getInterceptedMethodArgs(joinPoint);
            String methodName = getCurrentMethodName(joinPoint);
            Method[] methods = getAllControllerMethods(joinPoint);
            Method interceptedMethod = getInterceptedMethod(methods, methodName);
            String interceptedMethodRoute = getRouteFromInterceptedMethod(interceptedMethod);

            if (callYourLogic(request)) {
                mobileViewAnnotatedMethod = getMobileViewAnnotatedMethodWithRouteName(methods, interceptedMethodRoute);
                if (mobileViewAnnotatedMethod != null)
                    return invokeMethod(mobileViewAnnotatedMethod, interceptedMethodArgs, controllerName);
            }

            return continueInterceptedMethodExecution(joinPoint, interceptedMethodArgs);
        }

        private Object continueInterceptedMethodExecution(ProceedingJoinPoint joinPoint, Object[] interceptedMethodArgs) {

            try {
                return joinPoint.proceed(interceptedMethodArgs);
            } catch (Throwable e) {
                logger.error("unable to proceed with intercepted method call: " + e);
            }

            return null;
        }

        private Object[] getInterceptedMethodArgs(JoinPoint joinPoint) {
            return joinPoint.getArgs();
        }

        private boolean callYourLogic(HttpServletRequest request) {
            // INSERT HERE YOUR CUSTOM LOGIC (e.g.: is the server accessed from a mobile device?)
            // THIS IS A STUPID LOGIC USED ONLY FOR EXAMPLE
            return request.getParameter("mobile")!= null;   
        }

        private HttpServletRequest getCurrentHttpRequest() {
            return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        }

        private String invokeMethod(Method method, Object[] methodArgs, String className) {
            if (method != null) {
                try {
                    Object classInstance = getInstanceOfClass(method, className);
                    return (String) method.invoke(classInstance, methodArgs);
                } catch (Exception e) {
                    logger.error("unable to invoke method" + method + " - " + e);
                }
            }
            return null;
        }

        private Object getInstanceOfClass(Method method, String className) {
            return applicationContext.getBean(className);
        }

        private Method getMobileViewAnnotatedMethodWithRouteName(Method[] methods, String routeName) {
            for (Method m : methods) {
                MobileView mobileViewAnnotation = m.getAnnotation(MobileView.class);
                if (mobileViewAnnotation != null && mobileViewAnnotation.value().equals(routeName))
                    return m;
            }
            return null;
        }

        private String getRouteFromInterceptedMethod(Method method) {
            RequestMapping requestMappingAnnotation = method.getAnnotation(RequestMapping.class);
            if (requestMappingAnnotation != null)
                return requestMappingAnnotation.value()[0];

            return null;
        }

        private String getCurrentMethodName(JoinPoint joinPoint) {
            return joinPoint.getSignature().getName();
        }

        private Method[] getAllControllerMethods(JoinPoint joinPoint) {
            return joinPoint.getThis().getClass().getSuperclass().getMethods();
        }

        private String getSimpleClassNameWithFirstLetterLowercase(JoinPoint joinPoint) {
            String simpleClassName = joinPoint.getThis().getClass().getSuperclass().getSimpleName();
            return setFirstLetterLowercase(simpleClassName);
        }

        private String setFirstLetterLowercase(String simpleClassName) {
            String firstLetterOfTheString = simpleClassName.substring(0, 1).toLowerCase();
            String restOfTheString = simpleClassName.substring(1);
            return firstLetterOfTheString + restOfTheString;

        }

        private Method getInterceptedMethod(Method[] methods, String lookingForMethodName) {
            for (Method m : methods)
                if (m.getName().equals(lookingForMethodName))
                    return m;

            return null;
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }

    }