说明:SpringBoot一天速成不是口号,而在于您的基础。
1.此演示目的就是为了让大家速成。口号:“快快快狠”。
2.具备半年以上"SSM框架+Maven"实战经验的开发人员
3.跟着此系列博文《SpringBoot一天速成》练习一遍
4.这套演练包括工程的:持久层、服务层、web层,采用Intellej idea工具。
5.所有源码和资料免费提供给读者,需要的留言。
6.笔者将实践过程中遇到的问题与大家分享,让大家少走弯路。(请阅读注释部分)
SpringBoot是干嘛的?"简化开发,独立运行",瞄准的目标:微服务。下面是官方原话:
Spring Boot makes it easy to create stand-alone, production-grade Spring based
Applications that you can "just run". We take an opinionated view of
the Spring platform and third-party libraries so you can get started with minimum fuss.
Most Spring Boot applications need very little Spring configuration.
====>>> 持久层–>服务层 演练开始……
采用****的方式来演示《SpringBoot一天速成演练》,先从数据库开始最后到web层
声明:@author:拈花为何不一笑,“这是一套演练对于细节方面,需要读者自己完善。”
1.准备Intellij idea工具(此工具集成了Spring Initializr比eclipse更高效,缺点是占用大量内存接近900M)
1.1 下载ideaIU-2018.2.6.exe
1.2 **方法(此工具是收费的,若果是学习用可以使用**版,企业用建议购买)
这些资源,有需要的笔者都可以提供,请留言。
2.Intellij Idea工具中创建工程
File菜单--> New -->Project-->弹出对话框:选择Spring Initializr(用来初始化构建工程的环境),
接下来的操作看图,更清楚,如下:
3.在Mysql(版本:MySQL-5.5.61)中创建数据库和建表等
sql脚本:createTable.sql,有需要的笔者可以分享出来...
3.1 数据库名称;testsb2mybatis
3.2 表两张:dept和emp
截一张表结构图,如下:
|
4.编写Mapper接口和相关配置文件
4.1.在resources目录下创建以下目录结构,如图:
4.2.创建mybatis配置文件mybatis.xml和EmpMapper.xml文件(注意存放位置)
====>>> mybatis.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>
<!-- mybatis中加载的数据源datasource,由于与springboot进行整合,那么数据源交由Spring来管理,则配置在application.properties文件中了-->
<!-- 配置 mybatis sql日志输出 STDOUT_LOGGING
<settings>
<setting name="logImpl" value="SLF4J" />
</settings>
-->
</configuration>
====>>> EmpMapper.xml
<?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">
<!-- namespace指向mapper包中的相应的接口,这是Mybatis-Mapper方式的规则之一 -->
<mapper namespace="org.it.springboot4.mapper.EmpMapper">
<sql id="empfields">
empno,ename,job,mgr,hiredate,sal,comm,deptno
</sql>
<!-- id与mapper接口方法名相同,resultType与mapper接口的方法的返回类型相同,这是Mybatis-Mapper方式的规则之二 -->
<!-- parameterType相当于itatis中的parameterClass,
若参数为基本数据类型,占位符(#{参数名})可以是任意参数名;
若参数为java对象,如User那么占位符中的参数名,取名要与User中的属性对应,因为通过getXXX从User中取值的 -->
<select id="findEmpById" parameterType="java.lang.Integer" resultType="org.it.springboot4.entity.Emp">
select
<include refid="empfields"/>
from emp where empno = #{拈花为何不一笑}
</select>
<!-- 模糊查询拼接符 '%${}%',基本数据类型的模糊查询拼接符只能使用'%${value}%',
不能这样'%${username}%',防止拼接注入'%${username}% or 1=1' -->
<!-- 查询研发部所有薪资大于或等于6600的员工,返回类型resultType直接映射成Map
注意返回类型不是resultMap。
1.resultType表示基本数据类型和包装类及自定义类,还有这里的java.util.Map接口下的实现类,
若在此处误用resultMap是会因Map无法映射,而抛出异常:
java.lang.IllegalArgumentException: Result Maps collection does not contain value for java.util.Map
2.默认使用的是HashMap来实现Map,采用的是hash值对键进行排序,映射的数据顺序就有点乱,
可以直接指定LinkedHashMap来排序按插入(sql查询字段的顺序)排序特性并去重复的字段(如这里的deptno,排在前面的保留)
3.resultMap通常用于查询出多表关联数据与java类与类之间的关联关系进行映射,即通常所说的的一对多,多对多这类的映射关系。
-->
<select id="findEmpByDeptnoSal" parameterType="org.it.springboot4.entity.custom.EmpCustom" resultType="java.util.LinkedHashMap">
SELECT
e.empno,
e.ename,
e.hiredate,
e.job,
e.mgr,
e.sal,
e.deptno,
e.comm,
d.deptno,
d.dname,
d.location
FROM emp e, dept d
WHERE e.deptno = d.deptno
<!-- mybatis动态sql,根据参数有无来动态添加查询条件,如果是Map作为查询条件的参数,则在if test中直接使用key名判断即可-->
<if test="dname != null and dname !=''">
AND d.dname = #{dname}
</if>
<if test="sal != null and sal !=''">
AND sal >= #{sal}
</if>
</select>
<!-- 添加一个新员工,无需显示指明返回类型,mybatis自动把影响到的记录数据作为Integer返回 -->
<insert id="createEmp" parameterType="org.it.springboot4.entity.Emp" >
insert into emp(ename,hiredate,job,mgr,sal,comm,deptno)
values (#{ename},#{hiredate},#{job},#{mgr},#{sal},#{comm},#{deptno})
</insert>
<!-- 创建并映射当前新增加的员工编号(返回的还是影响的记录数) -->
<!-- 通过mysql数据库提供的函数last_insert_id(),获取由数据库mysql自动生成的主键并映射到Emp的empno属性中 -->
<!-- 注意:1.返回的是一个整数不能是Emp对象 2.selectKey 中的order属性值必须大写AFTER 3.如果使用resultType会报一个坑人的异常提示:
必须为元素类型 "insert" 声明属性 "resultType"。 -->
<insert id="createGetEmp" parameterType="org.it.springboot4.entity.Emp">
<selectKey keyColumn="empno" keyProperty="empno" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into emp(ename,hiredate,job,mgr,sal,comm,deptno)
values (#{ename},#{hiredate},#{job},#{mgr},#{sal},#{comm},#{deptno})
</insert>
<!-- 删除员工,使用Map接收删除条件,其中currentEmpno为Map设置的键名 -->
<delete id="deleteEmp" parameterType="java.util.Map">
delete from emp where empno = #{currentEmpno}
</delete>
<!-- 更新员工,这里使用if标签构建动态sql,防止空数据覆盖表中字段数据。其中set标签可以去最后面一个字段的逗号防止sql语法错误 -->
<update id="updateEmp" parameterType="org.it.springboot4.entity.Emp">
update emp
<set>
<if test="ename != null and ename !=''">
ename = #{ename},
</if>
<if test="hiredate != null and hiredate !=''">
hiredate = #{hiredate},
</if>
<if test="job != null and job !=''">
job = #{job},
</if>
<if test="mgr != null and mgr !=''">
mgr = #{mgr},
</if>
<if test="sal != null and sal !=''" >
sal = #{sal},
</if>
<if test="comm != null and comm !=''" >
comm = #{comm},
</if>
<if test="deptno != null and deptno !=''" >
deptno = #{deptno},
</if>
</set>
where empno =#{empno}
<if test="deptno != null and deptno !=''">
and deptno = #{deptno}
</if>
<if test="mgr != null and mgr !=''">
and mgr = #{mgr}
</if>
</update>
</mapper>
继续…
4.3.创建实体类:Dept.java和Emp.java 及EmpCustom(扩展Emp,用于包装前端参数)
====>>> Dept .java
package org.it.springboot4.entity;
public class Dept {
private Integer deptno;
private String dname;
private String location;
public Dept() {//无参构造函数
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
====>>> Emp.java
package org.it.springboot4.entity;
import java.util.Date;
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Float sal;
private Float comm;
private Integer deptno;
public Emp() {
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Float getSal() {
return sal;
}
public void setSal(Float sal) {
this.sal = sal;
}
public Float getComm() {
return comm;
}
public void setComm(Float comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
}
====>>> EmpCustom.java
package org.it.springboot4.entity.custom;
import org.it.springboot4.entity.Emp;
/**
* 自定义Emp扩展类,用于Emp属性的扩展
*/
public class EmpCustom extends Emp {
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
}
继续…
4.4.这里采用Mybatis-Mapper接口的开发方式,使用Mybatis。
(还有一种方式是向下兼容itatis,推荐Mybatis-Mapper)
编写EmpMapper接口,这里有一定的规则,要与EmpMapper.xml中的配置相对应,里面有注释说明。
====>>> EmpMapper.java(看清楚了,这个后缀是java)
package org.it.springboot4.mapper;
import org.it.springboot4.entity.Emp;
import org.it.springboot4.entity.custom.EmpCustom;
import java.util.List;
import java.util.Map;
/**
* mapper包相当于dao层包
* 这里演示Mybatis-Mapper方式使用mybatis
* 这个接口中的方法是需要遵守一定的规范的
* springboot自动扫描会扫描mapper包(未与sprngboot整合时,包的扫描是由mybatis来扫描的且mapper映射文件与java mapper接口放在同一个包中)
*/
public interface EmpMapper {
//查询员工根据员工编号(按实际开发过程中,service层方法是要求抛出异常的,这里简单演示就省略了)
Emp findEmpById(Integer empno);
// 查询研发部所有薪资大于或等于6600的员工(也可以使用Map作为参数,mapper.xml中取参数值方式#{map设置的key名})
List<Map> findEmpByDeptnoSal(EmpCustom empCustom);
//增加一个员工并返回影响的记录数
Integer createEmp(Emp emp);
//创建并映射当前新增加的员工编号(返回的还是影响的记录数)
Integer createGetEmp(Emp emp);
//删除员工
Integer deleteEmp(Map paramMap);
//更新员工
Integer updateEmp(Emp emp);
}
继续
4.5.创建application.properties配置文件,springboot入口类启动时会加载此配置文件
此配置在这里,笔者将其分成三块:a.基础配置信息 b.数据源配置 c.ybatis配置
配置文件内容,如下:
====>>> application.properties
##########基础配置信息 ##########
#debug=ture
#server.servlet.context-path=/myspringboot4
server.port=8080
spring.http.encoding.charset=UTF-8
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss SSS
spring.mvc.date-format=yyyy-MM-dd
#json缩进排版
spring.jackson.serialization.indent-output=true
##########数据源配置##########
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#这里有个时区问题,需要注意,GMT+8 ,其中%2B表示"+"
spring.datasource.url=jdbc:mysql://localhost:3306/testsb2mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#spring.jpa.show-sql=true
######mybatis配置 ######
mybatis.config-location=classpath:/mybatis/mybatis.xml
mybatis.mapper-locations=classpath:/mybatis/mapper/*.xml
继续
5.编写服务层,调用持久层接口(Mapper接口,比如EmpMapper.java)
5.1 创建EmpService接口,源码如下:
====>>> EmpService.java
package org.it.springboot4.service;
import org.it.springboot4.entity.Emp;
import org.it.springboot4.entity.custom.EmpCustom;
import java.util.List;
import java.util.Map;
public interface EmpService {
Emp getEmpById(Integer empno);
List<Map> getEmpByDeptnoSal(EmpCustom empCustom);
Integer insertEmp(Emp emp);
Integer insertGetEmp(Emp emp);
Integer deleteEmp(Map paramMap);
Integer updateEmp(Emp emp);
}
继续
5.2 创建EmpService接口的实现类EmpServiceImpl并且通过注解开启事务和进行事务控制
(不需要像以前一样再去配置Spring的事务配置文件了,只需要这个注解就OK,是不是方便了许多),源码如下(下面的事务简述很重要,记得要看):
====>>> EmpServiceImpl.java
package org.it.springboot4.service;
import org.it.springboot4.entity.Emp;
import org.it.springboot4.entity.custom.EmpCustom;
import org.it.springboot4.mapper.EmpMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
@Service
public class EmpServiceImpl implements EmpService{
@Resource//注入EmpMapper实现类(mybatis默认使用Cglib动态代理生成的EmpMapper接口的实现类)
private EmpMapper empMapper;
@Transactional(readOnly=true)
public Emp getEmpById(Integer empno) {
Emp emp = this.empMapper.findEmpById(empno);
return emp;
}
//查询研发部中薪资大于或等于6600的员工
@Override
public List<Map> getEmpByDeptnoSal(EmpCustom empCustom) {
List<Map> maps = this.empMapper.findEmpByDeptnoSal(empCustom);
return maps;
}
//添加一个新入职的员工
@Override
public Integer insertEmp(Emp emp) {
//影响的表中记录的条数,默认为空
Integer num = 0;
num = this.empMapper.createEmp(emp);
return num;
}
// 创建并映射当前新增加的员工编号(返回的还是影响的记录数)
public Integer insertGetEmp(Emp emp) {
Integer iInsert = 0;
iInsert = this.empMapper.createGetEmp(emp);
return iInsert;
}
//删除员工
@Override
public Integer deleteEmp(Map paramMap) {
Integer iDel = 0;
iDel = this.empMapper.deleteEmp(paramMap);
return iDel;
}
//更新员工
@Override
public Integer updateEmp(Emp emp) {
Integer iUpdate = 0;
iUpdate = this.empMapper.updateEmp(emp);
return iUpdate;
}
}
继续
在这里进行事务简述,@Transactional的常用方法(什么ACID概念的就不说了):
先来看看这个注解,
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
说明:
a.只读:readOnly() ,通常用于在查询方法上@Transactional(readOnly=true),是可以提高
效率的,默认为false
b.事务的传播特性:propagation(),说的直白一点"就是方法在调用的时候是开启一个新事
务,还是使用原来的事务这一类的操作"
感觉有点朦胧?这个东西在分布式数据源中就会发挥出明显的威力。
记得JPA中若果不开启事务,对于修改一类的操作是不成功的。但是在SSM中没有这个要求。
c.事务的隔离级别:isolation(),这个东西是来干嘛的?
若果你拿它来与线程中的概念进行对比,它就类似于java多线程和并发操作时DB所
采取的策略。 这个东西,好像需要DB来支持的,不能随意指定隔离级别,你得查看
你的DB所支持哪些隔离级别。
d.指定的异常及子异常进行事务回滚:rollbackFor(),
这个东西笔者常听人说,"哎呀,我这个业务操作失败了怎么部分数据还保存到DB中了"
若果你指定是的RuntimeException.class像java.text.ParseException是回滚不了的,
因为它不是RuntimeException的子类。
6.编写Web层(Controller+视图层)
请看博文"第2集 SpringBoot一天速成",地址:#更新中...