目录
1 目录结构
2 全局配置文件
2.1 application.properties(resources下,自动生成)
2.2 mybatis-config.xml(resources下,手动创建)
2.3 config文件夹(java包下,手动创建)
2.3.1 mapper文件夹
2.3.2 service文件夹
3 代码流程
3.1 第一步:Entity层
3.2 第二步:Dao层
3.3 第三步:Mapper配置文件
3.4 第四部:测试Dao层类
3.4 第五步:service层
3.5 第六步:controller层
4 运行效果
1 目录结构
注意:
1)Java包下的子文件夹需要手动创建
2)resources下的mapper文件夹和mybatis-config.xml文件需要手动创建。
2 全局配置文件
全局配置文件主要包括数据库配置、服务端口配置、事务配置等。
2.1 application.properties(resources下,自动生成)
application.properties是全局配置文件,通过修改此文件可以实现自定义配置,如端口、根路径等。
本模板仅配置数据源配置,配置如下:
#DataSource #数据库驱动(高版本mysql配置) jdbc.driver=com.mysql.cj.jdbc.Driver #数据库链接(高版本mysql配置) jdbc.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT #数据库用户名 jdbc.username=root #数据库密码 jdbc.password=1234 #Mybatis mybatis_config_file=mybatis-config.xml mapper_path=/mapper/**.xml # 要与包名一致 type_alias_package=com.example.demo.entity
2.2 mybatis-config.xml(resources下,手动创建)
此文件需要手动创建。名称可以自定义,需要与application.properties中一致。
配置如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置全局属性 --> <settings> <!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 --> <setting name="useGeneratedKeys" value="true" /> <!-- 使用列标签替换列别名 默认:true --> <setting name="useColumnLabel" value="true" /> <!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} --> <setting name="mapUnderscoreToCamelCase" value="true" /> </settings> </configuration>
2.3 config文件夹(java包下,手动创建)
本项目中,config文件夹下包含两个子文件夹mapper和service
2.3.1 mapper文件夹
mapper文件夹中为数据源的相关配置,主要实现全局配置文件Application.properties中的配置生效。
1)DataSourceConfiguration(数据配置类)
代码如下:
package com.example.demo.config.mapper;
import java.beans.PropertyVetoException;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 配置datasource到ioc容器里面
*
* @author xiangze
*
*/
@Configuration
// 配置mybatis mapper的扫描路径
@MapperScan("com.example.demo.dao")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String jdbcDriver;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
/**
* 生成与spring-dao.xml对应的bean dataSource
*
* @return
* @throws PropertyVetoException
*/
@Bean(name = "dataSource")
public ComboPooledDataSource createDataSource() throws PropertyVetoException {
// 生成datasource实例
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 跟配置文件一样设置以下信息
// 驱动
dataSource.setDriverClass(jdbcDriver);
// 数据库连接URL
dataSource.setJdbcUrl(jdbcUrl);
// 设置用户名
dataSource.setUser(jdbcUsername);
// 设置用户密码
dataSource.setPassword(jdbcPassword);
// 配置c3p0连接池的私有属性
// 连接池最大线程数
dataSource.setMaxPoolSize(30);
// 连接池最小线程数
dataSource.setMinPoolSize(10);
// 关闭连接后不自动commit
dataSource.setAutoCommitOnClose(false);
// 连接超时时间
dataSource.setCheckoutTimeout(10000);
// 连接失败重试次数
dataSource.setAcquireRetryAttempts(2);
return dataSource;
}
}
2)SessionFactoryConfiguration(数据库连接池配置类)
代码如下:
package com.example.demo.config.mapper; import java.io.IOException; import javax.sql.DataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @Configuration public class SessionFactoryConfiguration { // mybatis-config.xml配置文件的路径 private static String mybatisConfigFile; @Value("${mybatis_config_file}") public void setMybatisConfigFile(String mybatisConfigFile) { SessionFactoryConfiguration.mybatisConfigFile = mybatisConfigFile; } // mybatis mapper文件所在路径 private static String mapperPath; @Value("${mapper_path}") public void setMapperPath(String mapperPath) { SessionFactoryConfiguration.mapperPath = mapperPath; } // 实体类所在的package @Value("${type_alias_package}") private String typeAliasPackage; @Autowired private DataSource dataSource; /** * 创建sqlSessionFactoryBean 实例 并且设置configtion 设置mapper 映射路径 设置datasource数据源 * * @return * @throws IOException */ @Bean(name = "sqlSessionFactory") public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); // 设置mybatis configuration 扫描路径 sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFile)); // 添加mapper 扫描路径 PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath; sqlSessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources(packageSearchPath)); // 设置dataSource sqlSessionFactoryBean.setDataSource(dataSource); // 设置typeAlias 包扫描路径 sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasPackage); return sqlSessionFactoryBean; } }
2.3.2 service文件夹
1)TransactionManagementConfiguration(事务配置类)
代码如下:
package com.example.demo.config.service; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.TransactionManagementConfigurer; /** * 对标spring-service里面的transactionManager * 继承TransactionManagementConfigurer是因为开启annotation-driven * * @author xiangze * */ @Configuration // 首先使用注解 @EnableTransactionManagement 开启事务支持后 // 在Service方法上添加注解 @Transactional 便可 @EnableTransactionManagement public class TransactionManagementConfiguration implements TransactionManagementConfigurer { @Autowired // 注入DataSourceConfiguration里边的dataSource,通过createDataSource()获取 private DataSource dataSource; @Override /** * 关于事务管理,需要返回PlatformTransactionManager的实现 */ public PlatformTransactionManager annotationDrivenTransactionManager() { return new DataSourceTransactionManager(dataSource); } }
3 代码流程
编写代码的顺序,便于快速实现和测试。
3.1 第一步:Entity层
实体类层,需要提前建立数据库、数据表并添加实例数据。
代码如下:
package com.example.demo.entity; import java.util.Date; /** * 区域信息 * @author xiangze * */ public class Area { // 主键ID private Integer areaId; // 名称 private String areaName; // 权重,越大越排前显示 private Integer priority; // 创建时间 private Date createTime; // 更新时间 private Date lastEditTime; public Integer getAreaId() { return areaId; } public void setAreaId(Integer areaId) { this.areaId = areaId; } public String getAreaName() { return areaName; } public void setAreaName(String areaName) { this.areaName = areaName; } public Integer getPriority() { return priority; } public void setPriority(Integer priority) { this.priority = priority; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getLastEditTime() { return lastEditTime; } public void setLastEditTime(Date lastEditTime) { this.lastEditTime = lastEditTime; } }
3.2 第二步:Dao层
编写接口,代码如下:
package com.example.demo.dao; import java.util.List; import com.example.demo.entity.Area; public interface AreaDao { /** * 列出区域列表 * * @return areaList */ List<Area> queryArea(); /** * 根据Id列出具体区域 * * @return area */ Area queryAreaById(int areaId); /** * 插入区域信息 * * @param area * @return */ int insertArea(Area area); /** * 更新区域信息 * * @param area * @return */ int updateArea(Area area); /** * 删除区域信息 * * @param areaId * @return */ int deleteArea(int areaId); }
3.3 第三步:Mapper配置文件
编写Dao层中的SQL语句,代码如下:
<?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"> <mapper namespace="com.example.demo.dao.AreaDao"> <select id="queryArea" resultType="com.example.demo.entity.Area"> SELECT area_id, area_name, priority, create_time, last_edit_time FROM tb_area ORDER BY priority DESC </select> <select id="queryAreaById" resultType="com.example.demo.entity.Area"> SELECT area_id, area_name, priority, create_time, last_edit_time FROM tb_area WHERE area_id=#{areaId} </select> <insert id="insertArea" useGeneratedKeys="true" keyProperty="areaId" keyColumn="area_id" parameterType="com.example.demo.entity.Area"> INSERT INTO tb_area(area_name,priority, create_time,last_edit_time) VALUES (#{areaName},#{priority}, #{createTime},#{lastEditTime}) </insert> <update id="updateArea" parameterType="com.example.demo.entity.Area"> update tb_area <set> <if test="areaName != null">area_name=#{areaName},</if> <if test="priority != null">priority=#{priority},</if> <if test="lastEditTime != null">last_edit_time=#{lastEditTime}</if> </set> where area_id=#{areaId} </update> <delete id="deleteArea"> DELETE FROM tb_area WHERE area_id = #{areaId} </delete> </mapper>
3.4 第四部:测试Dao层类
测试Dao类是否可以正常操作数据库。代码如下:
idea下快捷方式:选中Dao类名,按Alt+Insert(先按Alt再按Insert),勾选要测试的类。具体测试方法需要手动编写。
package com.example.demo.dao; import static org.junit.Assert.assertEquals; import java.util.Date; import java.util.List; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import com.example.demo.entity.Area; @RunWith(SpringRunner.class) @SpringBootTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) // 按方法名大小升序执行 public class AreaDaoTest { //通过spring容器注入Dao的实现类 @Autowired private AreaDao areaDao; @Test public void testAQueryArea() { List<Area> areaList = areaDao.queryArea(); // 验证预期值和实际值是否相符 assertEquals(2, areaList.size()); } @Test public void testBInsertArea() { //创建一个区域对象 Area area = new Area(); area.setAreaName("测试区域"); area.setCreateTime(new Date()); area.setPriority(1); //将该对象实例添加入库 int effectedNum = areaDao.insertArea(area); //检测影响行数 assertEquals(1, effectedNum); //校验总数是否+1 List<Area> areaList = areaDao.queryArea(); assertEquals(3, areaList.size()); } @Test public void testCQueryAreaById() { Area area = areaDao.queryAreaById(2); assertEquals("东苑", area.getAreaName()); } @Test public void testDUpateArea() { List<Area> areaList = areaDao.queryArea(); for (Area area : areaList) { if ("测试区域".equals(area.getAreaName())) { // 对比之前的priority值 assertEquals(1, area.getPriority().intValue()); area.setPriority(2); int effectedNum = areaDao.updateArea(area); assertEquals(1, effectedNum); } } } @Test public void testEDeleteArea() { List<Area> areaList = areaDao.queryArea(); for (Area area : areaList) { if ("测试区域".equals(area.getAreaName())) { int effectedNum = areaDao.deleteArea(area.getAreaId()); assertEquals(1, effectedNum); } } // 重新获取一次列表,看看总数是否少1 areaList = areaDao.queryArea(); assertEquals(2, areaList.size()); } }
3.5 第四步:service层
调用Dao层中的类实现业务逻辑,先写接口再实现,目录结构如下:
代码如下:
1)接口代码
package com.example.demo.service; import java.util.List; import com.example.demo.entity.Area; public interface AreaService { /** * 获取区域列表 * * @return */ List<Area> getAreaList(); /** * 通过区域Id获取区域信息 * * @param areaId * @return */ Area getAreaById(int areaId); /** * 增加区域信息 * * @param area * @return */ boolean addArea(Area area); /** * 修改区域信息 * * @param area * @return */ boolean modifyArea(Area area); /** * 删除区域信息 * * @return */ boolean deleteArea(int areaId); }
2)实现类代码
package com.example.demo.service.Impl; import java.io.IOException; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.example.demo.dao.AreaDao; import com.example.demo.entity.Area; import com.example.demo.service.AreaService; @Service public class AreaServiceImpl implements AreaService { @Autowired private AreaDao areaDao; @Override public List<Area> getAreaList() { // 返回所有的区域信息 return areaDao.queryArea(); } @Override public Area getAreaById(int areaId) { return areaDao.queryAreaById(areaId); } @Transactional @Override public boolean addArea(Area area) { // 空值判断,主要是判断areaName不为空 if (area.getAreaName() != null && !"".equals(area.getAreaName())) { // 设置默认值 area.setCreateTime(new Date()); area.setLastEditTime(new Date()); try { int effectedNum = areaDao.insertArea(area); if (effectedNum > 0) { return true; } else { throw new RuntimeException("添加区域信息失败!"); } } catch (Exception e) { throw new RuntimeException("添加区域信息失败:" + e.toString()); } } else { throw new RuntimeException("区域信息不能为空!"); } } @Transactional @Override public boolean modifyArea(Area area) { // 空值判断,主要是areaId不为空 if (area.getAreaId() != null && area.getAreaId() > 0) { // 设置默认值 area.setLastEditTime(new Date()); try { // 更新区域信息 int effectedNum = areaDao.updateArea(area); if (effectedNum > 0) { return true; } else { throw new RuntimeException("更新区域信息失败!"); } } catch (Exception e) { throw new RuntimeException("更新区域信息失败:" + e.toString()); } } else { throw new RuntimeException("区域信息不能为空!"); } } @Transactional @Override public boolean deleteArea(int areaId) { if (areaId > 0) { try { // 删除区域信息 int effectedNum = areaDao.deleteArea(areaId); if (effectedNum > 0) { return true; } else { throw new RuntimeException("删除区域信息失败!"); } } catch (Exception e) { throw new RuntimeException("删除区域信息失败:" + e.toString()); } } else { throw new RuntimeException("区域Id不能为空!"); } } }
3.6 第五步:controller层
controller负责接收请求和响应。
代码如下:
package com.example.demo.controller; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.example.demo.entity.Area; import com.example.demo.service.AreaService; @RestController public class AreaController { @Autowired private AreaService areaService; /** * 获取所有的区域信息 * * @return */ @RequestMapping(value = "/listarea", method = RequestMethod.GET) private Map<String, Object> listArea() { Map<String, Object> modelMap = new HashMap<String, Object>(); List<Area> list = new ArrayList<Area>(); // 获取区域列表 list = areaService.getAreaList(); modelMap.put("areaList", list); return modelMap; } /** * 通过区域Id获取区域信息 * * @return */ @RequestMapping(value = "/getareabyid", method = RequestMethod.GET) private Map<String, Object> getAreaById(Integer areaId) { Map<String, Object> modelMap = new HashMap<String, Object>(); // 获取区域信息 Area area = areaService.getAreaById(areaId); modelMap.put("area", area); return modelMap; } /** * 添加区域信息 * * @param area * @return * @throws IOException * @throws JsonMappingException * @throws JsonParseException */ @RequestMapping(value = "/addarea", method = RequestMethod.POST) private Map<String, Object> addArea(@RequestBody Area area) throws JsonParseException, JsonMappingException, IOException { Map<String, Object> modelMap = new HashMap<String, Object>(); // 添加区域信息 modelMap.put("success", areaService.addArea(area)); return modelMap; } /** * 修改区域信息,主要修改名字 * * @param area * @return * @throws IOException * @throws JsonMappingException * @throws JsonParseException */ @RequestMapping(value = "/modifyarea", method = RequestMethod.POST) private Map<String, Object> modifyArea(@RequestBody Area area) throws JsonParseException, JsonMappingException, IOException { Map<String, Object> modelMap = new HashMap<String, Object>(); // 修改区域信息 modelMap.put("success", areaService.modifyArea(area)); return modelMap; } @RequestMapping(value = "/removearea", method = RequestMethod.GET) private Map<String, Object> removeArea(Integer areaId) { Map<String, Object> modelMap = new HashMap<String, Object>(); System.out.println(areaId); // 修改区域信息 modelMap.put("success", areaService.deleteArea(areaId)); return modelMap; } }
4 运行效果