终于来了!SSM整合!第二个SpringMVC撰写!

第一步:Spring整合MyBatis

请参考:http://www.moonlightgate.com/archives/88

第二步:将SpringMVC整合进入Spring和MyBatis

  1. 修改UserServiceImpl.java
package com.royotech.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.royotech.dao.PersonDAO;
import com.royotech.entity.Person;
import com.royotech.service.UserService;

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private PersonDAO personDAO;

    @Override
    public List<Person> select() {
        return personDAO.selectAll();
    }
}
  1. applicationContext.xml头部增加scanner语句。
<context:component-scan base-package="com.royotech.service"></context:component-scan>
  1. web.xml增加filter
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
  1. 撰写controller
package com.royotech.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.royotech.entity.Person;
import com.royotech.service.UserService;

@Controller //作用:将当前类的对象交给Spring工厂创建
@RequestMapping("user")   //请求路径
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("select") //请求路径
    public String select(Model model) {
        List<Person> listPerson = userService.select();
        model.addAttribute("listPerson",listPerson);
        return "forward:/list.jsp";
    }
}
  1. 撰写list.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome!</title>
</head>
<body>
    <c:forEach var="person" items="${listPerson}">
        ${person.id},${person.name},${person.birthday},${person.telephone},${person.address}<br/>
    </c:forEach>
</body>
</html>
  1. 大功告成,测试结果如下:
    file

为什么要用SpringMVC?撰写第一个SpringMVC程序

为什么要使用SpringMVC?

SpringMVC作为SSM三剑客中的一个S,其盛行有着以下几方面原因:

  1. Struts2的没落。
    在SSM之前,我们经常说SSH - Struts2、Spring、Hibernate;而现在谈SSM,是指SpringMVC、Spring、MyBatis。SpringMVC是活生生的把Struts2挤下了神坛。Struts2没落的原因有很多,有其重大安全漏洞导致的客户流失,也有框架使用繁琐不适合当代快速开发趋势的原因。
  2. 与Spring的血缘关系。
    SpringMVC与Spring之间有着天然的血缘关系,因此SpringMVC与Spring的结合更紧密,兼容性更好,整合也更容易。
  3. 开发更高效。
    当代程序语言除了“拼性能”外,还要“拼优美”。SpringMVC相较于Struts2而言其程序架构更加优美,开发时代码也更加优美。

说了这么多,还是让我们写一个最简单的SpringMVC程序,看看他的优美之处在哪里?

撰写第一个SpringMVC程序

第一步:添加依赖。

我们依然是基于Maven开发,运行SpringMVC程序的最小依赖如下:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
    </dependency>

这个不用记忆,固定模式。

第二步:配置web.xml

然后配置下WEB-INF目录下的web.xml,这些内容也不用记忆,也是固定模式。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

第三步:编写Controller

创建Controller包,并在下面建立UserController.java
扫盲一下:
struts和SpringMVC本质上都是对Java Servlet功能的封装和集成。
struts2地址习惯以.action结尾,控制器名字习惯以XxxAction方式命名。
SpringMVC地址习惯以.do结尾,控制器名字习惯以XxxController方式命名。

package com.royotech.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller //作用:将当前类的对象交给Spring工厂创建
@RequestMapping("user")   //请求路径
public class UserController {
    @RequestMapping("select") //请求路径
    public String select() {
        return "forward:/list.jsp"; //forward转发到的位置
    }
}

第四步:配置mvc.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置SpringMVC启用注解,哪个包下的内容要使用SpringMVC,就在这里写哪个包的位置 -->
    <context:component-scan base-package="com.royotech.controller"></context:component-scan>
</beans>

第五步:大功告成,测试一下!

新建userController跳转到的list.jsp文件:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome!</title>
</head>
<body>
    Hello!SpringMVC!
</body>
</html>

