刚接触编程的时候使用C语言写过一个通讯录,把数据存在本地的文件中,实现体系也比较low,当时完全没有把这个东西作为一个项目来写,在实现的时候也没有项目的层次体系,只是在一个.c文件中实现罢了。后来我使用JDBC尝试把信息储存到数据库里,但是当时自学的JDBC实现起来让我感觉很繁琐,后来也就不了了之了,至于项目构建,结构什么的都没有。
现在我重新实现了这个小小的项目,使用Spring的数据库支持和数据库事务管理,再加上Maven来构建项目,现在这个通讯录才有了一点项目的雏形,先上一部分代码,我来慢慢讲解。
1.项目的结构
首先这是一个Maven项目,实现的代码都在java下的com.dxy.memoapp包中,测试代码放在test下的java目录中。的Spring的三层架构里,因为这个小项目不需要接收用户请求和页面交互,所以就没有Controller层的代码,只需要DAO和Service层的就可以了。
首先,通讯录的信息保存在数据库里,我们必须要使程序和数据库有交互(增删改查),有关增删查改的具体操作统一放在DAO层,其次对于这些操作的业务判断放在Service层。这就是这个小项目的项目结构,接下来一一介绍。
2.Maven配置和Spring资源文件
对于一个Maven项目来说创建项目的时候就应该在pom.xml中配置项目所需的依赖了,下面是我所需要的依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dxy</groupId>
<artifactId>springlist</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- Spring 框架物料清单 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--spring 上下文模块-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!--spring JDBC模块-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!--spring AOP模块-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<!--数据库相关依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
<!--alibaba数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.2</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
基本的Spring配置是必须的,因为要用到Spring事务管理,所以配置一个阿里的数据源,同时配置了事务管理器,然后我们需要自己测试,所以配置了日志的依赖和测试框架的依赖,加入AOP的依赖是因为我们也可以在配置事务管理器的时候使用XML的配置方式。现在正好看一下Spring资源文件中的配置吧。
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--启动注解Bean装配-->
<context:component-scan base-package="com.dxy.memoapp"/>
<!--启动配置文件加载-->
<context:property-placeholder location="classpath:datasource.priperies"/>
<!--启动事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--数据源配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClassName" value="${jdbc.driverClass}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="10"/>
<property name="minIdle" value="10"/>
<property name="maxActive" value="20"/>
<property name="queryTimeout" value="30000"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="10000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="validationQuery" value="SELECT 'x' FROM DUAL"/>
<property name="testWhileIdle" value="true"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。 -->
<property name="poolPreparedStatements" value="false"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
</bean>
<!--配置一个事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--Spring JDBC 模版-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
我们可以采用两种方式来配置事务管理器,我现在采用的是注解的方式,这种方式比较方便,只需要开启事务注解驱动就可以了,现在相当于我们可以在某一层加上注解让事务管理器去进行事务管理。
3.DAO层
DAO层主要进行和数据库交互的操作,是最核心的部分,对于一个通讯录的实现,只需要进行增删改查就可以了。首先定义一个数据访问层的接口,因为是面向接口编程,所以我们要向Service层提供DAO层的接口。对于数据库的操作是DAO层接口的实现类,在DAO层中,我们只需要进行增删查改就可以了,业务的判断处理统统交给Service层。
package com.dxy.memoapp.dao;
import com.dxy.memoapp.entity.ChangeMessage;
import com.dxy.memoapp.entity.Message;
import java.util.List;
//数据层访问接口
public interface MessageDao {
int insetPeople(Message message);//信息插入
List<Message> queryPeopleByName(String name);//查询指定联系人的信息
int updatePeople(ChangeMessage changeMessage);//修改指定联系人的信息
List<Message> queryAllPeople();//列出所有联系人的信息
int deletePeople(int id);//根据id删除联系人信息
}
package com.dxy.memoapp.dao.imp;
import com.dxy.memoapp.entity.ChangeMessage;
import com.dxy.memoapp.entity.Message;
import com.dxy.memoapp.dao.MessageDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@Repository
public class MessageDaoImpl implements MessageDao {
private final Logger logger = LoggerFactory.getLogger(MessageDaoImpl.class);
//开启自动注入
@Autowired
private JdbcTemplate jdbcTemplate;
public int insetPeople(Message message) {//联系人加入
String sql = "INSERT INTO PhoneList (pname, pnumber, address) VALUES (?,?,?)";
return jdbcTemplate.update(sql,message.getName(), message.getNumber(),message.getAddress());
}
public List<Message> queryPeopleByName(String name) {//按名字查找指定联系人的信息
String sql = "SELECT * FROM PhoneList WHERE pname = ?";
List <Message> retMessage = jdbcTemplate.query(sql, new Object[]{name},
new RowMapper<Message>() {
public Message mapRow(ResultSet rs, int rowNum) throws SQLException {
Message message = new Message();
message.setName(rs.getString("pname"));
message.setNumber(rs.getString("pnumber"));
message.setAddress(rs.getString("address"));
return message;
}
});
return retMessage;
}
public int updatePeople(ChangeMessage changeMessage) {//联系人信息修改
String sql = "UPDATE phonelist SET ? = ? WHERE pname = ?;";
int effect = jdbcTemplate.update(sql,changeMessage.getProperty(),
changeMessage.getNewMessage(),changeMessage.getMessage().getName());
return effect;
}
public List<Message> queryAllPeople() {//打印所有人的信息
String sql = "select * from phonelist";
List<Message> messages = jdbcTemplate.query(sql, new
Object[]{}, new
RowMapper<Message>() {
public Message mapRow(ResultSet rs, int rowNum) throws SQLException {
Message message = new Message();
message.setId(rs.getInt("id"));
message.setName(rs.getString("pname"));
message.setNumber(rs.getString("pnumber"));
message.setAddress(rs.getString("address"));
return message;
}
});
logger.debug("query AllPeople result={}", messages);
return messages;
}
public int deletePeople(int id) {
String sql = "DELETE FROM phonelist WHERE id = ?";
return jdbcTemplate.update(sql,id);
}
}
主要的实现代码都在DAO层,我们通过数据库的映射来进行数据库的操作,然后通过注解的方式把实现类注入IOC容器并自动装配JDBCTemplate。最后,我们只需要把接口提供给Service层就可以了。
4.Service层
Service层进行事物的判断和处理,处理完事务之后直接使用DAO层的接口来执行数据库访问的操作。同样的,在Service层中也体现了面向接口编程的思想,有一个接口和一个实现类,把接口传递给测试类,测试类只需要调用Service层对象的方法就可以了。
package com.dxy.memoapp.service;
import com.dxy.memoapp.entity.Message;
import java.util.List;
public interface MessageService {
List<Message> Querypeople(String name);//查询
Boolean AddPeople(Message message);//添加
Boolean DeletePeople(Integer id);//删除
void QueryAllPeople();//打印所有人的信息
Boolean updatePeople(Message message, String property, String NewMassage);//更新联系人
}
package com.dxy.memoapp.service.Imp;
import com.dxy.memoapp.dao.MessageDao;
import com.dxy.memoapp.entity.ChangeMessage;
import com.dxy.memoapp.entity.Message;
import com.dxy.memoapp.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class MessageServiceImp implements MessageService {
@Autowired
private MessageDao messageDao;//自动注入数据访问层对象
public List<Message> Querypeople(String name) {//业务层联系人查询实现
if (name == null) {
throw new RuntimeException("name is null");
}
List<Message> message = messageDao.queryPeopleByName(name);
if (message.isEmpty()) {
throw new IllegalArgumentException("Id=" + name + " not found");
}
return message;
}
public Boolean AddPeople(Message message) {
if (message == null) {
throw new IllegalArgumentException("Message arguments error, please check");
}
int effect = messageDao.insetPeople(message);
return effect == 1;
}
public Boolean DeletePeople(Integer id) {
if(id <= 0){
throw new RuntimeException("id is not allowed there");
}
int effect = messageDao.deletePeople(id);
return effect == 1;
}
public void QueryAllPeople() {
messageDao.queryAllPeople();
}
public Boolean updatePeople(Message message, String property, String NewMassage) {
if(message == null){
throw new RuntimeException("didnt find people who need to update");
}
ChangeMessage changeMessage = new ChangeMessage();
changeMessage.setMessage(message);
changeMessage.setProperty(property);
changeMessage.setNewMessage(NewMassage);
int effect = messageDao.updatePeople(changeMessage);
return effect == 1;
}
}
在Service层的实现类上增加了@Transactional注解,现在这个实现类已经被事务管理器所管理了,同时实现类里自动注入了DAO层的接口,在处理完业务的时候可以直接进入DAO层进行数据访问的操作。这个项目所需要的事务处理并不是很多,所以比较简单。
5.测试
测试的类全都放在test的java目录下的包中,我们在pom.xml文件中导入了测试的依赖,所以可以直接使用测试框架。
package com.dxy.test;
import com.dxy.memoapp.entity.Message;
import com.dxy.memoapp.service.MessageService;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class listApp_Test {
private static ApplicationContext context = null;
private static MessageService memoGroupService = null;
private static Logger logger = LoggerFactory.getLogger(listApp_Test.class);
@BeforeClass
public static void BeforeTest(){
context = new ClassPathXmlApplicationContext("application-context.xml");
memoGroupService = context.getBean(MessageService.class);
}
@Test
public void Test_AddPeople(){
Message NeedToAdd = new Message();
NeedToAdd.setName("78s9");
NeedToAdd.setNumber("13892");
NeedToAdd.setAddress("7777777");
Boolean ret = memoGroupService.AddPeople(NeedToAdd);
Assert.assertTrue(ret);
}
@Test
public void Test_QueryPeople(){
String name = "7777";
List<Message> ret = memoGroupService.Querypeople(name);
Assert.assertNotNull(ret);
logger.debug("query people:{}", ret);
}
@Test
public void Test_DeletePeople(){
Integer id = 4;
Boolean ret = memoGroupService.DeletePeople(id);
logger.debug("delete is {}",ret);
}
@Test
public void Test_QueryAllPeople(){
memoGroupService.QueryAllPeople();
}
@Test
public void Test_updatePeople(){
Message message = memoGroupService.Querypeople("55554").get(0);
memoGroupService.updatePeople(message, "pname","www");
}
}
测试添加联系人
测试删除联系人
测试联系人查找
联系人更新
以上就是基于Spring的一个通讯录小项目的实现,仅供自己学习Spring使用。