做者:追夢1819
原文:https://www.cnblogs.com/yanfei1819/p/10936304.html
版權聲明:本文爲博主原創文章,轉載請附上博文連接!
html
總結前面幾章,咱們瞭解了 SpringBoot 的基本用法及其配置,整合各大 ORM 框架,並瞭解了 Thymelaf 的基本用法。java
本章將綜合前面的知識,作一個完整Java web 的增刪改查的示例。一來是對知識的整合,二來是考慮到不少讀者是新手,一個完整的示例可能更加有助於其對 SpringBoot 的理解和掌握。mysql
前面的ORM 框架有多種,本章中選取的是 MyBatis(沒有使用 MyBatis 相關插件) ,做者比較喜歡該框架,同時在行業中的應用也很普遍。git
本示例中,創建手機表,字段包括:名稱、價格、顏色和生產日期。github
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; CREATE TABLE `mobile_phone` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名稱', `price` decimal(7, 2) NOT NULL COMMENT '價格', `color` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '顏色', `production_date` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL COMMENT '生產日期', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact; INSERT INTO `mobile_phone` VALUES (1, '蘋果', 6988.00, '銀色', '2018-12-12'); INSERT INTO `mobile_phone` VALUES (2, '華爲', 3988.00, '白色', '2019-12-09'); SET FOREIGN_KEY_CHECKS = 1;
如下是做者用 idea 建立的示例項目:web
項目結構是做者的我的習慣,基本也符合 Java Web 的分層結構。下面也再次說明一下項目結構的含義:spring
com.yanfei1819.springbootmybatisthymeleafdemo.db.dao
sql
項目的持久化層,與數據庫交互;數據庫
com.yanfei1819.springbootmybatisthymeleafdemo.db.dto
json
與數據庫交互的實體類;
com.yanfei1819.springbootmybatisthymeleafdemo.entity.response
接口返回的參數實體類;
com.yanfei1819.springbootmybatisthymeleafdemo.entity.vo
與頁面交互的實體類;
com.yanfei1819.springbootmybatisthymeleafdemo.service
項目業務層的接口和實現類;
com.yanfei1819.springbootmybatisthymeleafdemo.web.controller
項目的 controller 層,外部直接訪問;
com.yanfei1819.springbootmybatisthymeleafdemo.SpringbootMybatisThymeleafDemoApplication
項目入口啓動類;
\src\main\resources\static
存放項目靜態資源文件;
\src\main\resources\templates
SpringBoot 默認的模板引擎存放位置(可自定義)。
一、 代碼是按照做者的以往的編寫習慣寫的,並不是標準,僅供你們參考;
二、 示例中的代碼,都是嚴格按照分層的,包括數據接收的實體類;
三、 有讀者有疑問,項目中爲何會有兩個屬性徹底一致的實體類,xxxDTO 和 xxxVO ?其實這是爲了增長項目的擴展性和健壯性而設的,xxxDTO 與數據庫交互,xxxVO 與頁面交互,嚴格分層了。其實實體類的種類根據項目規模大小而定,項目越大,可能定義的實體類的種類越多。名稱能夠參照《阿里巴巴Java開發手冊》:
四、 示例代碼,做者雖然儘可能遵照了代碼規範,可是因爲篇幅所限,仍是簡化了邏輯,只演示了基本的功能。時間項目中的業務邏輯可能比這個複雜不少,好比,實際項目中可能有分頁查詢、條件查詢、排序等。因此讀者要注意;
五、 在本文中,通用因爲篇幅的緣由,只列出示例中的核心代碼,若是讀者想獲取完整的代碼,能夠移步到 本人的GitHub 進行下載;
六、 示例中只作了功能的演示,沒有 CSS 樣式,讀者可自行添加。
1、引入 maven 依賴:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies>
2、配置相關的信息:
### 數據庫信息 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root ### 模板引擎 spring.thymeleaf.servlet.content-type=text/html spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html ### 駝峯命名法轉換 mybatis.configuration.map-underscore-to-camel-case=true
其他的信息,可自行配置。
3、建立 db 層:
實體類:
public class MobilePhoneDTO { private Long id; private String name; private Double price; private String color; private String productionDate; // get/set 省略 }
dao類:
public interface MobilePhoneDAO { @Select("select * from mobile_phone ") List<MobilePhoneDTO> listMobilePhones(); @Select("select * from mobile_phone where id = #{id}") MobilePhoneDTO getMobilePhoneById(Long id); @Update("insert into mobile_phone(`name`,price,color,production_date) values(#{name},#{price},#{color},#{productionDate}") int insertMobilePhone(MobilePhoneDTO dto); @Update("UPDATE mobile_phone set `name`=#{name},price=#{price},color=#{color},production_date=#{productionDate} WHERE id=#{id}") int updateMobilePhone(MobilePhoneDTO dto); @Delete("DELETE FROM mobile_phone WHERE id = #{id}") int deleteMobilePhoneById(Long id); }
4、建立 service 層:
接口:
public interface MobilePhoneService { List<MobilePhoneVO> listMobilePhones(); MobilePhoneVO getMobilePhoneById(Long id); BaseResponse updateMobilePhone(MobilePhoneVO vo); BaseResponse insertMobilePhone(MobilePhoneVO vo); BaseResponse deleteMobilePhoneById(Long id); }
實現類:
@Service public class MobilePhoneServiceImpl implements MobilePhoneService { @Autowired private MobilePhoneDAO mobilePhoneDAO; @Override public List<MobilePhoneVO> listMobilePhones() { List<MobilePhoneDTO> dtos = mobilePhoneDAO.listMobilePhones(); List<MobilePhoneVO> vos = new ArrayList<>(); for (MobilePhoneDTO dto : dtos) { MobilePhoneVO vo = new MobilePhoneVO(); BeanUtils.copyProperties(dto,vo); vos.add(vo); } return vos; } @Override public MobilePhoneVO getMobilePhoneById(Long id) { MobilePhoneDTO dto = mobilePhoneDAO.getMobilePhoneById(id); MobilePhoneVO vo = new MobilePhoneVO(); BeanUtils.copyProperties(dto,vo); return vo; } @Override public BaseResponse updateMobilePhone(MobilePhoneVO vo) { MobilePhoneDTO dto = new MobilePhoneDTO(); BeanUtils.copyProperties(vo,dto); int updateCount = mobilePhoneDAO.updateMobilePhone(dto); if(updateCount<1){ return new BaseResponse("數據更新失敗"); } return new BaseResponse(); } @Override public BaseResponse insertMobilePhone(MobilePhoneVO vo) { MobilePhoneDTO dto = new MobilePhoneDTO(); BeanUtils.copyProperties(vo,dto); int insertCount = mobilePhoneDAO.insertMobilePhone(dto); if(insertCount<1){ return new BaseResponse("數據插入失敗"); } return new BaseResponse(); } @Override public BaseResponse deleteMobilePhoneById(Long id) { int deleteCount = mobilePhoneDAO.deleteMobilePhoneById(id); if(deleteCount<1){ return new BaseResponse("數據刪除失敗"); } return new BaseResponse(); } }
以上的實現中,包含了增刪改查等功能。
此處爲了更加友好的返回數值,增長了 BaseResponse 類,該類是:
public class BaseResponse<T> { private Integer code; private String msg; private T data; // set/get 省略 public static BaseResponse defaultNo(String msg) { return new BaseResponse(1,msg); } public static BaseResponse defaultOk() { return new BaseResponse(); } public BaseResponse() { this.code = 0; this.msg = "success"; } public BaseResponse(String msg) { this.code = 1; this.msg = msg; } public BaseResponse(T data) { this.data = data; this.code = 0; this.msg = "success"; } public BaseResponse(Integer code, String msg){ this.code = code; this.msg = msg; } }
細心的讀者可能會發現以上的一個細節,有的方法返回了 BaseResponse,可是有的方法直接返回了頁面的實體類 MobilePhoneVO。
此處爲了作演示,特地作了兩種返回參數處理狀況。一般狀況下,咱們在開發先後端分離項目的時候,都會將返回的數值封裝爲 json 格式,以便後端能夠與 PC 端和 APP 端同時進行交互。若是非先後端分離,那基本就不作要求了。
不過,做者給你們的建議是,能統一格式時儘可能統一,代碼看起來也更加優雅一些。
5、建立 controller 層:
@Controller @RequestMapping("/mobile/phone") public class MobilePhoneController { @Autowired private MobilePhoneService service; @GetMapping("/listMobilePhones") public String listMobilePhones(Model model){ List<MobilePhoneVO> vos = service.listMobilePhones(); model.addAttribute("response",vos); return "mobilephoneList"; } @GetMapping("/get/{id}") @ResponseBody public BaseResponse getMobilePhoneById(@PathVariable Long id){ MobilePhoneVO vo = service.getMobilePhoneById(id); return new BaseResponse(vo); } @PostMapping("/insertMobilePhone") @ResponseBody public BaseResponse insertMobilePhone(@RequestBody MobilePhoneVO vo){ return service.insertMobilePhone(vo); } // 進入編輯頁面 @GetMapping("/toEditMobilePhone") public String toAddMobilePhone(Model model,Long id){ MobilePhoneVO vo = service.getMobilePhoneById(id); model.addAttribute("vo",vo); return "toEditMobilePhone"; } @PostMapping("/updateMobilePhone") @ResponseBody public String updateMobilePhone(@RequestBody MobilePhoneVO vo){ service.updateMobilePhone(vo); return "redirect:mobilephoneList"; // 跳轉至列表頁 } @GetMapping("/delete/{id}") @ResponseBody public BaseResponse deleteMobilePhoneById(@PathVariable Long id){ return service.deleteMobilePhoneById(id); } }
controller 層包括增刪改查接口,同時提供頁面跳轉的接口(此處只作了編輯功能,其他的都相似)。在作增刪改後,通常是跳轉至列表頁面。固然,你也能夠加入其它的交互邏輯。
6、建立頁面:
列表頁 mobilephoneList:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>追夢1819的SpringBoot教程</title> <style> table, table tr th, table tr td { border: 1px solid #0094ff; } </style> </head> <body> <div class="container-fluid"> <div class="row"> <main role="main"> <div class="content_bottom_right" id="mobilephoneList"> <div class="input-group"> <table class="table text-nowrap imagetable"> <thead> <tr> <th>序號</th> <th>名稱</th> <th>價格</th> <th>顏色</th> <th>生產日期</th> <th>操做</th> </tr> </thead> <tbody th:each="mobilephone,item:${response}"> <tr> <td>[[${item.count}]]</td> <td>[[${mobilephone.name}]]</td> <td>[[${mobilephone.price}]]</td> <td>[[${mobilephone.color}]]</td> <td>[[${mobilephone.productionDate}]]</td> <td> <a>詳情</a> <a th:href="@{/mobile/phone/toEditMobilePhone(id=${mobilephone.id})}">編輯</a> <a>刪除</a> </td> </tr> </tbody> </table> </div> </div> </main> </div> </div> </body> </html>
添加頁:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>追夢1819的SpringBoot教程</title> </head> <body class="container"> <br/> <h2>修改手機</h2> <br/> <div> <form class="form-horizontal" th:action="@{/mobile/phone/updateMobilePhone}" th:object="${vo}" method="post"> <div> <label>名稱</label> <input name="name" id="name" th:value="*{name}"> </div> <div> <label>顏色</label> <input name="color" id="color" th:value="*{color}"> </div> <div> <label>價格</label> <input name="price" id="price" th:value="*{price}"> </div> <div> <label>價格</label> <input name="productionDate" id="productionDate" th:value="*{productionDate}"> </div> <input type="submit" value="添加"/> </form> </div> </body> </html>
以上頁面說明幾點:
xmlns:th="http://www.thymeleaf.org"
;最後,能夠看看效果:
最後,補充一些關於thymelaf經常使用的屬性值配置:
# THYMELEAF (ThymeleafAutoConfiguration) #開啓模板緩存(默認值:true) spring.thymeleaf.cache=true #Check that the template exists before rendering it. spring.thymeleaf.check-template=true #檢查模板位置是否正確(默認值:true) spring.thymeleaf.check-template-location=true #Content-Type的值(默認值:text/html) spring.thymeleaf.content-type=text/html #開啓MVC Thymeleaf視圖解析(默認值:true) spring.thymeleaf.enabled=true #模板編碼 spring.thymeleaf.encoding=UTF-8 #要被排除在解析以外的視圖名稱列表,用逗號分隔 spring.thymeleaf.excluded-view-names= #要運用於模板之上的模板模式。另見StandardTemplate-ModeHandlers(默認值:HTML5) spring.thymeleaf.mode=HTML5 #在構建URL時添加到視圖名稱前的前綴(默認值:classpath:/templates/) spring.thymeleaf.prefix=classpath:/templates/ #在構建URL時添加到視圖名稱後的後綴(默認值:.html) spring.thymeleaf.suffix=.html #Thymeleaf模板解析器在解析器鏈中的順序。默認狀況下,它排第一位。順序從1開始,只有在定義了額外的TemplateResolver Bean時才須要設置這個屬性。 spring.thymeleaf.template-resolver-order= #可解析的視圖名稱列表,用逗號分隔 spring.thymeleaf.view-names=
至此,基本完成了 SpringBoot + MyBatis + Thymelaf 的綜合演示。功能很簡單,用法也很簡單,只不過作了總體的綜合。本章中演示的 ORM 框架是 MyBatis,讀者能夠自行將 SpringBoot + Thymelaf + 其餘 ORM 框架整合,以加深理解。
源碼:個人GitHub