在浏览器中输入:
http://localhost:8080/JAVA_ALL/user/select.do
注意:

  1. JAVA_ALL是项目名称,区分大小写。
  2. SpringMVC的Controller默认以.do结尾,不加.do访问不到。
    运行结果如下:
    file

第三个Spring程序撰写,整合Spring和MyBatis

MyBatis项目环境搭建及第一个MyBatis程序

请参考:http://www.moonlightgate.com/archives/59

搭建Spring开发环境

请参考:http://www.moonlightgate.com/archives/79

第一个Spring程序的撰写,理解SpringIOC

请参考:http://www.moonlightgate.com/archives/81

第二个Spring程序的撰写,理解SpringAOP

请参考:http://www.moonlightgate.com/archives/86

第三个Spring程序的撰写,整合Spring和MyBatis

第一步:添加依赖。

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.3</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>

第二步:建表、定义对应的实体类
数据库名:java_all,表名:t_person,表结构如下:
file

在entity包下新建实体类Person

package com.royotech.entity;

import java.io.Serializable;

public class Person implements Serializable{
    private Integer id;
    private String name;
    private String birthday;
    private String telephone;
    private String address;

    public Person() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", birthday=" + birthday + ", telephone=" + telephone
                + ", address=" + address + "]";
    }
}

第三步:DAO包下定义DAO接口

package com.royotech.dao;

import java.util.List;

import com.royotech.entity.Person;

public interface PersonDAO {
    public List<Person> selectAll();
}

第四步:applicationContext.xml下增加对应的bean标签

    <!-- 1.创建数据源(之前在mybatis-config.xml中配置) -->
    <bean id="ds" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/java_all?useUnicode=true&characterEncoding=utf8"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123123"></property>
    </bean>
    <!-- 2.创建SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="ds"></property>
        <!-- 相当于mybaits-config.xml中的mapper注册,可以使用通配符* -->
        <property name="mapperLocations" value="classpath:mappers/*Mapper.xml"></property>
        <property name="typeAliasesPackage" value="com.royotech.entity"></property>
    </bean>
    <!-- 3.创建DAO对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 提供DAO接口包名,自动创建该包下所有DAO接口的实现类对象 -->
        <!-- DAO类名的首字母小写,就是从工厂中获取该接口对应实现类对象的id -->
        <property name="basePackage" value="com.royotech.dao"></property>
    </bean>

第五步:在view包下建立SelectPersonSpringMyBatis对象

package com.royotech.view;

import java.util.List;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.royotech.dao.PersonDAO;
import com.royotech.entity.Person;

public class SelectPersonSpringMyBatis {    
    public static void main(String[] args) throws Exception{
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonDAO personDAO = (PersonDAO)ac.getBean("personDAO");
        List<Person> listPerson = personDAO.selectAll();
        for(Person person : listPerson) {
            System.out.println(person);
        }
    }
}

运行一下,大功告成:
file

程序使用Spring和MyBatis前后的对比

  1. MyBatis用于替换DAO.impl包下的实现类,也就是DAO实现类。替代方法是使用mybatis-config.xml和mapper.xml文件。
  2. Spring和MyBatis整合后,mybatis-config.xml文件也省略了,其中对应的内容被写进了Spring配置文件applicationContext.xml文件中。

第二个Spring程序的撰写,理解SpringAOP

搭建Spring开发环境

有关Spring开发环境的搭建,请参考:http://www.moonlightgate.com/archives/79

撰写第一个Spring程序,理解SpringIOC工厂机制

撰写第二个Spring程序前,需要首先理解SpringIOC机制,请参考:http://www.moonlightgate.com/archives/81

撰写第二个Spring程序

第一步:在Maven的pom.xml中添加AOP依赖,代码如下:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

第二步:确定目标类,编写核心功能(也可以理解为这是当前系统已经有的功能)
service包下新建UserService接口

package com.royotech.service;

public interface UserService {
    public boolean login(String username, String password);
}

service.impl子包下新建UserServiceImpl类,实现UserService接口。

