-
javaWeb - 2 — ajax、json — 最后附:后台获取前端中的input type = "file"中的信息
1、ajax是什么?
-
面向百度百科一下就知道了,这里就简单提炼一下
- Ajax即Asynchronous Javascript And XML(异步JavaScript和XML)。当然其实我们学的应该叫:异步JavaScript和ajax
- 包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的XMLHttpRequest
- 使用Ajax技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作
-
用我的话说就是:ajax就是为了异步提交请求,从而只刷新一个局部区域的内容,不影响另外内容的刷新
- 什么意思?很简单,都见过一个场景,当我们在注册账号的时候,我们输入用户名,输入框后面就会提示:该用户重名了,但是不是刷新了整个页面,而是只刷新了这一个用户名的输入框。这是怎么做到的,就是通过ajax异步请求做到的
2、原生的ajax应该怎么玩儿?
-
对于学java的人来说:简单得要死,就他喵的三部曲
- 获取xmlHttpRequest对象
- 回调监听 onreadystatechange / 获取需要传递的数据
- 向后台发起请求、发送数据( 注:get、post这两种方式的发送数据的方法不太一样,但是道理其实都没变
-
(1)、那么就来实操一下嘛,先用get方式提交请求
|
// 1、创建XMLRequest对象( 注意:考虑浏览器的不同 ) |
|
var xmlhttp; |
|
if (window.XMLHttpRequest) |
|
{ |
|
// IE7+, Firefox, Chrome, Opera, Safari 这几种浏览器获取XMLRequest对象的方式 |
|
xmlhttp=new XMLHttpRequest(); |
|
} |
|
else |
|
{ |
|
// IE6, IE5 浏览器执行代码 |
|
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); |
|
} |
|
|
|
|
|
// 2、回调监听onreadystatechange |
|
xmlhttp.onreadystatechange=function(){ |
|
if (xmlhttp.readyState==4 && xmlhttp.status==200){ |
|
|
|
document.getElementById("myDiv").innerHTML=xmlhttp.responseText; |
|
} |
|
} |
|
|
|
// 3、发送数据( 发送get请求 ) |
|
xmlhttp.open("GET","/接口名 ? 要传给后台的数据参数"); // 注意这个参数是:key-value的形式传送的 |
|
// 多个参数数据使用 & 隔开 |
|
xmlhttp.send(); // 发送请求 |
|
-
(2)、post方式提交
- 其实和get方式是差不多的,只是发送数据哪里做一下修改即可,改成如下方式:
|
xmlhttp.open("POST","/后端的接口名 ? 要给后台传送的数据参数"); |
|
xmlhttp.send(); |
或者是:
|
xmlhttp.open("POST","/后台的接口名",true); |
|
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); // 这是请求头的设置,不会的可以直接百度 |
|
xmlhttp.send("fname=Henry&lname=Ford"); // 即:这里面直接跟要发给后台的数据参数 |
-
(3)、后端是怎么获取这个ajax中传递过去的参数的呢?
- 很简单:get和post发给后台的数据不是都是以key-value的形式发过去的吗,那么:在后端直接使用 httpServletRequest对象.getParameter( String key ) 的方式即可获取到get或post中携带的value值。
多提一嘴:后台获取前端的数据,基本上都是通过 httpServletRequest对象.getParameter( String key / name ) 的方式获取的数据。但是:前端中input type = “file”的值不是这么获取的,而是需要在前端中 new一个FormData对象来进行操作。
即:在前端
- 获取file的files属性( 获取file的节点.prop( "files" ) )
- 然后通过 FormData对象.append("file" , files[0]) 的方式把这个file中的信息存到FormData中去
-
最后通过ajax传递到后台去( 这里必须使用:$.ajax()的方式进行传递 —— 这是jQuery中的ajax异步请求方式,即:jQuery对ajax进行了封装,而原理就是上面说的get和post的执行过程。
- 另外:记得对这个ajax设置:cache:false , contentType:false , processData:false
在后台:
- 后台获取这个file中的值是通过 httpServletRequest对象.getParts() 获取file的所有value值( 但是:浏览器不同,这个值不同,所以:需要对这个信息进行截取,得到自己想要的那个文件名( 当然:这个servlet必须加一个注解才可以实现对文件的操作:即 @multipartConfig ) , 不说多了,这个后续会进行演示
3、JSON
1)、JSON是个什么鬼东西?
-
JSON( JavaScript Object Notation, JS 对象简谱 ) 是一种轻量级的数据交换格式
-
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
-
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言
-
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率
-
当然:这些都是网上的话,好像不太通俗易懂,那就换一下语言表达
- 用java中能够让人一眼就明白的话来说就是:JSON就是用来存储东西的一个容器,这个容器在传输的时候very地快,同时很容易被解析( 无论是前端还是后台解析 )。这个玩意儿就这么回事儿
2)、JSON这个东西长什么样子嘞?
-
也非常的好理解,在前面说明前端的时候不是玩过js对象吗,这个js对象长什么样子?
-
{ fieldName1:"value" , fieldName2:"valud" ....... }
-
JSON对象 / 字符串就长这么个鬼样子
- ' { fieldName1:"value" , fieldName2:"valud" ....... } '
-
JSON数组长什么样子?
- ' [ { fieldName1:"value" , fieldName2:"valud" ....... } , { fieldName1:"value" , fieldName2:"valud" ....... } ] '
-
3)、那拿这个JSON来玩的是什么?
- java对象 ---转成---> JSON字符串 / 对象 <---转成---> js对象
(1)、先来玩一下前端中js对象和json对象之间的转换( 其实就只需要记住parse()、stringify()两个方法就完了 )
|
<script> |
|
// json 对象 |
|
var jsonStr = ' {"id":69","name":"苍老师","size":"G"} '; |
|
// json 数组 |
|
var jsonArray = ' [{"id":"1","name":"波多野结衣","size":"F"},{"id":"8","name":"汤wei","size":"B"} ] '; |
|
|
|
// JSON.parse( json格式的字符串 ) json字符串 = > JS对象(数组) ****重要*** |
|
// json对象 转 js对象 |
|
var js= JSON.parse(jsonStr); |
|
console.log( js.id , js.name , js.size); |
|
|
|
// json数组 转 js对象 |
|
var js= JSON.parse( jsonArray ); |
|
js.forEach( function (v,i) { |
|
console.log(v.name) |
|
}) |
|
|
|
// JSON.stringify( js对象 ) JS对象 = > JSON字符串 ****重要**** |
|
var perosn = { name:"张三",age:10}; |
|
var json = JSON.stringify(perosn); |
|
console.log(json) |
|
|
|
</script> |
(2)、java对象 转 json对象
-
这个就需要一个jar包了,有如下这些jar包供选择
- fastjson [ 流行 , 所以建议用这个 ]
- jackson
- json-lib
|
package cn.xieGongZi.servlet; |
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import javax.servlet.ServletException; |
|
import javax.servlet.http.HttpServlet; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import java.io.IOException; |
|
import java.util.HashMap; |
|
import java.util.Map; |
|
|
|
public class ToJson extends HttpServlet { |
|
|
|
|
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
|
|
|
req.setCharacterEncoding("utf-8"); |
|
resp.setCharacterEncoding("utf-8"); |
|
resp.setContentType("text/html;charset = utf-8"); // 这个其实这里不用配置也行,因为:要响应的是网页才设置这个嘛,这个示例哪里需要响应网页 |
|
// 要转成json对象,不让中文乱码,还需要做一件事情 |
|
resp.setContentType("application/json;charset=utf-8"); |
|
|
|
// 这里就直接硬拼一个对象出来 |
|
Map<String, Object> map = new HashMap<>(); |
|
map.put("name", "紫邪情"); |
|
map.put("sex", 18); |
|
map.put("code", 200); |
|
|
|
String jsonStr = JSON.toJSONString(map); // 这里就把java对象转成一个json对象了 |
|
|
|
resp.getWriter().print(jsonStr); // 这一步就是响应给前端 |
|
/* |
|
但是:这里涉及到了ajax的使用 [ 其实就是ajax中回调监听哪里的xmlHttpRequest.responseText ] ) |
|
请求获取响应文本嘛,这个响应文本内容不就是后台这里的响应流向浏览器发送的数据吗,但是被前端获取过去了 |
|
这样前端就可以拿到后端这里传过去的数据了 ———— 不会的,看不懂的,现在不理解没事,等到前后端连起来玩ajax时就懂了 |
|
*/ |
|
|
|
} |
|
} |
|
4、实操玩一下ajax
-
前面说了这么多理论的废话,没多大意思,所以:还是来实操一手儿ajax吧
-
使用jQuery中封装好了的ajax
-
要使用jQuery,那肯定需要导入jQuery的js咯
-
要使用jQuery,那肯定需要导入jQuery的js咯
-
get方式的ajax语法如下:
|
|
|
$.get( ' 后端的接口名-servlet中的那个servlet路径 ' ,{ fieldName1:valued , fieldName2:value .....} , function( 参数 ) { |
|
|
|
逻辑代码; |
|
|
|
} , 'json' ) |
|
- post方式的ajax语法如下:
|
|
|
$.post( ' 后端的接口名-servlet中的那个servlet路径 ' ,{ fieldName1:valued , fieldName2:value .....} , function( 参数 ) { |
|
|
|
逻辑代码; |
|
|
|
} , 'json' ) |
|
-
对如上式子的说明:
-
{ fieldName1:valued , fieldName2:value .....} 就是要传给后端 ' 后端的接口名-servlet中的那个servlet路径 ' 这个路径下的数据参数
- 这个数据参数的本质其实就是js对象,因此:要是要传的数据参数有多个的时候就可以封装成一个js对象,然后把对象名甩到这里来当数据参数就可以了
-
'json' 这个就是期望后端传回前端的数据格式类型是什么,具体可以填哪些类型,自行百度百科,这里用json类型
-
function( 参数 ) 这个就是回调函数 , 这个“ 参数 ”就是后端传给前端的数据( 一般都是json字符串 )
-
这个参数后端一般是怎么封装传过来的?
- 看前端需要的json格式是怎么样的
- 然后通过不断的使用map,从而一层之中套一层...达到想要的json格式,从而使用resq.getWriter().print()把这个json对象传到前端去
-
这个参数后端一般是怎么封装传过来的?
-
整个过程结合ajax的原生使用方法( 即 : 美没封装之前的用法 —— 前面说的那个三部曲 ), 这样就很好理解了
-
举个例子( **这个例子很重要很重要 , 后端获取前端的input type = “file”中的信息就是通过这个方法流程得到的 ):
-
前端需要的格式是这样的:
"errno":0 data:[ { url:"图片地址“ } , { alt:"图片说明“ } , { href:"null" } ] // href 其实是跳转链接
-
后端就是这么玩的:
-
|
package cn.xieGongZi.commons.util.http; |
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import javax.servlet.ServletException; |
|
import javax.servlet.annotation.MultipartConfig; |
|
import javax.servlet.annotation.WebServlet; |
|
import javax.servlet.http.HttpServlet; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import javax.servlet.http.Part; |
|
import java.io.File; |
|
import java.io.IOException; |
|
import java.time.LocalDate; |
|
import java.util.ArrayList; |
|
import java.util.Collection; |
|
import java.util.Date; |
|
import java.util.HashMap; |
|
|
|
|
|
// @MultipartConfig 注解就是文件注解,要获取前端的文件信息,必须加这个注解,不然做的所有事情都是无用功 |
|
|
|
|
|
public class UploadServlet extends HttpServlet { |
|
|
|
|
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
|
|
|
/* |
|
* 想要构建的是这么一个玩意儿 |
|
* "errno":0 data:[ { url:"图片地址“ } , { alt:"图片说明“ } , { href:"null" } ] // href 其实是跳转链接 |
|
* |
|
* */ |
|
|
|
ArrayList<Object> list = new ArrayList<>(); |
|
|
|
Collection<Part> parts = req.getParts(); // 这是获取前台上传的文件 |
|
|
|
for (Part part : parts) { |
|
|
|
// 先构建 data:[ { } , { } ]中的[ { } , { } ] |
|
|
|
// 获取文件的全路径 |
|
String filePath = part.getSubmittedFileName(); // 但是:不同浏览器的这个全路径都不一样,所以需要截取从而自定义文件名 |
|
// System.out.println(filePath); |
|
// 截取文件的后缀名 |
|
int subFileName = filePath.lastIndexOf("."); |
|
String fileSuffix = filePath.substring(subFileName); |
|
|
|
// 自己给文件重新定义一个名字,并规定存放的地方 |
|
String timeStr = LocalDate.now().toString(); |
|
|
|
// 获取当前项目的一个指定文件夹名字,用来保存文件 注意:getRealPath这是获取的当前项目的全路径,即:从盘符开始的路径 |
|
String proPathName = this.getServletContext().getRealPath("/upload/" + timeStr ); |
|
File file = new File(proPathName); |
|
if ( !file.exists() ){ |
|
file.mkdirs(); |
|
} |
|
|
|
// 拼接文件后缀名并保存文件 |
|
long timeStamp = new Date().getTime(); |
|
part.write(proPathName + "/" + timeStamp + fileSuffix ); |
|
|
|
HashMap<String, String> map = new HashMap<>(); |
|
map.put( "url" , "/upload/" + timeStr + "/" + timeStamp + fileSuffix ); |
|
map.put( "alt" , timeStamp + fileSuffix ); |
|
map.put( "href" , null ); |
|
list.add(map); |
|
} |
|
|
|
// 再构建"errno":0 data:[ { url:"图片地址“ } , { alt:"图片说明“ } , { href:"null" } ] |
|
HashMap<String, Object> map = new HashMap<>(); |
|
map.put("errno", "0"); |
|
map.put("data", list); |
|
|
|
resp.getWriter().print( JSON.toJSONString(map) ); |
|
} |
|
} |
|
- 前端的html是这样的:
|
|
|
<div id="image"> |
|
<label for="">标题图片:</label> |
|
<input type="file" id="file" name="file" > |
|
<img src="" alt="" width="100px" height="150px"> |
|
</div> |
|
- 前端的script是这样弄的:
|
// 当图片发生改变时 —— 也就是用户点击file框,上传文件时 |
|
$("#file").on( 'change' , function () { |
|
|
|
// 创建一个FormData空对象,就相当于是伪造了一个form表单 |
|
let formData = new FormData(); |
|
|
|
// 这个FromData对象就用来装文件内容 |
|
let files = $("#file").prop("files"); // 文件的files属性本质是个数组,可以使用 获取file输入框的节点.files 看一下答案 |
|
formData.append("upFile" , files[0] ); |
|
|
|
$.ajax( { // 这个就是jQuery中ajax的用法,“万变不离其宗”,上面的get和post使用也就会了 |
|
|
|
url: '/ajax/upload.do', |
|
type: 'post', |
|
data: formData, |
|
dataType: 'json', |
|
|
|
cache: false, // 上传文件不需要缓存 |
|
contentType: false, // 不需要对内容类型进行处理 因为内容是一个FormData对象 |
|
processData: false, // 不需要对数据进行处理,因为上面的data是一个FormData对象 |
|
|
|
// 后台返回的格式 : |
|
// { "errno":"0" , "data":[ {"alt":"1633528500498.jpg" , "url":"/upload/2021-10-06/1633528500498.jpg"} ] } |
|
success: function (info) { |
|
info.data.forEach( function (data) { |
|
|
|
// $("#image img").remove(); |
|
// $("#image").append( ' <img src=" '+data.url+' " alt="" width="100px" height="150px"> ' ) |
|
/* |
|
注掉的这种是:html中没有img标签时使用 |
|
因为:使用下面这种方法的情景是 —— 页面本来就有一个img框( 即:初始页面上这个file本身有一张图片 ),所以下面这种可以做到图片改变时把图片的路径换掉 |
|
也就是图片渲染( 这也是数据渲染 / 数据回填 的思想 ) |
|
但是:如果页面一开始file的位置是不应该有图片的,是后面用户选了之后才出现图片预览效果,那么:就使用注释掉的这种方法:追加 |
|
*、 |
|
|
|
$("#image img").attr("src" , data.url ); |
|
}); |
|
} |
|
} ); |
|
|
|
}) |
|
- 这个的效果是这样的,这个图片的信息是可以在后端获取到的( 当然:文件也可以 )
ajax、json的相关内容也就差不多是这些了,主要是:会用就行
作者:紫邪情