springboot 入门教程(3)-运行原理、关键注解和配置
springboot 入门教程(4)--web开发(spring mvc和Thymeleaf模板,带源码)
如果没看前面例子的同学建议先看下,我们这篇直接基于前面搭建的开发框架进行扩展。
准备工作或知识储备:maven、spring、spring mvc 、mybatis,jquery、Bootstrap、sql,druid连接池
上一篇我们已经完成了基于Thymeleaf模板的整合,为了降低门槛,我们这个ssm的demo前端使用Bootstrap+jquery+BootStrap Table来实现。(BootStrap Table和VUE.js有点像,理解和学习起来相对容易,从开始接触到使用到实际项目也就半天时间,官方文档和demo都比较完善,虽然是英文,直接照葫芦画瓢就行)
后台源码(有小bug):springBoot+mybatis实现CRUD源码 完整源码:springBoot+mybatis实现CRUD源码-完整版
=========================华丽分割线==============================
先说步骤
注:本篇不对单个框架进行深入介绍,如果点赞关注多我再补充单个框架更详细的系列教程。
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)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pxk.springboot</groupId>
<artifactId>SpringBootDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
<!-- 需要单独引用不然会报 java.lang.NoClassDefFoundError: org/springframework/dao/support/DaoSupport -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- spring jdbc支持, 不引用会报类似,具体类可能不同NoClassDefFoundError: org/springframework/jdbc/datasource/TransactionAwareDataSour -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
</dependencies>
</project>
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 {
List<User> findUserByPage(@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,这目录就是要被扫描的)
<?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.pxk.springboot.dao.UserMapper">
<!-- 使用别名的目的是让查询结果属性名称和实体bean的属性名对应,要不让绑定不上数据。要么就写resultMap这个大家自己搞了 -->
<select id="findUserByPage" resultType="User">
select name,age,gender,pass_word passWord,regest_date regestDate from user limit #{startIndex},#{pageSize};
</select>
<insert id="addUser" parameterType="User">
insert into
User
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name != null and name!=''">
name,
</if>
<if test="gender != null and gender!=''">
gender,
</if>
<if test="password != null and password!=''">
pass_word,
</if>
<if test="regestDate != null">
regest_date,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null and name!=''">
#{name,jdbcType=VARCHAR},
</if>
<if test="gender != null and gender!=''">
#{gender,jdbcType=CHAR},
</if>
<if test="password != null and password''">
#{pass_word,jdbcType=VARCHAR},
</if>
<if test="regestDate != null ">
#{regest_date,jdbcType=Date},
</if>
</trim>
</insert>
<select id="getUserById" parameterType="int" resultType="User">
select * from user where id=#{id}
</select>
<delete id="deleteUser" parameterType="User">
delete from user where id=#{id}
</delete>
</mapper>
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
*
*/
@Configuration
public 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//注入成service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUser(String name) {
return new User(name);
}
@Override
public List<User> findUserByPage(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 List<User> findUserByPage(int pageSize,int pageNum){
return userService.findUserByPage(pageSize, pageNum);
}
运行程序,输入http://localhost:8081/user/findUserByPage?pageSize=5&pageNum=1测试controller的findUserByPage方法,结果如下