package com.royotech.service.impl;

import com.royotech.service.UserService;

public class UserServiceImpl implements UserService{
    @Override
    public boolean login(String username, String password) {
        System.out.println("我是核心功能:我登陆成功了!我的名字:"+username+",我的密码:"+password);
        return true;
    }
}

第三步:编写新功能类。
在aop包下新建MyAdvice类,作为新功能。

package com.royotech.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAdvice implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("我是织入功能:开始统计啦!");
        invocation.proceed();//执行被切入类(目标类)中的既有方法的方法体。
        System.out.println("我是织入功能:统计结束啦!");
        return true;
    }

}

第四步:编写applicationContext.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 id="userServiceImpl" class="com.royotech.service.impl.UserServiceImpl"></bean>
    <!-- 2. 配置额外功能类 -->
    <bean id="myAdvice" class="com.royotech.aop.MyAdvice"></bean>
    <aop:config>
        <!-- 3. 确定切入点 --> 
        <aop:pointcut id="pcut" expression="execution(boolean com.royotech.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))"></aop:pointcut>
        <!-- 4. 将额外功能织入切入点 -->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="pcut"/>  
    </aop:config>
</beans>

注意,xml头部需要添加aop相关内容。

第五步:大功告成,测试一下
在view包下新建PersonSpringAOP.java

package com.royotech.view;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.royotech.service.UserService;

public class PersonSpringAOP {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 
        //这里面用接口,不能用UserServiceImpl类
        //因为本质上讲动态代理自动生成的隐藏对象应该与目标类实现同样的接口
        //因此动态代理对象和目标类不是同类对象,只是继承了相同的方法。
        UserService userService = (UserService)ac.getBean("userServiceImpl");
        userService.login("ROYOTECH", "123123");
    }
}

运行一下,看看结果,欧耶!!!
file

理解为什么使用SpringAOP

AOP(Aspect Oriented Programming)面向切面编程。底层基于动态代理机制实现。简单的来说就是如果系统需要增加某额外功能的时候,在不改变原有代码的情况下,可以通过AOP机制将新的功能织入到程序的切入点(切入点可以精确到方法)上。这是非常好的一种解耦合的机制。作用类似于JAVA拦截器和过滤器。

我能想到的典型应用场景有两个:
客户之前委托第三方开发了某JAVA系统,现在委托给你做新功能添加。最稳妥的方式是以AOP的形式将新功能织入到现有系统中。这样不会影响之前的代码结构,后期也便于单独维护自己的代码。
假如我们想统计下当前所有Service层函数的执行时间,以便优化代码。不可能给每个函数单独增加统计时间的代码。最好的方法是通过AOP,将统计代码织入到函数切入点中。

第一个Spring程序的撰写,理解SpringIOC工厂机制

搭建Spring开发环境

有关Spring开发环境的搭建,请参考:http://www.moonlightgate.com/archives/79

撰写第一个Spring程序

第一步:在entity包下定义Person实体类。

package com.royotech.entity;

import java.io.Serializable;

public class Person implements Serializable{
    private Integer id;
    private String name;
    private String birthday;
    private String telephone;
    private String address;

    public Person() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", birthday=" + birthday + ", telephone=" + telephone
                + ", address=" + address + "]";
    }
}

备注:

  1. 实体类的创建可以通过Eclipse自动生成代码的方式快速完成。
  2. 实体类为什么要实现Serializable接口,请参考文章:http://www.moonlightgate.com/archives/83

第二步:在applicationContext.xml文件下的<beans>标签下增加以下<bean>标签,内容如下:

<bean id="person" class="com.royotech.entity.Person">
    <property name="id" value="1"></property>
    <property name="name" value="Leon"></property>
    <property name="birthday" value="1990-01-01"></property>
    <property name="telephone" value="13811811118"></property>
    <property name="address" value="北京市西城区"></property>
</bean>   

