# 软件开发项目实践（三）

> 原文：https://pjhubs.com/2018/04/05/%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5%EF%BC%88%E4%B8%89%EF%BC%89/
>
> 作者：PJHubs · 发布于 2018-04-05 · 标签：后端、Java

终于到了实验三，吐槽一句，环境不一致真的很难受，又不想用Eclipse，还不想重写一份，这真的是很难办的事情呢。🙄

**1. 完成PersistService和SelectService这两个实现类中所有方法，定义他们的抽象父类，并抽象出公共方法，且用到枚举。**

有可能我看漏了，或者理解错报告要求的意思了，先这么做吧。

```Java

// persistService
@Override
public void updateStudent(StudentModel t, Integer id) {
	try {
		if (!super.checkWhitePermission(id)) {
			String string = String.format("记录%s无法更新", id);
			logger.warn(string);
		}

		studentMapper.updateStudent(t, id);
		logger.info("记录" + id + "已经更新");

	} catch (Exception e) {
		logger.error("Error", e);
	}
}

// studentMapperTest
@Test
public void testUpdateStudent() {
  StudentModel studentModel = new StudentModel("王五", "女", "软件二班", 1, 60 ,60 ,60, 60);
  persistService.updateStudent(studentModel, 1);
  logger.info("更新成功");
}

```

没看到SelectService类里有其它需要实现的类，也看了其继承的类和接口，同样都被实现过了。


**定义他们的抽象父类，并抽象出公共方法，且用到枚举**，这几句话想了好久，没搞懂什么意思，虽然这两个类都有在对StudentModel做事情，但是区分度已经很大了哇，没搞懂还能抽出什么公共方法，但是看到了后边说 **且需要用到枚举** ，难道是要把这几个对StudentModel操作的方法都统一到一个父类里，然后根据父类里的type类型枚举去判断当前子类是否有“权限”去执行这个方法？思来想去，还是没搞懂是啥意思。待做求解。

**2. 验证课堂上AOP的相关样例代码，编写在自己业务场景下的面向切面程序，包括before,after,around,After-Returning这四种通知。**

自己觉得Spring AOP有用到了类似JVM的runtime内容（存粹自己的猜测，没有查阅过相关资料），在运行时做了替换，比如说AABB类在执行`method()`之前，通过AOP的配置文件表明是用哪个类的哪个方法在哪些类的哪些方法运行前、后等时期先执行，这点跟OC中的`Runtime`思路非常的类似，使用AOP可以有两种做法，一是通过AOP类使用java注解的方式表明，另外一种是在Spring配置文件中写明是哪个类的哪个方法需要在什么地方被执行，经过一番折腾下来，个人觉得使用Spring配置文件写明切面函数的调用比较好。

老师一直想让我们编写自己的业务场景，自己的业务场景，但是落实到实处就是想要去验证AOP是你自己写的嘛，emmm，那就上demo程序好了。

