一、开发工具
开发过程中使用的操作系统是OS X,关于软件安装的问题请大家移步高效的Mac环境设置。
本文是我对自己学习过程的一个回顾,应该还有不少问题待改进,例如目录的设置、编码习惯和配置文件的处理等,请大家多多指正。
文中用到的开发工具列举如下:
- JDK 1.7.0_79
- Intellij IDEA Ultimate 14
- Mysql 5.6.25
- Maven 3
- Git、SourceTree
二、新建工程
1. 新建空的maven工程
第一步新建工程,选择Maven工程,如图1所示。注意,“create from archetype”是一些Maven的工程模板,在这里我们为了学习要从头开始自己配置。点击next,出现设置工程坐标的页面,如图2所示。GroupId 是公司组织的标号;ArtifactId是项目名称;综合来看,在src/main/java目录下会新建对应的包结构:GroupId.ArtifactId。
点击next,出现设置工程名字的界面,如图3所示。这里跟之前的ArtifactId一样就可以,设置完后选择finish完成工程构建。我们这个示例项目采用的是单模块项目,我猜这里是设置模块相关的吧,还需继续学习。2. 编辑.gitignore文件
我们不需要从头开始写.gitignore文件,已经有人为我们准备好了模板文件,只需要在模板文件的基础上稍作修改即可。
首先要给IDEA安装.gitignore插件,然后在工程名字上右击建立.gitignore文件,通过插件可以根据项目的内容选择需要忽略的文件或者文件夹。在这里我选择了三个类型:Java、JetBrains、OSX三个模板的组合文件。因为Maven编译生成的目录名为target,我又增加了target文件夹的忽略,如图4所示。3. 初始化仓库
通过SourceTree,创建本地仓库,将目标路径设置为usersDemo工程的根目录,如图5所示。仓库初始化完成后,我们的项目就在Git管理之下了,可以开始下一步了。三个月后补充:极力推荐大家使用IDEA自带的git插件,非常棒,可以可视化解决冲突。
三、Spring MVC支持
1. 添加Spring MVC库以及servlet库
首先在pom.xml文件中修改配置,通过properties标签统一管理依赖库的版本,方便后续更新;通过dependencies标签管理所有的库依赖,本次增加的配置代码如下所示:
4.1.7.RELEASE
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-core
${spring.version}
javax.servlet
servlet-api
2.5
provided
接下来为项目增加Spring MVC框架支持,也就是每个web项目都应该有的web文件夹等等。具体操作如图6和图7所示。其中Spring MVC框架的库已经不用下载,使用我们之前在pom中下载好的库即可。
选择相应的Web框架和库文件
添加完成后,要对项目的目录结构做一些调整:将web文件夹移动到src/main/目录下,并重命名为webapp,调整后的目录结构如图8所示。
2. web.xml
web.xml的作用是配置DispatcherServlet,在SpringMVC项目中DispatcherServlet作为前端控制器。服务器给用户的接口名并不是真正的servlet类的名字,只是一个逻辑名称,由DispatcherServlet完成这个逻辑名称到真正的servlet类的映射过程。
在web.xml的代码中,org.springframework.web.servlet.DispatcherServlet的实例名称为usersDemo,这个servlet-name 非常重要,默认情况下,DispatcherServlet在加载时会从一个机遇这个servlet名字的XML文件中加载Spring应用上下文,在这里,因为servlet-name是usersDemo,所以DispatcherServlet将会从usersDemo-servlet.xml文件中加载应用上下文。现在项目的目录结构图如图9所示。通过servlet-mapping标签指定由usersDemo这个DispatcherServlet实例处理哪些映射,在这里我们设置为“/”,即声明该DispatcherServlet实例会吹所有的请求,包括静态资源的请求。
最后,web.xml的代码列举如下:
contextConfigLocation
/WEB-INF/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
usersDemo
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
WEB-INF/usersDemo-servlet.xml
1
usersDemo
/
3. usersDemo-servlet.xml
DispatcherServlet需要咨询一个或者多个处理器映射器来决定要将请求发送给哪个控制器,我们这里常用的处理器映射器是DefaultAnnotationHandlerMapping:即将请求映射给使用@RequestMapping注解的控制器和控制器方法。
最新的Spring的发展趋势是依靠注解来减少XML配置,因此我们在usersDemo.xml中添加下面一行配置,就可以得到Spring MVC提供的注解驱动测试
我们将会给控制器类添加@Controller来表明这是一个控制器类,这个类是@Component的子类,也就是说可以通过"context:component-scan标签"来查找控制器类并将其自动注册为Bean。需要再usersDemo.xml中添加下面一行配置:
4. 控制器
经过了上一步的铺垫,控制器的代码比较简单。@Controller注解告诉Spring这是一个控制器类,要将它注册为Bean;@RequestMapping注解告诉Spring将"/showUsers“接口,并且HTTP方法是GET的请求由showUser方法处理。
在showUser方法中我们使用servlet直接打印HTTP响应内容,很熟悉的hello系列。
UsersController的代码列举如下:
package com.alibaba.yunos.usersDemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by duqi on 15/8/19.
*/
@Controller
public class UsersController {
@RequestMapping(value = "/showUser",method = RequestMethod.GET)
public void showUser(HttpServletResponse response) throws IOException {
response.getWriter().print("Hello SpringMVC
");
response.flushBuffer();
}
}
5. 启动web服务
- 配置maven的构建过程
在pom文件中要增加两个配置,第一个是打包格式;第二个是build生成文件的名称。
相关的配置代码为:
war
usersDemo
- 配置并运行tomcat
在IDEA中配置tomcat的步骤有下面几步:
(1)在屏幕右上角,选择”Edit Configuration“,如图10所示。
(2)选择建立一个本地的tomcat容器,如图11所示。
(3)配置项目的发布方式为:usersDemo:war exploded,并且将应用程序上下文设置为"/usersDemo",如图12所示。
(4)配置tomcat容器的安装地址、启动服务器后是否需要自动启动浏览器、有文件修改或者检查到新的框架时容器如何反应,我们这里选择”update classes and resources“,如图13所示。
![图13 配置tomcat服务器信息](http://img.blog.csdn.net/20150819133940882)
(5)启动tomcat容器,URL为:http://localhost:8080/usersDemo/showUser。
最后的运行效果如图所示:
6. 代码提交
使用SourceTree对刚才修改和增加的代码进行提交,如图15所示,对于commit message要尽量简洁。四、Velocity支持
Velocity的存在是为了辅助前后端分离:后端接口开发人员可以专心于提供数据、前端人员可以使用占位符(模板文件)暂时代替数据。渲染:将占位符替换为真正的变量值,并生成最终的网页页面。
1. 添加Velocity支持库
首先在pom.xml中编辑,下载Velocity的支持库,包括三个支持:Velocity、Velocity-tool、spring-context-support。
添加的依赖代码如下:
org.apache.velocity
velocity
${velocity.version}
org.apache.velocity
velocity-tools
${velocity-tools.version}
org.springframework
spring-context-support
${spring.version}
2. 增加Velocity视图解析器
在usersDemo-servlet.xml文件中配置Velocity视图解析器。配置代码如下:
utf-8
utf-8
3. 修改控制器代码
控制器的作用是根据请求调用BLL层提供的Service实例,当服务接口返回处理结果后,由控制器将模型对象和逻辑视图名称返回。在这里还不涉及模型数据,因此只关注逻辑视图,解析器根据这个逻辑视图名称,再加上在usersDemo-servlet.xml文件中定义的视图解析器设置,找到对应的模板文件进行渲染。
控制器的代码如下:
package com.alibaba.yunos.usersDemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Created by duqi on 15/8/19.
*/
@Controller
public class UsersController {
@RequestMapping(value = "/showUser",method = RequestMethod.GET)
public String showUser() {
//1.调用BLL层的服务接口
//2.设置模型数据
//3.返回逻辑视图名称
return "showUser";
}
}
4. 创建模板文件
现在的模板文件非常简单,就是一句话:”hello velocity!!“,现在项目目录结构和模板文件如图16所示(注意路径与usersDemo-servlet.xml中配置的对应关系)。5. 测试视图解析器
启动tomat服务器,运行结果如图17所示。6. 代码提交
通过SourceTree提交commit。
五、Mybatis支持
Mybatis 的着力点,则在于POJO 与SQL之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。 相对Hibernate“O/R”而言,Mybatis是一种“Sql Mapping”的ORM实现。
1. 增加Mybatis支持库以及Mysql库
在pom.xml文件中增加相应的支持库,包括mybatis、mybatis-spring、commons-dbcp2、mysql-connector-java等库。其中commons-dbcp2是用作管理数据库连接池。
增加的配置代码如下:
org.mybatis
mybatis
${mybatis.version}
org.mybatis
mybatis-spring
${mybatis-spring.version}
org.apache.commons
commons-dbcp2
2.0
mysql
mysql-connector-java
${mysql.connector.version}
2. 在Mysql准备好数据库和表
(1)建立一个数据库mybatis用于测试;
(2)建立一张表users,各个字段的设置如图18所示。
(3)为表中插入初始数据,如图19所示。
3. 配置数据源dataSource
数据源的配置在applicationContext.xml中完成,具体的配置代码如下:
4. 增加数据模型POJO
在数据库中,id字段我们设置为自动增加。User.java的代码如下
package com.alibaba.yunos.usersDemo.model;
/**
* Created by duqi on 15/8/19.
*/
public class User {
private String NAME;
private String age;
public String getNAME() {
return NAME;
}
public void setNAME(String NAME) {
this.NAME = NAME;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
4. 增加DAO层
要和 Spring 一起使用 MyBatis,你需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。在 MyBatis-Spring 中,SqlSessionFactoryBean 是用于创建 SqlSessionFactory 的。
首先新建一个接口UserMapper,完成请求方法(getUser)到SQL语句的映射,代码下所示:
package com.alibaba.yunos.usersDemo.mapper;
import com.alibaba.yunos.usersDemo.model.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* Created by duqi on 15/8/19.
*/
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{userId}")
User getUser(@Param("userId")String userId);
}
接着在applicationContext.xml文件中增加配置,将UserMapper接口加入到Spring容器中,配置代码如下所示:
至此,DAO和数据库层就已经配置好了。
5. 增加Service层
首先增加UserService接口,代码如下:
package com.alibaba.yunos.usersDemo.service;
import com.alibaba.yunos.usersDemo.model.User;
/**
* Created by duqi on 15/8/19.
*/
public interface UserService {
User getUser(String userId);
}
然后增加UserServiceImpl实现,代码如下:
package com.alibaba.yunos.usersDemo.service.impl;
import com.alibaba.yunos.usersDemo.mapper.UserMapper;
import com.alibaba.yunos.usersDemo.model.User;
import com.alibaba.yunos.usersDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Created by duqi on 15/8/19.
*/
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public User getUser(String userId) {
return this.userMapper.getUser(userId);
}
}
在applicationContext.xml中配置UserServieImpl的实例Bean,由于已经在代码中使用@Autiwired注解,因此不需要在配置文件中显式得规定属性以及提供setter函数。配置代码如下:
6. 修改控制器代码
控制器的逻辑依旧十分简单,就是三个步骤:
1. 调用BLL层的Service接口
2. 设置模型数据
3. 返回逻辑视图名称
修改后的控制器代码如下:
package com.alibaba.yunos.usersDemo.controller;
import com.alibaba.yunos.usersDemo.model.User;
import com.alibaba.yunos.usersDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by duqi on 15/8/19.
*/
@Controller
public class UsersController {
@Autowired
private UserService userService;
@RequestMapping(value = "/showUser",method = RequestMethod.GET)
public String showUser(@RequestParam("id") String id, ModelMap modelMap) {
//1.调用BLL层的服务接口
User user = userService.getUser(id);
//2.设置模型数据
modelMap.put("user",user);
//3.返回逻辑视图名称
return "showUser";
}
}
7. 修改模板代码
在模板中使用数据就像使用真正的java对象的数据一样,我们修改后的模板代码如下:
#if(${user})
${user.NAME}
#else
您查找的用户不存在!
#end
8. 启动Web服务开始测试
(1). http://localhost:8080/usersDemo/showUser?id=8
这次请求的访问结果如图20所示:
(2). http://localhost:8080/usersDemo/showUser?id=1
该URL对应的结果如图21所示:
9. 代码提交
至此,一个Spring+Mybatis+Velocity框架构成的简陋的Demo就完成一个查询功能了,通过SourceTree记录里程碑。
我们在这一步还做了一个调整,将applicationContext.xml调整到src/main/resources文件夹下。对此我的想法是将应用程序配置文件放在resources目录,至于是不是合理,还请各位看官讨论。
六、单元测试Junit
如上所示,一个接口从前端后数据库已经打通了,但是,每次都要等前端页面写好了才能开始测试?这样效率太低了,可不可以将前后端的工作分开,让后端人员能够专注于提供接口,并可以及时测试?可以,单元测试。
由于控制器层是非常薄的一层,负责将传入的URL请求传到BLL层对应的Service实例进行处理。我们可以假定控制器层的代码不需要测试,那么只要Service层保证自己的接口正确就ok。Java中最流行的单元测试框架是Junit,这里探讨如何在Junit的TestCase中自动注入Service实例。
首先在pom.xml中添加测试库支持,配置代码如下:
junit
junit
4.12
org.springframework
spring-test
${spring.version}
第二,在src/test/java下新建包,与src/main下保持一致,在这里我要测试的类是UserServiceImpl,因此新建com.alibaba.yunos.usersDemo.service。
新建测试类UserServiceImplTest,该类的代码如下:
package com.alibaba.yunos.usersDemo.service;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.alibaba.yunos.usersDemo.model.User;
/**
* Created by duqi on 15/8/19.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:/applicationContext.xml")
public class UserServiceImplTest {
@Autowired
private UserService userService;
@Test
public void getUserTest(){
User user = userService.getUser("1");
Assert.assertNotNull(user);
}
}
@RunWith(SpringJUnit4ClassRunner.class)是为Spring 3接入Junit 4框架,从Spring 3开始提供;
@ContextConfiguration("classpath*:/applicationContext.xml")是加载该类中使用的Bean所在的配置文件
七、增加新的接口
根据上文第一到第六步,我们接着给这个Demo增加新的接口:addUser、allUsers和deleteUser。
1. 考虑到新增用户或者删除用户之后需要重定向到"/allUsers"(避免重复提交),我们首先实现allUsers接口。
具体的步骤如下:
(1)修改DAO层
在UserMapper中增加接口getAllUsers,代码如下:
@Select("SELECT * FROM users")
List getAllUsers();
(2)修改Service层
在UserService中增加新的接口getAllUsers,代码如下:
List getAllUsers();
在UserServiceImpl中实现该接口,代码如下:
public List getAllUsers() {
return this.userMapper.getAllUsers();
}
(3)修改Controller
在UserController控制器中增加allUsers接口,代码如下:
@RequestMapping(value ="/allUsers", method = RequestMethod.GET)
public String allUsers(ModelMap modelMap){
List users = userService.getAllUsers();
modelMap.put("users",users);
return "allUsers";
}
(4)增加新的模板文件
在/WEB-INF/templates下增加allUsers.vm文件,内容为:
#if(${users})
#foreach(${user} in ${users})
${user.NAME}
#end
#else
目前没有数据!
#end
重新启动Web服务器,输入URL:http://localhost:8080/usersDemo/allUsers
结果如图22所示: