我一直在尝试编写通用控制器来提高代码的可重用性。以下是我到目前为止:
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 ?
}
}
T
可以是国家/地区,项目,注册和用户。我现在面临的问题是自动装配过程失败,出现以下错误:
No unique bean of type [com.ucmas.cms.service.BaseService] is defined: expected single matching bean but found 4: [countryServiceImpl, itemServiceImpl, registrationServiceImpl, userServiceImpl].
有可能实现我的需要吗?我该如何解决这个问题?
答案 0 :(得分: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
}
}
然后,您可以为扩展它的每个子类使用自动装配:
public class CountryController extends CRUDController<Country> {
@Autowired
public CountryController(CountryService countryService) {
super(countryService, "country");
}
}
或者,您可以在构造函数中使用@Qualifier注释来区分不同的BaseService
实现:
@Autowired
public CountryController(@Qualifier("countryServiceImpl") BaseService<Country> baseService) {
super(baseService, "country");
}
<强>更新强>
从Spring 4.0 RC1开始,可以基于泛型类型进行自动装配。因此,您可以在自动装配构造函数时使用通用BaseService<Country>
作为参数,Spring仍然可以在不抛出任何NoSuchBeanDefinitionException
的情况下找出哪个是正确的:
@Controller
public class CountryController extends CRUDController<Country> {
@Autowired
public CountryController(BaseService<Country> countryService) {
super(countryService, "country");
}
}
答案 1 :(得分: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;
}
在控制器中你可以做这样的事情
@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;
}
现在你可以使用路由mylocalhost / foo / get 这将给你们所有的回报。