一、HandlerMethodArgumentResolver的作用及其中的方法解释:
HandlerMethodArgumentResolver是个接口,这个接口中有两个方法:
publicinterfaceHandlerMethodArgumentResolver { booleansupportsParameter(MethodParameterparameter); ObjectresolveArgument(MethodParameterparameter, ModelAndViewContainermavContainer, NativeWebRequestwebRequest, WebDataBinderFactorybinderFactory) throwsException; }
看方法名应该大致能猜到:
supportsParameter这个方法返回值是boolean,它的作用是判断Controller层中的参数,是否满足条件,满足条件则执行resolveArgument方法,不满足则跳过。
resolveArgument方法,它只有在supportsParameter方法返回true的情况下才会被调用。用于处理一些业务,将返回值赋值给Controller层中的这个参数。
我们可以将HandlerMethodArgumentResolver理解为是一个参数解析器,我们可以通过写一个类实现HandlerMethodArgumentResolver接口来实现对Controller层中方法参数的修改。
二、项目实现
1、比如,我们现在用JWT方式登陆后需要通过下面的接口获取当前登录人的信息和权限菜单等详细信息。
"/routes") (order=7) (value="前端菜单数据", notes="前端菜单数据") (publicR<List<MenuVO>>routes(HttpServletRequestrequest) { Claimsclaims=getClaims(request); if (claims==null) { returnnull; } else { LonguserId=claims.get("user_id"); StringroleId=claims.get("role_id"); StringdeptId=claims.get("dept_id"); Stringaccount=claims.get("account"); StringroleName=claims.get("role_name"); StringuserName=claims.get("user_name"); Useruser=newUser(); user.setUserId(userId); user.setTenantId(tenantId); user.setAccount(account); user.setRoleId(roleId); user.setDeptId(deptId); user.setRoleName(roleName); user.setUserName(userName); } List<MenuVO>list=menuService.routes((user==null||user.getUserId() ==0L) ?null : user.getRoleId()); returnR.data(list); }
但是,在项目中肯定每个接口需要这样获取参数,这样的话代码太臃肿了。我们可以稍微改造一下,用HandlerMethodArgumentResolver这个接口:
2、首先写个实现类实现这个接口中的方法:
publicclassTokenArgumentResolverimplementsHandlerMethodArgumentResolver { privatestaticfinalLoggerlog=LoggerFactory.getLogger(TokenArgumentResolver.class); publicTokenArgumentResolver() { } publicbooleansupportsParameter(MethodParametermethodParameter) { returnmethodParameter.getParameterType().equals(User.class); } publicObjectresolveArgument(MethodParametermethodParameter, ModelAndViewContainermodelAndViewContainer, NativeWebRequestnativeWebRequest, WebDataBinderFactorywebDataBinderFactory) { returnSecureUtil.getUser(); } }
然后将这个实现类添加到项目的拦截其中:
( proxyBeanMethods=false) -2147483648) (publicclassMyWebMvcConfigurationimplementsWebMvcConfigurer { privatestaticfinalLoggerlog=LoggerFactory.getLogger(BladeWebMvcConfiguration.class); publicMyWebMvcConfiguration() { } publicvoidaddArgumentResolvers(List<HandlerMethodArgumentResolver>argumentResolvers) { argumentResolvers.add(newTokenArgumentResolver()); } }
这样在项目接口请求时会进入到我们自定义的TokenArgumentResolver类中进行解析接口类和参数信息。
然后,我们的接口就可以这样写啦:
"/routes") (order=7) (value="前端菜单数据", notes="前端菜单数据") (publicR<List<MenuVO>>routes(Useruser) { List<MenuVO>list=menuService.routes((user==null||user.getUserId() ==0L) ?null : user.getRoleId()); returnR.data(list); }
这样就不用每个接口都解析请求头中的token了,可以拿到token对应的用户信息