SpringBoot學習筆記(二)——Spring周邊生態系統

摘要

\quad 在前面的兩篇文章中,分別講解了Spring的IOC容器原理,以及如何從零開始建立一個Spring容器。可是實際工做中,光有這些確定是不夠的,還須要在這個基礎上再擴展數據庫、Redis緩存、消息隊列等。因此接下來就一步步的從無到有,擴展這個基本的Spring容器。
javascript

1.從Spring容器中引入Bean

\quad 首先咱們知道,通常狀況下,咱們會把業務邏輯分爲三層,既Controller,Service,Dao。css

  1. Controller層用以跟HTTP請求打交道。
  2. Service用於處理業務的具體邏輯。
  3. Dao只作與數據庫打交道的事情。

2.在Spring的基礎上增長Mybatis數據庫

2.1 配置數據庫

\quad 從引入Maven依賴開始,從官網中獲取SpringBoot的Maven依賴,接着引入數據庫,先使用最簡單的H2數據庫做爲例子。引入H2數據庫的Maven依賴以後,就能夠開始着手爲Spring配置數據庫了,在main目錄下新建resources文件夾,在其中新建application.properties文件,寫入基本配置信息:html

spring.datasource.url=jdbc:h2:file:C:/Users/catsme/Desktop/my-first-spring
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=org.h2.Driver
複製代碼

2.2 引入FlyWay數據庫自動遷移工具

\quad 設計數據庫:
前端

\quad 測試用數據:

User Id Name
User_1 1 大娃
User_2 2 二娃
User_3 3 三娃
User_4 4 四娃
User_5 5 五娃
User_6 6 六娃

Score Id User_id Score
Score_1 1 1 90
Score_2 2 2 91
Score_3 3 3 89
Score_4 4 4 88
Score_5 5 5 92
Score_6 6 6 94
Socre_7 7 2 2
Socre_8 8 4 3
在resources目錄下,新建db/migration/V1__CreateTables.sql文件,寫入sql語句:
--用戶表
create table user(name varchar(200),
id bigint primary key auto_increment);

--成績表
create table score(
id bigint primary key auto_increment,
user_id bigint,
Score bigint);

insert into user(name,id) values
('大娃',1),('二娃',2),('三娃',3),('四娃',4),('五娃',5),('六娃',6);

insert into score(id,user_id,score) values
    (1,1,90),(2,2,91),(3,3,89),(4,4,88),(5,5,92),(6,6,94),(7,2,2),(8,4,3);
複製代碼

添加如下信息至pom.xml中,用以引入flyway插件:java

<plugin>
         <groupId>org.flywaydb</groupId>
         <artifactId>flyway-maven-plugin</artifactId>
         <version>6.0.6</version>
         <configuration>
             <url>jdbc:h2:file:C:/Users/catsme/Desktop/my-first-spring</url>
             <user>root</user>
             <password>password</password>
          </configuration>
 </plugin>
複製代碼

接着,使用mvn flyway:migrate命令初始化數據庫,接下來就是引用MyBatis進行復雜的sql操做了。git

2.3 使用兩種方法在Spring中配置和引用MyBatis

  • (一) 使用註解的方式
    \quad 首先聲明一個接口:
@Mapper
public interface MyMapper {
    @Select("select * from user where id = #{}")
    User getUser(@Param("id") Integer id);
}
複製代碼

\quad 接着在mybatis目錄下的config.xml文件中的mapper塊中聲明該接口:
<mapper class="hello.dao.MyMapper"/>。到如今能夠發現,Spring關聯了MyBatis,MyBatis關聯了接口,那麼問題來了,接下來要怎麼實現這個MyMapper呢?
\quad 經過註解聲明他們之間的依賴關係,經過依賴注入實現這層關係。代碼以下:
github

//使用Autowired註解或者Resource註解注入依賴關係
 @Autowired
    private UserMapper myMapper;

    @RequestMapping("/getUser")
    @ResponseBody
    public User getUser(){
        return myMapper.getUserById(3);
    }
複製代碼

注意:如今最推薦的就是,引入@InjectMaven依賴以後在構造器中使用@Inject聲明注入依賴關係。好比這樣:spring

@Inject
    public OrderService(UserService userService) {
        this.userService = userService;
    }
複製代碼

那麼接下來就能夠在瀏覽器中經過訪問這個接口,獲取數據庫中的數據。 sql

  • (二)配置xml文件

\quad 如今有這樣一個需求:按總成績的降序,對用戶進行排序,這樣的話,就很差使用上面這種經過接口去實現的方式。 在db/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>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <typeAliases>
        <typeAlias alias="User" type="hello.entity.User"/>
        <typeAlias alias="ScoreItem" type="hello.entity.ScoreItem"/>
    </typeAliases>
    <mappers>
        <mapper resource="db/mybatis/MyMapper.xml"/>
        <mapper class="hello.dao.UserMapper"/>
    </mappers>
