【Spring】springAOP的自我思考

场景原因:

在项目过程中,接到新需求,用户进行操作进行数据交换的时候,需要详细记录具体哪个值由什么变为了什么,在最开始实现的时候,我是在controller中每次insert或者update或者delet的时候前后各查询一次,然后对比,输出不一样的字段,

具体实现代码段:

    /**
     * 只修改clientIndivInfo非空字段
     *
     * @param clientIndivInfo
     * @return
     */
    @EnableGameleyLog(name = ModifyName.UPDATE,serviceclass = ClientIndivInfoService.class)
    @RequestMapping(value = "/updateselective", method = RequestMethod.POST)
    public
    @ResponseBody
    Object updateselective(@RequestBody ClientIndivInfo clientIndivInfo ,HttpServletRequest request) {
    	Track track = new Track();
    	ClientIndivInfo oldDlientIndivInfo = clientIndivInfoServiceImp.selectByPrimaryKey(clientIndivInfo.getClientno());
        int result = clientIndivInfoServiceImp.updateByPrimaryKeySelective(clientIndivInfo);
        LOGGER.info("{}选择性修改数据结果:{}", JsonUtil.toJson(clientIndivInfo), result);
        ClientIndivInfo newDlientIndivInfo = clientIndivInfoServiceImp.selectByPrimaryKey(clientIndivInfo.getClientno());
        track.setId(clientIndivInfo.getClientno());
		try {
			List<Map<String, Object>> changelist = CompareTwoClassUtil.compareTwoClass(oldDlientIndivInfo,newDlientIndivInfo);
			 StringBuilder str=new StringBuilder();
			 str.append("修改:\n");
		        for(Map<String,Object> map:changelist){
		            str.append("【"+map.get("name")+"】从【"+map.get("old")+"】改为了【"+map.get("new")+"】;\n");
		        }
		        track.setOperation(str.toString());
		} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			String userId = SessionUtil.getUserId(request.getSession());
			track.setUserId(userId);
			String url = request.getRequestURI();
			track.setUrl(url);
			if(request.getRemoteAddr().toString().equals("0:0:0:0:0:0:0:1")){
				String address = "0.0.0.0";
				track.setAddress(address);
			}else if(request.getRemoteAddr().toString().equals(null)||request.getRemoteAddr()==""){
				String address = "- - - -";
				track.setAddress(address);
			}else {
				String address = request.getRemoteAddr();
				track.setAddress(address);
			}
				/*track.setOperation(dataInfo);*/
				try {
					trackServiceImpl.insert(track);
				} catch (Exception e) {
					e.printStackTrace();
				}

        return new RestBean(MsgCodeConstant.UPDATE_SUCCESS);
    }

过来一段时间,发现这么写,每个controller都得写,而且,就算规范代码,写在serviceImpl里边,也是要耗费许多精力去写如此多的重复的代码,于是我就在想,可以使用AOP作为一个切面开发,写一个公共的代码块,这样岂不是就会省略很多事,我好天才,然后我就开始具体实现:

实现思考:

1.我需要一个入口来作为开启AOP切面的标志,我想了想,觉得使用自定义注解,然后在方法头打自定义注解就可以了

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface EnableGameleyLog {
	/**
     * 操作的中文说明 可以直接调用ModifyName
     * @return
     */
    String name() default "";

    /**
     * 获取编辑信息的解析类,目前为使用id获取,复杂的解析需要自己实现,默认不填写
     * 则使用默认解析类
     * @return
     */
    Class parseclass() default DefaultContentParse.class;

    /**
     * 查询数据库所调用的class文件
     * @return
     */
    Class serviceclass() default IService.class;

    /**
     * 前台字段名称
     */
    String[] feildName() default {"workingname"};
    /**
     * 具体业务操作名称
     */
    String handleName() default "";

}

2.使用AOP注解配置,我是使用的SSM+AOP+MAVEN的配置,需要在xml文件中进行配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"
		
       default-autowire="byName">
    <mvc:resources location="/pages/" mapping="/pages/**"/>
    <mvc:default-servlet-handler/>
    <!-- task任务扫描注解 -->
    <task:annotation-driven/>
    <context:component-scan base-package="com.**.**.controller"/>
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean id="jacksonHttpMessageConverter"
                  class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- 定义跳转的文件的前后缀 ,视图模式配置 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>

    <!-- 多部分文件上传 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="104857600"/>
        <property name="maxInMemorySize" value="4096"/>
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>  
    
</beans>

注意:你的xmlns必须配置xmlns:aop="http://www.springframework.org/schema/aop";

你的xsi必须配置http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd",并且和你的spirng版本相符合

3.书写AOP切面逻辑

@Aspect
@Component
//@Conditional(OperatelogService.class)
public class ModifyAspect {

    private final static Logger logger = LoggerFactory.getLogger(ModifyAspect.class);

    private Operatelog operateLog=new Operatelog();

    private Object oldObject;

    private Object newObject;

    private Map<String,Object> feildValues;

    @Autowired
    private Service service;

    @Before("@annotation(enableGameleyLog)")
    public void doBefore(JoinPoint joinPoint, EnableGameleyLog enableGameleyLog){
        //自己的代码
    }

    @AfterReturning(pointcut = "@annotation(enableGameleyLog)", returning = "object")
    public void doAfterReturing(Object object, EnableGameleyLog enableGameleyLog){
        //自己的代码
        //将对比后的结果存入你的数据库
    }
    
    @After("@annotation(enableGameleyLog)")
    public void doAfter(JoinPoint joinPoint, EnableGameleyLog enableGameleyLog) {
        //自己的代码
    }

注意:你使用的是注解作为AOP切面的入口,所以,你在AOP的切面注解中,比如:@Before,@After,@AfterRueturing中必须加上你的注解("@annoration(enableGameleyLog)"),这样才能保证你在controller打注解后能进行切面逻辑

4.具体实现代码controll

    @EnableGameleyLog(name = ModifyName.UPDATE,serviceclass = ClientIndivInfoService.class)
    @RequestMapping(value = "/updateselective", method = RequestMethod.POST)
    public
    @ResponseBody
    Object updateselective(@RequestBody ClientIndivInfo clientIndivInfo ,HttpServletRequest request) {

    //你的代码实现逻辑
}

5.进行完这些后,我发现一个问题,就是除开从数据库查出来数据外,我无论如何得不到当前数据,我能得到的只是修改后的数据,而后,要解决这个问题,就得在@Before注解下的代码中从数据库查询,如果的数据都是从一个表来的并且关联其他表都一样,那么,就可以从数据库查询,但是目前项目查询时关联的都不一样,几乎一个功能有7个模块,7个里边的查询都不一样,要是写7个AOP还不如我之前一个个写,代码量算过来都一样,坑爹,很烦,AOP这个不适用,下次再更新新想法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值