Ajax 的 Java 对象序列化
- 格式:doc
- 大小:133.50 KB
- 文档页数:15
java反序列化魔术方法Java deserialization is a process that can lead to security vulnerabilities and exploits if not properly implemented. When an object is serialized in Java, it means that it is converted into a byte stream so that it can be easily stored or transmitted. However, when this object is then deserialized, it is reconstructed from the byte stream and reconstituted in memory.Java反序列化是一个过程,如果没有正确实现,可能会导致安全漏洞和利用。
当一个对象在Java中被序列化时,意味着它被转换成一个字节流,这样它可以很容易地被存储或传输。
然而,当这个对象被反序列化时,它会从字节流中重建并在内存中重新组成。
One of the security issues that can arise from deserialization is the potential for an attacker to manipulate the byte stream in order to execute arbitrary code on the server. This can lead to a wide range of attacks, including remote code execution, denial of service, and even the potential for an attacker to gain unauthorized access to sensitive data.反序列化可能出现的安全问题之一是攻击者可能操纵字节流,以执行服务器上的任意代码。
axios 序列化的方法-回复【axios 序列化的方法】Axios 是一个基于Promise 的HTTP 客户端,可以用于浏览器和Node.js 中发送网络请求。
它提供了许多便捷的方法来处理数据,其中一个重要的功能就是序列化请求数据。
在发送POST 请求时,我们通常需要传递一些数据作为请求的主体,这些数据可以是表单数据、JSON 数据等。
而序列化则是将这些数据转化为符合服务器要求的格式,从而能够成功发送请求并处理。
Axios 提供了多种序列化的方法,包括JSON 序列化、URLSearchParams 序列化、FormData 序列化、Blob 序列化等。
下面将一一介绍这些方法的使用。
1. JSON 序列化JSON 序列化是将JavaScript 对象转换为JSON 字符串的过程,它常用于发送JSON 数据格式的请求。
在Axios 中,可以通过设置请求头的Content-Type 来指定数据类型为JSON,并使用JSON.stringify() 方法将对象序列化为JSON 字符串。
示例代码如下:javascriptaxios.post('/api/post', {data: JSON.stringify({ key1: value1, key2: value2 }), headers: {'Content-Type': 'application/json'}}).then(response => {console.log(response.data);}).catch(error => {console.error(error);});以上代码中,通过设置`Content-Type` 请求头为`application/json` 来告知服务器发送的数据为JSON 格式。
`JSON.stringify()` 方法将JavaScript 对象转换为JSON 字符串。
关于序列化和反序列化案例看这⼀篇就够⽤了,简直讲的清新脱俗!前⾔序列化:将java对象转化为可传输的字节数组反序列化:将字节数组还原为java对象为啥⼦要序列化?序列化最终的⽬的是为了对象可以跨平台存储,和进⾏⽹络传输。
⽽我们进⾏跨平台存储和⽹络传输的⽅式就是IO,⽽我们的IO⽀持的数据格式就是字节数组什么情况下需要序列化?凡是需要进⾏跨平台存储和⽹络传输的数据,都需要进⾏序列化本质上存储和⽹络传输都需要经过把⼀个对象状态保存成⼀种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息序列化的⽅式序列化只是⼀种拆装组装对象的规则,这种规则多种多样,常见的序列化⽅式有:JDK(不⽀持跨语⾔)、JSON、XML、Hessian、Kryo(不⽀持跨语⾔)、Thrift、Protostuff、FST(不⽀持跨语⾔)举个栗⼦⾃定义协议中,需要序列化和反序列化,案例中枚举类Algorithm的内部类重写了⾃定义接⼝Serializer中的序列化和反序列化⽅法,本案例中枚举类Algorithm采⽤了jdk和json两种序列化⽅式,通过配置类Config类,可以灵活在application.properties中选择序列化的⽅式导⼊依赖<!-- https:///artifact/com.google.code.gson/gson --><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency>⾃定义Message类package com.lian.chatroom.message;import lombok.Data;import java.io.Serializable;import java.util.HashMap;import java.util.Map;@Datapublic abstract class Message implements Serializable {private int sequenceId;private int messageType;/*** 根据消息类型的数字编号,获得对应的消息 class* @param messageType 消息类型字节* @return 消息 class*/public static Class<? extends Message> getMessageClass(int messageType) {return messageClasses.get(messageType);//定义抽象⽅法,获取返回消息类型public abstract int getMessageType();//⾃定义静态常量,每种数据类型以数字代表public static final int LoginRequestMessage = 0;public static final int LoginResponseMessage = 1;public static final int ChatRequestMessage = 2;public static final int ChatResponseMessage = 3;public static final int GroupCreateRequestMessage = 4;public static final int GroupCreateResponseMessage = 5;public static final int GroupJoinRequestMessage = 6;public static final int GroupJoinResponseMessage = 7;public static final int GroupQuitRequestMessage = 8;public static final int GroupQuitResponseMessage = 9;public static final int GroupChatRequestMessage = 10;public static final int GroupChatResponseMessage = 11;public static final int GroupMembersRequestMessage = 12;public static final int GroupMembersResponseMessage = 13;public static final int PingMessage = 14;public static final int PongMessage = 15;/*** 请求类型 byte 值*/public static final int RPC_MESSAGE_TYPE_REQUEST = 101;/*** 响应类型 byte 值*/public static final int RPC_MESSAGE_TYPE_RESPONSE = 102;//map存储(消息类型数字编号,消息类型)private static final Map<Integer, Class<? extends Message>> messageClasses = new HashMap<>();//static代码块随着类的加载⽽执⾏,⽽且只执⾏⼀次static {messageClasses.put(LoginRequestMessage, LoginRequestMessage.class);messageClasses.put(LoginResponseMessage, LoginResponseMessage.class);messageClasses.put(ChatRequestMessage, ChatRequestMessage.class);messageClasses.put(ChatResponseMessage, ChatResponseMessage.class);messageClasses.put(GroupCreateRequestMessage, GroupCreateRequestMessage.class);messageClasses.put(GroupCreateResponseMessage, GroupCreateResponseMessage.class);messageClasses.put(GroupJoinRequestMessage, GroupJoinRequestMessage.class);messageClasses.put(GroupJoinResponseMessage, GroupJoinResponseMessage.class);messageClasses.put(GroupQuitRequestMessage, GroupQuitRequestMessage.class);messageClasses.put(GroupQuitResponseMessage, GroupQuitResponseMessage.class);messageClasses.put(GroupChatRequestMessage, GroupChatRequestMessage.class);messageClasses.put(GroupChatResponseMessage, GroupChatResponseMessage.class);messageClasses.put(GroupMembersRequestMessage, GroupMembersRequestMessage.class);messageClasses.put(GroupMembersResponseMessage, GroupMembersResponseMessage.class);messageClasses.put(RPC_MESSAGE_TYPE_REQUEST, RpcRequestMessage.class);messageClasses.put(RPC_MESSAGE_TYPE_RESPONSE, RpcResponseMessage.class);}}⾃定义序列化接⼝⾃定义枚举类Algorithm,⽽枚举类Algorithm也有两个内部类对象 java和json,分别重写了接⼝的序列化和反序列化⽅法package com.lian.chatroom.protocol;import com.google.gson.Gson;import java.io.*;import java.nio.charset.StandardCharsets;/*** 为了⽀持更多的序列化⽅法*/public interface Serializer {/*** 反序列化* 将byte[]或json 转换为 java对象* @param bytes 字节数组* @param clazz 要转换成的java对象类型* @param <T> 泛型* @return*/<T> T deSerializer(byte[] bytes, Class<T> clazz);* 序列化* 将java对象转换为 byte[]或json类型*/<T> byte[] serializer(T object);/*** 创建内部枚举类 Algorithm,实现序列化*/enum Algorithm implements Serializer{//java代表是⾃带jdk的序列化与反序列化java{@Overridepublic <T> T deSerializer(byte[] bytes, Class<T> clazz) {try {ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); //对象输出流读取java对象return (T) ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();throw new RuntimeException("反序列化失败", e);}}@Overridepublic <T> byte[] serializer(T object) {try {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);//将java对象写⼊到对象输出流中oos.writeObject(object);byte[] bytes = bos.toByteArray(); //返回字节数组return bytes;} catch (IOException e) {throw new RuntimeException("序列化失败", e);}}},json{@Overridepublic <T> T deSerializer(byte[] bytes, Class<T> clazz) {//将字节数组转换为字符串String json = new String(bytes, StandardCharsets.UTF_8);return new Gson().fromJson(json,clazz);}@Overridepublic <T> byte[] serializer(T object) {Gson gson = new Gson();//将java对象转化为json字符串String json = gson.toJson(object);//将json字符串转换为字节数组return json.getBytes(StandardCharsets.UTF_8);}}}}⾃定义协议类⾃定义的协议⾥需要编解码,序列化的⽅式,此处选择了jdk和jsonpackage com.lian.chatroom.protocol;import com.lian.chatroom.config.Config;import com.lian.chatroom.message.Message;import ty.buffer.ByteBuf;import ty.channel.ChannelHandler;import ty.channel.ChannelHandlerContext;import ty.handler.codec.MessageToMessageCodec;import lombok.extern.slf4j.Slf4j;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.List;/*** 必须和 LengthFieldBasedFrameDecoder ⼀起使⽤,确保接到的 ByteBuf 消息是完整的* 消息编解码* 出栈:ByteBuf格式数据转换为字符串等其他格式解码* ⼊栈:字符串等其他格式转换为 ByteBuf格式数据编码*/@Slf4j@ChannelHandler.Sharablepublic class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {@Overrideprotected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {//⽤通道分配⼀个缓存区ByteBuf out = ctx.alloc().buffer();//1. 4 字节的魔数,就是服务端和客户端约定好的暗号,例如:天王盖地虎宝塔镇魔妖out.writeBytes(new byte[]{1, 2, 3, 4});// 2. 1 字节的版本,out.writeByte(1);// 3. 1 字节的序列化⽅式 jdk 0 , json 1//out.writeByte(0); //写死的⽅式//3.1 采⽤配置类灵活选择序列化⽅式,返回此枚举常量的序号,如果序列化⽅式是jdk就会填写0,如果是json就会填写1 out.writeByte(Config.getSerializerAlgorithm().ordinal());// 4. 1 字节的指令类型out.writeByte(msg.getMessageType());// 5. 4 个字节out.writeInt(msg.getSequenceId());// ⽆意义,对齐填充out.writeByte(0xff);// 6. 获取内容的字节数组// ByteArrayOutputStream bos = new ByteArrayOutputStream();// ObjectOutputStream oos = new ObjectOutputStream(bos);// oos.writeObject(msg);// byte[] bytes = bos.toByteArray();//6.1、采⽤jdk⽅式序列化,将java对象转为字节数组//byte[] bytes = Serializer.Algorithm.java.serializer(msg);//6.2、采⽤json⽅式序列化//byte[] bytes = Serializer.Algorithm.json.serializer(msg);//6.3、采⽤配置类形式,来灵活选择使⽤哪种序列化⽅式byte[] bytes = Config.getSerializerAlgorithm().serializer(msg);// 7. 长度out.writeInt(bytes.length);// 8. 将字节数组写⼊到缓存区out.writeBytes(bytes);outList.add(out);}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {int magicNum = in.readInt();byte version = in.readByte();//从缓存区中读取到编码时⽤的哪种序列化算法类型,是jdk or json//返回 0 or 1, 0代表jdk序列化⽅式,1代表json序列化⽅式byte serializerAlgorithm = in.readByte();//消息类型,0,1,2,。
JSP Ajax Ajax框架概述在使用JavaScript、XML、DOM等技术编写Ajax页面时,我们需要考虑很多问题,如针对不同的浏览器,需要使用不同的方式创建XMLHttpRequest对象,以达到在所有的浏览器都能够浏览演示。
编写一个Ajax案例,如果还是采用以前的A jax设计方法,不可以避免的要产生大量的重复性代码,如每个Ajax页面都需要创建XMLHttpRequest对象,对XML文件的处理方式等。
编写Ajax页面的大量时间浪费在这些重复性的代码上,显然有点不划算。
这些情况对一个优秀的程序员来说,根本不是问题。
我们可以把这些重复性的代码,多次需要调用的代码,以面向对象的方式封装到一个文件里面,如创建XMLHttpReq uest对象。
把重复性、关键性代码封装起来,能够达到代码重复重用的目的,能够很好的维护程序和调试程序。
把重复性代码封装起来,做出独立的文件,这里文件的扩展名为.js。
利用这些封装JavaScript文件可以形成自己的代码库,进而形成属于自己的框架。
创建属于自己的Ajax代码库,会花费大量的时间,并且还需要时刻注意代码库的Bug并进行修正。
对于个人来说,还不如使用一些现成的Ajax框架,毕竟这些框架是经过优秀程序员创建和大量的用户测试。
从Ajax诞生以来,人们就发现使用Ajax框架可以带来极大的方便,节省了大量的时间和精力。
于是,大量的Ajax框架诞生了,Ajax框架很多,几乎每月都要产生一些新的框架。
有些框架基于客户端,有些基于服务器端;有些专门为特定语言设计,如Java。
另外还有一些与语言无关。
其中绝大部分都是开源的,但也有少数是专用的。
经过Ajax框架的发展,一些框架已经逐渐被淘汰,一些框架被保留了下来。
Ajax框架由于代码库封装代码的不同,可以分为基于浏览器的Ajax框架和基于服务器端的Ajax框架。
基于服务器端框架可以划分两种形式,分别为HTML/JS Generation(HTML/JS生成)和远程交互。
什么是Java序列化,如何实现java序列化简要解释: 序列化就是⼀种⽤来处理对象流的机制,所谓对象流也就是将对象的内容进⾏流化。
可以对流化后的对象进⾏读写操作,也可将流化后的对象传输于⽹络之间。
序列化是为了解决在对对象流进⾏读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接⼝,该接⼝没有需要实现的⽅法,implements Serializable只是为了标注该对象是可被序列化的,然后使⽤⼀个输出流(如:FileOutputStream)来构造⼀个ObjectOutputStream(对象流)对象,接着,使⽤ObjectOutputStream对象的writeObject(Object obj)⽅法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则⽤输⼊流。
详细解释:当两个进程在进⾏远程通信时,彼此可以发送各种类型的数据。
⽆论是何种类型的数据,都会以⼆进制序列的形式在⽹络上传送。
发送⽅需要把这个Java对象转换为字节序列,才能在⽹络上传送;接收⽅则需要把字节序列再恢复为Java对象。
只能将⽀持 java.io.Serializable 接⼝的对象写⼊流中。
每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引⽤的其他所有对象的闭包。
1.概念 序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
2.⽤途 对象的序列化主要有两种⽤途: 1)把对象的字节序列永久地保存到硬盘上,通常存放在⼀个⽂件中; 2)在⽹络上传送对象的字节序列。
3.对象序列化序列化API java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)⽅法可对参数指定的obj对象进⾏序列化,把得到的字节序列写到⼀个⽬标输出流中。
实例通过 AJAX 加载一段文本: jQuery 代码: $(document).ready(function(){ $("#b01").click(function(){ htmlobj=$.ajax({url:"",async:false}); $("#myDiv").html(htmlobj.responseText); }); });HTML 代码: <div id="myDiv"><h2>321 导航</h2></div> <button id="b01" type="button"></button>亲自试一试定义和用法ajax() 方法通过 HTTP 请求加载远程数据。
该方法是 jQuery 底层 AJAX 实现。
简单易用的高层实现见 $.get, $.post 等。
$.ajax() 返回其创建 的 XMLHttpRequest 对象。
大多数情况下你无需直接操作该函数,除非你需要操作不常用的选项,以获 得更多的灵活性。
最简单的情况下,$.ajax() 可以不带任何参数直接使用。
注意:所有的选项都可以通过 $.ajaxSetup() 函数来全局设置。
语法jQuery.ajax([settings])参数 settings描述 可选。
用于配置 Ajax 请求的键值对集合。
可以通过 $.ajaxSetup() 设置任何选项的默认值。
参数 options 类型:Object可选。
AJAX 请求设置。
所有选项都是可选的。
async 类型:Boolean 默认值: true。
默认设置下,所有请求均为异步请求。
如果需要发送同步请求,请将此选项设 置为 false。
注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
ajax调用java方法ajax调用java后台的方法,其实是通过url链接来访问。
下面是店铺为大家带来一篇ajax调用java方法,希望对大家有所帮助。
ajax调用java方法(一)public void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException,java.io.IOException{//得到类名、方法名和参数String methodName=req.getParameter("methodName");String className=req.getParameter("className");Object[] objs=req.getParameterValues("params");Object targetObj;try {targetObj = Class.forName(className).newInstance();Object obj=MethodUtils.invokeMethod(targetObj, methodName, objs);this.dealResp(resp, obj);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}private void dealResp(HttpServletResponse resp,Object obj) throws IOException{resp.setContentType("text/xml;charset=GBK");PrintWriter pw=resp.getWriter();pw.write(""+deal(obj)+"");pw.flush();pw.close();}private String deal(Object obj){String sbResult="";if(obj==null){sbResult="";}else if(obj instanceof ng.String){sbResult=dealString(obj);}else if(obj instanceof java.util.List){sbResult=dealList(obj);}else if(obj instanceof ng.Boolean){sbResult=dealBoolean(obj);}else if(obj instanceof ng.Double){sbResult=dealDouble(obj);}else if((obj instanceof ng.Integer) || (obj instanceof ng.Long)){sbResult=dealInteger(obj);}else if(obj instanceof ng.Throwable){sbResult=dealException(obj);}else if(obj instanceof java.util.Map){sbResult=dealMap(obj);}else if(obj instanceof java.util.Date){sbResult=dealDate(obj);}else if(obj instanceof java.util.Calendar){sbResult=dealDate(obj);}else if(obj instanceof org.w3c.dom.Document){sbResult=dealXml(obj);}else{sbResult=dealObject(obj);}return sbResult;}//处理Date或Calendar类型,返回值为yyyy-MM-dd-HH-mm-ss-SSS格式的字符串private String dealDate(Object obj){Calendar cal=null;if(obj instanceof Calendar){cal=(Calendar)obj;}else{cal=Calendar.getInstance();cal.setTime((Date)obj);}StringBuffer sb=new StringBuffer();sb.append("");sb.append(cal.get(Calendar.YEAR));sb.append("-");sb.append(cal.get(Calendar.MONTH));sb.append("-");sb.append(cal.get(Calendar.DAY_OF_MONTH));sb.append("-");sb.append(cal.get(Calendar.HOUR_OF_DAY));sb.append("-");sb.append(cal.get(Calendar.MINUTE));sb.append("-");sb.append(cal.get(Calendar.SECOND)); sb.append("-");sb.append(cal.get(LISECOND)); sb.append("");return sb.toString();}private String dealMap(Object obj){ StringBuffer sb=new StringBuffer();Map map=(Map)obj;sb.append("");Set entrys=map.entrySet();Iterator ite=entrys.iterator();Map.Entry entry=null;while(ite.hasNext()){entry=(Map.Entry)ite.next();sb.append("<");sb.append(entry.getKey());sb.append(">");sb.append(deal(entry.getValue()));sb.append(");sb.append(entry.getKey());sb.append(">");}sb.append("");return sb.toString();}ajax调用java方法(二)public class Test {public static String sayHello(String name){ return "hello, " + name;}}注意:必须是公开的静态方法。
ajaxdata参数
ajaxdata参数是用于发送Ajax请求时传递数据的一个重要参数。
该参数可以是一个对象或者一个序列化的字符串,用来向服务器发送数据并获取响应结果。
在使用ajaxdata参数时,需要注意以下几点: 1. 对象数据传递
如果ajaxdata参数是一个对象,则可以通过键值对的方式将要
传递的数据以属性名称和属性值的形式进行设置。
例如,
ajaxdata:{userna'admin',password:'123456'}表示将用户名和密
码传递给服务器进行验证。
2. 序列化数据传递
如果ajaxdata参数是一个序列化的字符串,则需要使用jQuery 的$.param()方法将要传递的数据进行序列化处理。
例如,ajaxdata:$.param({userna'admin',password:'123456'})表示将用
户名和密码进行序列化处理后再传递给服务器。
3. 多种数据传递方式
ajaxdata参数还可以使用其他数据传递方式,如JSON格式、XML 格式等。
需要根据具体的请求类型来设置ajaxdata参数的传递方式。
4. 避免数据重复提交
在使用ajaxdata参数传递数据时,需要注意避免数据重复提交
的问题。
可以通过设置一个标识变量来判断当前是否正在进行数据提交,从而避免重复提交的情况。
总之,ajaxdata参数是使用Ajax请求时非常重要的一个参数,
需要根据具体的请求类型和数据传递方式来进行设置,以确保数据能够正确地传递和获取响应结果。
前端传对象数组Java处理一、前端传对象数组的常见方式在前端开发中,传递对象数组通常采用以下几种方式:1. JSON格式:将对象数组转换成JSON格式的字符串,通过Ajax请求或Fetch API发送给后端。
这种方式在前后端交互中非常常见,因为JSON格式简洁、易读,且支持多种编程语言。
2. FormData:将对象数组封装到一个FormData对象中,通过表单提交的方式发送给后端。
这种方式适用于表单数据的提交,特别适用于文件上传等场景。
3. URL参数:将对象数组序列化为URL参数,添加到请求的URL中。
这种方式适用于短小的数据传输,但对于较大的数据集可能会导致URL过长。
二、Java处理前端传来的对象数组在Java后端中,处理前端传来的对象数组可以采用以下几种方式:1. 使用Java Servlet:在Servlet中,可以通过request.getParameter()方法获取前端传递的对象数组。
该方法会将JSON格式的字符串转换成Java对象,然后进行处理。
2. 使用Spring框架:Spring框架提供了强大的数据处理功能,可以通过Spring MVC的注解或Controller对象来接收前端传递的对象数组。
在Controller中,可以使用@RequestBody注解将JSON格式的字符串转换成Java对象。
3. 使用Java的JSON库:Java有很多优秀的JSON库,如Jackson、Gson等,可以用于解析前端传递的JSON格式字符串,将其转换成Java对象进行处理。
三、注意事项在处理前端传来的对象数组时,需要注意以下几点:1. 数据校验:在接收到前端传递的对象数组后,需要对数据进行校验,确保数据的有效性和安全性。
可以使用Java的验证框架如Hibernate Validator等来进行数据校验。
2. 异常处理:在处理对象数组时,可能会遇到各种异常情况,如数据格式不正确、数据类型不匹配等。
JSP Ajax DWR框架概述Direct Web Remoting简称为DWR,该框架直接把JavaBean的方法公开给Jav aScript代码并自动进行Ajax的繁重工作,DWR是一个Java开源类库,专门用来开发Ajax网站。
它可以使运行在服务端的Java方法好像运行在本地浏览器中一样。
从最简单的角度来说,DWR是一个引擎,可以把服务器端Java对象的方法公开给JavaScript代码。
使用DWR可以有效地从应用程序代码中把Ajax的全部请求-响应循环消除掉。
这意味着客户端代码再也不需要直接处理XMLHttpRequest对象或者服务器的响应。
不再需要编写对象的序列化代码或者使用第三方工具才能把对象变成XML。
甚至不再需要编写Servlet代码把Ajax请求调整成对Java域对象的调用。
DWR作为Web应用程序中的Servlet部署。
把它看作一个黑盒子,这个Servle t有两个主要作用:首先,对于公开的每个类,DWR动态地生成包含在Web页面中的JavaScript。
生成的JavaScript包含存根函数,代表Java类上的对应方法并在幕后执行XMLHttpRequest。
这些请求被发送给DWR,这时它的第二个作用就是把请求翻译成服务器端Java对象上的方法调用并把方法的返回值放在Servlet响应中发送回客户端,编码成JavaScript。
DWR 还提供了帮助执行常见的用户界面任务的Jav aScript工具函数。
设计DWR的目的是,要处理将Web页面安装到后端服务上所需的所有信息管道。
它是一个Java框架,可以很轻松地将它插入到Web应用程序中,以便JavaScr ipt代码可以调用服务器上的服务。
它甚至直接与Spring Framework集成,从而允许用户直接向Web客户机公开bean。
DWR真正的巧妙之处是,在用户配置了要向客户机公开的服务之后,它使用反射来生成JavaScript对象,以便Web页面能够使用这些对象来访问该服务。
面向 Java 开发人员的 Ajax: Ajax 的Java 对象序列化在 Ajax 应用程序中序列化数据的五种途径如果您正在使用异步 JavaScript 和 XML(Ajax)进行Java™ Web 开发,那么您最关心的问题可能就是把数据从服务器传递给客户机。
在面向 Java 开发人员的 Ajax系列的第二篇文章中,Philip McCarthy 介绍了 Java 对象序列化的五种方式,并提供了选择最适合应用程序的数据格式和技术所需要的全部信息。
在这个系列的第一篇文章中,我介绍了 Ajax 的构造块:∙如何用 JavaScript XMLHttpRequest 对象从 Web 页面向服务器发送异步请求。
∙如何用 Java servlet 处理和响应请求(向客户机返回 XML 文档)。
∙如何在客户端用响应文档更新页面视图。
这一次,我将继续讨论 Ajax 开发的基础知识,但是将侧重于许多 Java Web 开发人员最关心的问题:为客户机生成数据。
多数 Java 开发人员已经把模型-视图-控制器(MVC)模式应用在他们的 Web 应用程序上。
在传统的 Web 应用程序中,视图组件由 JSP 或者其他表示技术(例如 Velocity 模板)构成。
这些表示组件动态地生成全新的 HTML 页面,替代用户以前正在查看的页面,从而更新用户界面。
但是,在 Java Web 应用程序使用Ajax UI 的情况下,基于从 XMLHttpRequest 的响应接收到的数据,JavaScript 客户端代码对于更新用户看到的内容负有最终责任。
从服务器的角度来看,视图成为它响应客户机请求而发送的数据表示。
这篇文章侧重于可以用来生成 Java 对象以数据为中心的视图的技术。
我将演示可以把 JavaBeans 变成 XML 文档的各种方法,并且讨论每种方法的优劣。
您将看到为什么 XML 并不总是最好的途径:对于简单的 Ajax 请求来说,传输纯文本更好。
最后,我将介绍 JavaScript 对象标注(JSON)。
JSON 允许数据以序列化的 JavaScript 对象图的形式传输,在客户端代码中处理序列化的JavaScript 对象图极为容易。
关于示例我将使用一个示例应用程序和几个用例来演示这里讨论的技术特性和技术。
图 1 显示的极为简单的数据模型可以表示示例用例。
这个模型代表在线商店中的顾客帐户。
顾客拥有以前订单的集合,每个订单包含几个商品。
图 1. 简单的对象模型虽然 XMLHttpRequest 对于发送数据使用的格式没有做任何限制,但是对于多数目的来说,只发送传统的表单数据是适合的,所以我的讨论集中在服务器的响应上。
响应也可以有基于文本的格式,但是正如它的名字表示的,XMLHttpRequest 具有内置的处理 XML 响应数据的能力。
这使 XML 成为 Ajax 响应的默认选择,所以我们从 XML 格式开始讨论。
回页首从 Java 类产生 XML把 Ajax 响应作为 XML 来传递有许多原因:每个支持 Ajax 的浏览器都有导航XML 文档的方法,也有许多服务器端技术可以处理 XML 数据。
通过制定一个方案,描述要交换的文档类型,在 Ajax 客户端和服务器端之间很容易定义合约,而且如果服务器端架构采用面向服务的方式,那么使用 XML 也可以允许非 Ajax 客户机使用您提供的数据。
我将考虑从 Java 对象产生 XML 数据的三种方法,并讨论每种方法的优劣。
回页首自行进行序列化首先,可以从对象图以编程的方式生成 XML。
这种方式可以简单到只是在每个JavaBean 类中实现 toXml() 方法即可。
然后就可以选择合适的 XML API,让每个 bean 提供表示自己状态的元素,并递归地对自己的成员调用对象图。
显然,这种方式无法扩展到大量的类,因为每个类都需要专门编写自己的 XML 生成代码。
从好的方面来看,这是一个实现起来简单的方式,没有额外的配置支出或者更复杂的构建过程支出,任何 JavaBean 图都可以只用几个调用就变成 XML 文档。
在本系列前一篇文章的示例代码中,我把 XML 标记字符串连接在一起,实现了 toXml() 方法。
上次我就提到过,这是个糟糕的方法,因为它把确保标记配对、实体编码等工作的负担放在每个 toXml() 方法的代码中。
在 Java 平台上有几个 XML API 可以替您做这些工作,这样您就可以把精力集中在 XML 的内容上。
清单 1 用 JDOM API 实现了在线商店示例中表示订单的类中的 toXml()(请参阅图 1)。
清单 1. Order 类的 toXml() 的 JDOM 实现public Element toXml() {Element elOrder = new Element("order");elOrder.setAttribute("id",id);elOrder.setAttribute("cost",getFormattedCost());Element elDate = new Element("date").addContent(date);elOrder.addContent(elDate);Element elItems = new Element("items");for (Iterator<Item> iter =items.iterator() ; iter.hasNext() ; ) {elItems.addContent(iter.next().toXml());}elOrder.addContent(elItems);return elOrder;}在这里可以看到用 JDOM 创建元素、使用属性和添加元素内容有多么简单。
递归地调用复合 JavaBean 的 toXml() 方法是为了取得它们子图的 Element 表示。
例如,items 元素的内容是通过调用 Order 聚合的每个 Item 对象上的 toXml() 得到的。
一旦所有的 JavaBean 都实现了 toXml() 方法,那么把任意对象图序列化成XML 文档并返回给 Ajax 客户机就简单了,如清单 2 所示。
清单 2. 从 JDOM 元素生成 XML 响应public void doGet(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException, ServletException {String custId = req.getParameter("username");Customer customer = getCustomer(custId);Element responseElem = customer.toXml();Document responseDoc = new Document(responseElem);res.setContentType("application/xml");new XMLOutputter().output(responseDoc,res.getWriter());}JDOM 再次把工作变得非常简单。
只需要在对象图返回的 XML 元素外面包装一个Document,然后用 XMLOutputter 把文档写入 servlet 响应即可。
清单 3 显示了用这种方式生成的 XML 示例,用 JDOM Format.getPrettyFormat() 对XMLOutputter 进行初始化,格式化得非常好。
在这个示例中,顾客只做了一个订单,包含两个商品。
清单 3. 代表顾客的 XML 文档<?xml version="1.0" encoding="UTF-8"?><customer username="jimmy66"><realname>James Hyrax</realname><orders><order id="o-11123" cost="$349.98"><date>08-26-2005</date><items><item id="i-55768"><name>Oolong 512MB CF Card</name><description>512 Megabyte Type 1 CompactFlash card.Manufactured by Oolong Industries</description><price>$49.99</price></item><item id="i-74491"><name>Fujak Superpix72 Camera</name><description>7.2 Megapixel digital camera featuring six shooting modes and 3x optical zoom. Silver.</description> <price>$299.99</price></item></items></order></orders></customer>自行序列化的不足有趣的是,清单 3 中的代码展示了让 JavaBean 把自己序列化为 XML 的一个主要不足。
假设要用这个文档表示顾客的订单历史视图。
在这种情况下,不太可能要显示每个历史订单中每个商品的完整说明,或者告诉顾客他或她自己的姓名。
但是如果应用程序有一个 ProductSearch 类,它就是以 Item bean 列表的形式返回搜索结果,那么在 Item 的 XML 表示中包含说明可能会有帮助。
而且,Item 类上代表当前库存水平的额外字段,在产品搜索视图中可能就是需要显示的有用信息。
但是,不管当前的库存水平是否与当前情况相关(比如对顾客的订单历史来说),这个字段都会从包含 Item 的任何对象图中序列化出来。