</configuration>
複製代碼

\quad注意:因爲已經在application.properties文件中已經綁定了數據庫基本信息,因此這時候已經不須要在xml文件中配置數據源了。直接着在Spring的application.properties文件中寫入MyBatis的聲明,代碼以下:

mybatis.config-location=classpath:db/mybatis/config.xml
複製代碼

接在在MyBatis的映射文件中寫好sql語句,代碼以下:

<?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="MyUserMapper">
    <select id="rankUser" resultMap="scoreItem">
        select t.user_id,t.score_sum,user.name as user_name from
        (select user_id,sum(score) as score_sum from score group by user_id)t
        inner join user
        on user.id = t.user_id
        order by t.score_sum
        desc
    </select>

    <!-- 很是複雜的結果映射 -->
    <resultMap id="scoreItem" type="ScoreItem">
        <result property="score" column="score_sum"/>
        <association property="user" javaType="User">
            <result property="name" column="user_name"/>
            <result property="id" column="user_id"/>
        </association>
    </resultMap>
</mapper>
複製代碼

\quad 到這裏,該配置好的信息基本都以配置完畢,接下來該進行的就是,經過分層的思想,在不一樣的邏輯層上實現對應的功能。 對於dao層,實現與數據庫的交互:

@Service
public class RankDao {

     @Autowired
     SqlSession sqlSession;

     public List<ScoreItem> getRankItem(){
          return sqlSession.selectList("MyUserMapper.rankUser");
     }
}
複製代碼

\quad 在這裏能夠看到,本來須要使用SqlSessionFactory獲取sqlSession,如今只須要在Spring中聲明Autowired而後直接建立實例便可調用sqlSession的方法。接下來在entiy層中建立實體對象,用以存儲從dao層拿到的數據,代碼:

public class ScoreItem {
    private Integer id;
    private Integer score;
    private User user;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }
}
複製代碼

\quad 在service層實現業務邏輯:

@Service
public class RankService {
    @Autowired
    private RankDao rankDao;


    public List<ScoreItem> sort() {
        return rankDao.getRankItem();
    }
}
複製代碼

最後在Controller層實現與用戶界面的交互:

@RestController
public class HelloController {

    @Autowired
    private RankService rankService;

    @RequestMapping("/getUser")
    @ResponseBody
    public List<ScoreItem> getUserFromDatabase() {
      return rankService.sort();
    }
}
複製代碼

最後結果以下:

\quad 能夠看到,這樣就從頭至尾實現了一個較小的業務邏輯,若是加上一些渲染的話,就能變成一個真正的頁面。

3.渲染HTML

\quad 從數據庫中拿出數據後,接下來要作的就是對頁面進行渲染了,這個過程前端跟後端均可以實現。

3.1 使用FreeMarker進行後端渲染

\quad 何謂模板引擎呢,源自百度百科 的解釋:模板引擎(這裏特指用於Web開發的模板引擎)是爲了使用戶界面與業務數據(內容)分離而產生的,它能夠生成特定格式的文檔,用於網站的模板引擎就會生成一個標準的HTML文檔。在這裏使用FreeMarker工具渲染頁面。
\quad 何謂FreeMarker呢,源自維基百科 的解釋: FreeMarker是一個基於Java的模板引擎,最初專一於使用MVC軟件架構生成動態網頁。可是,它是一個通用的模板引擎,不依賴於servlets或HTTP或HTML,所以它一般用於生成源代碼,配置文件或電子郵件。
\quad 因此咱們能夠經過FreeMarker來生成HTML頁面。引入FreeMarker的mavne依賴,根據官網提示:

resources
        ├── application.yml
        ├── data-h2.sql
        ├── schema-h2.sql
        ├── static
        │   └── css
        │       └── style.css
        └── templates   
            ├── index.ftl
            └── showCities.ftl
複製代碼

\quad咱們須要在resources目錄下建立一個templates文件夾,這樣FreeMarker默認會去templates文件夾中尋找。而後新建index.ftl文件,在.ftl模板文件中寫好初始格式,而後把內容傳入其中。.ftl文件中寫入HTML格式的代碼:

<!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>成績排行榜</title>
    </head>
    <body>
    <table>
        <thead>
        <tr>
            <th>用戶號碼</th>
            <th>成績</th>
            <th>用戶名</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>${index}</td>
            <td>${name}</td>
            <td>${score}</td>
        </tr>
        </tbody>
    </table>
    </body>
    </html>
