仍是跨越,由于年少无知,文章中分享的方案并非最优解,存在不少局限的地方,所以误人子弟十分抱歉。对如今而言,我跨域的解决方案分两种。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实现动态权限控制,有空的时候会分享一下我的体会
之后可能完善,谢谢。