【问题标题】:How to make pattern of REST controllers如何制作 REST 控制器的模式
【发布时间】:2016-10-14 19:08:05
【问题描述】:

我正在编写我的第一个 Spring 应用程序,并希望获得经验以在 Spring 上编写最佳且有吸引力的代码。 我有一些 restcontrollers 有很大一部分类似的代码

   @RequestMapping(path = "/1154",
                method = RequestMethod.POST,
                headers = {"Content-Type=application/json"},
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

        public CreateUserResp processRequest(@RequestBody @Valid CreateUserReq request, BindingResult bindingResult) {

            CreateUserResp response = new CreateUserResp();

            if (bindingResult.hasErrors()){

                response.setResultCode(102); // Validation error
                response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");

            } else {
                   // main service
                   request = UserService.doSomething();

            }
            return response;
        }

 @RequestMapping(path = "/1155",
                method = RequestMethod.POST,
                headers = {"Content-Type=application/json"},
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

        public ChangeUserResp processRequest(@RequestBody @Valid ChangeUserReq request, BindingResult bindingResult) {

            ChangeUserResp response = new ChangeUserResp();

            if (bindingResult.hasErrors()){

                response.setResultCode(102); // Validation error
                response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");

            } else {
                   // main service
                   request = ChangeService.doSomething();

            }
            return response;
        }

 @RequestMapping(path = "/1156",
                method = RequestMethod.POST,
                headers = {"Content-Type=application/json"},
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

        public AddUserResp processRequest(@RequestBody @Valid AddUserReq request, BindingResult bindingResult) {

            AddUserResp response = new AddUserResp();

            if (bindingResult.hasErrors()){

                response.setResultCode(102); // Validation error
                response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");

            } else {
                   // main service
                   request = AddService.doSomething();

            }
            return response;
        }

 @RequestMapping(path = "/1157",
                method = RequestMethod.POST,
                headers = {"Content-Type=application/json"},
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

        public ModifyUserResp processRequest(@RequestBody @Valid ModifyUserReq request, BindingResult bindingResult) {

            ModifyUserResp response = new ModifyUserResp();

            if (bindingResult.hasErrors()){

                response.setResultCode(102); // Validation error
                response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");

            } else {
                   // main service
                   request = ModifyService.doSomething();

            }
            return response;
        }

等等……

(路径、@RequestBody 和 Responce 对象以及称为 service 的唯一区别)。所以,我将有 10-12 个这样的控制器。是否可以使此代码更优化而不是编写此可重复的代码块 10 次(弹簧方法或可能使用泛型类或方法)。这只是示例,不是真正的代码。谢谢

特别感谢那些忙于回答但有时间减号的人。

【问题讨论】:

  • 一个观察者来处理你所有请求方法的错误?
  • 是的,只是结构相同,我只更改传入 json 对象的 pojo 对象以进行验证。传入请求取决于控制器路径。响应取决于请求对象
  • 把所有常用的东西放在类上(对于@RequestMapping)只定义方法@RequestMapping的差异。除此之外,这些方法是不同的,看起来像 sme 的东西并不能使它们相同。如果您可以在这个级别上泛化事物,那么您就做错了恕我直言...

标签: java spring spring-mvc


【解决方案1】:

我的应用程序中有一些非常相似的东西。

例如,这就是我在用户控制器中的 editProfile 方法的样子:

@PostMapping(value = EDIT_CONTACT_INFO)
public ResponseEntity<?> editContactInfo(
        @Autowired HttpServletRequest httpServletRequest,
        @RequestBody @Valid ContactInfoDTO.Req requestBody,
        BindingResult bindingResult
)
{
    if (bindingResult.hasErrors())
        // 400 - BAD REQUEST
        return ErrorsDTO.from(bindingResult).responseEntity();

    String userName = ControllerUtils.getUserName(httpServletRequest);
    User user =  userService.findByUserName(userName);
    ContactInfo contactInfo = modelMapper.map(requestBody, ContactInfo.class);

    if (!userService.editContactInfo(user, contactInfo))
        // 500 - INTERNAL SERVER ERROR
        return ErrorsDTO.from(INTERNAL_SERVER_ERROR).responseEntity();

    // 200 - OK
    return ResponseEntity.ok(null);
}

我的大部分 API 看起来和你的很相似。我刚刚编写了我的自定义机制来报告错误,并使用ResponseEntity 实例返回数据。

我还有一个库可以将数据从 DTO 传递到我的模型并返回(它称为 ModelMapper)。

【讨论】:

  • 谢谢,但我应该在不同的控制器中更改 ContactInfoDTO.Req
【解决方案2】:

编辑:看起来这篇博文涵盖了您的问题: http://blog.codeleak.pl/2013/09/request-body-validation-in-spring-mvc-3.2.html


如果你真的想搞砸,你可以写一个拦截器,在一个新的注解ValidateBinding上有一个切入点和一个BindingResult的参数。它可能看起来像:

@Around("@annotation(ValidateBinding) && execution(* *(..)) && args(bindingResult)
public Object handleInvalidBindings(ProceedingJoinPoint p, BindingResult bindingResult) {

    if (bindingResult.hasErrors()){
        GenericResponse response = createTypedResponse(p);
        response.setResultCode(102); // Validation error
        response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
        return response;
    } 
    return pjp.proceed();
}

private GenericResponse createTypedResponse(ProceedingJoinPoint p) {
    MethodSignature signature = (MethodSignature) p.getSignature();
    Method method = signature.getMethod();
    Class responseClass = method.getReturnType();
    if(!GenericResponse.class.isAssignableFrom(responseClass)) {
        throw new IllegalArgumentException("Could not create proper response class - it should implement the GenericResponse interface");
    return (GenericResponse) responseClass.newInstance();
}

但我不保证表达式或代码有效。这是对其外观的粗略猜测。

为此,您需要一个接口 GenericResponse,它由您的响应类实现,并具有 setResultCode 和 setErrMsg。

【讨论】:

  • 谢谢,但可能是我没有清楚地解释我的问题(或者我不明白你的答案)。我已经更改了有问题的代码。我正在尝试找到一种方法来制作可重复代码的模式以使其更紧凑。
  • 如果您想使用通用代码,您的所有响应也应该是“通用”...或者至少是错误处理部分。而且由于您确实需要特定的响应,因此需要确定哪种响应的代码。想一想,您可能可以从被调用方法的反射中获得所有这些信息,因此应该稍微清理一下代码。但它是反射和变通方法,所以有点脏......正如其他人所说,您当前的代码是不是通用的,因为它使用特定的响应,这使得它与所有其他代码不同。
猜你喜欢
  • 2022-01-17
  • 2016-04-28
  • 2013-07-20
  • 2019-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2014-09-16
相关资源
最近更新 更多