作为一个做移动端的 coder,偶尔做一次后台项目,总是卡在项目的初始化上面,所以我觉得有必要做一个记录,方便下次初始化项目时使用。
文章用到的一些 MyBatis 的配置内容,详细参照《有关 MyBatis 的配置详解》
1. 创建项目,过程简单,图片代替:




得到项目的 package:
mm.cme.xxxos
2. 添加常用的依赖:
- c3p0 数据库连接池;
<dependencies>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
</dependencies>
- 由于项目中的 JavaBean 用到了 Kotlin 的
date class
,所以依赖了 Kotlin 相关的内容(其实这个也不必手动添加,直接在项目中编写 Kotlin 代码,IDEA 会自动识别并提醒添加依赖的);
<dependencies>
<!-- Kotlin -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
注意需要在配置中添加 Kotlin 的版本;
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.71</kotlin.version>
</properties>
3. SpringBoot 的配置文件,这里用了 yml
文件(application.yml
);
server:
port: 8082
servlet:
context-path: /xxxos # 配置项目的路由
主要是配置端口以及项目的路由;
4. 配置数据库 重点
- 在
resource
下创建 mybatis 的配置文件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 获取数据库自增的主键值
(当 insert 时,会返回数据库自增的主键值,如果传入的是实体类,它会自动向实体类的主键赋值)-->
<setting name="useGeneratedKeys" value="true"/>
<!-- 使用列标签替换列别名 -->
<setting name="useColumnLabel" value="true"/>
<!-- 开启驼峰命名转换 Table{user_name} -> Bean{userName} -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
重点是
useGeneratedKeys
,当 insert 时,会返回数据库自增的主键值,如果传入的是实体类,它会自动向实体类的主键赋值
- 配置
DataSource
;
- 在
application.yml
文件中添加数据库的连接信息:
jdbc:
driver: com.mysql.cj.jdbc.Driver # driver: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/xxxos
user: root
pwd: root
- 创建 package
config.dao
; - 在该 package 下面创建一个 class:
DataSourceConfiguration.java
;
@Configuration
@MapperScan("mm.cme.xxxos.dao") // 配置 mybatis mapper 的扫描路径
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driverClass;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.user}")
private String jdbcUser;
@Value("${jdbc.pwd}")
private String jdbcPwd;
@Bean(name = "dataSource")
public ComboPooledDataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driverClass);
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(jdbcUser);
dataSource.setPassword(jdbcPwd);
//关闭连接后不自动 commit,便于事务控制
dataSource.setAutoCommitOnClose(false);
return dataSource;
}
}
- 配置
SessionFactory
;
- 在
resource
下面创建 dir:mapper
,用于后面存放 mybatis 的 mapper 文件使用; - 在
application.yml
文件中添加 session 相关的控制信息:
mybatis_config_file: mybatis-config.xml
mapper_path: /mapper/**.xml
bean_package: mm.cme.xxxos.dao
- 在该
config.dao
下面创建一个 class:SessionFactoryConfiguration.java
;
@Configuration
public class SessionFactoryConfiguration {
// mybatis-config.xml 配置文件的路径
@Value("${mybatis_config_file}")
private String mybatisConfigFilePath;
// mybatis mapper 文件所在路径
@Value("${mapper_path}")
private String mapperPath;
// 实体类所在的 package
@Value("${bean_package}")
private String beanPackage;
@Autowired
@Qualifier("dataSource") // 加载 DataSourceConfiguration 中的 ComboPooledDataSource
private DataSource dataSource;
@Bean("sqlSessionFactory")
public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFilePath));
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String packageSearchPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(packageSearchPath));
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage(beanPackage);
return sqlSessionFactoryBean;
}
}
- 配置事务管理(开启事务管理):
- 创建 package:
config.service
; - 在该目录下创建 class:
TransactionManagementConfig.java
;
@Configuration
@EnableTransactionManagement // 开启事务的管理
public class TransactionManagementConfig implements TransactionManagementConfigurer{
@Autowired
private DataSource dataSource;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
5. 创建数据表,准备编码测试:
- 启动 MySql,并创建数据库
xxxos
; - 在
xxxos
中创建一个goods_color
表并插入数据;
-- ----------------------------
-- Table structure for goods_color
-- ----------------------------
DROP TABLE IF EXISTS `goods_color`;
CREATE TABLE `goods_color` (
`color_id` int(11) NOT NULL AUTO_INCREMENT,
`color_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '颜色名字',
`color_description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '描述',
`color_remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '备注',
PRIMARY KEY (`color_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of goods_color
-- ----------------------------
BEGIN;
INSERT INTO `goods_color` VALUES (1, '杂色', NULL, NULL);
INSERT INTO `goods_color` VALUES (2, '黑色', NULL, NULL);
INSERT INTO `goods_color` VALUES (3, '白色', NULL, NULL);
INSERT INTO `goods_color` VALUES (4, '红色', NULL, NULL);
INSERT INTO `goods_color` VALUES (5, '米色', NULL, NULL);
INSERT INTO `goods_color` VALUES (6, '灰色', NULL, NULL);
INSERT INTO `goods_color` VALUES (7, '黄色', NULL, NULL);
INSERT INTO `goods_color` VALUES (9, '蓝色', NULL, NULL);
COMMIT;
6. 编码:
- 在编码前,先完善项目的目录结构
mm.cme.xxxos
|-- base
|-- bean (存放 JavaBean)
|-- comm (存放一些公共的 class)
|-- config (存放配置文件)
|-- dao
|-- service
|-- constant (存放常量)
|-- controller
|-- dao
|-- domain (存放请求的参数的 JavaBean)
|-- handler (存放一些处理的 class,例如异常处理等)
|-- service
|-- impl
|-- utils
- 编写 Const:
- 在
comm
目录下创建:
public interface Const {
String Default_Chartest = "UTF-8";
String Default_JsonContentType = "application/json;charset=UTF-8";
}
- 编写 ResultCode:
- 在
constant
目录下创建:
enum class ResultCode(val code: Int, val message: String) {
Error(-1, "网络请求错误"),
ErrDataEmpty(1000, "数据为空"),
Success(0, "成功")
}
- 编写 BaseController:
- 在
base
目录下创建:
public class BaseController {
/**
* 将得到的 list 集合处理并返回
*
* @param list
* @param <T>
* @return
*/
protected <T> BaseResp<Map<String, Object>> handleListResult(List<T> list) {
BaseResp<Map<String, Object>> resp = new BaseResp<>();
Map<String, Object> map = new HashMap<>();
if (null == list || list.size() <= 0) {
resp.setStatus(ResultCode.ErrDataEmpty.getCode());
resp.setMsg(ResultCode.ErrDataEmpty.getMessage());
} else {
map.put("list", list);
resp.setData(map);
}
return resp;
}
/**
* 将得到的 map 集合处理并返回
*
* @param map
* @return
*/
protected BaseResp<Map<String, Object>> handleMapResult(Map<String, Object> map) {
BaseResp<Map<String, Object>> resp = new BaseResp<>();
resp.setData(map);
return resp;
}
/**
* 将得到的 bean 处理并返回
*
* @param bean
* @param <T>
* @return
*/
protected <T> BaseResp<T> handleBeanResult(T bean) {
BaseResp<T> resp = new BaseResp<>();
if (null == bean) {
resp.setStatus(ResultCode.Error.getCode());
resp.setMsg(ResultCode.Error.getMessage());
} else {
resp.setData(bean);
}
return resp;
}
/**
* 将得到的 bool 处理并返回
*
* @param isSuccess
* @return
*/
protected BaseResp handleSuccess(boolean isSuccess) {
BaseResp resp = new BaseResp();
if (!isSuccess) {
resp.setStatus(ResultCode.Error.getCode());
resp.setMsg(ResultCode.Error.getMessage());
}
return resp;
}
}
- 编写 BaseResp:
- 在
bean
目录下创建:
class BaseResp<T>(var status: Int = ResultCode.Success.code,
var msg: String = ResultCode.Success.message,
var data: T? = null) : Serializable
- 编写 JavaBean:
- 在
bean
目录下创建:
data class ColorBean(
val colorId: Int = 0,
val colorName: String,
val colorDescription: String?,
val colorRemark: String?
)
- 编写 Dao:
- 在
dao
目录下创建:
interface ColorDao {
/**
* 获取商品的所有颜色
*/
fun listAllColor(): List<ColorBean>
/**
* 更新颜色
*/
fun updateColor(bean: ColorBean): Int
/**
* 新增一个颜色
*/
fun addColor(bean: ColorBean): Int
}
- 编写 mapper:
- 在
resource/mapper
目录下创建:
<?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="mm.cme.xxxos.dao.ColorDao">
<select id="listAllColor" resultType="mm.cme.xxxos.bean.ColorBean">
SELECT * FROM goods_color;
</select>
<update id="updateColor" parameterType="mm.cme.xxxos.bean.ColorBean">
UPDATE goods_color
<set>
<if test="null!=colorName">color_name = #{colorName},</if>
<if test="null!=colorDescription">color_description = #{colorDescription},</if>
<if test="null!=colorRemark">color_remark = #{colorRemark},</if>
</set>
WHERE color_id = #{colorId};
</update>
<insert id="addColor" useGeneratedKeys="true" keyColumn="color_id" keyProperty="colorId"
parameterType="mm.cme.xxxos.bean.ColorBean">
INSERT INTO
goods_color(color_name, color_description, color_remark)
VALUES (#{colorName}, #{colorDescription}, #{colorRemark});
</insert>
</mapper>
- 编写 Service:
- 在
service
目录下创建:
interface ColorService {
/**
* 获取商品的所有颜色
*/
fun listAllColor(): List<ColorBean>
/**
* 更新颜色
*/
fun updateColor(bean: ColorBean): Boolean
/**
* 新增一个颜色
*/
fun addColor(bean: ColorBean): ColorBean
}
- 编写 ServiceImpl:
- 在
service/impl
目录下创建:
@Service
public class ColorServiceImpl implements ColorService {
@Autowired
ColorDao colorDao;
@NotNull
@Override
public List<ColorBean> listAllColor() {
return colorDao.listAllColor();
}
@Transactional
@Override
public boolean updateColor(@NotNull ColorBean bean) {
try {
if (colorDao.updateColor(bean) > 0) {
return true;
} else {
throw new RuntimeException("颜色信息更新失败!");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("颜色信息更新失败!");
}
}
@Transactional
@NotNull
@Override
public ColorBean addColor(@NotNull ColorBean bean) {
try {
if (colorDao.addColor(bean) > 0) {
return bean;
} else {
throw new RuntimeException("新增颜色失败!");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("新增颜色失败!");
}
}
}
- 编写 Controller:
- 在
controller
目录下创建:
@RestController
@RequestMapping(produces = {Const.Default_JsonContentType}, value = {"/color"})
public class ColorController extends BaseController {
@Autowired
ColorService mService;
/**
* 获取商品的所有颜色
*
* @return
*/
@GetMapping("/listAllColor")
public BaseResp<Map<String, Object>> listAllColor() {
return handleListResult(mService.listAllColor());
}
/**
* 更新颜色
*
* @return
*/
@PostMapping("/updateColor")
public BaseResp updateColor(@RequestBody ColorBean req) {
return handleSuccess(mService.updateColor(req));
}
/**
* 新增一个颜色
*
* @param bean
* @return
*/
@PostMapping("/addColor")
public BaseResp<ColorBean> addColor(@RequestBody ColorBean bean) {
return handleBeanResult(mService.addColor(bean));
}
}
- 统一异常处理:
- 在
handler
目录下创建:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public BaseResp<HashMap<String, Object>> exceptionHandler(HttpServletRequest req, Exception e) throws Exception {
BaseResp<HashMap<String, Object>> resp = new BaseResp<>();
resp.setStatus(ResultCode.Error.getCode());
resp.setMsg(e.getMessage());
return resp;
}
}
7. 运行测试:
listAllColor
// url
http://localhost:8082/xxxos/color/listAllColor
// resp (部分)
{
"status": 0,
"msg": "成功",
"data": {
"list": [
{
"colorId": 1,
"colorName": "杂色",
"colorDescription": null,
"colorRemark": null
},
{
"colorId": 2,
"colorName": "黑色",
"colorDescription": null,
"colorRemark": null
}
]
}
}
addColor
// url
http://localhost:8082/xxxos/color/addColor
// param
{
"colorName":"无色",
"colorDescription":"就是这么任性",
"colorRemark":"就是这么任性"
}
// resp
{
"status": 0,
"msg": "成功",
"data": {
"colorId": 10,
"colorName": "无色",
"colorDescription": "就是这么任性",
"colorRemark": "就是这么任性"
}
}
updateColor
// url
http://localhost:8082/xxxos/color/updateColor
// param
{
"colorId":10,
"colorName":"无色透明",
"colorDescription":"皇帝的新衣",
"colorRemark":"皇帝的新衣"
}
// resp
{
"status": 0,
"msg": "成功",
"data": null
}
网友评论