久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

SpringBoot+Thymeleaf+AdminLTE后臺(tái)CRUD實(shí)戰(zhàn)

SpringBoot+Thymeleaf+AdminLTE后臺(tái)CRUD實(shí)戰(zhàn) 做過(guò)后臺(tái)管理系統(tǒng)的人大概都遇到過(guò)一個(gè)岔路口一個(gè)只有十來(lái)個(gè)人用的內(nèi)部工具需求三天兩頭改前端要做的其實(shí)就是列表、表單、彈窗、刪除確認(rèn)這幾件事這時(shí)候如果上來(lái)就搞前后端分離光是接口聯(lián)調(diào)、跨域、權(quán)限透?jìng)?、部署兩套產(chǎn)物就能耗掉大半工期。我前陣子接手的一個(gè)運(yùn)維臺(tái)賬系統(tǒng)就是這么個(gè)場(chǎng)景十來(lái)個(gè)頁(yè)面二十多張表交付周期四周最后定下來(lái)的技術(shù)組合就是標(biāo)題里這四樣SpringBoot 打底、MyBatis-Plus 干數(shù)據(jù)層、Thymeleaf 渲染頁(yè)面、AdminLTE 套殼。整套東西跑起來(lái)增刪改查這類活兒的開發(fā)節(jié)奏會(huì)非??煲粋€(gè)標(biāo)準(zhǔn)模塊從建表到頁(yè)面能點(diǎn)熟練的話兩三個(gè)小時(shí)就能出一版。這篇內(nèi)容想聊的就是這套組合在真實(shí)項(xiàng)目里的落地細(xì)節(jié)不是官方文檔的復(fù)述。適合的人大概有三類剛接觸 SpringBoot 想做點(diǎn)完整東西練手的手上有個(gè)內(nèi)部系統(tǒng)要快速交付、不想被前端工程化拖住的以及已經(jīng)會(huì)用這套棧但總在分頁(yè)、表單回顯、靜態(tài)資源這些地方反復(fù)卡殼的。我會(huì)把依賴版本的坑、MyBatis-Plus 分頁(yè)插件的正確姿勢(shì)、AdminLTE 接 Thymeleaf 的布局復(fù)用方式、還有增刪改查四個(gè)動(dòng)作里那些文檔不會(huì)寫的細(xì)節(jié)一條一條攤開講。中間穿插的配置和代碼都是可以直接抄去改的遇到需要取舍的地方我會(huì)說(shuō)清楚為什么這么選。1. 先想清楚這套四件套各自的邊界在哪1.1 服務(wù)端渲染在內(nèi)部系統(tǒng)里的性價(jià)比賬選型這件事最怕的是拿互聯(lián)網(wǎng) C 端的標(biāo)準(zhǔn)去套內(nèi)部管理系統(tǒng)。C 端產(chǎn)品用戶量大、交互復(fù)雜、首屏性能敏感前后端分離帶來(lái)的收益能覆蓋掉工程復(fù)雜度。但內(nèi)部臺(tái)賬、審批、配置管理這類系統(tǒng)頁(yè)面數(shù)量有限、交互模式高度重復(fù)、用戶就那幾十個(gè)首屏慢個(gè)三百毫秒沒(méi)人在意反而更在意這個(gè)字段能不能加一列這個(gè)查詢條件能不能多一個(gè)這種需求變更的速度。服務(wù)端渲染在這個(gè)場(chǎng)景下的優(yōu)勢(shì)很直接一個(gè) Controller 方法配一個(gè)模板數(shù)據(jù)從數(shù)據(jù)庫(kù)到頁(yè)面是一條直線沒(méi)有中間層。改一個(gè)字段動(dòng)的是實(shí)體類、Mapper 不用動(dòng)、模板加一行、Controller 加一個(gè)取值五分鐘的事。換成前后端分離同樣的改動(dòng)要?jiǎng)?DTO、接口、前端 model、前端表單、可能還有類型定義五個(gè)文件起步還得等前端同學(xué)排期。代價(jià)也要說(shuō)清楚。Thymeleaf 的模板語(yǔ)法是在 HTML 屬性上做文章邏輯復(fù)雜了會(huì)很難看超過(guò)三層的條件嵌套基本就沒(méi)法維護(hù)了局部刷新能力弱想要個(gè)下拉聯(lián)動(dòng)、表格無(wú)刷新編輯就得自己寫零散的 JSSEO 完全談不上不過(guò)內(nèi)部系統(tǒng)也不需要。我的判斷標(biāo)準(zhǔn)很簡(jiǎn)單如果這個(gè)系統(tǒng)的主要使用者是公司內(nèi)部員工、頁(yè)面總數(shù)在五十個(gè)以內(nèi)、沒(méi)有復(fù)雜的前端狀態(tài)管理需求這套組合就是劃算的如果要做的是面向外部用戶的產(chǎn)品或者有大量實(shí)時(shí)交互那就老老實(shí)實(shí)上分離架構(gòu)。1.2 四個(gè)組件各管一段別讓職責(zé)串味實(shí)際寫代碼時(shí)最常見(jiàn)的混亂是把本該在 Service 層的邏輯塞進(jìn) Controller或者把查詢條件拼裝散落在模板里。這套棧里四樣?xùn)|西的職責(zé)其實(shí)很清晰組件負(fù)責(zé)的事不該干的事SpringBoot容器、依賴注入、配置、事務(wù)邊界不寫業(yè)務(wù)規(guī)則MyBatis-Plus單表 CRUD、條件構(gòu)造、分頁(yè)、邏輯刪除不處理展示格式、不做權(quán)限判斷Thymeleaf數(shù)據(jù)渲染、條件展示、循環(huán)、格式化不拼查詢條件、不做業(yè)務(wù)計(jì)算AdminLTE頁(yè)面骨架、樣式、常用交互組件不承載業(yè)務(wù)邏輯一個(gè)典型的分層寫法是Controller 只做參數(shù)接收、調(diào)用 Service、往 Model 里塞數(shù)據(jù)、返回視圖名Service 管事務(wù)和業(yè)務(wù)規(guī)則比如用戶名不能重復(fù)刪除前要檢查有沒(méi)有關(guān)聯(lián)數(shù)據(jù)Mapper 只管數(shù)據(jù)訪問(wèn)。Thymeleaf 模板里只做展示判斷比如狀態(tài)字段是 0 還是 1 決定顯示什么顏色的標(biāo)簽。這個(gè)邊界守住了后面加需求才不會(huì)牽一發(fā)動(dòng)全身。1.3 什么時(shí)候該果斷放棄這套方案我不太喜歡某某技術(shù)已死這種論調(diào)但確實(shí)有幾類需求不適合硬套。一是需要大量圖表實(shí)時(shí)刷新的看板Thymeleaf 渲染完就定死了后續(xù)全靠手寫 JS 輪詢不如直接上圖表庫(kù)配接口二是移動(dòng)端適配要求高的場(chǎng)景AdminLTE 是桌面優(yōu)先的布局雖然響應(yīng)式做了但在手機(jī)上體驗(yàn)一般三是需要多人協(xié)同編輯同一份數(shù)據(jù)的場(chǎng)景服務(wù)端渲染那套表單提交模型處理不了沖突合并。碰到這三類趁早換方案別等到寫了一半再返工。2. 骨架搭建依賴順序和版本對(duì)齊比想象中重要2.1 pom 里的依賴清單版本別隨手寫新建工程的時(shí)候最容易出事的就是版本。SpringBoot 版本、MyBatis-Plus 版本、Thymeleaf 版本三者之間有隱性約束尤其是 MyBatis-Plus它跟 SpringBoot 的適配是按大版本對(duì)應(yīng)的3.5.x 系列對(duì) SpringBoot 2.x 和 3.x 的支持情況不一樣。我的做法是先用 Spring Initializr 生成一個(gè)干凈的骨架選定 SpringBoot 版本然后把 MyBatis-Plus 的版本號(hào)顯式寫上不依賴父 POM 的默認(rèn)管理。dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies這里有兩個(gè)細(xì)節(jié)值得單獨(dú)拎出來(lái)。第一spring-boot-starter-validation必須單獨(dú)引入SpringBoot 2.3 之后校驗(yàn)相關(guān)的包已經(jīng)從 web starter 里剝離了不引這個(gè)Valid注解會(huì)靜默失效——注意是靜默不報(bào)錯(cuò)表單提交什么校驗(yàn)都不觸發(fā)很容易查半天。第二MySQL 驅(qū)動(dòng)在較新的 SpringBoot 里坐標(biāo)改成了com.mysql:mysql-connector-j老項(xiàng)目里常見(jiàn)的mysql:mysql-connector-java雖然還能用但會(huì)有告警新項(xiàng)目直接寫新的。如果你用的是 SpringBoot 3.xMyBatis-Plus 的 starter 也要換成mybatis-plus-spring-boot3-starter這個(gè)坐標(biāo)差異在官方文檔里不算顯眼但包名不一樣直接復(fù)制 2.x 的配置會(huì)啟動(dòng)失敗報(bào)找不到自動(dòng)配置類。2.2 application.yml 里必須動(dòng)的那幾項(xiàng)配置文件這塊默認(rèn)值大多能用但有四項(xiàng)我每次都會(huì)改server: port: 8080 servlet: encoding: charset: UTF-8 force: true spring: thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html mode: HTML datasource: url: jdbc:mysql://127.0.0.1:3306/demo_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: demo password: demo123 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 mapper-locations: classpath*:/mapper/**/*.xmlthymeleaf.cache在開發(fā)期一定要關(guān)掉這個(gè)后面還會(huì)展開講它是最容易讓人懷疑人生的一個(gè)配置。map-underscore-to-camel-case默認(rèn)是 true但顯式寫出來(lái)能避免接手別人項(xiàng)目時(shí)的困惑。log-impl打開 SQL 打印調(diào)試期非常有用上線前記得關(guān)掉不然日志量會(huì)很嚇人。serverTimezone這個(gè)參數(shù)不能省省了在寫入LocalDateTime的時(shí)候可能差八小時(shí)而且是那種數(shù)據(jù)看著對(duì)、時(shí)間就是不對(duì)的詭異問(wèn)題。數(shù)據(jù)源連接串里的allowPublicKeyRetrievaltrue是配合較新版本 MySQL 的認(rèn)證插件用的不加的話在某些環(huán)境下會(huì)報(bào)公鑰檢索失敗。這個(gè)參數(shù)涉及安全邊界只在本地和內(nèi)網(wǎng)開發(fā)環(huán)境用生產(chǎn)環(huán)境按各自的數(shù)據(jù)庫(kù)規(guī)范走。3. MyBatis-Plus 數(shù)據(jù)層從實(shí)體映射到分頁(yè)查詢的完整鏈路3.1 實(shí)體類和表結(jié)構(gòu)的映射約定MyBatis-Plus 默認(rèn)有一套約定類名轉(zhuǎn)下劃線對(duì)應(yīng)表名字段名轉(zhuǎn)下劃線對(duì)應(yīng)列名。遵守約定能省掉大量注解。我在項(xiàng)目里通常就三條規(guī)則表名統(tǒng)一加業(yè)務(wù)前綴比如sys_user、biz_order主鍵統(tǒng)一叫id且自增每張表都帶create_time、update_time、deleted三個(gè)公共字段。Data TableName(sys_user) public class SysUser { TableId(type IdType.AUTO) private Long id; private String username; private String realName; private String phone; private Integer status; TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; TableLogic private Integer deleted; }TableLogic這個(gè)注解是邏輯刪除的核心。加上它之后所有通過(guò) MyBatis-Plus 生成的刪除語(yǔ)句都會(huì)自動(dòng)變成UPDATE ... SET deleted 1查詢語(yǔ)句會(huì)自動(dòng)追加deleted 0。這個(gè)機(jī)制的好處是業(yè)務(wù)代碼里完全感知不到刪除的實(shí)現(xiàn)方式壞處是有幾個(gè)場(chǎng)景會(huì)失效手寫 XML 里的 SQL 不會(huì)自動(dòng)加條件需要自己補(bǔ)update語(yǔ)句也不會(huì)自動(dòng)過(guò)濾已刪除數(shù)據(jù)還有就是唯一索引要重新設(shè)計(jì)——如果username建了唯一索引刪掉一個(gè)用戶之后想再建同名用戶就會(huì)沖突因?yàn)槟菞l軟刪除的記錄還在表里。軟刪除的唯一索引問(wèn)題常見(jiàn)的解法是把deleted字段設(shè)計(jì)成刪除時(shí)寫入主鍵 ID而不是固定寫 1這樣聯(lián)合唯一索引(username, deleted)就能保證只有一條未刪除記錄。不過(guò)這樣配置就復(fù)雜一些小項(xiàng)目里我一般直接放棄用戶名唯一索引改在 Service 層做查重判斷簡(jiǎn)單夠用。自動(dòng)填充需要配一個(gè)處理器Component public class MetaHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }注意strictUpdateFill只對(duì)TableField(fill FieldFill.INSERT_UPDATE)標(biāo)注的字段生效如果實(shí)體類漏了這個(gè)注解填充不會(huì)執(zhí)行而且不會(huì)報(bào)錯(cuò)。3.2 分頁(yè)插件必須先注冊(cè)否則分頁(yè)永遠(yuǎn)返回全量這是我見(jiàn)過(guò)最多人踩的坑。MyBatis-Plus 從 3.4 開始分頁(yè)功能必須手動(dòng)注冊(cè)攔截器不注冊(cè)的話Page對(duì)象傳進(jìn)去也不報(bào)錯(cuò)但total永遠(yuǎn)是 0、records永遠(yuǎn)是全表數(shù)據(jù)。很多人第一次遇到會(huì)以為是Page參數(shù)位置傳錯(cuò)了查半天。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination new PaginationInnerInterceptor(DbType.MYSQL); pagination.setMaxLimit(500L); pagination.setOverflow(false); interceptor.addInnerInterceptor(pagination); return interceptor; } }setMaxLimit(500L)是個(gè)保護(hù)措施防止前端傳個(gè)size999999把數(shù)據(jù)庫(kù)拖死。setOverflow(false)的意思是頁(yè)碼超出范圍時(shí)返回空列表而不是回到第一頁(yè)這個(gè)選擇看業(yè)務(wù)習(xí)慣我傾向于 false因?yàn)榛氐降谝豁?yè)會(huì)讓用戶以為自己點(diǎn)錯(cuò)了。分頁(yè)查詢配合條件構(gòu)造器的典型寫法public IPageSysUser pageQuery(UserQuery query, long current, long size) { PageSysUser page new Page(current, size); LambdaQueryWrapperSysUser wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(query.getUsername()), SysUser::getUsername, query.getUsername()) .eq(query.getStatus() ! null, SysUser::getStatus, query.getStatus()) .ge(query.getBeginTime() ! null, SysUser::getCreateTime, query.getBeginTime()) .le(query.getEndTime() ! null, SysUser::getCreateTime, query.getEndTime()) .orderByDesc(SysUser::getId); return this.page(page, wrapper); }LambdaQueryWrapper比QueryWrapper好在字段名是方法引用改字段名的時(shí)候編譯器會(huì)報(bào)錯(cuò)字符串寫法的QueryWrapper只能等到運(yùn)行時(shí)才發(fā)現(xiàn)列名寫錯(cuò)了。條件構(gòu)造器里每個(gè)方法都有個(gè)重載版本第一個(gè)參數(shù)是布爾值用來(lái)控制這個(gè)條件是否生效這個(gè)特性在寫動(dòng)態(tài)查詢時(shí)極其好用能避免大量 if 判斷。3.3 多條件搜索的拼接邏輯應(yīng)該放在哪條件拼接的位置有兩派做法放 Controller 里用參數(shù)逐個(gè)判斷或者放 Service 里封裝成一個(gè)方法。我傾向后者Controller 就負(fù)責(zé)把請(qǐng)求參數(shù)打包成一個(gè)查詢對(duì)象傳下去。這樣做的另一個(gè)好處是查詢參數(shù)可以做成一個(gè)獨(dú)立的類字段上直接掛校驗(yàn)注解和日期格式注解。Data public class UserQuery { private String username; private Integer status; DateTimeFormat(pattern yyyy-MM-dd) private LocalDate beginTime; DateTimeFormat(pattern yyyy-MM-dd) private LocalDate endTime; }DateTimeFormat這個(gè)注解是給表單綁定用的處理的是從頁(yè)面提交上來(lái)的字符串到日期對(duì)象的轉(zhuǎn)換。如果是 JSON 接口用的是JsonFormat兩個(gè)注解長(zhǎng)得像但作用域完全不同混用會(huì)導(dǎo)致日期綁不上、拋 400 錯(cuò)誤。這個(gè)區(qū)別我在帶新人的時(shí)候解釋過(guò)很多遍本質(zhì)上就是數(shù)據(jù)來(lái)源不同表單走的是 Spring 的ConversionServiceJSON 走的是 Jackson。4. AdminLTE 接 Thymeleaf靜態(tài)資源、布局復(fù)用和腳本順序4.1 靜態(tài)資源目錄怎么擺路徑怎么寫才不打架AdminLTE 是一套基于 Bootstrap 的后臺(tái)模板下載下來(lái)是個(gè)完整的前端工程里面有dist、plugins兩個(gè)主要目錄。放進(jìn) SpringBoot 項(xiàng)目的正確位置是src/main/resources/static/放進(jìn)去之后通過(guò)/dist/css/adminlte.min.css這樣的路徑就能訪問(wèn)。目錄結(jié)構(gòu)我一般是這么組織的resources/ static/ dist/ AdminLTE 的 css、js plugins/ 各種插件fontawesome、jquery、bootstrap uploads/ 用戶上傳的圖片運(yùn)行時(shí)生成 templates/ layout/ 公共片段 user/ 業(yè)務(wù)頁(yè)面 login.html有個(gè)細(xì)節(jié)很容易被忽略SpringBoot 的靜態(tài)資源默認(rèn)映射到/**如果模板里寫的是link th:href{/dist/css/adminlte.min.css}加了{(lán)}語(yǔ)法之后SpringBoot 會(huì)自動(dòng)處理上下文路徑。如果你的應(yīng)用部署在非根路徑下比如server.servlet.context-path/admin不用{}寫死的相對(duì)路徑全部會(huì) 404。這個(gè)坑在本地開發(fā)時(shí)完全發(fā)現(xiàn)不了因?yàn)楸镜啬J(rèn)是根路徑。上傳目錄的問(wèn)題要單獨(dú)說(shuō)一下。static/uploads這個(gè)位置在打成 jar 包之后是只讀的往里寫文件會(huì)失敗。生產(chǎn)環(huán)境應(yīng)該把上傳路徑配成一個(gè)外部目錄通過(guò)WebMvcConfigurer加資源映射Configuration public class WebConfig implements WebMvcConfigurer { Value(${app.upload-path}) private String uploadPath; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/uploads/**) .addResourceLocations(file: uploadPath); } }這樣頁(yè)面里引用/uploads/xxx.png就能拿到外部目錄里的文件開發(fā)和生產(chǎn)的路徑差異用配置文件隔離。4.2 用 fragment 做布局復(fù)用別引額外的方言包Thymeleaf 復(fù)用頁(yè)面的方式有好幾種官方推薦的thymeleaf-layout-dialect用起來(lái)確實(shí)優(yōu)雅但它多一個(gè)依賴語(yǔ)法也自成一套團(tuán)隊(duì)里如果新人多學(xué)習(xí)成本不太劃算。我一般用原生的 fragment 組合來(lái)實(shí)現(xiàn)。先定義公共片段!-- templates/layout/common.html -- !DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head th:fragmenthead(title) meta charsetutf-8 title th:text${title}頁(yè)面標(biāo)題/title link th:href{/plugins/fontawesome-free/css/all.min.css} relstylesheet link th:href{/dist/css/adminlte.min.css} relstylesheet /head body nav th:fragmentnavbar classmain-header navbar navbar-expand navbar-white navbar-light ul classnavbar-nav li classnav-item a classnav-link>!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head th:replace~{layout/common :: head(用戶管理)}/head body classhold-transition sidebar-mini layout-fixed div classwrapper nav th:replace~{layout/common :: navbar}/nav aside th:replace~{layout/common :: sidebar}/aside div classcontent-wrapper section classcontent-header div classcontainer-fluid h1用戶管理/h1 /div /section section classcontent div classcontainer-fluid !-- 業(yè)務(wù)內(nèi)容 -- /div /section /div footer th:replace~{layout/common :: footer}/footer /div /body /htmlth:replace和th:insert的區(qū)別要說(shuō)一下replace是用片段整體替換掉當(dāng)前標(biāo)簽insert是把片段塞進(jìn)當(dāng)前標(biāo)簽內(nèi)部。用replace的時(shí)候當(dāng)前標(biāo)簽本身會(huì)被丟掉所以寫法上要保證被替換的標(biāo)簽類型跟片段的根標(biāo)簽一致。側(cè)邊欄的菜單高亮靠當(dāng)前路徑判斷a th:href{/user/list} classnav-link th:classappend${#httpServletRequest.requestURI.startsWith(/user)} ? active#httpServletRequest這個(gè)對(duì)象在 Thymeleaf 3 里默認(rèn)是可用的不過(guò)在嚴(yán)格的安全配置下可能取不到取不到就退回用手動(dòng)傳一個(gè)activeMenu變量的方式穩(wěn)一些。4.3 腳本加載順序不對(duì)頁(yè)面會(huì)靜默失靈AdminLTE 依賴 jQuery、Bootstrap、popper這幾個(gè)的順序不能亂。正確的寫法是 jQuery 在最前然后 bootstrap 的 bundle 版本自帶 popper最后才是 adminlte 的主腳本script th:src{/plugins/jquery/jquery.min.js}/script script th:src{/plugins/bootstrap/js/bootstrap.bundle.min.js}/script script th:src{/dist/js/adminlte.min.js}/script順序錯(cuò)了的典型現(xiàn)象是折疊菜單點(diǎn)不開、下拉框點(diǎn)一下閃一下就關(guān)、彈窗出不來(lái)??刂婆_(tái)可能只有一條$ is not defined或者干脆什么都沒(méi)有。我遇到過(guò)最隱蔽的一次是有人把 adminlte.min.js 放到了head里頁(yè)面骨架還沒(méi)渲染完腳本就執(zhí)行了界面看著正常但所有交互事件都沒(méi)綁上。所以腳本統(tǒng)一放/body前這是硬規(guī)矩。還有個(gè)版本匹配的坑AdminLTE 3 基于 Bootstrap 4AdminLTE 4 基于 Bootstrap 5。如果從網(wǎng)上復(fù)制了個(gè) AdminLTE 3 的頁(yè)面模板又去引了 Bootstrap 5 的 CSS會(huì)出現(xiàn)間距全亂、圓角對(duì)不上、按鈕顏色偏色這類看著像但又不太像的問(wèn)題。這種情況我的建議是一旦確定用哪個(gè)版本把整套靜態(tài)資源一次性拷全不要東拼西湊。5. 增刪改查四個(gè)動(dòng)作真正花時(shí)間的都在細(xì)節(jié)里5.1 列表頁(yè)分頁(yè)、搜索條件回填與參數(shù)保持列表頁(yè)看著最簡(jiǎn)單實(shí)際上坑最多。分頁(yè)組件要跟搜索條件共存翻到第二頁(yè)的時(shí)候搜索條件不能丟這個(gè)是最基本的要求。我的做法是 Controller 接收查詢對(duì)象和分頁(yè)參數(shù)把所有條件重新塞回 ModelGetMapping(/list) public String list(UserQuery query, RequestParam(defaultValue 1) long current, RequestParam(defaultValue 10) long size, Model model) { IPageSysUser page userService.pageQuery(query, current, size); model.addAttribute(page, page); model.addAttribute(query, query); return user/list; }模板里的分頁(yè)鏈接必須帶上搜索條件nav ul classpagination pagination-sm li classpage-item th:classappend${page.current 1} ? disabled a classpage-link th:href{/user/list(current${page.current - 1}, size${page.size}, username${query.username}, status${query.status})}上一頁(yè)/a /li li classpage-item th:eachi : ${#numbers.sequence(1, page.pages)} th:classappend${i page.current} ? active a classpage-link th:href{/user/list(current${i}, size${page.size}, username${query.username}, status${query.status})} th:text${i}1/a /li li classpage-item th:classappend${page.current page.pages} ? disabled a classpage-link th:href{/user/list(current${page.current 1}, size${page.size}, username${query.username}, status${query.status})}下一頁(yè)/a /li /ul /nav{...}語(yǔ)法里括號(hào)內(nèi)的參數(shù)會(huì)自動(dòng)做 URL 編碼不用手動(dòng)處理中文。這是 Thymeleaf 一個(gè)很實(shí)用的特性用字符串拼接的方式拼 URL 反而容易出問(wèn)題。頁(yè)碼直接用#numbers.sequence全展開在數(shù)據(jù)量小的內(nèi)部系統(tǒng)里夠用。如果分頁(yè)超過(guò)二十頁(yè)這個(gè)寫法會(huì)把頁(yè)碼撐爆需要做滑動(dòng)窗口那就得寫個(gè)小工具方法或者在 Controller 里算好beginPage和endPage傳給模板。內(nèi)部系統(tǒng)我一般不管頁(yè)面撐開了用戶自己會(huì)縮小范圍。搜索表單的回填也要注意th:value里如果原值是 null渲染出來(lái)是空字符串不會(huì)報(bào)錯(cuò)但下拉框要注意選中狀態(tài)select namestatus classform-control option value全部狀態(tài)/option option value1 th:selected${query.status 1}啟用/option option value0 th:selected${query.status 0}停用/option /select這里有個(gè)類型陷阱query.status是Integer如果表單里value1Thymeleaf 在比較時(shí)做的是對(duì)象比較Integer(1) 1在 Thymeleaf 的表達(dá)式引擎里通常能自動(dòng)拆箱成立但如果 status 是String類型就會(huì)失敗。我在項(xiàng)目里統(tǒng)一用Integer接狀態(tài)值避免這個(gè)歧義。5.2 新增和編輯表單復(fù)用、校驗(yàn)失敗回顯與查重時(shí)機(jī)新增和編輯的頁(yè)面高度相似字段完全一樣區(qū)別只是有沒(méi)有初始值。復(fù)用同一個(gè)模板是標(biāo)準(zhǔn)做法用一個(gè)id是否為空來(lái)判斷GetMapping(/form) public String form(RequestParam(required false) Long id, Model model) { SysUser user id null ? new SysUser() : userService.getById(id); model.addAttribute(user, user); return user/form; }模板里所有th:value都綁到user對(duì)象的字段上新增時(shí)是空對(duì)象自然是空值。保存用兩個(gè)方法分別處理新增和修改不要試圖用一個(gè)方法通用因?yàn)樾r?yàn)規(guī)則不一樣新增要查重修改要排除自己。校驗(yàn)這塊PostMapping(/save) public String save(Valid ModelAttribute(user) SysUser user, BindingResult bindingResult, RedirectAttributes ra) { if (userService.existsUsername(user.getUsername(), user.getId())) { bindingResult.rejectValue(username, duplicate, 該登錄名已被占用); } if (bindingResult.hasErrors()) { return user/form; } userService.saveOrUpdate(user); ra.addFlashAttribute(msg, 保存成功); return redirect:/user/list; }ModelAttribute(user)里的名字很關(guān)鍵它決定了模板里用${user}能不能取到值。如果校驗(yàn)失敗返回表單頁(yè)Model 里必須有這個(gè)對(duì)象ModelAttribute會(huì)自動(dòng)把它塞進(jìn)去。這一點(diǎn)如果漏了表現(xiàn)就是校驗(yàn)失敗跳回表單頁(yè)結(jié)果所有已填內(nèi)容全空用戶得重新填一遍體驗(yàn)極差。RedirectAttributes的addFlashAttribute是重定向后傳遞提示消息的標(biāo)準(zhǔn)做法數(shù)據(jù)存在 session 里跳轉(zhuǎn)后讀一次就沒(méi)了。如果用addAttribute參數(shù)會(huì)拼到 URL 上中文還得編碼很難看。表單模板里的錯(cuò)誤提示div classform-group label登錄名 span classtext-danger*/span/label input typetext classform-control th:classappend${#fields.hasErrors(user.username)} ? is-invalid th:field*{username} div classinvalid-feedback th:if${#fields.hasErrors(user.username)} th:errors*{username}錯(cuò)誤信息/div /divth:field*{username}會(huì)自動(dòng)生成id、name、value三個(gè)屬性比手寫th:value更省事而且跟#fields的錯(cuò)誤機(jī)制是配套的。用th:field的時(shí)候注意必須在form上掛th:object否則*{}語(yǔ)法找不到上下文。查重的時(shí)機(jī)也有講究。放在 Service 里做也行但那樣校驗(yàn)失敗的信息拿不到BindingResult只能拋異常或者返回錯(cuò)誤碼頁(yè)面回顯就得另想辦法。放在 Controller 里配合bindingResult.rejectValue是這套棧下最順手的做法錯(cuò)誤信息能直接出現(xiàn)在對(duì)應(yīng)字段下面。5.3 刪除單條、批量與邏輯刪除的取舍刪除功能最容易被輕視。一個(gè)GetMapping(/delete/{id})寫完就完事了看著能跑但這是典型的錯(cuò)誤做法——GET 請(qǐng)求被瀏覽器預(yù)加載、被爬蟲抓取、被用戶誤刷新都能觸發(fā)刪除。刪必須用 POST。PostMapping(/delete) public String delete(RequestParam Long id, RedirectAttributes ra) { userService.removeById(id); ra.addFlashAttribute(msg, 刪除成功); return redirect:/user/list; } PostMapping(/batchDelete) public String batchDelete(RequestParam(ids) ListLong ids, RedirectAttributes ra) { userService.removeByIds(ids); ra.addFlashAttribute(msg, 已刪除 ids.size() 條); return redirect:/user/list; }前端確認(rèn)用 AdminLTE 自帶的模態(tài)框或者confirm批量刪除要注意一個(gè)細(xì)節(jié)如果用戶一條都沒(méi)勾選就點(diǎn)刪除ids參數(shù)是空的Spring 綁定ListLong會(huì)直接拋 400。穩(wěn)妥的寫法是RequestParam(value ids, required false)進(jìn)來(lái)先判空if (CollectionUtils.isEmpty(ids)) { ra.addFlashAttribute(msg, 請(qǐng)先選擇要?jiǎng)h除的記錄); return redirect:/user/list; }邏輯刪除的取舍前面提過(guò)一部分這里補(bǔ)充一個(gè)實(shí)際場(chǎng)景如果業(yè)務(wù)上需要回收站功能邏輯刪除是必須的如果數(shù)據(jù)完全不敏感物理刪除反而干凈因?yàn)檐泟h除的記錄日積月累會(huì)讓表越來(lái)越大查詢還得帶條件。我的經(jīng)驗(yàn)是涉及人員、訂單、財(cái)務(wù)這類數(shù)據(jù)的表用邏輯刪除配置項(xiàng)、日志這類表直接物理刪?;熘脹](méi)問(wèn)題加不加TableLogic是按實(shí)體類控制的。6. 聯(lián)調(diào)階段最容易卡住的幾個(gè)現(xiàn)象與排查順序6.1 模板改了頁(yè)面不變先看緩存開關(guān)這個(gè)現(xiàn)象我第一次遇到時(shí)懷疑過(guò) IDE 沒(méi)保存、懷疑過(guò)瀏覽器緩存、懷疑過(guò) SpringBoot 沒(méi)熱加載折騰了快一個(gè)小時(shí)最后發(fā)現(xiàn)就是spring.thymeleaf.cachetrue。開發(fā)環(huán)境必須設(shè)成 false這個(gè)配置默認(rèn)值在 SpringBoot 里是 true。即使關(guān)了緩存如果你改了模板但沒(méi)重新編譯而項(xiàng)目又是從target/classes里讀模板的那還是看不到變化。IDEA 里的做法是 Build 一次或者用spring-boot-devtools配合自動(dòng)編譯。我用 devtools 的時(shí)候會(huì)把spring.thymeleaf.prefix指向file:src/main/resources/templates/直接從源碼目錄讀改完刷新就生效省掉編譯這一步spring: thymeleaf: prefix: file:src/main/resources/templates/ cache: false這個(gè)配置只能用在開發(fā)環(huán)境生產(chǎn)環(huán)境必須走 classpath。另外一個(gè)容易混淆的點(diǎn)改了 Java 代碼之后模板的變動(dòng)可能被編譯覆蓋。排查順序我一般是配置文件有沒(méi)有生效 → 模板路徑對(duì)不對(duì) → 編譯產(chǎn)物是不是最新的從外往里查比一上來(lái)就打斷點(diǎn)快。6.2 日期和數(shù)字的格式化Thymeleaf 里要靠工具類LocalDateTime直接輸出到頁(yè)面會(huì)是2024-03-15T10:23:45中間帶個(gè) T很難看。格式化的寫法td th:text${#temporals.format(user.createTime, yyyy-MM-dd HH:mm)}時(shí)間/td#temporals是 Thymeleaf 3 內(nèi)置的處理 Java 8 時(shí)間類型的工具需要thymeleaf-extras-java8time依賴不過(guò) SpringBoot 的 starter 里已經(jīng)包含了不用單獨(dú)引。如果是Date類型用的是#dates.format兩個(gè)工具類不能混用混了會(huì)報(bào)找不到方法。空值處理是另一個(gè)高頻問(wèn)題。${user.realName}如果是 null頁(yè)面直接不渲染內(nèi)容不會(huì)報(bào)錯(cuò)但#temporals.format(null, ...)會(huì)拋異常。穩(wěn)妥的寫法是td th:text${user.createTime ! null} ? ${#temporals.format(user.createTime, yyyy-MM-dd HH:mm)} : --/td金額類的字段用#numbers.formatDecimal(amount, 1, 2)保留兩位小數(shù)注意第一個(gè)參數(shù)是整數(shù)最少位數(shù)不是總位數(shù)這個(gè)參數(shù)含義經(jīng)常被搞反。6.3 靜態(tài)資源 404 與中文亂碼的分層排查靜態(tài)資源 404 的排查我有一套固定順序。先看 URL 對(duì)不對(duì)瀏覽器 F12 的網(wǎng)絡(luò)面板里能看到實(shí)際請(qǐng)求的路徑如果路徑里帶了../或者重復(fù)的/static/說(shuō)明模板里的路徑寫錯(cuò)了——{}語(yǔ)法不需要你手寫/static它對(duì)應(yīng)的就是static目錄的根。再看 Spring Security 有沒(méi)有攔截如果項(xiàng)目集成了安全框架靜態(tài)資源默認(rèn)是要放行的配置里漏了requestMatchers(/dist/**, /plugins/**).permitAll()就會(huì)全 404。最后看打包方式j(luò)ar 包里的static目錄是通過(guò) classpath 訪問(wèn)的如果資源放的目錄名不是static比如放成了public或者resources那 SpringBoot 也能識(shí)別但目錄名拼錯(cuò)就完了。中文亂碼分兩種。一種是請(qǐng)求參數(shù)亂碼表單提交的中文到后端變成問(wèn)號(hào)這是編碼配置問(wèn)題server.servlet.encoding.forcetrue加上頁(yè)面的charsetutf-8基本能解決。另一種是響應(yīng)內(nèi)容亂碼頁(yè)面上中文變成方塊或者亂碼通常是模板文件本身的編碼不對(duì)IDEA 里在文件右下角能看到當(dāng)前編碼確認(rèn)是 UTF-8 就行。還有一種最隱蔽的數(shù)據(jù)庫(kù)連接的characterEncoding寫成了utf8但表是utf8mb4存表情符號(hào)的時(shí)候報(bào)錯(cuò)或者截?cái)噙@個(gè)只能從建表語(yǔ)句開始統(tǒng)一。6.4 表單提交后提示信息不顯示addFlashAttribute存進(jìn)去的消息在頁(yè)面里要用${msg}取。取不到的情況一般是重定向的地址跟存放的會(huì)話不一致或者頁(yè)面模板里漏了判斷div classalert alert-success alert-dismissible th:if${msg ! null} button typebutton classclose>
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
欧美亚洲影视| 91欧美经典| 用力操死我| av亚欧| 国产精品午夜成人福利| 很很热性爱视频| 伊人国产AV| 嗯啊啊啊轻点视频| 亚洲AV性爱电影| 快灬快灬 一下爽蜜桃在线观看| 色月天AV导航| 日韩精品一区二区三区四虎影视| 国产一区二区在线播放量| 亚洲情色无码一区二区三区| 熟女天天干| 婷婷伊人| 国精精品无码一二三区水多多| 天天综合色图| 蜜区区视频79| 久久久91福利姬| 久久99国产综合精品女同| 黄色网址在线免费观看| 国产精品无码成人精品| AV乱伦国产| 五月天AV资源| 欧亚揄拍偷拍精品视频 | 亚洲综合精品国产一区| 人妻81p| 性无码专区2020| 熟女熟妇伦久久影院毛片一区二区 | 97资源久久| 九月丁香婷婷| 天美精品av| 麻花传媒免费网站在线观看| 色汉综合| 伊人网高清| 亚洲人在线| 啊啊啊啊一区| 精品一区二区成人| 夜夜操青青草| 亚洲一区操| 国产精品久久久久久久久久久久| 亚洲中文字幕久久无码精品| 精品高清牛人盗摄一区二区三区中文字幕A片免费在线观看 | 欧美在线电影| 久久久久久加勒比| 麻豆天美91| 老司机香蕉| 人妻激情在线视频| 多乙久久久久久| 啊啊啊啊操死我| 亚洲影视高清第一页| 欧美小说区视频区| 天美传媒国产原创中文字幕亚洲欧美另类| 国产最火爆久久国产网站网站| 蜜臀一二三区| 免费久久9999| 精品毛片久久久精品毛片| 欧美裸体美女日麻屄| 另类天堂| 视频在线观看一二三区| 美女91在线观看| 黄总AV色图| 岛国小电影| 国产黄a三级三级三级av在线看 | 日韩欧美亚洲自拍偷拍| 蜜臀AV秘一区翔田千里| 日韩精品免费高清视频在线| 欧美成人性爱视频免费观看 | 97在线视频免费看| 日欧毛片久久| 噜噜噜狠狠色综合| 97爱亚洲| 99999久久精| 欧美性爱18观看| 欧美爱爱97| 青久久| 欧美自拍网| 欧美超碰97| 国产综合色精品在线观看| 大香蕉78| 精品人妻一二三| 强奸乱伦AV一天堂网| 亚洲性爱电影| 激情av| 久久九九一区二区三区成人| 人妻 欧美 中文| 超碰97在线中文| 好色美女九七第一页| 麻豆av一区二区| 色在线视频导航| 精品人妻一区二区视频| 久久久免费的精品| 欧美天天谢综合网| 97在线免费公开视频| 久久啊啊| 99在线精品视频| 精品视频专区| 999热这里只有精品| 蜜乳中文字幕a在线| 波多野结衣先锋影音| 大香蕉免费中文| 嗯嗯啊啊视频一区二区三区| 国产精品另类| 色噜噜人妻丝袜a∨先锋影| 天天欧美色| 亚洲视频1区| 五月婷婷AV| 久久综合精品一区二区三区| 欧美在线啊啊| 五月丁香啪| 超碰这里有精品| 久久超碰国产一区二区三区| 久7色| 蜜臀Av一区二区三区| 天天躁日日躁AAAAXXXX国产| 神马久久69| 丁香婷婷五月| 日本伦理一区二区| 免费精品无码一级毛片牛牛影视| 亚洲1区| 一二三区精品视频| 五月天婷婷综合网| 水滴偷拍| 97久久视频| 日韩欧美蜜桃精品久久中文字幕久久| 免费一级性爱久久| 97色伦欧美| av橘色网站| 99国产精品视频尤物| 久久理论字幕视频| 在线午夜成人无码视频| juliaann精品熟女一区| 免费αV在线视频| 精品人妻一区二区三区-国产| 日日夜夜骑| 五月天婷婷欧美三区| 国产一区在线看| 天堂岛av| 26uuu国产亚洲综合| 久久人妻四季| 人人干人人操人人..com| 夜夜爽夜夜摸夜夜操免费视频| 秋霞成人做爱| 97伊人| 国产精品久久久亚洲一区| 丝袜狠狠草尤物 91| 顶级丝袜熟女一区二区三区 | 中文字幕精品日韩中文字幕| 操老熟女AV| 91free福利| 婷婷性网| 亚洲最大黄网| 精品国产91av一区二区三区| 精品无码产区一区二| 五月婷丁香| 亚州男人天堂| 一区二区首页| 熟妇的味道HD中文字幕| 国产乱码精品久久久久久| 久久久婷婷| 深夜国产一区二区三区在线看 | 日亚韩精品视频二区三| 成人羞羞视频国产| Aa东京男人的天堂| 日本一二区免费| 在线观看亚洲专区| 欧美组图日韩亚洲中文字幕| 啊啊啊啊啊啊啊在线| 五月天婷婷综合| 不卡av在线中文字幕| 噜噜噜噜天天狠狠| 丝袜狠狠草尤物 91| 色香阁在线| 国产99精品一区二区三区免费| 欧美色道啊| 打av高清| 后入美女国产| 一区在线观看中文字幕| 色狠狠 - 百度| 精品九九九九九| 中国黄色特级精品一区二区三区片| 99热这里是精品| 很黄很色的视频在线观看| 97天天日| 亚洲图片小说欧洲| 亚洲影视高清第一页| 午夜久久一区二区无码中出| 性爱1区| 国产精品99精品视频网站| 肥佬影院91| 啊啊啊啊啊舒服| 三上制服丝AV| 日日干日日操五月天伦理视频| 影音先锋国产精品| 丝袜熟女一区二区三区| 性做久久久久久久| 性爱边摸边日免费AV| 亚洲春色一区二区三区| 天天伊人| 91A欧美电影网站| 久热这里只有精品9| 日韩熟女视频二区| 日韩精品资源| 96精品久久| 嗯嗯不要 视频| 国内外毛片在线观看| 白丝在线一区| 亚洲资源网| 欧美少妇色综合| 99re这里| 夜夜躁狠狠躁日日躁av| 成人小说另类在线| 亚洲日韩人妻中文字幕一区| 国产一级特黄大片处女| 欧美人妻一区| 99热国产| 夂久色| 亚洲中文字幕有码视频一区二区三区| 精品久久在线区一区| 欧洲综合视频| 亚洲和欧美裸体美女双飞视频| 好看的91视频| 亚洲中亚日激情视频| 制服丝袜第二页| 中文字幕无码不卡啪啪| juliaann欧美丝袜办公室| 国产精品97视频| 超碰九7免费| 色在线视频导航| 熟妇乱伦一区二区| 强奸乱伦AV网址| 波多野结衣之双飞调教在线播放 | 美女写真| 好吊妞转入那个网| 日本999精品| 很狠操| 超碰97人妻自拍| 久久久96| 欧美强奸乱能| AV丝袜少妇| 欧美91丝袜| 天天综合站| 中国特猛少妇色xxx| 亚洲另类欧美精品| 午夜丁香| 青青操视频在线| 91综合熟女| 一区操逼| 日韩三级一区| 五月天亚洲网| 懂色AV中文| 久热精品色情| 亚洲色图欧美色图在线播放| 91久久青青草原精品| 最新av网站在线观看| 日本护士高潮| 久久超碰亚洲人| 青青草无码视频| 国产无码成人无码| 秋霞免费AV| 91网站18在线观看| 99re黄| 人人操人人摸人人看人人插| 综合网欧美在线| 天天插天天操天天摸天天射天天看| 欧成人在线| 无码 黑人一区二区三区| 丁香五月电影| 在线电影亚洲色图| 日韩精品中文字幕人妻| 色蜜AV| 本道在线| 久久亚洲AV无码专区国产精品| 尹人大香蕉视频在线| 日韩久久艹| 懂色Av| 亚洲日韩一区电影| 久久九九精品一区二区| 日韩卡一卡二卡三在线| 欧亚不卡| 国产一级高清免费观看| 六月激情婷婷| 美女91| 国产AV久久久蜜爱影集| 啊啊啊啊啊啊啊在线| 国产精品亚洲无码| 日本午夜福利视频| 久久久精品电影| 国产夜夜艹| 国产视频人人网| 婷婷丁香六月天| 久久精品国产97欧美精品亚洲 | 三级三级三级a级全黄三| 99re95| 最近2018中文字幕在线高清第一页| 天综合网| 成人无遮挡毛片免费看| 日韩精品第3页| 青青操网| 亚州 综合 色图| 永久免费av无码网站国产app | 国产精品不卡一区二区电影| 观看视频图片一区二区三区| 午夜男女爽爽爽影院视频| 97视频观看| 人妻色偷色噜| 91日产欧美| 无码高清专| 熟女熟妇伦久久影院毛片一区二区| 日韩精品中文字幕一 | 91精品啪在线观看国产城中村| 日韩精品怡红院| 日韩 欧美 另类 人妻| 在线情色电影 91大| 免费中文在线| 女优大全 - 91n| 亚洲中文制服诱惑| 欧美日韩国产另类综合| 日韩AV噜噜噜一区二区三区四区| 丝袜美腿诱惑亚洲欧美视频在线观看 | 精品一区二区人妖| 欧美91变态| 日本熟人妻中文字幕在线|...久久国产精品-国产精品_日本一区二区三区中文字幕 | 97国产精品视频| xxx亚洲午夜天堂| 中文字幕在线免费观看2| 99re69综合| 亚洲熟女性高潮久久久| 国产精品69久久久久久久| 超碰在线看| 国产强奸乱伦第1页| 亚洲男人天堂网久久| 99国产精品视频尤物| 夜夜爽夜夜摸夜夜操免费视频| 天堂种子在线www网资源| 天堂综合网| 国产高清不卡视频| 五月天婷婷基地| 欧美Ⅴ性爱| 欧美色色人| 久久午夜伦| 福利社区午夜一区二区| 91女日逼| 99黄页网站| 天天干少妇| 日本一区视频在线观看| 人人妻人人玩人人澡人人爽| 伊人久久蜜月| 青青操在线亚洲视频观看欧美在线| 日本国产欧美高清在线| A片大香蕉在线| 黑人综合色| 欧美综合色站| 欧美天天拍| 日本午夜久久电影| 久久久无码av精| 狠狠操,使劲操| 亚洲男人天堂手机版| 性爱欧美五月| 亚洲欧美天堂在线| 五月综合色| 无码免费精品高清| av一区二区三区四区| 啪啪综合网| 欧美草草高清日韩视频| 中文字幕精品亚洲熟女| 国产丝袜高跟美女av免费观看| 99re这里只有精品3| 丝袜大香蕉| 精品成人av一区二区三区在线| a男人的天堂久久一级A毛片| 中文一区二区三区影院| 欧美色就是色| 久久精品高清无码一区| A一级色女| 精品国产一区二区三区久久久蜜臀| 99热啪啪| 激情色播| 日本综合久久| 天天日天天干天天整| 日韩十八禁| 日韩欧美传媒一区国产| 91国产丝袜白虎| 中文字幕欧美日本乱码一线二线| 99蜜桃臀久久久欧美精品网站| 最新亚洲风情电影| 夜夜嗷嗷一区二区| 91N综合网在线| 少妇内射视频| 搡老女人老91妇女熟女| 超碰欧美97资源| 欧美性综合| 蜜臀th| 亚洲情色 无码专区| 久久久久无码一妻区| 伦在线97| 国产乱子伦一区二区三区免看| 91激情综合| 久久超碰98| 欧美91网站| 中文字幕久久精视频久久大全| 污污污8888| 综合av影片| 免费97视频| 日本二三四区| 成人五月天丁香激情综合| 亚洲av噜噜噜噜噜噜| 欧洲在线性爱视频| 免费在线观看国内色片网站网址| 成人性爱全视频观看| 久久这里只精品99re66图| 26uuu国产| 亚洲综合97中文网| 黄日韩| 亚洲人综合| 久久久91| 国产精品制服丝袜清纯唯美| 色999五月色| 日韩情色视频| 妇女乱色二区| 亚洲开心网| 91东京热男人的天堂| 天天躁日日躁XXXXYY| 久久香蕉网| 天天看少妇| 素颜老阿姨乱情色| 亚洲色图欧美| 操逼视频色| 欧美日韩国产高清在线一二三区 | 5252色欧美在线| 天堂中文日本在线观看| 91天天爱| 激情五月婷| 有码人妻系列| 精品一区二区麻豆| 国产精品老师| 欧洲亚洲人妻无码中字久久三区四区| 97伪v| 91美女视频直播| 精品日韩人妻视频| 亚卅熟女乱色| 欧美熟女妇同| 在线亚洲欧美| www99热| 大香蕉啪啪啪啪在线| 国内一区二区三区| 国产偷拍自拍在线视频| 91视频观看网站| 精品丰满熟妇人妻一区| 国产精品一区av在线| 五月天婷婷综合| 骚人妻少妇视频| 亚洲色图欧美色图另类图片| 久久XX| 性交一区二区在线播放| 日本操逼视频在线| 九九Av| 神马久久久久久久久久| 啊啊啊啊好多水| 日韩av一级黄片| yy少妇精品久久| 少妇久久久| 日本人妻A片成人免费看片| 国产精品久久久久久久久久久久久久久久 | 欧美丝袜亚洲| 超碰成人公开| 国产农村妇女精品一| 亚洲激情在线| 久久,精品一二三| 熟女高潮合集-永久久久-成人AV | 人人操人人摸人| 91成人在线| 欧美欧美啪啪视频| 手机不卡视频不卡在线一二三区| 91网站18| 97亚洲一区| 欧美片第一页| 91在线视频免费中出| 亚洲激情视频| 精品.99999| 国产精品视屏| 性色一线| 免费观看性欧美一级| 国产91精品久久久久久久网曝门| 91在线免费精品视频| 天天摸天天插天天日| 超碰成人人人爽人人爽| 啊啊啊啊啊啊啊国| 自拍偷拍第26| 欧美论理片| 美國A片| 另类成人首页一区| 丁香六月天| 国产精品扒开腿做爽爽爽视频| 久久久一级| 国产精品点击进入在线影院高清 | 三级日本一区二区三区| 白丝jkav| 免费伦费视频在线观看| 97欧美综合网| 影音综合网| 91av一区二区在线观看| 九九人妻| 国产日本熟女顶级一区二区三区视频| 一级性爱网| 欧美亚洲美少妇一区二区| 51一区二区三区| 揉揉揉夜夜| 澳门成人网站久国产日韩| 国产精品嫩草久久久久| 久久久精品九| 国产av白丝| 夜夜草我| 人人九九精| 亚洲 欧美 91| 日韩欧美国产一区二区三区四区| 9久久久久| 欧美一二在线| 日韩在线观看中文字幕视频| 亚洲AV成人精品网站在AV| 精品一二三区女同| 激情综合97| 干婷婷综合网| 国产精品4p在线观看| 亚欧美综合| 亚洲综合影视| 五月婷婷大香蕉| 久久久精品电影| 一起草在线视频| 嗯嗯啊啊好大好爽| av操操不卡| 可能人人看人人摸| 亚洲国产精品成人综合| 亚洲人妻日日日| 91爱做| 天天亚洲综合| 五月婷婷激情网| 91影库| 日韩电影在线观看网址| a啊啊啊啊啊啊啊啊一区二区| 婷婷丁香六月| 亚洲中文字母在线播放| 在线观看高清AV| yaouchengrenav| 少妇天堂| 四虎av在线| 狠狠操狠狠燥| 亚洲色情在线影视| 亚洲男人的天堂AV| 亚洲欧洲小说图片视频 | 日韩紧密久久| 99热色精品| 亚洲福利中文字幕在线| 另类 日韩 熟女| 強姦亂倫a| 热思思免费视频| 翔田千里AV无码秘 三区| 96久久久久久久| 人妻丰满熟妇av无码区蜜桃| 91劲爆| 熟女高潮合集-永久久久-成人AV | 亚洲精品久久久久久| 亚洲欧洲久久天堂| 丰满翘臀美女影院视频| 天天干天天日天天射黄色| 久久五月综合| 99热超碰| 四虎影库国产精品免费| 国产欧美美女免费观看视频| 中文字幕高清20页视频| 2010男人的天堂| 一道本久久棕合爱| 丝袜六区| 天天干天天日天天射黄色| 欧美三级一级| 极品内射| 蜜臀久久久国产| 青久久| 欧美人妖内射| 人妻天堂三区| 久久草草亚洲蜜桃臀| 亚洲 小说 欧美 激情 另类| 国产高清吃奶免费视频网站| 最新中文字幕在线亚洲| 一个人免费HD91视频| 在线观看日韩av不卡| 婷婷五月天伊人| 国产熟女少妇一区| 少妇同性| 久久久久久人| 天天日天天干天天操| 国产精品人妻一区二区| 亚洲av淫乱| 丁香五月天激情| 亚洲精品色| 草久久久| 日韩无码服务区| 99re免费| 能在线播放的国产三级| www.久久| 天堂涩涩| 日韩欧美传媒一区国产| 久久黄色视频一区二区三区| 黑人精品成人一区二区三区 | 天操老女人| 丝袜加勒比| 91天天| 强奸乱伦麻豆| 又大又长又爽| 蜜桃狠狠色伊人亚洲综合 | 丰满欧美少妇| 欧美性Fer办公室秘书| 人妻少妇精品久久久久久久| 国产精品999zyz| 天堂九九九九九九九九九| 色九九九综合| 99精品综合久久久久五月天| 日韩偷拍一区二区三区| 99热综合| 性色高清..……| 午夜舔阴达高潮视频免费看| 国产情侣自拍在线播放| 青青草乱入乱欲视频在线观看| 亚洲天堂电影网99999| 超碰精品日韩欧美国产| 六月丁香啪啪啪| 久久久精品中文字幕麻豆| 人人摸人人入| 久久草草欧美精品| 蜜臀aV午夜一区二区三区| 欧美18老人禁| 国产不卡精品91| www男人天堂| 天天干天天狼在线视频| 精品小视频在线| 国产操逼视频在线观看| 97超碰天天| 另类图片综合| 一区二区激情国产熟女 | 国产呦精品系列在线观看| 欧美性爱另类综合| 亚洲熟女少妇免费视频| 99re国产精品视频| 情色五月天久久久| 国产JDAV无码视频在线观看| 丰满人妻一区二区三区四| 男人综合网| 99热日本| 中文字幕乱妇免费视频| 色婷婷狠狠| 精产品久久| 极品白嫩美女白浆成人福利在线看| 超碰在线第一页| 亚州操逼图| 一区二区三区色综合| www.大香| 日本五区不卡| 婷婷五月天av| 欧亚日韩中文在线| 激情文学网伊人| 亚洲欧美另类激情小说| 男人天堂.AB| 天天干18禁| 色噜噜人妻av 中文字幕| 国产高清自拍| 中国黑人三级片网站上区| 亚洲欧洲自拍图片专区满春格| 亚洲不卡不卡中文字幕不卡| 日韩免费三级黄片电影| 久久国99999| 无码最新| 2003天天干夜夜操| 看一级特黄a大一片| 97亚洲国产| 久久美女福利是上海美女| 美女91AV| 午夜欧美J进J出白浆流出久久久| 久久久久久久久久va| 高清不卡一二三区视频......| 1024精品在线| 亚洲国产精品久久久久婷婷青年| 浓厚中出中文字幕在线| 99re这里| 婷婷久久综合久| 亚洲色图8| 亚洲综合网电影91| 国产欧美日本亚洲精品| 日韩毛片9| 丁香五月婷婷色| 超碰成人人人爽人人爽| 一区二区三区网站日日骚| 小视频玖玖| 欧美日韩久久精品爱爱| 人人妻人人色| 亚洲欧美日韩综合在线尤物| 亚洲本色精品一区二区久久| 本道在线| 97中文天堂| 亚洲国产高清福利视频| 欧美亚洲手机在线| 牛牛久久国产精品视频一二三| 婷婷丁香成人| 一级婬片120分钟试看| 久久久111| 亚洲日韩一区电影| 岛国网址国产 | 免费黄色片子| 少妇一级婬片免费放一级a性色.| 欧美91网| 99在线啪| 日韩少妇丰满亚洲| AAA久久| 国产精品一区二区校花| 精品一区二区三区麻豆| 中出人妻中文字幕91在线| 天天爽夜夜欢视| 五月婷婷色| 黑丝自慰喷水网站| 欧美一二三级精品在线| 天天色欧美| 欧美特黄视频网站| 亚洲日韩熟女人妻高清在线| 殴美牲| 99久久婷婷国产综合精品草原| se吧提供国产乱老熟视频胖女人 | av资源在线观看少妇| 免费国产电影一区二区| 超碰人妻久久| 上床啊啊啊| 91国产丝袜美女| 男人精品天堂一区| 久久男人网| 大香蕉综合| 强奸乱伦αv片| 精品人妻1区| 91深夜夜| 看免费的黄片| 欧美在线91| 国产97在线视频| 熟妇一区二区| 亚洲97在线| 97人人爱人人乐| 人人妻人人澡人人爽久久av| 青青草在线视频美女| 日韩熟女视频二区| 精品欧美日韩在线观看| 天天天天天天天天综合| 综合97亚洲| 亚州春色| 殴美综合色88| 亚洲国产精品久久久男人的天堂| 日韩精品三区四区| 综合久欧洲| 高清不卡视频| 日产中文字幕2020| 97视频620| 大香蕉国产中文自拍| 97超碰热线| 亚洲成人妻日韩在线| 欧美夜夜骑视频| 97干天天| 91N综合网在线| 久久久久久人| 后入国产| 少妇一级无码精品| 老熟女乱伦一区| 中文字幕一二区二三区人妻专区| 一类av片在线看| 色综合网1| 激情久久久| 天堂九九九九九九九九九| 欧美熟妇乱码在线一区| 97超碰免费人人性爱| 激情小说亚洲图片| 久久久月天| 亚洲中文字幕精品一区| 亚洲h片在线免费观看| 操逼片中文| 久久九九网| 亚洲AO在线| 长久操视频| 91精品少妇搡搡搡| 超碰97久久| 日日夜夜精品| 婷婷五月成人| 91日产欧美| 欧美人妻制服| AA级电影三区| av无码精品久久久久| 九九亚洲视频| 日本 免费 一区二区三区 久久香蕉 | 人人操人人uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii | 午夜黄色免费在线观看| 亚洲欧美中文日韩视频中国语| AV中文在线| 少妇同性| 狠色婷婷久久一区二区三区_| 丝袜天堂网| 在线视频免费观看午夜| 五月综合婷婷久久网站| 亚洲国产精品久久久久婷婷青年| 欧美在线l亚洲| 伊人96在线| 综合网少妇| 少妇一区二区三区精选| 日韩性爱播放| 99re9这里只有精品| 久久九九久精品国产尤物|国产精品爽黄69天堂A片潘金莲,国产亚洲精品第一综合 | 欧美另类天堂| 级做a爱无码性色永久免费| 亚洲性爱免费电影| 少妇 综合| 日韩三级性| 不卡av在线中文字幕| 国产精品久久久久亚洲av| 综合久久99| 操香逼| 久久春色| 日韩精品碰碰| 青青草中文-久久青草精品一区二区三| 久久黄黄| 2020天天色综合| 无码人妻精品一区二区中文| 欧美熟女激情| 91狠狠综合久久| 九九黄色视频在线观看| 蜜桃午夜视频一区二区 | 99在线精品视频| 欧洲一级性爱视频在线观看| 久久久啊啊| 精品人妻中文字幕4399| www.91理论| 激情五月天综合网| 国产精品高潮久久久无码| 久久夜嗨| 婷婷香蕉欧美在线一区二区三区| 欧美的性爱网站免费| 伊人嫩草| 色97| 欧美精品99久久久**| 亚洲双插| 天天看特黄的免费网站| 人妻激情偷乱视三区频一区二区| 男女激情黄色网址| 一本色道久久综合精品婷婷| 欧美少妇第一页| 偷拍网站久久男女男| 久操网视频| 欧美综合综合| 超碰在线综合97| 熟女高潮合集-永久久久-成人AV| 日本99视频| 国内毛片欧美香蕉精品| 91最新综合| 极品欧美一区二区三区| 欧美成人国产精品| 婷婷另类小说| 粉嫩绯色AV一区二区在线| 国产精品无套内谢| 久久久久久久久久va| 人妻另类 专区 欧美 制服| 九九热九九| 大香蕉懂9| 国产91 丝袜在线播放| 亚洲精品骚逼| 日本有码久久| 伊人精品久久网站| 国产精品久久久久久久久久久久| julia国产在线| 91久久九九精品国产综合| 久久原创中文| 婷婷五月天伊人| 999精品乱码| 亚洲综合色婷婷| 97天天综合| 天天欧美欧美亚洲网| 噜噜噜噜久久久精品免费| 大奶啊啊好爽 | 欧美日韩精品久久久久久久久东北老熟妇| 麻豆人妻精品一区二区| 久久免费少妇| 嗯,啊。舔我逼| 国产成人欧美一区二区三区的国产| 97av,com| 中亚精品极乱| 久久久久久日韩| 91 综合网| 久久久久久中文版| 色色网91| 日本色日夜干| 青草影院内射高潮| 欧美激情综合| 午夜AV人气不卡| 国模限制级电影| 国产亚洲日韩在线三区黑人| 草草影院在线视频| 婷婷六月天| 国产精品三级视频网站| Blackedraw视频一区二区| 久久久久久久久久久999| 久久久久久久久国产| 乱伦熟女论坛| 男女香蕉一区二区| 色第一页| 九九这里只有精品| 日韩熟女乱伦中出| 操人妻视频| 蜜桃AV天堂| 欧美熟妇操操视频| 99婷婷| 日本熟女中文字幕一区| 白丝av| 中文字幕1区2区| 97视频在线视频| 九九精品美女高溯喷水| 大香蕉五月天婷婷| 国产精品一区午夜福利| AVE乱伦| 欧美精品一二三| 狠狠做深爱婷婷久久二区| 国产怡红院| 久久黄黄| 男人的天堂啪啪啪啪啪蜜桃不卡| 久久大黄片| 97在线播放| 美女天天干| 欧美日韩人妻婷婷一区| 久日91在线| 四虎永久在线精品免费网址 | 日本福利二区视频| 久思思热视频在线观看| 最新日本中文字幕| 亚洲天堂2020| 一区二区三区高清| 国产一区二区精品久久久不卡蜜臀| 9 9精品一区二区三区| 激情五月天社区| 国产女生在线| 色婷婷激一区二区三区| japan日本高清乱xxxx| 麻豆国产视频精品观看| 91av一区二区在线观看| 中文字幕97| av网站在线看| 亚洲婷婷丁香在线| 绯色一区二区三区不卡少妇| 久久这里只有精品9| 欧美一二三| 成人性交免费视屏| 中国少妇啪啪视频| 99热一区二区三区四区| 99re99| 91春色| 91在线精品一区二区三区| 精品人妻一二三| 日本综合色图| 亚洲无码超碰免费| 日本一区二区三区午夜观看| 国产精品一区二区校花| 青青草视频爽一爽| 国精精品无码一二三区水多多| 操91| 婷婷尹人大香蕉免费| 高清无码在线播放网站| 日韩三A大片在线观看| 人人看欧美性爱| 久操不卡视频| 看看小穴| 极品内射| 日本一卡二区在线| 91成人18| 最新日日夜夜天天干干| 免费操逼视频下载| 另类小说五月天| 精品v1区| 极品AV网站在线观看| 欧美一区二区| 无码人妻精品一区二区三区99不卡| 1人人看人人摸人人操| 精品性爱一二三区| 精品超碰中文在线| 久久超碰大香蕉| 精品美女少妇一区二区三区| 4虎在线视频| 亚洲天天精品| 中文熟女五十乱码在线| 大香蕉淫人| 国产无码久久高清| 国产日韩欧美中文在线播放 | 激情小说图片亚洲首页| 国产精品嫩草影院免费| 丁香五月影院| 国产欧美一区二区| 熟妇艹鸡八| 大但人体久久久久| 欧美色图亚洲激情| 亚洲最新av无码成人精品区| 2020视频1区2区3区| 91成人国产综合久久精品蜜月| 五十路人妻在线| 91成人18| 四色永久成人网站| 青青草啪啪网| 日日超碰亚洲| 欧 美 自 拍 偷 拍| 色五月婷婷在线| 91日日夜夜| 久久久一区二区三区三州| 9丨亚洲一区二区在线| 日韩免费性爱视频在线观看| 男人的天堂2018.| 亚洲激情久久久伊人综合| 波多野结衣一级视频| 天天日B狠狠操| 一区e区三| 午夜精品五区| 99热这里只有精| 亚洲欧美综合图片| 欧美久久伊人| 中美日韩毛片| 99re9| 婷婷激情五月| 四虎免费在线播放| 性爱综合一区二区| www.91色| 人妻少妇久久中文| 国产日韩区| 久久精品72| 日语五十路和六十路亚洲国产精品 | 九九热精品在线| 九九九九九九九九九五码| 久久亚洲中文字幕视频| 久久黄黄| 97国产精品久久久久 | 人人妻人人狠人人| 草久久久| www熟女乱伦com| 操我啊啊啊啊啊| 中文乱码字字幕在线第5页| 日产狠狠干| 天天色欧美| 午夜精品久久久久久久男人的天堂| 骚人妻少妇视频| 91福利网在线观看| 四虎AV无码| 综合av社区| 久插综合| 亚洲av国产av综合av卡| 怡红院怡春院| 亚洲性少妇| 男人的天堂午夜av| 亚洲色图综合| 欧美猛交黑寡妇中文字幕| 国产操伦| 天堂伊人久久| 国产美女自拍AV| 久久久久久九九九九九九| 五月丁香六月综合缴清无码| 女同性恋一区二区三区精品视频| 免费的黄片有限公司| 天天色综合天天操| 97视频新免费| 色婷婷基地| 日韩综合97p| 国产精品熟女AV中文字幕在线播放| 欧美色图人妻| 亚洲一区二区三区AV无码| 无马一区二区| 超AV色女| 国产精品久久久久亚洲av | 久久丁香久草综合网| 91超级碰碰| 97天堂| 91久久18禁| 黄色大香焦1级‘′‘| 亚洲天堂加勒比| 国产a级精品| 人妻少妇被猛烈进入中| 后入式福利| 看看小穴| 激情综合二| 亚洲影视第一页| 91蜜臀在线久久久久| 亚洲欧洲日韩天堂av| 中国黄色特级精品一区二区三区片| 国产精品成人在线| 男同专区一区二区三区在线| 亚洲97P| 婷婷色综合| 99亚洲国产精品色一区二区三区| 欧美与日韩97| 日韩成人大片在线观看| 五月天亚洲色图| 久久精品日韩专区免费观看| 日本三级中国三级99人妇网站| av网站在线看| 1二区9| 91久久婷婷| 久操网址| 东京太热久久久| 无码99| 天海翼久久| 男人成人黄色视频在线观看免费下载| 午夜毛片高清免费不卡| 日韩欧美水蜜桃人妻| 久久动漫精品视频这里只有精品| 热久日综合| 中文字幕一区 二 区 三 四 五 区日 日 骚 | 2021久久国产综合精品青草| 中文字幕精品亚洲熟女| 熟妇一区二区三区| 首页中文字幕中文字幕免费| 26uuu久久| 国产AV天美传媒一区二区三区 | 玖玖综合色| 99热精品在线| 先锋激情∨在线视频播放| 精品亚洲| 极品少妇久久久久| 亚欧美综合网。| 少妇毛片久久| 国产九月婷婷| 99视频内射三四| 强奸乱伦αv片| 99re公开精品免费视频| 日本潮催一卡操| 另类欧美色| 欲综合网| 941超碰| 亚洲淫色网中文| 中出789在线视频| 综合日本女人伊人| 亚洲成人av色网| 亚洲制服欧美另类内射| 2020中文在线一区二区三区| 青娱乐二区免费| 91爱| 久久久人妻| 网友自拍第一页| 91情色在线| 深夜视频| 天天爽天天操| 五月天人妻综合| 97超碰碰碰| 青苹果影院男人的天堂| 色狠狠一区二区三区香蕉| 日本高清视频xxxx| 真实高潮91| 偷拍亚洲熟女视频播放| 91电影色诱| 欧美精品23| 国产精品网站www| 凹凸视频在线一区二区| 91操碰| 少妇被c 黄 免费观看| 男女香蕉一区二区| 综合一区中亚洲国产成人综合精品| 一级做受视频免费是看美女| 神马九九九|