什么是前后端分离?
将一个应用的前后端代码分开写
为什么要前后端分离?
在传统的Javaweb开发中,往往是前端人员写好html后,再由后端人员将java整合其中,变成JSP。 如此一来就造成了沟通不便、降低效率、前后端耦合度高等问题。
前后端分离是如何解决此问题的呢?
前端写客户端代码,后端写服务端代码并提供接口
前端通过ajax请求访问接口,将model展示到view中
如此前后端只需要约定接口文档(URL、参数、数据类型。注意:前后端是通过API进行交互的),之后便分别独立开发。前端可以通过json造假数据进行测试,后端用postman进行测试。如此,前后端开发过程中互不依赖,只需最后前后端集成即可,这真正实现了前后端的解耦合。
前端HTML→ajax→Restfull后端接口数据
图解分析前后端分离
传统开发:
前后端分离开发:
前后端分离就是将一个单体应用拆分为两个独立应用,前后端应用以json格式进行数据交互
前后端分离具体实现
SpringBoot + Vue
前端开发
前端项目搭建
Vue3及以上版本支持图形界面创建Vue项目(前提是先装好Vue环境)。在黑窗口中执行vue ui即可打开图形界面。
在左上角打开项目管理器
然后创建项目(创建项目时自行选择目录)
在创建过程中可以把Git先勾掉
在下一步中选择手动预设
再然后,选择打开Router、VueX功能,将Linter和Formatter功能关闭
然后下一步选择打开历史记录(Use history mode for router)
最后,创建项目,选择创建项目,不保存预设
创建成功后,点击页面左上角任务,选中点击server,运行,成功后就可以输出(两个访问地址:localhost和Network均可访问,且均为本地访问)。最后,在黑窗口中Ctrl+C关闭窗口。此时便可以在idea中打开项目(注意要在idea中安装插件:Vue.js)。idea代开项目后,左下角Terminal(这是一个内嵌服务器),可以执行vue指令进行调试。
Vue是单页面(App.vue)应用,页面的跳转都是通过路由跳转组件来更新的
什么是路由?
<router-link to="/student">Student</router-link>
/*
有点html里面的锚链接的感觉
Student 表示路由的名字
/student 表示要跳转到的相应组件
路由跳转的实现前提是先要在router(路由)包下的index.js文件中进行引入
引入方式一:
引入格式:
import Student from '../views/Student.vue'
再在index.js文件的routers数组中添加对象。如:
{
path: '/student',
name: 'Student', //可忽略
component: Home //与引入组件时import后面修饰的名字一致
}
引入方式二:
不需要在index.js开头引入
直接在routers数组中添加对象,如:
{
path: '/student',
name: 'Student',
component: () => import('../views/Student.vue')
}
前端项目测试
Vue测试假数据:
在目标页面组件的vue文件中script部分,找到export default {}入口。
写入数据,如:
data(){
return{
msg:'Hello Vue',
students:[
{
id:1,
name:'团子',
age:15
},
{
id:2,
name:'熊二',
age:16
},
{
id:3,
name:'小熊',
age:15
}
]
}
}
在表格中访问数据
<table>
<tr>
<td>id</td>
<td>姓名</td>
<td>年龄</td>
</tr>
<tr v-for="item in students">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
</tr>
</table>
后端开发
后端项目搭建
建立springboot项目,勾选依赖如下:
Developer Tools中的lombok
Web中的spring web
SQL中的Spring Data JPA和MySQL Driver
最后,建好项目后删掉resources文件夹中的application.properties文件,因为此处用yml配置(在此文件夹下新建application.yml)
yml配置文件如下:
spring:
datasource:
url: jdbc:mysql://localhost:3306/school?zhuguangliangDJB
username: root
password: 580231
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
server:
port: 8181
基本的后端项目建好后:
- 新建entity包,在该包下建立实体类(对应数据库中的表)
- 为实体类加==@Entity注解(通过映射关系把类名与表名绑定,注意类名首字母小写后与表明相同)和@Data==注解(自动引入get()、set()等方法)
- 为实体类中的主键元素加@Id注解,如:
@Id private Integer id;
- 创建repository包,在该包下创建实体类接口
- 在该接口后继承JpaRepository接口,泛型中传入一个实体类型,一个主键类型。如:
public interface StudentRepository extends JpaRepository<Student,Integer> { }
- 点击接口名右键选中“Go To”,然后点击“Great new Test”,直接默认选择Junity5测试,OK完成,建立新的测试类(个人觉得这样看起来比较规范化)
- 在test包下找到自动生成的该测试类,为该类加注解:@SpringBootTest
- 以将要测试的接口为引用,在此测试类中声明一个变量,并加注解:@Autowired。如:
@Autowired private StudentRepository studentRepository;
- 再在该类中写一个测试方法,并为该方法添加一个注解:@Test。然后在该方法中通过接口变量访问实体类中的元素及方法进行测试。如:
@Test void findAll(){ System.out.println(studentRepository.findAll()); }
外部调用数据
新建一个controller包,在该包下建一个StudentHandler类
为该类加注解:@RestController和 @RequestMapping(“/student”),其中/student表示的是访问路径,一般用实体类名小写表示。——访问该类
同样的再在该类中通过@Autowired进行注入。如:
@Autowired
private StudentRepository studentRepository;
//private 接口名 接口对象;
再通过@GetMapping("/findAll")返回数据,进行一个访问结果的回馈。其中/findAll同样为访问的路径。如:
@GetMapping("/findAll")
public List<Student> findAll(){
return studentRepository.findAll();
}
——通过类方法返回具体数据
前后端集成
只需要让前端想办法用Ajax访问对应的后端地址(如:localhost:8181/student/findAll)获取数据即可。
- 现在Vue控制台通过Vue add axios安装axios.js,安装成功后src目录下会多出一个plugins文件夹,里面会有一个axios.js文件
- 在目标获取数据的组件(Student.vue)的script中下写一个created()函数,如:
<script> export default { name: "Student", data(){ return{ students:[ { id:0, name:"", age:0 } ] } }, created() { const _this = this axios.get('http://localhost:8181/student/findAll').then(function (resp) { //在此不能直接用 this.students = resp.data,因为此处的this指的不是vue对象,而是回调 _this.students = resp.data }) } } </script>
注意:
从前端端口发送请求访问后端端口,端口名不同会出现跨域问题,通过前后端都可以解决此问题
后端解决方案:
1. 在后端项目中新建config包,在包下创建CrosConfig类,并添加注解:@Configuration。
2. 在该类后继承WebMvcConfigurer类,并重写addCorsMappings方法,此方法重写格式固定:
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.maxAge(3600)
.allowedHeaders("*")
.allowCredentials(true); //是否有请求头
}
```