0%

1
2
3
4
5
6
7
8
9
10
11
<update id=“updateAuthor”>
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id=“deleteAuthor”>
delete from Author where id = #{id}
</delete>

说明:flushCache=”true”为更新二级缓存,timeout=“20”超时连接

1
2
3
4
5
6
7
8
9
10
11
12
13
<update
id=“updateAuthor”
parameterType=“domain.blog.Author”
flushCache=”true
statementType=“PREPARED”
timeout=“20”>

<delete
id=“deleteAuthor”
parameterType=“domain.blog.Author”
flushCache=”true
statementType=“PREPARED”
timeout=“20”>

这里只是给出xml配置文件,测试文件就不写了。下面说的是配置文件都是数据库和实体类一样的情况,如果主键自增不一样,参考情况2.
情况1:

1
2
3
4
<insert id=“insertAuthor”>
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>

情况2:
插入有主键id的情况:

1
2
3
4
5
<insert id=“insertAuthor” useGeneratedKeys=”true”
keyProperty=“id”>
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MybatisUtils{
private SqlsessionFactory sqlsessionFactory;
public Sqlsession getSqlsession(){
try{
InputStream inputStream = Resources.getResourceAsStream(“mybaits.xml”);
if(sqlSessionFactory==null){
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
return sqlSessionFactory.openSession();
}catch(Exceprion e){
e.printStackTrace();
}
return null;
}
}

在传统的配置下,我们一般使用xml配置来完成bean的注入,例如

1
<bean id=”beanService” class=”com.bean.service.beanServiceImpl”/>

现在利用@javaConfig就能完成整个配置。下面是一个例子。

例子一:
1.Helloeorld类

1
2
3
public interface Helloeorld {
void printHelloWorld(String msg);
}

2.HelloworldImpl类

1
2
3
4
5
6
public class HelloworldImpl implements Helloeorld{
@Override
public void printHelloWorld(String msg) {
System.out.println(“Hello : “ + msg);
}
}
  1. TestConfig
1
2
3
4
5
6
7
@Configuration
public class TestConfig {
@Bean(name=“helloeorld”)
public Helloeorld getHello(){
return new HelloworldImpl();
}
}

4.测试类

1
2
3
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
Helloeorld obj = (Helloeorld) context.getBean(“helloeorld”);
obj.printHelloWorld(“Spring Java Config”);

例子2:
@Import
在我们运用传统xml方式进行配置Spring时,可以通过如下方式加载多个配置文件:

1、CustomerBo类

1
2
3
4
5
public class CustomerBo {
public void printMsg(String msg) {
System.out.println(“CustomerBo : “ + msg);
}
}

2.CustomerConfig类

1
2
3
4
5
6
7
@Configuration
public class CustomerConfig {
@Bean(name=“customer”)
public CustomerBo customerBo(){
return new CustomerBo();
}
}

3.AppConfig类

1
2
3
4
5
6
7
8
@Configuration
@Import({ CustomerConfig.class/* 这里写的多个配置SchedulerConfig.class */})
public class AppConfig {
}
ApplicationContext context = new AnnotationConfigApplicationContext(
AppConfig.class);
CustomerBo customer = (CustomerBo) context.getBean(“customer”);
customer.printMsg(“Hello 11”);

1.拼装成一个对象

1
2
3
4
var json2={};
json2.user_guid=597;
json2.p_type_id=2;
`

2.拼接成一个list

1
2
3
4
5
6
7
8
var json4=[];
for(var a=0;a<server_data.treeroot[i].des.length;a++){
json3.sn_index=”000000″;
json3.p_type_id=1;
json3.user_guid=0;
json3.warranty_status=”10″;
json4.push(json3); //推入法
}

3.转化成字符串给后台

1
var serdate=JSON.stringify(json4);

4.后台处理后返回的

1
var cargodata_in =  eval(‘(‘ + result + ‘)’);

environments主要是用于配置多个数据源,可以是mysql,也可以是oracle,还可以是plsql.

下面的就是增对下面的一个模板,可以配置不同的数据库

配置mybaits.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version=“1.0” encoding=“UTF-8” ?><!DOCTYPE configuration
PUBLIC “-//mybatis.org//DTD Config 3.0//EN”
“http://mybatis.org/dtd/mybatis-3-config.dtd”>
<configuration>
<environments default=”development”> //这里是下面的id名字
<environment id=“development”>
<transactionManager type=“JDBC”/>
<dataSource type=“POOLED”>
<property name=“driver” value=“${driver}”/>
<property name=“url” value=“${url}”/>
<property name=“username” value=“${username}”/>
<property name=“password” value=“${password}”/>
</dataSource>
</environment>
<environment id=”development1″>
<transactionManager type=”JDBC”/>
<dataSource type=”POOLED”>
<property name=”driver” value=”${driver}”/>
<property name=”url” value=”${url}”/>
<property name=”username” value=”${username}”/>
<property name=”password” value=”${password}”/>
</dataSource>
</environment>
<environment id=”development2″>
<transactionManager type=”JDBC”/>
<dataSource type=”POOLED”>
<property name=”driver” value=”${driver}”/>
<property name=”url” value=”${url}”/>
<property name=”username” value=”${username}”/>
<property name=”password” value=”${password}”/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource=“org/mybatis/example/studentMapper.xml”/>
</mappers>
</configuration>

@Service服务层组件,用于标注业务层组件,表示定义一个bean,自动根据bean的类名实例化一个首写字母为小写的bean,例如Chinese实例化为chinese,如果需要自己改名字则:@Service(“你自己改的bean名”)。
@Controller用于标注控制层组件(如struts中的action)
@Repository持久层组件,用于标注数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

可以使用以下方式指定初始化方法和销毁方法(方法名任意):

1
2
3
4
5
6
@PostConstruct 
public void init() {
}
@PreDestroy
public void destory() {
}

注明:spring结合springmvc完成以上的建立

1.安装maven

1
2
3
4
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version></dependency>

注意:加一个logger 这个参考官方文档

2.创建一个实体类,和dao层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class类  student
private int id;
private String name;
private String grade;
dao层
studentDao层
insertStudent(Student student);
updateStudent(Student student);
delStudent(Student student);
selectStudent(int id); //只测试查询,此列子
dao层的xml
studentDao层xml
<?xml version=“1.0” encoding=“UTF-8” ?><!DOCTYPE mapper
PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN”
“http://mybatis.org/dtd/mybatis-3-mapper.dtd”>
<mapper namespace=“org.mybatis.example.studentDao“>
<select id=“selectStudent“ resultType=“student“>
select * from student where id = #{id}
</select>
</mapper>

配置mybaits.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version=“1.0” encoding=“UTF-8” ?><!DOCTYPE configuration
PUBLIC “-//mybatis.org//DTD Config 3.0//EN”
“http://mybatis.org/dtd/mybatis-3-config.dtd”>
<configuration>
<environments default=“development”>
<environment id=“development”>
<transactionManager type=“JDBC”/>
<dataSource type=“POOLED”>
<property name=“driver” value=“${driver}”/>
<property name=“url” value=“${url}”/>
<property name=“username” value=“${username}”/>
<property name=“password” value=“${password}”/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource=“org/mybatis/example/studentMapper.xml”/>
</mappers>
</configuration>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
@test
public void test(){
String resource = “org/mybatis/example/mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
student student= session.selectStudent(1);
syso(student);
} finally {
session.close();
}
}

1.在jar加入sring-aop.jar加入进来,

2.在xml配置

1
2
3
4
5
6
7
xmlns:aop=”http://www.springframework.org/schema/aop”; 
xmlns:context=”http://www.springframework.org/schema/context”;
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

3.建立一个model层,如下图,其中testService4是测试类。

4.student类说明

1
2
3
4
5
6
7
8
9
10
@Component
public class student {
private int id;
@Value(“张三”)
private String name;
@Autowired // byType注入,根据is-a的关系
//@Qualifier
//byName注入需要@Autowired和@Qualifier一起配合使用
private School school;
}

5.在xml配置

1
<context:component-scan base-package=“com.bean.service4”/>

控制反转主要是由代码控制的对象将调用权转给容器,通过容器来实现对象的装配和管理。控制反转重要的是对象控制权的反转,从程序代码本身反转到了外部容器。

spring的ioc主要是依赖注入和依赖查找。依赖注入是最优秀的解耦方式。

依赖注入的三种方式:

1.构造器注入

1
2
3
<bean id=“school1” class=“com.bean.service3.School”>
<property name=“id” value=“1”/>
</bean>

2.set值注入

1
2
3
 <bean id=“school1” class=“com.bean.service3.School”>
<property name=“scools” ref=“z这里是对象的名字bean id”></property>
</bean>

3.接口注入

方法注入 init-method=”dopost”,类似这样的

匿名bean列子:

1
2
3
4
<bean class=“com.bean.service3.School” autowire=“byName”>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>

内部匿名例子:

1
2
3
4
5
6
public class Some {
private School schools;
}
<bean id=”sss” class=“com.bean.service3.Some“>
<bean class=“com.bean.service3.School”/>
</bean>

同类抽象:
由上面的例子可知重复代码过多,要求封装:

1
2
3
4
5
6
7
8
9
10
<bean class=“com.bean.service3.student” >
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
<property name=“school” value=“计算机”/>
</bean>
<bean class=“com.bean.service3.student” >
<property name=“id” value=“2”/>
<property name=“name” value=“张三2”/>
<property name=“school” value=“计算机”/>
</bean>

改为:

1
2
3
4
5
6
7
8
9
10
11
12
<bean  id=”ss” class=“com.bean.service3.student” abstract=“true”>
<property name=“school” value=“计算机”/>
</bean>
<bean id=”ss1″ class=“com.bean.service3.student”
parent=“ss“>
<property name=“id” value=“2”/>
<property name=“name” value=“张三2”/>
</bean>
<bean id=”ss2″ class=“com.bean.service3.student” parent=“ss“>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>

异类抽象:

1
2
3
4
5
6
7
8
9
10
11
12
<bean  id=”ss” abstract=“true”>
<property name=“school” value=“计算机”/>
</bean>
<bean id=”ss1″ class=“com.bean.service3.student“
parent=“ss“>
<property name=“id” value=“2”/>
<property name=“name” value=“张三2”/>
</bean>
<bean id=”ss2″ class=“com.bean.service3.teacher“ parent=“ss“>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>

js获取URL中的一些参数的意思
location对象 含有当前URL的信息. 属性 href 整个URL字符串.
protocol 含有URL第一部分的字符串,如http:
host 包含有URL中主机名:端口号部分的字符串.如//www.cenpok.net/server/
hostname 包含URL中主机名的字符串.如http://www.cenpok.net ;
port 包含URL中可能存在的端口号字符串.
pathname URL中”/”以后的部分.如~list/index.htm
hash “#”号(CGI参数)之后的字符串.
search “?”号(CGI参数)之后的字符串.

第一种:只适用于/User/vip_card_manager?useless=219

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function UrlSearch() {
var name, value;
var str = location.href; //取得整个地址栏
var num = str.indexOf(“ ? ”)
str = str.substr(num + 1); //取得所有参数 stringvar.substr(start [, length ]
var arr = str.split(“ & ”); //各个参数放到数组里 console.log(arr)
for (var i = 0; i < arr.length; i++) {
num = arr[i].indexOf(“ = ”);
if (num > 0) {
name = arr[i].substring(0, num);
value = arr[i].substr(num + 1);
this[name] = value;
}
}
}

第二种:
适应以下两种模式,来获取url参数值:
/User/vip_card_manager/useless/219/id/18
/User/vip_card_manager?useless=219&id=18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log(getQueryString(“useless”));

function getQueryString(name) {
var reg = new RegExp(“( ^ | & )” + name + “ = ([ ^ & ] * )( & | $)”, “i”);
var reg_rewrite = new RegExp("( ^ | /)” + name + “/([ ^ /]*)(/ | $)”, “i”);")
var r = window.location.search.substr(1).match(reg);
var q = window.location.pathname.substr(1).match(reg_rewrite);
if (r != null) {
return unescape(r[2]);
} else if (q != null) {
return unescape(q[2]);
} else {
return null;
}
}

第三种:自己没有用过,是同事给的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 获取指定的URL参数值
* URL:http://www.quwan.com/index?name=tyler
* 参数:paramName URL参数
* 调用方法:getParam(“name”)
* 返回值:tyler
*/function getParam(paramName) {
paramValue = “”, isFound = !1;
if (this.location.search.indexOf(“?”) == 0 && this.location.search.indexOf(“=”) > 1) {
arrSource = unescape(this.location.search).substring(1, this.location.search.length).split(“&”), i = 0;
while (i < arrSource.length && !isFound) arrSource[i].indexOf(“=”) > 0 && arrSource[i].split(“=”)[0].toLowerCase() == paramName.toLowerCase() && (paramValue = arrSource[i].split(“=”)[1], isFound = !0), i++
}
return paramValue == “” && (paramValue = null), paramValue
}
//设置或获取对象指定的文件名或路径。
alert(window.location.pathname);
//设置或获取整个 URL 为字符串。
alert(window.location.href);
//设置或获取与 URL 关联的端口号码。
alert(window.location.port);
//设置或获取 URL 的协议部分。
alert(window.location.protocol);
//设置或获取 href 属性中在井号“#”后面的分段。
alert(window.location.hash);
//设置或获取 location 或 URL 的 hostname 和 port 号码。
alert(window.location.host);
//设置或获取 href 属性中跟在问号后面的部分。
alert(window.location.search);

1.数据有对象,有list
数据1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var xml_data = [{
"name": "scene_img_3773_panorama",
"sceneAttr": {
"view": {
"hlookat": "1.008",
"vlookat": "-4.579"
},
"hotspots": [{
"ath": "-4.124",
"atv": "4.146",
"linkedscene": "scene_img_7994_panorama",
"name": "spot1"
},
{
"ath": "-4.124",
"atv": "8.146",
"name": "spot2"
}
]
}
},
{
"name": "scene_img_7994_panorama",
"secenAttr": {
"view": {
"hlookat": "-3.296",
"vlookat": "2.283"
},
"hotspots": [{
"ath": "-19.613",
"atv": "11.459",
"linkedscene": "scene_img_7984_panorama",
"name": "spot1"
},
{
"ath": "-75.014",
"atv": "8.862",
"linkedscene": "scene_img_3773_panorama",
"name": "spot2"
}
]
}
}
]

数据2:

1
var json={ "addr_num":"runoob", "user_guid":10000};

2.ajax调用

1
2
3
4
5
6
7
8
9
10
11
$.ajax({
type: ”POST”,
url: ” /panorama/saveScene”,
processData: false,
contentType: “application / json;charset = utf - 8”, //这个是发送信息至服务器时内容编码类型
dataType: “json”,
data: JSON.stringify(xml_data), //这里必须将对象转成string类型,否则将掉入无线的大坑中。。。
success: function(msg) {
alert(msg);
}
});

3.后台采用的是spring mvc来接收的,后台接收的方式也分为了两种,一种是用@RequestBody来处理的,一种是用common io的工具类IOUtils来读取二进制流将其解析成一个字符串,之后再用fastjson来将一个Json字符串转成java对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Controller  
@RequestMapping(“/panorama”)
public class PanoController extends BaseController {
/**
* 用@RequestBody的方式来将json反序列化成list<Scene>对象
* @param scene
* @return
*/
@RequestMapping(value = “saveScene”,method = RequestMethod.POST)
@ResponseBody
public List<Scene> saveScene(@RequestBody List<Scene> scene,或者是对象,@RequestBody Address user){
System.out.println(“JSONTOJAVAOBJ===================”+scene.size());
return scene;
}
//io流读取二进制json对象
public List<Scene> saveScene(HttpServletRequest request) throws IOException{
String jsonStr = IOUtils.toString(request.getInputStream(),”UTF-8″);
System.out.println(“JSONTOJAVAOBJ============”+JSON.parseObject(jsonStr,new TypeReference<List<Scene>>(){}));
return null;
}
}

1.byName就是通过Bean的id或者name,byType就是按Bean的Class的类型。

下面的例子就是一个时候才可以用

1
2
3
4
<bean id=“school1” class=“com.bean.service3.School” autowire=“byName”>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>

2.如果是两个,可能会出现以下情况

1
2
3
4
5
6
7
8
<bean id=“school1” class=“com.bean.service3.School” autowire=“byType“>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>
<bean id=“school2” class=“com.bean.service3.School” autowire=“byType“>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>

结果:报错。因为他们的class是一样的。
说明:byType不仅仅是以上的关系,还有is-a都不行。因为is-a是继承关系。

1
2
3
4
5
6
7
public class Some {
private School[] schools;
private List<String> myList;
private Set<String> mySet;
private Map<String,Object> map;
private Properties mypros;
}

xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<bean id=“school1” class=“com.bean.service3.School”>
<property name=“id” value=“1”/>
<property name=“name” value=“张三”/>
</bean>
<bean id=“school2” class=“com.bean.service3.School”>
<property name=“id” value=“2”/>
<property name=“name” value=“李四”/>
</bean>
<bean id=“some” class=“com.bean.service3.Some”>
<property name=“schools”>
<array>
<ref bean=“school1”/>
<ref bean=“school2”/>
</array>
</property>
//改写:<property name=“myList” value=”李四,张三”>
<property name=“mySet” value=”李四,张三”>
<property name=“myarray” value=”李四,张三”> private String[] myarray;
//改写结束
<property name=“myList”>
<list>
<value>张三</value>
<value>李四</value>
</list>
</property>
<property name=“mySet”>
<set>
<value>张三</value>
<value>李四</value>
</set>
</property>
<property name=“map”>
<map>
<entry key=“qq” value=“1234567”></entry>
<entry key=“weixin” value=“1234567”></entry>
</map>
</property>
<property name=“mypros”>
<props>
<prop key=“地址”>111</prop>
<prop key=“地址1”>222</prop>
</props>
</property>
</bean>

测试方法如下:

1
2
3
4
5
@Test
public void test2() {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“ApplicationContext.xml”);
beanService beanService= (com.bean.service2.beanService) applicationContext.getBean(“beanService”);
}

1.调用无参的构造器,创建实例对象。

1
2
3
4
5
6
public class beanServiceImpl implements beanService{
public beanServiceImpl() {
super();
System.out.println(“1:初始化完成”);
}
}

2.调用参数的setter,为属性注入值。

1
2
3
<bean id=“beanService” class=“com.bean.service2.beanServiceImpl”>
<property name=“dao” value=“aaa”></property>
</bean>
1
2
3
4
5
private String dao;
public void setDao(String dao) {
this.dao = dao;
System.out.println(“2:set属性方法”);
}

3.若bean实现了beanNameAware接口,则会执行接口方法setBeanName(String beanId),使bean类可以获取其在容器中的id名称。

1
public class beanServiceImpl implements beanService,BeanNameAware

继承了BeanNameAware的默认方法

1
2
3
4
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println(“3:BeanNameAware的setBeanName,其中实现了接口名:”+name);
}

4.若bean实现了beanFactoryAware接口,则会执行接口方法setBeanFactory(BeanFactrory factory),使bean类可以获取到beanFactory对象。

1
public class beanServiceImpl implements beanService,BeanNameAware,BeanFactoryAware

继承了BeanFactoryAware的默认方法

1
2
3
4
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println(“4:获取到beanFactory的容器”);
}

5.若定义并注册了bean后处理器beanpostProcessor,则执行接口方法postProcessBeforeInitialization();

创建beanpostprocessor实现BeanPostProcessor

1
2
3
4
5
6
public class beanpostprocessor implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“5:获取到BeanPostProcessor的beafore方法”);
return null;
}
}

6.若bean实现initializingBean接口,则执行接口方法afterPropertiesSet().该方法在bean的所有属性的set方法执行完毕后执行,是bean初始化的标志,实例化结束。

1
2
3
4
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println(“6:初始化结束”);
}

7.若设置了init-method方法,则执行。

1
2
3
<bean id=“beanService2” class=“com.bean.service2.beanServiceImpl” init-method=“doAfter”>
<property name=“dao” value=“aaa”></property>
</bean>

8若定义并注册了bean后处理器beanpostProcessor,则执行接口方法postProcessAfterInitialization();

1
2
3
4
5
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println(“8:获取到BeanPostProcessor的After方法”);
return bean;
}

9.执行业务方法。

1
2
3
4
public void dotest();
public void dotest() {
System.out.println(“9:主方法”);
}

10.若bean实现了DisposableBean接口,则执行接口方法destroy().

1
2
3
4
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println(“10:准备进行销毁工作”);
}

11.若设置了destrory-method方法,则执行。

1
2
3
4
5
6
7
<bean id=“beanService2” class=“com.bean.service2.beanServiceImpl” init-method=“doAfter” destroy-method=“doDestroy”>
<property name=“dao” value=“aaa”></property>
</bean>
public void doDestroy() throws Exception {
// TODO Auto-generated method stub
System.out.println(“11:进行销毁工作”);
}

GSON是谷歌提供的开源库,用来解析Json格式的数据,非常好用。如果要使用GSON的话,则要先下载gson-2.2.4.jar这个文件,如果是在Android项目中使用,则在Android项目的libs目录下添加这个文件即可;如果是在Java项目中,则把gson-2.2.4.jar先添加到当前项目的任意一个包中,然后右键点击这个jar包 -> 构建路径 -> 添加至构建路径。这样准备工作就做好了。

单条无嵌套Json数据的解析

比如有如下Json数据:

1
{“name”:”John”, “age”:20}  //也可以用单引号,写成:{‘name’:’John’, ‘age’:20}

解析该数据步骤如下:

1、定义Person类:

1
2
3
4
5
  public class Person{
private String name; //属性都定义成String类型,并且属性名要和Json数据中的键值对的键名完全一样
private String age;
//提供所有属性的getter和setter方法
}

2、创建GSON对象并解析:

1
2
3
4
5
String jsonData = “{\”name\”:\”John\”, \”age\”:20}”;  //注:这里也可以不使用转义字符,而用单引号:String jsonData = “{‘name’:’John’, ‘age’:20}”;

Gson gson = new Gson();

Person person = gson.fromJson(jsonData,Person.class);

3、然后使用Person对象的getter方法就可以获取到数据了。

4、扩展:考虑到Json数据的不同,那么解析Json的时候所用的类也可能不同,比如这里用的是Person,如果解析其他数据可能用的又是Dog、Cat…所以考虑将用GSON解析的步骤封装,并提供泛型参数,示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import com.google.gson.Gson;

/**

* 用GSON解析单条Json数据

*

*/

public class GsonTest1 {

public static void main(String[] args) {

String jsonData = “{‘name’:’John’, ‘age’:20}”;

Person person = GsonUtil.parseJsonWithGson(jsonData, Person.class);

System.out.println(person.getName() + “,” + person.getAge());

}

}

/*

* 封装的GSON解析工具类,提供泛型参数

*/

class GsonUtil {

//将Json数据解析成相应的映射对象

public static <T> T parseJsonWithGson(String jsonData, Class<T> type) {

Gson gson = new Gson();

T result = gson.fromJson(jsonData, type);

return result;

}

}

class Person {

private String name;

private String age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getAge() {

return age;

}

public void setAge(String age) {

this.age = age;

}


}

输出结果:

John,20

单条有嵌套的Json数据解析

比如有如下Json数据:

1
{“name”:”John”, “age”:20,”grade”:{“course”:”English”,”score”:100,”level”:”A”}}

对这样的数据就要用内部类的来解决了。解析步骤如下:

1、定义Student类:

1
2
3
4
5
6
7
8
9
class Student {
private String name;
private String age;
private Grade grade;
public class Grade { // 内部类要定义成public的
private String course;
private String score;
private String level;
}

2、使用(一)中封装的GsonUtil工具类进行解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class GsonTest1 {
public static void main(String[] args) {
String jsonData = “{‘name’:’John’, ‘age’:20,’grade’:{‘course’:’English’,’score’:100,’level’:’A’}}”;
Student student = GsonUtil.parseJsonWithGson(jsonData, Student.class);
System.out.println(student);
}
}
/*
* 封装的GSON解析工具类,提供泛型参数
*/
class GsonUtil {
// 将Json数据解析成相应的映射对象
public static <T> T parseJsonWithGson(String jsonData, Class<T> type) {
Gson gson = new Gson();
T result = gson.fromJson(jsonData, type);
return result;
}
}
Student:[name = John, age = 20, grade = Grade:[course = English, score = 100, level = A]]

解析Json数组(多条Json数据)

比如有如下Json数据:

1
[{‘name’:’John’, ‘grade’:[{‘course’:’English’,’score’:100},{‘course’:’Math’,’score’:78}]}, {‘name’:’Tom’, ‘grade’:[{‘course’:’English’,’score’:86},{‘course’:’Math’,’score’:90}]}]   //注:Json数组最外层一定要加”[]”

如何处理这样的数据呢?就要用到List。步骤如下:

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.lang.reflect.Type;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* 用GSON解析Json数组
*/
public class GsonTest {
public static void main(String[] args) {
// Json数组最外层要加”[]”
String jsonData = “[{‘name’:’John’, ‘grade’:[{‘course’:’English’,’score’:100},{‘course’:’Math’,’score’:78}]},{‘name’:’Tom’, ‘grade’:[{‘course’:’English’,’score’:86},{‘course’:’Math’,’score’:90}]}]”;
List<Student> students = GsonUtil.parseJsonArrayWithGson(jsonData,
Student.class);
System.out.println(students);
}
}
/*
* 封装的GSON解析工具类,提供泛型参数
*/
class GsonUtil {
// 将Json数据解析成相应的映射对象
public static <T> T parseJsonWithGson(String jsonData, Class<T> type) {
Gson gson = new Gson();
T result = gson.fromJson(jsonData, type);
return result;
}
// 将Json数组解析成相应的映射对象列表
public static <T> List<T> parseJsonArrayWithGson(String jsonData,
Class<T> type) {
Gson gson = new Gson();
List<T> result = gson.fromJson(jsonData, new TypeToken<List<T>>() {
}.getType());
return result;
}
}
class Student {
private String name;
private List<Grade> grade; // 因为grade是个数组,所以要定义成List

1.创建订单表

2.创建订单详情表

3,在创建订单表时,创建订单表的一样的订单状态
4.在更新订单表时,更新订单表的一样的订单状态
5.在删除订单表时,删除订单表的一样的订单状态
代码如下:
1.创建订单:

1
2
3
4
5
6
7
8
9
delimiter $$
create trigger crea_order_satus
AFTER INSERT ON t_order
FOR EACH ROW
begin
insert into order_details(order_status,order_id) values(new.ostatus,new.order_oid);
end
$$
delimiter ;

2.更新订单

1
2
3
4
5
6
7
8
9
10
drop trigger if exists up_order_satus;
delimiter $$
create trigger up_order_satus
after UPDATE ON t_order
FOR EACH ROW
begin
update order_details set order_details.order_status=new.ostatus where order_details.order_id=old.order_oid;
end
$$
delimiter ;

3.删除订单

1
2
3
4
5
6
7
8
9
10
drop trigger if exists del_order_satus;
delimiter $$
create trigger del_order_satus
after DELETE ON t_order
FOR EACH ROW
begin
DELETE from order_details where order_details.order_id=old.order_oid;
end
$$
delimiter ;

handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)

A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;

B、处理request header部分的注解: @RequestHeader, @CookieValue;

C、处理request body部分的注解:@RequestParam, @RequestBody;

D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

@PathVariable

当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。

示例代码:

1
2
3
4
5
6
7
8
9
@Controller  
@RequestMapping(“/owners/{ownerId}”)
public class RelativePathUriTemplateController {

@RequestMapping(“/pets/{petId}”)
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}

上面代码把URI template 中变量 ownerId的值和petId的值,绑定到方法的参数上。若方法参数名称和需要绑定的uri template中变量名称不一致,需要在@PathVariable(“name”)指定uri template中的名称。

@RequestHeader、@CookieValue

@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
示例代码:
这是一个Request 的header部分:

1
2
3
4
5
6
Host                    localhost:8080  
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
1
2
3
4
5
6
@RequestMapping(“/displayHeaderInfo.do”)  
public void displayHeaderInfo(@RequestHeader(“Accept-Encoding”) String encoding,
@RequestHeader(“Keep-Alive”) long keepAlive) {
//…

}

上面的代码,把request header部分的 Accept-Encoding的值,绑定到参数encoding上了, Keep-Alive header的值绑定到参数keepAlive上。
@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。
例如有如下Cookie值:

1
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

参数绑定的代码:

1
2
3
4
5
6
@RequestMapping(“/displayHeaderInfo.do”)  
public void displayHeaderInfo(@CookieValue(“JSESSIONID”) String cookie) {

//…

}

@RequestParam, @RequestBody

@RequestParam

  • 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String–> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;
  • 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;
  • 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller  
@RequestMapping(“/pets”)
@SessionAttributes(“pet”)
public class EditPetForm {

// …

@RequestMapping(method = RequestMethod.GET)
public String setupForm(@RequestParam(“petId”) int petId, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute(“pet”, pet);
return “petForm”;
}

// …

@RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。
因为配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里,这种情况在某些特殊需求下使用,详情查看FormHttpMessageConverter api;

示例代码:

1
2
3
4
@RequestMapping(value = “/something”, method = RequestMethod.PUT)  
public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}

@SessionAttributes, @ModelAttribute

@SessionAttributes:
该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。
该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象;

示例代码:

1
2
3
4
5
6
@Controller  
@RequestMapping(“/editPet.do”)
@SessionAttributes(“pet”)
public class EditPetForm {
// …
}

@ModelAttribute
该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;
用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:

  • @SessionAttributes 启用的attribute 对象上;
  • @ModelAttribute 用于方法上时指定的model对象;
  • 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean中。

用到方法上@ModelAttribute的示例代码:

1
2
3
4
5
6
7
8
// Add one attribute  
// The return value of the method is added to the model under the name “account”
// You can customize the name via @ModelAttribute(“myAccount”)

@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}

这种方式实际的效果就是在调用@RequestMapping的方法之前,为request对象的model里put(“account”, Account);
用在参数上的@ModelAttribute示例代码:

1
2
3
4
@RequestMapping(value=“/owners/{ownerId}/pets/{petId}/edit”, method = RequestMethod.POST)  
public String processSubmit(@ModelAttribute Pet pet) {

}

首先查询 @SessionAttributes有无绑定的Pet对象,若没有则查询@ModelAttribute方法层面上是否绑定了Pet对象,若没有则将URI template中的值按对应的名称绑定到Pet对象的各属性上。

@RequestBody @ResponseBody

@RequestBody

作用:

  • 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
  • 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。

使用时机:

  • GET、POST方式提时, 根据request header Content-Type的值来判断:

    • application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);
    • multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
    • 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
  • PUT方式提交时, 根据request header Content-Type的值来判断:

    • application/x-www-form-urlencoded, 必须;
    • multipart/form-data, 不能处理;
    • 其他格式, 必须;

说明:request的body部分的数据编码格式由header部分的Content-Type指定;

@ResponseBody

作用:

该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

使用时机:
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 实现远程服务调用

httpinvoker方式 服务器客户端都是spring时推荐这种方式

服务端 必须要实现 bean实体类 service接口类 serviceImpl服务实现类

客户端只需拷贝 bean 实体类 service接口类(注意 ,客户端 bean,service类要和服务端bean,service类包路径相同,比如都是

com.hlzt.csm.model.DataPlatFormCountBean,不然会报找不到类,而且 bean要序列化 public class DataPlatFormCount implements Serializable;
如果服务端有 序列化的private static final long serialVersionUID = 1L号,客户端也必须有,如果服务端没有此id,客户端也不要有此id,不然会出错。service类的包路径也要相同,最好服务端写好后直接把实体类和service服务接口类打包,拷贝到客户端,以免造成两端不同。

服务器端要在spring-mvc配置文件 spring-mvc-servlet.xml中加入以下(注意是在spring-mvc的配置文件中,不是spring的配置文件)

1
2
3
4
5
6
7
8
9
10
<beans xmlns=“http://www.springframework.org/schema/beans”  
xmlns:context=“http://www.springframework.org/schema/context”
xmlns:mvc=“http://www.springframework.org/schema/mvc” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd”>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    <!– 启用spring mvc 注解 –>  
<mvc:annotation-driven />
<!– 设置使用注解的类扫描的包 –>
<context:component-scan base-package=“com.hlzt.csm” />



<!–不被spring mvc过滤器 DispatcherServlet,前提文件不能放在WEB-INF下,引用必须使用jstlc标签–>
<mvc:default-servlet-handler/>

<!–指定自定义 <mvc:default-servlet-handler default-servlet-name=”StaticServlet”/> –>

<!– 指定静态文件的路径映射 可以访问 WEB-INF下 访问直接src=static1/js/1.js–>
<!– <mvc:resources mapping=”/static1/**” location=”/WEB-INF/static/”/> –>

<!– 对转向页面的路径解析。prefix:前缀, suffix:后缀 –>
<!– <bean
class=“org.springframework.web.servlet.view.InternalResourceViewResolver”>
<property name=“prefix”>
<value>/</value>
</property>
<property name=“suffix”>
<value>.jsp</value>
</property>
</bean> —>

<!– 下面是需要加入的–>
<!– 下面是需要加入的 ,id要和SimpleUrlHandlerMapping中的 propkey相同,name要和rop key对应的value相同,否则会导致找不到请求的地址–>
<bean id=“csmDataCountService” name=“/CsmDataCountSer.shtm” class=“org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter”>
<property name=“service” ref=“csmDataCountSerImpl”></property>
<property name=“serviceInterface” value=“com.hlzt.csm.service.CsmDataCountSer”>
</property>
</bean>
<!– 远程服务的URLkey值表示客户端请求的地址–>
<bean
class=“org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
<property name=“mappings”>
<props>
<prop key=“/CsmDataCountSer.shtm”>csmDataCountService</prop>
</props>
</property>
</bean>


</beans>

服务端 web.xml的配置

客户端配置
客户端 spring的xml文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version=“1.0” encoding=“UTF-8”?>  
<beans xmlns=“http://www.springframework.org/schema/beans” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=“http://www.springframework.org/schema/aop” xmlns:context=“http://www.springframework.org/schema/context”
xmlns:p=“http://www.springframework.org/schema/p”
xsi:schemaLocation=
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
default-lazy-init=“true”>

<bean id=“csmDataCountSer” name=“csmDataCountSer” class=“org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean”>
<property name=“serviceUrl”>
<value>http://localhost:80/chat/CsmDataCountSer.shtm</value>
</property>
<property name=“serviceInterface”>
<value>com.hlzt.csm.service.CsmDataCountSer</value>
</property>
</bean>

</beans>

注意的是 id=”csmDataCountSer” 本人测试结果是 此实例不能在java中通过 rource 或Autowired自动注入,而要通过手工载入方式获得
ApplicationContext context =new ClassPathXmlApplicationContext(“/spring/spring-remote.xml”);
CsmDataCountSer csmDataCountSer=(CsmDataCountSer)context.getBean(“csmDataCountSer”);

spring RMI方式

首先看下实例程序目录结构:

Spring中发布RMI服务(ZLv_RMIServerWithSpring):

(1) 定义接口MessageProvider及接口中供调用的方法(MessageProvider.java):

1
2
3
4
package org.thera.rmi.service;
public interface MessageProvider {
public String queryForMessage(String name);
}

(2) 实现MessageProvider接口(MessageProviderImpl.java):

1
2
3
4
5
6
7
package org.thera.rmi.service;
public class MessageProviderImpl implements MessageProvider {
@Override
public String queryForMessage(String name) {
return "Hello, " + name;
}
}

做好了上述准备,下面我们就可以通过Spring中集成RMI,方便的发布RMI服务端

(3) Spring配置文件作如下配置(context.xml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注入要发布的RMI服务类 -->
<bean id="messageService" class="org.thera.rmi.service.MessageProviderImpl"></bean>
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- RMI服务名称,可自定义服务名称 -->
<property name="serviceName" value="MessageService" />
<!-- 导出实体 -->
<property name="service" ref="messageService" />
<!-- 导出接口 -->
<property name="serviceInterface" value="org.thera.rmi.service.MessageProvider" />
<!-- spring默认使用1099端口 -->
<property name="registryPort" value="1199" />
</bean>
</beans>

(4) 加载Spring容器,发布RMI服务(Main.java):

1
2
3
4
5
6
7
8
9
package org.thera.rmi.service.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/context.xml");
System.out.println("已成功发布RMI服务类");
}
}

到这里,RMI的服务端已经发布成功,运行结果如下截图:

Spring中客户端调用RMI服务(ZLv_RMIClientWithSpring):

(1) 移植服务端服务接口文件MessageProvider.java;

(2) Spring配置文件做如下配置:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://192.168.1.100:1199/MessageService" />
<property name="serviceInterface" value="org.thera.rmi.service.MessageProvider" />
</bean>
</beans>

(3) 加载Spring容器,调用RMI服务端(Main.java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package org.thera.rmi.service.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.thera.rmi.service.MessageProvider;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/context.xml");
System.out.println("加载Spring容器,并初始化RMI客户端");
MessageProvider client = (MessageProvider)ctx.getBean("messageService");
String temp = client.queryForMessage("LvSantorini");

System.out.println("返回结果: " + temp);
}
}

运行Main.java,结果如下图:

四种方式总结

Spring Remote Service Overview

RPC调用类似于调用本地对象的方法,都是同步的操作,调用代码将被阻塞,直到被调用过程完成为止。

本地调用就是execute process在同一个应用的两个代码块中交换。RPC就是execute process从一个应用通过网络传递给另外一个应用。

Spring RemoteService支持这几种模式:RMI, Hessian, Burlap, HTTP invoker和JAX-RPC。

在Server端,Spring可以通过相应的RemoteExporter将一个Bean的发布成一个remote service。

RMI in Spring

RMI缺点:RMI在有防火墙的环境下运行会有困难,而且RMI要求客户端和服务器端都必须用Java编写。

Hessian和Burlap

Hession和Burlap都是Caucho Technology的框架,基于HTTP的轻量级remote service。

Hessian使用binary消息来建立客户端和服务器端之间的交流,因为基于binary所以对通迅带宽的占用小。所以不依赖于语言可以被Java之外的语言所用。

Burlap是基于XML的技术,消息可读性比较好,而且Burlap相比其他基于XML的技术比如SOAP来说,Burlap的消息结构比较简单,不需要WSDL之类的东西额外定义。

使用Hessian(客户端代码)

和RMI类似,Spring使用HessianProxyFactoryBean来创建一个指向Hessian服务的proxy。

由此可见,当使用Spring时,可以很简单的在各种Spring所支持的remote技术之间切换,而仅仅需要更改很少的配置。

输出Hessian服务

使用HessianServiceExporter
将POJO的public方法公开成Hessian服务。HessianServiceExporter是一个Spring MVC controller,接收Hessian的请求然后翻译成对POJO的方法调用。

输出Burlap服务

Burlap服务的输出几乎和Hessian是一样的,不同的地方就是使用org.springframework.remoting.caucho.BurlapServiceExporter。也需要为它配置URL handler和DispatcherServlet。

HTTP invoker

RMI使用Java标准的序列化机制,但是很难穿过防火墙;Hessian/Burlap能穿越防火墙但是使用自己私有的一套系列化机制。

因此HTTP invoker应运而生,使用HTTP协议能通过防火墙,并且使用Java序列化机制。

使用HTTP invoker

和RMI,Hessian等相同,HTTP invoker也是通过HttpInvokerProxyFactoryBean。

输出HTTP invoker服务

和Hessian相同,不同的地方就是使用org.springframework.remoting.httpinvoder.HttpInvokerServiceExporter。也需要为它配置URL handler和DispatcherServlet。

HTTP invoder的限制就是客户端和服务器端必须使用Spring