1 Spring框架搭建
1.1 下载Eclipse的SpringBoot插件
点击菜单栏的Help->Eclipse Marketplace,选中popular页签,安装Spring Tool插件
安装完成后可以在新建向导中看到Spring Boot的目录
1.2 创建项目
通过新建Spring Starter Project创建项目,选择MyBatis与Web组件,可以在生成的pom文件中将mybatis的依赖注释掉。
生成的MyFirstDemoApplication为项目启动入口,通过
@SpringBootApplication
注解来标识
@SpringBootApplication
public class MyFirstDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyFirstDemoApplication.class, args);
}
}
创建hello类,@RestController
表示该类为controller,其中匹配的路径及方法通过@RequestMapping
注解来配置
@RestController
public class hello {
@RequestMapping(value="/hello", method=RequestMethod.GET )
public String hello() {
return "Hello SpringBoot";
}
}
右键 Run As->Spring Boot App
启动项目,可以通过http://localhost:8080/hello
路径来访问该controller
2 Spring Boot 项目开发
2.1 数据库表及实体类创建
在MySQL中创建表
CREATE TABLE tb_area (
area_id int(2) NOT NULL auto_increment,
area_name varchar(200) NOT NULL,
priority int(2) NOT NULL DEFAULT'0',
create_time datetime DEFAULT NULL,
last_edit_time datetime DEFAULT NULL,
PRIMARY KEY(area_id),
UNIQUE KEY UK_AREA(area_name)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
在项目中新建entity包,在下面新建Area实体类,生成set/get方法
public class Area {
private Integer areaId;
private String areaName;
private Integer priority;
private Date createDate;
private Date lastEditTime;
// set / get method
...
}
2.2 相关配置
在pom文件中添加mysql及c3p0数据库连接池的依赖,确认mybatis依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
在resource下创建mybatis-config.xml
文件,配置全局属性
<?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>
创建config.dao包,在下面创建文件DataSourceConfiguration,@Configuration
表示其为配置文件,@MapperScan("com.example.demo.dao")
配置了扫描dao的位置,创建一个dataSource的bean,返回连接池的对象实例ComboPooledDataSource
@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;
}
其中变量在该方法前创建,通过@Value("${jdbc.driver}")
引入application.properties
文件中的配置内容
@Value("${jdbc.driver}")
private String jdbcDriver;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
在application.properties
文件中添加配置信息
#DataSource
#数据库驱动
jdbc.driver=com.mysql.jdbc.Driver
#数据库链接
jdbc.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false
#数据库用户名
jdbc.username=root
创建SessionFactoryConfiguration类,创建sqlSessionFactory bean,为其设置mybatis-config.xml
的ConfigLocation,mapper文件的MapperLocations,DataSource,entity包扫描路径TypeAliasesPackage
@Value("${mybatis_config_file}")
private static String mybatisConfigFile;
@Value("${mapper_path}")
private static String mapperPath;
// 实体类所在的package
@Value("${type_alias_package}")
private String typeAliasPackage;
@Autowired
private DataSource dataSource;
@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 DAO
创建interface AreaDao,添加相应方法
public interface AreaDao {
List<Area> queryArea();
Area queryAreaById(int areaId);
int insertArea(Area area);
int updateArea(Area area);
int deleteArea(int areaId);
}
在resource文件夹下创建mapper/AreaDao.xml文件,实现AreaDao中的方法
<?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>
创建Unit Test,@RunWith @SpringBootTest
表示用springboot的测试框架来运行,@Ignore
忽略该方法的测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class AreaDaoTest {
//通过spring容器注入Dao的实现类
@Autowired
private AreaDao areaDao;
@Test
@Ignore
public void testAQueryArea() {
List<Area> areaList = areaDao.queryArea();
// 验证预期值和实际值是否相符
assertEquals(2, areaList.size());
}
@Test
public void testBInsertArea() {
//创建一个区域对象
Area area = new Area();
area.setAreaName("Test Park");
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
@Ignore
public void testCQueryAreaById() {
Area area = areaDao.queryAreaById(2);
assertEquals("East Park", area.getAreaName());
}
@Test
@Ignore
public void testDUpateArea() {
List<Area> areaList = areaDao.queryArea();
for (Area area : areaList) {
if ("Test Park".equals(area.getAreaName())) {
// 对比之前的priority值
assertEquals(1, area.getPriority().intValue());
area.setPriority(2);
int effectedNum = areaDao.updateArea(area);
assertEquals(1, effectedNum);
}
}
}
@Test
@Ignore
public void testEDeleteArea() {
List<Area> areaList = areaDao.queryArea();
for (Area area : areaList) {
if ("Test Park".equals(area.getAreaName())) {
int effectedNum = areaDao.deleteArea(area.getAreaId());
assertEquals(1, effectedNum);
}
}
// 重新获取一次列表,看看总数是否少1
areaList = areaDao.queryArea();
assertEquals(2, areaList.size());
}
}
2.4 Service
创建配置class TransactionManagementConfiguration,通过@Configuration @EnableTransactionManagement
注解标识配置,实现TransactionManagementConfigurer方法,传入dataSource
@Configuration
@EnableTransactionManagement
public class TransactionManagementConfiguration implements TransactionManagementConfigurer{
@Autowired
private DataSource dataSource;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
// TODO Auto-generated method stub
return new DataSourceTransactionManager(dataSource);
}
}
新建interface
public interface AreaService {
List<Area> getAreaList();
Area getAreaById(int areaId);
boolean addArea(Area area);
boolean modifyArea(Area area);
boolean deleteArea(int areaId);
}
新建实现类,其中增删改通过@Transactional
来进行事务管理
@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不能为空!");
}
}
}
2.5 Controller
添加controller类,类上的@RequestMapping
注解是该类所有方法前面要添加的前缀,@RequestBody Area area
可以标识方法接受的数据类型为xml或jason
@RestController
@RequestMapping("/superadmin")
public class AreaController {
@Autowired
private AreaService areaService;
@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;
}
@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;
}
@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;
}
@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>();
// 修改区域信息
modelMap.put("success", areaService.deleteArea(areaId));
return modelMap;
}
}
运行测试相关url
2.6 统一异常处理
创建异常处理类,@ExceptionHandler(value = Exception.class)
指定异常类型,@ResponseBody
表示返回在页面的body
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> exceptionHandler(HttpServletRequest req, Exception e) throws Exception {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
}
将service中getAreaById方法添加int a = 1/0;
测试异常