【问题标题】:How to optimize my code in Spring MVC Controller using @RequestMapping?如何使用 @RequestMapping 在 Spring MVC 控制器中优化我的代码?
【发布时间】:2017-10-14 09:37:58
【问题描述】:

在我的控制器中,我的控制器方法名等于requestmapping url。例如,/list等于方法名list。是否有一个通用的处理程序方法来缩短我的代码?我不想以这种方式编写每个控制器和方法。我记得 .net mvc 有一个通用的方式来配置它。那么 Spring MVC 呢?

@Controller
@RequestMapping(value = "/fooController ")
public class FooController {
     @RequestMapping("/list") public String list(...) { ... }
     @RequestMapping("/save") public String save(...) { ... }
     @RequestMapping("/delete") public String delete(...) { ... }
}

@Controller
@RequestMapping(value = "/basketballController ")
public class BasketballController {
     @RequestMapping("/list") public String list(...) { ... }
     @RequestMapping("/save") public String save(...) { ... }
     @RequestMapping("/delete") public String delete(...) { ... }
}

【问题讨论】:

    标签: java spring spring-mvc spring-boot


    【解决方案1】:

    两个控制器的抽象基类都适合你吗?

    public abstract class BaseController<T> {
         @RequestMapping("/list") public String list(...) { ... }
         @RequestMapping("/save") public String save(...) { ... }
         @RequestMapping("/delete") public String delete(...) { ... }
    }
    
    @Controller
    @RequestMapping(value = "/fooController ")
    public class FooController extends BaseController<Foo> {      
    }
    
    @Controller
    @RequestMapping(value = "/basketballController ")
    public class BasketballController extends BaseController<Basketball> {
    }
    

    【讨论】:

    • 有点作用,但不是我想要的方式。如果我有一些方法不在BaseController中,我必须编写原始方式。
    • 我不太明白你所说的“某种方法”是什么意思。如果不是常用的方法,你想怎么优化?
    • 有些方法是指在某个控制器中可能有导出方法,在另一个控制器中根据实际业务可能有其他方法。
    • 在抽象类中灵活定制其工作没有任何问题。
    • 可以,如果basecontroller中的common方法和单controller中的特殊方法可以使用同一个handler就更好了。
    【解决方案2】:

    您可以使用RequestMappingHandlerMapping 并覆盖默认代码

    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
        }
        return info;
    }
    

    正如您在此处看到的,它尝试从方法中解析 RequestMapping 注释并与 Controller 类注释相结合。

    只需将逻辑替换为使用方法名称即可。

    参见here 类似的逻辑。使用了安全检查而不是方法名。

    更新:

    要测试的类。对我来说它有效。 MappingHandler 我使用方法名称检查,因为有更多的控制器、错误控制器等。对于真正的解决方案,我会在控制器上引入注释以从逻辑中排除默认的 spring 控制器

    public class ExtendedRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    
        protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
            RequestMappingInfo info;
            if (method.getName().startsWith("test")) {
                info = createRequestMappingInfoByMethodName(method);
            }
            else {
                info = super.getMappingForMethod(method, handlerType);
            }
            return info;
        }
    
        protected RequestMappingInfo createRequestMappingInfoByMethodName(Method method) {
            RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), RequestMapping.class);
            String path = requestMapping.value()[0] + "/" + method.getName();
            return RequestMappingInfo
                    .paths(path)
                    .methods(requestMapping.method())
                    .params(requestMapping.params())
                    .headers(requestMapping.headers())
                    .consumes(requestMapping.consumes())
                    .produces(requestMapping.produces())
                    .mappingName(requestMapping.name())
                    .build();
        }
    }
    

    配置使用映射

    @Configuration
    public class ExtendedWebMvcConfiguration extends WebMvcConfigurationSupport {
    
        @Override @Bean
        public RequestMappingHandlerMapping requestMappingHandlerMapping() {
            ExtendedRequestMappingHandlerMapping handlerMapping = new ExtendedRequestMappingHandlerMapping();
            handlerMapping.setOrder(0);
            handlerMapping.setInterceptors(getInterceptors());
            return handlerMapping;
        }
    
        @Override @Bean
        public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
            adapter.setIgnoreDefaultModelOnRedirect(true);
            return adapter;
        }
    
    }
    

    控制器

    @RestController
    
    @RequestMapping("/common")
    public class MethodNameController {
        public String test() {
            return "test";
        }
        public String test2() {
            return "test2";
        }
    }
    

    测试类

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class MethodNameControllerTest {
        @LocalServerPort
        private int port;
    
        @Value("${server.contextPath}")
        private String contextPath;
        private String base;
    
        @Autowired
        private TestRestTemplate template;
    
        @Before
        public void setUp() throws Exception {
            this.base = "http://localhost:" + port;
        }
    
        @Test
        public void testMethodNameMappingResolving() throws Exception {
            TestRestTemplate template = new TestRestTemplate();
            String url = base + contextPath + "/common/test";
            String res1 = template.getForObject(url, String.class);
            assertThat(res1, equalTo("test"));
    
            url += "2";
            String res2 = template.getForObject(url, String.class);
            assertThat(res2, equalTo("test2"));
        }
    
    }
    

    【讨论】:

    • 您能否编辑您的答案以显示一些方法名称逻辑,以防张贴者无法理解反射?
    • 请问 createRequestMappingInfo 方法在哪里?
    • 答案已更新。最好查看RequestMappingHandlerMapping类的源码
    • @StanislavL,它在 createRequestMappingInfoByMethodName() 中调用错误。方法 findMergedAnnotation(Class, Class) 未定义类型 AnnotatedElementUtils
    • 我使用 spring-core 4.3.8.RELEASE。猜猜它与版本有关。我认为您可以只获取方法的类并从该类中获取 RequestMapping (实际上是您的控制器的 RequestMapping 注释)
    【解决方案3】:

    您可以扩展至AbstractControllerUrlHandlerMapping 并覆盖该方法并在web.xml 中添加bean。

      <beans:bean id="myControllerClassNameHandlerMapping" class="com.qiyongkang.sys.controller.MyControllerClassNameHandlerMapping">
      <beans:property name="interceptors">
          <beans:array>
              <beans:bean id="sysLogInterceptor" class="com.qiyongkang.sys.interceptor.SysLogInterceptor"></beans:bean>
          </beans:array>
      </beans:property>
      <beans:property name="caseSensitive" value="true" />
      <beans:property name="frameworkPackagePrefixs" value="com.qiyongkang." />
      <beans:property name="actionPackageSuffixs" value=".ctrl,.controller" />
      <beans:property name="actionClassSuffixs" value="Ctrl,Controller" />
    

    这是example

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      • 1970-01-01
      • 2019-03-29
      • 2015-03-29
      • 2014-01-02
      • 2012-06-08
      • 1970-01-01
      相关资源
      最近更新 更多