添加<bean>标签的意思就是希望项目中的某一个类交由Spring框架去管理,由Spring工厂创建对象。
<bean>标签的id属性:对象创建好后,通过这个id取出来使用。
<bean>标签的class属性:交给Spring工厂创建对象的全类名。
<bean>标签的下的<property>标签:类的属性。

**第三步:在view包下创建PersonSpringIOC类

package com.royotech.view;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.royotech.entity.Person;

public class PersonSpringIOC {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 
        Person p = (Person)ac.getBean("person");  
        System.out.println(p);
    }
}

运行,输出结果如下:
file

理解为什么使用SpringIOC工厂机制创建对象

不得不说,从这个案例来看,创建一个类变得如此复杂,纯属吃饱了撑的,但是我们换个角度去想:

  • 使用SpringIOC创建对象类似于用乐高建房子,房子建好后拆卸仍然很容易。
  • 而使用传统方法创建对象类似用积木和胶水建房子,房子建好了,想拆开可是非常困难的。

Spring简介及Spring开发环境搭建

什么是Spring?

Java目前最流行的开发框架组合简称SSM:Spring,SpringMVC,MyBatis。有关Spring的“非人类语言”解释,请自行百度。
为什么说是“非人类语言”呢?
因为在我初学Spring的时候,网上查了很多资料,也翻看了一些书籍,对Spring的解释基本上都是用专业术语和抽象语言进行解释。如果你没学过Spring,看再多遍解释你还是不明白,所以这些解释都是非常不友好的。
今天我就现学现卖,说一下我对Spring框架的理解。

Spring:核心价值是IOC和AOP

  • IOC(Inversion of Control)控制反转。是通过Java反射原理去创建对象。实现了创建对象时的解耦合,提高代码的灵活性。Spring可以被理解为一个用于创建和管理对象的工厂,负责创建、管理所有JAVA对象。
    上面这些话翻译成人类语言就是说:
    之前我们用Java创建对象的时候都是用这种形式:

    new AClass();

    这种方式的问题是类名是写死在代码里面的,这种代码的耦合性太强。
    而在Spring里面,创建对象的时候是这样写的:

    xxx.getBean("AClass");

    类名是通过字符串传入的,这样耦合性大大降低。
    这一过程的实现,是由Spring基于Java的反射技术实现的,所以把Spring成为工厂,由这个工厂负责生产对象。

  • AOP(Aspect Oriented Programming)面向切面编程。底层基于动态代理机制实现。简单的来说就是如果系统需要增加某额外功能的时候,在不改变原有代码的情况下,可以通过AOP机制将新的功能织入到程序的切入点(切入点可以精确到方法)上。这是非常好的一种解耦合的机制。作用类似于JAVA拦截器和过滤器。
    我能想到的典型应用场景有两个:

    1. 客户之前委托第三方开发了某JAVA系统,现在委托给你做新功能添加。最稳妥的方式是以AOP的形式将新功能织入到现有系统中。这样不会影响之前的代码结构,后期也便于单独维护自己的代码。
    2. 假如我们想统计下当前所有Service层函数的执行时间,以便优化代码。不可能给每个函数单独增加统计时间的代码。最好的方法是通过AOP,将统计代码织入到函数切入点中。

如果看到这里还不明白,就不要再纠结概念问题了,直接学习技术,学完回过头来再看,就觉得上面的内容很好理解了。

Spring开发环境搭建

Spring开发环境搭建基于Maven。过程非常简单,只需要两步即可完成:

  1. 添加Spring依赖
    在Maven的pom.xml中添加如下依赖:

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.2.RELEASE</version>
    </dependency>
  2. 创建Spring配置文件applicationContext.xml
    在resources文件夹下新建applicationContext.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>

    applicationContext.xml在Eclipse里面只能自己创建空xml,然后撰写。在Intellij IDEA编辑器里面,可以直接从模板创建。或许这就是为什么越来越多的人转向Intellij IDEA的原因。