Spring MVC中的通用控制器

abi*_*eez 6 spring-mvc

我一直在尝试编写一个通用控制器来提高代码的可重用性.以下是我到目前为止:

public abstract class CRUDController<T> {

    @Autowired
    private BaseService<T> service;

    @RequestMapping(value = "/validation.json", method = RequestMethod.POST)
    @ResponseBody
    public ValidationResponse ajaxValidation(@Valid T t,
            BindingResult result) {
        ValidationResponse res = new ValidationResponse();
        if (!result.hasErrors()) {
            res.setStatus("SUCCESS");
        } else {
            res.setStatus("FAIL");
            List<FieldError> allErrors = result.getFieldErrors();
            List<ErrorMessage> errorMesages = new ArrayList<ErrorMessage>();
            for (FieldError objectError : allErrors) {
                errorMesages.add(new ErrorMessage(objectError.getField(),
                        objectError.getDefaultMessage()));
            }
            res.setErrorMessageList(errorMesages);
        }
        return res;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String initForm(Model model) {
        service.initializeForm(model);
        return "country"; // how can I make this generic too ?
    }
}
Run Code Online (Sandbox Code Playgroud)

T可以是国家,项目,注册和用户之类的东西.我现在面临的问题是自动装配过程失败,出现以下错误:

No unique bean of type [com.ucmas.cms.service.BaseService] is defined: expected single matching bean but found 4: [countryServiceImpl, itemServiceImpl, registrationServiceImpl, userServiceImpl].
Run Code Online (Sandbox Code Playgroud)

有可能实现我的需要吗?我怎样才能解决这个问题 ?

mat*_*sev 10

我建议你将这个BaseService构造函数参数添加到CRUDController类中:

public abstract class CRUDController<T> {

    private final BaseService<T> service;
    private final String initFormParam;

    public CRUDController(BaseService<T> service, String initFormParam) {
        this.service = service;
        this.initFormParam;
    }

    @RequestMapping(value = "/validation.json", method = RequestMethod.POST)
    @ResponseBody
    public ValidationResponse ajaxValidation(@Valid T t, BindingResult result) {
        // same as in the example
        return res;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String initForm(Model model) {
        service.initializeForm(model);
        return initFormParam;   // Now initialized by the constructor
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以为扩展它的每个子类使用自动装配:

public class CountryController extends CRUDController<Country> {

    @Autowired
    public CountryController(CountryService countryService) {
        super(countryService, "country");
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以在构造函数中使用@Qualifier批注来区分不同的BaseService实现:

@Autowired
public CountryController(@Qualifier("countryServiceImpl") BaseService<Country> baseService) {
    super(baseService, "country");
}
Run Code Online (Sandbox Code Playgroud)

更新:

Spring 4.0 RC1开始,可以基于泛型类型进行自动装配.因此,您可以BaseService<Country>在自动装配构造函数时使用泛型作为参数,Spring仍然能够找出哪个是正确的,而不抛出任何NoSuchBeanDefinitionException:

@Controller
public class CountryController extends CRUDController<Country> {

    @Autowired
    public CountryController(BaseService<Country> countryService) {
        super(countryService, "country");
    }
}
Run Code Online (Sandbox Code Playgroud)


Adm*_*vic 5

这是我的解决方案

public abstract class CrudController<Model extends MyEntity<Model>, Service extends SharedService>{

private Service service;

public void setDependencies(Service service){
    this.service = service;
}

@RequestMapping(value = "/get", method = RequestMethod.GET)
public Response get(){
    Response response = new Response();
    try{
        response.setStatusCode(200);
        response.setMessage("Successfully retrieved " + service.count() + ".");
        response.setData(service.getAll());
    }catch(Exception e){
        response.setServerError(e.getMessage());
    }
    return response;
}
Run Code Online (Sandbox Code Playgroud)

在控制器中,您可以执行以下操作

@RequestMapping(value = "/foo")
@RestController
public class FooController extends CrudController<Foo, FooServiceImpl> {

private final FooServiceImpl fooService;
}
@Autowired
public GroupsController(FooServiceImpl fooService){
    super.setDependencies(fooService);
    this.fooService = fooService;
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用路由mylocalhost / foo / get,它将返回给您所有的foos。