带有@PathVariable的Spring MVC带注释的控制器接口

wil*_*-ob 38 spring spring-mvc spring-boot

有没有理由不将控制器映射为接口?

在所有示例和问题中,我看到周围的控制器,都是具体的类.是否有一个原因?我想将请求映射与实现分开.当我试图@PathVariable在我的具体课程中获得一个参数时,我碰到了一堵墙.

我的Controller界面如下所示:

@Controller
@RequestMapping("/services/goal/")
public interface GoalService {

    @RequestMapping("options/")
    @ResponseBody
    Map<String, Long> getGoals();

    @RequestMapping(value = "{id}/", method = RequestMethod.DELETE)
    @ResponseBody
    void removeGoal(@PathVariable String id);

}
Run Code Online (Sandbox Code Playgroud)

而实施班:

@Component
public class GoalServiceImpl implements GoalService {

    /* init code */

    public Map<String, Long> getGoals() {
        /* method code */
        return map;
    }

    public void removeGoal(String id) {
        Goal goal = goalDao.findByPrimaryKey(Long.parseLong(id));
        goalDao.remove(goal);
    }

}
Run Code Online (Sandbox Code Playgroud)

getGoals()方法效果很好; 在removeGoal(String id)抛出一个异常

ExceptionHandlerExceptionResolver - Resolving exception from handler [public void
    todo.webapp.controllers.services.GoalServiceImpl.removeGoal(java.lang.String)]: 
    org.springframework.web.bind.MissingServletRequestParameterException: Required 
    String parameter 'id' is not present
Run Code Online (Sandbox Code Playgroud)

如果我将@PathVariable注释添加到具体类中,一切都按预期工作,但为什么我必须在具体类中重新声明它?它不应该由具有@Controller注释的任何东西处理吗?

wil*_*-ob 26

显然,当请求模式通过@RequestMapping注释映射到方法时,它将映射到具体的方法实现.因此,与声明匹配的请求将GoalServiceImpl.removeGoal()直接调用,而不是最初声明@RequestMappingie 的方法GoalService.removeGoal().

由于接口,接口方法或接口方法参数上的注释不会延续到实现,因此@PathVariable除非实现类明确声明,否则Spring MVC无法将其识别为.没有它,任何以@PathVariable参数为目标的AOP建议都不会被执行.

  • 最近添加了对接口注释的全面支持 - 请参阅下面的答案并投票 (2认同)

小智 8

它适用于较新版本的Spring.

import org.springframework.web.bind.annotation.RequestMapping;
public interface TestApi {
    @RequestMapping("/test")
    public String test();
}
Run Code Online (Sandbox Code Playgroud)

在Controller中实现接口

@RestController
@Slf4j
public class TestApiController implements TestApi {

    @Override
    public String test() {
        log.info("In Test");
        return "Value";
    }

}
Run Code Online (Sandbox Code Playgroud)

它可以用作: Rest客户端

  • 春天4.3.*工作.但是这个例子中没有参数.spring-mvc处理程序适配器不知道接口方法中的任何带注释的params.并且有一些解决方法:使用spring-mvc注释的接口方法可以具有默认实现.这个实现委托调用另一个_abstract_方法,该方法由带有`@ RestController`注释的类实现.在这种情况下,spring将http请求处理程序绑定到具有默认实现的接口方法.[见简单例子](https://gist.github.com/milovtim/d90e4aed64860658479423235e4fac97#file-democontroller-java) (3认同)
  • 您是否使用带注释的参数对其进行了测试? (2认同)

Ada*_*.IT 6

实际上在Spring 5.1.5中已实现了在接口上定义所有绑定的功能。

请查看此问题:https : //github.com/spring-projects/spring-framework/issues/15682-这很挣扎:)

现在您可以实际执行以下操作:

@RequestMapping("/random")
public interface RandomDataController {

    @RequestMapping(value = "/{type}", method = RequestMethod.GET)
    @ResponseBody
    RandomData getRandomData(
            @PathVariable(value = "type") RandomDataType type, @RequestParam(value = "size", required = false, defaultValue = "10") int size);
}
Run Code Online (Sandbox Code Playgroud)
@Controller
public class RandomDataImpl implements RandomDataController {

    @Autowired
    private RandomGenerator randomGenerator;

    @Override
    public RandomData getPathParamRandomData(RandomDataType type, int size) {
        return randomGenerator.generateRandomData(type, size);
    }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用此库:https : //github.com/ggeorgovassilis/spring-rest-invoker

要获得基于该接口的客户端代理,类似于RestEasys客户端框架在JAX-RS领域中的工作方式。