曾几什么时候,JSP和Servlet为Java带来了无限风光,一时间大红大紫,但随着互联网的不断发展,这样的开发方式逐渐显露其弊端,在移动互联网煊赫一时的今天,应用程序对于后台服务的要求发生了巨大的变化;html
在传统的web开发中,页面展现的内容以及页面之间的跳转逻辑,全都由后台来控制,这致使了先后端耦合度很是高,耦合度高则意味着,扩展性差,维护性差,等等问题前端
传统开发的问题以下:java
调试麻烦,出现问题时每每须要先后台一块儿检查node
交互逻辑混乱(还记得分页显示吗),最终形成代码腐烂jquery
为了适应快速发展的移动互联网,加快开发速度,就必须找到一种新的项目开发方式,来解决以上问题;web
上述问题产生的根本缘由在于先后端没有明显的分界,严重耦合在一块儿,想要解决这些问题的核心也就是将先后端代码彻底分开ajax
对比咱们以前编写的整个项目结构和部署环境而言,有如下区别数据库
特性/方式 | 传统 | 先后端分离 |
---|---|---|
服务器环境 | 所有部署到tomca便可 | 增长一个静态资源服务器 |
MVC职责 | 后台负责MVC所有 | 前台负责VC,后台负责M |
简单的说:json
先后端分离在传统开发上增长了一个服务器处理静态资源,将View层和Controller层放到了前端,后台仅需处理数据存取相关以及业务逻辑相关后端
前端:负责View和Controller层。
后端:只负责Model层,业务处理/数据等。
优势:
关注点分离,视图层和控制层逻辑移到了前端,后端更注重业务逻辑和系统构架
耦合大大下降,开发效率和维护效率都获得提升
错误友好,后台错误不影响前台界面展现
对于开发者,先后端再也不须要过多的涉及彼此的开发语言
缺点:
在此以前区分先后端是根据硬件环境
分离后根据职责划分:如图
Controller层中会使用流程控制来完成数据校验,数据解析,页面的跳转等动做,那么如何完成呢,这就须要使用到JavaScript了
那么一个先后端分离的项目,前端是如何完成最终的数据展现呢?
若是前端是其余的例如iOS,安卓,则无需请求静态页面,页面的绘制是由系统原始语言实现的,只须要向后台请求json数据便可
JSON全称(JavaScript Object Notation),js对象表示法,是一种轻量级数据交换格式
特色:
最初产生于web项目中,后来由于太优秀,被各类CS结构项目使用
案例:
{ "uniquekey":"a56e67162bd84ee9c480e22a1170c14b", "title":"人均负债17万从“全民储蓄”到“全民负债” 中国人的钱去哪儿了?", "date":"2019-12-22 13:43", "category":"头条", "author_name":"鹤川倾海", "url":"http://mini.eastday.com/mobile/191222134359221.html", "thumbnail_pic_s":"http://05imgmini.eastday.com/mobile/20191222/20191222134359_b6ded6df388f5c6747e67bacfc32d125_4_mwpm_03200403.jpg" }
你能够将其看作Map数据结构,以键值对形式存储,可是一些java中的数据结构json中是没有的例如,集合
如今你已经知道了先后端分离的概念以及运行流程,做为后端开发的你不由暗自窃喜,好了之后Controller不归我管了,你正要开始葛优躺时前端小伙伴炸锅了:
尼玛,各类页面跳转逻辑,用户验证逻辑,前端的表单验证………..,难道要在学学java?习惯了js的他们,确定不肯意
问题就是动力,国外的Ryan Dahl这为兄台,决定改变这个现状,因而开发了使用JS做为开发语言的Node.js(2009/5),提供了异步IO,数据库支持,网络支持,等等,广大前端开发者激动落泪,之后别整什么java了,先后台一套JS全搞定,梦想是美好的,java(1996)是强大的,经历了二十几年的努力java已是如此强大,稳定,node.js做为晚了13年的后期之秀还有很长的路要走;
相信使用一门语言编写全部程序的一天总会到来,也有不少人在努力实现这个梦想,例如RectNative;
你们都知道淘宝网站作得很大面对成百上千的前台页面,想要提升总体开发效率,以及项目扩展性等,必然要采用先后端分离,大量的Controller层逻辑,以及数据校验逻辑,致使前端开发亚历山大,而且没有相对固定的开发模型,很是容易出问题
淘宝目前使用了一种叫作中途岛的构架,利用Node.js来完成了Controller层,并提供了一些其余良好的特性
构架:
职责:
优势:
若是将其做为一个前端框架,Node.js对比Vue.js等无疑是重量级的
先后端分离并非必定要加入node.js,先后端分离是责任划分问题,与使用什么服务器没有关系;
在页面中使用Ajax来请求数据,服务器返回json数据,前端使用js完成页面渲染
Ajax是客户端的一种请求方式,全称(Asynchronous Javascript And XML)
用于异步的向服务器发送HTTP请求并获取响应数据,异步的好处在于,请求期间浏览器不会卡死,能够正常响应用户操做;而常见的表单提交,和直接打开指定地址,都是同步的;
json数据的基本形式是键值对,对应着对象中的属性,是有规律的,那就可使用代码来完成这一转换过程,下面列出了一些常见的json开源工具
性能对比请看这里对比
这里选择fastjson
http://repo1.maven.org/maven2/com/alibaba/fastjson/
import com.alibaba.fastjson.JSON; import java.util.ArrayList; public class Demo { public static void main(String[] args) { //Bean熟悉 ArrayList<String> hobby = new ArrayList<>(); hobby.add("girl"); hobby.add("music"); hobby.add("coding"); //JavaBean Person p = new Person("jerry",18,true,hobby); p.setDog(new Dog("小花花")); //Bean转json字符串 String s = JSON.toJSONString(p); System.out.println(s); //json字符转Bean Person person = JSON.parseObject(s,Person.class); System.out.println(person); //ArrAyList转json字符串 System.out.println(JSON.toJSONString(hobby)); } }
如今把本身当成是前端,要开发一个先后分离的简单页面,用于展现学生信息列表
第一步
编写一个用于展现表格的静态页面
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <table id="tab" border="1"> <tr> <th>编号</th> <th>名字</th> <th>年龄</th> <th>性别</th> </tr> </table> <button onclick="req()">请求数据</button> <img id="img" /> </body> </html>
不启动tomcat直接在编辑器中打开便可访问,测试他就是一个静态网页,而咱们的编辑器就是一个HTTP服务器,能够响应静态网页
第二步
引入jquery使得ajax编写更方便
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
第三步
编写ajax,向服务器发送请求
第四步
将数据展现到页面上
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> </head> <body> <table id="tab" border="1"> <tr> <th>编号</th> <th>名字</th> <th>年龄</th> <th>性别</th> </tr> </table> <button onclick="req()">请求数据</button> <img id="img" /> </body> <script> function req(){ document.getElementById("img").src = "img/timg.gif"; $.ajax({ url:"http://localhost:8080/MyServer/getData", success:function(data){ console.log(data); document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data)); document.getElementById("img").src = ""; }, error:function(err){ console.log(err); document.getElementById("img").src = ""; } }); } </script> </html>
如今身份切换回后端开发用于获取表格数据的接口
Servlet代码
package com.kkb; import java.io.IOException; public class AServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { String s = "{\"name\":\"jack\"}"; response.getWriter().println(s); } }
启动服务,测试访问,会发现页面上没有显示服务器返回的结果….
打开浏览器检查页面会发现没有输出服务器返回的消息而是,出现了一个错误信息,这就是先后端分离最多见的跨越问题
跨越为题之因此产生是由于浏览器都遵循了同源策略
同源策略(Same origin policy)是一种约定,它是[浏览器]最核心也最基本的安全功能,若是缺乏了同源策略,则浏览器的正常功能可能都会受到影响。能够说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,浏览器会先发送OPTION请求进行预检查,判断服务器是否容许跨域,若是容许才发送真正的请求,不然抛出异常。
同源策略浏览器的核心安全机制,其不容许在页面中解析执行来自其余服务器数据
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不一样即为跨域
没法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
没法向非同源地址发送 AJAX 请求
浏览器在解析执行一个网页时,若是页面中的js代码请求了另外一个非同源的资源,则会产生跨越问题
而浏览器直接跳转另外一个非同源的地址时不会有跨域问题
既然禁止跨域问题时浏览器的行为,那么只须要设置浏览器运行解析跨域请求的数据便可,可是这个设置必须放在服务器端,由服务器端来判断对方是否可信任
在响应头中添加一个字段,告诉浏览器,某个服务器是可信的
package com.kkb; import java.io.IOException; public class AServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { response.setHeader("Access-Control-Allow-Origin","*"); String s = "{\"name\":\"jack\"}"; response.getWriter().println(s); } }
其值跨越式某个指定的域名,也能够是*表示信任全部地址
其余相关设置
//指定容许其余域名访问 'Access-Control-Allow-Origin:http://XXX.XXX.XXX'//通常用法(*,指定域,动态设置),注意*不容许携带认证头和cookies //是否容许后续请求携带认证信息(cookies),该值只能是true,默认为false //且须要前端配合进行相应设置才能让cookie跨越 'Access-Control-Allow-Credentials:true' //预检查间隔时间 'Access-Control-Max-Age: 1800' //容许的请求类型 'Access-Control-Allow-Methods:GET,POST,PUT,POST' //列出必须携带的字段 'Access-Control-Allow-Headers:x-requested-with,content-type'
解决了跨越问题后再来完善上面的案例
package com.kkb; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import java.io.IOException; import java.util.ArrayList; public class AServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //容许来自任何主机的跨越访问 response.setHeader("Access-Control-Allow-Origin","*"); //设置响应类型为json数据 response.setContentType("application/json;charset=utf-8"); //学生信息 ArrayList<Student> students = new ArrayList<>(); Student stu1 = new Student("s1","jack",20,"man"); Student stu2 = new Student("s2","tom",22,"girl"); Student stu3 = new Student("s3","jerry",10,"woman"); Student stu4 = new Student("s4","scot",24,"boy"); students.add(stu1); students.add(stu2); students.add(stu3); students.add(stu4); response.getWriter().println(JSON.toJSONString(JSON.toJSONString(students))); } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> </head> <body> <table id="tab" border="1"> <tr> <th>编号</th> <th>名字</th> <th>年龄</th> <th>性别</th> </tr> </table> <button onclick="req()">请求数据</button> <img id="img" /> </body> <script> function req(){ document.getElementById("img").src = "img/timg.gif"; $.ajax({ url:"http://localhost:8080/MyServer/getData", success:function(data){ data = JSON.parse(data) console.log(data) for (var i = 0; i < data.length; i++) { a = data[i]; var row = "<tr><td>id</td><td>name</td><td>age</td><td>gender</td></tr>" row = row.replace("id",a.id); row = row.replace("name",a.name); row = row.replace("age",a.age); row = row.replace("gender",a.gender); document.getElementById("tab").insertAdjacentHTML("beforeend",row); } document.getElementById("img").src = ""; }, error:function(err){ console.log(err); document.getElementById("img").src = ""; } }); } </script> </html>
一个简单的先后端分离的案例就搞定了