frontpage建设网站的图片,广州黄埔做网站,学做网站论坛vip号码,广东省自然资源厅邮箱这里记录回顾一些知识#xff0c;不然就快忘记啦。 环境#xff1a;SpringBoot 2.0.4.RELEASE需求#xff1a;很多Controller方法#xff0c;刚进来要先获取当前登录用户的信息#xff0c;以便做后续的用户相关操作。准备工作#xff1a;前端每次请求都传token#xff0…这里记录回顾一些知识不然就快忘记啦。 环境SpringBoot 2.0.4.RELEASE需求很多Controller方法刚进来要先获取当前登录用户的信息以便做后续的用户相关操作。准备工作前端每次请求都传token后端封装一方法tokenUtils.getUserByToken(token)根据token解析得到currentUserInfo。 这是一个常见的业务需求为实现这个需求有以下几种解决方案 一、最原始直接 即每个Controller开始先调用tokenUtils.getUserByToken(token)不够优雅。
二、AOP AOP可以解决很多切面类问题思路同Spring AOP来自定义注解实现审计或日志记录将currentUser放到request里比起拦截器稍重。
三、拦截器方法参数解析器 使用mvc拦截器HandlerInterceptor方法参数解析器HandlerMethodArgumentResolver最合适。 SpringMVC提供了mvc拦截器HandlerInterceptor包含以下3个方法
preHandlepostHandleafterCompletion HandlerInterceptor经常被用来解决拦截事件如用户鉴权等。另外Spring也向我们提供了多种解析器Resolver如用来统一处理异常的HandlerExceptionResolver以及今天的主角 HandlerMethodArgumentResolver。HandlerMethodArgumentResolver是用来处理方法参数的解析器包含以下2个方法
supportsParameter满足某种要求返回true方可进入resolveArgument做参数处理resolveArgument 知识储备已到位接下来着手实现主要分为三步走 1. 自定义权限拦截器AuthenticationInterceptor拦截所有request请求并将token解析为currentUser最终放到request中 2. 自定义参数注解CurrentUser添加至controller的方法参数user之上 3. 自定义方法参数解析器CurrentUserMethodArgumentResolver取出request中的user并赋值给添加了CurrentUser注解的参数user。
使用方式
要使用 HandlerMethodArgumentResolver需要遵循以下步骤
创建一个自定义的 HandlerMethodArgumentResolver 实现类。在该类中实现 supportsParameter() 方法和 resolveArgument() 方法。在 Spring Boot 应用程序中注册该类。
创建自定义的 HandlerMethodArgumentResolver 实现类 为了将 HTTP 请求参数转换为 Java 对象我们需要创建一个自定义的 HandlerMethodArgumentResolver 实现类。在这个类中我们需要实现 supportsParameter() 方法和 resolveArgument() 方法。
supportsParameter() 方法 在 supportsParameter() 方法中我们需要检查方法参数是否与我们要转换的 Java 类型相同。如果是返回 true否则返回 false。
resolveArgument() 方法 在 resolveArgument() 方法中我们需要将 HTTP 请求参数转换为 Java 对象。为此我们可以使用 NativeWebRequest 对象来获取请求参数然后将其转换为 Java 对象。
注册自定义的 HandlerMethodArgumentResolver 实现类 要在 Spring Boot 应用程序中使用自定义的 HandlerMethodArgumentResolver 实现类我们需要将其注册到应用程序上下文中。为此我们可以创建一个 Configuration 类并实现 WebMvcConfigurer 接口。在这个类中我们需要重写 addArgumentResolvers() 方法并将自定义的 HandlerMethodArgumentResolver 实现类添加到参数解析器列表中。
Configuration
public class AppConfig implements WebMvcConfigurer {
Override
public void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) {
resolvers.add(new CustomHandlerMethodArgumentResolver());
}
} 3.1 自定义权限拦截器 自定义权限拦截器AuthenticationInterceptor需实现HandlerInterceptor。在preHandle中调用tokenUtils.getUserByToken(token)获取到当前用户最后塞进request中如下 import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import edp.core.utils.TokenUtils;
import edp.davinci.core.common.Constants;
import edp.davinci.model.User;public class AuthenticationInterceptor implements HandlerInterceptor {Autowiredprivate TokenUtils tokenUtils;Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token request.getHeader(Authorization);User user tokenUtils.getUserByToken(token);request.setAttribute(Constants.CURRENT_USER, user);return true;}Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}3.2 自定义参数注解 自定义方法参数上使用的注解CurrentUser代表被它注解过的参数的值都需要由方法参数解析器CurrentUserMethodArgumentResolver来“注入”如下 import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义 当前用户 注解* 注解 参数* 此注解在验证token通过后获取当前token包含用户*/
Target({ElementType.PARAMETER})
Retention(RetentionPolicy.RUNTIME)
public interface CurrentUser {
}3.3 自定义方法参数解析器 自定义方法参数解析器CurrentUserMethodArgumentResolver需实现HandlerMethodArgumentResolver。 import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;import edp.core.annotation.CurrentUser;
import edp.core.consts.Consts;
import edp.davinci.model.User;/*** CurrentUser 注解 解析器*/
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.getParameterType().isAssignableFrom(User.class) parameter.hasParameterAnnotation(CurrentUser.class);}Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {return (User) webRequest.getAttribute(Consts.CURRENT_USER, RequestAttributes.SCOPE_REQUEST);}
}As we all know拦截器定义好以后在SpringMVC项目中需要去SpringMVC的配置文件springmvc.xml添加该拦截器但是在SpringBoot中省去了很多配置文件取而代之的是被注解Configuration标识的配置类SpringMVC配置文件对应的配置类需继承WebMvcConfigurationSupport。同理解析器定义好以后也需被添加到SpringMVC的配置文件或配置类中。最后额外的一步配置mvc。3.4 配置MVC 定义MVC配置类需继承WebMvcConfigurationSupport。分别在addInterceptors和addArgumentResolvers方法中添加自定义的拦截器和参数解析器如下 import static edp.core.consts.Consts.EMPTY;import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import edp.davinci.core.common.Constants;
import edp.davinci.core.inteceptor.AuthenticationInterceptor;
import edp.davinci.core.inteceptor.CurrentUserMethodArgumentResolver;Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {Value(${file.userfiles-path})private String filePath;/*** 登录校验拦截器** return*/Beanpublic AuthenticationInterceptor loginRequiredInterceptor() {return new AuthenticationInterceptor();}/*** CurrentUser 注解参数解析器** return*/Beanpublic CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {return new CurrentUserMethodArgumentResolver();}/*** 参数解析器** param argumentResolvers*/Overrideprotected void addArgumentResolvers(ListHandlerMethodArgumentResolver argumentResolvers) {argumentResolvers.add(currentUserMethodArgumentResolver());super.addArgumentResolvers(argumentResolvers);}Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginRequiredInterceptor()).addPathPatterns(Constants.BASE_API_PATH /**).excludePathPatterns(Constants.BASE_API_PATH /login);super.addInterceptors(registry);}Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(/**).addResourceLocations(classpath:/META-INF/resources/).addResourceLocations(classpath:/static/page/).addResourceLocations(classpath:/static/templates/).addResourceLocations(file: filePath);}Overrideprotected void configureMessageConverters(ListHttpMessageConverter? converters) {FastJsonHttpMessageConverter fastConverter new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteDateUseDateFormat,SerializerFeature.DisableCircularReferenceDetect);fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) - {if (null ! source (source instanceof Long || source instanceof BigInteger) source.toString().length() 15) {return source.toString();} else {return null source ? EMPTY : source;}});//处理中文乱码问题ListMediaType fastMediaTypes new ArrayList();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);fastConverter.setSupportedMediaTypes(fastMediaTypes);fastConverter.setFastJsonConfig(fastJsonConfig);converters.add(fastConverter);}
} 多个场景案例 以下是一些场景案例演示了如何使用 HandlerMethodArgumentResolver 解析不同类型的请求参数。
将 JSON 请求体转换为 Java 对象 假设有一个 POST 请求其中包含以下 JSON 请求体
{ name: John, age: 30} 我们可以创建一个自定义的 HandlerMethodArgumentResolver 实现类来将这些参数转换为 Java 对象。
public class JsonHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String json webRequest.getNativeRequest(HttpServletRequest.class).getReader().lines().collect(Collectors.joining(System.lineSeparator())); ObjectMapper mapper new ObjectMapper(); return mapper.readValue(json, parameter.getParameterType()); } } 在这个示例中我们创建了一个名为 JsonHandlerMethodArgumentResolver 的自定义 HandlerMethodArgumentResolver 实现类并在其中解析 JSON 请求体。在 supportsParameter() 方法中我们检查方法参数是否带有 RequestBody 注解。在 resolveArgument() 方法中我们从请求体中读取 JSON 数据并使用 ObjectMapper 将其转换为 Java 对象。
将 XML 请求体转换为 Java 对象
假设有一个 POST 请求其中包含以下 XML 请求体
user nameJohn/name age30/age/user
我们可以创建一个自定义的 HandlerMethodArgumentResolver 实现类来将这些参数转换为 Java 对象。
public class XmlHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String xml webRequest.getNativeRequest(HttpServletRequest.class).getReader().lines().collect(Collectors.joining(System.lineSeparator())); JAXBContext jaxbContext JAXBContext.newInstance(parameter.getParameterType()); Unmarshaller unmarshaller jaxbContext.createUnmarshaller(); StringReader reader new StringReader(xml); return unmarshaller.unmarshal(reader); } }
在这个示例中我们创建了一个名为 XmlHandlerMethodArgumentResolver 的自定义 HandlerMethodArgumentResolver 实现类并在其中解析 XML 请求体。在 supportsParameter() 方法中我们检查方法参数是否带有 RequestBody 注解。在 resolveArgument() 方法中我们从请求体中读取 XML 数据并使用 JAXBContext 和 Unmarshaller 将其转换为 Java 对象。 将多个请求参数转换为 Java 对象
假设有一个 GET 请求其中包含以下请求参数
nameJohnage30
我们可以创建一个自定义的 HandlerMethodArgumentResolver 实现类来将这些参数转换为 Java 对象。
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(User.class); } Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String name webRequest.getParameter(name); int age Integer.parseInt(webRequest.getParameter(age)); User user new User(); user.setName(name); user.setAge(age); return user; } } 在这个示例中我们创建了一个名为 UserHandlerMethodArgumentResolver 的自定义 HandlerMethodArgumentResolver 实现类并在其中解析多个请求参数。在 supportsParameter() 方法中我们检查方法参数是否与 User 类型相同。在 resolveArgument() 方法中我们从请求参数中获取数据并将其转换为 User 对象。 注册自定义的 HandlerMethodArgumentResolver 实现类 要在 Spring Boot 应用程序中使用自定义的 HandlerMethodArgumentResolver 实现类我们需要将其注册到应用程序上下文中。为此我们可以创建一个 Configuration 类并实现 WebMvcConfigurer 接口。在这个类中我们需要重写 addArgumentResolvers() 方法并将自定义的 HandlerMethodArgumentResolver 实现类添加到参数解析器列表中。
Configuration
public class AppConfig implements WebMvcConfigurer {
Override
public void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) {
resolvers.add(new JsonHandlerMethodArgumentResolver());
resolvers.add(new XmlHandlerMethodArgumentResolver());
resolvers.add(new UserHandlerMethodArgumentResolver());
}
} 现在我们已经成功地创建了多个自定义的 HandlerMethodArgumentResolver 实现类并将它们注册到 Spring Boot 应用程序中。这样我们就能够轻松地处理不同类型的请求参数并将它们转换为 Java 对象。 自定义注解来简化参数赋值。
例如假设您有一个 UserParam 注解您可以使用以下代码来解析它
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(UserParam.class) ! null;
}
Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
UserParam userParam parameter.getParameterAnnotation(UserParam.class);
String name webRequest.getParameter(userParam.name());
int age Integer.parseInt(webRequest.getParameter(userParam.age()));
User user new User();
user.setName(name);
user.setAge(age);
return user;
}
} 在这个示例中我们创建了一个 UserParam 注解并将其应用于方法参数上。然后我们可以在 supportsParameter() 方法中检查方法参数是否带有 UserParam 注解。在 resolveArgument() 方法中我们从注解中获取参数名并从请求参数中获取相应的值然后将其转换为 User 对象。 要在 Spring Boot 应用程序中使用自定义注解您需要将您的注解类添加到 Configuration 类中并将其添加到 addArgumentResolvers() 方法中
Configuration
public class AppConfig implements WebMvcConfigurer {
Override
public void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) {
resolvers.add(new UserHandlerMethodArgumentResolver());
} Retention(RetentionPolicy.RUNTIME)
Target(ElementType.PARAMETER)
public interface UserParam {
String name() default name;
String age() default age;
}
}
现在您就可以在 Spring Boot 应用程序中使用 UserParam 注解来简化 参考
HandlerMethodArgumentResolver用于统一获取当前登录用户_metaobjecthandler获取token-CSDN博客
Spring Boot HandlerMethodArgumentResolver 使用和场景-Spring专区论坛-技术-SpringForAll社区
HandlerMethodArgumentResolver(四)自定参数解析器处理特定应用场景介绍PropertyNamingStrategy的使用【享学Spring MVC】-腾讯云开发者社区-腾讯云