說明: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) {
//影響的表中記錄的條數,默認爲0
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(),說的直白一點"就是方法在調用的時候是開啓一個新事
務,還是使用原來的事務這一類的操作"
感覺有點朦朧?這個東西在分佈式數據源中就會發揮出明顯的威力。
記得在EJB JPA中若果不開啓事務,對於修改一類的操作是不成功的。但是在SSM中沒有這個要求。
c.事務的隔離級別:isolation(),這個東西是來幹嘛的?
若果你拿它來與線程中的概念進行對比,它就類似於java多線程和併發操作時DB所
採取的策略。 這個東西,好像需要DB來支持的,不能隨意指定隔離級別,你得查看
你的DB所支持哪些隔離級別。
d.指定的異常及子異常進行事務回滾:rollbackFor(),
這個東西筆者常聽人說,"哎呀,我這個業務操作失敗了怎麼部分數據還保存到DB中了"
若果你指定是的RuntimeException.class像java.text.ParseException是回滾不了的,
因爲它不是RuntimeException的子類。
6.編寫Web層(Controller+視圖層)
請看博文"第2集 SpringBoot一天速成",地址:https://blog.csdn.net/Netaa001/article/details/84722496