由于前后端分离近几年已成为主流,故尝试了下Vue+SpringBoot的前后端整合。
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>myvuetitle>
head>
<body>
<div id="app">
div>
body>
html>
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip=false
new Vue({
el:"#app",
router,
components:{ App },
template:' '
})
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import aaa from '@/components/aaa'
import loginUI from '@/components/loginUI'
import success from '@/components/success'
import axios from 'axios'
Vue.prototype.$http = axios
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/abc',
name: 'aaa',
component: aaa
},
{
path: '/loginUI',
name: 'loginUI',
component: loginUI
},
{
path: '/success',
name: 'success',
component: success
}
]
})
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<button @click="go">点我跳转</button>
<button @click="loginUI">点我登录</button>
</div>
</template>
<script>
export default {
// name: 'HelloWorld',
data () {
return {
msg: '哈哈'
}
},
methods:{
go(){
console.log(66)
this.$router.push({
path:'/abc'
})
},
loginUI(){
this.$router.push({
path:'/loginUI'
})
}
}
}
</script>
<style>
</style>
aaa.vue
<template>
<div>我是aaa
<button @click="back">点我返回</button>
</div>
</template>
<script>
export default {
methods:{
back(){
this.$router.push('/')
}
}
}
</script>
login.vue(登录页面,点击登录通过axios请求后台接口)
<template>
<table id="loginUI">
<tr>
<td>用户名</td>
<td><input type="text" v-model="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" v-model="password"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" @click="login" value="提交"></td>
</tr>
</table>
</template>
<script>
import qs from 'qs'
export default {
data(){
return {
username:"",
password:""
}
},
methods:{
login(){
var that=this;
console.log(that.username+":"+that.password)
var user={
username:that.username,
password:that.password
}
this.$http.post('http://localhost:8080/user/login',qs.stringify(user))
.then(function (params) {
console.log(params)
if(params.data.status===200){
that.$router.push({
path:'/success'
})
}
})
.catch(function (reason) {
console.log(reason)
})
}
}
}
</script>
<style>
#loginUI {
margin:0 auto;
}
</style>
success.vue,登录成功页面
<template>
<div>
成功!
<router-link to="/">返回</router-link>
</div>
</template>
后台用SpringBoot完成,
UserController
package com.hpsyche.springboot_to_vue.controller;
import com.hpsyche.springboot_to_vue.entity.User;
import com.hpsyche.springboot_to_vue.entity.vo.ReturnMsgVo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Hpsyche
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
@PostMapping("/login")
public ReturnMsgVo login(User user){
System.out.println(user);
return ReturnMsgVo.success(null);
}
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
其中User和ReturnMsgVo就是普通的实体类和返回信息实体,在这里不做赘述。
先启动后台(端口8080),再启动前端:npm run dev(其发现8080被占用后,自动启用8081端口)。
首页如下,点击登录
提交后报错403,
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 403
搜索了以下,从这篇博客找到答案https://blog.csdn.net/Brave_Coder/article/details/77103899#
常规的GET,POST,PUT,DELETE请求是简单请求(相对于OPTIONS请求),但是OPTIONS有点儿特别,它要先发送请求问问服务器,你要不要我请求呀,要我就要发送数据过来咯(这完全是根据自己的理解写的,如果有误,敬请谅解,请参考阮一峰大神原文。)
在Vue的项目里,Http服务采用Axios,而它正是采用OPTIONS请求。
如果仅仅在header里面加入: ‘Access-Control-Allow-Origin’:*,是并不能解决问题的,错误就是如文章开头所示。
就需要我们在后台对OPTIONS请求额外处理
故我添加了一个拦截器
package com.hpsyche.springboot_to_vue.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Hpsyche
*/
@Component
public class ProcessInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
httpServletResponse.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
httpServletResponse.setHeader("X-Powered-By","Jetty");
String method= httpServletRequest.getMethod();
if (method.equals("OPTIONS")){
httpServletResponse.setStatus(200);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
同时在Spring中声明
package com.hpsyche.springboot_to_vue.config;
import com.hpsyche.springboot_to_vue.interceptor.ProcessInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author Hpsyche
*/
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ProcessInterceptor()).addPathPatterns("/**");
}
}