How to optimize my code in Spring MVC Controller u

2020-02-09 05:26发布

In my controller,My controller method names are equals to the requestmapping url.For example,/list is equal to method name list. Is there has a common handler method to short my code?I do not want to write every controller and method in these way.I remember that .net mvc has a comom way to config it.What about 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(...) { ... }
}

3条回答
ら.Afraid
2楼-- · 2020-02-09 05:39

You can extend to AbstractControllerUrlHandlerMapping and override the method and add bean in web.xml.

  <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" />

Here is an example.

查看更多
狗以群分
3楼-- · 2020-02-09 05:42

You can use RequestMappingHandlerMapping and override default code

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;
}

As you can see here it tries to resolve RequestMapping annotation from method and combine with Controller class annotation.

Just replace the logic to use method name instead.

See here a similar logic. Instead of method name security check was used.

UPDATE:

The classes to test. For me it works. MappingHandler I use method name check because there are much more controllers, errors controllers etc. For real solution I would introduce an annotation on the controllers to exclude default spring controllers from the logic

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();
    }
}

Config to use the mapping

@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;
    }

}

Controller

@RestController

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

test class

@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"));
    }

}
查看更多
我欲成王,谁敢阻挡
4楼-- · 2020-02-09 05:45

Will an abstract base class for both controllers work for you?

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> {
}
查看更多
登录 后发表回答