提交 467b5f3f 编写于 作者: S Sam Brannen

Introduce composed annotations for @RequestMapping

This commit introduces the following common composed annotations for
@RequestMapping in Spring MVC and Spring MVC REST.

- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping

Issue: SPR-13992
上级 5923ee8a
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -23,6 +23,7 @@ import java.util.concurrent.Callable;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -36,7 +37,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
......@@ -55,6 +56,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* Tests with Java configuration.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
......@@ -123,7 +125,7 @@ public class AsyncControllerJavaConfigTests {
@RestController
static class AsyncController {
@RequestMapping(path = "/callable")
@GetMapping("/callable")
public Callable<Map<String, String>> getCallable() {
return () -> Collections.singletonMap("key", "value");
}
......
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,25 +16,24 @@
package org.springframework.test.web.servlet.samples.context;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.Person;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@Controller
@RestController
@RequestMapping("/person")
public class PersonController {
private final PersonDao personDao;
public PersonController(PersonDao personDao) {
PersonController(PersonDao personDao) {
this.personDao = personDao;
}
@RequestMapping(value="/person/{id}", method=RequestMethod.GET)
@ResponseBody
@GetMapping("/{id}")
public Person getPerson(@PathVariable long id) {
return this.personDao.getPerson(id);
}
......
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
/**
* Annotation for mapping HTTP {@code DELETE} requests onto specific handler
* methods.
*
* <p>Specifically, {@code @DeleteMapping} is a <em>composed annotation</em> that
* acts as a shortcut for {@code @RequestMapping(method = RequestMethod.DELETE)}.
* Furthermore, this annotation does not support the
* {@link RequestMapping#method method}, {@link RequestMapping#name name},
* {@link RequestMapping#headers headers}, {@link RequestMapping#consumes consumes},
* and {@link RequestMapping#produces produces} attributes of {@code @RequestMapping}.
*
* @author Sam Brannen
* @since 4.3
* @see GetMapping
* @see PostMapping
* @see PutMapping
* @see PatchMapping
* @see RequestMapping
*/
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@RequestMapping(method = DELETE)
public @interface DeleteMapping {
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
}
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
/**
* Annotation for mapping HTTP {@code GET} requests onto specific handler
* methods.
*
* <p>Specifically, {@code @GetMapping} is a <em>composed annotation</em> that
* acts as a shortcut for {@code @RequestMapping(method = RequestMethod.GET)}.
* Furthermore, this annotation does not support the
* {@link RequestMapping#method method}, {@link RequestMapping#name name},
* {@link RequestMapping#headers headers}, and {@link RequestMapping#consumes
* consumes} attributes of {@code @RequestMapping}.
*
* @author Sam Brannen
* @since 4.3
* @see PostMapping
* @see PutMapping
* @see DeleteMapping
* @see PatchMapping
* @see RequestMapping
*/
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@RequestMapping(method = GET)
public @interface GetMapping {
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.springframework.web.bind.annotation.RequestMethod.PATCH;
/**
* Annotation for mapping HTTP {@code PATCH} requests onto specific handler
* methods.
*
* <p>Specifically, {@code @PatchMapping} is a <em>composed annotation</em> that
* acts as a shortcut for {@code @RequestMapping(method = RequestMethod.PATCH)}.
* Furthermore, this annotation does not support the
* {@link RequestMapping#method method}, {@link RequestMapping#name name},
* {@link RequestMapping#headers headers}, and {@link RequestMapping#produces
* produces} attributes of {@code @RequestMapping}.
*
* @author Sam Brannen
* @since 4.3
* @see GetMapping
* @see PostMapping
* @see PutMapping
* @see DeleteMapping
* @see RequestMapping
*/
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@RequestMapping(method = PATCH)
public @interface PatchMapping {
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
}
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/**
* Annotation for mapping HTTP {@code POST} requests onto specific handler
* methods.
*
* <p>Specifically, {@code @PostMapping} is a <em>composed annotation</em> that
* acts as a shortcut for {@code @RequestMapping(method = RequestMethod.POST)}.
* Furthermore, this annotation does not support the
* {@link RequestMapping#method method}, {@link RequestMapping#name name},
* {@link RequestMapping#headers headers}, and {@link RequestMapping#produces
* produces} attributes of {@code @RequestMapping}.
*
* @author Sam Brannen
* @since 4.3
* @see GetMapping
* @see PutMapping
* @see DeleteMapping
* @see PatchMapping
* @see RequestMapping
*/
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@RequestMapping(method = POST)
public @interface PostMapping {
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
}
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
/**
* Annotation for mapping HTTP {@code PUT} requests onto specific handler
* methods.
*
* <p>Specifically, {@code @PutMapping} is a <em>composed annotation</em> that
* acts as a shortcut for {@code @RequestMapping(method = RequestMethod.PUT)}.
* Furthermore, this annotation does not support the
* {@link RequestMapping#method method}, {@link RequestMapping#name name},
* {@link RequestMapping#headers headers}, and {@link RequestMapping#produces
* produces} attributes of {@code @RequestMapping}.
*
* @author Sam Brannen
* @since 4.3
* @see GetMapping
* @see PostMapping
* @see DeleteMapping
* @see PatchMapping
* @see RequestMapping
*/
@Target(METHOD)
@Retention(RUNTIME)
@Documented
@RequestMapping(method = PUT)
public @interface PutMapping {
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
}
......@@ -279,6 +279,11 @@ import org.springframework.core.annotation.AliasFor;
* @author Arjen Poutsma
* @author Sam Brannen
* @since 2.5
* @see GetMapping
* @see PostMapping
* @see PutMapping
* @see DeleteMapping
* @see PatchMapping
* @see RequestParam
* @see RequestAttribute
* @see PathVariable
......
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -34,6 +34,11 @@ import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.support.StaticWebApplicationContext;
......@@ -132,12 +137,64 @@ public class RequestMappingHandlerMappingTests {
@Test
public void resolveRequestMappingViaComposedAnnotation() throws Exception {
RequestMappingInfo info = assertComposedAnnotationMapping("postJson", "/postJson", RequestMethod.POST);
assertEquals(MediaType.APPLICATION_JSON_VALUE,
info.getConsumesCondition().getConsumableMediaTypes().iterator().next().toString());
assertEquals(MediaType.APPLICATION_JSON_VALUE,
info.getProducesCondition().getProducibleMediaTypes().iterator().next().toString());
}
@Test
public void getMapping() throws Exception {
assertComposedAnnotationMapping(RequestMethod.GET);
}
@Test
public void postMapping() throws Exception {
assertComposedAnnotationMapping(RequestMethod.POST);
}
@Test
public void putMapping() throws Exception {
assertComposedAnnotationMapping(RequestMethod.PUT);
}
@Test
public void deleteMapping() throws Exception {
assertComposedAnnotationMapping(RequestMethod.DELETE);
}
@Test
public void patchMapping() throws Exception {
assertComposedAnnotationMapping(RequestMethod.PATCH);
}
private RequestMappingInfo assertComposedAnnotationMapping(RequestMethod requestMethod) throws Exception {
String methodName = requestMethod.name().toLowerCase();
String path = "/" + methodName;
return assertComposedAnnotationMapping(methodName, path, requestMethod);
}
private RequestMappingInfo assertComposedAnnotationMapping(String methodName, String path,
RequestMethod requestMethod) throws Exception {
Class<?> clazz = ComposedAnnotationController.class;
Method method = clazz.getMethod("handleInput");
Method method = clazz.getMethod(methodName);
RequestMappingInfo info = this.handlerMapping.getMappingForMethod(method, clazz);
assertNotNull(info);
assertEquals(Collections.singleton("/input"), info.getPatternsCondition().getPatterns());
Set<String> paths = info.getPatternsCondition().getPatterns();
assertEquals(1, paths.size());
assertEquals(path, paths.iterator().next());
Set<RequestMethod> methods = info.getMethodsCondition().getMethods();
assertEquals(1, methods.size());
assertEquals(requestMethod, methods.iterator().next());
return info;
}
......@@ -148,9 +205,30 @@ public class RequestMappingHandlerMappingTests {
public void handle() {
}
@PostJson("/input")
public void handleInput() {
@PostJson("/postJson")
public void postJson() {
}
@GetMapping("/get")
public void get() {
}
@PostMapping("/post")
public void post() {
}
@PutMapping("/put")
public void put() {
}
@DeleteMapping("/delete")
public void delete() {
}
@PatchMapping("/patch")
public void patch() {
}
}
@RequestMapping(method = RequestMethod.POST,
......
......@@ -630,7 +630,7 @@ public @interface MyTestConfig {
=== Core Container Improvements
* It is no longer necessary to specify the `@Autowired` annotation if the target
bean only define one constructor.
bean only defines one constructor.
* `@Configuration` classes support constructor injection.
* Any SpEL expression used to specify the `condition` of an `@EventListener` can
now refer to beans (i.e. `@beanName.method()`).
......@@ -662,6 +662,8 @@ Spring 4.3 also improves the caching abstraction as follows:
=== Web Improvements
* Built-in support for <<mvc-ann-requestmapping-head-options,HTTP HEAD and HTTP OPTIONS>>.
* New `@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping`, and `@PatchMapping`
_composed annotations_ for `@RequestMapping`.
* New `@RequestScope`, `@SessionScope`, and `@ApplicationScope` _composed annotations_ for web scopes.
* New `@RestControllerAdvice` annotation with combined `@ControllerAdvice` with `@ResponseBody` semantics.
* `@ResponseStatus` is now supported at the class level and inherited by all methods.
......@@ -684,3 +686,4 @@ Spring 4.3 also improves the caching abstraction as follows:
* Client-side REST test support allows indicating how many times a request is expected and
whether the order of declaration for expectations should be ignored (see <<spring-mvc-test-client>>).
* Client-side REST Test supports expectations for form data in the request body.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册