仍是跨越,由於年少無知,文章中分享的方案並非最優解,存在不少侷限的地方,所以誤人子弟十分抱歉。對如今而言,我跨域的解決方案分兩種。1、在開發過程當中,vue提供了優雅的解決方式,即經過自身的反向代理實現(實際上我也不太清楚是基於包依賴,仍是webpack或node實現),通常在配置文件配置,在你的項目中找到相似的地方
module.exports = { dev: { .... proxyTable: { // 配置反向代理 } .... } }
貼一下個人配置方式javascript
proxyTable: { '/api': { // 代理轉發的地址前綴以api開頭,/ 表明全部請求 target: 'http://localhost:8080', // 轉發到 changeOrigin: true, pathRewrite: { // url重寫 '^/api': '' // 將/api前綴去掉 } }, },
這種配置方式,後端不用作任何配置,即我後面介紹的CorsConfig是徹底不須要的,並且axios的baseurl也是不須要配置的~注意,這種配置只對開發環境即dev環境生效,當npm run build以後,部署的時候實際上並不會生效。 那麼在生產環境,1、若是像我後面介紹的將打包文件直接丟到springboot static下,那是不會產生跨域問題的,原本就是同源的。其次,若是單獨部署,那麼nginx等等都有反向代理功能,只能配置這些服務器的方向代理就ok了~html
關於跨域_:_在實際開發過程當中,發現跨域問題並非那麼好解決的 由於Springboot安全控制框架使用了Securtiy,它的身份認證基於 JSESSIONID 而axios框架默認是不發送cookie的,所以須要在axios配置中添加前端
axios.defaults.withCredentials = true
@Configuration public class CorsConfig { /** 容許任何域名使用 容許任何頭 容許任何方法(post、get等) */ private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); // addAllowedOrigin 不能設置爲* 由於與 allowCredential 衝突 corsConfiguration.addAllowedOrigin("http://localhost:9528"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); // allowCredential 需設置爲true corsConfiguration.setAllowCredentials(true); return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } }
_ 需求:_ 最近本人在學習SpringBoot,但願本身能搭一個簡單的Demo應用出來,可是搭到前端的時候遇到了困惑,由於網絡上大部分教程前端都是應用模板引擎thymeleaf生成的,它給個人感受就是一個進化版的JSP,可是很明顯這種開發方式已經有些落後了。如今前端愈來愈工程化,Angular/Vue/React等框架很是流行,因此我但願搭建一個更符合技術進步方向的前端應用(我選擇了相對容易入門的Vue)。vue
_ 問題:_ 在查閱資料過程,我發現SpringBoot和Vue相關的入門材料很是的多,可是關於二者結合的相對較少,致使踩了很多坑。在不斷得試錯之下,終於成功搭建了一個Demo應用,並實現一個登錄實例,所以在此總結鞏固。java
_ 項目架構_ 服務端以SpringBoot框架爲核心,除提供轉發到首頁外,只提供RESTful接口,經過Json格式消息進行交互;前端以Vue全家桶爲核心,實現SPA單頁面應用,以ajax方式與服務端進行通訊;先後端分離開發,所以會建兩個項目,經過npm run build 打包項目(複製進)項目進行整合。node
** 閱讀者有必定的Java基礎,SpringBoot基礎,同時有必定的前端基礎,Vue基礎。**mysql
好吧,這篇博客其實主要是寫給我本身的webpack
都是一些基礎的開發環境,具體搭建過程略。ios
利用Spring Initializr 建立一個SpinrgBoot模板
組名及項目名隨意,添加依賴的話視需求而定,這裏就添加了Web的核心依賴和一些數據庫的依賴
pom.xml 文件 核心依賴nginx
<dependencies> <!-- JPA 默認實現爲Hibernate --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 核心依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 能夠實現熱部署,在IDEA上實現熱部署還需一些額外的配置,請查閱資料 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <!-- JDBC for mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- 測試框架 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
而後,添加配置文件,在這裏我用yml進行配置,感受比較優雅
application.xml 放置在resources根目錄下 記得把數據庫username和password和url改成本身的
# set server port server: port: 8888 # 配置端口 context-path: / # 項目啓動地址爲 localhost:8888/ spring: datasource: # set database config url: jdbc:mysql://localhost:3306/***?useUnicode=true&characterEncoding=utf8&useSSL=false username: ***** password: ***** driver-class-name: com.mysql.jdbc.Driver jpa: # set jpa database: MYSQL # specify ths DBMS show-sql: true # show or not log for each sql query hibernate: ddl-auto: update # Hibernate ddl auto(create, create-drop, update) naming: # naming strategy strategy: org.hibernate.cfg.ImprovedNamingStrategy properties: hibernate: # stripped before adding them to entity manager dialect: org.hibernate.dialect.MySQL5Dialect aop: #設置aop,aop依賴添加後默認是啓用的 proxy-target-class: true
建立目錄僅結構,目錄結構參考了網絡上的案例和本身的習慣,供參考
Demo項目僅實現登錄實例,所以數據實體只須要一個User就好,User類上需加 @Entity 註解,表明這是實體類,交由Hibernate進行管理;同時,我使用了spring boot核心依賴之一的validation做爲參數驗證框架,驗證方法會在controller中實現;詳細代碼參閱 entity/SysUser 若是全貼代碼的話,篇幅會很是的長,因此詳細代碼請到github上看源碼,都帶有詳細的註釋
順便把SysUser的Dao層接口實現
/** * 用戶Dao層 * 繼承JapRepository,能夠實現一些默認方法,如save/findAll/findOne/delete/count/exists 等 * Created by bekey on 2017/12/9. */ public interface SysUserRepository extends JpaRepository<SysUser,Integer> { //... }
咱們在SysUserRepository中只添加一個findFirstByNameAndPassword方法就夠了,詳細源碼參見 repository/SysUserRepository
接着,搭建服務層,服務層遵循服務接口 + 實現 的模式,咱們如今尚未建立用戶,那麼就提供 saveUser 和 checkLogin 兩個服務好啦,詳細代碼參閱 service/SysUserService 和 service/SysUserServiceImpl
服務層實現方式都比較簡單粗暴,經過修改實現類能夠增長密碼加密等更多功能
而後,該搭建控制層了,爲控制類添加 @RestController 就能夠實現該類下全部方法都會自動以Json格式返回數據啦!
/** * 用戶控制層 * . @RestController 該類下全部返回值默認以json格式進行返回 * . @RequestMapping 匹配url地址 /user * . @Validated 表明該類啓用參數驗證,經過添加註解能夠驗證參數 * Created by bekey on 2017/12/20. */ @RestController @RequestMapping("/user") @Validated public class SysUserController { //... }
如今還不急着實現控制層,由於咱們先要約定先後端交互的格式,下面是一個簡易的格式 ,code是狀態碼200表明正常,message是消息一般應該是簡單的一句話,data是額外的內容
消息格式及生成大量參考了 github傳送門 的代碼,在此表示感謝
{ "code":200, "message":"附帶的消息", "data":{} }
爲此,在entity下建立class RestResult 和 enum ResultCode 約定消息格式及狀態碼,由於RestResult十分經常使用,設置卻比較麻煩,爲防止錯誤返回,建議採用工廠模式生成,因此要在utils下添加一個生成類ResultGenerator 相關代碼參閱 entity/RestResult entity/ResultCode utils/ResultGenerator
好啦,這些搭完終於能夠寫controller了 /(ㄒoㄒ)/~~ java囉嗦果真名不虛傳
如今咱們只提供兩個接口 分別是 register/login ,可是要添加參數驗證
/** * 匹配 /user/register 地址 * .在實體前添加 @Valid 註解表明要對這個實體進行驗證,若是驗證不經過就會報異常 * bindingResult是對異常信息的包裝,不過這裏咱們不用,而是交由異常處理器進行處理 * @return 註冊成功會將註冊信息返回(!由於是demo因此沒有考慮安全性) */ @RequestMapping("/register") public RestResult register(@Valid SysUser user, BindingResult bindingResult) { return generator.getSuccessResult("用戶註冊成功",userService.saveUser(user)); } /** * 匹配 /user/login 地址 ,限定POST方法 * 。@NotNull 在字段前添加註解表明驗證該字段,若是爲空則報異常 * @return 登錄成功則返回相關信息,不然返回錯誤提示 */ @RequestMapping(value = "/login",method = RequestMethod.POST) public RestResult login(@NotNull(message = "用戶名不能爲空") String name,@NotNull(message = "密碼不能爲空") String password, HttpSession session) { SysUser user = userService.checkLogin(name, password); if(user != null) { //儲存到session中 session.setAttribute("user",user); return generator.getSuccessResult("登錄成功",user); } return generator.getFailResult("用戶名/密碼錯誤"); }
這樣咱們的接口就寫好了,可是若是參數沒經過驗證怎麼辦呢?程序報異常可是用戶卻得不到反饋是明顯不能夠的,因此咱們添加一個exceptionHandler
/** * 爲參數驗證添加異常處理器 */ @ExceptionHandler(ConstraintViolationException.class) public RestResult handleConstraintViolationException(ConstraintViolationException cve) { //這裏簡化處理了,cve.getConstraintViolations 會獲得全部錯誤信息的迭代,能夠酌情處理 String errorMessage = cve.getConstraintViolations().iterator().next().getMessage(); return generator.getFailResult(errorMessage); }
完整版代碼請參閱 controller/SysUserController
項目跑一下,訪問localhost:8888 ... 嗯 404 咱們沒有主頁,那在resources/static 下建立一個index.html,將就一下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>這是主頁</title> </head> <body> <h1>這是主頁</h1> </body> </html>
ok 在缺省配置下,框架會自動找到static下index.html 做爲主頁的 訪問
http://localhost:8888/user/register?name=myadmin&password=123456
看是否是返回一個json,告訴你註冊成功了呢?
{"code":200,"message":"用戶註冊成功","data":{"id":1,"name":"myadmin","password":"123456"}}
好,那再訪問一次
http://localhost:8888/user/register?name=myadmin&password=1234
看是否是返回一個json,告訴你密碼應設爲6至18位了呢?
{"code":400,"message":"密碼應設爲6至18位","data":null}
再來一次
http://localhost:8888/user/register?name=myadmin&password=456789
看是否是返回一個json,告訴你違反主鍵/惟一約束條件了呢?
試着登錄一下
http://localhost:8888/user/login?name=myadmin&password=123456
應該是一個404,由於只接受post請求,若是要驗證能夠經過其它方法
配置尚未結束 由於先後端分離,爲了開發的方便,咱們須要配置一下跨域,關於跨域問題,不理解的話能夠去查閱一下資料 在config下新建一個CorsConfig
/** * 設置容許跨域 */ @Configuration public class CorsConfig { /** 容許任何域名使用 容許任何頭 容許任何方法(post、get等) */ private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 corsConfiguration.addAllowedHeader("*"); // 2 corsConfiguration.addAllowedMethod("*"); // 3 return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } }
服務端的工做基本就完成大部分了,目前咱們僅建立了兩個接口,和一個臨時主頁,稍後完成前端項目以後才能繼續。
完總體源碼 -> github_spring-vue-demo
後續內容 先後端分離 Spring Boot + Vue 開發單頁面應用 我的總結(二)
服務端代碼Github上建立了新的分支dev,整合了認證框架Security,並自定義Filter實現動態權限控制,有空的時候會分享一下我的體會
之後可能完善,謝謝。