SpringBoot+Vue项目实例开发及部署
目錄
一、SpringBoot快速上手
1、SpringBoot介紹
2、SpringBoot特點(diǎn)
3、快速創(chuàng)建SpringBoot應(yīng)用
4、SpringBoot開發(fā)熱部署
二、Web開發(fā)基礎(chǔ)
1、Web入門
2、控制器
3、路由映射
4、參數(shù)傳遞
三、Web開發(fā)進(jìn)階
1、靜態(tài)資源訪問
2、文件上傳原理
3、攔截器
四、構(gòu)建RESTful服務(wù)
1、RESTful介紹
2、RESTful特點(diǎn)
3、RESTful API
4、HTTP狀態(tài)碼
5、SpringBoot實(shí)現(xiàn)RESTful API
6、Swagger
使用Swagger生成Web API文檔
配置Swagger
使用Swagger2進(jìn)行接口測(cè)試
Swagger常用注解
五、MybatisPlus快速上手
1、ORM介紹
2、MyBatis-Plus介紹
添加依賴
全局配置
Mybatis CRUD 注解
Mybatis CRUD 操作
Mybatis-Plus 注解
Mybatis-Plus CRUD操作
六、多表查詢及分頁查詢
多表查詢
多表查詢操作
條件查詢
分頁查詢
七、Vue框架快速上手
1、前端環(huán)境準(zhǔn)備
2、Vue框架介紹
MVVM模式:
Vue快速入門:
八、Vue組件化開發(fā)
1、NPM簡(jiǎn)介
2、NodeJS安裝
3、NPM使用
4、Vue Cli使用
5、組件化開發(fā)
6、組件的構(gòu)成
九、第三方組件 Element-UI
1、組件間的傳值
2、Element-UI介紹
3、第三方圖標(biāo)庫
十、Axios網(wǎng)絡(luò)請(qǐng)求
?1、Axios簡(jiǎn)介
2、發(fā)送網(wǎng)絡(luò)請(qǐng)求
發(fā)送GET請(qǐng)求
發(fā)生POST請(qǐng)求
異步回調(diào)問題(async/await)
其他請(qǐng)求方式
與Vue整合
3、Axios使用
為什么會(huì)出現(xiàn)跨域問題
跨域問題解決方法
十一、前端路由VueRouter
1、VueRouter安裝與使用
VueRouter安裝:
創(chuàng)建路由組件
聲明路由連接和占位標(biāo)簽
創(chuàng)建路由模塊
掛載路由模塊
實(shí)現(xiàn)效果
2、VueRouter進(jìn)階
路由重定向
嵌套路由
動(dòng)態(tài)路由
編程式導(dǎo)航
導(dǎo)航守衛(wèi)
十二、狀態(tài)管理VueX
1、VueX介紹
2、狀態(tài)管理
最簡(jiǎn)單的store
State
對(duì)象展開運(yùn)算符
Getter
Mutation
Action
Module
總結(jié)
十三、前端數(shù)據(jù)模擬Mock.js
1、Mock.js介紹
2、基本使用
3、核心方法
4、數(shù)據(jù)生成規(guī)則
十四、企業(yè)級(jí)后臺(tái)集成方案
1、vue-element-admin介紹
十五、跨域認(rèn)證
1、Session認(rèn)證
2、Token認(rèn)證
3、JWT
4、JWT組成
Header
Payload
Signature
5、JWT的特點(diǎn)
6、JWT的實(shí)現(xiàn)
十七、Springboot+Vue云端環(huán)境配置
1、安裝MySQL
2、安裝Nginx
3、配置JDK
十八、Springboot+Vue項(xiàng)目部署
1、部署Vue項(xiàng)目
2、打包運(yùn)行Java程序
一、SpringBoot快速上手
1、SpringBoot介紹
- SpringBoot是由Pivotal團(tuán)隊(duì)提供的基于Spring的全新框架,旨在簡(jiǎn)化Spring應(yīng)用的初始搭建和開發(fā)過程。
- SpringBoot是所有基于Spring開發(fā)項(xiàng)目的起點(diǎn)。
- SpringBoot就是盡可能地簡(jiǎn)化應(yīng)用開發(fā)的門檻,讓應(yīng)用開發(fā)、測(cè)試、部署變得更加簡(jiǎn)單。
2、SpringBoot特點(diǎn)
- 遵循“約定優(yōu)于配置”的原則,只需要很少的配置或使用默認(rèn)的配置。
- 能夠使用內(nèi)嵌的Tomcat、Jetty服務(wù)器,不需要部署war文件。
- 提供定制化的啟動(dòng)器starter,簡(jiǎn)化Maven配置,開箱即用。
- 純Java配置,沒有代碼生成,也不需要XML配置。
- 提供了生產(chǎn)級(jí)的服務(wù)監(jiān)控方案,如安全監(jiān)控、應(yīng)用監(jiān)控、健康檢測(cè)等。
3、快速創(chuàng)建SpringBoot應(yīng)用
- 利用IDEA的Spring Initializr創(chuàng)建SpringBoot項(xiàng)目
- 我們開發(fā)web項(xiàng)目,所以添加web依賴
- 這樣就會(huì)自動(dòng)將web項(xiàng)目所需要的依賴下載并引入
- 點(diǎn)擊完成項(xiàng)目就新建成功
- 接下來測(cè)試一下項(xiàng)目運(yùn)行
- 在項(xiàng)目新建一個(gè)controller包,里面專門用來存放controller控制器
- @RestController public class IndexController {@GetMapping("/index")public String index(){return "歡迎訪問首頁";} }
- 接著運(yùn)行主程序?
- 接下來查看控制臺(tái)
- 這樣就運(yùn)行成功
- 我們?cè)跒g覽器訪問一下http://localhost:8888/index
- 這樣就說明項(xiàng)目可以正常訪問了
4、SpringBoot開發(fā)熱部署
- 在實(shí)際的項(xiàng)目開發(fā)調(diào)試過程中會(huì)頻繁地修改后臺(tái)類文件,導(dǎo)致需要重新編譯、重新啟動(dòng),整個(gè)過程非常麻煩,影響開發(fā)效率。
- SpringBoot提供了spring-boot-devtools組件,使得無須手動(dòng)重啟SpringBoot應(yīng)用即可重新編譯、啟動(dòng)項(xiàng)目,大大縮短編譯啟動(dòng)的時(shí)間。
- devtools會(huì)監(jiān)聽classpath下文件的變動(dòng),觸發(fā)Restart類加載器重新加載該類,從而實(shí)現(xiàn)類文件和屬性文件的熱部署。
- 并不是所有的更改都需要重啟應(yīng)用(如靜態(tài)資源、視圖模板),可以通過設(shè)置spring.devtools.restart.exclude屬性來指定一些文件或目錄的修改不用重啟應(yīng)用。
- 實(shí)現(xiàn)步驟:
- 在pom.xml配置文件中添加dev-tools依賴。
- 使用optional=true表示依賴不會(huì)傳遞,即該項(xiàng)目依賴devtools;其他項(xiàng)目如果引入此項(xiàng)目生成的jar包,則不會(huì)包含devtools。
- <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
- 依賴引入后在application.yml中配置devtools
- spring:devtools:restart:enabled: true #熱部署生效additional-paths: src/main/java #設(shè)置重啟目錄exclude: static/** #設(shè)置classpath目錄下的WEB-INF文件夾內(nèi)容修改不重啟
- 配置后還不行,因?yàn)镮DEA還需要在設(shè)置中配置項(xiàng)目自動(dòng)運(yùn)行
- 打開Settings頁面,在左邊的菜單欄依次找到
- Build、Execution、Deployment、Compile,勾選Build project automatically
- 按Ctrl+Shift+Alt+/ 快捷鍵調(diào)出Maintenance頁面,單擊Registry,勾選
- compiler.automake.allow.when.app.running復(fù)選框
- 如果IDEA版本比較搞,可能沒有出現(xiàn)這個(gè)復(fù)選框,那么嘗試以下方法
- 在Settings中拉到最下面找到Advanced Settings
- 然后找到Allow auto-make to start even if developed application is currently running
- 然后勾選
- 這樣開發(fā)熱部署就配置完成。
二、Web開發(fā)基礎(chǔ)
1、Web入門
- SpringBoot將傳統(tǒng)Web開發(fā)的MVC、JSON、Tomcat等框架整合,提供了spring-boot-starter-web組件,簡(jiǎn)化了Web應(yīng)用配置。
- 創(chuàng)建SpringBoot項(xiàng)目勾選SpringWeb選項(xiàng)后,會(huì)自動(dòng)將spring-boot-starter-web組件加入到項(xiàng)目中。
- spring-boot-starter-web啟動(dòng)器主要包括WEB、WebMVC、JSON、Tomcat等基礎(chǔ)依賴組件,作用是提供Web開發(fā)場(chǎng)景所需要的所有底層依賴。
- WebMVC為Web開發(fā)的基礎(chǔ)框架,JSON為JSON數(shù)據(jù)解析組件,Tomcat為自帶的容器依賴。
- <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
2、控制器
- SpringBoot提供了@Controller和@RestController兩種注解來標(biāo)識(shí)此類負(fù)責(zé)接收和處理HTTP請(qǐng)求
- 如果請(qǐng)求的是頁面和數(shù)據(jù),使用@Controller注解即可;如果只是請(qǐng)求數(shù)據(jù),則可以使用@RestController注解
- @Controller的用法
- 下面示例中返回了index頁面和name的數(shù)據(jù),在前端頁面中可以通過${name}參數(shù)獲取后臺(tái)返回的數(shù)據(jù)并顯示。
- @Controller通常與Thymeleaf模板引擎結(jié)合使用
- @Controller public class IndexController {@GetMapping("/index")public String index(ModelMap map){map.addAttribute("name","張三");return "index";} }
- @RestController的用法
- 默認(rèn)情況下,@RestController注解會(huì)將返回的對(duì)象數(shù)據(jù)轉(zhuǎn)換為JSON格式
- @RestController public class IndexController {@GetMapping("/user")public User getUser(){User user = new User();user.setUsername("張三");user.setPassword("123");return user;} }
3、路由映射
- @RequestMapping注解主要負(fù)責(zé)URL的路由映射。它可以添加在Controller類或者具體的方法上。
- 如果添加在Controller類上,則這個(gè)Controller中的所有路由映射都將會(huì)加上此映射規(guī)則,如果添加在方法上,則只對(duì)當(dāng)前方法生效。
- @RequestMapping注解包含很多屬性參數(shù)來定義HTTP的請(qǐng)求映射規(guī)則。常用的屬性參數(shù)如下:
- value:請(qǐng)求URL的路徑,支持URL模板、正則表達(dá)式
- method:HTTP請(qǐng)求方法(POST/GET)
- consumes:請(qǐng)求的媒體類型(Content-Type),如application/json
- produces:響應(yīng)的媒體類型
- params,headers:請(qǐng)求的參數(shù)及請(qǐng)求頭的值
- value和method比較常用,其他三個(gè)比較少用
- @RequestMapping的value屬性用于匹配URL映射,value支持簡(jiǎn)單表達(dá)式
- @RequestMapping("/user")
- @RequestMapping支持使用通配符匹配URL,用于統(tǒng)一映射某些URL規(guī)則類似的請(qǐng)求:
- @RequestMapping("/getJson/*.json"),當(dāng)在瀏覽器中請(qǐng)求/getJson/a.json或者/getJson/b.json時(shí),都會(huì)匹配到后臺(tái)的json方法。
- @RequestMapping的通配符匹配非常簡(jiǎn)單實(shí)用,支持"*"、"?"、"**"等通配符:
- "*":匹配任意字符;
- "**":匹配任意路徑;
- "?":匹配單個(gè)字符。
- 有通配符的優(yōu)先低于沒有通配符的,比如/user/add.json比/user/*.json優(yōu)先匹配。
- 有"**"通配符的優(yōu)先級(jí)低于"*"通配符的。
4、參數(shù)傳遞
- @RequestParam將請(qǐng)求參數(shù)綁定到控制器的方法參數(shù)上,接收的參數(shù)來自HTTP請(qǐng)求體或請(qǐng)求URL的QueryString,當(dāng)請(qǐng)求的參數(shù)名稱與Controller的業(yè)務(wù)方法參數(shù)名稱一致時(shí),@RequestParam可以省略。
- @RequestParam注解一添加,這個(gè)方法就必須加參數(shù),如果URL沒有參數(shù)則會(huì)報(bào)錯(cuò)。如果想解除可不添加參數(shù),可以在注解后面加上required=false,如:
- @RequestParam( value = "xxx",required = false)
- @RestController public class IndexController {// http://localhost:8888/index?nickname=zhangsan@GetMapping("/index")public String index(@RequestParam("nickname") String name){return "你好"+name;} }
- 上面的代碼請(qǐng)求參數(shù)和方法參數(shù)名稱不一致,所以需要使用@RequestParam繼續(xù)綁定
- @RestController public class IndexController {// http://localhost:8888/index?nickname=zhangsan@GetMapping("/index")public String index(String nickname){return "你好"+nickname;} }
- 上面的代碼請(qǐng)求參數(shù)和方法參數(shù)名稱一致,所以不需要使用@RequestParam進(jìn)行綁定
- @RestController public class IndexController {// http://localhost:8888/index?nickname=zhangsan&phone=123@GetMapping("/index")public String index(String name,String phone){return "你好"+name+phone;} }
- 上面代碼是請(qǐng)求多個(gè)參數(shù),URL使用“&”進(jìn)行拼接,方法上再增加一個(gè)參數(shù)
- @PathVaraible:用于處理動(dòng)態(tài)的URL,URL的值可以作為控制器中處理方法的參數(shù)。
- 如果是Rest風(fēng)格的URI,比如動(dòng)態(tài)URI,/xxxx/yyyyy,其中yyyy代表一個(gè)ID,而這個(gè)ID可能是一個(gè)數(shù)據(jù)用用戶表的ID,那么就需要用@PathVaraible將該URI的值傳給controller方法參數(shù)
- @GetMapping("/getUser/{id}")public String getUser(@PathVariable String id){System.out.println("id->"+id);return "getUser";}
- @RequestBody接收的參數(shù)是來自requestBody中,即請(qǐng)求體。一般用于處理非Content-Type:application/x-www-form-urlencoded編碼格式的數(shù)據(jù):
- 比如:application/json、application/xml等類型的數(shù)據(jù)。?
- // http://localhost:8888/getUser@PostMapping("/getUser")public String getUser(@RequestBody User user){System.out.println(user);return "getUser";}
三、Web開發(fā)進(jìn)階
1、靜態(tài)資源訪問
- 使用IDEA創(chuàng)建SpringBoot項(xiàng)目,會(huì)默認(rèn)創(chuàng)建classpath:/static/目錄,靜態(tài)資源一般放在這個(gè)目錄下面即可。
- 如果默認(rèn)的靜態(tài)資源過濾策略不能滿足開發(fā)需求,也可以自定義靜態(tài)資源過濾策略。
- 過濾規(guī)則為/static/**,靜態(tài)資源位置為classpath:/static/
- 在appliction.yml文件中直接定義過濾規(guī)則和靜態(tài)資源位置:
- spring:mvc:static-path-pattern: /static/**web:resources:static-locations: classpath:/static/ #靜態(tài)資源
2、文件上傳原理
- 表單的enctype屬性規(guī)定在發(fā)送到服務(wù)器之前應(yīng)該如何對(duì)表單數(shù)據(jù)進(jìn)行編碼。
- 當(dāng)表單的enctype="application/x-www-form-urlencoded"(默認(rèn))時(shí),form表單中的數(shù)據(jù)格式為:key=value&key=value
- 當(dāng)表單的enctype="multipart/form-data"時(shí),其傳輸數(shù)據(jù)形式如下:
-
SpringBoot實(shí)現(xiàn)文件上傳功能?
-
Springboot工程嵌入的tomcat限制了請(qǐng)求的文件大小,每個(gè)文件的配置最大為1MB,單次請(qǐng)求的文件的總數(shù)不能大于10MB。
-
要更改這個(gè)默認(rèn)值需要在配置文件application.yml中加入兩個(gè)配置:
- spring:servlet:multipart:max-file-size: 10GB #文化最大10Gmax-request-size: 10GB #單次請(qǐng)求文件總數(shù)不能超過10G
-
當(dāng)表單的enctype="multipart/form-data"時(shí),可以使用MultipartFile獲取上傳的文件數(shù)據(jù),再通過transferTo方法將其寫入磁盤中:
- @RestController public class FileController {/*** 默認(rèn)定位到的當(dāng)前用戶目錄("user.dir")(即工程根目錄)* JVM就可以據(jù)"user.dir" + "你自己設(shè)置的目錄" 得到完整的路徑(即絕對(duì)路徑)*/// private static final String UPLOADED_FOLDER = System.getProperty("user.dir")+"/upload/";@PostMapping("/upload")public String upload(MultipartFile file, HttpServletRequest request)throws Exception{System.out.println("文件大小:"+file.getSize());System.out.println("文件的ContentType:"+file.getContentType());System.out.println("文件的初始名字:"+file.getOriginalFilename());String path = request.getServletContext().getRealPath("/upload/");System.out.println("獲取web服務(wù)器的運(yùn)行目錄:"+path);saveFile(file,path);return "upload success";}public void saveFile(MultipartFile f,String path)throws IOException{File upDir = new File(path);if (!upDir.exists()){upDir.mkdir();}File file = new File(path+f.getOriginalFilename());f.transferTo(file);} }
-
3、攔截器
- 攔截器在Web系統(tǒng)中非常常見,對(duì)于某些全局統(tǒng)一的操作,我們可以把它提取到攔截器中實(shí)現(xiàn)??偨Y(jié)起來,攔截器大致有以下幾種使用場(chǎng)景:
- 權(quán)限檢查:如登錄檢測(cè),進(jìn)入處理程序檢測(cè)是否登錄,如果沒有,則直接返回登錄頁面。
- 性能監(jiān)控:有時(shí)系統(tǒng)在某段時(shí)間莫名其妙很慢,可以通過攔截器在進(jìn)入處理程序之前記錄開始時(shí)間,在處理完后記錄結(jié)束時(shí)間,從而得到該請(qǐng)求的處理時(shí)間。
- 通用行為:讀取cookies得到用戶信息并將用戶對(duì)象放入請(qǐng)求,從而方便后續(xù)流程使用,還有提取Locale、Theme信息等,只要是多個(gè)處理程序都需要的,即可使用攔截器實(shí)現(xiàn)。
- Springboot定義了HandlerInterceptor接口來實(shí)現(xiàn)自定義攔截器的功能
- HandlerInterceptor接口定義了preHandle、postHandle、afterCompletion三種方法,通過重寫這三種方法實(shí)現(xiàn)請(qǐng)求前、請(qǐng)求后等操作。
- 攔截器定義:
- public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("LoginInterceptor");return true;} }
- 攔截器注冊(cè):
- addPathPatterns方法定義攔截的地址
- excludePathPatterns定義排除某些地址不被攔截
- 添加的一個(gè)攔截器沒有addPathPattern任何一個(gè)url則默認(rèn)攔截所有請(qǐng)求
- 如果沒有excludePathPatterns任何一個(gè)請(qǐng)求,則默認(rèn)不放過如何一個(gè)請(qǐng)求。
- @Configuration // Configuration必須要添加 public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()); // registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**"); // 攔截所有user下面的接口} }
四、構(gòu)建RESTful服務(wù)
1、RESTful介紹
-
RESTful是目前流行的互聯(lián)網(wǎng)軟件服務(wù)架構(gòu)設(shè)計(jì)風(fēng)格。
-
REST(Representational State Transfer,表述性狀態(tài)轉(zhuǎn)移) 一詞是由Roy Thomas Fielding在2000年的博士論文中提出的,它定義了互聯(lián)網(wǎng)軟件服務(wù)的架構(gòu)原則,如果一個(gè)架構(gòu)符合REST原則,則稱之為RESTful架構(gòu)。
-
REST并不是一個(gè)標(biāo)準(zhǔn),它更像一組客戶端和服務(wù)端交互時(shí)的架構(gòu)理念和設(shè)計(jì)原則,基于這種架構(gòu)理念和設(shè)計(jì)原則的Web API更加簡(jiǎn)潔、更有層次。
2、RESTful特點(diǎn)
- 每一個(gè)URL代表一個(gè)資源。
- 客戶端使用GET、POST、PUT、DELETE四種表示操作方式的動(dòng)詞對(duì)服務(wù)端資源進(jìn)行操作:
- GET用于獲取資源
- POST用于新建資源(也可以用于更新資源)
- PUT用于更新資源
- DELETE用于新建資源
- 通過操作資源的表現(xiàn)形式來實(shí)現(xiàn)服務(wù)端請(qǐng)求操作。
- 資源的表現(xiàn)形式是JSON或HTML。
- 客戶端與服務(wù)端之間的交互在請(qǐng)求之間是無狀態(tài)的,從客戶端到服務(wù)端的每個(gè)請(qǐng)求都包含必需的信息。
3、RESTful API
- 符合RESTful規(guī)范的Web API需要具備如下兩個(gè)關(guān)鍵特性:
- 安全性:安全的方法被期望不會(huì)產(chǎn)生如何副作用,當(dāng)我們使用GET操作獲取資源時(shí),不會(huì)引起資源本身的改變,也不會(huì)引起服務(wù)器狀態(tài)的改變。
- 冪等性:冪等的方法保證了重復(fù)進(jìn)行一個(gè)請(qǐng)求和一次請(qǐng)求的效果相同(并不是指響應(yīng)總是相同的,而是指服務(wù)器上資源的狀態(tài)從第一次請(qǐng)求后就不再改變了),在數(shù)學(xué)上冪等性是指N次變換和一次變換相同。
4、HTTP狀態(tài)碼
- HTTP狀態(tài)碼就是服務(wù)器向用戶返回的狀態(tài)碼和提示信息,客戶端的每一次請(qǐng)求,服務(wù)器都必須回應(yīng),回應(yīng)包括HTTP狀態(tài)碼和數(shù)據(jù)兩部分
- HTTP定義了40個(gè)標(biāo)準(zhǔn)狀態(tài)碼??捎糜趥鬟_(dá)客戶端請(qǐng)求的結(jié)果。狀態(tài)碼分為以下五個(gè)類別:
- 1xx:信息,通信傳輸協(xié)議級(jí)信息
- 2xx:成功,表示客戶端的請(qǐng)求已成功接受
- 3xx:重定向,表示客戶端必須執(zhí)行一些其他操作才能完成其請(qǐng)求
- 4xx:客戶端錯(cuò)誤,此類錯(cuò)誤狀態(tài)碼指向客戶端
- 5xx:服務(wù)器錯(cuò)誤,服務(wù)器負(fù)責(zé)這些錯(cuò)誤狀態(tài)碼
5、SpringBoot實(shí)現(xiàn)RESTful API
- 在RESTful架構(gòu)中,每個(gè)網(wǎng)址代表一種資源,所以URL中建議不要包含動(dòng)詞,只包含名詞即可,而且所用的名詞往往與數(shù)據(jù)庫的表格名對(duì)應(yīng)
- 用戶管理模塊API示例:
-
HTTP Method接口地址接口描述 POST /user 創(chuàng)建用戶 GET /user/id 根據(jù)id獲取用戶信息 PUT /user 更新用戶 DELETE /user/id 根據(jù)id刪除對(duì)應(yīng)用戶
-
- ???????? @RestController public class UserController {// @PathVariable:注:路由內(nèi)屬性與形參相同可簡(jiǎn)寫,// 若不相同,則需要加上對(duì)應(yīng)的名稱綁定,如:@PathVariable("id")@GetMapping("/user/{id}")public String getUserById(@PathVariable int id){System.out.println(id);return "根據(jù)ID獲取用戶信息";}@PostMapping("/user")public String save(User user){return "添加用戶";}@PutMapping("/user")public String update(User user){return "更新用戶";}@DeleteMapping("/user/{id}")public String deleteById(@PathVariable int id){System.out.println(id);return "根據(jù)id刪除用戶";} }
6、Swagger
- Swagger是一個(gè)規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化RESTful風(fēng)格的Web服務(wù),是非常流行的API表達(dá)工具。
- Swagger能夠自動(dòng)生成完善的RESTful API文檔,同時(shí)并根據(jù)后臺(tái)代碼的修改同步更新,同時(shí)提供完整的測(cè)試頁面來調(diào)試API。
-
使用Swagger生成Web API文檔
- 在Springboot項(xiàng)目中集成Swagger很簡(jiǎn)單,只需要在項(xiàng)目中引入springfox-swagger2和springfox-swagger-ui依賴即可。
- <!-- swagger --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency>
-
配置Swagger
- 注意:swagger版本不一樣,配置也不一樣(本人使用的是2.9.2版本)
- @Configuration // 告訴spring容器,這個(gè)類是一個(gè)配置類 @EnableSwagger2 // 啟用Swagger2功能 public class Swagger2Config {@Beanpublic Docket createRestApi(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()// com包下的所有API都交給Swagger2管理.apis(RequestHandlerSelectors.basePackage("com")).paths(PathSelectors.any()).build();}// API文檔頁面顯示信息private ApiInfo apiInfo(){return new ApiInfoBuilder().title("文件系統(tǒng)項(xiàng)目API") // 標(biāo)題.description("學(xué)習(xí)Springboot+Vue項(xiàng)目") // 描述.build();} }
- 如果項(xiàng)目報(bào)以下的錯(cuò)誤
- 這是因?yàn)镾pringboot2.6.x以后與Swagger有版本沖突問題,所以需要在yml文件或properties文件中添加以下配置
- # yml文件: mvc:pathmatch:matching-strategy: ant_path_matcher# properties文件: spring.mvc.pathmatch.matching-strategy=ant_path_matcher
- 這是因?yàn)镾pringboot2.6.x以后與Swagger有版本沖突問題,所以需要在yml文件或properties文件中添加以下配置
-
使用Swagger2進(jìn)行接口測(cè)試
- 啟動(dòng)項(xiàng)目訪問http://localhost:8888/swagger-ui.html,即可打開自動(dòng)生成的可視化測(cè)試頁面。
- 這個(gè)頁面就是成功打開了。
-
Swagger常用注解
- Swagger提供了一系列注解來描述接口信息,包括接口說明、請(qǐng)求方法、請(qǐng)求參數(shù)、返回信息等。
五、MybatisPlus快速上手
1、ORM介紹
- ORM(Object Relational Mapping,對(duì)象關(guān)系映射)是為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫存在的互不匹配現(xiàn)象的一種技術(shù)。
- ORM通過使用描述對(duì)象和數(shù)據(jù)庫之間映射的元數(shù)據(jù)將程序中的對(duì)象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫中。
- ORM框架的本質(zhì)是簡(jiǎn)化編程中操作數(shù)據(jù)庫的編碼。
2、MyBatis-Plus介紹
- MyBatis是一款優(yōu)秀的數(shù)據(jù)持久層ORM框架,被廣泛地應(yīng)用于應(yīng)用系統(tǒng)。
- MyBatis能夠非常靈活地實(shí)現(xiàn)動(dòng)態(tài)SQL,可以使用XML或注解來配置和映射原生信息,能夠輕松地將Java的POJO(Plain Ordinary Java Object,普通Java對(duì)象)與數(shù)據(jù)庫中的表和字段進(jìn)行映射關(guān)聯(lián)。
- MyBatis-Plus是一個(gè)MyBatis的增強(qiáng)工具,在MyBatis的基礎(chǔ)上做了增強(qiáng),簡(jiǎn)化了開發(fā)。
-
添加依賴
- <!-- mybatisPlus 依賴 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!-- mysql驅(qū)動(dòng)依賴 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- 數(shù)據(jù)庫連接池Druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.13-SNSAPSHOT</version></dependency>
-
全局配置
- 配置數(shù)據(jù)庫相關(guān)信息。
- spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/mydb?useSSL=falseusername: rootpassword: 646681 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- 添加@MapperScan注解
- 配置數(shù)據(jù)庫相關(guān)信息。
-
Mybatis CRUD 注解
-
Mybatis CRUD 操作
- @Mapper public interface UserMapper {// 增加用戶@Insert("insert into user(username,password,birthday) values (#{username},#{password},#{birthday})")int add(User user);// 根據(jù)id刪除用戶@Delete("delete from user where id=#{id}")int delete(int id);// 更新用戶信息@Update("update user set username=#{username},password=#{password},birthday=#{birthday} where id=#{id}")int update(User user);// 根據(jù)id查詢用戶@Select("select * from user where id=#{id}")User findById(int id);// 查詢所有用戶@Select("select * from user")List<User> findAll();}
- 以上是Mybatis的CRUD操作
-
Mybatis-Plus 注解
- @TableName,當(dāng)表名與實(shí)體類名稱不一致時(shí),可以使用@TableName注解進(jìn)行關(guān)聯(lián)。
- @TableField,當(dāng)表中字段名稱與實(shí)體類屬性不一致時(shí),使用@TableField進(jìn)行關(guān)聯(lián)。
- @TableId,用于標(biāo)記表中的主鍵字段,MybatisPlus也提供了主鍵生成策略。
- 以上就是MybatisPlus注解的使用
-
Mybatis-Plus CRUD操作
- 在mapper類中繼承BaseMapper<T>,T 表示要操作的entity對(duì)象
- @Mapper public interface UserMapper extends BaseMapper<User> {}
-
要操作User對(duì)象,就將User傳給BaseMapper
-
BaseMapper中提供了很多操作,如增刪改查等等。
-
?直接調(diào)用查詢方法即可,如需知道更多方法的操作使用,請(qǐng)到Mybatis-Plus官網(wǎng)查看
六、多表查詢及分頁查詢
多表查詢
- 實(shí)現(xiàn)復(fù)雜關(guān)系映射,可以使用@Results注解、@Result注解、@One注解、@Many注解組合完成復(fù)雜關(guān)系的配置。
-
多表查詢操作
- User類(對(duì)應(yīng)數(shù)據(jù)庫t_user表)
- @TableName("t_user") public class User {@TableId(type = IdType.AUTO)private int id;private String username;private String password;private String birthday;// 描述用戶的所有訂單@TableField(exist = false) // 表示在數(shù)據(jù)庫表中不存在,不需要做映射private List<Order> orders;public User() {}public User(String username, String password, String birthday) {this.username = username;this.password = password;this.birthday = birthday;}....省略了getter和setter方法@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", birthday='" + birthday + '\'' +'}';} }
- Order類(對(duì)應(yīng)數(shù)據(jù)庫t_order表)
- @TableName("t_order") public class Order {private int id;@TableField("order_time")private String orderTime;private double total;@TableField(exist = false)private User user;public Order() {}public Order(String orderTime, double total, User user) {this.orderTime = orderTime;this.total = total;this.user = user;}....省略了getter和setter方法@Overridepublic String toString() {return "Order{" +"id=" + id +", orderTime='" + orderTime + '\'' +", total=" + total +", user=" + user +'}';} }
- UserMapper接口
- @Mapper public interface UserMapper extends BaseMapper<User> {// 根據(jù)id查用戶@Select("select * from t_user where id=#{id}")User selectById(int id);// 查詢用戶及其所有的訂單@Select("select * from t_user")@Results({@Result(column = "id",property = "id"), // column:字段,property:映射到實(shí)體類的屬性@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(column = "birthday",property = "birthday"),@Result(column = "id",property = "orders",javaType = List.class,many = @Many(select = "com.org.mapper.OrderMapper.selectByUid")// 通過user的id去orderMapper的selectByUid查詢所以該用戶的訂單)})List<User> selectAllUserAndOrders(); }
- OrderMapper接口
- @Mapper public interface OrderMapper extends BaseMapper<Order> {@Select("select * from t_order where uid=#{uid}")List<Order> selectByUid(int uid);// 查詢所有的訂單,同時(shí)查詢訂單用戶@Select("select * from t_order")@Results({@Result(column = "id",property = "id"),@Result(column = "order_time",property = "orderTime"),@Result(column = "total",property = "total"),@Result(column = "uid",property = "user",javaType = User.class,one=@One(select = "com.org.mapper.UserMapper.selectById")// 根據(jù)order的uid到UserMapper的selectById方法中查詢?cè)撚唵嗡鶎俚挠脩?,})List<Order> selectAllOrderAndUser();}
- UserController
- @RestController public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("/user")public List<User> query() {// 查詢用戶及其所有訂單List<User> userList = userMapper.selectAllUserAndOrders();return userList;}}
- OrderController
- @RestController public class OrderController {@Autowiredprivate OrderMapper orderMapper;// 查詢訂單及其所屬的用戶@GetMapping("/order/findAll")public List findAll(){List<Order> orderList = orderMapper.selectAllOrderAndUser();return orderList;} }
- 效果展示如下:
- 查詢所有用戶及其所有訂單
- 查詢訂單及該訂單所屬用戶
條件查詢
- 使用QueryWrapper來創(chuàng)建條件
- 用法如下代碼所示:
- @GetMapping("/user")public List<User> query() {// 條件查詢QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // 創(chuàng)建實(shí)例queryWrapper.eq("username","tom"); // 查詢username為tom的用戶List<User> userList = userMapper.selectList(queryWrapper); // 將條件作為參數(shù)傳入查詢方法,若無條件,則在方法傳入nullreturn userList;}
- 更多條件如下圖所示:
-
條件條件實(shí)現(xiàn)功能例子 eq 等于 = 例: eq("name", "老王")--->name = '老王' ne 不等于 <> 例: ne("name", "老王")--->name <> '老王' gt 大于 > 例: gt("age", 18)--->age > 18 ge 大于等于 >= 例: ge("age", 18)--->age >= 18 lt 小于 < 例: lt("age", 18)--->age < 18 le 小于等于 <= 例: le("age", 18)--->age <= 18 between BETWEEN 值1 AND 值2 例: between("age", 18, 30)--->age between 18 and 30 notBetween NOT BETWEEN 值1 AND 值2 例: notBetween("age", 18, 30)--->age not between 18 and 30 like LIKE '%值%' 例: like("name", "王")--->name like '%王%' notLike NOT LIKE '%值%' 例: notLike("name", "王")--->name not like '%王%' likeLeft LIKE '%值' 例: likeLeft("name", "王")--->name like '%王' likeRight LIKE '值%' 例: likeRight("name", "王")--->name like '王%' isNull 字段 IS NULL 例: isNull("name")--->name is null isNotNull 字段 IS NOT NULL 例: isNotNull("name")--->name is not null in 字段 IN (v0, v1, ...) 例: in("age", 1, 2, 3)--->age in (1,2,3) notIn 字段 NOT IN (value.get(0), value.get(1), ...) 例: notIn("age",{1,2,3})--->age not in (1,2,3) - 更多操作可自行到Mybatis-Plus官網(wǎng)查看
-
分頁查詢
- 編寫配置類
- @Configuration public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor paginationInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); // 數(shù)據(jù)庫類型interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;} }
- 編寫分頁代碼
- // 分頁查詢@GetMapping("/user/findByPage")public IPage findByPage(){// 設(shè)置起始值及每頁條數(shù)Page<User> page = new Page<>(0,2);IPage iPage = userMapper.selectPage(page,null); // 第一個(gè)參數(shù)是page,第二個(gè)參數(shù)是查詢條件return iPage;}
- 效果展示
七、Vue框架快速上手
1、前端環(huán)境準(zhǔn)備
- 編碼工具:VSCode
- 依賴管理:NPM
- 項(xiàng)目構(gòu)建:VueCli
2、Vue框架介紹
- Vue.js是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。
- Vue.js提供了MVVM數(shù)據(jù)綁定和一個(gè)可組合的組件系統(tǒng),具有簡(jiǎn)單、靈活的API。
- 其目標(biāo)是通過盡可能簡(jiǎn)單的API實(shí)現(xiàn)響應(yīng)式的數(shù)據(jù)綁定和可組合的視圖組件。
-
MVVM模式:
- MVVM是Model-View-ViewModel的縮寫,它是一種基于前端開發(fā)的架構(gòu)模式,其核心是提供對(duì)View和ViewModel的雙向數(shù)據(jù)綁定。
- Vue提供了MVVM風(fēng)格的雙向數(shù)據(jù)綁定,核心是MVVM中的VM,也就是ViewModel,ViewModel負(fù)責(zé)連接View和Model,保證視圖和數(shù)據(jù)的一致性。
-
Vue快速入門:
- 導(dǎo)入vue.js的script腳本文件
- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
- 在頁面中聲明一個(gè)將要被vue所控制的DOM區(qū)域,既MVVM中的View
- <div id="app">{{ message }} </div>
- 創(chuàng)建vm實(shí)例對(duì)象(vue實(shí)例對(duì)象)
- const vm = {// 指定數(shù)據(jù)源:即MVVM中的Modeldata: function(){return{message: 'Hello Vue!'}} }const app = Vue.createApp(hello) app.mount('#app) // 指定當(dāng)前vue實(shí)例要控制頁面的哪個(gè)區(qū)域
- 本人使用的是Vue3語法,想了解Vue更多知識(shí)及操作可到Vue官網(wǎng)學(xué)習(xí)!!
- 導(dǎo)入vue.js的script腳本文件
八、Vue組件化開發(fā)
1、NPM簡(jiǎn)介
- NPM(Node Package Manager)是一個(gè)NodeJS包管理和分發(fā)工具。
- NPM以其優(yōu)秀的依賴管理機(jī)制和龐大的用戶群體,目前已經(jīng)發(fā)展成為整個(gè)JS領(lǐng)域的依賴管理工具。
- NPM最常見的用法就是用于安裝和更新依賴。要使用NPM,首先需要安裝Node工具。
2、NodeJS安裝
- NodeJS是一個(gè)基于Chrome V8引擎的JavaScript運(yùn)行時(shí)環(huán)境。
- Node中包含了NPM包管理工具。
- 下載地址:https://nodejs.org/zh-cn/
3、NPM使用
4、Vue Cli使用
- Vue Cli是Vue官方提供的構(gòu)建工具,通常稱為腳手架。
- 用于快速搭建一個(gè)帶有熱重載(代碼修改后不必刷新頁面即可呈現(xiàn)修改后的效果)及構(gòu)建生產(chǎn)版本等功能的單頁面應(yīng)用。
- Vue Cli基于webpack構(gòu)建,也可以通過項(xiàng)目?jī)?nèi)的配置文件進(jìn)行配置。
- 安裝:
- npm install -g @vue/cli
- 具體步驟:
- 以Vue3為例子演示
5、組件化開發(fā)
- 組件(Component)是Vue.js最強(qiáng)大的功能之一。組件可以擴(kuò)展HTML元素,封裝可重用的代碼。
- Vue的組件系統(tǒng)允許我們使用小型、獨(dú)立和通??蓮?fù)用的組件構(gòu)建大型應(yīng)用。
6、組件的構(gòu)成
- Vue中規(guī)定組件的后綴名是.vue
- 每個(gè).vue組件都由三部分組成:
- template:組件的模板結(jié)構(gòu),可以包含HTML標(biāo)簽及其他的組件
- script:組件的JavaScript代碼
- style:組件的樣式
-
想了解Vue Cli項(xiàng)目的更多知識(shí)及操作可到Vue官網(wǎng)學(xué)習(xí)!!
九、第三方組件 Element-UI
1、組件間的傳值
- 組件可以由內(nèi)部的Data提供數(shù)據(jù),也可以由父組件通過prop的方式傳值。
- 兄弟組件之間可以通過Vuex等統(tǒng)一數(shù)據(jù)源提供數(shù)據(jù)共享。
- 目前Element-UI成熟的版本是基于Vue2.x,所以使用Element-UI要?jiǎng)?chuàng)建Vue2.x項(xiàng)目
- 基本數(shù)據(jù)渲染
- 列表數(shù)據(jù)渲染
-
更多語法可在Vue官網(wǎng)學(xué)習(xí)!!
2、Element-UI介紹
- Element-UI是國(guó)內(nèi)餓了么公司提供的一套開源前端框架,簡(jiǎn)潔優(yōu)雅,提供了Vue、React、Angular等多個(gè)版本
- 文檔地址:https://element.eleme.cn/#/zh-CN
- 安裝:
- npm i element-ui
- 以上即為安裝成功
- 引入Element-UI:
- import Vue from 'vue' import App from './App.vue' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); // 全局注冊(cè)Vue.config.productionTip = falsenew Vue({render: h => h(App), }).$mount('#app')
- 簡(jiǎn)單使用Element-UI
- <template><el-table:data="tableData"style="width: 100%":row-class-name="tableRowClassName"><el-table-columnprop="date"label="日期"width="180"></el-table-column><el-table-columnprop="name"label="姓名"width="180"></el-table-column><el-table-columnprop="address"label="地址"></el-table-column></el-table> </template><script> export default {name:"Hello",props:[],data() {return {tableData: [{date: '2016-05-02',name: '王小虎',address: '上海市普陀區(qū)金沙江路 1518 弄',}, {date: '2016-05-04',name: '王小虎',address: '上海市普陀區(qū)金沙江路 1518 弄'}, {date: '2016-05-01',name: '王小虎',address: '上海市普陀區(qū)金沙江路 1518 弄',}, {date: '2016-05-03',name: '王小虎',address: '上海市普陀區(qū)金沙江路 1518 弄'}]}},methods: {tableRowClassName({row, rowIndex}) {if (rowIndex === 1) {return 'warning-row';} else if (rowIndex === 3) {return 'success-row';}return '';}} } </script><style>.el-table .warning-row {background: oldlace;}.el-table .success-row {background: #f0f9eb;} </style>
- 更多組件和樣式可參考官方文檔:https://element.eleme.cn/#/zh-CN
3、第三方圖標(biāo)庫
- 由于Element-UI提供的字體圖符較少,一般會(huì)采用其他圖標(biāo)庫,如著名的FontAwesome。
- FontAwesome提供了675個(gè)可縮放的矢量圖標(biāo),可以使用CSS所提供的所有特性對(duì)它們進(jìn)行更改,包括大小、顏色、陰影或者其他任何支持的效果。
- 文檔地址:https://fontawesome.dashgame.com/
- 安裝:
- npm install font-awesome
- 使用:
- import 'font-awesome/css/font-awesome.min.css';
- <i class="fa fa-camera-retro"></i> fa-camera-retro
- 更多圖標(biāo)可參考官網(wǎng):https://fontawesome.dashgame.com/
十、Axios網(wǎng)絡(luò)請(qǐng)求
?1、Axios簡(jiǎn)介
- 在實(shí)際項(xiàng)目開發(fā)中,前端頁面所需要的數(shù)據(jù)往往需要從服務(wù)器獲取,這必然涉及與服務(wù)器的通信。
- Axios是一個(gè)基于promise網(wǎng)絡(luò)請(qǐng)求庫,作用于node.js和瀏覽器中。
- Axios在瀏覽器端使用XMLHttpRequests發(fā)送網(wǎng)絡(luò)請(qǐng)求,并能自動(dòng)完成JSON數(shù)據(jù)的轉(zhuǎn)換。
- 安裝:
- npm install axios
- 地址:https://www.axios-http.cn/
- 引入:
- import axios from 'axios';
2、發(fā)送網(wǎng)絡(luò)請(qǐng)求
-
發(fā)送GET請(qǐng)求
- 方式一
- // 向給定id的用戶發(fā)起請(qǐng)求 axios.get('http://localhost:8080/user?id=123').then(function(response){// 處理成功情況console.log(response);}).catch(function(error){// 處理失敗情況console.log(error);}).then(function(){// 總是會(huì)執(zhí)行});
- ?方式二
- // 上述請(qǐng)求也可以按以下方式完成axios.get('http://localhost:8080/user',{params:{id:123}}).then(function(response){// 處理成功情況console.log(response);}).catch(function(error){// 處理失敗情況console.log(error);}).then(function(){// 總是會(huì)執(zhí)行});
- 方式一
-
發(fā)生POST請(qǐng)求
- axios.post('http://localhost:8080/user',{firstName: 'Fred',lastName: 'Flintstone' }) .then(function(response){console.log(response); }) .catch(function(error){console.log(error); });
-
異步回調(diào)問題(async/await)
- 可以取代上面的異步編程
- // 支持async/await 用法 async function getUser(){try{// 不需要.then就可以之間拿到response響應(yīng)數(shù)據(jù)const response = await.axios.get('http://localhost:8080/user?id=1');console.log(response);}catch(error){console.error(error);} }
-
其他請(qǐng)求方式
-
??參考官方文檔:https://axios-http.com/zh/docs/req_config
-
-
與Vue整合
-
在實(shí)際項(xiàng)目開發(fā)中,幾乎每個(gè)組件中都會(huì)用到axios發(fā)起的數(shù)據(jù)請(qǐng)求。此時(shí)會(huì)遇到如下兩個(gè)問題:
-
每個(gè)組件中都需要導(dǎo)入axios
-
每次發(fā)送請(qǐng)求都需要填寫完整的請(qǐng)求路徑
-
-
可以通過全局配置的方法解決上述問題:
- // 在main.js中導(dǎo)入axios,然后再繼續(xù)配置 import axios from 'axios'// 配置請(qǐng)求根路徑 axios.defaults.baseURL = 'http://xxx'// 將axios作為全局的自定義屬性,每個(gè)組件可以在內(nèi)部直接訪問(Vue3) app.config.globalProerties.$http = axios// 將axios作為全局的自定義屬性(不一定$http,可以自定義),每個(gè)組件可以在內(nèi)部直接訪問(Vue2) Vue.prototype.$http = axios //例如:直接在其他組件中寫:this.$http.get()就可以實(shí)現(xiàn)axios的功能
-
3、Axios使用
-
Vue項(xiàng)目的網(wǎng)絡(luò)請(qǐng)求一般在created里面做,這樣頁面一創(chuàng)建就會(huì)發(fā)送網(wǎng)絡(luò)請(qǐng)求。
- created:function(){axios.get("http://localhost:8888/user").then((response)=>{ // 箭頭函數(shù):ES6語法,它的作用:它的作用域繼承于父級(jí)(也就是Vue實(shí)例),如果用function(response),作用域就不是Vue實(shí)例console.log(response.data);this.tableData = response.data;console.log(this.tableData);}).catch(function(error){console.log(error);})},
-
當(dāng)我們運(yùn)行項(xiàng)目后,控制臺(tái)顯示報(bào)錯(cuò)了,這個(gè)的意思是沒有明確授權(quán)同源策略,導(dǎo)致被CORS策略阻止。
-
為什么會(huì)出現(xiàn)跨域問題
-
為了保證瀏覽器的安全,不同源的客戶端本在沒有明確授權(quán)的情況下,不能讀寫對(duì)方資源,稱為同源策略,同源策略是瀏覽器安全的基石。
-
同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能。
-
所謂同源(即指在同一個(gè)域)就是兩個(gè)頁面具有相同的協(xié)議(protocol),主機(jī)(host)和端口號(hào)(port)。
-
當(dāng)一個(gè)請(qǐng)求url的協(xié)議、域名、端口三者之間任意一個(gè)與當(dāng)前頁面url不同即為跨域,此時(shí)無法讀取非同源網(wǎng)頁的Cookie,無法向非同源地址發(fā)送Ajax請(qǐng)求或者Axios請(qǐng)求。
-
-
跨域問題解決方法
- CORS(Cross-Origin Resource Sharing)是由W3C制定的一種跨域資源共享技術(shù)標(biāo)準(zhǔn),其目的就是為了解決前端的跨域請(qǐng)求。
- CORS可以在不破壞既有規(guī)則的情況下,通過后端服務(wù)器實(shí)現(xiàn)CORS接口,從而實(shí)現(xiàn)跨域通信。
- CORS將請(qǐng)求分為兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求,分別對(duì)跨域通信提供支持。
- 簡(jiǎn)單請(qǐng)求:(滿足以下條件的請(qǐng)求即為簡(jiǎn)單請(qǐng)求,不滿足即為復(fù)雜請(qǐng)求)
- 請(qǐng)求方法:GET、POST、HEAD
- 除了以下的請(qǐng)求頭字段之外,沒有自定義的請(qǐng)求頭:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type
- Content-Type的值只有以下三種:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
-
簡(jiǎn)單請(qǐng)求的服務(wù)器處理
-
對(duì)于簡(jiǎn)單請(qǐng)求,CORS的策略是請(qǐng)求時(shí)在請(qǐng)求頭中增加一個(gè)Origin字段。
-
服務(wù)器收到請(qǐng)求后,根據(jù)該字段判斷是否允許該請(qǐng)求訪問,如果允許,則在HTTP頭信息中添加Access-Control-Allow-Origin字段。
-
如果沒有配置跨域,是不會(huì)有Access-Control-Allow-Origin字段的。
-
-
非簡(jiǎn)單請(qǐng)求
-
對(duì)于非簡(jiǎn)單請(qǐng)求的跨源請(qǐng)求,瀏覽器會(huì)在真實(shí)請(qǐng)求發(fā)出前增加一次OPTION請(qǐng)求,稱為預(yù)檢請(qǐng)求(preflight request)。
-
預(yù)檢請(qǐng)求將真實(shí)請(qǐng)求的信息,包括請(qǐng)求方法、自定義頭字段、源信息添加到HTTP頭信息字段中,詢問服務(wù)器是否允許這樣的操作。
-
例如一個(gè)GET請(qǐng)求:
-
Access-Control-Request-Method表示請(qǐng)求使用的HTTP方法,Access-Control-Request-Headers包含請(qǐng)求的自定義頭字段。
-
服務(wù)器收到請(qǐng)求時(shí),需要分別對(duì)Origin、Access-Control-Request-Method、Access-Control-Request-Headers進(jìn)行驗(yàn)證,驗(yàn)證通過后,會(huì)在返回HTTP頭信息中添加:
- Access-Control-Allow-Methods、Access-Control-Allow-Headers:真實(shí)請(qǐng)求允許的方法、允許使用的字段。
- Access-Control-Allow-Credentials:是否允許用戶發(fā)送、處理Cookie。
- Access-Control-Max-Age:預(yù)檢請(qǐng)求的有效期,單位為秒,有效期內(nèi)不會(huì)重復(fù)發(fā)送預(yù)檢請(qǐng)求。
- 當(dāng)預(yù)檢請(qǐng)求通過后,瀏覽器才會(huì)發(fā)送真實(shí)請(qǐng)求到服務(wù)器。這樣就實(shí)現(xiàn)了跨域資源的請(qǐng)求訪問。
-
- Springboot中配置CORS
- 方式一:
- @Configuration public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允許跨域訪問的路徑.allowedOrigins("*") // 允許跨域訪問的源.allowedMethods("POST","GET","PUT","OPTIONS","DELETE") // 允許請(qǐng)求的方法.maxAge(16800) // 預(yù)檢間隔時(shí)間.allowedHeaders("*") // 允許頭部設(shè)置.allowCredentials(true); // 是否發(fā)送Cookie} }
- 方式二:
- 方式一:
- ???配置好后重新訪問就可以請(qǐng)求成功了
十一、前端路由VueRouter
1、VueRouter安裝與使用
- Vue路由vue-router是官方的路由插件,能夠輕松的管理SPA項(xiàng)目中組件的切換。
- Vue的單頁面應(yīng)用是基于路由和組件的,路由用于設(shè)定訪問路徑,并將路徑和組件映射起來。
- vue-router目前有3.x版本和4.x版本:
- vue-router3.x只能結(jié)合vue2進(jìn)行使用;
- vue-router4.x只能結(jié)合vue3進(jìn)行使用。
-
VueRouter安裝:
- vue-router@3在vue2中使用 npm install vue-router@3vue-router@4在vue3中使用 npm install vue-router@4
-
創(chuàng)建路由組件
-
聲明路由連接和占位標(biāo)簽
- 可以使用<router-link>標(biāo)簽來聲明路由鏈接,并使用<router-view>標(biāo)簽來聲明路由占位符,示例如下:
- <template><div id="app"><!-- 聲明路由鏈接 --><router-link to="/teleplay">電視劇</router-link><router-link to="/film">電影</router-link><router-link to="/variety">綜藝</router-link><!-- 聲明路由占位標(biāo)簽 --><router-view></router-view></div> </template>
-
創(chuàng)建路由模塊
- 在項(xiàng)目src目錄下創(chuàng)建一個(gè)router目錄,在里面新建一個(gè)index.js路由模塊
- 然后編寫以下代碼
- import VueRouter from "vue-router"; import Vue from "vue"; import Teleplay from '../components/Teleplay.vue' import Film from '../components/Film.vue' import Variety from '../components/Variety.vue'// 將VueRouter設(shè)置為Vue組件 Vue.use(VueRouter)const router = new VueRouter({// 指定hash屬性與組件的對(duì)應(yīng)關(guān)系routes:[{path:'/teleplay',component:Teleplay},{path:'/film',component:Film},{path:'/variety',component:Variety}] })export default router
- 在項(xiàng)目src目錄下創(chuàng)建一個(gè)router目錄,在里面新建一個(gè)index.js路由模塊
-
掛載路由模塊
- 在main.js中導(dǎo)入并掛載router
- import Vue from 'vue' import App from './App.vue' import router from './router/index'Vue.config.productionTip = falsenew Vue({render: h => h(App),// router: router // 如果名稱和屬性一致可以直接寫router即可router }).$mount('#app')
-
實(shí)現(xiàn)效果
2、VueRouter進(jìn)階
-
路由重定向
- 路由重定向指的是:用戶在訪問地址A的時(shí)候,強(qiáng)制用戶跳轉(zhuǎn)到地址C,從而展示特定的組件頁面。
- 通過路由規(guī)則的redirect屬性,指定一個(gè)新的路由地址,可以很方便地設(shè)置路由的重定向。
- // 將VueRouter設(shè)置為Vue組件 Vue.use(VueRouter)const router = new VueRouter({// 指定hash屬性與組件的對(duì)應(yīng)關(guān)系routes:[// 當(dāng)用戶訪問時(shí),直接跳轉(zhuǎn)訪問teleplay{path:'/',redirect:'/teleplay'},{path:'/teleplay',component:Teleplay},{path:'/film',component:Film},{path:'/variety',component:Variety}] })export default router
-
嵌套路由
- 在Teleplay.vue組件中,聲明toplist和newlist的子路由鏈接以及子路由占位符,示例代碼如下:
- 在Teleplay中嵌套子路由:
- <template><div><h1>電視劇</h1><!-- 子路由鏈接 --><router-link to="/teleplay/toplist">推薦</router-link><router-link to="/teleplay/newlist">最新</router-link><hr><router-view></router-view></div> </template>
- 在index.js路由模塊中,導(dǎo)入需要的組件,并使用children屬性聲明子路由規(guī)則:
- const router = new VueRouter({// 指定hash屬性與組件的對(duì)應(yīng)關(guān)系routes:[// 當(dāng)用戶訪問時(shí),直接跳轉(zhuǎn)訪問teleplay{path:'/',redirect:'/teleplay'},{path:'/teleplay',component:Teleplay,// 通過children屬性,嵌套聲明子路由children:[{path:'toplist',component: Toplist},{path:'newlist',component: Newlist}]},{path:'/film',component:Film},{path:'/variety',component:Variety},] })export default router
- 在Teleplay中嵌套子路由:
- 在Teleplay.vue組件中,聲明toplist和newlist的子路由鏈接以及子路由占位符,示例代碼如下:
-
動(dòng)態(tài)路由
- 以下有三個(gè)路由鏈接,分別跳轉(zhuǎn)不同的電影界面
- 新建一個(gè)電影詳情頁Filmdetail.vue
- 然后在router中添加路由鏈接
- {path:'/film',component:Film,children:[{path:':id',component:Filmdetail},] },
- 這樣就能實(shí)現(xiàn)傳參
- 為了簡(jiǎn)化路由參數(shù)的獲取形式,vue-router允許在路由規(guī)則中開啟props傳參。
- {path:'/film',component:Film,children:[{path:':id',component:Filmdetail,props:true},] },
- <template><div><h1>電影詳情頁</h1><!-- 獲取動(dòng)態(tài)的id值 --><p>電影{{id}}</p></div> </template><script>export default{// 組件名稱name:'Filmdetail',props:["id"] // 定義屬性名稱} </script>
-
這樣就可以根據(jù)自己自定義的屬性來獲取傳過來的參數(shù)。
- 新建一個(gè)電影詳情頁Filmdetail.vue
- 以下有三個(gè)路由鏈接,分別跳轉(zhuǎn)不同的電影界面
-
編程式導(dǎo)航
-
聲明式編程式 <router-link to="..."> router.push(...) - 除了使用<router-link> 創(chuàng)建a標(biāo)簽來定義導(dǎo)航鏈接,我們還可以借助router的實(shí)例方法,通過編寫代碼來實(shí)現(xiàn)。
- 想要導(dǎo)航到不同的URL,則使用router.push方法。這個(gè)方法會(huì)向history棧添加一個(gè)新的記錄,所以,當(dāng)用戶點(diǎn)擊瀏覽器后退按鈕時(shí),則回到之前的URL。
- 當(dāng)你點(diǎn)擊<router-link>時(shí),這個(gè)方法會(huì)在內(nèi)部調(diào)用,所以說,點(diǎn)擊<router-link to="...">等同于調(diào)用router.push(....)。
- <template><div><h1>電影</h1><router-link to="/film/1">電影1</router-link><router-link to="/film/2">電影2</router-link><router-link to="/film/3">電影3</router-link><!-- 路由占位標(biāo)簽 --><router-view></router-view><button v-on:click="gotoFilmdetail(3)">跳轉(zhuǎn)到電影3</button></div> </template><script> export default{methods:{gotoFilmdetail:function(id){this.$router.push('/filmdetail/'+id); // 跳轉(zhuǎn)到特定的url(必須有聲明的url) }} } </script>
-
-
導(dǎo)航守衛(wèi)
- vue-router提供的導(dǎo)航守衛(wèi)主要用來攔截導(dǎo)航,讓它完成跳轉(zhuǎn)或取消。
- to:Route:即將要進(jìn)入的目標(biāo)路由。
- from:Route:當(dāng)前導(dǎo)航正要離開的路由。
- next:在守衛(wèi)方法中如果聲明了next形參,則必須調(diào)用next()函數(shù),否則不允許用戶訪問任何一個(gè)路由。
- 直接放行:next()
- 強(qiáng)制其跳轉(zhuǎn)到登錄頁面:next('/login')
- 強(qiáng)制其停留在當(dāng)前頁:next(false)
- 使用router.beforeEach注冊(cè)一個(gè)全局前置守衛(wèi):
- router.beforeEach((to,from,next)=>{if(to.path === '/main' && !isAuthenticated){next('/login');}else{next();} });
十二、狀態(tài)管理VueX
1、VueX介紹
- 對(duì)于組件化開發(fā)來說,大型應(yīng)用的狀態(tài)往往跨越多個(gè)組件。在多層嵌套的父子組件之間傳遞狀態(tài)已經(jīng)十分麻煩,而Vue更是沒有為兄弟組件提供直接共享數(shù)據(jù)的辦法。
- 基于這個(gè)問題,許多框架提供了解決方案——使用全局的狀態(tài)管理器,將所有分散的共享數(shù)據(jù)交由狀態(tài)管理器保管,Vue也不例外。
- VueX是一個(gè)專門Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理庫,采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)。
- 簡(jiǎn)單的說,VueX用于管理分散在Vue各個(gè)組件中的數(shù)據(jù)。
- 安裝:
- 這是vue2版本 npm install vuex@3這是vue3版本 npm install vuex@4
2、狀態(tài)管理
- 每一個(gè)Vuex應(yīng)用的核心都是一個(gè)store,與普通的全局對(duì)象不同的是,基于Vue數(shù)據(jù)與視圖綁定的特點(diǎn),當(dāng)store中的狀態(tài)發(fā)生變化時(shí),與之綁定的視圖也會(huì)被重新渲染。
- store中的狀態(tài)不允許被直接修改,改變store中的狀態(tài)的唯一途徑就是顯式地提交(commit)mutation,這可以讓我們方便地跟蹤每一個(gè)狀態(tài)的變化。
- 在大型復(fù)雜應(yīng)用中,如果無法有效地跟蹤到狀態(tài)的變化,將會(huì)對(duì)理解和維護(hù)代碼帶來極大的困擾。
- Vuex中有5個(gè)重要的概念:State、Getter、Mutation、Action、Module。
-
最簡(jiǎn)單的store
- 安裝Vuex之后,讓我們來創(chuàng)建一個(gè)store。創(chuàng)建過程直接了當(dāng)——僅需要提供一個(gè)初始state對(duì)象和一些mutation:
- 在src目錄下新建一個(gè)store目錄,在store目錄下新建一個(gè)index.js來創(chuàng)建store
- 在index.js中寫如下代碼:
- import Vue from "vue"; import Vuex from "vuex";Vue.use(Vuex); const store = new Vuex.Store({state:{count:0,},mutations:{increment(state){state.count++;}} })export default store;
- 在main.js中導(dǎo)入store這樣組件就都可以使用store
- // 導(dǎo)入store import store from './store/index'new Vue({render: h => h(App),store:store }).$mount('#app')
- 現(xiàn)在就可以通過store.state來獲取狀態(tài)對(duì)象,并通過store.commit方法觸發(fā)狀態(tài)變更:
- <template><div><h1>TestStore</h1><h2>{{this.$store.state.count}}</h2><button @click="add">+1</button></div> </template><script> export default{name:'TestStore',methods:{add(){this.$store.commit("increment"); }} } </script>
- 通過提交mutation的方式,而非直接改變store.state.count,是因?yàn)橥饷嫦胍?strong>更明確地追蹤到狀態(tài)的變化。這個(gè)簡(jiǎn)單的約定能夠讓你的意圖更加明顯,這樣你在閱讀代碼的時(shí)候更容易地解讀應(yīng)用內(nèi)部的狀態(tài)改變。此外,這樣讓我們有機(jī)會(huì)去實(shí)現(xiàn)一些能記錄每次狀態(tài)改變,保存狀態(tài)快照的調(diào)試工具。有了它,甚至可以實(shí)現(xiàn)如時(shí)間穿梭般的調(diào)試體驗(yàn)。
- 由于store中的狀態(tài)是響應(yīng)式的,在組件中調(diào)用store中的狀態(tài)簡(jiǎn)單到僅需要在計(jì)算屬性中返回即可。觸發(fā)變化也僅僅是在組件的methods中提交mutation。
- 在src目錄下新建一個(gè)store目錄,在store目錄下新建一個(gè)index.js來創(chuàng)建store
- 安裝Vuex之后,讓我們來創(chuàng)建一個(gè)store。創(chuàng)建過程直接了當(dāng)——僅需要提供一個(gè)初始state對(duì)象和一些mutation:
-
State
- State用于維護(hù)所有應(yīng)用層的狀態(tài),并確保應(yīng)用只有唯一的數(shù)據(jù)源
- const store = new Vuex.Store({state:{count:0},mutations:{increment(state){state.count++;}} })
- 在組件中,可以直接使用this.$store.count訪問數(shù)據(jù),也可以先用mapState輔助函數(shù)將其映射下來。
- 直接使用this.$store.count訪問數(shù)據(jù)
- <template><div><h1>TestStore</h1><h2>{{this.$store.state.count}}</h2></div> </template>
- 先用mapState輔助函數(shù)將其映射下來
- import {mapState} from 'vuex'export default{name: 'TestStore',computed: mapState({// 箭頭函數(shù)可使代碼更加簡(jiǎn)練count: state => state.count,// 傳字符串參數(shù) 'count' 等同于 'state => state.count'countAlias: 'count',// 為了能夠使用'this'獲取局部狀態(tài),必須使用常規(guī)函數(shù)countPlusLocalState(state){return state.count + this.localCount}}) }
- 注意:當(dāng)映射的計(jì)算屬性的名稱與state的子節(jié)點(diǎn)名稱相同時(shí),我們也可以給mapState傳一個(gè)字符串?dāng)?shù)組。
- computed: mapState([// 映射 this.count 為 store.state.count'count' ])
- 直接使用this.$store.count訪問數(shù)據(jù)
- State用于維護(hù)所有應(yīng)用層的狀態(tài),并確保應(yīng)用只有唯一的數(shù)據(jù)源
-
對(duì)象展開運(yùn)算符
- mapState函數(shù)返回的是一個(gè)對(duì)象。我們?nèi)绾螌⑺c局部計(jì)算屬性混合使用呢?通常,我們需要使用一個(gè)工具函數(shù)將多個(gè)對(duì)象合并為一個(gè),以使我們可以將最終對(duì)象傳給computed屬性。但是自從有了對(duì)象展開運(yùn)算符,我們可以極大地簡(jiǎn)化寫法:
- computed:{// 這是自定義的一個(gè)計(jì)算屬性localComputed(){....},// 使用對(duì)象展開運(yùn)算符("...")將此對(duì)象混入到外部對(duì)象中...mapState({// ...}) }
- mapState函數(shù)返回的是一個(gè)對(duì)象。我們?nèi)绾螌⑺c局部計(jì)算屬性混合使用呢?通常,我們需要使用一個(gè)工具函數(shù)將多個(gè)對(duì)象合并為一個(gè),以使我們可以將最終對(duì)象傳給computed屬性。但是自從有了對(duì)象展開運(yùn)算符,我們可以極大地簡(jiǎn)化寫法:
-
Getter
- Getter維護(hù)由State派生的一些狀態(tài),這些狀態(tài)隨著State狀態(tài)的變化而變化
- const store = new Vuex.Store({state:{todos:[{id:1,text:"吃飯",done:true},{id:2,text:"睡覺",done:false}]},getters:{doneTodos: (state) => {return state.todos.filter(todo => todo.done===false);}} })
- 在組件中,可以直接使用this.$store.getters.doneTodos,也可以先用mapGetters輔助函數(shù)將其映射下來,代碼如下:
- <script> import { mapGetters } from 'vuex'; export default{name:'TestStore',computed: {// 使用對(duì)象展開運(yùn)算符將getter混入computed對(duì)象中...mapGetters(['doneTodos'])} } </script>
- <template><div><ul><li v-for="todo in doneTodos" :key="todo.id">{{todo.text}}</li></ul></div> </template>
- Getter維護(hù)由State派生的一些狀態(tài),這些狀態(tài)隨著State狀態(tài)的變化而變化
-
Mutation
- Mutation提供修改State狀態(tài)的方法
- const store = new Vuex.Store({state:{count:0},mutations:{increment(state){state.count++;}} })
- 在組件中,可以直接使用store.commit來提交mutation
- methods: {increment(){this.$store.commit('increment')console.log(this.$store.state.count)} }
- 也可以先用mapMutation輔助函數(shù)
- methods:{...mapMutations(['increment', // 將'this.increment()'映射為'this.$store.commit('increment')'// 'mapMutations'也支持載荷:(可以傳入額外的參數(shù),即為載荷)'incrementBy' // 將'this.incrementBy(amount)'映射為'this.$store.commit('incrementBy',amount)']), }
- Mutation提供修改State狀態(tài)的方法
-
Action
- Action類似Mutation,不同在于:
- Action不能直接修改狀態(tài),只能通過提交mutation來修改,Action可以包含異步操作
- const store = createStore({state: {count: 0;},mutations: {increment(state){state.count ++;}},actions: {increment(context){context.commit('increment');}} })
- 在組件中,可以直接使用this.$store.dispatch('xxx')分發(fā)action,或者使用mapActions輔助函數(shù)先將其映射下來
- methods:{...mapActions(['increment', // 將'this.increment()' 映射為 'this.$store.dispatch('increment')'// 'mapActions' 也支持載荷:'incrementBy' // 將 'this.incrementBy(amount)' 映射為 'this.$store.dispatch('incrementBy',amount)']),...mapActions({add: 'increment' // 將'this.add()' 映射為 'this.$store.dispatch('increment')'}) }
- Action類似Mutation,不同在于:
-
Module
- 由于使用單一狀態(tài)樹,當(dāng)項(xiàng)目的狀態(tài)非常多時(shí),store對(duì)象就會(huì)變得十分臃腫。因此,Vuex允許我們將store分割成模塊(Module)。
- 每個(gè)模塊擁有獨(dú)立的State、Getter、Mutation和Action,模塊之中還可以嵌套模塊,每一級(jí)都有著相同的結(jié)構(gòu)。
- const moduleA = {state: ()=>({...}),mutations: {...},actions:{...},getters: {...} }const moduleB = {state: ()=>({...}),mutations: {...},actions:{...} }const store = createStore({modules: {a: moduleA,b: moduleB} })store.state.a // ——>moduleA的狀態(tài) store.state.b // ——>moduleB的狀態(tài)
-
總結(jié)
- 作為一個(gè)狀態(tài)管理器,首先要有保管狀態(tài)的容器——State
- 為了滿足衍生數(shù)據(jù)和數(shù)據(jù)鏈的需求,從而有了Getter
- 為了可以“顯式地”修改狀態(tài),所以需要Mutation
- 為了可以“異步地”修改狀態(tài)(滿足AJAX等異步數(shù)據(jù)交互),所以需要Action
- 最后,如果應(yīng)用有成百上千個(gè)狀態(tài),放在一起會(huì)顯得十分龐雜,所以分模塊管理(Module)也是必不可少的
- Vuex并不是Vue應(yīng)用開發(fā)的必選項(xiàng),在使用時(shí),應(yīng)先考慮項(xiàng)目的規(guī)模和特點(diǎn)。有所選擇地進(jìn)行取舍,對(duì)于小型應(yīng)用來說,完全沒有必要引入狀態(tài)管理,因?yàn)闀?huì)帶來更多的開發(fā)成本。
十三、前端數(shù)據(jù)模擬Mock.js
1、Mock.js介紹
- Mock.js是一款前端開發(fā)中攔截Ajax請(qǐng)求再生成隨機(jī)數(shù)據(jù)響應(yīng)的工具,可以用來模擬服務(wù)器響應(yīng)。
- 優(yōu)點(diǎn):非常簡(jiǎn)單方便、無侵入性,基本覆蓋常用的接口數(shù)據(jù)類型。
- 支持生成隨機(jī)的文本、數(shù)字、布爾值、日期、郵箱、鏈接、圖片、顏色等。
- 安裝:
- npm install mockjs
2、基本使用
- 在項(xiàng)目src目錄下創(chuàng)建mock目錄,新建index.js文件
- // 引入mock.js import Mock from 'mockjs'// 設(shè)置延遲時(shí)間 // Mock.setup({ // timeout: 400 // })// 使用mock.js模擬數(shù)據(jù) Mock.mock('/product/search',{"ret": 0,"data": {"mtime": "@datatime", // 隨機(jī)生成日期時(shí)間"score|1-800": 800, // 隨機(jī)生成1-800的數(shù)字"rank|1-100": 100, // 隨機(jī)生成1-100的數(shù)字"stars|1-5": 5, // 隨機(jī)生成1-5的數(shù)字"nickname": "@cname", // 隨機(jī)生成中文名字"img": "@image('200x100','#ffcc33','#FFF','png','Fast Mock')"// 尺寸 背景顏色 文字顏色 圖片格式 圖片文字 }})
- 然后在main.js中導(dǎo)入,否則無法使用
- import './mock/index'
- 組件中調(diào)用mock.js中模擬的數(shù)據(jù)接口,這時(shí)返回的response就是mock.js中用Mock.mock('url',data)中設(shè)置的data
- import axios from 'axios'export default{mounted:function(){axios.get("/product/search").then(res=>{console.log(res)})} }
- 效果如下:
3、核心方法
- Mock.mock(rurl?, rtype?, template|function(options))
- rurl:表示需要攔截的URL,可以是URL字符串或URL正則
- rtype:表示需要攔截的Ajax請(qǐng)求類型。例如GET、POST、PUT、DELETE等。
- template:表示數(shù)據(jù)模板,可以是對(duì)象或字符串
- function:表示用于生成響應(yīng)數(shù)據(jù)的函數(shù)。
- 設(shè)置延時(shí)請(qǐng)求到數(shù)據(jù)
- // 延時(shí)400ms請(qǐng)求到數(shù)據(jù) Mock.setup({timeout: 400 })// 延時(shí)200-600ms請(qǐng)求到數(shù)據(jù) Mock.setup({timeout: '200-600' })
4、數(shù)據(jù)生成規(guī)則
- mock的語法規(guī)范包含兩層規(guī)范:數(shù)據(jù)模板(DTD)、數(shù)據(jù)占位符(DPD)
- 數(shù)據(jù)模板中的每個(gè)屬性由3部分構(gòu)成:屬性名name、生成規(guī)則rule、屬性值value:
- // 屬性名 name // 生成規(guī)則 rule // 屬性值 value 'name|rule': value
- 屬性名和生成規(guī)則之間用豎線|分隔,生成規(guī)則是可選的,有7中格式:
- 更多詳細(xì)知識(shí)可在mockJS官網(wǎng)了解
十四、企業(yè)級(jí)后臺(tái)集成方案
1、vue-element-admin介紹
- vue-element-admin是一個(gè)后臺(tái)前端解決方案,它基于vue和element-ui實(shí)現(xiàn)。
- 內(nèi)置了i18國(guó)際化解決方案,動(dòng)態(tài)路由,權(quán)限驗(yàn)證,提煉了典型的業(yè)務(wù)模型,提供了豐富的功能組件。
- 可以快速搭建企業(yè)級(jí)中后臺(tái)產(chǎn)品原型。
- 地址:https://panjiachen.github.io/vue-element-admin-site/zh/guide/
- 在github上把項(xiàng)目下載下來https://github.com/PanJiaChen/vue-admin-template
- 具體使用可在官網(wǎng)查看文檔。
十五、跨域認(rèn)證
1、Session認(rèn)證
互聯(lián)網(wǎng)服務(wù)離不開用戶認(rèn)證。一般是一下流程:
- 用戶向服務(wù)器發(fā)送用戶名和密碼。
- 服務(wù)器驗(yàn)證通過后,在當(dāng)前對(duì)話(session)里面保存相關(guān)數(shù)據(jù),比如用戶角色、登錄時(shí)間等。
- 服務(wù)器向用戶返回一個(gè)session_id,寫入用戶的Cookie。
- 用戶隨后的每一次請(qǐng)求,都會(huì)通過Cookie,將session_id傳回服務(wù)器。
- 服務(wù)器收到session_id,找到前期保存的數(shù)據(jù),由此得知用戶的身份。
- session認(rèn)證過程:
- session認(rèn)證的方式應(yīng)用非常普遍,但也存在一些問題,擴(kuò)展性不好,如果是服務(wù)器集群,或者是跨域的服務(wù)導(dǎo)向結(jié)構(gòu),就要求session數(shù)據(jù)共享,每臺(tái)服務(wù)器都能夠讀取session,針對(duì)此種問題有兩種方案:
- 一種是session數(shù)據(jù)持久化,寫入數(shù)據(jù)庫或者別的持久層。各種服務(wù)收到請(qǐng)求后,都向持久層請(qǐng)求數(shù)據(jù)。這種方案的優(yōu)點(diǎn)是架構(gòu)清晰,缺點(diǎn)是工程量比較大。
- 另一種是服務(wù)器不再保存session數(shù)據(jù),所有數(shù)據(jù)都保存在客戶端,每次請(qǐng)求都發(fā)回服務(wù)器。Token認(rèn)證就是這種方案的一個(gè)代表。
2、Token認(rèn)證
Token是在服務(wù)端產(chǎn)生的一串字符串,是客戶端訪問資源接口(API)時(shí)所需要的資源憑證,流程如下:
- 客戶端使用用戶名跟密碼請(qǐng)求登錄,服務(wù)端收到請(qǐng)求,去驗(yàn)證用戶名與密碼
- 驗(yàn)證成功后,服務(wù)端會(huì)簽發(fā)一個(gè)token并把這個(gè)token發(fā)送給客戶端
- 客戶端收到token以后,會(huì)把它存儲(chǔ)起來,比如放在cookie里或者localStorage里
- 客戶端每次向服務(wù)端請(qǐng)求資源的時(shí)候需要帶著服務(wù)端簽發(fā)的token
- 服務(wù)端收到請(qǐng)求,然后去驗(yàn)證客戶端請(qǐng)求里面帶著的token,如果驗(yàn)證成功,就向客戶端返回請(qǐng)求的數(shù)據(jù)
- token認(rèn)證流程:
- Token認(rèn)證的特點(diǎn):
- 基于token的用戶認(rèn)證是一種服務(wù)端無狀態(tài)的認(rèn)證方式,服務(wù)端不用存放token數(shù)據(jù)
- 用解析token的計(jì)算時(shí)間換取session的存儲(chǔ)空間,從而減輕服務(wù)器的壓力,減少頻繁的查詢數(shù)據(jù)庫
- token完全由應(yīng)用管理,所以它可以避開同源策略CORS
3、JWT
- JSON Web Token(簡(jiǎn)稱JWT)是一個(gè)token的具體實(shí)現(xiàn)方式,是目前最流行的跨域認(rèn)證解決方案。
- JWT的原理是,服務(wù)器認(rèn)證以后,生成一個(gè)JSON對(duì)象,發(fā)回給用戶,具體如下:
- 用戶與服務(wù)端通信的時(shí)候,都要發(fā)回這個(gè)JSON對(duì)象。服務(wù)器完全只靠這個(gè)對(duì)象認(rèn)定用戶身份。
- 為了防止用戶篡改數(shù)據(jù),服務(wù)器在生成這個(gè)對(duì)象的時(shí)候,會(huì)加上簽名。
4、JWT組成
- JWT由三部分組成,依次如下:
- Header(頭部)
- Payload(負(fù)載)
- Signature(簽名)
- 三部分最終組合完成一個(gè)完整的字符串,中間用“.”分隔,如下:
- Header.Payload.Signature
-
Header
- Header部分是一個(gè)JSON對(duì)象,描述JWT的元數(shù)據(jù)
- alg屬性表示簽名的算法(algorithm),默認(rèn)是HMAC SHA256(寫成HS256)
- typ屬性表示這個(gè)令牌(token)的類型(type),JWT令牌統(tǒng)一寫為JWT
- 最后,將上面的JSON對(duì)象使用Base64URL算法轉(zhuǎn)成字符串
- Header部分是一個(gè)JSON對(duì)象,描述JWT的元數(shù)據(jù)
-
Payload
- Payload部分也是一個(gè)JSON對(duì)象,用來存放實(shí)際需要傳遞的數(shù)據(jù)。JWT規(guī)定了7個(gè)官方字段,供選用。
- iss(issuer):簽發(fā)人
- exp(expiration time):過期時(shí)間
- sub(subject):主題
- aud(audience):受眾
- nbf(Not Before):生效時(shí)間
- iat(Issued At):簽發(fā)時(shí)間
- jti(JWT ID):編號(hào)
- 注意,JWT默認(rèn)不加密的,任何人都可以讀到,所以不要把秘密信息放在這個(gè)部分。
- 這個(gè)JSON對(duì)象也要使用Base64URL算法轉(zhuǎn)成字符串。
- Payload部分也是一個(gè)JSON對(duì)象,用來存放實(shí)際需要傳遞的數(shù)據(jù)。JWT規(guī)定了7個(gè)官方字段,供選用。
-
Signature
- Signature部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。
- 首先,需要指定一個(gè)密鑰(secret)。這個(gè)密鑰只有服務(wù)器才知道,不能泄露給用戶。
- 然后,使用Header里面指定的簽名算法(默認(rèn)是HMAC SHA256),按照下面的公式產(chǎn)生簽名。
5、JWT的特點(diǎn)
- 客戶端收到服務(wù)器返回的JWT,可以儲(chǔ)存在Cookie里面,也可以儲(chǔ)存在localStorage。
- 客戶端每次與服務(wù)器通信,都要帶上這個(gè)JWT,可以把它放在Cookie里面自動(dòng)發(fā)送,但是這樣不能跨域。
- 更好的做法是放在HTTP請(qǐng)求的頭信息"Authorization"字段里面,單獨(dú)發(fā)送。
6、JWT的實(shí)現(xiàn)
- 加入依賴
- <!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
- 生成和解析token的工具類
- public class JwtUtil {// 7天過期private static long expire = 604800;// 32位秘鑰private static String secret = "abcdfghiabcdfghiabcdfghiabcdfghi";// 生成tokenpublic static String generateToken(String username){Date now = new Date();Date expiration = new Date(now.getTime() + 1000 * expire);return Jwts.builder().setHeaderParam("type","JWT") // 設(shè)置Header.setSubject(username) // 設(shè)置負(fù)載.setIssuedAt(now) // 設(shè)置生效時(shí)間.setExpiration(expiration) // 設(shè)置過期時(shí)間.signWith(SignatureAlgorithm.HS512,secret) // 指定簽名算法.compact();}// 解析tokenpublic static Claims getClaimsByToken(String token){return Jwts.parser().setSigningKey(secret) // 傳密鑰,查看是否有篡改.parseClaimsJws(token) // token是否正確.getBody();} }
- 生成token
- @PostMapping("/login")public String login(@RequestBody User user){ // 用@RequestBody接收,前臺(tái)就需要發(fā)送的是json格式String token = JwtUtil.generateToken(user.getUsername());return token;}
- 解析token
- @GetMapping("/info")public String info(String token){String username = JwtUtil.getClaimsByToken(token).getSubject(); // 解析token獲取用戶名return username;}
- 這樣就簡(jiǎn)單實(shí)現(xiàn)了生成token和解析token
十七、Springboot+Vue云端環(huán)境配置
- 以下部署基于Centos7 系統(tǒng)環(huán)境(使用XShell鏈接和Xftp進(jìn)行文件傳輸)
1、安裝MySQL
- 卸載Centos7自帶的mariadb
- # 查找 是否安裝了mariadb rpm -qa|grep mariadb # mariadb-libs-5.5.52-1.el7.x86_64 # 卸載(版本根據(jù)自己系統(tǒng)自帶的自行更改) rpm -e mariadb-libs-5.5.52-1.el7.x86_64 --nodeps
-
解壓MySQL
- # 創(chuàng)建mysql安裝包存放點(diǎn) mkdir /usr/server/mysql # 解壓 tar xvf mysql-5.7.34-1.el7.x86_64.rpm-bundle.tar
-
執(zhí)行安裝
- # 切換到安裝目錄 cd /usr/server/mysql/ yum -y install libaio yum -y install libncurses* yum -y install perl perl-devel # 安裝 rpm -ivh mysql-community-common-5.7.34-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-5.7.34-1.el7.x86_64.rpm rpm -ivh mysql-community-client-5.7.34-1.el7.x86_64.rpm rpm -ivh mysql-community-server-5.7.34-1.el7.x86_64.rpm
-
啟動(dòng)MySQL
- #啟動(dòng)mysql systemctl start mysqld.service #查看生成的臨時(shí)root密碼 cat /var/log/mysqld.log | grep password
-
修改初始的隨機(jī)密碼
- # 登錄mysql mysql -u root -p Enter password: #輸入在日志中生成的臨時(shí)密碼 # 更新root密碼 設(shè)置為root(密碼自行定義,后面遠(yuǎn)程連接需要用到) set global validate_password_policy=0; set global validate_password_length=1; set password=password('root');
-
授予遠(yuǎn)程連接權(quán)限
- # 讓數(shù)據(jù)庫支持遠(yuǎn)程連接 grant all privileges on *.* to 'root' @'%' identified by 'root'; # 刷新 flush privileges;
-
控制命令
- #mysql的啟動(dòng)和關(guān)閉 狀態(tài)查看 systemctl stop mysqld systemctl status mysqld systemctl start mysqld #建議設(shè)置為開機(jī)自啟動(dòng)服務(wù) systemctl enable mysqld #查看是否已經(jīng)設(shè)置自啟動(dòng)成功 systemctl list-unit-files | grep mysqld
-
關(guān)閉防火墻
- firewall-cmd --state #查看防火墻狀態(tài) systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall開機(jī)啟動(dòng)
2、安裝Nginx
- 安裝Nginx
- yum install epel-release yum update yum -y install nginx
- nginx命令
- systemctl start nginx #開啟nginx服務(wù) systemctl stop nginx #停止nginx服務(wù) systemctl restart nginx #重啟nginx服務(wù)
3、配置JDK
- 到官網(wǎng)https://www.oracle.com/java/technologies/downloads/#java8下載jdk版本
- 解壓
- tar -zvxf jdk-8u131-linux-x64.tar.gz
- 編輯 /etc/profile 文件
- vi /etc/profile # 文件末尾增加 export JAVA_HOME=/usr/server/jdk1.8.0_351 export PATH=${JAVA_HOME}/bin:$PATH
- 執(zhí)行source命令,使配置立即生效
- source /etc/profile
- 檢查是否安裝成功
- java -version
?
十八、Springboot+Vue項(xiàng)目部署
1、部署Vue項(xiàng)目
- 打包Vue項(xiàng)目
- 在vue項(xiàng)目的目錄,執(zhí)行以下代碼
- npm run build
- 將生成的dist目錄上傳至服務(wù)器 /usr/vue/dist(路徑自定義)
- 配置Nginx
- 進(jìn)入到/etc/nginx/conf.d目錄,創(chuàng)建vue.conf文件,內(nèi)容如下
- server {listen 80;server_name locahost;location / {root /usr/app/dist;index index.html;} }
- 使配置生效
- nginx -s reload
2、打包運(yùn)行Java程序
- 在右邊的maven中雙擊package,會(huì)自動(dòng)打包在項(xiàng)目路徑文件夾的/target文件夾下
- 因?yàn)閟pringboot有內(nèi)置tomcat容器,這點(diǎn)比較方便,省去了tomcat的部署。我們到時(shí)候直接可以直接
把jar包扔到linux上 - # 表示讓java程序在后臺(tái)運(yùn)行,然后生成運(yùn)行日志,方便查看項(xiàng)目是否報(bào)錯(cuò)。 nohup java -jar shop-0.0.1-SNAPSHOT.jar > logName.log 2>&1 &
項(xiàng)目正常運(yùn)行了,說明部署成功了,這樣項(xiàng)目所有人就可以訪問了。
?
總結(jié)
以上是生活随笔為你收集整理的SpringBoot+Vue项目实例开发及部署的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SICP读书笔记 2.5
- 下一篇: ktv点歌系统 Vue +Express