需求:現在有這麼個需求,假如有一個自定義註解,我打在Controller層的方法上面,然後需要輸出這個方法的路徑,然後controller是多個,不能指定,方法也不能指定,大概就是一個方法解決所有類似的情況,該怎麼做?(自定義註解@ResMapping)
import jdk.nashorn.internal.ir.annotations.Ignore;
import org.omg.CORBA.DynAnyPackage.Invalid;
import java.lang.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author :xianglong
* @Company com.suixingpay
* @Create 2018/11/30 16:17
* @Effect :
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResMapping {
}
首先我們的思路就是先要通過@Controller和@ResController去找到這個類,然後遍歷其中的方法,如果發現某個方法上面有@ResMapping,看下面這個例子。
@Slf4j
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*")
public class MqController {
@PostMapping("/login")
@ResMapping
public JsonResult login(@RequestBody UserInfoForm userInfoForm, HttpServletRequest request) throws IOException{
}
然後需要通過日誌打印這麼個數據:/api/login,這就是這麼個需求。我們一步一步來解決這個問題,最後我把有用的代碼貼出來供大家直接使用,重在學習!
1.BeanPostProcessor接口
這個接口裏面有兩個需要實現的方法,
@Slf4j
@Configuration
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
你可以試試在裏面將beanName輸出看看,你會發現幾乎所有的spring容器內的bean都會通過這個實現的方法輸出出來,這就很好的解決了一個問題:怎麼獲取controller控制類,那就是通過反射的機制,判斷類上是否有@Controller
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class clz = bean.getClass();
/**判斷此bean是否是controlelr*/
boolean clzHasAnno = clz.isAnnotationPresent(Controller.class);
boolean clzzHasAnno = clz.isAnnotationPresent(RestController.class);
if (clzHasAnno || clzzHasAnno) {
}
return bean;
}
我感覺我直接貼代碼比較合適,因爲上面有註釋
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* bean後置處理器
*
* @author xl
*/
@Slf4j
@Configuration
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class clz = bean.getClass();
/**判斷此bean是否是controlelr*/
boolean clzHasAnno = clz.isAnnotationPresent(Controller.class);
boolean clzzHasAnno = clz.isAnnotationPresent(RestController.class);
if (clzHasAnno || clzzHasAnno) {
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
/**優先判斷某個方法是否有自定義註解*/
boolean getHasAnno = method.isAnnotationPresent(ResMapping.class);
if (getHasAnno) {
/**獲取此類的一級路徑,沒有返回空*/
String fath = StringUtils.defaultString(lookupRequestMappingPath(bean.getClass().getAnnotations()));
RequestMapping isRequestMapping = AnnotationUtils.findAnnotation(method,RequestMapping.class);
if (isRequestMapping != null) {
String path = lookupRequestMappingPath(AnnotationUtils.getAnnotations(method));
path = fath+path;
log.info("Request entry ->{path:{}}",path);
}
}
}
}
return bean;
}
private String lookupRequestMappingPath(Annotation[] annotations) {
for (Annotation ann : annotations) {
Class annType = ann.annotationType();
// 如果annType與RequestMapping類型一致 或 RequestMapping註釋存在於annType上
if (annType.isAssignableFrom(RequestMapping.class) || annType.isAnnotationPresent(RequestMapping.class)) {
String[] paths = (String[]) AnnotationUtils.getValue(ann);
return paths.length > 0 ? paths[0] : null;
}
}
return null;
}
}
這是整個過程,自定義註解也給了,可以自己試試,不懂的可以私信我