SpringMVC4+thymeleaf3的一個簡單例項(篇五:頁面和MySql的資料互動-展示以及儲存)
這一篇將介紹怎樣把頁面資料儲存的MySql資料庫,並將資料庫內容展示到頁面上。
首先做一個基礎工作,新增以下jar到lib:
2: spring-jdbc-4.3.3.RELEASE.jar
3: spring-tx-4.3.3.RELEASE.jar
2和3從spring framework釋出包裡面找。
繼續沿用前面篇節的程式程式碼。我們開始吧!
一、建立資料庫
開啟ubuntu終端,輸入命令: mysql -u root -p,提示輸入使用者root的密碼後即可進入資料庫,你也可用其它有建立資料庫許可權的使用者進入:
建立名為test的schema(資料庫):CREATE SCHEMA `test` DEFAULT CHARACTER SET utf8 ;
完成後進入test資料庫:mysql> use test;
建立資料表:
CREATE TABLE `animals` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) DEFAULT NULL, `count` int(11) DEFAULT NULL, `memo` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id_UNIQUE` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
插入幾條資料:
INSERT INTO animals(name, count, memo) VALUES('大馬猴', 10, '散養');
INSERT INTO animals(name, count, memo) VALUES('小綿陽', 8, '圈養');
INSERT INTO animals(name, count, memo) VALUES('火星猿', 1, '圈養');
我們使用select * from animals;看看結果:
大功告成!
以上所有操作都可通過MysqlWorkbench圖形介面來操作完成,介面是這個樣子:
二、在Spring中配置MySql資料庫
新增以下程式碼到spring-mvc.xml檔案
<context:component-scan base-package="com.zoo.dao"/>
<context:component-scan base-package="com.zoo.service"/>
<!-- 資料來源配置 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
掃描dao包和service包以便讓spring自動繫結程式碼中用到的元件(用@Autowired標註的程式碼)。
資料來源讓spring來管理,記得把password改成你自己的哦。重點說一下url屬性,格式為 jdbc:mysql://host:port/database?prams,其中host是資料庫所在伺服器的ip或者名稱;port為埠號,預設是3306;使用test資料庫(我在我的資料庫中建立了一個名叫test的庫);問號後面是各種引數,本例設定了3個。
注意useUnicode和characterEncoding這兩個引數,為了確保儲存到資料庫的字元不出現亂碼,記得把它們設定成useUnicode=true&characterEncoding=UTF-8,否則很有可能在開發的時候碰到:頁面傳到後臺程式的字元是正常的,但是儲存到資料庫就是亂碼了。
另外細心的同學已經發現url的字串裡怎麼會有”&“,這是因為”&“符號對xml來說是個特殊字元,如果不將其轉義為"&",你會收到一個解析exception,類似這個:org.xml.sax.SAXParseException; lineNumber:
24; columnNumber: 95; 對實體 "characterEncoding" 的引用必須以 ';' 分隔符結尾?
三、新增幾個java類
(1)新建三個包:com.zoo.service,com.zoo.service.impl,com.zoo.dao,com.zoo.entity
(2)在com.zoo.entity中新增類AnimalEntity.java,對應資料表內的一條資料,從資料庫取出的資料會放在這個類的例項中
package com.zoo.entity;
public class AnimalEntity {
//資料庫自動生成的id
private Long id;
//動物名稱
private String name;
//動物數量
private Integer count;
//備註
private String memo;
//getters and setters
}
(3)在com.zoo.dao內新增AnimalDAO.java,dao用於操作資料表(增刪改查等)
package com.zoo.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import com.zoo.entity.AnimalEntity;
@Repository
public class AnimalDAO {
@Autowired
private JdbcTemplate jdbcTmplt;
//從animals表檢索出所有資料
public List<AnimalEntity> getAll() {
String sql = "SELECT id, name, count, memo FROM animals";
List<AnimalEntity> list = this.jdbcTmplt.query(sql, new BeanPropertyRowMapper<AnimalEntity>(AnimalEntity.class));
return list;
}
//插入一條資料到animals表
public int insertOne(AnimalEntity entity){
int cnt = this.jdbcTmplt.update("INSERT INTO animals(name, count, memo) VALUES(?, ?, ?)",
entity.getName(), entity.getCount(), entity.getMemo());
return cnt;
}
}
解釋:
@Service標註,還記得上面spring-mvc.xml中的context:component-scan麼標籤?它用於掃描指定包下(含子包)所有帶@Component, @Service, @Controller以及@Repository的類,並將其註冊到spring容器,以供其它程式碼使用。spring推薦將@Service用於業務邏輯層,@Controller用於控制層,@Repository用於持久化層。
@Autowired標註的欄位,spring容器會自動從已經註冊的元件中找到對應的component,並將其繫結。
注意:在getAll方法中我們用到了spring提供的一個非常實用的工具類:BeanPropertyRowMapper,它的作用就是將資料表裡每條資料填充到指定類中,用了它好省心呀。注意指定類裡的欄位和資料表的欄位名稱要保持一致哦。
(4)在com.zoo.service裡新增介面類AnimalService.java,controller會呼叫service層的方法
package com.zoo.service;
import java.util.List;
import com.zoo.entity.AnimalEntity;
public interface AnimalService {
public List<AnimalEntity> getAllAnimals();
public int insertOne(AnimalEntity entity);
}
(5)在com.zoo.service.impl中新增AnimalService的實現類AnimalServiceImpl.java:
package com.zoo.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zoo.dao.AnimalDAO;
import com.zoo.entity.AnimalEntity;
import com.zoo.service.AnimalService;
@Service
public class AnimalServiceImpl implements AnimalService {
@Autowired
private AnimalDAO dao;
@Override
public List<AnimalEntity> getAllAnimals() {
return dao.getAll();
}
@Override
public int insertOne(AnimalEntity entity) {
return dao.insertOne(entity);
}
}
(6)修改ZooController,定義AnimalService欄位並將其標註為自動繫結@Autowired;修改showZooList方法,呼叫service取出資料庫資料
@Autowired
private AnimalService service;
@RequestMapping(path = "/list", method = RequestMethod.GET)
public ModelAndView showZooList(){
//從資料庫取出資料
List<AnimalEntity> animals = service.getAllAnimals();
ModelAndView mav = new ModelAndView();
mav.setViewName("zoolist");
mav.addObject("animalForm", new AnimalForm());
mav.addObject("animalsList", animals);
return mav;
}
我們呼叫service的getAllAnimals方法,取得動物列表,並將這個list傳遞給頁面用於展示。
(7)修改zoolist.html,由於我們在頁面上一直用的是靜態資料,現在有了資料庫就可以用動態的了,但是需要修改程式碼以便顯示list中的內容,只修改table那段
<table border="1">
<thead>
<tr>
<th>序號</th>
<th>動物名稱</th>
<th>數量</th>
<th>備註</th>
</tr>
</thead>
<tbody th:remove="all-but-first">
<tr th:each="obj, objStat: ${animalsList}">
<td th:text="${objStat.count}">1</td>
<td th:text="${obj.name}">大馬猴</td>
<td th:text="${obj.count}">10</td>
<td th:text="${obj.memo}">機靈古怪,俏皮活潑</td>
</tr>
<tr>
<td>2</td>
<td>大熊貓</td>
<td>80</td>
<td>體型笨重,喜歡吃竹子</td>
</tr>
<tr>
<td>3</td>
<td>澳洲羊駝</td>
<td>13</td>
<td>長相奇特,大國人俗稱其草泥馬</td>
</tr>
<tr>
<td>4</td>
<td>峨眉山猴</td>
<td>90</td>
<td>不怕人,有時候發賤搶遊客麵包吃</td>
</tr>
</tbody>
</table>
注意:我們在table裡增加了thead和tbody標籤,用於將table分成兩部分;
在tbody標籤中的th:remove="all-but-first",意思是隻保留tbody中第一個子標籤,其它子標籤全都刪掉,什麼意思呢,讓我們先看看tbody裡的內容:它有4組tr標籤,也就是有4條靜態資料,當thymeleaf解析到這裡的時候一看有個th:remove="all-but-first",好吧,它就會把第一組tr保留,剩下的三個給刪掉,等下執行畫面讓你有個直觀感受。th:remove的5個備選值及其含義:
all:刪除所在的標籤以及所在標籤的所有子節點
body:除所在標籤外,刪除所有所在標籤的子節點
tag:刪除所在標籤,但保留所在標籤的子節點
all-but-first:刪除除所在標籤第一個子節點外的所有其他子節點
none:不做任何事情,等同於不宣告th:remove表示式
<tr th:each="obj, objStat: ${animalsList}">,裡面的th:each表示式意思是把${animalList}變數進行迭代,以將list裡的所有資料條目顯示出來。注意前面的兩個變數obj和objStat,obj表示list裡面的具體例項,我們這裡是AnimalEntity的例項;objStat是一個狀態變數,表示迭代的當前狀態,這個狀態變數包含以下屬性,程式碼中可直接使用:
index:當前迭代的index,從0開始
count:當前迭代的index,從1開始
size:迭代變數所含元素總數
current:表示當前迭代的元素,也就是某個AnimalEntity的例項
even/odd:布林值,表示當前迭代是奇數還是偶數
first:布林值,表示當前迭代是不是第一條記錄
last:布林值,表示當前迭代是不是最後一條記錄
我們執行tomcat看看:
哇,資料庫的資料出來了,是我們想要的結果。這就是thymeleaf不同於其它template(比如jsp,freeMarker,volecity等)的地方,同一個頁面既可用於展示靜態資料也可以用於執行動態資料。
如果把th:remove去掉會是怎樣的效果呢:
嗯,聰明的你看懂了吧!有興趣你還可以試一試th:remove其它的值。
ok,接下來我們製作最後一個步驟:插資料庫。
四、儲存資料到資料庫
修改ZooCotroller,增加copyDataFromForm2Entity方法將form裡的資料copy到entity中;
在doAdd方法中呼叫service的insertOne方法儲存資料;
完整程式碼:
package com.zoo.web.controller;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.zoo.entity.AnimalEntity;
import com.zoo.service.AnimalService;
import com.zoo.web.form.AnimalForm;
@Controller
public class ZooController {
@Autowired
private AnimalService service;
@RequestMapping(path = "/list", method = RequestMethod.GET)
public ModelAndView showZooList(){
//從資料庫取出資料
List<AnimalEntity> animals = service.getAllAnimals();
ModelAndView mav = new ModelAndView();
mav.setViewName("zoolist");
mav.addObject("animalForm", new AnimalForm());
mav.addObject("animalsList", animals);
return mav;
}
@RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)
public String doAdd(Model model, @Valid AnimalForm form, BindingResult result){
if(result.hasErrors()){
model.addAttribute("MSG", "出錯啦!");
}else{
//儲存資料到資料庫
service.insertOne(this.copyDataFromForm2Entity(form));
model.addAttribute("MSG", "提交成功!");
}
//從資料庫取出資料
List<AnimalEntity> animals = service.getAllAnimals();
model.addAttribute("animalsList", animals);
return "zoolist";
}
//把form裡的資料copy到entity中
private AnimalEntity copyDataFromForm2Entity(AnimalForm form){
AnimalEntity entity = new AnimalEntity();
entity.setName(form.getOname());
entity.setCount(Integer.valueOf(form.getOcount()));
entity.setMemo(form.getMemo());
return entity;
}
}
刪除之前的system.out.print語句,在資料儲存後,需要重新從資料庫選出資料以重新整理畫面。
試一試吧!
聰明的你一定做出來了吧!
我們的例項小製作也就到這裡結束了,希望這些程式碼能讓你對springMVC+thymeleaf+mysql有所瞭解,那我也就開心了!
末語:
在這個例項中,我僅簡單的介紹了最基本的一些用法,希望能幫助到你們。本人水平有限,也只能寫成這樣了,如果哪裡寫錯了請毫無保留的披頭蓋臉的向我指出來,在下必虛心改之!
springMVC和thymeleaf都是非常優秀的開源專案,而且相應的文件也很詳細,如果大家遇到了問題,請先查閱文件以及API,應該會讓你找到答案的。