如果没看前面例子的同学建议先看下,我们这篇直接基于前面搭建的开发框架进行扩展。
准备工作或知识储备:maven、spring、spring mvc 、mybatis,jquery、Bootstrap、sql,
上一篇我们已经完成了基于Thymeleaf模板的整合,为了降低门槛,我们这个ssm的demo前端使用Bootstrap+jquery+BootStrap Table来实现。(BootStrap Table和VUE.js有点像,理解和学习起来相对容易,从开始接触到使用到实际项目也就半天时间,都比较完善,虽然是英文,直接照葫芦画瓢就行)
后台源码(有小bug): 完整源码:
=========================华丽分割线==============================
先说步骤
注:本篇不对单个框架进行深入介绍,如果点赞关注多我再补充单个框架更详细的系列教程。
1、引入需要的jar包(mysql驱动、mybatis)
2、建库建表
3、编写实体bean
4、整合spring+mybatis(dao、servcei层)
5、使用spring mvc提供rest服务(controller)
6、前端框架整合调用rest服务
接下来开始撸代码吧
1、引入需要的jar包(mysql驱动、mybatis)
有坑(spring-tx必须引用,要不找不到DaoSurport)
4.0.0 com.pxk.springboot SpringBootDemo 0.0.1-SNAPSHOT src maven-compiler-plugin 3.3 org.springframework.boot spring-boot-starter-parent 1.5.6.RELEASE org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web 1.5.6.RELEASE org.springframework spring-tx 4.3.10.RELEASE org.springframework spring-jdbc 4.3.10.RELEASE org.mybatis mybatis 3.4.0 org.mybatis mybatis-spring 1.3.0 mysql mysql-connector-java 5.1.40 log4j log4j 1.2.17 com.alibaba druid 1.0.18
2、建库建表
数据使用的是myql5.5,客户端工具是Navicat 8(i表结构会包含在源码中)
一张普通的用户表,id采用数据库自增长,随便补充十条数据
3、编写实体bean
get、set方法就不贴出来了,免得浪费篇幅
有个坑哦(构造函数必须有)
package com.pxk.springboot.domain;import java.util.Date;import com.fasterxml.jackson.annotation.JsonFormat;public class User { private Integer id; private String name; private Integer age; private String passWord; private char gender; //json日期格式化 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date regestDate; //默认构造函数不能少 ,如果没有会报ibatis.executor.ExecutorException: No constructor found public User() { super(); }
4、整合spring+mybatis(dao【其实就被mapper替代了】、servcei层)
首先介绍下mybatis,用过的同学应该都知道它是一个半自动的ORM框架,比Hibernate更灵活,但是开发效率没有Hibernate高,不过现在有很多开源的插件封装了crud操作,效率也还可以,目前开源中国比较热的是mybatis-plus,我也用过基本能满足需求,就是源代码没注释,文档少,遇到坑的时候就就比较浪费时间去理源码。
本文主要是在spring+mybatis的基础上使用springboot的整合方式而已,如搭建过常规spring+mybatis框架的就很好理解。
这部分也是本文的核心,首先我们要编写mapper、然后定义接口,spring会自动调用接口对应的mapper中的方法(实现原理就是使用的反射--框架开发利器)
1、定义接口
新建UserMapper接口(如果使用自动扫描接口名必须和xml的mapper文件名对应)
package com.pxk.springboot.dao;import java.util.List;import org.apache.ibatis.annotations.Param;import com.pxk.springboot.domain.User;public interface UserMapper { ListfindUserByPage(@Param("startIndex")int startIndex ,@Param("pageSize")int pageSize); User getUserById(int id); int updateUser(User user); int deleteUser(User user); int addUser(User user);}
2、编写接口对应mapper,并配置扫描(xml文件)
这部分就是mybatis中的内容了,没有用到什么高级的特性,只是普通的单表操作,sql不严谨不必纠结哈(动态sql,resultMap关联等都没用)
为了能让spring通过接口调用我们的mapper中的sql语句,我们必须让spring将mapper和接口对应上,那我们在调用接口的时候,spring才知道去找哪个mapper中的那个sql啊。首先,保证mapper的文件名和接口名要一致,否则是匹配不上的(当然我们如果采用配置文件的方式是可以配置对应关系的,但这又和我们使用SpringBoot的零配置思想背离了,所以我还是认为约定优于配置)。其次,采用java配置,让Spring扫描mapper文件,我知道的至少有三种方式我这里就随便选了一种(注意:直接在springBootApplication上配置mapperScan后期打包部署的时候会有jar包扫描不到的问题,我跳的过坑,建议大家像我一样用别去采坑了,浪费了我一个下午的时间,开发环境能启动,打包后就不行了,这是mybaitis的一个bug,不知道后来修复没有)。我采用的是新建一个configration类的方式进行配置,详见下面代码:MyBatisConfig .java
UserMapper.xml(所在目录SpringBootDemo/src/main/resources/com/pxk/springboot/dao,这目录就是要被扫描的)
insert into User name, gender, pass_word, regest_date, #{name,jdbcType=VARCHAR}, #{gender,jdbcType=CHAR}, #{pass_word,jdbcType=VARCHAR}, #{regest_date,jdbcType=Date}, delete from user where id=#{id}
MyBatisConfig .java
package com.pxk.springboot.config;import org.mybatis.spring.mapper.MapperScannerConfigurer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * mybatis 配置文件 * @author Administrator * */@Configurationpublic class MyBatisConfig { @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); //指定扫描的mapper.xml文件所在目录 mapperScannerConfigurer.setBasePackage("com.pxk.springboot.dao"); return mapperScannerConfigurer; }}
3.配置实体类
为什么配置实体类呢,因为spring通过反射调用接口以后要知道你返回的结果是什么类型啊,这些实体也需要托管到spring容器他才会给你封装好啊,所以我们还是得像spring+mybatis一样配置TypeAliases,只是配置方式不同而已。那么采用springBoot集成该怎么做能,只需要在APPlication中覆盖默认配置sqlSessionFactory的方法,指定实体类所在路径即可,springBoot内部也是通过扫描的方式去加载的。具体代码如下:
Application.java
package com.pxk.springboot;import javax.sql.DataSource;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.log4j.lf5.util.Resource;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.annotation.MapperScan;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import com.alibaba.druid.pool.DruidDataSource;@SpringBootApplication//@MapperScan(basePackages = { "com.pxk.springboot.dao" })//这种扫描会有bug哦public class Application { private final static Logger log=LoggerFactory.getLogger(Application.class); @Bean @ConfigurationProperties(prefix = "spring.datasource") //覆盖默认数据源 使用druid数据源 public DataSource dataSource() { return new DruidDataSource(); } @Bean public SqlSessionFactory sqlSessionFactory() { try { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); //扫描实体类所在包 sessionFactory.setTypeAliasesPackage("com.pxk.springboot.domain"); return sessionFactory.getObject(); } catch (Exception e) { return null; } } public static void main(String[] args) { SpringApplication.run(Application.class, args); log.info("启动成功"); }}
4、编写srvice调用dao
service层比较简单就是依赖注入以后调用没有任何业务逻辑,直接上代码
UserServiceImpl.java
package com.pxk.springboot.serivce.imp;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.pxk.springboot.dao.UserMapper;import com.pxk.springboot.domain.User;import com.pxk.springboot.serivce.UserService;@Service//注入成servicepublic class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User getUser(String name) { return new User(name); } @Override public ListfindUserByPage(int pageSize, int pageNum) { return userMapper.findUserByPage((pageNum-1)*pageSize, pageSize); } @Override public User getUserById(int id) { return userMapper.getUserById(id); } @Override public int updateUser(User user) { return userMapper.updateUser(user); } @Override public int deleteUser(User user) { return userMapper.deleteUser(user); } @Override public int addUser(User user) { return userMapper.addUser(user); }}
5、编写controller并测试
也没什么特殊的,直接上代码(大家有点spring mvc基础就能看懂的)
UserController.java(代码片段,先做个测试)
@RequestMapping("/findUserByPage") @ResponseBody//返回json格式数据 protected ListfindUserByPage(int pageSize,int pageNum){ return userService.findUserByPage(pageSize, pageNum); }
运行程序,输入http://localhost:8081/user/findUserByPage?pageSize=5&pageNum=1测试controller的findUserByPage方法,结果如下