【系列】使用springmvc+mybatis创建Web应用(二)—— 数据库、配置和测试
2017-03-18 10:36
696 查看
上一篇文章简单地介绍了如何从零开始构建一个Spring MVC应用,如果我们仅仅需要做一些静态页面或者数据不变化的Web应用,那么其实这样就足够了。这当然是不现实的,我们的页面中的数据需要不断地变化,不同的用户登录进来之后应用只能看到属于自己的数据,诸如此类的需求告诉我们原本的代码框架是不够的。
对于一个功能相对齐整的Web应用,除了上一篇文章中介绍的代码框架,还需要:
连接和操作数据库
配置文件
单元测试(虽然可以省略,但还是建议保留)
接下来的内容就介绍上面所列举的内容,以期能创建一个比较完整的Web应用框架。
在项目中使用连接池是非常有必要,主要有以下好处:
减少连接创建时间
简化的编程模式
受控的资源使用
Java中有以下常用的开源连接池:
C3P0
DBCP
Proxool
在本文中将使用C3P0来作为数据库连接池组件,并且用Spring来管理C3P0。为了使用Spring来管理应用中的所有组件,我们先在Web.xml文件中配置下面的代码,使得Spring的上下文(context)文件能够随着应用一块启动。
插个题外话,注意Spring的上下文配置的路径为:
classpath表示一个绝对路径,但不是一个固定值。它是编译完毕后存放xxx.class文件的最顶层目录所对应的路径。譬如使用Maven编译之后通常(如果没有手动修改Maven配置)会将编译后的class文件放置在target\classes目录下,于是
在
数据表User的结构如下:
笔者使用的是mysql数据库,sql语句如下:
在【mybatis SqlSessionFactory配置】配置项中,指定了mybatis的Mapper文件所在的位置(
在
接着创建一个
最后创建UserMapper所对应的Mapper文件(UserMapper.xml),mybatis会根据这个文件生成这个接口的一个实现类。
首先,创建一个User控制器(UserController.java)。
然后,创建对应的jsp页面来显示结果。
登录页面:
登录成功页面:
登录失败页面:
使用Jetty启动应用,在浏览器中输入
比较推荐的方法是将这些常量集中写到一个常量配置文件中。Java中默认的配置文件后缀是
首先,在
在
同时,修改
这样在spring容器启动时,会用配置文件中的值替换掉对应的表达式。
使用springmvc+mybatis创建Web应用(一)—— 相关概念,工具,搭建Web应用
Github地址:https://github.com/xialei199023/springmvc-mybati-webapp
本文由xialei原创,转载请说明出处http://hinylover.space/2016/04/11/springmvc-mybatis-createproject-demo-2/。
对于一个功能相对齐整的Web应用,除了上一篇文章中介绍的代码框架,还需要:
连接和操作数据库
配置文件
单元测试(虽然可以省略,但还是建议保留)
接下来的内容就介绍上面所列举的内容,以期能创建一个比较完整的Web应用框架。
使用Mybatis操作数据库
上一篇文章中已经简单地介绍过了Mybatis中的基本概念,下面直接进入实战环节。由于要依赖第三方的工具包,pom.xml文件中需要新添加依赖如下:<!-- database --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- test --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>0.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path-assert</artifactId> <version>0.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.9.5</version> <scope>test</scope> <exclusions> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency> <!-- test end -->
JDBC连接池
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。在项目中使用连接池是非常有必要,主要有以下好处:
减少连接创建时间
简化的编程模式
受控的资源使用
Java中有以下常用的开源连接池:
C3P0
DBCP
Proxool
在本文中将使用C3P0来作为数据库连接池组件,并且用Spring来管理C3P0。为了使用Spring来管理应用中的所有组件,我们先在Web.xml文件中配置下面的代码,使得Spring的上下文(context)文件能够随着应用一块启动。
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
插个题外话,注意Spring的上下文配置的路径为:
classpath:applicationContext.xml。在笔者刚开始学习Java的很长一段时间里,都不太明白什么是classpath,以致于常常取不到资源文件。
classpath表示一个绝对路径,但不是一个固定值。它是编译完毕后存放xxx.class文件的最顶层目录所对应的路径。譬如使用Maven编译之后通常(如果没有手动修改Maven配置)会将编译后的class文件放置在target\classes目录下,于是
classpath表示的绝对路径为:
工程根路径\target\classes\。所以,本文中的Spring的上下文配置文件的绝对路径为:
工程根路径\target\classes\applicationContext.xml
在
src/main/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" xmlns:tx="http://www.springframework.org/schema/tx" 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-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- 配置数据连接池(C3P0) --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8" /> <property name="user" value="test" /> <!-- 数据库用户名 --> <property name="password" value="test" /> <!-- 数据库密码 --> <property name="maxPoolSize" value="10" /> <property name="minPoolSize" value="1" /> <property name="initialPoolSize" value="2" /> <property name="maxIdleTime" value="20" /> <property name="acquireIncrement" value="3" /> <property name="idleConnectionTestPeriod" value="60" /> <property name="unreturnedConnectionTimeout" value="190" /> <property name="checkoutTimeout" value="20000" /> <property name="acquireRetryAttempts" value="30" /> </bean> <!-- 配置数据库事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
数据库表
Mybatis的主要功能是将Mapper配置映射成对应的sql语句并执行。在介绍Mybatis的配置之前,先创建一个简单的数据表作为数据示例。数据表User的结构如下:
字段 | 类型 | 索引 | 字段含义 |
---|---|---|---|
username | varchar(50) | 主键 | 用户名 |
password | varchar(50) | 密码 | |
role | int | 用户角色 |
CREATE DATABASE test; USE test; CREATE TABLE `test`.`User`( `username` VARCHAR(50) COMMENT '用户名', `password` VARCHAR(50) COMMENT '密码', `role` INT COMMENT '角色' ) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci; INSERT INTO User VALUES("test", "test", 1); # 插入一条记录
Mybatis配置
在src/main/resources资源文件夹中创建一个
spring-mybatis.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-3.0.xsd"> <!-- mybatis SqlSessionFactory配置 --> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath:/mapper/*.xml" /> </bean> <!-- Mapper 扫描配置 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sessionFactory" /> <property name="basePackage" value="demo.dao" /> </bean> </beans>
在【mybatis SqlSessionFactory配置】配置项中,指定了mybatis的Mapper文件所在的位置(
classpath:/mapper/*.xml)。于是,在
src/main/resources资源文件夹创建一个mapper子目录,将所有的Mapper文件放置在这个文件夹下。
在
applicationContext.xml文件中引入
spring-mybatis.xml,使其加入spring的管理容器中。
<import resource="classpath:spring-mybatis.xml"/>
Dao接口和Mapper配置
首先创建一个demo.model包,在这个包下创建一个名为User的类。这个类的字段与上面设计的数据表里面的字段是一一对应的。
package demo.model; /** * 数据模型,与数据库表里面的字段对应。 * @author xialei * */ public class User { private String username; private String password; private Integer role; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getRole() { return role; } public void setRole(Integer role) { this.role = role; } }
接着创建一个
demo.dao包,在这个包下创建一个名为UserMapper的类。这个类的作用是定义一系列数据操作方法。
package demo.dao; import org.apache.ibatis.annotations.Param; import demo.model.User; public interface UserMapper { /** * 访问数据库,检查用户名和密码输入是否正确。 * @param username * @param password * @return */ public User check(@Param("username") String username, @Param("password") String password); }
最后创建UserMapper所对应的Mapper文件(UserMapper.xml),mybatis会根据这个文件生成这个接口的一个实现类。
<?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" > <!-- demo.dao.UserMapper与UserMapper定义路径一致 --> <mapper namespace="demo.dao.UserMapper" > <!-- demo.model.User与User的定义路径一致,下面是Java对象与数据库字段的映射关系。 --> <resultMap id="BaseResultMap" type="demo.model.User" > <id column="username" property="username" jdbcType="VARCHAR" /> <result column="password" property="password" jdbcType="VARCHAR" /> <result column="role" property="role" jdbcType="TINYINT" /> </resultMap> <sql id="Base_Column_List" > username, password, role </sql> <!-- id必须与UserMapper中定义的方法名一致。 --> <select id="check" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from user where username = #{username,jdbcType=VARCHAR} and password = #{password,jdbcType=VARCHAR} </select> </mapper>
示例
为了测试整个框架是否已经打好,我们写一个测试页面来测试一下,就用最常用的登录功能来验证。首先,创建一个User控制器(UserController.java)。
package demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import demo.dao.UserMapper; import demo.model.User; @Controller public class UserController { @Autowired private UserMapper userMapper; @RequestMapping("/login") public String login() { return "login"; } @RequestMapping("/dologin") public ModelAndView doLogin(String username, String password) { User user = this.userMapper.check(username, password); if (user == null) { return new ModelAndView("error"); } else { ModelAndView modelAndView = new ModelAndView("success"); modelAndView.addObject("username", username); return modelAndView; } } }
然后,创建对应的jsp页面来显示结果。
登录页面:
login.jsp,文件路径为:
src/main/webapp/WEB-INF/jsp/login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html > <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>登录</title> </head> <body> <form action="${pageContext.servletContext.contextPath}/dologin" method="post"> 用户名:<input name="username" type="text" > 密码:<input name="password" type="password"> <button type="submit">登录</button> </form> </body> </html>
登录成功页面:
success.jsp,文件路径为:
src/main/webapp/WEB-INF/jsp/success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html > <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>登录成功</title> </head> <body> 登录成功!您的用户名为:<%=request.getParameter("username")%> </body> </html>
登录失败页面:
error.jsp,文件路径为:
src/main/webapp/WEB-INF/jsp/error.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html > <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>登录失败</title> </head> <body> 登录失败,用户名或密码错误。 </body> </html>
使用Jetty启动应用,在浏览器中输入
http://localhost:8080/login进入登录界面。如果输入正确的用户名和密码(test/test),则跳入success.jsp对应的页面,输入其他信息,则跳入error.jsp对应的页面。
使用配置文件
通常系统中存在常量(数据库连接URL、用户名、密码等),这些常量如果直接嵌入到Java代码中,则一旦代码编译完毕后就无法更改,如需更改则只能在源代码中改完后重新编译。当然,如果像上面一样,写在诸如applicationContext.xml的xml文件中也是可以的。但是如果这样的文件很多,找起来就会比较困难。
比较推荐的方法是将这些常量集中写到一个常量配置文件中。Java中默认的配置文件后缀是
.properties,下面就将常量移入配置文件中。
首先,在
applicationContext.xml中加入下面的代码,表示用配置文件中的值来替换掉
applicationContext.xml中的变量引用表达式。
<context:property-placeholder location="classpath:config.properties"/>
在
src/main/resources文件夹中创建
config.properties配置文件,加入如下代码:
# ------------------ Data source ---------------- dataSource.pool.driverClass=com.mysql.jdbc.Driver dataSource.pool.jdbcUrl=jdbc:mysql://localhost:3306/test?characterEncoding=utf8 dataSource.pool.user=test dataSource.pool.password=test dataSource.pool.maxPoolSize=10 dataSource.pool.minPoolSize=1 dataSource.pool.initialPoolSize=2 dataSource.pool.maxIdleTime=20 dataSource.pool.acquireIncrement=3 dataSource.pool.idleConnectionTestPeriod=60 dataSource.pool.unreturnedConnectionTimeout=190 dataSource.pool.checkoutTimeout=20000 dataSource.pool.acquireRetryAttempts=30
同时,修改
applicationContext.xml文件代码,使用EL表达式来引用这些配置项的值。
<!-- 配置数据连接池(C3P0) --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${dataSource.pool.driverClass}" /> <property name="jdbcUrl" value="${dataSource.pool.jdbcUrl}" /> <property name="user" value="${dataSource.pool.user}" /> <property name="password" value="${dataSource.pool.password}" /> <property name="maxPoolSize" value="${dataSource.pool.maxPoolSize}" /> <property name="minPoolSize" value="${dataSource.pool.minPoolSize}" /> <property name="initialPoolSize" value="${dataSource.pool.initialPoolSize}" /> <property name="maxIdleTime" value="${dataSource.pool.maxIdleTime}" /> <property name="acquireIncrement" value="${dataSource.pool.acquireIncrement}" /> <property name="idleConnectionTestPeriod" value="${dataSource.pool.idleConnectionTestPeriod}" /> <property name="unreturnedConnectionTimeout" value="${dataSource.pool.unreturnedConnectionTimeout}" /> <property name="checkoutTimeout" value="${dataSource.pool.checkoutTimeout}" /> <property name="acquireRetryAttempts" value="${dataSource.pool.acquireRetryAttempts}" /> </bean>
这样在spring容器启动时,会用配置文件中的值替换掉对应的表达式。
单元测试
在Java体系中,JUnit无疑是最强大的单元测试工具,这里就不介绍JUnit的使用了。Spring管理的应用中,依赖关系比较复杂,而且有时会有隐蔽性,单纯的JUnit恐怕很难进行测试。下文介绍专门用于Spring应用单元测试的spring-test组件,以及用于Web应用测试的mock组件的简单使用。简单的测试
Maven中,通常将所有的测试用例写在src/test/java源文件夹下。下面的代码测试UserMapper这个类,这仅仅是一个样例,介绍如何使用spring-test进行测试而已,测试用例并具有可参考性。
package demo.test.dao; 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 demo.dao.UserMapper; import demo.model.User; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testDoLoginWrong() { User user = this.userMapper.check("eroor", "error"); Assert.assertNull(user); } @Test public void testDoLoginRight() { User user = this.userMapper.check("test", "test"); Assert.assertNotNull(user); } }
web测试
进行web测试时,需要模拟HTTP请求。使用spring-test无需将Web应用部署到服务器就可以进行测试,非常方便实用。下面是一个示例,更多的关于spring-test的知识可以看这篇博文。package demo.test.controller; import org.junit.Assert; import org.junit.Before; 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 org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; /** * * @author xialei * */ @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration("src/main/webapp") @ContextConfiguration(locations = {"classpath:applicationContext.xml", "file:src/main/webapp/WEB-INF/dispatch-servlet.xml"}) @EnableWebMvc public class UserControllerTest { @Autowired private WebApplicationContext wac; protected MockMvc mockMvc; @Before public void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void testDoLogin() throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/dologin").param("username", "test").param("password", "test")) .andDo(MockMvcResultHandlers.print()).andReturn(); String viewName = mvcResult.getModelAndView().getViewName(); Assert.assertEquals("success", viewName); String value = (String)mvcResult.getModelAndView().getModelMap().get("username"); Assert.assertEquals("test", value); } @Test public void testDoLoginIllegalInput() throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/dologin").param("username", "error").param("password", "error")) .andDo(MockMvcResultHandlers.print()).andReturn(); String viewName = mvcResult.getModelAndView().getViewName(); Assert.assertEquals("error", viewName); } }
总结
关于使用SpringMVC+Mybatis来创建一个Web应用系列已经写完了。文章从无到有地创建了一个Web应用,知识点讲得不太细,旨在梳理创建整个应用过程中涉及到的概念、组件。阅读本系列文章可以了解到创建一个基于SpringMVC+Mybatis的Web应用是如何一步一步地搭建起来的,虽然示例比较简单,基本停留在Demo级别,但还是比较完整的。在今后创建类似Web应用时,可以直接拿来做代码骨架。使用springmvc+mybatis创建Web应用(一)—— 相关概念,工具,搭建Web应用
Github地址:https://github.com/xialei199023/springmvc-mybati-webapp
本文由xialei原创,转载请说明出处http://hinylover.space/2016/04/11/springmvc-mybatis-createproject-demo-2/。
相关文章推荐
- 【系列】使用springmvc+mybatis创建Web应用(一)—— 相关概念,工具,搭建Web应用
- jeesite项目使用-多数据库配置【Spring mvc + Mybatis】
- Intellij IDEA使用(十二)—— 使用Intellij IDEA导入Eclipse创建的Spring+SpringMVC+Mybatis(SSM)整合项目并修改相关配置
- springmvc+mybatis主从数据库的配置
- Eclipse使用(八)—— 使用Eclipse创建Spring+SpringMVC+Mybatis(SSM)整合项目
- IDEA17用Maven创建SpringMVC+Spring+Mybatis工程及整合配置与实例
- 使用Idea创建ssm项目,SpringMVC+Spring+MyBatis+Maven整合
- springboot+springmvc+mybatis 使用注解对数据库的增、改和查操作
- springMVC+mybatis+spring security<三>:使用数据库管理资源
- 使用Idea创建ssm项目,SpringMVC+Spring+MyBatis+Maven整合
- 使用Idea创建ssm项目,SpringMVC+Spring+MyBatis+Maven整合
- Spring+SpringMVC+Mybatis使用注解方式配置双数据源
- SpringBoot系列三:SpringBoot基本概念(统一父 pom 管理、SpringBoot 代码测试、启动注解分析、配置访问路径、使用内置对象、项目打包发布)
- 【虫师--系列】使用JMeter创建数据库(Mysql)测试
- J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现
- 使用maven创建java web项目+SpringMVC+Mybatis
- 关于CKEditor4.5.6的使用,自定义toolbar配置,上传图片案例(SpringMVC+MyBatis案例),自定义行高,去编辑器的中内容,将编辑器中内容设置到指定的位置等
- ehcache配置:使用Spring+SpringMVC+Mybatis或者有shiro【转】
- ehcache配置:使用Spring+SpringMVC+Mybatis或者有shiro【转】
- SpringMVC+Spring+MyBatis 的综合练习 10 (使用 Spring 测试 DAO)