app開發制作過程中,使用JAVA注解方式,實現(xiàn)權限功能開發
app開發制作過程中,app端請求後端數據,每個方法都要判斷該用戶是(shì)否登陸,這樣就會造成代碼重複,不易維護,對于該問題,閃端講解一種更方便的方法,希望能幫助到大家!
SpringBoot 參數解析 HandlerMethodArgumentResolver
SpringMVC提供了各種姿勢的http參數解析支持,GET/POST參數解析篇也可以看到,加一個@RequestParam
注解就可以将方法參數與http參數綁定,看到這時自然就會好奇這是(shì)怎麽做到的,我們能不能自己定義一種參數解析規則呢?
将介紹如何實現(xiàn)自定義的參數解析,并讓其生效
I. 環境搭建
首先得搭建一個web應用才有可能繼續後續的測試,借助SpringBoot搭建一個web應用屬于比較簡單的活;
創建一個maven項目,pom文件如下
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7</version> <relativePath/> <!-- lookup parent from update --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
II. 自定義參數解析器
對于如何自定義參數解析器,一個較推薦的方法是(shì),先搞清楚springmvc接收到一個請求之後完整的處理鏈路,然後再來看在什麽地方,什麽時機,來插入自定義參數解析器,無論是(shì)從理解還是(shì)實現(xiàn)都會簡單很多。遺憾的是(shì),本篇主要目标放(fàng)在的是(shì)使用角度,所以這裏隻會簡單的提一下參數解析的鏈路,具體的深入留待後續的源碼解析
1. 參數解析鏈路
http請求流程圖:
既然是(shì)參數解析,所以肯定是(shì)在方法調用之前就會被觸發,在Spring中,負責将http參數與目标方法參數進行關聯的,主要是(shì)借助org.springframework.web.method.support.HandlerMethodArgumentResolver
類來實現(xiàn)
/** * Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it. * @throws IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found. */ @Override @Nullable public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
上面這段核心代碼來自org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument
,主要作用就是(shì)獲取一個合适的HandlerMethodArgumentResolver
,實現(xiàn)将http參數(webRequest)
映射到目标方法的參數上(parameter)
apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial; background-color: rgb(255, 255, 255);">所以說,實現(xiàn)自定義參數解析器的核心就是(shì)實現(xiàn)一個自己的HandlerMethodArgumentResolver
2. HandlerMethodArgumentResolver
實現(xiàn)一個自定義的參數解析器,首先得有個目标,我們在get參數解析,當時遇到了一個問題,當傳參爲數組時,定義的方法參數需要爲數組,而不能是(shì)List,否則無法正常解析;現(xiàn)在我們則希望能實現(xiàn)這樣一個參數解析,以支持上面的場景
爲了實現(xiàn)上面這個小目标,我們可以如下操作
a. 自定義注解ListParam
定義這個注解,主要就是(shì)用于表明,帶有這個注解的參數,希望可以使用我們自定義的參數解析器來解析;
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ListParam { /** * Alias for {@link #name}. */ @AliasFor("name") String value() default ""; /** * The name of the request parameter to bind to. * * @since 4.2 */ @AliasFor("value") String name() default ""; }
b. 參數解析器ListHandlerMethodArgumentResolver
接下來就是(shì)自定義的參數解析器了,需要實現(xiàn)接口HandlerMethodArgumentResolver
public class ListHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(ListParam.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { ListParam param = parameter.getParameterAnnotation(ListParam.class); if (param == null) { throw new IllegalArgumentException( "Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } String name = "".equalsIgnoreCase(param.name()) ? param.value() : param.name(); if ("".equalsIgnoreCase(name)) { name = parameter.getParameter().getName(); } String ans = webRequest.getParameter(name); if (ans == null) { return null; } String[] cells = StringUtils.split(ans, ","); return Arrays.asList(cells); } }
上面有兩個方法:
supportsParameter
就是(shì)用來表明這個參數解析器适不适用
實現(xiàn)也比較簡單,就是(shì)看參數上有沒有前面定義的
ListParam
注解
resolveArgument
這個方法就是(shì)實現(xiàn)将http參數粗轉換爲目标方法參數的具體邏輯
上面主要是(shì)爲了演示自定義參數解析器的過程,實現(xiàn)比較簡單,默認隻支持
List<String>
3. 注冊
上面雖然實現(xiàn)了自定義的參數解析器,但(dàn)是(shì)我們需要把它注冊到HandlerMethodArgumentResolver
才能生效,一個簡單的方法如下
@SpringBootApplication public class Application extends WebMvcConfigurationSupport { @Override protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new ListHandlerMethodArgumentResolver()); } public static void main(String[] args) { SpringApplication.run(Application.class); } }
4. 測試
爲了驗證我們的自定義參數解析器ok,我們開兩個對比的rest服務
@RestController @RequestMapping(path = "get") public class ParamGetRest { /** * 自定義參數解析器 * * @param names * @param age * @return */ @GetMapping(path = "self") public String selfParam(@ListParam(name = "names") List<String> names, Integer age) { return names + " | age=" + age; } @GetMapping(path = "self2") public String selfParam2(List<String> names, Integer age) { return names + " | age=" + age; } }
如您有開發需求,可聯系閃端,我們專注于微信小程序開發、外賣、社區團購、分銷商城、分銷系統、量身定制開發、原生android定制、opencv人臉識别項目、網站建設等互聯網平台業務!
掃一掃,關注我們