A. Controller接收前端参数的几种方式总结
http://127.0.0.1:8080/param/add?lastName=旺旺&[email protected]
http://127.0.0.1:8080/test/employee?lastName=战三&[email protected]
注意可以在参数中增加丛伏碧@RequestParam注解。如果在方法中的参数增加了该注解,说明请求的url必须带该带有该参厅首数,否则不能执行该方法。如果在方法中的参数没有增加该注解,说明请求的url无需带有该参数,也能继续执行该方法。
http://127.0.0.1:8080/office/deport?name=张三&[email protected]
http://127.0.0.1:8080/office/deport?lastName=张三&渗举[email protected]
报错:
http://127.0.0.1:8080/office/deport?name=张三
报错:
http://127.0.0.1:8080/emp/1
1、JSON格式接收普通对象
http://127.0.0.1:8080/resp/test
2、JSON格式接收List对象
http://127.0.0.1:8080/resplist/testlist
3、JSON格式接收Map对象
http://127.0.0.1:8080/respmap/testmap
B. 前端vue如何在vuehttp地址栏上添加参数
1、使用
2、通过query属性添加了一个名为拍中name的参数,值为John。
3、这将在地址栏袭茄山上显纳巧示为/usersname=John。
C. 前端get请求url拼接多项参数方法
var toString = "";
for (var key in data) {
if(!data[key]){
delete data.key
}else{
var obj = data[key];
if (Array.isArray(obj)) {
var arrayString = obj.join(",");
toString += key + "=" + arrayString + "&";
} else {
厅禅燃 扮虚 toString += key + "=" + data[key] + "&";
}
袭碰 }
}
toString.substring(0, toString.length - 1).replace(/$/, "");
D. SpringMVC前后端分离交互传参详细教程-
温故而知新,本文为一时兴起写出,如有错误还请指正
本文后台基于SpringBoot2.5.6编写,前端基于Vue2 + axios和微信小程序JS版分别编写进行联调测试,用于理解前后端分离式开发的交互流程,如果没用过axios可以点我看之前的帖子
如果你没有学过SpringBoot也不要紧,把他看做成SpringMVC即可,写法完全一致(其实我不说你也发现不了)
本文主要讲前后端交互流程,力求帮助新人快速入门前后端分离式开发,不会讲关于数胡环境搭建部分的内容
在文章开头快速的过一遍SpringMVC接收参数的几种方式,一定要记住这几种方式,看不懂或不理解都没关系,后续会结合前端代码过一遍,这里就不过多解释了,直接上代码
细心的人应该留意到了,最后使用变量接收参数的时候只接收了 username 这一个值,并没有接收 password ,作为扩展在这里解释一下, 不看也可以,看了不理解也没关系,知道这个事儿就够了,以后接触多了就理解了
如果请求参数放在了请求体中,只有参数列表第一个变量能接收到值,这里需要站在Servlet的角度来看:
可以看到请求体内容是存到了 InputStream 输入流对象中,想要知道请求体中的内容是什么必须读流中的数据,读取到数据后会将值给第一个变量,而流中的数据读取一次之后就没了,当第二个变量读流时发现流已经被关闭了,自然就接收不到
SpringMVC回顾到此为止,只需要记住那三种方式即可,在前后端交互之前先在Controller中写个测试接口
这个接口对应的是GET类型的请求,这里直接在浏览器地址栏访问测试一下:
这里推荐一个Chrome浏览器的插件 JSONView ,它可以对浏览器显示的JSON数据进行格式化显示,推荐的同时也提个醒,安装需谨慎,如果JSON数据量太大的话页面会很卡
之前已经写好一个GET请求的测试接口了,这里就在前端写代码访问一下试试看
代码已经写完了,接下来打开页面试一下能不能调通:州凳
可以看到请求代码报错了,查看报错信息找到重点关键词 CORS ,表示该请求属于 跨域请求
什么是跨域请求?跨域请求主要体现在跨域两个字上,当发起请求的客户端和接收请求的服务端他们的【协议、域名、端口号】有任意一项不一致的情况都属于跨域请求,拿刚刚访问的地址举例,VUE页面运行在9000端口上,后台接口运行在8080端口上,端口号没有对上所以该请求为跨域请求
如果在调试的时候仔细一点就会发现,虽然前端提示请求报错了,但是后端还是接收到请求了,那为什么会报错呢?是因为后端返回数据后,浏览器接收到响应结果发现该请求跨域,然后给我们提示错误信息,也就是说问题在浏览器这里
怎样才能让浏览器允许该请求呢?我们需要在后端动点手脚,在返回结果的时候设置允许前端访问即可
首先配置一个过滤器,配置过滤器有很多种实现的方法,我这里是实现Filter接口
过滤器创建完成了,回来看前端提示的报错信息为 Access-Control-Allow-Origin ,意思是允许访问的地址中并不包含当前VUE的地址,那么我们就在响应结果时将VUE的地址追加上
添加完成后重启项目后台就会发现请求已经成功并且拿到了返回值
再次册毕旅进行测试,将后台的GetMapping修改为PostMapping,修改前端请求代码后重新发起请求进行测试
可以看到POST请求还是提示跨域请求,对应的错误信息则是 Access-Control-Allow-Headers ,也就是说请求头中包含了不被允许的信息,这里图省事儿用 * 通配符把所有请求头都放行
这样处理之后,请求就可以正常访问啦
路径占位参数,就是将参数作为请求路径的一部分,例如你现在正在看的这篇博客使用的就是路径占位传参
这种传参方法很简单,就不细讲了,可以效仿他这种方法写个测试案例
这里需要注意区分【路径占位传参】和【路径传参】两个概念,不要记混
什么是路径传参?发起一个请求 http://localhost:8080/index?a=1&b=2 ,在路径 ? 后面的都属于路径传参,路径传参就是将参数以明文方式拼接在请求地址后面
路径传参使用【正常接收参数】中的实例代码即可接收到值
除了自己手动拼接请求参数之外,axios在config中提供了params属性,也可以实现该功能
表单类型参数,就是通过form表单提交的参数,通常用在例如HTML、JSP页面的form标签上,但如果是前后端分离的话就不能使用form表单提交了,这里可以手动创建表单对象进行传值
需要注意,GET请求一般只用于路径传参,其他类型传参需要使用POST或其他类型的请求
表单类型参数也是【正常接收参数】中的实例代码接收值
小程序删除了FormData对象,不能发起表单类型参数的请求,如果非要写的话可以试着使用 wx.uploadFile 实现,这里就不尝试了
请求体传参,是在发起请求时将参数放在请求体中
表单类型参数需要使用上面【请求体接收参数】中的实例代码接收值
axios如果发起的为POST类型请求,默认会将参数放在请求体中,这里直接写即可
小程序代码也是一样的,当发起的时POST类型的请求时,默认会把参数放在请求体中
在实际开发中大概率不用写前端代码,只负责编写后台接口,但怎样才能知道前端请求是什么类型参数?
关于这点可以通过浏览器开发者工具的【网络】面板可以看出来,网络面板打开时会录制网页发起的所有请求
路径占位传参就不解释了,没啥好说的,这里介绍一下路径传参、表单传参和请求体传参
编写好路径传参的请求代码后切换到网络面板,点击发起请求:
编写好请求体传参的请求代码后切换到网络面板,点击发起请求:
编写好表单类型传参的请求代码后切换到网络面板,点击发起请求:
掌握了前后端交互的流程就可以正常开发网站了,这里推荐后端返回一套规定好的模板数据,否则某些情况可能会比较难处理,例如这个查询用户列表的接口:
该接口乍一看没毛病,拿到用户列表数据后返回给前端用于渲染,合情合理,可是如果后端业务逻辑有BUG可能会导致前端接收到的结果为空,这种情况下前端就需要判断,如果接收到的值为空,就提示请求出错,问题貌似已经解决,但是如果表中本来就没有任何数据的话有应该怎么处理
上述的就是最常见的一种比较头疼的情况,所以针对这种情况最好指定一套标准的返回模板进行处理
根据刚刚的举例来看,返回结果中应该有一个标识来判断该请求是否执行成功,如果执行失败的话还应该返回失败原因,响应给前端的数据会被转换为JSON数据,使用Map集合来返回最合适不过了
在后台接口编写完成后,一般情况下我们都需要进行测试,GET请求还好,浏览器直接就访问呢了,如果是POST请求还要去写前端代码就很烦,这里介绍一款接口调试工具ApiPost
你可能没听过ApiPost,但是你大概率听说过Postman,他们的用法几乎一致,且ApiPost是国人开发的免费的接口调试工具,界面中文很友好
这里也可以看出来,form表单传参其实也算在了请求体里面,只不过使用的是 multipart/form-data 类型的参数而已,而之前提到的请求体传参对应的就是 application/json
E. 前端ajax异步传值以及后端接收参数的几种方式
前台往后台传值呢,有很多种方式,大家听我细野猜细道来。
第一种呢,也是最简单的一种,通过get提交方式,将参数在链接中以问颂袭型号的形式进行传递。
后台往前台传值就要简单一些,单个数据或者封装数据可以直接使用return返回json数据给前台,如果是多个数据,可以使用```
PrintWriter进行传值,具体操作如下
非异步方式传值
非异步方式前台传递参数
1.与异步方式类似,使用form直接提交或者在链接中拼接参数即可。
2.后台接受参数方式不变,与异步方式完全相同。禅野
非异步方式后台向前台传递数据
F. 前端路由(1):基础知识
URI: Uniform Resource Identifier 统一资源标识符; 由5部分组成:
URI = scheme:[//authority]path[?query][#fragment]
scheme: 协议 常见的有 http , https , file等
authority: 可以由三部分组成 [userinfo]host:[port]
其中userinfo指用户信息,可以通过authority中的userinfo进行的登录(当然现在前端应用并不会这么做)
host指的是主机地址,可以是ipv4或者是用方括号括起来的ipv6地址,或者是可以通过DNS解析成ip地址的域名,如www..com
port指端口号, 如果不指定则使用默认端口号,http默认端口号80, https默认端口号443
path: 指文件路径,指定服务器上文件路径以访问特定资源
query: 查询字符串 又称search值 get接口传参会通过此部分进行传输
fragment: 片段标识符 又称hash值, 通常用于标记已获取资源的子资源,不会被传递到服务器端
关于编码:
URI是用的是百分号编码,对于需要编码的字符,将其表示为2个十六进制的字符,然后在其前面加入转义字符%
两个编码api:
encodeURI 与 encodeURIComponent: encodeURI编码的范围比encodeURIComponent要小 ,其中encodeURI是w3c的标准。
window.history对象存在很多属性, 比较重点关注的有:
readonly length: number;
readonly state: any;
方法:
pushState(state: any, title: string, url?: string | null) : void;
replaceState(state: any, title: string, url?: string | null) : void;
go(delta: number): void 与 back():void; forward():void;
第一个参数需要是可被结构化复制的数据类型, (结构化复制: 可以处理循环引用的JSON),会持久化存储在浏览器内部,在每次页面生成的时候会被重新提取出来(属于浏览器实现的深拷贝)
第二个参数title传字符串,用于标记当前方法
第三个参数url,可以传简单字符串,也可以传url对象,需要注意的是因为此方法被同源策略所限制,url必须与当前href同源,否则会报错。此参数可以不传,不传的时候就是单纯的操作浏览器历史栈。
方法作用: 生成一个新的历史栈并将指针指向它,操作并不会刷新浏览器,也就是说此方法会改变浏览器的历史栈length,和state对象;
replaceState与pushState参数完全相同,使用方法类似,但其作用是替换当前历史栈,也就是说历史栈的指针与长度不会发生变化,其作用仅仅是替换当前的url与state。
pushState与replaceState方法其url传参方式多种多样,可以是绝对路径,也可以是相对路径,也可以传递查询字符串search值"?xxx"与片段标识符"#xxx",其最大特点是操作浏览器url,history对象的state与length属性,但不会触发浏览器跳转。
pushState与replaceState方法以相对路径方式进行操作url的时候,会受到当前html的<base>元素的href的影响,此时base元素的href会替换浏览器的url的href作为基准值进行相对路径跳转。
浏览器的跳转方法主要围绕window.location与window.history这两个对象进行。
1) window.history
window.history.go(delta: number): void;
移动浏览器历史栈指针并且刷新页面
window.history.back() === window.history.go(-1)
window.history.forward() === window.history.go(1)
2) window.location
window.location.href
get :() =>string;
set : (url: string) => void; // 触发浏览器跳转 并增加历史栈 不收同源策略限制
window.location.hash
get: () => string;
set: (hash: string) => void;
与href类似,其区别是用于修改浏览器导航栏url的hash值,会产生新的历史栈,但不会触发浏览器页面刷新,并且在set hash值与当前url的hash值相同时,不会有任何事发生(等于没执行)。
window.location.replace
这是一个纯方法,其作用是替换当前浏览器的栈记录,设置为传入新的URL,并且刷新页面。
replace可以对hash进行操作并且触发对应的事件,不会受相同hash的规则影响
1) popstate事件
history.pushState与history.replaceState产生的历史栈记录中,如果栈指针发生了移动,或者点击了浏览器的前进或者回退按钮时,会触发popstate事件,可以通过window.addEventListener去添加事件监听。
popstate拿到的event对象最关键的属性是event.state,这个event.state是直接从浏览器底层存储器中取出(属于深拷贝),而非从历史栈中的state取出,因此直接修改历史栈state并不会对event.state造成影响(反之亦然)。
前后两次设置相同的location.hash时不会触发两次popstate事件,但是通过location.href设置两次相同的hash可以,虽然可以触发两次popstate事件,但是历史栈只会增加一层。
2)hashchange事件
hashchange时间监听的是浏览器url的片段标识符的变化,也就是hash值的变化,事件对象event可以拿到关键的oldUrl和newUrl,表示hash跳转前的url和跳转后的url。
pushState方法即使是只改动了浏览器的hash值,也不会触发hashchange事件。
这两个事件都可以通过window.dispatchEvent方法去触发,dispatchEvent方法需要传入一个事件对象:
window.dispatchEvent(new PopStateEvent());
对于hashchang事件同理:
window.dispatchEvent(new HashChangeEvent());
G. 接口请求处理全路径
前端参数PARS组装:
。参数数组转JSON字符串
。BASE64编码 然后替换掉+ / =这三个URL有意义的字符
例如:
。4台4H4G的服务器
。每台运行4个NODEJS进程
。每个NGINX后面跟2台服务器
发出请求:
。请求先到域名服务器 DNS轮询随机决定本次请求由哪个IP处理
。NGINX负载均衡首先判断缓存是否命中 如果是 直接返回结果了(这里暂迅野未启用 用不好可能会带来不好的问题)
。NGINX根据权重或随机选择一台后端服务器上的某一个NODEJS进程处理
NODEJS接收到请求:
。koa框架解析取出请求体
。通过路由设置进到请求的TS(如果请求的是私有方法或私有服务直接返回错误)
。TS初始化 取出UPINFO所有参数 还原参数数组 (未上传参数设置为默认值 )
。进入API函数 _upcheck方法验证用户输入并取出用户信息(会话ID 帐套ID 用户名 真实姓名 微信OPENID等)
。进行业务处理 并返回
。IP记录 SQL效率统计 API效率统计等
整套目的:
。参数数组较灵活 容易自定义 其它参数固定方便(防注入只需注意不要拼接参数数组即可)
。全是亩局喊JS语言 有培养全栈工程师的优势
。腊颂减少前后端沟通协调的成本(前后端至少能相互看懂)
。减少后端工作量(一部分接口可以省略 由前端组装)
前端自定义请求的说明
H. 前端页面跳转时路径上传参数有特殊符号时报错,解决
encodeURI() 函数用于对 URI 进行编码,此函数对特殊字符进行编码,除了: , / ? : @ & = + $ #,http路径采用encodeURI进行编码
encodeURIComponent()对 : , / ? : @ & = + $ #这些字符进行编码滑数模,在路径中携带的信缓参数采用encodeURIComponent进行编码
请使用 decodeURI() 函数对已编码毕猛的 URI 进行解码。