Java AOP 通過注解實(shí)現(xiàn)切面及通過注解改變返回值
AOP簡(jiǎn)介
學(xué)習(xí)過java的小伙伴都知道Spring的重要知識(shí)點(diǎn)之一就是AOP,AOP也就是切面編程,切面編程它能夠幫助我們實(shí)現(xiàn)非侵入式的功能增強(qiáng),解耦現(xiàn)有的業(yè)務(wù)邏輯和要新增的功能增強(qiáng)。
實(shí)際應(yīng)用中的場(chǎng)景
事務(wù)管理、攔截器、日志處理、權(quán)限控制等。
AOP的增強(qiáng)方式
前置增強(qiáng)、后置增強(qiáng)、異常增強(qiáng)、環(huán)繞增強(qiáng)
AOP的通知方式及執(zhí)行順序
通知方式:前置通知、后置通知、環(huán)繞通知、返回通知、異常通知。
執(zhí)行順序:前置通知、環(huán)繞通知,如果發(fā)生異常執(zhí)行異常通知,如果沒有發(fā)生異常執(zhí)行后置通知(after),最后執(zhí)行返回通知(afterReturning)。
AOP實(shí)戰(zhàn)
假設(shè)場(chǎng)景1
查詢學(xué)生類(包括證件類型、證件號(hào)、性別、名稱等),如果證件類型為 “01” ,也就是身份證,那么性別由身份證第17位決定,即使數(shù)據(jù)庫(kù)有性別字段值,也會(huì)被覆蓋,證件類型不是**“01”**身份證,則不做處理,性別為數(shù)據(jù)庫(kù)存儲(chǔ)的性別。
處理邏輯1
自定義一個(gè)注解SexType,用在方法上,寫一個(gè)切面類,切點(diǎn)就是SexType注解,在返回通知(afterReturning)階段進(jìn)行增強(qiáng)。
實(shí)現(xiàn)邏輯1
定義SexType注解:
@Inherited
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SexType {
}
使用SexType的示例:
@SexType
public Students selectById(Integer id) {
Students students = studentsMapper.selectById(id);
return students;
}
切面類StudentAop:
@Aspect
@Component
@Order(1)
public class StudentAop {
@Pointcut(value = "@annotation(com.qiaofc.sharding.aop.SexType)")
private void setSex() {}
@Around("setSex()")
public static Object logStart(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("執(zhí)行切面");
return joinPoint.proceed();
}
@AfterReturning(value = "setSex()",returning = "methodResult")
public static void setSexType(JoinPoint joinPoint, Object methodResult) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
String sexResult = "";
//拿到setSex方法,方便后面通過反射調(diào)用sexSex方法給屬性賦值
Method setSex = methodResult.getClass().getMethod("setSex", String.class);
//拿到屬性值
Field fieldIdentifyType = methodResult.getClass().getDeclaredField("identifyType");
//設(shè)置為true可以拿到private的屬性值,否則拿不到
fieldIdentifyType.setAccessible(true);
String identifyType = (String)fieldIdentifyType.get(methodResult);
Field fieldIdentifyNumber = methodResult.getClass().getDeclaredField("identifyNumber");
fieldIdentifyNumber.setAccessible(true);
String identifyNumber = (String)fieldIdentifyNumber.get(methodResult);
Field fieldSex = methodResult.getClass().getDeclaredField("sex");
fieldSex.setAccessible(true);
String sex = (String)fieldSex.get(methodResult);
if (methodResult != null) {
if ("01".equals(identifyType) && !StringUtils.isEmpty(identifyNumber) && identifyNumber.length() == 18) {
String sexN = identifyNumber.substring(16,17);
try {
int sexI = Integer.valueOf(sexN);
if (sexI % 2 == 1) {
sexResult = "男";
} else {
sexResult = "女";
}
} catch (Exception e) {
sexResult = "";
}
}
if (StringUtils.isEmpty(sexResult)) {
if (!StringUtils.isEmpty(sex)) {
if ("0".equals(sex)) {
//通過反射的方法給屬性賦值
setSex.invoke(methodResult,"男");
} else {
setSex.invoke(methodResult,"女");
}
} else {
setSex.invoke(methodResult,"未知");
}
} else {
setSex.invoke(methodResult,sexResult);
}
} else {
System.out.println("返回值為空!");
}
}
}
測(cè)試
請(qǐng)求報(bào)文
{
"sid": 1
}
返回報(bào)文文章來源:http://www.zghlxwxcb.cn/news/detail-627357.html
{
"sid": 1,
"sname": "小明",
"address": null,
"identifyType": "01",
"identifyNumber": "510123196908151288",
"sex": "女"
}
假設(shè)場(chǎng)景2
在場(chǎng)景一的基礎(chǔ)上,我們又有了一個(gè)新的需求,為了方便展示,后端在返回identifyType=01的基礎(chǔ)上再返回一個(gè)證件類型的中文名稱。
處理邏輯2
添加一個(gè)注解,可以直接操作json,添加一個(gè)字段,返回證件的中文名稱。
實(shí)現(xiàn)邏輯2
添加注解IdentifyTypeChange,將使用此注解的參數(shù),在IdentifyTypeSerialize類中統(tǒng)一處理
@Inherited
@Documented
@Target({ElementType.FIELD})
@JsonSerialize(using = IdentifyTypeSerialize.class)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
public @interface IdentifyTypeChange {
String identifyType() default "";
}
定義IdentifyTypeSerialize類,繼承JsonSerializer,并實(shí)現(xiàn)接口ContextualSerializer,在serialize中通過jsonGenerator.writeStringField方法直接添加一個(gè)參數(shù),并賦值
public class IdentifyTypeSerialize<T> extends JsonSerializer<T> implements ContextualSerializer {
private static Map<String,String> identifyTypeMap = new HashMap<>();
static {
//定義常用的證件類型,或者通過數(shù)據(jù)庫(kù)查詢
identifyTypeMap.put("01","身份證");
}
private String fieldName = "";
//無參構(gòu)造方法必須要有,否則報(bào)錯(cuò)
private IdentifyTypeSerialize() {}
public IdentifyTypeSerialize(String fieldName) {
this.fieldName = fieldName;
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
IdentifyTypeChange identifyTypeChange = beanProperty.getAnnotation(IdentifyTypeChange.class);
if (Objects.nonNull(identifyTypeChange) && Objects.equals(String.class,beanProperty.getType().getRawClass())) {
//拿到注解下面的參數(shù)名,并且賦值給fieldName,serialize方法會(huì)用到
return new IdentifyTypeSerialize(beanProperty.getName());
}
return null;
}
@Override
public void serialize(T value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
//如果原參數(shù)的值為空,那么還是寫回null
if (Objects.isNull(value)) {
jsonGenerator.writeNull();
return;
}
//value注解下的參數(shù)的值
String valueStr = value.toString();
if (StringUtils.isBlank(valueStr)) {
//將原參數(shù)值寫回,如果不寫回,原有identifyType的值將會(huì)為空
jsonGenerator.writeString(valueStr);
return;
}
if (StringUtils.isNotBlank(this.fieldName)) {
//根據(jù)參數(shù)值獲取對(duì)應(yīng)的證件名字,然后再添加一個(gè)字段并賦值
String identifyTypeName = identifyTypeMap.get(valueStr);
if (StringUtils.isNotBlank(identifyTypeName)) {
//這里寫注解下參數(shù)的值,也可以直接在這里修改注解下參數(shù)的值,例如現(xiàn)在identifyType的值為01,可以在后面直接加上身份證,就是:valueStr + identifyTypeName
jsonGenerator.writeString(valueStr);
//根據(jù)上面拿到的注解下參數(shù)名,添加一個(gè)反參
jsonGenerator.writeStringField(this.fieldName + "Name", identifyTypeName);
return;
}
} else {
jsonGenerator.writeString(valueStr);
}
}
}
測(cè)試
請(qǐng)求報(bào)文
{
"sid": 1
}
返回報(bào)文
{
"sid": 1,
"sname": "小明",
"address": null,
"identifyType": "01",
"identifyTypeName": "身份證",
"identifyNumber": "510123196908151288",
"sex": "女"
}
總結(jié)
通過以上兩種方式,即可實(shí)現(xiàn)通過注解來處理結(jié)果,可以解決大多數(shù)問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-627357.html
到了這里,關(guān)于Java AOP 通過注解實(shí)現(xiàn)切面及通過注解改變返回值的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!