由于最近工作较轻松,所以想整合一套SpringMVC框架。一来可以记录自己的工作过程,二来可以给读者提供一些帮助。之所以没有用mybatis而是采用了jdbc来操作数据库是因为jdbc要比mybatis快得多,毕竟mybatis对jdbc做了一层包装,尽管这层包装并不厚,但还是足够影响效率的。因为个人并不喜欢在Java程序中写sql语句,所以将sql语句提取到xml中,在项目启动的过程中读取xml,并将每条sql的id存储成静态变量,在程序中直接调用sql对应的静态变量即可。
别的不多说,直接进入正题(以下项目是基于maven环境的)。
一、目录结构
我的目录结构如上图,标准的maven结构,大家或许会注意到我的xml文件中包含mybatis的相关配置,那是因为之前整合mybatis留下的,没有来得及删,本文使用的是jdbc。
二、配置文件详解
首先是jdbc.properties,所在目录为src/main/resources/config/properties/jdbc.properties,里面存储的是jdbc的url、user、password等,内容如下;
#mysql datasource
driverClass=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF- 8&autoReconnect=true&failOverReadOnly=false
jdbc_user=root
jdbc_password=root
与之对应的是property.xml,所在目录为src\main\resources\config\spring\property.xml,用于读取jdbc.properties,代码如下:
<!-- 读取JDBC 配置文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/properties/jdbc.properties</value>
<!-- redis memcached.properties
<value>classpath:jdbc.properties</value>
<value>classpath:jdbc.properties</value>
<value>classpath:jdbc.properties</value>
<value>classpath:jdbc.properties</value>
<value>classpath:jdbc.properties</value>
-->
</list>
</property>
</bean>
接下来是jdbc.xml,所在目录为src/main/resources/config/spring/jdbc.xml,在该项目中datasource使用的是阿里数据源,主要代码如下:
<!-- 配置数据源 Druid -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_user}" />
<property name="password" value="${jdbc_password}" />
<!-- 配置获取连接等待超时的时间 单位是毫秒 -->
<property name="maxWait" value="60000" />
<!-- 配置初始化连接数 -->
<property name="initialSize" value="30" />
<!-- 配置最小存在的连接数 -->
<property name="minIdle" value="10" />
<!-- 配置最大活跃连接数 -->
<property name="maxActive" value="80" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 ***配合最小生存时间,到了指定时间才会检测,关闭空闲连接 如果检测时间大于最小生存时间,连接的生存时间是按检测时间来计算的***
超过该时间没有使用,会被物理性关闭 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 ***到该指定时间后,如果连接没有使用,则会连接池和数据库的连接*** -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 当前连接不活跃时间超过 timeBetweenEvictionRunsMillis 则手动检测当前连接有效性 检测活跃性时,如果当前活跃时间大于
minEvictableIdleTimeMillis 则需要关闭当前连接 -->
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="SELECT 'X'" />
<!-- 确保绝对可用性,将下面两项设为true,但会影响性能 -->
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<!-- 通过dataSource获取的连接必须在 removeAbandonedTimeout 秒内被调用,否则被移除 ***对长时间不使用的连接强制关闭*** -->
<property name="removeAbandoned" value="true" />
<!-- 超过该时间开始关闭空闲连接 单位是秒 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
<property name="filters" value="stat" />
</bean>
代码和注释都很详细,这里我就不多说了。
下面是springmvc配置文件springmvc.xml,在该xml中开启扫描,扫描@controller
<!-- 开启扫描(指定扫描基本包,但只扫描@controller注解,不扫描spring的注解),避免事务出错 -->
<context:component-scan base-package="com.inspur" use-default-filters="false">
<!-- include不同于exclude,它是一定会扫描指定注解,但扫都后不会停下来会继续扫,所以要配置不使用默认过滤器 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
添加视图解释器,用于从controller中返回到页面
<!-- 视图解释器 jspViewResolver 默认支持 jstl -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<!-- 配置前缀 -->
<property name="prefix" value="/WEB-INF/pages/"/>
<!-- 配置后缀 -->
<property name="suffix" value=".jsp"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
</bean>
为了保证DispatcherServlet不拦截以下静态资源,需要设置静态文件访问,如下:
<!--静态文件访问,主要是让DispatcherServlet不拦截以下静态资源-->
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/upload/" mapping="/upload/**"/>
<mvc:resources location="/resource/" mapping="/resource/**"/>
<mvc:resources location="/html/" mapping="/html/**"/>
JDBC操作基类,用于关闭数据库连接
public abstract class BaseJDBCDao{
private static Logger log = Logger.getLogger(BaseJDBCDao.class);
public void closeAllConnection(Connection connection,Statement pstmt,ResultSet rs) {
try {
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}finally {
try {
if(pstmt != null) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}finally{
try {
if(connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
}
}
}
新建SystemConstant类,它用于存储静态变量,它里面的每个静态变量都代表一条sql,代码如下。
public class SystemConstant {
public static String SELECT_ALL_FRIEND;
}
新建StartupListener类,它实现ServletContextListener接口,用于在项目启动初始化上下文时读取存储sql的xml并将其赋值到上面SystemContant类静态变量中,代码如下:
public class StartupListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("-----------");
JDomXml();
}
@SuppressWarnings("unchecked")
public void JDomXml(){
SAXBuilder builder = new SAXBuilder();
Document doc;
try {
doc = builder.build(new File("D://data_10k2.xml"));
Element foo = doc.getRootElement();
List allChildren = foo.getChildren();
for (int i = 0; i < allChildren.size(); i++) {
SystemConstant.SELECT_ALL_FRIEND=((Element) allChildren.get(i)).getChild("selectAllFriend").getText();
}
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上面用到了org.jdom工具,它可以用于解析xml,jar包可以百度到,后面项目源码中也会有。
data_10k2.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<RESULT>
<VALUE>
<selectAllFriend>select * from user</selectAllFriend>
</VALUE>
</RESULT>当然,你也可以将data_10k2.xml放到项目中。
下面是controller、service、dao中的代码,没什么好说的,直接贴:
@Controller
public class TestController {
@Autowired private TestService testService;
private List userList;
@RequestMapping(value="toTestList", method = RequestMethod.GET)
public String toTestList(Model model,Map map, HttpServletRequest request){ userList=testService.getAllFriend();
map.put("userList", userList);
return "jsp/test_list1";
}
}
TestEntity是实体类,根据自己情况来写。test_list1.jsp所在目录为 src\main\webapp\WEB-INF\pages\jsp\test_list1.jsp。
TestServiceImpl中的代码如下:
@Transactional
@Service
public class TestServiceImpl implements TestService{
@Autowired private TestDao testDao;
@Override
public List getAllFriend() {
return testDao.selectAllFriend();
}
}
个人编程习惯将service、dao定义成接口,再定义类实现这些接口。
TestDaoImpl中的代码如下:
public class TestDaoImpl extends BaseJDBCDao implements TestDao{
@Autowired
private DataSource dataSource;
@Override
public List selectAllFriend() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List list=new ArrayList();
TestEntity testEntity=new TestEntity();
try {
conn = dataSource.getConnection();
StringBuilder tempSql = new StringBuilder();
tempSql.append(SystemConstant.SELECT_ALL_FRIEND);
pstmt = conn.prepareStatement(tempSql.toString());
rs = pstmt.executeQuery();
while(rs.next()) {
testEntity.setId(rs.getInt("id"));
testEntity.setUname(rs.getString("uname"));
}
} catch (Exception e) {
list=new ArrayList();
System.out.println(e.getMessage());
} finally {
this.closeAllConnection(conn, pstmt, rs);
}
return list;
}
}
最后,在web.xml中自定义监听类,在项目启动初始化上下文时读取存储sql的xml文件并给系统静态变量赋值。
<!-- 自定义监听器 -->
<listener>
<listener-class>com.inspur.base.StartupListener</listener-class>
</listener>
大功告成!将项目添加到tomcat并启动,输入http://localhost:8080/myframe/toTestList,会出现如下页面。