Spring控制器组成而不是继承

时间:2014-12-20 13:30:51

标签: java spring rest spring-mvc

我开发基于Spring MVC的REST应用程序。

我有以下控制器:

UserController extends ImageController
 ImageController extends SuggestController // Controller that has GET-DELETE-POST for image
  SuggestController extends CrudController// Controller that has some suggest methods
   CrudController // CRUD operations

所以我在runtume中有以下映射:

/users (POST-GET-PUT-DELETE)
/users/suggest (GET, POST(Spring Pageable))
/users/image (POST-GET-DELETE)

在我意识到之前没关系,一个控制器必须能够为我提供其内容的图像,但不能实现“建议”方法:

/stuff (POST-GET-PUT-DELETE)
/stuff/image (POST-GET-DELETE)

另一个没有“图像”功能,但有“建议”:

/things (POST-GET-PUT-DELETE)
/things/suggest (GET, POST(Spring Pageable))

Java说:“在这种情况下使用组合”:

StuffController {
    @InlineThisController
    ImageController imagedController;
    @InlineThisController
    CrudController crudController;
... //some additional methods
}

那么如何在没有样板委托的情况下在Spring MVC中实现这一点呢?注释? XML?

2 个答案:

答案 0 :(得分:2)

Spring MVC不允许覆盖使用@RequestMapping注释的方法,或者更确切地说,它不允许您使用@RequestMapping注释覆盖方法,并将使用基类中的映射。

但是你总是可以在基类中定义两个方法:一个用@RequestMapping注释,它只委托给第二个没有注释的方法。然后,您可以自由地覆盖子类中的第二个方法。示例:

CRUD控制器的抽象基类

public abstract class AbstractCRUDController<K extends Serializable, X>
// X is the data class, K is the class of the key (int or String)
    @RequestMapping({"/{data}"})
    public String show(@ModelAttribute("data") X data, HttpSession session, Model model,
            @RequestParam(value = "pagesize", required = false, defaultValue = "-1") int pageSize,
            WebRequest request,
            @RequestParam(value = "all", defaultValue = "false") boolean all) {
        return doShow(data, session, model, pageSize, request, all);
    }
    protected String doShow(X data, HttpSession session, Model model,
            int pageSize, WebRequest request, boolean all) {
        return this.getPrefix() + "/view";
    }
    @RequestMapping(value={"/{data}/edit"}, method=RequestMethod.GET)
    public String edit(@ModelAttribute("data") X data, Model model) {
        return doEdit(data, model);
    }

    protected String doEdit(@ModelAttribute("data") X data, Model model) {
        model.addAttribute("title", editTitle);
        return this.getPrefix() + "/edit";
    }

    @RequestMapping(value={"/{data}/edit"}, method=RequestMethod.POST)
    public String update(@ModelAttribute("data") X data, BindingResult result, Model model) {
        if (data == null) {
            throw new NoSuchElementException();
        }
        if (save(data, result, model, SimpleSaveType.UPDATE, null) != null) {
            return "redirect:" + savedUrl(data);
        }
        else {
            model.addAttribute("title", editTitle);
            return getPrefix() + "/edit";
        }
    }

    public K save(X data, BindingResult result, Model model, SaveType saveType, K id) {
        ...
    }

    ...
    public abstract String getPrefix();
}

ProcessQ类的具体实现

@Controller
@RequestMapping(ProcessController.PREFIX)
public class ProcessController extends AbstractCRUDController<Integer, ProcessQ> {
    public static final String PREFIX = "/process";

    @Override
    public String getPrefix() {
        return PREFIX;
    }

    @Override
    protected String doShow(ProcessQ process, HttpSession session, Model model,
            int pageSize, WebRequest request, boolean all) {
        String viewName = super.doShow(process, session, model, pageSize, request, all);
        // specialized processing for class ProcessQ
        ...
        return viewName;
    }
    ...
}

示例来自一个真实的程序,这就是为什么你可以看到分页,错误处理和访问底层请求的元素的原因。

答案 1 :(得分:0)

以下是可能的方法:

  1. 使用Lombok's @Delegate
  2. 使用Kotlin's delegation support
  3. 使用Java's default interface methods(看上去比1和2难看)