複製代碼

\quad 在這裏定義好渲染的HTML文檔的模板以後,就是想辦法將數據傳入其中了。與MyBatis中相似,代碼以下:

@RequestMapping("/getUser")
    @ResponseBody
    public ModelAndView getUserFromDatabase() {
        Map<String, Object> model = new HashMap<>();
        model.put("index",1);
        model.put("name","zhangsan");
        model.put("score",97);
        //接受兩個參數,一個模板文件一個數據
        return new ModelAndView("index",model);
    }
複製代碼

結果:

\quad 能夠看到這時候,咱們就經過向模板文件中傳入參數,實現了對頁面的渲染。這只是測試一下效果,實際上咱們是須要經過循環將內容展示出來。那麼接下來就是把數據庫中真正的數據拿出來,放在頁面中了。問題來了: 從數據庫中拿到的是六條數據,那麼實現循環渲染呢? 查閱 FreeMarker官網後,修改模板文件中的部分代碼:

<thead>
    <tr>
        <th>序號</th>
        <th>成績</th>
        <th>姓名</th>
        <th>學號</th>
    </tr>
    </thead>
    <tbody>

    <#list items as item>
         <tr>
            <td>${item?index+1}</td>
            <td>${item.user.name}</td>
            <td>${item.score}</td>
            <td>${item.user.id}</td>
         </tr>
    </#list>
    </tbody
複製代碼

實現效果:

3.2 使用JS和JSON進行前端渲染

\quad 這裏本來是能夠直接使用前端的框架進行JS的設計的,可是爲了加深對先後端渲染的理解(其實是本身不會),因此使用最原始的方式進行,工做中千萬不要用!!!
\quad 在resources目錄下新建static文件夾,在這個文件夾中的內容能夠被直接訪問。在其中新建index.html頁面文檔,在文檔中寫入:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>成績排行榜</title>
</head>
<body>
<table id="rank-table">
    <thead>
    <tr>
        <th>序號</th>
        <th>成績</th>
        <th>姓名</th>
        <th>學號</th>
    </tr>
    
    </thead>
    <tbody>
    
    </tbody>
</table>
</body>
</html>
複製代碼

這時候是能夠經過瀏覽器直接訪問index.html的:

接下來在html中添加 script標籤,用以發送http請求:

<script>
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if( xhr.readyState == 4){
             if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
             var json = xhr.responseText;
             <!--後將獲取的結果打印至控制檯-->
             console.log(json);
          }
       }
    };
     <!--先經過getRankItem接口發送請求-->
        xhr.open("get", "/getRankItem", true);
        xhr.send(null);
    </script>
複製代碼

接下來就能夠在瀏覽器中看到獲取的JSON字符串:

\quad 如今須要作的是,經過javascript將script標籤中獲取的結果,拼接到html中,展現到頁面上。 注意:現實工做中不要這樣作! 現學現賣,使用最基礎的方式實現字符串的拼接,而後將其寫入html中:

<script>
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if( xhr.readyState == 4){
             if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
             var json = xhr.responseText;
             var list = JSON.parse(json);
             var str1 = '';
             var step;
             for (step = 0; step < 5; step++) {
                str1 += '<tr><td>'+(step+1)+'</td><td>'+list[step].score+'</td><td>'+list[step].user.name+'</td><td>'+list[step].user.id+'</td></tr> '
             }

             var str = '<tr><th>序號</th><th>成績</th><th>姓名</th><th>學號</th>'+str1+
             '<tr><td>6</td><td>'+list[5].score+'</td><td>'+list[5].user.name+'</td><td>'+list[5].user.id+'</td></tr>'

          document.getElementById('rank-table').innerHTML = str;
          }
       }
    };
        xhr.open("get", "/getRankItem", true);
        xhr.send(null);

    </script>
複製代碼

實現效果以下:

4. 報錯解決

4.1mvn flyway:migrate命令報錯:

-> Applied to database : 1062144176
-> Resolved locally : 1432425380
複製代碼

這種狀況須要刪除數據庫中的記錄:

或者直接使用mvn flyway:repair修復版本。

4.2 代碼檢查工具老是報File does not end with a newline.'錯誤

\quad 刪除.circle目錄下的

<module name="NewlineAtEndOfFile">
        <property name="lineSeparator" value="lf" />
    </module>
複製代碼

便可。

項目地址:github.com/Scott-YuYan…

5.參考資料

  1. 掘金 .《你的項目應該如何正確分層?》點擊此處查看源文檔

  2. CSDN 《Flyway Validate failed:migration checksum mismatch for migration 1.0.0003》點擊此處查看源文檔
相關文章
相關標籤/搜索