0. 创建Spring工程，导入额外的[aopalliance.jar](http://www.java2s.com/Code/Jar/a/aopalliance.htm)和[aspectjweaver](http://mvnrepository.com/artifact/org.aspectj/aspectjweaver/1.8.7)包

1. 创建`User`类；

  ```java
  public class User {

      private Integer id;
      private String nickname;

      public Integer getId() {
          return id;
      }

      public void setId(Integer id) {
          this.id = id;
      }

      public String getNickname() {
          return nickname;
      }

      public void setNickname(String nickname) {
          this.nickname = nickname;
      }
  }

  ```

2. 创建`UserMapper`类，可以不用手撸SQL，让Mybatis去做：

  ```java
  import java.util.List;

  public interface UserMapper {

      public User selectUserWithID(int ID) throws Exception;

  }

  ```

3. 创建`selectUserAdvice`类，里边包含了对User类进行操作的所有切面程序：

	```java
	  public class userAdvice {

	    public void userSayHello() {
	      System.out.println("user say hello!");
	    }

	    public void userSayBay() {
	      System.out.println("user say bay!");
	    }

	    public void userSaySee() {
	      System.out.println("user say see!");
	    }

	    public void userSayUser(User user) {
	      System.out.println("user say " + user.nickname);
	    }

	  }

	```

4. 配置User.xml，供MyBatis操作user表：
	```xml
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

  <mapper namespace="com.pjhubs.UserMapper">
    <select id="selectUserWithID" parameterType="int" resultType="com.pjhubs.User">
        select * from user where id = #{id}
    </select>
  </mapper>

  ```

5. 配置SqlMapConfig.xml，MyBatis的配置文件：

  ```xml

  <?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE configuration
          PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
          "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <configuration>
      <environments default="development">
          <environment id="development">
              <transactionManager type="JDBC"/>
              <dataSource type="POOLED">
                  <property name="driver" value="com.mysql.jdbc.Driver"/>
                  <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
                  <property name="username" value="your DB name"/>
                  <property name="password" value="your DB password"/>
              </dataSource>
          </environment>
      </environments>
      <mappers>
          <mapper resource="User.xml"/>
      </mappers>
  </configuration>

  ```

6. 创建Spring配置文件（intelliJ在创建Spring工程的时候可进行勾选协助创建），并写下，（参考实验文档中内容）：

	```xml

	  <?xml version="1.0" encoding="UTF-8"?>
	  <beans xmlns="http://www.springframework.org/schema/beans"
	  	xmlns:task="http://www.springframework.org/schema/task" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	  	xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
	  	xmlns:cache="http://www.springframework.org/schema/cache"
	  	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	  	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
	          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
	  	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
	  	http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
	  	http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">


	    <bean id="user" class="com.pjhubs.user" />
	    <bean id="userAdvice" class="com.pjhubs.userAdvice" />

	  	<aop:config proxy-target-class="true">
	  		<aop:pointcut id="selectUser" expression="target(com.pjhubs.user) and execution(* select*(..))" />
	  		  <aop:aspect id="userAdvice" ref="userAdvice">
	  			  <aop:before method="userSayHello" pointcut-ref="selectUser" />
	  			  <aop:around method="userSayBay" pointcut-ref="selectUser" />
	    			<aop:after method="userSaySee" pointcut-ref="selectUser" />
	    			<aop:after-returning method="userSayUser" pointcut-ref="selectUser" returning="bindParam" />
	  		</aop:aspect>
	  	</aop:config>

	  </beans>

  ```

7. 测试。同时也在做第三题——（**利用Spring框架的单元测试跑通以上所有方法。**），因为我们已经引入了Spring，所以就不要再只是使用JUnit啦~需要同时引入以下jar包，
  * JUnit4
  * Spring-Test
  本着赶紧做完的心态，并没有使用Maven等依赖工具对java工程的各种依赖包进行管理🙂，所以每次都会对其手动添加jar包。emmm。创建测试类`userTest`:

  ```java

  @RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration("/spring-config.xml")

  public class userTest() {
    @Resource
    public User user;

    @Test
    public void testSelectUser() {
      User user = userMapper.selectUserWithID(2);
      System.out.println("id:" + user.getId() + " 昵称：" + user.getNickname());
    }
  }

  ```



## 如果你嫌弃上边说的太啰嗦，那么这还有个简约版的。

首先在intelliJ下创建一个Spring工程，当然要你的intelliJ是社区版的就算了，功能支持的受限。记得勾选创建默认的Spring XML配置文件。

### 验证IOC相关内容，随意创建一个类，在其中随意写下一个方法，

```java
public class IOCTest {

    private String IOCName;


    public String getIOCName() {
        return IOCName;
    }

    public void setIOCName(String IOCName) {
        this.IOCName = IOCName;
    }

    public void printIOCName() {
        System.out.println(IOCName);
    }
}

```

2. 在工程默认生成的Spring XML配置文件中，新增，

	```Java
	<bean id="IOCTest" class="IOCTest">
		<property name="IOCName" value="pjhubs"></property>
	</bean>
	```

3. 在Main类中或者新建一个测试类的测试方法，在该方法中写下，

```java
public class Main {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        IOCTest iocTest = (IOCTest)context.getBean("IOCTest");
        iocTest.printIOCName();
    }
}  
```

这样就完成了IOC的内容，把创建对象的能力“转移”掉了，同时也达到了我们只需要定义接口，相关类的控制交由IOC管理即可，而且当我们有需要对两个类定义关系时，只需要在配置文件中定义好即可。

### 验证AOC的相关内容

1. 创建好工程后，在[这个地址](http://www.java2s.com/Code/Jar/a/Downloadaspectjweaver172jar.htm)下载`aspectjweaver`包，导入工程。

2. 分别创建两个类，本次我们采用XML文件配置的方式来做AOP，如下所示，

	```Java
		public class AOPTest {

	    public void AOPTest() {
	        System.out.println("AOPTest......");
	    }

		}

	```

	```Java

	import org.aspectj.lang.ProceedingJoinPoint;

	public class AOPMethon {

	    //前置增强
	    public void before(){
	        System.out.println("前置增强........");
	    }

	    //后置增强
	    public void after(){
	        System.out.println("后置增强........");
	    }

	    //环绕增强
	    public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
	        //方法之前执行的代码
	        System.out.println("环绕增强 方法之前执行........");

	        //执行被增强的方法
	        proceedingJoinPoint.proceed();

	        //方法之后执行的代码
	        System.out.println("环绕增强 方法之后执行........");
	    }

	}

	```

3. 修改Spring XML配置文件为，

	```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:aop="http://www.springframework.org/schema/aop"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	    <!--1 配置对象-->
	    <bean class="AOPMethon" id="AOPMethon"></bean>
	    <bean class="AOPTest" id="AOPTest"></bean>

	    <!--2 配置AOP操作-->
	    <aop:config>
	        <!--配置切入点-->
	        <aop:pointcut id="pointcut" expression="execution(* AOPTest.AOPTest())"/>
	        <!--配置切面
	            把增强用到方法上面
	        -->
	        <aop:aspect ref="AOPMethon">
	            <!--前置增强-->
	            <aop:before method="before" pointcut-ref="pointcut"/>

	            <!--后置增强-->
	            <aop:after-returning method="after" pointcut-ref="pointcut"/>

	            <!--环绕增强-->
	            <aop:around method="arround" pointcut-ref="pointcut"/>
	        </aop:aspect>
	    </aop:config>

	</beans>
	```

4. 新建一个测试类，写下相关的测试方法，

	```Java
	import org.junit.Test;
	import org.springframework.context.ApplicationContext;
	import org.springframework.context.support.ClassPathXmlApplicationContext;

	public class test {
	    @Test
	    public void AOPTest() {
	        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
	        AOPTest aopTest = (AOPTest) applicationContext.getBean("AOPTest");
	        aopTest.AOPTest();
	    }
}

	```

5. 输出的结果为：
	```
		前置增强........
		环绕增强 方法之前执行........
		AOPTest......
		环绕增强 方法之后执行........
		后置增强........
	```

至于AOP中的这几个增强方法的区别，就不展开啦~~~
