自定义批注从HttpServletRequest获取具有指定的@RequestHeaders集的自定义对象

时间:2019-05-21 13:53:12

标签: java spring spring-mvc

我正在寻找创建自定义注释以从HttpServletRequest读取标头集的方式

假设我有以下代码:

@RestController
public class ExampleController {

    @PostMapping(path = "/path")
    public void method(@RequestHeader("session-session_id") long sessionId,
                       @RequestHeader("session-user_id") long userId,
                       @RequestHeader("session-user_name") String userName) {
        UserInfo userInfo = UserInfo.of(sessionId, userId, userName);
        //service.handle(userInfo);
    }

    public static final class UserInfo {
        private final long sessionId;
        private final long userId;
        private final String userName;

        private UserInfo(long sessionId, long userId, String userName) {
            this.sessionId = sessionId;
            this.userId = userId;
            this.userName = userName;
        }

        public static UserInfo of(long sessionId, long userId, String userName) {
            return new UserInfo(sessionId, userId, userName);
        }
    }
} 

如您所见,请求标头中包含用户信息。所有用户信息标题都将以“ session-”前缀开头。在实际系统上,我将有3个以上的字段。它们将用于许多请求。 因此,我必须将具有完整用户信息的对象转移到服务级别。为每个UserInfo之类的请求创建此UserInfo.of(sessionId, userId, userName)看起来很多余而且很丑陋。那就是问题所在。

我至少知道另外两种解决方法:

@PostMapping(path = "/path")
public void method(HttpServletRequest request) {
    UserInfo userInfo = UserInfo.of(request);
}

public static UserInfo of(HttpServletRequest request) {
    //request.getHeader("header name");
}

@PostMapping(path = "/path")
public void method(@RequestHeader Map<String, String> request) {
    UserInfo userInfo = UserInfo.of(request);
}

public static UserInfo of(Map<String, String> request) {
    //map.get("header name");
}

但事实并非如此。我正在寻找创建UserInfo的方法,就像spring那样:

@PostMapping(path = "/path")
public void method(@UserInfo UserInfo request) {
    UserInfo userInfo = UserInfo.of(request);
}

您能帮我解决一个问题吗?或至少提供指向文档的链接,其中描述了@RequestHeader在Spring内部如何实现

1 个答案:

答案 0 :(得分:1)

您需要定义自定义HandlerMethodArgumentResolver

public class UserInfoResolver implements HandlerMethodArgumentResolver {

    private static final String sessionIdParam = "session-session_id";
    private static final String userIdParam = "session-user_id";
    private static final String userNameParam = "session-user_name";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(UserInfo.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        // There are no null-checks here for simplicity, 
        // so don't forget to add them in production code
        return UserInfo(
            Long.parseLong(webRequest.getHeader(sessionIdParam)), 
            Long.parseLong(webRequest.getHeader(userIdParam)),
            webRequest.getHeader(userNameParam)
        );
    }
}

然后让Spring在您的Web配置类中意识到该参数解析器:

@Configuration
public class WebApiConfiguration extends WebMvcConfigurationSupport {
    ...

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new UserInfoResolver());
    }

    ...
}

最后,您可以通过以下方式使用它:

@PostMapping(path = "/path")
public void method(UserInfo userInfo) {
    //service.handle(userInfo);
}