SpringBoot + MyBatis 创建一个新项目

2018-12-04  本文已影响25人  ChenME

作为一个做移动端的 coder,偶尔做一次后台项目,总是卡在项目的初始化上面,所以我觉得有必要做一个记录,方便下次初始化项目时使用。


文章用到的一些 MyBatis 的配置内容,详细参照《有关 MyBatis 的配置详解》


1. 创建项目,过程简单,图片代替:

创建项目1.png 创建项目2.png 创建项目3.png 创建项目4.png

得到项目的 package:mm.cme.xxxos

2. 添加常用的依赖:

  1. c3p0 数据库连接池;
<dependencies>
  <!-- 数据库连接池 -->
  <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
  </dependency>
</dependencies>
  1. 由于项目中的 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. 配置数据库 重点

  1. 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 时,会返回数据库自增的主键值,如果传入的是实体类,它会自动向实体类的主键赋值

  1. 配置 DataSource
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
@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;
    }
}
  1. 配置 SessionFactory
mybatis_config_file: mybatis-config.xml
mapper_path: /mapper/**.xml
bean_package: mm.cme.xxxos.dao
@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;
    }
}
  1. 配置事务管理(开启事务管理):
@Configuration
@EnableTransactionManagement // 开启事务的管理
public class TransactionManagementConfig implements TransactionManagementConfigurer{

    @Autowired
    private DataSource dataSource;

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}

5. 创建数据表,准备编码测试:

  1. 启动 MySql,并创建数据库 xxxos
  2. 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. 编码:

  1. 在编码前,先完善项目的目录结构
mm.cme.xxxos
  |-- base
  |-- bean (存放 JavaBean)
  |-- comm (存放一些公共的 class)
  |-- config (存放配置文件)
    |-- dao
    |-- service
  |-- constant (存放常量)
  |-- controller
  |-- dao
  |-- domain (存放请求的参数的 JavaBean)
  |-- handler (存放一些处理的 class,例如异常处理等)
  |-- service
    |-- impl
  |-- utils
  1. 编写 Const:
public interface Const {
    String Default_Chartest = "UTF-8";
    String Default_JsonContentType = "application/json;charset=UTF-8";
}
  1. 编写 ResultCode:
enum class ResultCode(val code: Int, val message: String) {
    Error(-1, "网络请求错误"),
    ErrDataEmpty(1000, "数据为空"),
    Success(0, "成功")
}
  1. 编写 BaseController:
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;
    }
}
  1. 编写 BaseResp:
class BaseResp<T>(var status: Int = ResultCode.Success.code,
                  var msg: String = ResultCode.Success.message,
                  var data: T? = null) : Serializable
  1. 编写 JavaBean:
data class ColorBean(
        val colorId: Int = 0,
        val colorName: String,
        val colorDescription: String?,
        val colorRemark: String?
)
  1. 编写 Dao:
interface ColorDao {

    /**
     * 获取商品的所有颜色
     */
    fun listAllColor(): List<ColorBean>

    /**
     * 更新颜色
     */
    fun updateColor(bean: ColorBean): Int

    /**
     * 新增一个颜色
     */
    fun addColor(bean: ColorBean): Int
}
  1. 编写 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>
  1. 编写 Service:
interface ColorService {

    /**
     * 获取商品的所有颜色
     */
    fun listAllColor(): List<ColorBean>

    /**
     * 更新颜色
     */
    fun updateColor(bean: ColorBean): Boolean


    /**
     * 新增一个颜色
     */
    fun addColor(bean: ColorBean): ColorBean
}
  1. 编写 ServiceImpl:
@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("新增颜色失败!");
        }
    }
}
  1. 编写 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));
    }
}
  1. 统一异常处理:
@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. 运行测试:

  1. 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
            }
        ]
    }
}
  1. addColor
// url
http://localhost:8082/xxxos/color/addColor

// param
{
    "colorName":"无色",
    "colorDescription":"就是这么任性",
    "colorRemark":"就是这么任性"
}

// resp
{
    "status": 0,
    "msg": "成功",
    "data": {
        "colorId": 10,
        "colorName": "无色",
        "colorDescription": "就是这么任性",
        "colorRemark": "就是这么任性"
    }
}
  1. updateColor
// url
http://localhost:8082/xxxos/color/updateColor

// param
{
    "colorId":10,
    "colorName":"无色透明",
    "colorDescription":"皇帝的新衣",
    "colorRemark":"皇帝的新衣"
}

// resp
{
    "status": 0,
    "msg": "成功",
    "data": null
}
上一篇下一篇

猜你喜欢

热点阅读