1

我对编写 Servlet 和 REST 服务还很陌生,但现在我遇到了一个问题,我不确定我是否做得正确。我的服务如下所示:

@POST
@Produces ("application/json")
@Path ("/register")
public String register(
    @FormParam("name") String name,
    @FormParam("username") String username,
    @FormParam("password") String password,
    @Context HttpServletResponse servletResponse) throws IOException {

    if( this.user_taken(username) ) return "USERNAME_TAKEN";
    User user = new User(name,username,password);

    .....

    return mapper.writeValueAsString(user);

}

因此,正如您所看到的,Service负责后端(数据库和创建用户),Servlet另一方面负责从表单获取请求,正确验证并将其传递给Service. 小服务程序代码:

... validate user input form ...

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource("http://localhost/Jaba");

String map = mapper.writeValueAsString(request.getParameterMap());
MultivaluedMap<String, String> obj = mapper.readValue(map, MultivaluedMap.class);

String result = 
    service.path("api").path("register")
        .accept("application/json")
        .post(String.class, obj);

如您所见,客户端(Servlet)必须做很多令人讨厌的工作,才能将数据传递给服务。如何更改/改进/优化或更好地重构?我正在尝试遵循最佳实践以及在现实生活中的例子。

4

1 回答 1

2

这是我可能会做的:

而不是做

String result = 
    service.path("api").path("register")
        .accept("application/json")
        .post(String.class, obj);

我会做一些更像是创建一个 DTO 对象、填写它然后将其传递给您的服务的事情。这就是您将在客户端调用上应用一个方面以及 JSR 验证和注释(您可以对您拥有的东西执行此操作,但它不会那么好)。

例子:

@Aspect
public class DtoValidator {

    private Validator validator;

    public DtoValidator() {
    }

    public DtoValidator(Validator validator) {
        this.validator = validator;
    }

    public void doValidation(JoinPoint jp){
        for( Object arg : jp.getArgs() ){
            if (arg != null) {
                Set<ConstraintViolation<Object>> violations = validator.validate(arg);
                if( violations.size() > 0 ){
                    throw buildError(violations);
                }
            }
        }
    }

    private static BadRequestException buildError( Set<ConstraintViolation<Object>> violations ){
        Map<String, String> errorMap = new HashMap<String, String>();
        for( ConstraintViolation error : violations ){
            errorMap.put(error.getPropertyPath().toString(), error.getMessage());
        }
        return new BadRequestException(errorMap);
    }
}

您可以注释性地声明您的方面,也可以在配置中进行(使其可重用)。像这样:

<aop:config proxy-target-class="true">
    <aop:aspect id="dtoValidator" ref="dtoValidator" order="10">
        <aop:before method="doValidation" pointcut="execution(public * com.mycompany.client.*.*(..))"/>
    </aop:aspect>
</aop:config>

现在您可以拥有这样的 DTO:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class LoginRequest extends AbstractDto{

    @NotNull
    private String userName;

    @NotNull
    private String password;

    private LoginRequest() {
    }

    public LoginRequest(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }

}

当它未能通过这些@NotNull检查时,您将得到如下信息:

{
   "message":"{username=must not be null",
   "httpStatusCode":400,
   "httpMessage":"Bad Request",
   "details":{
      "username":"must not be null"
   }
}

然后使用 RestOperation 客户端

org.springframework.web.client.RestOperations restClient ...
restClient.postForObject(URL,new Dto(...),args);  

把方面放在这个周围restClient,你就是黄金(而且,实际上,在你的服务调用上也是如此)。

于 2013-04-19T21:46:54.110 回答